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

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'source/blender')
-rw-r--r--source/blender/CMakeLists.txt36
-rw-r--r--source/blender/blenfont/BLF_api.h49
-rw-r--r--source/blender/blenfont/intern/blf.c28
-rw-r--r--source/blender/blenfont/intern/blf_font.c22
-rw-r--r--source/blender/blenfont/intern/blf_font_default.c43
-rw-r--r--source/blender/blenfont/intern/blf_glyph.c403
-rw-r--r--source/blender/blenfont/intern/blf_internal.h6
-rw-r--r--source/blender/blenfont/intern/blf_internal_types.h12
-rw-r--r--source/blender/blenkernel/BKE_DerivedMesh.h21
-rw-r--r--source/blender/blenkernel/BKE_attribute.h64
-rw-r--r--source/blender/blenkernel/BKE_attribute_access.hh54
-rw-r--r--source/blender/blenkernel/BKE_attribute_math.hh14
-rw-r--r--source/blender/blenkernel/BKE_blender_version.h2
-rw-r--r--source/blender/blenkernel/BKE_bvhutils.h21
-rw-r--r--source/blender/blenkernel/BKE_callbacks.h6
-rw-r--r--source/blender/blenkernel/BKE_camera.h10
-rw-r--r--source/blender/blenkernel/BKE_collection.h12
-rw-r--r--source/blender/blenkernel/BKE_colortools.h30
-rw-r--r--source/blender/blenkernel/BKE_constraint.h21
-rw-r--r--source/blender/blenkernel/BKE_context.h7
-rw-r--r--source/blender/blenkernel/BKE_curves.h2
-rw-r--r--source/blender/blenkernel/BKE_curves.hh82
-rw-r--r--source/blender/blenkernel/BKE_curves_utils.hh84
-rw-r--r--source/blender/blenkernel/BKE_customdata.h77
-rw-r--r--source/blender/blenkernel/BKE_customdata_file.h6
-rw-r--r--source/blender/blenkernel/BKE_deform.h29
-rw-r--r--source/blender/blenkernel/BKE_fcurve.h37
-rw-r--r--source/blender/blenkernel/BKE_geometry_fields.hh22
-rw-r--r--source/blender/blenkernel/BKE_geometry_set.hh91
-rw-r--r--source/blender/blenkernel/BKE_global.h1
-rw-r--r--source/blender/blenkernel/BKE_gpencil.h12
-rw-r--r--source/blender/blenkernel/BKE_icons.h9
-rw-r--r--source/blender/blenkernel/BKE_image.h17
-rw-r--r--source/blender/blenkernel/BKE_image_format.h2
-rw-r--r--source/blender/blenkernel/BKE_image_partial_update.hh5
-rw-r--r--source/blender/blenkernel/BKE_image_save.h16
-rw-r--r--source/blender/blenkernel/BKE_lib_id.h2
-rw-r--r--source/blender/blenkernel/BKE_lib_override.h32
-rw-r--r--source/blender/blenkernel/BKE_lib_remap.h8
-rw-r--r--source/blender/blenkernel/BKE_main.h10
-rw-r--r--source/blender/blenkernel/BKE_material.h2
-rw-r--r--source/blender/blenkernel/BKE_mesh.h8
-rw-r--r--source/blender/blenkernel/BKE_mesh_boolean_convert.hh5
-rw-r--r--source/blender/blenkernel/BKE_mesh_remap.h2
-rw-r--r--source/blender/blenkernel/BKE_mesh_runtime.h2
-rw-r--r--source/blender/blenkernel/BKE_mesh_sample.hh61
-rw-r--r--source/blender/blenkernel/BKE_mesh_tangent.h2
-rw-r--r--source/blender/blenkernel/BKE_modifier.h9
-rw-r--r--source/blender/blenkernel/BKE_multires.h2
-rw-r--r--source/blender/blenkernel/BKE_node.h5
-rw-r--r--source/blender/blenkernel/BKE_node_runtime.hh89
-rw-r--r--source/blender/blenkernel/BKE_paint.h9
-rw-r--r--source/blender/blenkernel/BKE_particle.h2
-rw-r--r--source/blender/blenkernel/BKE_pbvh.h5
-rw-r--r--source/blender/blenkernel/BKE_pbvh_pixels.hh27
-rw-r--r--source/blender/blenkernel/BKE_pointcloud.h3
-rw-r--r--source/blender/blenkernel/BKE_shrinkwrap.h2
-rw-r--r--source/blender/blenkernel/BKE_sound.h4
-rw-r--r--source/blender/blenkernel/BKE_spline.hh24
-rw-r--r--source/blender/blenkernel/BKE_subdiv.h32
-rw-r--r--source/blender/blenkernel/BKE_subdiv_ccg.h7
-rw-r--r--source/blender/blenkernel/BKE_subdiv_eval.h11
-rw-r--r--source/blender/blenkernel/BKE_subdiv_modifier.h46
-rw-r--r--source/blender/blenkernel/BKE_subsurf.h21
-rw-r--r--source/blender/blenkernel/BKE_tracking.h153
-rw-r--r--source/blender/blenkernel/BKE_unit.h6
-rw-r--r--source/blender/blenkernel/CMakeLists.txt9
-rw-r--r--source/blender/blenkernel/intern/DerivedMesh.cc56
-rw-r--r--source/blender/blenkernel/intern/action.c9
-rw-r--r--source/blender/blenkernel/intern/anim_sys.c4
-rw-r--r--source/blender/blenkernel/intern/anonymous_attribute.cc2
-rw-r--r--source/blender/blenkernel/intern/appdir.c10
-rw-r--r--source/blender/blenkernel/intern/asset_catalog_test.cc2
-rw-r--r--source/blender/blenkernel/intern/attribute.cc (renamed from source/blender/blenkernel/intern/attribute.c)287
-rw-r--r--source/blender/blenkernel/intern/attribute_access.cc216
-rw-r--r--source/blender/blenkernel/intern/attribute_access_intern.hh74
-rw-r--r--source/blender/blenkernel/intern/blender_copybuffer.c4
-rw-r--r--source/blender/blenkernel/intern/blender_undo.c12
-rw-r--r--source/blender/blenkernel/intern/blendfile_link_append.c43
-rw-r--r--source/blender/blenkernel/intern/brush.c4
-rw-r--r--source/blender/blenkernel/intern/bvhutils.cc34
-rw-r--r--source/blender/blenkernel/intern/camera.c42
-rw-r--r--source/blender/blenkernel/intern/cdderivedmesh.c13
-rw-r--r--source/blender/blenkernel/intern/cloth.c6
-rw-r--r--source/blender/blenkernel/intern/collection.c39
-rw-r--r--source/blender/blenkernel/intern/colortools.c74
-rw-r--r--source/blender/blenkernel/intern/constraint.c180
-rw-r--r--source/blender/blenkernel/intern/crazyspace.c2
-rw-r--r--source/blender/blenkernel/intern/curve.cc1
-rw-r--r--source/blender/blenkernel/intern/curve_bezier.cc7
-rw-r--r--source/blender/blenkernel/intern/curve_catmull_rom.cc8
-rw-r--r--source/blender/blenkernel/intern/curve_eval.cc56
-rw-r--r--source/blender/blenkernel/intern/curve_nurbs.cc40
-rw-r--r--source/blender/blenkernel/intern/curve_poly.cc65
-rw-r--r--source/blender/blenkernel/intern/curve_to_mesh_convert.cc41
-rw-r--r--source/blender/blenkernel/intern/curves.cc93
-rw-r--r--source/blender/blenkernel/intern/curves_geometry.cc400
-rw-r--r--source/blender/blenkernel/intern/curves_utils.cc122
-rw-r--r--source/blender/blenkernel/intern/customdata.cc290
-rw-r--r--source/blender/blenkernel/intern/customdata_file.c12
-rw-r--r--source/blender/blenkernel/intern/data_transfer.c22
-rw-r--r--source/blender/blenkernel/intern/deform.c43
-rw-r--r--source/blender/blenkernel/intern/dynamicpaint.c9
-rw-r--r--source/blender/blenkernel/intern/editmesh.c1
-rw-r--r--source/blender/blenkernel/intern/effect.c2
-rw-r--r--source/blender/blenkernel/intern/fcurve.c191
-rw-r--r--source/blender/blenkernel/intern/fluid.c27
-rw-r--r--source/blender/blenkernel/intern/geometry_component_curve.cc49
-rw-r--r--source/blender/blenkernel/intern/geometry_component_curves.cc27
-rw-r--r--source/blender/blenkernel/intern/geometry_component_instances.cc14
-rw-r--r--source/blender/blenkernel/intern/geometry_component_mesh.cc23
-rw-r--r--source/blender/blenkernel/intern/geometry_component_pointcloud.cc2
-rw-r--r--source/blender/blenkernel/intern/geometry_set.cc21
-rw-r--r--source/blender/blenkernel/intern/geometry_set_instances.cc4
-rw-r--r--source/blender/blenkernel/intern/gpencil.c4
-rw-r--r--source/blender/blenkernel/intern/gpencil_geom.cc20
-rw-r--r--source/blender/blenkernel/intern/gpencil_modifier.c43
-rw-r--r--source/blender/blenkernel/intern/icons.cc75
-rw-r--r--source/blender/blenkernel/intern/idprop.c4
-rw-r--r--source/blender/blenkernel/intern/idprop_utils.c2
-rw-r--r--source/blender/blenkernel/intern/image.cc226
-rw-r--r--source/blender/blenkernel/intern/image_format.cc5
-rw-r--r--source/blender/blenkernel/intern/image_gpu.cc223
-rw-r--r--source/blender/blenkernel/intern/image_save.cc269
-rw-r--r--source/blender/blenkernel/intern/lib_id.c12
-rw-r--r--source/blender/blenkernel/intern/lib_id_delete.c17
-rw-r--r--source/blender/blenkernel/intern/lib_override.cc (renamed from source/blender/blenkernel/intern/lib_override.c)1022
-rw-r--r--source/blender/blenkernel/intern/lib_override_proxy_conversion.c5
-rw-r--r--source/blender/blenkernel/intern/lib_remap.c7
-rw-r--r--source/blender/blenkernel/intern/linestyle.c2
-rw-r--r--source/blender/blenkernel/intern/main.c6
-rw-r--r--source/blender/blenkernel/intern/material.c10
-rw-r--r--source/blender/blenkernel/intern/mesh.cc69
-rw-r--r--source/blender/blenkernel/intern/mesh_boolean_convert.cc24
-rw-r--r--source/blender/blenkernel/intern/mesh_calc_edges.cc6
-rw-r--r--source/blender/blenkernel/intern/mesh_convert.cc39
-rw-r--r--source/blender/blenkernel/intern/mesh_evaluate.cc86
-rw-r--r--source/blender/blenkernel/intern/mesh_normals.cc4
-rw-r--r--source/blender/blenkernel/intern/mesh_remesh_voxel.cc4
-rw-r--r--source/blender/blenkernel/intern/mesh_sample.cc174
-rw-r--r--source/blender/blenkernel/intern/mesh_tangent.c31
-rw-r--r--source/blender/blenkernel/intern/mesh_tessellate.c16
-rw-r--r--source/blender/blenkernel/intern/mesh_validate.cc4
-rw-r--r--source/blender/blenkernel/intern/mesh_wrapper.cc23
-rw-r--r--source/blender/blenkernel/intern/modifier.c14
-rw-r--r--source/blender/blenkernel/intern/movieclip.c3
-rw-r--r--source/blender/blenkernel/intern/multires.c4
-rw-r--r--source/blender/blenkernel/intern/multires_reshape_smooth.c4
-rw-r--r--source/blender/blenkernel/intern/multires_reshape_util.c2
-rw-r--r--source/blender/blenkernel/intern/nla.c113
-rw-r--r--source/blender/blenkernel/intern/node.cc59
-rw-r--r--source/blender/blenkernel/intern/node_tree_update.cc134
-rw-r--r--source/blender/blenkernel/intern/object.cc27
-rw-r--r--source/blender/blenkernel/intern/object_update.c5
-rw-r--r--source/blender/blenkernel/intern/ocean.c2
-rw-r--r--source/blender/blenkernel/intern/packedFile.c24
-rw-r--r--source/blender/blenkernel/intern/paint.c19
-rw-r--r--source/blender/blenkernel/intern/particle.c43
-rw-r--r--source/blender/blenkernel/intern/particle_distribute.c19
-rw-r--r--source/blender/blenkernel/intern/particle_system.c9
-rw-r--r--source/blender/blenkernel/intern/pbvh.c150
-rw-r--r--source/blender/blenkernel/intern/pbvh.cc12
-rw-r--r--source/blender/blenkernel/intern/pbvh_bmesh.c3
-rw-r--r--source/blender/blenkernel/intern/pbvh_intern.h27
-rw-r--r--source/blender/blenkernel/intern/pbvh_pixels.cc13
-rw-r--r--source/blender/blenkernel/intern/pointcache.c16
-rw-r--r--source/blender/blenkernel/intern/pointcloud.cc24
-rw-r--r--source/blender/blenkernel/intern/rigidbody.c129
-rw-r--r--source/blender/blenkernel/intern/sound.c32
-rw-r--r--source/blender/blenkernel/intern/spline_base.cc58
-rw-r--r--source/blender/blenkernel/intern/spline_bezier.cc46
-rw-r--r--source/blender/blenkernel/intern/spline_nurbs.cc56
-rw-r--r--source/blender/blenkernel/intern/spline_poly.cc2
-rw-r--r--source/blender/blenkernel/intern/subdiv.c20
-rw-r--r--source/blender/blenkernel/intern/subdiv_ccg_mask.c3
-rw-r--r--source/blender/blenkernel/intern/subdiv_ccg_material.c1
-rw-r--r--source/blender/blenkernel/intern/subdiv_eval.c67
-rw-r--r--source/blender/blenkernel/intern/subdiv_mesh.c43
-rw-r--r--source/blender/blenkernel/intern/subdiv_modifier.c97
-rw-r--r--source/blender/blenkernel/intern/subsurf_ccg.c153
-rw-r--r--source/blender/blenkernel/intern/text.c9
-rw-r--r--source/blender/blenkernel/intern/tracking.c233
-rw-r--r--source/blender/blenkernel/intern/tracking_stabilize.c2
-rw-r--r--source/blender/blenkernel/intern/unit.c23
-rw-r--r--source/blender/blenkernel/intern/volume.cc17
-rw-r--r--source/blender/blenlib/BLI_any.hh2
-rw-r--r--source/blender/blenlib/BLI_array.hh4
-rw-r--r--source/blender/blenlib/BLI_assert.h2
-rw-r--r--source/blender/blenlib/BLI_bitmap.h2
-rw-r--r--source/blender/blenlib/BLI_bounds.hh6
-rw-r--r--source/blender/blenlib/BLI_color.hh10
-rw-r--r--source/blender/blenlib/BLI_color_mix.hh2
-rw-r--r--source/blender/blenlib/BLI_fileops.h14
-rw-r--r--source/blender/blenlib/BLI_float3x3.hh192
-rw-r--r--source/blender/blenlib/BLI_float4x4.hh29
-rw-r--r--source/blender/blenlib/BLI_generic_array.hh2
-rw-r--r--source/blender/blenlib/BLI_generic_virtual_array.hh111
-rw-r--r--source/blender/blenlib/BLI_ghash.h2
-rw-r--r--source/blender/blenlib/BLI_hash_tables.hh6
-rw-r--r--source/blender/blenlib/BLI_index_mask.hh2
-rw-r--r--source/blender/blenlib/BLI_length_parameterize.hh4
-rw-r--r--source/blender/blenlib/BLI_linear_allocator.hh2
-rw-r--r--source/blender/blenlib/BLI_map.hh4
-rw-r--r--source/blender/blenlib/BLI_math_base.h10
-rw-r--r--source/blender/blenlib/BLI_math_base.hh34
-rw-r--r--source/blender/blenlib/BLI_math_color.h5
-rw-r--r--source/blender/blenlib/BLI_math_geom.h2
-rw-r--r--source/blender/blenlib/BLI_math_matrix.h2
-rw-r--r--source/blender/blenlib/BLI_math_mpq.hh6
-rw-r--r--source/blender/blenlib/BLI_math_rotation.h1
-rw-r--r--source/blender/blenlib/BLI_math_vec_types.hh4
-rw-r--r--source/blender/blenlib/BLI_math_vector.hh47
-rw-r--r--source/blender/blenlib/BLI_memory_utils.hh24
-rw-r--r--source/blender/blenlib/BLI_set.hh8
-rw-r--r--source/blender/blenlib/BLI_stack.hh4
-rw-r--r--source/blender/blenlib/BLI_string.h10
-rw-r--r--source/blender/blenlib/BLI_task.hh18
-rw-r--r--source/blender/blenlib/BLI_utildefines.h12
-rw-r--r--source/blender/blenlib/BLI_utildefines_iter.h2
-rw-r--r--source/blender/blenlib/BLI_vector.hh4
-rw-r--r--source/blender/blenlib/BLI_vector_set.hh4
-rw-r--r--source/blender/blenlib/BLI_virtual_array.hh66
-rw-r--r--source/blender/blenlib/CMakeLists.txt3
-rw-r--r--source/blender/blenlib/intern/BLI_assert.c2
-rw-r--r--source/blender/blenlib/intern/BLI_filelist.c4
-rw-r--r--source/blender/blenlib/intern/BLI_ghash.c2
-rw-r--r--source/blender/blenlib/intern/BLI_kdopbvh.c2
-rw-r--r--source/blender/blenlib/intern/array_utils.c2
-rw-r--r--source/blender/blenlib/intern/delaunay_2d.cc1
-rw-r--r--source/blender/blenlib/intern/fileops.c86
-rw-r--r--source/blender/blenlib/intern/generic_virtual_array.cc162
-rw-r--r--source/blender/blenlib/intern/hash_md5.c8
-rw-r--r--source/blender/blenlib/intern/kdtree_impl.h27
-rw-r--r--source/blender/blenlib/intern/listbase.c10
-rw-r--r--source/blender/blenlib/intern/math_base_inline.c20
-rw-r--r--source/blender/blenlib/intern/math_color.c157
-rw-r--r--source/blender/blenlib/intern/math_matrix.c12
-rw-r--r--source/blender/blenlib/intern/math_rotation.c2
-rw-r--r--source/blender/blenlib/intern/math_solvers.c4
-rw-r--r--source/blender/blenlib/intern/scanfill.c2
-rw-r--r--source/blender/blenlib/intern/string.c20
-rw-r--r--source/blender/blenlib/intern/string_cursor_utf8.c4
-rw-r--r--source/blender/blenlib/intern/string_utf8.c4
-rw-r--r--source/blender/blenlib/intern/threads.cc2
-rw-r--r--source/blender/blenlib/tests/BLI_array_store_test.cc2
-rw-r--r--source/blender/blenlib/tests/BLI_bounds_test.cc7
-rw-r--r--source/blender/blenlib/tests/BLI_float3x3_test.cc119
-rw-r--r--source/blender/blenlib/tests/BLI_kdtree_test.cc63
-rw-r--r--source/blender/blenlib/tests/BLI_math_color_test.cc68
-rw-r--r--source/blender/blenlib/tests/BLI_math_vector_test.cc20
-rw-r--r--source/blender/blenlib/tests/BLI_path_util_test.cc4
-rw-r--r--source/blender/blenlib/tests/BLI_string_test.cc86
-rw-r--r--source/blender/blenlib/tests/performance/BLI_ghash_performance_test.cc12
-rw-r--r--source/blender/blenloader/BLO_readfile.h5
-rw-r--r--source/blender/blenloader/BLO_undofile.h4
-rw-r--r--source/blender/blenloader/intern/readblenentry.c6
-rw-r--r--source/blender/blenloader/intern/readfile.c19
-rw-r--r--source/blender/blenloader/intern/undofile.c10
-rw-r--r--source/blender/blenloader/intern/versioning_280.c8
-rw-r--r--source/blender/blenloader/intern/versioning_290.c31
-rw-r--r--source/blender/blenloader/intern/versioning_300.c589
-rw-r--r--source/blender/blenloader/intern/versioning_defaults.c3
-rw-r--r--source/blender/blenloader/intern/versioning_userdef.c1
-rw-r--r--source/blender/blenloader/intern/writefile.c44
-rw-r--r--source/blender/blentranslation/BLT_translation.h7
-rw-r--r--source/blender/blentranslation/intern/blt_lang.c9
-rw-r--r--source/blender/bmesh/intern/bmesh_construct.c15
-rw-r--r--source/blender/bmesh/intern/bmesh_core.c2
-rw-r--r--source/blender/bmesh/intern/bmesh_edgeloop.c2
-rw-r--r--source/blender/bmesh/intern/bmesh_interp.c21
-rw-r--r--source/blender/bmesh/intern/bmesh_interp.h4
-rw-r--r--source/blender/bmesh/intern/bmesh_log.c7
-rw-r--r--source/blender/bmesh/intern/bmesh_mesh_convert.cc5
-rw-r--r--source/blender/bmesh/intern/bmesh_mods.c2
-rw-r--r--source/blender/bmesh/intern/bmesh_polygon.c4
-rw-r--r--source/blender/bmesh/operators/bmo_join_triangles.c2
-rw-r--r--source/blender/bmesh/tools/bmesh_bevel.c2
-rw-r--r--source/blender/compositor/intern/COM_Debug.cc8
-rw-r--r--source/blender/compositor/operations/COM_FastGaussianBlurOperation.cc10
-rw-r--r--source/blender/compositor/operations/COM_OutputFileMultiViewOperation.cc1
-rw-r--r--source/blender/compositor/operations/COM_OutputFileOperation.cc6
-rw-r--r--source/blender/compositor/operations/COM_TonemapOperation.h4
-rwxr-xr-xsource/blender/datatoc/datatoc_icon.py2
-rwxr-xr-xsource/blender/datatoc/datatoc_icon_split.py2
-rw-r--r--source/blender/depsgraph/CMakeLists.txt2
-rw-r--r--source/blender/depsgraph/DEG_depsgraph_query.h2
-rw-r--r--source/blender/depsgraph/intern/builder/deg_builder.cc33
-rw-r--r--source/blender/depsgraph/intern/builder/deg_builder_cycle.cc6
-rw-r--r--source/blender/depsgraph/intern/builder/deg_builder_nodes.cc19
-rw-r--r--source/blender/depsgraph/intern/builder/deg_builder_relations.cc148
-rw-r--r--source/blender/depsgraph/intern/builder/deg_builder_relations.h2
-rw-r--r--source/blender/depsgraph/intern/builder/deg_builder_relations_impl.h49
-rw-r--r--source/blender/depsgraph/intern/builder/deg_builder_relations_rig.cc6
-rw-r--r--source/blender/depsgraph/intern/builder/deg_builder_relations_scene.cc6
-rw-r--r--source/blender/depsgraph/intern/builder/deg_builder_rna.cc4
-rw-r--r--source/blender/depsgraph/intern/builder/deg_builder_stack.cc94
-rw-r--r--source/blender/depsgraph/intern/builder/deg_builder_stack.h140
-rw-r--r--source/blender/depsgraph/intern/depsgraph_query.cc69
-rw-r--r--source/blender/draw/CMakeLists.txt234
-rw-r--r--source/blender/draw/DRW_engine.h9
-rw-r--r--source/blender/draw/DRW_select_buffer.h8
-rw-r--r--source/blender/draw/engines/basic/basic_shader.c6
-rw-r--r--source/blender/draw/engines/basic/shaders/basic_conservative_depth_geom.glsl (renamed from source/blender/draw/engines/basic/shaders/conservative_depth_geom.glsl)0
-rw-r--r--source/blender/draw/engines/basic/shaders/basic_depth_frag.glsl (renamed from source/blender/draw/engines/basic/shaders/depth_frag.glsl)0
-rw-r--r--source/blender/draw/engines/basic/shaders/basic_depth_pointcloud_vert.glsl (renamed from source/blender/draw/engines/basic/shaders/depth_pointcloud_vert.glsl)0
-rw-r--r--source/blender/draw/engines/basic/shaders/basic_depth_vert.glsl (renamed from source/blender/draw/engines/basic/shaders/depth_vert.glsl)0
-rw-r--r--source/blender/draw/engines/basic/shaders/infos/basic_depth_info.hh8
-rw-r--r--source/blender/draw/engines/eevee/eevee_bloom.c24
-rw-r--r--source/blender/draw/engines/eevee/eevee_cryptomatte.c8
-rw-r--r--source/blender/draw/engines/eevee/eevee_data.c10
-rw-r--r--source/blender/draw/engines/eevee/eevee_lightcache.c14
-rw-r--r--source/blender/draw/engines/eevee/eevee_lookdev.c6
-rw-r--r--source/blender/draw/engines/eevee/eevee_materials.c27
-rw-r--r--source/blender/draw/engines/eevee/eevee_motion_blur.c9
-rw-r--r--source/blender/draw/engines/eevee/eevee_private.h15
-rw-r--r--source/blender/draw/engines/eevee/eevee_shaders.c8
-rw-r--r--source/blender/draw/engines/eevee/eevee_shaders_extra.cc4
-rw-r--r--source/blender/draw/engines/eevee/shaders/closure_eval_surface_lib.glsl13
-rw-r--r--source/blender/draw/engines/eevee/shaders/closure_eval_volume_lib.glsl4
-rw-r--r--source/blender/draw/engines/eevee/shaders/closure_type_lib.glsl8
-rw-r--r--source/blender/draw/engines/eevee/shaders/cryptomatte_vert.glsl6
-rw-r--r--source/blender/draw/engines/eevee/shaders/prepass_frag.glsl15
-rw-r--r--source/blender/draw/engines/eevee/shaders/shadow_vert.glsl24
-rw-r--r--source/blender/draw/engines/eevee/shaders/surface_lib.glsl14
-rw-r--r--source/blender/draw/engines/eevee/shaders/surface_vert.glsl26
-rw-r--r--source/blender/draw/engines/eevee/shaders/volumetric_frag.glsl8
-rw-r--r--source/blender/draw/engines/eevee/shaders/volumetric_integration_frag.glsl2
-rw-r--r--source/blender/draw/engines/eevee/shaders/volumetric_vert.glsl30
-rw-r--r--source/blender/draw/engines/eevee_next/eevee_camera.cc152
-rw-r--r--source/blender/draw/engines/eevee_next/eevee_camera.hh88
-rw-r--r--source/blender/draw/engines/eevee_next/eevee_defines.hh2
-rw-r--r--source/blender/draw/engines/eevee_next/eevee_engine.cc35
-rw-r--r--source/blender/draw/engines/eevee_next/eevee_instance.cc29
-rw-r--r--source/blender/draw/engines/eevee_next/eevee_instance.hh36
-rw-r--r--source/blender/draw/engines/eevee_next/eevee_material.cc65
-rw-r--r--source/blender/draw/engines/eevee_next/eevee_material.hh45
-rw-r--r--source/blender/draw/engines/eevee_next/eevee_pipeline.cc29
-rw-r--r--source/blender/draw/engines/eevee_next/eevee_pipeline.hh27
-rw-r--r--source/blender/draw/engines/eevee_next/eevee_shader.cc9
-rw-r--r--source/blender/draw/engines/eevee_next/eevee_shader.hh4
-rw-r--r--source/blender/draw/engines/eevee_next/eevee_shader_shared.hh102
-rw-r--r--source/blender/draw/engines/eevee_next/eevee_sync.cc25
-rw-r--r--source/blender/draw/engines/eevee_next/eevee_sync.hh1
-rw-r--r--source/blender/draw/engines/eevee_next/eevee_velocity.cc420
-rw-r--r--source/blender/draw/engines/eevee_next/eevee_velocity.hh178
-rw-r--r--source/blender/draw/engines/eevee_next/eevee_view.cc28
-rw-r--r--source/blender/draw/engines/eevee_next/eevee_view.hh10
-rw-r--r--source/blender/draw/engines/eevee_next/eevee_world.cc12
-rw-r--r--source/blender/draw/engines/eevee_next/shaders/eevee_attributes_lib.glsl31
-rw-r--r--source/blender/draw/engines/eevee_next/shaders/eevee_camera_lib.glsl166
-rw-r--r--source/blender/draw/engines/eevee_next/shaders/eevee_geom_curves_vert.glsl16
-rw-r--r--source/blender/draw/engines/eevee_next/shaders/eevee_geom_gpencil_vert.glsl11
-rw-r--r--source/blender/draw/engines/eevee_next/shaders/eevee_geom_mesh_vert.glsl11
-rw-r--r--source/blender/draw/engines/eevee_next/shaders/eevee_nodetree_lib.glsl5
-rw-r--r--source/blender/draw/engines/eevee_next/shaders/eevee_surf_depth_frag.glsl13
-rw-r--r--source/blender/draw/engines/eevee_next/shaders/eevee_surf_lib.glsl7
-rw-r--r--source/blender/draw/engines/eevee_next/shaders/eevee_velocity_lib.glsl101
-rw-r--r--source/blender/draw/engines/eevee_next/shaders/eevee_velocity_resolve_comp.glsl58
-rw-r--r--source/blender/draw/engines/eevee_next/shaders/infos/eevee_material_info.hh14
-rw-r--r--source/blender/draw/engines/eevee_next/shaders/infos/eevee_velocity_info.hh55
-rw-r--r--source/blender/draw/engines/external/external_engine.c4
-rw-r--r--source/blender/draw/engines/gpencil/gpencil_cache_utils.c2
-rw-r--r--source/blender/draw/engines/gpencil/gpencil_render.c12
-rw-r--r--source/blender/draw/engines/image/image_instance_data.hh6
-rw-r--r--source/blender/draw/engines/image/image_texture_info.hh2
-rw-r--r--source/blender/draw/engines/overlay/overlay_edit_uv.c2
-rw-r--r--source/blender/draw/engines/overlay/overlay_extra.c10
-rw-r--r--source/blender/draw/engines/overlay/overlay_gpencil.c6
-rw-r--r--source/blender/draw/engines/overlay/overlay_shader.c4
-rw-r--r--source/blender/draw/engines/overlay/overlay_shader_shared.h26
-rw-r--r--source/blender/draw/engines/overlay/shaders/infos/overlay_antialiasing_info.hh (renamed from source/blender/draw/engines/overlay/shaders/infos/antialiasing_info.hh)4
-rw-r--r--source/blender/draw/engines/overlay/shaders/infos/overlay_armature_info.hh (renamed from source/blender/draw/engines/overlay/shaders/infos/armature_info.hh)44
-rw-r--r--source/blender/draw/engines/overlay/shaders/infos/overlay_background_info.hh (renamed from source/blender/draw/engines/overlay/shaders/infos/background_info.hh)8
-rw-r--r--source/blender/draw/engines/overlay/shaders/infos/overlay_edit_mode_info.hh (renamed from source/blender/draw/engines/overlay/shaders/infos/edit_mode_info.hh)140
-rw-r--r--source/blender/draw/engines/overlay/shaders/infos/overlay_extra_info.hh (renamed from source/blender/draw/engines/overlay/shaders/infos/extra_info.hh)50
-rw-r--r--source/blender/draw/engines/overlay/shaders/infos/overlay_facing_info.hh (renamed from source/blender/draw/engines/overlay/shaders/infos/facing_info.hh)4
-rw-r--r--source/blender/draw/engines/overlay/shaders/infos/overlay_grid_info.hh (renamed from source/blender/draw/engines/overlay/shaders/infos/grid_info.hh)14
-rw-r--r--source/blender/draw/engines/overlay/shaders/infos/overlay_outline_info.hh (renamed from source/blender/draw/engines/overlay/shaders/infos/outline_info.hh)16
-rw-r--r--source/blender/draw/engines/overlay/shaders/infos/overlay_paint_info.hh (renamed from source/blender/draw/engines/overlay/shaders/infos/paint_info.hh)26
-rw-r--r--source/blender/draw/engines/overlay/shaders/infos/overlay_sculpt_info.hh (renamed from source/blender/draw/engines/overlay/shaders/infos/sculpt_info.hh)4
-rw-r--r--source/blender/draw/engines/overlay/shaders/infos/overlay_volume_info.hh (renamed from source/blender/draw/engines/overlay/shaders/infos/volume_info.hh)12
-rw-r--r--source/blender/draw/engines/overlay/shaders/infos/overlay_wireframe_info.hh (renamed from source/blender/draw/engines/overlay/shaders/infos/wireframe_info.hh)4
-rw-r--r--source/blender/draw/engines/overlay/shaders/overlay_antialiasing_frag.glsl (renamed from source/blender/draw/engines/overlay/shaders/antialiasing_frag.glsl)0
-rw-r--r--source/blender/draw/engines/overlay/shaders/overlay_armature_dof_solid_frag.glsl (renamed from source/blender/draw/engines/overlay/shaders/armature_dof_solid_frag.glsl)0
-rw-r--r--source/blender/draw/engines/overlay/shaders/overlay_armature_dof_vert.glsl (renamed from source/blender/draw/engines/overlay/shaders/armature_dof_vert.glsl)0
-rw-r--r--source/blender/draw/engines/overlay/shaders/overlay_armature_envelope_outline_vert.glsl (renamed from source/blender/draw/engines/overlay/shaders/armature_envelope_outline_vert.glsl)0
-rw-r--r--source/blender/draw/engines/overlay/shaders/overlay_armature_envelope_solid_frag.glsl (renamed from source/blender/draw/engines/overlay/shaders/armature_envelope_solid_frag.glsl)0
-rw-r--r--source/blender/draw/engines/overlay/shaders/overlay_armature_envelope_solid_vert.glsl (renamed from source/blender/draw/engines/overlay/shaders/armature_envelope_solid_vert.glsl)0
-rw-r--r--source/blender/draw/engines/overlay/shaders/overlay_armature_shape_outline_geom.glsl (renamed from source/blender/draw/engines/overlay/shaders/armature_shape_outline_geom.glsl)0
-rw-r--r--source/blender/draw/engines/overlay/shaders/overlay_armature_shape_outline_vert.glsl (renamed from source/blender/draw/engines/overlay/shaders/armature_shape_outline_vert.glsl)0
-rw-r--r--source/blender/draw/engines/overlay/shaders/overlay_armature_shape_solid_frag.glsl (renamed from source/blender/draw/engines/overlay/shaders/armature_shape_solid_frag.glsl)0
-rw-r--r--source/blender/draw/engines/overlay/shaders/overlay_armature_shape_solid_vert.glsl (renamed from source/blender/draw/engines/overlay/shaders/armature_shape_solid_vert.glsl)0
-rw-r--r--source/blender/draw/engines/overlay/shaders/overlay_armature_shape_wire_vert.glsl (renamed from source/blender/draw/engines/overlay/shaders/armature_shape_wire_vert.glsl)0
-rw-r--r--source/blender/draw/engines/overlay/shaders/overlay_armature_sphere_outline_vert.glsl (renamed from source/blender/draw/engines/overlay/shaders/armature_sphere_outline_vert.glsl)0
-rw-r--r--source/blender/draw/engines/overlay/shaders/overlay_armature_sphere_solid_frag.glsl (renamed from source/blender/draw/engines/overlay/shaders/armature_sphere_solid_frag.glsl)0
-rw-r--r--source/blender/draw/engines/overlay/shaders/overlay_armature_sphere_solid_vert.glsl (renamed from source/blender/draw/engines/overlay/shaders/armature_sphere_solid_vert.glsl)0
-rw-r--r--source/blender/draw/engines/overlay/shaders/overlay_armature_stick_frag.glsl (renamed from source/blender/draw/engines/overlay/shaders/armature_stick_frag.glsl)0
-rw-r--r--source/blender/draw/engines/overlay/shaders/overlay_armature_stick_vert.glsl (renamed from source/blender/draw/engines/overlay/shaders/armature_stick_vert.glsl)0
-rw-r--r--source/blender/draw/engines/overlay/shaders/overlay_armature_wire_frag.glsl (renamed from source/blender/draw/engines/overlay/shaders/armature_wire_frag.glsl)0
-rw-r--r--source/blender/draw/engines/overlay/shaders/overlay_armature_wire_vert.glsl (renamed from source/blender/draw/engines/overlay/shaders/armature_wire_vert.glsl)0
-rw-r--r--source/blender/draw/engines/overlay/shaders/overlay_background_frag.glsl (renamed from source/blender/draw/engines/overlay/shaders/background_frag.glsl)0
-rw-r--r--source/blender/draw/engines/overlay/shaders/overlay_clipbound_vert.glsl (renamed from source/blender/draw/engines/overlay/shaders/clipbound_vert.glsl)0
-rw-r--r--source/blender/draw/engines/overlay/shaders/overlay_common_lib.glsl (renamed from source/blender/draw/engines/overlay/shaders/common_overlay_lib.glsl)0
-rw-r--r--source/blender/draw/engines/overlay/shaders/overlay_depth_only_frag.glsl6
-rw-r--r--source/blender/draw/engines/overlay/shaders/overlay_depth_only_vert.glsl (renamed from source/blender/draw/engines/overlay/shaders/depth_only_vert.glsl)0
-rw-r--r--source/blender/draw/engines/overlay/shaders/overlay_edit_curve_handle_geom.glsl (renamed from source/blender/draw/engines/overlay/shaders/edit_curve_handle_geom.glsl)0
-rw-r--r--source/blender/draw/engines/overlay/shaders/overlay_edit_curve_handle_vert.glsl (renamed from source/blender/draw/engines/overlay/shaders/edit_curve_handle_vert.glsl)0
-rw-r--r--source/blender/draw/engines/overlay/shaders/overlay_edit_curve_point_vert.glsl (renamed from source/blender/draw/engines/overlay/shaders/edit_curve_point_vert.glsl)0
-rw-r--r--source/blender/draw/engines/overlay/shaders/overlay_edit_curve_wire_vert.glsl (renamed from source/blender/draw/engines/overlay/shaders/edit_curve_wire_vert.glsl)0
-rw-r--r--source/blender/draw/engines/overlay/shaders/overlay_edit_gpencil_canvas_vert.glsl (renamed from source/blender/draw/engines/overlay/shaders/edit_gpencil_canvas_vert.glsl)0
-rw-r--r--source/blender/draw/engines/overlay/shaders/overlay_edit_gpencil_guide_vert.glsl (renamed from source/blender/draw/engines/overlay/shaders/edit_gpencil_guide_vert.glsl)0
-rw-r--r--source/blender/draw/engines/overlay/shaders/overlay_edit_gpencil_vert.glsl (renamed from source/blender/draw/engines/overlay/shaders/edit_gpencil_vert.glsl)0
-rw-r--r--source/blender/draw/engines/overlay/shaders/overlay_edit_lattice_point_vert.glsl (renamed from source/blender/draw/engines/overlay/shaders/edit_lattice_point_vert.glsl)0
-rw-r--r--source/blender/draw/engines/overlay/shaders/overlay_edit_lattice_wire_vert.glsl (renamed from source/blender/draw/engines/overlay/shaders/edit_lattice_wire_vert.glsl)0
-rw-r--r--source/blender/draw/engines/overlay/shaders/overlay_edit_mesh_analysis_frag.glsl (renamed from source/blender/draw/engines/overlay/shaders/edit_mesh_analysis_frag.glsl)0
-rw-r--r--source/blender/draw/engines/overlay/shaders/overlay_edit_mesh_analysis_vert.glsl (renamed from source/blender/draw/engines/overlay/shaders/edit_mesh_analysis_vert.glsl)0
-rw-r--r--source/blender/draw/engines/overlay/shaders/overlay_edit_mesh_common_lib.glsl (renamed from source/blender/draw/engines/overlay/shaders/edit_mesh_common_lib.glsl)0
-rw-r--r--source/blender/draw/engines/overlay/shaders/overlay_edit_mesh_frag.glsl (renamed from source/blender/draw/engines/overlay/shaders/edit_mesh_frag.glsl)0
-rw-r--r--source/blender/draw/engines/overlay/shaders/overlay_edit_mesh_geom.glsl (renamed from source/blender/draw/engines/overlay/shaders/edit_mesh_geom.glsl)0
-rw-r--r--source/blender/draw/engines/overlay/shaders/overlay_edit_mesh_normal_vert.glsl (renamed from source/blender/draw/engines/overlay/shaders/edit_mesh_normal_vert.glsl)0
-rw-r--r--source/blender/draw/engines/overlay/shaders/overlay_edit_mesh_skin_root_vert.glsl (renamed from source/blender/draw/engines/overlay/shaders/edit_mesh_skin_root_vert.glsl)0
-rw-r--r--source/blender/draw/engines/overlay/shaders/overlay_edit_mesh_vert.glsl (renamed from source/blender/draw/engines/overlay/shaders/edit_mesh_vert.glsl)2
-rw-r--r--source/blender/draw/engines/overlay/shaders/overlay_edit_particle_point_vert.glsl (renamed from source/blender/draw/engines/overlay/shaders/edit_particle_point_vert.glsl)0
-rw-r--r--source/blender/draw/engines/overlay/shaders/overlay_edit_particle_strand_vert.glsl (renamed from source/blender/draw/engines/overlay/shaders/edit_particle_strand_vert.glsl)0
-rw-r--r--source/blender/draw/engines/overlay/shaders/overlay_edit_uv_edges_frag.glsl (renamed from source/blender/draw/engines/overlay/shaders/edit_uv_edges_frag.glsl)2
-rw-r--r--source/blender/draw/engines/overlay/shaders/overlay_edit_uv_edges_geom.glsl (renamed from source/blender/draw/engines/overlay/shaders/edit_uv_edges_geom.glsl)5
-rw-r--r--source/blender/draw/engines/overlay/shaders/overlay_edit_uv_edges_vert.glsl (renamed from source/blender/draw/engines/overlay/shaders/edit_uv_edges_vert.glsl)0
-rw-r--r--source/blender/draw/engines/overlay/shaders/overlay_edit_uv_face_dots_vert.glsl (renamed from source/blender/draw/engines/overlay/shaders/edit_uv_face_dots_vert.glsl)2
-rw-r--r--source/blender/draw/engines/overlay/shaders/overlay_edit_uv_faces_vert.glsl (renamed from source/blender/draw/engines/overlay/shaders/edit_uv_faces_vert.glsl)0
-rw-r--r--source/blender/draw/engines/overlay/shaders/overlay_edit_uv_image_mask_frag.glsl (renamed from source/blender/draw/engines/overlay/shaders/edit_uv_image_mask_frag.glsl)0
-rw-r--r--source/blender/draw/engines/overlay/shaders/overlay_edit_uv_image_vert.glsl (renamed from source/blender/draw/engines/overlay/shaders/edit_uv_image_vert.glsl)0
-rw-r--r--source/blender/draw/engines/overlay/shaders/overlay_edit_uv_stretching_vert.glsl (renamed from source/blender/draw/engines/overlay/shaders/edit_uv_stretching_vert.glsl)0
-rw-r--r--source/blender/draw/engines/overlay/shaders/overlay_edit_uv_tiled_image_borders_vert.glsl (renamed from source/blender/draw/engines/overlay/shaders/edit_uv_tiled_image_borders_vert.glsl)0
-rw-r--r--source/blender/draw/engines/overlay/shaders/overlay_edit_uv_verts_frag.glsl (renamed from source/blender/draw/engines/overlay/shaders/edit_uv_verts_frag.glsl)0
-rw-r--r--source/blender/draw/engines/overlay/shaders/overlay_edit_uv_verts_vert.glsl (renamed from source/blender/draw/engines/overlay/shaders/edit_uv_verts_vert.glsl)0
-rw-r--r--source/blender/draw/engines/overlay/shaders/overlay_extra_frag.glsl (renamed from source/blender/draw/engines/overlay/shaders/extra_frag.glsl)0
-rw-r--r--source/blender/draw/engines/overlay/shaders/overlay_extra_groundline_vert.glsl (renamed from source/blender/draw/engines/overlay/shaders/extra_groundline_vert.glsl)0
-rw-r--r--source/blender/draw/engines/overlay/shaders/overlay_extra_lightprobe_grid_vert.glsl (renamed from source/blender/draw/engines/overlay/shaders/extra_lightprobe_grid_vert.glsl)0
-rw-r--r--source/blender/draw/engines/overlay/shaders/overlay_extra_loose_point_frag.glsl (renamed from source/blender/draw/engines/overlay/shaders/extra_loose_point_frag.glsl)0
-rw-r--r--source/blender/draw/engines/overlay/shaders/overlay_extra_loose_point_vert.glsl (renamed from source/blender/draw/engines/overlay/shaders/extra_loose_point_vert.glsl)0
-rw-r--r--source/blender/draw/engines/overlay/shaders/overlay_extra_point_vert.glsl (renamed from source/blender/draw/engines/overlay/shaders/extra_point_vert.glsl)0
-rw-r--r--source/blender/draw/engines/overlay/shaders/overlay_extra_vert.glsl (renamed from source/blender/draw/engines/overlay/shaders/extra_vert.glsl)0
-rw-r--r--source/blender/draw/engines/overlay/shaders/overlay_extra_wire_frag.glsl (renamed from source/blender/draw/engines/overlay/shaders/extra_wire_frag.glsl)0
-rw-r--r--source/blender/draw/engines/overlay/shaders/overlay_extra_wire_vert.glsl (renamed from source/blender/draw/engines/overlay/shaders/extra_wire_vert.glsl)0
-rw-r--r--source/blender/draw/engines/overlay/shaders/overlay_facing_frag.glsl (renamed from source/blender/draw/engines/overlay/shaders/facing_frag.glsl)0
-rw-r--r--source/blender/draw/engines/overlay/shaders/overlay_facing_vert.glsl (renamed from source/blender/draw/engines/overlay/shaders/facing_vert.glsl)0
-rw-r--r--source/blender/draw/engines/overlay/shaders/overlay_grid_background_frag.glsl (renamed from source/blender/draw/engines/overlay/shaders/grid_background_frag.glsl)0
-rw-r--r--source/blender/draw/engines/overlay/shaders/overlay_grid_frag.glsl (renamed from source/blender/draw/engines/overlay/shaders/grid_frag.glsl)0
-rw-r--r--source/blender/draw/engines/overlay/shaders/overlay_grid_vert.glsl (renamed from source/blender/draw/engines/overlay/shaders/grid_vert.glsl)0
-rw-r--r--source/blender/draw/engines/overlay/shaders/overlay_image_frag.glsl (renamed from source/blender/draw/engines/overlay/shaders/image_frag.glsl)0
-rw-r--r--source/blender/draw/engines/overlay/shaders/overlay_image_vert.glsl (renamed from source/blender/draw/engines/overlay/shaders/image_vert.glsl)0
-rw-r--r--source/blender/draw/engines/overlay/shaders/overlay_motion_path_line_frag.glsl (renamed from source/blender/draw/engines/overlay/shaders/motion_path_line_frag.glsl)0
-rw-r--r--source/blender/draw/engines/overlay/shaders/overlay_motion_path_line_geom.glsl (renamed from source/blender/draw/engines/overlay/shaders/motion_path_line_geom.glsl)0
-rw-r--r--source/blender/draw/engines/overlay/shaders/overlay_motion_path_line_vert.glsl (renamed from source/blender/draw/engines/overlay/shaders/motion_path_line_vert.glsl)0
-rw-r--r--source/blender/draw/engines/overlay/shaders/overlay_motion_path_point_vert.glsl (renamed from source/blender/draw/engines/overlay/shaders/motion_path_point_vert.glsl)0
-rw-r--r--source/blender/draw/engines/overlay/shaders/overlay_outline_detect_frag.glsl (renamed from source/blender/draw/engines/overlay/shaders/outline_detect_frag.glsl)4
-rw-r--r--source/blender/draw/engines/overlay/shaders/overlay_outline_prepass_frag.glsl (renamed from source/blender/draw/engines/overlay/shaders/outline_prepass_frag.glsl)0
-rw-r--r--source/blender/draw/engines/overlay/shaders/overlay_outline_prepass_geom.glsl (renamed from source/blender/draw/engines/overlay/shaders/outline_prepass_geom.glsl)0
-rw-r--r--source/blender/draw/engines/overlay/shaders/overlay_outline_prepass_gpencil_frag.glsl (renamed from source/blender/draw/engines/overlay/shaders/outline_prepass_gpencil_frag.glsl)0
-rw-r--r--source/blender/draw/engines/overlay/shaders/overlay_outline_prepass_gpencil_vert.glsl (renamed from source/blender/draw/engines/overlay/shaders/outline_prepass_gpencil_vert.glsl)0
-rw-r--r--source/blender/draw/engines/overlay/shaders/overlay_outline_prepass_pointcloud_vert.glsl (renamed from source/blender/draw/engines/overlay/shaders/outline_prepass_pointcloud_vert.glsl)0
-rw-r--r--source/blender/draw/engines/overlay/shaders/overlay_outline_prepass_vert.glsl (renamed from source/blender/draw/engines/overlay/shaders/outline_prepass_vert.glsl)0
-rw-r--r--source/blender/draw/engines/overlay/shaders/overlay_paint_face_vert.glsl (renamed from source/blender/draw/engines/overlay/shaders/paint_face_vert.glsl)0
-rw-r--r--source/blender/draw/engines/overlay/shaders/overlay_paint_point_vert.glsl (renamed from source/blender/draw/engines/overlay/shaders/paint_point_vert.glsl)0
-rw-r--r--source/blender/draw/engines/overlay/shaders/overlay_paint_texture_frag.glsl (renamed from source/blender/draw/engines/overlay/shaders/paint_texture_frag.glsl)0
-rw-r--r--source/blender/draw/engines/overlay/shaders/overlay_paint_texture_vert.glsl (renamed from source/blender/draw/engines/overlay/shaders/paint_texture_vert.glsl)0
-rw-r--r--source/blender/draw/engines/overlay/shaders/overlay_paint_vertcol_frag.glsl (renamed from source/blender/draw/engines/overlay/shaders/paint_vertcol_frag.glsl)0
-rw-r--r--source/blender/draw/engines/overlay/shaders/overlay_paint_vertcol_vert.glsl (renamed from source/blender/draw/engines/overlay/shaders/paint_vertcol_vert.glsl)0
-rw-r--r--source/blender/draw/engines/overlay/shaders/overlay_paint_weight_frag.glsl (renamed from source/blender/draw/engines/overlay/shaders/paint_weight_frag.glsl)0
-rw-r--r--source/blender/draw/engines/overlay/shaders/overlay_paint_weight_vert.glsl (renamed from source/blender/draw/engines/overlay/shaders/paint_weight_vert.glsl)0
-rw-r--r--source/blender/draw/engines/overlay/shaders/overlay_paint_wire_vert.glsl (renamed from source/blender/draw/engines/overlay/shaders/paint_wire_vert.glsl)0
-rw-r--r--source/blender/draw/engines/overlay/shaders/overlay_particle_frag.glsl (renamed from source/blender/draw/engines/overlay/shaders/particle_frag.glsl)0
-rw-r--r--source/blender/draw/engines/overlay/shaders/overlay_particle_vert.glsl (renamed from source/blender/draw/engines/overlay/shaders/particle_vert.glsl)0
-rw-r--r--source/blender/draw/engines/overlay/shaders/overlay_point_varying_color_frag.glsl23
-rw-r--r--source/blender/draw/engines/overlay/shaders/overlay_point_varying_color_varying_outline_aa_frag.glsl27
-rw-r--r--source/blender/draw/engines/overlay/shaders/overlay_sculpt_mask_frag.glsl (renamed from source/blender/draw/engines/overlay/shaders/sculpt_mask_frag.glsl)0
-rw-r--r--source/blender/draw/engines/overlay/shaders/overlay_sculpt_mask_vert.glsl (renamed from source/blender/draw/engines/overlay/shaders/sculpt_mask_vert.glsl)0
-rw-r--r--source/blender/draw/engines/overlay/shaders/overlay_uniform_color_frag.glsl4
-rw-r--r--source/blender/draw/engines/overlay/shaders/overlay_varying_color.glsl4
-rw-r--r--source/blender/draw/engines/overlay/shaders/overlay_volume_gridlines_vert.glsl (renamed from source/blender/draw/engines/overlay/shaders/volume_gridlines_vert.glsl)0
-rw-r--r--source/blender/draw/engines/overlay/shaders/overlay_volume_velocity_vert.glsl (renamed from source/blender/draw/engines/overlay/shaders/volume_velocity_vert.glsl)0
-rw-r--r--source/blender/draw/engines/overlay/shaders/overlay_wireframe_frag.glsl (renamed from source/blender/draw/engines/overlay/shaders/wireframe_frag.glsl)0
-rw-r--r--source/blender/draw/engines/overlay/shaders/overlay_wireframe_vert.glsl (renamed from source/blender/draw/engines/overlay/shaders/wireframe_vert.glsl)0
-rw-r--r--source/blender/draw/engines/overlay/shaders/overlay_xray_fade_frag.glsl (renamed from source/blender/draw/engines/overlay/shaders/xray_fade_frag.glsl)0
-rw-r--r--source/blender/draw/engines/workbench/shaders/infos/workbench_prepass_info.hh2
-rw-r--r--source/blender/draw/engines/workbench/shaders/workbench_volume_frag.glsl8
-rw-r--r--source/blender/draw/engines/workbench/workbench_engine.c5
-rw-r--r--source/blender/draw/engines/workbench/workbench_render.c6
-rw-r--r--source/blender/draw/engines/workbench/workbench_volume.c22
-rw-r--r--source/blender/draw/intern/DRW_gpu_wrapper.hh111
-rw-r--r--source/blender/draw/intern/DRW_render.h17
-rw-r--r--source/blender/draw/intern/draw_attributes.cc114
-rw-r--r--source/blender/draw/intern/draw_attributes.h61
-rw-r--r--source/blender/draw/intern/draw_cache.c35
-rw-r--r--source/blender/draw/intern/draw_cache_extract.hh (renamed from source/blender/draw/intern/draw_cache_extract.h)152
-rw-r--r--source/blender/draw/intern/draw_cache_extract_mesh.cc104
-rw-r--r--source/blender/draw/intern/draw_cache_extract_mesh_render_data.cc (renamed from source/blender/draw/intern/draw_cache_extract_mesh_render_data.c)131
-rw-r--r--source/blender/draw/intern/draw_cache_impl.h17
-rw-r--r--source/blender/draw/intern/draw_cache_impl_curve.cc2
-rw-r--r--source/blender/draw/intern/draw_cache_impl_curves.cc292
-rw-r--r--source/blender/draw/intern/draw_cache_impl_mesh.cc (renamed from source/blender/draw/intern/draw_cache_impl_mesh.c)912
-rw-r--r--source/blender/draw/intern/draw_cache_impl_particles.c54
-rw-r--r--source/blender/draw/intern/draw_cache_impl_subdivision.cc239
-rw-r--r--source/blender/draw/intern/draw_common.h8
-rw-r--r--source/blender/draw/intern/draw_curves.cc245
-rw-r--r--source/blender/draw/intern/draw_curves_private.h41
-rw-r--r--source/blender/draw/intern/draw_fluid.c4
-rw-r--r--source/blender/draw/intern/draw_hair.cc (renamed from source/blender/draw/intern/draw_hair.c)41
-rw-r--r--source/blender/draw/intern/draw_manager.c20
-rw-r--r--source/blender/draw/intern/draw_manager.h6
-rw-r--r--source/blender/draw/intern/draw_manager_data.c43
-rw-r--r--source/blender/draw/intern/draw_manager_exec.c6
-rw-r--r--source/blender/draw/intern/draw_shader.cc (renamed from source/blender/draw/intern/draw_shader.c)32
-rw-r--r--source/blender/draw/intern/draw_shader.h2
-rw-r--r--source/blender/draw/intern/draw_shader_shared.h14
-rw-r--r--source/blender/draw/intern/draw_subdivision.h17
-rw-r--r--source/blender/draw/intern/draw_view_data.cc17
-rw-r--r--source/blender/draw/intern/draw_volume.cc12
-rw-r--r--source/blender/draw/intern/mesh_extractors/extract_mesh.cc (renamed from source/blender/draw/intern/mesh_extractors/extract_mesh.c)6
-rw-r--r--source/blender/draw/intern/mesh_extractors/extract_mesh.hh (renamed from source/blender/draw/intern/mesh_extractors/extract_mesh.h)140
-rw-r--r--source/blender/draw/intern/mesh_extractors/extract_mesh_ibo_edituv.cc40
-rw-r--r--source/blender/draw/intern/mesh_extractors/extract_mesh_ibo_fdots.cc8
-rw-r--r--source/blender/draw/intern/mesh_extractors/extract_mesh_ibo_lines.cc55
-rw-r--r--source/blender/draw/intern/mesh_extractors/extract_mesh_ibo_lines_adjacency.cc12
-rw-r--r--source/blender/draw/intern/mesh_extractors/extract_mesh_ibo_lines_paint_mask.cc13
-rw-r--r--source/blender/draw/intern/mesh_extractors/extract_mesh_ibo_points.cc34
-rw-r--r--source/blender/draw/intern/mesh_extractors/extract_mesh_ibo_tris.cc14
-rw-r--r--source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_attributes.cc191
-rw-r--r--source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_edge_fac.cc10
-rw-r--r--source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_edit_data.cc6
-rw-r--r--source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_edituv_data.cc6
-rw-r--r--source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_edituv_stretch_angle.cc14
-rw-r--r--source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_edituv_stretch_area.cc10
-rw-r--r--source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_fdots_edituv_data.cc6
-rw-r--r--source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_fdots_nor.cc12
-rw-r--r--source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_fdots_pos.cc15
-rw-r--r--source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_fdots_uv.cc10
-rw-r--r--source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_lnor.cc10
-rw-r--r--source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_mesh_analysis.cc8
-rw-r--r--source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_orco.cc77
-rw-r--r--source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_pos_nor.cc32
-rw-r--r--source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_sculpt_data.cc18
-rw-r--r--source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_select_idx.cc8
-rw-r--r--source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_skin_roots.cc6
-rw-r--r--source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_tan.cc19
-rw-r--r--source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_uv.cc13
-rw-r--r--source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_vcol.cc119
-rw-r--r--source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_weights.cc8
-rw-r--r--source/blender/draw/intern/shaders/common_globals_lib.glsl2
-rw-r--r--source/blender/draw/intern/shaders/common_gpencil_lib.glsl2
-rw-r--r--source/blender/draw/intern/shaders/common_hair_lib.glsl6
-rw-r--r--source/blender/draw/intern/shaders/common_math_lib.glsl1
-rw-r--r--source/blender/draw/intern/shaders/common_subdiv_ibo_lines_comp.glsl43
-rw-r--r--source/blender/draw/intern/shaders/common_subdiv_ibo_tris_comp.glsl41
-rw-r--r--source/blender/draw/intern/shaders/common_subdiv_lib.glsl19
-rw-r--r--source/blender/draw/intern/shaders/common_subdiv_patch_evaluation_comp.glsl77
-rw-r--r--source/blender/draw/intern/shaders/common_subdiv_vbo_lnor_comp.glsl38
-rw-r--r--source/blender/draw/intern/shaders/draw_object_infos_info.hh4
-rw-r--r--source/blender/editors/animation/anim_channels_defines.c10
-rw-r--r--source/blender/editors/animation/anim_channels_edit.c74
-rw-r--r--source/blender/editors/animation/anim_markers.c2
-rw-r--r--source/blender/editors/animation/anim_ops.c5
-rw-r--r--source/blender/editors/animation/drivers.c2
-rw-r--r--source/blender/editors/animation/keyframes_draw.c38
-rw-r--r--source/blender/editors/animation/keyframes_keylist.cc4
-rw-r--r--source/blender/editors/animation/keyframing.c36
-rw-r--r--source/blender/editors/animation/keyingsets.c66
-rw-r--r--source/blender/editors/armature/armature_add.c11
-rw-r--r--source/blender/editors/armature/armature_edit.c7
-rw-r--r--source/blender/editors/armature/armature_naming.c9
-rw-r--r--source/blender/editors/armature/armature_relations.c27
-rw-r--r--source/blender/editors/armature/armature_skinning.c1
-rw-r--r--source/blender/editors/armature/pose_lib.c2
-rw-r--r--source/blender/editors/armature/pose_select.c9
-rw-r--r--source/blender/editors/curve/editcurve.c42
-rw-r--r--source/blender/editors/curve/editcurve_paint.c8
-rw-r--r--source/blender/editors/curve/editcurve_pen.c10
-rw-r--r--source/blender/editors/curves/CMakeLists.txt5
-rw-r--r--source/blender/editors/curves/intern/curves_add.cc2
-rw-r--r--source/blender/editors/curves/intern/curves_ops.cc513
-rw-r--r--source/blender/editors/datafiles/CMakeLists.txt19
-rw-r--r--source/blender/editors/geometry/geometry_attributes.cc131
-rw-r--r--source/blender/editors/geometry/geometry_intern.hh1
-rw-r--r--source/blender/editors/geometry/geometry_ops.cc1
-rw-r--r--source/blender/editors/gizmo_library/geometry/geom_arrow_gizmo.c2
-rw-r--r--source/blender/editors/gizmo_library/gizmo_draw_utils.c2
-rw-r--r--source/blender/editors/gizmo_library/gizmo_types/arrow3d_gizmo.c62
-rw-r--r--source/blender/editors/gizmo_library/gizmo_types/button2d_gizmo.c30
-rw-r--r--source/blender/editors/gizmo_library/gizmo_types/dial3d_gizmo.c112
-rw-r--r--source/blender/editors/gizmo_library/gizmo_types/move3d_gizmo.c4
-rw-r--r--source/blender/editors/gizmo_library/gizmo_types/snap3d_gizmo.c4
-rw-r--r--source/blender/editors/gpencil/drawgpencil.c4
-rw-r--r--source/blender/editors/gpencil/gpencil_bake_animation.cc1
-rw-r--r--source/blender/editors/gpencil/gpencil_convert.c2
-rw-r--r--source/blender/editors/gpencil/gpencil_edit.c62
-rw-r--r--source/blender/editors/gpencil/gpencil_intern.h10
-rw-r--r--source/blender/editors/gpencil/gpencil_interpolate.c17
-rw-r--r--source/blender/editors/gpencil/gpencil_sculpt_paint.c2
-rw-r--r--source/blender/editors/gpencil/gpencil_select.c3
-rw-r--r--source/blender/editors/gpencil/gpencil_utils.c44
-rw-r--r--source/blender/editors/gpencil/gpencil_vertex_ops.c2
-rw-r--r--source/blender/editors/include/BIF_glutil.h20
-rw-r--r--source/blender/editors/include/ED_anim_api.h2
-rw-r--r--source/blender/editors/include/ED_clip.h42
-rw-r--r--source/blender/editors/include/ED_curve.h2
-rw-r--r--source/blender/editors/include/ED_datafiles.h38
-rw-r--r--source/blender/editors/include/ED_fileselect.h8
-rw-r--r--source/blender/editors/include/ED_geometry.h12
-rw-r--r--source/blender/editors/include/ED_gizmo_library.h22
-rw-r--r--source/blender/editors/include/ED_gpencil.h6
-rw-r--r--source/blender/editors/include/ED_image.h43
-rw-r--r--source/blender/editors/include/ED_keyframing.h22
-rw-r--r--source/blender/editors/include/ED_mask.h29
-rw-r--r--source/blender/editors/include/ED_mesh.h16
-rw-r--r--source/blender/editors/include/ED_object.h14
-rw-r--r--source/blender/editors/include/ED_scene.h5
-rw-r--r--source/blender/editors/include/ED_screen.h5
-rw-r--r--source/blender/editors/include/ED_sculpt.h2
-rw-r--r--source/blender/editors/include/ED_select_utils.h20
-rw-r--r--source/blender/editors/include/ED_transform_snap_object_context.h66
-rw-r--r--source/blender/editors/include/ED_uvedit.h4
-rw-r--r--source/blender/editors/include/ED_view3d.h30
-rw-r--r--source/blender/editors/include/UI_grid_view.hh264
-rw-r--r--source/blender/editors/include/UI_icons.h17
-rw-r--r--source/blender/editors/include/UI_interface.h155
-rw-r--r--source/blender/editors/include/UI_interface.hh5
-rw-r--r--source/blender/editors/include/UI_interface_icons.h2
-rw-r--r--source/blender/editors/include/UI_tree_view.hh6
-rw-r--r--source/blender/editors/interface/CMakeLists.txt2
-rw-r--r--source/blender/editors/interface/grid_view.cc525
-rw-r--r--source/blender/editors/interface/interface.cc264
-rw-r--r--source/blender/editors/interface/interface_anim.c2
-rw-r--r--source/blender/editors/interface/interface_drag.cc144
-rw-r--r--source/blender/editors/interface/interface_draw.c4
-rw-r--r--source/blender/editors/interface/interface_eyedropper_color.c8
-rw-r--r--source/blender/editors/interface/interface_eyedropper_datablock.c2
-rw-r--r--source/blender/editors/interface/interface_eyedropper_depth.c2
-rw-r--r--source/blender/editors/interface/interface_handlers.c435
-rw-r--r--source/blender/editors/interface/interface_icons.c17
-rw-r--r--source/blender/editors/interface/interface_icons_event.c6
-rw-r--r--source/blender/editors/interface/interface_intern.h50
-rw-r--r--source/blender/editors/interface/interface_layout.c55
-rw-r--r--source/blender/editors/interface/interface_ops.c46
-rw-r--r--source/blender/editors/interface/interface_query.cc47
-rw-r--r--source/blender/editors/interface/interface_region_color_picker.cc10
-rw-r--r--source/blender/editors/interface/interface_region_menu_popup.cc6
-rw-r--r--source/blender/editors/interface/interface_region_search.cc44
-rw-r--r--source/blender/editors/interface/interface_region_tooltip.c2
-rw-r--r--source/blender/editors/interface/interface_style.cc20
-rw-r--r--source/blender/editors/interface/interface_template_attribute_search.cc11
-rw-r--r--source/blender/editors/interface/interface_template_list.cc9
-rw-r--r--source/blender/editors/interface/interface_templates.c29
-rw-r--r--source/blender/editors/interface/interface_utils.cc166
-rw-r--r--source/blender/editors/interface/interface_view.cc89
-rw-r--r--source/blender/editors/interface/interface_widgets.c485
-rw-r--r--source/blender/editors/interface/tree_view.cc15
-rw-r--r--source/blender/editors/interface/view2d.cc21
-rw-r--r--source/blender/editors/io/CMakeLists.txt28
-rw-r--r--source/blender/editors/io/io_alembic.c2
-rw-r--r--source/blender/editors/io/io_cache.c18
-rw-r--r--source/blender/editors/io/io_collada.c4
-rw-r--r--source/blender/editors/io/io_gpencil_export.c54
-rw-r--r--source/blender/editors/io/io_gpencil_import.c40
-rw-r--r--source/blender/editors/io/io_gpencil_utils.c14
-rw-r--r--source/blender/editors/io/io_obj.c136
-rw-r--r--source/blender/editors/io/io_ops.c17
-rw-r--r--source/blender/editors/io/io_stl_ops.c133
-rw-r--r--source/blender/editors/io/io_stl_ops.h12
-rw-r--r--source/blender/editors/io/io_usd.c63
-rw-r--r--source/blender/editors/mask/mask_add.c60
-rw-r--r--source/blender/editors/mask/mask_draw.c25
-rw-r--r--source/blender/editors/mask/mask_edit.c32
-rw-r--r--source/blender/editors/mask/mask_intern.h3
-rw-r--r--source/blender/editors/mask/mask_ops.c26
-rw-r--r--source/blender/editors/mask/mask_query.c6
-rw-r--r--source/blender/editors/mask/mask_relationships.c3
-rw-r--r--source/blender/editors/mask/mask_select.c29
-rw-r--r--source/blender/editors/mask/mask_shapekey.c8
-rw-r--r--source/blender/editors/mesh/CMakeLists.txt6
-rw-r--r--source/blender/editors/mesh/editface.cc (renamed from source/blender/editors/mesh/editface.c)172
-rw-r--r--source/blender/editors/mesh/editmesh_add.c18
-rw-r--r--source/blender/editors/mesh/editmesh_add_gizmo.c2
-rw-r--r--source/blender/editors/mesh/editmesh_bevel.c2
-rw-r--r--source/blender/editors/mesh/editmesh_intersect.c2
-rw-r--r--source/blender/editors/mesh/editmesh_knife.c641
-rw-r--r--source/blender/editors/mesh/editmesh_knife_project.c2
-rw-r--r--source/blender/editors/mesh/editmesh_select_similar.c8
-rw-r--r--source/blender/editors/mesh/editmesh_tools.c16
-rw-r--r--source/blender/editors/mesh/editmesh_undo.c4
-rw-r--r--source/blender/editors/mesh/editmesh_utils.c33
-rw-r--r--source/blender/editors/mesh/mesh_data.cc (renamed from source/blender/editors/mesh/mesh_data.c)148
-rw-r--r--source/blender/editors/mesh/mesh_intern.h13
-rw-r--r--source/blender/editors/mesh/meshtools.cc (renamed from source/blender/editors/mesh/meshtools.c)236
-rw-r--r--source/blender/editors/object/object_add.cc215
-rw-r--r--source/blender/editors/object/object_bake.c20
-rw-r--r--source/blender/editors/object/object_bake_api.c119
-rw-r--r--source/blender/editors/object/object_collection.c18
-rw-r--r--source/blender/editors/object/object_constraint.c26
-rw-r--r--source/blender/editors/object/object_data_transfer.c15
-rw-r--r--source/blender/editors/object/object_edit.c35
-rw-r--r--source/blender/editors/object/object_modes.c10
-rw-r--r--source/blender/editors/object/object_modifier.cc56
-rw-r--r--source/blender/editors/object/object_ops.c12
-rw-r--r--source/blender/editors/object/object_relations.c267
-rw-r--r--source/blender/editors/object/object_remesh.cc13
-rw-r--r--source/blender/editors/object/object_transform.cc2
-rw-r--r--source/blender/editors/object/object_vgroup.c26
-rw-r--r--source/blender/editors/render/render_preview.cc24
-rw-r--r--source/blender/editors/scene/scene_edit.c12
-rw-r--r--source/blender/editors/screen/area.c10
-rw-r--r--source/blender/editors/screen/screen_edit.c6
-rw-r--r--source/blender/editors/screen/screen_ops.c35
-rw-r--r--source/blender/editors/sculpt_paint/CMakeLists.txt7
-rw-r--r--source/blender/editors/sculpt_paint/curves_sculpt_add.cc674
-rw-r--r--source/blender/editors/sculpt_paint/curves_sculpt_brush.cc183
-rw-r--r--source/blender/editors/sculpt_paint/curves_sculpt_comb.cc157
-rw-r--r--source/blender/editors/sculpt_paint/curves_sculpt_delete.cc181
-rw-r--r--source/blender/editors/sculpt_paint/curves_sculpt_grow_shrink.cc206
-rw-r--r--source/blender/editors/sculpt_paint/curves_sculpt_intern.hh99
-rw-r--r--source/blender/editors/sculpt_paint/curves_sculpt_ops.cc54
-rw-r--r--source/blender/editors/sculpt_paint/curves_sculpt_selection.cc105
-rw-r--r--source/blender/editors/sculpt_paint/curves_sculpt_selection_paint.cc394
-rw-r--r--source/blender/editors/sculpt_paint/curves_sculpt_snake_hook.cc167
-rw-r--r--source/blender/editors/sculpt_paint/paint_cursor.c7
-rw-r--r--source/blender/editors/sculpt_paint/paint_image.cc20
-rw-r--r--source/blender/editors/sculpt_paint/paint_image_2d.c55
-rw-r--r--source/blender/editors/sculpt_paint/paint_image_ops_paint.cc6
-rw-r--r--source/blender/editors/sculpt_paint/paint_image_proj.c330
-rw-r--r--source/blender/editors/sculpt_paint/paint_intern.h1
-rw-r--r--source/blender/editors/sculpt_paint/paint_mask.c8
-rw-r--r--source/blender/editors/sculpt_paint/paint_ops.c148
-rw-r--r--source/blender/editors/sculpt_paint/paint_stroke.c27
-rw-r--r--source/blender/editors/sculpt_paint/paint_vertex.cc83
-rw-r--r--source/blender/editors/sculpt_paint/paint_vertex_color_ops.cc (renamed from source/blender/editors/sculpt_paint/paint_vertex_color_ops.c)58
-rw-r--r--source/blender/editors/sculpt_paint/sculpt.c171
-rw-r--r--source/blender/editors/sculpt_paint/sculpt_automasking.cc (renamed from source/blender/editors/sculpt_paint/sculpt_automasking.c)59
-rw-r--r--source/blender/editors/sculpt_paint/sculpt_cloth.c6
-rw-r--r--source/blender/editors/sculpt_paint/sculpt_detail.c49
-rw-r--r--source/blender/editors/sculpt_paint/sculpt_expand.c30
-rw-r--r--source/blender/editors/sculpt_paint/sculpt_face_set.c45
-rw-r--r--source/blender/editors/sculpt_paint/sculpt_filter_color.c18
-rw-r--r--source/blender/editors/sculpt_paint/sculpt_filter_mesh.c6
-rw-r--r--source/blender/editors/sculpt_paint/sculpt_intern.h27
-rw-r--r--source/blender/editors/sculpt_paint/sculpt_mask_expand.c14
-rw-r--r--source/blender/editors/sculpt_paint/sculpt_ops.c39
-rw-r--r--source/blender/editors/sculpt_paint/sculpt_paint_color.c23
-rw-r--r--source/blender/editors/sculpt_paint/sculpt_paint_image.cc86
-rw-r--r--source/blender/editors/sculpt_paint/sculpt_transform.c180
-rw-r--r--source/blender/editors/sculpt_paint/sculpt_undo.c25
-rw-r--r--source/blender/editors/sound/sound_ops.c3
-rw-r--r--source/blender/editors/space_action/action_select.c1
-rw-r--r--source/blender/editors/space_buttons/space_buttons.c3
-rw-r--r--source/blender/editors/space_clip/clip_buttons.c6
-rw-r--r--source/blender/editors/space_clip/clip_draw.c62
-rw-r--r--source/blender/editors/space_clip/clip_editor.c22
-rw-r--r--source/blender/editors/space_clip/clip_intern.h6
-rw-r--r--source/blender/editors/space_clip/clip_ops.c6
-rw-r--r--source/blender/editors/space_clip/space_clip.c168
-rw-r--r--source/blender/editors/space_clip/tracking_ops.c367
-rw-r--r--source/blender/editors/space_clip/tracking_select.c86
-rw-r--r--source/blender/editors/space_file/asset_catalog_tree_view.cc11
-rw-r--r--source/blender/editors/space_file/file_intern.h1
-rw-r--r--source/blender/editors/space_file/file_ops.c46
-rw-r--r--source/blender/editors/space_file/filelist.c25
-rw-r--r--source/blender/editors/space_file/filesel.c21
-rw-r--r--source/blender/editors/space_file/fsmenu.c10
-rw-r--r--source/blender/editors/space_file/fsmenu.h4
-rw-r--r--source/blender/editors/space_file/space_file.c1
-rw-r--r--source/blender/editors/space_graph/graph_select.c1
-rw-r--r--source/blender/editors/space_image/CMakeLists.txt2
-rw-r--r--source/blender/editors/space_image/image_buttons.c5
-rw-r--r--source/blender/editors/space_image/image_edit.c20
-rw-r--r--source/blender/editors/space_image/image_intern.h1
-rw-r--r--source/blender/editors/space_image/image_ops.c530
-rw-r--r--source/blender/editors/space_image/image_sequence.c4
-rw-r--r--source/blender/editors/space_image/image_undo.c4
-rw-r--r--source/blender/editors/space_image/space_image.c7
-rw-r--r--source/blender/editors/space_info/info_stats.cc18
-rw-r--r--source/blender/editors/space_nla/nla_channels.c116
-rw-r--r--source/blender/editors/space_nla/nla_draw.c129
-rw-r--r--source/blender/editors/space_nla/nla_edit.c6
-rw-r--r--source/blender/editors/space_node/drawnode.cc5
-rw-r--r--source/blender/editors/space_node/node_add.cc130
-rw-r--r--source/blender/editors/space_node/node_context_path.cc4
-rw-r--r--source/blender/editors/space_node/node_draw.cc90
-rw-r--r--source/blender/editors/space_node/node_edit.cc205
-rw-r--r--source/blender/editors/space_node/node_geometry_attribute_search.cc12
-rw-r--r--source/blender/editors/space_node/node_intern.hh23
-rw-r--r--source/blender/editors/space_node/node_relationships.cc6
-rw-r--r--source/blender/editors/space_node/node_select.cc180
-rw-r--r--source/blender/editors/space_node/node_view.cc6
-rw-r--r--source/blender/editors/space_node/space_node.cc92
-rw-r--r--source/blender/editors/space_outliner/CMakeLists.txt3
-rw-r--r--source/blender/editors/space_outliner/outliner_context.cc12
-rw-r--r--source/blender/editors/space_outliner/outliner_dragdrop.cc13
-rw-r--r--source/blender/editors/space_outliner/outliner_draw.cc575
-rw-r--r--source/blender/editors/space_outliner/outliner_edit.cc308
-rw-r--r--source/blender/editors/space_outliner/outliner_intern.hh18
-rw-r--r--source/blender/editors/space_outliner/outliner_query.cc48
-rw-r--r--source/blender/editors/space_outliner/outliner_select.cc50
-rw-r--r--source/blender/editors/space_outliner/outliner_tools.cc517
-rw-r--r--source/blender/editors/space_outliner/outliner_tree.cc14
-rw-r--r--source/blender/editors/space_outliner/outliner_utils.cc3
-rw-r--r--source/blender/editors/space_outliner/space_outliner.cc2
-rw-r--r--source/blender/editors/space_outliner/tree/tree_display.cc4
-rw-r--r--source/blender/editors/space_outliner/tree/tree_display.hh16
-rw-r--r--source/blender/editors/space_outliner/tree/tree_display_libraries.cc8
-rw-r--r--source/blender/editors/space_outliner/tree/tree_display_override_library_hierarchies.cc14
-rw-r--r--source/blender/editors/space_outliner/tree/tree_display_scenes.cc5
-rw-r--r--source/blender/editors/space_outliner/tree/tree_display_view_layer.cc11
-rw-r--r--source/blender/editors/space_outliner/tree/tree_element.cc40
-rw-r--r--source/blender/editors/space_outliner/tree/tree_element.hh25
-rw-r--r--source/blender/editors/space_outliner/tree/tree_element_id.cc10
-rw-r--r--source/blender/editors/space_outliner/tree/tree_element_id_library.cc19
-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_overrides.cc70
-rw-r--r--source/blender/editors/space_outliner/tree/tree_element_overrides.hh9
-rw-r--r--source/blender/editors/space_outliner/tree/tree_iterator.cc59
-rw-r--r--source/blender/editors/space_outliner/tree/tree_iterator.hh35
-rw-r--r--source/blender/editors/space_sequencer/sequencer_add.c155
-rw-r--r--source/blender/editors/space_sequencer/sequencer_channels_draw.c4
-rw-r--r--source/blender/editors/space_sequencer/sequencer_drag_drop.c5
-rw-r--r--source/blender/editors/space_sequencer/sequencer_draw.c140
-rw-r--r--source/blender/editors/space_sequencer/sequencer_edit.c355
-rw-r--r--source/blender/editors/space_sequencer/sequencer_intern.h2
-rw-r--r--source/blender/editors/space_sequencer/sequencer_ops.c2
-rw-r--r--source/blender/editors/space_sequencer/sequencer_select.c70
-rw-r--r--source/blender/editors/space_sequencer/sequencer_thumbnails.c26
-rw-r--r--source/blender/editors/space_sequencer/sequencer_view.c6
-rw-r--r--source/blender/editors/space_spreadsheet/space_spreadsheet.cc3
-rw-r--r--source/blender/editors/space_spreadsheet/spreadsheet_column.cc3
-rw-r--r--source/blender/editors/space_spreadsheet/spreadsheet_data_source_geometry.cc31
-rw-r--r--source/blender/editors/space_spreadsheet/spreadsheet_data_source_geometry.hh4
-rw-r--r--source/blender/editors/space_spreadsheet/spreadsheet_dataset_draw.cc10
-rw-r--r--source/blender/editors/space_spreadsheet/spreadsheet_ops.cc10
-rw-r--r--source/blender/editors/space_spreadsheet/spreadsheet_row_filter.cc79
-rw-r--r--source/blender/editors/space_spreadsheet/spreadsheet_row_filter_ui.cc5
-rw-r--r--source/blender/editors/space_text/text_draw.c2
-rw-r--r--source/blender/editors/space_view3d/drawobject.c4
-rw-r--r--source/blender/editors/space_view3d/space_view3d.c17
-rw-r--r--source/blender/editors/space_view3d/view3d_cursor_snap.c32
-rw-r--r--source/blender/editors/space_view3d/view3d_draw.c6
-rw-r--r--source/blender/editors/space_view3d/view3d_edit.c31
-rw-r--r--source/blender/editors/space_view3d/view3d_gizmo_ruler.c10
-rw-r--r--source/blender/editors/space_view3d/view3d_gizmo_tool_generic.c2
-rw-r--r--source/blender/editors/space_view3d/view3d_navigate_roll.c6
-rw-r--r--source/blender/editors/space_view3d/view3d_navigate_rotate.c6
-rw-r--r--source/blender/editors/space_view3d/view3d_navigate_walk.c4
-rw-r--r--source/blender/editors/space_view3d/view3d_placement.c6
-rw-r--r--source/blender/editors/space_view3d/view3d_project.c10
-rw-r--r--source/blender/editors/space_view3d/view3d_select.c21
-rw-r--r--source/blender/editors/space_view3d/view3d_utils.c57
-rw-r--r--source/blender/editors/transform/transform.c41
-rw-r--r--source/blender/editors/transform/transform.h33
-rw-r--r--source/blender/editors/transform/transform_convert.c90
-rw-r--r--source/blender/editors/transform/transform_convert.h2
-rw-r--r--source/blender/editors/transform/transform_convert_armature.c2
-rw-r--r--source/blender/editors/transform/transform_convert_graph.c5
-rw-r--r--source/blender/editors/transform/transform_convert_mask.c10
-rw-r--r--source/blender/editors/transform/transform_convert_nla.c5
-rw-r--r--source/blender/editors/transform/transform_convert_node.c4
-rw-r--r--source/blender/editors/transform/transform_convert_object.c2
-rw-r--r--source/blender/editors/transform/transform_convert_sequencer.c379
-rw-r--r--source/blender/editors/transform/transform_convert_sequencer_image.c81
-rw-r--r--source/blender/editors/transform/transform_convert_tracking.c21
-rw-r--r--source/blender/editors/transform/transform_generics.c4
-rw-r--r--source/blender/editors/transform/transform_gizmo_3d.c448
-rw-r--r--source/blender/editors/transform/transform_mode.c2
-rw-r--r--source/blender/editors/transform/transform_mode.h2
-rw-r--r--source/blender/editors/transform/transform_mode_rotate.c20
-rw-r--r--source/blender/editors/transform/transform_mode_trackball.c61
-rw-r--r--source/blender/editors/transform/transform_mode_translate.c12
-rw-r--r--source/blender/editors/transform/transform_ops.c8
-rw-r--r--source/blender/editors/transform/transform_snap.c182
-rw-r--r--source/blender/editors/transform/transform_snap.h13
-rw-r--r--source/blender/editors/transform/transform_snap_object.cc401
-rw-r--r--source/blender/editors/transform/transform_snap_sequencer.c28
-rw-r--r--source/blender/editors/util/CMakeLists.txt1
-rw-r--r--source/blender/editors/util/ed_util.c22
-rw-r--r--source/blender/editors/util/ed_util_ops.cc10
-rw-r--r--source/blender/editors/util/select_utils.c76
-rw-r--r--source/blender/editors/uvedit/uvedit_intern.h1
-rw-r--r--source/blender/editors/uvedit/uvedit_ops.c1
-rw-r--r--source/blender/editors/uvedit/uvedit_select.c602
-rw-r--r--source/blender/editors/uvedit/uvedit_smart_stitch.c2
-rw-r--r--source/blender/editors/uvedit/uvedit_unwrap_ops.c303
-rw-r--r--source/blender/freestyle/intern/blender_interface/BlenderFileLoader.cpp8
-rw-r--r--source/blender/freestyle/intern/blender_interface/BlenderStrokeRenderer.cpp6
-rw-r--r--source/blender/freestyle/intern/geometry/SweepLine.h2
-rw-r--r--source/blender/functions/FN_field.hh6
-rw-r--r--source/blender/functions/FN_multi_function_builder.hh26
-rw-r--r--source/blender/functions/FN_multi_function_params.hh37
-rw-r--r--source/blender/functions/FN_multi_function_procedure.hh8
-rw-r--r--source/blender/functions/FN_multi_function_signature.hh25
-rw-r--r--source/blender/functions/intern/field.cc8
-rw-r--r--source/blender/functions/intern/multi_function_procedure.cc4
-rw-r--r--source/blender/functions/intern/multi_function_procedure_executor.cc368
-rw-r--r--source/blender/geometry/CMakeLists.txt8
-rw-r--r--source/blender/geometry/GEO_add_curves_on_mesh.hh54
-rw-r--r--source/blender/geometry/GEO_mesh_primitive_cuboid.hh21
-rw-r--r--source/blender/geometry/GEO_resample_curves.hh39
-rw-r--r--source/blender/geometry/GEO_reverse_uv_sampler.hh42
-rw-r--r--source/blender/geometry/GEO_uv_parametrizer.h41
-rw-r--r--source/blender/geometry/intern/add_curves_on_mesh.cc354
-rw-r--r--source/blender/geometry/intern/mesh_merge_by_distance.cc162
-rw-r--r--source/blender/geometry/intern/mesh_primitive_cuboid.cc431
-rw-r--r--source/blender/geometry/intern/point_merge_by_distance.cc17
-rw-r--r--source/blender/geometry/intern/realize_instances.cc95
-rw-r--r--source/blender/geometry/intern/resample_curves.cc444
-rw-r--r--source/blender/geometry/intern/reverse_uv_sampler.cc32
-rw-r--r--source/blender/geometry/intern/uv_parametrizer.c1108
-rw-r--r--source/blender/gpencil_modifiers/CMakeLists.txt1
-rw-r--r--source/blender/gpencil_modifiers/intern/MOD_gpencil_util.c2
-rw-r--r--source/blender/gpencil_modifiers/intern/MOD_gpencil_util.h2
-rw-r--r--source/blender/gpencil_modifiers/intern/MOD_gpencilarmature.c3
-rw-r--r--source/blender/gpencil_modifiers/intern/MOD_gpencilarray.c9
-rw-r--r--source/blender/gpencil_modifiers/intern/MOD_gpencilbuild.c11
-rw-r--r--source/blender/gpencil_modifiers/intern/MOD_gpencilcolor.c1
-rw-r--r--source/blender/gpencil_modifiers/intern/MOD_gpencildash.c4
-rw-r--r--source/blender/gpencil_modifiers/intern/MOD_gpencilenvelope.c3
-rw-r--r--source/blender/gpencil_modifiers/intern/MOD_gpencilhook.c6
-rw-r--r--source/blender/gpencil_modifiers/intern/MOD_gpencillength.c3
-rw-r--r--source/blender/gpencil_modifiers/intern/MOD_gpencillineart.c57
-rw-r--r--source/blender/gpencil_modifiers/intern/MOD_gpencilmirror.c2
-rw-r--r--source/blender/gpencil_modifiers/intern/MOD_gpencilmultiply.c4
-rw-r--r--source/blender/gpencil_modifiers/intern/MOD_gpencilnoise.c5
-rw-r--r--source/blender/gpencil_modifiers/intern/MOD_gpenciloffset.c7
-rw-r--r--source/blender/gpencil_modifiers/intern/MOD_gpencilopacity.c4
-rw-r--r--source/blender/gpencil_modifiers/intern/MOD_gpencilshrinkwrap.c3
-rw-r--r--source/blender/gpencil_modifiers/intern/MOD_gpencilsimplify.c1
-rw-r--r--source/blender/gpencil_modifiers/intern/MOD_gpenciltexture.c2
-rw-r--r--source/blender/gpencil_modifiers/intern/MOD_gpencilthick.c2
-rw-r--r--source/blender/gpencil_modifiers/intern/MOD_gpenciltime.c86
-rw-r--r--source/blender/gpencil_modifiers/intern/MOD_gpenciltint.c3
-rw-r--r--source/blender/gpencil_modifiers/intern/MOD_gpencilweight_angle.c4
-rw-r--r--source/blender/gpencil_modifiers/intern/MOD_gpencilweight_proximity.c3
-rw-r--r--source/blender/gpencil_modifiers/intern/lineart/MOD_lineart.h337
-rw-r--r--source/blender/gpencil_modifiers/intern/lineart/lineart_chain.c384
-rw-r--r--source/blender/gpencil_modifiers/intern/lineart/lineart_cpp_bridge.cc2
-rw-r--r--source/blender/gpencil_modifiers/intern/lineart/lineart_cpu.c2626
-rw-r--r--source/blender/gpencil_modifiers/intern/lineart/lineart_intern.h61
-rw-r--r--source/blender/gpencil_modifiers/intern/lineart/lineart_ops.c4
-rw-r--r--source/blender/gpencil_modifiers/intern/lineart/lineart_util.c17
-rw-r--r--source/blender/gpu/CMakeLists.txt54
-rw-r--r--source/blender/gpu/GPU_buffers.h44
-rw-r--r--source/blender/gpu/GPU_capabilities.h4
-rw-r--r--source/blender/gpu/GPU_common_types.h18
-rw-r--r--source/blender/gpu/GPU_legacy_stubs.h2
-rw-r--r--source/blender/gpu/GPU_material.h8
-rw-r--r--source/blender/gpu/GPU_shader.h10
-rw-r--r--source/blender/gpu/GPU_state.h13
-rw-r--r--source/blender/gpu/GPU_storage_buffer.h12
-rw-r--r--source/blender/gpu/GPU_texture.h6
-rw-r--r--source/blender/gpu/GPU_vertex_buffer.h1
-rw-r--r--source/blender/gpu/GPU_vertex_format.h2
-rw-r--r--source/blender/gpu/intern/gpu_batch.cc1
-rw-r--r--source/blender/gpu/intern/gpu_batch_presets.c11
-rw-r--r--source/blender/gpu/intern/gpu_batch_utils.c1
-rw-r--r--source/blender/gpu/intern/gpu_buffers.c634
-rw-r--r--source/blender/gpu/intern/gpu_capabilities.cc17
-rw-r--r--source/blender/gpu/intern/gpu_capabilities_private.hh2
-rw-r--r--source/blender/gpu/intern/gpu_codegen.cc44
-rw-r--r--source/blender/gpu/intern/gpu_compute.cc1
-rw-r--r--source/blender/gpu/intern/gpu_context.cc4
-rw-r--r--source/blender/gpu/intern/gpu_debug.cc6
-rw-r--r--source/blender/gpu/intern/gpu_drawlist.cc3
-rw-r--r--source/blender/gpu/intern/gpu_framebuffer.cc2
-rw-r--r--source/blender/gpu/intern/gpu_immediate.cc3
-rw-r--r--source/blender/gpu/intern/gpu_immediate_util.c27
-rw-r--r--source/blender/gpu/intern/gpu_index_buffer.cc1
-rw-r--r--source/blender/gpu/intern/gpu_index_buffer_private.hh7
-rw-r--r--source/blender/gpu/intern/gpu_init_exit.c5
-rw-r--r--source/blender/gpu/intern/gpu_material.c12
-rw-r--r--source/blender/gpu/intern/gpu_material_library.h2
-rw-r--r--source/blender/gpu/intern/gpu_node_graph.c16
-rw-r--r--source/blender/gpu/intern/gpu_select.c4
-rw-r--r--source/blender/gpu/intern/gpu_select_pick.c1
-rw-r--r--source/blender/gpu/intern/gpu_select_sample_query.cc1
-rw-r--r--source/blender/gpu/intern/gpu_shader_builtin.c31
-rw-r--r--source/blender/gpu/intern/gpu_shader_create_info.cc1
-rw-r--r--source/blender/gpu/intern/gpu_shader_dependency.cc61
-rw-r--r--source/blender/gpu/intern/gpu_shader_interface.cc2
-rw-r--r--source/blender/gpu/intern/gpu_shader_log.cc2
-rw-r--r--source/blender/gpu/intern/gpu_state.cc2
-rw-r--r--source/blender/gpu/intern/gpu_storage_buffer.cc8
-rw-r--r--source/blender/gpu/intern/gpu_storage_buffer_private.hh1
-rw-r--r--source/blender/gpu/intern/gpu_texture.cc7
-rw-r--r--source/blender/gpu/intern/gpu_vertex_buffer.cc16
-rw-r--r--source/blender/gpu/intern/gpu_vertex_buffer_private.hh1
-rw-r--r--source/blender/gpu/intern/gpu_vertex_format.cc22
-rw-r--r--source/blender/gpu/intern/gpu_viewport.c31
-rw-r--r--source/blender/gpu/metal/kernels/depth_2d_update_float_frag.glsl2
-rw-r--r--source/blender/gpu/metal/kernels/depth_2d_update_int24_frag.glsl2
-rw-r--r--source/blender/gpu/metal/kernels/depth_2d_update_int32_frag.glsl2
-rw-r--r--source/blender/gpu/metal/kernels/depth_2d_update_vert.glsl2
-rw-r--r--source/blender/gpu/metal/mtl_backend.mm2
-rw-r--r--source/blender/gpu/metal/mtl_context.hh306
-rw-r--r--source/blender/gpu/metal/mtl_context.mm236
-rw-r--r--source/blender/gpu/metal/mtl_state.hh73
-rw-r--r--source/blender/gpu/metal/mtl_state.mm677
-rw-r--r--source/blender/gpu/metal/mtl_texture.hh49
-rw-r--r--source/blender/gpu/metal/mtl_texture.mm2
-rw-r--r--source/blender/gpu/opengl/gl_backend.cc32
-rw-r--r--source/blender/gpu/opengl/gl_batch.cc3
-rw-r--r--source/blender/gpu/opengl/gl_compute.cc2
-rw-r--r--source/blender/gpu/opengl/gl_context.cc1
-rw-r--r--source/blender/gpu/opengl/gl_debug.cc20
-rw-r--r--source/blender/gpu/opengl/gl_debug_layer.cc2
-rw-r--r--source/blender/gpu/opengl/gl_drawlist.cc3
-rw-r--r--source/blender/gpu/opengl/gl_framebuffer.cc2
-rw-r--r--source/blender/gpu/opengl/gl_immediate.cc2
-rw-r--r--source/blender/gpu/opengl/gl_index_buffer.cc1
-rw-r--r--source/blender/gpu/opengl/gl_shader.cc9
-rw-r--r--source/blender/gpu/opengl/gl_shader_interface.cc1
-rw-r--r--source/blender/gpu/opengl/gl_state.cc3
-rw-r--r--source/blender/gpu/opengl/gl_storage_buffer.cc26
-rw-r--r--source/blender/gpu/opengl/gl_storage_buffer.hh1
-rw-r--r--source/blender/gpu/opengl/gl_texture.cc2
-rw-r--r--source/blender/gpu/opengl/gl_texture.hh2
-rw-r--r--source/blender/gpu/opengl/gl_uniform_buffer.cc4
-rw-r--r--source/blender/gpu/opengl/gl_vertex_array.cc5
-rw-r--r--source/blender/gpu/opengl/gl_vertex_buffer.cc14
-rw-r--r--source/blender/gpu/opengl/gl_vertex_buffer.hh10
-rw-r--r--source/blender/gpu/shaders/common/gpu_shader_common_color_ramp.glsl (renamed from source/blender/gpu/shaders/material/gpu_shader_material_color_ramp.glsl)0
-rw-r--r--source/blender/gpu/shaders/common/gpu_shader_common_color_utils.glsl (renamed from source/blender/gpu/shaders/material/gpu_shader_material_color_util.glsl)0
-rw-r--r--source/blender/gpu/shaders/common/gpu_shader_common_curves.glsl162
-rw-r--r--source/blender/gpu/shaders/common/gpu_shader_common_hash.glsl (renamed from source/blender/gpu/shaders/material/gpu_shader_material_hash.glsl)0
-rw-r--r--source/blender/gpu/shaders/common/gpu_shader_common_math.glsl (renamed from source/blender/gpu/shaders/material/gpu_shader_material_math.glsl)2
-rw-r--r--source/blender/gpu/shaders/common/gpu_shader_common_math_utils.glsl (renamed from source/blender/gpu/shaders/material/gpu_shader_material_math_util.glsl)72
-rw-r--r--source/blender/gpu/shaders/common/gpu_shader_common_mix_rgb.glsl (renamed from source/blender/gpu/shaders/material/gpu_shader_material_mix_rgb.glsl)2
-rw-r--r--source/blender/gpu/shaders/gpu_shader_codegen_lib.glsl4
-rw-r--r--source/blender/gpu/shaders/gpu_shader_common_obinfos_lib.glsl23
-rw-r--r--source/blender/gpu/shaders/gpu_shader_geometry.glsl93
-rw-r--r--source/blender/gpu/shaders/gpu_shader_image_overlays_stereo_merge_frag.glsl12
-rw-r--r--source/blender/gpu/shaders/gpu_shader_point_varying_color_frag.glsl2
-rw-r--r--source/blender/gpu/shaders/infos/gpu_shader_2D_image_overlays_stereo_merge_info.hh4
-rw-r--r--source/blender/gpu/shaders/infos/gpu_shader_3D_depth_only_info.hh3
-rw-r--r--source/blender/gpu/shaders/infos/gpu_shader_3D_flat_color_info.hh3
-rw-r--r--source/blender/gpu/shaders/infos/gpu_shader_3D_image_info.hh20
-rw-r--r--source/blender/gpu/shaders/infos/gpu_shader_3D_point_info.hh3
-rw-r--r--source/blender/gpu/shaders/infos/gpu_shader_3D_polyline_info.hh2
-rw-r--r--source/blender/gpu/shaders/infos/gpu_shader_3D_smooth_color_info.hh3
-rw-r--r--source/blender/gpu/shaders/material/gpu_shader_material_add_shader.glsl2
-rw-r--r--source/blender/gpu/shaders/material/gpu_shader_material_blackbody.glsl12
-rw-r--r--source/blender/gpu/shaders/material/gpu_shader_material_camera.glsl8
-rw-r--r--source/blender/gpu/shaders/material/gpu_shader_material_combine_color.glsl2
-rw-r--r--source/blender/gpu/shaders/material/gpu_shader_material_combine_hsv.glsl2
-rw-r--r--source/blender/gpu/shaders/material/gpu_shader_material_eevee_specular.glsl15
-rw-r--r--source/blender/gpu/shaders/material/gpu_shader_material_float_curve.glsl33
-rw-r--r--source/blender/gpu/shaders/material/gpu_shader_material_fractal_noise.glsl2
-rw-r--r--source/blender/gpu/shaders/material/gpu_shader_material_gamma.glsl2
-rw-r--r--source/blender/gpu/shaders/material/gpu_shader_material_geometry.glsl8
-rw-r--r--source/blender/gpu/shaders/material/gpu_shader_material_hair.glsl2
-rw-r--r--source/blender/gpu/shaders/material/gpu_shader_material_hair_info.glsl6
-rw-r--r--source/blender/gpu/shaders/material/gpu_shader_material_hue_sat_val.glsl2
-rw-r--r--source/blender/gpu/shaders/material/gpu_shader_material_map_range.glsl2
-rw-r--r--source/blender/gpu/shaders/material/gpu_shader_material_mapping.glsl2
-rw-r--r--source/blender/gpu/shaders/material/gpu_shader_material_mix_shader.glsl2
-rw-r--r--source/blender/gpu/shaders/material/gpu_shader_material_noise.glsl2
-rw-r--r--source/blender/gpu/shaders/material/gpu_shader_material_normal_map.glsl3
-rw-r--r--source/blender/gpu/shaders/material/gpu_shader_material_point_info.glsl2
-rw-r--r--source/blender/gpu/shaders/material/gpu_shader_material_principled.glsl6
-rw-r--r--source/blender/gpu/shaders/material/gpu_shader_material_rgb_curves.glsl73
-rw-r--r--source/blender/gpu/shaders/material/gpu_shader_material_separate_color.glsl2
-rw-r--r--source/blender/gpu/shaders/material/gpu_shader_material_separate_hsv.glsl2
-rw-r--r--source/blender/gpu/shaders/material/gpu_shader_material_tex_brick.glsl4
-rw-r--r--source/blender/gpu/shaders/material/gpu_shader_material_tex_environment.glsl2
-rw-r--r--source/blender/gpu/shaders/material/gpu_shader_material_tex_musgrave.glsl2
-rw-r--r--source/blender/gpu/shaders/material/gpu_shader_material_tex_noise.glsl2
-rw-r--r--source/blender/gpu/shaders/material/gpu_shader_material_tex_voronoi.glsl4
-rw-r--r--source/blender/gpu/shaders/material/gpu_shader_material_tex_wave.glsl2
-rw-r--r--source/blender/gpu/shaders/material/gpu_shader_material_tex_white_noise.glsl2
-rw-r--r--source/blender/gpu/shaders/material/gpu_shader_material_transform_utils.glsl71
-rw-r--r--source/blender/gpu/shaders/material/gpu_shader_material_vector_curves.glsl41
-rw-r--r--source/blender/gpu/shaders/material/gpu_shader_material_vector_math.glsl2
-rw-r--r--source/blender/gpu/shaders/material/gpu_shader_material_vector_rotate.glsl2
-rw-r--r--source/blender/gpu/shaders/material/gpu_shader_material_wavelength.glsl12
-rw-r--r--source/blender/gpu/tests/gpu_shader_builtin_test.cc1
-rw-r--r--source/blender/imbuf/CMakeLists.txt8
-rw-r--r--source/blender/imbuf/IMB_colormanagement.h44
-rw-r--r--source/blender/imbuf/IMB_imbuf.h10
-rw-r--r--source/blender/imbuf/IMB_imbuf_types.h9
-rw-r--r--source/blender/imbuf/IMB_thumbs.h10
-rw-r--r--source/blender/imbuf/intern/IMB_colormanagement_intern.h8
-rw-r--r--source/blender/imbuf/intern/IMB_filetype.h17
-rw-r--r--source/blender/imbuf/intern/anim_movie.c2
-rw-r--r--source/blender/imbuf/intern/cineon/cineon_dpx.c10
-rw-r--r--source/blender/imbuf/intern/cineon/cineonlib.c22
-rw-r--r--source/blender/imbuf/intern/cineon/cineonlib.h2
-rw-r--r--source/blender/imbuf/intern/cineon/dpxlib.c18
-rw-r--r--source/blender/imbuf/intern/cineon/dpxlib.h2
-rw-r--r--source/blender/imbuf/intern/cineon/logImageCore.c14
-rw-r--r--source/blender/imbuf/intern/cineon/logImageCore.h10
-rw-r--r--source/blender/imbuf/intern/colormanagement.c575
-rw-r--r--source/blender/imbuf/intern/colormanagement_inline.c40
-rw-r--r--source/blender/imbuf/intern/dds/Color.h5
-rw-r--r--source/blender/imbuf/intern/dds/Stream.cpp6
-rw-r--r--source/blender/imbuf/intern/filetype.c2
-rw-r--r--source/blender/imbuf/intern/indexer.c96
-rw-r--r--source/blender/imbuf/intern/iris.c54
-rw-r--r--source/blender/imbuf/intern/jpeg.c8
-rw-r--r--source/blender/imbuf/intern/openexr/openexr_api.cpp222
-rw-r--r--source/blender/imbuf/intern/openexr/openexr_api.h7
-rw-r--r--source/blender/imbuf/intern/readimage.c10
-rw-r--r--source/blender/imbuf/intern/stereoimbuf.c31
-rw-r--r--source/blender/imbuf/intern/thumbs.c21
-rw-r--r--source/blender/imbuf/intern/thumbs_font.c4
-rw-r--r--source/blender/imbuf/intern/tiff.c22
-rw-r--r--source/blender/imbuf/intern/transform.cc23
-rw-r--r--source/blender/imbuf/intern/util.c11
-rw-r--r--source/blender/imbuf/intern/util_gpu.c73
-rw-r--r--source/blender/imbuf/intern/writeimage.c37
-rw-r--r--source/blender/io/CMakeLists.txt19
-rw-r--r--source/blender/io/alembic/exporter/abc_custom_props.cc4
-rw-r--r--source/blender/io/alembic/exporter/abc_export_capi.cc2
-rw-r--r--source/blender/io/alembic/exporter/abc_hierarchy_iterator.cc5
-rw-r--r--source/blender/io/alembic/exporter/abc_hierarchy_iterator.h4
-rw-r--r--source/blender/io/alembic/intern/abc_customdata.cc34
-rw-r--r--source/blender/io/alembic/intern/abc_reader_mesh.cc15
-rw-r--r--source/blender/io/alembic/intern/alembic_capi.cc24
-rw-r--r--source/blender/io/avi/AVI_avi.h3
-rw-r--r--source/blender/io/collada/AnimationImporter.h2
-rw-r--r--source/blender/io/collada/BCAnimationSampler.cpp12
-rw-r--r--source/blender/io/collada/BCMath.cpp6
-rw-r--r--source/blender/io/collada/GeometryExporter.cpp7
-rw-r--r--source/blender/io/collada/MeshImporter.h10
-rw-r--r--source/blender/io/collada/SceneExporter.cpp11
-rw-r--r--source/blender/io/common/CMakeLists.txt10
-rw-r--r--source/blender/io/common/IO_abstract_hierarchy_iterator.h9
-rw-r--r--source/blender/io/common/IO_orientation.h16
-rw-r--r--source/blender/io/common/IO_path_util.hh29
-rw-r--r--source/blender/io/common/IO_path_util_types.h18
-rw-r--r--source/blender/io/common/IO_string_utils.hh69
-rw-r--r--source/blender/io/common/intern/abstract_hierarchy_iterator.cc9
-rw-r--r--source/blender/io/common/intern/abstract_hierarchy_iterator_test.cc5
-rw-r--r--source/blender/io/common/intern/orientation.c14
-rw-r--r--source/blender/io/common/intern/path_util.cc82
-rw-r--r--source/blender/io/common/intern/string_utils.cc99
-rw-r--r--source/blender/io/stl/CMakeLists.txt44
-rw-r--r--source/blender/io/stl/IO_stl.cc16
-rw-r--r--source/blender/io/stl/IO_stl.h35
-rw-r--r--source/blender/io/stl/importer/stl_import.cc114
-rw-r--r--source/blender/io/stl/importer/stl_import.hh22
-rw-r--r--source/blender/io/stl/importer/stl_import_ascii_reader.cc160
-rw-r--r--source/blender/io/stl/importer/stl_import_ascii_reader.hh35
-rw-r--r--source/blender/io/stl/importer/stl_import_binary_reader.cc58
-rw-r--r--source/blender/io/stl/importer/stl_import_binary_reader.hh31
-rw-r--r--source/blender/io/stl/importer/stl_import_mesh.cc114
-rw-r--r--source/blender/io/stl/importer/stl_import_mesh.hh71
-rw-r--r--source/blender/io/usd/CMakeLists.txt15
-rw-r--r--source/blender/io/usd/intern/usd_capi_export.cc14
-rw-r--r--source/blender/io/usd/intern/usd_capi_import.cc39
-rw-r--r--source/blender/io/usd/intern/usd_exporter_context.h2
-rw-r--r--source/blender/io/usd/intern/usd_hierarchy_iterator.cc21
-rw-r--r--source/blender/io/usd/intern/usd_hierarchy_iterator.h5
-rw-r--r--source/blender/io/usd/intern/usd_reader_mesh.cc102
-rw-r--r--source/blender/io/usd/intern/usd_reader_prim.h15
-rw-r--r--source/blender/io/usd/intern/usd_writer_abstract.cc5
-rw-r--r--source/blender/io/usd/intern/usd_writer_abstract.h1
-rw-r--r--source/blender/io/usd/intern/usd_writer_material.cc22
-rw-r--r--source/blender/io/usd/intern/usd_writer_volume.cc188
-rw-r--r--source/blender/io/usd/intern/usd_writer_volume.h36
-rw-r--r--source/blender/io/usd/tests/usd_tests_common.h2
-rw-r--r--source/blender/io/usd/usd.h12
-rw-r--r--source/blender/io/wavefront_obj/CMakeLists.txt4
-rw-r--r--source/blender/io/wavefront_obj/IO_wavefront_obj.h39
-rw-r--r--source/blender/io/wavefront_obj/exporter/obj_export_file_writer.cc73
-rw-r--r--source/blender/io/wavefront_obj/exporter/obj_export_file_writer.hh17
-rw-r--r--source/blender/io/wavefront_obj/exporter/obj_export_io.hh6
-rw-r--r--source/blender/io/wavefront_obj/exporter/obj_export_mesh.cc15
-rw-r--r--source/blender/io/wavefront_obj/exporter/obj_export_mesh.hh7
-rw-r--r--source/blender/io/wavefront_obj/exporter/obj_export_mtl.cc6
-rw-r--r--source/blender/io/wavefront_obj/exporter/obj_export_nurbs.cc7
-rw-r--r--source/blender/io/wavefront_obj/exporter/obj_export_nurbs.hh2
-rw-r--r--source/blender/io/wavefront_obj/exporter/obj_exporter.cc13
-rw-r--r--source/blender/io/wavefront_obj/importer/importer_mesh_utils.cc9
-rw-r--r--source/blender/io/wavefront_obj/importer/obj_import_file_reader.cc367
-rw-r--r--source/blender/io/wavefront_obj/importer/obj_import_file_reader.hh2
-rw-r--r--source/blender/io/wavefront_obj/importer/obj_import_mesh.cc67
-rw-r--r--source/blender/io/wavefront_obj/importer/obj_import_mesh.hh7
-rw-r--r--source/blender/io/wavefront_obj/importer/obj_import_mtl.cc3
-rw-r--r--source/blender/io/wavefront_obj/importer/obj_import_objects.hh5
-rw-r--r--source/blender/io/wavefront_obj/importer/obj_import_string_utils.cc100
-rw-r--r--source/blender/io/wavefront_obj/importer/obj_import_string_utils.hh82
-rw-r--r--source/blender/io/wavefront_obj/importer/obj_importer.cc1
-rw-r--r--source/blender/io/wavefront_obj/tests/obj_exporter_tests.cc83
-rw-r--r--source/blender/io/wavefront_obj/tests/obj_exporter_tests.hh7
-rw-r--r--source/blender/io/wavefront_obj/tests/obj_import_string_utils_tests.cc (renamed from source/blender/io/common/intern/string_utils_test.cc)31
-rw-r--r--source/blender/io/wavefront_obj/tests/obj_importer_tests.cc141
-rw-r--r--source/blender/makesdna/DNA_ID.h4
-rw-r--r--source/blender/makesdna/DNA_ID_enums.h2
-rw-r--r--source/blender/makesdna/DNA_anim_types.h2
-rw-r--r--source/blender/makesdna/DNA_brush_enums.h2
-rw-r--r--source/blender/makesdna/DNA_brush_types.h2
-rw-r--r--source/blender/makesdna/DNA_camera_types.h3
-rw-r--r--source/blender/makesdna/DNA_cloth_types.h4
-rw-r--r--source/blender/makesdna/DNA_constraint_types.h7
-rw-r--r--source/blender/makesdna/DNA_curves_types.h19
-rw-r--r--source/blender/makesdna/DNA_customdata_types.h8
-rw-r--r--source/blender/makesdna/DNA_gpencil_modifier_defaults.h3
-rw-r--r--source/blender/makesdna/DNA_gpencil_modifier_types.h3
-rw-r--r--source/blender/makesdna/DNA_image_types.h36
-rw-r--r--source/blender/makesdna/DNA_ipo_types.h2
-rw-r--r--source/blender/makesdna/DNA_light_types.h2
-rw-r--r--source/blender/makesdna/DNA_lineart_types.h12
-rw-r--r--source/blender/makesdna/DNA_mask_types.h1
-rw-r--r--source/blender/makesdna/DNA_mesh_types.h23
-rw-r--r--source/blender/makesdna/DNA_modifier_types.h7
-rw-r--r--source/blender/makesdna/DNA_node_types.h121
-rw-r--r--source/blender/makesdna/DNA_object_types.h2
-rw-r--r--source/blender/makesdna/DNA_scene_types.h115
-rw-r--r--source/blender/makesdna/DNA_sequence_types.h2
-rw-r--r--source/blender/makesdna/DNA_sound_types.h6
-rw-r--r--source/blender/makesdna/DNA_space_defaults.h3
-rw-r--r--source/blender/makesdna/DNA_space_types.h10
-rw-r--r--source/blender/makesdna/DNA_texture_types.h3
-rw-r--r--source/blender/makesdna/DNA_userdef_types.h9
-rw-r--r--source/blender/makesdna/DNA_volume_defaults.h1
-rw-r--r--source/blender/makesdna/DNA_volume_types.h7
-rw-r--r--source/blender/makesdna/DNA_windowmanager_types.h15
-rw-r--r--source/blender/makesdna/intern/CMakeLists.txt50
-rw-r--r--source/blender/makesdna/intern/dna_rename_defs.h2
-rw-r--r--source/blender/makesdna/intern/makesdna.c192
-rw-r--r--source/blender/makesrna/RNA_access.h95
-rw-r--r--source/blender/makesrna/RNA_define.h6
-rw-r--r--source/blender/makesrna/RNA_enum_items.h16
-rw-r--r--source/blender/makesrna/RNA_types.h70
-rw-r--r--source/blender/makesrna/intern/CMakeLists.txt2
-rw-r--r--source/blender/makesrna/intern/makesrna.c38
-rw-r--r--source/blender/makesrna/intern/rna_ID.c34
-rw-r--r--source/blender/makesrna/intern/rna_access.c234
-rw-r--r--source/blender/makesrna/intern/rna_access_compare_override.c17
-rw-r--r--source/blender/makesrna/intern/rna_action.c2
-rw-r--r--source/blender/makesrna/intern/rna_armature.c6
-rw-r--r--source/blender/makesrna/intern/rna_attribute.c38
-rw-r--r--source/blender/makesrna/intern/rna_boid.c12
-rw-r--r--source/blender/makesrna/intern/rna_brush.c43
-rw-r--r--source/blender/makesrna/intern/rna_camera.c91
-rw-r--r--source/blender/makesrna/intern/rna_cloth.c12
-rw-r--r--source/blender/makesrna/intern/rna_color.c12
-rw-r--r--source/blender/makesrna/intern/rna_constraint.c42
-rw-r--r--source/blender/makesrna/intern/rna_curve.c27
-rw-r--r--source/blender/makesrna/intern/rna_curves.c80
-rw-r--r--source/blender/makesrna/intern/rna_define.c43
-rw-r--r--source/blender/makesrna/intern/rna_dynamicpaint.c18
-rw-r--r--source/blender/makesrna/intern/rna_fcurve.c10
-rw-r--r--source/blender/makesrna/intern/rna_fluid.c33
-rw-r--r--source/blender/makesrna/intern/rna_gpencil.c6
-rw-r--r--source/blender/makesrna/intern/rna_gpencil_modifier.c39
-rw-r--r--source/blender/makesrna/intern/rna_image.c128
-rw-r--r--source/blender/makesrna/intern/rna_image_api.c89
-rw-r--r--source/blender/makesrna/intern/rna_internal.h7
-rw-r--r--source/blender/makesrna/intern/rna_internal_types.h16
-rw-r--r--source/blender/makesrna/intern/rna_key.c41
-rw-r--r--source/blender/makesrna/intern/rna_lattice.c8
-rw-r--r--source/blender/makesrna/intern/rna_layer.c7
-rw-r--r--source/blender/makesrna/intern/rna_linestyle.c16
-rw-r--r--source/blender/makesrna/intern/rna_mask.c4
-rw-r--r--source/blender/makesrna/intern/rna_material.c12
-rw-r--r--source/blender/makesrna/intern/rna_mesh.c164
-rw-r--r--source/blender/makesrna/intern/rna_meta.c6
-rw-r--r--source/blender/makesrna/intern/rna_modifier.c36
-rw-r--r--source/blender/makesrna/intern/rna_movieclip.c25
-rw-r--r--source/blender/makesrna/intern/rna_nla.c88
-rw-r--r--source/blender/makesrna/intern/rna_nodetree.c224
-rw-r--r--source/blender/makesrna/intern/rna_object.c43
-rw-r--r--source/blender/makesrna/intern/rna_object_force.c108
-rw-r--r--source/blender/makesrna/intern/rna_particle.c19
-rw-r--r--source/blender/makesrna/intern/rna_pointcloud.c13
-rw-r--r--source/blender/makesrna/intern/rna_pose.c12
-rw-r--r--source/blender/makesrna/intern/rna_render.c5
-rw-r--r--source/blender/makesrna/intern/rna_rigidbody.c6
-rw-r--r--source/blender/makesrna/intern/rna_rna.c212
-rw-r--r--source/blender/makesrna/intern/rna_scene.c92
-rw-r--r--source/blender/makesrna/intern/rna_scene_api.c2
-rw-r--r--source/blender/makesrna/intern/rna_sculpt_paint.c52
-rw-r--r--source/blender/makesrna/intern/rna_sequencer.c134
-rw-r--r--source/blender/makesrna/intern/rna_sequencer_api.c29
-rw-r--r--source/blender/makesrna/intern/rna_shader_fx.c4
-rw-r--r--source/blender/makesrna/intern/rna_sound.c28
-rw-r--r--source/blender/makesrna/intern/rna_space.c122
-rw-r--r--source/blender/makesrna/intern/rna_texture.c12
-rw-r--r--source/blender/makesrna/intern/rna_tracking.c14
-rw-r--r--source/blender/makesrna/intern/rna_ui.c9
-rw-r--r--source/blender/makesrna/intern/rna_userdef.c20
-rw-r--r--source/blender/makesrna/intern/rna_volume.c19
-rw-r--r--source/blender/makesrna/intern/rna_wm.c55
-rw-r--r--source/blender/makesrna/intern/rna_wm_api.c1
-rw-r--r--source/blender/makesrna/intern/rna_xr.c59
-rw-r--r--source/blender/modifiers/CMakeLists.txt2
-rw-r--r--source/blender/modifiers/intern/MOD_array.c4
-rw-r--r--source/blender/modifiers/intern/MOD_bevel.c5
-rw-r--r--source/blender/modifiers/intern/MOD_boolean.cc40
-rw-r--r--source/blender/modifiers/intern/MOD_correctivesmooth.c22
-rw-r--r--source/blender/modifiers/intern/MOD_displace.c5
-rw-r--r--source/blender/modifiers/intern/MOD_dynamicpaint.c6
-rw-r--r--source/blender/modifiers/intern/MOD_explode.c13
-rw-r--r--source/blender/modifiers/intern/MOD_hook.c4
-rw-r--r--source/blender/modifiers/intern/MOD_laplaciandeform.c22
-rw-r--r--source/blender/modifiers/intern/MOD_mask.cc13
-rw-r--r--source/blender/modifiers/intern/MOD_meshdeform.c61
-rw-r--r--source/blender/modifiers/intern/MOD_meshsequencecache.cc47
-rw-r--r--source/blender/modifiers/intern/MOD_nodes.cc76
-rw-r--r--source/blender/modifiers/intern/MOD_normal_edit.c5
-rw-r--r--source/blender/modifiers/intern/MOD_particlesystem.cc (renamed from source/blender/modifiers/intern/MOD_particlesystem.c)93
-rw-r--r--source/blender/modifiers/intern/MOD_screw.c134
-rw-r--r--source/blender/modifiers/intern/MOD_skin.c37
-rw-r--r--source/blender/modifiers/intern/MOD_solidify.c2
-rw-r--r--source/blender/modifiers/intern/MOD_subsurf.c45
-rw-r--r--source/blender/modifiers/intern/MOD_surfacedeform.c39
-rw-r--r--source/blender/modifiers/intern/MOD_util.c3
-rw-r--r--source/blender/modifiers/intern/MOD_util.h8
-rw-r--r--source/blender/modifiers/intern/MOD_warp.c19
-rw-r--r--source/blender/modifiers/intern/MOD_wave.c1
-rw-r--r--source/blender/modifiers/intern/MOD_weighted_normal.c12
-rw-r--r--source/blender/modifiers/intern/MOD_weightvg_util.c7
-rw-r--r--source/blender/modifiers/intern/MOD_weightvgedit.c4
-rw-r--r--source/blender/modifiers/intern/MOD_weightvgproximity.c4
-rw-r--r--source/blender/nodes/NOD_geometry.h3
-rw-r--r--source/blender/nodes/NOD_geometry_exec.hh45
-rw-r--r--source/blender/nodes/NOD_geometry_nodes_eval_log.hh21
-rw-r--r--source/blender/nodes/NOD_node_tree_ref.hh3
-rw-r--r--source/blender/nodes/NOD_static_types.h9
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_map_range.cc4
-rw-r--r--source/blender/nodes/function/nodes/node_fn_compare.cc4
-rw-r--r--source/blender/nodes/function/nodes/node_fn_random_value.cc8
-rw-r--r--source/blender/nodes/function/nodes/node_fn_replace_string.cc18
-rw-r--r--source/blender/nodes/geometry/CMakeLists.txt3
-rw-r--r--source/blender/nodes/geometry/node_geometry_tree.cc2
-rw-r--r--source/blender/nodes/geometry/node_geometry_util.cc4
-rw-r--r--source/blender/nodes/geometry/node_geometry_util.hh9
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_accumulate_field.cc36
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_attribute_capture.cc72
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_attribute_domain_size.cc17
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_attribute_statistic.cc18
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_boolean.cc62
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_bounding_box.cc4
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_convex_hull.cc10
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_curve_endpoint_selection.cc2
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_curve_fillet.cc86
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_curve_handle_type_selection.cc2
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_curve_resample.cc537
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_curve_reverse.cc4
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_curve_spline_parameter.cc14
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_curve_spline_type.cc822
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_curve_subdivide.cc40
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_curve_to_points.cc37
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_curve_trim.cc62
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_delete_geometry.cc360
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_distribute_points_on_faces.cc12
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_dual_mesh.cc4
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_duplicate_elements.cc132
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_edge_split.cc4
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_extrude_mesh.cc63
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_field_at_index.cc16
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_flip_faces.cc6
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_input_curve_handles.cc2
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_input_instance_rotation.cc65
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_input_instance_scale.cc64
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_input_mesh_edge_angle.cc4
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_input_mesh_edge_neighbors.cc2
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_input_mesh_edge_vertices.cc8
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_input_mesh_face_area.cc4
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_input_mesh_face_is_planar.cc4
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_input_mesh_face_neighbors.cc8
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_input_mesh_island.cc7
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_input_mesh_vertex_neighbors.cc8
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_input_named_attribute.cc13
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_input_spline_length.cc4
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_input_tangent.cc4
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_instance_on_points.cc14
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_instances_to_points.cc4
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_join_geometry.cc14
-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.cc14
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_cube.cc419
-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.cc10
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_points_to_vertices.cc8
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_points_to_volume.cc12
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_raycast.cc14
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_remove_attribute.cc7
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_rotate_instances.cc4
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_scale_elements.cc2
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_scale_instances.cc2
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_separate_geometry.cc25
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_set_curve_handles.cc6
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_set_curve_radius.cc6
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_set_curve_tilt.cc6
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_set_id.cc12
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_set_material_index.cc6
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_set_point_radius.cc6
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_set_position.cc13
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_set_shade_smooth.cc6
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_set_spline_cyclic.cc6
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_set_spline_resolution.cc6
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_store_named_attribute.cc29
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_string_to_curves.cc4
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_subdivision_surface.cc4
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_transfer_attribute.cc42
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_translate_instances.cc2
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_triangulate.cc4
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_viewer.cc6
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_volume_cube.cc197
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_volume_to_mesh.cc14
-rw-r--r--source/blender/nodes/intern/geometry_nodes_eval_log.cc14
-rw-r--r--source/blender/nodes/intern/node_common.cc38
-rw-r--r--source/blender/nodes/intern/node_geometry_exec.cc135
-rw-r--r--source/blender/nodes/intern/node_socket.cc5
-rw-r--r--source/blender/nodes/intern/node_socket_declarations.cc7
-rw-r--r--source/blender/nodes/shader/node_shader_tree.cc8
-rw-r--r--source/blender/nodes/shader/node_shader_util.cc2
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_blackbody.cc4
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_curves.cc211
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_map_range.cc10
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_sepcomb_xyz.cc38
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_tex_image.cc2
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_uvmap.cc2
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_vertex_color.cc16
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_volume_principled.cc4
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_wavelength.cc17
-rw-r--r--source/blender/nodes/texture/node_texture_tree.c8
-rw-r--r--source/blender/nodes/texture/node_texture_util.c4
-rw-r--r--source/blender/nodes/texture/nodes/node_texture_output.c17
-rw-r--r--source/blender/nodes/texture/nodes/node_texture_proc.c39
-rw-r--r--source/blender/nodes/texture/nodes/node_texture_texture.c2
-rw-r--r--source/blender/python/bmesh/bmesh_py_types.c37
-rw-r--r--source/blender/python/generic/blf_py_api.c2
-rw-r--r--source/blender/python/generic/idprop_py_api.c5
-rw-r--r--source/blender/python/generic/imbuf_py_api.c14
-rw-r--r--source/blender/python/gpu/gpu_py_api.c4
-rw-r--r--source/blender/python/gpu/gpu_py_batch.c4
-rw-r--r--source/blender/python/gpu/gpu_py_element.c7
-rw-r--r--source/blender/python/gpu/gpu_py_offscreen.c3
-rw-r--r--source/blender/python/gpu/gpu_py_platform.c2
-rw-r--r--source/blender/python/gpu/gpu_py_select.c2
-rw-r--r--source/blender/python/gpu/gpu_py_shader.c50
-rw-r--r--source/blender/python/gpu/gpu_py_shader_create_info.cc1
-rw-r--r--source/blender/python/gpu/gpu_py_types.c1
-rw-r--r--source/blender/python/gpu/gpu_py_uniformbuffer.c2
-rw-r--r--source/blender/python/gpu/gpu_py_vertex_format.c4
-rw-r--r--source/blender/python/intern/CMakeLists.txt21
-rw-r--r--source/blender/python/intern/bpy.c110
-rw-r--r--source/blender/python/intern/bpy_app.c54
-rw-r--r--source/blender/python/intern/bpy_app_build_options.c21
-rw-r--r--source/blender/python/intern/bpy_app_handlers.c6
-rw-r--r--source/blender/python/intern/bpy_interface.c36
-rw-r--r--source/blender/python/intern/bpy_library_load.c8
-rw-r--r--source/blender/python/intern/bpy_props.c421
-rw-r--r--source/blender/python/intern/bpy_rna.c2
-rw-r--r--source/blender/python/intern/bpy_rna_text.h2
-rw-r--r--source/blender/python/intern/bpy_rna_types_capi.c3
-rw-r--r--source/blender/python/intern/bpy_traceback.c2
-rw-r--r--source/blender/python/intern/bpy_utils_units.c14
-rw-r--r--source/blender/python/mathutils/CMakeLists.txt2
-rw-r--r--source/blender/python/mathutils/mathutils_Color.c418
-rw-r--r--source/blender/python/mathutils/mathutils_Color.h3
-rw-r--r--source/blender/python/mathutils/mathutils_Euler.c218
-rw-r--r--source/blender/python/mathutils/mathutils_Euler.h1
-rw-r--r--source/blender/python/mathutils/mathutils_Matrix.c1056
-rw-r--r--source/blender/python/mathutils/mathutils_Matrix.h4
-rw-r--r--source/blender/python/mathutils/mathutils_Quaternion.c569
-rw-r--r--source/blender/python/mathutils/mathutils_Quaternion.h3
-rw-r--r--source/blender/python/mathutils/mathutils_Vector.c835
-rw-r--r--source/blender/python/mathutils/mathutils_Vector.h3
-rw-r--r--source/blender/python/rna_dump.py2
-rw-r--r--source/blender/render/RE_pipeline.h16
-rw-r--r--source/blender/render/RE_texture.h3
-rw-r--r--source/blender/render/RE_texture_margin.h9
-rw-r--r--source/blender/render/intern/bake.c25
-rw-r--r--source/blender/render/intern/multires_bake.c242
-rw-r--r--source/blender/render/intern/pipeline.c8
-rw-r--r--source/blender/render/intern/render_result.c2
-rw-r--r--source/blender/render/intern/render_result.h2
-rw-r--r--source/blender/render/intern/texture_image.c310
-rw-r--r--source/blender/render/intern/texture_margin.cc9
-rw-r--r--source/blender/render/intern/texture_pointdensity.c7
-rw-r--r--source/blender/render/intern/texture_procedural.c429
-rw-r--r--source/blender/sequencer/SEQ_add.h3
-rw-r--r--source/blender/sequencer/SEQ_channels.h4
-rw-r--r--source/blender/sequencer/SEQ_iterator.h3
-rw-r--r--source/blender/sequencer/SEQ_sequencer.h3
-rw-r--r--source/blender/sequencer/SEQ_time.h12
-rw-r--r--source/blender/sequencer/SEQ_transform.h13
-rw-r--r--source/blender/sequencer/SEQ_utils.h14
-rw-r--r--source/blender/sequencer/intern/disk_cache.c43
-rw-r--r--source/blender/sequencer/intern/effects.c21
-rw-r--r--source/blender/sequencer/intern/image_cache.c28
-rw-r--r--source/blender/sequencer/intern/proxy.c9
-rw-r--r--source/blender/sequencer/intern/render.c25
-rw-r--r--source/blender/sequencer/intern/sequence_lookup.c94
-rw-r--r--source/blender/sequencer/intern/sequencer.c8
-rw-r--r--source/blender/sequencer/intern/sequencer.h26
-rw-r--r--source/blender/sequencer/intern/sound.c10
-rw-r--r--source/blender/sequencer/intern/strip_add.c41
-rw-r--r--source/blender/sequencer/intern/strip_edit.c119
-rw-r--r--source/blender/sequencer/intern/strip_relations.c9
-rw-r--r--source/blender/sequencer/intern/strip_time.c250
-rw-r--r--source/blender/sequencer/intern/strip_time.h5
-rw-r--r--source/blender/sequencer/intern/strip_transform.c496
-rw-r--r--source/blender/sequencer/intern/utils.c74
-rw-r--r--source/blender/simulation/intern/SIM_mass_spring.cpp5
-rw-r--r--source/blender/windowmanager/CMakeLists.txt2
-rw-r--r--source/blender/windowmanager/WM_api.h85
-rw-r--r--source/blender/windowmanager/WM_toolsystem.h5
-rw-r--r--source/blender/windowmanager/WM_types.h5
-rw-r--r--source/blender/windowmanager/gizmo/WM_gizmo_api.h2
-rw-r--r--source/blender/windowmanager/gizmo/intern/wm_gizmo_map.c210
-rw-r--r--source/blender/windowmanager/gizmo/intern/wm_gizmo_target_props.c2
-rw-r--r--source/blender/windowmanager/intern/wm_cursors.c2
-rw-r--r--source/blender/windowmanager/intern/wm_dragdrop.c15
-rw-r--r--source/blender/windowmanager/intern/wm_draw.c241
-rw-r--r--source/blender/windowmanager/intern/wm_event_query.c7
-rw-r--r--source/blender/windowmanager/intern/wm_event_system.cc (renamed from source/blender/windowmanager/intern/wm_event_system.c)1026
-rw-r--r--source/blender/windowmanager/intern/wm_files.c11
-rw-r--r--source/blender/windowmanager/intern/wm_files_link.c8
-rw-r--r--source/blender/windowmanager/intern/wm_gesture_ops.c2
-rw-r--r--source/blender/windowmanager/intern/wm_init_exit.c10
-rw-r--r--source/blender/windowmanager/intern/wm_jobs.c60
-rw-r--r--source/blender/windowmanager/intern/wm_keymap.c5
-rw-r--r--source/blender/windowmanager/intern/wm_keymap_utils.c6
-rw-r--r--source/blender/windowmanager/intern/wm_menu_type.c18
-rw-r--r--source/blender/windowmanager/intern/wm_operator_props.c72
-rw-r--r--source/blender/windowmanager/intern/wm_operator_type.c21
-rw-r--r--source/blender/windowmanager/intern/wm_operators.c105
-rw-r--r--source/blender/windowmanager/intern/wm_panel_type.c18
-rw-r--r--source/blender/windowmanager/intern/wm_playanim.c14
-rw-r--r--source/blender/windowmanager/intern/wm_toolsystem.c3
-rw-r--r--source/blender/windowmanager/intern/wm_uilist_type.c1
-rw-r--r--source/blender/windowmanager/intern/wm_window.c25
-rw-r--r--source/blender/windowmanager/xr/intern/wm_xr_action.c9
-rw-r--r--source/blender/windowmanager/xr/intern/wm_xr_intern.h4
-rw-r--r--source/blender/windowmanager/xr/intern/wm_xr_operators.c5
-rw-r--r--source/blender/windowmanager/xr/intern/wm_xr_session.c12
1534 files changed, 43661 insertions, 26276 deletions
diff --git a/source/blender/CMakeLists.txt b/source/blender/CMakeLists.txt
index deff45d0350..8ba6e7318bb 100644
--- a/source/blender/CMakeLists.txt
+++ b/source/blender/CMakeLists.txt
@@ -89,6 +89,42 @@ set(SRC_DNA_INC
${CMAKE_CURRENT_SOURCE_DIR}/makesdna/DNA_xr_types.h
)
+set(SRC_DNA_DEFAULTS_INC
+ ${CMAKE_CURRENT_SOURCE_DIR}/makesdna/DNA_armature_defaults.h
+ ${CMAKE_CURRENT_SOURCE_DIR}/makesdna/DNA_asset_defaults.h
+ ${CMAKE_CURRENT_SOURCE_DIR}/makesdna/DNA_brush_defaults.h
+ ${CMAKE_CURRENT_SOURCE_DIR}/makesdna/DNA_cachefile_defaults.h
+ ${CMAKE_CURRENT_SOURCE_DIR}/makesdna/DNA_camera_defaults.h
+ ${CMAKE_CURRENT_SOURCE_DIR}/makesdna/DNA_collection_defaults.h
+ ${CMAKE_CURRENT_SOURCE_DIR}/makesdna/DNA_curve_defaults.h
+ ${CMAKE_CURRENT_SOURCE_DIR}/makesdna/DNA_curves_defaults.h
+ ${CMAKE_CURRENT_SOURCE_DIR}/makesdna/DNA_defaults.h
+ ${CMAKE_CURRENT_SOURCE_DIR}/makesdna/DNA_fluid_defaults.h
+ ${CMAKE_CURRENT_SOURCE_DIR}/makesdna/DNA_gpencil_modifier_defaults.h
+ ${CMAKE_CURRENT_SOURCE_DIR}/makesdna/DNA_image_defaults.h
+ ${CMAKE_CURRENT_SOURCE_DIR}/makesdna/DNA_lattice_defaults.h
+ ${CMAKE_CURRENT_SOURCE_DIR}/makesdna/DNA_light_defaults.h
+ ${CMAKE_CURRENT_SOURCE_DIR}/makesdna/DNA_lightprobe_defaults.h
+ ${CMAKE_CURRENT_SOURCE_DIR}/makesdna/DNA_linestyle_defaults.h
+ ${CMAKE_CURRENT_SOURCE_DIR}/makesdna/DNA_material_defaults.h
+ ${CMAKE_CURRENT_SOURCE_DIR}/makesdna/DNA_mesh_defaults.h
+ ${CMAKE_CURRENT_SOURCE_DIR}/makesdna/DNA_meta_defaults.h
+ ${CMAKE_CURRENT_SOURCE_DIR}/makesdna/DNA_modifier_defaults.h
+ ${CMAKE_CURRENT_SOURCE_DIR}/makesdna/DNA_movieclip_defaults.h
+ ${CMAKE_CURRENT_SOURCE_DIR}/makesdna/DNA_object_defaults.h
+ ${CMAKE_CURRENT_SOURCE_DIR}/makesdna/DNA_particle_defaults.h
+ ${CMAKE_CURRENT_SOURCE_DIR}/makesdna/DNA_pointcloud_defaults.h
+ ${CMAKE_CURRENT_SOURCE_DIR}/makesdna/DNA_scene_defaults.h
+ ${CMAKE_CURRENT_SOURCE_DIR}/makesdna/DNA_simulation_defaults.h
+ ${CMAKE_CURRENT_SOURCE_DIR}/makesdna/DNA_space_defaults.h
+ ${CMAKE_CURRENT_SOURCE_DIR}/makesdna/DNA_speaker_defaults.h
+ ${CMAKE_CURRENT_SOURCE_DIR}/makesdna/DNA_texture_defaults.h
+ ${CMAKE_CURRENT_SOURCE_DIR}/makesdna/DNA_vec_defaults.h
+ ${CMAKE_CURRENT_SOURCE_DIR}/makesdna/DNA_view3d_defaults.h
+ ${CMAKE_CURRENT_SOURCE_DIR}/makesdna/DNA_volume_defaults.h
+ ${CMAKE_CURRENT_SOURCE_DIR}/makesdna/DNA_world_defaults.h
+)
+
add_subdirectory(datatoc)
add_subdirectory(editors)
add_subdirectory(windowmanager)
diff --git a/source/blender/blenfont/BLF_api.h b/source/blender/blenfont/BLF_api.h
index e5e2b1711b1..83ca9158efc 100644
--- a/source/blender/blenfont/BLF_api.h
+++ b/source/blender/blenfont/BLF_api.h
@@ -14,6 +14,15 @@
extern "C" {
#endif
+/* Name of subfolder inside BLENDER_DATAFILES that contains font files. */
+#define BLF_DATAFILES_FONTS_DIR "fonts"
+
+/* File name of the default variable-width font. */
+#define BLF_DEFAULT_PROPORTIONAL_FONT "droidsans.ttf"
+
+/* File name of the default fixed-pitch font. */
+#define BLF_DEFAULT_MONOSPACED_FONT "bmonofont-i18n.ttf"
+
/* enable this only if needed (unused circa 2016) */
#define BLF_BLUR_ENABLE 0
@@ -37,12 +46,14 @@ void BLF_cache_flush_set_fn(void (*cache_flush_fn)(void));
*/
int BLF_load(const char *name) ATTR_NONNULL();
int BLF_load_mem(const char *name, const unsigned char *mem, int mem_size) ATTR_NONNULL();
+bool BLF_is_loaded(const char *name) ATTR_NONNULL();
int BLF_load_unique(const char *name) ATTR_NONNULL();
int BLF_load_mem_unique(const char *name, const unsigned char *mem, int mem_size) ATTR_NONNULL();
void BLF_unload(const char *name) ATTR_NONNULL();
void BLF_unload_id(int fontid);
+void BLF_unload_all(void);
char *BLF_display_name_from_file(const char *filepath);
@@ -312,25 +323,35 @@ int BLF_set_default(void);
int BLF_load_default(bool unique);
int BLF_load_mono_default(bool unique);
+void BLF_load_font_stack(void);
#ifdef DEBUG
void BLF_state_print(int fontid);
#endif
-/* font->flags. */
-#define BLF_ROTATION (1 << 0)
-#define BLF_CLIPPING (1 << 1)
-#define BLF_SHADOW (1 << 2)
-// #define BLF_FLAG_UNUSED_3 (1 << 3) /* dirty */
-#define BLF_MATRIX (1 << 4)
-#define BLF_ASPECT (1 << 5)
-#define BLF_WORD_WRAP (1 << 6)
-#define BLF_MONOCHROME (1 << 7) /* no-AA */
-#define BLF_HINTING_NONE (1 << 8)
-#define BLF_HINTING_SLIGHT (1 << 9)
-#define BLF_HINTING_FULL (1 << 10)
-#define BLF_BOLD (1 << 11)
-#define BLF_ITALIC (1 << 12)
+/** #FontBLF.flags. */
+enum {
+ BLF_ROTATION = 1 << 0,
+ BLF_CLIPPING = 1 << 1,
+ BLF_SHADOW = 1 << 2,
+ // BLF_FLAG_UNUSED_3 = 1 << 3, /* dirty */
+ BLF_MATRIX = 1 << 4,
+ BLF_ASPECT = 1 << 5,
+ BLF_WORD_WRAP = 1 << 6,
+ /** No anti-aliasing. */
+ BLF_MONOCHROME = 1 << 7,
+ BLF_HINTING_NONE = 1 << 8,
+ BLF_HINTING_SLIGHT = 1 << 9,
+ BLF_HINTING_FULL = 1 << 10,
+ BLF_BOLD = 1 << 11,
+ BLF_ITALIC = 1 << 12,
+ /** Intended USE is monospaced, regardless of font type. */
+ BLF_MONOSPACED = 1 << 13,
+ /** A font within the default stack of fonts. */
+ BLF_DEFAULT = 1 << 14,
+ /** Must only be used as last font in the stack. */
+ BLF_LAST_RESORT = 1 << 15,
+};
#define BLF_DRAW_STR_DUMMY_MAX 1024
diff --git a/source/blender/blenfont/intern/blf.c b/source/blender/blenfont/intern/blf.c
index a944ab332bd..a1fcc17ca3f 100644
--- a/source/blender/blenfont/intern/blf.c
+++ b/source/blender/blenfont/intern/blf.c
@@ -34,13 +34,6 @@
#include "blf_internal.h"
#include "blf_internal_types.h"
-/* Max number of font in memory.
- * Take care that now every font have a glyph cache per size/dpi,
- * so we don't need load the same font with different size, just
- * load one and call BLF_size.
- */
-#define BLF_MAX_FONT 16
-
#define BLF_RESULT_CHECK_INIT(r_info) \
if (r_info) { \
memset(r_info, 0, sizeof(*(r_info))); \
@@ -48,7 +41,7 @@
((void)0)
/* Font array. */
-static FontBLF *global_font[BLF_MAX_FONT] = {NULL};
+FontBLF *global_font[BLF_MAX_FONT] = {NULL};
/* XXX: should these be made into global_font_'s too? */
@@ -134,6 +127,11 @@ bool BLF_has_glyph(int fontid, unsigned int unicode)
return false;
}
+bool BLF_is_loaded(const char *name)
+{
+ return blf_search(name) >= 0;
+}
+
int BLF_load(const char *name)
{
/* check if we already load this font. */
@@ -255,6 +253,20 @@ void BLF_unload_id(int fontid)
}
}
+void BLF_unload_all(void)
+{
+ for (int i = 0; i < BLF_MAX_FONT; i++) {
+ FontBLF *font = global_font[i];
+ if (font) {
+ blf_font_free(font);
+ global_font[i] = NULL;
+ }
+ }
+ blf_mono_font = -1;
+ blf_mono_font_render = -1;
+ BLF_default_set(-1);
+}
+
void BLF_enable(int fontid, int option)
{
FontBLF *font = blf_get(fontid);
diff --git a/source/blender/blenfont/intern/blf_font.c b/source/blender/blenfont/intern/blf_font.c
index f93cb8b2d64..3e2927d581e 100644
--- a/source/blender/blenfont/intern/blf_font.c
+++ b/source/blender/blenfont/intern/blf_font.c
@@ -18,6 +18,7 @@
#include FT_FREETYPE_H
#include FT_GLYPH_H
+#include FT_TRUETYPE_TABLES_H /* For TT_OS2 */
#include "MEM_guardedalloc.h"
@@ -1288,6 +1289,25 @@ FontBLF *blf_font_new(const char *name, const char *filepath)
font->filepath = BLI_strdup(filepath);
blf_font_fill(font);
+ /* Save TrueType table with bits to quickly test most unicode block coverage. */
+ TT_OS2 *os2_table = (TT_OS2 *)FT_Get_Sfnt_Table(font->face, FT_SFNT_OS2);
+ if (os2_table) {
+ font->UnicodeRanges[0] = (uint)os2_table->ulUnicodeRange1;
+ font->UnicodeRanges[1] = (uint)os2_table->ulUnicodeRange2;
+ font->UnicodeRanges[2] = (uint)os2_table->ulUnicodeRange3;
+ font->UnicodeRanges[3] = (uint)os2_table->ulUnicodeRange4;
+ }
+
+ /* Detect "Last resort" fonts. They have everything. Usually except last 5 bits. */
+ if (font->UnicodeRanges[0] == 0xffffffffU && font->UnicodeRanges[1] == 0xffffffffU &&
+ font->UnicodeRanges[2] == 0xffffffffU && font->UnicodeRanges[3] >= 0x7FFFFFFU) {
+ font->flags |= BLF_LAST_RESORT;
+ }
+
+ if (FT_IS_FIXED_WIDTH(font->face)) {
+ font->flags |= BLF_MONOSPACED;
+ }
+
if (FT_HAS_KERNING(font->face)) {
/* Create kerning cache table and fill with value indicating "unset". */
font->kerning_cache = MEM_mallocN(sizeof(KerningCacheBLF), __func__);
@@ -1374,7 +1394,7 @@ bool blf_font_size(FontBLF *font, float size, unsigned int dpi)
font->dpi = dpi;
}
else {
- printf("The current font does not support the size, %f and dpi, %u\n", size, dpi);
+ printf("The current font does not support the size, %f and DPI, %u\n", size, dpi);
return false;
}
}
diff --git a/source/blender/blenfont/intern/blf_font_default.c b/source/blender/blenfont/intern/blf_font_default.c
index 3a68423e64e..1bde25b5776 100644
--- a/source/blender/blenfont/intern/blf_font_default.c
+++ b/source/blender/blenfont/intern/blf_font_default.c
@@ -11,13 +11,14 @@
#include "BLF_api.h"
+#include "BLI_fileops.h"
#include "BLI_path_util.h"
#include "BKE_appdir.h"
static int blf_load_font_default(const char *filename, const bool unique)
{
- const char *dir = BKE_appdir_folder_id(BLENDER_DATAFILES, "fonts");
+ const char *dir = BKE_appdir_folder_id(BLENDER_DATAFILES, BLF_DATAFILES_FONTS_DIR);
if (dir == NULL) {
fprintf(stderr,
"%s: 'fonts' data path not found for '%s', will not be able to display text\n",
@@ -34,10 +35,46 @@ static int blf_load_font_default(const char *filename, const bool unique)
int BLF_load_default(const bool unique)
{
- return blf_load_font_default("droidsans.ttf", unique);
+ int font_id = blf_load_font_default(BLF_DEFAULT_PROPORTIONAL_FONT, unique);
+ BLF_enable(font_id, BLF_DEFAULT);
+ return font_id;
}
int BLF_load_mono_default(const bool unique)
{
- return blf_load_font_default("bmonofont-i18n.ttf", unique);
+ int font_id = blf_load_font_default(BLF_DEFAULT_MONOSPACED_FONT, unique);
+ BLF_enable(font_id, BLF_MONOSPACED | BLF_DEFAULT);
+ return font_id;
+}
+
+void BLF_load_font_stack()
+{
+ /* Load these if not already, might have been replaced by user custom. */
+ BLF_load_default(false);
+ BLF_load_mono_default(false);
+
+ const char *path = BKE_appdir_folder_id(BLENDER_DATAFILES, BLF_DATAFILES_FONTS_DIR SEP_STR);
+ if (path && BLI_exists(path)) {
+ struct direntry *dir;
+ uint num_files = BLI_filelist_dir_contents(path, &dir);
+ for (int f = 0; f < num_files; f++) {
+ if (!FILENAME_IS_CURRPAR(dir[f].relname) && !BLI_is_dir(dir[f].path)) {
+ if (!BLF_is_loaded(dir[f].path)) {
+ int font_id = BLF_load(dir[f].path);
+ if (font_id == -1) {
+ fprintf(stderr, "Unable to load font: %s\n", dir[f].path);
+ }
+ else {
+ BLF_enable(font_id, BLF_DEFAULT);
+ /* TODO: FontBLF will later load FT_Face on demand. When this is in
+ * place we can drop this face now since we have all needed data. */
+ }
+ }
+ }
+ }
+ BLI_filelist_free(dir, num_files);
+ }
+ else {
+ fprintf(stderr, "Fonts not found at %s\n", path);
+ }
}
diff --git a/source/blender/blenfont/intern/blf_glyph.c b/source/blender/blenfont/intern/blf_glyph.c
index 2694b179a11..ed30cca4da2 100644
--- a/source/blender/blenfont/intern/blf_glyph.c
+++ b/source/blender/blenfont/intern/blf_glyph.c
@@ -39,6 +39,7 @@
#include "BLI_math_vector.h"
#include "BLI_strict_flags.h"
+#include "BLI_string_utf8.h"
/* -------------------------------------------------------------------- */
/** \name Internal Utilities
@@ -222,6 +223,335 @@ static GlyphBLF *blf_glyph_cache_add_glyph(
return g;
}
+/* This table can be used to find a coverage bit based on a charcode. later we can get default
+ * language and script from codepoint. */
+
+typedef struct eUnicodeBlock {
+ unsigned int first;
+ unsigned int last;
+ int coverage_bit; /* 0-122. -1 is N/A. */
+ /* Later we add primary script and language for Harfbuzz, data from
+ * https://en.wikipedia.org/wiki/Unicode_block */
+} eUnicodeBlock;
+
+static eUnicodeBlock unicode_blocks[] = {
+ /* Must be in ascending order by start of range. */
+ {0x0, 0x7F, 0}, /* Basic Latin. */
+ {0x80, 0xFF, 1}, /* Latin-1 Supplement. */
+ {0x100, 0x17F, 2}, /* Latin Extended-A. */
+ {0x180, 0x24F, 3}, /* Latin Extended-B. */
+ {0x250, 0x2AF, 4}, /* IPA Extensions. */
+ {0x2B0, 0x2FF, 5}, /* Spacing Modifier Letters. */
+ {0x300, 0x36F, 6}, /* Combining Diacritical Marks. */
+ {0x370, 0x3FF, 7}, /* Greek. */
+ {0x400, 0x52F, 9}, /* Cyrillic. */
+ {0x530, 0x58F, 10}, /* Armenian. */
+ {0x590, 0x5FF, 11}, /* Hebrew. */
+ {0x600, 0x6FF, 13}, /* Arabic. */
+ {0x700, 0x74F, 71}, /* Syriac. */
+ {0x750, 0x77F, 13}, /* Arabic Supplement. */
+ {0x780, 0x7BF, 72}, /* Thaana. */
+ {0x7C0, 0x7FF, 14}, /* NKo. */
+ {0x800, 0x83F, -1}, /* Samaritan. */
+ {0x840, 0x85F, -1}, /* Mandaic. */
+ {0x900, 0x97F, 15}, /* Devanagari. */
+ {0x980, 0x9FF, 16}, /* Bengali. */
+ {0xA00, 0xA7F, 17}, /* Gurmukhi. */
+ {0xA80, 0xAFF, 18}, /* Gujarati. */
+ {0xB00, 0xB7F, 19}, /* Oriya. */
+ {0xB80, 0xBFF, 20}, /* Tamil. */
+ {0xC00, 0xC7F, 21}, /* Telugu. */
+ {0xC80, 0xCFF, 22}, /* Kannada. */
+ {0xD00, 0xD7F, 23}, /* Malayalam. */
+ {0xD80, 0xDFF, 73}, /* Sinhala. */
+ {0xE00, 0xE7F, 24}, /* Thai. */
+ {0xE80, 0xEFF, 25}, /* Lao. */
+ {0xF00, 0xFFF, 70}, /* Tibetan. */
+ {0x1000, 0x109F, 74}, /* Myanmar. */
+ {0x10A0, 0x10FF, 26}, /* Georgian. */
+ {0x1100, 0x11FF, 28}, /* Hangul Jamo. */
+ {0x1200, 0x139F, 75}, /* Ethiopic. */
+ {0x13A0, 0x13FF, 76}, /* Cherokee. */
+ {0x1400, 0x167F, 77}, /* Canadian Aboriginal. */
+ {0x1680, 0x169F, 78}, /* Ogham. */
+ {0x16A0, 0x16FF, 79}, /* unic. */
+ {0x1700, 0x171F, 84}, /* Tagalog. */
+ {0x1720, 0x173F, 84}, /* Hanunoo. */
+ {0x1740, 0x175F, 84}, /* Buhid. */
+ {0x1760, 0x177F, 84}, /* Tagbanwa. */
+ {0x1780, 0x17FF, 80}, /* Khmer. */
+ {0x1800, 0x18AF, 81}, /* Mongolian. */
+ {0x1900, 0x194F, 93}, /* Limbu. */
+ {0x1950, 0x197F, 94}, /* Tai Le. */
+ {0x1980, 0x19DF, 95}, /* New Tai Lue". */
+ {0x19E0, 0x19FF, 80}, /* Khmer. */
+ {0x1A00, 0x1A1F, 96}, /* Buginese. */
+ {0x1A20, 0x1AAF, -1}, /* Tai Tham. */
+ {0x1B00, 0x1B7F, 27}, /* Balinese. */
+ {0x1B80, 0x1BBF, 112}, /* Sundanese. */
+ {0x1BC0, 0x1BFF, -1}, /* Batak. */
+ {0x1C00, 0x1C4F, 113}, /* Lepcha. */
+ {0x1C50, 0x1C7F, 114}, /* Ol Chiki. */
+ {0x1D00, 0x1DBF, 4}, /* IPA Extensions. */
+ {0x1DC0, 0x1DFF, 6}, /* Combining Diacritical Marks. */
+ {0x1E00, 0x1EFF, 29}, /* Latin Extended Additional. */
+ {0x1F00, 0x1FFF, 30}, /* Greek Extended. */
+ {0x2000, 0x206F, 31}, /* General Punctuation. */
+ {0x2070, 0x209F, 32}, /* Superscripts And Subscripts. */
+ {0x20A0, 0x20CF, 33}, /* Currency Symbols. */
+ {0x20D0, 0x20FF, 34}, /* Combining Diacritical Marks For Symbols. */
+ {0x2100, 0x214F, 35}, /* Letterlike Symbols. */
+ {0x2150, 0x218F, 36}, /* Number Forms. */
+ {0x2190, 0x21FF, 37}, /* Arrows. */
+ {0x2200, 0x22FF, 38}, /* Mathematical Operators. */
+ {0x2300, 0x23FF, 39}, /* Miscellaneous Technical. */
+ {0x2400, 0x243F, 40}, /* Control Pictures. */
+ {0x2440, 0x245F, 41}, /* Optical Character Recognition. */
+ {0x2460, 0x24FF, 42}, /* Enclosed Alphanumerics. */
+ {0x2500, 0x257F, 43}, /* Box Drawing. */
+ {0x2580, 0x259F, 44}, /* Block Elements. */
+ {0x25A0, 0x25FF, 45}, /* Geometric Shapes. */
+ {0x2600, 0x26FF, 46}, /* Miscellaneous Symbols. */
+ {0x2700, 0x27BF, 47}, /* Dingbats. */
+ {0x27C0, 0x27EF, 38}, /* Mathematical Operators. */
+ {0x27F0, 0x27FF, 37}, /* Arrows. */
+ {0x2800, 0x28FF, 82}, /* Braille. */
+ {0x2900, 0x297F, 37}, /* Arrows. */
+ {0x2980, 0x2AFF, 38}, /* Mathematical Operators. */
+ {0x2B00, 0x2BFF, 37}, /* Arrows. */
+ {0x2C00, 0x2C5F, 97}, /* Glagolitic. */
+ {0x2C60, 0x2C7F, 29}, /* Latin Extended Additional. */
+ {0x2C80, 0x2CFF, 8}, /* Coptic. */
+ {0x2D00, 0x2D2F, 26}, /* Georgian. */
+ {0x2D30, 0x2D7F, 98}, /* Tifinagh. */
+ {0x2D80, 0x2DDF, 75}, /* Ethiopic. */
+ {0x2DE0, 0x2DFF, 9}, /* Cyrillic. */
+ {0x2E00, 0x2E7F, 31}, /* General Punctuation. */
+ {0x2E80, 0x2FFF, 59}, /* CJK Unified Ideographs. */
+ {0x3000, 0x303F, 48}, /* CJK Symbols And Punctuation. */
+ {0x3040, 0x309F, 49}, /* Hiragana. */
+ {0x30A0, 0x30FF, 50}, /* Katakana. */
+ {0x3100, 0x312F, 51}, /* Bopomofo. */
+ {0x3130, 0x318F, 52}, /* Hangul Compatibility Jamo. */
+ {0x3190, 0x319F, 59}, /* CJK Unified Ideographs. */
+ {0x31A0, 0x31BF, 51}, /* Bopomofo. */
+ {0x31C0, 0x31EF, 59}, /* CJK Unified Ideographs. */
+ {0x31F0, 0x31FF, 50}, /* Katakana. */
+ {0x3200, 0x32FF, 54}, /* Enclosed CJK Letters And Months. */
+ {0x3300, 0x33FF, 55}, /* CJK Compatibility. */
+ {0x3400, 0x4DBF, 59}, /* CJK Unified Ideographs. */
+ {0x4DC0, 0x4DFF, 99}, /* Yijing. */
+ {0x4E00, 0x9FFF, 59}, /* CJK Unified Ideographs. */
+ {0xA000, 0xA4CF, 83}, /* Yi. */
+ {0xA4D0, 0xA4FF, -1}, /* Lisu. */
+ {0xA500, 0xA63F, 12}, /* Vai. */
+ {0xA640, 0xA69F, 9}, /* Cyrillic. */
+ {0xA6A0, 0xA6FF, -1}, /* Bamum. */
+ {0xA700, 0xA71F, 5}, /* Spacing Modifier Letters. */
+ {0xA720, 0xA7FF, 29}, /* Latin Extended Additional. */
+ {0xA800, 0xA82F, 100}, /* Syloti Nagri. */
+ {0xA840, 0xA87F, 53}, /* Phags-pa. */
+ {0xA880, 0xA8DF, 115}, /* Saurashtra. */
+ {0xA900, 0xA92F, 116}, /* Kayah Li. */
+ {0xA930, 0xA95F, 117}, /* Rejang. */
+ {0xA960, 0xA97F, 56}, /* Hangul Syllables. */
+ {0xA980, 0xA9DF, -1}, /* Javanese. */
+ {0xA9E0, 0xA9FF, 74}, /* Myanmar. */
+ {0xAA00, 0xAA5F, 118}, /* Cham. */
+ {0xAA60, 0xAA7F, 74}, /* Myanmar. */
+ {0xAA80, 0xAADF, -1}, /* Tai Viet. */
+ {0xAAE0, 0xAAFF, -1}, /* Meetei Mayek. */
+ {0xAB00, 0xAB2F, 75}, /* Ethiopic. */
+ {0xAB70, 0xABBF, 76}, /* Cherokee. */
+ {0xABC0, 0xABFF, -1}, /* Meetei Mayek. */
+ {0xAC00, 0xD7AF, 56}, /* Hangul Syllables. */
+ {0xD800, 0xDFFF, 57}, /* Non-Plane 0. */
+ {0xE000, 0xF6FF, 60}, /* Private Use Area. */
+ {0xE700, 0xEFFF, -1}, /* MS Wingdings. */
+ {0xF000, 0xF8FF, -1}, /* MS Symbols. */
+ {0xF900, 0xFAFF, 61}, /* CJK Compatibility Ideographs. */
+ {0xFB00, 0xFB4F, 62}, /* Alphabetic Presentation Forms. */
+ {0xFB50, 0xFDFF, 63}, /* Arabic Presentation Forms-A. */
+ {0xFE00, 0xFE0F, 91}, /* Variation Selectors. */
+ {0xFE10, 0xFE1F, 65}, /* CJK Compatibility Forms. */
+ {0xFE20, 0xFE2F, 64}, /* Combining Half Marks. */
+ {0xFE30, 0xFE4F, 65}, /* CJK Compatibility Forms. */
+ {0xFE50, 0xFE6F, 66}, /* Small Form Variants. */
+ {0xFE70, 0xFEFF, 67}, /* Arabic Presentation Forms-B. */
+ {0xFF00, 0xFFEF, 68}, /* Halfwidth And Fullwidth Forms. */
+ {0xFFF0, 0xFFFF, 69}, /* Specials. */
+ {0x10000, 0x1013F, 101}, /* Linear B. */
+ {0x10140, 0x1018F, 102}, /* Ancient Greek Numbers. */
+ {0x10190, 0x101CF, 119}, /* Ancient Symbols. */
+ {0x101D0, 0x101FF, 120}, /* Phaistos Disc. */
+ {0x10280, 0x1029F, 121}, /* Lycian. */
+ {0x102A0, 0x102DF, 121}, /* Carian. */
+ {0x10300, 0x1032F, 85}, /* Old Italic. */
+ {0x10330, 0x1034F, 86}, /* Gothic. */
+ {0x10350, 0x1037F, -1}, /* Old Permic. */
+ {0x10380, 0x1039F, 103}, /* Ugaritic. */
+ {0x103A0, 0x103DF, 104}, /* Old Persian. */
+ {0x10400, 0x1044F, 87}, /* Deseret. */
+ {0x10450, 0x1047F, 105}, /* Shavian. */
+ {0x10480, 0x104AF, 106}, /* Osmanya. */
+ {0x104B0, 0x104FF, -1}, /* Osage. */
+ {0x10500, 0x1052F, -1}, /* Elbasan. */
+ {0x10530, 0x1056F, -1}, /* Caucasian Albanian. */
+ {0x10570, 0x105BF, -1}, /* Vithkuqi. */
+ {0x10600, 0x1077F, -1}, /* Linear A. */
+ {0x10780, 0x107BF, 3}, /* Latin Extended-B. */
+ {0x10800, 0x1083F, 107}, /* Cypriot Syllabary. */
+ {0x10840, 0x1085F, -1}, /* Imperial Aramaic. */
+ {0x10860, 0x1087F, -1}, /* Palmyrene. */
+ {0x10880, 0x108AF, -1}, /* Nabataean. */
+ {0x108E0, 0x108FF, -1}, /* Hatran. */
+ {0x10900, 0x1091F, 58}, /* Phoenician. */
+ {0x10920, 0x1093F, 121}, /* Lydian. */
+ {0x10980, 0x1099F, -1}, /* Meroitic Hieroglyphs. */
+ {0x109A0, 0x109FF, -1}, /* Meroitic Cursive. */
+ {0x10A00, 0x10A5F, 108}, /* Kharoshthi. */
+ {0x10A60, 0x10A7F, -1}, /* Old South Arabian. */
+ {0x10A80, 0x10A9F, -1}, /* Old North Arabian. */
+ {0x10AC0, 0x10AFF, -1}, /* Manichaean. */
+ {0x10B00, 0x10B3F, -1}, /* Avestan. */
+ {0x10B40, 0x10B5F, -1}, /* Inscriptional Parthian. */
+ {0x10B60, 0x10B7F, -1}, /* Inscriptional Pahlavi. */
+ {0x10B80, 0x10BAF, -1}, /* Psalter Pahlavi. */
+ {0x10C00, 0x10C4F, -1}, /* Old Turkic. */
+ {0x10C80, 0x10CFF, -1}, /* Old Hungarian. */
+ {0x10D00, 0x10D3F, -1}, /* Hanifi Rohingya. */
+ {0x108E0, 0x10E7F, -1}, /* Rumi Numeral Symbols. */
+ {0x10E80, 0x10EBF, -1}, /* Yezidi. */
+ {0x10F00, 0x10F2F, -1}, /* Old Sogdian. */
+ {0x10F30, 0x10F6F, -1}, /* Sogdian. */
+ {0x10F70, 0x10FAF, -1}, /* Old Uyghur. */
+ {0x10FB0, 0x10FDF, -1}, /* Chorasmian. */
+ {0x10FE0, 0x10FFF, -1}, /* Elymaic. */
+ {0x11000, 0x1107F, -1}, /* Brahmi. */
+ {0x11080, 0x110CF, -1}, /* Kaithi. */
+ {0x110D0, 0x110FF, -1}, /* Sora Sompeng. */
+ {0x11100, 0x1114F, -1}, /* Chakma. */
+ {0x11150, 0x1117F, -1}, /* Mahajani. */
+ {0x11180, 0x111DF, -1}, /* Sharada. */
+ {0x111E0, 0x111FF, -1}, /* Sinhala Archaic Numbers. */
+ {0x11200, 0x1124F, -1}, /* Khojki. */
+ {0x11280, 0x112AF, -1}, /* Multani. */
+ {0x112B0, 0x112FF, -1}, /* Khudawadi. */
+ {0x11300, 0x1137F, -1}, /* Grantha. */
+ {0x11400, 0x1147F, -1}, /* Newa. */
+ {0x11480, 0x114DF, -1}, /* Tirhuta. */
+ {0x11580, 0x115FF, -1}, /* Siddham. */
+ {0x11600, 0x1165F, -1}, /* Modi. */
+ {0x11660, 0x1167F, 81}, /* Mongolian. */
+ {0x11680, 0x116CF, -1}, /* Takri. */
+ {0x11700, 0x1174F, -1}, /* Ahom. */
+ {0x11800, 0x1184F, -1}, /* Dogra. */
+ {0x118A0, 0x118FF, -1}, /* Warang Citi. */
+ {0x11900, 0x1195F, -1}, /* Dives Akuru. */
+ {0x119A0, 0x119FF, -1}, /* Nandinagari. */
+ {0x11A00, 0x11A4F, -1}, /* Zanabazar Square. */
+ {0x11A50, 0x11AAF, -1}, /* Soyombo. */
+ {0x11AB0, 0x11ABF, 77}, /* Canadian Aboriginal Syllabics. */
+ {0x11AC0, 0x11AFF, -1}, /* Pau Cin Hau. */
+ {0x11C00, 0x11C6F, -1}, /* Bhaiksuki. */
+ {0x11C70, 0x11CBF, -1}, /* Marchen. */
+ {0x11D00, 0x11D5F, -1}, /* Masaram Gondi. */
+ {0x11D60, 0x11DAF, -1}, /* Gunjala Gondi. */
+ {0x11EE0, 0x11EFF, -1}, /* Makasar. */
+ {0x11FB0, 0x11FBF, -1}, /* Lisu. */
+ {0x11FC0, 0x11FFF, 20}, /* Tamil. */
+ {0x12000, 0x1254F, 110}, /* Cuneiform. */
+ {0x12F90, 0x12FFF, -1}, /* Cypro-Minoan. */
+ {0x13000, 0x1343F, -1}, /* Egyptian Hieroglyphs. */
+ {0x14400, 0x1467F, -1}, /* Anatolian Hieroglyphs. */
+ {0x16800, 0x16A3F, -1}, /* Bamum. */
+ {0x16A40, 0x16A6F, -1}, /* Mro. */
+ {0x16A70, 0x16ACF, -1}, /* Tangsa. */
+ {0x16AD0, 0x16AFF, -1}, /* Bassa Vah. */
+ {0x16B00, 0x16B8F, -1}, /* Pahawh Hmong. */
+ {0x16E40, 0x16E9F, -1}, /* Medefaidrin. */
+ {0x16F00, 0x16F9F, -1}, /* Miao. */
+ {0x16FE0, 0x16FFF, -1}, /* Ideographic Symbols. */
+ {0x17000, 0x18AFF, -1}, /* Tangut. */
+ {0x1B170, 0x1B2FF, -1}, /* Nushu. */
+ {0x1BC00, 0x1BC9F, -1}, /* Duployan. */
+ {0x1D000, 0x1D24F, 88}, /* Musical Symbols. */
+ {0x1D2E0, 0x1D2FF, -1}, /* Mayan Numerals. */
+ {0x1D300, 0x1D35F, 109}, /* Tai Xuan Jing. */
+ {0x1D360, 0x1D37F, 111}, /* Counting Rod Numerals. */
+ {0x1D400, 0x1D7FF, 89}, /* Mathematical Alphanumeric Symbols. */
+ {0x1E2C0, 0x1E2FF, -1}, /* Wancho. */
+ {0x1E800, 0x1E8DF, -1}, /* Mende Kikakui. */
+ {0x1E900, 0x1E95F, -1}, /* Adlam. */
+ {0x1EC70, 0x1ECBF, -1}, /* Indic Siyaq Numbers. */
+ {0x1F000, 0x1F02F, 122}, /* Mahjong Tiles. */
+ {0x1F030, 0x1F09F, 122}, /* Domino Tiles. */
+ {0x1F600, 0x1F64F, -1}, /* Emoticons. */
+ {0x20000, 0x2A6DF, 59}, /* CJK Unified Ideographs. */
+ {0x2F800, 0x2FA1F, 61}, /* CJK Compatibility Ideographs. */
+ {0xE0000, 0xE007F, 92}, /* Tags. */
+ {0xE0100, 0xE01EF, 91}, /* Variation Selectors. */
+ {0xF0000, 0x10FFFD, 90}}; /* Private Use Supplementary. */
+
+/* Find a unicode block that a charcode belongs to. */
+static eUnicodeBlock *blf_charcode_to_unicode_block(uint charcode)
+{
+ if (charcode < 0x80) {
+ /* Shortcut to Basic Latin. */
+ return &unicode_blocks[0];
+ }
+
+ /* Binary search for other blocks. */
+
+ int min = 0;
+ int max = ARRAY_SIZE(unicode_blocks) - 1;
+ int mid;
+
+ if (charcode < unicode_blocks[0].first || charcode > unicode_blocks[max].last) {
+ return NULL;
+ }
+
+ while (max >= min) {
+ mid = (min + max) / 2;
+ if (charcode > unicode_blocks[mid].last) {
+ min = mid + 1;
+ }
+ else if (charcode < unicode_blocks[mid].first) {
+ max = mid - 1;
+ }
+ else {
+ return &unicode_blocks[mid];
+ }
+ }
+
+ return NULL;
+}
+
+static int blf_charcode_to_coverage_bit(uint charcode)
+{
+ int coverage_bit = -1;
+ eUnicodeBlock *block = blf_charcode_to_unicode_block(charcode);
+ if (block) {
+ coverage_bit = block->coverage_bit;
+ }
+
+ if (coverage_bit < 0 && charcode > 0xFFFF) {
+ /* No coverage bit, but OpenType specs v.1.3+ says bit 57 implies that there
+ * are codepoints supported beyond the BMP, so only check fonts with this set. */
+ coverage_bit = 57;
+ }
+
+ return coverage_bit;
+}
+
+static bool blf_font_has_coverage_bit(FontBLF *font, int coverage_bit)
+{
+ if (coverage_bit < 0) {
+ return false;
+ }
+ return (font->UnicodeRanges[(uint)coverage_bit >> 5] & (1u << ((uint)coverage_bit % 32)));
+}
+
/**
* Return a glyph index from `charcode`. Not found returns zero, which is a valid
* printable character (`.notdef` or `tofu`). Font is allowed to change here.
@@ -229,8 +559,42 @@ static GlyphBLF *blf_glyph_cache_add_glyph(
static FT_UInt blf_glyph_index_from_charcode(FontBLF **font, const uint charcode)
{
FT_UInt glyph_index = FT_Get_Char_Index((*font)->face, charcode);
- /* TODO: If not found in this font, check others, update font pointer. */
- return glyph_index;
+ if (glyph_index) {
+ return glyph_index;
+ }
+
+ /* Not found in main font, so look in the others. */
+ FontBLF *last_resort = NULL;
+ int coverage_bit = blf_charcode_to_coverage_bit(charcode);
+ for (int i = 0; i < BLF_MAX_FONT; i++) {
+ FontBLF *f = global_font[i];
+ if (!f || f == *font || !(f->flags & BLF_DEFAULT)) {
+ continue;
+ }
+
+ if (f->flags & BLF_LAST_RESORT) {
+ last_resort = f;
+ continue;
+ }
+ if (coverage_bit < 0 || blf_font_has_coverage_bit(f, coverage_bit)) {
+ glyph_index = FT_Get_Char_Index(f->face, charcode);
+ if (glyph_index) {
+ *font = f;
+ return glyph_index;
+ }
+ }
+ }
+
+ /* Not found in the stack, return from Last Resort if there is one. */
+ if (last_resort) {
+ glyph_index = FT_Get_Char_Index(last_resort->face, charcode);
+ if (glyph_index) {
+ *font = last_resort;
+ return glyph_index;
+ }
+ }
+
+ return 0;
}
/**
@@ -377,24 +741,24 @@ static bool UNUSED_FUNCTION(blf_glyph_transform_width)(FT_GlyphSlot glyph, float
/**
* Transform glyph to fit nicely within a fixed column width.
*/
-static bool UNUSED_FUNCTION(blf_glyph_transform_monospace)(FT_GlyphSlot glyph, int width)
+static bool blf_glyph_transform_monospace(FT_GlyphSlot glyph, int width)
{
if (glyph->format == FT_GLYPH_FORMAT_OUTLINE) {
- int gwidth = (int)(glyph->linearHoriAdvance >> 16);
- if (gwidth > width) {
- float scale = (float)width / (float)gwidth;
+ FT_Fixed current = glyph->linearHoriAdvance;
+ FT_Fixed target = width << 16; /* Do math in 16.16 values. */
+ if (target < current) {
+ const FT_Pos embolden = (FT_Pos)((current - target) >> 13);
+ /* Horizontally widen strokes to counteract narrowing. */
+ FT_Outline_EmboldenXY(&glyph->outline, embolden, 0);
+ const float scale = (float)(target - (embolden << 9)) / (float)current;
FT_Matrix matrix = {to_16dot16(scale), 0, 0, to_16dot16(1)};
- /* Narrowing all points also thins vertical strokes. */
FT_Outline_Transform(&glyph->outline, &matrix);
- const FT_Pos extra_x = (int)((float)(gwidth - width) * 5.65f);
- /* Horizontally widen strokes to counteract narrowing. */
- FT_Outline_EmboldenXY(&glyph->outline, extra_x, 0);
}
- else if (gwidth < width) {
- /* Narrow glyphs only need to be centered. */
- int nudge = (width - gwidth) / 2;
- FT_Outline_Translate(&glyph->outline, (FT_Pos)nudge * 64, 0);
+ else if (target > current) {
+ /* Center narrow glyphs. */
+ FT_Outline_Translate(&glyph->outline, (FT_Pos)((target - current) >> 11), 0);
}
+ glyph->advance.x = width << 6;
return true;
}
return false;
@@ -411,7 +775,9 @@ static bool UNUSED_FUNCTION(blf_glyph_transform_monospace)(FT_GlyphSlot glyph, i
*/
static FT_GlyphSlot blf_glyph_render(FontBLF *settings_font,
FontBLF *glyph_font,
- FT_UInt glyph_index)
+ FT_UInt glyph_index,
+ uint charcode,
+ int fixed_width)
{
if (glyph_font != settings_font) {
FT_Set_Char_Size(glyph_font->face,
@@ -428,6 +794,10 @@ static FT_GlyphSlot blf_glyph_render(FontBLF *settings_font,
return NULL;
}
+ if ((settings_font->flags & BLF_MONOSPACED) && (settings_font != glyph_font)) {
+ blf_glyph_transform_monospace(glyph, BLI_wcwidth((char32_t)charcode) * fixed_width);
+ }
+
if ((settings_font->flags & BLF_ITALIC) != 0) {
/* 37.5% of maximum rightward slant results in 6 degree slope, matching italic
* version (`DejaVuSans-Oblique.ttf`) of our current font. But a nice median when
@@ -466,7 +836,8 @@ GlyphBLF *blf_glyph_ensure(FontBLF *font, GlyphCacheBLF *gc, uint charcode)
* renderer uses a shared buffer internally. */
BLI_spin_lock(font_with_glyph->ft_lib_mutex);
- FT_GlyphSlot glyph = blf_glyph_render(font, font_with_glyph, glyph_index);
+ FT_GlyphSlot glyph = blf_glyph_render(
+ font, font_with_glyph, glyph_index, charcode, gc->fixed_width);
if (glyph) {
/* Save this glyph in the initial font's cache. */
diff --git a/source/blender/blenfont/intern/blf_internal.h b/source/blender/blenfont/intern/blf_internal.h
index 7754f960043..84037ff4bd0 100644
--- a/source/blender/blenfont/intern/blf_internal.h
+++ b/source/blender/blenfont/intern/blf_internal.h
@@ -14,6 +14,12 @@ struct ResultBLF;
struct rctf;
struct rcti;
+/* Max number of fonts in memory. Take care that every font has a glyph cache per size/dpi,
+ * so we don't need load the same font with different size, just load one and call BLF_size. */
+#define BLF_MAX_FONT 32
+
+extern struct FontBLF *global_font[BLF_MAX_FONT];
+
void blf_batch_draw_begin(struct FontBLF *font);
void blf_batch_draw(void);
diff --git a/source/blender/blenfont/intern/blf_internal_types.h b/source/blender/blenfont/intern/blf_internal_types.h
index 62bce36dda0..998093dae70 100644
--- a/source/blender/blenfont/intern/blf_internal_types.h
+++ b/source/blender/blenfont/intern/blf_internal_types.h
@@ -123,7 +123,7 @@ typedef struct GlyphCacheBLF {
/* font size. */
float size;
- /* and dpi. */
+ /* and DPI. */
unsigned int dpi;
bool bold;
@@ -226,6 +226,11 @@ typedef struct FontBLF {
/** File-path or NULL. */
char *filepath;
+ /* Copied from the SFNT OS/2 table. Bit flags for unicode blocks and ranges
+ * considered "functional". Cached here because face might not always exist.
+ * See: https://docs.microsoft.com/en-us/typography/opentype/spec/os2#ur */
+ uint UnicodeRanges[4];
+
/* aspect ratio or scale. */
float aspect[3];
@@ -264,7 +269,7 @@ typedef struct FontBLF {
/* the width to wrap the text, see BLF_WORD_WRAP */
int wrap_width;
- /* font dpi (default 72). */
+ /* Font DPI (default 72). */
unsigned int dpi;
/* font size. */
@@ -276,7 +281,8 @@ typedef struct FontBLF {
/* font options. */
int flags;
- /* List of glyph caches (GlyphCacheBLF) for this font for size, dpi, bold, italic.
+ /**
+ * List of glyph caches (#GlyphCacheBLF) for this font for size, DPI, bold, italic.
* Use blf_glyph_cache_acquire(font) and blf_glyph_cache_release(font) to access cache!
*/
ListBase cache;
diff --git a/source/blender/blenkernel/BKE_DerivedMesh.h b/source/blender/blenkernel/BKE_DerivedMesh.h
index fea5f515db8..4274ca97fd1 100644
--- a/source/blender/blenkernel/BKE_DerivedMesh.h
+++ b/source/blender/blenkernel/BKE_DerivedMesh.h
@@ -46,14 +46,9 @@
* as it is and stick with using BMesh and CDDM.
*/
-#include "DNA_customdata_types.h"
-#include "DNA_defs.h"
-#include "DNA_meshdata_types.h"
-
#include "BLI_compiler_attrs.h"
-#include "BKE_bvhutils.h"
-#include "BKE_customdata.h"
+#include "DNA_customdata_types.h"
#ifdef __cplusplus
extern "C" {
@@ -73,8 +68,8 @@ struct Object;
struct Scene;
/*
- * NOTE: all mface interfaces now officially operate on tessellated data.
- * Also, the mface origindex layer indexes mpolys, not mfaces.
+ * NOTE: all #MFace interfaces now officially operate on tessellated data.
+ * Also, the #MFace orig-index layer indexes #MPoly, not #MFace.
*/
/* keep in sync with MFace/MPoly types */
@@ -125,7 +120,6 @@ struct DerivedMesh {
/* Also called in Editmode */
int (*getNumVerts)(DerivedMesh *dm);
int (*getNumEdges)(DerivedMesh *dm);
- int (*getNumTessFaces)(DerivedMesh *dm);
int (*getNumLoops)(DerivedMesh *dm);
int (*getNumPolys)(DerivedMesh *dm);
@@ -233,15 +227,6 @@ bool DM_release(DerivedMesh *dm);
*/
void DM_set_only_copy(DerivedMesh *dm, const struct CustomData_MeshMasks *mask);
-/* Adds a vertex/edge/face custom data layer to a DerivedMesh, optionally
- * backed by an external data array
- * alloctype defines how the layer is allocated or copied, and how it is
- * freed, see BKE_customdata.h for the different options. */
-
-void DM_add_vert_layer(struct DerivedMesh *dm, int type, eCDAllocType alloctype, void *layer);
-void DM_add_edge_layer(struct DerivedMesh *dm, int type, eCDAllocType alloctype, void *layer);
-void DM_add_poly_layer(struct DerivedMesh *dm, int type, eCDAllocType alloctype, void *layer);
-
/* -------------------------------------------------------------------- */
/** \name Custom Data Layer Access Functions
*
diff --git a/source/blender/blenkernel/BKE_attribute.h b/source/blender/blenkernel/BKE_attribute.h
index f3a29736bc8..13eefd27bec 100644
--- a/source/blender/blenkernel/BKE_attribute.h
+++ b/source/blender/blenkernel/BKE_attribute.h
@@ -22,7 +22,7 @@ struct ID;
struct ReportList;
/** #Attribute.domain */
-typedef enum AttributeDomain {
+typedef enum eAttrDomain {
ATTR_DOMAIN_AUTO = -1, /* Use for nodes to choose automatically based on other data. */
ATTR_DOMAIN_POINT = 0, /* Mesh, Curve or Point Cloud Point */
ATTR_DOMAIN_EDGE = 1, /* Mesh Edge */
@@ -30,52 +30,64 @@ typedef enum AttributeDomain {
ATTR_DOMAIN_CORNER = 3, /* Mesh Corner */
ATTR_DOMAIN_CURVE = 4, /* A single curve in a larger curve data-block */
ATTR_DOMAIN_INSTANCE = 5, /* Instance */
+} eAttrDomain;
+#define ATTR_DOMAIN_NUM 6
- ATTR_DOMAIN_NUM
-} AttributeDomain;
-
-typedef enum AttributeDomainMask {
+typedef enum eAttrDomainMask {
ATTR_DOMAIN_MASK_POINT = (1 << 0),
ATTR_DOMAIN_MASK_EDGE = (1 << 1),
ATTR_DOMAIN_MASK_FACE = (1 << 2),
ATTR_DOMAIN_MASK_CORNER = (1 << 3),
ATTR_DOMAIN_MASK_CURVE = (1 << 4),
ATTR_DOMAIN_MASK_ALL = (1 << 5) - 1
-} AttributeDomainMask;
+} eAttrDomainMask;
+
+#define ATTR_DOMAIN_AS_MASK(domain) ((eAttrDomainMask)((1 << (int)(domain))))
/* All domains that support color attributes. */
#define ATTR_DOMAIN_MASK_COLOR \
- ((AttributeDomainMask)((ATTR_DOMAIN_MASK_POINT | ATTR_DOMAIN_MASK_CORNER)))
+ ((eAttrDomainMask)((ATTR_DOMAIN_MASK_POINT | ATTR_DOMAIN_MASK_CORNER)))
/* Attributes. */
-bool BKE_id_attributes_supported(struct ID *id);
+bool BKE_id_attributes_supported(const struct ID *id);
+bool BKE_attribute_allow_procedural_access(const char *attribute_name);
/**
* Create a new attribute layer.
*/
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 ID *id, const char *name, int type, eAttrDomain domain, struct ReportList *reports);
+bool BKE_id_attribute_remove(struct ID *id, const char *name, struct ReportList *reports);
+
+/**
+ * Creates a duplicate attribute layer.
+ */
+struct CustomDataLayer *BKE_id_attribute_duplicate(struct ID *id,
+ const char *name,
+ struct ReportList *reports);
struct CustomDataLayer *BKE_id_attribute_find(const struct ID *id,
const char *name,
int type,
- AttributeDomain domain);
+ eAttrDomain domain);
+
+struct CustomDataLayer *BKE_id_attribute_search(struct ID *id,
+ const char *name,
+ eCustomDataMask type,
+ eAttrDomainMask domain_mask);
-AttributeDomain BKE_id_attribute_domain(const struct ID *id, const struct CustomDataLayer *layer);
+eAttrDomain BKE_id_attribute_domain(const struct ID *id, const struct CustomDataLayer *layer);
int BKE_id_attribute_data_length(struct ID *id, struct CustomDataLayer *layer);
-bool BKE_id_attribute_required(struct ID *id, struct CustomDataLayer *layer);
+bool BKE_id_attribute_required(const struct ID *id, const char *name);
bool BKE_id_attribute_rename(struct ID *id,
- struct CustomDataLayer *layer,
+ const char *old_name,
const char *new_name,
struct ReportList *reports);
int BKE_id_attributes_length(const struct ID *id,
- AttributeDomainMask domain_mask,
- CustomDataMask mask);
+ eAttrDomainMask domain_mask,
+ eCustomDataMask mask);
struct CustomDataLayer *BKE_id_attributes_active_get(struct ID *id);
void BKE_id_attributes_active_set(struct ID *id, struct CustomDataLayer *layer);
@@ -84,24 +96,24 @@ int *BKE_id_attributes_active_index_p(struct ID *id);
CustomData *BKE_id_attributes_iterator_next_domain(struct ID *id, struct CustomDataLayer *layers);
CustomDataLayer *BKE_id_attribute_from_index(struct ID *id,
int lookup_index,
- AttributeDomainMask domain_mask,
- CustomDataMask layer_mask);
+ eAttrDomainMask domain_mask,
+ eCustomDataMask layer_mask);
/** Layer is allowed to be nullptr; if so -1 (layer not found) will be returned. */
int BKE_id_attribute_to_index(const struct ID *id,
const CustomDataLayer *layer,
- AttributeDomainMask domain_mask,
- CustomDataMask layer_mask);
+ eAttrDomainMask domain_mask,
+ eCustomDataMask layer_mask);
struct CustomDataLayer *BKE_id_attribute_subset_active_get(const struct ID *id,
int active_flag,
- AttributeDomainMask domain_mask,
- CustomDataMask mask);
+ eAttrDomainMask domain_mask,
+ eCustomDataMask mask);
void BKE_id_attribute_subset_active_set(struct ID *id,
struct CustomDataLayer *layer,
int active_flag,
- AttributeDomainMask domain_mask,
- CustomDataMask mask);
+ eAttrDomainMask domain_mask,
+ eCustomDataMask mask);
/**
* Sets up a temporary ID with arbitrary CustomData domains. `r_id` will
diff --git a/source/blender/blenkernel/BKE_attribute_access.hh b/source/blender/blenkernel/BKE_attribute_access.hh
index 8d449a124ec..fef91d6f75d 100644
--- a/source/blender/blenkernel/BKE_attribute_access.hh
+++ b/source/blender/blenkernel/BKE_attribute_access.hh
@@ -32,7 +32,7 @@
* 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
+ * 2. Domain interpolation: When retrieving an attribute, a domain (#eAttrDomain) 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`.
@@ -77,6 +77,9 @@ class AttributeIDRef {
friend std::ostream &operator<<(std::ostream &stream, const AttributeIDRef &attribute_id);
};
+bool allow_procedural_attribute_access(StringRef attribute_name);
+extern const char *no_procedural_access_message;
+
} // namespace blender::bke
/**
@@ -85,8 +88,8 @@ class AttributeIDRef {
* stored (uv map, vertex group, ...).
*/
struct AttributeMetaData {
- AttributeDomain domain;
- CustomDataType data_type;
+ eAttrDomain domain;
+ eCustomDataType data_type;
constexpr friend bool operator==(AttributeMetaData a, AttributeMetaData b)
{
@@ -95,8 +98,8 @@ struct AttributeMetaData {
};
struct AttributeKind {
- AttributeDomain domain;
- CustomDataType data_type;
+ eAttrDomain domain;
+ eCustomDataType data_type;
};
/**
@@ -164,12 +167,12 @@ using AttributeForeachCallback = blender::FunctionRef<bool(
namespace blender::bke {
-CustomDataType attribute_data_type_highest_complexity(Span<CustomDataType> data_types);
+eCustomDataType attribute_data_type_highest_complexity(Span<eCustomDataType> data_types);
/**
* Domains with a higher "information density" have a higher priority,
* in order to choose a domain that will not lose data through domain conversion.
*/
-AttributeDomain attribute_domain_highest_priority(Span<AttributeDomain> domains);
+eAttrDomain attribute_domain_highest_priority(Span<eAttrDomain> domains);
/**
* Used when looking up a "plain attribute" based on a name for reading from it.
@@ -178,7 +181,7 @@ struct ReadAttributeLookup {
/* The virtual array that is used to read from this attribute. */
GVArray varray;
/* Domain the attribute lives on in the geometry. */
- AttributeDomain domain;
+ eAttrDomain domain;
/* Convenience function to check if the attribute has been found. */
operator bool() const
@@ -194,7 +197,7 @@ struct WriteAttributeLookup {
/** The virtual array that is used to read from and write to the attribute. */
GVMutableArray varray;
/** Domain the attributes lives on in the geometry component. */
- AttributeDomain domain;
+ eAttrDomain domain;
/**
* 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.
@@ -229,7 +232,7 @@ class OutputAttribute {
private:
GVMutableArray varray_;
- AttributeDomain domain_ = ATTR_DOMAIN_AUTO;
+ eAttrDomain domain_ = ATTR_DOMAIN_AUTO;
SaveFn save_;
std::unique_ptr<GVMutableArray_GSpan> optional_span_varray_;
bool ignore_old_values_ = false;
@@ -238,10 +241,7 @@ class OutputAttribute {
public:
OutputAttribute();
OutputAttribute(OutputAttribute &&other);
- OutputAttribute(GVMutableArray varray,
- AttributeDomain domain,
- SaveFn save,
- bool ignore_old_values);
+ OutputAttribute(GVMutableArray varray, eAttrDomain domain, SaveFn save, bool ignore_old_values);
~OutputAttribute();
@@ -250,9 +250,9 @@ class OutputAttribute {
GVMutableArray &operator*();
GVMutableArray *operator->();
GVMutableArray &varray();
- AttributeDomain domain() const;
+ eAttrDomain domain() const;
const CPPType &cpp_type() const;
- CustomDataType custom_data_type() const;
+ eCustomDataType custom_data_type() const;
GMutableSpan as_span();
template<typename T> MutableSpan<T> as_span();
@@ -310,7 +310,7 @@ template<typename T> class OutputAttribute_Typed {
return varray_;
}
- AttributeDomain domain() const
+ eAttrDomain domain() const
{
return attribute_.domain();
}
@@ -320,7 +320,7 @@ template<typename T> class OutputAttribute_Typed {
return CPPType::get<T>();
}
- CustomDataType custom_data_type() const
+ eCustomDataType custom_data_type() const
{
return cpp_type_to_custom_data_type(this->cpp_type());
}
@@ -376,23 +376,21 @@ class CustomDataAttributes {
* value for the type will be used.
*/
blender::GVArray get_for_read(const AttributeIDRef &attribute_id,
- const CustomDataType data_type,
+ eCustomDataType data_type,
const void *default_value) const;
template<typename T>
blender::VArray<T> get_for_read(const AttributeIDRef &attribute_id, const T &default_value) const
{
const blender::CPPType &cpp_type = blender::CPPType::get<T>();
- const CustomDataType type = blender::bke::cpp_type_to_custom_data_type(cpp_type);
+ const eCustomDataType type = blender::bke::cpp_type_to_custom_data_type(cpp_type);
GVArray varray = this->get_for_read(attribute_id, type, &default_value);
return varray.typed<T>();
}
std::optional<blender::GMutableSpan> get_for_write(const AttributeIDRef &attribute_id);
- bool create(const AttributeIDRef &attribute_id, const CustomDataType data_type);
- bool create_by_move(const AttributeIDRef &attribute_id,
- const CustomDataType data_type,
- void *buffer);
+ bool create(const AttributeIDRef &attribute_id, eCustomDataType data_type);
+ bool create_by_move(const AttributeIDRef &attribute_id, eCustomDataType data_type, void *buffer);
bool remove(const AttributeIDRef &attribute_id);
/**
@@ -400,7 +398,7 @@ class CustomDataAttributes {
*/
void reorder(Span<AttributeIDRef> new_order);
- bool foreach_attribute(const AttributeForeachCallback callback, AttributeDomain domain) const;
+ bool foreach_attribute(const AttributeForeachCallback callback, eAttrDomain domain) const;
};
/* -------------------------------------------------------------------- */
@@ -488,7 +486,7 @@ inline OutputAttribute::OutputAttribute() = default;
inline OutputAttribute::OutputAttribute(OutputAttribute &&other) = default;
inline OutputAttribute::OutputAttribute(GVMutableArray varray,
- AttributeDomain domain,
+ eAttrDomain domain,
SaveFn save,
const bool ignore_old_values)
: varray_(std::move(varray)),
@@ -518,7 +516,7 @@ inline GVMutableArray &OutputAttribute::varray()
return varray_;
}
-inline AttributeDomain OutputAttribute::domain() const
+inline eAttrDomain OutputAttribute::domain() const
{
return domain_;
}
@@ -528,7 +526,7 @@ inline const CPPType &OutputAttribute::cpp_type() const
return varray_.type();
}
-inline CustomDataType OutputAttribute::custom_data_type() const
+inline eCustomDataType OutputAttribute::custom_data_type() const
{
return cpp_type_to_custom_data_type(this->cpp_type());
}
diff --git a/source/blender/blenkernel/BKE_attribute_math.hh b/source/blender/blenkernel/BKE_attribute_math.hh
index 4482e13e1cf..01c2ef988f2 100644
--- a/source/blender/blenkernel/BKE_attribute_math.hh
+++ b/source/blender/blenkernel/BKE_attribute_math.hh
@@ -39,7 +39,7 @@ inline void convert_to_static_type(const CPPType &cpp_type, const Func &func)
}
template<typename Func>
-inline void convert_to_static_type(const CustomDataType data_type, const Func &func)
+inline void convert_to_static_type(const eCustomDataType data_type, const Func &func)
{
const CPPType &cpp_type = *bke::custom_data_type_to_cpp_type(data_type);
convert_to_static_type(cpp_type, func);
@@ -56,7 +56,7 @@ template<typename T> T mix3(const float3 &weights, const T &v0, const T &v1, con
template<>
inline int8_t mix3(const float3 &weights, const int8_t &v0, const int8_t &v1, const int8_t &v2)
{
- return static_cast<int8_t>(weights.x * v0 + weights.y * v1 + weights.z * v2);
+ return static_cast<int8_t>(std::round(weights.x * v0 + weights.y * v1 + weights.z * v2));
}
template<> inline bool mix3(const float3 &weights, const bool &v0, const bool &v1, const bool &v2)
@@ -66,7 +66,7 @@ template<> inline bool mix3(const float3 &weights, const bool &v0, const bool &v
template<> inline int mix3(const float3 &weights, const int &v0, const int &v1, const int &v2)
{
- return static_cast<int>(weights.x * v0 + weights.y * v1 + weights.z * v2);
+ return static_cast<int>(std::round(weights.x * v0 + weights.y * v1 + weights.z * v2));
}
template<>
@@ -131,12 +131,12 @@ template<> inline bool mix2(const float factor, const bool &a, const bool &b)
template<> inline int8_t mix2(const float factor, const int8_t &a, const int8_t &b)
{
- return static_cast<int8_t>((1.0f - factor) * a + factor * b);
+ return static_cast<int8_t>(std::round((1.0f - factor) * a + factor * b));
}
template<> inline int mix2(const float factor, const int &a, const int &b)
{
- return static_cast<int>((1.0f - factor) * a + factor * b);
+ return static_cast<int>(std::round((1.0f - factor) * a + factor * b));
}
template<> inline float mix2(const float factor, const float &a, const float &b)
@@ -356,7 +356,7 @@ template<> struct DefaultMixerStruct<ColorGeometry4b> {
template<> struct DefaultMixerStruct<int> {
static int double_to_int(const double &value)
{
- return static_cast<int>(value);
+ return static_cast<int>(std::round(value));
}
/* Store interpolated ints in a double temporarily, so that weights are handled correctly. It
* uses double instead of float so that it is accurate for all 32 bit integers. */
@@ -375,7 +375,7 @@ template<> struct DefaultMixerStruct<bool> {
template<> struct DefaultMixerStruct<int8_t> {
static int8_t float_to_int8_t(const float &value)
{
- return static_cast<int8_t>(value);
+ return static_cast<int8_t>(std::round(value));
}
/* Store interpolated 8 bit integers in a float temporarily to increase accuracy. */
using type = SimpleMixerWithAccumulationType<int8_t, float, float_to_int8_t>;
diff --git a/source/blender/blenkernel/BKE_blender_version.h b/source/blender/blenkernel/BKE_blender_version.h
index ab13a2e85d0..04767a742ce 100644
--- a/source/blender/blenkernel/BKE_blender_version.h
+++ b/source/blender/blenkernel/BKE_blender_version.h
@@ -25,7 +25,7 @@ extern "C" {
/* Blender file format version. */
#define BLENDER_FILE_VERSION BLENDER_VERSION
-#define BLENDER_FILE_SUBVERSION 0
+#define BLENDER_FILE_SUBVERSION 3
/* Minimum Blender version that supports reading file written with the current
* version. Older Blender versions will test this and show a warning if the file
diff --git a/source/blender/blenkernel/BKE_bvhutils.h b/source/blender/blenkernel/BKE_bvhutils.h
index 8f33003fa9d..d22abd235df 100644
--- a/source/blender/blenkernel/BKE_bvhutils.h
+++ b/source/blender/blenkernel/BKE_bvhutils.h
@@ -157,25 +157,6 @@ BVHTree *bvhtree_from_mesh_edges_ex(struct BVHTreeFromMesh *data,
int tree_type,
int axis);
-/**
- * Builds a BVH-tree where nodes are the given tessellated faces
- * (NOTE: does not copy given mfaces!).
- * \param vert_allocated: if true, vert freeing will be done when freeing data.
- * \param face_allocated: if true, face freeing will be done when freeing data.
- * \param faces_mask: if not null, true elements give which faces to add to BVH-tree.
- * \param faces_num_active: if >= 0, number of active faces to add to BVH-tree
- * (else will be computed from mask).
- */
-BVHTree *bvhtree_from_mesh_faces_ex(struct BVHTreeFromMesh *data,
- const struct MVert *vert,
- const struct MFace *face,
- int numFaces,
- const BLI_bitmap *faces_mask,
- int faces_num_active,
- float epsilon,
- int tree_type,
- int axis);
-
BVHTree *bvhtree_from_editmesh_looptri(
BVHTreeFromEditMesh *data, struct BMEditMesh *em, float epsilon, int tree_type, int axis);
@@ -192,8 +173,6 @@ BVHTree *bvhtree_from_editmesh_looptri_ex(BVHTreeFromEditMesh *data,
/**
* Builds a BVH-tree where nodes are the looptri faces of the given mesh.
- *
- * \note for edit-mesh this is currently a duplicate of #bvhtree_from_mesh_faces_ex
*/
BVHTree *bvhtree_from_mesh_looptri_ex(struct BVHTreeFromMesh *data,
const struct MVert *vert,
diff --git a/source/blender/blenkernel/BKE_callbacks.h b/source/blender/blenkernel/BKE_callbacks.h
index 8b2af96a063..8c65214c78e 100644
--- a/source/blender/blenkernel/BKE_callbacks.h
+++ b/source/blender/blenkernel/BKE_callbacks.h
@@ -97,6 +97,12 @@ typedef enum {
BKE_CB_EVT_XR_SESSION_START_PRE,
BKE_CB_EVT_ANNOTATION_PRE,
BKE_CB_EVT_ANNOTATION_POST,
+ BKE_CB_EVT_OBJECT_BAKE_PRE,
+ BKE_CB_EVT_OBJECT_BAKE_COMPLETE,
+ BKE_CB_EVT_OBJECT_BAKE_CANCEL,
+ BKE_CB_EVT_COMPOSITE_PRE,
+ BKE_CB_EVT_COMPOSITE_POST,
+ BKE_CB_EVT_COMPOSITE_CANCEL,
BKE_CB_EVT_TOT,
} eCbEvent;
diff --git a/source/blender/blenkernel/BKE_camera.h b/source/blender/blenkernel/BKE_camera.h
index 57dc1e288dc..40df7acd066 100644
--- a/source/blender/blenkernel/BKE_camera.h
+++ b/source/blender/blenkernel/BKE_camera.h
@@ -79,7 +79,7 @@ typedef struct CameraParams {
void BKE_camera_params_init(CameraParams *params);
void BKE_camera_params_from_object(CameraParams *params, const struct Object *cam_ob);
void BKE_camera_params_from_view3d(CameraParams *params,
- struct Depsgraph *depsgraph,
+ const struct Depsgraph *depsgraph,
const struct View3D *v3d,
const struct RegionView3D *rv3d);
@@ -164,6 +164,14 @@ bool BKE_camera_multiview_spherical_stereo(const struct RenderData *rd,
/* Camera background image API */
struct CameraBGImage *BKE_camera_background_image_new(struct Camera *cam);
+/**
+ * Duplicate a background image, in a ID management compatible way.
+ *
+ * \param copy_flag The usual ID copying flags, see `LIB_ID_CREATE_`/`LIB_ID_COPY_` enums in
+ * `BKE_lib_id.h`.
+ */
+struct CameraBGImage *BKE_camera_background_image_copy(struct CameraBGImage *bgpic_src,
+ const int copy_flag);
void BKE_camera_background_image_remove(struct Camera *cam, struct CameraBGImage *bgpic);
void BKE_camera_background_image_clear(struct Camera *cam);
diff --git a/source/blender/blenkernel/BKE_collection.h b/source/blender/blenkernel/BKE_collection.h
index a3bbcc8687a..feb3dc7de80 100644
--- a/source/blender/blenkernel/BKE_collection.h
+++ b/source/blender/blenkernel/BKE_collection.h
@@ -115,6 +115,18 @@ bool BKE_collection_is_empty(const struct Collection *collection);
bool BKE_collection_object_add(struct Main *bmain,
struct Collection *collection,
struct Object *ob);
+
+/**
+ * Add object to given collection, similar to #BKE_collection_object_add.
+ *
+ * However, it additionally ensures that the selected collection is also part of the given
+ * `view_layer`, if non-NULL. Otherwise, the object is not added to any collection.
+ */
+bool BKE_collection_viewlayer_object_add(struct Main *bmain,
+ const struct ViewLayer *view_layer,
+ struct Collection *collection,
+ struct Object *ob);
+
/**
* Same as #BKE_collection_object_add, but unconditionally adds the object to the given collection.
*
diff --git a/source/blender/blenkernel/BKE_colortools.h b/source/blender/blenkernel/BKE_colortools.h
index 0d4560207ea..d52fd91ccdd 100644
--- a/source/blender/blenkernel/BKE_colortools.h
+++ b/source/blender/blenkernel/BKE_colortools.h
@@ -129,6 +129,36 @@ bool BKE_curvemapping_RGBA_does_something(const struct CurveMapping *cumap);
void BKE_curvemapping_table_F(const struct CurveMapping *cumap, float **array, int *size);
void BKE_curvemapping_table_RGBA(const struct CurveMapping *cumap, float **array, int *size);
+/** Get the minimum x value of each curve map table. */
+void BKE_curvemapping_get_range_minimums(const struct CurveMapping *curve_mapping,
+ float minimums[4]);
+
+/** Get the reciprocal of the difference between the maximum and the minimum x value of each curve
+ * map table. Evaluation parameters can be multiplied by this value to be normalized. If the
+ * difference is zero, 1^8 is returned. */
+void BKE_curvemapping_compute_range_dividers(const struct CurveMapping *curve_mapping,
+ float dividers[4]);
+
+/** Compute the slopes at the start and end points of each curve map. The slopes are multiplied by
+ * the range of the curve map to compensate for parameter normalization. If the slope is vertical,
+ * 1^8 is returned. */
+void BKE_curvemapping_compute_slopes(const struct CurveMapping *curve_mapping,
+ float start_slopes[4],
+ float end_slopes[4]);
+
+/** Check if the curve map at the index is identity, that is, does nothing. A curve map is said to
+ * be identity if:
+ * - The curve mapping uses extrapolation.
+ * - Its range is 1.
+ * - The slope at its start point is 1.
+ * - The slope at its end point is 1.
+ * - The number of points is 2.
+ * - The start point is at (0, 0).
+ * - The end point is at (1, 1).
+ * Note that this could return false even if the curve map is identity, this happens in the case
+ * when more than 2 points exist in the curve map but all points are collinear. */
+bool BKE_curvemapping_is_map_identity(const struct CurveMapping *curve_mapping, int index);
+
/**
* Call when you do images etc, needs restore too. also verifies tables.
* non-const (these modify the curve).
diff --git a/source/blender/blenkernel/BKE_constraint.h b/source/blender/blenkernel/BKE_constraint.h
index b3119666f0a..737b05fee0c 100644
--- a/source/blender/blenkernel/BKE_constraint.h
+++ b/source/blender/blenkernel/BKE_constraint.h
@@ -67,7 +67,7 @@ typedef void (*ConstraintIDFunc)(struct bConstraint *con,
* Callers of these functions must check that they actually point to something useful,
* as some constraints don't define some of these.
*
- * Warning:
+ * WARNING:
* it is not too advisable to reorder order of members of this struct,
* as you'll have to edit quite a few #NUM_CONSTRAINT_TYPES of these
* structs.
@@ -307,6 +307,25 @@ void BKE_constraint_target_matrix_get(struct Depsgraph *depsgraph,
void *ownerdata,
float mat[4][4],
float ctime);
+
+/**
+ * Retrieves the list of all constraint targets, including the custom space target.
+ * Must be followed by a call to BKE_constraint_targets_flush to free memory.
+ *
+ * \param r_targets Pointer to the list to be initialized with target data.
+ * \returns the number of targets stored in the list.
+ */
+int BKE_constraint_targets_get(struct bConstraint *con, struct ListBase *r_targets);
+
+/**
+ * Copies changed data from the list produced by BKE_constraint_targets_get back to the constraint
+ * data structures and frees memory.
+ *
+ * \param targets List of targets filled by BKE_constraint_targets_get.
+ * \param no_copy Only free memory without copying changes (read-only mode).
+ */
+void BKE_constraint_targets_flush(struct bConstraint *con, struct ListBase *targets, bool no_copy);
+
/**
* Get the list of targets required for solving a constraint.
*/
diff --git a/source/blender/blenkernel/BKE_context.h b/source/blender/blenkernel/BKE_context.h
index f441203d9d6..b7068720469 100644
--- a/source/blender/blenkernel/BKE_context.h
+++ b/source/blender/blenkernel/BKE_context.h
@@ -222,9 +222,10 @@ void CTX_wm_operator_poll_msg_clear(struct bContext *C);
/* Data Context
*
- * - listbases consist of CollectionPointerLink items and must be
- * freed with BLI_freelistN!
- * - the dir listbase consists of LinkData items */
+ * - #ListBase consists of #CollectionPointerLink items and must be
+ * freed with #BLI_freelistN!
+ * - The dir #ListBase consists of #LinkData items.
+ */
/* data type, needed so we can tell between a NULL pointer and an empty list */
enum {
diff --git a/source/blender/blenkernel/BKE_curves.h b/source/blender/blenkernel/BKE_curves.h
index 88bb1c67fd1..c3302c6d2aa 100644
--- a/source/blender/blenkernel/BKE_curves.h
+++ b/source/blender/blenkernel/BKE_curves.h
@@ -25,7 +25,7 @@ void *BKE_curves_add(struct Main *bmain, const char *name);
struct BoundBox *BKE_curves_boundbox_get(struct Object *ob);
-bool BKE_curves_customdata_required(struct Curves *curves, struct CustomDataLayer *layer);
+bool BKE_curves_customdata_required(const struct Curves *curves, const char *name);
/* Depsgraph */
diff --git a/source/blender/blenkernel/BKE_curves.hh b/source/blender/blenkernel/BKE_curves.hh
index bf2d50f63be..2bebd3ff97d 100644
--- a/source/blender/blenkernel/BKE_curves.hh
+++ b/source/blender/blenkernel/BKE_curves.hh
@@ -50,7 +50,7 @@ struct BasisCache {
Vector<int> start_indices;
/**
- * The result of #check_valid_size_and_order, to avoid retrieving its inputs later on.
+ * The result of #check_valid_num_and_order, to avoid retrieving its inputs later on.
* If this is true, the data above will be invalid, and original data should be copied
* to the evaluated result.
*/
@@ -127,7 +127,7 @@ class CurvesGeometry : public ::CurvesGeometry {
* Create curves with the given size. Only the position attribute is created, along with the
* offsets.
*/
- CurvesGeometry(int point_size, int curve_size);
+ CurvesGeometry(int point_num, int curve_num);
CurvesGeometry(const CurvesGeometry &other);
CurvesGeometry(CurvesGeometry &&other);
CurvesGeometry &operator=(const CurvesGeometry &other);
@@ -182,6 +182,7 @@ class CurvesGeometry : public ::CurvesGeometry {
void update_curve_types();
bool has_curve_with_type(CurveType type) const;
+ bool has_curve_with_type(Span<CurveType> types) const;
/** Return true if all of the curves have the provided type. */
bool is_single_type(CurveType type) const;
/** Return the number of curves with each type. */
@@ -264,22 +265,15 @@ class CurvesGeometry : public ::CurvesGeometry {
MutableSpan<float> nurbs_weights_for_write();
/**
- * The index of a triangle (#MLoopTri) that a curve is attached to.
- * The index is -1, if the curve is not attached.
+ * UV coordinate for each curve that encodes where the curve is attached to the surface mesh.
*/
- VArray<int> surface_triangle_indices() const;
- MutableSpan<int> surface_triangle_indices_for_write();
+ Span<float2> surface_uv_coords() const;
+ MutableSpan<float2> surface_uv_coords_for_write();
- /**
- * Barycentric coordinates of the attachment point within a triangle.
- * Only the first two coordinates are stored. The third coordinate can be derived because the sum
- * of the three coordinates is 1.
- *
- * When the triangle index is -1, this coordinate should be ignored.
- * The span can be empty, when all triangle indices are -1.
- */
- Span<float2> surface_triangle_coords() const;
- MutableSpan<float2> surface_triangle_coords_for_write();
+ VArray<float> selection_point_float() const;
+ MutableSpan<float> selection_point_float_for_write();
+ VArray<float> selection_curve_float() const;
+ MutableSpan<float> selection_curve_float_for_write();
/**
* Calculate the largest and smallest position values, only including control points
@@ -393,6 +387,7 @@ class CurvesGeometry : public ::CurvesGeometry {
void update_customdata_pointers();
+ void remove_points(IndexMask points_to_delete);
void remove_curves(IndexMask curves_to_delete);
/**
@@ -401,11 +396,21 @@ class CurvesGeometry : public ::CurvesGeometry {
*/
void reverse_curves(IndexMask curves_to_reverse);
+ /**
+ * Remove any attributes that are unused based on the types in the curves.
+ */
+ void remove_attributes_based_on_types();
+
/* --------------------------------------------------------------------
* Attributes.
*/
- GVArray adapt_domain(const GVArray &varray, AttributeDomain from, AttributeDomain to) const;
+ GVArray adapt_domain(const GVArray &varray, eAttrDomain from, eAttrDomain to) const;
+ template<typename T>
+ VArray<T> adapt_domain(const VArray<T> &varray, eAttrDomain from, eAttrDomain to) const
+ {
+ return this->adapt_domain(GVArray(varray), from, to).typed<T>();
+ }
};
namespace curves {
@@ -418,7 +423,7 @@ namespace curves {
* The number of segments between control points, accounting for the last segment of cyclic
* curves. The logic is simple, but this function should be used to make intentions clearer.
*/
-inline int curve_segment_size(const int points_num, const bool cyclic)
+inline int curve_segment_num(const int points_num, const bool cyclic)
{
BLI_assert(points_num > 0);
return (cyclic && points_num > 1) ? points_num : points_num - 1;
@@ -453,7 +458,7 @@ void calculate_tangents(Span<float3> positions, bool is_cyclic, MutableSpan<floa
/**
* Calculate directions perpendicular to the tangent at every point by rotating an arbitrary
- * starting vector by the same rotation of each tangent. If the curve is cylic, propagate a
+ * starting vector by the same rotation of each tangent. If the curve is cyclic, propagate a
* correction through the entire to make sure the first and last normal align.
*/
void calculate_normals_minimum(Span<float3> tangents, bool cyclic, MutableSpan<float3> normals);
@@ -483,10 +488,11 @@ bool segment_is_vector(Span<int8_t> handle_types_left,
int segment_index);
/**
- * Return true if the curve's last cylic segment has a vector type.
+ * Return true if the curve's last cyclic segment has a vector type.
* This only makes a difference in the shape of cyclic curves.
*/
-bool last_cylic_segment_is_vector(Span<int8_t> handle_types_left, Span<int8_t> handle_types_right);
+bool last_cyclic_segment_is_vector(Span<int8_t> handle_types_left,
+ Span<int8_t> handle_types_right);
/**
* Return true if the handle types at the index are free (#BEZIER_HANDLE_FREE) or vector
@@ -585,11 +591,11 @@ namespace catmull_rom {
* \param points_num: The number of points in the curve.
* \param resolution: The resolution for each segment.
*/
-int calculate_evaluated_size(int points_num, bool cyclic, int resolution);
+int calculate_evaluated_num(int points_num, bool cyclic, int resolution);
/**
* Evaluate the Catmull Rom curve. The length of the #dst span should be calculated with
- * #calculate_evaluated_size and is expected to divide evenly by the #src span's segment size.
+ * #calculate_evaluated_num and is expected to divide evenly by the #src span's segment size.
*/
void interpolate_to_evaluated(GSpan src, bool cyclic, int resolution, GMutableSpan dst);
@@ -606,7 +612,7 @@ namespace nurbs {
/**
* Checks the conditions that a NURBS curve needs to evaluate.
*/
-bool check_valid_size_and_order(int points_num, int8_t order, bool cyclic, KnotsMode knots_mode);
+bool check_valid_num_and_order(int points_num, int8_t order, bool cyclic, KnotsMode knots_mode);
/**
* Calculate the standard evaluated size for a NURBS curve, using the standard that
@@ -616,7 +622,7 @@ bool check_valid_size_and_order(int points_num, int8_t order, bool cyclic, Knots
* for predictability and so that cached basis weights of NURBS curves with these properties can be
* shared.
*/
-int calculate_evaluated_size(
+int calculate_evaluated_num(
int points_num, int8_t order, bool cyclic, int resolution, KnotsMode knots_mode);
/**
@@ -624,7 +630,7 @@ int calculate_evaluated_size(
* The knots must be longer for a cyclic curve, for example, in order to provide weights for the
* last evaluated points that are also influenced by the first control points.
*/
-int knots_size(int points_num, int8_t order, bool cyclic);
+int knots_num(int points_num, int8_t order, bool cyclic);
/**
* Calculate the knots for a curve given its properties, based on built-in standards defined by
@@ -644,7 +650,7 @@ void calculate_knots(
* and a weight for each control point.
*/
void calculate_basis_cache(int points_num,
- int evaluated_size,
+ int evaluated_num,
int8_t order,
bool cyclic,
Span<float> knots,
@@ -671,6 +677,7 @@ void interpolate_to_evaluated(const BasisCache &basis_cache,
} // namespace curves
Curves *curves_new_nomain(int points_num, int curves_num);
+Curves *curves_new_nomain(CurvesGeometry curves);
/**
* Create a new curves data-block containing a single curve with the given length and type.
@@ -685,11 +692,11 @@ std::array<int, CURVE_TYPES_NUM> calculate_type_counts(const VArray<int8_t> &typ
inline int CurvesGeometry::points_num() const
{
- return this->point_size;
+ return this->point_num;
}
inline int CurvesGeometry::curves_num() const
{
- return this->curve_size;
+ return this->curve_num;
}
inline IndexRange CurvesGeometry::points_range() const
{
@@ -710,6 +717,12 @@ inline bool CurvesGeometry::has_curve_with_type(const CurveType type) const
return this->curve_type_counts()[type] > 0;
}
+inline bool CurvesGeometry::has_curve_with_type(const Span<CurveType> types) const
+{
+ return std::any_of(
+ types.begin(), types.end(), [&](CurveType type) { return this->has_curve_with_type(type); });
+}
+
inline const std::array<int, CURVE_TYPES_NUM> &CurvesGeometry::curve_type_counts() const
{
BLI_assert(this->runtime->type_counts == calculate_type_counts(this->curve_types()));
@@ -719,7 +732,7 @@ inline const std::array<int, CURVE_TYPES_NUM> &CurvesGeometry::curve_type_counts
inline IndexRange CurvesGeometry::points_for_curve(const int index) const
{
/* Offsets are not allocated when there are no curves. */
- BLI_assert(this->curve_size > 0);
+ BLI_assert(this->curve_num > 0);
BLI_assert(this->curve_offsets != nullptr);
const int offset = this->curve_offsets[index];
const int offset_next = this->curve_offsets[index + 1];
@@ -729,7 +742,7 @@ inline IndexRange CurvesGeometry::points_for_curve(const int index) const
inline IndexRange CurvesGeometry::points_for_curves(const IndexRange curves) const
{
/* Offsets are not allocated when there are no curves. */
- BLI_assert(this->curve_size > 0);
+ BLI_assert(this->curve_num > 0);
BLI_assert(this->curve_offsets != nullptr);
const int offset = this->curve_offsets[curves.start()];
const int offset_next = this->curve_offsets[curves.one_after_last()];
@@ -751,7 +764,7 @@ inline IndexRange CurvesGeometry::evaluated_points_for_curve(int index) const
inline IndexRange CurvesGeometry::evaluated_points_for_curves(const IndexRange curves) const
{
BLI_assert(!this->runtime->offsets_cache_dirty);
- BLI_assert(this->curve_size > 0);
+ BLI_assert(this->curve_num > 0);
const int offset = this->runtime->evaluated_offsets_cache[curves.start()];
const int offset_next = this->runtime->evaluated_offsets_cache[curves.one_after_last()];
return {offset, offset_next - offset};
@@ -769,7 +782,7 @@ inline IndexRange CurvesGeometry::lengths_range_for_curve(const int curve_index,
BLI_assert(cyclic == this->cyclic()[curve_index]);
const IndexRange points = this->evaluated_points_for_curve(curve_index);
const int start = points.start() + curve_index;
- return {start, curves::curve_segment_size(points.size(), cyclic)};
+ return {start, curves::curve_segment_num(points.size(), cyclic)};
}
inline Span<float> CurvesGeometry::evaluated_lengths_for_curve(const int curve_index,
@@ -784,6 +797,9 @@ inline float CurvesGeometry::evaluated_length_total_for_curve(const int curve_in
const bool cyclic) const
{
const Span<float> lengths = this->evaluated_lengths_for_curve(curve_index, cyclic);
+ if (lengths.is_empty()) {
+ return 0.0f;
+ }
return lengths.last();
}
diff --git a/source/blender/blenkernel/BKE_curves_utils.hh b/source/blender/blenkernel/BKE_curves_utils.hh
new file mode 100644
index 00000000000..f223e173ea9
--- /dev/null
+++ b/source/blender/blenkernel/BKE_curves_utils.hh
@@ -0,0 +1,84 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+
+#pragma once
+
+#include "BKE_curves.hh"
+
+/** \file
+ * \ingroup bke
+ * \brief Low-level operations for curves.
+ */
+
+#include "BLI_function_ref.hh"
+#include "BLI_generic_pointer.hh"
+
+namespace blender::bke::curves {
+
+/**
+ * Copy the provided point attribute values between all curves in the #curve_ranges index
+ * ranges, assuming that all curves have the same number of control points in #src_curves
+ * and #dst_curves.
+ */
+void copy_point_data(const CurvesGeometry &src_curves,
+ const CurvesGeometry &dst_curves,
+ Span<IndexRange> curve_ranges,
+ GSpan src,
+ GMutableSpan dst);
+
+void copy_point_data(const CurvesGeometry &src_curves,
+ const CurvesGeometry &dst_curves,
+ IndexMask src_curve_selection,
+ GSpan src,
+ GMutableSpan dst);
+
+template<typename T>
+void copy_point_data(const CurvesGeometry &src_curves,
+ const CurvesGeometry &dst_curves,
+ const IndexMask src_curve_selection,
+ const Span<T> src,
+ MutableSpan<T> dst)
+{
+ copy_point_data(src_curves, dst_curves, src_curve_selection, GSpan(src), GMutableSpan(dst));
+}
+
+void fill_points(const CurvesGeometry &curves,
+ IndexMask curve_selection,
+ GPointer value,
+ GMutableSpan dst);
+
+template<typename T>
+void fill_points(const CurvesGeometry &curves,
+ const IndexMask curve_selection,
+ const T &value,
+ MutableSpan<T> dst)
+{
+ fill_points(curves, curve_selection, &value, dst);
+}
+
+/**
+ * Copy the size of every curve in #curve_ranges to the corresponding index in #counts.
+ */
+void fill_curve_counts(const bke::CurvesGeometry &curves,
+ Span<IndexRange> curve_ranges,
+ MutableSpan<int> counts);
+
+/**
+ * Turn an array of sizes into the offset at each index including all previous sizes.
+ */
+void accumulate_counts_to_offsets(MutableSpan<int> counts_to_offsets, int start_offset = 0);
+
+IndexMask indices_for_type(const VArray<int8_t> &types,
+ const std::array<int, CURVE_TYPES_NUM> &type_counts,
+ const CurveType type,
+ const IndexMask selection,
+ Vector<int64_t> &r_indices);
+
+void foreach_curve_by_type(const VArray<int8_t> &types,
+ const std::array<int, CURVE_TYPES_NUM> &type_counts,
+ IndexMask selection,
+ FunctionRef<void(IndexMask)> catmull_rom_fn,
+ FunctionRef<void(IndexMask)> poly_fn,
+ FunctionRef<void(IndexMask)> bezier_fn,
+ FunctionRef<void(IndexMask)> nurbs_fn);
+
+} // namespace blender::bke::curves
diff --git a/source/blender/blenkernel/BKE_customdata.h b/source/blender/blenkernel/BKE_customdata.h
index f05dfb164cf..a1101c1df44 100644
--- a/source/blender/blenkernel/BKE_customdata.h
+++ b/source/blender/blenkernel/BKE_customdata.h
@@ -10,6 +10,10 @@
#include "BLI_sys_types.h"
#include "BLI_utildefines.h"
+#ifdef __cplusplus
+# include "BLI_span.hh"
+# include "BLI_vector.hh"
+#endif
#include "DNA_customdata_types.h"
@@ -24,7 +28,7 @@ struct BlendWriter;
struct CustomData;
struct CustomData_MeshMasks;
struct ID;
-typedef uint64_t CustomDataMask;
+typedef uint64_t eCustomDataMask;
/* A data type large enough to hold 1 element from any custom-data layer type. */
typedef struct {
@@ -59,7 +63,7 @@ typedef enum eCDAllocType {
CD_DUPLICATE = 4,
} eCDAllocType;
-#define CD_TYPE_AS_MASK(_type) (CustomDataMask)((CustomDataMask)1 << (CustomDataMask)(_type))
+#define CD_TYPE_AS_MASK(_type) (eCustomDataMask)((eCustomDataMask)1 << (eCustomDataMask)(_type))
void customData_mask_layers__print(const struct CustomData_MeshMasks *mask);
@@ -133,7 +137,7 @@ void CustomData_data_add(int type, void *data1, const void *data2);
*/
void CustomData_copy(const struct CustomData *source,
struct CustomData *dest,
- CustomDataMask mask,
+ eCustomDataMask mask,
eCDAllocType alloctype,
int totelem);
@@ -146,7 +150,7 @@ void CustomData_update_typemap(struct CustomData *data);
*/
bool CustomData_merge(const struct CustomData *source,
struct CustomData *dest,
- CustomDataMask mask,
+ eCustomDataMask mask,
eCDAllocType alloctype,
int totelem);
@@ -166,7 +170,7 @@ void CustomData_realloc(struct CustomData *data, int totelem);
*/
bool CustomData_bmesh_merge(const struct CustomData *source,
struct CustomData *dest,
- CustomDataMask mask,
+ eCustomDataMask mask,
eCDAllocType alloctype,
struct BMesh *bm,
char htype);
@@ -184,7 +188,7 @@ void CustomData_free(struct CustomData *data, int totelem);
/**
* Same as above, but only frees layers which matches the given mask.
*/
-void CustomData_free_typemask(struct CustomData *data, int totelem, CustomDataMask mask);
+void CustomData_free_typemask(struct CustomData *data, int totelem, eCustomDataMask mask);
/**
* Frees all layers with #CD_FLAG_TEMPORARY.
@@ -221,6 +225,7 @@ void *CustomData_add_layer_anonymous(struct CustomData *data,
* In edit-mode, use #EDBM_data_layer_free instead of this function.
*/
bool CustomData_free_layer(struct CustomData *data, int type, int totelem, int index);
+bool CustomData_free_layer_named(struct CustomData *data, const char *name, const int totelem);
/**
* Frees the layer index with the give type.
@@ -244,7 +249,7 @@ bool CustomData_has_layer(const struct CustomData *data, int type);
* Returns the number of layers with this type.
*/
int CustomData_number_of_layers(const struct CustomData *data, int type);
-int CustomData_number_of_layers_typemask(const struct CustomData *data, CustomDataMask mask);
+int CustomData_number_of_layers_typemask(const struct CustomData *data, eCustomDataMask mask);
/**
* Duplicate data of a layer with flag NOFREE, and remove that flag.
@@ -272,7 +277,7 @@ void CustomData_duplicate_referenced_layers(CustomData *data, int totelem);
* Set the #CD_FLAG_NOCOPY flag in custom data layers where the mask is
* zero for the layer type, so only layer types specified by the mask will be copied
*/
-void CustomData_set_only_copy(const struct CustomData *data, CustomDataMask mask);
+void CustomData_set_only_copy(const struct CustomData *data, eCustomDataMask mask);
/**
* Copies data from one CustomData object to another
@@ -305,7 +310,7 @@ void CustomData_bmesh_copy_data_exclude_by_type(const struct CustomData *source,
struct CustomData *dest,
void *src_block,
void **dest_block,
- CustomDataMask mask_exclude);
+ eCustomDataMask mask_exclude);
/**
* Copies data of a single layer of a given type.
@@ -484,7 +489,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,
- CustomDataMask mask_exclude);
+ eCustomDataMask mask_exclude);
/**
* Copy custom data to/from layers as in mesh/derived-mesh, to edit-mesh
@@ -589,14 +594,14 @@ void CustomData_external_remove(struct CustomData *data, struct ID *id, int type
bool CustomData_external_test(struct CustomData *data, int type);
void CustomData_external_write(
- struct CustomData *data, struct ID *id, CustomDataMask mask, int totelem, int free);
+ struct CustomData *data, struct ID *id, eCustomDataMask mask, int totelem, int free);
void CustomData_external_read(struct CustomData *data,
struct ID *id,
- CustomDataMask mask,
+ eCustomDataMask mask,
int totelem);
void CustomData_external_reload(struct CustomData *data,
struct ID *id,
- CustomDataMask mask,
+ eCustomDataMask mask,
int totelem);
/* Mesh-to-mesh transfer data. */
@@ -700,39 +705,33 @@ void CustomData_data_transfer(const struct MeshPairRemap *me_remap,
/* .blend file I/O */
+#ifdef __cplusplus
+
/**
* Prepare given custom data for file writing.
*
- * \param data: the custom-data to tweak for .blend file writing (modified in place).
- * \param r_write_layers: contains a reduced set of layers to be written to file,
- * use it with #writestruct_at_address()
- * (caller must free it if != \a write_layers_buff).
- *
- * \param write_layers_buff: An optional buffer for r_write_layers (to avoid allocating it).
- * \param write_layers_size: The size of pre-allocated \a write_layer_buff.
+ * \param data: The custom-data to tweak for .blend file writing (modified in place).
+ * \param layers_to_write: A reduced set of layers to be written to file.
*
- * \warning After this function has ran, given custom data is no more valid from Blender POV
- * (its `totlayer` is invalid). This function shall always be called with localized data
- * (as it is in write_meshes()).
- *
- * \note `data->typemap` is not updated here, since it is always rebuilt on file read anyway.
- * This means written `typemap` does not match written layers (as returned by \a r_write_layers).
- * Trivial to fix is ever needed.
+ * \warning This function invalidates the custom data struct by changing the layer counts and the
+ * #layers pointer, and by invalidating the type map. It expects to work on a shallow copy of
+ * the struct.
*/
-void CustomData_blend_write_prepare(struct CustomData *data,
- struct CustomDataLayer **r_write_layers,
- struct CustomDataLayer *write_layers_buff,
- size_t write_layers_size);
+void CustomData_blend_write_prepare(CustomData &data,
+ blender::Vector<CustomDataLayer, 16> &layers_to_write);
/**
- * \param layers: The layers argument assigned by #CustomData_blend_write_prepare.
+ * \param layers_to_write: Layers created by #CustomData_blend_write_prepare.
*/
-void CustomData_blend_write(struct BlendWriter *writer,
- struct CustomData *data,
- CustomDataLayer *layers,
+void CustomData_blend_write(BlendWriter *writer,
+ CustomData *data,
+ blender::Span<CustomDataLayer> layers_to_write,
int count,
- CustomDataMask cddata_mask,
- struct ID *id);
+ eCustomDataMask cddata_mask,
+ ID *id);
+
+#endif
+
void CustomData_blend_read(struct BlendDataReader *reader, struct CustomData *data, int count);
#ifndef NDEBUG
@@ -751,7 +750,7 @@ void CustomData_debug_info_from_layers(const struct CustomData *data,
# include "BLI_cpp_type.hh"
namespace blender::bke {
-const CPPType *custom_data_type_to_cpp_type(const CustomDataType type);
-CustomDataType cpp_type_to_custom_data_type(const CPPType &type);
+const CPPType *custom_data_type_to_cpp_type(eCustomDataType type);
+eCustomDataType cpp_type_to_custom_data_type(const CPPType &type);
} // namespace blender::bke
#endif
diff --git a/source/blender/blenkernel/BKE_customdata_file.h b/source/blender/blenkernel/BKE_customdata_file.h
index 9d45d28bd18..6972dcb8681 100644
--- a/source/blender/blenkernel/BKE_customdata_file.h
+++ b/source/blender/blenkernel/BKE_customdata_file.h
@@ -25,17 +25,17 @@ void cdf_free(CDataFile *cdf);
/* File read/write/remove */
-bool cdf_read_open(CDataFile *cdf, const char *filename);
+bool cdf_read_open(CDataFile *cdf, const char *filepath);
bool cdf_read_layer(CDataFile *cdf, CDataFileLayer *blay);
bool cdf_read_data(CDataFile *cdf, unsigned int size, void *data);
void cdf_read_close(CDataFile *cdf);
-bool cdf_write_open(CDataFile *cdf, const char *filename);
+bool cdf_write_open(CDataFile *cdf, const char *filepath);
bool cdf_write_layer(CDataFile *cdf, CDataFileLayer *blay);
bool cdf_write_data(CDataFile *cdf, unsigned int size, void *data);
void cdf_write_close(CDataFile *cdf);
-void cdf_remove(const char *filename);
+void cdf_remove(const char *filepath);
/* Layers */
diff --git a/source/blender/blenkernel/BKE_deform.h b/source/blender/blenkernel/BKE_deform.h
index 1b225884b14..a21d9141ac0 100644
--- a/source/blender/blenkernel/BKE_deform.h
+++ b/source/blender/blenkernel/BKE_deform.h
@@ -228,39 +228,44 @@ void BKE_defvert_normalize_lock_map(struct MDeformVert *dvert,
/* Utilities to 'extract' a given vgroup into a simple float array,
* for verts, but also edges/polys/loops. */
-void BKE_defvert_extract_vgroup_to_vertweights(
- struct MDeformVert *dvert, int defgroup, int num_verts, float *r_weights, bool invert_vgroup);
+void BKE_defvert_extract_vgroup_to_vertweights(const struct MDeformVert *dvert,
+ int defgroup,
+ int num_verts,
+ bool invert_vgroup,
+ float *r_weights);
/**
* 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,
+void BKE_defvert_extract_vgroup_to_edgeweights(const struct MDeformVert *dvert,
int defgroup,
int num_verts,
struct MEdge *edges,
int num_edges,
- float *r_weights,
- bool invert_vgroup);
-void BKE_defvert_extract_vgroup_to_loopweights(struct MDeformVert *dvert,
+ bool invert_vgroup,
+ float *r_weights);
+void BKE_defvert_extract_vgroup_to_loopweights(const struct MDeformVert *dvert,
int defgroup,
int num_verts,
struct MLoop *loops,
int num_loops,
- float *r_weights,
- bool invert_vgroup);
-void BKE_defvert_extract_vgroup_to_polyweights(struct MDeformVert *dvert,
+ bool invert_vgroup,
+ float *r_weights);
+void BKE_defvert_extract_vgroup_to_polyweights(const struct MDeformVert *dvert,
int defgroup,
int num_verts,
struct MLoop *loops,
int num_loops,
struct MPoly *polys,
int num_polys,
- float *r_weights,
- bool invert_vgroup);
+ bool invert_vgroup,
+ float *r_weights);
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_write(struct BlendWriter *writer,
+ int count,
+ const struct MDeformVert *dvlist);
void BKE_defvert_blend_read(struct BlendDataReader *reader,
int count,
struct MDeformVert *mdverts);
diff --git a/source/blender/blenkernel/BKE_fcurve.h b/source/blender/blenkernel/BKE_fcurve.h
index 6784a1296e9..4489527fcab 100644
--- a/source/blender/blenkernel/BKE_fcurve.h
+++ b/source/blender/blenkernel/BKE_fcurve.h
@@ -259,6 +259,18 @@ struct FCurve *BKE_fcurve_iter_step(struct FCurve *fcu_iter, const char rna_path
/**
* High level function to get an f-curve from C without having the RNA.
+ *
+ * If there is an action assigned to the `id`'s #AnimData, it will be searched for a matching
+ * F-curve first. Drivers are searched only if no valid action F-curve could be found.
+ *
+ * \note Return pointer parameter (`r_driven`) is optional and may be NULL.
+ *
+ * \warning In case no animation (from an Action) F-curve is found, returned value is always NULL.
+ * This means that this function will set `r_driven` to True in case a valid driver F-curve is
+ * found, but will not return said F-curve. In other words:
+ * - Animated with FCurve: returns the `FCurve*` and `*r_driven = false`.
+ * - Animated with driver: returns `NULL` and `*r_driven = true`.
+ * - Not animated: returns `NULL` and `*r_driven = false`.
*/
struct FCurve *id_data_find_fcurve(
ID *id, void *data, struct StructRNA *type, const char *prop_name, int index, bool *r_driven);
@@ -279,6 +291,25 @@ struct FCurve *id_data_find_fcurve(
int BKE_fcurves_filter(ListBase *dst, ListBase *src, const char *dataPrefix, const char *dataName);
/**
+ * Find an F-Curve from its rna path and index.
+ *
+ * If there is an action assigned to the `animdata`, it will be searched for a matching F-curve
+ * first. Drivers are searched only if no valid action F-curve could be found.
+ *
+ * \note Typically, indices in RNA arrays are stored separately in F-curves, so the rna_path
+ * should not include them (e.g. `rna_path='location[0]'` will not match any F-Curve on an Object,
+ * but `rna_path='location', rna_index=0` will if it exists).
+ *
+ * \note Return pointer parameters (`r_action`, `r_driven` and `r_special`) are all optional and
+ * may be NULL.
+ */
+struct FCurve *BKE_animadata_fcurve_find_by_rna_path(struct AnimData *animdata,
+ const char *rna_path,
+ const int rna_index,
+ struct bAction **r_action,
+ bool *r_driven);
+
+/**
* Find an f-curve based on an rna property.
*/
struct FCurve *BKE_fcurve_find_by_rna(struct PointerRNA *ptr,
@@ -291,9 +322,11 @@ struct FCurve *BKE_fcurve_find_by_rna(struct PointerRNA *ptr,
/**
* Same as above, but takes a context data,
* temp hack needed for complex paths like texture ones.
- */
+ *
+ * \param r_special Optional, ignored when NULL. Set to `true` if the given RNA `ptr` is a NLA
+ * strip, and the returned F-curve comes from this NLA strip. */
struct FCurve *BKE_fcurve_find_by_rna_context_ui(struct bContext *C,
- struct PointerRNA *ptr,
+ const struct PointerRNA *ptr,
struct PropertyRNA *prop,
int rnaindex,
struct AnimData **r_animdata,
diff --git a/source/blender/blenkernel/BKE_geometry_fields.hh b/source/blender/blenkernel/BKE_geometry_fields.hh
index 9c86ab262ef..7c504826044 100644
--- a/source/blender/blenkernel/BKE_geometry_fields.hh
+++ b/source/blender/blenkernel/BKE_geometry_fields.hh
@@ -17,10 +17,10 @@ namespace blender::bke {
class GeometryComponentFieldContext : public fn::FieldContext {
private:
const GeometryComponent &component_;
- const AttributeDomain domain_;
+ const eAttrDomain domain_;
public:
- GeometryComponentFieldContext(const GeometryComponent &component, const AttributeDomain domain)
+ GeometryComponentFieldContext(const GeometryComponent &component, const eAttrDomain domain)
: component_(component), domain_(domain)
{
}
@@ -30,7 +30,7 @@ class GeometryComponentFieldContext : public fn::FieldContext {
return component_;
}
- AttributeDomain domain() const
+ eAttrDomain domain() const
{
return domain_;
}
@@ -45,7 +45,7 @@ class GeometryFieldInput : public fn::FieldInput {
ResourceScope &scope) const override;
virtual GVArray get_varray_for_context(const GeometryComponent &component,
- AttributeDomain domain,
+ eAttrDomain domain,
IndexMask mask) const = 0;
};
@@ -73,7 +73,7 @@ class AttributeFieldInput : public GeometryFieldInput {
}
GVArray get_varray_for_context(const GeometryComponent &component,
- AttributeDomain domain,
+ eAttrDomain domain,
IndexMask mask) const override;
std::string socket_inspection_name() const override;
@@ -90,7 +90,7 @@ class IDAttributeFieldInput : public GeometryFieldInput {
}
GVArray get_varray_for_context(const GeometryComponent &component,
- AttributeDomain domain,
+ eAttrDomain domain,
IndexMask mask) const override;
std::string socket_inspection_name() const override;
@@ -99,12 +99,12 @@ class IDAttributeFieldInput : public GeometryFieldInput {
bool is_equal_to(const fn::FieldNode &other) const override;
};
-VArray<float3> curve_normals_varray(const CurveComponent &component, const AttributeDomain domain);
+VArray<float3> curve_normals_varray(const CurveComponent &component, const eAttrDomain domain);
VArray<float3> mesh_normals_varray(const MeshComponent &mesh_component,
const Mesh &mesh,
const IndexMask mask,
- const AttributeDomain domain);
+ eAttrDomain domain);
class NormalFieldInput : public GeometryFieldInput {
public:
@@ -114,7 +114,7 @@ class NormalFieldInput : public GeometryFieldInput {
}
GVArray get_varray_for_context(const GeometryComponent &component,
- const AttributeDomain domain,
+ const eAttrDomain domain,
IndexMask mask) const override;
std::string socket_inspection_name() const override;
@@ -153,7 +153,7 @@ class AnonymousAttributeFieldInput : public GeometryFieldInput {
}
GVArray get_varray_for_context(const GeometryComponent &component,
- AttributeDomain domain,
+ eAttrDomain domain,
IndexMask mask) const override;
std::string socket_inspection_name() const override;
@@ -166,7 +166,7 @@ class CurveLengthFieldInput final : public GeometryFieldInput {
public:
CurveLengthFieldInput();
GVArray get_varray_for_context(const GeometryComponent &component,
- AttributeDomain domain,
+ eAttrDomain domain,
IndexMask mask) const final;
uint64_t hash() const override;
bool is_equal_to(const fn::FieldNode &other) const override;
diff --git a/source/blender/blenkernel/BKE_geometry_set.hh b/source/blender/blenkernel/BKE_geometry_set.hh
index dfd9fccebbd..8d658c9be15 100644
--- a/source/blender/blenkernel/BKE_geometry_set.hh
+++ b/source/blender/blenkernel/BKE_geometry_set.hh
@@ -94,11 +94,11 @@ class GeometryComponent {
* \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;
+ bool attribute_domain_supported(eAttrDomain 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;
+ virtual int attribute_domain_num(eAttrDomain domain) const;
/**
* Return true if the attribute name corresponds to a built-in attribute with a hardcoded domain
@@ -130,16 +130,16 @@ class GeometryComponent {
* \return null if the interpolation is not implemented.
*/
blender::GVArray attribute_try_adapt_domain(const blender::GVArray &varray,
- const AttributeDomain from_domain,
- const AttributeDomain to_domain) const
+ const eAttrDomain from_domain,
+ const eAttrDomain 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,
- const AttributeDomain to_domain) const
+ const eAttrDomain from_domain,
+ const eAttrDomain to_domain) const
{
return this->attribute_try_adapt_domain_impl(varray, from_domain, to_domain)
.template typed<T>();
@@ -156,8 +156,8 @@ class GeometryComponent {
/** Returns true when the attribute has been created. */
bool attribute_try_create(const blender::bke::AttributeIDRef &attribute_id,
- AttributeDomain domain,
- const CustomDataType data_type,
+ eAttrDomain domain,
+ eCustomDataType data_type,
const AttributeInit &initializer);
/**
@@ -182,8 +182,8 @@ class GeometryComponent {
* interpolated or converted.
*/
blender::GVArray attribute_try_get_for_read(const blender::bke::AttributeIDRef &attribute_id,
- AttributeDomain domain,
- const CustomDataType data_type) const;
+ eAttrDomain domain,
+ eCustomDataType data_type) const;
/**
* Get a virtual array that refers to the data of an attribute, interpolated to the given domain.
@@ -191,7 +191,7 @@ class GeometryComponent {
* interpolated.
*/
blender::GVArray attribute_try_get_for_read(const blender::bke::AttributeIDRef &attribute_id,
- AttributeDomain domain) const;
+ eAttrDomain domain) const;
/**
* Get a virtual array that refers to the data of an attribute converted to the given data type.
@@ -199,7 +199,7 @@ class GeometryComponent {
* cannot be converted.
*/
blender::bke::ReadAttributeLookup attribute_try_get_for_read(
- const blender::bke::AttributeIDRef &attribute_id, const CustomDataType data_type) const;
+ const blender::bke::AttributeIDRef &attribute_id, eCustomDataType data_type) const;
/**
* Get a virtual array that refers to the data of an attribute, interpolated to the given domain
@@ -207,17 +207,17 @@ class GeometryComponent {
* contain a default value. This never returns null.
*/
blender::GVArray attribute_get_for_read(const blender::bke::AttributeIDRef &attribute_id,
- AttributeDomain domain,
- const CustomDataType data_type,
+ eAttrDomain domain,
+ eCustomDataType data_type,
const void *default_value = nullptr) const;
/* Use instead of the method above when the type is known at compile time for type safety. */
template<typename T>
blender::VArray<T> attribute_get_for_read(const blender::bke::AttributeIDRef &attribute_id,
- const AttributeDomain domain,
+ const eAttrDomain domain,
const T &default_value) const
{
const blender::CPPType &cpp_type = blender::CPPType::get<T>();
- const CustomDataType type = blender::bke::cpp_type_to_custom_data_type(cpp_type);
+ const eCustomDataType type = blender::bke::cpp_type_to_custom_data_type(cpp_type);
return this->attribute_get_for_read(attribute_id, domain, type, &default_value)
.template typed<T>();
}
@@ -234,18 +234,18 @@ class GeometryComponent {
*/
blender::bke::OutputAttribute attribute_try_get_for_output(
const blender::bke::AttributeIDRef &attribute_id,
- AttributeDomain domain,
- const CustomDataType data_type,
+ eAttrDomain domain,
+ eCustomDataType data_type,
const void *default_value = nullptr);
/* 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,
- const AttributeDomain domain,
+ const eAttrDomain domain,
const T default_value)
{
const blender::CPPType &cpp_type = blender::CPPType::get<T>();
- const CustomDataType data_type = blender::bke::cpp_type_to_custom_data_type(cpp_type);
+ const eCustomDataType data_type = blender::bke::cpp_type_to_custom_data_type(cpp_type);
return this->attribute_try_get_for_output(attribute_id, domain, data_type, &default_value);
}
@@ -257,15 +257,15 @@ class GeometryComponent {
*/
blender::bke::OutputAttribute attribute_try_get_for_output_only(
const blender::bke::AttributeIDRef &attribute_id,
- AttributeDomain domain,
- const CustomDataType data_type);
+ eAttrDomain domain,
+ eCustomDataType 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)
+ const blender::bke::AttributeIDRef &attribute_id, const eAttrDomain domain)
{
const blender::CPPType &cpp_type = blender::CPPType::get<T>();
- const CustomDataType data_type = blender::bke::cpp_type_to_custom_data_type(cpp_type);
+ const eCustomDataType data_type = blender::bke::cpp_type_to_custom_data_type(cpp_type);
return this->attribute_try_get_for_output_only(attribute_id, domain, data_type);
}
@@ -273,8 +273,8 @@ class GeometryComponent {
virtual const blender::bke::ComponentAttributeProviders *get_attribute_providers() const;
virtual blender::GVArray attribute_try_adapt_domain_impl(const blender::GVArray &varray,
- AttributeDomain from_domain,
- AttributeDomain to_domain) const;
+ eAttrDomain from_domain,
+ eAttrDomain to_domain) const;
};
template<typename T>
@@ -521,11 +521,11 @@ struct GeometrySet {
};
/**
- * A geometry component that can store a mesh, storing the #Mesh data structure.
+ * A geometry component that can store a mesh, using the #Mesh data-block.
*
- * Attributes are stored in the mesh itself, on any of the four attribute domains. Generic
- * attributes are stored in contiguous arrays, but often built-in attributes are stored in an
- * array of structs fashion for historical reasons, requiring more complex attribute access.
+ * Attributes are stored, on any of the four attribute domains. Generic attributes are stored in
+ * contiguous arrays, but often built-in attributes are stored in an array of structs fashion for
+ * historical reasons, requiring more complex attribute access.
*/
class MeshComponent : public GeometryComponent {
private:
@@ -560,7 +560,7 @@ class MeshComponent : public GeometryComponent {
*/
Mesh *get_for_write();
- int attribute_domain_size(AttributeDomain domain) const final;
+ int attribute_domain_num(eAttrDomain domain) const final;
bool is_empty() const final;
@@ -573,8 +573,8 @@ class MeshComponent : public GeometryComponent {
const blender::bke::ComponentAttributeProviders *get_attribute_providers() const final;
blender::GVArray attribute_try_adapt_domain_impl(const blender::GVArray &varray,
- AttributeDomain from_domain,
- AttributeDomain to_domain) const final;
+ eAttrDomain from_domain,
+ eAttrDomain to_domain) const final;
};
/**
@@ -623,7 +623,7 @@ class PointCloudComponent : public GeometryComponent {
*/
PointCloud *get_for_write();
- int attribute_domain_size(AttributeDomain domain) const final;
+ int attribute_domain_num(eAttrDomain domain) const final;
bool is_empty() const final;
@@ -664,7 +664,7 @@ class CurveComponentLegacy : public GeometryComponent {
const CurveEval *get_for_read() const;
CurveEval *get_for_write();
- int attribute_domain_size(AttributeDomain domain) const final;
+ int attribute_domain_num(eAttrDomain domain) const final;
bool is_empty() const final;
@@ -677,13 +677,14 @@ class CurveComponentLegacy : public GeometryComponent {
const blender::bke::ComponentAttributeProviders *get_attribute_providers() const final;
blender::GVArray attribute_try_adapt_domain_impl(const blender::GVArray &varray,
- AttributeDomain from_domain,
- AttributeDomain to_domain) const final;
+ eAttrDomain from_domain,
+ eAttrDomain to_domain) const final;
};
/**
- * A geometry component that stores a group of curves, corresponding the #Curves and
- * #CurvesGeometry types.
+ * A geometry component that stores a group of curves, corresponding the #Curves data-block type
+ * and the #CurvesGeometry type. Attributes are are stored on the control point domain and the
+ * curve domain.
*/
class CurveComponent : public GeometryComponent {
private:
@@ -715,7 +716,7 @@ class CurveComponent : public GeometryComponent {
const Curves *get_for_read() const;
Curves *get_for_write();
- int attribute_domain_size(AttributeDomain domain) const final;
+ int attribute_domain_num(eAttrDomain domain) const final;
bool is_empty() const final;
@@ -734,8 +735,8 @@ class CurveComponent : public GeometryComponent {
const blender::bke::ComponentAttributeProviders *get_attribute_providers() const final;
blender::GVArray attribute_try_adapt_domain_impl(const blender::GVArray &varray,
- AttributeDomain from_domain,
- AttributeDomain to_domain) const final;
+ eAttrDomain from_domain,
+ eAttrDomain to_domain) const final;
};
/**
@@ -949,8 +950,8 @@ class InstancesComponent : public GeometryComponent {
blender::MutableSpan<blender::float4x4> instance_transforms();
blender::Span<blender::float4x4> instance_transforms() const;
- int instances_amount() const;
- int references_amount() const;
+ int instances_num() const;
+ int references_num() const;
/**
* Remove the indices that are not contained in the mask input, and remove unused instance
@@ -963,7 +964,7 @@ class InstancesComponent : public GeometryComponent {
blender::bke::CustomDataAttributes &attributes();
const blender::bke::CustomDataAttributes &attributes() const;
- int attribute_domain_size(AttributeDomain domain) const final;
+ int attribute_domain_num(eAttrDomain domain) const final;
void foreach_referenced_geometry(
blender::FunctionRef<void(const GeometrySet &geometry_set)> callback) const;
diff --git a/source/blender/blenkernel/BKE_global.h b/source/blender/blenkernel/BKE_global.h
index 06feb07aef2..96b6f7a53b0 100644
--- a/source/blender/blenkernel/BKE_global.h
+++ b/source/blender/blenkernel/BKE_global.h
@@ -81,6 +81,7 @@ typedef struct Global {
* * 1 - 30: EEVEE debug/stats values (01/2018).
* * 31: Enable the Select Debug Engine. Only available with #WITH_DRAW_DEBUG (08/2021).
* * 101: Enable UI debug drawing of fullscreen area's corner widget (10/2014).
+ * * 102: Enable extra items in string search UI (05/2022).
* * 666: Use quicker batch delete for outliners' delete hierarchy (01/2019).
* * 777: Enable UI node panel's sockets polling (11/2011).
* * 799: Enable some mysterious new depsgraph behavior (05/2015).
diff --git a/source/blender/blenkernel/BKE_gpencil.h b/source/blender/blenkernel/BKE_gpencil.h
index 60564d1282e..dc7a5ab003a 100644
--- a/source/blender/blenkernel/BKE_gpencil.h
+++ b/source/blender/blenkernel/BKE_gpencil.h
@@ -76,13 +76,13 @@ struct bGPdata;
void BKE_gpencil_free_point_weights(struct MDeformVert *dvert);
void BKE_gpencil_free_stroke_weights(struct bGPDstroke *gps);
void BKE_gpencil_free_stroke_editcurve(struct bGPDstroke *gps);
-/* free stroke, doesn't unlink from any listbase */
+/** Free stroke, doesn't unlink from any #ListBase. */
void BKE_gpencil_free_stroke(struct bGPDstroke *gps);
-/* Free strokes belonging to a gp-frame */
+/** Free strokes belonging to a gp-frame. */
bool BKE_gpencil_free_strokes(struct bGPDframe *gpf);
-/* Free all of a gp-layer's frames */
+/** Free all of a gp-layer's frames. */
void BKE_gpencil_free_frames(struct bGPDlayer *gpl);
-/* Free all of the gp-layers for a viewport (list should be &gpd->layers or so) */
+/** Free all of the gp-layers for a viewport (list should be `&gpd->layers` or so). */
void BKE_gpencil_free_layers(struct ListBase *list);
/** Free (or release) any data used by this grease pencil (does not free the gpencil itself). */
void BKE_gpencil_free_data(struct bGPdata *gpd, bool free_all);
@@ -108,9 +108,9 @@ void BKE_gpencil_batch_cache_free(struct bGPdata *gpd);
*/
void BKE_gpencil_stroke_sync_selection(struct bGPdata *gpd, struct bGPDstroke *gps);
void BKE_gpencil_curve_sync_selection(struct bGPdata *gpd, struct bGPDstroke *gps);
-/* Assign unique stroke ID for selection. */
+/** Assign unique stroke ID for selection. */
void BKE_gpencil_stroke_select_index_set(struct bGPdata *gpd, struct bGPDstroke *gps);
-/* Reset unique stroke ID for selection. */
+/** Reset unique stroke ID for selection. */
void BKE_gpencil_stroke_select_index_reset(struct bGPDstroke *gps);
/**
diff --git a/source/blender/blenkernel/BKE_icons.h b/source/blender/blenkernel/BKE_icons.h
index db45e405e79..8d9351806c4 100644
--- a/source/blender/blenkernel/BKE_icons.h
+++ b/source/blender/blenkernel/BKE_icons.h
@@ -172,7 +172,7 @@ bool BKE_previewimg_id_supports_jobs(const struct ID *id);
/**
* Trigger deferred loading of a custom image file into the preview buffer.
*/
-void BKE_previewimg_id_custom_set(struct ID *id, const char *path);
+void BKE_previewimg_id_custom_set(struct ID *id, const char *filepath);
/**
* Free the preview image belonging to the id.
@@ -223,11 +223,12 @@ struct PreviewImage *BKE_previewimg_cached_get(const char *name);
struct PreviewImage *BKE_previewimg_cached_ensure(const char *name);
/**
- * Generate a #PreviewImage from given file path, using thumbnails management, if not yet existing.
- * Does not actually generate the preview, #BKE_previewimg_ensure() must be called for that.
+ * Generate a #PreviewImage from given `filepath`, using thumbnails management, if not yet
+ * existing. Does not actually generate the preview, #BKE_previewimg_ensure() must be called for
+ * that.
*/
struct PreviewImage *BKE_previewimg_cached_thumbnail_read(const char *name,
- const char *path,
+ const char *filepath,
int source,
bool force_update);
diff --git a/source/blender/blenkernel/BKE_image.h b/source/blender/blenkernel/BKE_image.h
index 42d0e66cf49..1f131568900 100644
--- a/source/blender/blenkernel/BKE_image.h
+++ b/source/blender/blenkernel/BKE_image.h
@@ -273,14 +273,6 @@ bool BKE_image_is_openexr(struct Image *ima);
void BKE_image_backup_render(struct Scene *scene, struct Image *ima, bool free_current_slot);
/**
- * For single-layer OpenEXR saving.
- */
-bool BKE_image_save_openexr_multiview(struct Image *ima,
- struct ImBuf *ibuf,
- const char *filepath,
- int flags);
-
-/**
* Goes over all textures that use images.
*/
void BKE_image_free_all_textures(struct Main *bmain);
@@ -379,6 +371,11 @@ typedef enum {
} eUDIM_TILE_FORMAT;
/**
+ * Checks if the filename portion of the path contains a UDIM token.
+ */
+bool BKE_image_is_filename_tokenized(char *filepath);
+
+/**
* Ensures that `filename` contains a UDIM token if we find a supported format pattern.
* \note This must only be the name component (without slashes).
*/
@@ -387,7 +384,7 @@ 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,
+ * 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);
@@ -454,7 +451,7 @@ bool BKE_image_is_dirty_writable(struct Image *image, bool *r_is_writable);
int BKE_image_sequence_guess_offset(struct Image *image);
bool BKE_image_has_anim(struct Image *image);
bool BKE_image_has_packedfile(const struct Image *image);
-bool BKE_image_has_filepath(struct Image *ima);
+bool BKE_image_has_filepath(const struct Image *ima);
/**
* Checks the image buffer changes with time (not keyframed values).
*/
diff --git a/source/blender/blenkernel/BKE_image_format.h b/source/blender/blenkernel/BKE_image_format.h
index 633af54ea4f..6a03d1d8df5 100644
--- a/source/blender/blenkernel/BKE_image_format.h
+++ b/source/blender/blenkernel/BKE_image_format.h
@@ -76,6 +76,8 @@ char BKE_imtype_from_arg(const char *arg);
void BKE_image_format_from_imbuf(struct ImageFormatData *im_format, const struct ImBuf *imbuf);
void BKE_image_format_to_imbuf(struct ImBuf *ibuf, const struct ImageFormatData *imf);
+bool BKE_image_format_is_byte(const struct ImageFormatData *imf);
+
/* Color Management */
void BKE_image_format_color_management_copy(struct ImageFormatData *imf,
diff --git a/source/blender/blenkernel/BKE_image_partial_update.hh b/source/blender/blenkernel/BKE_image_partial_update.hh
index 393bf003caa..6611efe7a61 100644
--- a/source/blender/blenkernel/BKE_image_partial_update.hh
+++ b/source/blender/blenkernel/BKE_image_partial_update.hh
@@ -172,6 +172,11 @@ class ImageTileData : AbstractTileData {
if (image_user != nullptr) {
this->image_user = *image_user;
}
+ else {
+ /* When no image user is given the lastframe of the image should be used. This reflect the
+ * same logic when using a stencil image in the clone tool. */
+ this->image_user.framenr = image->lastframe;
+ }
}
void init_data(TileNumber new_tile_number) override
diff --git a/source/blender/blenkernel/BKE_image_save.h b/source/blender/blenkernel/BKE_image_save.h
index 052fc937af9..673a7dffb82 100644
--- a/source/blender/blenkernel/BKE_image_save.h
+++ b/source/blender/blenkernel/BKE_image_save.h
@@ -13,10 +13,11 @@ extern "C" {
#endif
struct Image;
+struct ImageUser;
struct Main;
+struct RenderResult;
struct ReportList;
struct Scene;
-struct RenderResult;
/* Image datablock saving. */
@@ -34,11 +35,20 @@ typedef struct ImageSaveOptions {
bool save_copy;
bool save_as_render;
bool do_newpath;
+
+ /* Keep track of previous values for auto updates in UI. */
+ bool prev_save_as_render;
+ int prev_imtype;
} ImageSaveOptions;
-void BKE_image_save_options_init(struct ImageSaveOptions *opts,
+bool BKE_image_save_options_init(ImageSaveOptions *opts,
struct Main *bmain,
- struct Scene *scene);
+ struct Scene *scene,
+ struct Image *ima,
+ struct ImageUser *iuser,
+ const bool guess_path,
+ const bool save_as_render);
+void BKE_image_save_options_update(struct ImageSaveOptions *opts, struct Image *ima);
void BKE_image_save_options_free(struct ImageSaveOptions *opts);
bool BKE_image_save(struct ReportList *reports,
diff --git a/source/blender/blenkernel/BKE_lib_id.h b/source/blender/blenkernel/BKE_lib_id.h
index 504ab47c1c5..beac608a138 100644
--- a/source/blender/blenkernel/BKE_lib_id.h
+++ b/source/blender/blenkernel/BKE_lib_id.h
@@ -603,7 +603,7 @@ bool BKE_id_can_be_asset(const struct ID *id);
* we should either cache that status info also in virtual override IDs, or address the
* long-standing TODO of getting an efficient 'owner_id' access for all embedded ID types.
*/
-bool BKE_id_is_editable(struct Main *bmain, struct ID *id);
+bool BKE_id_is_editable(const struct Main *bmain, const struct ID *id);
/**
* Returns ordered list of data-blocks for display in the UI.
diff --git a/source/blender/blenkernel/BKE_lib_override.h b/source/blender/blenkernel/BKE_lib_override.h
index dfb2b900b10..2e28b3c00ee 100644
--- a/source/blender/blenkernel/BKE_lib_override.h
+++ b/source/blender/blenkernel/BKE_lib_override.h
@@ -62,12 +62,25 @@ void BKE_lib_override_library_free(struct IDOverrideLibrary **override, bool do_
/**
* Check if given ID has some override rules that actually indicate the user edited it.
*/
-bool BKE_lib_override_library_is_user_edited(struct ID *id);
+bool BKE_lib_override_library_is_user_edited(const struct ID *id);
/**
* Check if given ID is a system override.
*/
-bool BKE_lib_override_library_is_system_defined(struct Main *bmain, struct ID *id);
+bool BKE_lib_override_library_is_system_defined(const struct Main *bmain, const struct ID *id);
+
+/**
+ * Check if given Override Property for given ID is animated (through a F-Curve in an Action, or
+ * from a driver).
+ *
+ * \param override_rna_prop if not NULL, the RNA property matching the given path in the
+ * `override_prop`.
+ * \param rnaprop_index Array in the RNA property, 0 if unknown or irrelevant.
+ */
+bool BKE_lib_override_library_property_is_animated(const ID *id,
+ const IDOverrideLibraryProperty *override_prop,
+ const struct PropertyRNA *override_rna_prop,
+ const int rnaprop_index);
/**
* Check if given ID is a leaf in its liboverride hierarchy (i.e. if it does not use any other
@@ -116,6 +129,8 @@ struct ID *BKE_lib_override_library_create_from_id(struct Main *bmain,
* \param do_no_main: Create the new override data outside of Main database.
* Used for resyncing of linked overrides.
*
+ * \param do_fully_editable: if true, tag all created overrides as user-editable by default.
+ *
* \return \a true on success, \a false otherwise.
*/
bool BKE_lib_override_library_create_from_tag(struct Main *bmain,
@@ -123,7 +138,8 @@ bool BKE_lib_override_library_create_from_tag(struct Main *bmain,
const struct ID *id_root_reference,
struct ID *id_hierarchy_root,
const struct ID *id_hierarchy_root_reference,
- bool do_no_main);
+ bool do_no_main,
+ const bool do_fully_editable);
/**
* Advanced 'smart' function to create fully functional overrides.
*
@@ -154,6 +170,8 @@ bool BKE_lib_override_library_create_from_tag(struct Main *bmain,
*
* \param r_id_root_override: if not NULL, the override generated for the given \a id_root.
*
+ * \param do_fully_editable: if true, tag all created overrides as user-editable by default.
+ *
* \return true if override was successfully created.
*/
bool BKE_lib_override_library_create(struct Main *bmain,
@@ -163,7 +181,8 @@ bool BKE_lib_override_library_create(struct Main *bmain,
struct ID *id_root_reference,
struct ID *id_hierarchy_root_reference,
struct ID *id_instance_hint,
- struct ID **r_id_root_override);
+ struct ID **r_id_root_override,
+ const bool do_fully_editable);
/**
* Create a library override template.
*/
@@ -275,11 +294,14 @@ void BKE_lib_override_library_property_delete(struct IDOverrideLibrary *override
*
* \param idpoin: Pointer to the override ID.
* \param library_prop: The library override property to find the matching RNA property for.
+ * \param r_index: The RNA array flat index (i.e. flattened index in case of multi-dimensional
+ * array properties). See #RNA_path_resolve_full family of functions for details.
*/
bool BKE_lib_override_rna_property_find(struct PointerRNA *idpoin,
const struct IDOverrideLibraryProperty *library_prop,
struct PointerRNA *r_override_poin,
- struct PropertyRNA **r_override_prop);
+ struct PropertyRNA **r_override_prop,
+ int *r_index);
/**
* Find override property operation from given sub-item(s), if it exists.
diff --git a/source/blender/blenkernel/BKE_lib_remap.h b/source/blender/blenkernel/BKE_lib_remap.h
index f62225179bd..37b626fb4da 100644
--- a/source/blender/blenkernel/BKE_lib_remap.h
+++ b/source/blender/blenkernel/BKE_lib_remap.h
@@ -95,11 +95,11 @@ typedef enum eIDRemapType {
*/
void BKE_libblock_remap_multiple_locked(struct Main *bmain,
struct IDRemapper *mappings,
- const short remap_flags);
+ short remap_flags);
void BKE_libblock_remap_multiple(struct Main *bmain,
struct IDRemapper *mappings,
- const short remap_flags);
+ short remap_flags);
/**
* Replace all references in given Main to \a old_id by \a new_id
@@ -142,9 +142,9 @@ void BKE_libblock_relink_ex(struct Main *bmain,
*/
void BKE_libblock_relink_multiple(struct Main *bmain,
struct LinkNode *ids,
- const eIDRemapType remap_type,
+ eIDRemapType remap_type,
struct IDRemapper *id_remapper,
- const short remap_flags);
+ short remap_flags);
/**
* Remaps ID usages of given ID to their `id->newid` pointer if not None, and proceeds recursively
diff --git a/source/blender/blenkernel/BKE_main.h b/source/blender/blenkernel/BKE_main.h
index 59b22f7759b..2c444f42c46 100644
--- a/source/blender/blenkernel/BKE_main.h
+++ b/source/blender/blenkernel/BKE_main.h
@@ -77,8 +77,16 @@ typedef struct MainIDRelationsEntry {
typedef enum eMainIDRelationsEntryTags {
/* Generic tag marking the entry as to be processed. */
MAINIDRELATIONS_ENTRY_TAGS_DOIT = 1 << 0,
+
+ /* Generic tag marking the entry as processed in the `to` direction (i.e. we processed the IDs
+ * used by this item). */
+ MAINIDRELATIONS_ENTRY_TAGS_PROCESSED_TO = 1 << 1,
+ /* Generic tag marking the entry as processed in the `from` direction (i.e. we processed the IDs
+ * using by this item). */
+ MAINIDRELATIONS_ENTRY_TAGS_PROCESSED_FROM = 1 << 2,
/* Generic tag marking the entry as processed. */
- MAINIDRELATIONS_ENTRY_TAGS_PROCESSED = 1 << 1,
+ MAINIDRELATIONS_ENTRY_TAGS_PROCESSED = MAINIDRELATIONS_ENTRY_TAGS_PROCESSED_TO |
+ MAINIDRELATIONS_ENTRY_TAGS_PROCESSED_FROM,
} eMainIDRelationsEntryTags;
typedef struct MainIDRelations {
diff --git a/source/blender/blenkernel/BKE_material.h b/source/blender/blenkernel/BKE_material.h
index f38f6afff7e..05e502f06c2 100644
--- a/source/blender/blenkernel/BKE_material.h
+++ b/source/blender/blenkernel/BKE_material.h
@@ -52,7 +52,7 @@ void BKE_object_material_remap_calc(struct Object *ob_dst,
*/
void BKE_object_material_from_eval_data(struct Main *bmain,
struct Object *ob_orig,
- struct ID *data_eval);
+ const struct ID *data_eval);
struct Material *BKE_material_add(struct Main *bmain, const char *name);
struct Material *BKE_gpencil_material_add(struct Main *bmain, const char *name);
void BKE_gpencil_material_attr_init(struct Material *ma);
diff --git a/source/blender/blenkernel/BKE_mesh.h b/source/blender/blenkernel/BKE_mesh.h
index 091f30825ae..23ec69babc8 100644
--- a/source/blender/blenkernel/BKE_mesh.h
+++ b/source/blender/blenkernel/BKE_mesh.h
@@ -204,6 +204,7 @@ 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, bool use_smooth);
+void BKE_mesh_auto_smooth_flag_set(struct Mesh *me, bool use_auto_smooth, float auto_smooth_angle);
/**
* Needed after converting a mesh with subsurf optimal display to mesh.
@@ -931,13 +932,6 @@ void BKE_mesh_flush_select_from_polys_ex(struct MVert *mvert,
const struct MPoly *mpoly,
int totpoly);
void BKE_mesh_flush_select_from_polys(struct Mesh *me);
-void BKE_mesh_flush_select_from_verts_ex(const struct MVert *mvert,
- int totvert,
- const struct MLoop *mloop,
- struct MEdge *medge,
- int totedge,
- struct MPoly *mpoly,
- int totpoly);
void BKE_mesh_flush_select_from_verts(struct Mesh *me);
/* spatial evaluation */
diff --git a/source/blender/blenkernel/BKE_mesh_boolean_convert.hh b/source/blender/blenkernel/BKE_mesh_boolean_convert.hh
index abaf2ab0178..441783d46a1 100644
--- a/source/blender/blenkernel/BKE_mesh_boolean_convert.hh
+++ b/source/blender/blenkernel/BKE_mesh_boolean_convert.hh
@@ -23,6 +23,8 @@ namespace blender::meshintersect {
* \param material_remaps: An array of maps from material slot numbers in the corresponding mesh
* to the material slot in the first mesh. It is OK for material_remaps or any of its constituent
* arrays to be empty.
+ * \param r_intersecting_edges: Array to store indices of edges on the resulting mesh in. These
+ * 'new' edges are the result of the intersections.
*/
Mesh *direct_mesh_boolean(Span<const Mesh *> meshes,
Span<const float4x4 *> transforms,
@@ -30,6 +32,7 @@ Mesh *direct_mesh_boolean(Span<const Mesh *> meshes,
Span<Array<short>> material_remaps,
bool use_self,
bool hole_tolerant,
- int boolean_mode);
+ int boolean_mode,
+ Vector<int> *r_intersecting_edges);
} // namespace blender::meshintersect
diff --git a/source/blender/blenkernel/BKE_mesh_remap.h b/source/blender/blenkernel/BKE_mesh_remap.h
index e2b16a7681d..ee0179c7a77 100644
--- a/source/blender/blenkernel/BKE_mesh_remap.h
+++ b/source/blender/blenkernel/BKE_mesh_remap.h
@@ -42,7 +42,7 @@ void BKE_mesh_remap_free(MeshPairRemap *map);
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.
+ * Add other 'from/to' mapping sources, like e.g. using a UVMap, etc.
* https://blenderartists.org/t/619105
*
* We could also use similar topology mappings inside a same mesh
diff --git a/source/blender/blenkernel/BKE_mesh_runtime.h b/source/blender/blenkernel/BKE_mesh_runtime.h
index 0e78f9d7e15..dfefe125a51 100644
--- a/source/blender/blenkernel/BKE_mesh_runtime.h
+++ b/source/blender/blenkernel/BKE_mesh_runtime.h
@@ -8,7 +8,7 @@
* This file contains access functions for the Mesh.runtime struct.
*/
-//#include "BKE_customdata.h" /* for CustomDataMask */
+//#include "BKE_customdata.h" /* for eCustomDataMask */
#ifdef __cplusplus
extern "C" {
diff --git a/source/blender/blenkernel/BKE_mesh_sample.hh b/source/blender/blenkernel/BKE_mesh_sample.hh
index a942f3bb7ed..cbbd0249f4f 100644
--- a/source/blender/blenkernel/BKE_mesh_sample.hh
+++ b/source/blender/blenkernel/BKE_mesh_sample.hh
@@ -6,12 +6,20 @@
* \ingroup bke
*/
+#include "BLI_function_ref.hh"
#include "BLI_generic_virtual_array.hh"
#include "BLI_math_vec_types.hh"
+#include "DNA_meshdata_types.h"
+
#include "BKE_attribute.h"
struct Mesh;
+struct BVHTreeFromMesh;
+
+namespace blender {
+class RandomNumberGenerator;
+}
namespace blender::bke {
struct ReadAttributeLookup;
@@ -69,7 +77,7 @@ class MeshAttributeInterpolator {
const Span<int> looptri_indices);
void sample_data(const GVArray &src,
- AttributeDomain domain,
+ eAttrDomain domain,
eAttributeMapMode mode,
const GMutableSpan dst);
@@ -82,4 +90,55 @@ class MeshAttributeInterpolator {
Span<float3> ensure_nearest_weights();
};
+/**
+ * Find randomly distributed points on the surface of a mesh within a 3D sphere. This does not
+ * sample an exact number of points because it comes with extra overhead to avoid bias that is only
+ * required in some cases. If an exact number of points is required, that has to be implemented at
+ * a higher level.
+ *
+ * \param approximate_density: Roughly the number of points per unit of area.
+ * \return The number of added points.
+ */
+int sample_surface_points_spherical(RandomNumberGenerator &rng,
+ const Mesh &mesh,
+ Span<int> looptri_indices_to_sample,
+ const float3 &sample_pos,
+ float sample_radius,
+ float approximate_density,
+ Vector<float3> &r_bary_coords,
+ Vector<int> &r_looptri_indices,
+ Vector<float3> &r_positions);
+
+/**
+ * Find randomly distributed points on the surface of a mesh within a circle that is projected on
+ * the mesh. This does not result in an exact number of points because that would come with extra
+ * overhead and is not always possible. If an exact number of points is required, that has to be
+ * implemented at a higher level.
+ *
+ * \param region_position_to_ray: Function that converts a 2D position into a 3D ray that is used
+ * to find positions on the mesh.
+ * \param mesh_bvhtree: BVH tree of the triangles in the mesh. Passed in so that it does not have
+ * to be retrieved again.
+ * \param tries_num: Number of 2d positions that are sampled. The maximum
+ * number of new samples.
+ * \return The number of added points.
+ */
+int sample_surface_points_projected(
+ RandomNumberGenerator &rng,
+ const Mesh &mesh,
+ BVHTreeFromMesh &mesh_bvhtree,
+ const float2 &sample_pos_re,
+ float sample_radius_re,
+ FunctionRef<void(const float2 &pos_re, float3 &r_start, float3 &r_end)> region_position_to_ray,
+ bool front_face_only,
+ int tries_num,
+ int max_points,
+ Vector<float3> &r_bary_coords,
+ Vector<int> &r_looptri_indices,
+ Vector<float3> &r_positions);
+
+float3 compute_bary_coord_in_triangle(const Mesh &mesh,
+ const MLoopTri &looptri,
+ const float3 &position);
+
} // namespace blender::bke::mesh_surface_sample
diff --git a/source/blender/blenkernel/BKE_mesh_tangent.h b/source/blender/blenkernel/BKE_mesh_tangent.h
index 27061a5766e..58142653a90 100644
--- a/source/blender/blenkernel/BKE_mesh_tangent.h
+++ b/source/blender/blenkernel/BKE_mesh_tangent.h
@@ -21,7 +21,7 @@ void BKE_mesh_calc_loop_tangent_single_ex(const struct MVert *mverts,
int numVerts,
const struct MLoop *mloops,
float (*r_looptangent)[4],
- float (*loopnors)[3],
+ const float (*loopnors)[3],
const struct MLoopUV *loopuv,
int numLoops,
const struct MPoly *mpolys,
diff --git a/source/blender/blenkernel/BKE_modifier.h b/source/blender/blenkernel/BKE_modifier.h
index a38bfb497a2..866b0353d07 100644
--- a/source/blender/blenkernel/BKE_modifier.h
+++ b/source/blender/blenkernel/BKE_modifier.h
@@ -102,6 +102,7 @@ typedef enum {
/** Accepts #BMesh input (without conversion). */
eModifierTypeFlag_AcceptsBMesh = (1 << 11),
} ModifierTypeFlag;
+ENUM_OPERATORS(ModifierTypeFlag, eModifierTypeFlag_AcceptsBMesh)
typedef void (*IDWalkFunc)(void *userData, struct Object *ob, struct ID **idpoin, int cb_flag);
typedef void (*TexWalkFunc)(void *userData,
@@ -363,7 +364,9 @@ typedef struct ModifierTypeInfo {
* This method should write any additional arrays and referenced structs that should be
* stored in the file.
*/
- void (*blendWrite)(struct BlendWriter *writer, const struct ModifierData *md);
+ void (*blendWrite)(struct BlendWriter *writer,
+ const struct ID *id_owner,
+ const struct ModifierData *md);
/**
* Is called when the modifier is read from a file.
@@ -592,7 +595,9 @@ struct Mesh *BKE_modifier_get_evaluated_mesh_from_evaluated_object(struct Object
void BKE_modifier_check_uuids_unique_and_report(const struct Object *object);
-void BKE_modifier_blend_write(struct BlendWriter *writer, struct ListBase *modbase);
+void BKE_modifier_blend_write(struct BlendWriter *writer,
+ const struct ID *id_owner,
+ struct ListBase *modbase);
void BKE_modifier_blend_read_data(struct BlendDataReader *reader,
struct ListBase *lb,
struct Object *ob);
diff --git a/source/blender/blenkernel/BKE_multires.h b/source/blender/blenkernel/BKE_multires.h
index 0efe38c1e8f..dfa330ff508 100644
--- a/source/blender/blenkernel/BKE_multires.h
+++ b/source/blender/blenkernel/BKE_multires.h
@@ -130,7 +130,7 @@ void multiresModifier_prepare_join(struct Depsgraph *depsgraph,
struct Object *ob,
struct Object *to_ob);
-int multires_mdisp_corners(struct MDisps *s);
+int multires_mdisp_corners(const struct MDisps *s);
/**
* Update multi-res data after topology changing.
diff --git a/source/blender/blenkernel/BKE_node.h b/source/blender/blenkernel/BKE_node.h
index d9a0b841708..5917f9b88d7 100644
--- a/source/blender/blenkernel/BKE_node.h
+++ b/source/blender/blenkernel/BKE_node.h
@@ -1493,7 +1493,10 @@ struct TexResult;
#define GEO_NODE_STORE_NAMED_ATTRIBUTE 1156
#define GEO_NODE_INPUT_NAMED_ATTRIBUTE 1157
#define GEO_NODE_REMOVE_ATTRIBUTE 1158
-#define GEO_NODE_DEFORM_CURVES_WITH_SURFACE 1159
+#define GEO_NODE_INPUT_INSTANCE_ROTATION 1159
+#define GEO_NODE_INPUT_INSTANCE_SCALE 1160
+#define GEO_NODE_VOLUME_CUBE 1161
+#define GEO_NODE_DEFORM_CURVES_WITH_SURFACE 1162
/** \} */
diff --git a/source/blender/blenkernel/BKE_node_runtime.hh b/source/blender/blenkernel/BKE_node_runtime.hh
new file mode 100644
index 00000000000..f5fb53f962b
--- /dev/null
+++ b/source/blender/blenkernel/BKE_node_runtime.hh
@@ -0,0 +1,89 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+
+#pragma once
+
+#include <memory>
+
+#include "BLI_sys_types.h"
+#include "BLI_utility_mixins.hh"
+
+namespace blender::nodes {
+struct FieldInferencingInterface;
+class NodeDeclaration;
+} // namespace blender::nodes
+
+namespace blender::bke {
+
+class bNodeTreeRuntime : NonCopyable, NonMovable {
+ public:
+ /**
+ * 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 = 0;
+ /**
+ * 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 = 0;
+
+ /**
+ * Used to cache run-time information of the node tree.
+ * #eNodeTreeRuntimeFlag.
+ */
+ uint8_t runtime_flag = 0;
+
+ /** Information about how inputs and outputs of the node group interact with fields. */
+ std::unique_ptr<nodes::FieldInferencingInterface> field_inferencing_interface;
+};
+
+/**
+ * Run-time data for every socket. This should only contain data that is somewhat persistent (i.e.
+ * data that lives longer than a single depsgraph evaluation + redraw). Data that's only used in
+ * smaller scopes should generally be stored in separate arrays and/or maps.
+ */
+class bNodeSocketRuntime : NonCopyable, NonMovable {
+ public:
+ /**
+ * References a socket declaration that is owned by `node->declaration`. This is only runtime
+ * data. It has to be updated when the node declaration changes.
+ */
+ const SocketDeclarationHandle *declaration = nullptr;
+
+ /** #eNodeTreeChangedFlag. */
+ uint32_t changed_flag = 0;
+};
+
+/**
+ * Run-time data for every node. This should only contain data that is somewhat persistent (i.e.
+ * data that lives longer than a single depsgraph evaluation + redraw). Data that's only used in
+ * smaller scopes should generally be stored in separate arrays and/or maps.
+ */
+class bNodeRuntime : NonCopyable, NonMovable {
+ public:
+ /**
+ * Describes the desired interface of the node. This is run-time data only.
+ * The actual interface of the node may deviate from the declaration temporarily.
+ * It's possible to sync the actual state of the node to the desired state. Currently, this is
+ * only done when a node is created or loaded.
+ *
+ * In the future, we may want to keep more data only in the declaration, so that it does not have
+ * to be synced to other places that are stored in files. That especially applies to data that
+ * can't be edited by users directly (e.g. min/max values of sockets, tooltips, ...).
+ *
+ * The declaration of a node can be recreated at any time when it is used. Caching it here is
+ * just a bit more efficient when it is used a lot. To make sure that the cache is up-to-date,
+ * call #nodeDeclarationEnsure before using it.
+ *
+ * Currently, the declaration is the same for every node of the same type. Going forward, that is
+ * intended to change though. Especially when nodes become more dynamic with respect to how many
+ * sockets they have.
+ */
+ NodeDeclarationHandle *declaration = nullptr;
+
+ /** #eNodeTreeChangedFlag. */
+ uint32_t changed_flag = 0;
+};
+
+} // namespace blender::bke
diff --git a/source/blender/blenkernel/BKE_paint.h b/source/blender/blenkernel/BKE_paint.h
index 03cbcf575c3..a47e4a24f75 100644
--- a/source/blender/blenkernel/BKE_paint.h
+++ b/source/blender/blenkernel/BKE_paint.h
@@ -180,6 +180,7 @@ struct Paint *BKE_paint_get_active_from_context(const struct bContext *C);
ePaintMode BKE_paintmode_get_active_from_context(const struct bContext *C);
ePaintMode BKE_paintmode_get_from_tool(const struct bToolRef *tref);
struct Brush *BKE_paint_brush(struct Paint *paint);
+const struct Brush *BKE_paint_brush_for_read(const struct Paint *p);
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);
@@ -500,8 +501,8 @@ typedef struct SculptSession {
struct MPropCol *vcol;
struct MLoopCol *mcol;
- AttributeDomain vcol_domain;
- CustomDataType vcol_type;
+ eAttrDomain vcol_domain;
+ eCustomDataType vcol_type;
float *vmask;
@@ -612,6 +613,10 @@ 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 123fdbb8bac..5f8b2fafdd3 100644
--- a/source/blender/blenkernel/BKE_particle.h
+++ b/source/blender/blenkernel/BKE_particle.h
@@ -583,7 +583,7 @@ void psys_interpolate_face(struct Mesh *mesh,
const float (*vert_normals)[3],
struct MFace *mface,
struct MTFace *tface,
- float (*orcodata)[3],
+ const float (*orcodata)[3],
float w[4],
float vec[3],
float nor[3],
diff --git a/source/blender/blenkernel/BKE_pbvh.h b/source/blender/blenkernel/BKE_pbvh.h
index 291b9b6b778..f517ff3a949 100644
--- a/source/blender/blenkernel/BKE_pbvh.h
+++ b/source/blender/blenkernel/BKE_pbvh.h
@@ -221,7 +221,8 @@ void BKE_pbvh_draw_cb(PBVH *pbvh,
PBVHFrustumPlanes *update_frustum,
PBVHFrustumPlanes *draw_frustum,
void (*draw_fn)(void *user_data, struct GPU_PBVH_Buffers *buffers),
- void *user_data);
+ void *user_data,
+ bool full_render);
void BKE_pbvh_draw_debug_cb(
PBVH *pbvh,
@@ -549,7 +550,7 @@ PBVHColorBufferNode *BKE_pbvh_node_color_buffer_get(PBVHNode *node);
void BKE_pbvh_node_color_buffer_free(PBVH *pbvh);
bool BKE_pbvh_get_color_layer(const struct Mesh *me,
CustomDataLayer **r_layer,
- AttributeDomain *r_attr);
+ eAttrDomain *r_attr);
/* Swaps colors at each element in indices (of domain pbvh->vcol_domain)
* with values in colors. */
diff --git a/source/blender/blenkernel/BKE_pbvh_pixels.hh b/source/blender/blenkernel/BKE_pbvh_pixels.hh
index fdfb5fa037e..e73950e6299 100644
--- a/source/blender/blenkernel/BKE_pbvh_pixels.hh
+++ b/source/blender/blenkernel/BKE_pbvh_pixels.hh
@@ -132,12 +132,22 @@ struct UDIMTilePixels {
}
};
+struct UDIMTileUndo {
+ short tile_number;
+ rcti region;
+
+ UDIMTileUndo(short tile_number, rcti &region) : tile_number(tile_number), region(region)
+ {
+ }
+};
+
struct NodeData {
struct {
bool dirty : 1;
} flags;
Vector<UDIMTilePixels> tiles;
+ Vector<UDIMTileUndo> undo_regions;
Triangles triangles;
NodeData()
@@ -155,6 +165,23 @@ struct NodeData {
return nullptr;
}
+ void rebuild_undo_regions()
+ {
+ undo_regions.clear();
+ for (UDIMTilePixels &tile : tiles) {
+ rcti region;
+ BLI_rcti_init_minmax(&region);
+ for (PackedPixelRow &pixel_row : tile.pixel_rows) {
+ BLI_rcti_do_minmax_v(
+ &region, int2(pixel_row.start_image_coordinate.x, pixel_row.start_image_coordinate.y));
+ BLI_rcti_do_minmax_v(&region,
+ int2(pixel_row.start_image_coordinate.x + pixel_row.num_pixels + 1,
+ pixel_row.start_image_coordinate.y + 1));
+ }
+ undo_regions.append(UDIMTileUndo(tile.tile_number, region));
+ }
+ }
+
void mark_region(Image &image, const image::ImageTileWrapper &image_tile, ImBuf &image_buffer)
{
UDIMTilePixels *tile = find_tile_data(image_tile);
diff --git a/source/blender/blenkernel/BKE_pointcloud.h b/source/blender/blenkernel/BKE_pointcloud.h
index c238a24f173..6dbba11a56d 100644
--- a/source/blender/blenkernel/BKE_pointcloud.h
+++ b/source/blender/blenkernel/BKE_pointcloud.h
@@ -30,8 +30,7 @@ struct BoundBox *BKE_pointcloud_boundbox_get(struct Object *ob);
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,
- struct CustomDataLayer *layer);
+bool BKE_pointcloud_customdata_required(const struct PointCloud *pointcloud, const char *name);
/* Dependency Graph */
diff --git a/source/blender/blenkernel/BKE_shrinkwrap.h b/source/blender/blenkernel/BKE_shrinkwrap.h
index 2144419728e..3e06bd84805 100644
--- a/source/blender/blenkernel/BKE_shrinkwrap.h
+++ b/source/blender/blenkernel/BKE_shrinkwrap.h
@@ -73,7 +73,7 @@ typedef struct ShrinkwrapTreeData {
BVHTreeFromMesh treeData;
const float (*pnors)[3];
- float (*clnors)[3];
+ const float (*clnors)[3];
ShrinkwrapBoundaryData *boundary;
} ShrinkwrapTreeData;
diff --git a/source/blender/blenkernel/BKE_sound.h b/source/blender/blenkernel/BKE_sound.h
index 8931418e49c..9965b6f1351 100644
--- a/source/blender/blenkernel/BKE_sound.h
+++ b/source/blender/blenkernel/BKE_sound.h
@@ -20,6 +20,7 @@ struct Depsgraph;
struct Main;
struct Sequence;
struct bSound;
+struct SoundInfo;
typedef struct SoundWaveform {
int length;
@@ -78,6 +79,7 @@ typedef enum eSoundChannels {
typedef struct SoundInfo {
struct {
eSoundChannels channels;
+ int samplerate;
} specs;
float length;
} SoundInfo;
@@ -134,7 +136,7 @@ void BKE_sound_remove_scene_sound(struct Scene *scene, void *handle);
void BKE_sound_mute_scene_sound(void *handle, char mute);
-void BKE_sound_move_scene_sound(struct Scene *scene,
+void BKE_sound_move_scene_sound(const struct Scene *scene,
void *handle,
int startframe,
int endframe,
diff --git a/source/blender/blenkernel/BKE_spline.hh b/source/blender/blenkernel/BKE_spline.hh
index 6cbb47dc709..28f326a4ad4 100644
--- a/source/blender/blenkernel/BKE_spline.hh
+++ b/source/blender/blenkernel/BKE_spline.hh
@@ -102,7 +102,7 @@ class Spline {
/** Return the number of control points. */
virtual int size() const = 0;
- int segments_size() const;
+ int segments_num() const;
bool is_cyclic() const;
void set_cyclic(bool value);
@@ -127,8 +127,8 @@ class Spline {
* change the generated positions, tangents, normals, mapping, etc. of the evaluated points.
*/
virtual void mark_cache_invalid() = 0;
- virtual int evaluated_points_size() const = 0;
- int evaluated_edges_size() const;
+ virtual int evaluated_points_num() const = 0;
+ int evaluated_edges_num() const;
float length() const;
@@ -164,7 +164,7 @@ class Spline {
/**
* The index of the evaluated point after the result location, accounting for wrapping when
* the spline is cyclic. If the sampled factor/length is the very end of the spline, this will
- * be the last index (#evaluated_points_size - 1).
+ * be the last index (#evaluated_points_num - 1).
*/
int next_evaluated_index;
/**
@@ -191,7 +191,7 @@ class Spline {
* 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(int samples_size) const;
+ blender::Array<float> sample_uniform_index_factors(int samples_num) const;
LookupResult lookup_data_from_index_factor(float index_factor) const;
/**
@@ -344,7 +344,7 @@ class BezierSpline final : public Spline {
bool point_is_sharp(int index) const;
void mark_cache_invalid() final;
- int evaluated_points_size() const final;
+ int evaluated_points_num() const final;
/**
* Returns access to a cache of offsets into the evaluated point array for each control point.
@@ -472,7 +472,7 @@ class NURBSpline final : public Spline {
/**
* Determines where and how the control points affect the evaluated points. The length should
- * always be the value returned by #knots_size(), and each value should be greater than or equal
+ * always be the value returned by #knots_num(), and each value should be greater than or equal
* to the previous. Only invalidated when a point is added or removed.
*/
mutable blender::Vector<float> knots_;
@@ -514,8 +514,8 @@ class NURBSpline final : public Spline {
uint8_t order() const;
void set_order(uint8_t value);
- bool check_valid_size_and_order() const;
- int knots_size() const;
+ bool check_valid_num_and_order() const;
+ int knots_num() const;
void resize(int size) final;
blender::MutableSpan<blender::float3> positions() final;
@@ -530,7 +530,7 @@ class NURBSpline final : public Spline {
blender::Span<float> weights() const;
void mark_cache_invalid() final;
- int evaluated_points_size() const final;
+ int evaluated_points_num() const final;
blender::Span<blender::float3> evaluated_positions() const final;
@@ -582,7 +582,7 @@ class PolySpline final : public Spline {
blender::Span<float> tilts() const final;
void mark_cache_invalid() final;
- int evaluated_points_size() const final;
+ int evaluated_points_num() const final;
blender::Span<blender::float3> evaluated_positions() const final;
@@ -665,7 +665,7 @@ struct CurveEval {
blender::Array<float> accumulated_spline_lengths() const;
float total_length() const;
- int total_control_point_size() const;
+ int total_control_point_num() const;
void mark_cache_invalid();
diff --git a/source/blender/blenkernel/BKE_subdiv.h b/source/blender/blenkernel/BKE_subdiv.h
index 436853fe47b..486c9430279 100644
--- a/source/blender/blenkernel/BKE_subdiv.h
+++ b/source/blender/blenkernel/BKE_subdiv.h
@@ -186,13 +186,17 @@ typedef struct Subdiv {
} cache_;
} Subdiv;
-/* =================----====--===== MODULE ==========================------== */
+/* --------------------------------------------------------------------
+ * Module.
+ */
/* (De)initialize the entire subdivision surface module. */
void BKE_subdiv_init(void);
void BKE_subdiv_exit(void);
-/* ========================== CONVERSION HELPERS ============================ */
+/* --------------------------------------------------------------------
+ * Conversion helpers.
+ */
/* NOTE: uv_smooth is eSubsurfUVSmooth. */
eSubdivFVarLinearInterpolation BKE_subdiv_fvar_interpolation_from_uv_smooth(int uv_smooth);
@@ -200,7 +204,9 @@ eSubdivFVarLinearInterpolation BKE_subdiv_fvar_interpolation_from_uv_smooth(int
eSubdivVtxBoundaryInterpolation BKE_subdiv_vtx_boundary_interpolation_from_subsurf(
int boundary_smooth);
-/* =============================== STATISTICS =============================== */
+/* --------------------------------------------------------------------
+ * Statistics.
+ */
void BKE_subdiv_stats_init(SubdivStats *stats);
@@ -211,11 +217,15 @@ void BKE_subdiv_stats_reset(SubdivStats *stats, eSubdivStatsValue value);
void BKE_subdiv_stats_print(const SubdivStats *stats);
-/* ================================ SETTINGS ================================ */
+/* --------------------------------------------------------------------
+ * Settings.
+ */
bool BKE_subdiv_settings_equal(const SubdivSettings *settings_a, const SubdivSettings *settings_b);
-/* ============================== CONSTRUCTION ============================== */
+/* --------------------------------------------------------------------
+ * Construction.
+ */
/* Construct new subdivision surface descriptor, from scratch, using given
* settings and topology. */
@@ -240,7 +250,9 @@ Subdiv *BKE_subdiv_update_from_mesh(Subdiv *subdiv,
void BKE_subdiv_free(Subdiv *subdiv);
-/* ============================ DISPLACEMENT API ============================ */
+/* --------------------------------------------------------------------
+ * Displacement API.
+ */
void BKE_subdiv_displacement_attach_from_multires(Subdiv *subdiv,
struct Mesh *mesh,
@@ -248,14 +260,18 @@ void BKE_subdiv_displacement_attach_from_multires(Subdiv *subdiv,
void BKE_subdiv_displacement_detach(Subdiv *subdiv);
-/* ============================ TOPOLOGY HELPERS ============================ */
+/* --------------------------------------------------------------------
+ * 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 ========================= */
+/* --------------------------------------------------------------------
+ * PTex faces and grids.
+ */
/* For a given (ptex_u, ptex_v) within a ptex face get corresponding
* (grid_u, grid_v) within a grid. */
diff --git a/source/blender/blenkernel/BKE_subdiv_ccg.h b/source/blender/blenkernel/BKE_subdiv_ccg.h
index 31a1912bc68..b30b707759c 100644
--- a/source/blender/blenkernel/BKE_subdiv_ccg.h
+++ b/source/blender/blenkernel/BKE_subdiv_ccg.h
@@ -8,7 +8,6 @@
#pragma once
#include "BKE_DerivedMesh.h"
-#include "BKE_customdata.h"
#include "BLI_bitmap.h"
#include "BLI_sys_types.h"
@@ -21,6 +20,8 @@ struct CCGFace;
struct CCGKey;
struct DMFlagMat;
struct Mesh;
+struct MPoly;
+struct MLoop;
struct Subdiv;
/* --------------------------------------------------------------------
@@ -309,8 +310,8 @@ typedef enum SubdivCCGAdjacencyType {
* adjacent to a vertex, r_v1 and r_v2 will be the index of that vertex. */
SubdivCCGAdjacencyType BKE_subdiv_ccg_coarse_mesh_adjacency_info_get(const SubdivCCG *subdiv_ccg,
const SubdivCCGCoord *coord,
- const MLoop *mloop,
- const MPoly *mpoly,
+ const struct MLoop *mloop,
+ const struct MPoly *mpoly,
int *r_v1,
int *r_v2);
diff --git a/source/blender/blenkernel/BKE_subdiv_eval.h b/source/blender/blenkernel/BKE_subdiv_eval.h
index a33140b721d..cb0f2ac7e32 100644
--- a/source/blender/blenkernel/BKE_subdiv_eval.h
+++ b/source/blender/blenkernel/BKE_subdiv_eval.h
@@ -15,6 +15,7 @@ extern "C" {
struct Mesh;
struct OpenSubdiv_EvaluatorCache;
+struct OpenSubdiv_EvaluatorSettings;
struct Subdiv;
typedef enum eSubdivEvaluatorType {
@@ -25,7 +26,8 @@ typedef enum eSubdivEvaluatorType {
/* Returns true if evaluator is ready for use. */
bool BKE_subdiv_eval_begin(struct Subdiv *subdiv,
eSubdivEvaluatorType evaluator_type,
- struct OpenSubdiv_EvaluatorCache *evaluator_cache);
+ struct OpenSubdiv_EvaluatorCache *evaluator_cache,
+ const struct OpenSubdiv_EvaluatorSettings *settings);
/* coarse_vertex_cos is an optional argument which allows to override coordinates of the coarse
* mesh. */
@@ -60,6 +62,13 @@ void BKE_subdiv_eval_limit_point_and_derivatives(struct Subdiv *subdiv,
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 smoothly interpolated vertex data (such as ORCO). */
+void BKE_subdiv_eval_vertex_data(struct Subdiv *subdiv,
+ const int ptex_face_index,
+ const float u,
+ const float v,
+ float r_vertex_data[]);
+
/* Evaluate face-varying layer (such as UV). */
void BKE_subdiv_eval_face_varying(struct Subdiv *subdiv,
int face_varying_channel,
diff --git a/source/blender/blenkernel/BKE_subdiv_modifier.h b/source/blender/blenkernel/BKE_subdiv_modifier.h
index e9de7d1532e..271026d4253 100644
--- a/source/blender/blenkernel/BKE_subdiv_modifier.h
+++ b/source/blender/blenkernel/BKE_subdiv_modifier.h
@@ -7,6 +7,8 @@
#pragma once
+#include "BKE_subdiv.h"
+
#include "BLI_sys_types.h"
#ifdef __cplusplus
@@ -24,9 +26,30 @@ struct Subdiv;
struct SubdivSettings;
struct SubsurfModifierData;
-void BKE_subsurf_modifier_subdiv_settings_init(struct SubdivSettings *settings,
- const struct SubsurfModifierData *smd,
- bool use_render_params);
+/* Runtime subsurf modifier data, cached in modifier on evaluated meshes. */
+typedef struct SubsurfRuntimeData {
+ /* Subdivision settings, exists before descriptor or mesh wrapper is created. */
+ SubdivSettings settings;
+
+ /* Cached subdivision surface descriptor, with topology and settings. */
+ struct Subdiv *subdiv;
+ bool set_by_draw_code;
+
+ /* Cached mesh wrapper data, to be used for GPU subdiv or lazy evaluation on CPU. */
+ bool has_gpu_subdiv;
+ int resolution;
+ bool use_optimal_display;
+ bool calc_loop_normals;
+ bool use_loop_normals;
+
+ /* Cached from the draw code for stats display. */
+ int stats_totvert;
+ int stats_totedge;
+ int stats_totpoly;
+ int stats_totloop;
+} SubsurfRuntimeData;
+
+bool BKE_subsurf_modifier_runtime_init(struct SubsurfModifierData *smd, bool use_render_params);
bool BKE_subsurf_modifier_use_custom_loop_normals(const struct SubsurfModifierData *smd,
const struct Mesh *mesh);
@@ -42,18 +65,14 @@ bool BKE_subsurf_modifier_force_disable_gpu_evaluation_for_mesh(
* \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 Mesh *mesh,
- const struct SubsurfModifierData *smd,
- int required_mode,
- bool skip_check_is_last);
-
bool BKE_subsurf_modifier_can_do_gpu_subdiv(const struct Scene *scene,
const struct Object *ob,
const struct Mesh *mesh,
+ const struct SubsurfModifierData *smd,
int required_mode);
+bool BKE_subsurf_modifier_has_gpu_subdiv(const struct Mesh *mesh);
+
extern void (*BKE_subsurf_modifier_free_gpu_cache_cb)(struct Subdiv *subdiv);
/**
@@ -61,12 +80,7 @@ extern void (*BKE_subsurf_modifier_free_gpu_cache_cb)(struct Subdiv *subdiv);
* 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);
+ struct SubsurfRuntimeData *runtime_data, const struct Mesh *mesh, bool for_draw_code);
/**
* Return the #ModifierMode required for the evaluation of the subsurf modifier,
diff --git a/source/blender/blenkernel/BKE_subsurf.h b/source/blender/blenkernel/BKE_subsurf.h
index 5dd2935ad0d..f32a78c3015 100644
--- a/source/blender/blenkernel/BKE_subsurf.h
+++ b/source/blender/blenkernel/BKE_subsurf.h
@@ -61,27 +61,6 @@ int BKE_ccg_gridsize(int level);
*/
int BKE_ccg_factor(int low_level, int high_level);
-/**
- * Translate #GridHidden into the #ME_HIDE flag for MVerts. Assumes
- * vertices are in the order output by #ccgDM_copyFinalVertArray.
- */
-void subsurf_copy_grid_hidden(struct DerivedMesh *dm,
- const struct MPoly *mpoly,
- struct MVert *mvert,
- const struct MDisps *mdisps);
-
-/**
- * Translate #GridPaintMask into vertex paint masks. Assumes vertices
- * are in the order output by #ccgDM_copyFinalVertArray.
- */
-void subsurf_copy_grid_paint_mask(struct DerivedMesh *dm,
- const struct MPoly *mpoly,
- float *paint_mask,
- const struct GridPaintMask *grid_paint_mask);
-
-bool subsurf_has_edges(struct DerivedMesh *dm);
-bool subsurf_has_faces(struct DerivedMesh *dm);
-
typedef enum MultiresModifiedFlags {
/* indicates the grids have been sculpted on, so MDisps
* have to be updated */
diff --git a/source/blender/blenkernel/BKE_tracking.h b/source/blender/blenkernel/BKE_tracking.h
index 29eb180a2ab..3f6d32e2f70 100644
--- a/source/blender/blenkernel/BKE_tracking.h
+++ b/source/blender/blenkernel/BKE_tracking.h
@@ -28,7 +28,22 @@ struct Scene;
struct bGPDlayer;
struct rcti;
-/* **** Common functions **** */
+/* --------------------------------------------------------------------
+ * Common types and constants.
+ */
+
+typedef enum eTrackArea {
+ TRACK_AREA_POINT = (1 << 0),
+ TRACK_AREA_PAT = (1 << 1),
+ TRACK_AREA_SEARCH = (1 << 2),
+
+ TRACK_AREA_NONE = 0,
+ TRACK_AREA_ALL = (TRACK_AREA_POINT | TRACK_AREA_PAT | TRACK_AREA_SEARCH),
+} eTrackArea;
+
+/* --------------------------------------------------------------------
+ * Common functions.
+ */
/**
* Free tracking structure, only frees structure contents
@@ -84,7 +99,10 @@ void BKE_tracking_get_projection_matrix(struct MovieTracking *tracking,
int winy,
float mat[4][4]);
-/* **** Clipboard **** */
+/* --------------------------------------------------------------------
+ * Clipboard.
+ */
+
/**
* Free clipboard by freeing memory used by all tracks in it.
*/
@@ -204,15 +222,21 @@ bool BKE_tracking_track_has_marker_at_frame(struct MovieTrackingTrack *track, in
bool BKE_tracking_track_has_enabled_marker_at_frame(struct MovieTrackingTrack *track, int framenr);
/**
- * Clear track's path:
- *
- * - If action is #TRACK_CLEAR_REMAINED path from `ref_frame+1` up to end will be clear.
- * - If action is #TRACK_CLEAR_UPTO path from the beginning up to `ref_frame-1` will be clear.
- * - If action is #TRACK_CLEAR_ALL only marker at frame ref_frame will remain.
+ * Clear track's path.
*
* \note frame number should be in clip space, not scene space.
*/
-void BKE_tracking_track_path_clear(struct MovieTrackingTrack *track, int ref_frame, int action);
+typedef enum eTrackClearAction {
+ /* Clear path from `ref_frame+1` up to the . */
+ TRACK_CLEAR_UPTO,
+ /* Clear path from the beginning up to `ref_frame-1`. */
+ TRACK_CLEAR_REMAINED,
+ /* Only marker at frame `ref_frame` will remain. */
+ TRACK_CLEAR_ALL,
+} eTrackClearAction;
+void BKE_tracking_track_path_clear(struct MovieTrackingTrack *track,
+ int ref_frame,
+ eTrackClearAction action);
void BKE_tracking_tracks_join(struct MovieTracking *tracking,
struct MovieTrackingTrack *dst_track,
@@ -240,7 +264,9 @@ float BKE_tracking_track_get_weight_for_marker(struct MovieClip *clip,
struct MovieTrackingTrack *track,
struct MovieTrackingMarker *marker);
-/* Selection */
+/* --------------------------------------------------------------------
+ * Selection.
+ */
/**
* \param area: which part of marker should be selected. see TRACK_AREA_* constants.
@@ -252,12 +278,43 @@ void BKE_tracking_track_select(struct ListBase *tracksbase,
void BKE_tracking_track_deselect(struct MovieTrackingTrack *track, int area);
void BKE_tracking_tracks_deselect_all(struct ListBase *tracksbase);
-/* **** Marker **** */
+/* --------------------------------------------------------------------
+ * Marker.
+ */
+
struct MovieTrackingMarker *BKE_tracking_marker_insert(struct MovieTrackingTrack *track,
struct MovieTrackingMarker *marker);
void BKE_tracking_marker_delete(struct MovieTrackingTrack *track, int framenr);
-void BKE_tracking_marker_clamp(struct MovieTrackingMarker *marker, int event);
+/**
+ * If the pattern area is outside of the search area its position will be modified in a way that it
+ * is within the pattern is within the search area.
+ *
+ * If the pattern area is already within the search area nothing happens.
+ *
+ * If the pattern area is bigger than the search area the behavior is undefined.
+ *
+ * Search area is never modified.
+ */
+void BKE_tracking_marker_clamp_pattern_position(struct MovieTrackingMarker *marker);
+
+/**
+ * If the search size is such that pattern area is (partially) outside of the search area make the
+ * search area bigger so that the pattern is within the search area.
+ *
+ * Pattern area is never modified.
+ */
+void BKE_tracking_marker_clamp_search_size(struct MovieTrackingMarker *marker);
+
+/**
+ * If the search position is such that pattern area is (partially) outside of the search area move
+ * the search area so that the pattern is within the search area.
+ *
+ * If the search area is smaller than the pattern the behavior is undefined.
+ *
+ * Pattern area is never modified.
+ */
+void BKE_tracking_marker_clamp_search_position(struct MovieTrackingMarker *marker);
/**
* Get marker closest to the given frame number.
@@ -296,7 +353,10 @@ void BKE_tracking_marker_get_subframe_position(struct MovieTrackingTrack *track,
float framenr,
float pos[2]);
-/* **** Plane Track **** */
+/* --------------------------------------------------------------------
+ * Plane track.
+ */
+
/**
* Creates new plane track out of selected point tracks.
*/
@@ -342,7 +402,10 @@ void BKE_tracking_plane_tracks_replace_point_track(struct MovieTracking *trackin
struct MovieTrackingTrack *old_track,
struct MovieTrackingTrack *new_track);
-/* **** Plane Marker **** */
+/* --------------------------------------------------------------------
+ * Plane marker.
+ */
+
struct MovieTrackingPlaneMarker *BKE_tracking_plane_marker_insert(
struct MovieTrackingPlaneTrack *plane_track, struct MovieTrackingPlaneMarker *plane_marker);
void BKE_tracking_plane_marker_delete(struct MovieTrackingPlaneTrack *plane_track, int framenr);
@@ -368,7 +431,10 @@ void BKE_tracking_plane_marker_get_subframe_corners(struct MovieTrackingPlaneTra
float framenr,
float corners[4][2]);
-/* **** Object **** */
+/* --------------------------------------------------------------------
+ * Object.
+ */
+
struct MovieTrackingObject *BKE_tracking_object_add(struct MovieTracking *tracking,
const char *name);
bool BKE_tracking_object_delete(struct MovieTracking *tracking,
@@ -390,7 +456,10 @@ struct ListBase *BKE_tracking_object_get_plane_tracks(struct MovieTracking *trac
struct MovieTrackingReconstruction *BKE_tracking_object_get_reconstruction(
struct MovieTracking *tracking, struct MovieTrackingObject *object);
-/* **** Camera **** */
+/* --------------------------------------------------------------------
+ * Camera.
+ */
+
/**
* Converts principal offset from center to offset of blender's camera.
*/
@@ -409,7 +478,10 @@ void BKE_tracking_camera_get_reconstructed_interpolate(struct MovieTracking *tra
float framenr,
float mat[4][4]);
-/* **** Distortion/Undistortion **** */
+/* --------------------------------------------------------------------
+ * (Un)distortion.
+ */
+
struct MovieDistortion *BKE_tracking_distortion_new(struct MovieTracking *tracking,
int calibration_width,
int calibration_height);
@@ -463,7 +535,10 @@ void BKE_tracking_max_distortion_delta_across_bound(struct MovieTracking *tracki
bool undistort,
float delta[2]);
-/* **** Image sampling **** */
+/* --------------------------------------------------------------------
+ * Image sampling.
+ */
+
struct ImBuf *BKE_tracking_sample_pattern(int frame_width,
int frame_height,
struct ImBuf *search_ib,
@@ -493,7 +568,9 @@ struct ImBuf *BKE_tracking_get_search_imbuf(struct ImBuf *ibuf,
void BKE_tracking_disable_channels(
struct ImBuf *ibuf, bool disable_red, bool disable_green, bool disable_blue, bool grayscale);
-/* **** 2D tracking **** */
+/* --------------------------------------------------------------------
+ * 2D tracking.
+ */
/**
* Refine marker's position using previously known keyframe.
@@ -505,7 +582,9 @@ void BKE_tracking_refine_marker(struct MovieClip *clip,
struct MovieTrackingMarker *marker,
bool backwards);
-/* *** 2D auto track *** */
+/* --------------------------------------------------------------------
+ * 2D tracking using auto-track pipeline.
+ */
struct AutoTrackContext *BKE_autotrack_context_new(struct MovieClip *clip,
struct MovieClipUser *user,
@@ -517,7 +596,9 @@ void BKE_autotrack_context_sync_user(struct AutoTrackContext *context, struct Mo
void BKE_autotrack_context_finish(struct AutoTrackContext *context);
void BKE_autotrack_context_free(struct AutoTrackContext *context);
-/* **** Plane tracking **** */
+/* --------------------------------------------------------------------
+ * Plane tracking.
+ */
/**
* \note frame number should be in clip space, not scene space.
@@ -530,7 +611,9 @@ void BKE_tracking_homography_between_two_quads(/*const*/ float reference_corners
/*const*/ float corners[4][2],
float H[3][3]);
-/* **** Camera solving **** */
+/* --------------------------------------------------------------------
+ * Camera solving.
+ */
/**
* Perform early check on whether everything is fine to start reconstruction.
@@ -617,7 +700,9 @@ void BKE_tracking_detect_harris(struct MovieTracking *tracking,
struct bGPDlayer *layer,
bool place_outside_layer);
-/* **** 2D stabilization **** */
+/* --------------------------------------------------------------------
+ * 2D stabilization.
+ */
/**
* Get stabilization data (translation, scaling and angle) for a given frame.
@@ -686,7 +771,9 @@ void BKE_tracking_dopesheet_tag_update(struct MovieTracking *tracking);
*/
void BKE_tracking_dopesheet_update(struct MovieTracking *tracking);
-/* **** Query/search **** */
+/* --------------------------------------------------------------------
+ * Query and search.
+ */
/**
* \note Returns NULL if the track comes from camera object,.
@@ -722,7 +809,9 @@ void BKE_tracking_get_rna_path_prefix_for_plane_track(
char *rna_path,
size_t rna_path_len);
-/* **** Utility macros **** */
+/* --------------------------------------------------------------------
+ * Utility macros.
+ */
#define TRACK_SELECTED(track) \
((track)->flag & SELECT || (track)->pat_flag & SELECT || (track)->search_flag & SELECT)
@@ -745,22 +834,6 @@ void BKE_tracking_get_rna_path_prefix_for_plane_track(
(((marker)->flag & MARKER_DISABLED) == 0 || ((sc)->flag & SC_HIDE_DISABLED) == 0 || \
((sc)->clip->tracking.act_track == track))
-#define TRACK_CLEAR_UPTO 0
-#define TRACK_CLEAR_REMAINED 1
-#define TRACK_CLEAR_ALL 2
-
-#define CLAMP_PAT_DIM 1
-#define CLAMP_PAT_POS 2
-#define CLAMP_SEARCH_DIM 3
-#define CLAMP_SEARCH_POS 4
-
-#define TRACK_AREA_NONE -1
-#define TRACK_AREA_POINT 1
-#define TRACK_AREA_PAT 2
-#define TRACK_AREA_SEARCH 4
-
-#define TRACK_AREA_ALL (TRACK_AREA_POINT | TRACK_AREA_PAT | TRACK_AREA_SEARCH)
-
#ifdef __cplusplus
}
#endif
diff --git a/source/blender/blenkernel/BKE_unit.h b/source/blender/blenkernel/BKE_unit.h
index d6de95a19b7..f051335fc41 100644
--- a/source/blender/blenkernel/BKE_unit.h
+++ b/source/blender/blenkernel/BKE_unit.h
@@ -19,6 +19,10 @@ struct UnitSettings;
*/
size_t BKE_unit_value_as_string_adaptive(
char *str, int len_max, double value, int prec, int system, int type, bool split, bool pad);
+/**
+ * Representation of a value in units. Negative precision is used to disable stripping of zeroes.
+ * This reduces text jumping when changing values.
+ */
size_t BKE_unit_value_as_string(char *str,
int len_max,
double value,
@@ -91,7 +95,7 @@ const char *BKE_unit_identifier_get(const void *usys_pt, int index);
double BKE_unit_scalar_get(const void *usys_pt, int index);
bool BKE_unit_is_suppressed(const void *usys_pt, int index);
-/** Aligned with #PropertyUnit. */
+/** Aligned with #PropertyUnit and `bpyunits_ucategories_items` in `bpy_utils_units.c`. */
enum {
B_UNIT_NONE = 0,
B_UNIT_LENGTH = 1,
diff --git a/source/blender/blenkernel/CMakeLists.txt b/source/blender/blenkernel/CMakeLists.txt
index c9e88362b80..8dc6f711fae 100644
--- a/source/blender/blenkernel/CMakeLists.txt
+++ b/source/blender/blenkernel/CMakeLists.txt
@@ -76,7 +76,7 @@ set(SRC
intern/asset_catalog_path.cc
intern/asset_library.cc
intern/asset_library_service.cc
- intern/attribute.c
+ intern/attribute.cc
intern/attribute_access.cc
intern/attribute_math.cc
intern/autoexec.c
@@ -117,6 +117,7 @@ set(SRC
intern/curveprofile.cc
intern/curves.cc
intern/curves_geometry.cc
+ intern/curves_utils.cc
intern/customdata.cc
intern/customdata_file.c
intern/data_transfer.c
@@ -173,7 +174,7 @@ set(SRC
intern/lib_id_delete.c
intern/lib_id_eval.c
intern/lib_id_remapper.cc
- intern/lib_override.c
+ intern/lib_override.cc
intern/lib_override_proxy_conversion.c
intern/lib_query.c
intern/lib_remap.c
@@ -356,6 +357,7 @@ set(SRC
BKE_curveprofile.h
BKE_curves.h
BKE_curves.hh
+ BKE_curves_utils.hh
BKE_customdata.h
BKE_customdata_file.h
BKE_data_transfer.h
@@ -429,6 +431,7 @@ set(SRC
BKE_multires.h
BKE_nla.h
BKE_node.h
+ BKE_node_runtime.hh
BKE_node_tree_update.h
BKE_object.h
BKE_object_deform.h
@@ -608,7 +611,7 @@ if(WITH_IMAGE_HDR)
endif()
if(WITH_IMAGE_WEBP)
- add_definitions(-DWITH_WEBP)
+ add_definitions(-DWITH_WEBP)
endif()
if(WITH_CODEC_AVI)
diff --git a/source/blender/blenkernel/intern/DerivedMesh.cc b/source/blender/blenkernel/intern/DerivedMesh.cc
index 7ca76e72839..b3a9d894944 100644
--- a/source/blender/blenkernel/intern/DerivedMesh.cc
+++ b/source/blender/blenkernel/intern/DerivedMesh.cc
@@ -52,6 +52,7 @@
#include "BKE_object.h"
#include "BKE_object_deform.h"
#include "BKE_paint.h"
+#include "BKE_subdiv_modifier.h"
#include "BLI_sys_types.h" /* for intptr_t support */
@@ -423,21 +424,6 @@ static void mesh_set_only_copy(Mesh *mesh, const CustomData_MeshMasks *mask)
#endif
}
-void DM_add_vert_layer(DerivedMesh *dm, int type, eCDAllocType alloctype, void *layer)
-{
- CustomData_add_layer(&dm->vertData, type, alloctype, layer, dm->numVertData);
-}
-
-void DM_add_edge_layer(DerivedMesh *dm, int type, eCDAllocType alloctype, void *layer)
-{
- CustomData_add_layer(&dm->edgeData, type, alloctype, layer, dm->numEdgeData);
-}
-
-void DM_add_poly_layer(DerivedMesh *dm, int type, eCDAllocType alloctype, void *layer)
-{
- CustomData_add_layer(&dm->polyData, type, alloctype, layer, dm->numPolyData);
-}
-
void *DM_get_vert_data_layer(DerivedMesh *dm, int type)
{
if (type == CD_MVERT) {
@@ -613,10 +599,10 @@ static bool mesh_has_modifier_final_normals(const Mesh *mesh_input,
/* Test if mesh has the required loop normals, in case an additional modifier
* evaluation from another instance or from an operator requests it but the
* initial normals were not loop normals. */
- const bool do_loop_normals = ((mesh_input->flag & ME_AUTOSMOOTH) != 0 ||
- (final_datamask->lmask & CD_MASK_NORMAL) != 0);
+ const bool calc_loop_normals = ((mesh_input->flag & ME_AUTOSMOOTH) != 0 ||
+ (final_datamask->lmask & CD_MASK_NORMAL) != 0);
- return (!do_loop_normals || CustomData_has_layer(&mesh_final->ldata, CD_NORMAL));
+ return (!calc_loop_normals || CustomData_has_layer(&mesh_final->ldata, CD_NORMAL));
}
static void mesh_calc_modifier_final_normals(const Mesh *mesh_input,
@@ -625,16 +611,19 @@ static void mesh_calc_modifier_final_normals(const Mesh *mesh_input,
Mesh *mesh_final)
{
/* Compute normals. */
- const bool do_loop_normals = ((mesh_input->flag & ME_AUTOSMOOTH) != 0 ||
- (final_datamask->lmask & CD_MASK_NORMAL) != 0);
+ const bool calc_loop_normals = ((mesh_input->flag & ME_AUTOSMOOTH) != 0 ||
+ (final_datamask->lmask & CD_MASK_NORMAL) != 0);
/* Needed as `final_datamask` is not preserved outside modifier stack evaluation. */
- mesh_final->runtime.subsurf_do_loop_normals = do_loop_normals;
+ SubsurfRuntimeData *subsurf_runtime_data = mesh_final->runtime.subsurf_runtime_data;
+ if (subsurf_runtime_data) {
+ subsurf_runtime_data->calc_loop_normals = calc_loop_normals;
+ }
- if (do_loop_normals) {
+ if (calc_loop_normals) {
/* Compute loop normals (NOTE: will compute poly and vert normals as well, if needed!). In case
* of deferred CPU subdivision, this will be computed when the wrapper is generated. */
- if (mesh_final->runtime.subsurf_resolution == 0) {
+ if (!subsurf_runtime_data || subsurf_runtime_data->resolution == 0) {
BKE_mesh_calc_normals_split(mesh_final);
}
}
@@ -643,14 +632,14 @@ static void mesh_calc_modifier_final_normals(const Mesh *mesh_input,
/* without this, drawing ngon tri's faces will show ugly tessellated face
* 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
+ * note that this isn't a problem for subsurf (only quads) or edit-mode
* which deals with drawing differently. */
BKE_mesh_ensure_normals_for_display(mesh_final);
}
/* Some modifiers, like data-transfer, may generate those data as temp layer,
* we do not want to keep them, as they are used by display code when available
- * (i.e. even if autosmooth is disabled). */
+ * (i.e. even if auto-smooth is disabled). */
if (CustomData_has_layer(&mesh_final->ldata, CD_NORMAL)) {
CustomData_free_layers(&mesh_final->ldata, CD_NORMAL, mesh_final->totloop);
}
@@ -1180,6 +1169,10 @@ static void mesh_calc_modifiers(struct Depsgraph *depsgraph,
BKE_id_free(nullptr, mesh_orco_cloth);
}
+ /* Remove temporary data layer only needed for modifier evaluation.
+ * Save some memory, and ensure GPU subdivision does not need to deal with this. */
+ CustomData_free_layers(&mesh_final->vdata, CD_CLOTH_ORCO, mesh_final->totvert);
+
/* Compute normals. */
if (is_own_mesh) {
mesh_calc_modifier_final_normals(mesh_input, &final_datamask, sculpt_dyntopo, mesh_final);
@@ -1277,15 +1270,18 @@ static void editbmesh_calc_modifier_final_normals(Mesh *mesh_final,
return;
}
- const bool do_loop_normals = ((mesh_final->flag & ME_AUTOSMOOTH) != 0 ||
- (final_datamask->lmask & CD_MASK_NORMAL) != 0);
+ const bool calc_loop_normals = ((mesh_final->flag & ME_AUTOSMOOTH) != 0 ||
+ (final_datamask->lmask & CD_MASK_NORMAL) != 0);
- mesh_final->runtime.subsurf_do_loop_normals = do_loop_normals;
+ SubsurfRuntimeData *subsurf_runtime_data = mesh_final->runtime.subsurf_runtime_data;
+ if (subsurf_runtime_data) {
+ subsurf_runtime_data->calc_loop_normals = calc_loop_normals;
+ }
- if (do_loop_normals) {
+ if (calc_loop_normals) {
/* Compute loop normals. In case of deferred CPU subdivision, this will be computed when the
* wrapper is generated. */
- if (mesh_final->runtime.subsurf_resolution == 0) {
+ if (!subsurf_runtime_data || subsurf_runtime_data->resolution == 0) {
BKE_mesh_calc_normals_split(mesh_final);
}
}
diff --git a/source/blender/blenkernel/intern/action.c b/source/blender/blenkernel/intern/action.c
index 371bd8ded6d..05b51e0c9fa 100644
--- a/source/blender/blenkernel/intern/action.c
+++ b/source/blender/blenkernel/intern/action.c
@@ -980,13 +980,10 @@ void BKE_pose_channels_remove(Object *ob,
else {
/* Maybe something the bone references is being removed instead? */
for (con = pchan->constraints.first; con; con = con->next) {
- const bConstraintTypeInfo *cti = BKE_constraint_typeinfo_get(con);
ListBase targets = {NULL, NULL};
bConstraintTarget *ct;
- if (cti && cti->get_constraint_targets) {
- cti->get_constraint_targets(con, &targets);
-
+ if (BKE_constraint_targets_get(con, &targets)) {
for (ct = targets.first; ct; ct = ct->next) {
if (ct->tar == ob) {
if (ct->subtarget[0]) {
@@ -998,9 +995,7 @@ void BKE_pose_channels_remove(Object *ob,
}
}
- if (cti->flush_constraint_targets) {
- cti->flush_constraint_targets(con, &targets, 0);
- }
+ BKE_constraint_targets_flush(con, &targets, 0);
}
}
diff --git a/source/blender/blenkernel/intern/anim_sys.c b/source/blender/blenkernel/intern/anim_sys.c
index b886722676b..eb4784bebff 100644
--- a/source/blender/blenkernel/intern/anim_sys.c
+++ b/source/blender/blenkernel/intern/anim_sys.c
@@ -2868,7 +2868,7 @@ static void nlastrip_evaluate_meta(const int evaluation_mode,
/* Assert currently supported modes. If new mode added, then assertion marks potentially missed
* area.
*
- * Note: In the future if support is ever added to metastrips to support nested tracks, then
+ * NOTE: In the future if support is ever added to metastrips to support nested tracks, then
* STRIP_EVAL_BLEND and STRIP_EVAL_BLEND_GET_INVERTED_LOWER_SNAPSHOT cases are no longer
* equivalent. The output of nlastrips_ctime_get_strip() may return a list of strips. The only
* case difference should be the evaluation order.
@@ -4074,7 +4074,7 @@ void BKE_animsys_evaluate_all_animation(Main *main, Depsgraph *depsgraph, float
/* objects */
/* ADT_RECALC_ANIM doesn't need to be supplied here, since object AnimData gets
- * this tagged by Depsgraph on framechange. This optimization means that objects
+ * this tagged by Depsgraph on frame-change. This optimization means that objects
* linked from other (not-visible) scenes will not need their data calculated.
*/
EVAL_ANIM_IDS(main->objects.first, 0);
diff --git a/source/blender/blenkernel/intern/anonymous_attribute.cc b/source/blender/blenkernel/intern/anonymous_attribute.cc
index 6ce6bee547c..636e0af0edf 100644
--- a/source/blender/blenkernel/intern/anonymous_attribute.cc
+++ b/source/blender/blenkernel/intern/anonymous_attribute.cc
@@ -41,7 +41,7 @@ static std::string get_new_internal_name()
{
static std::atomic<int> index = 0;
const int next_index = index.fetch_add(1);
- return "anonymous_attribute_" + std::to_string(next_index);
+ return ".a_" + std::to_string(next_index);
}
AnonymousAttributeID *BKE_anonymous_attribute_id_new_weak(const char *debug_name)
diff --git a/source/blender/blenkernel/intern/appdir.c b/source/blender/blenkernel/intern/appdir.c
index 8d3649fef08..031d3647878 100644
--- a/source/blender/blenkernel/intern/appdir.c
+++ b/source/blender/blenkernel/intern/appdir.c
@@ -61,7 +61,7 @@ static CLG_LogRef LOG = {"bke.appdir"};
static struct {
/** Full path to program executable. */
- char program_filename[FILE_MAX];
+ char program_filepath[FILE_MAX];
/** Full path to directory in which executable is located. */
char program_dirname[FILE_MAX];
/** Persistent temporary directory (defined by the preferences or OS). */
@@ -860,14 +860,14 @@ static void where_am_i(char *fullname, const size_t maxlen, const char *name)
void BKE_appdir_program_path_init(const char *argv0)
{
- where_am_i(g_app.program_filename, sizeof(g_app.program_filename), argv0);
- BLI_split_dir_part(g_app.program_filename, g_app.program_dirname, sizeof(g_app.program_dirname));
+ where_am_i(g_app.program_filepath, sizeof(g_app.program_filepath), argv0);
+ BLI_split_dir_part(g_app.program_filepath, g_app.program_dirname, sizeof(g_app.program_dirname));
}
const char *BKE_appdir_program_path(void)
{
- BLI_assert(g_app.program_filename[0]);
- return g_app.program_filename;
+ BLI_assert(g_app.program_filepath[0]);
+ return g_app.program_filepath;
}
const char *BKE_appdir_program_dir(void)
diff --git a/source/blender/blenkernel/intern/asset_catalog_test.cc b/source/blender/blenkernel/intern/asset_catalog_test.cc
index 11f36e32b74..81eb1786322 100644
--- a/source/blender/blenkernel/intern/asset_catalog_test.cc
+++ b/source/blender/blenkernel/intern/asset_catalog_test.cc
@@ -318,7 +318,7 @@ TEST_F(AssetCatalogTest, load_catalog_path_backslashes)
const AssetCatalog *found_by_id = service.find_catalog(UUID_POSES_ELLIE_BACKSLASHES);
ASSERT_NE(nullptr, found_by_id);
EXPECT_EQ(AssetCatalogPath("character/Ellie/backslashes"), found_by_id->path)
- << "Backslashes should be normalised when loading from disk.";
+ << "Backslashes should be normalized when loading from disk.";
EXPECT_EQ(StringRefNull("Windows For Life!"), found_by_id->simple_name);
const AssetCatalog *found_by_path = service.find_catalog_by_path("character/Ellie/backslashes");
diff --git a/source/blender/blenkernel/intern/attribute.c b/source/blender/blenkernel/intern/attribute.cc
index 0cb0704ff80..7c09b4a4ce3 100644
--- a/source/blender/blenkernel/intern/attribute.c
+++ b/source/blender/blenkernel/intern/attribute.cc
@@ -7,7 +7,7 @@
* on top of CustomData, which manages individual domains.
*/
-#include <string.h>
+#include <cstring>
#include "MEM_guardedalloc.h"
@@ -18,10 +18,12 @@
#include "DNA_meshdata_types.h"
#include "DNA_pointcloud_types.h"
+#include "BLI_index_range.hh"
#include "BLI_string_utf8.h"
#include "BLI_string_utils.h"
#include "BKE_attribute.h"
+#include "BKE_attribute_access.hh"
#include "BKE_curves.h"
#include "BKE_customdata.h"
#include "BKE_editmesh.h"
@@ -30,10 +32,12 @@
#include "RNA_access.h"
-typedef struct DomainInfo {
+using blender::IndexRange;
+
+struct DomainInfo {
CustomData *customdata;
int length;
-} DomainInfo;
+};
static void get_domains(const ID *id, DomainInfo info[ATTR_DOMAIN_NUM])
{
@@ -49,7 +53,7 @@ static void get_domains(const ID *id, DomainInfo info[ATTR_DOMAIN_NUM])
case ID_ME: {
Mesh *mesh = (Mesh *)id;
BMEditMesh *em = mesh->edit_mesh;
- if (em != NULL) {
+ if (em != nullptr) {
BMesh *bm = em->bm;
info[ATTR_DOMAIN_POINT].customdata = &bm->vdata;
info[ATTR_DOMAIN_POINT].length = bm->totvert;
@@ -75,9 +79,9 @@ static void get_domains(const ID *id, DomainInfo info[ATTR_DOMAIN_NUM])
case ID_CV: {
Curves *curves = (Curves *)id;
info[ATTR_DOMAIN_POINT].customdata = &curves->geometry.point_data;
- info[ATTR_DOMAIN_POINT].length = curves->geometry.point_size;
+ info[ATTR_DOMAIN_POINT].length = curves->geometry.point_num;
info[ATTR_DOMAIN_CURVE].customdata = &curves->geometry.curve_data;
- info[ATTR_DOMAIN_CURVE].length = curves->geometry.curve_size;
+ info[ATTR_DOMAIN_CURVE].length = curves->geometry.curve_num;
break;
}
default:
@@ -85,27 +89,11 @@ static void get_domains(const ID *id, DomainInfo info[ATTR_DOMAIN_NUM])
}
}
-static CustomData *attribute_customdata_find(ID *id, CustomDataLayer *layer)
+bool BKE_id_attributes_supported(const ID *id)
{
DomainInfo info[ATTR_DOMAIN_NUM];
get_domains(id, info);
-
- for (AttributeDomain domain = 0; domain < ATTR_DOMAIN_NUM; domain++) {
- CustomData *customdata = info[domain].customdata;
- if (customdata &&
- ARRAY_HAS_ITEM((CustomDataLayer *)layer, customdata->layers, customdata->totlayer)) {
- return customdata;
- }
- }
-
- return NULL;
-}
-
-bool BKE_id_attributes_supported(struct ID *id)
-{
- DomainInfo info[ATTR_DOMAIN_NUM];
- get_domains(id, info);
- for (AttributeDomain domain = 0; domain < ATTR_DOMAIN_NUM; domain++) {
+ for (const int domain : IndexRange(ATTR_DOMAIN_NUM)) {
if (info[domain].customdata) {
return true;
}
@@ -113,30 +101,38 @@ bool BKE_id_attributes_supported(struct ID *id)
return false;
}
+bool BKE_attribute_allow_procedural_access(const char *attribute_name)
+{
+ return blender::bke::allow_procedural_attribute_access(attribute_name);
+}
+
bool BKE_id_attribute_rename(ID *id,
- CustomDataLayer *layer,
+ const char *old_name,
const char *new_name,
ReportList *reports)
{
- if (BKE_id_attribute_required(id, layer)) {
+ if (BKE_id_attribute_required(id, old_name)) {
BLI_assert_msg(0, "Required attribute name is not editable");
return false;
}
- CustomData *customdata = attribute_customdata_find(id, layer);
- if (customdata == NULL) {
+ CustomDataLayer *layer = BKE_id_attribute_search(
+ id, old_name, CD_MASK_PROP_ALL, ATTR_DOMAIN_MASK_ALL);
+ if (layer == nullptr) {
BKE_report(reports, RPT_ERROR, "Attribute is not part of this geometry");
return false;
}
- BLI_strncpy_utf8(layer->name, new_name, sizeof(layer->name));
- CustomData_set_layer_unique_name(customdata, layer - customdata->layers);
+ char result_name[MAX_CUSTOMDATA_LAYER_NAME];
+ BKE_id_attribute_calc_unique_name(id, new_name, result_name);
+ BLI_strncpy_utf8(layer->name, result_name, sizeof(layer->name));
+
return true;
}
-typedef struct AttrUniqueData {
+struct AttrUniqueData {
ID *id;
-} AttrUniqueData;
+};
static bool unique_name_cb(void *arg, const char *name)
{
@@ -145,7 +141,7 @@ static bool unique_name_cb(void *arg, const char *name)
DomainInfo info[ATTR_DOMAIN_NUM];
get_domains(data->id, info);
- for (AttributeDomain domain = ATTR_DOMAIN_POINT; domain < ATTR_DOMAIN_NUM; domain++) {
+ for (const int domain : IndexRange(ATTR_DOMAIN_NUM)) {
if (!info[domain].customdata) {
continue;
}
@@ -165,23 +161,24 @@ static bool unique_name_cb(void *arg, const char *name)
bool BKE_id_attribute_calc_unique_name(ID *id, const char *name, char *outname)
{
- AttrUniqueData data = {.id = id};
+ AttrUniqueData data{id};
BLI_strncpy_utf8(outname, name, MAX_CUSTOMDATA_LAYER_NAME);
- return BLI_uniquename_cb(unique_name_cb, &data, NULL, '.', outname, MAX_CUSTOMDATA_LAYER_NAME);
+ return BLI_uniquename_cb(
+ unique_name_cb, &data, nullptr, '.', outname, MAX_CUSTOMDATA_LAYER_NAME);
}
CustomDataLayer *BKE_id_attribute_new(
- ID *id, const char *name, const int type, const AttributeDomain domain, ReportList *reports)
+ ID *id, const char *name, const int type, const eAttrDomain domain, ReportList *reports)
{
DomainInfo info[ATTR_DOMAIN_NUM];
get_domains(id, info);
CustomData *customdata = info[domain].customdata;
- if (customdata == NULL) {
+ if (customdata == nullptr) {
BKE_report(reports, RPT_ERROR, "Attribute domain not supported by this geometry type");
- return NULL;
+ return nullptr;
}
char uniquename[MAX_CUSTOMDATA_LAYER_NAME];
@@ -191,77 +188,106 @@ CustomDataLayer *BKE_id_attribute_new(
case ID_ME: {
Mesh *me = (Mesh *)id;
BMEditMesh *em = me->edit_mesh;
- if (em != NULL) {
+ if (em != nullptr) {
BM_data_layer_add_named(em->bm, customdata, type, uniquename);
}
else {
CustomData_add_layer_named(
- customdata, type, CD_DEFAULT, NULL, info[domain].length, uniquename);
+ customdata, type, CD_DEFAULT, nullptr, info[domain].length, uniquename);
}
break;
}
default: {
CustomData_add_layer_named(
- customdata, type, CD_DEFAULT, NULL, info[domain].length, uniquename);
+ customdata, type, CD_DEFAULT, nullptr, info[domain].length, uniquename);
break;
}
}
const int index = CustomData_get_named_layer_index(customdata, type, uniquename);
- return (index == -1) ? NULL : &(customdata->layers[index]);
+ return (index == -1) ? nullptr : &(customdata->layers[index]);
}
-bool BKE_id_attribute_remove(ID *id, CustomDataLayer *layer, ReportList *reports)
+CustomDataLayer *BKE_id_attribute_duplicate(ID *id, const char *name, ReportList *reports)
{
- CustomData *customdata = attribute_customdata_find(id, layer);
- const int index = (customdata) ?
- CustomData_get_named_layer_index(customdata, layer->type, layer->name) :
- -1;
-
- if (index == -1) {
+ const CustomDataLayer *src_layer = BKE_id_attribute_search(
+ id, name, CD_MASK_PROP_ALL, ATTR_DOMAIN_MASK_ALL);
+ if (src_layer == nullptr) {
BKE_report(reports, RPT_ERROR, "Attribute is not part of this geometry");
- return false;
+ return nullptr;
}
- if (BKE_id_attribute_required(id, layer)) {
+ const eCustomDataType type = (eCustomDataType)src_layer->type;
+ const eAttrDomain domain = BKE_id_attribute_domain(id, src_layer);
+
+ /* Make a copy of name in case CustomData API reallocates the layers. */
+ const std::string name_copy = name;
+
+ DomainInfo info[ATTR_DOMAIN_NUM];
+ get_domains(id, info);
+ CustomData *customdata = info[domain].customdata;
+
+ CustomDataLayer *new_layer = BKE_id_attribute_new(id, name_copy.c_str(), type, domain, reports);
+ if (new_layer == nullptr) {
+ return nullptr;
+ }
+
+ const int from_index = CustomData_get_named_layer_index(customdata, type, name_copy.c_str());
+ const int to_index = CustomData_get_named_layer_index(customdata, type, new_layer->name);
+ CustomData_copy_data_layer(
+ customdata, customdata, from_index, to_index, 0, 0, info[domain].length);
+
+ return new_layer;
+}
+
+bool BKE_id_attribute_remove(ID *id, const char *name, ReportList *reports)
+{
+ if (BKE_id_attribute_required(id, name)) {
BKE_report(reports, RPT_ERROR, "Attribute is required and can't be removed");
return false;
}
+ DomainInfo info[ATTR_DOMAIN_NUM];
+ get_domains(id, info);
+
switch (GS(id->name)) {
case ID_ME: {
- Mesh *me = (Mesh *)id;
- BMEditMesh *em = me->edit_mesh;
- if (em != NULL) {
- BM_data_layer_free(em->bm, customdata, layer->type);
- }
- else {
- const int length = BKE_id_attribute_data_length(id, layer);
- CustomData_free_layer(customdata, layer->type, length, index);
+ Mesh *mesh = reinterpret_cast<Mesh *>(id);
+ if (BMEditMesh *em = mesh->edit_mesh) {
+ for (const int domain : IndexRange(ATTR_DOMAIN_NUM)) {
+ if (CustomData *data = info[domain].customdata) {
+ if (BM_data_layer_free_named(em->bm, data, name)) {
+ return true;
+ }
+ }
+ }
+ return false;
}
- break;
- }
- default: {
- const int length = BKE_id_attribute_data_length(id, layer);
- CustomData_free_layer(customdata, layer->type, length, index);
- break;
+ ATTR_FALLTHROUGH;
}
+ default:
+ for (const int domain : IndexRange(ATTR_DOMAIN_NUM)) {
+ if (CustomData *data = info[domain].customdata) {
+ if (CustomData_free_layer_named(data, name, info[domain].length)) {
+ return true;
+ }
+ }
+ }
+ return false;
}
-
- return true;
}
CustomDataLayer *BKE_id_attribute_find(const ID *id,
const char *name,
const int type,
- const AttributeDomain domain)
+ const eAttrDomain domain)
{
DomainInfo info[ATTR_DOMAIN_NUM];
get_domains(id, info);
CustomData *customdata = info[domain].customdata;
- if (customdata == NULL) {
- return NULL;
+ if (customdata == nullptr) {
+ return nullptr;
}
for (int i = 0; i < customdata->totlayer; i++) {
@@ -271,17 +297,47 @@ CustomDataLayer *BKE_id_attribute_find(const ID *id,
}
}
- return NULL;
+ return nullptr;
+}
+
+CustomDataLayer *BKE_id_attribute_search(ID *id,
+ const char *name,
+ const eCustomDataMask type_mask,
+ const eAttrDomainMask domain_mask)
+{
+ DomainInfo info[ATTR_DOMAIN_NUM];
+ get_domains(id, info);
+
+ for (eAttrDomain domain = ATTR_DOMAIN_POINT; domain < ATTR_DOMAIN_NUM;
+ domain = static_cast<eAttrDomain>((static_cast<int>(domain)) + 1)) {
+ if (!(domain_mask & ATTR_DOMAIN_AS_MASK(domain))) {
+ continue;
+ }
+
+ CustomData *customdata = info[domain].customdata;
+ if (customdata == nullptr) {
+ continue;
+ }
+
+ for (int i = 0; i < customdata->totlayer; i++) {
+ CustomDataLayer *layer = &customdata->layers[i];
+ if ((CD_TYPE_AS_MASK(layer->type) & type_mask) && STREQ(layer->name, name)) {
+ return layer;
+ }
+ }
+ }
+
+ return nullptr;
}
-int BKE_id_attributes_length(const ID *id, AttributeDomainMask domain_mask, CustomDataMask mask)
+int BKE_id_attributes_length(const ID *id, eAttrDomainMask domain_mask, eCustomDataMask mask)
{
DomainInfo info[ATTR_DOMAIN_NUM];
get_domains(id, info);
int length = 0;
- for (AttributeDomain domain = 0; domain < ATTR_DOMAIN_NUM; domain++) {
+ for (const int domain : IndexRange(ATTR_DOMAIN_NUM)) {
CustomData *customdata = info[domain].customdata;
if (customdata && ((1 << (int)domain) & domain_mask)) {
@@ -292,21 +348,21 @@ int BKE_id_attributes_length(const ID *id, AttributeDomainMask domain_mask, Cust
return length;
}
-AttributeDomain BKE_id_attribute_domain(const ID *id, const CustomDataLayer *layer)
+eAttrDomain BKE_id_attribute_domain(const ID *id, const CustomDataLayer *layer)
{
DomainInfo info[ATTR_DOMAIN_NUM];
get_domains(id, info);
- for (AttributeDomain domain = 0; domain < ATTR_DOMAIN_NUM; domain++) {
+ for (const int domain : IndexRange(ATTR_DOMAIN_NUM)) {
CustomData *customdata = info[domain].customdata;
if (customdata &&
ARRAY_HAS_ITEM((CustomDataLayer *)layer, customdata->layers, customdata->totlayer)) {
- return domain;
+ return static_cast<eAttrDomain>(domain);
}
}
BLI_assert_msg(0, "Custom data layer not found in geometry");
- return ATTR_DOMAIN_NUM;
+ return static_cast<eAttrDomain>(ATTR_DOMAIN_POINT);
}
int BKE_id_attribute_data_length(ID *id, CustomDataLayer *layer)
@@ -317,7 +373,7 @@ int BKE_id_attribute_data_length(ID *id, CustomDataLayer *layer)
switch (GS(id->name)) {
case ID_ME: {
Mesh *mesh = (Mesh *)id;
- if (mesh->edit_mesh != NULL) {
+ if (mesh->edit_mesh != nullptr) {
return 0;
}
}
@@ -328,7 +384,7 @@ int BKE_id_attribute_data_length(ID *id, CustomDataLayer *layer)
DomainInfo info[ATTR_DOMAIN_NUM];
get_domains(id, info);
- for (AttributeDomain domain = 0; domain < ATTR_DOMAIN_NUM; domain++) {
+ for (const int domain : IndexRange(ATTR_DOMAIN_NUM)) {
CustomData *customdata = info[domain].customdata;
if (customdata &&
ARRAY_HAS_ITEM((CustomDataLayer *)layer, customdata->layers, customdata->totlayer)) {
@@ -340,14 +396,14 @@ int BKE_id_attribute_data_length(ID *id, CustomDataLayer *layer)
return 0;
}
-bool BKE_id_attribute_required(ID *id, CustomDataLayer *layer)
+bool BKE_id_attribute_required(const ID *id, const char *name)
{
switch (GS(id->name)) {
case ID_PT: {
- return BKE_pointcloud_customdata_required((PointCloud *)id, layer);
+ return BKE_pointcloud_customdata_required((const PointCloud *)id, name);
}
case ID_CV: {
- return BKE_curves_customdata_required((Curves *)id, layer);
+ return BKE_curves_customdata_required((const Curves *)id, name);
}
default:
return false;
@@ -366,7 +422,7 @@ CustomDataLayer *BKE_id_attributes_active_get(ID *id)
int index = 0;
- for (AttributeDomain domain = 0; domain < ATTR_DOMAIN_NUM; domain++) {
+ for (const int domain : IndexRange(ATTR_DOMAIN_NUM)) {
CustomData *customdata = info[domain].customdata;
if (customdata) {
for (int i = 0; i < customdata->totlayer; i++) {
@@ -381,7 +437,7 @@ CustomDataLayer *BKE_id_attributes_active_get(ID *id)
}
}
- return NULL;
+ return nullptr;
}
void BKE_id_attributes_active_set(ID *id, CustomDataLayer *active_layer)
@@ -391,7 +447,7 @@ void BKE_id_attributes_active_set(ID *id, CustomDataLayer *active_layer)
int index = 0;
- for (AttributeDomain domain = 0; domain < ATTR_DOMAIN_NUM; domain++) {
+ for (const int domain : IndexRange(ATTR_DOMAIN_NUM)) {
CustomData *customdata = info[domain].customdata;
if (customdata) {
for (int i = 0; i < customdata->totlayer; i++) {
@@ -421,7 +477,7 @@ int *BKE_id_attributes_active_index_p(ID *id)
return &((Curves *)id)->attributes_active_index;
}
default:
- return NULL;
+ return nullptr;
}
}
@@ -430,9 +486,9 @@ CustomData *BKE_id_attributes_iterator_next_domain(ID *id, CustomDataLayer *laye
DomainInfo info[ATTR_DOMAIN_NUM];
get_domains(id, info);
- bool use_next = (layers == NULL);
+ bool use_next = (layers == nullptr);
- for (AttributeDomain domain = 0; domain < ATTR_DOMAIN_NUM; domain++) {
+ for (const int domain : IndexRange(ATTR_DOMAIN_NUM)) {
CustomData *customdata = info[domain].customdata;
if (customdata && customdata->layers && customdata->totlayer) {
if (customdata->layers == layers) {
@@ -444,19 +500,19 @@ CustomData *BKE_id_attributes_iterator_next_domain(ID *id, CustomDataLayer *laye
}
}
- return NULL;
+ return nullptr;
}
CustomDataLayer *BKE_id_attribute_from_index(ID *id,
int lookup_index,
- AttributeDomainMask domain_mask,
- CustomDataMask layer_mask)
+ eAttrDomainMask domain_mask,
+ eCustomDataMask layer_mask)
{
DomainInfo info[ATTR_DOMAIN_NUM];
get_domains(id, info);
int index = 0;
- for (AttributeDomain domain = 0; domain < ATTR_DOMAIN_NUM; domain++) {
+ for (const int domain : IndexRange(ATTR_DOMAIN_NUM)) {
CustomData *customdata = info[domain].customdata;
if (!customdata || !((1 << (int)domain) & domain_mask)) {
@@ -477,33 +533,33 @@ CustomDataLayer *BKE_id_attribute_from_index(ID *id,
}
}
- return NULL;
+ return nullptr;
}
/** Get list of domain types but with ATTR_DOMAIN_FACE and
* ATTR_DOMAIN_CORNER swapped.
*/
-static void get_domains_types(AttributeDomain domains[ATTR_DOMAIN_NUM])
+static void get_domains_types(eAttrDomain domains[ATTR_DOMAIN_NUM])
{
- for (AttributeDomain i = 0; i < ATTR_DOMAIN_NUM; i++) {
- domains[i] = i;
+ for (const int i : IndexRange(ATTR_DOMAIN_NUM)) {
+ domains[i] = static_cast<eAttrDomain>(i);
}
/* Swap corner and face. */
- SWAP(AttributeDomain, domains[ATTR_DOMAIN_FACE], domains[ATTR_DOMAIN_CORNER]);
+ SWAP(eAttrDomain, domains[ATTR_DOMAIN_FACE], domains[ATTR_DOMAIN_CORNER]);
}
-int BKE_id_attribute_to_index(const struct ID *id,
+int BKE_id_attribute_to_index(const ID *id,
const CustomDataLayer *layer,
- AttributeDomainMask domain_mask,
- CustomDataMask layer_mask)
+ eAttrDomainMask domain_mask,
+ eCustomDataMask layer_mask)
{
if (!layer) {
return -1;
}
DomainInfo info[ATTR_DOMAIN_NUM];
- AttributeDomain domains[ATTR_DOMAIN_NUM];
+ eAttrDomain domains[ATTR_DOMAIN_NUM];
get_domains_types(domains);
get_domains(id, info);
@@ -513,9 +569,9 @@ int BKE_id_attribute_to_index(const struct ID *id,
continue;
}
- CustomData *cdata = info[domains[i]].customdata;
+ const CustomData *cdata = info[domains[i]].customdata;
for (int j = 0; j < cdata->totlayer; j++) {
- CustomDataLayer *layer_iter = cdata->layers + j;
+ const CustomDataLayer *layer_iter = cdata->layers + j;
if (!(CD_TYPE_AS_MASK(layer_iter->type) & layer_mask) ||
(layer_iter->flag & CD_FLAG_TEMPORARY)) {
@@ -535,16 +591,16 @@ int BKE_id_attribute_to_index(const struct ID *id,
CustomDataLayer *BKE_id_attribute_subset_active_get(const ID *id,
int active_flag,
- AttributeDomainMask domain_mask,
- CustomDataMask mask)
+ eAttrDomainMask domain_mask,
+ eCustomDataMask mask)
{
DomainInfo info[ATTR_DOMAIN_NUM];
- AttributeDomain domains[ATTR_DOMAIN_NUM];
+ eAttrDomain domains[ATTR_DOMAIN_NUM];
get_domains_types(domains);
get_domains(id, info);
- CustomDataLayer *candidate = NULL;
+ CustomDataLayer *candidate = nullptr;
for (int i = 0; i < ARRAY_SIZE(domains); i++) {
if (!((1 << domains[i]) & domain_mask) || !info[domains[i]].customdata) {
continue;
@@ -573,17 +629,17 @@ CustomDataLayer *BKE_id_attribute_subset_active_get(const ID *id,
void BKE_id_attribute_subset_active_set(ID *id,
CustomDataLayer *layer,
int active_flag,
- AttributeDomainMask domain_mask,
- CustomDataMask mask)
+ eAttrDomainMask domain_mask,
+ eCustomDataMask mask)
{
DomainInfo info[ATTR_DOMAIN_NUM];
- AttributeDomain domains[ATTR_DOMAIN_NUM];
+ eAttrDomain domains[ATTR_DOMAIN_NUM];
get_domains_types(domains);
get_domains(id, info);
for (int i = 0; i < ATTR_DOMAIN_NUM; i++) {
- AttributeDomainMask domain_mask2 = (AttributeDomainMask)(1 << domains[i]);
+ eAttrDomainMask domain_mask2 = (eAttrDomainMask)(1 << domains[i]);
if (!(domain_mask2 & domain_mask) || !info[domains[i]].customdata) {
continue;
@@ -632,15 +688,16 @@ void BKE_id_attributes_render_color_set(ID *id, CustomDataLayer *active_layer)
CustomDataLayer *BKE_id_attributes_color_find(const ID *id, const char *name)
{
CustomDataLayer *layer = BKE_id_attribute_find(id, name, CD_PROP_COLOR, ATTR_DOMAIN_POINT);
- if (layer == NULL) {
+ if (layer == nullptr) {
layer = BKE_id_attribute_find(id, name, CD_PROP_COLOR, ATTR_DOMAIN_CORNER);
}
- if (layer == NULL) {
+ if (layer == nullptr) {
layer = BKE_id_attribute_find(id, name, CD_PROP_BYTE_COLOR, ATTR_DOMAIN_POINT);
}
- if (layer == NULL) {
+ if (layer == nullptr) {
layer = BKE_id_attribute_find(id, name, CD_PROP_BYTE_COLOR, ATTR_DOMAIN_CORNER);
}
+
return layer;
}
@@ -661,7 +718,7 @@ void BKE_id_attribute_copy_domains_temp(short id_type,
Mesh *me = (Mesh *)r_id;
memset((void *)me, 0, sizeof(*me));
- me->edit_mesh = NULL;
+ me->edit_mesh = nullptr;
me->vdata = vdata ? *vdata : reset;
me->edata = edata ? *edata : reset;
diff --git a/source/blender/blenkernel/intern/attribute_access.cc b/source/blender/blenkernel/intern/attribute_access.cc
index d33b64c493b..bc146d87e4c 100644
--- a/source/blender/blenkernel/intern/attribute_access.cc
+++ b/source/blender/blenkernel/intern/attribute_access.cc
@@ -55,7 +55,15 @@ std::ostream &operator<<(std::ostream &stream, const AttributeIDRef &attribute_i
return stream;
}
-static int attribute_data_type_complexity(const CustomDataType data_type)
+const char *no_procedural_access_message =
+ "This attribute can not be accessed in a procedural context";
+
+bool allow_procedural_attribute_access(StringRef attribute_name)
+{
+ return !attribute_name.startswith(".selection");
+}
+
+static int attribute_data_type_complexity(const eCustomDataType data_type)
{
switch (data_type) {
case CD_PROP_BOOL:
@@ -85,12 +93,12 @@ static int attribute_data_type_complexity(const CustomDataType data_type)
}
}
-CustomDataType attribute_data_type_highest_complexity(Span<CustomDataType> data_types)
+eCustomDataType attribute_data_type_highest_complexity(Span<eCustomDataType> data_types)
{
int highest_complexity = INT_MIN;
- CustomDataType most_complex_type = CD_PROP_COLOR;
+ eCustomDataType most_complex_type = CD_PROP_COLOR;
- for (const CustomDataType data_type : data_types) {
+ for (const eCustomDataType data_type : data_types) {
const int complexity = attribute_data_type_complexity(data_type);
if (complexity > highest_complexity) {
highest_complexity = complexity;
@@ -105,7 +113,7 @@ CustomDataType attribute_data_type_highest_complexity(Span<CustomDataType> data_
* \note Generally the order should mirror the order of the domains
* established in each component's ComponentAttributeProviders.
*/
-static int attribute_domain_priority(const AttributeDomain domain)
+static int attribute_domain_priority(const eAttrDomain domain)
{
switch (domain) {
case ATTR_DOMAIN_INSTANCE:
@@ -127,12 +135,12 @@ static int attribute_domain_priority(const AttributeDomain domain)
}
}
-AttributeDomain attribute_domain_highest_priority(Span<AttributeDomain> domains)
+eAttrDomain attribute_domain_highest_priority(Span<eAttrDomain> domains)
{
int highest_priority = INT_MIN;
- AttributeDomain highest_priority_domain = ATTR_DOMAIN_CORNER;
+ eAttrDomain highest_priority_domain = ATTR_DOMAIN_CORNER;
- for (const AttributeDomain domain : domains) {
+ for (const eAttrDomain domain : domains) {
const int priority = attribute_domain_priority(domain);
if (priority > highest_priority) {
highest_priority = priority;
@@ -183,17 +191,17 @@ static AttributeIDRef attribute_id_from_custom_data_layer(const CustomDataLayer
}
static bool add_builtin_type_custom_data_layer_from_init(CustomData &custom_data,
- const CustomDataType data_type,
- const int domain_size,
+ const eCustomDataType data_type,
+ const int domain_num,
const AttributeInit &initializer)
{
switch (initializer.type) {
case AttributeInit::Type::Default: {
- void *data = CustomData_add_layer(&custom_data, data_type, CD_DEFAULT, nullptr, domain_size);
+ void *data = CustomData_add_layer(&custom_data, data_type, CD_DEFAULT, nullptr, domain_num);
return data != nullptr;
}
case AttributeInit::Type::VArray: {
- void *data = CustomData_add_layer(&custom_data, data_type, CD_DEFAULT, nullptr, domain_size);
+ void *data = CustomData_add_layer(&custom_data, data_type, CD_DEFAULT, nullptr, domain_num);
if (data == nullptr) {
return false;
}
@@ -204,7 +212,7 @@ static bool add_builtin_type_custom_data_layer_from_init(CustomData &custom_data
case AttributeInit::Type::MoveArray: {
void *source_data = static_cast<const AttributeInitMove &>(initializer).data;
void *data = CustomData_add_layer(
- &custom_data, data_type, CD_ASSIGN, source_data, domain_size);
+ &custom_data, data_type, CD_ASSIGN, source_data, domain_num);
if (data == nullptr) {
MEM_freeN(source_data);
return false;
@@ -218,38 +226,38 @@ static bool add_builtin_type_custom_data_layer_from_init(CustomData &custom_data
}
static void *add_generic_custom_data_layer(CustomData &custom_data,
- const CustomDataType data_type,
+ const eCustomDataType data_type,
const eCDAllocType alloctype,
void *layer_data,
- const int domain_size,
+ const int domain_num,
const AttributeIDRef &attribute_id)
{
if (attribute_id.is_named()) {
char attribute_name_c[MAX_NAME];
attribute_id.name().copy(attribute_name_c);
return CustomData_add_layer_named(
- &custom_data, data_type, alloctype, layer_data, domain_size, attribute_name_c);
+ &custom_data, data_type, alloctype, layer_data, domain_num, attribute_name_c);
}
const AnonymousAttributeID &anonymous_id = attribute_id.anonymous_id();
return CustomData_add_layer_anonymous(
- &custom_data, data_type, alloctype, layer_data, domain_size, &anonymous_id);
+ &custom_data, data_type, alloctype, layer_data, domain_num, &anonymous_id);
}
static bool add_custom_data_layer_from_attribute_init(const AttributeIDRef &attribute_id,
CustomData &custom_data,
- const CustomDataType data_type,
- const int domain_size,
+ const eCustomDataType data_type,
+ const int domain_num,
const AttributeInit &initializer)
{
switch (initializer.type) {
case AttributeInit::Type::Default: {
void *data = add_generic_custom_data_layer(
- custom_data, data_type, CD_DEFAULT, nullptr, domain_size, attribute_id);
+ custom_data, data_type, CD_DEFAULT, nullptr, domain_num, attribute_id);
return data != nullptr;
}
case AttributeInit::Type::VArray: {
void *data = add_generic_custom_data_layer(
- custom_data, data_type, CD_DEFAULT, nullptr, domain_size, attribute_id);
+ custom_data, data_type, CD_DEFAULT, nullptr, domain_num, attribute_id);
if (data == nullptr) {
return false;
}
@@ -260,7 +268,7 @@ static bool add_custom_data_layer_from_attribute_init(const AttributeIDRef &attr
case AttributeInit::Type::MoveArray: {
void *source_data = static_cast<const AttributeInitMove &>(initializer).data;
void *data = add_generic_custom_data_layer(
- custom_data, data_type, CD_ASSIGN, source_data, domain_size, attribute_id);
+ custom_data, data_type, CD_ASSIGN, source_data, domain_num, attribute_id);
if (data == nullptr) {
MEM_freeN(source_data);
return false;
@@ -303,8 +311,8 @@ GVArray BuiltinCustomDataLayerProvider::try_get_for_read(const GeometryComponent
return {};
}
- const int domain_size = component.attribute_domain_size(domain_);
- return as_read_attribute_(data, domain_size);
+ const int domain_num = component.attribute_domain_num(domain_);
+ return as_read_attribute_(data, domain_num);
}
WriteAttributeLookup BuiltinCustomDataLayerProvider::try_get_for_write(
@@ -317,7 +325,7 @@ WriteAttributeLookup BuiltinCustomDataLayerProvider::try_get_for_write(
if (custom_data == nullptr) {
return {};
}
- const int domain_size = component.attribute_domain_size(domain_);
+ const int domain_num = component.attribute_domain_num(domain_);
void *data;
if (stored_as_named_attribute_) {
@@ -333,10 +341,10 @@ WriteAttributeLookup BuiltinCustomDataLayerProvider::try_get_for_write(
void *new_data;
if (stored_as_named_attribute_) {
new_data = CustomData_duplicate_referenced_layer_named(
- custom_data, stored_type_, name_.c_str(), domain_size);
+ custom_data, stored_type_, name_.c_str(), domain_num);
}
else {
- new_data = CustomData_duplicate_referenced_layer(custom_data, stored_type_, domain_size);
+ new_data = CustomData_duplicate_referenced_layer(custom_data, stored_type_, domain_num);
}
if (data != new_data) {
@@ -353,7 +361,7 @@ WriteAttributeLookup BuiltinCustomDataLayerProvider::try_get_for_write(
};
}
- return {as_write_attribute_(data, domain_size), domain_, std::move(tag_modified_fn)};
+ return {as_write_attribute_(data, domain_num), domain_, std::move(tag_modified_fn)};
}
bool BuiltinCustomDataLayerProvider::try_delete(GeometryComponent &component) const
@@ -366,7 +374,7 @@ bool BuiltinCustomDataLayerProvider::try_delete(GeometryComponent &component) co
return {};
}
- const int domain_size = component.attribute_domain_size(domain_);
+ const int domain_num = component.attribute_domain_num(domain_);
int layer_index;
if (stored_as_named_attribute_) {
for (const int i : IndexRange(custom_data->totlayer)) {
@@ -381,7 +389,7 @@ bool BuiltinCustomDataLayerProvider::try_delete(GeometryComponent &component) co
}
const bool delete_success = CustomData_free_layer(
- custom_data, stored_type_, domain_size, layer_index);
+ custom_data, stored_type_, domain_num, layer_index);
if (delete_success) {
if (custom_data_access_.update_custom_data_pointers) {
custom_data_access_.update_custom_data_pointers(component);
@@ -401,7 +409,7 @@ bool BuiltinCustomDataLayerProvider::try_create(GeometryComponent &component,
return false;
}
- const int domain_size = component.attribute_domain_size(domain_);
+ const int domain_num = component.attribute_domain_num(domain_);
bool success;
if (stored_as_named_attribute_) {
if (CustomData_get_layer_named(custom_data, data_type_, name_.c_str())) {
@@ -409,7 +417,7 @@ bool BuiltinCustomDataLayerProvider::try_create(GeometryComponent &component,
return false;
}
success = add_custom_data_layer_from_attribute_init(
- name_, *custom_data, stored_type_, domain_size, initializer);
+ name_, *custom_data, stored_type_, domain_num, initializer);
}
else {
if (CustomData_get_layer(custom_data, stored_type_) != nullptr) {
@@ -417,7 +425,7 @@ bool BuiltinCustomDataLayerProvider::try_create(GeometryComponent &component,
return false;
}
success = add_builtin_type_custom_data_layer_from_init(
- *custom_data, stored_type_, domain_size, initializer);
+ *custom_data, stored_type_, domain_num, initializer);
}
if (success) {
if (custom_data_access_.update_custom_data_pointers) {
@@ -446,16 +454,16 @@ ReadAttributeLookup CustomDataAttributeProvider::try_get_for_read(
if (custom_data == nullptr) {
return {};
}
- const int domain_size = component.attribute_domain_size(domain_);
+ const int domain_num = component.attribute_domain_num(domain_);
for (const CustomDataLayer &layer : Span(custom_data->layers, custom_data->totlayer)) {
if (!custom_data_layer_matches_attribute_id(layer, attribute_id)) {
continue;
}
- const CPPType *type = custom_data_type_to_cpp_type((CustomDataType)layer.type);
+ const CPPType *type = custom_data_type_to_cpp_type((eCustomDataType)layer.type);
if (type == nullptr) {
continue;
}
- GSpan data{*type, layer.data, domain_size};
+ GSpan data{*type, layer.data, domain_num};
return {GVArray::ForSpan(data), domain_};
}
return {};
@@ -468,24 +476,23 @@ WriteAttributeLookup CustomDataAttributeProvider::try_get_for_write(
if (custom_data == nullptr) {
return {};
}
- const int domain_size = component.attribute_domain_size(domain_);
+ const int domain_num = component.attribute_domain_num(domain_);
for (CustomDataLayer &layer : MutableSpan(custom_data->layers, custom_data->totlayer)) {
if (!custom_data_layer_matches_attribute_id(layer, attribute_id)) {
continue;
}
if (attribute_id.is_named()) {
- CustomData_duplicate_referenced_layer_named(
- custom_data, layer.type, layer.name, domain_size);
+ CustomData_duplicate_referenced_layer_named(custom_data, layer.type, layer.name, domain_num);
}
else {
CustomData_duplicate_referenced_layer_anonymous(
- custom_data, layer.type, &attribute_id.anonymous_id(), domain_size);
+ custom_data, layer.type, &attribute_id.anonymous_id(), domain_num);
}
- const CPPType *type = custom_data_type_to_cpp_type((CustomDataType)layer.type);
+ const CPPType *type = custom_data_type_to_cpp_type((eCustomDataType)layer.type);
if (type == nullptr) {
continue;
}
- GMutableSpan data{*type, layer.data, domain_size};
+ GMutableSpan data{*type, layer.data, domain_num};
return {GVMutableArray::ForSpan(data), domain_};
}
return {};
@@ -498,12 +505,12 @@ bool CustomDataAttributeProvider::try_delete(GeometryComponent &component,
if (custom_data == nullptr) {
return false;
}
- const int domain_size = component.attribute_domain_size(domain_);
+ const int domain_num = component.attribute_domain_num(domain_);
for (const int i : IndexRange(custom_data->totlayer)) {
const CustomDataLayer &layer = custom_data->layers[i];
- if (this->type_is_supported((CustomDataType)layer.type) &&
+ if (this->type_is_supported((eCustomDataType)layer.type) &&
custom_data_layer_matches_attribute_id(layer, attribute_id)) {
- CustomData_free_layer(custom_data, layer.type, domain_size, i);
+ CustomData_free_layer(custom_data, layer.type, domain_num, i);
return true;
}
}
@@ -512,8 +519,8 @@ bool CustomDataAttributeProvider::try_delete(GeometryComponent &component,
bool CustomDataAttributeProvider::try_create(GeometryComponent &component,
const AttributeIDRef &attribute_id,
- const AttributeDomain domain,
- const CustomDataType data_type,
+ const eAttrDomain domain,
+ const eCustomDataType data_type,
const AttributeInit &initializer) const
{
if (domain_ != domain) {
@@ -531,9 +538,9 @@ bool CustomDataAttributeProvider::try_create(GeometryComponent &component,
return false;
}
}
- const int domain_size = component.attribute_domain_size(domain_);
+ const int domain_num = component.attribute_domain_num(domain_);
add_custom_data_layer_from_attribute_init(
- attribute_id, *custom_data, data_type, domain_size, initializer);
+ attribute_id, *custom_data, data_type, domain_num, initializer);
return true;
}
@@ -545,7 +552,7 @@ bool CustomDataAttributeProvider::foreach_attribute(const GeometryComponent &com
return true;
}
for (const CustomDataLayer &layer : Span(custom_data->layers, custom_data->totlayer)) {
- const CustomDataType data_type = (CustomDataType)layer.type;
+ const eCustomDataType data_type = (eCustomDataType)layer.type;
if (this->type_is_supported(data_type)) {
AttributeMetaData meta_data{domain_, data_type};
const AttributeIDRef attribute_id = attribute_id_from_custom_data_layer(layer);
@@ -567,8 +574,8 @@ ReadAttributeLookup NamedLegacyCustomDataProvider::try_get_for_read(
for (const CustomDataLayer &layer : Span(custom_data->layers, custom_data->totlayer)) {
if (layer.type == stored_type_) {
if (custom_data_layer_matches_attribute_id(layer, attribute_id)) {
- const int domain_size = component.attribute_domain_size(domain_);
- return {as_read_attribute_(layer.data, domain_size), domain_};
+ const int domain_num = component.attribute_domain_num(domain_);
+ return {as_read_attribute_(layer.data, domain_num), domain_};
}
}
}
@@ -585,16 +592,16 @@ WriteAttributeLookup NamedLegacyCustomDataProvider::try_get_for_write(
for (CustomDataLayer &layer : MutableSpan(custom_data->layers, custom_data->totlayer)) {
if (layer.type == stored_type_) {
if (custom_data_layer_matches_attribute_id(layer, attribute_id)) {
- const int domain_size = component.attribute_domain_size(domain_);
+ const int domain_num = component.attribute_domain_num(domain_);
void *data_old = layer.data;
void *data_new = CustomData_duplicate_referenced_layer_named(
- custom_data, stored_type_, layer.name, domain_size);
+ custom_data, stored_type_, layer.name, domain_num);
if (data_old != data_new) {
if (custom_data_access_.update_custom_data_pointers) {
custom_data_access_.update_custom_data_pointers(component);
}
}
- return {as_write_attribute_(layer.data, domain_size), domain_};
+ return {as_write_attribute_(layer.data, domain_num), domain_};
}
}
}
@@ -612,8 +619,8 @@ bool NamedLegacyCustomDataProvider::try_delete(GeometryComponent &component,
const CustomDataLayer &layer = custom_data->layers[i];
if (layer.type == stored_type_) {
if (custom_data_layer_matches_attribute_id(layer, attribute_id)) {
- const int domain_size = component.attribute_domain_size(domain_);
- CustomData_free_layer(custom_data, stored_type_, domain_size, i);
+ const int domain_num = component.attribute_domain_num(domain_);
+ CustomData_free_layer(custom_data, stored_type_, domain_num, i);
if (custom_data_access_.update_custom_data_pointers) {
custom_data_access_.update_custom_data_pointers(component);
}
@@ -643,7 +650,7 @@ bool NamedLegacyCustomDataProvider::foreach_attribute(
}
void NamedLegacyCustomDataProvider::foreach_domain(
- const FunctionRef<void(AttributeDomain)> callback) const
+ const FunctionRef<void(eAttrDomain)> callback) const
{
callback(domain_);
}
@@ -686,7 +693,7 @@ std::optional<GSpan> CustomDataAttributes::get_for_read(const AttributeIDRef &at
{
for (const CustomDataLayer &layer : Span(data.layers, data.totlayer)) {
if (custom_data_layer_matches_attribute_id(layer, attribute_id)) {
- const CPPType *cpp_type = custom_data_type_to_cpp_type((CustomDataType)layer.type);
+ const CPPType *cpp_type = custom_data_type_to_cpp_type((eCustomDataType)layer.type);
BLI_assert(cpp_type != nullptr);
return GSpan(*cpp_type, layer.data, size_);
}
@@ -695,16 +702,16 @@ std::optional<GSpan> CustomDataAttributes::get_for_read(const AttributeIDRef &at
}
GVArray CustomDataAttributes::get_for_read(const AttributeIDRef &attribute_id,
- const CustomDataType data_type,
+ const eCustomDataType data_type,
const void *default_value) const
{
const CPPType *type = blender::bke::custom_data_type_to_cpp_type(data_type);
std::optional<GSpan> attribute = this->get_for_read(attribute_id);
if (!attribute) {
- const int domain_size = this->size_;
+ const int domain_num = this->size_;
return GVArray::ForSingle(
- *type, domain_size, (default_value == nullptr) ? type->default_value() : default_value);
+ *type, domain_num, (default_value == nullptr) ? type->default_value() : default_value);
}
if (attribute->type() == *type) {
@@ -719,7 +726,7 @@ std::optional<GMutableSpan> CustomDataAttributes::get_for_write(const AttributeI
{
for (CustomDataLayer &layer : MutableSpan(data.layers, data.totlayer)) {
if (custom_data_layer_matches_attribute_id(layer, attribute_id)) {
- const CPPType *cpp_type = custom_data_type_to_cpp_type((CustomDataType)layer.type);
+ const CPPType *cpp_type = custom_data_type_to_cpp_type((eCustomDataType)layer.type);
BLI_assert(cpp_type != nullptr);
return GMutableSpan(*cpp_type, layer.data, size_);
}
@@ -728,7 +735,7 @@ std::optional<GMutableSpan> CustomDataAttributes::get_for_write(const AttributeI
}
bool CustomDataAttributes::create(const AttributeIDRef &attribute_id,
- const CustomDataType data_type)
+ const eCustomDataType data_type)
{
void *result = add_generic_custom_data_layer(
data, data_type, CD_DEFAULT, nullptr, size_, attribute_id);
@@ -736,7 +743,7 @@ bool CustomDataAttributes::create(const AttributeIDRef &attribute_id,
}
bool CustomDataAttributes::create_by_move(const AttributeIDRef &attribute_id,
- const CustomDataType data_type,
+ const eCustomDataType data_type,
void *buffer)
{
void *result = add_generic_custom_data_layer(
@@ -769,10 +776,10 @@ void CustomDataAttributes::clear()
}
bool CustomDataAttributes::foreach_attribute(const AttributeForeachCallback callback,
- const AttributeDomain domain) const
+ const eAttrDomain domain) const
{
for (const CustomDataLayer &layer : Span(data.layers, data.totlayer)) {
- AttributeMetaData meta_data{domain, (CustomDataType)layer.type};
+ AttributeMetaData meta_data{domain, (eCustomDataType)layer.type};
const AttributeIDRef attribute_id = attribute_id_from_custom_data_layer(layer);
if (!callback(attribute_id, meta_data)) {
return false;
@@ -812,7 +819,7 @@ const blender::bke::ComponentAttributeProviders *GeometryComponent::get_attribut
return nullptr;
}
-bool GeometryComponent::attribute_domain_supported(const AttributeDomain domain) const
+bool GeometryComponent::attribute_domain_supported(const eAttrDomain domain) const
{
using namespace blender::bke;
const ComponentAttributeProviders *providers = this->get_attribute_providers();
@@ -822,7 +829,7 @@ bool GeometryComponent::attribute_domain_supported(const AttributeDomain domain)
return providers->supported_domains().contains(domain);
}
-int GeometryComponent::attribute_domain_size(const AttributeDomain UNUSED(domain)) const
+int GeometryComponent::attribute_domain_num(const eAttrDomain UNUSED(domain)) const
{
return 0;
}
@@ -870,8 +877,8 @@ blender::bke::ReadAttributeLookup GeometryComponent::attribute_try_get_for_read(
blender::GVArray GeometryComponent::attribute_try_adapt_domain_impl(
const blender::GVArray &varray,
- const AttributeDomain from_domain,
- const AttributeDomain to_domain) const
+ const eAttrDomain from_domain,
+ const eAttrDomain to_domain) const
{
if (from_domain == to_domain) {
return varray;
@@ -942,8 +949,8 @@ void GeometryComponent::attributes_remove_anonymous()
}
bool GeometryComponent::attribute_try_create(const AttributeIDRef &attribute_id,
- const AttributeDomain domain,
- const CustomDataType data_type,
+ const eAttrDomain domain,
+ const eCustomDataType data_type,
const AttributeInit &initializer)
{
using namespace blender::bke;
@@ -1080,8 +1087,8 @@ static blender::GVArray try_adapt_data_type(blender::GVArray varray,
blender::GVArray GeometryComponent::attribute_try_get_for_read(
const AttributeIDRef &attribute_id,
- const AttributeDomain domain,
- const CustomDataType data_type) const
+ const eAttrDomain domain,
+ const eCustomDataType data_type) const
{
blender::bke::ReadAttributeLookup attribute = this->attribute_try_get_for_read(attribute_id);
if (!attribute) {
@@ -1109,7 +1116,7 @@ blender::GVArray GeometryComponent::attribute_try_get_for_read(
}
blender::GVArray GeometryComponent::attribute_try_get_for_read(const AttributeIDRef &attribute_id,
- const AttributeDomain domain) const
+ const eAttrDomain domain) const
{
if (!this->attribute_domain_supported(domain)) {
return {};
@@ -1128,7 +1135,7 @@ blender::GVArray GeometryComponent::attribute_try_get_for_read(const AttributeID
}
blender::bke::ReadAttributeLookup GeometryComponent::attribute_try_get_for_read(
- const AttributeIDRef &attribute_id, const CustomDataType data_type) const
+ const AttributeIDRef &attribute_id, const eCustomDataType data_type) const
{
blender::bke::ReadAttributeLookup attribute = this->attribute_try_get_for_read(attribute_id);
if (!attribute) {
@@ -1145,8 +1152,8 @@ blender::bke::ReadAttributeLookup GeometryComponent::attribute_try_get_for_read(
}
blender::GVArray GeometryComponent::attribute_get_for_read(const AttributeIDRef &attribute_id,
- const AttributeDomain domain,
- const CustomDataType data_type,
+ const eAttrDomain domain,
+ const eCustomDataType data_type,
const void *default_value) const
{
blender::GVArray varray = this->attribute_try_get_for_read(attribute_id, domain, data_type);
@@ -1157,8 +1164,8 @@ blender::GVArray GeometryComponent::attribute_get_for_read(const AttributeIDRef
if (default_value == nullptr) {
default_value = type->default_value();
}
- const int domain_size = this->attribute_domain_size(domain);
- return blender::GVArray::ForSingle(*type, domain_size, default_value);
+ const int domain_num = this->attribute_domain_num(domain);
+ return blender::GVArray::ForSingle(*type, domain_num, default_value);
}
class GVMutableAttribute_For_OutputAttribute : public blender::GVArrayImpl_For_GSpan {
@@ -1207,8 +1214,8 @@ static void save_output_attribute(OutputAttribute &output_attribute)
else {
attribute_id = varray.anonymous_attribute_id.extract();
}
- const AttributeDomain domain = output_attribute.domain();
- const CustomDataType data_type = output_attribute.custom_data_type();
+ const eAttrDomain domain = output_attribute.domain();
+ const eCustomDataType data_type = output_attribute.custom_data_type();
const CPPType &cpp_type = output_attribute.cpp_type();
component.attribute_try_delete(attribute_id);
@@ -1245,8 +1252,8 @@ static std::function<void(OutputAttribute &)> get_simple_output_attribute_save_m
static OutputAttribute create_output_attribute(GeometryComponent &component,
const AttributeIDRef &attribute_id,
- const AttributeDomain domain,
- const CustomDataType data_type,
+ const eAttrDomain domain,
+ const eCustomDataType data_type,
const bool ignore_old_values,
const void *default_value)
{
@@ -1267,10 +1274,10 @@ static OutputAttribute create_output_attribute(GeometryComponent &component,
WriteAttributeLookup attribute = component.attribute_try_get_for_write(attribute_name);
if (!attribute) {
if (default_value) {
- const int64_t domain_size = component.attribute_domain_size(domain);
+ const int64_t domain_num = component.attribute_domain_num(domain);
component.attribute_try_create_builtin(
attribute_name,
- AttributeInitVArray(GVArray::ForSingleRef(*cpp_type, domain_size, default_value)));
+ AttributeInitVArray(GVArray::ForSingleRef(*cpp_type, domain_num, default_value)));
}
else {
component.attribute_try_create_builtin(attribute_name, AttributeInitDefault());
@@ -1301,7 +1308,7 @@ static OutputAttribute create_output_attribute(GeometryComponent &component,
ignore_old_values);
}
- const int domain_size = component.attribute_domain_size(domain);
+ const int domain_num = component.attribute_domain_num(domain);
WriteAttributeLookup attribute = component.attribute_try_get_for_write(attribute_id);
if (!attribute) {
@@ -1310,7 +1317,7 @@ static OutputAttribute create_output_attribute(GeometryComponent &component,
attribute_id,
domain,
data_type,
- AttributeInitVArray(GVArray::ForSingleRef(*cpp_type, domain_size, default_value)));
+ AttributeInitVArray(GVArray::ForSingleRef(*cpp_type, domain_num, default_value)));
}
else {
component.attribute_try_create(attribute_id, domain, data_type, AttributeInitDefault());
@@ -1333,8 +1340,7 @@ static OutputAttribute create_output_attribute(GeometryComponent &component,
/* Allocate a new array that lives next to the existing attribute. It will overwrite the existing
* attribute after processing is done. */
- void *data = MEM_mallocN_aligned(
- cpp_type->size() * domain_size, cpp_type->alignment(), __func__);
+ void *data = MEM_mallocN_aligned(cpp_type->size() * domain_num, cpp_type->alignment(), __func__);
if (ignore_old_values) {
/* This does nothing for trivially constructible types, but is necessary for correctness. */
cpp_type->default_construct_n(data, domain);
@@ -1343,26 +1349,24 @@ static OutputAttribute create_output_attribute(GeometryComponent &component,
/* Fill the temporary array with values from the existing attribute. */
GVArray old_varray = component.attribute_get_for_read(
attribute_id, domain, data_type, default_value);
- old_varray.materialize_to_uninitialized(IndexRange(domain_size), data);
+ old_varray.materialize_to_uninitialized(IndexRange(domain_num), data);
}
GVMutableArray varray = GVMutableArray::For<GVMutableAttribute_For_OutputAttribute>(
- GMutableSpan{*cpp_type, data, domain_size}, component, attribute_id);
+ GMutableSpan{*cpp_type, data, domain_num}, component, attribute_id);
return OutputAttribute(std::move(varray), domain, save_output_attribute, true);
}
OutputAttribute GeometryComponent::attribute_try_get_for_output(const AttributeIDRef &attribute_id,
- const AttributeDomain domain,
- const CustomDataType data_type,
+ const eAttrDomain domain,
+ const eCustomDataType data_type,
const void *default_value)
{
return create_output_attribute(*this, attribute_id, domain, data_type, false, default_value);
}
OutputAttribute GeometryComponent::attribute_try_get_for_output_only(
- const AttributeIDRef &attribute_id,
- const AttributeDomain domain,
- const CustomDataType data_type)
+ const AttributeIDRef &attribute_id, const eAttrDomain domain, const eCustomDataType data_type)
{
return create_output_attribute(*this, attribute_id, domain, data_type, true, nullptr);
}
@@ -1376,17 +1380,17 @@ GVArray GeometryFieldInput::get_varray_for_context(const fn::FieldContext &conte
if (const GeometryComponentFieldContext *geometry_context =
dynamic_cast<const GeometryComponentFieldContext *>(&context)) {
const GeometryComponent &component = geometry_context->geometry_component();
- const AttributeDomain domain = geometry_context->domain();
+ const eAttrDomain domain = geometry_context->domain();
return this->get_varray_for_context(component, domain, mask);
}
return {};
}
GVArray AttributeFieldInput::get_varray_for_context(const GeometryComponent &component,
- const AttributeDomain domain,
+ const eAttrDomain domain,
IndexMask UNUSED(mask)) const
{
- const CustomDataType data_type = cpp_type_to_custom_data_type(*type_);
+ const eCustomDataType data_type = cpp_type_to_custom_data_type(*type_);
return component.attribute_try_get_for_read(name_, domain, data_type);
}
@@ -1410,7 +1414,7 @@ bool AttributeFieldInput::is_equal_to(const fn::FieldNode &other) const
return false;
}
-static StringRef get_random_id_attribute_name(const AttributeDomain domain)
+static StringRef get_random_id_attribute_name(const eAttrDomain domain)
{
switch (domain) {
case ATTR_DOMAIN_POINT:
@@ -1422,14 +1426,14 @@ static StringRef get_random_id_attribute_name(const AttributeDomain domain)
}
GVArray IDAttributeFieldInput::get_varray_for_context(const GeometryComponent &component,
- const AttributeDomain domain,
+ const eAttrDomain domain,
IndexMask mask) const
{
const StringRef name = get_random_id_attribute_name(domain);
GVArray attribute = component.attribute_try_get_for_read(name, domain, CD_PROP_INT32);
if (attribute) {
- BLI_assert(attribute.size() == component.attribute_domain_size(domain));
+ BLI_assert(attribute.size() == component.attribute_domain_num(domain));
return attribute;
}
@@ -1455,10 +1459,10 @@ bool IDAttributeFieldInput::is_equal_to(const fn::FieldNode &other) const
}
GVArray AnonymousAttributeFieldInput::get_varray_for_context(const GeometryComponent &component,
- const AttributeDomain domain,
+ const eAttrDomain domain,
IndexMask UNUSED(mask)) const
{
- const CustomDataType data_type = cpp_type_to_custom_data_type(*type_);
+ const eCustomDataType data_type = cpp_type_to_custom_data_type(*type_);
return component.attribute_try_get_for_read(anonymous_id_.get(), domain, data_type);
}
diff --git a/source/blender/blenkernel/intern/attribute_access_intern.hh b/source/blender/blenkernel/intern/attribute_access_intern.hh
index 8c021ed0e21..ac43754dd1a 100644
--- a/source/blender/blenkernel/intern/attribute_access_intern.hh
+++ b/source/blender/blenkernel/intern/attribute_access_intern.hh
@@ -47,16 +47,16 @@ class BuiltinAttributeProvider {
protected:
const std::string name_;
- const AttributeDomain domain_;
- const CustomDataType data_type_;
+ const eAttrDomain domain_;
+ const eCustomDataType data_type_;
const CreatableEnum createable_;
const WritableEnum writable_;
const DeletableEnum deletable_;
public:
BuiltinAttributeProvider(std::string name,
- const AttributeDomain domain,
- const CustomDataType data_type,
+ const eAttrDomain domain,
+ const eCustomDataType data_type,
const CreatableEnum createable,
const WritableEnum writable,
const DeletableEnum deletable)
@@ -81,12 +81,12 @@ class BuiltinAttributeProvider {
return name_;
}
- AttributeDomain domain() const
+ eAttrDomain domain() const
{
return domain_;
}
- CustomDataType data_type() const
+ eCustomDataType data_type() const
{
return data_type_;
}
@@ -106,8 +106,8 @@ class DynamicAttributesProvider {
const AttributeIDRef &attribute_id) const = 0;
virtual bool try_create(GeometryComponent &UNUSED(component),
const AttributeIDRef &UNUSED(attribute_id),
- const AttributeDomain UNUSED(domain),
- const CustomDataType UNUSED(data_type),
+ const eAttrDomain UNUSED(domain),
+ const eCustomDataType UNUSED(data_type),
const AttributeInit &UNUSED(initializer)) const
{
/* Some providers should not create new attributes. */
@@ -116,7 +116,7 @@ class DynamicAttributesProvider {
virtual bool foreach_attribute(const GeometryComponent &component,
const AttributeForeachCallback callback) const = 0;
- virtual void foreach_domain(const FunctionRef<void(AttributeDomain)> callback) const = 0;
+ virtual void foreach_domain(const FunctionRef<void(eAttrDomain)> callback) const = 0;
};
/**
@@ -128,11 +128,11 @@ class CustomDataAttributeProvider final : public DynamicAttributesProvider {
CD_MASK_PROP_FLOAT3 | CD_MASK_PROP_INT32 |
CD_MASK_PROP_COLOR | CD_MASK_PROP_BOOL |
CD_MASK_PROP_INT8 | CD_MASK_PROP_BYTE_COLOR;
- const AttributeDomain domain_;
+ const eAttrDomain domain_;
const CustomDataAccessInfo custom_data_access_;
public:
- CustomDataAttributeProvider(const AttributeDomain domain,
+ CustomDataAttributeProvider(const eAttrDomain domain,
const CustomDataAccessInfo custom_data_access)
: domain_(domain), custom_data_access_(custom_data_access)
{
@@ -148,20 +148,20 @@ class CustomDataAttributeProvider final : public DynamicAttributesProvider {
bool try_create(GeometryComponent &component,
const AttributeIDRef &attribute_id,
- AttributeDomain domain,
- const CustomDataType data_type,
+ eAttrDomain domain,
+ const eCustomDataType data_type,
const AttributeInit &initializer) const final;
bool foreach_attribute(const GeometryComponent &component,
const AttributeForeachCallback callback) const final;
- void foreach_domain(const FunctionRef<void(AttributeDomain)> callback) const final
+ void foreach_domain(const FunctionRef<void(eAttrDomain)> callback) const final
{
callback(domain_);
}
private:
- bool type_is_supported(CustomDataType data_type) const
+ bool type_is_supported(eCustomDataType data_type) const
{
return ((1ULL << data_type) & supported_types_mask) != 0;
}
@@ -172,19 +172,19 @@ class CustomDataAttributeProvider final : public DynamicAttributesProvider {
*/
class NamedLegacyCustomDataProvider final : public DynamicAttributesProvider {
private:
- 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_;
+ using AsReadAttribute = GVArray (*)(const void *data, int domain_num);
+ using AsWriteAttribute = GVMutableArray (*)(void *data, int domain_num);
+ const eAttrDomain domain_;
+ const eCustomDataType attribute_type_;
+ const eCustomDataType stored_type_;
const CustomDataAccessInfo custom_data_access_;
const AsReadAttribute as_read_attribute_;
const AsWriteAttribute as_write_attribute_;
public:
- NamedLegacyCustomDataProvider(const AttributeDomain domain,
- const CustomDataType attribute_type,
- const CustomDataType stored_type,
+ NamedLegacyCustomDataProvider(const eAttrDomain domain,
+ const eCustomDataType attribute_type,
+ const eCustomDataType stored_type,
const CustomDataAccessInfo custom_data_access,
const AsReadAttribute as_read_attribute,
const AsWriteAttribute as_write_attribute)
@@ -204,17 +204,17 @@ class NamedLegacyCustomDataProvider final : public DynamicAttributesProvider {
bool try_delete(GeometryComponent &component, const AttributeIDRef &attribute_id) const final;
bool foreach_attribute(const GeometryComponent &component,
const AttributeForeachCallback callback) const final;
- void foreach_domain(const FunctionRef<void(AttributeDomain)> callback) const final;
+ void foreach_domain(const FunctionRef<void(eAttrDomain)> callback) const final;
};
-template<typename T> GVArray make_array_read_attribute(const void *data, const int domain_size)
+template<typename T> GVArray make_array_read_attribute(const void *data, const int domain_num)
{
- return VArray<T>::ForSpan(Span<T>((const T *)data, domain_size));
+ return VArray<T>::ForSpan(Span<T>((const T *)data, domain_num));
}
-template<typename T> GVMutableArray make_array_write_attribute(void *data, const int domain_size)
+template<typename T> GVMutableArray make_array_write_attribute(void *data, const int domain_num)
{
- return VMutableArray<T>::ForSpan(MutableSpan<T>((T *)data, domain_size));
+ return VMutableArray<T>::ForSpan(MutableSpan<T>((T *)data, domain_num));
}
/**
@@ -226,11 +226,11 @@ template<typename T> GVMutableArray make_array_write_attribute(void *data, const
* if the stored type is the same as the attribute type.
*/
class BuiltinCustomDataLayerProvider final : public BuiltinAttributeProvider {
- using AsReadAttribute = GVArray (*)(const void *data, int domain_size);
- using AsWriteAttribute = GVMutableArray (*)(void *data, int domain_size);
+ using AsReadAttribute = GVArray (*)(const void *data, int domain_num);
+ using AsWriteAttribute = GVMutableArray (*)(void *data, int domain_num);
using UpdateOnRead = void (*)(const GeometryComponent &component);
using UpdateOnWrite = void (*)(GeometryComponent &component);
- const CustomDataType stored_type_;
+ const eCustomDataType stored_type_;
const CustomDataAccessInfo custom_data_access_;
const AsReadAttribute as_read_attribute_;
const AsWriteAttribute as_write_attribute_;
@@ -239,9 +239,9 @@ class BuiltinCustomDataLayerProvider final : public BuiltinAttributeProvider {
public:
BuiltinCustomDataLayerProvider(std::string attribute_name,
- const AttributeDomain domain,
- const CustomDataType attribute_type,
- const CustomDataType stored_type,
+ const eAttrDomain domain,
+ const eCustomDataType attribute_type,
+ const eCustomDataType stored_type,
const CreatableEnum creatable,
const WritableEnum writable,
const DeletableEnum deletable,
@@ -288,7 +288,7 @@ class ComponentAttributeProviders {
/**
* All the domains that are supported by at least one of the providers above.
*/
- VectorSet<AttributeDomain> supported_domains_;
+ VectorSet<eAttrDomain> supported_domains_;
public:
ComponentAttributeProviders(Span<const BuiltinAttributeProvider *> builtin_attribute_providers,
@@ -301,7 +301,7 @@ class ComponentAttributeProviders {
supported_domains_.add(provider->domain());
}
for (const DynamicAttributesProvider *provider : dynamic_attribute_providers) {
- provider->foreach_domain([&](AttributeDomain domain) { supported_domains_.add(domain); });
+ provider->foreach_domain([&](eAttrDomain domain) { supported_domains_.add(domain); });
}
}
@@ -315,7 +315,7 @@ class ComponentAttributeProviders {
return dynamic_attribute_providers_;
}
- Span<AttributeDomain> supported_domains() const
+ Span<eAttrDomain> supported_domains() const
{
return supported_domains_;
}
diff --git a/source/blender/blenkernel/intern/blender_copybuffer.c b/source/blender/blenkernel/intern/blender_copybuffer.c
index f93b3efa8dd..4b507beb6b3 100644
--- a/source/blender/blenkernel/intern/blender_copybuffer.c
+++ b/source/blender/blenkernel/intern/blender_copybuffer.c
@@ -96,7 +96,7 @@ bool BKE_copybuffer_read(Main *bmain_dst,
ReportList *reports,
const uint64_t id_types_mask)
{
- /* Note: No recursive append here (no `BLO_LIBLINK_APPEND_RECURSIVE`), external linked data
+ /* NOTE: No recursive append here (no `BLO_LIBLINK_APPEND_RECURSIVE`), external linked data
* should remain linked. */
const int flag = 0;
const int id_tag_extra = 0;
@@ -132,7 +132,7 @@ int BKE_copybuffer_paste(bContext *C,
View3D *v3d = CTX_wm_view3d(C); /* may be NULL. */
const int id_tag_extra = 0;
- /* Note: No recursive append here, external linked data should remain linked. */
+ /* NOTE: No recursive append here, external linked data should remain linked. */
BLI_assert((flag & BLO_LIBLINK_APPEND_RECURSIVE) == 0);
struct LibraryLink_Params liblink_params;
diff --git a/source/blender/blenkernel/intern/blender_undo.c b/source/blender/blenkernel/intern/blender_undo.c
index c32941ccbc9..a5096b4f9eb 100644
--- a/source/blender/blenkernel/intern/blender_undo.c
+++ b/source/blender/blenkernel/intern/blender_undo.c
@@ -65,7 +65,7 @@ bool BKE_memfile_undo_decode(MemFileUndoData *mfu,
if (UNDO_DISK) {
const struct BlendFileReadParams params = {0};
BlendFileReadReport bf_reports = {.reports = NULL};
- struct BlendFileData *bfd = BKE_blendfile_read(mfu->filename, &params, &bf_reports);
+ struct BlendFileData *bfd = BKE_blendfile_read(mfu->filepath, &params, &bf_reports);
if (bfd != NULL) {
BKE_blendfile_read_setup(C, bfd, &params, &bf_reports);
success = true;
@@ -108,20 +108,20 @@ MemFileUndoData *BKE_memfile_undo_encode(Main *bmain, MemFileUndoData *mfu_prev)
/* disk save version */
if (UNDO_DISK) {
static int counter = 0;
- char filename[FILE_MAX];
+ char filepath[FILE_MAX];
char numstr[32];
- /* Calculate current filename. */
+ /* Calculate current filepath. */
counter++;
counter = counter % U.undosteps;
BLI_snprintf(numstr, sizeof(numstr), "%d.blend", counter);
- BLI_join_dirfile(filename, sizeof(filename), BKE_tempdir_session(), numstr);
+ BLI_join_dirfile(filepath, sizeof(filepath), BKE_tempdir_session(), numstr);
/* success = */ /* UNUSED */ BLO_write_file(
- bmain, filename, fileflags, &(const struct BlendFileWriteParams){0}, NULL);
+ bmain, filepath, fileflags, &(const struct BlendFileWriteParams){0}, NULL);
- BLI_strncpy(mfu->filename, filename, sizeof(mfu->filename));
+ BLI_strncpy(mfu->filepath, filepath, sizeof(mfu->filepath));
}
else {
MemFile *prevfile = (mfu_prev) ? &(mfu_prev->memfile) : NULL;
diff --git a/source/blender/blenkernel/intern/blendfile_link_append.c b/source/blender/blenkernel/intern/blendfile_link_append.c
index e2f22ef00d3..ebf48acde0f 100644
--- a/source/blender/blenkernel/intern/blendfile_link_append.c
+++ b/source/blender/blenkernel/intern/blendfile_link_append.c
@@ -400,7 +400,9 @@ typedef struct LooseDataInstantiateContext {
static bool object_in_any_scene(Main *bmain, Object *ob)
{
LISTBASE_FOREACH (Scene *, sce, &bmain->scenes) {
- if (BKE_scene_object_find(sce, ob)) {
+ /* #BKE_scene_has_object checks bases cache of the scenes' view-layer, not actual content of
+ * their collections. */
+ if (BKE_collection_has_object_recursive(sce->master_collection, ob)) {
return true;
}
}
@@ -456,17 +458,6 @@ static ID *loose_data_instantiate_process_check(LooseDataInstantiateContext *ins
return NULL;
}
- if (item->action == LINK_APPEND_ACT_COPY_LOCAL) {
- BLI_assert(ID_IS_LINKED(id));
- id = id->newid;
- if (id == NULL) {
- return NULL;
- }
-
- BLI_assert(!ID_IS_LINKED(id));
- return id;
- }
-
BLI_assert(!ID_IS_LINKED(id));
return id;
}
@@ -1123,7 +1114,7 @@ void BKE_blendfile_append(BlendfileLinkAppendContext *lapp_context, ReportList *
&LOG, "Unexpected unset append action for '%s' ID, assuming 'keep link'", id->name);
break;
default:
- BLI_assert(0);
+ BLI_assert_unreachable();
}
if (local_appended_new_id != NULL) {
@@ -1176,7 +1167,7 @@ void BKE_blendfile_append(BlendfileLinkAppendContext *lapp_context, ReportList *
for (itemlink = lapp_context->items.list; itemlink; itemlink = itemlink->next) {
BlendfileLinkAppendContextItem *item = itemlink->link;
- if (item->action != LINK_APPEND_ACT_REUSE_LOCAL) {
+ if (!ELEM(item->action, LINK_APPEND_ACT_COPY_LOCAL, LINK_APPEND_ACT_REUSE_LOCAL)) {
continue;
}
@@ -1187,13 +1178,15 @@ void BKE_blendfile_append(BlendfileLinkAppendContext *lapp_context, ReportList *
BLI_assert(ID_IS_LINKED(id));
BLI_assert(id->newid != NULL);
+ /* Calling code may want to access newly appended IDs from the link/append context items. */
+ item->new_id = id->newid;
+
/* Do NOT delete a linked data that was already linked before this append. */
if (id->tag & LIB_TAG_PRE_EXISTING) {
continue;
}
id->tag |= LIB_TAG_DOIT;
- item->new_id = id->newid;
}
BKE_id_multi_tagged_delete(bmain);
@@ -1202,26 +1195,6 @@ void BKE_blendfile_append(BlendfileLinkAppendContext *lapp_context, ReportList *
.active_collection = NULL};
loose_data_instantiate(&instantiate_context);
- /* Attempt to deal with object proxies.
- *
- * NOTE: Copied from `BKE_library_make_local`, but this is not really working (as in, not
- * producing any useful result in any known use case), neither here nor in
- * `BKE_library_make_local` currently.
- * Proxies are end of life anyway, so not worth spending time on this. */
- for (itemlink = lapp_context->items.list; itemlink; itemlink = itemlink->next) {
- BlendfileLinkAppendContextItem *item = itemlink->link;
-
- if (item->action != LINK_APPEND_ACT_COPY_LOCAL) {
- continue;
- }
-
- ID *id = item->new_id;
- if (id == NULL) {
- continue;
- }
- BLI_assert(ID_IS_LINKED(id));
- }
-
BKE_main_id_newptr_and_tag_clear(bmain);
blendfile_link_append_proxies_convert(bmain, reports);
diff --git a/source/blender/blenkernel/intern/brush.c b/source/blender/blenkernel/intern/brush.c
index e8c95869910..083d5af063a 100644
--- a/source/blender/blenkernel/intern/brush.c
+++ b/source/blender/blenkernel/intern/brush.c
@@ -2030,7 +2030,7 @@ float BKE_brush_sample_tex_3d(const Scene *scene,
/* leave the coordinates relative to the screen */
/* use unadjusted size for tiled mode */
- invradius = 1.0f / BKE_brush_size_get(scene, br);
+ invradius = 1.0f / ups->start_pixel_radius;
x = point_2d[0];
y = point_2d[1];
@@ -2143,7 +2143,7 @@ float BKE_brush_sample_masktex(
/* leave the coordinates relative to the screen */
/* use unadjusted size for tiled mode */
- invradius = 1.0f / BKE_brush_size_get(scene, br);
+ invradius = 1.0f / ups->start_pixel_radius;
x = point_2d[0];
y = point_2d[1];
diff --git a/source/blender/blenkernel/intern/bvhutils.cc b/source/blender/blenkernel/intern/bvhutils.cc
index 37b0875db67..35c2039634a 100644
--- a/source/blender/blenkernel/intern/bvhutils.cc
+++ b/source/blender/blenkernel/intern/bvhutils.cc
@@ -967,31 +967,6 @@ static BVHTree *bvhtree_from_mesh_faces_create_tree(float epsilon,
return tree;
}
-BVHTree *bvhtree_from_mesh_faces_ex(BVHTreeFromMesh *data,
- const MVert *vert,
- const MFace *face,
- const int numFaces,
- const BLI_bitmap *faces_mask,
- int faces_num_active,
- float epsilon,
- int tree_type,
- int axis)
-{
- BVHTree *tree = nullptr;
- tree = bvhtree_from_mesh_faces_create_tree(
- epsilon, tree_type, axis, vert, face, numFaces, faces_mask, faces_num_active);
-
- bvhtree_balance(tree, false);
-
- if (data) {
- /* Setup BVHTreeFromMesh */
- bvhtree_from_mesh_setup_data(
- tree, BVHTREE_FROM_FACES, vert, nullptr, face, nullptr, nullptr, nullptr, data);
- }
-
- return tree;
-}
-
/** \} */
/* -------------------------------------------------------------------- */
@@ -1212,10 +1187,11 @@ static BLI_bitmap *looptri_no_hidden_map_get(const MPoly *mpoly,
int looptri_no_hidden_len = 0;
int looptri_iter = 0;
- const MPoly *mp = mpoly;
+ int i_poly = 0;
while (looptri_iter != looptri_len) {
- int mp_totlooptri = mp->totloop - 2;
- if (mp->flag & ME_HIDE) {
+ int mp_totlooptri = mpoly[i_poly].totloop - 2;
+ const MPoly &mp = mpoly[i_poly];
+ if (mp.flag & ME_HIDE) {
looptri_iter += mp_totlooptri;
}
else {
@@ -1225,7 +1201,7 @@ static BLI_bitmap *looptri_no_hidden_map_get(const MPoly *mpoly,
looptri_no_hidden_len++;
}
}
- mp++;
+ i_poly++;
}
*r_looptri_active_len = looptri_no_hidden_len;
diff --git a/source/blender/blenkernel/intern/camera.c b/source/blender/blenkernel/intern/camera.c
index 32925168437..6325251647b 100644
--- a/source/blender/blenkernel/intern/camera.c
+++ b/source/blender/blenkernel/intern/camera.c
@@ -66,14 +66,19 @@ static void camera_init_data(ID *id)
*
* \param flag: Copying options (see BKE_lib_id.h's LIB_ID_COPY_... flags for more).
*/
-static void camera_copy_data(Main *UNUSED(bmain),
- ID *id_dst,
- const ID *id_src,
- const int UNUSED(flag))
+static void camera_copy_data(Main *UNUSED(bmain), ID *id_dst, const ID *id_src, const int flag)
{
Camera *cam_dst = (Camera *)id_dst;
const Camera *cam_src = (const Camera *)id_src;
- BLI_duplicatelist(&cam_dst->bg_images, &cam_src->bg_images);
+
+ /* We never handle usercount here for own data. */
+ const int flag_subdata = flag | LIB_ID_CREATE_NO_USER_REFCOUNT;
+
+ BLI_listbase_clear(&cam_dst->bg_images);
+ LISTBASE_FOREACH (CameraBGImage *, bgpic_src, &cam_src->bg_images) {
+ CameraBGImage *bgpic_dst = BKE_camera_background_image_copy(bgpic_src, flag_subdata);
+ BLI_addtail(&cam_dst->bg_images, bgpic_dst);
+ }
}
/** Free (or release) any data used by this camera (does not free the camera itself). */
@@ -125,6 +130,11 @@ static void camera_blend_read_data(BlendDataReader *reader, ID *id)
LISTBASE_FOREACH (CameraBGImage *, bgpic, &ca->bg_images) {
bgpic->iuser.scene = NULL;
+
+ /* If linking from a library, clear 'local' library override flag. */
+ if (ID_IS_LINKED(ca)) {
+ bgpic->flag &= ~CAM_BGIMG_FLAG_OVERRIDE_LIBRARY_LOCAL;
+ }
}
}
@@ -302,7 +312,7 @@ void BKE_camera_params_from_object(CameraParams *params, const Object *cam_ob)
}
void BKE_camera_params_from_view3d(CameraParams *params,
- Depsgraph *depsgraph,
+ const Depsgraph *depsgraph,
const View3D *v3d,
const RegionView3D *rv3d)
{
@@ -1119,13 +1129,31 @@ CameraBGImage *BKE_camera_background_image_new(Camera *cam)
bgpic->scale = 1.0f;
bgpic->alpha = 0.5f;
bgpic->iuser.flag |= IMA_ANIM_ALWAYS;
- bgpic->flag |= CAM_BGIMG_FLAG_EXPANDED;
+ bgpic->flag |= CAM_BGIMG_FLAG_EXPANDED | CAM_BGIMG_FLAG_OVERRIDE_LIBRARY_LOCAL;
BLI_addtail(&cam->bg_images, bgpic);
return bgpic;
}
+CameraBGImage *BKE_camera_background_image_copy(CameraBGImage *bgpic_src, const int flag)
+{
+ CameraBGImage *bgpic_dst = MEM_dupallocN(bgpic_src);
+
+ bgpic_dst->next = bgpic_dst->prev = NULL;
+
+ if ((flag & LIB_ID_CREATE_NO_USER_REFCOUNT) == 0) {
+ id_us_plus((ID *)bgpic_dst->ima);
+ id_us_plus((ID *)bgpic_dst->clip);
+ }
+
+ if ((flag & LIB_ID_COPY_NO_LIB_OVERRIDE_LOCAL_DATA_FLAG) == 0) {
+ bgpic_dst->flag |= CAM_BGIMG_FLAG_OVERRIDE_LIBRARY_LOCAL;
+ }
+
+ return bgpic_dst;
+}
+
void BKE_camera_background_image_remove(Camera *cam, CameraBGImage *bgpic)
{
BLI_remlink(&cam->bg_images, bgpic);
diff --git a/source/blender/blenkernel/intern/cdderivedmesh.c b/source/blender/blenkernel/intern/cdderivedmesh.c
index 2d742a103af..93286751f92 100644
--- a/source/blender/blenkernel/intern/cdderivedmesh.c
+++ b/source/blender/blenkernel/intern/cdderivedmesh.c
@@ -65,18 +65,6 @@ static int cdDM_getNumEdges(DerivedMesh *dm)
return dm->numEdgeData;
}
-static int cdDM_getNumTessFaces(DerivedMesh *dm)
-{
- /* uncomment and add a breakpoint on the printf()
- * to help debug tessfaces issues since BMESH merge. */
-#if 0
- if (dm->numTessFaceData == 0 && dm->numPolyData != 0) {
- printf("%s: has no faces!\n");
- }
-#endif
- return dm->numTessFaceData;
-}
-
static int cdDM_getNumLoops(DerivedMesh *dm)
{
return dm->numLoopData;
@@ -173,7 +161,6 @@ static CDDerivedMesh *cdDM_create(const char *desc)
dm->getNumVerts = cdDM_getNumVerts;
dm->getNumEdges = cdDM_getNumEdges;
- dm->getNumTessFaces = cdDM_getNumTessFaces;
dm->getNumLoops = cdDM_getNumLoops;
dm->getNumPolys = cdDM_getNumPolys;
diff --git a/source/blender/blenkernel/intern/cloth.c b/source/blender/blenkernel/intern/cloth.c
index 0d6a0c045a5..ab9a27a3996 100644
--- a/source/blender/blenkernel/intern/cloth.c
+++ b/source/blender/blenkernel/intern/cloth.c
@@ -632,7 +632,7 @@ static void cloth_apply_vgroup(ClothModifierData *clmd, Mesh *mesh)
verts->flags &= ~(CLOTH_VERT_FLAG_PINNED | CLOTH_VERT_FLAG_NOSELFCOLL |
CLOTH_VERT_FLAG_NOOBJCOLL);
- MDeformVert *dvert = CustomData_get(&mesh->vdata, i, CD_MDEFORMVERT);
+ const MDeformVert *dvert = CustomData_get(&mesh->vdata, i, CD_MDEFORMVERT);
if (dvert) {
for (int j = 0; j < dvert->totweight; j++) {
if (dvert->dw[j].def_nr == (clmd->sim_parms->vgroup_mass - 1)) {
@@ -715,7 +715,7 @@ static bool cloth_from_object(
int i = 0;
MVert *mvert = NULL;
ClothVertex *verts = NULL;
- float(*shapekey_rest)[3] = NULL;
+ const float(*shapekey_rest)[3] = NULL;
const float tnull[3] = {0, 0, 0};
/* If we have a clothObject, free it. */
@@ -1127,7 +1127,7 @@ static void cloth_update_springs(ClothModifierData *clmd)
spring->lin_stiffness = (v1->bend_stiff + v2->bend_stiff) / 2.0f;
}
else if (spring->type == CLOTH_SPRING_TYPE_GOAL) {
- /* Warning: Appending NEW goal springs does not work
+ /* WARNING: Appending NEW goal springs does not work
* because implicit solver would need reset! */
/* Activate / Deactivate existing springs */
diff --git a/source/blender/blenkernel/intern/collection.c b/source/blender/blenkernel/intern/collection.c
index 0edc16e822c..b71bcef229a 100644
--- a/source/blender/blenkernel/intern/collection.c
+++ b/source/blender/blenkernel/intern/collection.c
@@ -996,9 +996,11 @@ static void collection_tag_update_parent_recursive(Main *bmain,
}
}
-static Collection *collection_parent_editable_find_recursive(Collection *collection)
+static Collection *collection_parent_editable_find_recursive(const ViewLayer *view_layer,
+ Collection *collection)
{
- if (!ID_IS_LINKED(collection) && !ID_IS_OVERRIDE_LIBRARY(collection)) {
+ if (!ID_IS_LINKED(collection) && !ID_IS_OVERRIDE_LIBRARY(collection) &&
+ (view_layer == NULL || BKE_view_layer_has_collection(view_layer, collection))) {
return collection;
}
@@ -1009,10 +1011,16 @@ static Collection *collection_parent_editable_find_recursive(Collection *collect
LISTBASE_FOREACH (CollectionParent *, collection_parent, &collection->parents) {
if (!ID_IS_LINKED(collection_parent->collection) &&
!ID_IS_OVERRIDE_LIBRARY(collection_parent->collection)) {
+ if (view_layer != NULL &&
+ !BKE_view_layer_has_collection(view_layer, collection_parent->collection)) {
+ /* In case this parent collection is not in given view_layer, there is no point in
+ * searching in its ancestors either, we can skip that whole parenting branch. */
+ continue;
+ }
return collection_parent->collection;
}
Collection *editable_collection = collection_parent_editable_find_recursive(
- collection_parent->collection);
+ view_layer, collection_parent->collection);
if (editable_collection != NULL) {
return editable_collection;
}
@@ -1110,11 +1118,23 @@ bool BKE_collection_object_add_notest(Main *bmain, Collection *collection, Objec
bool BKE_collection_object_add(Main *bmain, Collection *collection, Object *ob)
{
+ return BKE_collection_viewlayer_object_add(bmain, NULL, collection, ob);
+}
+
+bool BKE_collection_viewlayer_object_add(Main *bmain,
+ const ViewLayer *view_layer,
+ Collection *collection,
+ Object *ob)
+{
if (collection == NULL) {
return false;
}
- collection = collection_parent_editable_find_recursive(collection);
+ collection = collection_parent_editable_find_recursive(view_layer, collection);
+
+ if (collection == NULL) {
+ return false;
+ }
return BKE_collection_object_add_notest(bmain, collection, ob);
}
@@ -1172,14 +1192,21 @@ static bool scene_collections_object_remove(
{
bool removed = false;
+ /* If given object is removed from all collections in given scene, then it can also be safely
+ * removed from rigidbody world for given scene. */
if (collection_skip == NULL) {
BKE_scene_remove_rigidbody_object(bmain, scene, ob, free_us);
}
FOREACH_SCENE_COLLECTION_BEGIN (scene, collection) {
- if (collection != collection_skip) {
- removed |= collection_object_remove(bmain, collection, ob, free_us);
+ if (ID_IS_LINKED(collection) || ID_IS_OVERRIDE_LIBRARY(collection)) {
+ continue;
}
+ if (collection == collection_skip) {
+ continue;
+ }
+
+ removed |= collection_object_remove(bmain, collection, ob, free_us);
}
FOREACH_SCENE_COLLECTION_END;
diff --git a/source/blender/blenkernel/intern/colortools.c b/source/blender/blenkernel/intern/colortools.c
index c3d66d4463d..e4c46703f8a 100644
--- a/source/blender/blenkernel/intern/colortools.c
+++ b/source/blender/blenkernel/intern/colortools.c
@@ -1158,6 +1158,80 @@ bool BKE_curvemapping_RGBA_does_something(const CurveMapping *cumap)
return false;
}
+void BKE_curvemapping_get_range_minimums(const CurveMapping *curve_mapping, float minimums[CM_TOT])
+{
+ for (int i = 0; i < CM_TOT; i++) {
+ minimums[i] = curve_mapping->cm[i].mintable;
+ }
+}
+
+void BKE_curvemapping_compute_range_dividers(const CurveMapping *curve_mapping,
+ float dividers[CM_TOT])
+{
+ for (int i = 0; i < CM_TOT; i++) {
+ const CurveMap *curve_map = &curve_mapping->cm[i];
+ dividers[i] = 1.0f / max_ff(1e-8f, curve_map->maxtable - curve_map->mintable);
+ }
+}
+
+void BKE_curvemapping_compute_slopes(const CurveMapping *curve_mapping,
+ float start_slopes[CM_TOT],
+ float end_slopes[CM_TOT])
+{
+ float range_dividers[CM_TOT];
+ BKE_curvemapping_compute_range_dividers(curve_mapping, range_dividers);
+ for (int i = 0; i < CM_TOT; i++) {
+ const CurveMap *curve_map = &curve_mapping->cm[i];
+ /* If extrapolation is not enabled, the slopes are horizontal. */
+ if (!(curve_mapping->flag & CUMA_EXTEND_EXTRAPOLATE)) {
+ start_slopes[i] = 0.0f;
+ end_slopes[i] = 0.0f;
+ continue;
+ }
+
+ if (curve_map->ext_in[0] != 0.0f) {
+ start_slopes[i] = curve_map->ext_in[1] / (curve_map->ext_in[0] * range_dividers[i]);
+ }
+ else {
+ start_slopes[i] = 1e8f;
+ }
+
+ if (curve_map->ext_out[0] != 0.0f) {
+ end_slopes[i] = curve_map->ext_out[1] / (curve_map->ext_out[0] * range_dividers[i]);
+ }
+ else {
+ end_slopes[i] = 1e8f;
+ }
+ }
+}
+
+bool BKE_curvemapping_is_map_identity(const CurveMapping *curve_mapping, int index)
+{
+ if (!(curve_mapping->flag & CUMA_EXTEND_EXTRAPOLATE)) {
+ return false;
+ }
+ const CurveMap *curve_map = &curve_mapping->cm[index];
+ if (curve_map->maxtable - curve_map->mintable != 1.0f) {
+ return false;
+ }
+ if (curve_map->ext_in[0] != curve_map->ext_in[1]) {
+ return false;
+ }
+ if (curve_map->ext_out[0] != curve_map->ext_out[1]) {
+ return false;
+ }
+ if (curve_map->totpoint != 2) {
+ return false;
+ }
+ if (curve_map->curve[0].x != 0 || curve_map->curve[0].y != 0) {
+ return false;
+ }
+ if (curve_map->curve[1].x != 0 || curve_map->curve[1].y != 0) {
+ return false;
+ }
+ return true;
+}
+
void BKE_curvemapping_init(CurveMapping *cumap)
{
int a;
diff --git a/source/blender/blenkernel/intern/constraint.c b/source/blender/blenkernel/intern/constraint.c
index 35f2f94bc91..aa09541c043 100644
--- a/source/blender/blenkernel/intern/constraint.c
+++ b/source/blender/blenkernel/intern/constraint.c
@@ -949,30 +949,9 @@ static void default_get_tarmat_full_bbone(struct Depsgraph *UNUSED(depsgraph),
} \
(void)0
-static void custom_space_id_looper(bConstraint *con, ConstraintIDFunc func, void *userdata)
+static bool is_custom_space_needed(bConstraint *con)
{
- func(con, (ID **)&con->space_object, false, userdata);
-}
-
-static int get_space_tar(bConstraint *con, ListBase *list)
-{
- if (!con || !list ||
- (con->ownspace != CONSTRAINT_SPACE_CUSTOM && con->tarspace != CONSTRAINT_SPACE_CUSTOM)) {
- return 0;
- }
- bConstraintTarget *ct;
- SINGLETARGET_GET_TARS(con, con->space_object, con->space_subtarget, ct, list);
- return 1;
-}
-
-static void flush_space_tar(bConstraint *con, ListBase *list, bool no_copy)
-{
- if (!con || !list ||
- (con->ownspace != CONSTRAINT_SPACE_CUSTOM && con->tarspace != CONSTRAINT_SPACE_CUSTOM)) {
- return;
- }
- bConstraintTarget *ct = (bConstraintTarget *)list->last;
- SINGLETARGET_FLUSH_TARS(con, con->space_object, con->space_subtarget, ct, list, no_copy);
+ return con->ownspace == CONSTRAINT_SPACE_CUSTOM || con->tarspace == CONSTRAINT_SPACE_CUSTOM;
}
/* --------- ChildOf Constraint ------------ */
@@ -1161,8 +1140,6 @@ static void trackto_id_looper(bConstraint *con, ConstraintIDFunc func, void *use
/* target only */
func(con, (ID **)&data->tar, false, userdata);
-
- custom_space_id_looper(con, func, userdata);
}
static int trackto_get_tars(bConstraint *con, ListBase *list)
@@ -1174,7 +1151,7 @@ static int trackto_get_tars(bConstraint *con, ListBase *list)
/* standard target-getting macro for single-target constraints */
SINGLETARGET_GET_TARS(con, data->tar, data->subtarget, ct, list);
- return 1 + get_space_tar(con, list);
+ return 1;
}
return 0;
@@ -1188,7 +1165,6 @@ static void trackto_flush_tars(bConstraint *con, ListBase *list, bool no_copy)
/* the following macro is used for all standard single-target constraints */
SINGLETARGET_FLUSH_TARS(con, data->tar, data->subtarget, ct, list, no_copy);
- flush_space_tar(con, list, no_copy);
}
}
@@ -1661,11 +1637,11 @@ static bConstraintTypeInfo CTI_LOCLIMIT = {
"Limit Location", /* name */
"bLocLimitConstraint", /* struct name */
NULL, /* free data */
- custom_space_id_looper, /* id looper */
+ NULL, /* id looper */
NULL, /* copy data */
NULL, /* new data */
- get_space_tar, /* get constraint targets */
- flush_space_tar, /* flush constraint targets */
+ NULL, /* get constraint targets */
+ NULL, /* flush constraint targets */
NULL, /* get target matrix */
loclimit_evaluate, /* evaluate */
};
@@ -1742,11 +1718,11 @@ static bConstraintTypeInfo CTI_ROTLIMIT = {
"Limit Rotation", /* name */
"bRotLimitConstraint", /* struct name */
NULL, /* free data */
- custom_space_id_looper, /* id looper */
+ NULL, /* id looper */
NULL, /* copy data */
NULL, /* new data */
- get_space_tar, /* get constraint targets */
- flush_space_tar, /* flush constraint targets */
+ NULL, /* get constraint targets */
+ NULL, /* flush constraint targets */
NULL, /* get target matrix */
rotlimit_evaluate, /* evaluate */
};
@@ -1809,11 +1785,11 @@ static bConstraintTypeInfo CTI_SIZELIMIT = {
"Limit Scale", /* name */
"bSizeLimitConstraint", /* struct name */
NULL, /* free data */
- custom_space_id_looper, /* id looper */
+ NULL, /* id looper */
NULL, /* copy data */
NULL, /* new data */
- get_space_tar, /* get constraint targets */
- flush_space_tar, /* flush constraint targets */
+ NULL, /* get constraint targets */
+ NULL, /* flush constraint targets */
NULL, /* get target matrix */
sizelimit_evaluate, /* evaluate */
};
@@ -1833,8 +1809,6 @@ static void loclike_id_looper(bConstraint *con, ConstraintIDFunc func, void *use
/* target only */
func(con, (ID **)&data->tar, false, userdata);
-
- custom_space_id_looper(con, func, userdata);
}
static int loclike_get_tars(bConstraint *con, ListBase *list)
@@ -1846,7 +1820,7 @@ static int loclike_get_tars(bConstraint *con, ListBase *list)
/* standard target-getting macro for single-target constraints */
SINGLETARGET_GET_TARS(con, data->tar, data->subtarget, ct, list);
- return 1 + get_space_tar(con, list);
+ return 1;
}
return 0;
@@ -1860,7 +1834,6 @@ static void loclike_flush_tars(bConstraint *con, ListBase *list, bool no_copy)
/* the following macro is used for all standard single-target constraints */
SINGLETARGET_FLUSH_TARS(con, data->tar, data->subtarget, ct, list, no_copy);
- flush_space_tar(con, list, no_copy);
}
}
@@ -1933,8 +1906,6 @@ static void rotlike_id_looper(bConstraint *con, ConstraintIDFunc func, void *use
/* target only */
func(con, (ID **)&data->tar, false, userdata);
-
- custom_space_id_looper(con, func, userdata);
}
static int rotlike_get_tars(bConstraint *con, ListBase *list)
@@ -1946,7 +1917,7 @@ static int rotlike_get_tars(bConstraint *con, ListBase *list)
/* standard target-getting macro for single-target constraints */
SINGLETARGET_GET_TARS(con, data->tar, data->subtarget, ct, list);
- return 1 + get_space_tar(con, list);
+ return 1;
}
return 0;
@@ -1960,7 +1931,6 @@ static void rotlike_flush_tars(bConstraint *con, ListBase *list, bool no_copy)
/* the following macro is used for all standard single-target constraints */
SINGLETARGET_FLUSH_TARS(con, data->tar, data->subtarget, ct, list, no_copy);
- flush_space_tar(con, list, no_copy);
}
}
@@ -2114,8 +2084,6 @@ static void sizelike_id_looper(bConstraint *con, ConstraintIDFunc func, void *us
/* target only */
func(con, (ID **)&data->tar, false, userdata);
-
- custom_space_id_looper(con, func, userdata);
}
static int sizelike_get_tars(bConstraint *con, ListBase *list)
@@ -2127,7 +2095,7 @@ static int sizelike_get_tars(bConstraint *con, ListBase *list)
/* standard target-getting macro for single-target constraints */
SINGLETARGET_GET_TARS(con, data->tar, data->subtarget, ct, list);
- return 1 + get_space_tar(con, list);
+ return 1;
}
return 0;
@@ -2141,7 +2109,6 @@ static void sizelike_flush_tars(bConstraint *con, ListBase *list, bool no_copy)
/* the following macro is used for all standard single-target constraints */
SINGLETARGET_FLUSH_TARS(con, data->tar, data->subtarget, ct, list, no_copy);
- flush_space_tar(con, list, no_copy);
}
}
@@ -2239,8 +2206,6 @@ static void translike_id_looper(bConstraint *con, ConstraintIDFunc func, void *u
/* target only */
func(con, (ID **)&data->tar, false, userdata);
-
- custom_space_id_looper(con, func, userdata);
}
static int translike_get_tars(bConstraint *con, ListBase *list)
@@ -2252,7 +2217,7 @@ static int translike_get_tars(bConstraint *con, ListBase *list)
/* standard target-getting macro for single-target constraints */
SINGLETARGET_GET_TARS(con, data->tar, data->subtarget, ct, list);
- return 1 + get_space_tar(con, list);
+ return 1;
}
return 0;
@@ -2266,7 +2231,6 @@ static void translike_flush_tars(bConstraint *con, ListBase *list, bool no_copy)
/* the following macro is used for all standard single-target constraints */
SINGLETARGET_FLUSH_TARS(con, data->tar, data->subtarget, ct, list, no_copy);
- flush_space_tar(con, list, no_copy);
}
}
@@ -2400,11 +2364,11 @@ static bConstraintTypeInfo CTI_SAMEVOL = {
"Maintain Volume", /* name */
"bSameVolumeConstraint", /* struct name */
NULL, /* free data */
- custom_space_id_looper, /* id looper */
+ NULL, /* id looper */
NULL, /* copy data */
samevolume_new_data, /* new data */
- get_space_tar, /* get constraint targets */
- flush_space_tar, /* flush constraint targets */
+ NULL, /* get constraint targets */
+ NULL, /* flush constraint targets */
NULL, /* get target matrix */
samevolume_evaluate, /* evaluate */
};
@@ -2810,8 +2774,6 @@ static void actcon_id_looper(bConstraint *con, ConstraintIDFunc func, void *user
/* action */
func(con, (ID **)&data->act, true, userdata);
-
- custom_space_id_looper(con, func, userdata);
}
static int actcon_get_tars(bConstraint *con, ListBase *list)
@@ -2823,7 +2785,7 @@ static int actcon_get_tars(bConstraint *con, ListBase *list)
/* standard target-getting macro for single-target constraints */
SINGLETARGET_GET_TARS(con, data->tar, data->subtarget, ct, list);
- return 1 + get_space_tar(con, list);
+ return 1;
}
return 0;
@@ -2837,7 +2799,6 @@ static void actcon_flush_tars(bConstraint *con, ListBase *list, bool no_copy)
/* the following macro is used for all standard single-target constraints */
SINGLETARGET_FLUSH_TARS(con, data->tar, data->subtarget, ct, list, no_copy);
- flush_space_tar(con, list, no_copy);
}
}
@@ -3338,8 +3299,6 @@ static void distlimit_id_looper(bConstraint *con, ConstraintIDFunc func, void *u
/* target only */
func(con, (ID **)&data->tar, false, userdata);
-
- custom_space_id_looper(con, func, userdata);
}
static int distlimit_get_tars(bConstraint *con, ListBase *list)
@@ -3351,7 +3310,7 @@ static int distlimit_get_tars(bConstraint *con, ListBase *list)
/* standard target-getting macro for single-target constraints */
SINGLETARGET_GET_TARS(con, data->tar, data->subtarget, ct, list);
- return 1 + get_space_tar(con, list);
+ return 1;
}
return 0;
@@ -3365,7 +3324,6 @@ static void distlimit_flush_tars(bConstraint *con, ListBase *list, bool no_copy)
/* the following macro is used for all standard single-target constraints */
SINGLETARGET_FLUSH_TARS(con, data->tar, data->subtarget, ct, list, no_copy);
- flush_space_tar(con, list, no_copy);
}
}
@@ -3694,8 +3652,6 @@ static void minmax_id_looper(bConstraint *con, ConstraintIDFunc func, void *user
/* target only */
func(con, (ID **)&data->tar, false, userdata);
-
- custom_space_id_looper(con, func, userdata);
}
static int minmax_get_tars(bConstraint *con, ListBase *list)
@@ -3707,7 +3663,7 @@ static int minmax_get_tars(bConstraint *con, ListBase *list)
/* standard target-getting macro for single-target constraints */
SINGLETARGET_GET_TARS(con, data->tar, data->subtarget, ct, list);
- return 1 + get_space_tar(con, list);
+ return 1;
}
return 0;
@@ -3721,7 +3677,6 @@ static void minmax_flush_tars(bConstraint *con, ListBase *list, bool no_copy)
/* the following macro is used for all standard single-target constraints */
SINGLETARGET_FLUSH_TARS(con, data->tar, data->subtarget, ct, list, no_copy);
- flush_space_tar(con, list, no_copy);
}
}
@@ -4019,8 +3974,6 @@ static void transform_id_looper(bConstraint *con, ConstraintIDFunc func, void *u
/* target only */
func(con, (ID **)&data->tar, false, userdata);
-
- custom_space_id_looper(con, func, userdata);
}
static int transform_get_tars(bConstraint *con, ListBase *list)
@@ -4032,7 +3985,7 @@ static int transform_get_tars(bConstraint *con, ListBase *list)
/* standard target-getting macro for single-target constraints */
SINGLETARGET_GET_TARS(con, data->tar, data->subtarget, ct, list);
- return 1 + get_space_tar(con, list);
+ return 1;
}
return 0;
@@ -4046,7 +3999,6 @@ static void transform_flush_tars(bConstraint *con, ListBase *list, bool no_copy)
/* the following macro is used for all standard single-target constraints */
SINGLETARGET_FLUSH_TARS(con, data->tar, data->subtarget, ct, list, no_copy);
- flush_space_tar(con, list, no_copy);
}
}
@@ -5582,6 +5534,19 @@ static void con_unlink_refs_cb(bConstraint *UNUSED(con),
}
}
+/** Helper function to invoke the id_looper callback, including custom space. */
+static void con_invoke_id_looper(const bConstraintTypeInfo *cti,
+ bConstraint *con,
+ ConstraintIDFunc func,
+ void *userdata)
+{
+ if (cti->id_looper) {
+ cti->id_looper(con, func, userdata);
+ }
+
+ func(con, (ID **)&con->space_object, false, userdata);
+}
+
void BKE_constraint_free_data_ex(bConstraint *con, bool do_id_user)
{
if (con->data) {
@@ -5594,8 +5559,8 @@ void BKE_constraint_free_data_ex(bConstraint *con, bool do_id_user)
}
/* unlink the referenced resources it uses */
- if (do_id_user && cti->id_looper) {
- cti->id_looper(con, con_unlink_refs_cb, NULL);
+ if (do_id_user) {
+ con_invoke_id_looper(cti, con, con_unlink_refs_cb, NULL);
}
}
@@ -5913,9 +5878,7 @@ void BKE_constraints_id_loop(ListBase *conlist, ConstraintIDFunc func, void *use
const bConstraintTypeInfo *cti = BKE_constraint_typeinfo_get(con);
if (cti) {
- if (cti->id_looper) {
- cti->id_looper(con, func, userdata);
- }
+ con_invoke_id_looper(cti, con, func, userdata);
}
}
}
@@ -5967,16 +5930,14 @@ static void constraint_copy_data_ex(bConstraint *dst,
}
/* Fix usercounts for all referenced data that need it. */
- if (cti->id_looper && (flag & LIB_ID_CREATE_NO_USER_REFCOUNT) == 0) {
- cti->id_looper(dst, con_fix_copied_refs_cb, NULL);
+ if ((flag & LIB_ID_CREATE_NO_USER_REFCOUNT) == 0) {
+ con_invoke_id_looper(cti, dst, con_fix_copied_refs_cb, NULL);
}
/* for proxies we don't want to make extern */
if (do_extern) {
/* go over used ID-links for this constraint to ensure that they are valid for proxies */
- if (cti->id_looper) {
- cti->id_looper(dst, con_extern_cb, NULL);
- }
+ con_invoke_id_looper(cti, dst, con_extern_cb, NULL);
}
}
}
@@ -6191,6 +6152,63 @@ bool BKE_constraint_is_nonlocal_in_liboverride(const Object *ob, const bConstrai
/* -------- Target-Matrix Stuff ------- */
+int BKE_constraint_targets_get(struct bConstraint *con, struct ListBase *r_targets)
+{
+ BLI_listbase_clear(r_targets);
+
+ const bConstraintTypeInfo *cti = BKE_constraint_typeinfo_get(con);
+
+ if (!cti) {
+ return 0;
+ }
+
+ int count = 0;
+
+ /* Constraint-specific targets. */
+ if (cti->get_constraint_targets) {
+ count = cti->get_constraint_targets(con, r_targets);
+ }
+
+ /* Add the custom target. */
+ if (is_custom_space_needed(con)) {
+ bConstraintTarget *ct;
+ SINGLETARGET_GET_TARS(con, con->space_object, con->space_subtarget, ct, r_targets);
+ ct->space = CONSTRAINT_SPACE_WORLD;
+ ct->flag |= CONSTRAINT_TAR_CUSTOM_SPACE;
+ count++;
+ }
+
+ return count;
+}
+
+void BKE_constraint_targets_flush(struct bConstraint *con, struct ListBase *targets, bool no_copy)
+{
+ const bConstraintTypeInfo *cti = BKE_constraint_typeinfo_get(con);
+
+ if (!cti) {
+ return;
+ }
+
+ /* Remove the custom target. */
+ bConstraintTarget *ct = (bConstraintTarget *)targets->last;
+
+ if (ct && (ct->flag & CONSTRAINT_TAR_CUSTOM_SPACE)) {
+ BLI_assert(is_custom_space_needed(con));
+
+ if (!no_copy) {
+ con->space_object = ct->tar;
+ BLI_strncpy(con->space_subtarget, ct->subtarget, sizeof(con->space_subtarget));
+ }
+
+ BLI_freelinkN(targets, ct);
+ }
+
+ /* Release the constraint-specific targets. */
+ if (cti->flush_constraint_targets) {
+ cti->flush_constraint_targets(con, targets, no_copy);
+ }
+}
+
void BKE_constraint_target_matrix_get(struct Depsgraph *depsgraph,
Scene *scene,
bConstraint *con,
diff --git a/source/blender/blenkernel/intern/crazyspace.c b/source/blender/blenkernel/intern/crazyspace.c
index 96389c44839..14e862c2377 100644
--- a/source/blender/blenkernel/intern/crazyspace.c
+++ b/source/blender/blenkernel/intern/crazyspace.c
@@ -13,8 +13,8 @@
#include "DNA_object_types.h"
#include "DNA_scene_types.h"
+#include "BLI_bitmap.h"
#include "BLI_linklist.h"
-#include "BLI_math.h"
#include "BLI_utildefines.h"
#include "BKE_DerivedMesh.h"
diff --git a/source/blender/blenkernel/intern/curve.cc b/source/blender/blenkernel/intern/curve.cc
index 4338883853d..5125e010b81 100644
--- a/source/blender/blenkernel/intern/curve.cc
+++ b/source/blender/blenkernel/intern/curve.cc
@@ -44,7 +44,6 @@
#include "BKE_lib_query.h"
#include "BKE_main.h"
#include "BKE_object.h"
-#include "BKE_spline.hh"
#include "BKE_vfont.h"
#include "DEG_depsgraph.h"
diff --git a/source/blender/blenkernel/intern/curve_bezier.cc b/source/blender/blenkernel/intern/curve_bezier.cc
index 13695525616..5ba17f1761b 100644
--- a/source/blender/blenkernel/intern/curve_bezier.cc
+++ b/source/blender/blenkernel/intern/curve_bezier.cc
@@ -20,8 +20,8 @@ bool segment_is_vector(const Span<int8_t> handle_types_left,
handle_types_left[segment_index + 1] == BEZIER_HANDLE_VECTOR;
}
-bool last_cylic_segment_is_vector(const Span<int8_t> handle_types_left,
- const Span<int8_t> handle_types_right)
+bool last_cyclic_segment_is_vector(const Span<int8_t> handle_types_left,
+ const Span<int8_t> handle_types_right)
{
return handle_types_right.last() == BEZIER_HANDLE_VECTOR &&
handle_types_left.first() == BEZIER_HANDLE_VECTOR;
@@ -49,7 +49,8 @@ void calculate_evaluated_offsets(const Span<int8_t> handle_types_left,
}
if (cyclic) {
- offset += last_cylic_segment_is_vector(handle_types_left, handle_types_right) ? 1 : resolution;
+ offset += last_cyclic_segment_is_vector(handle_types_left, handle_types_right) ? 1 :
+ resolution;
}
else {
offset++;
diff --git a/source/blender/blenkernel/intern/curve_catmull_rom.cc b/source/blender/blenkernel/intern/curve_catmull_rom.cc
index 2db183eea3e..4b2174c912c 100644
--- a/source/blender/blenkernel/intern/curve_catmull_rom.cc
+++ b/source/blender/blenkernel/intern/curve_catmull_rom.cc
@@ -9,11 +9,11 @@
namespace blender::bke::curves::catmull_rom {
-int calculate_evaluated_size(const int points_num, const bool cyclic, const int resolution)
+int calculate_evaluated_num(const int points_num, const bool cyclic, const int resolution)
{
- const int eval_size = resolution * curve_segment_size(points_num, cyclic);
+ const int eval_num = resolution * curve_segment_num(points_num, cyclic);
/* If the curve isn't cyclic, one last point is added to the final point. */
- return cyclic ? eval_size : eval_size + 1;
+ return cyclic ? eval_num : eval_num + 1;
}
/* Adapted from Cycles #catmull_rom_basis_eval function. */
@@ -46,7 +46,7 @@ static void interpolate_to_evaluated(const Span<T> src,
MutableSpan<T> dst)
{
- BLI_assert(dst.size() == calculate_evaluated_size(src.size(), cyclic, resolution));
+ BLI_assert(dst.size() == calculate_evaluated_num(src.size(), cyclic, resolution));
/* - First deal with one and two point curves need special attention.
* - Then evaluate the first and last segment(s) whose control points need to wrap around
diff --git a/source/blender/blenkernel/intern/curve_eval.cc b/source/blender/blenkernel/intern/curve_eval.cc
index 3d9dd3ecf31..dd2bd982506 100644
--- a/source/blender/blenkernel/intern/curve_eval.cc
+++ b/source/blender/blenkernel/intern/curve_eval.cc
@@ -117,7 +117,7 @@ float CurveEval::total_length() const
return length;
}
-int CurveEval::total_control_point_size() const
+int CurveEval::total_control_point_num() const
{
int count = 0;
for (const SplinePtr &spline : this->splines()) {
@@ -144,7 +144,7 @@ blender::Array<int> CurveEval::evaluated_point_offsets() const
int offset = 0;
for (const int i : splines_.index_range()) {
offsets[i] = offset;
- offset += splines_[i]->evaluated_points_size();
+ offset += splines_[i]->evaluated_points_num();
}
offsets.last() = offset;
return offsets;
@@ -373,15 +373,15 @@ static void copy_attributes_between_components(const GeometryComponent &src_comp
});
}
-std::unique_ptr<CurveEval> curves_to_curve_eval(const Curves &curves)
+std::unique_ptr<CurveEval> curves_to_curve_eval(const Curves &curves_id)
{
CurveComponent src_component;
- src_component.replace(&const_cast<Curves &>(curves), GeometryOwnershipType::ReadOnly);
- const blender::bke::CurvesGeometry &geometry = blender::bke::CurvesGeometry::wrap(
- curves.geometry);
+ src_component.replace(&const_cast<Curves &>(curves_id), GeometryOwnershipType::ReadOnly);
+ const blender::bke::CurvesGeometry &curves = blender::bke::CurvesGeometry::wrap(
+ curves_id.geometry);
- VArray<int> resolution = geometry.resolution();
- VArray<int8_t> normal_mode = geometry.normal_mode();
+ VArray<int> resolution = curves.resolution();
+ VArray<int8_t> normal_mode = curves.normal_mode();
VArray_Span<float> nurbs_weights{
src_component.attribute_get_for_read<float>("nurbs_weight", ATTR_DOMAIN_POINT, 0.0f)};
@@ -396,34 +396,34 @@ std::unique_ptr<CurveEval> curves_to_curve_eval(const Curves &curves)
src_component.attribute_get_for_read<int8_t>("handle_type_left", ATTR_DOMAIN_POINT, 0)};
/* Create splines with the correct size and type. */
- VArray<int8_t> curve_types = geometry.curve_types();
+ VArray<int8_t> curve_types = curves.curve_types();
std::unique_ptr<CurveEval> curve_eval = std::make_unique<CurveEval>();
for (const int curve_index : curve_types.index_range()) {
- const IndexRange point_range = geometry.points_for_curve(curve_index);
+ const IndexRange points = curves.points_for_curve(curve_index);
std::unique_ptr<Spline> spline;
/* #CurveEval does not support catmull rom curves, so convert those to poly splines. */
switch (std::max<int8_t>(1, curve_types[curve_index])) {
case CURVE_TYPE_POLY: {
spline = std::make_unique<PolySpline>();
- spline->resize(point_range.size());
+ spline->resize(points.size());
break;
}
case CURVE_TYPE_BEZIER: {
std::unique_ptr<BezierSpline> bezier_spline = std::make_unique<BezierSpline>();
- bezier_spline->resize(point_range.size());
+ bezier_spline->resize(points.size());
bezier_spline->set_resolution(resolution[curve_index]);
- bezier_spline->handle_types_left().copy_from(handle_types_left.slice(point_range));
- bezier_spline->handle_types_right().copy_from(handle_types_right.slice(point_range));
+ bezier_spline->handle_types_left().copy_from(handle_types_left.slice(points));
+ bezier_spline->handle_types_right().copy_from(handle_types_right.slice(points));
spline = std::move(bezier_spline);
break;
}
case CURVE_TYPE_NURBS: {
std::unique_ptr<NURBSpline> nurb_spline = std::make_unique<NURBSpline>();
- nurb_spline->resize(point_range.size());
+ nurb_spline->resize(points.size());
nurb_spline->set_resolution(resolution[curve_index]);
- nurb_spline->weights().copy_from(nurbs_weights.slice(point_range));
+ nurb_spline->weights().copy_from(nurbs_weights.slice(points));
nurb_spline->set_order(nurbs_orders[curve_index]);
nurb_spline->knots_mode = static_cast<KnotsMode>(nurbs_knots_modes[curve_index]);
@@ -463,14 +463,14 @@ std::unique_ptr<CurveEval> curves_to_curve_eval(const Curves &curves)
Curves *curve_eval_to_curves(const CurveEval &curve_eval)
{
- Curves *curves = blender::bke::curves_new_nomain(curve_eval.total_control_point_size(),
- curve_eval.splines().size());
+ Curves *curves_id = blender::bke::curves_new_nomain(curve_eval.total_control_point_num(),
+ curve_eval.splines().size());
CurveComponent dst_component;
- dst_component.replace(curves, GeometryOwnershipType::Editable);
+ dst_component.replace(curves_id, GeometryOwnershipType::Editable);
- blender::bke::CurvesGeometry &geometry = blender::bke::CurvesGeometry::wrap(curves->geometry);
- geometry.offsets_for_write().copy_from(curve_eval.control_point_offsets());
- MutableSpan<int8_t> curve_types = geometry.curve_types_for_write();
+ blender::bke::CurvesGeometry &curves = blender::bke::CurvesGeometry::wrap(curves_id->geometry);
+ curves.offsets_for_write().copy_from(curve_eval.control_point_offsets());
+ MutableSpan<int8_t> curve_types = curves.curve_types_for_write();
OutputAttribute_Typed<int8_t> normal_mode =
dst_component.attribute_try_get_for_output_only<int8_t>("normal_mode", ATTR_DOMAIN_CURVE);
@@ -498,22 +498,22 @@ Curves *curve_eval_to_curves(const CurveEval &curve_eval)
const Spline &spline = *curve_eval.splines()[curve_index];
curve_types[curve_index] = curve_eval.splines()[curve_index]->type();
normal_mode.as_span()[curve_index] = curve_eval.splines()[curve_index]->normal_mode;
- const IndexRange point_range = geometry.points_for_curve(curve_index);
+ const IndexRange points = curves.points_for_curve(curve_index);
switch (spline.type()) {
case CURVE_TYPE_POLY:
break;
case CURVE_TYPE_BEZIER: {
const BezierSpline &src = static_cast<const BezierSpline &>(spline);
- handle_type_right.as_span().slice(point_range).copy_from(src.handle_types_right());
- handle_type_left.as_span().slice(point_range).copy_from(src.handle_types_left());
+ handle_type_right.as_span().slice(points).copy_from(src.handle_types_right());
+ handle_type_left.as_span().slice(points).copy_from(src.handle_types_left());
break;
}
case CURVE_TYPE_NURBS: {
const NURBSpline &src = static_cast<const NURBSpline &>(spline);
nurbs_knots_mode.as_span()[curve_index] = static_cast<int8_t>(src.knots_mode);
nurbs_order.as_span()[curve_index] = src.order();
- nurbs_weight.as_span().slice(point_range).copy_from(src.weights());
+ nurbs_weight.as_span().slice(points).copy_from(src.weights());
break;
}
case CURVE_TYPE_CATMULL_ROM: {
@@ -523,7 +523,7 @@ Curves *curve_eval_to_curves(const CurveEval &curve_eval)
}
}
- geometry.update_curve_types();
+ curves.update_curve_types();
normal_mode.save();
nurbs_weight.save();
@@ -537,7 +537,7 @@ Curves *curve_eval_to_curves(const CurveEval &curve_eval)
copy_attributes_between_components(src_component, dst_component, {});
- return curves;
+ return curves_id;
}
void CurveEval::assert_valid_point_attributes() const
diff --git a/source/blender/blenkernel/intern/curve_nurbs.cc b/source/blender/blenkernel/intern/curve_nurbs.cc
index 45440358221..cd6b64e9a03 100644
--- a/source/blender/blenkernel/intern/curve_nurbs.cc
+++ b/source/blender/blenkernel/intern/curve_nurbs.cc
@@ -10,10 +10,10 @@
namespace blender::bke::curves::nurbs {
-bool check_valid_size_and_order(const int points_num,
- const int8_t order,
- const bool cyclic,
- const KnotsMode knots_mode)
+bool check_valid_num_and_order(const int points_num,
+ const int8_t order,
+ const bool cyclic,
+ const KnotsMode knots_mode)
{
if (points_num < order) {
return false;
@@ -29,19 +29,19 @@ bool check_valid_size_and_order(const int points_num,
return true;
}
-int calculate_evaluated_size(const int points_num,
- const int8_t order,
- const bool cyclic,
- const int resolution,
- const KnotsMode knots_mode)
+int calculate_evaluated_num(const int points_num,
+ const int8_t order,
+ const bool cyclic,
+ const int resolution,
+ const KnotsMode knots_mode)
{
- if (!check_valid_size_and_order(points_num, order, cyclic, knots_mode)) {
+ if (!check_valid_num_and_order(points_num, order, cyclic, knots_mode)) {
return points_num;
}
- return resolution * curve_segment_size(points_num, cyclic);
+ return resolution * curve_segment_num(points_num, cyclic);
}
-int knots_size(const int points_num, const int8_t order, const bool cyclic)
+int knots_num(const int points_num, const int8_t order, const bool cyclic)
{
if (cyclic) {
return points_num + order * 2 - 1;
@@ -55,7 +55,7 @@ void calculate_knots(const int points_num,
const bool cyclic,
MutableSpan<float> knots)
{
- BLI_assert(knots.size() == knots_size(points_num, order, cyclic));
+ BLI_assert(knots.size() == knots_num(points_num, order, cyclic));
UNUSED_VARS_NDEBUG(points_num);
const bool is_bezier = ELEM(mode, NURBS_KNOT_MODE_BEZIER, NURBS_KNOT_MODE_ENDPOINT_BEZIER);
@@ -147,7 +147,7 @@ static void calculate_basis_for_point(const float parameter,
}
void calculate_basis_cache(const int points_num,
- const int evaluated_size,
+ const int evaluated_num,
const int8_t order,
const bool cyclic,
const Span<float> knots,
@@ -157,10 +157,10 @@ void calculate_basis_cache(const int points_num,
const int8_t degree = order - 1;
- basis_cache.weights.resize(evaluated_size * order);
- basis_cache.start_indices.resize(evaluated_size);
+ basis_cache.weights.resize(evaluated_num * order);
+ basis_cache.start_indices.resize(evaluated_num);
- if (evaluated_size == 0) {
+ if (evaluated_num == 0) {
return;
}
@@ -168,12 +168,12 @@ void calculate_basis_cache(const int points_num,
MutableSpan<int> basis_start_indices(basis_cache.start_indices);
const int last_control_point_index = cyclic ? points_num + degree : points_num;
- const int evaluated_segment_size = curve_segment_size(evaluated_size, cyclic);
+ const int evaluated_segment_num = curve_segment_num(evaluated_num, cyclic);
const float start = knots[degree];
const float end = knots[last_control_point_index];
- const float step = (end - start) / evaluated_segment_size;
- for (const int i : IndexRange(evaluated_size)) {
+ const float step = (end - start) / evaluated_segment_num;
+ for (const int i : IndexRange(evaluated_num)) {
/* Clamp parameter due to floating point inaccuracy. */
const float parameter = std::clamp(start + step * i, knots[0], knots[points_num + degree]);
diff --git a/source/blender/blenkernel/intern/curve_poly.cc b/source/blender/blenkernel/intern/curve_poly.cc
index 1b337379604..7ab92068d81 100644
--- a/source/blender/blenkernel/intern/curve_poly.cc
+++ b/source/blender/blenkernel/intern/curve_poly.cc
@@ -13,15 +13,28 @@
namespace blender::bke::curves::poly {
-static float3 direction_bisect(const float3 &prev, const float3 &middle, const float3 &next)
+static float3 direction_bisect(const float3 &prev,
+ const float3 &middle,
+ const float3 &next,
+ bool &r_used_fallback)
{
+ const float epsilon = 1e-6f;
+ const bool prev_equal = math::almost_equal_relative(prev, middle, epsilon);
+ const bool next_equal = math::almost_equal_relative(middle, next, epsilon);
+ if (prev_equal && next_equal) {
+ r_used_fallback = true;
+ return {0.0f, 0.0f, 0.0f};
+ }
+ if (prev_equal) {
+ return math::normalize(next - middle);
+ }
+ if (next_equal) {
+ return math::normalize(middle - prev);
+ }
+
const float3 dir_prev = math::normalize(middle - prev);
const float3 dir_next = math::normalize(next - middle);
-
const float3 result = math::normalize(dir_prev + dir_next);
- if (UNLIKELY(math::is_zero(result))) {
- return float3(0.0f, 0.0f, 1.0f);
- }
return result;
}
@@ -36,8 +49,11 @@ void calculate_tangents(const Span<float3> positions,
return;
}
+ bool used_fallback = false;
+
for (const int i : IndexRange(1, positions.size() - 2)) {
- tangents[i] = direction_bisect(positions[i - 1], positions[i], positions[i + 1]);
+ tangents[i] = direction_bisect(
+ positions[i - 1], positions[i], positions[i + 1], used_fallback);
}
if (is_cyclic) {
@@ -45,13 +61,46 @@ void calculate_tangents(const Span<float3> positions,
const float3 &last = positions.last();
const float3 &first = positions.first();
const float3 &second = positions[1];
- tangents.first() = direction_bisect(last, first, second);
- tangents.last() = direction_bisect(second_to_last, last, first);
+ tangents.first() = direction_bisect(last, first, second, used_fallback);
+ tangents.last() = direction_bisect(second_to_last, last, first, used_fallback);
}
else {
tangents.first() = math::normalize(positions[1] - positions.first());
tangents.last() = math::normalize(positions.last() - positions[positions.size() - 2]);
}
+
+ if (!used_fallback) {
+ return;
+ }
+
+ /* Find the first tangent that does not use the fallback. */
+ int first_valid_tangent_index = -1;
+ for (const int i : tangents.index_range()) {
+ if (!math::is_zero(tangents[i])) {
+ first_valid_tangent_index = i;
+ break;
+ }
+ }
+ if (first_valid_tangent_index == -1) {
+ /* If all tangents used the fallback, it means that all positions are (almost) the same. Just
+ * use the up-vector as default tangent. */
+ const float3 up_vector{0.0f, 0.0f, 1.0f};
+ tangents.fill(up_vector);
+ }
+ else {
+ const float3 &first_valid_tangent = tangents[first_valid_tangent_index];
+ /* If the first few tangents are invalid, use the tangent from the first point with a valid
+ * tangent. */
+ tangents.take_front(first_valid_tangent_index).fill(first_valid_tangent);
+ /* Use the previous valid tangent for points that had no valid tangent. */
+ for (const int i : tangents.index_range().drop_front(first_valid_tangent_index + 1)) {
+ float3 &tangent = tangents[i];
+ if (math::is_zero(tangent)) {
+ const float3 &prev_tangent = tangents[i - 1];
+ tangent = prev_tangent;
+ }
+ }
+ }
}
void calculate_normals_z_up(const Span<float3> tangents, MutableSpan<float3> normals)
diff --git a/source/blender/blenkernel/intern/curve_to_mesh_convert.cc b/source/blender/blenkernel/intern/curve_to_mesh_convert.cc
index ef921797698..58380a1a35f 100644
--- a/source/blender/blenkernel/intern/curve_to_mesh_convert.cc
+++ b/source/blender/blenkernel/intern/curve_to_mesh_convert.cc
@@ -39,8 +39,8 @@ static void fill_mesh_topology(const int vert_offset,
MutableSpan<MLoop> loops,
MutableSpan<MPoly> polys)
{
- const int main_segment_num = curves::curve_segment_size(main_point_num, main_cyclic);
- const int profile_segment_num = curves::curve_segment_size(profile_point_num, profile_cyclic);
+ const int main_segment_num = curves::curve_segment_num(main_point_num, main_cyclic);
+ const int profile_segment_num = curves::curve_segment_num(profile_point_num, profile_cyclic);
if (profile_point_num == 1) {
for (const int i : IndexRange(main_point_num - 1)) {
@@ -134,9 +134,9 @@ static void fill_mesh_topology(const int vert_offset,
const bool has_caps = fill_caps && !main_cyclic && profile_cyclic;
if (has_caps) {
- const int poly_size = main_segment_num * profile_segment_num;
- const int cap_loop_offset = loop_offset + poly_size * 4;
- const int cap_poly_offset = poly_offset + poly_size;
+ const int poly_num = main_segment_num * profile_segment_num;
+ const int cap_loop_offset = loop_offset + poly_num * 4;
+ const int cap_poly_offset = poly_offset + poly_num;
MPoly &poly_start = polys[cap_poly_offset];
poly_start.loopstart = cap_loop_offset;
@@ -273,7 +273,7 @@ static ResultOffsets calculate_result_offsets(const CurvesInfo &info, const bool
for (const int i_main : info.main.curves_range()) {
const bool main_cyclic = info.main_cyclic[i_main];
const int main_point_num = info.main.evaluated_points_for_curve(i_main).size();
- const int main_segment_num = curves::curve_segment_size(main_point_num, main_cyclic);
+ const int main_segment_num = curves::curve_segment_num(main_point_num, main_cyclic);
for (const int i_profile : info.profile.curves_range()) {
result.vert[mesh_index] = vert_offset;
result.edge[mesh_index] = edge_offset;
@@ -285,8 +285,7 @@ static ResultOffsets calculate_result_offsets(const CurvesInfo &info, const bool
const bool profile_cyclic = info.profile_cyclic[i_profile];
const int profile_point_num = info.profile.evaluated_points_for_curve(i_profile).size();
- const int profile_segment_num = curves::curve_segment_size(profile_point_num,
- profile_cyclic);
+ const int profile_segment_num = curves::curve_segment_num(profile_point_num, profile_cyclic);
const bool has_caps = fill_caps && !main_cyclic && profile_cyclic;
const int tube_face_num = main_segment_num * profile_segment_num;
@@ -316,8 +315,8 @@ static ResultOffsets calculate_result_offsets(const CurvesInfo &info, const bool
return result;
}
-static AttributeDomain get_attribute_domain_for_mesh(const MeshComponent &mesh,
- const AttributeIDRef &attribute_id)
+static eAttrDomain get_attribute_domain_for_mesh(const MeshComponent &mesh,
+ const AttributeIDRef &attribute_id)
{
/* Only use a different domain if it is builtin and must only exist on one domain. */
if (!mesh.attribute_is_builtin(attribute_id)) {
@@ -408,8 +407,8 @@ static void foreach_curve_combination(const CurvesInfo &info,
profile_points,
main_cyclic,
profile_cyclic,
- curves::curve_segment_size(main_points.size(), main_cyclic),
- curves::curve_segment_size(profile_points.size(), profile_cyclic),
+ curves::curve_segment_num(main_points.size(), main_cyclic),
+ curves::curve_segment_num(profile_points.size(), profile_cyclic),
offsets_to_range(offsets.vert.as_span(), i),
offsets_to_range(offsets.edge.as_span(), i),
offsets_to_range(offsets.poly.as_span(), i),
@@ -457,7 +456,7 @@ static void copy_main_point_data_to_mesh_faces(const Span<T> src,
static void copy_main_point_domain_attribute_to_mesh(const CurvesInfo &curves_info,
const ResultOffsets &offsets,
- const AttributeDomain dst_domain,
+ const eAttrDomain dst_domain,
const GSpan src_all,
GMutableSpan dst_all)
{
@@ -539,7 +538,7 @@ static void copy_profile_point_data_to_mesh_faces(const Span<T> src,
static void copy_profile_point_domain_attribute_to_mesh(const CurvesInfo &curves_info,
const ResultOffsets &offsets,
- const AttributeDomain dst_domain,
+ const eAttrDomain dst_domain,
const GSpan src_all,
GMutableSpan dst_all)
{
@@ -598,7 +597,7 @@ static void copy_indices_to_offset_ranges(const VArray<T> &src,
static void copy_curve_domain_attribute_to_mesh(const ResultOffsets &mesh_offsets,
const Span<int> curve_indices,
- const AttributeDomain dst_domain,
+ const eAttrDomain dst_domain,
const GVArray &src,
GMutableSpan dst)
{
@@ -729,11 +728,11 @@ Mesh *curve_to_mesh_sweep(const CurvesGeometry &main,
}
main_attributes.add_new(id);
- const AttributeDomain src_domain = meta_data.domain;
- const CustomDataType type = meta_data.data_type;
+ const eAttrDomain src_domain = meta_data.domain;
+ const eCustomDataType type = meta_data.data_type;
GVArray src = main_component.attribute_try_get_for_read(id, src_domain, type);
- const AttributeDomain dst_domain = get_attribute_domain_for_mesh(mesh_component, id);
+ const eAttrDomain dst_domain = get_attribute_domain_for_mesh(mesh_component, id);
OutputAttribute dst = mesh_component.attribute_try_get_for_output_only(id, dst_domain, type);
if (!dst) {
return true;
@@ -764,11 +763,11 @@ Mesh *curve_to_mesh_sweep(const CurvesGeometry &main,
if (!should_add_attribute_to_mesh(profile_component, mesh_component, id)) {
return true;
}
- const AttributeDomain src_domain = meta_data.domain;
- const CustomDataType type = meta_data.data_type;
+ const eAttrDomain src_domain = meta_data.domain;
+ const eCustomDataType type = meta_data.data_type;
GVArray src = profile_component.attribute_try_get_for_read(id, src_domain, type);
- const AttributeDomain dst_domain = get_attribute_domain_for_mesh(mesh_component, id);
+ const eAttrDomain dst_domain = get_attribute_domain_for_mesh(mesh_component, id);
OutputAttribute dst = mesh_component.attribute_try_get_for_output_only(id, dst_domain, type);
if (!dst) {
return true;
diff --git a/source/blender/blenkernel/intern/curves.cc b/source/blender/blenkernel/intern/curves.cc
index 1df1492bac1..7ad83263b73 100644
--- a/source/blender/blenkernel/intern/curves.cc
+++ b/source/blender/blenkernel/intern/curves.cc
@@ -23,6 +23,7 @@
#include "BLI_span.hh"
#include "BLI_string.h"
#include "BLI_utildefines.h"
+#include "BLI_vector.hh"
#include "BKE_anim_data.h"
#include "BKE_curves.hh"
@@ -48,6 +49,7 @@ using blender::IndexRange;
using blender::MutableSpan;
using blender::RandomNumberGenerator;
using blender::Span;
+using blender::Vector;
static const char *ATTR_POSITION = "position";
@@ -78,15 +80,19 @@ static void curves_copy_data(Main *UNUSED(bmain), ID *id_dst, const ID *id_src,
* shallow copy from the source to the destination, and because the copy-on-write functionality
* isn't supported more generically yet. */
- dst.point_size = src.point_size;
- dst.curve_size = src.curve_size;
+ dst.point_num = src.point_num;
+ dst.curve_num = src.curve_num;
const eCDAllocType alloc_type = (flag & LIB_ID_COPY_CD_REFERENCE) ? CD_REFERENCE : CD_DUPLICATE;
- CustomData_copy(&src.point_data, &dst.point_data, CD_MASK_ALL, alloc_type, dst.point_size);
- CustomData_copy(&src.curve_data, &dst.curve_data, CD_MASK_ALL, alloc_type, dst.curve_size);
+ CustomData_copy(&src.point_data, &dst.point_data, CD_MASK_ALL, alloc_type, dst.point_num);
+ CustomData_copy(&src.curve_data, &dst.curve_data, CD_MASK_ALL, alloc_type, dst.curve_num);
dst.curve_offsets = static_cast<int *>(MEM_dupallocN(src.curve_offsets));
+ if (curves_src->surface_uv_map != nullptr) {
+ curves_dst->surface_uv_map = BLI_strdup(curves_src->surface_uv_map);
+ }
+
dst.runtime = MEM_new<bke::CurvesGeometryRuntime>(__func__);
dst.runtime->type_counts = src.runtime->type_counts;
@@ -106,6 +112,7 @@ static void curves_free_data(ID *id)
BKE_curves_batch_cache_free(curves);
MEM_SAFE_FREE(curves->mat);
+ MEM_SAFE_FREE(curves->surface_uv_map);
}
static void curves_foreach_id(ID *id, LibraryForeachIDData *data)
@@ -121,12 +128,10 @@ static void curves_blend_write(BlendWriter *writer, ID *id, const void *id_addre
{
Curves *curves = (Curves *)id;
- CustomDataLayer *players = nullptr, players_buff[CD_TEMP_CHUNK_SIZE];
- CustomDataLayer *clayers = nullptr, clayers_buff[CD_TEMP_CHUNK_SIZE];
- CustomData_blend_write_prepare(
- &curves->geometry.point_data, &players, players_buff, ARRAY_SIZE(players_buff));
- CustomData_blend_write_prepare(
- &curves->geometry.curve_data, &clayers, clayers_buff, ARRAY_SIZE(clayers_buff));
+ Vector<CustomDataLayer, 16> point_layers;
+ Vector<CustomDataLayer, 16> curve_layers;
+ CustomData_blend_write_prepare(curves->geometry.point_data, point_layers);
+ CustomData_blend_write_prepare(curves->geometry.curve_data, curve_layers);
/* Write LibData */
BLO_write_id_struct(writer, Curves, id_address, &curves->id);
@@ -135,31 +140,25 @@ static void curves_blend_write(BlendWriter *writer, ID *id, const void *id_addre
/* Direct data */
CustomData_blend_write(writer,
&curves->geometry.point_data,
- players,
- curves->geometry.point_size,
+ point_layers,
+ curves->geometry.point_num,
CD_MASK_ALL,
&curves->id);
CustomData_blend_write(writer,
&curves->geometry.curve_data,
- clayers,
- curves->geometry.curve_size,
+ curve_layers,
+ curves->geometry.curve_num,
CD_MASK_ALL,
&curves->id);
- BLO_write_int32_array(writer, curves->geometry.curve_size + 1, curves->geometry.curve_offsets);
+ BLO_write_int32_array(writer, curves->geometry.curve_num + 1, curves->geometry.curve_offsets);
+
+ BLO_write_string(writer, curves->surface_uv_map);
BLO_write_pointer_array(writer, curves->totcol, curves->mat);
if (curves->adt) {
BKE_animdata_blend_write(writer, curves->adt);
}
-
- /* Remove temporary data. */
- if (players && players != players_buff) {
- MEM_freeN(players);
- }
- if (clayers && clayers != clayers_buff) {
- MEM_freeN(clayers);
- }
}
static void curves_blend_read_data(BlendDataReader *reader, ID *id)
@@ -169,11 +168,13 @@ static void curves_blend_read_data(BlendDataReader *reader, ID *id)
BKE_animdata_blend_read_data(reader, curves->adt);
/* Geometry */
- CustomData_blend_read(reader, &curves->geometry.point_data, curves->geometry.point_size);
- CustomData_blend_read(reader, &curves->geometry.curve_data, curves->geometry.curve_size);
+ CustomData_blend_read(reader, &curves->geometry.point_data, curves->geometry.point_num);
+ CustomData_blend_read(reader, &curves->geometry.curve_data, curves->geometry.curve_num);
update_custom_data_pointers(*curves);
- BLO_read_int32_array(reader, curves->geometry.curve_size + 1, &curves->geometry.curve_offsets);
+ BLO_read_int32_array(reader, curves->geometry.curve_num + 1, &curves->geometry.curve_offsets);
+
+ BLO_read_data_address(reader, &curves->surface_uv_map);
curves->geometry.runtime = MEM_new<blender::bke::CurvesGeometryRuntime>(__func__);
@@ -207,8 +208,8 @@ IDTypeInfo IDType_ID_CV = {
/*id_filter */ FILTER_ID_CV,
/*main_listbase_index */ INDEX_ID_CV,
/*struct_size */ sizeof(Curves),
- /*name */ "Hair Curves",
- /*name_plural */ "Hair Curves",
+ /*name */ "Curves",
+ /*name_plural */ "curves",
/*translation_context */ BLT_I18NCONTEXT_ID_CURVES,
/*flags */ IDTYPE_FLAGS_APPEND_IS_REUSABLE,
/*asset_type_info */ nullptr,
@@ -247,7 +248,7 @@ void *BKE_curves_add(Main *bmain, const char *name)
BoundBox *BKE_curves_boundbox_get(Object *ob)
{
BLI_assert(ob->type == OB_CURVES);
- Curves *curves = static_cast<Curves *>(ob->data);
+ const Curves *curves_id = static_cast<const Curves *>(ob->data);
if (ob->runtime.bb != nullptr && (ob->runtime.bb->flag & BOUNDBOX_DIRTY) == 0) {
return ob->runtime.bb;
@@ -256,11 +257,12 @@ BoundBox *BKE_curves_boundbox_get(Object *ob)
if (ob->runtime.bb == nullptr) {
ob->runtime.bb = MEM_cnew<BoundBox>(__func__);
- blender::bke::CurvesGeometry &geometry = blender::bke::CurvesGeometry::wrap(curves->geometry);
+ const blender::bke::CurvesGeometry &curves = blender::bke::CurvesGeometry::wrap(
+ curves_id->geometry);
float3 min(FLT_MAX);
float3 max(-FLT_MAX);
- if (!geometry.bounds_min_max(min, max)) {
+ if (!curves.bounds_min_max(min, max)) {
min = float3(-1);
max = float3(1);
}
@@ -271,9 +273,9 @@ BoundBox *BKE_curves_boundbox_get(Object *ob)
return ob->runtime.bb;
}
-bool BKE_curves_customdata_required(Curves *UNUSED(curves), CustomDataLayer *layer)
+bool BKE_curves_customdata_required(const Curves *UNUSED(curves), const char *name)
{
- return layer->type == CD_PROP_FLOAT3 && STREQ(layer->name, ATTR_POSITION);
+ return STREQ(name, ATTR_POSITION);
}
Curves *BKE_curves_copy_for_eval(Curves *curves_src, bool reference)
@@ -364,19 +366,26 @@ namespace blender::bke {
Curves *curves_new_nomain(const int points_num, const int curves_num)
{
- Curves *curves = static_cast<Curves *>(BKE_id_new_nomain(ID_CV, nullptr));
- CurvesGeometry &geometry = CurvesGeometry::wrap(curves->geometry);
- geometry.resize(points_num, curves_num);
- return curves;
+ Curves *curves_id = static_cast<Curves *>(BKE_id_new_nomain(ID_CV, nullptr));
+ CurvesGeometry &curves = CurvesGeometry::wrap(curves_id->geometry);
+ curves.resize(points_num, curves_num);
+ return curves_id;
}
Curves *curves_new_nomain_single(const int points_num, const CurveType type)
{
- Curves *curves = curves_new_nomain(points_num, 1);
- CurvesGeometry &geometry = CurvesGeometry::wrap(curves->geometry);
- geometry.offsets_for_write().last() = points_num;
- geometry.fill_curve_types(type);
- return curves;
+ Curves *curves_id = curves_new_nomain(points_num, 1);
+ CurvesGeometry &curves = CurvesGeometry::wrap(curves_id->geometry);
+ curves.offsets_for_write().last() = points_num;
+ curves.fill_curve_types(type);
+ return curves_id;
+}
+
+Curves *curves_new_nomain(CurvesGeometry curves)
+{
+ Curves *curves_id = static_cast<Curves *>(BKE_id_new_nomain(ID_CV, nullptr));
+ bke::CurvesGeometry::wrap(curves_id->geometry) = std::move(curves);
+ return curves_id;
}
} // namespace blender::bke
diff --git a/source/blender/blenkernel/intern/curves_geometry.cc b/source/blender/blenkernel/intern/curves_geometry.cc
index e7337d5c012..b58781ce806 100644
--- a/source/blender/blenkernel/intern/curves_geometry.cc
+++ b/source/blender/blenkernel/intern/curves_geometry.cc
@@ -18,6 +18,7 @@
#include "BKE_attribute_math.hh"
#include "BKE_curves.hh"
+#include "BKE_curves_utils.hh"
namespace blender::bke {
@@ -35,8 +36,9 @@ static const std::string ATTR_HANDLE_POSITION_RIGHT = "handle_right";
static const std::string ATTR_NURBS_ORDER = "nurbs_order";
static const std::string ATTR_NURBS_WEIGHT = "nurbs_weight";
static const std::string ATTR_NURBS_KNOTS_MODE = "knots_mode";
-static const std::string ATTR_SURFACE_TRIANGLE_INDEX = "surface_triangle_index";
-static const std::string ATTR_SURFACE_TRIANGLE_COORDINATE = "surface_triangle_coordinate";
+static const std::string ATTR_SELECTION_POINT_FLOAT = ".selection_point_float";
+static const std::string ATTR_SELECTION_CURVE_FLOAT = ".selection_curve_float";
+static const std::string ATTR_SURFACE_UV_COORDINATE = "surface_uv_coordinate";
/* -------------------------------------------------------------------- */
/** \name Constructors/Destructor
@@ -46,10 +48,10 @@ CurvesGeometry::CurvesGeometry() : CurvesGeometry(0, 0)
{
}
-CurvesGeometry::CurvesGeometry(const int point_size, const int curve_size)
+CurvesGeometry::CurvesGeometry(const int point_num, const int curve_num)
{
- this->point_size = point_size;
- this->curve_size = curve_size;
+ this->point_num = point_num;
+ this->curve_num = curve_num;
CustomData_reset(&this->point_data);
CustomData_reset(&this->curve_data);
@@ -57,14 +59,16 @@ CurvesGeometry::CurvesGeometry(const int point_size, const int curve_size)
CD_PROP_FLOAT3,
CD_DEFAULT,
nullptr,
- this->point_size,
+ this->point_num,
ATTR_POSITION.c_str());
- this->curve_offsets = (int *)MEM_calloc_arrayN(this->curve_size + 1, sizeof(int), __func__);
+ this->curve_offsets = (int *)MEM_calloc_arrayN(this->curve_num + 1, sizeof(int), __func__);
this->update_customdata_pointers();
this->runtime = MEM_new<CurvesGeometryRuntime>(__func__);
+ /* Fill the type counts with the default so they're in a valid state. */
+ this->runtime->type_counts[CURVE_TYPE_CATMULL_ROM] = curve_num;
}
/**
@@ -72,15 +76,15 @@ CurvesGeometry::CurvesGeometry(const int point_size, const int curve_size)
*/
static void copy_curves_geometry(CurvesGeometry &dst, const CurvesGeometry &src)
{
- CustomData_free(&dst.point_data, dst.point_size);
- CustomData_free(&dst.curve_data, dst.curve_size);
- dst.point_size = src.point_size;
- dst.curve_size = src.curve_size;
- CustomData_copy(&src.point_data, &dst.point_data, CD_MASK_ALL, CD_DUPLICATE, dst.point_size);
- CustomData_copy(&src.curve_data, &dst.curve_data, CD_MASK_ALL, CD_DUPLICATE, dst.curve_size);
+ CustomData_free(&dst.point_data, dst.point_num);
+ CustomData_free(&dst.curve_data, dst.curve_num);
+ dst.point_num = src.point_num;
+ dst.curve_num = src.curve_num;
+ CustomData_copy(&src.point_data, &dst.point_data, CD_MASK_ALL, CD_DUPLICATE, dst.point_num);
+ CustomData_copy(&src.curve_data, &dst.curve_data, CD_MASK_ALL, CD_DUPLICATE, dst.curve_num);
MEM_SAFE_FREE(dst.curve_offsets);
- dst.curve_offsets = (int *)MEM_calloc_arrayN(dst.point_size + 1, sizeof(int), __func__);
+ dst.curve_offsets = (int *)MEM_calloc_arrayN(dst.point_num + 1, sizeof(int), __func__);
dst.offsets_for_write().copy_from(src.offsets());
dst.tag_topology_changed();
@@ -92,7 +96,7 @@ static void copy_curves_geometry(CurvesGeometry &dst, const CurvesGeometry &src)
}
CurvesGeometry::CurvesGeometry(const CurvesGeometry &other)
- : CurvesGeometry(other.point_size, other.curve_size)
+ : CurvesGeometry(other.point_num, other.curve_num)
{
copy_curves_geometry(*this, other);
}
@@ -108,15 +112,15 @@ CurvesGeometry &CurvesGeometry::operator=(const CurvesGeometry &other)
/* The source should be empty, but in a valid state so that using it further will work. */
static void move_curves_geometry(CurvesGeometry &dst, CurvesGeometry &src)
{
- dst.point_size = src.point_size;
+ dst.point_num = src.point_num;
std::swap(dst.point_data, src.point_data);
- CustomData_free(&src.point_data, src.point_size);
- src.point_size = 0;
+ CustomData_free(&src.point_data, src.point_num);
+ src.point_num = 0;
- dst.curve_size = src.curve_size;
+ dst.curve_num = src.curve_num;
std::swap(dst.curve_data, src.curve_data);
- CustomData_free(&src.curve_data, src.curve_size);
- src.curve_size = 0;
+ CustomData_free(&src.curve_data, src.curve_num);
+ src.curve_num = 0;
std::swap(dst.curve_offsets, src.curve_offsets);
MEM_SAFE_FREE(src.curve_offsets);
@@ -128,7 +132,7 @@ static void move_curves_geometry(CurvesGeometry &dst, CurvesGeometry &src)
}
CurvesGeometry::CurvesGeometry(CurvesGeometry &&other)
- : CurvesGeometry(other.point_size, other.curve_size)
+ : CurvesGeometry(other.point_num, other.curve_num)
{
move_curves_geometry(*this, other);
}
@@ -143,8 +147,8 @@ CurvesGeometry &CurvesGeometry::operator=(CurvesGeometry &&other)
CurvesGeometry::~CurvesGeometry()
{
- CustomData_free(&this->point_data, this->point_size);
- CustomData_free(&this->curve_data, this->curve_size);
+ CustomData_free(&this->point_data, this->point_num);
+ CustomData_free(&this->curve_data, this->curve_num);
MEM_SAFE_FREE(this->curve_offsets);
MEM_delete(this->runtime);
this->runtime = nullptr;
@@ -156,74 +160,73 @@ CurvesGeometry::~CurvesGeometry()
/** \name Accessors
* \{ */
-static int domain_size(const CurvesGeometry &curves, const AttributeDomain domain)
+static int domain_num(const CurvesGeometry &curves, const eAttrDomain domain)
{
return domain == ATTR_DOMAIN_POINT ? curves.points_num() : curves.curves_num();
}
-static CustomData &domain_custom_data(CurvesGeometry &curves, const AttributeDomain domain)
+static CustomData &domain_custom_data(CurvesGeometry &curves, const eAttrDomain domain)
{
return domain == ATTR_DOMAIN_POINT ? curves.point_data : curves.curve_data;
}
-static const CustomData &domain_custom_data(const CurvesGeometry &curves,
- const AttributeDomain domain)
+static const CustomData &domain_custom_data(const CurvesGeometry &curves, const eAttrDomain domain)
{
return domain == ATTR_DOMAIN_POINT ? curves.point_data : curves.curve_data;
}
template<typename T>
static VArray<T> get_varray_attribute(const CurvesGeometry &curves,
- const AttributeDomain domain,
+ const eAttrDomain domain,
const StringRefNull name,
const T default_value)
{
- const int size = domain_size(curves, domain);
- const CustomDataType type = cpp_type_to_custom_data_type(CPPType::get<T>());
+ const int num = domain_num(curves, domain);
+ const eCustomDataType type = cpp_type_to_custom_data_type(CPPType::get<T>());
const CustomData &custom_data = domain_custom_data(curves, domain);
const T *data = (const T *)CustomData_get_layer_named(&custom_data, type, name.c_str());
if (data != nullptr) {
- return VArray<T>::ForSpan(Span<T>(data, size));
+ return VArray<T>::ForSpan(Span<T>(data, num));
}
- return VArray<T>::ForSingle(default_value, size);
+ return VArray<T>::ForSingle(default_value, num);
}
template<typename T>
static Span<T> get_span_attribute(const CurvesGeometry &curves,
- const AttributeDomain domain,
+ const eAttrDomain domain,
const StringRefNull name)
{
- const int size = domain_size(curves, domain);
+ const int num = domain_num(curves, domain);
const CustomData &custom_data = domain_custom_data(curves, domain);
- const CustomDataType type = cpp_type_to_custom_data_type(CPPType::get<T>());
+ const eCustomDataType type = cpp_type_to_custom_data_type(CPPType::get<T>());
T *data = (T *)CustomData_get_layer_named(&custom_data, type, name.c_str());
if (data == nullptr) {
return {};
}
- return {data, size};
+ return {data, num};
}
template<typename T>
static MutableSpan<T> get_mutable_attribute(CurvesGeometry &curves,
- const AttributeDomain domain,
+ const eAttrDomain domain,
const StringRefNull name,
const T default_value = T())
{
- const int size = domain_size(curves, domain);
- const CustomDataType type = cpp_type_to_custom_data_type(CPPType::get<T>());
+ const int num = domain_num(curves, domain);
+ const eCustomDataType type = cpp_type_to_custom_data_type(CPPType::get<T>());
CustomData &custom_data = domain_custom_data(curves, domain);
T *data = (T *)CustomData_duplicate_referenced_layer_named(
- &custom_data, type, name.c_str(), size);
+ &custom_data, type, name.c_str(), num);
if (data != nullptr) {
- return {data, size};
+ return {data, num};
}
data = (T *)CustomData_add_layer_named(
- &custom_data, type, CD_CALLOC, nullptr, size, name.c_str());
- MutableSpan<T> span = {data, size};
- if (size > 0 && span.first() != default_value) {
+ &custom_data, type, CD_CALLOC, nullptr, num, name.c_str());
+ MutableSpan<T> span = {data, num};
+ if (num > 0 && span.first() != default_value) {
span.fill(default_value);
}
return span;
@@ -299,22 +302,22 @@ void CurvesGeometry::update_curve_types()
Span<float3> CurvesGeometry::positions() const
{
- return {(const float3 *)this->position, this->point_size};
+ return {(const float3 *)this->position, this->point_num};
}
MutableSpan<float3> CurvesGeometry::positions_for_write()
{
this->position = (float(*)[3])CustomData_duplicate_referenced_layer_named(
- &this->point_data, CD_PROP_FLOAT3, ATTR_POSITION.c_str(), this->point_size);
- return {(float3 *)this->position, this->point_size};
+ &this->point_data, CD_PROP_FLOAT3, ATTR_POSITION.c_str(), this->point_num);
+ return {(float3 *)this->position, this->point_num};
}
Span<int> CurvesGeometry::offsets() const
{
- return {this->curve_offsets, this->curve_size + 1};
+ return {this->curve_offsets, this->curve_num + 1};
}
MutableSpan<int> CurvesGeometry::offsets_for_write()
{
- return {this->curve_offsets, this->curve_size + 1};
+ return {this->curve_offsets, this->curve_num + 1};
}
VArray<bool> CurvesGeometry::cyclic() const
@@ -416,24 +419,34 @@ MutableSpan<int8_t> CurvesGeometry::nurbs_knots_modes_for_write()
return get_mutable_attribute<int8_t>(*this, ATTR_DOMAIN_CURVE, ATTR_NURBS_KNOTS_MODE, 0);
}
-VArray<int> CurvesGeometry::surface_triangle_indices() const
+Span<float2> CurvesGeometry::surface_uv_coords() const
{
- return get_varray_attribute<int>(*this, ATTR_DOMAIN_CURVE, ATTR_SURFACE_TRIANGLE_INDEX, -1);
+ return get_span_attribute<float2>(*this, ATTR_DOMAIN_CURVE, ATTR_SURFACE_UV_COORDINATE);
}
-MutableSpan<int> CurvesGeometry::surface_triangle_indices_for_write()
+MutableSpan<float2> CurvesGeometry::surface_uv_coords_for_write()
{
- return get_mutable_attribute<int>(*this, ATTR_DOMAIN_CURVE, ATTR_SURFACE_TRIANGLE_INDEX, -1);
+ return get_mutable_attribute<float2>(*this, ATTR_DOMAIN_CURVE, ATTR_SURFACE_UV_COORDINATE);
}
-Span<float2> CurvesGeometry::surface_triangle_coords() const
+VArray<float> CurvesGeometry::selection_point_float() const
{
- return get_span_attribute<float2>(*this, ATTR_DOMAIN_CURVE, ATTR_SURFACE_TRIANGLE_COORDINATE);
+ return get_varray_attribute<float>(*this, ATTR_DOMAIN_POINT, ATTR_SELECTION_POINT_FLOAT, 1.0f);
}
-MutableSpan<float2> CurvesGeometry::surface_triangle_coords_for_write()
+MutableSpan<float> CurvesGeometry::selection_point_float_for_write()
{
- return get_mutable_attribute<float2>(*this, ATTR_DOMAIN_CURVE, ATTR_SURFACE_TRIANGLE_COORDINATE);
+ return get_mutable_attribute<float>(*this, ATTR_DOMAIN_POINT, ATTR_SELECTION_POINT_FLOAT, 1.0f);
+}
+
+VArray<float> CurvesGeometry::selection_curve_float() const
+{
+ return get_varray_attribute<float>(*this, ATTR_DOMAIN_CURVE, ATTR_SELECTION_CURVE_FLOAT, 1.0f);
+}
+
+MutableSpan<float> CurvesGeometry::selection_curve_float_for_write()
+{
+ return get_mutable_attribute<float>(*this, ATTR_DOMAIN_CURVE, ATTR_SELECTION_CURVE_FLOAT, 1.0f);
}
/** \} */
@@ -442,12 +455,12 @@ MutableSpan<float2> CurvesGeometry::surface_triangle_coords_for_write()
/** \name Evaluation
* \{ */
-template<typename SizeFn> void build_offsets(MutableSpan<int> offsets, const SizeFn &size_fn)
+template<typename CountFn> void build_offsets(MutableSpan<int> offsets, const CountFn &count_fn)
{
int offset = 0;
for (const int i : offsets.drop_back(1).index_range()) {
offsets[i] = offset;
- offset += size_fn(i);
+ offset += count_fn(i);
}
offsets.last() = offset;
}
@@ -470,7 +483,7 @@ static void calculate_evaluated_offsets(const CurvesGeometry &curves,
const IndexRange points = curves.points_for_curve(curve_index);
switch (types[curve_index]) {
case CURVE_TYPE_CATMULL_ROM:
- return curves::catmull_rom::calculate_evaluated_size(
+ return curves::catmull_rom::calculate_evaluated_num(
points.size(), cyclic[curve_index], resolution[curve_index]);
case CURVE_TYPE_POLY:
return points.size();
@@ -482,11 +495,11 @@ static void calculate_evaluated_offsets(const CurvesGeometry &curves,
bezier_evaluated_offsets.slice(points));
return bezier_evaluated_offsets[points.last()];
case CURVE_TYPE_NURBS:
- return curves::nurbs::calculate_evaluated_size(points.size(),
- nurbs_orders[curve_index],
- cyclic[curve_index],
- resolution[curve_index],
- KnotsMode(nurbs_knots_modes[curve_index]));
+ return curves::nurbs::calculate_evaluated_num(points.size(),
+ nurbs_orders[curve_index],
+ cyclic[curve_index],
+ resolution[curve_index],
+ KnotsMode(nurbs_knots_modes[curve_index]));
}
BLI_assert_unreachable();
return 0;
@@ -538,12 +551,8 @@ IndexMask CurvesGeometry::indices_for_curve_type(const CurveType type,
const IndexMask selection,
Vector<int64_t> &r_indices) const
{
- if (this->curve_type_counts()[type] == this->curves_num()) {
- return selection;
- }
- Span<int8_t> types_span = this->curve_types().get_internal_span();
- return index_mask_ops::find_indices_based_on_predicate(
- selection, 1024, r_indices, [&](const int index) { return types_span[index] == type; });
+ return curves::indices_for_type(
+ this->curve_types(), this->curve_type_counts(), type, selection, r_indices);
}
void CurvesGeometry::ensure_nurbs_basis_cache() const
@@ -581,13 +590,13 @@ void CurvesGeometry::ensure_nurbs_basis_cache() const
const bool is_cyclic = cyclic[curve_index];
const KnotsMode mode = KnotsMode(knots_modes[curve_index]);
- if (!curves::nurbs::check_valid_size_and_order(points.size(), order, is_cyclic, mode)) {
+ if (!curves::nurbs::check_valid_num_and_order(points.size(), order, is_cyclic, mode)) {
basis_caches[curve_index].invalid = true;
continue;
}
- const int knots_size = curves::nurbs::knots_size(points.size(), order, is_cyclic);
- Array<float> knots(knots_size);
+ const int knots_num = curves::nurbs::knots_num(points.size(), order, is_cyclic);
+ Array<float> knots(knots_num);
curves::nurbs::calculate_knots(points.size(), mode, order, is_cyclic, knots);
curves::nurbs::calculate_basis_cache(points.size(),
evaluated_points.size(),
@@ -908,8 +917,8 @@ void CurvesGeometry::ensure_evaluated_lengths() const
threading::isolate_task([&]() {
/* Use an extra length value for the final cyclic segment for a consistent size
* (see comment on #evaluated_length_cache). */
- const int total_size = this->evaluated_points_num() + this->curves_num();
- this->runtime->evaluated_length_cache.resize(total_size);
+ const int total_num = this->evaluated_points_num() + this->curves_num();
+ this->runtime->evaluated_length_cache.resize(total_num);
MutableSpan<float> evaluated_lengths = this->runtime->evaluated_length_cache;
Span<float3> evaluated_positions = this->evaluated_positions();
@@ -938,13 +947,13 @@ void CurvesGeometry::ensure_evaluated_lengths() const
void CurvesGeometry::resize(const int points_num, const int curves_num)
{
- if (points_num != this->point_size) {
+ if (points_num != this->point_num) {
CustomData_realloc(&this->point_data, points_num);
- this->point_size = points_num;
+ this->point_num = points_num;
}
- if (curves_num != this->curve_size) {
+ if (curves_num != this->curve_num) {
CustomData_realloc(&this->curve_data, curves_num);
- this->curve_size = curves_num;
+ this->curve_num = curves_num;
this->curve_offsets = (int *)MEM_reallocN(this->curve_offsets, sizeof(int) * (curves_num + 1));
}
this->tag_topology_changed();
@@ -1078,7 +1087,7 @@ void CurvesGeometry::update_customdata_pointers()
static void *ensure_customdata_layer(CustomData &custom_data,
const StringRefNull name,
- const CustomDataType data_type,
+ const eCustomDataType data_type,
const int tot_elements)
{
for (const int other_layer_i : IndexRange(custom_data.totlayer)) {
@@ -1091,6 +1100,165 @@ static void *ensure_customdata_layer(CustomData &custom_data,
&custom_data, data_type, CD_DEFAULT, nullptr, tot_elements, name.c_str());
}
+static void copy_between_buffers(const CPPType &type,
+ const void *src_buffer,
+ void *dst_buffer,
+ const IndexRange src_range,
+ const IndexRange dst_range)
+{
+ BLI_assert(src_range.size() == dst_range.size());
+ type.copy_construct_n(POINTER_OFFSET(src_buffer, type.size() * src_range.start()),
+ POINTER_OFFSET(dst_buffer, type.size() * dst_range.start()),
+ src_range.size());
+}
+
+template<typename T>
+static void copy_with_map(const Span<T> src, const Span<int> map, MutableSpan<T> dst)
+{
+ threading::parallel_for(map.index_range(), 1024, [&](const IndexRange range) {
+ for (const int i : range) {
+ dst[i] = src[map[i]];
+ }
+ });
+}
+
+static void copy_with_map(const GSpan src, const Span<int> map, GMutableSpan dst)
+{
+ attribute_math::convert_to_static_type(src.type(), [&](auto dummy) {
+ using T = decltype(dummy);
+ copy_with_map(src.typed<T>(), map, dst.typed<T>());
+ });
+}
+
+/**
+ * Builds an array that for every point, contains the corresponding curve index.
+ */
+static Array<int> build_point_to_curve_map(const CurvesGeometry &curves)
+{
+ Array<int> point_to_curve_map(curves.points_num());
+ threading::parallel_for(curves.curves_range(), 1024, [&](const IndexRange curves_range) {
+ for (const int i_curve : curves_range) {
+ point_to_curve_map.as_mutable_span().slice(curves.points_for_curve(i_curve)).fill(i_curve);
+ }
+ });
+ return point_to_curve_map;
+}
+
+static CurvesGeometry copy_with_removed_points(const CurvesGeometry &curves,
+ const IndexMask points_to_delete)
+{
+ /* Use a map from points to curves to facilitate using an #IndexMask input. */
+ const Array<int> point_to_curve_map = build_point_to_curve_map(curves);
+
+ const Vector<IndexRange> copy_point_ranges = points_to_delete.extract_ranges_invert(
+ curves.points_range());
+
+ /* For every range of points to copy, find the offset in the result curves point layers. */
+ int new_point_count = 0;
+ Array<int> copy_point_range_dst_offsets(copy_point_ranges.size());
+ for (const int i : copy_point_ranges.index_range()) {
+ copy_point_range_dst_offsets[i] = new_point_count;
+ new_point_count += copy_point_ranges[i].size();
+ }
+ BLI_assert(new_point_count == (curves.points_num() - points_to_delete.size()));
+
+ /* Find out how many non-deleted points there are in every curve. */
+ Array<int> curve_point_counts(curves.curves_num(), 0);
+ for (const IndexRange range : copy_point_ranges) {
+ for (const int point_i : range) {
+ curve_point_counts[point_to_curve_map[point_i]]++;
+ }
+ }
+
+ /* Build the offsets for the new curve points, skipping curves that had all points deleted.
+ * Also store the original indices of the corresponding input curves, to facilitate parallel
+ * copying of curve domain data. */
+ int new_curve_count = 0;
+ int curve_point_offset = 0;
+ Vector<int> new_curve_offsets;
+ Vector<int> new_curve_orig_indices;
+ new_curve_offsets.append(0);
+ for (const int i : curve_point_counts.index_range()) {
+ if (curve_point_counts[i] > 0) {
+ curve_point_offset += curve_point_counts[i];
+ new_curve_offsets.append(curve_point_offset);
+
+ new_curve_count++;
+ new_curve_orig_indices.append(i);
+ }
+ }
+
+ CurvesGeometry new_curves{new_point_count, new_curve_count};
+
+ threading::parallel_invoke(
+ /* Initialize curve offsets. */
+ [&]() { new_curves.offsets_for_write().copy_from(new_curve_offsets); },
+ /* Copy over point attributes. */
+ [&]() {
+ const CustomData &old_point_data = curves.point_data;
+ CustomData &new_point_data = new_curves.point_data;
+ for (const int layer_i : IndexRange(old_point_data.totlayer)) {
+ const CustomDataLayer &old_layer = old_point_data.layers[layer_i];
+ const eCustomDataType data_type = static_cast<eCustomDataType>(old_layer.type);
+ const CPPType &type = *bke::custom_data_type_to_cpp_type(data_type);
+
+ void *dst_buffer = ensure_customdata_layer(
+ new_point_data, old_layer.name, data_type, new_point_count);
+
+ threading::parallel_for(
+ copy_point_ranges.index_range(), 128, [&](const IndexRange ranges_range) {
+ for (const int range_i : ranges_range) {
+ const IndexRange src_range = copy_point_ranges[range_i];
+ copy_between_buffers(type,
+ old_layer.data,
+ dst_buffer,
+ src_range,
+ {copy_point_range_dst_offsets[range_i], src_range.size()});
+ }
+ });
+ }
+ },
+ /* Copy over curve attributes.
+ * In some cases points are just dissolved, so the the number of
+ * curves will be the same. That could be optimized in the future. */
+ [&]() {
+ const CustomData &old_curve_data = curves.curve_data;
+ CustomData &new_curve_data = new_curves.curve_data;
+ for (const int layer_i : IndexRange(old_curve_data.totlayer)) {
+ const CustomDataLayer &old_layer = old_curve_data.layers[layer_i];
+ const eCustomDataType data_type = static_cast<eCustomDataType>(old_layer.type);
+ const CPPType &type = *bke::custom_data_type_to_cpp_type(data_type);
+
+ void *dst_buffer = ensure_customdata_layer(
+ new_curve_data, old_layer.name, data_type, new_curve_count);
+
+ if (new_curves.curves_num() == curves.curves_num()) {
+ type.copy_construct_n(old_layer.data, dst_buffer, new_curves.curves_num());
+ }
+ else {
+ copy_with_map({type, old_layer.data, curves.curves_num()},
+ new_curve_orig_indices,
+ {type, dst_buffer, new_curves.curves_num()});
+ }
+ }
+ });
+
+ new_curves.update_curve_types();
+
+ return new_curves;
+}
+
+void CurvesGeometry::remove_points(const IndexMask points_to_delete)
+{
+ if (points_to_delete.is_empty()) {
+ return;
+ }
+ if (points_to_delete.size() == this->points_num()) {
+ *this = {};
+ }
+ *this = copy_with_removed_points(*this, points_to_delete);
+}
+
static CurvesGeometry copy_with_removed_curves(const CurvesGeometry &curves,
const IndexMask curves_to_delete)
{
@@ -1147,23 +1315,20 @@ static CurvesGeometry copy_with_removed_curves(const CurvesGeometry &curves,
CustomData &new_point_data = new_curves.point_data;
for (const int layer_i : IndexRange(old_point_data.totlayer)) {
const CustomDataLayer &old_layer = old_point_data.layers[layer_i];
- const CustomDataType data_type = static_cast<CustomDataType>(old_layer.type);
+ const eCustomDataType data_type = static_cast<eCustomDataType>(old_layer.type);
const CPPType &type = *bke::custom_data_type_to_cpp_type(data_type);
- const void *src_buffer = old_layer.data;
void *dst_buffer = ensure_customdata_layer(
new_point_data, old_layer.name, data_type, new_tot_points);
threading::parallel_for(
old_curve_ranges.index_range(), 128, [&](const IndexRange ranges_range) {
for (const int range_i : ranges_range) {
- const IndexRange old_point_range = old_point_ranges[range_i];
- const IndexRange new_point_range = new_point_ranges[range_i];
-
- type.copy_construct_n(
- POINTER_OFFSET(src_buffer, type.size() * old_point_range.start()),
- POINTER_OFFSET(dst_buffer, type.size() * new_point_range.start()),
- old_point_range.size());
+ copy_between_buffers(type,
+ old_layer.data,
+ dst_buffer,
+ old_point_ranges[range_i],
+ new_point_ranges[range_i]);
}
});
}
@@ -1174,23 +1339,20 @@ static CurvesGeometry copy_with_removed_curves(const CurvesGeometry &curves,
CustomData &new_curve_data = new_curves.curve_data;
for (const int layer_i : IndexRange(old_curve_data.totlayer)) {
const CustomDataLayer &old_layer = old_curve_data.layers[layer_i];
- const CustomDataType data_type = static_cast<CustomDataType>(old_layer.type);
+ const eCustomDataType data_type = static_cast<eCustomDataType>(old_layer.type);
const CPPType &type = *bke::custom_data_type_to_cpp_type(data_type);
- const void *src_buffer = old_layer.data;
void *dst_buffer = ensure_customdata_layer(
- new_curve_data, old_layer.name, data_type, new_tot_points);
+ new_curve_data, old_layer.name, data_type, new_tot_curves);
threading::parallel_for(
old_curve_ranges.index_range(), 128, [&](const IndexRange ranges_range) {
for (const int range_i : ranges_range) {
- const IndexRange old_curve_range = old_curve_ranges[range_i];
- const IndexRange new_curve_range = new_curve_ranges[range_i];
-
- type.copy_construct_n(
- POINTER_OFFSET(src_buffer, type.size() * old_curve_range.start()),
- POINTER_OFFSET(dst_buffer, type.size() * new_curve_range.start()),
- old_curve_range.size());
+ copy_between_buffers(type,
+ old_layer.data,
+ dst_buffer,
+ old_curve_ranges[range_i],
+ new_curve_ranges[range_i]);
}
});
}
@@ -1203,6 +1365,13 @@ static CurvesGeometry copy_with_removed_curves(const CurvesGeometry &curves,
void CurvesGeometry::remove_curves(const IndexMask curves_to_delete)
{
+ if (curves_to_delete.is_empty()) {
+ return;
+ }
+ if (curves_to_delete.size() == this->curves_num()) {
+ *this = {};
+ return;
+ }
*this = copy_with_removed_curves(*this, curves_to_delete);
}
@@ -1240,7 +1409,7 @@ static void reverse_swap_curve_point_data(const CurvesGeometry &curves,
static bool layer_matches_name_and_type(const CustomDataLayer &layer,
const StringRef name,
- const CustomDataType type)
+ const eCustomDataType type)
{
if (layer.type != type) {
return false;
@@ -1283,7 +1452,7 @@ void CurvesGeometry::reverse_curves(const IndexMask curves_to_reverse)
continue;
}
- const CustomDataType data_type = static_cast<CustomDataType>(layer.type);
+ const eCustomDataType data_type = static_cast<eCustomDataType>(layer.type);
attribute_math::convert_to_static_type(data_type, [&](auto dummy) {
using T = decltype(dummy);
reverse_curve_point_data<T>(
@@ -1306,6 +1475,27 @@ void CurvesGeometry::reverse_curves(const IndexMask curves_to_reverse)
this->tag_topology_changed();
}
+void CurvesGeometry::remove_attributes_based_on_types()
+{
+ const int points_num = this->points_num();
+ const int curves_num = this->curves_num();
+ if (!this->has_curve_with_type(CURVE_TYPE_BEZIER)) {
+ CustomData_free_layer_named(&this->point_data, ATTR_HANDLE_TYPE_LEFT.c_str(), points_num);
+ CustomData_free_layer_named(&this->point_data, ATTR_HANDLE_TYPE_RIGHT.c_str(), points_num);
+ CustomData_free_layer_named(&this->point_data, ATTR_HANDLE_POSITION_LEFT.c_str(), points_num);
+ CustomData_free_layer_named(&this->point_data, ATTR_HANDLE_POSITION_RIGHT.c_str(), points_num);
+ }
+ if (!this->has_curve_with_type(CURVE_TYPE_NURBS)) {
+ CustomData_free_layer_named(&this->point_data, ATTR_NURBS_WEIGHT.c_str(), points_num);
+ CustomData_free_layer_named(&this->curve_data, ATTR_NURBS_ORDER.c_str(), curves_num);
+ CustomData_free_layer_named(&this->curve_data, ATTR_NURBS_KNOTS_MODE.c_str(), curves_num);
+ }
+ if (!this->has_curve_with_type({CURVE_TYPE_BEZIER, CURVE_TYPE_CATMULL_ROM, CURVE_TYPE_NURBS})) {
+ CustomData_free_layer_named(&this->curve_data, ATTR_RESOLUTION.c_str(), curves_num);
+ }
+ this->update_customdata_pointers();
+}
+
/** \} */
/* -------------------------------------------------------------------- */
@@ -1402,8 +1592,8 @@ static GVArray adapt_curve_domain_curve_to_point(const CurvesGeometry &curves,
}
GVArray CurvesGeometry::adapt_domain(const GVArray &varray,
- const AttributeDomain from,
- const AttributeDomain to) const
+ const eAttrDomain from,
+ const eAttrDomain to) const
{
if (!varray) {
return {};
diff --git a/source/blender/blenkernel/intern/curves_utils.cc b/source/blender/blenkernel/intern/curves_utils.cc
new file mode 100644
index 00000000000..802469399ab
--- /dev/null
+++ b/source/blender/blenkernel/intern/curves_utils.cc
@@ -0,0 +1,122 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+
+/** \file
+ * \ingroup bke
+ */
+
+#include "BLI_index_mask_ops.hh"
+
+#include "BKE_curves_utils.hh"
+
+namespace blender::bke::curves {
+
+void fill_curve_counts(const bke::CurvesGeometry &curves,
+ const Span<IndexRange> curve_ranges,
+ MutableSpan<int> counts)
+{
+ threading::parallel_for(curve_ranges.index_range(), 512, [&](IndexRange ranges_range) {
+ for (const IndexRange curves_range : curve_ranges.slice(ranges_range)) {
+ threading::parallel_for(curves_range, 4096, [&](IndexRange range) {
+ for (const int i : range) {
+ counts[i] = curves.points_for_curve(i).size();
+ }
+ });
+ }
+ });
+}
+
+void accumulate_counts_to_offsets(MutableSpan<int> counts_to_offsets, const int start_offset)
+{
+ int offset = start_offset;
+ for (const int i : counts_to_offsets.index_range().drop_back(1)) {
+ const int count = counts_to_offsets[i];
+ BLI_assert(count > 0);
+ counts_to_offsets[i] = offset;
+ offset += count;
+ }
+ counts_to_offsets.last() = offset;
+}
+
+void copy_point_data(const CurvesGeometry &src_curves,
+ const CurvesGeometry &dst_curves,
+ const Span<IndexRange> curve_ranges,
+ const GSpan src,
+ GMutableSpan dst)
+{
+ threading::parallel_for(curve_ranges.index_range(), 512, [&](IndexRange range) {
+ for (const IndexRange range : curve_ranges.slice(range)) {
+ const IndexRange src_points = src_curves.points_for_curves(range);
+ const IndexRange dst_points = dst_curves.points_for_curves(range);
+ /* The arrays might be large, so a threaded copy might make sense here too. */
+ dst.slice(dst_points).copy_from(src.slice(src_points));
+ }
+ });
+}
+
+void copy_point_data(const CurvesGeometry &src_curves,
+ const CurvesGeometry &dst_curves,
+ const IndexMask src_curve_selection,
+ const GSpan src,
+ GMutableSpan dst)
+{
+ threading::parallel_for(src_curve_selection.index_range(), 512, [&](IndexRange range) {
+ for (const int i : src_curve_selection.slice(range)) {
+ const IndexRange src_points = src_curves.points_for_curve(i);
+ const IndexRange dst_points = dst_curves.points_for_curve(i);
+ /* The arrays might be large, so a threaded copy might make sense here too. */
+ dst.slice(dst_points).copy_from(src.slice(src_points));
+ }
+ });
+}
+
+void fill_points(const CurvesGeometry &curves,
+ const IndexMask curve_selection,
+ const GPointer value,
+ GMutableSpan dst)
+{
+ BLI_assert(*value.type() == dst.type());
+ const CPPType &type = dst.type();
+ threading::parallel_for(curve_selection.index_range(), 512, [&](IndexRange range) {
+ for (const int i : curve_selection.slice(range)) {
+ const IndexRange points = curves.points_for_curve(i);
+ type.fill_assign_n(value.get(), dst.slice(curves.points_for_curve(i)).data(), points.size());
+ }
+ });
+}
+
+IndexMask indices_for_type(const VArray<int8_t> &types,
+ const std::array<int, CURVE_TYPES_NUM> &type_counts,
+ const CurveType type,
+ const IndexMask selection,
+ Vector<int64_t> &r_indices)
+{
+ if (type_counts[type] == types.size()) {
+ return selection;
+ }
+ if (types.is_single()) {
+ return types.get_internal_single() == type ? IndexMask(types.size()) : IndexMask(0);
+ }
+ Span<int8_t> types_span = types.get_internal_span();
+ return index_mask_ops::find_indices_based_on_predicate(
+ selection, 4096, r_indices, [&](const int index) { return types_span[index] == type; });
+}
+
+void foreach_curve_by_type(const VArray<int8_t> &types,
+ const std::array<int, CURVE_TYPES_NUM> &counts,
+ const IndexMask selection,
+ FunctionRef<void(IndexMask)> catmull_rom_fn,
+ FunctionRef<void(IndexMask)> poly_fn,
+ FunctionRef<void(IndexMask)> bezier_fn,
+ FunctionRef<void(IndexMask)> nurbs_fn)
+{
+ Vector<int64_t> catmull_rom;
+ Vector<int64_t> poly;
+ Vector<int64_t> bezier;
+ Vector<int64_t> nurbs;
+ catmull_rom_fn(indices_for_type(types, counts, CURVE_TYPE_CATMULL_ROM, selection, catmull_rom));
+ poly_fn(indices_for_type(types, counts, CURVE_TYPE_POLY, selection, poly));
+ bezier_fn(indices_for_type(types, counts, CURVE_TYPE_BEZIER, selection, bezier));
+ nurbs_fn(indices_for_type(types, counts, CURVE_TYPE_NURBS, selection, nurbs));
+}
+
+} // namespace blender::bke::curves
diff --git a/source/blender/blenkernel/intern/customdata.cc b/source/blender/blenkernel/intern/customdata.cc
index 62351a31042..bb5b2ee0836 100644
--- a/source/blender/blenkernel/intern/customdata.cc
+++ b/source/blender/blenkernel/intern/customdata.cc
@@ -20,12 +20,15 @@
#include "BLI_bitmap.h"
#include "BLI_color.hh"
#include "BLI_endian_switch.h"
+#include "BLI_index_range.hh"
#include "BLI_math.h"
#include "BLI_math_color_blend.h"
#include "BLI_math_vector.hh"
#include "BLI_mempool.h"
#include "BLI_path_util.h"
+#include "BLI_span.hh"
#include "BLI_string.h"
+#include "BLI_string_ref.hh"
#include "BLI_string_utils.h"
#include "BLI_utildefines.h"
@@ -54,6 +57,11 @@
/* only for customdata_data_transfer_interp_normal_normals */
#include "data_transfer_intern.h"
+using blender::IndexRange;
+using blender::Span;
+using blender::StringRef;
+using blender::Vector;
+
/* number of layers to add when growing a CustomData object */
#define CUSTOMDATA_GROW 5
@@ -256,8 +264,8 @@ static void layerInterp_mdeformvert(const void **sources,
};
MDeformVert *dvert = static_cast<MDeformVert *>(dest);
- struct MDeformWeight_Link *dest_dwlink = nullptr;
- struct MDeformWeight_Link *node;
+ MDeformWeight_Link *dest_dwlink = nullptr;
+ MDeformWeight_Link *node;
/* build a list of unique def_nrs for dest */
int totweight = 0;
@@ -284,7 +292,7 @@ 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 = static_cast<MDeformWeight_Link *>(
+ 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;
@@ -517,6 +525,22 @@ static void layerCopy_propInt(const void *source, void *dest, int count)
memcpy(dest, source, sizeof(MIntProperty) * count);
}
+static void layerInterp_propInt(const void **sources,
+ const float *weights,
+ const float *UNUSED(sub_weights),
+ int count,
+ void *dest)
+{
+ float result = 0.0f;
+ for (const int i : IndexRange(count)) {
+ const float weight = weights[i];
+ const float src = *static_cast<const int *>(sources[i]);
+ result += src * weight;
+ }
+ const int rounded_result = static_cast<int>(round(result));
+ *static_cast<int *>(dest) = rounded_result;
+}
+
/** \} */
/* -------------------------------------------------------------------- */
@@ -1679,7 +1703,7 @@ static const LayerTypeInfo LAYERTYPEINFO[CD_NUMTYPES] = {
N_("Int"),
layerCopy_propInt,
nullptr,
- nullptr,
+ layerInterp_propInt,
nullptr},
/* 12: CD_PROP_STRING */
{sizeof(MStringProperty),
@@ -2216,9 +2240,9 @@ static bool customdata_typemap_is_valid(const CustomData *data)
}
#endif
-bool CustomData_merge(const struct CustomData *source,
- struct CustomData *dest,
- CustomDataMask mask,
+bool CustomData_merge(const CustomData *source,
+ CustomData *dest,
+ eCustomDataMask mask,
eCDAllocType alloctype,
int totelem)
{
@@ -2318,9 +2342,9 @@ void CustomData_realloc(CustomData *data, int totelem)
}
}
-void CustomData_copy(const struct CustomData *source,
- struct CustomData *dest,
- CustomDataMask mask,
+void CustomData_copy(const CustomData *source,
+ CustomData *dest,
+ eCustomDataMask mask,
eCDAllocType alloctype,
int totelem)
{
@@ -2382,7 +2406,7 @@ void CustomData_free(CustomData *data, int totelem)
CustomData_reset(data);
}
-void CustomData_free_typemask(struct CustomData *data, int totelem, CustomDataMask mask)
+void CustomData_free_typemask(CustomData *data, int totelem, eCustomDataMask mask)
{
for (int i = 0; i < data->totlayer; i++) {
CustomDataLayer *layer = &data->layers[i];
@@ -2437,7 +2461,7 @@ int CustomData_get_layer_index(const CustomData *data, int type)
return data->typemap[type];
}
-int CustomData_get_layer_index_n(const struct CustomData *data, int type, int n)
+int CustomData_get_layer_index_n(const CustomData *data, int type, int n)
{
BLI_assert(n >= 0);
int i = CustomData_get_layer_index(data, type);
@@ -2494,7 +2518,7 @@ int CustomData_get_stencil_layer_index(const CustomData *data, int type)
/* -------------------------------------------------------------------- */
/* index values per layer type */
-int CustomData_get_named_layer(const struct CustomData *data, int type, const char *name)
+int CustomData_get_named_layer(const CustomData *data, int type, const char *name)
{
const int named_index = CustomData_get_named_layer_index(data, type, name);
const int layer_index = data->typemap[type];
@@ -2530,7 +2554,7 @@ int CustomData_get_stencil_layer(const CustomData *data, int type)
return (layer_index != -1) ? data->layers[layer_index].active_mask : -1;
}
-const char *CustomData_get_active_layer_name(const struct CustomData *data, const int type)
+const char *CustomData_get_active_layer_name(const CustomData *data, const int type)
{
/* Get the layer index of the active layer of this type. */
const int layer_index = CustomData_get_active_layer_index(data, type);
@@ -2575,41 +2599,53 @@ void CustomData_set_layer_stencil(CustomData *data, int type, int n)
void CustomData_set_layer_active_index(CustomData *data, int type, int n)
{
+ const int layer_index = data->typemap[type];
+ BLI_assert(customdata_typemap_is_valid(data));
+
for (int i = 0; i < data->totlayer; i++) {
if (data->layers[i].type == type) {
- data->layers[i].active = n - i;
+ data->layers[i].active = n - layer_index;
}
}
}
void CustomData_set_layer_render_index(CustomData *data, int type, int n)
{
+ const int layer_index = data->typemap[type];
+ BLI_assert(customdata_typemap_is_valid(data));
+
for (int i = 0; i < data->totlayer; i++) {
if (data->layers[i].type == type) {
- data->layers[i].active_rnd = n - i;
+ data->layers[i].active_rnd = n - layer_index;
}
}
}
void CustomData_set_layer_clone_index(CustomData *data, int type, int n)
{
+ const int layer_index = data->typemap[type];
+ BLI_assert(customdata_typemap_is_valid(data));
+
for (int i = 0; i < data->totlayer; i++) {
if (data->layers[i].type == type) {
- data->layers[i].active_clone = n - i;
+ data->layers[i].active_clone = n - layer_index;
}
}
}
void CustomData_set_layer_stencil_index(CustomData *data, int type, int n)
{
+ const int layer_index = data->typemap[type];
+ BLI_assert(customdata_typemap_is_valid(data));
+
for (int i = 0; i < data->totlayer; i++) {
if (data->layers[i].type == type) {
- data->layers[i].active_mask = n - i;
+ data->layers[i].active_mask = n - layer_index;
}
}
}
-void CustomData_set_layer_flag(struct CustomData *data, int type, int flag)
+void CustomData_set_layer_flag(CustomData *data, int type, int flag)
{
for (int i = 0; i < data->totlayer; i++) {
if (data->layers[i].type == type) {
@@ -2618,7 +2654,7 @@ void CustomData_set_layer_flag(struct CustomData *data, int type, int flag)
}
}
-void CustomData_clear_layer_flag(struct CustomData *data, int type, int flag)
+void CustomData_clear_layer_flag(CustomData *data, int type, int flag)
{
const int nflag = ~flag;
@@ -2793,7 +2829,7 @@ void *CustomData_add_layer_named(CustomData *data,
return nullptr;
}
-void *CustomData_add_layer_anonymous(struct CustomData *data,
+void *CustomData_add_layer_anonymous(CustomData *data,
int type,
eCDAllocType alloctype,
void *layerdata,
@@ -2866,6 +2902,18 @@ bool CustomData_free_layer(CustomData *data, int type, int totelem, int index)
return true;
}
+bool CustomData_free_layer_named(CustomData *data, const char *name, const int totelem)
+{
+ for (const int i : IndexRange(data->totlayer)) {
+ const CustomDataLayer &layer = data->layers[i];
+ if (StringRef(layer.name) == name) {
+ CustomData_free_layer(data, layer.type, totelem, i);
+ return true;
+ }
+ }
+ return false;
+}
+
bool CustomData_free_layer_active(CustomData *data, int type, int totelem)
{
const int index = CustomData_get_active_layer_index(data, type);
@@ -2901,7 +2949,7 @@ int CustomData_number_of_layers(const CustomData *data, int type)
return number;
}
-int CustomData_number_of_layers_typemask(const CustomData *data, CustomDataMask mask)
+int CustomData_number_of_layers_typemask(const CustomData *data, eCustomDataMask mask)
{
int number = 0;
@@ -2999,7 +3047,7 @@ void CustomData_duplicate_referenced_layers(CustomData *data, int totelem)
}
}
-bool CustomData_is_referenced_layer(struct CustomData *data, int type)
+bool CustomData_is_referenced_layer(CustomData *data, int type)
{
/* get the layer index of the first layer of type */
int layer_index = CustomData_get_active_layer_index(data, type);
@@ -3044,7 +3092,7 @@ void CustomData_free_temporary(CustomData *data, int totelem)
}
}
-void CustomData_set_only_copy(const struct CustomData *data, CustomDataMask mask)
+void CustomData_set_only_copy(const CustomData *data, eCustomDataMask mask)
{
for (int i = 0; i < data->totlayer; i++) {
if (!(mask & CD_TYPE_AS_MASK(data->layers[i].type))) {
@@ -3277,7 +3325,7 @@ void CustomData_interp(const CustomData *source,
}
}
-void CustomData_swap_corners(struct CustomData *data, int index, const int *corner_indices)
+void CustomData_swap_corners(CustomData *data, int index, const int *corner_indices)
{
for (int i = 0; i < data->totlayer; i++) {
const LayerTypeInfo *typeInfo = layerType_getInfo(data->layers[i].type);
@@ -3290,7 +3338,7 @@ void CustomData_swap_corners(struct CustomData *data, int index, const int *corn
}
}
-void CustomData_swap(struct CustomData *data, const int index_a, const int index_b)
+void CustomData_swap(CustomData *data, const int index_a, const int index_b)
{
char buff_static[256];
@@ -3369,7 +3417,7 @@ void *CustomData_get_layer_n(const CustomData *data, int type, int n)
return data->layers[layer_index].data;
}
-void *CustomData_get_layer_named(const struct CustomData *data, int type, const char *name)
+void *CustomData_get_layer_named(const CustomData *data, int type, const char *name)
{
int layer_index = CustomData_get_named_layer_index(data, type, name);
if (layer_index == -1) {
@@ -3436,7 +3484,7 @@ void *CustomData_set_layer(const CustomData *data, int type, void *ptr)
return ptr;
}
-void *CustomData_set_layer_n(const struct CustomData *data, int type, int n, void *ptr)
+void *CustomData_set_layer_n(const CustomData *data, int type, int n, void *ptr)
{
/* get the layer index of the first layer of type */
int layer_index = CustomData_get_layer_index_n(data, type, n);
@@ -3646,7 +3694,7 @@ void CustomData_bmesh_init_pool(CustomData *data, int totelem, const char htype)
chunksize = bm_mesh_chunksize_default.totface;
break;
default:
- BLI_assert(0);
+ BLI_assert_unreachable();
chunksize = 512;
break;
}
@@ -3659,7 +3707,7 @@ void CustomData_bmesh_init_pool(CustomData *data, int totelem, const char htype)
bool CustomData_bmesh_merge(const CustomData *source,
CustomData *dest,
- CustomDataMask mask,
+ eCustomDataMask mask,
eCDAllocType alloctype,
BMesh *bm,
const char htype)
@@ -3808,7 +3856,7 @@ static void CustomData_bmesh_alloc_block(CustomData *data, void **block)
void CustomData_bmesh_free_block_data_exclude_by_type(CustomData *data,
void *block,
- const CustomDataMask mask_exclude)
+ const eCustomDataMask mask_exclude)
{
if (block == nullptr) {
return;
@@ -3855,7 +3903,7 @@ void CustomData_bmesh_copy_data_exclude_by_type(const CustomData *source,
CustomData *dest,
void *src_block,
void **dest_block,
- const CustomDataMask mask_exclude)
+ const eCustomDataMask mask_exclude)
{
/* Note that having a version of this function without a 'mask_exclude'
* would cause too much duplicate code, so add a check instead. */
@@ -3953,7 +4001,7 @@ void *CustomData_bmesh_get_layer_n(const CustomData *data, void *block, int n)
return POINTER_OFFSET(block, data->layers[n].offset);
}
-bool CustomData_layer_has_math(const struct CustomData *data, int layer_n)
+bool CustomData_layer_has_math(const CustomData *data, int layer_n)
{
const LayerTypeInfo *typeInfo = layerType_getInfo(data->layers[layer_n].type);
@@ -3965,7 +4013,7 @@ bool CustomData_layer_has_math(const struct CustomData *data, int layer_n)
return false;
}
-bool CustomData_layer_has_interp(const struct CustomData *data, int layer_n)
+bool CustomData_layer_has_interp(const CustomData *data, int layer_n)
{
const LayerTypeInfo *typeInfo = layerType_getInfo(data->layers[layer_n].type);
@@ -3976,7 +4024,7 @@ bool CustomData_layer_has_interp(const struct CustomData *data, int layer_n)
return false;
}
-bool CustomData_has_math(const struct CustomData *data)
+bool CustomData_has_math(const CustomData *data)
{
/* interpolates a layer at a time */
for (int i = 0; i < data->totlayer; i++) {
@@ -3988,7 +4036,7 @@ bool CustomData_has_math(const struct CustomData *data)
return false;
}
-bool CustomData_bmesh_has_free(const struct CustomData *data)
+bool CustomData_bmesh_has_free(const CustomData *data)
{
for (int i = 0; i < data->totlayer; i++) {
if (!(data->layers[i].flag & CD_FLAG_NOFREE)) {
@@ -4001,7 +4049,7 @@ bool CustomData_bmesh_has_free(const struct CustomData *data)
return false;
}
-bool CustomData_has_interp(const struct CustomData *data)
+bool CustomData_has_interp(const CustomData *data)
{
/* interpolates a layer at a time */
for (int i = 0; i < data->totlayer; i++) {
@@ -4013,7 +4061,7 @@ bool CustomData_has_interp(const struct CustomData *data)
return false;
}
-bool CustomData_has_referenced(const struct CustomData *data)
+bool CustomData_has_referenced(const CustomData *data)
{
for (int i = 0; i < data->totlayer; i++) {
if (data->layers[i].flag & CD_FLAG_NOFREE) {
@@ -4337,45 +4385,19 @@ void CustomData_file_write_info(int type, const char **r_struct_name, int *r_str
*r_struct_num = typeInfo->structnum;
}
-void CustomData_blend_write_prepare(CustomData *data,
- CustomDataLayer **r_write_layers,
- CustomDataLayer *write_layers_buff,
- size_t write_layers_size)
+void CustomData_blend_write_prepare(CustomData &data, Vector<CustomDataLayer, 16> &layers_to_write)
{
- CustomDataLayer *write_layers = write_layers_buff;
- const size_t chunk_size = (write_layers_size > 0) ? write_layers_size : CD_TEMP_CHUNK_SIZE;
-
- const int totlayer = data->totlayer;
- int i, j;
-
- 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 != nullptr) {
- data->totlayer--;
- // CLOG_WARN(&LOG, "skipping layer %p (%s)", layer, layer->name);
+ for (const CustomDataLayer &layer : Span(data.layers, data.totlayer)) {
+ if (layer.flag & CD_FLAG_NOCOPY) {
+ continue;
}
- else {
- if (UNLIKELY((size_t)j >= write_layers_size)) {
- if (write_layers == write_layers_buff) {
- 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 = (CustomDataLayer *)MEM_reallocN(
- write_layers, sizeof(*write_layers) * (write_layers_size + chunk_size));
- }
- write_layers_size += chunk_size;
- }
- write_layers[j++] = *layer;
+ if (layer.anonymous_id != nullptr) {
+ continue;
}
+ layers_to_write.append(layer);
}
- BLI_assert(j == data->totlayer);
- data->maxlayer = data->totlayer; /* We only write that much of data! */
- *r_write_layers = write_layers;
+ data.totlayer = layers_to_write.size();
+ data.maxlayer = data.totlayer;
}
int CustomData_sizeof(int type)
@@ -4498,7 +4520,7 @@ void CustomData_validate_layer_name(const CustomData *data,
}
}
-bool CustomData_verify_versions(struct CustomData *data, int index)
+bool CustomData_verify_versions(CustomData *data, int index)
{
const LayerTypeInfo *typeInfo;
CustomDataLayer *layer = &data->layers[index];
@@ -4593,7 +4615,10 @@ static void customdata_external_filename(char filepath[FILE_MAX],
BLI_path_abs(filepath, ID_BLEND_PATH_FROM_GLOBAL(id));
}
-void CustomData_external_reload(CustomData *data, ID *UNUSED(id), CustomDataMask mask, int totelem)
+void CustomData_external_reload(CustomData *data,
+ ID *UNUSED(id),
+ eCustomDataMask mask,
+ int totelem)
{
for (int i = 0; i < data->totlayer; i++) {
CustomDataLayer *layer = &data->layers[i];
@@ -4611,7 +4636,7 @@ void CustomData_external_reload(CustomData *data, ID *UNUSED(id), CustomDataMask
}
}
-void CustomData_external_read(CustomData *data, ID *id, CustomDataMask mask, int totelem)
+void CustomData_external_read(CustomData *data, ID *id, eCustomDataMask mask, int totelem)
{
CustomDataExternal *external = data->external;
CustomDataLayer *layer;
@@ -4685,7 +4710,7 @@ void CustomData_external_read(CustomData *data, ID *id, CustomDataMask mask, int
}
void CustomData_external_write(
- CustomData *data, ID *id, CustomDataMask mask, int totelem, int free)
+ CustomData *data, ID *id, eCustomDataMask mask, int totelem, int free)
{
CustomDataExternal *external = data->external;
int update = 0;
@@ -5137,12 +5162,12 @@ void CustomData_data_transfer(const MeshPairRemap *me_remap,
/** \name Custom Data IO
* \{ */
-static void write_mdisps(BlendWriter *writer, int count, MDisps *mdlist, int external)
+static void write_mdisps(BlendWriter *writer, int count, const MDisps *mdlist, int external)
{
if (mdlist) {
BLO_write_struct_array(writer, MDisps, count, mdlist);
for (int i = 0; i < count; i++) {
- MDisps *md = &mdlist[i];
+ const MDisps *md = &mdlist[i];
if (md->disps) {
if (!external) {
BLO_write_float3_array(writer, md->totdisp, &md->disps[0][0]);
@@ -5156,12 +5181,14 @@ static void write_mdisps(BlendWriter *writer, int count, MDisps *mdlist, int ext
}
}
-static void write_grid_paint_mask(BlendWriter *writer, int count, GridPaintMask *grid_paint_mask)
+static void write_grid_paint_mask(BlendWriter *writer,
+ int count,
+ const GridPaintMask *grid_paint_mask)
{
if (grid_paint_mask) {
BLO_write_struct_array(writer, GridPaintMask, count, grid_paint_mask);
for (int i = 0; i < count; i++) {
- GridPaintMask *gpm = &grid_paint_mask[i];
+ const GridPaintMask *gpm = &grid_paint_mask[i];
if (gpm->data) {
const int gridsize = BKE_ccg_gridsize(gpm->level);
BLO_write_raw(writer, sizeof(*gpm->data) * gridsize * gridsize, gpm->data);
@@ -5172,9 +5199,9 @@ static void write_grid_paint_mask(BlendWriter *writer, int count, GridPaintMask
void CustomData_blend_write(BlendWriter *writer,
CustomData *data,
- CustomDataLayer *layers,
+ Span<CustomDataLayer> layers_to_write,
int count,
- CustomDataMask cddata_mask,
+ eCustomDataMask cddata_mask,
ID *id)
{
/* write external customdata (not for undo) */
@@ -5182,55 +5209,50 @@ void CustomData_blend_write(BlendWriter *writer,
CustomData_external_write(data, id, cddata_mask, count, 0);
}
- BLO_write_struct_array_at_address(writer, CustomDataLayer, data->totlayer, data->layers, layers);
-
- for (int i = 0; i < data->totlayer; i++) {
- CustomDataLayer *layer = &layers[i];
+ BLO_write_struct_array_at_address(
+ writer, CustomDataLayer, data->totlayer, data->layers, layers_to_write.data());
- if (layer->type == CD_MDEFORMVERT) {
- /* layer types that allocate own memory need special handling */
- BKE_defvert_blend_write(writer, count, static_cast<struct MDeformVert *>(layer->data));
- }
- else if (layer->type == CD_MDISPS) {
- 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 = 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 = 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, static_cast<GridPaintMask *>(layer->data));
- }
- else if (layer->type == CD_FACEMAP) {
- 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 = 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 {
- const char *structname;
- int structnum;
- CustomData_file_write_info(layer->type, &structname, &structnum);
- if (structnum) {
- int datasize = structnum * count;
- BLO_write_struct_array_by_name(writer, structname, datasize, layer->data);
- }
- else if (!BLO_write_is_undo(writer)) { /* Do not warn on undo. */
- printf("%s error: layer '%s':%d - can't be written to file\n",
- __func__,
- structname,
- layer->type);
+ for (const CustomDataLayer &layer : layers_to_write) {
+ switch (layer.type) {
+ case CD_MDEFORMVERT:
+ BKE_defvert_blend_write(writer, count, static_cast<const MDeformVert *>(layer.data));
+ break;
+ case CD_MDISPS:
+ write_mdisps(
+ writer, count, static_cast<const MDisps *>(layer.data), layer.flag & CD_FLAG_EXTERNAL);
+ break;
+ case CD_PAINT_MASK:
+ BLO_write_raw(writer, sizeof(float) * count, static_cast<const float *>(layer.data));
+ break;
+ case CD_SCULPT_FACE_SETS:
+ BLO_write_raw(writer, sizeof(float) * count, static_cast<const float *>(layer.data));
+ break;
+ case CD_GRID_PAINT_MASK:
+ write_grid_paint_mask(writer, count, static_cast<const GridPaintMask *>(layer.data));
+ break;
+ case CD_FACEMAP:
+ BLO_write_raw(writer, sizeof(int) * count, static_cast<const int *>(layer.data));
+ break;
+ case CD_PROP_BOOL:
+ BLO_write_raw(writer, sizeof(bool) * count, static_cast<const bool *>(layer.data));
+ break;
+ case CD_CREASE:
+ BLO_write_raw(writer, sizeof(float) * count, static_cast<const float *>(layer.data));
+ break;
+ default: {
+ const char *structname;
+ int structnum;
+ CustomData_file_write_info(layer.type, &structname, &structnum);
+ if (structnum) {
+ int datasize = structnum * count;
+ BLO_write_struct_array_by_name(writer, structname, datasize, layer.data);
+ }
+ else if (!BLO_write_is_undo(writer)) { /* Do not warn on undo. */
+ printf("%s error: layer '%s':%d - can't be written to file\n",
+ __func__,
+ structname,
+ layer.type);
+ }
}
}
}
@@ -5380,7 +5402,7 @@ namespace blender::bke {
/** \name Custom Data C++ API
* \{ */
-const blender::CPPType *custom_data_type_to_cpp_type(const CustomDataType type)
+const blender::CPPType *custom_data_type_to_cpp_type(const eCustomDataType type)
{
switch (type) {
case CD_PROP_FLOAT:
@@ -5405,7 +5427,7 @@ const blender::CPPType *custom_data_type_to_cpp_type(const CustomDataType type)
return nullptr;
}
-CustomDataType cpp_type_to_custom_data_type(const blender::CPPType &type)
+eCustomDataType cpp_type_to_custom_data_type(const blender::CPPType &type)
{
if (type.is<float>()) {
return CD_PROP_FLOAT;
@@ -5431,7 +5453,7 @@ CustomDataType cpp_type_to_custom_data_type(const blender::CPPType &type)
if (type.is<ColorGeometry4b>()) {
return CD_PROP_BYTE_COLOR;
}
- return static_cast<CustomDataType>(-1);
+ return static_cast<eCustomDataType>(-1);
}
/** \} */
diff --git a/source/blender/blenkernel/intern/customdata_file.c b/source/blender/blenkernel/intern/customdata_file.c
index 9716b4909b2..cbfaf2831d1 100644
--- a/source/blender/blenkernel/intern/customdata_file.c
+++ b/source/blender/blenkernel/intern/customdata_file.c
@@ -268,11 +268,11 @@ static bool cdf_write_header(CDataFile *cdf)
return true;
}
-bool cdf_read_open(CDataFile *cdf, const char *filename)
+bool cdf_read_open(CDataFile *cdf, const char *filepath)
{
FILE *f;
- f = BLI_fopen(filename, "rb");
+ f = BLI_fopen(filepath, "rb");
if (!f) {
return false;
}
@@ -333,14 +333,14 @@ void cdf_read_close(CDataFile *cdf)
}
}
-bool cdf_write_open(CDataFile *cdf, const char *filename)
+bool cdf_write_open(CDataFile *cdf, const char *filepath)
{
CDataFileHeader *header;
CDataFileImageHeader *image;
CDataFileMeshHeader *mesh;
FILE *f;
- f = BLI_fopen(filename, "wb");
+ f = BLI_fopen(filepath, "wb");
if (!f) {
return false;
}
@@ -402,9 +402,9 @@ void cdf_write_close(CDataFile *cdf)
}
}
-void cdf_remove(const char *filename)
+void cdf_remove(const char *filepath)
{
- BLI_delete(filename, false, false);
+ BLI_delete(filepath, false, false);
}
/********************************** Layers ***********************************/
diff --git a/source/blender/blenkernel/intern/data_transfer.c b/source/blender/blenkernel/intern/data_transfer.c
index 6a3f6a47f5e..196a6a00ade 100644
--- a/source/blender/blenkernel/intern/data_transfer.c
+++ b/source/blender/blenkernel/intern/data_transfer.c
@@ -222,7 +222,7 @@ int BKE_object_data_transfer_dttype_to_cdtype(const int dtdata_type)
case DT_TYPE_MPROPCOL_LOOP:
return CD_PROP_COLOR;
default:
- BLI_assert(0);
+ BLI_assert_unreachable();
}
return 0; /* Should never be reached! */
}
@@ -477,7 +477,7 @@ static void data_transfer_layersmapping_add_item_cd(ListBase *r_map,
const int mix_mode,
const float mix_factor,
const float *mix_weights,
- void *data_src,
+ const void *data_src,
void *data_dst,
cd_datatransfer_interp interp,
void *interp_data)
@@ -532,7 +532,8 @@ static bool data_transfer_layersmapping_cdlayers_multisrc_to_dst(ListBase *r_map
cd_datatransfer_interp interp,
void *interp_data)
{
- void *data_src, *data_dst = NULL;
+ const void *data_src;
+ void *data_dst = NULL;
int idx_src = num_layers_src;
int idx_dst, tot_dst = CustomData_number_of_layers(cd_dst, cddata_type);
bool *data_dst_to_delete = NULL;
@@ -695,7 +696,8 @@ static bool data_transfer_layersmapping_cdlayers(ListBase *r_map,
void *interp_data)
{
int idx_src, idx_dst;
- void *data_src, *data_dst = NULL;
+ const void *data_src;
+ void *data_dst = NULL;
if (CustomData_layertype_is_singleton(cddata_type)) {
if (!(data_src = CustomData_get_layer(cd_src, cddata_type))) {
@@ -1369,7 +1371,7 @@ bool BKE_object_data_transfer_ex(struct Depsgraph *depsgraph,
/* Assumed always true if not using an evaluated mesh as destination. */
bool dirty_nors_dst = true;
- MDeformVert *mdef = NULL;
+ const MDeformVert *mdef = NULL;
int vg_idx = -1;
float *weights[DATAMAX] = {NULL};
@@ -1509,7 +1511,7 @@ bool BKE_object_data_transfer_ex(struct Depsgraph *depsgraph,
if (mdef && vg_idx != -1 && !weights[VDATA]) {
weights[VDATA] = MEM_mallocN(sizeof(*(weights[VDATA])) * (size_t)num_verts_dst, __func__);
BKE_defvert_extract_vgroup_to_vertweights(
- mdef, vg_idx, num_verts_dst, weights[VDATA], invert_vgroup);
+ mdef, vg_idx, num_verts_dst, invert_vgroup, weights[VDATA]);
}
if (data_transfer_layersmapping_generate(&lay_map,
@@ -1588,7 +1590,7 @@ bool BKE_object_data_transfer_ex(struct Depsgraph *depsgraph,
if (mdef && vg_idx != -1 && !weights[EDATA]) {
weights[EDATA] = MEM_mallocN(sizeof(*weights[EDATA]) * (size_t)num_edges_dst, __func__);
BKE_defvert_extract_vgroup_to_edgeweights(
- mdef, vg_idx, num_verts_dst, edges_dst, num_edges_dst, weights[EDATA], invert_vgroup);
+ mdef, vg_idx, num_verts_dst, edges_dst, num_edges_dst, invert_vgroup, weights[EDATA]);
}
if (data_transfer_layersmapping_generate(&lay_map,
@@ -1683,7 +1685,7 @@ bool BKE_object_data_transfer_ex(struct Depsgraph *depsgraph,
if (mdef && vg_idx != -1 && !weights[LDATA]) {
weights[LDATA] = MEM_mallocN(sizeof(*weights[LDATA]) * (size_t)num_loops_dst, __func__);
BKE_defvert_extract_vgroup_to_loopweights(
- mdef, vg_idx, num_verts_dst, loops_dst, num_loops_dst, weights[LDATA], invert_vgroup);
+ mdef, vg_idx, num_verts_dst, loops_dst, num_loops_dst, invert_vgroup, weights[LDATA]);
}
if (data_transfer_layersmapping_generate(&lay_map,
@@ -1769,8 +1771,8 @@ bool BKE_object_data_transfer_ex(struct Depsgraph *depsgraph,
num_loops_dst,
polys_dst,
num_polys_dst,
- weights[PDATA],
- invert_vgroup);
+ invert_vgroup,
+ weights[PDATA]);
}
if (data_transfer_layersmapping_generate(&lay_map,
diff --git a/source/blender/blenkernel/intern/deform.c b/source/blender/blenkernel/intern/deform.c
index 1d276e9108c..ebe06fa85eb 100644
--- a/source/blender/blenkernel/intern/deform.c
+++ b/source/blender/blenkernel/intern/deform.c
@@ -147,9 +147,9 @@ void BKE_defvert_copy_index(MDeformVert *dvert_dst,
const MDeformVert *dvert_src,
const int defgroup_src)
{
- MDeformWeight *dw_src, *dw_dst;
+ MDeformWeight *dw_dst;
- dw_src = BKE_defvert_find_index(dvert_src, defgroup_src);
+ const MDeformWeight *dw_src = BKE_defvert_find_index(dvert_src, defgroup_src);
if (dw_src) {
/* Source is valid, ensure destination is created. */
@@ -1008,11 +1008,11 @@ void BKE_defvert_array_free(MDeformVert *dvert, int totvert)
MEM_freeN(dvert);
}
-void BKE_defvert_extract_vgroup_to_vertweights(MDeformVert *dvert,
+void BKE_defvert_extract_vgroup_to_vertweights(const MDeformVert *dvert,
const int defgroup,
const int num_verts,
- float *r_weights,
- const bool invert_vgroup)
+ const bool invert_vgroup,
+ float *r_weights)
{
if (dvert && defgroup != -1) {
int i = num_verts;
@@ -1027,20 +1027,20 @@ void BKE_defvert_extract_vgroup_to_vertweights(MDeformVert *dvert,
}
}
-void BKE_defvert_extract_vgroup_to_edgeweights(MDeformVert *dvert,
+void BKE_defvert_extract_vgroup_to_edgeweights(const MDeformVert *dvert,
const int defgroup,
const int num_verts,
MEdge *edges,
const int num_edges,
- float *r_weights,
- const bool invert_vgroup)
+ const bool invert_vgroup,
+ float *r_weights)
{
if (dvert && defgroup != -1) {
int i = num_edges;
float *tmp_weights = MEM_mallocN(sizeof(*tmp_weights) * (size_t)num_verts, __func__);
BKE_defvert_extract_vgroup_to_vertweights(
- dvert, defgroup, num_verts, tmp_weights, invert_vgroup);
+ dvert, defgroup, num_verts, invert_vgroup, tmp_weights);
while (i--) {
MEdge *me = &edges[i];
@@ -1055,20 +1055,20 @@ void BKE_defvert_extract_vgroup_to_edgeweights(MDeformVert *dvert,
}
}
-void BKE_defvert_extract_vgroup_to_loopweights(MDeformVert *dvert,
+void BKE_defvert_extract_vgroup_to_loopweights(const MDeformVert *dvert,
const int defgroup,
const int num_verts,
MLoop *loops,
const int num_loops,
- float *r_weights,
- const bool invert_vgroup)
+ const bool invert_vgroup,
+ float *r_weights)
{
if (dvert && defgroup != -1) {
int i = num_loops;
float *tmp_weights = MEM_mallocN(sizeof(*tmp_weights) * (size_t)num_verts, __func__);
BKE_defvert_extract_vgroup_to_vertweights(
- dvert, defgroup, num_verts, tmp_weights, invert_vgroup);
+ dvert, defgroup, num_verts, invert_vgroup, tmp_weights);
while (i--) {
MLoop *ml = &loops[i];
@@ -1083,22 +1083,22 @@ void BKE_defvert_extract_vgroup_to_loopweights(MDeformVert *dvert,
}
}
-void BKE_defvert_extract_vgroup_to_polyweights(MDeformVert *dvert,
+void BKE_defvert_extract_vgroup_to_polyweights(const MDeformVert *dvert,
const int defgroup,
const int num_verts,
MLoop *loops,
const int UNUSED(num_loops),
MPoly *polys,
const int num_polys,
- float *r_weights,
- const bool invert_vgroup)
+ const bool invert_vgroup,
+ float *r_weights)
{
if (dvert && defgroup != -1) {
int i = num_polys;
float *tmp_weights = MEM_mallocN(sizeof(*tmp_weights) * (size_t)num_verts, __func__);
BKE_defvert_extract_vgroup_to_vertweights(
- dvert, defgroup, num_verts, tmp_weights, invert_vgroup);
+ dvert, defgroup, num_verts, invert_vgroup, tmp_weights);
while (i--) {
MPoly *mp = &polys[i];
@@ -1193,7 +1193,7 @@ static bool data_transfer_layersmapping_vgroups_multisrc_to_dst(ListBase *r_map,
const bool use_delete,
Object *ob_src,
Object *ob_dst,
- MDeformVert *data_src,
+ const MDeformVert *data_src,
MDeformVert *data_dst,
CustomData *UNUSED(cd_src),
CustomData *cd_dst,
@@ -1348,7 +1348,6 @@ bool data_transfer_layersmapping_vgroups(ListBase *r_map,
const int tolayers)
{
int idx_src, idx_dst;
- MDeformVert *data_src, *data_dst = NULL;
const size_t elem_size = sizeof(*((MDeformVert *)NULL));
@@ -1370,9 +1369,9 @@ bool data_transfer_layersmapping_vgroups(ListBase *r_map,
return true;
}
- data_src = CustomData_get_layer(cd_src, CD_MDEFORMVERT);
+ const MDeformVert *data_src = CustomData_get_layer(cd_src, CD_MDEFORMVERT);
- data_dst = CustomData_get_layer(cd_dst, CD_MDEFORMVERT);
+ MDeformVert *data_dst = CustomData_get_layer(cd_dst, CD_MDEFORMVERT);
if (data_dst && use_dupref_dst && r_map) {
/* If dest is a derivedmesh, we do not want to overwrite cdlayers of org mesh! */
data_dst = CustomData_duplicate_referenced_layer(cd_dst, CD_MDEFORMVERT, num_elem_dst);
@@ -1562,7 +1561,7 @@ void BKE_defbase_blend_write(BlendWriter *writer, const ListBase *defbase)
}
}
-void BKE_defvert_blend_write(BlendWriter *writer, int count, MDeformVert *dvlist)
+void BKE_defvert_blend_write(BlendWriter *writer, int count, const MDeformVert *dvlist)
{
if (dvlist == NULL) {
return;
diff --git a/source/blender/blenkernel/intern/dynamicpaint.c b/source/blender/blenkernel/intern/dynamicpaint.c
index 22341f98375..e5bb70f8cda 100644
--- a/source/blender/blenkernel/intern/dynamicpaint.c
+++ b/source/blender/blenkernel/intern/dynamicpaint.c
@@ -1607,7 +1607,6 @@ static void dynamicPaint_setInitialColor(const Scene *scene, DynamicPaintSurface
const MLoop *mloop = mesh->mloop;
const MLoopTri *mlooptri = BKE_mesh_runtime_looptri_ensure(mesh);
const int tottri = BKE_mesh_runtime_looptri_len(mesh);
- const MLoopUV *mloopuv = NULL;
char uvname[MAX_CUSTOMDATA_LAYER_NAME];
@@ -1617,7 +1616,7 @@ static void dynamicPaint_setInitialColor(const Scene *scene, DynamicPaintSurface
/* get uv map */
CustomData_validate_layer_name(&mesh->ldata, CD_MLOOPUV, surface->init_layername, uvname);
- mloopuv = CustomData_get_layer_named(&mesh->ldata, CD_MLOOPUV, uvname);
+ const MLoopUV *mloopuv = CustomData_get_layer_named(&mesh->ldata, CD_MLOOPUV, uvname);
if (!mloopuv) {
return;
}
@@ -1675,7 +1674,7 @@ static void dynamicPaint_setInitialColor(const Scene *scene, DynamicPaintSurface
}
else if (surface->format == MOD_DPAINT_SURFACE_F_IMAGESEQ) {
const MLoopTri *mlooptri = BKE_mesh_runtime_looptri_ensure(mesh);
- MLoopCol *col = CustomData_get_layer_named(
+ const MLoopCol *col = CustomData_get_layer_named(
&mesh->ldata, CD_PROP_BYTE_COLOR, surface->init_layername);
if (!col) {
return;
@@ -2025,13 +2024,13 @@ static Mesh *dynamicPaint_Modifier_apply(DynamicPaintModifierData *pmd, Object *
settings.use_threading = (sData->total_points > 1000);
BLI_task_parallel_range(
0, sData->total_points, &data, dynamic_paint_apply_surface_wave_cb, &settings);
- BKE_mesh_normals_tag_dirty(mesh);
+ BKE_mesh_normals_tag_dirty(result);
}
/* displace */
if (surface->type == MOD_DPAINT_SURFACE_T_DISPLACE) {
dynamicPaint_applySurfaceDisplace(surface, result);
- BKE_mesh_normals_tag_dirty(mesh);
+ BKE_mesh_normals_tag_dirty(result);
}
}
}
diff --git a/source/blender/blenkernel/intern/editmesh.c b/source/blender/blenkernel/intern/editmesh.c
index d176bf41254..a952da6fa52 100644
--- a/source/blender/blenkernel/intern/editmesh.c
+++ b/source/blender/blenkernel/intern/editmesh.c
@@ -15,6 +15,7 @@
#include "BLI_math.h"
#include "BKE_DerivedMesh.h"
+#include "BKE_customdata.h"
#include "BKE_editmesh.h"
#include "BKE_editmesh_cache.h"
#include "BKE_lib_id.h"
diff --git a/source/blender/blenkernel/intern/effect.c b/source/blender/blenkernel/intern/effect.c
index f2915a97746..7722c2fa004 100644
--- a/source/blender/blenkernel/intern/effect.c
+++ b/source/blender/blenkernel/intern/effect.c
@@ -868,8 +868,6 @@ static void do_texture_effector(EffectorCache *eff,
return;
}
- result[0].nor = result[1].nor = result[2].nor = result[3].nor = NULL;
-
strength = eff->pd->f_strength * efd->falloff;
copy_v3_v3(tex_co, point->loc);
diff --git a/source/blender/blenkernel/intern/fcurve.c b/source/blender/blenkernel/intern/fcurve.c
index 34357c3e454..0203620df84 100644
--- a/source/blender/blenkernel/intern/fcurve.c
+++ b/source/blender/blenkernel/intern/fcurve.c
@@ -229,16 +229,13 @@ FCurve *id_data_find_fcurve(
return NULL;
}
- /* Animation takes priority over drivers. */
- if (adt->action && adt->action->curves.first) {
- fcu = BKE_fcurve_find(&adt->action->curves, path, index);
- }
-
- /* If not animated, check if driven. */
- if (fcu == NULL && adt->drivers.first) {
- fcu = BKE_fcurve_find(&adt->drivers, path, index);
- if (fcu && r_driven) {
- *r_driven = true;
+ /* FIXME: The way drivers are handled here (always NULL-ifying `fcu`) is very weird, this needs
+ * to be re-checked I think?. */
+ bool is_driven = false;
+ fcu = BKE_animadata_fcurve_find_by_rna_path(adt, path, index, NULL, &is_driven);
+ if (is_driven) {
+ if (r_driven != NULL) {
+ *r_driven = is_driven;
}
fcu = NULL;
}
@@ -259,12 +256,11 @@ FCurve *BKE_fcurve_find(ListBase *list, const char rna_path[], const int array_i
/* Check paths of curves, then array indices... */
for (fcu = list->first; fcu; fcu = fcu->next) {
+ /* Check indices first, much cheaper than a string comparison. */
/* Simple string-compare (this assumes that they have the same root...) */
- if (fcu->rna_path && STREQ(fcu->rna_path, rna_path)) {
- /* Now check indices. */
- if (fcu->array_index == array_index) {
- return fcu;
- }
+ if (UNLIKELY(fcu->array_index == array_index && fcu->rna_path &&
+ fcu->rna_path[0] == rna_path[0] && STREQ(fcu->rna_path, rna_path))) {
+ return fcu;
}
}
@@ -339,6 +335,47 @@ int BKE_fcurves_filter(ListBase *dst, ListBase *src, const char *dataPrefix, con
return matches;
}
+FCurve *BKE_animadata_fcurve_find_by_rna_path(
+ AnimData *animdata, const char *rna_path, int rna_index, bAction **r_action, bool *r_driven)
+{
+ if (r_driven != NULL) {
+ *r_driven = false;
+ }
+ if (r_action != NULL) {
+ *r_action = NULL;
+ }
+
+ const bool has_action_fcurves = animdata->action != NULL &&
+ !BLI_listbase_is_empty(&animdata->action->curves);
+ const bool has_drivers = !BLI_listbase_is_empty(&animdata->drivers);
+
+ /* Animation takes priority over drivers. */
+ if (has_action_fcurves) {
+ FCurve *fcu = BKE_fcurve_find(&animdata->action->curves, rna_path, rna_index);
+
+ if (fcu != NULL) {
+ if (r_action != NULL) {
+ *r_action = animdata->action;
+ }
+ return fcu;
+ }
+ }
+
+ /* If not animated, check if driven. */
+ if (has_drivers) {
+ FCurve *fcu = BKE_fcurve_find(&animdata->drivers, rna_path, rna_index);
+
+ if (fcu != NULL) {
+ if (r_driven != NULL) {
+ *r_driven = true;
+ }
+ return fcu;
+ }
+ }
+
+ return NULL;
+}
+
FCurve *BKE_fcurve_find_by_rna(PointerRNA *ptr,
PropertyRNA *prop,
int rnaindex,
@@ -351,8 +388,8 @@ FCurve *BKE_fcurve_find_by_rna(PointerRNA *ptr,
NULL, ptr, prop, rnaindex, r_adt, r_action, r_driven, r_special);
}
-FCurve *BKE_fcurve_find_by_rna_context_ui(bContext *C,
- PointerRNA *ptr,
+FCurve *BKE_fcurve_find_by_rna_context_ui(bContext *UNUSED(C),
+ const PointerRNA *ptr,
PropertyRNA *prop,
int rnaindex,
AnimData **r_animdata,
@@ -360,18 +397,18 @@ FCurve *BKE_fcurve_find_by_rna_context_ui(bContext *C,
bool *r_driven,
bool *r_special)
{
- FCurve *fcu = NULL;
- PointerRNA tptr = *ptr;
-
- *r_driven = false;
- *r_special = false;
-
- if (r_animdata) {
+ if (r_animdata != NULL) {
*r_animdata = NULL;
}
- if (r_action) {
+ if (r_action != NULL) {
*r_action = NULL;
}
+ if (r_driven != NULL) {
+ *r_driven = false;
+ }
+ if (r_special) {
+ *r_special = false;
+ }
/* Special case for NLA Control Curves... */
if (BKE_nlastrip_has_curves_for_property(ptr, prop)) {
@@ -380,87 +417,46 @@ FCurve *BKE_fcurve_find_by_rna_context_ui(bContext *C,
/* Set the special flag, since it cannot be a normal action/driver
* if we've been told to start looking here...
*/
- *r_special = true;
+ if (r_special) {
+ *r_special = true;
+ }
+
+ *r_driven = false;
+ if (r_animdata) {
+ *r_animdata = NULL;
+ }
+ if (r_action) {
+ *r_action = NULL;
+ }
/* The F-Curve either exists or it doesn't here... */
- fcu = BKE_fcurve_find(&strip->fcurves, RNA_property_identifier(prop), rnaindex);
- return fcu;
+ return BKE_fcurve_find(&strip->fcurves, RNA_property_identifier(prop), rnaindex);
}
/* There must be some RNA-pointer + property combo. */
- if (prop && tptr.owner_id && RNA_property_animateable(&tptr, prop)) {
- AnimData *adt = BKE_animdata_from_id(tptr.owner_id);
- int step = (
- /* Always 1 in case we have no context (can't check in 'ancestors' of given RNA ptr). */
- C ? 2 : 1);
- char *path = NULL;
-
- if (!adt && C) {
- path = RNA_path_from_ID_to_property(&tptr, prop);
- adt = BKE_animdata_from_id(tptr.owner_id);
- step--;
- }
-
- /* Standard F-Curve - Animation (Action) or Drivers. */
- while (adt && step--) {
- if ((adt->action == NULL || adt->action->curves.first == NULL) &&
- (adt->drivers.first == NULL)) {
- continue;
- }
-
- /* XXX This function call can become a performance bottleneck. */
- if (step) {
- path = RNA_path_from_ID_to_property(&tptr, prop);
- }
- if (path == NULL) {
- continue;
- }
-
- /* XXX: The logic here is duplicated with a function up above. */
- /* animation takes priority over drivers. */
- if (adt->action && adt->action->curves.first) {
- fcu = BKE_fcurve_find(&adt->action->curves, path, rnaindex);
-
- if (fcu && r_action) {
- *r_action = adt->action;
- }
- }
+ if (!prop || !ptr->owner_id || !RNA_property_animateable(ptr, prop)) {
+ return NULL;
+ }
- /* If not animated, check if driven. */
- if (!fcu && (adt->drivers.first)) {
- fcu = BKE_fcurve_find(&adt->drivers, path, rnaindex);
+ AnimData *adt = BKE_animdata_from_id(ptr->owner_id);
+ if (adt == NULL) {
+ return NULL;
+ }
- if (fcu) {
- if (r_animdata) {
- *r_animdata = adt;
- }
- *r_driven = true;
- }
- }
+ /* XXX This function call can become a performance bottleneck. */
+ char *rna_path = RNA_path_from_ID_to_property(ptr, prop);
+ if (rna_path == NULL) {
+ return NULL;
+ }
- if (fcu && r_action) {
- if (r_animdata) {
- *r_animdata = adt;
- }
- *r_action = adt->action;
- break;
- }
+ /* Standard F-Curve from animdata - Animation (Action) or Drivers. */
+ FCurve *fcu = BKE_animadata_fcurve_find_by_rna_path(adt, rna_path, rnaindex, r_action, r_driven);
- if (step) {
- char *tpath = path ? path : RNA_path_from_ID_to_property(&tptr, prop);
- if (tpath && tpath != path) {
- MEM_freeN(path);
- path = tpath;
- adt = BKE_animdata_from_id(tptr.owner_id);
- }
- else {
- adt = NULL;
- }
- }
- }
- MEM_SAFE_FREE(path);
+ if (fcu != NULL && r_animdata != NULL) {
+ *r_animdata = adt;
}
+ MEM_freeN(rna_path);
return fcu;
}
@@ -1028,9 +1024,8 @@ static void UNUSED_FUNCTION(bezt_add_to_cfra_elem)(ListBase *lb, BezTriple *bezt
* \{ */
/* Some utilities for working with FPoints (i.e. 'sampled' animation curve data, such as
- * data imported from BVH/Mocap files), which are specialized for use with high density datasets,
- * which BezTriples/Keyframe data are ill equipped to do.
- */
+ * data imported from BVH/motion-capture files), which are specialized for use with high density
+ * datasets, which BezTriples/Keyframe data are ill equipped to do. */
float fcurve_samplingcb_evalcurve(FCurve *fcu, void *UNUSED(data), float evaltime)
{
diff --git a/source/blender/blenkernel/intern/fluid.c b/source/blender/blenkernel/intern/fluid.c
index 5de13fbdbed..5cd5a699dec 100644
--- a/source/blender/blenkernel/intern/fluid.c
+++ b/source/blender/blenkernel/intern/fluid.c
@@ -1824,7 +1824,7 @@ static void sample_mesh(FluidFlowSettings *ffs,
const float *vert_vel,
bool has_velocity,
int defgrp_index,
- MDeformVert *dvert,
+ const MDeformVert *dvert,
float x,
float y,
float z)
@@ -1942,7 +1942,6 @@ static void sample_mesh(FluidFlowSettings *ffs,
tex_co[1] = tex_co[1] * 2.0f - 1.0f;
tex_co[2] = ffs->texture_offset;
}
- texres.nor = NULL;
BKE_texture_get_value(NULL, ffs->noise_texture, tex_co, &texres, false);
emission_strength *= texres.tin;
}
@@ -2008,7 +2007,7 @@ typedef struct EmitFromDMData {
const MLoop *mloop;
const MLoopTri *mlooptri;
const MLoopUV *mloopuv;
- MDeformVert *dvert;
+ const MDeformVert *dvert;
int defgrp_index;
BVHTreeFromMesh *tree;
@@ -2074,14 +2073,8 @@ static void emit_from_mesh(
Object *flow_ob, FluidDomainSettings *fds, FluidFlowSettings *ffs, FluidObjectBB *bb, float dt)
{
if (ffs->mesh) {
- Mesh *me = NULL;
- MVert *mvert = NULL;
- const MLoopTri *mlooptri = NULL;
- const MLoop *mloop = NULL;
- const MLoopUV *mloopuv = NULL;
- MDeformVert *dvert = NULL;
BVHTreeFromMesh tree_data = {NULL};
- int numverts, i;
+ int i;
float *vert_vel = NULL;
bool has_velocity = false;
@@ -2092,7 +2085,7 @@ static void emit_from_mesh(
/* Copy mesh for thread safety as we modify it.
* Main issue is its VertArray being modified, then replaced and freed. */
- me = BKE_mesh_copy_for_eval(ffs->mesh, true);
+ Mesh *me = BKE_mesh_copy_for_eval(ffs->mesh, true);
/* Duplicate vertices to modify. */
if (me->mvert) {
@@ -2100,12 +2093,12 @@ static void emit_from_mesh(
CustomData_set_layer(&me->vdata, CD_MVERT, me->mvert);
}
- mvert = me->mvert;
- mloop = me->mloop;
- mlooptri = BKE_mesh_runtime_looptri_ensure(me);
- numverts = me->totvert;
- dvert = CustomData_get_layer(&me->vdata, CD_MDEFORMVERT);
- mloopuv = CustomData_get_layer_named(&me->ldata, CD_MLOOPUV, ffs->uvlayer_name);
+ MVert *mvert = me->mvert;
+ const MLoop *mloop = me->mloop;
+ const MLoopTri *mlooptri = BKE_mesh_runtime_looptri_ensure(me);
+ const int numverts = me->totvert;
+ const MDeformVert *dvert = CustomData_get_layer(&me->vdata, CD_MDEFORMVERT);
+ const MLoopUV *mloopuv = CustomData_get_layer_named(&me->ldata, CD_MLOOPUV, ffs->uvlayer_name);
if (ffs->flags & FLUID_FLOW_INITVELOCITY) {
vert_vel = MEM_callocN(sizeof(float[3]) * numverts, "manta_flow_velocity");
diff --git a/source/blender/blenkernel/intern/geometry_component_curve.cc b/source/blender/blenkernel/intern/geometry_component_curve.cc
index f409389e463..898869c3c44 100644
--- a/source/blender/blenkernel/intern/geometry_component_curve.cc
+++ b/source/blender/blenkernel/intern/geometry_component_curve.cc
@@ -114,7 +114,7 @@ void CurveComponentLegacy::ensure_owns_direct_data()
/** \name Attribute Access Helper Functions
* \{ */
-int CurveComponentLegacy::attribute_domain_size(const AttributeDomain domain) const
+int CurveComponentLegacy::attribute_domain_num(const eAttrDomain domain) const
{
if (curve_ == nullptr) {
return 0;
@@ -251,8 +251,8 @@ template<typename T> class VArray_For_SplineToPoint final : public VArrayImpl<T>
void materialize(const IndexMask mask, MutableSpan<T> r_span) const final
{
- const int total_size = offsets_.last();
- if (mask.is_range() && mask.as_range() == IndexRange(total_size)) {
+ const int total_num = offsets_.last();
+ if (mask.is_range() && mask.as_range() == IndexRange(total_num)) {
for (const int spline_index : original_data_.index_range()) {
const int offset = offsets_[spline_index];
const int next_offset = offsets_[spline_index + 1];
@@ -273,8 +273,8 @@ template<typename T> class VArray_For_SplineToPoint final : public VArrayImpl<T>
void materialize_to_uninitialized(const IndexMask mask, MutableSpan<T> r_span) const final
{
T *dst = r_span.data();
- const int total_size = offsets_.last();
- if (mask.is_range() && mask.as_range() == IndexRange(total_size)) {
+ const int total_num = offsets_.last();
+ if (mask.is_range() && mask.as_range() == IndexRange(total_num)) {
for (const int spline_index : original_data_.index_range()) {
const int offset = offsets_[spline_index];
const int next_offset = offsets_[spline_index + 1];
@@ -308,10 +308,9 @@ static GVArray adapt_curve_domain_spline_to_point(const CurveEval &curve, GVArra
} // namespace blender::bke
-GVArray CurveComponentLegacy::attribute_try_adapt_domain_impl(
- const GVArray &varray,
- const AttributeDomain from_domain,
- const AttributeDomain to_domain) const
+GVArray CurveComponentLegacy::attribute_try_adapt_domain_impl(const GVArray &varray,
+ const eAttrDomain from_domain,
+ const eAttrDomain to_domain) const
{
if (!varray) {
return {};
@@ -366,7 +365,7 @@ class BuiltinSplineAttributeProvider final : public BuiltinAttributeProvider {
public:
BuiltinSplineAttributeProvider(std::string attribute_name,
- const CustomDataType attribute_type,
+ const eCustomDataType attribute_type,
const WritableEnum writable,
const AsReadAttribute as_read_attribute,
const AsWriteAttribute as_write_attribute)
@@ -415,7 +414,7 @@ class BuiltinSplineAttributeProvider final : public BuiltinAttributeProvider {
bool exists(const GeometryComponent &component) const final
{
- return component.attribute_domain_size(ATTR_DOMAIN_CURVE) != 0;
+ return component.attribute_domain_num(ATTR_DOMAIN_CURVE) != 0;
}
};
@@ -495,8 +494,8 @@ static void point_attribute_materialize(Span<Span<T>> data,
const IndexMask mask,
MutableSpan<T> r_span)
{
- const int total_size = offsets.last();
- if (mask.is_range() && mask.as_range() == IndexRange(total_size)) {
+ const int total_num = offsets.last();
+ if (mask.is_range() && mask.as_range() == IndexRange(total_num)) {
for (const int spline_index : data.index_range()) {
const int offset = offsets[spline_index];
const int next_offset = offsets[spline_index + 1];
@@ -541,8 +540,8 @@ static void point_attribute_materialize_to_uninitialized(Span<Span<T>> data,
MutableSpan<T> r_span)
{
T *dst = r_span.data();
- const int total_size = offsets.last();
- if (mask.is_range() && mask.as_range() == IndexRange(total_size)) {
+ const int total_num = offsets.last();
+ if (mask.is_range() && mask.as_range() == IndexRange(total_num)) {
for (const int spline_index : data.index_range()) {
const int offset = offsets[spline_index];
const int next_offset = offsets[spline_index + 1];
@@ -577,7 +576,7 @@ static void point_attribute_materialize_to_uninitialized(Span<Span<T>> data,
}
static GVArray varray_from_initializer(const AttributeInit &initializer,
- const CustomDataType data_type,
+ const eCustomDataType data_type,
const Span<SplinePtr> splines)
{
switch (initializer.type) {
@@ -589,13 +588,13 @@ static GVArray varray_from_initializer(const AttributeInit &initializer,
case AttributeInit::Type::VArray:
return static_cast<const AttributeInitVArray &>(initializer).varray;
case AttributeInit::Type::MoveArray:
- int total_size = 0;
+ int total_num = 0;
for (const SplinePtr &spline : splines) {
- total_size += spline->size();
+ total_num += spline->size();
}
return GVArray::ForSpan(GSpan(*bke::custom_data_type_to_cpp_type(data_type),
static_cast<const AttributeInitMove &>(initializer).data,
- total_size));
+ total_num));
}
BLI_assert_unreachable();
return {};
@@ -604,7 +603,7 @@ static GVArray varray_from_initializer(const AttributeInit &initializer,
static bool create_point_attribute(GeometryComponent &component,
const AttributeIDRef &attribute_id,
const AttributeInit &initializer,
- const CustomDataType data_type)
+ const eCustomDataType data_type)
{
CurveEval *curve = get_curve_from_component_for_write(component);
if (curve == nullptr || curve->splines().size() == 0) {
@@ -1168,7 +1167,7 @@ class BezierHandleAttributeProvider : public BuiltinAttributeProvider {
}
return curve->has_spline_with_type(CURVE_TYPE_BEZIER) &&
- component.attribute_domain_size(ATTR_DOMAIN_POINT) != 0;
+ component.attribute_domain_num(ATTR_DOMAIN_POINT) != 0;
}
};
@@ -1306,8 +1305,8 @@ class DynamicPointAttributeProvider final : public DynamicAttributesProvider {
bool try_create(GeometryComponent &component,
const AttributeIDRef &attribute_id,
- const AttributeDomain domain,
- const CustomDataType data_type,
+ const eAttrDomain domain,
+ const eCustomDataType data_type,
const AttributeInit &initializer) const final
{
BLI_assert(this->type_is_supported(data_type));
@@ -1336,12 +1335,12 @@ class DynamicPointAttributeProvider final : public DynamicAttributesProvider {
return true;
}
- void foreach_domain(const FunctionRef<void(AttributeDomain)> callback) const final
+ void foreach_domain(const FunctionRef<void(eAttrDomain)> callback) const final
{
callback(ATTR_DOMAIN_POINT);
}
- bool type_is_supported(CustomDataType data_type) const
+ bool type_is_supported(eCustomDataType data_type) const
{
return ((1ULL << data_type) & supported_types_mask) != 0;
}
diff --git a/source/blender/blenkernel/intern/geometry_component_curves.cc b/source/blender/blenkernel/intern/geometry_component_curves.cc
index 7c4a7db6462..af058534f68 100644
--- a/source/blender/blenkernel/intern/geometry_component_curves.cc
+++ b/source/blender/blenkernel/intern/geometry_component_curves.cc
@@ -12,7 +12,6 @@
#include "BKE_geometry_fields.hh"
#include "BKE_geometry_set.hh"
#include "BKE_lib_id.h"
-#include "BKE_spline.hh"
#include "attribute_access_intern.hh"
@@ -135,12 +134,12 @@ const Curve *CurveComponent::get_curve_for_render() const
/** \} */
+namespace blender::bke {
+
/* -------------------------------------------------------------------- */
/** \name Curve Normals Access
* \{ */
-namespace blender::bke {
-
static Array<float3> curve_normal_point_domain(const bke::CurvesGeometry &curves)
{
const VArray<int8_t> types = curves.curve_types();
@@ -208,7 +207,7 @@ static Array<float3> curve_normal_point_domain(const bke::CurvesGeometry &curves
return results;
}
-VArray<float3> curve_normals_varray(const CurveComponent &component, const AttributeDomain domain)
+VArray<float3> curve_normals_varray(const CurveComponent &component, const eAttrDomain domain)
{
if (!component.has_curves()) {
return {};
@@ -244,7 +243,7 @@ VArray<float3> curve_normals_varray(const CurveComponent &component, const Attri
* \{ */
static VArray<float> construct_curve_length_gvarray(const CurveComponent &component,
- const AttributeDomain domain)
+ const eAttrDomain domain)
{
if (!component.has_curves()) {
return {};
@@ -279,7 +278,7 @@ CurveLengthFieldInput::CurveLengthFieldInput()
}
GVArray CurveLengthFieldInput::get_varray_for_context(const GeometryComponent &component,
- const AttributeDomain domain,
+ const eAttrDomain domain,
IndexMask UNUSED(mask)) const
{
if (component.type() == GEO_COMPONENT_TYPE_CURVE) {
@@ -300,33 +299,33 @@ bool CurveLengthFieldInput::is_equal_to(const fn::FieldNode &other) const
return dynamic_cast<const CurveLengthFieldInput *>(&other) != nullptr;
}
-} // namespace blender::bke
-
/** \} */
+} // namespace blender::bke
+
/* -------------------------------------------------------------------- */
/** \name Attribute Access Helper Functions
* \{ */
-int CurveComponent::attribute_domain_size(const AttributeDomain domain) const
+int CurveComponent::attribute_domain_num(const eAttrDomain domain) const
{
if (curves_ == nullptr) {
return 0;
}
- const blender::bke::CurvesGeometry &geometry = blender::bke::CurvesGeometry::wrap(
+ const blender::bke::CurvesGeometry &curves = blender::bke::CurvesGeometry::wrap(
curves_->geometry);
if (domain == ATTR_DOMAIN_POINT) {
- return geometry.points_num();
+ return curves.points_num();
}
if (domain == ATTR_DOMAIN_CURVE) {
- return geometry.curves_num();
+ return curves.curves_num();
}
return 0;
}
GVArray CurveComponent::attribute_try_adapt_domain_impl(const GVArray &varray,
- const AttributeDomain from_domain,
- const AttributeDomain to_domain) const
+ const eAttrDomain from_domain,
+ const eAttrDomain to_domain) const
{
return blender::bke::CurvesGeometry::wrap(curves_->geometry)
.adapt_domain(varray, from_domain, to_domain);
diff --git a/source/blender/blenkernel/intern/geometry_component_instances.cc b/source/blender/blenkernel/intern/geometry_component_instances.cc
index 0dc6f486d28..653be03b991 100644
--- a/source/blender/blenkernel/intern/geometry_component_instances.cc
+++ b/source/blender/blenkernel/intern/geometry_component_instances.cc
@@ -79,7 +79,7 @@ void InstancesComponent::add_instance(const int instance_handle, const float4x4
BLI_assert(instance_handle < references_.size());
instance_reference_handles_.append(instance_handle);
instance_transforms_.append(transform);
- attributes_.reallocate(this->instances_amount());
+ attributes_.reallocate(this->instances_num());
}
blender::Span<int> InstancesComponent::instance_reference_handles() const
@@ -183,7 +183,7 @@ void InstancesComponent::remove_unused_references()
using namespace blender;
using namespace blender::bke;
- const int tot_instances = this->instances_amount();
+ const int tot_instances = this->instances_num();
const int tot_references_before = references_.size();
if (tot_instances == 0) {
@@ -258,12 +258,12 @@ void InstancesComponent::remove_unused_references()
});
}
-int InstancesComponent::instances_amount() const
+int InstancesComponent::instances_num() const
{
return instance_transforms_.size();
}
-int InstancesComponent::references_amount() const
+int InstancesComponent::references_num() const
{
return references_.size();
}
@@ -358,7 +358,7 @@ blender::Span<int> InstancesComponent::almost_unique_ids() const
}
}
else {
- almost_unique_ids_.reinitialize(this->instances_amount());
+ almost_unique_ids_.reinitialize(this->instances_num());
for (const int i : almost_unique_ids_.index_range()) {
almost_unique_ids_[i] = i;
}
@@ -366,12 +366,12 @@ blender::Span<int> InstancesComponent::almost_unique_ids() const
return almost_unique_ids_;
}
-int InstancesComponent::attribute_domain_size(const AttributeDomain domain) const
+int InstancesComponent::attribute_domain_num(const eAttrDomain domain) const
{
if (domain != ATTR_DOMAIN_INSTANCE) {
return 0;
}
- return this->instances_amount();
+ return this->instances_num();
}
blender::bke::CustomDataAttributes &InstancesComponent::attributes()
diff --git a/source/blender/blenkernel/intern/geometry_component_mesh.cc b/source/blender/blenkernel/intern/geometry_component_mesh.cc
index fb39861d3e7..8a021e596bd 100644
--- a/source/blender/blenkernel/intern/geometry_component_mesh.cc
+++ b/source/blender/blenkernel/intern/geometry_component_mesh.cc
@@ -119,7 +119,7 @@ namespace blender::bke {
VArray<float3> mesh_normals_varray(const MeshComponent &mesh_component,
const Mesh &mesh,
const IndexMask mask,
- const AttributeDomain domain)
+ const eAttrDomain domain)
{
switch (domain) {
case ATTR_DOMAIN_FACE: {
@@ -169,7 +169,7 @@ VArray<float3> mesh_normals_varray(const MeshComponent &mesh_component,
/** \name Attribute Access
* \{ */
-int MeshComponent::attribute_domain_size(const AttributeDomain domain) const
+int MeshComponent::attribute_domain_num(const eAttrDomain domain) const
{
if (mesh_ == nullptr) {
return 0;
@@ -747,10 +747,9 @@ static GVArray adapt_mesh_domain_edge_to_face(const Mesh &mesh, const GVArray &v
} // namespace blender::bke
-blender::GVArray MeshComponent::attribute_try_adapt_domain_impl(
- const blender::GVArray &varray,
- const AttributeDomain from_domain,
- const AttributeDomain to_domain) const
+blender::GVArray MeshComponent::attribute_try_adapt_domain_impl(const blender::GVArray &varray,
+ const eAttrDomain from_domain,
+ const eAttrDomain to_domain) const
{
if (!varray) {
return {};
@@ -839,20 +838,20 @@ static const Mesh *get_mesh_from_component_for_read(const GeometryComponent &com
namespace blender::bke {
template<typename StructT, typename ElemT, ElemT (*GetFunc)(const StructT &)>
-static GVArray make_derived_read_attribute(const void *data, const int domain_size)
+static GVArray make_derived_read_attribute(const void *data, const int domain_num)
{
return VArray<ElemT>::template ForDerivedSpan<StructT, GetFunc>(
- Span<StructT>((const StructT *)data, domain_size));
+ Span<StructT>((const StructT *)data, domain_num));
}
template<typename StructT,
typename ElemT,
ElemT (*GetFunc)(const StructT &),
void (*SetFunc)(StructT &, ElemT)>
-static GVMutableArray make_derived_write_attribute(void *data, const int domain_size)
+static GVMutableArray make_derived_write_attribute(void *data, const int domain_num)
{
return VMutableArray<ElemT>::template ForDerivedSpan<StructT, GetFunc, SetFunc>(
- MutableSpan<StructT>((StructT *)data, domain_size));
+ MutableSpan<StructT>((StructT *)data, domain_num));
}
static float3 get_vertex_position(const MVert &vert)
@@ -1115,7 +1114,7 @@ class VertexGroupsAttributeProvider final : public DynamicAttributesProvider {
return true;
}
- void foreach_domain(const FunctionRef<void(AttributeDomain)> callback) const final
+ void foreach_domain(const FunctionRef<void(eAttrDomain)> callback) const final
{
callback(ATTR_DOMAIN_POINT);
}
@@ -1160,7 +1159,7 @@ class NormalAttributeProvider final : public BuiltinAttributeProvider {
bool exists(const GeometryComponent &component) const final
{
- return component.attribute_domain_size(ATTR_DOMAIN_FACE) != 0;
+ return component.attribute_domain_num(ATTR_DOMAIN_FACE) != 0;
}
};
diff --git a/source/blender/blenkernel/intern/geometry_component_pointcloud.cc b/source/blender/blenkernel/intern/geometry_component_pointcloud.cc
index 400e0ea5e15..facdbed265d 100644
--- a/source/blender/blenkernel/intern/geometry_component_pointcloud.cc
+++ b/source/blender/blenkernel/intern/geometry_component_pointcloud.cc
@@ -104,7 +104,7 @@ void PointCloudComponent::ensure_owns_direct_data()
/** \name Attribute Access
* \{ */
-int PointCloudComponent::attribute_domain_size(const AttributeDomain domain) const
+int PointCloudComponent::attribute_domain_num(const eAttrDomain domain) const
{
if (pointcloud_ == nullptr) {
return 0;
diff --git a/source/blender/blenkernel/intern/geometry_set.cc b/source/blender/blenkernel/intern/geometry_set.cc
index 2bd8b643899..1a43c4d01b0 100644
--- a/source/blender/blenkernel/intern/geometry_set.cc
+++ b/source/blender/blenkernel/intern/geometry_set.cc
@@ -1,5 +1,6 @@
/* SPDX-License-Identifier: GPL-2.0-or-later */
+#include "BLI_bounds.hh"
#include "BLI_map.hh"
#include "BLI_task.hh"
@@ -15,7 +16,6 @@
#include "BKE_mesh_wrapper.h"
#include "BKE_modifier.h"
#include "BKE_pointcloud.h"
-#include "BKE_spline.hh"
#include "BKE_volume.h"
#include "DNA_collection_types.h"
@@ -175,6 +175,7 @@ Vector<const GeometryComponent *> GeometrySet::get_components_for_read() const
bool GeometrySet::compute_boundbox_without_instances(float3 *r_min, float3 *r_max) const
{
+ using namespace blender;
bool have_minmax = false;
if (const PointCloud *pointcloud = this->get_pointcloud_for_read()) {
have_minmax |= BKE_pointcloud_minmax(pointcloud, *r_min, *r_max);
@@ -185,10 +186,16 @@ bool GeometrySet::compute_boundbox_without_instances(float3 *r_min, float3 *r_ma
if (const Volume *volume = this->get_volume_for_read()) {
have_minmax |= BKE_volume_min_max(volume, *r_min, *r_max);
}
- if (const Curves *curves = this->get_curves_for_read()) {
- std::unique_ptr<CurveEval> curve = curves_to_curve_eval(*curves);
+ if (const Curves *curves_id = this->get_curves_for_read()) {
+ const bke::CurvesGeometry &curves = bke::CurvesGeometry::wrap(curves_id->geometry);
/* Using the evaluated positions is somewhat arbitrary, but it is probably expected. */
- have_minmax |= curve->bounds_min_max(*r_min, *r_max, true);
+ std::optional<bounds::MinMaxResult<float3>> min_max = bounds::min_max(
+ curves.evaluated_positions());
+ if (min_max) {
+ have_minmax = true;
+ *r_min = math::min(*r_min, min_max->min);
+ *r_max = math::max(*r_max, min_max->max);
+ }
}
return have_minmax;
}
@@ -272,7 +279,7 @@ bool GeometrySet::has_pointcloud() const
bool GeometrySet::has_instances() const
{
const InstancesComponent *component = this->get_component_for_read<InstancesComponent>();
- return component != nullptr && component->instances_amount() >= 1;
+ return component != nullptr && component->instances_num() >= 1;
}
bool GeometrySet::has_volume() const
@@ -470,7 +477,7 @@ void GeometrySet::gather_attributes_for_propagation(
return;
}
- AttributeDomain domain = meta_data.domain;
+ eAttrDomain domain = meta_data.domain;
if (dst_component_type != GEO_COMPONENT_TYPE_INSTANCES && domain == ATTR_DOMAIN_INSTANCE) {
domain = ATTR_DOMAIN_POINT;
}
@@ -567,7 +574,7 @@ void GeometrySet::modify_geometry_sets(ForeachSubGeometryCallback callback)
namespace blender::bke {
GVArray NormalFieldInput::get_varray_for_context(const GeometryComponent &component,
- const AttributeDomain domain,
+ const eAttrDomain domain,
IndexMask mask) const
{
if (component.type() == GEO_COMPONENT_TYPE_MESH) {
diff --git a/source/blender/blenkernel/intern/geometry_set_instances.cc b/source/blender/blenkernel/intern/geometry_set_instances.cc
index d3c3f41779a..2d6e0e05a97 100644
--- a/source/blender/blenkernel/intern/geometry_set_instances.cc
+++ b/source/blender/blenkernel/intern/geometry_set_instances.cc
@@ -32,9 +32,7 @@ static void add_final_mesh_as_geometry_component(const Object &object, GeometryS
if (mesh != nullptr) {
BKE_mesh_wrapper_ensure_mdata(mesh);
-
- MeshComponent &mesh_component = geometry_set.get_component_for_write<MeshComponent>();
- mesh_component.replace(mesh, GeometryOwnershipType::ReadOnly);
+ geometry_set.replace_mesh(mesh, GeometryOwnershipType::ReadOnly);
}
}
diff --git a/source/blender/blenkernel/intern/gpencil.c b/source/blender/blenkernel/intern/gpencil.c
index 84621be1960..f86e947910b 100644
--- a/source/blender/blenkernel/intern/gpencil.c
+++ b/source/blender/blenkernel/intern/gpencil.c
@@ -867,7 +867,7 @@ bGPDstroke *BKE_gpencil_stroke_duplicate(bGPDstroke *gps_src,
if (dup_points) {
gps_dst->points = MEM_dupallocN(gps_src->points);
- if ((gps_src->dvert != NULL) && (gps_src->dvert->totweight > 0)) {
+ if (gps_src->dvert != NULL) {
gps_dst->dvert = MEM_dupallocN(gps_src->dvert);
BKE_gpencil_stroke_weights_duplicate(gps_src, gps_dst);
}
@@ -2803,7 +2803,7 @@ void BKE_gpencil_update_layer_transforms(const Depsgraph *depsgraph, Object *ob)
/* Iterate over frame range. */
for (bGPDframe *gpf = gpf_start; gpf != NULL && gpf != gpf_end; gpf = gpf->next) {
- /* Skip frames without a valid onion skinning id (note: active frame has one). */
+ /* Skip frames without a valid onion skinning id (NOTE: active frame has one). */
if (gpf->runtime.onion_id == INT_MAX) {
continue;
}
diff --git a/source/blender/blenkernel/intern/gpencil_geom.cc b/source/blender/blenkernel/intern/gpencil_geom.cc
index 041696fa8d3..792474d30ea 100644
--- a/source/blender/blenkernel/intern/gpencil_geom.cc
+++ b/source/blender/blenkernel/intern/gpencil_geom.cc
@@ -236,6 +236,7 @@ static int stroke_march_next_point(const bGPDstroke *gps,
}
else {
next_point_index = gps->totpoints - 1;
+ remaining_till_next = 0;
break;
}
}
@@ -263,15 +264,18 @@ static int stroke_march_next_point(const bGPDstroke *gps,
float ratio = remaining_march / remaining_till_next;
interp_v3_v3v3(result, step_start, point, ratio);
*ratio_result = ratio;
+ float d1 = len_v3v3(result, &gps->points[*index_from].x);
+ float d2 = len_v3v3(result, &gps->points[next_point_index].x);
+ float vratio = d1 / (d1 + d2);
*pressure = interpf(
- gps->points[next_point_index].pressure, gps->points[*index_from].pressure, ratio);
+ gps->points[next_point_index].pressure, gps->points[*index_from].pressure, vratio);
*strength = interpf(
- gps->points[next_point_index].strength, gps->points[*index_from].strength, ratio);
+ gps->points[next_point_index].strength, gps->points[*index_from].strength, vratio);
interp_v4_v4v4(vert_color,
gps->points[*index_from].vert_color,
gps->points[next_point_index].vert_color,
- ratio);
+ vratio);
return next_point_index == 0 ? gps->totpoints : next_point_index;
}
@@ -320,6 +324,7 @@ static int stroke_march_next_point_no_interp(const bGPDstroke *gps,
}
else {
next_point_index = gps->totpoints - 1;
+ remaining_till_next = 0;
break;
}
}
@@ -4204,7 +4209,14 @@ bGPDstroke *BKE_gpencil_stroke_perimeter_from_view(struct RegionView3D *rv3d,
if (gps->totpoints == 0) {
return nullptr;
}
- bGPDstroke *gps_temp = BKE_gpencil_stroke_duplicate(gps, true, false);
+ /* Duplicate only points and fill data. Weight and Curve are not needed. */
+ bGPDstroke *gps_temp = (bGPDstroke *)MEM_dupallocN(gps);
+ gps_temp->prev = gps_temp->next = nullptr;
+ gps_temp->triangles = (bGPDtriangle *)MEM_dupallocN(gps->triangles);
+ gps_temp->points = (bGPDspoint *)MEM_dupallocN(gps->points);
+ gps_temp->dvert = nullptr;
+ gps_temp->editcurve = nullptr;
+
const bool cyclic = ((gps_temp->flag & GP_STROKE_CYCLIC) != 0);
/* If Cyclic, add a new point. */
diff --git a/source/blender/blenkernel/intern/gpencil_modifier.c b/source/blender/blenkernel/intern/gpencil_modifier.c
index faafd1e1040..0bf5418ea8f 100644
--- a/source/blender/blenkernel/intern/gpencil_modifier.c
+++ b/source/blender/blenkernel/intern/gpencil_modifier.c
@@ -647,32 +647,38 @@ static bGPdata *gpencil_copy_structure_for_eval(bGPdata *gpd)
return gpd_eval;
}
-static void copy_frame_to_eval_cb(bGPDlayer *UNUSED(gpl),
+static void copy_frame_to_eval_ex(bGPDframe *gpf_orig, bGPDframe *gpf_eval)
+{
+ /* Free any existing eval stroke data. This happens in case we have a single user on the data
+ * block and the strokes have not been deleted. */
+ if (!BLI_listbase_is_empty(&gpf_eval->strokes)) {
+ BKE_gpencil_free_strokes(gpf_eval);
+ }
+ /* Copy strokes to eval frame and update internal orig pointers. */
+ BKE_gpencil_frame_copy_strokes(gpf_orig, gpf_eval);
+ BKE_gpencil_frame_original_pointers_update(gpf_orig, gpf_eval);
+}
+
+static void copy_frame_to_eval_cb(bGPDlayer *gpl,
bGPDframe *gpf,
bGPDstroke *UNUSED(gps),
void *UNUSED(thunk))
{
- /* Early return when callback is not provided with a frame. */
- if (gpf == NULL) {
+ /* Early return when callback:
+ * - Is not provided with a frame.
+ * - When the frame is the layer's active frame (already handled in
+ * gpencil_copy_visible_frames_to_eval).
+ */
+ if (gpf == NULL || gpf == gpl->actframe) {
return;
}
- /* Free any existing eval stroke data. This happens in case we have a single user on the data
- * block and the strokes have not been deleted. */
- if (!BLI_listbase_is_empty(&gpf->strokes)) {
- BKE_gpencil_free_strokes(gpf);
- }
-
- /* Get original frame. */
- bGPDframe *gpf_orig = gpf->runtime.gpf_orig;
- /* Copy strokes to eval frame and update internal orig pointers. */
- BKE_gpencil_frame_copy_strokes(gpf_orig, gpf);
- BKE_gpencil_frame_original_pointers_update(gpf_orig, gpf);
+ copy_frame_to_eval_ex(gpf->runtime.gpf_orig, gpf);
}
static void gpencil_copy_visible_frames_to_eval(Depsgraph *depsgraph, Scene *scene, Object *ob)
{
- /* Remap layers' active frame with time modifiers applied. */
+ /* Remap layers active frame with time modifiers applied. */
bGPdata *gpd_eval = ob->data;
LISTBASE_FOREACH (bGPDlayer *, gpl_eval, &gpd_eval->layers) {
bGPDframe *gpf_eval = gpl_eval->actframe;
@@ -680,9 +686,14 @@ static void gpencil_copy_visible_frames_to_eval(Depsgraph *depsgraph, Scene *sce
if (gpf_eval == NULL || gpf_eval->framenum != remap_cfra) {
gpl_eval->actframe = BKE_gpencil_layer_frame_get(gpl_eval, remap_cfra, GP_GETFRAME_USE_PREV);
}
+ /* Always copy active frame to eval, because the modifiers always evaluate the active frame,
+ * even if it's not visible (e.g. the layer is hidden).*/
+ if (gpl_eval->actframe != NULL) {
+ copy_frame_to_eval_ex(gpl_eval->actframe->runtime.gpf_orig, gpl_eval->actframe);
+ }
}
- /* Copy only visible frames to evaluated version. */
+ /* Copy visible frames that are not the active one to evaluated version. */
BKE_gpencil_visible_stroke_advanced_iter(
NULL, ob, copy_frame_to_eval_cb, NULL, NULL, true, scene->r.cfra);
}
diff --git a/source/blender/blenkernel/intern/icons.cc b/source/blender/blenkernel/intern/icons.cc
index 2ba6510ee71..f59f5352aad 100644
--- a/source/blender/blenkernel/intern/icons.cc
+++ b/source/blender/blenkernel/intern/icons.cc
@@ -114,32 +114,35 @@ static void icon_free(void *val)
static void icon_free_data(int icon_id, Icon *icon)
{
- if (icon->obj_type == ICON_DATA_ID) {
- ((ID *)(icon->obj))->icon_id = 0;
- }
- else if (icon->obj_type == ICON_DATA_IMBUF) {
- ImBuf *imbuf = (ImBuf *)icon->obj;
- if (imbuf) {
- IMB_freeImBuf(imbuf);
+ switch (icon->obj_type) {
+ case ICON_DATA_ID:
+ ((ID *)(icon->obj))->icon_id = 0;
+ break;
+ case ICON_DATA_IMBUF: {
+ ImBuf *imbuf = (ImBuf *)icon->obj;
+ if (imbuf) {
+ IMB_freeImBuf(imbuf);
+ }
+ break;
}
- }
- else if (icon->obj_type == ICON_DATA_PREVIEW) {
- ((PreviewImage *)(icon->obj))->icon_id = 0;
- }
- else if (icon->obj_type == ICON_DATA_GPLAYER) {
- ((bGPDlayer *)(icon->obj))->runtime.icon_id = 0;
- }
- else if (icon->obj_type == ICON_DATA_GEOM) {
- ((struct Icon_Geom *)(icon->obj))->icon_id = 0;
- }
- else if (icon->obj_type == ICON_DATA_STUDIOLIGHT) {
- StudioLight *sl = (StudioLight *)icon->obj;
- if (sl != nullptr) {
- BKE_studiolight_unset_icon_id(sl, icon_id);
+ case ICON_DATA_PREVIEW:
+ ((PreviewImage *)(icon->obj))->icon_id = 0;
+ break;
+ case ICON_DATA_GPLAYER:
+ ((bGPDlayer *)(icon->obj))->runtime.icon_id = 0;
+ break;
+ case ICON_DATA_GEOM:
+ ((struct Icon_Geom *)(icon->obj))->icon_id = 0;
+ break;
+ case ICON_DATA_STUDIOLIGHT: {
+ StudioLight *sl = (StudioLight *)icon->obj;
+ if (sl != nullptr) {
+ BKE_studiolight_unset_icon_id(sl, icon_id);
+ }
+ break;
}
- }
- else {
- BLI_assert(0);
+ default:
+ BLI_assert_unreachable();
}
}
@@ -241,16 +244,16 @@ static PreviewImage *previewimg_create_ex(size_t deferred_data_size)
return prv_img;
}
-static PreviewImage *previewimg_deferred_create(const char *path, int source)
+static PreviewImage *previewimg_deferred_create(const char *filepath, int source)
{
- /* We pack needed data for lazy loading (source type, in a single char, and path). */
- const size_t deferred_data_size = strlen(path) + 2;
+ /* We pack needed data for lazy loading (source type, in a single char, and filepath). */
+ const size_t deferred_data_size = strlen(filepath) + 2;
char *deferred_data;
PreviewImage *prv = previewimg_create_ex(deferred_data_size);
deferred_data = (char *)PRV_DEFERRED_DATA(prv);
deferred_data[0] = source;
- memcpy(&deferred_data[1], path, deferred_data_size - 1);
+ memcpy(&deferred_data[1], filepath, deferred_data_size - 1);
return prv;
}
@@ -393,7 +396,7 @@ PreviewImage *BKE_previewimg_id_ensure(ID *id)
return nullptr;
}
-void BKE_previewimg_id_custom_set(ID *id, const char *path)
+void BKE_previewimg_id_custom_set(ID *id, const char *filepath)
{
PreviewImage **prv = BKE_previewimg_id_get_p(id);
@@ -403,7 +406,7 @@ void BKE_previewimg_id_custom_set(ID *id, const char *path)
if (*prv) {
BKE_previewimg_deferred_release(*prv);
}
- *prv = previewimg_deferred_create(path, THB_SOURCE_IMAGE);
+ *prv = previewimg_deferred_create(filepath, THB_SOURCE_IMAGE);
/* Can't lazy-render the preview on access. ID previews are saved to files and we want them to be
* there in time. Not only if something happened to have accessed it meanwhile. */
@@ -458,7 +461,7 @@ PreviewImage *BKE_previewimg_cached_ensure(const char *name)
}
PreviewImage *BKE_previewimg_cached_thumbnail_read(const char *name,
- const char *path,
+ const char *filepath,
const int source,
bool force_update)
{
@@ -476,8 +479,8 @@ PreviewImage *BKE_previewimg_cached_thumbnail_read(const char *name,
if (prv && force_update) {
const char *prv_deferred_data = (char *)PRV_DEFERRED_DATA(prv);
- if (((int)prv_deferred_data[0] == source) && STREQ(&prv_deferred_data[1], path)) {
- /* If same path, no need to re-allocate preview, just clear it up. */
+ if (((int)prv_deferred_data[0] == source) && STREQ(&prv_deferred_data[1], filepath)) {
+ /* If same filepath, no need to re-allocate preview, just clear it up. */
BKE_previewimg_clear(prv);
}
else {
@@ -486,7 +489,7 @@ PreviewImage *BKE_previewimg_cached_thumbnail_read(const char *name,
}
if (!prv) {
- prv = previewimg_deferred_create(path, source);
+ prv = previewimg_deferred_create(filepath, source);
force_update = true;
}
@@ -521,10 +524,10 @@ void BKE_previewimg_ensure(PreviewImage *prv, const int size)
ImBuf *thumb;
char *prv_deferred_data = (char *)PRV_DEFERRED_DATA(prv);
int source = prv_deferred_data[0];
- char *path = &prv_deferred_data[1];
+ char *filepath = &prv_deferred_data[1];
int icon_w, icon_h;
- thumb = IMB_thumb_manage(path, THB_LARGE, (ThumbSource)source);
+ thumb = IMB_thumb_manage(filepath, THB_LARGE, (ThumbSource)source);
if (thumb) {
/* PreviewImage assumes premultiplied alhpa... */
diff --git a/source/blender/blenkernel/intern/idprop.c b/source/blender/blenkernel/intern/idprop.c
index 7b8dfdc690c..35f02c29a00 100644
--- a/source/blender/blenkernel/intern/idprop.c
+++ b/source/blender/blenkernel/intern/idprop.c
@@ -168,7 +168,7 @@ void IDP_ResizeIDPArray(IDProperty *prop, int newlen)
/* NOTE: This code comes from python, here's the corresponding comment. */
/* This over-allocates proportional to the list size, making room
- * for additional growth. The over-allocation is mild, but is
+ * for additional growth. The over-allocation is mild, but is
* enough to give linear-time amortized behavior over a long
* sequence of appends() in the presence of a poorly-performing
* system realloc().
@@ -872,7 +872,7 @@ bool IDP_EqualsProperties_ex(IDProperty *prop1, IDProperty *prop2, const bool is
case IDP_ID:
return (IDP_Id(prop1) == IDP_Id(prop2));
default:
- BLI_assert(0);
+ BLI_assert_unreachable();
break;
}
diff --git a/source/blender/blenkernel/intern/idprop_utils.c b/source/blender/blenkernel/intern/idprop_utils.c
index 2ffa5125b1d..5b7484ab422 100644
--- a/source/blender/blenkernel/intern/idprop_utils.c
+++ b/source/blender/blenkernel/intern/idprop_utils.c
@@ -181,7 +181,7 @@ static void idp_repr_fn_recursive(struct ReprState *state, const IDProperty *pro
break;
}
default: {
- BLI_assert(0);
+ BLI_assert_unreachable();
break;
}
}
diff --git a/source/blender/blenkernel/intern/image.cc b/source/blender/blenkernel/intern/image.cc
index dfa820519a5..0c1f01c3796 100644
--- a/source/blender/blenkernel/intern/image.cc
+++ b/source/blender/blenkernel/intern/image.cc
@@ -182,9 +182,7 @@ static void image_copy_data(Main *UNUSED(bmain), ID *id_dst, const ID *id_src, c
for (int eye = 0; eye < 2; eye++) {
for (int i = 0; i < TEXTARGET_COUNT; i++) {
- for (int resolution = 0; resolution < IMA_TEXTURE_RESOLUTION_LEN; resolution++) {
- image_dst->gputexture[i][eye][resolution] = nullptr;
- }
+ image_dst->gputexture[i][eye] = nullptr;
}
}
@@ -236,24 +234,21 @@ static void image_foreach_cache(ID *id,
key.offset_in_ID = offsetof(Image, cache);
function_callback(id, &key, (void **)&image->cache, 0, user_data);
- auto gputexture_offset = [image](int target, int eye, int resolution) {
+ auto gputexture_offset = [image](int target, int eye) {
constexpr size_t base_offset = offsetof(Image, gputexture);
- struct GPUTexture **first = &image->gputexture[0][0][0];
- const size_t array_offset = sizeof(*first) *
- (&image->gputexture[target][eye][resolution] - first);
+ struct GPUTexture **first = &image->gputexture[0][0];
+ const size_t array_offset = sizeof(*first) * (&image->gputexture[target][eye] - first);
return base_offset + array_offset;
};
for (int eye = 0; eye < 2; eye++) {
for (int a = 0; a < TEXTARGET_COUNT; a++) {
- for (int resolution = 0; resolution < IMA_TEXTURE_RESOLUTION_LEN; resolution++) {
- GPUTexture *texture = image->gputexture[a][eye][resolution];
- if (texture == nullptr) {
- continue;
- }
- key.offset_in_ID = gputexture_offset(a, eye, resolution);
- function_callback(id, &key, (void **)&image->gputexture[a][eye][resolution], 0, user_data);
+ GPUTexture *texture = image->gputexture[a][eye];
+ if (texture == nullptr) {
+ continue;
}
+ key.offset_in_ID = gputexture_offset(a, eye);
+ function_callback(id, &key, (void **)&image->gputexture[a][eye], 0, user_data);
}
}
@@ -335,9 +330,7 @@ static void image_blend_write(BlendWriter *writer, ID *id, const void *id_addres
ima->runtime.partial_update_user = nullptr;
for (int i = 0; i < 3; i++) {
for (int j = 0; j < 2; j++) {
- for (int resolution = 0; resolution < IMA_TEXTURE_RESOLUTION_LEN; resolution++) {
- ima->gputexture[i][j][resolution] = nullptr;
- }
+ ima->gputexture[i][j] = nullptr;
}
}
@@ -721,6 +714,9 @@ static void copy_image_packedfiles(ListBase *lb_dst, const ListBase *lb_src)
imapf_src = imapf_src->next) {
ImagePackedFile *imapf_dst = static_cast<ImagePackedFile *>(
MEM_mallocN(sizeof(ImagePackedFile), "Image Packed Files (copy)"));
+
+ imapf_dst->view = imapf_src->view;
+ imapf_dst->tile_number = imapf_src->tile_number;
STRNCPY(imapf_dst->filepath, imapf_src->filepath);
if (imapf_src->packedfile) {
@@ -781,10 +777,8 @@ bool BKE_image_has_opengl_texture(Image *ima)
{
for (int eye = 0; eye < 2; eye++) {
for (int i = 0; i < TEXTARGET_COUNT; i++) {
- for (int resolution = 0; resolution < IMA_TEXTURE_RESOLUTION_LEN; resolution++) {
- if (ima->gputexture[i][eye][resolution] != nullptr) {
- return true;
- }
+ if (ima->gputexture[i][eye] != nullptr) {
+ return true;
}
}
}
@@ -1197,7 +1191,8 @@ Image *BKE_image_add_from_imbuf(Main *bmain, ImBuf *ibuf, const char *name)
}
/** Pack image buffer to memory as PNG or EXR. */
-static bool image_memorypack_imbuf(Image *ima, ImBuf *ibuf, const char *filepath)
+static bool image_memorypack_imbuf(
+ Image *ima, ImBuf *ibuf, int view, int tile_number, const char *filepath)
{
ibuf->ftype = (ibuf->rect_float) ? IMB_FTYPE_OPENEXR : IMB_FTYPE_PNG;
@@ -1219,6 +1214,8 @@ static bool image_memorypack_imbuf(Image *ima, ImBuf *ibuf, const char *filepath
imapf = static_cast<ImagePackedFile *>(MEM_mallocN(sizeof(ImagePackedFile), "Image PackedFile"));
STRNCPY(imapf->filepath, filepath);
imapf->packedfile = pf;
+ imapf->view = view;
+ imapf->tile_number = tile_number;
BLI_addtail(&ima->packedfiles, imapf);
ibuf->encodedbuffer = nullptr;
@@ -1234,42 +1231,47 @@ bool BKE_image_memorypack(Image *ima)
image_free_packedfiles(ima);
- if (BKE_image_is_multiview(ima)) {
- /* Store each view as a separate packed files with R_IMF_VIEWS_INDIVIDUAL. */
- ImageView *iv;
- int i;
+ const int tot_viewfiles = image_num_viewfiles(ima);
+ const bool is_tiled = (ima->source == IMA_SRC_TILED);
+ const bool is_multiview = BKE_image_is_multiview(ima);
- for (i = 0, iv = static_cast<ImageView *>(ima->views.first); iv;
- iv = static_cast<ImageView *>(iv->next), i++) {
- ImBuf *ibuf = image_get_cached_ibuf_for_index_entry(ima, i, 0, nullptr);
+ ImageUser iuser{};
+ BKE_imageuser_default(&iuser);
+ char tiled_filepath[FILE_MAX];
+ for (int view = 0; view < tot_viewfiles; view++) {
+ LISTBASE_FOREACH (ImageTile *, tile, &ima->tiles) {
+ int index = (is_multiview || is_tiled) ? view : IMA_NO_INDEX;
+ int entry = is_tiled ? tile->tile_number : 0;
+ ImBuf *ibuf = image_get_cached_ibuf_for_index_entry(ima, index, entry, nullptr);
if (!ibuf) {
ok = false;
break;
}
- /* if the image was a R_IMF_VIEWS_STEREO_3D we force _L, _R suffices */
- if (ima->views_format == R_IMF_VIEWS_STEREO_3D) {
- const char *suffix[2] = {STEREO_LEFT_SUFFIX, STEREO_RIGHT_SUFFIX};
- BLI_path_suffix(iv->filepath, FILE_MAX, suffix[i], "");
+ const char *filepath = ibuf->name;
+ if (is_tiled) {
+ iuser.tile = tile->tile_number;
+ BKE_image_user_file_path(&iuser, ima, tiled_filepath);
+ filepath = tiled_filepath;
+ }
+ else if (is_multiview) {
+ ImageView *iv = static_cast<ImageView *>(BLI_findlink(&ima->views, view));
+ /* if the image was a R_IMF_VIEWS_STEREO_3D we force _L, _R suffices */
+ if (ima->views_format == R_IMF_VIEWS_STEREO_3D) {
+ const char *suffix[2] = {STEREO_LEFT_SUFFIX, STEREO_RIGHT_SUFFIX};
+ BLI_path_suffix(iv->filepath, FILE_MAX, suffix[view], "");
+ }
+ filepath = iv->filepath;
}
- ok = ok && image_memorypack_imbuf(ima, ibuf, iv->filepath);
+ ok = ok && image_memorypack_imbuf(ima, ibuf, view, tile->tile_number, filepath);
IMB_freeImBuf(ibuf);
}
-
- ima->views_format = R_IMF_VIEWS_INDIVIDUAL;
}
- else {
- ImBuf *ibuf = image_get_cached_ibuf_for_index_entry(ima, IMA_NO_INDEX, 0, nullptr);
- if (ibuf) {
- ok = ok && image_memorypack_imbuf(ima, ibuf, ibuf->name);
- IMB_freeImBuf(ibuf);
- }
- else {
- ok = false;
- }
+ if (is_multiview) {
+ ima->views_format = R_IMF_VIEWS_INDIVIDUAL;
}
if (ok && ima->source == IMA_SRC_GENERATED) {
@@ -1284,27 +1286,24 @@ void BKE_image_packfiles(ReportList *reports, Image *ima, const char *basepath)
{
const int tot_viewfiles = image_num_viewfiles(ima);
- if (tot_viewfiles == 1) {
- ImagePackedFile *imapf = static_cast<ImagePackedFile *>(
- MEM_mallocN(sizeof(ImagePackedFile), "Image packed file"));
- BLI_addtail(&ima->packedfiles, imapf);
- imapf->packedfile = BKE_packedfile_new(reports, ima->filepath, basepath);
- if (imapf->packedfile) {
- STRNCPY(imapf->filepath, ima->filepath);
- }
- else {
- BLI_freelinkN(&ima->packedfiles, imapf);
- }
- }
- else {
- for (ImageView *iv = static_cast<ImageView *>(ima->views.first); iv; iv = iv->next) {
+ ImageUser iuser{};
+ BKE_imageuser_default(&iuser);
+ for (int view = 0; view < tot_viewfiles; view++) {
+ iuser.view = view;
+ LISTBASE_FOREACH (ImageTile *, tile, &ima->tiles) {
+ iuser.tile = tile->tile_number;
+ char filepath[FILE_MAX];
+ BKE_image_user_file_path(&iuser, ima, filepath);
+
ImagePackedFile *imapf = static_cast<ImagePackedFile *>(
MEM_mallocN(sizeof(ImagePackedFile), "Image packed file"));
BLI_addtail(&ima->packedfiles, imapf);
- imapf->packedfile = BKE_packedfile_new(reports, iv->filepath, basepath);
+ imapf->packedfile = BKE_packedfile_new(reports, filepath, basepath);
+ imapf->view = view;
+ imapf->tile_number = tile->tile_number;
if (imapf->packedfile) {
- STRNCPY(imapf->filepath, iv->filepath);
+ STRNCPY(imapf->filepath, filepath);
}
else {
BLI_freelinkN(&ima->packedfiles, imapf);
@@ -1323,11 +1322,16 @@ void BKE_image_packfiles_from_mem(ReportList *reports,
if (tot_viewfiles != 1) {
BKE_report(reports, RPT_ERROR, "Cannot pack multiview images from raw data currently...");
}
+ else if (ima->source == IMA_SRC_TILED) {
+ BKE_report(reports, RPT_ERROR, "Cannot pack tiled images from raw data currently...");
+ }
else {
ImagePackedFile *imapf = static_cast<ImagePackedFile *>(
MEM_mallocN(sizeof(ImagePackedFile), __func__));
BLI_addtail(&ima->packedfiles, imapf);
imapf->packedfile = BKE_packedfile_new_from_memory(data, data_len);
+ imapf->view = 0;
+ imapf->tile_number = 1001;
STRNCPY(imapf->filepath, ima->filepath);
}
}
@@ -1726,7 +1730,7 @@ static void stampdata_from_template(StampData *stamp_data,
stamp_data->file[0] = '\0';
}
if (scene->r.stamp & R_STAMP_NOTE) {
- SNPRINTF(stamp_data->note, "%s", stamp_data_template->note);
+ STRNCPY(stamp_data->note, stamp_data_template->note);
}
else {
stamp_data->note[0] = '\0';
@@ -2851,11 +2855,9 @@ static void image_free_tile(Image *ima, ImageTile *tile)
}
for (int eye = 0; eye < 2; eye++) {
- for (int resolution = 0; resolution < IMA_TEXTURE_RESOLUTION_LEN; resolution++) {
- if (ima->gputexture[i][eye][resolution] != nullptr) {
- GPU_texture_free(ima->gputexture[i][eye][resolution]);
- ima->gputexture[i][eye][resolution] = nullptr;
- }
+ if (ima->gputexture[i][eye] != nullptr) {
+ GPU_texture_free(ima->gputexture[i][eye]);
+ ima->gputexture[i][eye] = nullptr;
}
}
}
@@ -2927,6 +2929,7 @@ void BKE_image_signal(Main *bmain, Image *ima, ImageUser *iuser, int signal)
MEM_freeN(tile);
}
base_tile->next = nullptr;
+ base_tile->tile_number = 1001;
ima->tiles.last = base_tile;
}
@@ -2950,8 +2953,9 @@ void BKE_image_signal(Main *bmain, Image *ima, ImageUser *iuser, int signal)
/* try to repack file */
if (BKE_image_has_packedfile(ima)) {
const int tot_viewfiles = image_num_viewfiles(ima);
+ const int tot_files = tot_viewfiles * BLI_listbase_count(&ima->tiles);
- if (tot_viewfiles != BLI_listbase_count_at_most(&ima->packedfiles, tot_viewfiles + 1)) {
+ if (tot_files != BLI_listbase_count_at_most(&ima->packedfiles, tot_files + 1)) {
/* in case there are new available files to be loaded */
image_free_packedfiles(ima);
BKE_image_packfiles(nullptr, ima, ID_BLEND_PATH(bmain, &ima->id));
@@ -3108,7 +3112,9 @@ bool BKE_image_get_tile_info(char *filepath, ListBase *tiles, int *r_tile_start,
char filename[FILE_MAXFILE], dirname[FILE_MAXDIR];
BLI_split_dirfile(filepath, dirname, filename, sizeof(dirname), sizeof(filename));
- BKE_image_ensure_tile_token(filename);
+ if (!BKE_image_is_filename_tokenized(filename)) {
+ BKE_image_ensure_tile_token(filename);
+ }
eUDIM_TILE_FORMAT tile_format;
char *udim_pattern = BKE_image_get_tile_strformat(filename, &tile_format);
@@ -3142,10 +3148,7 @@ bool BKE_image_get_tile_info(char *filepath, ListBase *tiles, int *r_tile_start,
BLI_filelist_free(dirs, dirs_num);
MEM_SAFE_FREE(udim_pattern);
- /* Ensure that all discovered UDIMs are valid and that there's at least 2 files in total.
- * Downstream code checks the range value to determine tiled-ness; it's important we match that
- * expectation here too (T97366). */
- if (all_valid_udim && min_udim <= IMA_UDIM_MAX && max_udim > min_udim) {
+ if (all_valid_udim && min_udim <= IMA_UDIM_MAX) {
BLI_join_dirfile(filepath, FILE_MAX, dirname, filename);
*r_tile_start = min_udim;
@@ -3194,16 +3197,14 @@ ImageTile *BKE_image_add_tile(struct Image *ima, int tile_number, const char *la
}
for (int eye = 0; eye < 2; eye++) {
- for (int resolution = 0; resolution < IMA_TEXTURE_RESOLUTION_LEN; resolution++) {
- /* Reallocate GPU tile array. */
- if (ima->gputexture[TEXTARGET_2D_ARRAY][eye][resolution] != nullptr) {
- GPU_texture_free(ima->gputexture[TEXTARGET_2D_ARRAY][eye][resolution]);
- ima->gputexture[TEXTARGET_2D_ARRAY][eye][resolution] = nullptr;
- }
- if (ima->gputexture[TEXTARGET_TILE_MAPPING][eye][resolution] != nullptr) {
- GPU_texture_free(ima->gputexture[TEXTARGET_TILE_MAPPING][eye][resolution]);
- ima->gputexture[TEXTARGET_TILE_MAPPING][eye][resolution] = nullptr;
- }
+ /* Reallocate GPU tile array. */
+ if (ima->gputexture[TEXTARGET_2D_ARRAY][eye] != nullptr) {
+ GPU_texture_free(ima->gputexture[TEXTARGET_2D_ARRAY][eye]);
+ ima->gputexture[TEXTARGET_2D_ARRAY][eye] = nullptr;
+ }
+ if (ima->gputexture[TEXTARGET_TILE_MAPPING][eye] != nullptr) {
+ GPU_texture_free(ima->gputexture[TEXTARGET_TILE_MAPPING][eye]);
+ ima->gputexture[TEXTARGET_TILE_MAPPING][eye] = nullptr;
}
}
BKE_image_partial_update_mark_full_update(ima);
@@ -3259,17 +3260,14 @@ void BKE_image_reassign_tile(struct Image *ima, ImageTile *tile, int new_tile_nu
}
for (int eye = 0; eye < 2; eye++) {
- for (int resolution = 0; resolution < IMA_TEXTURE_RESOLUTION_LEN; resolution++) {
-
- /* Reallocate GPU tile array. */
- if (ima->gputexture[TEXTARGET_2D_ARRAY][eye][resolution] != nullptr) {
- GPU_texture_free(ima->gputexture[TEXTARGET_2D_ARRAY][eye][resolution]);
- ima->gputexture[TEXTARGET_2D_ARRAY][eye][resolution] = nullptr;
- }
- if (ima->gputexture[TEXTARGET_TILE_MAPPING][eye][resolution] != nullptr) {
- GPU_texture_free(ima->gputexture[TEXTARGET_TILE_MAPPING][eye][resolution]);
- ima->gputexture[TEXTARGET_TILE_MAPPING][eye][resolution] = nullptr;
- }
+ /* Reallocate GPU tile array. */
+ if (ima->gputexture[TEXTARGET_2D_ARRAY][eye] != nullptr) {
+ GPU_texture_free(ima->gputexture[TEXTARGET_2D_ARRAY][eye]);
+ ima->gputexture[TEXTARGET_2D_ARRAY][eye] = nullptr;
+ }
+ if (ima->gputexture[TEXTARGET_TILE_MAPPING][eye] != nullptr) {
+ GPU_texture_free(ima->gputexture[TEXTARGET_TILE_MAPPING][eye]);
+ ima->gputexture[TEXTARGET_TILE_MAPPING][eye] = nullptr;
}
}
BKE_image_partial_update_mark_full_update(ima);
@@ -3317,13 +3315,18 @@ bool BKE_image_fill_tile(struct Image *ima,
return false;
}
+bool BKE_image_is_filename_tokenized(char *filepath)
+{
+ const char *filename = BLI_path_basename(filepath);
+ return strstr(filename, "<UDIM>") != nullptr || strstr(filename, "<UVTILE>") != nullptr;
+}
+
void BKE_image_ensure_tile_token(char *filename)
{
BLI_assert_msg(BLI_path_slash_find(filename) == nullptr,
"Only the file-name component should be used!");
- /* Is there a '<' character in the filename? Assume tokens already present. */
- if (strstr(filename, "<") != nullptr) {
+ if (BKE_image_is_filename_tokenized(filename)) {
return;
}
@@ -3892,7 +3895,7 @@ static ImBuf *image_load_movie_file(Image *ima, ImageUser *iuser, int frame)
}
if (BKE_image_is_stereo(ima) && ima->views_format == R_IMF_VIEWS_STEREO_3D) {
- IMB_ImBufFromStereo3d(ima->stereo3d_format, ibuf_arr[0], &ibuf_arr[0], &ibuf_arr[1]);
+ IMB_ImBufFromStereo3d(ima->stereo3d_format, ibuf_arr[0], ibuf_arr.data(), &ibuf_arr[1]);
}
for (int i = 0; i < totviews; i++) {
@@ -3926,18 +3929,23 @@ static ImBuf *load_image_single(Image *ima,
int flag = IB_rect | IB_multilayer;
*r_cache_ibuf = true;
+ const int tile_number = image_get_tile_number_from_iuser(ima, iuser);
/* is there a PackedFile with this image ? */
if (has_packed && !is_sequence) {
- ImagePackedFile *imapf = static_cast<ImagePackedFile *>(
- BLI_findlink(&ima->packedfiles, view_id));
- if (imapf->packedfile) {
- flag |= imbuf_alpha_flags_for_image(ima);
- ibuf = IMB_ibImageFromMemory((unsigned char *)imapf->packedfile->data,
- imapf->packedfile->size,
- flag,
- ima->colorspace_settings.name,
- "<packed data>");
+ flag |= imbuf_alpha_flags_for_image(ima);
+
+ LISTBASE_FOREACH (ImagePackedFile *, imapf, &ima->packedfiles) {
+ if (imapf->view == view_id && imapf->tile_number == tile_number) {
+ if (imapf->packedfile) {
+ ibuf = IMB_ibImageFromMemory((unsigned char *)imapf->packedfile->data,
+ imapf->packedfile->size,
+ flag,
+ ima->colorspace_settings.name,
+ "<packed data>");
+ }
+ break;
+ }
}
}
else {
@@ -3996,6 +4004,8 @@ static ImBuf *load_image_single(Image *ima,
BLI_addtail(&ima->packedfiles, imapf);
STRNCPY(imapf->filepath, filepath);
+ imapf->view = view_id;
+ imapf->tile_number = tile_number;
imapf->packedfile = BKE_packedfile_new(
nullptr, filepath, ID_BLEND_PATH_FROM_GLOBAL(&ima->id));
}
@@ -4054,7 +4064,7 @@ static ImBuf *image_load_image_file(
/* multi-views/multi-layers OpenEXR files directly populate ima, and return null ibuf... */
if (BKE_image_is_stereo(ima) && ima->views_format == R_IMF_VIEWS_STEREO_3D && ibuf_arr[0] &&
tot_viewfiles == 1 && totviews >= 2) {
- IMB_ImBufFromStereo3d(ima->stereo3d_format, ibuf_arr[0], &ibuf_arr[0], &ibuf_arr[1]);
+ IMB_ImBufFromStereo3d(ima->stereo3d_format, ibuf_arr[0], ibuf_arr.data(), &ibuf_arr[1]);
}
/* return the original requested ImBuf */
@@ -5103,7 +5113,7 @@ bool BKE_image_has_packedfile(const Image *ima)
return (BLI_listbase_is_empty(&ima->packedfiles) == false);
}
-bool BKE_image_has_filepath(Image *ima)
+bool BKE_image_has_filepath(const Image *ima)
{
/* This could be improved to detect cases like //../../, currently path
* remapping empty file paths empty. */
diff --git a/source/blender/blenkernel/intern/image_format.cc b/source/blender/blenkernel/intern/image_format.cc
index 30be1fdaba7..57763e1670f 100644
--- a/source/blender/blenkernel/intern/image_format.cc
+++ b/source/blender/blenkernel/intern/image_format.cc
@@ -911,6 +911,11 @@ void BKE_image_format_from_imbuf(ImageFormatData *im_format, const ImBuf *imbuf)
im_format->planes = imbuf->planes;
}
+bool BKE_image_format_is_byte(const ImageFormatData *imf)
+{
+ return (imf->depth == R_IMF_CHAN_DEPTH_8) && (BKE_imtype_valid_depths(imf->imtype) & imf->depth);
+}
+
/* Color Management */
void BKE_image_format_color_management_copy(ImageFormatData *imf, const ImageFormatData *imf_src)
diff --git a/source/blender/blenkernel/intern/image_gpu.cc b/source/blender/blenkernel/intern/image_gpu.cc
index 0d470c5b663..6edb9e1b24c 100644
--- a/source/blender/blenkernel/intern/image_gpu.cc
+++ b/source/blender/blenkernel/intern/image_gpu.cc
@@ -38,7 +38,6 @@ extern "C" {
/* Prototypes. */
static void gpu_free_unused_buffers();
static void image_free_gpu(Image *ima, const bool immediate);
-static void image_free_gpu_limited_scale(Image *ima);
static void image_update_gputexture_ex(
Image *ima, ImageTile *tile, ImBuf *ibuf, int x, int y, int w, int h);
@@ -68,22 +67,19 @@ bool BKE_image_has_gpu_texture_premultiplied_alpha(Image *image, ImBuf *ibuf)
/** \name UDIM GPU Texture
* \{ */
-static bool is_over_resolution_limit(int w, int h, bool limit_gl_texture_size)
+static bool is_over_resolution_limit(int w, int h)
{
- return (w > GPU_texture_size_with_limit(w, limit_gl_texture_size) ||
- h > GPU_texture_size_with_limit(h, limit_gl_texture_size));
+ return (w > GPU_texture_size_with_limit(w) || h > GPU_texture_size_with_limit(h));
}
-static int smaller_power_of_2_limit(int num, bool limit_gl_texture_size)
+static int smaller_power_of_2_limit(int num)
{
- return power_of_2_min_i(GPU_texture_size_with_limit(num, limit_gl_texture_size));
+ return power_of_2_min_i(GPU_texture_size_with_limit(num));
}
-static GPUTexture *gpu_texture_create_tile_mapping(
- Image *ima, const int multiview_eye, const eImageTextureResolution texture_resolution)
+static GPUTexture *gpu_texture_create_tile_mapping(Image *ima, const int multiview_eye)
{
- const int resolution = (texture_resolution == IMA_TEXTURE_RESOLUTION_LIMITED) ? 1 : 0;
- GPUTexture *tilearray = ima->gputexture[TEXTARGET_2D_ARRAY][multiview_eye][resolution];
+ GPUTexture *tilearray = ima->gputexture[TEXTARGET_2D_ARRAY][multiview_eye];
if (tilearray == nullptr) {
return nullptr;
@@ -105,7 +101,7 @@ static GPUTexture *gpu_texture_create_tile_mapping(
}
LISTBASE_FOREACH (ImageTile *, tile, &ima->tiles) {
int i = tile->tile_number - 1001;
- ImageTile_RuntimeTextureSlot *tile_runtime = &tile->runtime.slots[resolution];
+ ImageTile_Runtime *tile_runtime = &tile->runtime;
data[4 * i] = tile_runtime->tilearray_layer;
float *tile_info = &data[4 * width + 4 * i];
@@ -137,12 +133,8 @@ static int compare_packtile(const void *a, const void *b)
return tile_a->pack_score < tile_b->pack_score;
}
-static GPUTexture *gpu_texture_create_tile_array(Image *ima,
- ImBuf *main_ibuf,
- const eImageTextureResolution texture_resolution)
+static GPUTexture *gpu_texture_create_tile_array(Image *ima, ImBuf *main_ibuf)
{
- const bool limit_gl_texture_size = texture_resolution == IMA_TEXTURE_RESOLUTION_LIMITED;
- const int resolution = texture_resolution == IMA_TEXTURE_RESOLUTION_LIMITED ? 1 : 0;
int arraywidth = 0, arrayheight = 0;
ListBase boxes = {nullptr};
@@ -158,10 +150,9 @@ static GPUTexture *gpu_texture_create_tile_array(Image *ima,
packtile->boxpack.w = ibuf->x;
packtile->boxpack.h = ibuf->y;
- if (is_over_resolution_limit(
- packtile->boxpack.w, packtile->boxpack.h, limit_gl_texture_size)) {
- packtile->boxpack.w = smaller_power_of_2_limit(packtile->boxpack.w, limit_gl_texture_size);
- packtile->boxpack.h = smaller_power_of_2_limit(packtile->boxpack.h, limit_gl_texture_size);
+ if (is_over_resolution_limit(packtile->boxpack.w, packtile->boxpack.h)) {
+ packtile->boxpack.w = smaller_power_of_2_limit(packtile->boxpack.w);
+ packtile->boxpack.h = smaller_power_of_2_limit(packtile->boxpack.h);
}
arraywidth = max_ii(arraywidth, packtile->boxpack.w);
arrayheight = max_ii(arrayheight, packtile->boxpack.h);
@@ -188,7 +179,7 @@ static GPUTexture *gpu_texture_create_tile_array(Image *ima,
LISTBASE_FOREACH (PackTile *, packtile, &packed) {
ImageTile *tile = packtile->tile;
- ImageTile_RuntimeTextureSlot *tile_runtime = &tile->runtime.slots[resolution];
+ ImageTile_Runtime *tile_runtime = &tile->runtime;
int *tileoffset = tile_runtime->tilearray_offset;
int *tilesize = tile_runtime->tilearray_size;
@@ -210,7 +201,7 @@ static GPUTexture *gpu_texture_create_tile_array(Image *ima,
/* Upload each tile one by one. */
LISTBASE_FOREACH (ImageTile *, tile, &ima->tiles) {
- ImageTile_RuntimeTextureSlot *tile_runtime = &tile->runtime.slots[resolution];
+ ImageTile_Runtime *tile_runtime = &tile->runtime;
int tilelayer = tile_runtime->tilearray_layer;
int *tileoffset = tile_runtime->tilearray_offset;
int *tilesize = tile_runtime->tilearray_size;
@@ -258,33 +249,16 @@ static GPUTexture *gpu_texture_create_tile_array(Image *ima,
/** \name Regular gpu texture
* \{ */
-static bool image_max_resolution_texture_fits_in_limited_scale(Image *ima,
- eGPUTextureTarget textarget,
- const int multiview_eye)
-{
- BLI_assert_msg(U.glreslimit != 0,
- "limited scale function called without limited scale being set.");
- GPUTexture *max_resolution_texture =
- ima->gputexture[textarget][multiview_eye][IMA_TEXTURE_RESOLUTION_FULL];
- if (max_resolution_texture && GPU_texture_width(max_resolution_texture) <= U.glreslimit &&
- GPU_texture_height(max_resolution_texture) <= U.glreslimit) {
- return true;
- }
- return false;
-}
-
static GPUTexture **get_image_gpu_texture_ptr(Image *ima,
eGPUTextureTarget textarget,
- const int multiview_eye,
- const eImageTextureResolution texture_resolution)
+ const int multiview_eye)
{
const bool in_range = (textarget >= 0) && (textarget < TEXTARGET_COUNT);
BLI_assert(in_range);
BLI_assert(ELEM(multiview_eye, 0, 1));
- const int resolution = (texture_resolution == IMA_TEXTURE_RESOLUTION_LIMITED) ? 1 : 0;
if (in_range) {
- return &(ima->gputexture[textarget][multiview_eye][resolution]);
+ return &(ima->gputexture[textarget][multiview_eye]);
}
return nullptr;
}
@@ -303,21 +277,6 @@ static GPUTexture *image_gpu_texture_error_create(eGPUTextureTarget textarget)
}
}
-static void image_update_reusable_textures(Image *ima,
- eGPUTextureTarget textarget,
- const int multiview_eye)
-{
- if ((ima->gpuflag & IMA_GPU_HAS_LIMITED_SCALE_TEXTURES) == 0) {
- return;
- }
-
- if (ELEM(textarget, TEXTARGET_2D, TEXTARGET_2D_ARRAY)) {
- if (image_max_resolution_texture_fits_in_limited_scale(ima, textarget, multiview_eye)) {
- image_free_gpu_limited_scale(ima);
- }
- }
-}
-
static void image_gpu_texture_partial_update_changes_available(
Image *image, PartialUpdateChecker<ImageTileData>::CollectResult &changes)
{
@@ -412,14 +371,7 @@ static GPUTexture *image_get_gpu_texture(Image *ima,
if (current_view >= 2) {
current_view = 0;
}
- const bool limit_resolution = U.glreslimit != 0 &&
- ((iuser && (iuser->flag & IMA_SHOW_MAX_RESOLUTION) == 0) ||
- (iuser == nullptr)) &&
- ((ima->gpuflag & IMA_GPU_REUSE_MAX_RESOLUTION) == 0);
- const eImageTextureResolution texture_resolution = limit_resolution ?
- IMA_TEXTURE_RESOLUTION_LIMITED :
- IMA_TEXTURE_RESOLUTION_FULL;
- GPUTexture **tex = get_image_gpu_texture_ptr(ima, textarget, current_view, texture_resolution);
+ GPUTexture **tex = get_image_gpu_texture_ptr(ima, textarget, current_view);
if (*tex) {
return *tex;
}
@@ -443,11 +395,10 @@ static GPUTexture *image_get_gpu_texture(Image *ima,
}
if (textarget == TEXTARGET_2D_ARRAY) {
- *tex = gpu_texture_create_tile_array(ima, ibuf_intern, texture_resolution);
+ *tex = gpu_texture_create_tile_array(ima, ibuf_intern);
}
else if (textarget == TEXTARGET_TILE_MAPPING) {
- *tex = gpu_texture_create_tile_mapping(
- ima, iuser ? iuser->multiview_eye : 0, texture_resolution);
+ *tex = gpu_texture_create_tile_mapping(ima, iuser ? iuser->multiview_eye : 0);
}
else {
const bool use_high_bitdepth = (ima->flag & IMA_HIGH_BITDEPTH);
@@ -455,7 +406,7 @@ static GPUTexture *image_get_gpu_texture(Image *ima,
ibuf_intern);
*tex = IMB_create_gpu_texture(
- ima->id.name + 2, ibuf_intern, use_high_bitdepth, store_premultiplied, limit_resolution);
+ ima->id.name + 2, ibuf_intern, use_high_bitdepth, store_premultiplied);
if (*tex) {
GPU_texture_wrap_mode(*tex, true, false);
@@ -473,20 +424,6 @@ static GPUTexture *image_get_gpu_texture(Image *ima,
}
}
- switch (texture_resolution) {
- case IMA_TEXTURE_RESOLUTION_LIMITED:
- ima->gpuflag |= IMA_GPU_HAS_LIMITED_SCALE_TEXTURES;
- break;
-
- case IMA_TEXTURE_RESOLUTION_FULL:
- image_update_reusable_textures(ima, textarget, current_view);
- break;
-
- case IMA_TEXTURE_RESOLUTION_LEN:
- BLI_assert_unreachable();
- break;
- }
-
if (*tex) {
GPU_texture_orig_size_set(*tex, ibuf_intern->x, ibuf_intern->y);
}
@@ -558,39 +495,22 @@ static void image_free_gpu(Image *ima, const bool immediate)
{
for (int eye = 0; eye < 2; eye++) {
for (int i = 0; i < TEXTARGET_COUNT; i++) {
- for (int resolution = 0; resolution < IMA_TEXTURE_RESOLUTION_LEN; resolution++) {
- if (ima->gputexture[i][eye][resolution] != nullptr) {
- if (immediate) {
- GPU_texture_free(ima->gputexture[i][eye][resolution]);
- }
- else {
- BLI_mutex_lock(&gpu_texture_queue_mutex);
- BLI_linklist_prepend(&gpu_texture_free_queue, ima->gputexture[i][eye][resolution]);
- BLI_mutex_unlock(&gpu_texture_queue_mutex);
- }
-
- ima->gputexture[i][eye][resolution] = nullptr;
+ if (ima->gputexture[i][eye] != nullptr) {
+ if (immediate) {
+ GPU_texture_free(ima->gputexture[i][eye]);
+ }
+ else {
+ BLI_mutex_lock(&gpu_texture_queue_mutex);
+ BLI_linklist_prepend(&gpu_texture_free_queue, ima->gputexture[i][eye]);
+ BLI_mutex_unlock(&gpu_texture_queue_mutex);
}
- }
- }
- }
-
- ima->gpuflag &= ~(IMA_GPU_MIPMAP_COMPLETE | IMA_GPU_HAS_LIMITED_SCALE_TEXTURES);
-}
-static void image_free_gpu_limited_scale(Image *ima)
-{
- const eImageTextureResolution resolution = IMA_TEXTURE_RESOLUTION_LIMITED;
- for (int eye = 0; eye < 2; eye++) {
- for (int i = 0; i < TEXTARGET_COUNT; i++) {
- if (ima->gputexture[i][eye][resolution] != nullptr) {
- GPU_texture_free(ima->gputexture[i][eye][resolution]);
- ima->gputexture[i][eye][resolution] = nullptr;
+ ima->gputexture[i][eye] = nullptr;
}
}
}
- ima->gpuflag &= ~(IMA_GPU_MIPMAP_COMPLETE | IMA_GPU_HAS_LIMITED_SCALE_TEXTURES);
+ ima->gpuflag &= ~IMA_GPU_MIPMAP_COMPLETE;
}
void BKE_image_free_gputextures(Image *ima)
@@ -767,20 +687,12 @@ static void gpu_texture_update_unscaled(GPUTexture *tex,
GPU_unpack_row_length_set(0);
}
-static void gpu_texture_update_from_ibuf(GPUTexture *tex,
- Image *ima,
- ImBuf *ibuf,
- ImageTile *tile,
- int x,
- int y,
- int w,
- int h,
- eImageTextureResolution texture_resolution)
+static void gpu_texture_update_from_ibuf(
+ GPUTexture *tex, Image *ima, ImBuf *ibuf, ImageTile *tile, int x, int y, int w, int h)
{
- const int resolution = texture_resolution == IMA_TEXTURE_RESOLUTION_LIMITED ? 1 : 0;
bool scaled;
if (tile != nullptr) {
- ImageTile_RuntimeTextureSlot *tile_runtime = &tile->runtime.slots[resolution];
+ ImageTile_Runtime *tile_runtime = &tile->runtime;
int *tilesize = tile_runtime->tilearray_size;
scaled = (ibuf->x != tilesize[0]) || (ibuf->y != tilesize[1]);
}
@@ -806,12 +718,31 @@ static void gpu_texture_update_from_ibuf(GPUTexture *tex,
int tex_offset = ibuf->channels * (y * ibuf->x + x);
const bool store_premultiplied = BKE_image_has_gpu_texture_premultiplied_alpha(ima, ibuf);
- if (rect_float == nullptr) {
- /* Byte pixels. */
- if (!IMB_colormanagement_space_is_data(ibuf->rect_colorspace)) {
- const bool compress_as_srgb = !IMB_colormanagement_space_is_scene_linear(
- ibuf->rect_colorspace);
+ if (rect_float) {
+ /* Float image is already in scene linear colorspace or non-color data by
+ * convention, no colorspace conversion needed. But we do require 4 channels
+ * currently. */
+ if (ibuf->channels != 4 || scaled || !store_premultiplied) {
+ rect_float = (float *)MEM_mallocN(sizeof(float[4]) * w * h, __func__);
+ if (rect_float == nullptr) {
+ return;
+ }
+
+ tex_stride = w;
+ tex_offset = 0;
+ IMB_colormanagement_imbuf_to_float_texture(
+ rect_float, x, y, w, h, ibuf, store_premultiplied);
+ }
+ }
+ else {
+ /* Byte image is in original colorspace from the file, and may need conversion. */
+ if (IMB_colormanagement_space_is_data(ibuf->rect_colorspace) ||
+ IMB_colormanagement_space_is_scene_linear(ibuf->rect_colorspace)) {
+ /* Non-color data, just store buffer as is. */
+ }
+ else if (IMB_colormanagement_space_is_srgb(ibuf->rect_colorspace)) {
+ /* sRGB or scene linear, store as byte texture that the GPU can decode directly. */
rect = (uchar *)MEM_mallocN(sizeof(uchar[4]) * w * h, __func__);
if (rect == nullptr) {
return;
@@ -822,13 +753,10 @@ static void gpu_texture_update_from_ibuf(GPUTexture *tex,
/* Convert to scene linear with sRGB compression, and premultiplied for
* correct texture interpolation. */
- IMB_colormanagement_imbuf_to_byte_texture(
- rect, x, y, w, h, ibuf, compress_as_srgb, store_premultiplied);
+ IMB_colormanagement_imbuf_to_byte_texture(rect, x, y, w, h, ibuf, store_premultiplied);
}
- }
- else {
- /* Float pixels. */
- if (ibuf->channels != 4 || scaled || !store_premultiplied) {
+ else {
+ /* Other colorspace, store as float texture to avoid precision loss. */
rect_float = (float *)MEM_mallocN(sizeof(float[4]) * w * h, __func__);
if (rect_float == nullptr) {
return;
@@ -845,7 +773,7 @@ static void gpu_texture_update_from_ibuf(GPUTexture *tex,
if (scaled) {
/* Slower update where we first have to scale the input pixels. */
if (tile != nullptr) {
- ImageTile_RuntimeTextureSlot *tile_runtime = &tile->runtime.slots[resolution];
+ ImageTile_Runtime *tile_runtime = &tile->runtime;
int *tileoffset = tile_runtime->tilearray_offset;
int *tilesize = tile_runtime->tilearray_size;
int tilelayer = tile_runtime->tilearray_layer;
@@ -860,7 +788,7 @@ static void gpu_texture_update_from_ibuf(GPUTexture *tex,
else {
/* Fast update at same resolution. */
if (tile != nullptr) {
- ImageTile_RuntimeTextureSlot *tile_runtime = &tile->runtime.slots[resolution];
+ ImageTile_Runtime *tile_runtime = &tile->runtime;
int *tileoffset = tile_runtime->tilearray_offset;
int tilelayer = tile_runtime->tilearray_layer;
gpu_texture_update_unscaled(
@@ -894,19 +822,16 @@ static void image_update_gputexture_ex(
Image *ima, ImageTile *tile, ImBuf *ibuf, int x, int y, int w, int h)
{
const int eye = 0;
- for (int resolution = 0; resolution < IMA_TEXTURE_RESOLUTION_LEN; resolution++) {
- GPUTexture *tex = ima->gputexture[TEXTARGET_2D][eye][resolution];
- eImageTextureResolution texture_resolution = static_cast<eImageTextureResolution>(resolution);
- /* Check if we need to update the main gputexture. */
- if (tex != nullptr && tile == ima->tiles.first) {
- gpu_texture_update_from_ibuf(tex, ima, ibuf, nullptr, x, y, w, h, texture_resolution);
- }
+ GPUTexture *tex = ima->gputexture[TEXTARGET_2D][eye];
+ /* Check if we need to update the main gputexture. */
+ if (tex != nullptr && tile == ima->tiles.first) {
+ gpu_texture_update_from_ibuf(tex, ima, ibuf, nullptr, x, y, w, h);
+ }
- /* Check if we need to update the array gputexture. */
- tex = ima->gputexture[TEXTARGET_2D_ARRAY][eye][resolution];
- if (tex != nullptr) {
- gpu_texture_update_from_ibuf(tex, ima, ibuf, tile, x, y, w, h, texture_resolution);
- }
+ /* Check if we need to update the array gputexture. */
+ tex = ima->gputexture[TEXTARGET_2D_ARRAY][eye];
+ if (tex != nullptr) {
+ gpu_texture_update_from_ibuf(tex, ima, ibuf, tile, x, y, w, h);
}
}
@@ -946,11 +871,9 @@ void BKE_image_paint_set_mipmap(Main *bmain, bool mipmap)
for (int a = 0; a < TEXTARGET_COUNT; a++) {
if (ELEM(a, TEXTARGET_2D, TEXTARGET_2D_ARRAY)) {
for (int eye = 0; eye < 2; eye++) {
- for (int resolution = 0; resolution < IMA_TEXTURE_RESOLUTION_LEN; resolution++) {
- GPUTexture *tex = ima->gputexture[a][eye][resolution];
- if (tex != nullptr) {
- GPU_texture_mipmap_mode(tex, mipmap, true);
- }
+ GPUTexture *tex = ima->gputexture[a][eye];
+ if (tex != nullptr) {
+ GPU_texture_mipmap_mode(tex, mipmap, true);
}
}
}
diff --git a/source/blender/blenkernel/intern/image_save.cc b/source/blender/blenkernel/intern/image_save.cc
index 0d7d238f3b2..9dda3762553 100644
--- a/source/blender/blenkernel/intern/image_save.cc
+++ b/source/blender/blenkernel/intern/image_save.cc
@@ -23,6 +23,7 @@
#include "IMB_openexr.h"
#include "BKE_colortools.h"
+#include "BKE_global.h"
#include "BKE_image.h"
#include "BKE_image_format.h"
#include "BKE_image_save.h"
@@ -34,14 +35,217 @@
using blender::Vector;
-void BKE_image_save_options_init(ImageSaveOptions *opts, Main *bmain, Scene *scene)
+static char imtype_best_depth(ImBuf *ibuf, const char imtype)
{
+ const char depth_ok = BKE_imtype_valid_depths(imtype);
+
+ if (ibuf->rect_float) {
+ if (depth_ok & R_IMF_CHAN_DEPTH_32) {
+ return R_IMF_CHAN_DEPTH_32;
+ }
+ if (depth_ok & R_IMF_CHAN_DEPTH_24) {
+ return R_IMF_CHAN_DEPTH_24;
+ }
+ if (depth_ok & R_IMF_CHAN_DEPTH_16) {
+ return R_IMF_CHAN_DEPTH_16;
+ }
+ if (depth_ok & R_IMF_CHAN_DEPTH_12) {
+ return R_IMF_CHAN_DEPTH_12;
+ }
+ return R_IMF_CHAN_DEPTH_8;
+ }
+
+ if (depth_ok & R_IMF_CHAN_DEPTH_8) {
+ return R_IMF_CHAN_DEPTH_8;
+ }
+ if (depth_ok & R_IMF_CHAN_DEPTH_12) {
+ return R_IMF_CHAN_DEPTH_12;
+ }
+ if (depth_ok & R_IMF_CHAN_DEPTH_16) {
+ return R_IMF_CHAN_DEPTH_16;
+ }
+ if (depth_ok & R_IMF_CHAN_DEPTH_24) {
+ return R_IMF_CHAN_DEPTH_24;
+ }
+ if (depth_ok & R_IMF_CHAN_DEPTH_32) {
+ return R_IMF_CHAN_DEPTH_32;
+ }
+ return R_IMF_CHAN_DEPTH_8; /* fallback, should not get here */
+}
+
+bool BKE_image_save_options_init(ImageSaveOptions *opts,
+ Main *bmain,
+ Scene *scene,
+ Image *ima,
+ ImageUser *iuser,
+ const bool guess_path,
+ const bool save_as_render)
+{
+ /* For saving a tiled image we need an iuser, so use a local one if there isn't already one. */
+ ImageUser save_iuser;
+ if (iuser == nullptr) {
+ BKE_imageuser_default(&save_iuser);
+ iuser = &save_iuser;
+ iuser->scene = scene;
+ }
+
memset(opts, 0, sizeof(*opts));
opts->bmain = bmain;
opts->scene = scene;
+ opts->save_as_render = ima->source == IMA_SRC_VIEWER || save_as_render;
BKE_image_format_init(&opts->im_format, false);
+
+ void *lock;
+ ImBuf *ibuf = BKE_image_acquire_ibuf(ima, iuser, &lock);
+
+ if (ibuf) {
+ Scene *scene = opts->scene;
+ bool is_depth_set = false;
+ const char *ima_colorspace = ima->colorspace_settings.name;
+
+ if (opts->save_as_render) {
+ /* Render/compositor output or user chose to save with render settings. */
+ BKE_image_format_init_for_write(&opts->im_format, scene, nullptr);
+ is_depth_set = true;
+ if (!BKE_image_is_multiview(ima)) {
+ /* In case multiview is disabled,
+ * render settings would be invalid for render result in this area. */
+ opts->im_format.stereo3d_format = *ima->stereo3d_format;
+ opts->im_format.views_format = ima->views_format;
+ }
+ }
+ else {
+ if (ima->source == IMA_SRC_GENERATED) {
+ opts->im_format.imtype = R_IMF_IMTYPE_PNG;
+ opts->im_format.compress = ibuf->foptions.quality;
+ opts->im_format.planes = ibuf->planes;
+ if (!IMB_colormanagement_space_name_is_data(ima_colorspace)) {
+ ima_colorspace = IMB_colormanagement_role_colorspace_name_get(COLOR_ROLE_DEFAULT_BYTE);
+ }
+ }
+ else {
+ BKE_image_format_from_imbuf(&opts->im_format, ibuf);
+ }
+
+ /* use the multiview image settings as the default */
+ opts->im_format.stereo3d_format = *ima->stereo3d_format;
+ opts->im_format.views_format = ima->views_format;
+
+ /* Render output: colorspace from render settings. */
+ BKE_image_format_color_management_copy_from_scene(&opts->im_format, scene);
+ }
+
+ /* Default to saving in the same colorspace as the image setting. */
+ if (!opts->save_as_render) {
+ STRNCPY(opts->im_format.linear_colorspace_settings.name, ima_colorspace);
+ }
+
+ opts->im_format.color_management = R_IMF_COLOR_MANAGEMENT_FOLLOW_SCENE;
+
+ if (ibuf->name[0] == '\0' || 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 */
+
+ /* unlikely but just in case */
+ if (ELEM(opts->im_format.planes, R_IMF_PLANES_BW, R_IMF_PLANES_RGB, R_IMF_PLANES_RGBA) == 0) {
+ opts->im_format.planes = R_IMF_PLANES_RGBA;
+ }
+
+ /* depth, account for float buffer and format support */
+ if (is_depth_set == false) {
+ opts->im_format.depth = imtype_best_depth(ibuf, opts->im_format.imtype);
+ }
+
+ /* some formats don't use quality so fallback to scenes quality */
+ if (opts->im_format.quality == 0) {
+ opts->im_format.quality = scene->r.im_format.quality;
+ }
+
+ /* check for empty path */
+ if (guess_path && opts->filepath[0] == 0) {
+ const bool is_prev_save = !STREQ(G.ima, "//");
+ if (opts->save_as_render) {
+ if (is_prev_save) {
+ BLI_strncpy(opts->filepath, G.ima, sizeof(opts->filepath));
+ }
+ else {
+ BLI_strncpy(opts->filepath, "//untitled", sizeof(opts->filepath));
+ BLI_path_abs(opts->filepath, BKE_main_blendfile_path(bmain));
+ }
+ }
+ else {
+ BLI_snprintf(opts->filepath, sizeof(opts->filepath), "//%s", ima->id.name + 2);
+ BLI_path_make_safe(opts->filepath);
+ BLI_path_abs(opts->filepath, is_prev_save ? G.ima : BKE_main_blendfile_path(bmain));
+ }
+
+ /* append UDIM marker if not present */
+ if (ima->source == IMA_SRC_TILED && strstr(opts->filepath, "<UDIM>") == nullptr) {
+ int len = strlen(opts->filepath);
+ STR_CONCAT(opts->filepath, len, ".<UDIM>");
+ }
+ }
+ }
+
+ /* Copy for detecting UI changes. */
+ opts->prev_save_as_render = opts->save_as_render;
+ opts->prev_imtype = opts->im_format.imtype;
+
+ BKE_image_release_ibuf(ima, ibuf, lock);
+
+ return (ibuf != nullptr);
+}
+
+void BKE_image_save_options_update(ImageSaveOptions *opts, Image *image)
+{
+ /* Auto update color space when changing save as render and file type. */
+ if (opts->save_as_render) {
+ if (!opts->prev_save_as_render) {
+ if (ELEM(image->type, IMA_TYPE_R_RESULT, IMA_TYPE_COMPOSITE)) {
+ BKE_image_format_init_for_write(&opts->im_format, opts->scene, nullptr);
+ }
+ else {
+ BKE_image_format_color_management_copy_from_scene(&opts->im_format, opts->scene);
+ }
+ }
+ }
+ else {
+ if (opts->prev_save_as_render) {
+ /* Copy colorspace from image settings. */
+ BKE_color_managed_colorspace_settings_copy(&opts->im_format.linear_colorspace_settings,
+ &image->colorspace_settings);
+ }
+ else if (opts->im_format.imtype != opts->prev_imtype &&
+ !IMB_colormanagement_space_name_is_data(
+ opts->im_format.linear_colorspace_settings.name)) {
+ const bool linear_float_output = BKE_imtype_requires_linear_float(opts->im_format.imtype);
+
+ /* TODO: detect if the colorspace is linear, not just equal to scene linear. */
+ const bool is_linear = IMB_colormanagement_space_name_is_scene_linear(
+ opts->im_format.linear_colorspace_settings.name);
+
+ /* If changing to a linear float or byte format, ensure we have a compatible color space. */
+ if (linear_float_output && !is_linear) {
+ STRNCPY(opts->im_format.linear_colorspace_settings.name,
+ IMB_colormanagement_role_colorspace_name_get(COLOR_ROLE_DEFAULT_FLOAT));
+ }
+ else if (!linear_float_output && is_linear) {
+ STRNCPY(opts->im_format.linear_colorspace_settings.name,
+ IMB_colormanagement_role_colorspace_name_get(COLOR_ROLE_DEFAULT_BYTE));
+ }
+ }
+ }
+
+ opts->prev_save_as_render = opts->save_as_render;
+ opts->prev_imtype = opts->im_format.imtype;
}
void BKE_image_save_options_free(ImageSaveOptions *opts)
@@ -70,6 +274,12 @@ static void image_save_post(ReportList *reports,
if (opts->do_newpath) {
BLI_strncpy(ibuf->name, filepath, sizeof(ibuf->name));
BLI_strncpy(ima->filepath, filepath, sizeof(ima->filepath));
+
+ /* only image path, never ibuf */
+ if (opts->relative) {
+ const char *relbase = ID_BLEND_PATH(opts->bmain, &ima->id);
+ BLI_path_rel(ima->filepath, relbase); /* only after saving */
+ }
}
ibuf->userflags &= ~IB_BITMAPDIRTY;
@@ -99,18 +309,17 @@ static void image_save_post(ReportList *reports,
ima->type = IMA_TYPE_IMAGE;
}
- /* only image path, never ibuf */
- if (opts->relative) {
- const char *relbase = ID_BLEND_PATH(opts->bmain, &ima->id);
- BLI_path_rel(ima->filepath, relbase); /* only after saving */
- }
+ /* Update image file color space when saving to another color space. */
+ const bool linear_float_output = BKE_imtype_requires_linear_float(opts->im_format.imtype);
- ColorManagedColorspaceSettings old_colorspace_settings;
- BKE_color_managed_colorspace_settings_copy(&old_colorspace_settings, &ima->colorspace_settings);
- IMB_colormanagement_colorspace_from_ibuf_ftype(&ima->colorspace_settings, ibuf);
- if (!BKE_color_managed_colorspace_settings_equals(&old_colorspace_settings,
- &ima->colorspace_settings)) {
- *r_colorspace_changed = true;
+ if (!opts->save_as_render || linear_float_output) {
+ if (opts->im_format.linear_colorspace_settings.name[0] &&
+ !BKE_color_managed_colorspace_settings_equals(
+ &ima->colorspace_settings, &opts->im_format.linear_colorspace_settings)) {
+ BKE_color_managed_colorspace_settings_copy(&ima->colorspace_settings,
+ &opts->im_format.linear_colorspace_settings);
+ *r_colorspace_changed = true;
+ }
}
}
@@ -176,12 +385,12 @@ static bool image_save_single(ReportList *reports,
/* we need renderresult for exr and rendered multiview */
rr = BKE_image_acquire_renderresult(opts->scene, ima);
- bool is_mono = rr ? BLI_listbase_count_at_most(&rr->views, 2) < 2 :
- BLI_listbase_count_at_most(&ima->views, 2) < 2;
- bool is_exr_rr = rr && ELEM(imf->imtype, R_IMF_IMTYPE_OPENEXR, R_IMF_IMTYPE_MULTILAYER) &&
- RE_HasFloatPixels(rr);
- bool is_multilayer = is_exr_rr && (imf->imtype == R_IMF_IMTYPE_MULTILAYER);
- int layer = (iuser && !is_multilayer) ? iuser->layer : -1;
+ const bool is_mono = rr ? BLI_listbase_count_at_most(&rr->views, 2) < 2 :
+ BLI_listbase_count_at_most(&ima->views, 2) < 2;
+ const bool is_exr_rr = rr && ELEM(imf->imtype, R_IMF_IMTYPE_OPENEXR, R_IMF_IMTYPE_MULTILAYER) &&
+ RE_HasFloatPixels(rr);
+ const bool is_multilayer = is_exr_rr && (imf->imtype == R_IMF_IMTYPE_MULTILAYER);
+ const int layer = (iuser && !is_multilayer) ? iuser->layer : -1;
/* error handling */
if (rr == nullptr) {
@@ -366,7 +575,6 @@ static bool image_save_single(ReportList *reports,
colormanaged_ibuf = IMB_colormanagement_imbuf_for_write(ibuf, save_as_render, true, imf);
BKE_image_format_to_imbuf(colormanaged_ibuf, imf);
- IMB_prepare_write_ImBuf(IMB_isfloat(colormanaged_ibuf), colormanaged_ibuf);
/* duplicate buffer to prevent locker issue when using render result */
ibuf_stereo[i] = IMB_dupImBuf(colormanaged_ibuf);
@@ -401,8 +609,13 @@ static bool image_save_single(ReportList *reports,
bool BKE_image_save(
ReportList *reports, Main *bmain, Image *ima, ImageUser *iuser, ImageSaveOptions *opts)
{
+ /* For saving a tiled image we need an iuser, so use a local one if there isn't already one. */
ImageUser save_iuser;
- BKE_imageuser_default(&save_iuser);
+ if (iuser == nullptr) {
+ BKE_imageuser_default(&save_iuser);
+ iuser = &save_iuser;
+ iuser->scene = opts->scene;
+ }
bool colorspace_changed = false;
@@ -419,12 +632,6 @@ bool BKE_image_save(
opts->filepath);
return false;
}
-
- /* For saving a tiled image we need an iuser, so use a local one if there isn't already one.
- */
- if (iuser == nullptr) {
- iuser = &save_iuser;
- }
}
/* Save images */
@@ -600,10 +807,11 @@ bool BKE_image_render_write_exr(ReportList *reports,
const bool pass_half_float = half_float && pass_RGBA;
/* Colorspace conversion only happens on RGBA passes. */
- float *output_rect = (save_as_render && pass_RGBA) ?
- image_exr_from_scene_linear_to_output(
- rp->rect, rr->rectx, rr->recty, 4, imf, tmp_output_rects) :
- rp->rect;
+ float *output_rect =
+ (save_as_render && pass_RGBA) ?
+ image_exr_from_scene_linear_to_output(
+ rp->rect, rr->rectx, rr->recty, rp->channels, imf, tmp_output_rects) :
+ rp->rect;
for (int a = 0; a < rp->channels; a++) {
/* Save Combined as RGBA if single layer save. */
@@ -786,7 +994,6 @@ bool BKE_image_render_write(ReportList *reports,
int view_id = BLI_findstringindex(&rr->views, names[i], offsetof(RenderView, name));
ibuf_arr[i] = RE_render_result_rect_to_ibuf(rr, &image_format, dither, view_id);
IMB_colormanagement_imbuf_for_write(ibuf_arr[i], true, false, &image_format);
- IMB_prepare_write_ImBuf(IMB_isfloat(ibuf_arr[i]), ibuf_arr[i]);
}
ibuf_arr[2] = IMB_stereo3d_ImBuf(&image_format, ibuf_arr[0], ibuf_arr[1]);
diff --git a/source/blender/blenkernel/intern/lib_id.c b/source/blender/blenkernel/intern/lib_id.c
index 27427b1fb44..90a4853fd3e 100644
--- a/source/blender/blenkernel/intern/lib_id.c
+++ b/source/blender/blenkernel/intern/lib_id.c
@@ -263,7 +263,6 @@ void id_us_ensure_real(ID *id)
"ID user count error: %s (from '%s')",
id->name,
id->lib ? id->lib->filepath_abs : "[Main]");
- BLI_assert(0);
}
id->us = limit + 1;
id->tag |= LIB_TAG_EXTRAUSER_SET;
@@ -312,7 +311,7 @@ void id_us_min(ID *id)
const int limit = ID_FAKE_USERS(id);
if (id->us <= limit) {
- if (GS(id->name) != ID_IP) {
+ if (!ID_TYPE_IS_DEPRECATED(GS(id->name))) {
/* Do not assert on deprecated ID types, we cannot really ensure that their ID refcounting
* is valid... */
CLOG_ERROR(&LOG,
@@ -321,7 +320,6 @@ void id_us_min(ID *id)
id->lib ? id->lib->filepath_abs : "[Main]",
id->us,
limit);
- BLI_assert(0);
}
id->us = limit;
}
@@ -592,11 +590,9 @@ static int id_copy_libmanagement_cb(LibraryIDLinkCallbackData *cb_data)
bool BKE_id_copy_is_allowed(const ID *id)
{
-#define LIB_ID_TYPES_NOCOPY \
- ID_LI, ID_SCR, ID_WM, ID_WS, /* Not supported */ \
- ID_IP /* Deprecated */
+#define LIB_ID_TYPES_NOCOPY ID_LI, ID_SCR, ID_WM, ID_WS /* Not supported */
- return !ELEM(GS(id->name), LIB_ID_TYPES_NOCOPY);
+ return !ID_TYPE_IS_DEPRECATED(GS(id->name)) && !ELEM(GS(id->name), LIB_ID_TYPES_NOCOPY);
#undef LIB_ID_TYPES_NOCOPY
}
@@ -2165,7 +2161,7 @@ bool BKE_id_can_be_asset(const ID *id)
BKE_idtype_idcode_is_linkable(GS(id->name));
}
-bool BKE_id_is_editable(Main *bmain, ID *id)
+bool BKE_id_is_editable(const Main *bmain, const ID *id)
{
return !(ID_IS_LINKED(id) || BKE_lib_override_library_is_system_defined(bmain, id));
}
diff --git a/source/blender/blenkernel/intern/lib_id_delete.c b/source/blender/blenkernel/intern/lib_id_delete.c
index 904039d56c8..f14c11a949e 100644
--- a/source/blender/blenkernel/intern/lib_id_delete.c
+++ b/source/blender/blenkernel/intern/lib_id_delete.c
@@ -6,6 +6,8 @@
* Contains management of ID's for freeing & deletion.
*/
+#include "CLG_log.h"
+
#include "MEM_guardedalloc.h"
/* all types are needed here, in order to do memory operations */
@@ -35,8 +37,7 @@
# include "BPY_extern.h"
#endif
-/* Not used currently. */
-// static CLG_LogRef LOG = {.identifier = "bke.lib_id_delete"};
+static CLG_LogRef LOG = {.identifier = "bke.lib_id_delete"};
void BKE_libblock_free_data(ID *id, const bool do_id_user)
{
@@ -334,11 +335,13 @@ static size_t id_delete(Main *bmain, const bool do_tagged_deletion)
for (id = do_tagged_deletion ? tagged_deleted_ids.first : lb->first; id; id = id_next) {
id_next = id->next;
if (id->tag & tag) {
- if (id->us != 0) {
-#ifdef DEBUG_PRINT
- printf("%s: deleting %s (%d)\n", __func__, id->name, id->us);
-#endif
- BLI_assert(id->us == 0);
+ if (((id->tag & LIB_TAG_EXTRAUSER_SET) == 0 && ID_REAL_USERS(id) != 0) ||
+ ((id->tag & LIB_TAG_EXTRAUSER_SET) != 0 && ID_REAL_USERS(id) != 1)) {
+ CLOG_ERROR(&LOG,
+ "Deleting %s which still has %d users (including %d 'extra' shallow users)\n",
+ id->name,
+ ID_REAL_USERS(id),
+ (id->tag & LIB_TAG_EXTRAUSER_SET) != 0 ? 1 : 0);
}
BKE_id_free_ex(bmain, id, free_flag, !do_tagged_deletion);
++num_datablocks_deleted;
diff --git a/source/blender/blenkernel/intern/lib_override.c b/source/blender/blenkernel/intern/lib_override.cc
index a2338eb9b39..22012662180 100644
--- a/source/blender/blenkernel/intern/lib_override.c
+++ b/source/blender/blenkernel/intern/lib_override.cc
@@ -5,8 +5,8 @@
* \ingroup bke
*/
-#include <stdlib.h>
-#include <string.h>
+#include <cstdlib>
+#include <cstring>
#include "CLG_log.h"
@@ -21,8 +21,10 @@
#include "DEG_depsgraph.h"
#include "DEG_depsgraph_build.h"
+#include "BKE_anim_data.h"
#include "BKE_armature.h"
#include "BKE_collection.h"
+#include "BKE_fcurve.h"
#include "BKE_global.h"
#include "BKE_idtype.h"
#include "BKE_key.h"
@@ -72,17 +74,36 @@ static void lib_override_library_property_clear(IDOverrideLibraryProperty *op);
static void lib_override_library_property_operation_clear(
IDOverrideLibraryPropertyOperation *opop);
+/** Helper to preserve Pose mode on override objects.
+ * A bit annoying to have this special case, but not much to be done here currently, since the
+ * matching RNA property is read-only. */
+BLI_INLINE void lib_override_object_posemode_transfer(ID *id_dst, ID *id_src)
+{
+ if (GS(id_src->name) == ID_OB && GS(id_dst->name) == ID_OB) {
+ Object *ob_src = (Object *)id_src;
+ Object *ob_dst = (Object *)id_dst;
+ if (ob_src->type == OB_ARMATURE && (ob_src->mode & OB_MODE_POSE) != 0) {
+ ob_dst->restore_mode = ob_dst->mode;
+ ob_dst->mode |= OB_MODE_POSE;
+ }
+ }
+}
+
/** Get override data for a given ID. Needed because of our beloved shape keys snowflake. */
-BLI_INLINE IDOverrideLibrary *lib_override_get(Main *bmain, ID *id, ID **r_owner_id)
+BLI_INLINE const IDOverrideLibrary *lib_override_get(const Main *bmain,
+ const ID *id,
+ const ID **r_owner_id)
{
- if (r_owner_id != NULL) {
+ if (r_owner_id != nullptr) {
*r_owner_id = id;
}
if (id->flag & LIB_EMBEDDED_DATA_LIB_OVERRIDE) {
const IDTypeInfo *id_type = BKE_idtype_get_info_from_id(id);
- if (id_type->owner_get != NULL) {
- ID *owner_id = id_type->owner_get(bmain, id);
- if (r_owner_id != NULL) {
+ if (id_type->owner_get != nullptr) {
+ /* The #IDTypeInfo::owner_get callback should not modify the arguments, so casting away const
+ * is okay. */
+ const ID *owner_id = id_type->owner_get(const_cast<Main *>(bmain), const_cast<ID *>(id));
+ if (r_owner_id != nullptr) {
*r_owner_id = owner_id;
}
return owner_id->override_library;
@@ -92,21 +113,31 @@ BLI_INLINE IDOverrideLibrary *lib_override_get(Main *bmain, ID *id, ID **r_owner
return id->override_library;
}
+BLI_INLINE IDOverrideLibrary *lib_override_get(Main *bmain, ID *id, ID **r_owner_id)
+{
+ /* Reuse the implementation of the const access function, which does not change the arguments.
+ * Add const explicitly to make it clear to the compiler to avoid just calling this function. */
+ return const_cast<IDOverrideLibrary *>(lib_override_get(const_cast<const Main *>(bmain),
+ const_cast<const ID *>(id),
+ const_cast<const ID **>(r_owner_id)));
+}
+
IDOverrideLibrary *BKE_lib_override_library_init(ID *local_id, ID *reference_id)
{
- /* If reference_id is NULL, we are creating an override template for purely local data.
+ /* If reference_id is nullptr, we are creating an override template for purely local data.
* Else, reference *must* be linked data. */
- BLI_assert(reference_id == NULL || ID_IS_LINKED(reference_id));
- BLI_assert(local_id->override_library == NULL);
+ BLI_assert(reference_id == nullptr || ID_IS_LINKED(reference_id));
+ BLI_assert(local_id->override_library == nullptr);
ID *ancestor_id;
- for (ancestor_id = reference_id; ancestor_id != NULL && ancestor_id->override_library != NULL &&
- ancestor_id->override_library->reference != NULL;
+ for (ancestor_id = reference_id;
+ ancestor_id != nullptr && ancestor_id->override_library != nullptr &&
+ ancestor_id->override_library->reference != nullptr;
ancestor_id = ancestor_id->override_library->reference) {
/* pass */
}
- if (ancestor_id != NULL && ancestor_id->override_library != NULL) {
+ if (ancestor_id != nullptr && ancestor_id->override_library != nullptr) {
/* Original ID has a template, use it! */
BKE_lib_override_library_copy(local_id, ancestor_id, true);
if (local_id->override_library->reference != reference_id) {
@@ -118,7 +149,7 @@ IDOverrideLibrary *BKE_lib_override_library_init(ID *local_id, ID *reference_id)
}
/* Else, generate new empty override. */
- local_id->override_library = MEM_callocN(sizeof(*local_id->override_library), __func__);
+ local_id->override_library = MEM_cnew<IDOverrideLibrary>(__func__);
local_id->override_library->reference = reference_id;
id_us_plus(local_id->override_library->reference);
local_id->tag &= ~LIB_TAG_OVERRIDE_LIBRARY_REFOK;
@@ -133,20 +164,20 @@ void BKE_lib_override_library_copy(ID *dst_id, const ID *src_id, const bool do_f
{
BLI_assert(ID_IS_OVERRIDE_LIBRARY(src_id) || ID_IS_OVERRIDE_LIBRARY_TEMPLATE(src_id));
- if (dst_id->override_library != NULL) {
- if (src_id->override_library == NULL) {
+ if (dst_id->override_library != nullptr) {
+ if (src_id->override_library == nullptr) {
BKE_lib_override_library_free(&dst_id->override_library, true);
return;
}
BKE_lib_override_library_clear(dst_id->override_library, true);
}
- else if (src_id->override_library == NULL) {
+ else if (src_id->override_library == nullptr) {
/* Virtual overrides of embedded data does not require any extra work. */
return;
}
else {
- BKE_lib_override_library_init(dst_id, NULL);
+ BKE_lib_override_library_init(dst_id, nullptr);
}
/* If source is already overriding data, we copy it but reuse its reference for dest ID.
@@ -162,8 +193,10 @@ void BKE_lib_override_library_copy(ID *dst_id, const ID *src_id, const bool do_f
if (do_full_copy) {
BLI_duplicatelist(&dst_id->override_library->properties,
&src_id->override_library->properties);
- for (IDOverrideLibraryProperty *op_dst = dst_id->override_library->properties.first,
- *op_src = src_id->override_library->properties.first;
+ for (IDOverrideLibraryProperty *op_dst = static_cast<IDOverrideLibraryProperty *>(
+ dst_id->override_library->properties.first),
+ *op_src = static_cast<IDOverrideLibraryProperty *>(
+ src_id->override_library->properties.first);
op_dst;
op_dst = op_dst->next, op_src = op_src->next) {
lib_override_library_property_copy(op_dst, op_src);
@@ -175,10 +208,10 @@ void BKE_lib_override_library_copy(ID *dst_id, const ID *src_id, const bool do_f
void BKE_lib_override_library_clear(IDOverrideLibrary *override, const bool do_id_user)
{
- BLI_assert(override != NULL);
+ BLI_assert(override != nullptr);
- if (!ELEM(NULL, override->runtime, override->runtime->rna_path_to_override_properties)) {
- BLI_ghash_clear(override->runtime->rna_path_to_override_properties, NULL, NULL);
+ if (!ELEM(nullptr, override->runtime, override->runtime->rna_path_to_override_properties)) {
+ BLI_ghash_clear(override->runtime->rna_path_to_override_properties, nullptr, nullptr);
}
LISTBASE_FOREACH (IDOverrideLibraryProperty *, op, &override->properties) {
@@ -192,20 +225,20 @@ void BKE_lib_override_library_clear(IDOverrideLibrary *override, const bool do_i
}
}
-void BKE_lib_override_library_free(struct IDOverrideLibrary **override, const bool do_id_user)
+void BKE_lib_override_library_free(IDOverrideLibrary **override, const bool do_id_user)
{
- BLI_assert(*override != NULL);
+ BLI_assert(*override != nullptr);
- if ((*override)->runtime != NULL) {
- if ((*override)->runtime->rna_path_to_override_properties != NULL) {
- BLI_ghash_free((*override)->runtime->rna_path_to_override_properties, NULL, NULL);
+ if ((*override)->runtime != nullptr) {
+ if ((*override)->runtime->rna_path_to_override_properties != nullptr) {
+ BLI_ghash_free((*override)->runtime->rna_path_to_override_properties, nullptr, nullptr);
}
MEM_SAFE_FREE((*override)->runtime);
}
BKE_lib_override_library_clear(*override, do_id_user);
MEM_freeN(*override);
- *override = NULL;
+ *override = nullptr;
}
static ID *lib_override_library_create_from(Main *bmain,
@@ -217,12 +250,12 @@ static ID *lib_override_library_create_from(Main *bmain,
* override template, or already an override of some other ref data). */
ID *local_id = BKE_id_copy_ex(bmain,
reference_id,
- NULL,
+ nullptr,
LIB_ID_COPY_DEFAULT | LIB_ID_COPY_NO_LIB_OVERRIDE |
lib_id_copy_flags);
- if (local_id == NULL) {
- return NULL;
+ if (local_id == nullptr) {
+ return nullptr;
}
id_us_min(local_id);
@@ -238,9 +271,9 @@ static ID *lib_override_library_create_from(Main *bmain,
* data-blocks, just like root node trees or master collections. Therefore, we never need to
* create overrides for them. We need a way to mark them as overrides though. */
Key *reference_key;
- if ((reference_key = BKE_key_from_id(reference_id)) != NULL) {
+ if ((reference_key = BKE_key_from_id(reference_id)) != nullptr) {
Key *local_key = BKE_key_from_id(local_id);
- BLI_assert(local_key != NULL);
+ BLI_assert(local_key != nullptr);
local_key->id.flag |= LIB_EMBEDDED_DATA_LIB_OVERRIDE;
}
@@ -249,7 +282,7 @@ static ID *lib_override_library_create_from(Main *bmain,
/* TODO: This could be simplified by storing a flag in #IDOverrideLibrary
* during the diffing process? */
-bool BKE_lib_override_library_is_user_edited(struct ID *id)
+bool BKE_lib_override_library_is_user_edited(const ID *id)
{
if (!ID_IS_OVERRIDE_LIBRARY(id)) {
@@ -263,8 +296,8 @@ bool BKE_lib_override_library_is_user_edited(struct ID *id)
return false;
}
- LISTBASE_FOREACH (IDOverrideLibraryProperty *, op, &id->override_library->properties) {
- LISTBASE_FOREACH (IDOverrideLibraryPropertyOperation *, opop, &op->operations) {
+ LISTBASE_FOREACH (const IDOverrideLibraryProperty *, op, &id->override_library->properties) {
+ LISTBASE_FOREACH (const IDOverrideLibraryPropertyOperation *, opop, &op->operations) {
if ((opop->flag & IDOVERRIDE_LIBRARY_FLAG_IDPOINTER_MATCH_REFERENCE) != 0) {
continue;
}
@@ -279,11 +312,10 @@ bool BKE_lib_override_library_is_user_edited(struct ID *id)
return false;
}
-bool BKE_lib_override_library_is_system_defined(Main *bmain, ID *id)
+bool BKE_lib_override_library_is_system_defined(const Main *bmain, const ID *id)
{
-
if (ID_IS_OVERRIDE_LIBRARY(id)) {
- ID *override_owner_id;
+ const ID *override_owner_id;
lib_override_get(bmain, id, &override_owner_id);
return (override_owner_id->override_library->flag & IDOVERRIDE_LIBRARY_FLAG_SYSTEM_DEFINED) !=
0;
@@ -291,13 +323,41 @@ bool BKE_lib_override_library_is_system_defined(Main *bmain, ID *id)
return false;
}
+bool BKE_lib_override_library_property_is_animated(const ID *id,
+ const IDOverrideLibraryProperty *override_prop,
+ const PropertyRNA *override_rna_prop,
+ const int rnaprop_index)
+{
+ AnimData *anim_data = BKE_animdata_from_id(id);
+ if (anim_data != nullptr) {
+ struct FCurve *fcurve;
+ char *index_token_start = const_cast<char *>(
+ RNA_path_array_index_token_find(override_prop->rna_path, override_rna_prop));
+ if (index_token_start != nullptr) {
+ const char index_token_start_backup = *index_token_start;
+ *index_token_start = '\0';
+ fcurve = BKE_animadata_fcurve_find_by_rna_path(
+ anim_data, override_prop->rna_path, rnaprop_index, nullptr, nullptr);
+ *index_token_start = index_token_start_backup;
+ }
+ else {
+ fcurve = BKE_animadata_fcurve_find_by_rna_path(
+ anim_data, override_prop->rna_path, 0, nullptr, nullptr);
+ }
+ if (fcurve != nullptr) {
+ return true;
+ }
+ }
+ return false;
+}
+
static int foreachid_is_hierarchy_leaf_fn(LibraryIDLinkCallbackData *cb_data)
{
ID *id_owner = cb_data->id_owner;
ID *id = *cb_data->id_pointer;
- bool *is_leaf = cb_data->user_data;
+ bool *is_leaf = static_cast<bool *>(cb_data->user_data);
- if (id != NULL && ID_IS_OVERRIDE_LIBRARY_REAL(id) &&
+ if (id != nullptr && ID_IS_OVERRIDE_LIBRARY_REAL(id) &&
id->override_library->hierarchy_root == id_owner->override_library->hierarchy_root) {
*is_leaf = false;
return IDWALK_RET_STOP_ITER;
@@ -321,10 +381,10 @@ ID *BKE_lib_override_library_create_from_id(Main *bmain,
ID *reference_id,
const bool do_tagged_remap)
{
- BLI_assert(reference_id != NULL);
+ BLI_assert(reference_id != nullptr);
BLI_assert(ID_IS_LINKED(reference_id));
- ID *local_id = lib_override_library_create_from(bmain, NULL, reference_id, 0);
+ ID *local_id = lib_override_library_create_from(bmain, nullptr, 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. */
@@ -333,10 +393,10 @@ ID *BKE_lib_override_library_create_from_id(Main *bmain,
local_id->override_library->hierarchy_root = local_id;
if (do_tagged_remap) {
- Key *reference_key, *local_key = NULL;
- if ((reference_key = BKE_key_from_id(reference_id)) != NULL) {
+ Key *reference_key, *local_key = nullptr;
+ if ((reference_key = BKE_key_from_id(reference_id)) != nullptr) {
local_key = BKE_key_from_id(local_id);
- BLI_assert(local_key != NULL);
+ BLI_assert(local_key != nullptr);
}
ID *other_id;
@@ -349,7 +409,7 @@ ID *BKE_lib_override_library_create_from_id(Main *bmain,
reference_id,
local_id,
ID_REMAP_SKIP_INDIRECT_USAGE | ID_REMAP_SKIP_OVERRIDE_LIBRARY);
- if (reference_key != NULL) {
+ if (reference_key != nullptr) {
BKE_libblock_relink_ex(bmain,
other_id,
&reference_key->id,
@@ -383,18 +443,19 @@ bool BKE_lib_override_library_create_from_tag(Main *bmain,
const ID *id_root_reference,
ID *id_hierarchy_root,
const ID *id_hierarchy_root_reference,
- const bool do_no_main)
+ const bool do_no_main,
+ const bool do_fully_editable)
{
- BLI_assert(id_root_reference != NULL && ID_IS_LINKED(id_root_reference));
+ BLI_assert(id_root_reference != nullptr && ID_IS_LINKED(id_root_reference));
/* If we do not have any hierarchy root given, then the root reference must be tagged for
* override. */
- BLI_assert(id_hierarchy_root != NULL || id_hierarchy_root_reference != NULL ||
+ BLI_assert(id_hierarchy_root != nullptr || id_hierarchy_root_reference != nullptr ||
(id_root_reference->tag & LIB_TAG_DOIT) != 0);
- /* At least one of the hierarchy root pointers must be NULL, passing both is useless and can
+ /* At least one of the hierarchy root pointers must be nullptr, passing both is useless and can
* create confusion. */
- BLI_assert(ELEM(NULL, id_hierarchy_root, id_hierarchy_root_reference));
+ BLI_assert(ELEM(nullptr, id_hierarchy_root, id_hierarchy_root_reference));
- if (id_hierarchy_root != NULL) {
+ if (id_hierarchy_root != nullptr) {
/* If the hierarchy root is given, it must be a valid existing override (used during partial
* resync process mainly). */
BLI_assert((ID_IS_OVERRIDE_LIBRARY_REAL(id_hierarchy_root) &&
@@ -407,7 +468,7 @@ bool BKE_lib_override_library_create_from_tag(Main *bmain,
lib_override_prefill_newid_from_existing_overrides(bmain, id_hierarchy_root);
}
}
- if (!ELEM(id_hierarchy_root_reference, NULL, id_root_reference)) {
+ if (!ELEM(id_hierarchy_root_reference, nullptr, id_root_reference)) {
/* If the reference hierarchy root is given, it must be from the same library as the reference
* root, and also tagged for override. */
BLI_assert((id_hierarchy_root_reference->lib == id_root_reference->lib &&
@@ -419,14 +480,14 @@ bool BKE_lib_override_library_create_from_tag(Main *bmain,
ID *reference_id;
bool success = true;
- ListBase todo_ids = {NULL};
+ ListBase todo_ids = {nullptr};
LinkData *todo_id_iter;
/* Get all IDs we want to override. */
FOREACH_MAIN_ID_BEGIN (bmain, reference_id) {
if ((reference_id->tag & LIB_TAG_DOIT) != 0 && reference_id->lib == reference_library &&
BKE_idtype_idcode_is_linkable(GS(reference_id->name))) {
- todo_id_iter = MEM_callocN(sizeof(*todo_id_iter), __func__);
+ todo_id_iter = MEM_cnew<LinkData>(__func__);
todo_id_iter->data = reference_id;
BLI_addtail(&todo_ids, todo_id_iter);
}
@@ -434,31 +495,35 @@ bool BKE_lib_override_library_create_from_tag(Main *bmain,
FOREACH_MAIN_ID_END;
/* Override the IDs. */
- for (todo_id_iter = todo_ids.first; todo_id_iter != NULL; todo_id_iter = todo_id_iter->next) {
- reference_id = todo_id_iter->data;
+ for (todo_id_iter = static_cast<LinkData *>(todo_ids.first); todo_id_iter != nullptr;
+ todo_id_iter = todo_id_iter->next) {
+ reference_id = static_cast<ID *>(todo_id_iter->data);
/* If `newid` is already set, assume it has been handled by calling code.
* Only current use case: re-using proxy ID when converting to liboverride. */
- if (reference_id->newid == NULL) {
+ if (reference_id->newid == nullptr) {
/* NOTE: `no main` case is used during resync procedure, to support recursive resync.
* This requires extra care further down the resync process,
* see: #BKE_lib_override_library_resync. */
reference_id->newid = lib_override_library_create_from(
bmain, owner_library, reference_id, do_no_main ? LIB_ID_CREATE_NO_MAIN : 0);
- if (reference_id->newid == NULL) {
+ if (reference_id->newid == nullptr) {
success = false;
break;
}
+ if (do_fully_editable) {
+ reference_id->newid->override_library->flag &= ~IDOVERRIDE_LIBRARY_FLAG_SYSTEM_DEFINED;
+ }
}
/* We also tag the new IDs so that in next step we can remap their pointers too. */
reference_id->newid->tag |= LIB_TAG_DOIT;
Key *reference_key;
- if ((reference_key = BKE_key_from_id(reference_id)) != NULL) {
+ if ((reference_key = BKE_key_from_id(reference_id)) != nullptr) {
reference_key->id.tag |= LIB_TAG_DOIT;
Key *local_key = BKE_key_from_id(reference_id->newid);
- BLI_assert(local_key != NULL);
+ BLI_assert(local_key != nullptr);
reference_key->id.newid = &local_key->id;
/* We also tag the new IDs so that in next step we can remap their pointers too. */
local_key->id.tag |= LIB_TAG_DOIT;
@@ -468,17 +533,17 @@ bool BKE_lib_override_library_create_from_tag(Main *bmain,
/* Only remap new local ID's pointers, we don't want to force our new overrides onto our whole
* existing linked IDs usages. */
if (success) {
- if (id_hierarchy_root_reference != NULL) {
+ if (id_hierarchy_root_reference != nullptr) {
id_hierarchy_root = id_hierarchy_root_reference->newid;
}
- else if (id_root_reference->newid != NULL &&
- (id_hierarchy_root == NULL ||
+ else if (id_root_reference->newid != nullptr &&
+ (id_hierarchy_root == nullptr ||
id_hierarchy_root->override_library->reference == id_root_reference)) {
id_hierarchy_root = id_root_reference->newid;
}
- BLI_assert(id_hierarchy_root != NULL);
+ BLI_assert(id_hierarchy_root != nullptr);
- LinkNode *relinked_ids = NULL;
+ LinkNode *relinked_ids = nullptr;
/* Still checking the whole Main, that way we can tag other local IDs as needing to be
* remapped to use newly created overriding IDs, if needed. */
ID *id;
@@ -486,14 +551,14 @@ bool BKE_lib_override_library_create_from_tag(Main *bmain,
ID *other_id;
/* In case we created new overrides as 'no main', they are not accessible directly in this
* loop, but we can get to them through their reference's `newid` pointer. */
- if (do_no_main && id->lib == id_root_reference->lib && id->newid != NULL) {
+ if (do_no_main && id->lib == id_root_reference->lib && id->newid != nullptr) {
other_id = id->newid;
/* Otherwise we cannot properly distinguish between IDs that are actually from the
* linked library (and should not be remapped), and IDs that are overrides re-generated
* from the reference from the linked library, and must therefore be remapped.
*
* This is reset afterwards at the end of this loop. */
- other_id->lib = NULL;
+ other_id->lib = nullptr;
}
else {
other_id = id;
@@ -510,12 +575,13 @@ bool BKE_lib_override_library_create_from_tag(Main *bmain,
}
FOREACH_MAIN_ID_END;
- struct IDRemapper *id_remapper = BKE_id_remapper_create();
- for (todo_id_iter = todo_ids.first; todo_id_iter != NULL; todo_id_iter = todo_id_iter->next) {
- reference_id = todo_id_iter->data;
+ IDRemapper *id_remapper = BKE_id_remapper_create();
+ for (todo_id_iter = static_cast<LinkData *>(todo_ids.first); todo_id_iter != nullptr;
+ todo_id_iter = todo_id_iter->next) {
+ reference_id = static_cast<ID *>(todo_id_iter->data);
ID *local_id = reference_id->newid;
- if (local_id == NULL) {
+ if (local_id == nullptr) {
continue;
}
@@ -523,10 +589,10 @@ bool BKE_lib_override_library_create_from_tag(Main *bmain,
BKE_id_remapper_add(id_remapper, reference_id, local_id);
- Key *reference_key, *local_key = NULL;
- if ((reference_key = BKE_key_from_id(reference_id)) != NULL) {
+ Key *reference_key, *local_key = nullptr;
+ if ((reference_key = BKE_key_from_id(reference_id)) != nullptr) {
local_key = BKE_key_from_id(reference_id->newid);
- BLI_assert(local_key != NULL);
+ BLI_assert(local_key != nullptr);
BKE_id_remapper_add(id_remapper, &reference_key->id, &local_key->id);
}
@@ -539,14 +605,15 @@ bool BKE_lib_override_library_create_from_tag(Main *bmain,
ID_REMAP_SKIP_OVERRIDE_LIBRARY | ID_REMAP_FORCE_USER_REFCOUNT);
BKE_id_remapper_free(id_remapper);
- BLI_linklist_free(relinked_ids, NULL);
+ BLI_linklist_free(relinked_ids, nullptr);
}
else {
/* We need to cleanup potentially already created data. */
- for (todo_id_iter = todo_ids.first; todo_id_iter != NULL; todo_id_iter = todo_id_iter->next) {
- reference_id = todo_id_iter->data;
+ for (todo_id_iter = static_cast<LinkData *>(todo_ids.first); todo_id_iter != nullptr;
+ todo_id_iter = todo_id_iter->next) {
+ reference_id = static_cast<ID *>(todo_id_iter->data);
BKE_id_delete(bmain, reference_id->newid);
- reference_id->newid = NULL;
+ reference_id->newid = nullptr;
}
}
@@ -555,7 +622,7 @@ bool BKE_lib_override_library_create_from_tag(Main *bmain,
return success;
}
-typedef struct LibOverrideGroupTagData {
+struct LibOverrideGroupTagData {
Main *bmain;
Scene *scene;
ID *id_root;
@@ -571,7 +638,7 @@ typedef struct LibOverrideGroupTagData {
* 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)
@@ -586,8 +653,8 @@ static void lib_override_group_tag_data_object_to_collection_init_collection_pro
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));
+ *collections_linkedlist_p = static_cast<LinkNodePair *>(
+ BLI_memarena_calloc(data->mem_arena, sizeof(**collections_linkedlist_p)));
}
BLI_linklist_append_arena(*collections_linkedlist_p, collection, data->mem_arena);
}
@@ -604,7 +671,7 @@ static void lib_override_group_tag_data_object_to_collection_init(LibOverrideGro
data->linked_object_to_instantiating_collections = BLI_ghash_new(
BLI_ghashutil_ptrhash, BLI_ghashutil_ptrcmp, __func__);
- if (data->scene != NULL) {
+ if (data->scene != nullptr) {
lib_override_group_tag_data_object_to_collection_init_collection_process(
data, data->scene->master_collection);
}
@@ -615,7 +682,7 @@ static void lib_override_group_tag_data_object_to_collection_init(LibOverrideGro
static void lib_override_group_tag_data_clear(LibOverrideGroupTagData *data)
{
- BLI_ghash_free(data->linked_object_to_instantiating_collections, NULL, NULL);
+ BLI_ghash_free(data->linked_object_to_instantiating_collections, nullptr, nullptr);
BLI_memarena_free(data->mem_arena);
memset(data, 0, sizeof(*data));
}
@@ -632,8 +699,9 @@ static bool lib_override_hierarchy_dependencies_recursive_tag(LibOverrideGroupTa
ID *id = data->id_root;
const bool is_override = data->is_override;
- MainIDRelationsEntry *entry = BLI_ghash_lookup(bmain->relations->relations_from_pointers, id);
- BLI_assert(entry != NULL);
+ MainIDRelationsEntry *entry = static_cast<MainIDRelationsEntry *>(
+ BLI_ghash_lookup(bmain->relations->relations_from_pointers, id));
+ BLI_assert(entry != nullptr);
if (entry->tags & MAINIDRELATIONS_ENTRY_TAGS_PROCESSED) {
/* This ID has already been processed. */
@@ -643,7 +711,7 @@ static bool lib_override_hierarchy_dependencies_recursive_tag(LibOverrideGroupTa
* relationship hierarchy. */
entry->tags |= MAINIDRELATIONS_ENTRY_TAGS_PROCESSED;
- for (MainIDRelationsEntryItem *to_id_entry = entry->to_ids; to_id_entry != NULL;
+ for (MainIDRelationsEntryItem *to_id_entry = entry->to_ids; to_id_entry != nullptr;
to_id_entry = to_id_entry->next) {
if ((to_id_entry->usage_flag & IDWALK_CB_OVERRIDE_LIBRARY_NOT_OVERRIDABLE) != 0) {
/* Never consider non-overridable relationships ('from', 'parents', 'owner' etc. pointers) as
@@ -652,7 +720,7 @@ static bool lib_override_hierarchy_dependencies_recursive_tag(LibOverrideGroupTa
}
/* We only consider IDs from the same library. */
ID *to_id = *to_id_entry->id_pointer.to;
- if (to_id == NULL || to_id->lib != id->lib ||
+ if (to_id == nullptr || to_id->lib != id->lib ||
(is_override && !ID_IS_OVERRIDE_LIBRARY(to_id))) {
/* IDs from different libraries, or non-override IDs in case we are processing overrides, are
* both barriers of dependency. */
@@ -677,9 +745,9 @@ static void lib_override_linked_group_tag_recursive(LibOverrideGroupTagData *dat
const uint tag = data->tag;
const uint missing_tag = data->missing_tag;
- MainIDRelationsEntry *entry = BLI_ghash_lookup(bmain->relations->relations_from_pointers,
- id_owner);
- BLI_assert(entry != NULL);
+ MainIDRelationsEntry *entry = static_cast<MainIDRelationsEntry *>(
+ BLI_ghash_lookup(bmain->relations->relations_from_pointers, id_owner));
+ BLI_assert(entry != nullptr);
if (entry->tags & MAINIDRELATIONS_ENTRY_TAGS_PROCESSED) {
/* This ID has already been processed. */
@@ -689,7 +757,7 @@ static void lib_override_linked_group_tag_recursive(LibOverrideGroupTagData *dat
* relationship hierarchy. */
entry->tags |= MAINIDRELATIONS_ENTRY_TAGS_PROCESSED;
- for (MainIDRelationsEntryItem *to_id_entry = entry->to_ids; to_id_entry != NULL;
+ for (MainIDRelationsEntryItem *to_id_entry = entry->to_ids; to_id_entry != nullptr;
to_id_entry = to_id_entry->next) {
if ((to_id_entry->usage_flag & IDWALK_CB_OVERRIDE_LIBRARY_NOT_OVERRIDABLE) != 0) {
/* Never consider non-overridable relationships as actual dependencies. */
@@ -697,7 +765,7 @@ static void lib_override_linked_group_tag_recursive(LibOverrideGroupTagData *dat
}
ID *to_id = *to_id_entry->id_pointer.to;
- if (ELEM(to_id, NULL, id_owner)) {
+ if (ELEM(to_id, nullptr, id_owner)) {
continue;
}
/* We only consider IDs from the same library. */
@@ -732,10 +800,12 @@ static bool lib_override_linked_group_tag_collections_keep_tagged_check_recursiv
* is not usable here, as it may have become invalid from some previous operation and it should
* not be updated here. So instead only use collections' reliable 'raw' data to check if some
* object in the hierarchy of the given collection is still tagged for override. */
- for (CollectionObject *collection_object = collection->gobject.first; collection_object != NULL;
+ for (CollectionObject *collection_object =
+ static_cast<CollectionObject *>(collection->gobject.first);
+ collection_object != nullptr;
collection_object = collection_object->next) {
Object *object = collection_object->ob;
- if (object == NULL) {
+ if (object == nullptr) {
continue;
}
if ((object->id.tag & data->tag) != 0) {
@@ -743,7 +813,9 @@ static bool lib_override_linked_group_tag_collections_keep_tagged_check_recursiv
}
}
- for (CollectionChild *collection_child = collection->children.first; collection_child != NULL;
+ for (CollectionChild *collection_child =
+ static_cast<CollectionChild *>(collection->children.first);
+ collection_child != nullptr;
collection_child = collection_child->next) {
if (lib_override_linked_group_tag_collections_keep_tagged_check_recursive(
data, collection_child->collection)) {
@@ -757,13 +829,16 @@ static bool lib_override_linked_group_tag_collections_keep_tagged_check_recursiv
static void lib_override_linked_group_tag_clear_boneshapes_objects(LibOverrideGroupTagData *data)
{
Main *bmain = data->bmain;
+ ID *id_root = data->id_root;
/* 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) {
+ if (ob->type == OB_ARMATURE && ob->pose != nullptr && (ob->id.tag & data->tag)) {
+ for (bPoseChannel *pchan = static_cast<bPoseChannel *>(ob->pose->chanbase.first);
+ pchan != nullptr;
+ pchan = pchan->next) {
+ if (pchan->custom != nullptr && &pchan->custom->id != id_root) {
pchan->custom->id.tag &= ~data->tag;
}
}
@@ -773,7 +848,7 @@ static void lib_override_linked_group_tag_clear_boneshapes_objects(LibOverrideGr
/* 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) {
+ if ((collection->id.tag & data->tag) == 0 || &collection->id == id_root) {
continue;
}
@@ -840,17 +915,18 @@ static void lib_override_linked_group_tag(LibOverrideGroupTagData *data)
}
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;
+ Collection *instantiating_collection = nullptr;
+ Collection *instantiating_collection_override_candidate = nullptr;
/* 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) {
+ LinkNodePair *instantiating_collection_linklist = static_cast<LinkNodePair *>(
+ BLI_ghash_lookup(data->linked_object_to_instantiating_collections, ob));
+ if (instantiating_collection_linklist != nullptr) {
for (LinkNode *instantiating_collection_linknode = instantiating_collection_linklist->list;
- instantiating_collection_linknode != NULL;
+ instantiating_collection_linknode != nullptr;
instantiating_collection_linknode = instantiating_collection_linknode->next) {
- instantiating_collection = instantiating_collection_linknode->link;
+ instantiating_collection = static_cast<Collection *>(
+ instantiating_collection_linknode->link);
if (!ID_IS_LINKED(instantiating_collection)) {
/* There is a local collection instantiating the linked object to override, nothing
* else to be done here. */
@@ -862,12 +938,12 @@ static void lib_override_linked_group_tag(LibOverrideGroupTagData *data)
break;
}
instantiating_collection_override_candidate = instantiating_collection;
- instantiating_collection = NULL;
+ instantiating_collection = nullptr;
}
}
- if (instantiating_collection == NULL &&
- instantiating_collection_override_candidate != NULL) {
+ if (instantiating_collection == nullptr &&
+ instantiating_collection_override_candidate != nullptr) {
if (instantiating_collection_override_candidate->id.tag & LIB_TAG_MISSING) {
instantiating_collection_override_candidate->id.tag |= data->missing_tag;
}
@@ -896,9 +972,9 @@ static void lib_override_overrides_group_tag_recursive(LibOverrideGroupTagData *
const uint tag = data->tag;
const uint missing_tag = data->missing_tag;
- MainIDRelationsEntry *entry = BLI_ghash_lookup(bmain->relations->relations_from_pointers,
- id_owner);
- BLI_assert(entry != NULL);
+ MainIDRelationsEntry *entry = static_cast<MainIDRelationsEntry *>(
+ BLI_ghash_lookup(bmain->relations->relations_from_pointers, id_owner));
+ BLI_assert(entry != nullptr);
if (entry->tags & MAINIDRELATIONS_ENTRY_TAGS_PROCESSED) {
/* This ID has already been processed. */
@@ -908,7 +984,7 @@ static void lib_override_overrides_group_tag_recursive(LibOverrideGroupTagData *
* relationship hierarchy. */
entry->tags |= MAINIDRELATIONS_ENTRY_TAGS_PROCESSED;
- for (MainIDRelationsEntryItem *to_id_entry = entry->to_ids; to_id_entry != NULL;
+ for (MainIDRelationsEntryItem *to_id_entry = entry->to_ids; to_id_entry != nullptr;
to_id_entry = to_id_entry->next) {
if ((to_id_entry->usage_flag & IDWALK_CB_OVERRIDE_LIBRARY_NOT_OVERRIDABLE) != 0) {
/* Never consider non-overridable relationships as actual dependencies. */
@@ -916,7 +992,7 @@ static void lib_override_overrides_group_tag_recursive(LibOverrideGroupTagData *
}
ID *to_id = *to_id_entry->id_pointer.to;
- if (ELEM(to_id, NULL, id_owner)) {
+ if (ELEM(to_id, nullptr, id_owner)) {
continue;
}
/* Different libraries or different hierarchy roots are break points in override hierarchies.
@@ -929,8 +1005,8 @@ static void lib_override_overrides_group_tag_recursive(LibOverrideGroupTagData *
continue;
}
- Library *reference_lib = lib_override_get(bmain, id_owner, NULL)->reference->lib;
- ID *to_id_reference = lib_override_get(bmain, to_id, NULL)->reference;
+ const Library *reference_lib = lib_override_get(bmain, id_owner, nullptr)->reference->lib;
+ const ID *to_id_reference = lib_override_get(bmain, to_id, nullptr)->reference;
if (to_id_reference->lib != reference_lib) {
/* We do not override data-blocks from other libraries, nor do we process them. */
continue;
@@ -958,7 +1034,7 @@ static void lib_override_overrides_group_tag(LibOverrideGroupTagData *data)
BLI_assert(data->is_override);
ID *id_hierarchy_root = data->hierarchy_root_id;
- BLI_assert(id_hierarchy_root != NULL);
+ BLI_assert(id_hierarchy_root != nullptr);
BLI_assert(ID_IS_OVERRIDE_LIBRARY_REAL(id_hierarchy_root));
UNUSED_VARS_NDEBUG(id_hierarchy_root);
@@ -977,16 +1053,18 @@ static bool lib_override_library_create_do(Main *bmain,
Scene *scene,
Library *owner_library,
ID *id_root_reference,
- ID *id_hierarchy_root_reference)
+ ID *id_hierarchy_root_reference,
+ const bool do_fully_editable)
{
BKE_main_relations_create(bmain, 0);
- LibOverrideGroupTagData data = {.bmain = bmain,
- .scene = scene,
- .id_root = id_root_reference,
- .tag = LIB_TAG_DOIT,
- .missing_tag = LIB_TAG_MISSING,
- .is_override = false,
- .is_resync = false};
+ LibOverrideGroupTagData data{};
+ data.bmain = bmain;
+ data.scene = scene;
+ data.id_root = id_root_reference;
+ data.tag = LIB_TAG_DOIT;
+ data.missing_tag = LIB_TAG_MISSING;
+ data.is_override = false;
+ data.is_resync = false;
lib_override_group_tag_data_object_to_collection_init(&data);
lib_override_linked_group_tag(&data);
@@ -1001,12 +1079,22 @@ static bool lib_override_library_create_do(Main *bmain,
BLI_assert(ID_IS_OVERRIDE_LIBRARY_REAL(id_hierarchy_root_reference));
BLI_assert(id_hierarchy_root_reference->override_library->reference->lib ==
id_root_reference->lib);
- success = BKE_lib_override_library_create_from_tag(
- bmain, owner_library, id_root_reference, id_hierarchy_root_reference, NULL, false);
+ success = BKE_lib_override_library_create_from_tag(bmain,
+ owner_library,
+ id_root_reference,
+ id_hierarchy_root_reference,
+ nullptr,
+ false,
+ do_fully_editable);
}
else {
- success = BKE_lib_override_library_create_from_tag(
- bmain, owner_library, id_root_reference, NULL, id_hierarchy_root_reference, false);
+ success = BKE_lib_override_library_create_from_tag(bmain,
+ owner_library,
+ id_root_reference,
+ nullptr,
+ id_hierarchy_root_reference,
+ false,
+ do_fully_editable);
}
return success;
@@ -1033,25 +1121,25 @@ static void lib_override_library_create_post_process(Main *bmain,
/* We create a set of all objects referenced into the scene by its hierarchy of collections.
* NOTE: This is different that the list of bases, since objects in excluded collections etc.
* won't have a base, but are still considered as instanced from our point of view. */
- GSet *all_objects_in_scene = BKE_scene_objects_as_gset(scene, NULL);
+ GSet *all_objects_in_scene = BKE_scene_objects_as_gset(scene, nullptr);
/* Instantiating the root collection or object should never be needed in resync case, since the
* old override would be remapped to the new one. */
- if (!is_resync && id_root != NULL && id_root->newid != NULL &&
+ if (!is_resync && id_root != nullptr && id_root->newid != nullptr &&
(!ID_IS_LINKED(id_root->newid) || id_root->newid->lib == owner_library)) {
switch (GS(id_root->name)) {
case ID_GR: {
- Object *ob_reference = id_instance_hint != NULL && GS(id_instance_hint->name) == ID_OB ?
+ Object *ob_reference = id_instance_hint != nullptr && GS(id_instance_hint->name) == ID_OB ?
(Object *)id_instance_hint :
- NULL;
+ nullptr;
Collection *collection_new = ((Collection *)id_root->newid);
if (is_resync && BKE_collection_is_in_scene(collection_new)) {
break;
}
- if (ob_reference != NULL) {
+ if (ob_reference != nullptr) {
BKE_collection_add_from_object(bmain, scene, ob_reference, collection_new);
}
- else if (id_instance_hint != NULL) {
+ else if (id_instance_hint != nullptr) {
BLI_assert(GS(id_instance_hint->name) == ID_GR);
BKE_collection_add_from_collection(
bmain, scene, ((Collection *)id_instance_hint), collection_new);
@@ -1068,7 +1156,7 @@ static void lib_override_library_create_post_process(Main *bmain,
}
case ID_OB: {
Object *ob_new = (Object *)id_root->newid;
- if (BLI_gset_lookup(all_objects_in_scene, ob_new) == NULL) {
+ if (BLI_gset_lookup(all_objects_in_scene, ob_new) == nullptr) {
BKE_collection_object_add_from(bmain, scene, (Object *)id_root, ob_new);
all_objects_in_scene = BKE_scene_objects_as_gset(scene, all_objects_in_scene);
}
@@ -1083,16 +1171,16 @@ static void lib_override_library_create_post_process(Main *bmain,
Collection *default_instantiating_collection = residual_storage;
LISTBASE_FOREACH (Object *, ob, &bmain->objects) {
Object *ob_new = (Object *)ob->id.newid;
- if (ob_new == NULL || (ID_IS_LINKED(ob_new) && ob_new->id.lib != owner_library)) {
+ if (ob_new == nullptr || (ID_IS_LINKED(ob_new) && ob_new->id.lib != owner_library)) {
continue;
}
- BLI_assert(ob_new->id.override_library != NULL &&
+ BLI_assert(ob_new->id.override_library != nullptr &&
ob_new->id.override_library->reference == &ob->id);
- if (BLI_gset_lookup(all_objects_in_scene, ob_new) == NULL) {
- if (id_root != NULL && default_instantiating_collection == NULL) {
- ID *id_ref = id_root->newid != NULL ? id_root->newid : id_root;
+ if (BLI_gset_lookup(all_objects_in_scene, ob_new) == nullptr) {
+ if (id_root != nullptr && default_instantiating_collection == nullptr) {
+ ID *id_ref = id_root->newid != nullptr ? id_root->newid : id_root;
switch (GS(id_ref->name)) {
case ID_GR: {
/* Adding the object to a specific collection outside of the root overridden one is a
@@ -1105,8 +1193,9 @@ static void lib_override_library_create_post_process(Main *bmain,
if (ID_REAL_USERS(ob_new) != 0) {
continue;
}
- default_instantiating_collection = BKE_collection_add(
- bmain, (Collection *)id_root, "OVERRIDE_HIDDEN");
+ default_instantiating_collection = static_cast<Collection *>(
+ BKE_id_new(bmain, ID_GR, "OVERRIDE_HIDDEN"));
+ id_us_min(&default_instantiating_collection->id);
/* Hide the collection from viewport and render. */
default_instantiating_collection->flag |= COLLECTION_HIDE_VIEWPORT |
COLLECTION_HIDE_RENDER;
@@ -1118,7 +1207,7 @@ static void lib_override_library_create_post_process(Main *bmain,
Object *ob_ref = (Object *)id_ref;
LISTBASE_FOREACH (Collection *, collection, &bmain->collections) {
if (BKE_collection_has_object(collection, ob_ref) &&
- (view_layer != NULL ?
+ (view_layer != nullptr ?
BKE_view_layer_has_collection(view_layer, collection) :
BKE_collection_has_collection(scene->master_collection, collection)) &&
!ID_IS_LINKED(collection) && !ID_IS_OVERRIDE_LIBRARY(collection)) {
@@ -1131,7 +1220,7 @@ static void lib_override_library_create_post_process(Main *bmain,
break;
}
}
- if (default_instantiating_collection == NULL) {
+ if (default_instantiating_collection == nullptr) {
default_instantiating_collection = scene->master_collection;
}
@@ -1140,7 +1229,23 @@ static void lib_override_library_create_post_process(Main *bmain,
}
}
- BLI_gset_free(all_objects_in_scene, NULL);
+ if (id_root != nullptr &&
+ !ELEM(default_instantiating_collection, nullptr, scene->master_collection)) {
+ ID *id_ref = id_root->newid != nullptr ? id_root->newid : id_root;
+ switch (GS(id_ref->name)) {
+ case ID_GR:
+ BKE_collection_add_from_collection(
+ bmain, scene, (Collection *)id_ref, default_instantiating_collection);
+ break;
+ default:
+ /* Add to master collection. */
+ BKE_collection_add_from_collection(
+ bmain, scene, nullptr, default_instantiating_collection);
+ break;
+ }
+ }
+
+ BLI_gset_free(all_objects_in_scene, nullptr);
}
bool BKE_lib_override_library_create(Main *bmain,
@@ -1150,29 +1255,40 @@ bool BKE_lib_override_library_create(Main *bmain,
ID *id_root_reference,
ID *id_hierarchy_root_reference,
ID *id_instance_hint,
- ID **r_id_root_override)
+ ID **r_id_root_override,
+ const bool do_fully_editable)
{
- if (r_id_root_override != NULL) {
- *r_id_root_override = NULL;
+ if (r_id_root_override != nullptr) {
+ *r_id_root_override = nullptr;
}
- if (id_hierarchy_root_reference == NULL) {
+ if (id_hierarchy_root_reference == nullptr) {
id_hierarchy_root_reference = id_root_reference;
}
- const bool success = lib_override_library_create_do(
- bmain, scene, owner_library, id_root_reference, id_hierarchy_root_reference);
+ const bool success = lib_override_library_create_do(bmain,
+ scene,
+ owner_library,
+ id_root_reference,
+ id_hierarchy_root_reference,
+ do_fully_editable);
if (!success) {
return success;
}
- if (r_id_root_override != NULL) {
+ if (r_id_root_override != nullptr) {
*r_id_root_override = id_root_reference->newid;
}
- lib_override_library_create_post_process(
- bmain, scene, view_layer, owner_library, id_root_reference, id_instance_hint, NULL, false);
+ lib_override_library_create_post_process(bmain,
+ scene,
+ view_layer,
+ owner_library,
+ id_root_reference,
+ id_instance_hint,
+ nullptr,
+ false);
/* Cleanup. */
BKE_main_id_newptr_and_tag_clear(bmain);
@@ -1184,7 +1300,7 @@ bool BKE_lib_override_library_create(Main *bmain,
return success;
}
-bool BKE_lib_override_library_template_create(struct ID *id)
+bool BKE_lib_override_library_template_create(ID *id)
{
if (ID_IS_LINKED(id)) {
return false;
@@ -1193,7 +1309,7 @@ bool BKE_lib_override_library_template_create(struct ID *id)
return false;
}
- BKE_lib_override_library_init(id, NULL);
+ BKE_lib_override_library_init(id, nullptr);
return true;
}
@@ -1204,17 +1320,17 @@ static ID *lib_override_root_find(Main *bmain, ID *id, const int curr_level, int
"Levels of dependency relationships between library overrides IDs is way too high, "
"skipping further processing loops (involves at least '%s')",
id->name);
- BLI_assert(0);
- return NULL;
+ return nullptr;
}
if (!ID_IS_OVERRIDE_LIBRARY(id)) {
- BLI_assert(0);
- return NULL;
+ BLI_assert_unreachable();
+ return nullptr;
}
- MainIDRelationsEntry *entry = BLI_ghash_lookup(bmain->relations->relations_from_pointers, id);
- BLI_assert(entry != NULL);
+ MainIDRelationsEntry *entry = static_cast<MainIDRelationsEntry *>(
+ BLI_ghash_lookup(bmain->relations->relations_from_pointers, id));
+ BLI_assert(entry != nullptr);
if (entry->tags & MAINIDRELATIONS_ENTRY_TAGS_PROCESSED) {
if (ID_IS_OVERRIDE_LIBRARY_REAL(id)) {
@@ -1236,7 +1352,7 @@ static ID *lib_override_root_find(Main *bmain, ID *id, const int curr_level, int
int best_level_candidate = curr_level;
ID *best_root_id_candidate = id;
- for (MainIDRelationsEntryItem *from_id_entry = entry->from_ids; from_id_entry != NULL;
+ for (MainIDRelationsEntryItem *from_id_entry = entry->from_ids; from_id_entry != nullptr;
from_id_entry = from_id_entry->next) {
if ((from_id_entry->usage_flag & IDWALK_CB_OVERRIDE_LIBRARY_NOT_OVERRIDABLE) != 0) {
/* Never consider non-overridable relationships as actual dependencies. */
@@ -1244,7 +1360,7 @@ static ID *lib_override_root_find(Main *bmain, ID *id, const int curr_level, int
}
ID *from_id = from_id_entry->id_pointer.from;
- if (ELEM(from_id, NULL, id)) {
+ if (ELEM(from_id, nullptr, id)) {
continue;
}
if (!ID_IS_OVERRIDE_LIBRARY(from_id) || (from_id->lib != id->lib)) {
@@ -1255,7 +1371,7 @@ static ID *lib_override_root_find(Main *bmain, ID *id, const int curr_level, int
/* Recursively process the parent. */
ID *root_id_candidate = lib_override_root_find(
bmain, from_id, curr_level + 1, &level_candidate);
- if (level_candidate > best_level_candidate && root_id_candidate != NULL) {
+ if (level_candidate > best_level_candidate && root_id_candidate != nullptr) {
best_root_id_candidate = root_id_candidate;
best_level_candidate = level_candidate;
}
@@ -1270,7 +1386,7 @@ static ID *lib_override_root_find(Main *bmain, ID *id, const int curr_level, int
bmain, id_owner, curr_level + 1, &best_level_placeholder);
}
- BLI_assert(best_root_id_candidate != NULL);
+ BLI_assert(best_root_id_candidate != nullptr);
BLI_assert((best_root_id_candidate->flag & LIB_EMBEDDED_DATA_LIB_OVERRIDE) == 0);
*r_best_level = best_level_candidate;
@@ -1288,14 +1404,14 @@ static void lib_override_root_hierarchy_set(Main *bmain, ID *id_root, ID *id, ID
/* Hierarchy root already set, and not matching currently proposed one, try to find which is
* best. */
- if (id->override_library->hierarchy_root != NULL) {
+ if (id->override_library->hierarchy_root != nullptr) {
/* Check if given `id_from` matches with the hierarchy of the linked reference ID, in which
* case we assume that the given hierarchy root is the 'real' one.
*
* NOTE: This can fail if user mixed dependencies between several overrides of a same
* reference linked hierarchy. Not much to be done in that case, it's virtually impossible to
* fix this automatically in a reliable way. */
- if (id_from == NULL || !ID_IS_OVERRIDE_LIBRARY_REAL(id_from)) {
+ if (id_from == nullptr || !ID_IS_OVERRIDE_LIBRARY_REAL(id_from)) {
/* Too complicated to deal with for now. */
CLOG_WARN(&LOG,
"Inconsistency in library override hierarchy of ID '%s'.\n"
@@ -1308,12 +1424,12 @@ static void lib_override_root_hierarchy_set(Main *bmain, ID *id_root, ID *id, ID
}
ID *id_from_ref = id_from->override_library->reference;
- MainIDRelationsEntry *entry = BLI_ghash_lookup(bmain->relations->relations_from_pointers,
- id->override_library->reference);
- BLI_assert(entry != NULL);
+ MainIDRelationsEntry *entry = static_cast<MainIDRelationsEntry *>(BLI_ghash_lookup(
+ bmain->relations->relations_from_pointers, id->override_library->reference));
+ BLI_assert(entry != nullptr);
bool do_replace_root = false;
- for (MainIDRelationsEntryItem *from_id_entry = entry->from_ids; from_id_entry != NULL;
+ for (MainIDRelationsEntryItem *from_id_entry = entry->from_ids; from_id_entry != nullptr;
from_id_entry = from_id_entry->next) {
if ((from_id_entry->usage_flag & IDWALK_CB_OVERRIDE_LIBRARY_NOT_OVERRIDABLE) != 0) {
/* Never consider non-overridable relationships as actual dependencies. */
@@ -1350,10 +1466,11 @@ static void lib_override_root_hierarchy_set(Main *bmain, ID *id_root, ID *id, ID
id->override_library->hierarchy_root = id_root;
}
- MainIDRelationsEntry *entry = BLI_ghash_lookup(bmain->relations->relations_from_pointers, id);
- BLI_assert(entry != NULL);
+ MainIDRelationsEntry *entry = static_cast<MainIDRelationsEntry *>(
+ BLI_ghash_lookup(bmain->relations->relations_from_pointers, id));
+ BLI_assert(entry != nullptr);
- for (MainIDRelationsEntryItem *to_id_entry = entry->to_ids; to_id_entry != NULL;
+ for (MainIDRelationsEntryItem *to_id_entry = entry->to_ids; to_id_entry != nullptr;
to_id_entry = to_id_entry->next) {
if ((to_id_entry->usage_flag & IDWALK_CB_OVERRIDE_LIBRARY_NOT_OVERRIDABLE) != 0) {
/* Never consider non-overridable relationships as actual dependencies. */
@@ -1361,7 +1478,7 @@ static void lib_override_root_hierarchy_set(Main *bmain, ID *id_root, ID *id, ID
}
ID *to_id = *to_id_entry->id_pointer.to;
- if (ELEM(to_id, NULL, id)) {
+ if (ELEM(to_id, nullptr, id)) {
continue;
}
if (!ID_IS_OVERRIDE_LIBRARY(to_id) || (to_id->lib != id->lib)) {
@@ -1383,8 +1500,22 @@ void BKE_lib_override_library_main_hierarchy_root_ensure(Main *bmain)
if (!ID_IS_OVERRIDE_LIBRARY_REAL(id)) {
continue;
}
- if (id->override_library->hierarchy_root != NULL) {
- continue;
+ if (id->override_library->hierarchy_root != nullptr) {
+ if (!ID_IS_OVERRIDE_LIBRARY_REAL(id->override_library->hierarchy_root) ||
+ id->override_library->hierarchy_root->lib != id->lib) {
+ CLOG_ERROR(
+ &LOG,
+ "Existing override hierarchy root ('%s') for ID '%s' is invalid, will try to find a "
+ "new valid one",
+ id->override_library->hierarchy_root != nullptr ?
+ id->override_library->hierarchy_root->name :
+ "<NONE>",
+ id->name);
+ id->override_library->hierarchy_root = nullptr;
+ }
+ else {
+ continue;
+ }
}
BKE_main_relations_tag_set(bmain, MAINIDRELATIONS_ENTRY_TAGS_PROCESSED, false);
@@ -1392,7 +1523,7 @@ void BKE_lib_override_library_main_hierarchy_root_ensure(Main *bmain)
int best_level = 0;
ID *id_root = lib_override_root_find(bmain, id, best_level, &best_level);
- if (!ELEM(id_root->override_library->hierarchy_root, id_root, NULL)) {
+ if (!ELEM(id_root->override_library->hierarchy_root, id_root, nullptr)) {
CLOG_WARN(&LOG,
"Potential inconsistency in library override hierarchy of ID '%s', detected as "
"part of the hierarchy of '%s', which has a different root '%s'",
@@ -1402,9 +1533,9 @@ void BKE_lib_override_library_main_hierarchy_root_ensure(Main *bmain)
continue;
}
- lib_override_root_hierarchy_set(bmain, id_root, id_root, NULL);
+ lib_override_root_hierarchy_set(bmain, id_root, id, nullptr);
- BLI_assert(id->override_library->hierarchy_root != NULL);
+ BLI_assert(id->override_library->hierarchy_root != nullptr);
}
FOREACH_MAIN_ID_END;
@@ -1416,14 +1547,14 @@ static void lib_override_library_remap(Main *bmain,
GHash *linkedref_to_old_override)
{
ID *id;
- struct IDRemapper *remapper = BKE_id_remapper_create();
- LinkNode *nomain_ids = NULL;
+ IDRemapper *remapper = BKE_id_remapper_create();
+ LinkNode *nomain_ids = nullptr;
FOREACH_MAIN_ID_BEGIN (bmain, id) {
- if (id->tag & LIB_TAG_DOIT && id->newid != NULL && id->lib == id_root_reference->lib) {
+ if (id->tag & LIB_TAG_DOIT && id->newid != nullptr && 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) {
+ ID *id_override_old = static_cast<ID *>(BLI_ghash_lookup(linkedref_to_old_override, id));
+ if (id_override_old == nullptr) {
continue;
}
@@ -1435,7 +1566,8 @@ static void lib_override_library_remap(Main *bmain,
/* 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);
+ ID *id_override_old_iter = static_cast<ID *>(
+ BLI_ghashIterator_getValue(&linkedref_to_old_override_iter));
if ((id_override_old_iter->tag & LIB_TAG_NO_MAIN) == 0) {
continue;
}
@@ -1451,6 +1583,7 @@ static void lib_override_library_remap(Main *bmain,
remapper,
ID_REMAP_FORCE_USER_REFCOUNT | ID_REMAP_FORCE_NEVER_NULL_USAGE);
BKE_id_remapper_free(remapper);
+ BLI_linklist_free(nomain_ids, nullptr);
}
static bool lib_override_library_resync(Main *bmain,
@@ -1470,7 +1603,7 @@ static bool lib_override_library_resync(Main *bmain,
ID *id;
if (id_root_reference->tag & LIB_TAG_MISSING) {
- BKE_reportf(reports != NULL ? reports->reports : NULL,
+ BKE_reportf(reports != nullptr ? reports->reports : nullptr,
RPT_ERROR,
"Impossible to resync data-block %s and its dependencies, as its linked reference "
"is missing",
@@ -1479,14 +1612,15 @@ static bool lib_override_library_resync(Main *bmain,
}
BKE_main_relations_create(bmain, 0);
- LibOverrideGroupTagData data = {.bmain = bmain,
- .scene = scene,
- .id_root = id_root,
- .hierarchy_root_id = id_root->override_library->hierarchy_root,
- .tag = LIB_TAG_DOIT,
- .missing_tag = LIB_TAG_MISSING,
- .is_override = true,
- .is_resync = true};
+ LibOverrideGroupTagData data{};
+ data.bmain = bmain;
+ data.scene = scene;
+ data.id_root = id_root;
+ data.hierarchy_root_id = id_root->override_library->hierarchy_root;
+ data.tag = LIB_TAG_DOIT;
+ data.missing_tag = LIB_TAG_MISSING;
+ data.is_override = true;
+ data.is_resync = true;
lib_override_group_tag_data_object_to_collection_init(&data);
/* Mapping 'linked reference IDs' -> 'Local override IDs' of existing overrides, populated from
@@ -1496,9 +1630,9 @@ static bool lib_override_library_resync(Main *bmain,
/* Only tag linked IDs from related linked reference hierarchy that are actually part of
* the sub-trees of each detected sub-roots needing resync. */
- for (LinkNode *resync_root_link = id_resync_roots; resync_root_link != NULL;
+ for (LinkNode *resync_root_link = id_resync_roots; resync_root_link != nullptr;
resync_root_link = resync_root_link->next) {
- ID *id_resync_root = resync_root_link->link;
+ ID *id_resync_root = static_cast<ID *>(resync_root_link->link);
BLI_assert(ID_IS_OVERRIDE_LIBRARY_REAL(id_resync_root));
if ((id_resync_root->tag & LIB_TAG_NO_MAIN) != 0) {
@@ -1520,12 +1654,12 @@ static bool lib_override_library_resync(Main *bmain,
if (id_resync_root_reference->tag & LIB_TAG_MISSING) {
BKE_reportf(
- reports != NULL ? reports->reports : NULL,
+ reports != nullptr ? reports->reports : nullptr,
RPT_ERROR,
"Impossible to resync data-block %s and its dependencies, as its linked reference "
"is missing",
id_root->name + 2);
- BLI_ghash_free(linkedref_to_old_override, NULL, NULL);
+ BLI_ghash_free(linkedref_to_old_override, nullptr, nullptr);
BKE_main_relations_free(bmain);
lib_override_group_tag_data_clear(&data);
return false;
@@ -1564,7 +1698,7 @@ static bool lib_override_library_resync(Main *bmain,
/* While this should not happen in typical cases (and won't be properly supported here),
* user is free to do all kind of very bad things, including having different local
* overrides of a same linked ID in a same hierarchy. */
- IDOverrideLibrary *id_override_library = lib_override_get(bmain, id, NULL);
+ IDOverrideLibrary *id_override_library = lib_override_get(bmain, id, nullptr);
ID *reference_id = id_override_library->reference;
if (GS(reference_id->name) != GS(id->name)) {
switch (GS(id->name)) {
@@ -1636,19 +1770,25 @@ static bool lib_override_library_resync(Main *bmain,
* override IDs (including within the old overrides themselves, since those are tagged too
* above). */
const bool success = BKE_lib_override_library_create_from_tag(
- bmain, NULL, id_root_reference, id_root->override_library->hierarchy_root, NULL, true);
+ bmain,
+ nullptr,
+ id_root_reference,
+ id_root->override_library->hierarchy_root,
+ nullptr,
+ true,
+ false);
if (!success) {
- BLI_ghash_free(linkedref_to_old_override, NULL, NULL);
+ BLI_ghash_free(linkedref_to_old_override, nullptr, nullptr);
return success;
}
ListBase *lb;
FOREACH_MAIN_LISTBASE_BEGIN (bmain, lb) {
FOREACH_MAIN_LISTBASE_ID_BEGIN (lb, id) {
- if (id->tag & LIB_TAG_DOIT && id->newid != NULL && id->lib == id_root_reference->lib) {
+ if (id->tag & LIB_TAG_DOIT && id->newid != nullptr && id->lib == id_root_reference->lib) {
ID *id_override_new = id->newid;
- ID *id_override_old = BLI_ghash_lookup(linkedref_to_old_override, id);
+ ID *id_override_old = static_cast<ID *>(BLI_ghash_lookup(linkedref_to_old_override, id));
BLI_assert((id_override_new->tag & LIB_TAG_LIB_OVERRIDE_NEED_RESYNC) == 0);
@@ -1656,14 +1796,14 @@ static bool lib_override_library_resync(Main *bmain,
* duplicated from the reference ID with 'no main' option, it should currently be the same
* as the reference ID one). */
BLI_assert(/*!ID_IS_LINKED(id_override_new) || */ id_override_new->lib == id->lib);
- BLI_assert(id_override_old == NULL || id_override_old->lib == id_root->lib);
+ BLI_assert(id_override_old == nullptr || id_override_old->lib == id_root->lib);
id_override_new->lib = id_root->lib;
/* Remap step below will tag directly linked ones properly as needed. */
if (ID_IS_LINKED(id_override_new)) {
id_override_new->tag |= LIB_TAG_INDIRECT;
}
- if (id_override_old != NULL) {
+ if (id_override_old != nullptr) {
/* Swap the names between old override ID and new one. */
char id_name_buf[MAX_ID_NAME];
memcpy(id_name_buf, id_override_old->name, sizeof(id_name_buf));
@@ -1674,6 +1814,8 @@ static bool lib_override_library_resync(Main *bmain,
id_override_old->tag |= LIB_TAG_NO_MAIN;
id_override_new->tag &= ~LIB_TAG_NO_MAIN;
+ lib_override_object_posemode_transfer(id_override_new, id_override_old);
+
if (ID_IS_OVERRIDE_LIBRARY_REAL(id_override_new)) {
BLI_assert(ID_IS_OVERRIDE_LIBRARY_REAL(id_override_old));
@@ -1682,10 +1824,10 @@ static bool lib_override_library_resync(Main *bmain,
/* Copy over overrides rules from old override ID to new one. */
BLI_duplicatelist(&id_override_new->override_library->properties,
&id_override_old->override_library->properties);
- IDOverrideLibraryProperty *op_new =
- id_override_new->override_library->properties.first;
- IDOverrideLibraryProperty *op_old =
- id_override_old->override_library->properties.first;
+ IDOverrideLibraryProperty *op_new = static_cast<IDOverrideLibraryProperty *>(
+ id_override_new->override_library->properties.first);
+ IDOverrideLibraryProperty *op_old = static_cast<IDOverrideLibraryProperty *>(
+ id_override_old->override_library->properties.first);
for (; op_new; op_new = op_new->next, op_old = op_old->next) {
lib_override_library_property_copy(op_new, op_old);
}
@@ -1710,20 +1852,20 @@ static bool lib_override_library_resync(Main *bmain,
BKE_main_collection_sync(bmain);
- LinkNode *id_override_old_list = NULL;
+ LinkNode *id_override_old_list = nullptr;
/* We need to apply override rules in a separate loop, after all ID pointers have been properly
* remapped, and all new local override IDs have gotten their proper original names, otherwise
* override operations based on those ID names would fail. */
FOREACH_MAIN_ID_BEGIN (bmain, id) {
- if (id->tag & LIB_TAG_DOIT && id->newid != NULL && id->lib == id_root_reference->lib) {
+ if (id->tag & LIB_TAG_DOIT && id->newid != nullptr && id->lib == id_root_reference->lib) {
ID *id_override_new = id->newid;
if (!ID_IS_OVERRIDE_LIBRARY_REAL(id_override_new)) {
continue;
}
- ID *id_override_old = BLI_ghash_lookup(linkedref_to_old_override, id);
+ ID *id_override_old = static_cast<ID *>(BLI_ghash_lookup(linkedref_to_old_override, id));
- if (id_override_old == NULL) {
+ if (id_override_old == nullptr) {
continue;
}
if (ID_IS_OVERRIDE_LIBRARY_REAL(id_override_old)) {
@@ -1754,7 +1896,7 @@ static bool lib_override_library_resync(Main *bmain,
RNA_struct_override_apply(bmain,
&rnaptr_dst,
&rnaptr_src,
- NULL,
+ nullptr,
id_override_new->override_library,
do_hierarchy_enforce ?
RNA_OVERRIDE_APPLY_FLAG_IGNORE_ID_POINTERS :
@@ -1769,18 +1911,18 @@ static bool lib_override_library_resync(Main *bmain,
/* Once overrides have been properly 'transferred' from old to new ID, we can clear ID usages
* of the old one.
* This is necessary in case said old ID is not in Main anymore. */
- struct IDRemapper *id_remapper = BKE_id_remapper_create();
+ IDRemapper *id_remapper = BKE_id_remapper_create();
BKE_libblock_relink_multiple(bmain,
id_override_old_list,
ID_REMAP_TYPE_CLEANUP,
id_remapper,
ID_REMAP_FORCE_USER_REFCOUNT | ID_REMAP_FORCE_NEVER_NULL_USAGE);
- for (LinkNode *ln_iter = id_override_old_list; ln_iter != NULL; ln_iter = ln_iter->next) {
- ID *id_override_old = ln_iter->link;
+ for (LinkNode *ln_iter = id_override_old_list; ln_iter != nullptr; ln_iter = ln_iter->next) {
+ ID *id_override_old = static_cast<ID *>(ln_iter->link);
id_override_old->tag |= LIB_TAG_NO_USER_REFCOUNT;
}
BKE_id_remapper_free(id_remapper);
- BLI_linklist_free(id_override_old_list, NULL);
+ BLI_linklist_free(id_override_old_list, nullptr);
/* Delete old override IDs.
* Note that we have to use tagged group deletion here, since ID deletion also uses
@@ -1791,10 +1933,10 @@ static bool lib_override_library_resync(Main *bmain,
/* Note that this works because linked IDs are always after local ones (including
* overrides), so we will only ever tag an old override ID after we have already checked it
* in this loop, hence we cannot untag it later. */
- if (id->newid != NULL && id->lib == id_root_reference->lib) {
- ID *id_override_old = BLI_ghash_lookup(linkedref_to_old_override, id);
+ if (id->newid != nullptr && id->lib == id_root_reference->lib) {
+ ID *id_override_old = static_cast<ID *>(BLI_ghash_lookup(linkedref_to_old_override, id));
- if (id_override_old != NULL) {
+ if (id_override_old != nullptr) {
id->newid->tag &= ~LIB_TAG_DOIT;
id_override_old->tag |= LIB_TAG_DOIT;
if (id_override_old->tag & LIB_TAG_NO_MAIN) {
@@ -1838,19 +1980,19 @@ static bool lib_override_library_resync(Main *bmain,
FOREACH_MAIN_ID_END;
/* Cleanup, many pointers in this GHash are already invalid now. */
- BLI_ghash_free(linkedref_to_old_override, NULL, NULL);
+ BLI_ghash_free(linkedref_to_old_override, nullptr, nullptr);
BKE_id_multi_tagged_delete(bmain);
/* At this point, `id_root` may have been resynced, therefore deleted. In that case we need to
* update it to its new version.
*/
- if (id_root_reference->newid != NULL) {
+ if (id_root_reference->newid != nullptr) {
id_root = id_root_reference->newid;
}
if (user_edited_overrides_deletion_count > 0) {
- BKE_reportf(reports != NULL ? reports->reports : NULL,
+ BKE_reportf(reports != nullptr ? reports->reports : nullptr,
RPT_WARNING,
"During resync of data-block %s, %d obsolete overrides were deleted, that had "
"local changes defined by user",
@@ -1867,7 +2009,7 @@ static bool lib_override_library_resync(Main *bmain,
lib_override_library_create_post_process(bmain,
scene,
view_layer,
- NULL,
+ nullptr,
id_root_reference,
id_root,
override_resync_residual_storage,
@@ -1889,8 +2031,10 @@ bool BKE_lib_override_library_resync(Main *bmain,
const bool do_hierarchy_enforce,
BlendFileReadReport *reports)
{
- ListBase no_main_ids_list = {NULL};
- LinkNode id_resync_roots = {.link = id_root, .next = NULL};
+ ListBase no_main_ids_list = {nullptr};
+ LinkNode id_resync_roots{};
+ id_resync_roots.link = id_root;
+ id_resync_roots.next = nullptr;
const bool success = lib_override_library_resync(bmain,
scene,
@@ -1924,14 +2068,14 @@ static ID *lib_override_library_main_resync_root_get(Main *bmain, ID *id)
{
if (!ID_IS_OVERRIDE_LIBRARY_REAL(id)) {
const IDTypeInfo *id_type = BKE_idtype_get_info_from_id(id);
- if (id_type->owner_get != NULL) {
+ if (id_type->owner_get != nullptr) {
id = id_type->owner_get(bmain, id);
}
BLI_assert(ID_IS_OVERRIDE_LIBRARY_REAL(id));
}
ID *hierarchy_root_id = id->override_library->hierarchy_root;
- BLI_assert(hierarchy_root_id != NULL);
+ BLI_assert(hierarchy_root_id != nullptr);
BLI_assert(ID_IS_OVERRIDE_LIBRARY_REAL(hierarchy_root_id));
return hierarchy_root_id;
}
@@ -1966,8 +2110,9 @@ static bool lib_override_resync_tagging_finalize_recurse(
return false;
}
- MainIDRelationsEntry *entry = BLI_ghash_lookup(bmain->relations->relations_from_pointers, id);
- BLI_assert(entry != NULL);
+ MainIDRelationsEntry *entry = static_cast<MainIDRelationsEntry *>(
+ BLI_ghash_lookup(bmain->relations->relations_from_pointers, id));
+ BLI_assert(entry != nullptr);
if (entry->tags & MAINIDRELATIONS_ENTRY_TAGS_PROCESSED) {
/* This ID has already been processed. */
@@ -2001,7 +2146,7 @@ static bool lib_override_resync_tagging_finalize_recurse(
id->tag &= ~LIB_TAG_LIB_OVERRIDE_NEED_RESYNC;
bool is_ancestor_tagged_for_resync = false;
- for (MainIDRelationsEntryItem *entry_item = entry->from_ids; entry_item != NULL;
+ for (MainIDRelationsEntryItem *entry_item = entry->from_ids; entry_item != nullptr;
entry_item = entry_item->next) {
if (entry_item->usage_flag &
(IDWALK_CB_OVERRIDE_LIBRARY_NOT_OVERRIDABLE | IDWALK_CB_LOOPBACK)) {
@@ -2058,9 +2203,11 @@ static bool lib_override_resync_tagging_finalize_recurse(
CLOG_INFO(&LOG, 4, "Found root ID '%s' for resync root ID '%s'", id_root->name, id->name);
+ BLI_assert(id_root->override_library != nullptr);
+
LinkNodePair **id_resync_roots_p;
if (!BLI_ghash_ensure_p(id_roots, id_root, (void ***)&id_resync_roots_p)) {
- *id_resync_roots_p = MEM_callocN(sizeof(**id_resync_roots_p), __func__);
+ *id_resync_roots_p = MEM_cnew<LinkNodePair>(__func__);
}
BLI_linklist_append(*id_resync_roots_p, id);
@@ -2095,13 +2242,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};
+ LibOverrideGroupTagData data = {};
+ data.bmain = bmain;
+ data.scene = scene;
+ data.id_root = nullptr;
+ data.tag = LIB_TAG_DOIT;
+ data.missing_tag = LIB_TAG_MISSING;
+ data.is_override = false;
+ data.is_resync = true;
lib_override_group_tag_data_object_to_collection_init(&data);
ID *id;
FOREACH_MAIN_ID_BEGIN (bmain, id) {
@@ -2154,10 +2302,11 @@ static void lib_override_library_main_resync_on_library_indirect_level(
continue;
}
- MainIDRelationsEntry *entry = BLI_ghash_lookup(bmain->relations->relations_from_pointers, id);
- BLI_assert(entry != NULL);
+ MainIDRelationsEntry *entry = static_cast<MainIDRelationsEntry *>(
+ BLI_ghash_lookup(bmain->relations->relations_from_pointers, id));
+ BLI_assert(entry != nullptr);
- for (MainIDRelationsEntryItem *entry_item = entry->to_ids; entry_item != NULL;
+ for (MainIDRelationsEntryItem *entry_item = entry->to_ids; entry_item != nullptr;
entry_item = entry_item->next) {
if (entry_item->usage_flag & IDWALK_CB_OVERRIDE_LIBRARY_NOT_OVERRIDABLE) {
continue;
@@ -2190,13 +2339,14 @@ static void lib_override_library_main_resync_on_library_indirect_level(
BKE_main_relations_tag_set(bmain, MAINIDRELATIONS_ENTRY_TAGS_PROCESSED, false);
GHashIterator *id_roots_iter = BLI_ghashIterator_new(id_roots);
while (!BLI_ghashIterator_done(id_roots_iter)) {
- ID *id_root = BLI_ghashIterator_getKey(id_roots_iter);
- LinkNodePair *id_resync_roots = BLI_ghashIterator_getValue(id_roots_iter);
+ ID *id_root = static_cast<ID *>(BLI_ghashIterator_getKey(id_roots_iter));
+ LinkNodePair *id_resync_roots = static_cast<LinkNodePair *>(
+ BLI_ghashIterator_getValue(id_roots_iter));
CLOG_INFO(
&LOG, 2, "Checking validity of computed TODO data for root '%s'... \n", id_root->name);
- for (LinkNode *id_resync_root_iter = id_resync_roots->list; id_resync_root_iter != NULL;
+ for (LinkNode *id_resync_root_iter = id_resync_roots->list; id_resync_root_iter != nullptr;
id_resync_root_iter = id_resync_root_iter->next) {
- ID *id_resync_root = id_resync_root_iter->link;
+ ID *id_resync_root = static_cast<ID *>(id_resync_root_iter->link);
BLI_assert(id_resync_root == id_root || !BLI_ghash_haskey(id_roots, id_resync_root));
if (id_resync_root == id_root) {
BLI_assert(id_resync_root_iter == id_resync_roots->list &&
@@ -2214,13 +2364,14 @@ static void lib_override_library_main_resync_on_library_indirect_level(
BKE_main_relations_free(bmain);
BKE_main_id_tag_all(bmain, LIB_TAG_DOIT, false);
- ListBase no_main_ids_list = {NULL};
+ ListBase no_main_ids_list = {nullptr};
GHashIterator *id_roots_iter = BLI_ghashIterator_new(id_roots);
while (!BLI_ghashIterator_done(id_roots_iter)) {
- ID *id_root = BLI_ghashIterator_getKey(id_roots_iter);
+ ID *id_root = static_cast<ID *>(BLI_ghashIterator_getKey(id_roots_iter));
Library *library = id_root->lib;
- LinkNodePair *id_resync_roots = BLI_ghashIterator_getValue(id_roots_iter);
+ LinkNodePair *id_resync_roots = static_cast<LinkNodePair *>(
+ BLI_ghashIterator_getValue(id_roots_iter));
if (ID_IS_LINKED(id_root)) {
id_root->lib->tag |= LIBRARY_TAG_RESYNC_REQUIRED;
@@ -2252,7 +2403,7 @@ static void lib_override_library_main_resync_on_library_indirect_level(
}
}
- BLI_linklist_free(id_resync_roots->list, NULL);
+ BLI_linklist_free(id_resync_roots->list, nullptr);
BLI_ghashIterator_step(id_roots_iter);
}
BLI_ghashIterator_free(id_roots_iter);
@@ -2280,10 +2431,10 @@ static void lib_override_library_main_resync_on_library_indirect_level(
}
FOREACH_MAIN_ID_END;
- BLI_ghash_free(id_roots, NULL, MEM_freeN);
+ BLI_ghash_free(id_roots, nullptr, MEM_freeN);
/* In some fairly rare (and degenerate) cases, some root ID from other liboverrides may have been
- * freed, and therefore set to NULL. Attempt to fix this as best as possible. */
+ * freed, and therefore set to nullptr. Attempt to fix this as best as possible. */
BKE_lib_override_library_main_hierarchy_root_ensure(bmain);
if (do_reports_recursive_resync_timing) {
@@ -2298,18 +2449,29 @@ static int lib_override_sort_libraries_func(LibraryIDLinkCallbackData *cb_data)
}
ID *id_owner = cb_data->id_owner;
ID *id = *cb_data->id_pointer;
- if (id != NULL && ID_IS_LINKED(id) && id->lib != id_owner->lib) {
+ if (id != nullptr && ID_IS_LINKED(id) && id->lib != id_owner->lib) {
const int owner_library_indirect_level = ID_IS_LINKED(id_owner) ? id_owner->lib->temp_index :
0;
- if (owner_library_indirect_level > 10000) {
- CLOG_ERROR(
+ if (owner_library_indirect_level > 100) {
+ CLOG_ERROR(&LOG,
+ "Levels of indirect usages of libraries is way too high, there are most likely "
+ "dependency loops, skipping further building loops (involves at least '%s' from "
+ "'%s' and '%s' from '%s')",
+ id_owner->name,
+ id_owner->lib->filepath,
+ id->name,
+ id->lib->filepath);
+ return IDWALK_RET_NOP;
+ }
+ if (owner_library_indirect_level > 90) {
+ CLOG_WARN(
&LOG,
- "Levels of indirect usages of libraries is way too high, skipping further building "
- "loops (Involves at least '%s' and '%s')",
+ "Levels of indirect usages of libraries is suspiciously too high, there are most likely "
+ "dependency loops (involves at least '%s' from '%s' and '%s' from '%s')",
+ id_owner->name,
id_owner->lib->filepath,
+ id->name,
id->lib->filepath);
- BLI_assert(0);
- return IDWALK_RET_NOP;
}
if (owner_library_indirect_level >= id->lib->temp_index) {
@@ -2358,12 +2520,13 @@ void BKE_lib_override_library_main_resync(Main *bmain,
/* We use a specific collection to gather/store all 'orphaned' override collections and objects
* generated by re-sync-process. This avoids putting them in scene's master collection. */
#define OVERRIDE_RESYNC_RESIDUAL_STORAGE_NAME "OVERRIDE_RESYNC_LEFTOVERS"
- Collection *override_resync_residual_storage = BLI_findstring(
- &bmain->collections, OVERRIDE_RESYNC_RESIDUAL_STORAGE_NAME, offsetof(ID, name) + 2);
- if (override_resync_residual_storage != NULL && ID_IS_LINKED(override_resync_residual_storage)) {
- override_resync_residual_storage = NULL;
+ Collection *override_resync_residual_storage = static_cast<Collection *>(BLI_findstring(
+ &bmain->collections, OVERRIDE_RESYNC_RESIDUAL_STORAGE_NAME, offsetof(ID, name) + 2));
+ if (override_resync_residual_storage != nullptr &&
+ ID_IS_LINKED(override_resync_residual_storage)) {
+ override_resync_residual_storage = nullptr;
}
- if (override_resync_residual_storage == NULL) {
+ if (override_resync_residual_storage == nullptr) {
override_resync_residual_storage = BKE_collection_add(
bmain, scene->master_collection, OVERRIDE_RESYNC_RESIDUAL_STORAGE_NAME);
/* Hide the collection from viewport and render. */
@@ -2391,7 +2554,7 @@ void BKE_lib_override_library_main_resync(Main *bmain,
/* Essentially ensures that potentially new overrides of new objects will be instantiated. */
lib_override_library_create_post_process(
- bmain, scene, view_layer, NULL, NULL, NULL, override_resync_residual_storage, true);
+ bmain, scene, view_layer, nullptr, nullptr, nullptr, override_resync_residual_storage, true);
if (BKE_collection_is_empty(override_resync_residual_storage)) {
BKE_collection_delete(bmain, override_resync_residual_storage, true);
@@ -2414,14 +2577,15 @@ void BKE_lib_override_library_delete(Main *bmain, ID *id_root)
/* Tag all library overrides in the chains of dependencies from the given root one. */
BKE_main_relations_create(bmain, 0);
- LibOverrideGroupTagData data = {.bmain = bmain,
- .scene = NULL,
- .id_root = id_root,
- .hierarchy_root_id = id_root->override_library->hierarchy_root,
- .tag = LIB_TAG_DOIT,
- .missing_tag = LIB_TAG_MISSING,
- .is_override = true,
- .is_resync = false};
+ LibOverrideGroupTagData data{};
+ data.bmain = bmain;
+ data.scene = nullptr;
+ data.id_root = id_root;
+ data.hierarchy_root_id = id_root->override_library->hierarchy_root;
+ data.tag = LIB_TAG_DOIT;
+ data.missing_tag = LIB_TAG_MISSING;
+ data.is_override = true;
+ data.is_resync = false;
lib_override_group_tag_data_object_to_collection_init(&data);
lib_override_overrides_group_tag(&data);
@@ -2463,19 +2627,19 @@ void BKE_lib_override_library_make_local(ID *id)
BKE_lib_override_library_free(&id->override_library, true);
Key *shape_key = BKE_key_from_id(id);
- if (shape_key != NULL) {
+ if (shape_key != nullptr) {
shape_key->id.flag &= ~LIB_EMBEDDED_DATA_LIB_OVERRIDE;
}
if (GS(id->name) == ID_SCE) {
Collection *master_collection = ((Scene *)id)->master_collection;
- if (master_collection != NULL) {
+ if (master_collection != nullptr) {
master_collection->id.flag &= ~LIB_EMBEDDED_DATA_LIB_OVERRIDE;
}
}
bNodeTree *node_tree = ntreeFromID(id);
- if (node_tree != NULL) {
+ if (node_tree != nullptr) {
node_tree->id.flag &= ~LIB_EMBEDDED_DATA_LIB_OVERRIDE;
}
}
@@ -2483,8 +2647,8 @@ void BKE_lib_override_library_make_local(ID *id)
BLI_INLINE IDOverrideLibraryRuntime *override_library_rna_path_runtime_ensure(
IDOverrideLibrary *override)
{
- if (override->runtime == NULL) {
- override->runtime = MEM_callocN(sizeof(*override->runtime), __func__);
+ if (override->runtime == nullptr) {
+ override->runtime = MEM_cnew<IDOverrideLibraryRuntime>(__func__);
}
return override->runtime;
}
@@ -2493,10 +2657,13 @@ BLI_INLINE IDOverrideLibraryRuntime *override_library_rna_path_runtime_ensure(
BLI_INLINE GHash *override_library_rna_path_mapping_ensure(IDOverrideLibrary *override)
{
IDOverrideLibraryRuntime *override_runtime = override_library_rna_path_runtime_ensure(override);
- if (override_runtime->rna_path_to_override_properties == NULL) {
+ if (override_runtime->rna_path_to_override_properties == nullptr) {
override_runtime->rna_path_to_override_properties = BLI_ghash_new(
BLI_ghashutil_strhash_p_murmur, BLI_ghashutil_strcmp, __func__);
- for (IDOverrideLibraryProperty *op = override->properties.first; op != NULL; op = op->next) {
+ for (IDOverrideLibraryProperty *op =
+ static_cast<IDOverrideLibraryProperty *>(override->properties.first);
+ op != nullptr;
+ op = op->next) {
BLI_ghash_insert(override_runtime->rna_path_to_override_properties, op->rna_path, op);
}
}
@@ -2508,7 +2675,7 @@ IDOverrideLibraryProperty *BKE_lib_override_library_property_find(IDOverrideLibr
const char *rna_path)
{
GHash *override_runtime = override_library_rna_path_mapping_ensure(override);
- return BLI_ghash_lookup(override_runtime, rna_path);
+ return static_cast<IDOverrideLibraryProperty *>(BLI_ghash_lookup(override_runtime, rna_path));
}
IDOverrideLibraryProperty *BKE_lib_override_library_property_get(IDOverrideLibrary *override,
@@ -2517,8 +2684,8 @@ IDOverrideLibraryProperty *BKE_lib_override_library_property_get(IDOverrideLibra
{
IDOverrideLibraryProperty *op = BKE_lib_override_library_property_find(override, rna_path);
- if (op == NULL) {
- op = MEM_callocN(sizeof(IDOverrideLibraryProperty), __func__);
+ if (op == nullptr) {
+ op = MEM_cnew<IDOverrideLibraryProperty>(__func__);
op->rna_path = BLI_strdup(rna_path);
BLI_addtail(&override->properties, op);
@@ -2539,11 +2706,12 @@ IDOverrideLibraryProperty *BKE_lib_override_library_property_get(IDOverrideLibra
bool BKE_lib_override_rna_property_find(PointerRNA *idpoin,
const IDOverrideLibraryProperty *library_prop,
PointerRNA *r_override_poin,
- PropertyRNA **r_override_prop)
+ PropertyRNA **r_override_prop,
+ int *r_index)
{
BLI_assert(RNA_struct_is_ID(idpoin->type) && ID_IS_OVERRIDE_LIBRARY(idpoin->data));
- return RNA_path_resolve_property(
- idpoin, library_prop->rna_path, r_override_poin, r_override_prop);
+ return RNA_path_resolve_property_full(
+ idpoin, library_prop->rna_path, r_override_poin, r_override_prop, r_index);
}
void lib_override_library_property_copy(IDOverrideLibraryProperty *op_dst,
@@ -2552,8 +2720,9 @@ void lib_override_library_property_copy(IDOverrideLibraryProperty *op_dst,
op_dst->rna_path = BLI_strdup(op_src->rna_path);
BLI_duplicatelist(&op_dst->operations, &op_src->operations);
- for (IDOverrideLibraryPropertyOperation *opop_dst = op_dst->operations.first,
- *opop_src = op_src->operations.first;
+ for (IDOverrideLibraryPropertyOperation *
+ opop_dst = static_cast<IDOverrideLibraryPropertyOperation *>(op_dst->operations.first),
+ *opop_src = static_cast<IDOverrideLibraryPropertyOperation *>(op_src->operations.first);
opop_dst;
opop_dst = opop_dst->next, opop_src = opop_src->next) {
lib_override_library_property_operation_copy(opop_dst, opop_src);
@@ -2562,7 +2731,7 @@ void lib_override_library_property_copy(IDOverrideLibraryProperty *op_dst,
void lib_override_library_property_clear(IDOverrideLibraryProperty *op)
{
- BLI_assert(op->rna_path != NULL);
+ BLI_assert(op->rna_path != nullptr);
MEM_freeN(op->rna_path);
@@ -2575,11 +2744,11 @@ void lib_override_library_property_clear(IDOverrideLibraryProperty *op)
void BKE_lib_override_library_property_delete(IDOverrideLibrary *override,
IDOverrideLibraryProperty *override_property)
{
- if (!ELEM(NULL, override->runtime, override->runtime->rna_path_to_override_properties)) {
+ if (!ELEM(nullptr, override->runtime, override->runtime->rna_path_to_override_properties)) {
BLI_ghash_remove(override->runtime->rna_path_to_override_properties,
override_property->rna_path,
- NULL,
- NULL);
+ nullptr,
+ nullptr);
}
lib_override_library_property_clear(override_property);
BLI_freelinkN(&override->properties, override_property);
@@ -2601,74 +2770,75 @@ IDOverrideLibraryPropertyOperation *BKE_lib_override_library_property_operation_
*r_strict = true;
}
- if (subitem_locname != NULL) {
- opop = BLI_findstring_ptr(&override_property->operations,
- subitem_locname,
- offsetof(IDOverrideLibraryPropertyOperation, subitem_local_name));
+ if (subitem_locname != nullptr) {
+ opop = static_cast<IDOverrideLibraryPropertyOperation *>(
+ BLI_findstring_ptr(&override_property->operations,
+ subitem_locname,
+ offsetof(IDOverrideLibraryPropertyOperation, subitem_local_name)));
- if (opop == NULL) {
- return NULL;
+ if (opop == nullptr) {
+ return nullptr;
}
- if (subitem_refname == NULL || opop->subitem_reference_name == NULL) {
- return subitem_refname == opop->subitem_reference_name ? opop : NULL;
+ if (subitem_refname == nullptr || opop->subitem_reference_name == nullptr) {
+ return subitem_refname == opop->subitem_reference_name ? opop : nullptr;
}
- return (subitem_refname != NULL && opop->subitem_reference_name != NULL &&
+ return (subitem_refname != nullptr && opop->subitem_reference_name != nullptr &&
STREQ(subitem_refname, opop->subitem_reference_name)) ?
opop :
- NULL;
+ nullptr;
}
- if (subitem_refname != NULL) {
- opop = BLI_findstring_ptr(
- &override_property->operations,
- subitem_refname,
- offsetof(IDOverrideLibraryPropertyOperation, subitem_reference_name));
+ if (subitem_refname != nullptr) {
+ opop = static_cast<IDOverrideLibraryPropertyOperation *>(
+ BLI_findstring_ptr(&override_property->operations,
+ subitem_refname,
+ offsetof(IDOverrideLibraryPropertyOperation, subitem_reference_name)));
- if (opop == NULL) {
- return NULL;
+ if (opop == nullptr) {
+ return nullptr;
}
- if (subitem_locname == NULL || opop->subitem_local_name == NULL) {
- return subitem_locname == opop->subitem_local_name ? opop : NULL;
+ if (subitem_locname == nullptr || opop->subitem_local_name == nullptr) {
+ return subitem_locname == opop->subitem_local_name ? opop : nullptr;
}
- return (subitem_locname != NULL && opop->subitem_local_name != NULL &&
+ return (subitem_locname != nullptr && opop->subitem_local_name != nullptr &&
STREQ(subitem_locname, opop->subitem_local_name)) ?
opop :
- NULL;
+ nullptr;
}
- if ((opop = BLI_listbase_bytes_find(
+ if ((opop = static_cast<IDOverrideLibraryPropertyOperation *>(BLI_listbase_bytes_find(
&override_property->operations,
&subitem_locindex,
sizeof(subitem_locindex),
- offsetof(IDOverrideLibraryPropertyOperation, subitem_local_index)))) {
- return ELEM(subitem_refindex, -1, opop->subitem_reference_index) ? opop : NULL;
+ offsetof(IDOverrideLibraryPropertyOperation, subitem_local_index))))) {
+ return ELEM(subitem_refindex, -1, opop->subitem_reference_index) ? opop : nullptr;
}
- if ((opop = BLI_listbase_bytes_find(
+ if ((opop = static_cast<IDOverrideLibraryPropertyOperation *>(BLI_listbase_bytes_find(
&override_property->operations,
&subitem_refindex,
sizeof(subitem_refindex),
- offsetof(IDOverrideLibraryPropertyOperation, subitem_reference_index)))) {
- return ELEM(subitem_locindex, -1, opop->subitem_local_index) ? opop : NULL;
+ offsetof(IDOverrideLibraryPropertyOperation, subitem_reference_index))))) {
+ return ELEM(subitem_locindex, -1, opop->subitem_local_index) ? opop : nullptr;
}
/* `index == -1` means all indices, that is a valid fallback in case we requested specific index.
*/
if (!strict && (subitem_locindex != subitem_defindex) &&
- (opop = BLI_listbase_bytes_find(
+ (opop = static_cast<IDOverrideLibraryPropertyOperation *>(BLI_listbase_bytes_find(
&override_property->operations,
&subitem_defindex,
sizeof(subitem_defindex),
- offsetof(IDOverrideLibraryPropertyOperation, subitem_local_index)))) {
+ offsetof(IDOverrideLibraryPropertyOperation, subitem_local_index))))) {
if (r_strict) {
*r_strict = false;
}
return opop;
}
- return NULL;
+ return nullptr;
}
IDOverrideLibraryPropertyOperation *BKE_lib_override_library_property_operation_get(
@@ -2691,8 +2861,8 @@ IDOverrideLibraryPropertyOperation *BKE_lib_override_library_property_operation_
strict,
r_strict);
- if (opop == NULL) {
- opop = MEM_callocN(sizeof(IDOverrideLibraryPropertyOperation), __func__);
+ if (opop == nullptr) {
+ opop = MEM_cnew<IDOverrideLibraryPropertyOperation>(__func__);
opop->operation = operation;
if (subitem_locname) {
opop->subitem_local_name = BLI_strdup(subitem_locname);
@@ -2746,13 +2916,13 @@ void BKE_lib_override_library_property_operation_delete(
}
bool BKE_lib_override_library_property_operation_operands_validate(
- struct IDOverrideLibraryPropertyOperation *override_property_operation,
- struct PointerRNA *ptr_dst,
- struct PointerRNA *ptr_src,
- struct PointerRNA *ptr_storage,
- struct PropertyRNA *prop_dst,
- struct PropertyRNA *prop_src,
- struct PropertyRNA *prop_storage)
+ IDOverrideLibraryPropertyOperation *override_property_operation,
+ PointerRNA *ptr_dst,
+ PointerRNA *ptr_src,
+ PointerRNA *ptr_storage,
+ PropertyRNA *prop_dst,
+ PropertyRNA *prop_src,
+ PropertyRNA *prop_storage)
{
switch (override_property_operation->operation) {
case IDOVERRIDE_LIBRARY_OP_NOOP:
@@ -2762,7 +2932,7 @@ bool BKE_lib_override_library_property_operation_operands_validate(
case IDOVERRIDE_LIBRARY_OP_SUBTRACT:
ATTR_FALLTHROUGH;
case IDOVERRIDE_LIBRARY_OP_MULTIPLY:
- if (ptr_storage == NULL || ptr_storage->data == NULL || prop_storage == NULL) {
+ if (ptr_storage == nullptr || ptr_storage->data == nullptr || prop_storage == nullptr) {
BLI_assert_msg(0, "Missing data to apply differential override operation.");
return false;
}
@@ -2772,8 +2942,8 @@ bool BKE_lib_override_library_property_operation_operands_validate(
case IDOVERRIDE_LIBRARY_OP_INSERT_BEFORE:
ATTR_FALLTHROUGH;
case IDOVERRIDE_LIBRARY_OP_REPLACE:
- if ((ptr_dst == NULL || ptr_dst->data == NULL || prop_dst == NULL) ||
- (ptr_src == NULL || ptr_src->data == NULL || prop_src == NULL)) {
+ if ((ptr_dst == nullptr || ptr_dst->data == nullptr || prop_dst == nullptr) ||
+ (ptr_src == nullptr || ptr_src->data == nullptr || prop_src == nullptr)) {
BLI_assert_msg(0, "Missing data to apply override operation.");
return false;
}
@@ -2784,10 +2954,10 @@ bool BKE_lib_override_library_property_operation_operands_validate(
void BKE_lib_override_library_validate(Main *UNUSED(bmain), ID *id, ReportList *reports)
{
- if (id->override_library == NULL) {
+ if (id->override_library == nullptr) {
return;
}
- if (id->override_library->reference == NULL) {
+ if (id->override_library->reference == nullptr) {
/* This is a template ID, could be linked or local, not an override. */
return;
}
@@ -2798,7 +2968,7 @@ void BKE_lib_override_library_validate(Main *UNUSED(bmain), ID *id, ReportList *
RPT_ERROR,
"Data corruption: data-block '%s' is using itself as library override reference",
id->name);
- id->override_library->reference = NULL;
+ id->override_library->reference = nullptr;
return;
}
if (!ID_IS_LINKED(id->override_library->reference)) {
@@ -2810,7 +2980,7 @@ void BKE_lib_override_library_validate(Main *UNUSED(bmain), ID *id, ReportList *
"library override reference",
id->name,
id->override_library->reference->name);
- id->override_library->reference = NULL;
+ id->override_library->reference = nullptr;
return;
}
}
@@ -2820,7 +2990,7 @@ void BKE_lib_override_library_main_validate(Main *bmain, ReportList *reports)
ID *id;
FOREACH_MAIN_ID_BEGIN (bmain, id) {
- if (id->override_library != NULL) {
+ if (id->override_library != nullptr) {
BKE_lib_override_library_validate(bmain, id, reports);
}
}
@@ -2833,7 +3003,7 @@ bool BKE_lib_override_library_status_check_local(Main *bmain, ID *local)
ID *reference = local->override_library->reference;
- if (reference == NULL) {
+ if (reference == nullptr) {
/* This is an override template, local status is always OK! */
return true;
}
@@ -2847,10 +3017,10 @@ bool BKE_lib_override_library_status_check_local(Main *bmain, ID *local)
Object *ob_local = (Object *)local;
if (ob_local->type == OB_ARMATURE) {
Object *ob_reference = (Object *)local->override_library->reference;
- BLI_assert(ob_local->data != NULL);
- BLI_assert(ob_reference->data != NULL);
- BKE_pose_ensure(bmain, ob_local, ob_local->data, true);
- BKE_pose_ensure(bmain, ob_reference, ob_reference->data, true);
+ BLI_assert(ob_local->data != nullptr);
+ BLI_assert(ob_reference->data != nullptr);
+ BKE_pose_ensure(bmain, ob_local, static_cast<bArmature *>(ob_local->data), true);
+ BKE_pose_ensure(bmain, ob_reference, static_cast<bArmature *>(ob_reference->data), true);
}
}
@@ -2860,15 +3030,16 @@ bool BKE_lib_override_library_status_check_local(Main *bmain, ID *local)
RNA_id_pointer_create(local, &rnaptr_local);
RNA_id_pointer_create(reference, &rnaptr_reference);
- if (!RNA_struct_override_matches(bmain,
- &rnaptr_local,
- &rnaptr_reference,
- NULL,
- 0,
- local->override_library,
- RNA_OVERRIDE_COMPARE_IGNORE_NON_OVERRIDABLE |
- RNA_OVERRIDE_COMPARE_IGNORE_OVERRIDDEN,
- NULL)) {
+ if (!RNA_struct_override_matches(
+ bmain,
+ &rnaptr_local,
+ &rnaptr_reference,
+ nullptr,
+ 0,
+ local->override_library,
+ (eRNAOverrideMatch)(RNA_OVERRIDE_COMPARE_IGNORE_NON_OVERRIDABLE |
+ RNA_OVERRIDE_COMPARE_IGNORE_OVERRIDDEN),
+ nullptr)) {
local->tag &= ~LIB_TAG_OVERRIDE_LIBRARY_REFOK;
return false;
}
@@ -2882,7 +3053,7 @@ bool BKE_lib_override_library_status_check_reference(Main *bmain, ID *local)
ID *reference = local->override_library->reference;
- if (reference == NULL) {
+ if (reference == nullptr) {
/* This is an override template, reference is virtual, so its status is always OK! */
return true;
}
@@ -2906,10 +3077,10 @@ bool BKE_lib_override_library_status_check_reference(Main *bmain, ID *local)
Object *ob_local = (Object *)local;
if (ob_local->type == OB_ARMATURE) {
Object *ob_reference = (Object *)local->override_library->reference;
- BLI_assert(ob_local->data != NULL);
- BLI_assert(ob_reference->data != NULL);
- BKE_pose_ensure(bmain, ob_local, ob_local->data, true);
- BKE_pose_ensure(bmain, ob_reference, ob_reference->data, true);
+ BLI_assert(ob_local->data != nullptr);
+ BLI_assert(ob_reference->data != nullptr);
+ BKE_pose_ensure(bmain, ob_local, static_cast<bArmature *>(ob_local->data), true);
+ BKE_pose_ensure(bmain, ob_reference, static_cast<bArmature *>(ob_reference->data), true);
}
}
@@ -2920,11 +3091,11 @@ bool BKE_lib_override_library_status_check_reference(Main *bmain, ID *local)
if (!RNA_struct_override_matches(bmain,
&rnaptr_local,
&rnaptr_reference,
- NULL,
+ nullptr,
0,
local->override_library,
RNA_OVERRIDE_COMPARE_IGNORE_OVERRIDDEN,
- NULL)) {
+ nullptr)) {
local->tag &= ~LIB_TAG_OVERRIDE_LIBRARY_REFOK;
return false;
}
@@ -2935,8 +3106,8 @@ bool BKE_lib_override_library_status_check_reference(Main *bmain, ID *local)
bool BKE_lib_override_library_operations_create(Main *bmain, ID *local)
{
BLI_assert(!ID_IS_LINKED(local));
- BLI_assert(local->override_library != NULL);
- const bool is_template = (local->override_library->reference == NULL);
+ BLI_assert(local->override_library != nullptr);
+ const bool is_template = (local->override_library->reference == nullptr);
bool created = false;
if (!is_template) {
@@ -2954,10 +3125,10 @@ bool BKE_lib_override_library_operations_create(Main *bmain, ID *local)
Object *ob_local = (Object *)local;
if (ob_local->type == OB_ARMATURE) {
Object *ob_reference = (Object *)local->override_library->reference;
- BLI_assert(ob_local->data != NULL);
- BLI_assert(ob_reference->data != NULL);
- BKE_pose_ensure(bmain, ob_local, ob_local->data, true);
- BKE_pose_ensure(bmain, ob_reference, ob_reference->data, true);
+ BLI_assert(ob_local->data != nullptr);
+ BLI_assert(ob_reference->data != nullptr);
+ BKE_pose_ensure(bmain, ob_local, static_cast<bArmature *>(ob_local->data), true);
+ BKE_pose_ensure(bmain, ob_reference, static_cast<bArmature *>(ob_reference->data), true);
}
}
@@ -2965,15 +3136,16 @@ bool BKE_lib_override_library_operations_create(Main *bmain, ID *local)
RNA_id_pointer_create(local, &rnaptr_local);
RNA_id_pointer_create(local->override_library->reference, &rnaptr_reference);
- eRNAOverrideMatchResult report_flags = 0;
- RNA_struct_override_matches(bmain,
- &rnaptr_local,
- &rnaptr_reference,
- NULL,
- 0,
- local->override_library,
- RNA_OVERRIDE_COMPARE_CREATE | RNA_OVERRIDE_COMPARE_RESTORE,
- &report_flags);
+ eRNAOverrideMatchResult report_flags = (eRNAOverrideMatchResult)0;
+ RNA_struct_override_matches(
+ bmain,
+ &rnaptr_local,
+ &rnaptr_reference,
+ nullptr,
+ 0,
+ local->override_library,
+ (eRNAOverrideMatch)(RNA_OVERRIDE_COMPARE_CREATE | RNA_OVERRIDE_COMPARE_RESTORE),
+ &report_flags);
if (report_flags & RNA_OVERRIDE_MATCH_RESULT_CREATED) {
created = true;
@@ -2999,8 +3171,9 @@ struct LibOverrideOpCreateData {
static void lib_override_library_operations_create_cb(TaskPool *__restrict pool, void *taskdata)
{
- struct LibOverrideOpCreateData *create_data = BLI_task_pool_user_data(pool);
- ID *id = taskdata;
+ LibOverrideOpCreateData *create_data = static_cast<LibOverrideOpCreateData *>(
+ BLI_task_pool_user_data(pool));
+ ID *id = static_cast<ID *>(taskdata);
if (BKE_lib_override_library_operations_create(create_data->bmain, id)) {
/* Technically no need for atomic, all jobs write the same value and we only care if one did
@@ -3029,12 +3202,14 @@ bool BKE_lib_override_library_main_operations_create(Main *bmain, const bool for
* #BKE_lib_override_library_operations_create is not a problem then. */
LISTBASE_FOREACH (Object *, ob, &bmain->objects) {
if (ob->type == OB_ARMATURE) {
- BLI_assert(ob->data != NULL);
- BKE_pose_ensure(bmain, ob, ob->data, true);
+ BLI_assert(ob->data != nullptr);
+ BKE_pose_ensure(bmain, ob, static_cast<bArmature *>(ob->data), true);
}
}
- struct LibOverrideOpCreateData create_pool_data = {.bmain = bmain, .changed = false};
+ LibOverrideOpCreateData create_pool_data{};
+ create_pool_data.bmain = bmain;
+ create_pool_data.changed = false;
TaskPool *task_pool = BLI_task_pool_create(&create_pool_data, TASK_PRIORITY_HIGH);
FOREACH_MAIN_ID_BEGIN (bmain, id) {
@@ -3045,14 +3220,15 @@ bool BKE_lib_override_library_main_operations_create(Main *bmain, const bool for
if (GS(id->name) == ID_OB) {
Object *ob = (Object *)id;
if (ob->type == OB_ARMATURE) {
- BLI_assert(ob->data != NULL);
- BKE_pose_ensure(bmain, ob, ob->data, true);
+ BLI_assert(ob->data != nullptr);
+ BKE_pose_ensure(bmain, ob, static_cast<bArmature *>(ob->data), true);
}
}
/* Only check overrides if we do have the real reference data available, and not some empty
* 'placeholder' for missing data (broken links). */
if ((id->override_library->reference->tag & LIB_TAG_MISSING) == 0) {
- BLI_task_pool_push(task_pool, lib_override_library_operations_create_cb, id, false, NULL);
+ BLI_task_pool_push(
+ task_pool, lib_override_library_operations_create_cb, id, false, nullptr);
}
else {
BKE_lib_override_library_properties_tag(
@@ -3123,10 +3299,10 @@ static bool lib_override_library_id_reset_do(Main *bmain,
ptr = RNA_property_pointer_get(&ptr, prop);
ptr_lib = RNA_property_pointer_get(&ptr_lib, prop_lib);
}
- if (ptr.owner_id != NULL && ptr_lib.owner_id != NULL) {
+ if (ptr.owner_id != nullptr && ptr_lib.owner_id != nullptr) {
BLI_assert(ptr.type == ptr_lib.type);
do_op_delete = !(RNA_struct_is_ID(ptr.type) &&
- ptr.owner_id->override_library != NULL &&
+ ptr.owner_id->override_library != nullptr &&
ptr.owner_id->override_library->reference == ptr_lib.owner_id);
}
}
@@ -3158,7 +3334,7 @@ void BKE_lib_override_library_id_reset(Main *bmain,
}
if (lib_override_library_id_reset_do(bmain, id_root, do_reset_system_override)) {
- if (id_root->override_library->runtime != NULL &&
+ if (id_root->override_library->runtime != nullptr &&
(id_root->override_library->runtime->tag & IDOVERRIDE_LIBRARY_RUNTIME_TAG_NEEDS_RELOAD) !=
0) {
BKE_lib_override_library_update(bmain, id_root);
@@ -3176,13 +3352,13 @@ static void lib_override_library_id_hierarchy_recursive_reset(Main *bmain,
}
void **entry_vp = BLI_ghash_lookup_p(bmain->relations->relations_from_pointers, id_root);
- if (entry_vp == NULL) {
+ if (entry_vp == nullptr) {
/* This ID is not used by nor using any other ID. */
lib_override_library_id_reset_do(bmain, id_root, do_reset_system_override);
return;
}
- MainIDRelationsEntry *entry = *entry_vp;
+ MainIDRelationsEntry *entry = static_cast<MainIDRelationsEntry *>(*entry_vp);
if (entry->tags & MAINIDRELATIONS_ENTRY_TAGS_PROCESSED) {
/* This ID has already been processed. */
return;
@@ -3194,7 +3370,7 @@ static void lib_override_library_id_hierarchy_recursive_reset(Main *bmain,
* relationship hierarchy. */
entry->tags |= MAINIDRELATIONS_ENTRY_TAGS_PROCESSED;
- for (MainIDRelationsEntryItem *to_id_entry = entry->to_ids; to_id_entry != NULL;
+ for (MainIDRelationsEntryItem *to_id_entry = entry->to_ids; to_id_entry != nullptr;
to_id_entry = to_id_entry->next) {
if ((to_id_entry->usage_flag & IDWALK_CB_OVERRIDE_LIBRARY_NOT_OVERRIDABLE) != 0) {
/* Never consider non-overridable relationships ('from', 'parents', 'owner' etc. pointers) as
@@ -3202,9 +3378,9 @@ static void lib_override_library_id_hierarchy_recursive_reset(Main *bmain,
continue;
}
/* We only consider IDs from the same library. */
- if (*to_id_entry->id_pointer.to != NULL) {
+ if (*to_id_entry->id_pointer.to != nullptr) {
ID *to_id = *to_id_entry->id_pointer.to;
- if (to_id->override_library != NULL) {
+ if (to_id->override_library != nullptr) {
lib_override_library_id_hierarchy_recursive_reset(bmain, to_id, do_reset_system_override);
}
}
@@ -3223,7 +3399,7 @@ void BKE_lib_override_library_id_hierarchy_reset(Main *bmain,
ID *id;
FOREACH_MAIN_ID_BEGIN (bmain, id) {
- if (!ID_IS_OVERRIDE_LIBRARY_REAL(id) || id->override_library->runtime == NULL ||
+ if (!ID_IS_OVERRIDE_LIBRARY_REAL(id) || id->override_library->runtime == nullptr ||
(id->override_library->runtime->tag & IDOVERRIDE_LIBRARY_RUNTIME_TAG_NEEDS_RELOAD) == 0) {
continue;
}
@@ -3233,11 +3409,11 @@ void BKE_lib_override_library_id_hierarchy_reset(Main *bmain,
FOREACH_MAIN_ID_END;
}
-void BKE_lib_override_library_operations_tag(struct IDOverrideLibraryProperty *override_property,
+void BKE_lib_override_library_operations_tag(IDOverrideLibraryProperty *override_property,
const short tag,
const bool do_set)
{
- if (override_property != NULL) {
+ if (override_property != nullptr) {
if (do_set) {
override_property->tag |= tag;
}
@@ -3256,18 +3432,18 @@ void BKE_lib_override_library_operations_tag(struct IDOverrideLibraryProperty *o
}
}
-void BKE_lib_override_library_properties_tag(struct IDOverrideLibrary *override,
+void BKE_lib_override_library_properties_tag(IDOverrideLibrary *override,
const short tag,
const bool do_set)
{
- if (override != NULL) {
+ if (override != nullptr) {
LISTBASE_FOREACH (IDOverrideLibraryProperty *, op, &override->properties) {
BKE_lib_override_library_operations_tag(op, tag, do_set);
}
}
}
-void BKE_lib_override_library_main_tag(struct Main *bmain, const short tag, const bool do_set)
+void BKE_lib_override_library_main_tag(Main *bmain, const short tag, const bool do_set)
{
ID *id;
@@ -3279,7 +3455,7 @@ void BKE_lib_override_library_main_tag(struct Main *bmain, const short tag, cons
FOREACH_MAIN_ID_END;
}
-void BKE_lib_override_library_id_unused_cleanup(struct ID *local)
+void BKE_lib_override_library_id_unused_cleanup(ID *local)
{
if (ID_IS_OVERRIDE_LIBRARY_REAL(local)) {
LISTBASE_FOREACH_MUTABLE (
@@ -3298,7 +3474,7 @@ void BKE_lib_override_library_id_unused_cleanup(struct ID *local)
}
}
-void BKE_lib_override_library_main_unused_cleanup(struct Main *bmain)
+void BKE_lib_override_library_main_unused_cleanup(Main *bmain)
{
ID *id;
@@ -3354,10 +3530,10 @@ void BKE_lib_override_library_update(Main *bmain, ID *local)
ID *tmp_id = BKE_id_copy_ex(bmain,
local->override_library->reference,
- NULL,
+ nullptr,
LIB_ID_COPY_DEFAULT | LIB_ID_COPY_NO_LIB_OVERRIDE_LOCAL_DATA_FLAG);
- if (tmp_id == NULL) {
+ if (tmp_id == nullptr) {
return;
}
@@ -3373,12 +3549,12 @@ void BKE_lib_override_library_update(Main *bmain, ID *local)
* collections' parents are fully runtime and reconstructed later. */
Key *local_key = BKE_key_from_id(local);
Key *tmp_key = BKE_key_from_id(tmp_id);
- if (local_key != NULL && tmp_key != NULL) {
+ if (local_key != nullptr && tmp_key != nullptr) {
tmp_key->id.flag |= (local_key->id.flag & LIB_EMBEDDED_DATA_LIB_OVERRIDE);
tmp_key->id.lib = local_key->id.lib;
}
- PointerRNA rnaptr_src, rnaptr_dst, rnaptr_storage_stack, *rnaptr_storage = NULL;
+ PointerRNA rnaptr_src, rnaptr_dst, rnaptr_storage_stack, *rnaptr_storage = nullptr;
RNA_id_pointer_create(local, &rnaptr_src);
RNA_id_pointer_create(tmp_id, &rnaptr_dst);
if (local->override_library->storage) {
@@ -3393,11 +3569,13 @@ void BKE_lib_override_library_update(Main *bmain, ID *local)
local->override_library,
RNA_OVERRIDE_APPLY_FLAG_NOP);
+ lib_override_object_posemode_transfer(tmp_id, local);
+
/* This also transfers all pointers (memory) owned by local to tmp_id, and vice-versa.
* So when we'll free tmp_id, we'll actually free old, outdated data from local. */
lib_override_id_swap(bmain, local, tmp_id);
- if (local_key != NULL && tmp_key != NULL) {
+ if (local_key != nullptr && tmp_key != nullptr) {
/* This is some kind of hard-coded 'always enforced override'. */
lib_override_id_swap(bmain, &local_key->id, &tmp_key->id);
tmp_key->id.flag |= (local_key->id.flag & LIB_EMBEDDED_DATA_LIB_OVERRIDE);
@@ -3417,7 +3595,7 @@ void BKE_lib_override_library_update(Main *bmain, ID *local)
/* Fun times again, thanks to bone pointers in pose data of objects. We keep same ID addresses,
* but internal data has changed for sure, so we need to invalidate pose-bones caches. */
LISTBASE_FOREACH (Object *, ob, &bmain->objects) {
- if (ob->pose != NULL && ob->data == local) {
+ if (ob->pose != nullptr && ob->data == local) {
BLI_assert(ob->type == OB_ARMATURE);
ob->pose->flag |= POSE_RECALC;
/* We need to clear pose bone pointers immediately, some code may access those before pose
@@ -3432,7 +3610,7 @@ void BKE_lib_override_library_update(Main *bmain, ID *local)
/* XXX For until we get fully shadow copies, we still need to ensure storage releases
* its usage of any ID pointers it may have. */
BKE_id_free_ex(bmain, local->override_library->storage, LIB_ID_FREE_NO_UI_USER, true);
- local->override_library->storage = NULL;
+ local->override_library->storage = nullptr;
}
local->tag |= LIB_TAG_OVERRIDE_LIBRARY_REFOK;
@@ -3456,7 +3634,7 @@ void BKE_lib_override_library_main_update(Main *bmain)
G_MAIN = bmain;
FOREACH_MAIN_ID_BEGIN (bmain, id) {
- if (id->override_library != NULL) {
+ if (id->override_library != nullptr) {
BKE_lib_override_library_update(bmain, id);
}
}
@@ -3465,7 +3643,7 @@ void BKE_lib_override_library_main_update(Main *bmain)
G_MAIN = orig_gmain;
}
-bool BKE_lib_override_library_id_is_user_deletable(struct Main *bmain, struct ID *id)
+bool BKE_lib_override_library_id_is_user_deletable(Main *bmain, ID *id)
{
/* The only strong known case currently are objects used by override collections. */
/* TODO: There are most likely other cases... This may need to be addressed in a better way at
@@ -3514,11 +3692,11 @@ ID *BKE_lib_override_library_operations_store_start(Main *bmain,
/* This is actually purely local data with an override template, or one of those embedded IDs
* (root node trees, master collections or shape-keys) that cannot have their own override.
* Nothing to do here! */
- return NULL;
+ return nullptr;
}
BLI_assert(ID_IS_OVERRIDE_LIBRARY_REAL(local));
- BLI_assert(override_storage != NULL);
+ BLI_assert(override_storage != nullptr);
UNUSED_VARS_NDEBUG(override_storage);
/* Forcefully ensure we know about all needed override operations. */
@@ -3546,7 +3724,7 @@ ID *BKE_lib_override_library_operations_store_start(Main *bmain,
* actually a (performances) issue here, before doing it. */
storage_id = BKE_id_copy((Main *)override_storage, local);
- if (storage_id != NULL) {
+ if (storage_id != nullptr) {
PointerRNA rnaptr_reference, rnaptr_final, rnaptr_storage;
RNA_id_pointer_create(local->override_library->reference, &rnaptr_reference);
RNA_id_pointer_create(local, &rnaptr_final);
@@ -3555,11 +3733,11 @@ ID *BKE_lib_override_library_operations_store_start(Main *bmain,
if (!RNA_struct_override_store(
bmain, &rnaptr_final, &rnaptr_reference, &rnaptr_storage, local->override_library)) {
BKE_id_free_ex(override_storage, storage_id, LIB_ID_FREE_NO_UI_USER, true);
- storage_id = NULL;
+ storage_id = nullptr;
}
}
#else
- storage_id = NULL;
+ storage_id = nullptr;
#endif
local->override_library->storage = storage_id;
@@ -3577,7 +3755,7 @@ void BKE_lib_override_library_operations_store_end(
/* Nothing else to do here really, we need to keep all temp override storage data-blocks in
* memory until whole file is written anyway (otherwise we'd get mem pointers overlap). */
- local->override_library->storage = NULL;
+ local->override_library->storage = nullptr;
}
void BKE_lib_override_library_operations_store_finalize(OverrideLibraryStorage *override_storage)
diff --git a/source/blender/blenkernel/intern/lib_override_proxy_conversion.c b/source/blender/blenkernel/intern/lib_override_proxy_conversion.c
index 5e9d8e8c4d0..88f6fbb0ead 100644
--- a/source/blender/blenkernel/intern/lib_override_proxy_conversion.c
+++ b/source/blender/blenkernel/intern/lib_override_proxy_conversion.c
@@ -39,7 +39,8 @@ bool BKE_lib_override_library_proxy_convert(Main *bmain,
/* `proxy_group`, if defined, is the empty instantiating the collection from which the proxy is
* coming. */
Object *ob_proxy_group = ob_proxy->proxy_group;
- const bool is_override_instancing_object = ob_proxy_group != NULL;
+ const bool is_override_instancing_object = (ob_proxy_group != NULL) &&
+ (ob_proxy_group->instance_collection != NULL);
ID *id_root = is_override_instancing_object ? &ob_proxy_group->instance_collection->id :
&ob_proxy->proxy->id;
ID *id_instance_hint = is_override_instancing_object ? &ob_proxy_group->id : &ob_proxy->id;
@@ -82,7 +83,7 @@ bool BKE_lib_override_library_proxy_convert(Main *bmain,
FOREACH_MAIN_ID_END;
return BKE_lib_override_library_create(
- bmain, scene, view_layer, ob_proxy->id.lib, id_root, id_root, id_instance_hint, NULL);
+ bmain, scene, view_layer, ob_proxy->id.lib, id_root, id_root, id_instance_hint, NULL, false);
}
static void lib_override_library_proxy_convert_do(Main *bmain,
diff --git a/source/blender/blenkernel/intern/lib_remap.c b/source/blender/blenkernel/intern/lib_remap.c
index 971db852463..246999a1179 100644
--- a/source/blender/blenkernel/intern/lib_remap.c
+++ b/source/blender/blenkernel/intern/lib_remap.c
@@ -75,6 +75,7 @@ static void foreach_libblock_remap_callback_skip(const ID *UNUSED(id_owner),
{
ID *id = *id_ptr;
BLI_assert(id != NULL);
+
if (is_indirect) {
id->runtime.remap.skipped_indirect++;
}
@@ -82,8 +83,9 @@ static void foreach_libblock_remap_callback_skip(const ID *UNUSED(id_owner),
id->runtime.remap.skipped_direct++;
}
else {
- BLI_assert(0);
+ BLI_assert_unreachable();
}
+
if (cb_flag & IDWALK_CB_USER) {
id->runtime.remap.skipped_refcounted++;
}
@@ -452,7 +454,7 @@ static void libblock_remap_reset_remapping_status_callback(ID *old_id,
* \param old_id: the data-block to dereference (may be NULL if \a id is non-NULL).
* \param new_id: the new data-block to replace \a old_id references with (may be NULL).
* \param r_id_remap_data: if non-NULL, the IDRemap struct to use
- * (uselful to retrieve info about remapping process).
+ * (useful to retrieve info about remapping process).
*/
ATTR_NONNULL(1)
static void libblock_remap_data(Main *bmain,
@@ -553,7 +555,6 @@ static void libblock_remap_foreach_idpair_cb(ID *old_id, ID *new_id, void *user_
new_id ? new_id->name : "<NULL>",
new_id,
old_id->us - skipped_refcounted);
- BLI_assert(0);
}
const int skipped_direct = old_id->runtime.remap.skipped_direct;
diff --git a/source/blender/blenkernel/intern/linestyle.c b/source/blender/blenkernel/intern/linestyle.c
index c0eb1955fdf..12a661d139b 100644
--- a/source/blender/blenkernel/intern/linestyle.c
+++ b/source/blender/blenkernel/intern/linestyle.c
@@ -55,7 +55,7 @@ static void linestyle_copy_data(Main *bmain, ID *id_dst, const ID *id_src, const
FreestyleLineStyle *linestyle_dst = (FreestyleLineStyle *)id_dst;
const FreestyleLineStyle *linestyle_src = (const FreestyleLineStyle *)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;
/* We always need allocation of our private ID data. */
const int flag_private_id_data = flag & ~LIB_ID_CREATE_NO_ALLOCATE;
diff --git a/source/blender/blenkernel/intern/main.c b/source/blender/blenkernel/intern/main.c
index 03e03dacfbc..b9ed783fa8c 100644
--- a/source/blender/blenkernel/intern/main.c
+++ b/source/blender/blenkernel/intern/main.c
@@ -502,13 +502,13 @@ BlendThumbnail *BKE_main_thumbnail_from_imbuf(Main *bmain, ImBuf *img)
}
if (img) {
- const size_t sz = BLEN_THUMB_MEMSIZE(img->x, img->y);
- data = MEM_mallocN(sz, __func__);
+ const size_t data_size = BLEN_THUMB_MEMSIZE(img->x, img->y);
+ data = MEM_mallocN(data_size, __func__);
IMB_rect_from_float(img); /* Just in case... */
data->width = img->x;
data->height = img->y;
- memcpy(data->rect, img->rect, sz - sizeof(*data));
+ memcpy(data->rect, img->rect, data_size - sizeof(*data));
}
if (bmain) {
diff --git a/source/blender/blenkernel/intern/material.c b/source/blender/blenkernel/intern/material.c
index 002b496393f..04a07fb42be 100644
--- a/source/blender/blenkernel/intern/material.c
+++ b/source/blender/blenkernel/intern/material.c
@@ -1123,15 +1123,16 @@ void BKE_object_material_remap_calc(Object *ob_dst, Object *ob_src, short *remap
BLI_ghash_free(gh_mat_map, NULL, NULL);
}
-void BKE_object_material_from_eval_data(Main *bmain, Object *ob_orig, ID *data_eval)
+void BKE_object_material_from_eval_data(Main *bmain, Object *ob_orig, const ID *data_eval)
{
ID *data_orig = ob_orig->data;
short *orig_totcol = BKE_id_material_len_p(data_orig);
Material ***orig_mat = BKE_id_material_array_p(data_orig);
- short *eval_totcol = BKE_id_material_len_p(data_eval);
- Material ***eval_mat = BKE_id_material_array_p(data_eval);
+ /* Can cast away const, because the data is not changed. */
+ const short *eval_totcol = BKE_id_material_len_p((ID *)data_eval);
+ Material ***eval_mat = BKE_id_material_array_p((ID *)data_eval);
if (ELEM(NULL, orig_totcol, orig_mat, eval_totcol, eval_mat)) {
return;
@@ -1244,7 +1245,6 @@ bool BKE_object_material_slot_remove(Main *bmain, Object *ob)
/* this should never happen and used to crash */
if (ob->actcol <= 0) {
CLOG_ERROR(&LOG, "invalid material index %d, report a bug!", ob->actcol);
- BLI_assert(0);
return false;
}
@@ -1448,7 +1448,7 @@ static bool fill_texpaint_slots_cb(bNode *node, void *userdata)
slot->attribute_name = storage->name;
if (storage->type == SHD_ATTRIBUTE_GEOMETRY) {
const Mesh *mesh = (const Mesh *)fill_data->ob->data;
- CustomDataLayer *layer = BKE_id_attributes_color_find(&mesh->id, storage->name);
+ const CustomDataLayer *layer = BKE_id_attributes_color_find(&mesh->id, storage->name);
slot->valid = layer != NULL;
}
diff --git a/source/blender/blenkernel/intern/mesh.cc b/source/blender/blenkernel/intern/mesh.cc
index 628f59ae449..7c86aff6624 100644
--- a/source/blender/blenkernel/intern/mesh.cc
+++ b/source/blender/blenkernel/intern/mesh.cc
@@ -31,6 +31,7 @@
#include "BLI_string.h"
#include "BLI_task.hh"
#include "BLI_utildefines.h"
+#include "BLI_vector.hh"
#include "BLT_translation.h"
@@ -60,6 +61,7 @@
#include "BLO_read_write.h"
using blender::float3;
+using blender::Vector;
static void mesh_clear_geometry(Mesh *mesh);
static void mesh_tessface_clear_intern(Mesh *mesh, int free_customdata);
@@ -114,7 +116,7 @@ static void mesh_copy_data(Main *bmain, ID *id_dst, const ID *id_src, const int
CustomData_MeshMasks mask = CD_MASK_MESH;
if (mesh_src->id.tag & LIB_TAG_NO_MAIN) {
- /* For copies in depsgraph, keep data like origindex and orco. */
+ /* For copies in depsgraph, keep data like #CD_ORIGINDEX and #CD_ORCO. */
CustomData_MeshMasks_update(&mask, &CD_MASK_DERIVEDMESH);
}
@@ -208,46 +210,40 @@ static void mesh_blend_write(BlendWriter *writer, ID *id, const void *id_address
Mesh *mesh = (Mesh *)id;
const bool is_undo = BLO_write_is_undo(writer);
- CustomDataLayer *vlayers = nullptr, vlayers_buff[CD_TEMP_CHUNK_SIZE];
- CustomDataLayer *elayers = nullptr, elayers_buff[CD_TEMP_CHUNK_SIZE];
- CustomDataLayer *flayers = nullptr, flayers_buff[CD_TEMP_CHUNK_SIZE];
- CustomDataLayer *llayers = nullptr, llayers_buff[CD_TEMP_CHUNK_SIZE];
- CustomDataLayer *players = nullptr, players_buff[CD_TEMP_CHUNK_SIZE];
+ Vector<CustomDataLayer, 16> vert_layers;
+ Vector<CustomDataLayer, 16> edge_layers;
+ Vector<CustomDataLayer, 16> loop_layers;
+ Vector<CustomDataLayer, 16> poly_layers;
/* cache only - don't write */
mesh->mface = nullptr;
mesh->totface = 0;
memset(&mesh->fdata, 0, sizeof(mesh->fdata));
mesh->runtime = blender::dna::shallow_zero_initialize();
- flayers = flayers_buff;
/* Do not store actual geometry data in case this is a library override ID. */
if (ID_IS_OVERRIDE_LIBRARY(mesh) && !is_undo) {
mesh->mvert = nullptr;
mesh->totvert = 0;
memset(&mesh->vdata, 0, sizeof(mesh->vdata));
- vlayers = vlayers_buff;
mesh->medge = nullptr;
mesh->totedge = 0;
memset(&mesh->edata, 0, sizeof(mesh->edata));
- elayers = elayers_buff;
mesh->mloop = nullptr;
mesh->totloop = 0;
memset(&mesh->ldata, 0, sizeof(mesh->ldata));
- llayers = llayers_buff;
mesh->mpoly = nullptr;
mesh->totpoly = 0;
memset(&mesh->pdata, 0, sizeof(mesh->pdata));
- players = players_buff;
}
else {
- CustomData_blend_write_prepare(&mesh->vdata, &vlayers, vlayers_buff, ARRAY_SIZE(vlayers_buff));
- CustomData_blend_write_prepare(&mesh->edata, &elayers, elayers_buff, ARRAY_SIZE(elayers_buff));
- CustomData_blend_write_prepare(&mesh->ldata, &llayers, llayers_buff, ARRAY_SIZE(llayers_buff));
- CustomData_blend_write_prepare(&mesh->pdata, &players, players_buff, ARRAY_SIZE(players_buff));
+ CustomData_blend_write_prepare(mesh->vdata, vert_layers);
+ CustomData_blend_write_prepare(mesh->edata, edge_layers);
+ CustomData_blend_write_prepare(mesh->ldata, loop_layers);
+ CustomData_blend_write_prepare(mesh->pdata, poly_layers);
}
BLO_write_id_struct(writer, Mesh, id_address, &mesh->id);
@@ -264,33 +260,15 @@ static void mesh_blend_write(BlendWriter *writer, ID *id, const void *id_address
BLO_write_raw(writer, sizeof(MSelect) * mesh->totselect, mesh->mselect);
CustomData_blend_write(
- writer, &mesh->vdata, vlayers, mesh->totvert, CD_MASK_MESH.vmask, &mesh->id);
+ writer, &mesh->vdata, vert_layers, mesh->totvert, CD_MASK_MESH.vmask, &mesh->id);
CustomData_blend_write(
- writer, &mesh->edata, elayers, mesh->totedge, CD_MASK_MESH.emask, &mesh->id);
+ writer, &mesh->edata, edge_layers, mesh->totedge, CD_MASK_MESH.emask, &mesh->id);
/* fdata is really a dummy - written so slots align */
+ CustomData_blend_write(writer, &mesh->fdata, {}, mesh->totface, CD_MASK_MESH.fmask, &mesh->id);
CustomData_blend_write(
- writer, &mesh->fdata, flayers, mesh->totface, CD_MASK_MESH.fmask, &mesh->id);
+ writer, &mesh->ldata, loop_layers, mesh->totloop, CD_MASK_MESH.lmask, &mesh->id);
CustomData_blend_write(
- writer, &mesh->ldata, llayers, mesh->totloop, CD_MASK_MESH.lmask, &mesh->id);
- CustomData_blend_write(
- writer, &mesh->pdata, players, mesh->totpoly, CD_MASK_MESH.pmask, &mesh->id);
-
- /* Free temporary data */
-
- /* Free custom-data layers, when not assigned a buffer value. */
-#define CD_LAYERS_FREE(id) \
- if (id && id != id##_buff) { \
- MEM_freeN(id); \
- } \
- ((void)0)
-
- CD_LAYERS_FREE(vlayers);
- CD_LAYERS_FREE(elayers);
- // CD_LAYER_FREE(flayers); /* Never allocated. */
- CD_LAYERS_FREE(llayers);
- CD_LAYERS_FREE(players);
-
-#undef CD_LAYERS_FREE
+ writer, &mesh->pdata, poly_layers, mesh->totpoly, CD_MASK_MESH.pmask, &mesh->id);
}
static void mesh_blend_read_data(BlendDataReader *reader, ID *id)
@@ -1577,6 +1555,19 @@ void BKE_mesh_smooth_flag_set(Mesh *me, const bool use_smooth)
}
}
+void BKE_mesh_auto_smooth_flag_set(Mesh *me,
+ const bool use_auto_smooth,
+ const float auto_smooth_angle)
+{
+ if (use_auto_smooth) {
+ me->flag |= ME_AUTOSMOOTH;
+ me->smoothresh = auto_smooth_angle;
+ }
+ else {
+ me->flag &= ~ME_AUTOSMOOTH;
+ }
+}
+
int poly_find_loop_from_vert(const MPoly *poly, const MLoop *loopstart, uint vert)
{
for (int j = 0; j < poly->totloop; j++, loopstart++) {
@@ -1809,7 +1800,7 @@ void BKE_mesh_mselect_validate(Mesh *me)
break;
}
default: {
- BLI_assert(0);
+ BLI_assert_unreachable();
break;
}
}
diff --git a/source/blender/blenkernel/intern/mesh_boolean_convert.cc b/source/blender/blenkernel/intern/mesh_boolean_convert.cc
index 14bd6aa5b2f..a1ef2d2e6b5 100644
--- a/source/blender/blenkernel/intern/mesh_boolean_convert.cc
+++ b/source/blender/blenkernel/intern/mesh_boolean_convert.cc
@@ -791,7 +791,8 @@ Mesh *direct_mesh_boolean(Span<const Mesh *> meshes,
Span<Array<short>> material_remaps,
const bool use_self,
const bool hole_tolerant,
- const int boolean_mode)
+ const int boolean_mode,
+ Vector<int> *r_intersecting_edges)
{
#ifdef WITH_GMP
BLI_assert(meshes.size() == transforms.size());
@@ -828,7 +829,23 @@ Mesh *direct_mesh_boolean(Span<const Mesh *> meshes,
write_obj_mesh(m_out, "m_out");
}
- return imesh_to_mesh(&m_out, mim);
+ Mesh *result = imesh_to_mesh(&m_out, mim);
+
+ /* Store intersecting edge indices. */
+ if (r_intersecting_edges != nullptr) {
+ for (int fi : m_out.face_index_range()) {
+ const Face &face = *m_out.face(fi);
+ const MPoly &poly = result->mpoly[fi];
+ for (int corner_i : face.index_range()) {
+ if (face.is_intersect[corner_i]) {
+ int e_index = result->mloop[poly.loopstart + corner_i].e;
+ r_intersecting_edges->append(e_index);
+ }
+ }
+ }
+ }
+
+ return result;
#else // WITH_GMP
UNUSED_VARS(meshes,
transforms,
@@ -836,7 +853,8 @@ Mesh *direct_mesh_boolean(Span<const Mesh *> meshes,
target_transform,
use_self,
hole_tolerant,
- boolean_mode);
+ boolean_mode,
+ r_intersecting_edges);
return nullptr;
#endif // WITH_GMP
}
diff --git a/source/blender/blenkernel/intern/mesh_calc_edges.cc b/source/blender/blenkernel/intern/mesh_calc_edges.cc
index 5895eb7fd71..31e20750cf2 100644
--- a/source/blender/blenkernel/intern/mesh_calc_edges.cc
+++ b/source/blender/blenkernel/intern/mesh_calc_edges.cc
@@ -81,7 +81,7 @@ static void add_existing_edges_to_hash_maps(Mesh *mesh,
{
/* Assume existing edges are valid. */
threading::parallel_for_each(edge_maps, [&](EdgeMap &edge_map) {
- const int task_index = &edge_map - &edge_maps[0];
+ const int task_index = &edge_map - edge_maps.data();
for (const MEdge &edge : Span(mesh->medge, mesh->totedge)) {
OrderedEdge ordered_edge{edge.v1, edge.v2};
/* Only add the edge when it belongs into this map. */
@@ -98,7 +98,7 @@ static void add_polygon_edges_to_hash_maps(Mesh *mesh,
{
const Span<MLoop> loops{mesh->mloop, mesh->totloop};
threading::parallel_for_each(edge_maps, [&](EdgeMap &edge_map) {
- const int task_index = &edge_map - &edge_maps[0];
+ const int task_index = &edge_map - edge_maps.data();
for (const MPoly &poly : Span(mesh->mpoly, mesh->totpoly)) {
Span<MLoop> poly_loops = loops.slice(poly.loopstart, poly.totloop);
const MLoop *prev_loop = &poly_loops.last();
@@ -131,7 +131,7 @@ static void serialize_and_initialize_deduplicated_edges(MutableSpan<EdgeMap> edg
}
threading::parallel_for_each(edge_maps, [&](EdgeMap &edge_map) {
- const int task_index = &edge_map - &edge_maps[0];
+ const int task_index = &edge_map - edge_maps.data();
int new_edge_index = edge_index_offsets[task_index];
for (EdgeMap::MutableItem item : edge_map.items()) {
diff --git a/source/blender/blenkernel/intern/mesh_convert.cc b/source/blender/blenkernel/intern/mesh_convert.cc
index 0038a2aa806..48c49055899 100644
--- a/source/blender/blenkernel/intern/mesh_convert.cc
+++ b/source/blender/blenkernel/intern/mesh_convert.cc
@@ -12,6 +12,7 @@
#include "DNA_key_types.h"
#include "DNA_material_types.h"
#include "DNA_mesh_types.h"
+#include "DNA_meshdata_types.h"
#include "DNA_meta_types.h"
#include "DNA_object_types.h"
#include "DNA_pointcloud_types.h"
@@ -40,7 +41,6 @@
#include "BKE_mesh_runtime.h"
#include "BKE_mesh_wrapper.h"
#include "BKE_modifier.h"
-#include "BKE_spline.hh"
/* these 2 are only used by conversion functions */
#include "BKE_curve.h"
/* -- */
@@ -889,8 +889,15 @@ static void object_for_curve_to_mesh_free(Object *temp_object)
curve.editnurb = nullptr;
}
- BKE_id_free(nullptr, temp_object->data);
+ /* Only free the final object data if it is *not* stored in the #data_eval field. This is still
+ * necessary because #temp_object's data could be replaced by a #Curve data-block that isn't also
+ * assigned to #data_eval. */
+ const bool object_data_stored_in_data_eval = final_object_data == temp_object->runtime.data_eval;
+
BKE_id_free(nullptr, temp_object);
+ if (!object_data_stored_in_data_eval) {
+ BKE_id_free(nullptr, final_object_data);
+ }
}
/**
@@ -936,24 +943,9 @@ static void curve_to_mesh_eval_ensure(Object &object)
BKE_object_runtime_free_data(&taper_object);
}
-/* Necessary because #BKE_object_get_evaluated_mesh doesn't look in the geometry set yet. */
-static const Mesh *get_evaluated_mesh_from_object(const Object *object)
-{
- const Mesh *mesh = BKE_object_get_evaluated_mesh(object);
- if (mesh) {
- return mesh;
- }
- GeometrySet *geometry_set_eval = object->runtime.geometry_set_eval;
- if (geometry_set_eval) {
- return geometry_set_eval->get_mesh_for_read();
- }
- return nullptr;
-}
-
static const Curves *get_evaluated_curves_from_object(const Object *object)
{
- GeometrySet *geometry_set_eval = object->runtime.geometry_set_eval;
- if (geometry_set_eval) {
+ if (GeometrySet *geometry_set_eval = object->runtime.geometry_set_eval) {
return geometry_set_eval->get_curves_for_read();
}
return nullptr;
@@ -961,12 +953,10 @@ static const Curves *get_evaluated_curves_from_object(const Object *object)
static Mesh *mesh_new_from_evaluated_curve_type_object(const Object *evaluated_object)
{
- const Mesh *mesh = get_evaluated_mesh_from_object(evaluated_object);
- if (mesh) {
+ if (const Mesh *mesh = BKE_object_get_evaluated_mesh(evaluated_object)) {
return BKE_mesh_copy_for_eval(mesh, false);
}
- const Curves *curves = get_evaluated_curves_from_object(evaluated_object);
- if (curves) {
+ if (const Curves *curves = get_evaluated_curves_from_object(evaluated_object)) {
return blender::bke::curve_to_wire_mesh(blender::bke::CurvesGeometry::wrap(curves->geometry));
}
return nullptr;
@@ -1385,7 +1375,7 @@ static void shapekey_layers_to_keyblocks(Mesh *mesh_src, Mesh *mesh_dst, int act
for (i = 0; i < tot; i++) {
CustomDataLayer *layer =
&mesh_src->vdata.layers[CustomData_get_layer_index_n(&mesh_src->vdata, CD_SHAPEKEY, i)];
- float(*cos)[3], (*kbcos)[3];
+ float(*kbcos)[3];
for (kb = (KeyBlock *)mesh_dst->key->block.first; kb; kb = kb->next) {
if (kb->uid == layer->uid) {
@@ -1402,7 +1392,8 @@ static void shapekey_layers_to_keyblocks(Mesh *mesh_src, Mesh *mesh_dst, int act
MEM_freeN(kb->data);
}
- cos = (float(*)[3])CustomData_get_layer_n(&mesh_src->vdata, CD_SHAPEKEY, i);
+ const float(*cos)[3] = (const float(*)[3])CustomData_get_layer_n(
+ &mesh_src->vdata, CD_SHAPEKEY, i);
kb->totelem = mesh_src->totvert;
kb->data = kbcos = (float(*)[3])MEM_malloc_arrayN(kb->totelem, sizeof(float[3]), __func__);
diff --git a/source/blender/blenkernel/intern/mesh_evaluate.cc b/source/blender/blenkernel/intern/mesh_evaluate.cc
index ec2660a0145..de0489d668f 100644
--- a/source/blender/blenkernel/intern/mesh_evaluate.cc
+++ b/source/blender/blenkernel/intern/mesh_evaluate.cc
@@ -18,8 +18,9 @@
#include "BLI_alloca.h"
#include "BLI_bitmap.h"
#include "BLI_edgehash.h"
-
+#include "BLI_index_range.hh"
#include "BLI_math.h"
+#include "BLI_span.hh"
#include "BLI_utildefines.h"
#include "BKE_customdata.h"
@@ -27,6 +28,10 @@
#include "BKE_mesh.h"
#include "BKE_multires.h"
+using blender::IndexRange;
+using blender::MutableSpan;
+using blender::Span;
+
/* -------------------------------------------------------------------- */
/** \name Polygon Calculations
* \{ */
@@ -644,7 +649,7 @@ static void bm_corners_to_loops_ex(ID *id,
MFace *mf = mface + findex;
for (int i = 0; i < numTex; i++) {
- MTFace *texface = (MTFace *)CustomData_get_n(fdata, CD_MTFACE, findex, i);
+ const MTFace *texface = (const MTFace *)CustomData_get_n(fdata, CD_MTFACE, findex, i);
MLoopUV *mloopuv = (MLoopUV *)CustomData_get_n(ldata, CD_MLOOPUV, loopstart, i);
copy_v2_v2(mloopuv->uv, texface->uv[0]);
@@ -662,7 +667,7 @@ static void bm_corners_to_loops_ex(ID *id,
for (int i = 0; i < numCol; i++) {
MLoopCol *mloopcol = (MLoopCol *)CustomData_get_n(ldata, CD_PROP_BYTE_COLOR, loopstart, i);
- MCol *mcol = (MCol *)CustomData_get_n(fdata, CD_MCOL, findex, i);
+ const MCol *mcol = (const MCol *)CustomData_get_n(fdata, CD_MCOL, findex, i);
MESH_MLOOPCOL_FROM_MCOL(mloopcol, &mcol[0]);
mloopcol++;
@@ -678,7 +683,7 @@ static void bm_corners_to_loops_ex(ID *id,
if (CustomData_has_layer(fdata, CD_TESSLOOPNORMAL)) {
float(*lnors)[3] = (float(*)[3])CustomData_get(ldata, loopstart, CD_NORMAL);
- short(*tlnors)[3] = (short(*)[3])CustomData_get(fdata, findex, CD_TESSLOOPNORMAL);
+ const short(*tlnors)[3] = (short(*)[3])CustomData_get(fdata, findex, CD_TESSLOOPNORMAL);
const int max = mf->v4 ? 4 : 3;
for (int i = 0; i < max; i++, lnors++, tlnors++) {
@@ -688,8 +693,8 @@ static void bm_corners_to_loops_ex(ID *id,
if (CustomData_has_layer(fdata, CD_MDISPS)) {
MDisps *ld = (MDisps *)CustomData_get(ldata, loopstart, CD_MDISPS);
- MDisps *fd = (MDisps *)CustomData_get(fdata, findex, CD_MDISPS);
- float(*disps)[3] = fd->disps;
+ const MDisps *fd = (const MDisps *)CustomData_get(fdata, findex, CD_MDISPS);
+ const float(*disps)[3] = fd->disps;
int tot = mf->v4 ? 4 : 3;
int corners;
@@ -1113,58 +1118,49 @@ void BKE_mesh_flush_select_from_polys(Mesh *me)
me->mvert, me->totvert, me->mloop, me->medge, me->totedge, me->mpoly, me->totpoly);
}
-void BKE_mesh_flush_select_from_verts_ex(const MVert *mvert,
- const int UNUSED(totvert),
- const MLoop *mloop,
- MEdge *medge,
- const int totedge,
- MPoly *mpoly,
- const int totpoly)
+static void mesh_flush_select_from_verts(const Span<MVert> verts,
+ const Span<MLoop> loops,
+ MutableSpan<MEdge> edges,
+ MutableSpan<MPoly> polys)
{
- MEdge *med;
- MPoly *mp;
-
- /* edges */
- int i = totedge;
- for (med = medge; i--; med++) {
- if ((med->flag & ME_HIDE) == 0) {
- if ((mvert[med->v1].flag & SELECT) && (mvert[med->v2].flag & SELECT)) {
- med->flag |= SELECT;
+ for (const int i : edges.index_range()) {
+ if ((edges[i].flag & ME_HIDE) == 0) {
+ MEdge &edge = edges[i];
+ if ((verts[edge.v1].flag & SELECT) && (verts[edge.v2].flag & SELECT)) {
+ edge.flag |= SELECT;
}
else {
- med->flag &= ~SELECT;
+ edge.flag &= ~SELECT;
}
}
}
- /* polys */
- i = totpoly;
- for (mp = mpoly; i--; mp++) {
- if ((mp->flag & ME_HIDE) == 0) {
- bool ok = true;
- const MLoop *ml;
- int j;
- j = mp->totloop;
- for (ml = &mloop[mp->loopstart]; j--; ml++) {
- if ((mvert[ml->v].flag & SELECT) == 0) {
- ok = false;
- break;
- }
- }
-
- if (ok) {
- mp->flag |= ME_FACE_SEL;
- }
- else {
- mp->flag &= (char)~ME_FACE_SEL;
+ for (const int i : polys.index_range()) {
+ if (polys[i].flag & ME_HIDE) {
+ continue;
+ }
+ MPoly &poly = polys[i];
+ bool all_verts_selected = true;
+ for (const MLoop &loop : loops.slice(poly.loopstart, poly.totloop)) {
+ if (!(verts[loop.v].flag & SELECT)) {
+ all_verts_selected = false;
}
}
+ if (all_verts_selected) {
+ poly.flag |= ME_FACE_SEL;
+ }
+ else {
+ poly.flag &= (char)~ME_FACE_SEL;
+ }
}
}
+
void BKE_mesh_flush_select_from_verts(Mesh *me)
{
- BKE_mesh_flush_select_from_verts_ex(
- me->mvert, me->totvert, me->mloop, me->medge, me->totedge, me->mpoly, me->totpoly);
+ mesh_flush_select_from_verts({me->mvert, me->totvert},
+ {me->mloop, me->totloop},
+ {me->medge, me->totedge},
+ {me->mpoly, me->totpoly});
}
/** \} */
diff --git a/source/blender/blenkernel/intern/mesh_normals.cc b/source/blender/blenkernel/intern/mesh_normals.cc
index ba1004e8371..2366b7526a1 100644
--- a/source/blender/blenkernel/intern/mesh_normals.cc
+++ b/source/blender/blenkernel/intern/mesh_normals.cc
@@ -345,7 +345,7 @@ void BKE_mesh_calc_normals_poly_and_vertex(const MVert *mvert,
const float (*BKE_mesh_vertex_normals_ensure(const Mesh *mesh))[3]
{
- if (!(BKE_mesh_vertex_normals_are_dirty(mesh) || BKE_mesh_poly_normals_are_dirty(mesh))) {
+ if (!BKE_mesh_vertex_normals_are_dirty(mesh)) {
BLI_assert(mesh->runtime.vert_normals != nullptr || mesh->totvert == 0);
return mesh->runtime.vert_normals;
}
@@ -356,7 +356,7 @@ const float (*BKE_mesh_vertex_normals_ensure(const Mesh *mesh))[3]
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))) {
+ if (!BKE_mesh_vertex_normals_are_dirty(mesh)) {
BLI_assert(mesh->runtime.vert_normals != nullptr);
BLI_mutex_unlock(normals_mutex);
return mesh->runtime.vert_normals;
diff --git a/source/blender/blenkernel/intern/mesh_remesh_voxel.cc b/source/blender/blenkernel/intern/mesh_remesh_voxel.cc
index 02c9f61957d..85aed01ce52 100644
--- a/source/blender/blenkernel/intern/mesh_remesh_voxel.cc
+++ b/source/blender/blenkernel/intern/mesh_remesh_voxel.cc
@@ -290,7 +290,7 @@ void BKE_mesh_remesh_reproject_paint_mask(Mesh *target, Mesh *source)
&target->vdata, CD_PAINT_MASK, CD_CALLOC, nullptr, target->totvert);
}
- float *source_mask;
+ const float *source_mask;
if (CustomData_has_layer(&source->vdata, CD_PAINT_MASK)) {
source_mask = (float *)CustomData_get_layer(&source->vdata, CD_PAINT_MASK);
}
@@ -375,7 +375,7 @@ void BKE_remesh_reproject_vertex_paint(Mesh *target, const Mesh *source)
while ((layer = BKE_id_attribute_from_index(
const_cast<ID *>(&source->id), i++, ATTR_DOMAIN_MASK_COLOR, CD_MASK_COLOR_ALL))) {
- AttributeDomain domain = BKE_id_attribute_domain(&source->id, layer);
+ eAttrDomain domain = BKE_id_attribute_domain(&source->id, layer);
CustomData *target_cdata = domain == ATTR_DOMAIN_POINT ? &target->vdata : &target->ldata;
const CustomData *source_cdata = domain == ATTR_DOMAIN_POINT ? &source->vdata : &source->ldata;
diff --git a/source/blender/blenkernel/intern/mesh_sample.cc b/source/blender/blenkernel/intern/mesh_sample.cc
index 33b051c792c..106c4c610ba 100644
--- a/source/blender/blenkernel/intern/mesh_sample.cc
+++ b/source/blender/blenkernel/intern/mesh_sample.cc
@@ -2,12 +2,15 @@
#include "BKE_attribute_access.hh"
#include "BKE_attribute_math.hh"
+#include "BKE_bvhutils.h"
#include "BKE_mesh_runtime.h"
#include "BKE_mesh_sample.hh"
#include "DNA_mesh_types.h"
#include "DNA_meshdata_types.h"
+#include "BLI_rand.hh"
+
namespace blender::bke::mesh_surface_sample {
template<typename T>
@@ -204,7 +207,7 @@ Span<float3> MeshAttributeInterpolator::ensure_nearest_weights()
}
void MeshAttributeInterpolator::sample_data(const GVArray &src,
- const AttributeDomain domain,
+ const eAttrDomain domain,
const eAttributeMapMode mode,
const GMutableSpan dst)
{
@@ -259,4 +262,173 @@ void MeshAttributeInterpolator::sample_attribute(const ReadAttributeLookup &src_
}
}
+int sample_surface_points_spherical(RandomNumberGenerator &rng,
+ const Mesh &mesh,
+ const Span<int> looptri_indices_to_sample,
+ const float3 &sample_pos,
+ const float sample_radius,
+ const float approximate_density,
+ Vector<float3> &r_bary_coords,
+ Vector<int> &r_looptri_indices,
+ Vector<float3> &r_positions)
+{
+ const Span<MLoopTri> looptris{BKE_mesh_runtime_looptri_ensure(&mesh),
+ BKE_mesh_runtime_looptri_len(&mesh)};
+
+ const float sample_radius_sq = pow2f(sample_radius);
+ const float sample_plane_area = M_PI * sample_radius_sq;
+ /* Used for switching between two triangle sampling strategies. */
+ const float area_threshold = sample_plane_area;
+
+ const int old_num = r_bary_coords.size();
+
+ for (const int looptri_index : looptri_indices_to_sample) {
+ const MLoopTri &looptri = looptris[looptri_index];
+
+ const float3 &v0 = mesh.mvert[mesh.mloop[looptri.tri[0]].v].co;
+ const float3 &v1 = mesh.mvert[mesh.mloop[looptri.tri[1]].v].co;
+ const float3 &v2 = mesh.mvert[mesh.mloop[looptri.tri[2]].v].co;
+
+ const float looptri_area = area_tri_v3(v0, v1, v2);
+
+ if (looptri_area < area_threshold) {
+ /* The triangle is small compared to the sample radius. Sample by generating random
+ * barycentric coordinates. */
+ const int amount = rng.round_probabilistic(approximate_density * looptri_area);
+ for ([[maybe_unused]] const int i : IndexRange(amount)) {
+ const float3 bary_coord = rng.get_barycentric_coordinates();
+ const float3 point_pos = attribute_math::mix3(bary_coord, v0, v1, v2);
+ const float dist_to_sample_sq = math::distance_squared(point_pos, sample_pos);
+ if (dist_to_sample_sq > sample_radius_sq) {
+ continue;
+ }
+
+ r_bary_coords.append(bary_coord);
+ r_looptri_indices.append(looptri_index);
+ r_positions.append(point_pos);
+ }
+ }
+ else {
+ /* The triangle is large compared to the sample radius. Sample by generating random points
+ * on the triangle plane within the sample radius. */
+ float3 normal;
+ normal_tri_v3(normal, v0, v1, v2);
+
+ float3 sample_pos_proj = sample_pos;
+ project_v3_plane(sample_pos_proj, normal, v0);
+
+ const float proj_distance_sq = math::distance_squared(sample_pos_proj, sample_pos);
+ const float sample_radius_factor_sq = 1.0f -
+ std::min(1.0f, proj_distance_sq / sample_radius_sq);
+ const float radius_proj_sq = sample_radius_sq * sample_radius_factor_sq;
+ const float radius_proj = std::sqrt(radius_proj_sq);
+ const float circle_area = M_PI * radius_proj;
+
+ const int amount = rng.round_probabilistic(approximate_density * circle_area);
+
+ const float3 axis_1 = math::normalize(v1 - v0) * radius_proj;
+ const float3 axis_2 = math::normalize(math::cross(axis_1, math::cross(axis_1, v2 - v0))) *
+ radius_proj;
+
+ for ([[maybe_unused]] const int i : IndexRange(amount)) {
+ const float r = std::sqrt(rng.get_float());
+ const float angle = rng.get_float() * 2.0f * M_PI;
+ const float x = r * std::cos(angle);
+ const float y = r * std::sin(angle);
+ const float3 point_pos = sample_pos_proj + axis_1 * x + axis_2 * y;
+ if (!isect_point_tri_prism_v3(point_pos, v0, v1, v2)) {
+ /* Sampled point is not in the triangle. */
+ continue;
+ }
+
+ float3 bary_coord;
+ interp_weights_tri_v3(bary_coord, v0, v1, v2, point_pos);
+
+ r_bary_coords.append(bary_coord);
+ r_looptri_indices.append(looptri_index);
+ r_positions.append(point_pos);
+ }
+ }
+ }
+ return r_bary_coords.size() - old_num;
+}
+
+int sample_surface_points_projected(
+ RandomNumberGenerator &rng,
+ const Mesh &mesh,
+ BVHTreeFromMesh &mesh_bvhtree,
+ const float2 &sample_pos_re,
+ const float sample_radius_re,
+ const FunctionRef<void(const float2 &pos_re, float3 &r_start, float3 &r_end)>
+ region_position_to_ray,
+ const bool front_face_only,
+ const int tries_num,
+ const int max_points,
+ Vector<float3> &r_bary_coords,
+ Vector<int> &r_looptri_indices,
+ Vector<float3> &r_positions)
+{
+ const Span<MLoopTri> looptris{BKE_mesh_runtime_looptri_ensure(&mesh),
+ BKE_mesh_runtime_looptri_len(&mesh)};
+
+ int point_count = 0;
+ for ([[maybe_unused]] const int _ : IndexRange(tries_num)) {
+ if (point_count == max_points) {
+ break;
+ }
+
+ const float r = sample_radius_re * std::sqrt(rng.get_float());
+ const float angle = rng.get_float() * 2.0f * M_PI;
+ float3 ray_start, ray_end;
+ const float2 pos_re = sample_pos_re + r * float2(std::cos(angle), std::sin(angle));
+ region_position_to_ray(pos_re, ray_start, ray_end);
+ const float3 ray_direction = math::normalize(ray_end - ray_start);
+
+ BVHTreeRayHit ray_hit;
+ ray_hit.dist = FLT_MAX;
+ ray_hit.index = -1;
+ BLI_bvhtree_ray_cast(mesh_bvhtree.tree,
+ ray_start,
+ ray_direction,
+ 0.0f,
+ &ray_hit,
+ mesh_bvhtree.raycast_callback,
+ &mesh_bvhtree);
+
+ if (ray_hit.index == -1) {
+ continue;
+ }
+
+ if (front_face_only) {
+ const float3 normal = ray_hit.no;
+ if (math::dot(ray_direction, normal) >= 0.0f) {
+ continue;
+ }
+ }
+
+ const int looptri_index = ray_hit.index;
+ const float3 pos = ray_hit.co;
+
+ const float3 bary_coords = compute_bary_coord_in_triangle(mesh, looptris[looptri_index], pos);
+
+ r_positions.append(pos);
+ r_bary_coords.append(bary_coords);
+ r_looptri_indices.append(looptri_index);
+ point_count++;
+ }
+ return point_count;
+}
+
+float3 compute_bary_coord_in_triangle(const Mesh &mesh,
+ const MLoopTri &looptri,
+ const float3 &position)
+{
+ const float3 &v0 = mesh.mvert[mesh.mloop[looptri.tri[0]].v].co;
+ const float3 &v1 = mesh.mvert[mesh.mloop[looptri.tri[1]].v].co;
+ const float3 &v2 = mesh.mvert[mesh.mloop[looptri.tri[2]].v].co;
+ float3 bary_coords;
+ interp_weights_tri_v3(bary_coords, v0, v1, v2, position);
+ return bary_coords;
+}
+
} // namespace blender::bke::mesh_surface_sample
diff --git a/source/blender/blenkernel/intern/mesh_tangent.c b/source/blender/blenkernel/intern/mesh_tangent.c
index f2e46c3bd92..a677a0d6ebb 100644
--- a/source/blender/blenkernel/intern/mesh_tangent.c
+++ b/source/blender/blenkernel/intern/mesh_tangent.c
@@ -37,13 +37,13 @@
/* User data. */
typedef struct {
- const MPoly *mpolys; /* faces */
- const MLoop *mloops; /* faces's vertices */
- const MVert *mverts; /* vertices */
- const MLoopUV *luvs; /* texture coordinates */
- float (*lnors)[3]; /* loops' normals */
- float (*tangents)[4]; /* output tangents */
- int num_polys; /* number of polygons */
+ const MPoly *mpolys; /* faces */
+ const MLoop *mloops; /* faces's vertices */
+ const MVert *mverts; /* vertices */
+ const MLoopUV *luvs; /* texture coordinates */
+ const float (*lnors)[3]; /* loops' normals */
+ float (*tangents)[4]; /* output tangents */
+ int num_polys; /* number of polygons */
} BKEMeshToTangent;
/* Mikktspace's API */
@@ -103,7 +103,7 @@ void BKE_mesh_calc_loop_tangent_single_ex(const MVert *mverts,
const int UNUSED(numVerts),
const MLoop *mloops,
float (*r_looptangent)[4],
- float (*loopnors)[3],
+ const float (*loopnors)[3],
const MLoopUV *loopuvs,
const int UNUSED(numLoops),
const MPoly *mpolys,
@@ -155,8 +155,7 @@ void BKE_mesh_calc_loop_tangent_single(Mesh *mesh,
float (*r_looptangents)[4],
ReportList *reports)
{
- MLoopUV *loopuvs;
- float(*loopnors)[3];
+ const MLoopUV *loopuvs;
/* Check we have valid texture coordinates first! */
if (uvmap) {
@@ -168,12 +167,12 @@ void BKE_mesh_calc_loop_tangent_single(Mesh *mesh,
if (!loopuvs) {
BKE_reportf(reports,
RPT_ERROR,
- "Tangent space computation needs an UVMap, \"%s\" not found, aborting",
+ "Tangent space computation needs a UV Map, \"%s\" not found, aborting",
uvmap);
return;
}
- loopnors = CustomData_get_layer(&mesh->ldata, CD_NORMAL);
+ const float(*loopnors)[3] = CustomData_get_layer(&mesh->ldata, CD_NORMAL);
if (!loopnors) {
BKE_report(
reports, RPT_ERROR, "Tangent space computation needs loop normals, none found, aborting");
@@ -205,10 +204,10 @@ typedef struct {
const float (*precomputedFaceNormals)[3];
const float (*precomputedLoopNormals)[3];
const MLoopTri *looptri;
- MLoopUV *mloopuv; /* texture coordinates */
- const MPoly *mpoly; /* indices */
- const MLoop *mloop; /* indices */
- const MVert *mvert; /* vertex coordinates */
+ const MLoopUV *mloopuv; /* texture coordinates */
+ const MPoly *mpoly; /* indices */
+ const MLoop *mloop; /* indices */
+ const MVert *mvert; /* vertex coordinates */
const float (*vert_normals)[3];
const float (*orco)[3];
float (*tangent)[4]; /* destination */
diff --git a/source/blender/blenkernel/intern/mesh_tessellate.c b/source/blender/blenkernel/intern/mesh_tessellate.c
index ea3cc043267..7cb656d2357 100644
--- a/source/blender/blenkernel/intern/mesh_tessellate.c
+++ b/source/blender/blenkernel/intern/mesh_tessellate.c
@@ -69,7 +69,7 @@ static void mesh_loops_to_tessdata(CustomData *fdata,
for (i = 0; i < numUV; i++) {
MTFace *texface = CustomData_get_layer_n(fdata, CD_MTFACE, i);
- MLoopUV *mloopuv = CustomData_get_layer_n(ldata, CD_MLOOPUV, i);
+ const MLoopUV *mloopuv = CustomData_get_layer_n(ldata, CD_MLOOPUV, i);
for (findex = 0, pidx = polyindices, lidx = loopindices; findex < num_faces;
pidx++, lidx++, findex++, texface++) {
@@ -81,7 +81,7 @@ static void mesh_loops_to_tessdata(CustomData *fdata,
for (i = 0; i < numCol; i++) {
MCol(*mcol)[4] = CustomData_get_layer_n(fdata, CD_MCOL, i);
- MLoopCol *mloopcol = CustomData_get_layer_n(ldata, CD_PROP_BYTE_COLOR, i);
+ const MLoopCol *mloopcol = CustomData_get_layer_n(ldata, CD_PROP_BYTE_COLOR, i);
for (findex = 0, lidx = loopindices; findex < num_faces; lidx++, findex++, mcol++) {
for (j = (mface ? mface[findex].v4 : (*lidx)[3]) ? 4 : 3; j--;) {
@@ -92,7 +92,7 @@ static void mesh_loops_to_tessdata(CustomData *fdata,
if (hasPCol) {
MCol(*mcol)[4] = CustomData_get_layer(fdata, CD_PREVIEW_MCOL);
- MLoopCol *mloopcol = CustomData_get_layer(ldata, CD_PREVIEW_MLOOPCOL);
+ const MLoopCol *mloopcol = CustomData_get_layer(ldata, CD_PREVIEW_MLOOPCOL);
for (findex = 0, lidx = loopindices; findex < num_faces; lidx++, findex++, mcol++) {
for (j = (mface ? mface[findex].v4 : (*lidx)[3]) ? 4 : 3; j--;) {
@@ -103,7 +103,7 @@ static void mesh_loops_to_tessdata(CustomData *fdata,
if (hasOrigSpace) {
OrigSpaceFace *of = CustomData_get_layer(fdata, CD_ORIGSPACE);
- OrigSpaceLoop *lof = CustomData_get_layer(ldata, CD_ORIGSPACE_MLOOP);
+ const OrigSpaceLoop *lof = CustomData_get_layer(ldata, CD_ORIGSPACE_MLOOP);
for (findex = 0, lidx = loopindices; findex < num_faces; lidx++, findex++, of++) {
for (j = (mface ? mface[findex].v4 : (*lidx)[3]) ? 4 : 3; j--;) {
@@ -114,7 +114,7 @@ static void mesh_loops_to_tessdata(CustomData *fdata,
if (hasLoopNormal) {
short(*fnors)[4][3] = CustomData_get_layer(fdata, CD_TESSLOOPNORMAL);
- float(*lnors)[3] = CustomData_get_layer(ldata, CD_NORMAL);
+ const float(*lnors)[3] = CustomData_get_layer(ldata, CD_NORMAL);
for (findex = 0, lidx = loopindices; findex < num_faces; lidx++, findex++, fnors++) {
for (j = (mface ? mface[findex].v4 : (*lidx)[3]) ? 4 : 3; j--;) {
@@ -126,7 +126,7 @@ static void mesh_loops_to_tessdata(CustomData *fdata,
if (hasLoopTangent) {
/* Need to do for all UV maps at some point. */
float(*ftangents)[4] = CustomData_get_layer(fdata, CD_TANGENT);
- float(*ltangents)[4] = CustomData_get_layer(ldata, CD_TANGENT);
+ const float(*ltangents)[4] = CustomData_get_layer(ldata, CD_TANGENT);
for (findex = 0, pidx = polyindices, lidx = loopindices; findex < num_faces;
pidx++, lidx++, findex++) {
@@ -154,8 +154,8 @@ int BKE_mesh_tessface_calc_ex(CustomData *fdata,
const int looptri_num = poly_to_tri_count(totpoly, totloop);
- MPoly *mp, *mpoly;
- MLoop *ml, *mloop;
+ const MPoly *mp, *mpoly;
+ const MLoop *ml, *mloop;
MFace *mface, *mf;
MemArena *arena = NULL;
int *mface_to_poly_map;
diff --git a/source/blender/blenkernel/intern/mesh_validate.cc b/source/blender/blenkernel/intern/mesh_validate.cc
index d16f7eaf588..9b2697ecc84 100644
--- a/source/blender/blenkernel/intern/mesh_validate.cc
+++ b/source/blender/blenkernel/intern/mesh_validate.cc
@@ -926,7 +926,7 @@ bool BKE_mesh_validate_arrays(Mesh *mesh,
}
static bool mesh_validate_customdata(CustomData *data,
- CustomDataMask mask,
+ eCustomDataMask mask,
const uint totitems,
const bool do_verbose,
const bool do_fixes,
@@ -953,7 +953,7 @@ static bool mesh_validate_customdata(CustomData *data,
}
if (mask != 0) {
- CustomDataMask layer_typemask = CD_TYPE_AS_MASK(layer->type);
+ eCustomDataMask layer_typemask = CD_TYPE_AS_MASK(layer->type);
if ((layer_typemask & mask) == 0) {
PRINT_ERR("\tCustomDataLayer type %d which isn't in the mask\n", layer->type);
ok = false;
diff --git a/source/blender/blenkernel/intern/mesh_wrapper.cc b/source/blender/blenkernel/intern/mesh_wrapper.cc
index c505a74724b..fdebf1d6a26 100644
--- a/source/blender/blenkernel/intern/mesh_wrapper.cc
+++ b/source/blender/blenkernel/intern/mesh_wrapper.cc
@@ -314,28 +314,23 @@ static Mesh *mesh_wrapper_ensure_subdivision(const Object *ob, Mesh *me)
return me;
}
+ SubsurfRuntimeData *runtime_data = (SubsurfRuntimeData *)smd->modifier.runtime;
+ if (runtime_data == nullptr || runtime_data->settings.level == 0) {
+ 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;
+ mesh_settings.resolution = runtime_data->resolution;
+ mesh_settings.use_optimal_display = runtime_data->use_optimal_display;
if (mesh_settings.resolution < 3) {
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) {
- return me;
- }
-
- SubsurfRuntimeData *runtime_data = BKE_subsurf_modifier_ensure_runtime(smd);
-
- Subdiv *subdiv = BKE_subsurf_modifier_subdiv_descriptor_ensure(smd, &subdiv_settings, me, false);
+ Subdiv *subdiv = BKE_subsurf_modifier_subdiv_descriptor_ensure(runtime_data, me, false);
if (subdiv == nullptr) {
/* Happens on bad topology, but also on empty input mesh. */
return me;
@@ -358,7 +353,7 @@ static Mesh *mesh_wrapper_ensure_subdivision(const Object *ob, Mesh *me)
CustomData_set_layer_flag(&me->ldata, CD_NORMAL, CD_FLAG_TEMPORARY);
CustomData_set_layer_flag(&subdiv_mesh->ldata, CD_NORMAL, CD_FLAG_TEMPORARY);
}
- else if (me->runtime.subsurf_do_loop_normals) {
+ else if (runtime_data->calc_loop_normals) {
BKE_mesh_calc_normals_split(subdiv_mesh);
}
diff --git a/source/blender/blenkernel/intern/modifier.c b/source/blender/blenkernel/intern/modifier.c
index 5ffd253be3b..6348d83362e 100644
--- a/source/blender/blenkernel/intern/modifier.c
+++ b/source/blender/blenkernel/intern/modifier.c
@@ -1067,7 +1067,7 @@ void BKE_modifier_check_uuids_unique_and_report(const Object *object)
BLI_gset_free(used_uuids, NULL);
}
-void BKE_modifier_blend_write(BlendWriter *writer, ListBase *modbase)
+void BKE_modifier_blend_write(BlendWriter *writer, const ID *id_owner, ListBase *modbase)
{
if (modbase == NULL) {
return;
@@ -1076,7 +1076,13 @@ void BKE_modifier_blend_write(BlendWriter *writer, ListBase *modbase)
LISTBASE_FOREACH (ModifierData *, md, modbase) {
const ModifierTypeInfo *mti = BKE_modifier_get_info(md->type);
if (mti == NULL) {
- return;
+ continue;
+ }
+
+ /* If the blendWrite callback is defined, it should handle the whole writing process. */
+ if (mti->blendWrite != NULL) {
+ mti->blendWrite(writer, id_owner, md);
+ continue;
}
BLO_write_struct_by_name(writer, mti->structName, md);
@@ -1162,10 +1168,6 @@ void BKE_modifier_blend_write(BlendWriter *writer, ListBase *modbase)
writestruct(wd, DATA, MFace, collmd->numfaces, collmd->mfaces);
#endif
}
-
- if (mti->blendWrite != NULL) {
- mti->blendWrite(writer, md);
- }
}
}
diff --git a/source/blender/blenkernel/intern/movieclip.c b/source/blender/blenkernel/intern/movieclip.c
index accbca42da6..19ee2ba6605 100644
--- a/source/blender/blenkernel/intern/movieclip.c
+++ b/source/blender/blenkernel/intern/movieclip.c
@@ -2085,8 +2085,7 @@ GPUTexture *BKE_movieclip_get_gpu_texture(MovieClip *clip, MovieClipUser *cuser)
/* This only means RGBA16F instead of RGBA32F. */
const bool high_bitdepth = false;
const bool store_premultiplied = ibuf->rect_float ? false : true;
- *tex = IMB_create_gpu_texture(
- clip->id.name + 2, ibuf, high_bitdepth, store_premultiplied, false);
+ *tex = IMB_create_gpu_texture(clip->id.name + 2, ibuf, high_bitdepth, store_premultiplied);
/* Do not generate mips for movieclips... too slow. */
GPU_texture_mipmap_mode(*tex, false, true);
diff --git a/source/blender/blenkernel/intern/multires.c b/source/blender/blenkernel/intern/multires.c
index b0e235662cb..63945f9ed42 100644
--- a/source/blender/blenkernel/intern/multires.c
+++ b/source/blender/blenkernel/intern/multires.c
@@ -1021,7 +1021,7 @@ void multires_modifier_update_mdisps(struct DerivedMesh *dm, Scene *scene)
CCGDerivedMesh *ccgdm = (CCGDerivedMesh *)dm;
Object *ob;
Mesh *me;
- MDisps *mdisps;
+ const MDisps *mdisps;
MultiresModifierData *mmd;
ob = ccgdm->multires.ob;
@@ -1403,7 +1403,7 @@ static void multires_apply_smat(struct Depsgraph *UNUSED(depsgraph),
}
}
-int multires_mdisp_corners(MDisps *s)
+int multires_mdisp_corners(const MDisps *s)
{
int lvl = 13;
diff --git a/source/blender/blenkernel/intern/multires_reshape_smooth.c b/source/blender/blenkernel/intern/multires_reshape_smooth.c
index b76e2b3aec6..8246de12ebf 100644
--- a/source/blender/blenkernel/intern/multires_reshape_smooth.c
+++ b/source/blender/blenkernel/intern/multires_reshape_smooth.c
@@ -1073,7 +1073,9 @@ 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, SUBDIV_EVALUATOR_TYPE_CPU, NULL);
+
+ OpenSubdiv_EvaluatorSettings evaluator_settings = {0};
+ BKE_subdiv_eval_begin(reshape_subdiv, SUBDIV_EVALUATOR_TYPE_CPU, NULL, &evaluator_settings);
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 aed13adf56d..34aa90aa554 100644
--- a/source/blender/blenkernel/intern/multires_reshape_util.c
+++ b/source/blender/blenkernel/intern/multires_reshape_util.c
@@ -10,12 +10,14 @@
#include "MEM_guardedalloc.h"
#include "DNA_mesh_types.h"
+#include "DNA_meshdata_types.h"
#include "DNA_modifier_types.h"
#include "DNA_object_types.h"
#include "DNA_scene_types.h"
#include "BLI_task.h"
+#include "BKE_customdata.h"
#include "BKE_mesh.h"
#include "BKE_mesh_runtime.h"
#include "BKE_multires.h"
diff --git a/source/blender/blenkernel/intern/nla.c b/source/blender/blenkernel/intern/nla.c
index 5d804f53779..10abb8f20df 100644
--- a/source/blender/blenkernel/intern/nla.c
+++ b/source/blender/blenkernel/intern/nla.c
@@ -244,27 +244,71 @@ void BKE_nla_tracks_copy(Main *bmain, ListBase *dst, const ListBase *src, const
}
}
-/* Set adt_dest->actstrip to the strip with the same index as adt_source->actstrip. */
+/**
+ * Find `active_strip` in `strips_source`, then return the strip with the same
+ * index from `strips_dest`.
+ */
+static NlaStrip *find_active_strip_from_listbase(const NlaStrip *active_strip,
+ const ListBase /* NlaStrip */ *strips_source,
+ const ListBase /* NlaStrip */ *strips_dest)
+{
+ BLI_assert_msg(BLI_listbase_count(strips_source) == BLI_listbase_count(strips_dest),
+ "Expecting the same number of source and destination strips");
+
+ NlaStrip *strip_dest = strips_dest->first;
+ LISTBASE_FOREACH (const NlaStrip *, strip_source, strips_source) {
+ if (strip_dest == NULL) {
+ /* The tracks are assumed to have an equal number of strips, but this is
+ * not the case. Not sure when this might happen, but it's better to not
+ * crash. */
+ break;
+ }
+ if (strip_source == active_strip) {
+ return strip_dest;
+ }
+
+ const bool src_is_meta = strip_source->type == NLASTRIP_TYPE_META;
+ const bool dst_is_meta = strip_dest->type == NLASTRIP_TYPE_META;
+ BLI_assert_msg(src_is_meta == dst_is_meta,
+ "Expecting topology of source and destination strips to be equal");
+ if (src_is_meta && dst_is_meta) {
+ NlaStrip *found_in_meta = find_active_strip_from_listbase(
+ active_strip, &strip_source->strips, &strip_dest->strips);
+ if (found_in_meta != NULL) {
+ return found_in_meta;
+ }
+ }
+
+ strip_dest = strip_dest->next;
+ }
+
+ return NULL;
+}
+
+/* Set adt_dest->actstrip to the strip with the same index as
+ * adt_source->actstrip. Note that this always sets `adt_dest->actstrip`; sets
+ * to NULL when `adt_source->actstrip` cannot be found. */
static void update_active_strip(AnimData *adt_dest,
NlaTrack *track_dest,
const AnimData *adt_source,
- NlaTrack *track_source)
+ const NlaTrack *track_source)
{
BLI_assert(BLI_listbase_count(&track_source->strips) == BLI_listbase_count(&track_dest->strips));
- NlaStrip *strip_dest = track_dest->strips.first;
- LISTBASE_FOREACH (NlaStrip *, strip_source, &track_source->strips) {
- if (strip_source == adt_source->actstrip) {
- adt_dest->actstrip = strip_dest;
- }
-
- strip_dest = strip_dest->next;
- }
+ NlaStrip *active_strip = find_active_strip_from_listbase(
+ adt_source->actstrip, &track_source->strips, &track_dest->strips);
+ adt_dest->actstrip = active_strip;
}
/* Set adt_dest->act_track to the track with the same index as adt_source->act_track. */
static void update_active_track(AnimData *adt_dest, const AnimData *adt_source)
{
+ adt_dest->act_track = NULL;
+ adt_dest->actstrip = NULL;
+ if (adt_source->act_track == NULL && adt_source->actstrip == NULL) {
+ return;
+ }
+
BLI_assert(BLI_listbase_count(&adt_source->nla_tracks) ==
BLI_listbase_count(&adt_dest->nla_tracks));
@@ -272,20 +316,24 @@ static void update_active_track(AnimData *adt_dest, const AnimData *adt_source)
LISTBASE_FOREACH (NlaTrack *, track_source, &adt_source->nla_tracks) {
if (track_source == adt_source->act_track) {
adt_dest->act_track = track_dest;
- /* Assumption: the active strip is on the active track. */
+ }
+
+ /* Only search for the active strip if it hasn't been found yet. */
+ if (adt_dest->actstrip == NULL && adt_source->actstrip != NULL) {
update_active_strip(adt_dest, track_dest, adt_source, track_source);
}
track_dest = track_dest->next;
}
- /* If the above assumption failed to hold, do a more thorough search for the active strip. */
- if (adt_source->actstrip != NULL && adt_dest->actstrip == NULL) {
- nla_tweakmode_find_active(&adt_source->nla_tracks, &track_dest, &adt_dest->actstrip);
+#ifndef NDEBUG
+ {
+ const bool source_has_actstrip = adt_source->actstrip != NULL;
+ const bool dest_has_actstrip = adt_dest->actstrip != NULL;
+ BLI_assert_msg(source_has_actstrip == dest_has_actstrip,
+ "Active strip did not copy correctly");
}
-
- BLI_assert_msg((adt_source->actstrip == NULL) == (adt_dest->actstrip == NULL),
- "Active strip did not copy correctly");
+#endif
}
void BKE_nla_tracks_copy_from_adt(Main *bmain,
@@ -1171,26 +1219,35 @@ bool BKE_nlatrack_is_nonlocal_in_liboverride(const ID *id, const NlaTrack *nlt)
/* NLA Strips -------------------------------------- */
-NlaStrip *BKE_nlastrip_find_active(NlaTrack *nlt)
+static NlaStrip *nlastrip_find_active(ListBase /* NlaStrip */ *strips)
{
- NlaStrip *strip;
-
- /* sanity check */
- if (ELEM(NULL, nlt, nlt->strips.first)) {
- return NULL;
- }
-
- /* try to find the first active strip */
- for (strip = nlt->strips.first; strip; strip = strip->next) {
+ LISTBASE_FOREACH (NlaStrip *, strip, strips) {
if (strip->flag & NLASTRIP_FLAG_ACTIVE) {
return strip;
}
+
+ if (strip->type != NLASTRIP_TYPE_META) {
+ continue;
+ }
+
+ NlaStrip *inner_active = nlastrip_find_active(&strip->strips);
+ if (inner_active != NULL) {
+ return inner_active;
+ }
}
- /* none found */
return NULL;
}
+NlaStrip *BKE_nlastrip_find_active(NlaTrack *nlt)
+{
+ if (nlt == NULL) {
+ return NULL;
+ }
+
+ return nlastrip_find_active(&nlt->strips);
+}
+
void BKE_nlastrip_set_active(AnimData *adt, NlaStrip *strip)
{
NlaTrack *nlt;
diff --git a/source/blender/blenkernel/intern/node.cc b/source/blender/blenkernel/intern/node.cc
index 20e190526c4..d4d14ca45be 100644
--- a/source/blender/blenkernel/intern/node.cc
+++ b/source/blender/blenkernel/intern/node.cc
@@ -60,6 +60,7 @@
#include "BKE_lib_query.h"
#include "BKE_main.h"
#include "BKE_node.h"
+#include "BKE_node_runtime.hh"
#include "BKE_node_tree_update.h"
#include "RNA_access.h"
@@ -94,6 +95,9 @@ using blender::Stack;
using blender::StringRef;
using blender::Vector;
using blender::VectorSet;
+using blender::bke::bNodeRuntime;
+using blender::bke::bNodeSocketRuntime;
+using blender::bke::bNodeTreeRuntime;
using blender::nodes::FieldInferencingInterface;
using blender::nodes::InputSocketFieldType;
using blender::nodes::NodeDeclaration;
@@ -123,6 +127,7 @@ static void nodeMuteRerouteOutputLinks(struct bNodeTree *ntree,
static void ntree_init_data(ID *id)
{
bNodeTree *ntree = (bNodeTree *)id;
+ ntree->runtime = MEM_new<bNodeTreeRuntime>(__func__);
ntree_set_typeinfo(ntree, nullptr);
}
@@ -134,6 +139,8 @@ static void ntree_copy_data(Main *UNUSED(bmain), ID *id_dst, const ID *id_src, c
/* We never handle usercount here for own data. */
const int flag_subdata = flag | LIB_ID_CREATE_NO_USER_REFCOUNT;
+ ntree_dst->runtime = MEM_new<bNodeTreeRuntime>(__func__);
+
/* in case a running nodetree is copied */
ntree_dst->execdata = nullptr;
@@ -203,9 +210,9 @@ static void ntree_copy_data(Main *UNUSED(bmain), ID *id_dst, const ID *id_src, c
/* node tree will generate its own interface type */
ntree_dst->interface_type = nullptr;
- if (ntree_src->field_inferencing_interface) {
- ntree_dst->field_inferencing_interface = new FieldInferencingInterface(
- *ntree_src->field_inferencing_interface);
+ if (ntree_src->runtime->field_inferencing_interface) {
+ ntree_dst->runtime->field_inferencing_interface = std::make_unique<FieldInferencingInterface>(
+ *ntree_src->runtime->field_inferencing_interface);
}
if (flag & LIB_ID_COPY_NO_PREVIEW) {
@@ -258,8 +265,6 @@ static void ntree_free_data(ID *id)
MEM_freeN(sock);
}
- delete ntree->field_inferencing_interface;
-
/* free preview hash */
if (ntree->previews) {
BKE_node_instance_hash_free(ntree->previews, (bNodeInstanceValueFP)BKE_node_preview_free);
@@ -270,6 +275,7 @@ static void ntree_free_data(ID *id)
}
BKE_previewimg_free(&ntree->preview);
+ MEM_delete(ntree->runtime);
}
static void library_foreach_node_socket(LibraryForeachIDData *data, bNodeSocket *sock)
@@ -658,7 +664,7 @@ static void direct_link_node_socket(BlendDataReader *reader, bNodeSocket *sock)
BLO_read_data_address(reader, &sock->default_attribute_name);
sock->total_inputs = 0; /* Clear runtime data set before drawing. */
sock->cache = nullptr;
- sock->declaration = nullptr;
+ sock->runtime = MEM_new<bNodeSocketRuntime>(__func__);
}
void ntreeBlendReadData(BlendDataReader *reader, bNodeTree *ntree)
@@ -670,8 +676,7 @@ void ntreeBlendReadData(BlendDataReader *reader, bNodeTree *ntree)
ntree->progress = nullptr;
ntree->execdata = nullptr;
-
- ntree->field_inferencing_interface = nullptr;
+ ntree->runtime = MEM_new<bNodeTreeRuntime>(__func__);
BKE_ntree_update_tag_missing_runtime_data(ntree);
BLO_read_data_address(reader, &ntree->adt);
@@ -679,8 +684,8 @@ void ntreeBlendReadData(BlendDataReader *reader, bNodeTree *ntree)
BLO_read_list(reader, &ntree->nodes);
LISTBASE_FOREACH (bNode *, node, &ntree->nodes) {
+ node->runtime = MEM_new<bNodeRuntime>(__func__);
node->typeinfo = nullptr;
- node->declaration = nullptr;
BLO_read_list(reader, &node->inputs);
BLO_read_list(reader, &node->outputs);
@@ -1116,7 +1121,7 @@ static void node_init(const struct bContext *C, bNodeTree *ntree, bNode *node)
PointerRNA ptr;
RNA_pointer_create((ID *)ntree, &RNA_Node, node, &ptr);
- /* XXX Warning: context can be nullptr in case nodes are added in do_versions.
+ /* 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. */
BLI_assert(C != nullptr);
ntype->initfunc_api(C, &ptr);
@@ -1165,7 +1170,7 @@ static void node_set_typeinfo(const struct bContext *C,
}
}
-/* Warning: default_value must either be null or match the typeinfo at this point.
+/* WARNING: default_value must either be null or match the typeinfo at this point.
* This function is called both for initializing new sockets and after loading files.
*/
static void node_socket_set_typeinfo(bNodeTree *ntree,
@@ -1511,6 +1516,7 @@ static bNodeSocket *make_socket(bNodeTree *ntree,
unique_identifier_check, lb, "socket", '_', auto_identifier, sizeof(auto_identifier));
bNodeSocket *sock = MEM_cnew<bNodeSocket>("sock");
+ sock->runtime = MEM_new<bNodeSocketRuntime>(__func__);
sock->in_out = in_out;
BLI_strncpy(sock->identifier, auto_identifier, NODE_MAXSTR);
@@ -1916,6 +1922,7 @@ static void node_socket_free(bNodeSocket *sock, const bool do_id_user)
}
MEM_freeN(sock->default_value);
}
+ MEM_delete(sock->runtime);
}
void nodeRemoveSocket(bNodeTree *ntree, bNode *node, bNodeSocket *sock)
@@ -2121,6 +2128,7 @@ void nodeUniqueName(bNodeTree *ntree, bNode *node)
bNode *nodeAddNode(const struct bContext *C, bNodeTree *ntree, const char *idname)
{
bNode *node = MEM_cnew<bNode>("new node");
+ node->runtime = MEM_new<bNodeRuntime>(__func__);
BLI_addtail(&ntree->nodes, node);
BLI_strncpy(node->idname, idname, sizeof(node->idname));
@@ -2158,6 +2166,7 @@ bNode *nodeAddStaticNode(const struct bContext *C, bNodeTree *ntree, int type)
static void node_socket_copy(bNodeSocket *sock_dst, const bNodeSocket *sock_src, const int flag)
{
+ sock_dst->runtime = MEM_new<bNodeSocketRuntime>(__func__);
if (sock_src->prop) {
sock_dst->prop = IDP_CopyProperty_ex(sock_src->prop, flag);
}
@@ -2190,6 +2199,8 @@ bNode *node_copy_with_mapping(bNodeTree *dst_tree,
bNode *node_dst = (bNode *)MEM_mallocN(sizeof(bNode), __func__);
*node_dst = node_src;
+ node_dst->runtime = MEM_new<bNodeRuntime>(__func__);
+
/* Can be called for nodes outside a node tree (e.g. clipboard). */
if (dst_tree) {
if (unique_name) {
@@ -2250,7 +2261,6 @@ bNode *node_copy_with_mapping(bNodeTree *dst_tree,
}
/* Reset the declaration of the new node. */
- node_dst->declaration = nullptr;
nodeDeclarationEnsure(dst_tree, node_dst);
return node_dst;
@@ -2667,6 +2677,7 @@ bNodeTree *ntreeAddTree(Main *bmain, const char *name, const char *idname)
flag |= LIB_ID_CREATE_NO_MAIN;
}
bNodeTree *ntree = (bNodeTree *)BKE_libblock_alloc(bmain, ID_NT, name, flag);
+ BKE_libblock_init_empty(&ntree->id);
if (is_embedded) {
ntree->id.flag |= LIB_EMBEDDED_DATA;
}
@@ -2968,9 +2979,10 @@ static void node_free_node(bNodeTree *ntree, bNode *node)
}
if (node->typeinfo->declaration_is_dynamic) {
- delete node->declaration;
+ delete node->runtime->declaration;
}
+ MEM_delete(node->runtime);
MEM_freeN(node);
if (ntree) {
@@ -3062,6 +3074,7 @@ static void node_socket_interface_free(bNodeTree *UNUSED(ntree),
}
MEM_freeN(sock->default_value);
}
+ MEM_delete(sock->runtime);
}
static void free_localized_node_groups(bNodeTree *ntree)
@@ -3288,6 +3301,7 @@ static bNodeSocket *make_socket_interface(bNodeTree *ntree,
}
bNodeSocket *sock = MEM_cnew<bNodeSocket>("socket template");
+ sock->runtime = MEM_new<bNodeSocketRuntime>(__func__);
BLI_strncpy(sock->idname, stype->idname, sizeof(sock->idname));
sock->in_out = in_out;
sock->type = SOCK_CUSTOM; /* int type undefined by default */
@@ -3675,34 +3689,34 @@ static void update_socket_declarations(ListBase *sockets,
int index;
LISTBASE_FOREACH_INDEX (bNodeSocket *, socket, sockets, index) {
const SocketDeclaration &socket_decl = *declarations[index];
- socket->declaration = &socket_decl;
+ socket->runtime->declaration = &socket_decl;
}
}
void nodeSocketDeclarationsUpdate(bNode *node)
{
- BLI_assert(node->declaration != nullptr);
- update_socket_declarations(&node->inputs, node->declaration->inputs());
- update_socket_declarations(&node->outputs, node->declaration->outputs());
+ BLI_assert(node->runtime->declaration != nullptr);
+ update_socket_declarations(&node->inputs, node->runtime->declaration->inputs());
+ update_socket_declarations(&node->outputs, node->runtime->declaration->outputs());
}
bool nodeDeclarationEnsureOnOutdatedNode(bNodeTree *UNUSED(ntree), bNode *node)
{
- if (node->declaration != nullptr) {
+ if (node->runtime->declaration != nullptr) {
return false;
}
if (node->typeinfo->declare == nullptr) {
return false;
}
if (node->typeinfo->declaration_is_dynamic) {
- node->declaration = new blender::nodes::NodeDeclaration();
- blender::nodes::NodeDeclarationBuilder builder{*node->declaration};
+ node->runtime->declaration = new blender::nodes::NodeDeclaration();
+ blender::nodes::NodeDeclarationBuilder builder{*node->runtime->declaration};
node->typeinfo->declare(builder);
}
else {
/* Declaration should have been created in #nodeRegisterType. */
BLI_assert(node->typeinfo->fixed_declaration != nullptr);
- node->declaration = node->typeinfo->fixed_declaration;
+ node->runtime->declaration = node->typeinfo->fixed_declaration;
}
return true;
}
@@ -4751,6 +4765,8 @@ static void registerGeometryNodes()
register_node_type_geo_input_curve_tilt();
register_node_type_geo_input_id();
register_node_type_geo_input_index();
+ register_node_type_geo_input_instance_rotation();
+ register_node_type_geo_input_instance_scale();
register_node_type_geo_input_material_index();
register_node_type_geo_input_material();
register_node_type_geo_input_mesh_edge_angle();
@@ -4821,6 +4837,7 @@ static void registerGeometryNodes()
register_node_type_geo_translate_instances();
register_node_type_geo_triangulate();
register_node_type_geo_viewer();
+ register_node_type_geo_volume_cube();
register_node_type_geo_volume_to_mesh();
}
diff --git a/source/blender/blenkernel/intern/node_tree_update.cc b/source/blender/blenkernel/intern/node_tree_update.cc
index baf3a0c8d22..019ab114b83 100644
--- a/source/blender/blenkernel/intern/node_tree_update.cc
+++ b/source/blender/blenkernel/intern/node_tree_update.cc
@@ -12,8 +12,10 @@
#include "DNA_node_types.h"
#include "BKE_anim_data.h"
+#include "BKE_image.h"
#include "BKE_main.h"
#include "BKE_node.h"
+#include "BKE_node_runtime.hh"
#include "BKE_node_tree_update.h"
#include "MOD_nodes.h"
@@ -47,19 +49,19 @@ enum eNodeTreeChangedFlag {
static void add_tree_tag(bNodeTree *ntree, const eNodeTreeChangedFlag flag)
{
- ntree->changed_flag |= flag;
+ ntree->runtime->changed_flag |= flag;
}
static void add_node_tag(bNodeTree *ntree, bNode *node, const eNodeTreeChangedFlag flag)
{
add_tree_tag(ntree, flag);
- node->changed_flag |= flag;
+ node->runtime->changed_flag |= flag;
}
static void add_socket_tag(bNodeTree *ntree, bNodeSocket *socket, const eNodeTreeChangedFlag flag)
{
add_tree_tag(ntree, flag);
- socket->changed_flag |= flag;
+ socket->runtime->changed_flag |= flag;
}
namespace blender::bke {
@@ -171,11 +173,11 @@ static FieldInferencingInterface get_node_field_inferencing_interface(const Node
/* 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) {
+ if (!group->runtime->field_inferencing_interface) {
/* This shouldn't happen because referenced node groups should always be updated first. */
BLI_assert_unreachable();
}
- return *group->field_inferencing_interface;
+ return *group->runtime->field_inferencing_interface;
}
FieldInferencingInterface inferencing_interface;
@@ -550,7 +552,8 @@ 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();
+ std::unique_ptr<FieldInferencingInterface> new_inferencing_interface =
+ std::make_unique<FieldInferencingInterface>();
new_inferencing_interface->inputs.resize(BLI_listbase_count(&btree.inputs),
InputSocketFieldType::IsSupported);
new_inferencing_interface->outputs.resize(BLI_listbase_count(&btree.outputs),
@@ -566,11 +569,10 @@ static bool update_field_inferencing(const NodeTreeRef &tree)
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 !=
+ const bool group_interface_changed = !btree.runtime->field_inferencing_interface ||
+ *btree.runtime->field_inferencing_interface !=
*new_inferencing_interface;
- delete btree.field_inferencing_interface;
- btree.field_inferencing_interface = new_inferencing_interface;
+ btree.runtime->field_inferencing_interface = std::move(new_inferencing_interface);
return group_interface_changed;
}
@@ -798,7 +800,7 @@ class NodeTreeMainUpdater {
{
Vector<bNodeTree *> changed_ntrees;
FOREACH_NODETREE_BEGIN (bmain_, ntree, id) {
- if (ntree->changed_flag != NTREE_CHANGED_NOTHING) {
+ if (ntree->runtime->changed_flag != NTREE_CHANGED_NOTHING) {
changed_ntrees.append(ntree);
}
}
@@ -816,7 +818,7 @@ class NodeTreeMainUpdater {
if (root_ntrees.size() == 1) {
bNodeTree *ntree = root_ntrees[0];
- if (ntree->changed_flag == NTREE_CHANGED_NOTHING) {
+ if (ntree->runtime->changed_flag == NTREE_CHANGED_NOTHING) {
return;
}
const TreeUpdateResult result = this->update_tree(*ntree);
@@ -829,7 +831,7 @@ class NodeTreeMainUpdater {
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) {
+ if (ntree->runtime->changed_flag == NTREE_CHANGED_NOTHING) {
continue;
}
if (!update_result_by_tree_.contains(ntree)) {
@@ -984,6 +986,7 @@ class NodeTreeMainUpdater {
this->remove_unused_previews_when_necessary(ntree);
this->ensure_tree_ref(ntree, tree_ref);
+ this->propagate_runtime_flags(*tree_ref);
if (ntree.type == NTREE_GEOMETRY) {
if (node_field_inferencing::update_field_inferencing(*tree_ref)) {
result.interface_changed = true;
@@ -1000,7 +1003,8 @@ class NodeTreeMainUpdater {
ntreeTexCheckCyclics(&ntree);
}
- if (ntree.changed_flag & NTREE_CHANGED_INTERFACE || ntree.changed_flag & NTREE_CHANGED_ANY) {
+ if (ntree.runtime->changed_flag & NTREE_CHANGED_INTERFACE ||
+ ntree.runtime->changed_flag & NTREE_CHANGED_ANY) {
result.interface_changed = true;
}
@@ -1055,18 +1059,18 @@ class NodeTreeMainUpdater {
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;
+ const uint32_t old_changed_flag = ntree.runtime->changed_flag;
+ ntree.runtime->changed_flag = NTREE_CHANGED_NOTHING;
- /* This may set #ntree.changed_flag which is detected below. */
+ /* This may set #ntree.runtime->changed_flag which is detected below. */
this->update_individual_node(node);
- if (ntree.changed_flag != NTREE_CHANGED_NOTHING) {
+ if (ntree.runtime->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;
+ ntree.runtime->changed_flag |= old_changed_flag;
}
}
}
@@ -1075,13 +1079,13 @@ class NodeTreeMainUpdater {
{
bNodeTree &ntree = *node.btree();
bNode &bnode = *node.bnode();
- if (ntree.changed_flag & NTREE_CHANGED_ANY) {
+ if (ntree.runtime->changed_flag & NTREE_CHANGED_ANY) {
return true;
}
- if (bnode.changed_flag & NTREE_CHANGED_NODE_PROPERTY) {
+ if (bnode.runtime->changed_flag & NTREE_CHANGED_NODE_PROPERTY) {
return true;
}
- if (ntree.changed_flag & NTREE_CHANGED_LINK) {
+ if (ntree.runtime->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()) {
@@ -1099,7 +1103,7 @@ class NodeTreeMainUpdater {
return true;
}
}
- if (ntree.changed_flag & NTREE_CHANGED_INTERFACE) {
+ if (ntree.runtime->changed_flag & NTREE_CHANGED_INTERFACE) {
if (node.is_group_input_node() || node.is_group_output_node()) {
return true;
}
@@ -1230,16 +1234,16 @@ class NodeTreeMainUpdater {
}
/* 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;
+ const uint32_t old_changed_flag = ntree.runtime->changed_flag;
+ ntree.runtime->changed_flag = NTREE_CHANGED_NOTHING;
ntree.typeinfo->update(&ntree);
- if (ntree.changed_flag != NTREE_CHANGED_NOTHING) {
+ if (ntree.runtime->changed_flag != NTREE_CHANGED_NOTHING) {
/* The tree ref is outdated and needs to be rebuilt. */
tree_ref.reset();
}
- ntree.changed_flag |= old_changed_flag;
+ ntree.runtime->changed_flag |= old_changed_flag;
}
void remove_unused_previews_when_necessary(bNodeTree &ntree)
@@ -1248,12 +1252,50 @@ class NodeTreeMainUpdater {
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) {
+ if ((ntree.runtime->changed_flag & allowed_flags) == ntree.runtime->changed_flag) {
return;
}
BKE_node_preview_remove_unused(&ntree);
}
+ void propagate_runtime_flags(const NodeTreeRef &tree_ref)
+ {
+ bNodeTree &ntree = *tree_ref.btree();
+ ntree.runtime->runtime_flag = 0;
+ if (ntree.type != NTREE_SHADER) {
+ return;
+ }
+
+ /* Check if a used node group has an animated image. */
+ for (const NodeRef *group_node : tree_ref.nodes_by_type("NodeGroup")) {
+ const bNodeTree *group = reinterpret_cast<bNodeTree *>(group_node->bnode()->id);
+ if (group != nullptr) {
+ ntree.runtime->runtime_flag |= group->runtime->runtime_flag;
+ }
+ }
+ /* Check if the tree itself has an animated image. */
+ for (const StringRefNull idname : {"ShaderNodeTexImage", "ShaderNodeTexEnvironment"}) {
+ for (const NodeRef *node : tree_ref.nodes_by_type(idname)) {
+ Image *image = reinterpret_cast<Image *>(node->bnode()->id);
+ if (image != nullptr && BKE_image_is_animated(image)) {
+ ntree.runtime->runtime_flag |= NTREE_RUNTIME_FLAG_HAS_IMAGE_ANIMATION;
+ break;
+ }
+ }
+ }
+ /* Check if the tree has a material output. */
+ for (const StringRefNull idname : {"ShaderNodeOutputMaterial",
+ "ShaderNodeOutputLight",
+ "ShaderNodeOutputWorld",
+ "ShaderNodeOutputAOV"}) {
+ const Span<const NodeRef *> nodes = tree_ref.nodes_by_type(idname);
+ if (!nodes.is_empty()) {
+ ntree.runtime->runtime_flag |= NTREE_RUNTIME_FLAG_HAS_MATERIAL_OUTPUT;
+ break;
+ }
+ }
+ }
+
void update_node_levels(bNodeTree &ntree)
{
ntreeUpdateNodeLevels(&ntree);
@@ -1283,12 +1325,12 @@ class NodeTreeMainUpdater {
/* 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. */
+ * #btree.runtime.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 old_topology_hash = btree.runtime->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;
+ btree.runtime->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
@@ -1312,7 +1354,7 @@ class NodeTreeMainUpdater {
}
}
- if (btree.changed_flag & NTREE_CHANGED_ANY) {
+ if (btree.runtime->changed_flag & NTREE_CHANGED_ANY) {
return true;
}
@@ -1321,8 +1363,8 @@ class NodeTreeMainUpdater {
}
/* 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 (btree.runtime->changed_flag ==
+ (btree.runtime->changed_flag & (NTREE_CHANGED_LINK | NTREE_CHANGED_REMOVED_NODE))) {
if (old_topology_hash == new_topology_hash) {
return false;
}
@@ -1361,10 +1403,12 @@ class NodeTreeMainUpdater {
return true;
}
/* Assume node groups without output sockets are outputs. */
- /* TODO: Store whether a node group contains a top-level output node (e.g. Material Output) in
- * run-time information on the node group itself. */
- if (bnode.type == NODE_GROUP && node.outputs().is_empty()) {
- return true;
+ if (bnode.type == NODE_GROUP) {
+ const bNodeTree *node_group = reinterpret_cast<const bNodeTree *>(bnode.id);
+ if (node_group != nullptr &&
+ node_group->runtime->runtime_flag & NTREE_RUNTIME_FLAG_HAS_MATERIAL_OUTPUT) {
+ return true;
+ }
}
return false;
}
@@ -1498,12 +1542,12 @@ class NodeTreeMainUpdater {
const NodeRef &node = in_out_socket.node();
const bNode &bnode = *node.bnode();
const bNodeSocket &bsocket = *in_out_socket.bsocket();
- if (bsocket.changed_flag != NTREE_CHANGED_NOTHING) {
+ if (bsocket.runtime->changed_flag != NTREE_CHANGED_NOTHING) {
return true;
}
- if (bnode.changed_flag != NTREE_CHANGED_NOTHING) {
+ if (bnode.runtime->changed_flag != NTREE_CHANGED_NOTHING) {
const bool only_unused_internal_link_changed = (bnode.flag & NODE_MUTED) == 0 &&
- bnode.changed_flag ==
+ bnode.runtime->changed_flag ==
NTREE_CHANGED_INTERNAL_LINK;
if (!only_unused_internal_link_changed) {
return true;
@@ -1549,15 +1593,15 @@ class NodeTreeMainUpdater {
void reset_changed_flags(bNodeTree &ntree)
{
- ntree.changed_flag = NTREE_CHANGED_NOTHING;
+ ntree.runtime->changed_flag = NTREE_CHANGED_NOTHING;
LISTBASE_FOREACH (bNode *, node, &ntree.nodes) {
- node->changed_flag = NTREE_CHANGED_NOTHING;
+ node->runtime->changed_flag = NTREE_CHANGED_NOTHING;
node->update = 0;
LISTBASE_FOREACH (bNodeSocket *, socket, &node->inputs) {
- socket->changed_flag = NTREE_CHANGED_NOTHING;
+ socket->runtime->changed_flag = NTREE_CHANGED_NOTHING;
}
LISTBASE_FOREACH (bNodeSocket *, socket, &node->outputs) {
- socket->changed_flag = NTREE_CHANGED_NOTHING;
+ socket->runtime->changed_flag = NTREE_CHANGED_NOTHING;
}
}
}
diff --git a/source/blender/blenkernel/intern/object.cc b/source/blender/blenkernel/intern/object.cc
index 7f5146f14e0..c8b87c27697 100644
--- a/source/blender/blenkernel/intern/object.cc
+++ b/source/blender/blenkernel/intern/object.cc
@@ -583,7 +583,7 @@ static void object_blend_write(BlendWriter *writer, ID *id, const void *id_addre
}
BKE_particle_system_blend_write(writer, &ob->particlesystem);
- BKE_modifier_blend_write(writer, &ob->modifiers);
+ BKE_modifier_blend_write(writer, &ob->id, &ob->modifiers);
BKE_gpencil_modifier_blend_write(writer, &ob->greasepencil_modifiers);
BKE_shaderfx_blend_write(writer, &ob->shader_fx);
@@ -2271,10 +2271,14 @@ Object *BKE_object_add(Main *bmain, ViewLayer *view_layer, int type, const char
Object *ob = object_add_common(bmain, view_layer, type, name);
LayerCollection *layer_collection = BKE_layer_collection_get_active(view_layer);
- BKE_collection_object_add(bmain, layer_collection->collection, ob);
+ BKE_collection_viewlayer_object_add(bmain, view_layer, layer_collection->collection, ob);
+ /* Note: There is no way to be sure that #BKE_collection_viewlayer_object_add will actually
+ * manage to find a valid collection in given `view_layer` to add the new object to. */
Base *base = BKE_view_layer_base_find(view_layer, ob);
- BKE_view_layer_base_select_and_set_active(view_layer, base);
+ if (base != nullptr) {
+ BKE_view_layer_base_select_and_set_active(view_layer, base);
+ }
return ob;
}
@@ -2479,21 +2483,16 @@ static void copy_object_pose(Object *obn, const Object *ob, const int flag)
* BKE_library_remap stuff, but...
* the flush_constraint_targets callback am not sure about, so will delay that for now. */
LISTBASE_FOREACH (bConstraint *, con, &chan->constraints) {
- const bConstraintTypeInfo *cti = BKE_constraint_typeinfo_get(con);
ListBase targets = {nullptr, nullptr};
- if (cti && cti->get_constraint_targets) {
- cti->get_constraint_targets(con, &targets);
-
+ if (BKE_constraint_targets_get(con, &targets)) {
LISTBASE_FOREACH (bConstraintTarget *, ct, &targets) {
if (ct->tar == ob) {
ct->tar = obn;
}
}
- if (cti->flush_constraint_targets) {
- cti->flush_constraint_targets(con, &targets, false);
- }
+ BKE_constraint_targets_flush(con, &targets, false);
}
}
}
@@ -5484,11 +5483,9 @@ bool BKE_object_modifier_update_subframe(Depsgraph *depsgraph,
/* also update constraint targets */
LISTBASE_FOREACH (bConstraint *, con, &ob->constraints) {
- const bConstraintTypeInfo *cti = BKE_constraint_typeinfo_get(con);
ListBase targets = {nullptr, nullptr};
- if (cti && cti->get_constraint_targets) {
- cti->get_constraint_targets(con, &targets);
+ if (BKE_constraint_targets_get(con, &targets)) {
LISTBASE_FOREACH (bConstraintTarget *, ct, &targets) {
if (ct->tar) {
BKE_object_modifier_update_subframe(
@@ -5496,9 +5493,7 @@ bool BKE_object_modifier_update_subframe(Depsgraph *depsgraph,
}
}
/* free temp targets */
- if (cti->flush_constraint_targets) {
- cti->flush_constraint_targets(con, &targets, false);
- }
+ BKE_constraint_targets_flush(con, &targets, false);
}
}
}
diff --git a/source/blender/blenkernel/intern/object_update.c b/source/blender/blenkernel/intern/object_update.c
index f41d59c77ba..8ff02c7e698 100644
--- a/source/blender/blenkernel/intern/object_update.c
+++ b/source/blender/blenkernel/intern/object_update.c
@@ -130,11 +130,6 @@ void BKE_object_eval_transform_final(Depsgraph *depsgraph, Object *ob)
else {
ob->transflag &= ~OB_NEG_SCALE;
}
-
- /* Assign evaluated version. */
- if ((ob->type == OB_GPENCIL) && (ob->runtime.gpd_eval != NULL)) {
- ob->data = ob->runtime.gpd_eval;
- }
}
void BKE_object_handle_data_update(Depsgraph *depsgraph, Scene *scene, Object *ob)
diff --git a/source/blender/blenkernel/intern/ocean.c b/source/blender/blenkernel/intern/ocean.c
index 4dc0130366e..dec9a594938 100644
--- a/source/blender/blenkernel/intern/ocean.c
+++ b/source/blender/blenkernel/intern/ocean.c
@@ -48,7 +48,7 @@ static float nextfr(RNG *rng, float min, float max)
static float gaussRand(RNG *rng)
{
/* NOTE: to avoid numerical problems with very small numbers, we make these variables
- * singe-precision floats, but later we call the double-precision log() and sqrt() functions
+ * single-precision floats, but later we call the double-precision log() and sqrt() functions
* instead of logf() and sqrtf(). */
float x;
float y;
diff --git a/source/blender/blenkernel/intern/packedFile.c b/source/blender/blenkernel/intern/packedFile.c
index e7ed100ed03..7c96c463339 100644
--- a/source/blender/blenkernel/intern/packedFile.c
+++ b/source/blender/blenkernel/intern/packedFile.c
@@ -237,14 +237,14 @@ void BKE_packedfile_pack_all(Main *bmain, ReportList *reports, bool verbose)
for (ima = bmain->images.first; ima; ima = ima->id.next) {
if (BKE_image_has_packedfile(ima) == false && !ID_IS_LINKED(ima)) {
- if (ima->source == IMA_SRC_FILE) {
+ if (ELEM(ima->source, IMA_SRC_FILE, IMA_SRC_TILED)) {
BKE_image_packfiles(reports, ima, ID_BLEND_PATH(bmain, &ima->id));
tot++;
}
- else if (BKE_image_has_multiple_ibufs(ima) && verbose) {
+ else if (ELEM(ima->source, IMA_SRC_MOVIE, IMA_SRC_SEQUENCE) && verbose) {
BKE_reportf(reports,
RPT_WARNING,
- "Image '%s' skipped, movies, image sequences and packed files not supported",
+ "Image '%s' skipped, packing movies or image sequences not supported",
ima->id.name + 2);
}
}
@@ -494,15 +494,22 @@ static void unpack_generate_paths(const char *name,
if (tempname[0] == '\0') {
/* NOTE: we generally do not have any real way to re-create extension out of data. */
- BLI_strncpy(tempname, id->name + 2, sizeof(tempname));
+ const size_t len = BLI_strncpy_rlen(tempname, id->name + 2, sizeof(tempname));
printf("%s\n", tempname);
- /* For images we can add the file extension based on the file magic. */
+ /* For images ensure that the temporary filename contains tile number information as well as
+ * a file extension based on the file magic. */
if (id_type == ID_IM) {
- ImagePackedFile *imapf = ((Image *)id)->packedfiles.last;
+ Image *ima = (Image *)id;
+ ImagePackedFile *imapf = ima->packedfiles.last;
if (imapf != NULL && imapf->packedfile != NULL) {
const PackedFile *pf = imapf->packedfile;
enum eImbFileType ftype = IMB_ispic_type_from_memory((const uchar *)pf->data, pf->size);
+ if (ima->source == IMA_SRC_TILED) {
+ char tile_number[6];
+ BLI_snprintf(tile_number, sizeof(tile_number), ".%d", imapf->tile_number);
+ BLI_strncpy(tempname + len, tile_number, sizeof(tempname) - len);
+ }
if (ftype != IMB_FTYPE_NONE) {
const int imtype = BKE_ftype_to_imtype(ftype, NULL);
BKE_image_path_ensure_ext_from_imtype(tempname, imtype);
@@ -639,6 +646,11 @@ int BKE_packedfile_unpack_image(Main *bmain,
/* keep the new name in the image for non-pack specific reasons */
if (how != PF_REMOVE) {
BLI_strncpy(ima->filepath, new_file_path, sizeof(imapf->filepath));
+ if (ima->source == IMA_SRC_TILED) {
+ /* Ensure that the Image filepath is kept in a tokenized format. */
+ char *filename = (char *)BLI_path_basename(ima->filepath);
+ BKE_image_ensure_tile_token(filename);
+ }
}
MEM_freeN(new_file_path);
}
diff --git a/source/blender/blenkernel/intern/paint.c b/source/blender/blenkernel/intern/paint.c
index 0f523d87d9b..81c7e7f34da 100644
--- a/source/blender/blenkernel/intern/paint.c
+++ b/source/blender/blenkernel/intern/paint.c
@@ -606,6 +606,11 @@ ePaintMode BKE_paintmode_get_from_tool(const struct bToolRef *tref)
Brush *BKE_paint_brush(Paint *p)
{
+ return (Brush *)BKE_paint_brush_for_read((const Paint *)p);
+}
+
+const Brush *BKE_paint_brush_for_read(const Paint *p)
+{
return p ? p->brush : NULL;
}
@@ -1669,7 +1674,7 @@ static void sculpt_update_object(Depsgraph *depsgraph,
ss->vmask = CustomData_get_layer(&me->vdata, CD_PAINT_MASK);
CustomDataLayer *layer;
- AttributeDomain domain;
+ eAttrDomain domain;
if (BKE_pbvh_get_color_layer(me, &layer, &domain)) {
if (layer->type == CD_PROP_COLOR) {
@@ -2051,7 +2056,7 @@ void BKE_sculpt_face_sets_ensure_from_base_mesh_visibility(Mesh *mesh)
void BKE_sculpt_sync_face_sets_visibility_to_base_mesh(Mesh *mesh)
{
- int *face_sets = CustomData_get_layer(&mesh->pdata, CD_SCULPT_FACE_SETS);
+ const int *face_sets = CustomData_get_layer(&mesh->pdata, CD_SCULPT_FACE_SETS);
if (!face_sets) {
return;
}
@@ -2066,7 +2071,7 @@ void BKE_sculpt_sync_face_sets_visibility_to_base_mesh(Mesh *mesh)
void BKE_sculpt_sync_face_sets_visibility_to_grids(Mesh *mesh, SubdivCCG *subdiv_ccg)
{
- int *face_sets = CustomData_get_layer(&mesh->pdata, CD_SCULPT_FACE_SETS);
+ const int *face_sets = CustomData_get_layer(&mesh->pdata, CD_SCULPT_FACE_SETS);
if (!face_sets) {
return;
}
@@ -2112,7 +2117,7 @@ void BKE_sculpt_ensure_orig_mesh_data(Scene *scene, Object *object)
/* Copy the current mesh visibility to the Face Sets. */
BKE_sculpt_face_sets_ensure_from_base_mesh_visibility(mesh);
if (object->sculpt != NULL) {
- /* If a sculpt session is active, ensure we have its faceset data porperly up-to-date. */
+ /* If a sculpt session is active, ensure we have its face-set data properly up-to-date. */
object->sculpt->face_sets = CustomData_get_layer(&mesh->pdata, CD_SCULPT_FACE_SETS);
/* NOTE: In theory we could add that on the fly when required by sculpt code.
@@ -2279,7 +2284,7 @@ void BKE_sculpt_bvh_update_from_ccg(PBVH *pbvh, SubdivCCG *subdiv_ccg)
subdiv_ccg->grid_hidden);
}
-bool BKE_sculptsession_use_pbvh_draw(const Object *ob, const View3D *v3d)
+bool BKE_sculptsession_use_pbvh_draw(const Object *ob, const View3D *UNUSED(v3d))
{
SculptSession *ss = ob->sculpt;
if (ss == NULL || ss->pbvh == NULL || ss->mode_type != OB_MODE_SCULPT) {
@@ -2288,8 +2293,8 @@ bool BKE_sculptsession_use_pbvh_draw(const Object *ob, const View3D *v3d)
if (BKE_pbvh_type(ss->pbvh) == PBVH_FACES) {
/* Regular mesh only draws from PBVH without modifiers and shape keys. */
- const bool full_shading = (v3d && (v3d->shading.type > OB_SOLID));
- return !(ss->shapekey_active || ss->deform_modifiers_active || full_shading);
+
+ return !(ss->shapekey_active || ss->deform_modifiers_active);
}
/* Multires and dyntopo always draw directly from the PBVH. */
diff --git a/source/blender/blenkernel/intern/particle.c b/source/blender/blenkernel/intern/particle.c
index b935f2afaaa..b44b70bcd55 100644
--- a/source/blender/blenkernel/intern/particle.c
+++ b/source/blender/blenkernel/intern/particle.c
@@ -1667,7 +1667,7 @@ void psys_interpolate_face(Mesh *mesh,
const float (*vert_normals)[3],
MFace *mface,
MTFace *tface,
- float (*orcodata)[3],
+ const float (*orcodata)[3],
float w[4],
float vec[3],
float nor[3],
@@ -1680,7 +1680,7 @@ void psys_interpolate_face(Mesh *mesh,
float *uv1, *uv2, *uv3, *uv4;
float n1[3], n2[3], n3[3], n4[3];
float tuv[4][2];
- float *o1, *o2, *o3, *o4;
+ const float *o1, *o2, *o3, *o4;
v1 = mvert[mface->v1].co;
v2 = mvert[mface->v2].co;
@@ -1903,9 +1903,10 @@ int psys_particle_dm_face_lookup(Mesh *mesh_final,
struct LinkNode **poly_nodes)
{
MFace *mtessface_final;
- OrigSpaceFace *osface_final;
+ const OrigSpaceFace *osface_final;
int pindex_orig;
- float uv[2], (*faceuv)[2];
+ float uv[2];
+ const float(*faceuv)[2];
const int *index_mf_to_mpoly_deformed = NULL;
const int *index_mf_to_mpoly = NULL;
@@ -2048,11 +2049,7 @@ static int psys_map_index_on_dm(Mesh *mesh,
}
else { /* FROM_FACE/FROM_VOLUME */
/* find a face on the derived mesh that uses this face */
- MFace *mface;
- OrigSpaceFace *osface;
- int i;
-
- i = index_dmcache;
+ int i = index_dmcache;
if (i == DMCACHE_NOTFOUND || i >= mesh->totface) {
return 0;
@@ -2062,8 +2059,8 @@ static int psys_map_index_on_dm(Mesh *mesh,
/* modify the original weights to become
* weights for the derived mesh face */
- osface = CustomData_get_layer(&mesh->fdata, CD_ORIGSPACE);
- mface = &mesh->mface[i];
+ OrigSpaceFace *osface = CustomData_get_layer(&mesh->fdata, CD_ORIGSPACE);
+ const MFace *mface = &mesh->mface[i];
if (osface == NULL) {
mapfw[0] = mapfw[1] = mapfw[2] = mapfw[3] = 0.0f;
@@ -2090,7 +2087,7 @@ void psys_particle_on_dm(Mesh *mesh_final,
float orco[3])
{
float tmpnor[3], mapfw[4];
- float(*orcodata)[3];
+ const float(*orcodata)[3];
int mapindex;
if (!psys_map_index_on_dm(
@@ -2279,7 +2276,7 @@ void psys_emitter_customdata_mask(ParticleSystem *psys, CustomData_MeshMasks *r_
r_cddata_masks->fmask |= CD_MASK_MTFACE;
}
- /* ask for vertexgroups if we need them */
+ /* Ask for vertex-groups if we need them. */
for (i = 0; i < PSYS_TOT_VG; i++) {
if (psys->vgroup[i]) {
r_cddata_masks->vmask |= CD_MASK_MDEFORMVERT;
@@ -3628,7 +3625,7 @@ static void psys_cache_edit_paths_iter(void *__restrict iter_data_v,
BKE_defvert_weight_to_rgb(ca->col, pind.hkey[1]->weight);
}
else {
- /* warning: copied from 'do_particle_interpolation' (without 'mvert' array stepping) */
+ /* WARNING: copied from 'do_particle_interpolation' (without 'mvert' array stepping) */
float real_t;
if (result.time < 0.0f) {
real_t = -result.time;
@@ -3796,7 +3793,7 @@ void psys_get_from_key(ParticleKey *key, float loc[3], float vel[3], float rot[4
}
}
-static void triatomat(float *v1, float *v2, float *v3, float (*uv)[2], float mat[4][4])
+static void triatomat(float *v1, float *v2, float *v3, const float (*uv)[2], float mat[4][4])
{
float det, w1, w2, d1[2], d2[2];
@@ -3842,8 +3839,7 @@ static void psys_face_mat(Object *ob, Mesh *mesh, ParticleData *pa, float mat[4]
{
float v[3][3];
MFace *mface;
- OrigSpaceFace *osface;
- float(*orcodata)[3];
+ const float(*orcodata)[3];
int i = (ELEM(pa->num_dmcache, DMCACHE_ISCHILD, DMCACHE_NOTFOUND)) ? pa->num : pa->num_dmcache;
if (i == -1 || i >= mesh->totface) {
@@ -3852,7 +3848,7 @@ static void psys_face_mat(Object *ob, Mesh *mesh, ParticleData *pa, float mat[4]
}
mface = &mesh->mface[i];
- osface = CustomData_get(&mesh->fdata, i, CD_ORIGSPACE);
+ const OrigSpaceFace *osface = CustomData_get(&mesh->fdata, i, CD_ORIGSPACE);
if (orco && (orcodata = CustomData_get_layer(&mesh->vdata, CD_ORCO))) {
copy_v3_v3(v[0], orcodata[mface->v1]);
@@ -4159,7 +4155,7 @@ static int get_particle_uv(Mesh *mesh,
bool from_vert)
{
MFace *mf;
- MTFace *tf;
+ const MTFace *tf;
int i;
tf = CustomData_get_layer_named(&mesh->fdata, CD_MTFACE, name);
@@ -5039,7 +5035,6 @@ void psys_get_dupli_texture(ParticleSystem *psys,
float uv[2],
float orco[3])
{
- MFace *mface;
float loc[3];
int num;
@@ -5063,9 +5058,9 @@ void psys_get_dupli_texture(ParticleSystem *psys,
const int uv_idx = CustomData_get_render_layer(mtf_data, CD_MTFACE);
if (uv_idx >= 0) {
- MTFace *mtface = CustomData_get_layer_n(mtf_data, CD_MTFACE, uv_idx);
+ const MTFace *mtface = CustomData_get_layer_n(mtf_data, CD_MTFACE, uv_idx);
if (mtface != NULL) {
- mface = CustomData_get(&psmd->mesh_final->fdata, cpa->num, CD_MFACE);
+ const MFace *mface = CustomData_get(&psmd->mesh_final->fdata, cpa->num, CD_MFACE);
mtface += cpa->num;
psys_interpolate_uvs(mtface, mface->v4, cpa->fuv, uv);
}
@@ -5107,8 +5102,8 @@ void psys_get_dupli_texture(ParticleSystem *psys,
const int uv_idx = CustomData_get_render_layer(mtf_data, CD_MTFACE);
if (uv_idx >= 0) {
- MTFace *mtface = CustomData_get_layer_n(mtf_data, CD_MTFACE, uv_idx);
- mface = CustomData_get(&psmd->mesh_final->fdata, num, CD_MFACE);
+ const MTFace *mtface = CustomData_get_layer_n(mtf_data, CD_MTFACE, uv_idx);
+ const MFace *mface = CustomData_get(&psmd->mesh_final->fdata, num, CD_MFACE);
mtface += num;
psys_interpolate_uvs(mtface, mface->v4, pa->fuv, uv);
}
diff --git a/source/blender/blenkernel/intern/particle_distribute.c b/source/blender/blenkernel/intern/particle_distribute.c
index 244396af6e6..c461b7f108d 100644
--- a/source/blender/blenkernel/intern/particle_distribute.c
+++ b/source/blender/blenkernel/intern/particle_distribute.c
@@ -808,7 +808,7 @@ static void exec_distribute_child(TaskPool *__restrict UNUSED(pool), void *taskd
static int distribute_compare_orig_index(const void *p1, const void *p2, void *user_data)
{
- int *orig_index = (int *)user_data;
+ const int *orig_index = (const int *)user_data;
int index1 = orig_index[*(const int *)p1];
int index2 = orig_index[*(const int *)p2];
@@ -989,7 +989,7 @@ static int psys_thread_context_init_distribute(ParticleThreadContext *ctx,
if (from == PART_FROM_VERT) {
MVert *mv = mesh->mvert;
- float(*orcodata)[3] = CustomData_get_layer(&mesh->vdata, CD_ORCO);
+ const float(*orcodata)[3] = CustomData_get_layer(&mesh->vdata, CD_ORCO);
int totvert = mesh->totvert;
tree = BLI_kdtree_3d_new(totvert);
@@ -1037,7 +1037,7 @@ static int psys_thread_context_init_distribute(ParticleThreadContext *ctx,
if ((part->flag & PART_EDISTR || children) && from != PART_FROM_VERT) {
MVert *v1, *v2, *v3, *v4;
float totarea = 0.0f, co1[3], co2[3], co3[3], co4[3];
- float(*orcodata)[3];
+ const float(*orcodata)[3];
orcodata = CustomData_get_layer(&mesh->vdata, CD_ORCO);
@@ -1216,10 +1216,10 @@ static int psys_thread_context_init_distribute(ParticleThreadContext *ctx,
MEM_freeN(element_sum);
MEM_freeN(element_map);
- /* For hair, sort by origindex (allows optimization's in rendering), */
- /* however with virtual parents the children need to be in random order. */
+ /* For hair, sort by #CD_ORIGINDEX (allows optimization's in rendering),
+ * however with virtual parents the children need to be in random order. */
if (part->type == PART_HAIR && !(part->childtype == PART_CHILD_FACES && part->parents != 0.0f)) {
- int *orig_index = NULL;
+ const int *orig_index = NULL;
if (from == PART_FROM_VERT) {
if (mesh->totvert) {
@@ -1233,8 +1233,11 @@ static int psys_thread_context_init_distribute(ParticleThreadContext *ctx,
}
if (orig_index) {
- BLI_qsort_r(
- particle_element, totpart, sizeof(int), distribute_compare_orig_index, orig_index);
+ BLI_qsort_r(particle_element,
+ totpart,
+ sizeof(int),
+ distribute_compare_orig_index,
+ (void *)orig_index);
}
}
diff --git a/source/blender/blenkernel/intern/particle_system.c b/source/blender/blenkernel/intern/particle_system.c
index 7fdc60a265b..3ad770c5429 100644
--- a/source/blender/blenkernel/intern/particle_system.c
+++ b/source/blender/blenkernel/intern/particle_system.c
@@ -321,8 +321,9 @@ void psys_calc_dmcache(Object *ob, Mesh *mesh_final, Mesh *mesh_original, Partic
if (!mesh_final->runtime.deformed_only) {
/* Will use later to speed up subsurf/evaluated mesh. */
LinkNode *node, *nodedmelem, **nodearray;
- int totdmelem, totelem, i, *origindex, *origindex_poly = NULL;
-
+ int totdmelem, totelem, i;
+ const int *origindex;
+ const int *origindex_poly = NULL;
if (psys->part->from == PART_FROM_VERT) {
totdmelem = mesh_final->totvert;
@@ -3120,7 +3121,7 @@ static void collision_check(ParticleSimulationData *sim, int p, float dfra, floa
col.cfra = cfra;
col.old_cfra = sim->psys->cfra;
- /* get acceleration (from gravity, forcefields etc. to be re-applied in collision response) */
+ /* Get acceleration (from gravity, force-fields etc. to be re-applied in collision response). */
sub_v3_v3v3(col.acc, pa->state.vel, pa->prev_state.vel);
mul_v3_fl(col.acc, 1.0f / col.total_time);
@@ -4961,7 +4962,7 @@ void particle_system_update(struct Depsgraph *depsgraph,
}
/* Save matrix for duplicators,
- * at rendertime the actual dupliobject's matrix is used so don't update! */
+ * at render-time the actual dupli-object's matrix is used so don't update! */
invert_m4_m4(psys->imat, ob->obmat);
BKE_particle_batch_cache_dirty_tag(psys, BKE_PARTICLE_BATCH_DIRTY_ALL);
diff --git a/source/blender/blenkernel/intern/pbvh.c b/source/blender/blenkernel/intern/pbvh.c
index e1ab4ccfb0a..3b20bdc826c 100644
--- a/source/blender/blenkernel/intern/pbvh.c
+++ b/source/blender/blenkernel/intern/pbvh.c
@@ -244,8 +244,8 @@ static int map_insert_vert(
key = POINTER_FROM_INT(vertex);
if (!BLI_ghash_ensure_p(map, key, &value_p)) {
int value_i;
- if (BLI_BITMAP_TEST(pbvh->vert_bitmap, vertex) == 0) {
- BLI_BITMAP_ENABLE(pbvh->vert_bitmap, vertex);
+ if (!pbvh->vert_bitmap[vertex]) {
+ pbvh->vert_bitmap[vertex] = true;
value_i = *uniq_verts;
(*uniq_verts)++;
}
@@ -562,7 +562,7 @@ void BKE_pbvh_build_mesh(PBVH *pbvh,
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->vert_bitmap = MEM_calloc_arrayN(totvert, sizeof(bool), "bvh->vert_bitmap");
pbvh->totvert = totvert;
pbvh->leaf_limit = LEAF_LIMIT;
pbvh->vdata = vdata;
@@ -600,7 +600,7 @@ void BKE_pbvh_build_mesh(PBVH *pbvh,
MEM_freeN(prim_bbc);
/* Clear the bitmap so it can be used as an update tag later on. */
- BLI_bitmap_set_all(pbvh->vert_bitmap, false, totvert);
+ memset(pbvh->vert_bitmap, 0, sizeof(bool) * totvert);
BKE_pbvh_update_active_vcol(pbvh, mesh);
}
@@ -714,6 +714,10 @@ void BKE_pbvh_free(PBVH *pbvh)
MEM_SAFE_FREE(pbvh->vert_bitmap);
+ if (pbvh->vbo_id) {
+ GPU_pbvh_free_format(pbvh->vbo_id);
+ }
+
MEM_freeN(pbvh);
}
@@ -1021,7 +1025,7 @@ static void pbvh_update_normals_clear_task_cb(void *__restrict userdata,
const int totvert = node->uniq_verts;
for (int i = 0; i < totvert; i++) {
const int v = verts[i];
- if (BLI_BITMAP_TEST(pbvh->vert_bitmap, v)) {
+ if (pbvh->vert_bitmap[v]) {
zero_v3(vnors[v]);
}
}
@@ -1064,7 +1068,7 @@ static void pbvh_update_normals_accum_task_cb(void *__restrict userdata,
for (int j = sides; j--;) {
const int v = vtri[j];
- if (BLI_BITMAP_TEST(pbvh->vert_bitmap, v)) {
+ if (pbvh->vert_bitmap[v]) {
/* NOTE: This avoids `lock, add_v3_v3, unlock`
* and is five to ten times quicker than a spin-lock.
* Not exact equivalent though, since atomicity is only ensured for one component
@@ -1096,9 +1100,9 @@ static void pbvh_update_normals_store_task_cb(void *__restrict userdata,
/* No atomics necessary because we are iterating over uniq_verts only,
* so we know only this thread will handle this vertex. */
- if (BLI_BITMAP_TEST(pbvh->vert_bitmap, v)) {
+ if (pbvh->vert_bitmap[v]) {
normalize_v3(vnors[v]);
- BLI_BITMAP_DISABLE(pbvh->vert_bitmap, v);
+ pbvh->vert_bitmap[v] = false;
}
}
@@ -1264,7 +1268,7 @@ static int pbvh_get_buffers_update_flags(PBVH *UNUSED(pbvh))
return update_flags;
}
-bool BKE_pbvh_get_color_layer(const Mesh *me, CustomDataLayer **r_layer, AttributeDomain *r_attr)
+bool BKE_pbvh_get_color_layer(const Mesh *me, CustomDataLayer **r_layer, eAttrDomain *r_attr)
{
CustomDataLayer *layer = BKE_id_attributes_active_color_get((ID *)me);
@@ -1274,7 +1278,7 @@ bool BKE_pbvh_get_color_layer(const Mesh *me, CustomDataLayer **r_layer, Attribu
return false;
}
- AttributeDomain domain = BKE_id_attribute_domain((ID *)me, layer);
+ eAttrDomain domain = BKE_id_attribute_domain((ID *)me, layer);
if (!ELEM(domain, ATTR_DOMAIN_POINT, ATTR_DOMAIN_CORNER)) {
*r_layer = NULL;
@@ -1299,6 +1303,17 @@ static void pbvh_update_draw_buffer_cb(void *__restrict userdata,
PBVH *pbvh = data->pbvh;
PBVHNode *node = data->nodes[n];
+ CustomData *vdata, *ldata;
+
+ if (!pbvh->bm) {
+ vdata = pbvh->vdata;
+ ldata = pbvh->ldata;
+ }
+ else {
+ vdata = &pbvh->bm->vdata;
+ ldata = &pbvh->bm->ldata;
+ }
+
if (node->flag & PBVH_RebuildDrawBuffers) {
switch (pbvh->type) {
case PBVH_GRIDS:
@@ -1326,7 +1341,8 @@ static void pbvh_update_draw_buffer_cb(void *__restrict userdata,
const int update_flags = pbvh_get_buffers_update_flags(pbvh);
switch (pbvh->type) {
case PBVH_GRIDS:
- GPU_pbvh_grid_buffers_update(node->draw_buffers,
+ GPU_pbvh_grid_buffers_update(pbvh->vbo_id,
+ node->draw_buffers,
pbvh->subdiv_ccg,
pbvh->grids,
pbvh->grid_flag_mats,
@@ -1339,26 +1355,22 @@ static void pbvh_update_draw_buffer_cb(void *__restrict userdata,
update_flags);
break;
case PBVH_FACES: {
- CustomDataLayer *layer = NULL;
- AttributeDomain domain;
-
- BKE_pbvh_get_color_layer(pbvh->mesh, &layer, &domain);
-
- GPU_pbvh_mesh_buffers_update(node->draw_buffers,
+ GPU_pbvh_mesh_buffers_update(pbvh->vbo_id,
+ node->draw_buffers,
pbvh->verts,
- pbvh->vert_normals,
+ vdata,
+ ldata,
CustomData_get_layer(pbvh->vdata, CD_PAINT_MASK),
- layer ? layer->data : NULL,
- layer ? layer->type : -1,
- layer ? domain : ATTR_DOMAIN_AUTO,
CustomData_get_layer(pbvh->pdata, CD_SCULPT_FACE_SETS),
pbvh->face_sets_color_seed,
pbvh->face_sets_color_default,
- update_flags);
+ update_flags,
+ pbvh->vert_normals);
break;
}
case PBVH_BMESH:
- GPU_pbvh_bmesh_buffers_update(node->draw_buffers,
+ GPU_pbvh_bmesh_buffers_update(pbvh->vbo_id,
+ node->draw_buffers,
pbvh->bm,
node->bm_faces,
node->bm_unique_verts,
@@ -1379,8 +1391,79 @@ void pbvh_free_draw_buffers(PBVH *pbvh, PBVHNode *node)
}
}
+static void pbvh_check_draw_layout(PBVH *pbvh)
+{
+ const CustomData *vdata;
+ const CustomData *ldata;
+
+ if (!pbvh->vbo_id) {
+ pbvh->vbo_id = GPU_pbvh_make_format();
+ }
+
+ switch (pbvh->type) {
+ case PBVH_BMESH:
+ if (!pbvh->bm) {
+ /* BMesh hasn't been created yet */
+ return;
+ }
+
+ vdata = &pbvh->bm->vdata;
+ ldata = &pbvh->bm->ldata;
+ break;
+ case PBVH_FACES:
+ vdata = pbvh->vdata;
+ ldata = pbvh->ldata;
+ break;
+ case PBVH_GRIDS:
+ ldata = vdata = NULL;
+ break;
+ }
+
+ /* Rebuild all draw buffers if attribute layout changed.
+ *
+ * NOTE: The optimization where we only send active attributes
+ * to the GPU in workbench mode is disabled due to bugs
+ * (there's no guarantee there isn't another EEVEE viewport which would
+ * free the draw buffers and corrupt the draw cache).
+ */
+ if (GPU_pbvh_attribute_names_update(pbvh->type, pbvh->vbo_id, vdata, ldata, false)) {
+ /* attribute layout changed; force rebuild */
+ for (int i = 0; i < pbvh->totnode; i++) {
+ PBVHNode *node = pbvh->nodes + i;
+
+ if (node->flag & PBVH_Leaf) {
+ node->flag |= PBVH_RebuildDrawBuffers | PBVH_UpdateDrawBuffers | PBVH_UpdateRedraw;
+ }
+ }
+ }
+}
+
static void pbvh_update_draw_buffers(PBVH *pbvh, PBVHNode **nodes, int totnode, int update_flag)
{
+ const CustomData *vdata;
+
+ if (!pbvh->vbo_id) {
+ pbvh->vbo_id = GPU_pbvh_make_format();
+ }
+
+ switch (pbvh->type) {
+ case PBVH_BMESH:
+ if (!pbvh->bm) {
+ /* BMesh hasn't been created yet */
+ return;
+ }
+
+ vdata = &pbvh->bm->vdata;
+ break;
+ case PBVH_FACES:
+ vdata = pbvh->vdata;
+ break;
+ case PBVH_GRIDS:
+ vdata = NULL;
+ break;
+ }
+ UNUSED_VARS(vdata);
+
if ((update_flag & PBVH_RebuildDrawBuffers) || ELEM(pbvh->type, PBVH_GRIDS, PBVH_BMESH)) {
/* Free buffers uses OpenGL, so not in parallel. */
for (int n = 0; n < totnode; n++) {
@@ -1879,7 +1962,7 @@ bool BKE_pbvh_node_fully_unmasked_get(PBVHNode *node)
void BKE_pbvh_vert_mark_update(PBVH *pbvh, int index)
{
BLI_assert(pbvh->type == PBVH_FACES);
- BLI_BITMAP_ENABLE(pbvh->vert_bitmap, index);
+ pbvh->vert_bitmap[index] = true;
}
void BKE_pbvh_node_get_loops(PBVH *pbvh,
@@ -2044,7 +2127,7 @@ bool BKE_pbvh_node_vert_update_check_any(PBVH *pbvh, PBVHNode *node)
for (int i = 0; i < totvert; i++) {
const int v = verts[i];
- if (BLI_BITMAP_TEST(pbvh->vert_bitmap, v)) {
+ if (pbvh->vert_bitmap[v]) {
return true;
}
}
@@ -2540,7 +2623,7 @@ static bool pbvh_faces_node_nearest_to_ray(PBVH *pbvh,
}
if (origco) {
- /* intersect with backuped original coordinates */
+ /* Intersect with backed-up original coordinates. */
hit |= ray_face_nearest_tri(ray_start,
ray_normal,
origco[face_verts[0]],
@@ -2783,7 +2866,8 @@ void BKE_pbvh_draw_cb(PBVH *pbvh,
PBVHFrustumPlanes *update_frustum,
PBVHFrustumPlanes *draw_frustum,
void (*draw_fn)(void *user_data, GPU_PBVH_Buffers *buffers),
- void *user_data)
+ void *user_data,
+ bool UNUSED(full_render))
{
PBVHNode **nodes;
int totnode;
@@ -2806,6 +2890,8 @@ void BKE_pbvh_draw_cb(PBVH *pbvh,
update_flag = PBVH_RebuildDrawBuffers | PBVH_UpdateDrawBuffers;
}
+ pbvh_check_draw_layout(pbvh);
+
/* Update draw buffers. */
if (totnode != 0 && (update_flag & (PBVH_RebuildDrawBuffers | PBVH_UpdateDrawBuffers))) {
pbvh_update_draw_buffers(pbvh, nodes, totnode, update_flag);
@@ -3156,6 +3242,11 @@ bool BKE_pbvh_is_drawing(const PBVH *pbvh)
return pbvh->is_drawing;
}
+bool BKE_pbvh_draw_cache_invalid(const PBVH *pbvh)
+{
+ return pbvh->draw_cache_invalid;
+}
+
void BKE_pbvh_is_drawing_set(PBVH *pbvh, bool val)
{
pbvh->is_drawing = val;
@@ -3229,8 +3320,3 @@ void BKE_pbvh_ensure_node_loops(PBVH *pbvh)
MEM_SAFE_FREE(visit);
}
-
-bool BKE_pbvh_draw_cache_invalid(const PBVH *pbvh)
-{
- return pbvh->draw_cache_invalid;
-}
diff --git a/source/blender/blenkernel/intern/pbvh.cc b/source/blender/blenkernel/intern/pbvh.cc
index be6e95426c2..dec93826b9b 100644
--- a/source/blender/blenkernel/intern/pbvh.cc
+++ b/source/blender/blenkernel/intern/pbvh.cc
@@ -44,7 +44,7 @@ using blender::IndexRange;
namespace blender::bke {
template<typename Func>
-inline void to_static_color_type(const CustomDataType type, const Func &func)
+inline void to_static_color_type(const eCustomDataType type, const Func &func)
{
switch (type) {
case CD_PROP_COLOR:
@@ -146,7 +146,7 @@ static void pbvh_vertex_color_set(PBVH &pbvh, int vertex, const float color[4])
extern "C" {
void BKE_pbvh_vertex_color_get(const PBVH *pbvh, int vertex, float r_color[4])
{
- blender::bke::to_static_color_type(CustomDataType(pbvh->color_layer->type), [&](auto dummy) {
+ blender::bke::to_static_color_type(eCustomDataType(pbvh->color_layer->type), [&](auto dummy) {
using T = decltype(dummy);
blender::bke::pbvh_vertex_color_get<T>(*pbvh, vertex, r_color);
});
@@ -154,7 +154,7 @@ void BKE_pbvh_vertex_color_get(const PBVH *pbvh, int vertex, float r_color[4])
void BKE_pbvh_vertex_color_set(PBVH *pbvh, int vertex, const float color[4])
{
- blender::bke::to_static_color_type(CustomDataType(pbvh->color_layer->type), [&](auto dummy) {
+ blender::bke::to_static_color_type(eCustomDataType(pbvh->color_layer->type), [&](auto dummy) {
using T = decltype(dummy);
blender::bke::pbvh_vertex_color_set<T>(*pbvh, vertex, color);
});
@@ -165,7 +165,7 @@ void BKE_pbvh_swap_colors(PBVH *pbvh,
const int indices_num,
float (*r_colors)[4])
{
- blender::bke::to_static_color_type(CustomDataType(pbvh->color_layer->type), [&](auto dummy) {
+ blender::bke::to_static_color_type(eCustomDataType(pbvh->color_layer->type), [&](auto dummy) {
using T = decltype(dummy);
T *pbvh_colors = static_cast<T *>(pbvh->color_layer->data);
for (const int i : IndexRange(indices_num)) {
@@ -181,7 +181,7 @@ void BKE_pbvh_store_colors(PBVH *pbvh,
const int indices_num,
float (*r_colors)[4])
{
- blender::bke::to_static_color_type(CustomDataType(pbvh->color_layer->type), [&](auto dummy) {
+ blender::bke::to_static_color_type(eCustomDataType(pbvh->color_layer->type), [&](auto dummy) {
using T = decltype(dummy);
T *pbvh_colors = static_cast<T *>(pbvh->color_layer->data);
for (const int i : IndexRange(indices_num)) {
@@ -199,7 +199,7 @@ void BKE_pbvh_store_colors_vertex(PBVH *pbvh,
BKE_pbvh_store_colors(pbvh, indices, indices_num, r_colors);
}
else {
- blender::bke::to_static_color_type(CustomDataType(pbvh->color_layer->type), [&](auto dummy) {
+ blender::bke::to_static_color_type(eCustomDataType(pbvh->color_layer->type), [&](auto dummy) {
using T = decltype(dummy);
for (const int i : IndexRange(indices_num)) {
blender::bke::pbvh_vertex_color_get<T>(*pbvh, indices[i], r_colors[i]);
diff --git a/source/blender/blenkernel/intern/pbvh_bmesh.c b/source/blender/blenkernel/intern/pbvh_bmesh.c
index d4c6dcfbc96..112fd01c699 100644
--- a/source/blender/blenkernel/intern/pbvh_bmesh.c
+++ b/source/blender/blenkernel/intern/pbvh_bmesh.c
@@ -376,6 +376,9 @@ static bool pbvh_bmesh_node_limit_ensure(PBVH *pbvh, int node_index)
return false;
}
+ /* Trigger draw manager cache invalidation. */
+ pbvh->draw_cache_invalid = true;
+
/* For each BMFace, store the AABB and AABB centroid */
BBC *bbc_array = MEM_mallocN(sizeof(BBC) * bm_faces_size, "BBC");
diff --git a/source/blender/blenkernel/intern/pbvh_intern.h b/source/blender/blenkernel/intern/pbvh_intern.h
index b5480673653..a4ac2744a73 100644
--- a/source/blender/blenkernel/intern/pbvh_intern.h
+++ b/source/blender/blenkernel/intern/pbvh_intern.h
@@ -2,6 +2,8 @@
#pragma once
+struct PBVHGPUFormat;
+
/** \file
* \ingroup bke
*/
@@ -10,6 +12,11 @@
extern "C" {
#endif
+struct MLoop;
+struct MLoopTri;
+struct MPoly;
+struct MVert;
+
/* Axis-aligned bounding box */
typedef struct {
float bmin[3], bmax[3];
@@ -118,9 +125,7 @@ struct PBVHNode {
PBVHPixelsNode pixels;
};
-typedef enum {
- PBVH_DYNTOPO_SMOOTH_SHADING = 1,
-} PBVHFlags;
+typedef enum { PBVH_DYNTOPO_SMOOTH_SHADING = 1 } PBVHFlags;
typedef struct PBVHBMeshLog PBVHBMeshLog;
@@ -141,12 +146,12 @@ struct PBVH {
/* Mesh data */
const struct Mesh *mesh;
- /* Note: Normals are not const because they can be updated for drawing by sculpt code. */
+ /* 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;
- const MLoopTri *looptri;
+ struct MVert *verts;
+ const struct MPoly *mpoly;
+ const struct MLoop *mloop;
+ const struct MLoopTri *looptri;
CustomData *vdata;
CustomData *ldata;
CustomData *pdata;
@@ -165,7 +170,7 @@ struct PBVH {
/* Used during BVH build and later to mark that a vertex needs to update
* (its normal must be recalculated). */
- BLI_bitmap *vert_bitmap;
+ bool *vert_bitmap;
#ifdef PERFCNTRS
int perf_modified;
@@ -193,12 +198,14 @@ struct PBVH {
const struct MeshElemMap *pmap;
CustomDataLayer *color_layer;
- AttributeDomain color_domain;
+ eAttrDomain color_domain;
bool is_drawing;
/* Used by DynTopo to invalidate the draw cache. */
bool draw_cache_invalid;
+
+ struct PBVHGPUFormat *vbo_id;
};
/* pbvh.c */
diff --git a/source/blender/blenkernel/intern/pbvh_pixels.cc b/source/blender/blenkernel/intern/pbvh_pixels.cc
index 5623cac44ac..49397797c0d 100644
--- a/source/blender/blenkernel/intern/pbvh_pixels.cc
+++ b/source/blender/blenkernel/intern/pbvh_pixels.cc
@@ -71,7 +71,7 @@ static void extract_barycentric_pixels(UDIMTilePixels &tile_data,
int x;
for (x = minx; x < maxx; x++) {
- float2 uv(float(x) / image_buffer->x, float(y) / image_buffer->y);
+ float2 uv((float(x) + 0.5f) / image_buffer->x, (float(y) + 0.5f) / image_buffer->y);
float3 barycentric_weights;
barycentric_weights_v2(uvs[0], uvs[1], uvs[2], uv, barycentric_weights);
@@ -108,7 +108,7 @@ struct EncodePixelsUserData {
ImageUser *image_user;
PBVH *pbvh;
Vector<PBVHNode *> *nodes;
- MLoopUV *ldata_uv;
+ const MLoopUV *ldata_uv;
};
static void do_encode_pixels(void *__restrict userdata,
@@ -283,7 +283,8 @@ static void update_pixels(PBVH *pbvh, Mesh *mesh, Image *image, ImageUser *image
return;
}
- MLoopUV *ldata_uv = static_cast<MLoopUV *>(CustomData_get_layer(&mesh->ldata, CD_MLOOPUV));
+ const MLoopUV *ldata_uv = static_cast<const MLoopUV *>(
+ CustomData_get_layer(&mesh->ldata, CD_MLOOPUV));
if (ldata_uv == nullptr) {
return;
}
@@ -307,6 +308,12 @@ static void update_pixels(PBVH *pbvh, Mesh *mesh, Image *image, ImageUser *image
apply_watertight_check(pbvh, image, image_user);
}
+ /* Rebuild the undo regions. */
+ for (PBVHNode *node : nodes_to_update) {
+ NodeData *node_data = static_cast<NodeData *>(node->pixels.node_data);
+ node_data->rebuild_undo_regions();
+ }
+
/* Clear the UpdatePixels flag. */
for (PBVHNode *node : nodes_to_update) {
node->flag = static_cast<PBVHNodeFlags>(node->flag & ~PBVH_RebuildPixels);
diff --git a/source/blender/blenkernel/intern/pointcache.c b/source/blender/blenkernel/intern/pointcache.c
index 353f89068d8..d7bdfe08ab9 100644
--- a/source/blender/blenkernel/intern/pointcache.c
+++ b/source/blender/blenkernel/intern/pointcache.c
@@ -1450,7 +1450,7 @@ static PTCacheFile *ptcache_file_open(PTCacheID *pid, int mode, int cfra)
{
PTCacheFile *pf;
FILE *fp = NULL;
- char filename[MAX_PTCACHE_FILE];
+ char filepath[MAX_PTCACHE_FILE];
#ifndef DURIAN_POINTCACHE_LIB_OK
/* don't allow writing for linked objects */
@@ -1465,20 +1465,20 @@ static PTCacheFile *ptcache_file_open(PTCacheID *pid, int mode, int cfra)
}
}
- ptcache_filename(pid, filename, cfra, true, true);
+ ptcache_filename(pid, filepath, cfra, true, true);
if (mode == PTCACHE_FILE_READ) {
- fp = BLI_fopen(filename, "rb");
+ fp = BLI_fopen(filepath, "rb");
}
else if (mode == PTCACHE_FILE_WRITE) {
/* Will create the dir if needs be, same as "//textures" is created. */
- BLI_make_existing_file(filename);
+ BLI_make_existing_file(filepath);
- fp = BLI_fopen(filename, "wb");
+ fp = BLI_fopen(filepath, "wb");
}
else if (mode == PTCACHE_FILE_UPDATE) {
- BLI_make_existing_file(filename);
- fp = BLI_fopen(filename, "rb+");
+ BLI_make_existing_file(filepath);
+ fp = BLI_fopen(filepath, "rb+");
}
if (!fp) {
@@ -3232,7 +3232,7 @@ void BKE_ptcache_bake(PTCacheBaker *baker)
scene, pid->calldata, &cache->startframe, &cache->endframe);
}
- /* XXX workaround for regression inroduced in ee3fadd, needs looking into */
+ /* XXX: workaround for regression introduced in ee3fadd, needs looking into. */
if (pid->type == PTCACHE_TYPE_RIGIDBODY) {
if ((cache->flag & PTCACHE_REDO_NEEDED ||
(cache->flag & PTCACHE_SIMULATION_VALID) == 0) &&
diff --git a/source/blender/blenkernel/intern/pointcloud.cc b/source/blender/blenkernel/intern/pointcloud.cc
index 3ee46fc4f15..e38c20d8eb7 100644
--- a/source/blender/blenkernel/intern/pointcloud.cc
+++ b/source/blender/blenkernel/intern/pointcloud.cc
@@ -20,6 +20,7 @@
#include "BLI_string.h"
#include "BLI_task.hh"
#include "BLI_utildefines.h"
+#include "BLI_vector.hh"
#include "BKE_anim_data.h"
#include "BKE_customdata.h"
@@ -44,6 +45,7 @@
using blender::float3;
using blender::IndexRange;
using blender::Span;
+using blender::Vector;
/* PointCloud datablock */
@@ -107,27 +109,25 @@ static void pointcloud_blend_write(BlendWriter *writer, ID *id, const void *id_a
{
PointCloud *pointcloud = (PointCloud *)id;
- CustomDataLayer *players = nullptr, players_buff[CD_TEMP_CHUNK_SIZE];
- CustomData_blend_write_prepare(
- &pointcloud->pdata, &players, players_buff, ARRAY_SIZE(players_buff));
+ Vector<CustomDataLayer, 16> point_layers;
+ CustomData_blend_write_prepare(pointcloud->pdata, point_layers);
/* Write LibData */
BLO_write_id_struct(writer, PointCloud, id_address, &pointcloud->id);
BKE_id_blend_write(writer, &pointcloud->id);
/* Direct data */
- CustomData_blend_write(
- writer, &pointcloud->pdata, players, pointcloud->totpoint, CD_MASK_ALL, &pointcloud->id);
+ CustomData_blend_write(writer,
+ &pointcloud->pdata,
+ point_layers,
+ pointcloud->totpoint,
+ CD_MASK_ALL,
+ &pointcloud->id);
BLO_write_pointer_array(writer, pointcloud->totcol, pointcloud->mat);
if (pointcloud->adt) {
BKE_animdata_blend_write(writer, pointcloud->adt);
}
-
- /* Remove temporary data. */
- if (players && players != players_buff) {
- MEM_freeN(players);
- }
}
static void pointcloud_blend_read_data(BlendDataReader *reader, ID *id)
@@ -315,9 +315,9 @@ void BKE_pointcloud_update_customdata_pointers(PointCloud *pointcloud)
CustomData_get_layer_named(&pointcloud->pdata, CD_PROP_FLOAT, POINTCLOUD_ATTR_RADIUS));
}
-bool BKE_pointcloud_customdata_required(PointCloud *UNUSED(pointcloud), CustomDataLayer *layer)
+bool BKE_pointcloud_customdata_required(const PointCloud *UNUSED(pointcloud), const char *name)
{
- return layer->type == CD_PROP_FLOAT3 && STREQ(layer->name, POINTCLOUD_ATTR_POSITION);
+ return STREQ(name, POINTCLOUD_ATTR_POSITION);
}
/* Dependency Graph */
diff --git a/source/blender/blenkernel/intern/rigidbody.c b/source/blender/blenkernel/intern/rigidbody.c
index 60cc4ce83af..821976f8e0e 100644
--- a/source/blender/blenkernel/intern/rigidbody.c
+++ b/source/blender/blenkernel/intern/rigidbody.c
@@ -1660,8 +1660,7 @@ static void rigidbody_update_sim_world(Scene *scene, RigidBodyWorld *rbw)
rigidbody_update_ob_array(rbw);
}
-static void rigidbody_update_sim_ob(
- Depsgraph *depsgraph, Scene *scene, RigidBodyWorld *rbw, Object *ob, RigidBodyOb *rbo)
+static void rigidbody_update_sim_ob(Depsgraph *depsgraph, Object *ob, RigidBodyOb *rbo)
{
/* only update if rigid body exists */
if (rbo->shared->physics_object == NULL) {
@@ -1712,54 +1711,6 @@ static void rigidbody_update_sim_ob(
RB_body_set_mass(rbo->shared->physics_object, 0.0f);
}
- /* update influence of effectors - but don't do it on an effector */
- /* only dynamic bodies need effector update */
- else if (rbo->type == RBO_TYPE_ACTIVE &&
- ((ob->pd == NULL) || (ob->pd->forcefield == PFIELD_NULL))) {
- EffectorWeights *effector_weights = rbw->effector_weights;
- EffectedPoint epoint;
- ListBase *effectors;
-
- /* get effectors present in the group specified by effector_weights */
- effectors = BKE_effectors_create(depsgraph, ob, NULL, effector_weights, false);
- if (effectors) {
- float eff_force[3] = {0.0f, 0.0f, 0.0f};
- float eff_loc[3], eff_vel[3];
-
- /* create dummy 'point' which represents last known position of object as result of sim */
- /* XXX: this can create some inaccuracies with sim position,
- * but is probably better than using un-simulated values? */
- RB_body_get_position(rbo->shared->physics_object, eff_loc);
- RB_body_get_linear_velocity(rbo->shared->physics_object, eff_vel);
-
- pd_point_from_loc(scene, eff_loc, eff_vel, 0, &epoint);
-
- /* Calculate net force of effectors, and apply to sim object:
- * - we use 'central force' since apply force requires a "relative position"
- * which we don't have... */
- BKE_effectors_apply(effectors, NULL, effector_weights, &epoint, eff_force, NULL, NULL);
- if (G.f & G_DEBUG) {
- printf("\tapplying force (%f,%f,%f) to '%s'\n",
- eff_force[0],
- eff_force[1],
- eff_force[2],
- ob->id.name + 2);
- }
- /* activate object in case it is deactivated */
- if (!is_zero_v3(eff_force)) {
- RB_body_activate(rbo->shared->physics_object);
- }
- RB_body_apply_central_force(rbo->shared->physics_object, eff_force);
- }
- else if (G.f & G_DEBUG) {
- printf("\tno forces to apply to '%s'\n", ob->id.name + 2);
- }
-
- /* cleanup */
- BKE_effectors_free(effectors);
- }
- /* NOTE: passive objects don't need to be updated since they don't move */
-
/* NOTE: no other settings need to be explicitly updated here,
* since RNA setters take care of the rest :)
*/
@@ -1854,7 +1805,7 @@ static void rigidbody_update_simulation(Depsgraph *depsgraph,
rbo->flag &= ~(RBO_FLAG_NEEDS_VALIDATE | RBO_FLAG_NEEDS_RESHAPE);
/* update simulation object... */
- rigidbody_update_sim_ob(depsgraph, scene, rbw, ob, rbo);
+ rigidbody_update_sim_ob(depsgraph, ob, rbo);
}
}
FOREACH_COLLECTION_OBJECT_RECURSIVE_END;
@@ -1986,6 +1937,69 @@ static void rigidbody_update_kinematic_obj_substep(ListBase *substep_targets, fl
}
}
+static void rigidbody_update_external_forces(Depsgraph *depsgraph,
+ Scene *scene,
+ RigidBodyWorld *rbw)
+{
+ FOREACH_COLLECTION_OBJECT_RECURSIVE_BEGIN (rbw->group, ob) {
+ /* only update if rigid body exists */
+ RigidBodyOb *rbo = ob->rigidbody_object;
+ if (ob->type != OB_MESH || rbo->shared->physics_object == NULL) {
+ continue;
+ }
+
+ /* update influence of effectors - but don't do it on an effector */
+ /* only dynamic bodies need effector update */
+ if (rbo->type == RBO_TYPE_ACTIVE &&
+ ((ob->pd == NULL) || (ob->pd->forcefield == PFIELD_NULL))) {
+ EffectorWeights *effector_weights = rbw->effector_weights;
+ EffectedPoint epoint;
+ ListBase *effectors;
+
+ /* get effectors present in the group specified by effector_weights */
+ effectors = BKE_effectors_create(depsgraph, ob, NULL, effector_weights, false);
+ if (effectors) {
+ float eff_force[3] = {0.0f, 0.0f, 0.0f};
+ float eff_loc[3], eff_vel[3];
+
+ /* create dummy 'point' which represents last known position of object as result of sim
+ */
+ /* XXX: this can create some inaccuracies with sim position,
+ * but is probably better than using un-simulated values? */
+ RB_body_get_position(rbo->shared->physics_object, eff_loc);
+ RB_body_get_linear_velocity(rbo->shared->physics_object, eff_vel);
+
+ pd_point_from_loc(scene, eff_loc, eff_vel, 0, &epoint);
+
+ /* Calculate net force of effectors, and apply to sim object:
+ * - we use 'central force' since apply force requires a "relative position"
+ * which we don't have... */
+ BKE_effectors_apply(effectors, NULL, effector_weights, &epoint, eff_force, NULL, NULL);
+ if (G.f & G_DEBUG) {
+ printf("\tapplying force (%f,%f,%f) to '%s'\n",
+ eff_force[0],
+ eff_force[1],
+ eff_force[2],
+ ob->id.name + 2);
+ }
+ /* activate object in case it is deactivated */
+ if (!is_zero_v3(eff_force)) {
+ RB_body_activate(rbo->shared->physics_object);
+ }
+ RB_body_apply_central_force(rbo->shared->physics_object, eff_force);
+ }
+ else if (G.f & G_DEBUG) {
+ printf("\tno forces to apply to '%s'\n", ob->id.name + 2);
+ }
+
+ /* cleanup */
+ BKE_effectors_free(effectors);
+ }
+ /* NOTE: passive objects don't need to be updated since they don't move */
+ }
+ FOREACH_COLLECTION_OBJECT_RECURSIVE_END;
+}
+
static void rigidbody_free_substep_data(ListBase *substep_targets)
{
LISTBASE_FOREACH (LinkData *, link, substep_targets) {
@@ -2220,26 +2234,27 @@ void BKE_rigidbody_do_simulation(Depsgraph *depsgraph, Scene *scene, float ctime
BKE_ptcache_write(&pid, startframe);
}
- /* update and validate simulation */
- rigidbody_update_simulation(depsgraph, scene, rbw, false);
-
const float frame_diff = ctime - rbw->ltime;
/* calculate how much time elapsed since last step in seconds */
const float timestep = 1.0f / (float)FPS * frame_diff * rbw->time_scale;
const float substep = timestep / rbw->substeps_per_frame;
- ListBase substep_targets = rigidbody_create_substep_data(rbw);
+ ListBase kinematic_substep_targets = rigidbody_create_substep_data(rbw);
const float interp_step = 1.0f / rbw->substeps_per_frame;
float cur_interp_val = interp_step;
+ /* update and validate simulation */
+ rigidbody_update_simulation(depsgraph, scene, rbw, false);
+
for (int i = 0; i < rbw->substeps_per_frame; i++) {
- rigidbody_update_kinematic_obj_substep(&substep_targets, cur_interp_val);
+ rigidbody_update_external_forces(depsgraph, scene, rbw);
+ rigidbody_update_kinematic_obj_substep(&kinematic_substep_targets, cur_interp_val);
RB_dworld_step_simulation(rbw->shared->physics_world, substep, 0, substep);
cur_interp_val += interp_step;
}
- rigidbody_free_substep_data(&substep_targets);
+ rigidbody_free_substep_data(&kinematic_substep_targets);
rigidbody_update_simulation_post_step(depsgraph, rbw);
diff --git a/source/blender/blenkernel/intern/sound.c b/source/blender/blenkernel/intern/sound.c
index 864a4f3281b..5bafce15b34 100644
--- a/source/blender/blenkernel/intern/sound.c
+++ b/source/blender/blenkernel/intern/sound.c
@@ -54,6 +54,7 @@
#include "SEQ_sequencer.h"
#include "SEQ_sound.h"
+#include "SEQ_time.h"
static void sound_free_audio(bSound *sound);
@@ -264,6 +265,14 @@ bSound *BKE_sound_new_file(Main *bmain, const char *filepath)
BLI_strncpy(sound->filepath, filepath, FILE_MAX);
/* sound->type = SOUND_TYPE_FILE; */ /* XXX unused currently */
+ /* Extract sound specs for bSound */
+ SoundInfo info;
+ bool success = BKE_sound_info_get(bmain, sound, &info);
+ if (success) {
+ sound->samplerate = info.specs.samplerate;
+ sound->audio_channels = info.specs.channels;
+ }
+
sound->spinlock = MEM_mallocN(sizeof(SpinLock), "sound_spinlock");
BLI_spin_init(sound->spinlock);
@@ -711,8 +720,8 @@ void *BKE_sound_scene_add_scene_sound_defaults(Scene *scene, Sequence *sequence)
{
return BKE_sound_scene_add_scene_sound(scene,
sequence,
- sequence->startdisp,
- sequence->enddisp,
+ SEQ_time_left_handle_frame_get(sequence),
+ SEQ_time_right_handle_frame_get(sequence),
sequence->startofs + sequence->anim_startofs);
}
@@ -737,8 +746,8 @@ void *BKE_sound_add_scene_sound_defaults(Scene *scene, Sequence *sequence)
{
return BKE_sound_add_scene_sound(scene,
sequence,
- sequence->startdisp,
- sequence->enddisp,
+ SEQ_time_left_handle_frame_get(sequence),
+ SEQ_time_right_handle_frame_get(sequence),
sequence->startofs + sequence->anim_startofs);
}
@@ -752,8 +761,12 @@ void BKE_sound_mute_scene_sound(void *handle, char mute)
AUD_SequenceEntry_setMuted(handle, mute);
}
-void BKE_sound_move_scene_sound(
- Scene *scene, void *handle, int startframe, int endframe, int frameskip, double audio_offset)
+void BKE_sound_move_scene_sound(const Scene *scene,
+ void *handle,
+ int startframe,
+ int endframe,
+ int frameskip,
+ double audio_offset)
{
sound_verify_evaluated_id(&scene->id);
const double fps = FPS;
@@ -766,8 +779,8 @@ void BKE_sound_move_scene_sound_defaults(Scene *scene, Sequence *sequence)
if (sequence->scene_sound) {
BKE_sound_move_scene_sound(scene,
sequence->scene_sound,
- sequence->startdisp,
- sequence->enddisp,
+ SEQ_time_left_handle_frame_get(sequence),
+ SEQ_time_right_handle_frame_get(sequence),
sequence->startofs + sequence->anim_startofs,
0.0);
}
@@ -1202,6 +1215,7 @@ static bool sound_info_from_playback_handle(void *playback_handle, SoundInfo *so
AUD_SoundInfo info = AUD_getInfo(playback_handle);
sound_info->specs.channels = (eSoundChannels)info.specs.channels;
sound_info->length = info.length;
+ sound_info->specs.samplerate = info.specs.rate;
return true;
}
@@ -1335,7 +1349,7 @@ void BKE_sound_remove_scene_sound(Scene *UNUSED(scene), void *UNUSED(handle))
void BKE_sound_mute_scene_sound(void *UNUSED(handle), char UNUSED(mute))
{
}
-void BKE_sound_move_scene_sound(Scene *UNUSED(scene),
+void BKE_sound_move_scene_sound(const Scene *UNUSED(scene),
void *UNUSED(handle),
int UNUSED(startframe),
int UNUSED(endframe),
diff --git a/source/blender/blenkernel/intern/spline_base.cc b/source/blender/blenkernel/intern/spline_base.cc
index 7704a74841a..e8c7aff75d1 100644
--- a/source/blender/blenkernel/intern/spline_base.cc
+++ b/source/blender/blenkernel/intern/spline_base.cc
@@ -116,15 +116,15 @@ void Spline::reverse()
this->mark_cache_invalid();
}
-int Spline::evaluated_edges_size() const
+int Spline::evaluated_edges_num() const
{
- const int eval_size = this->evaluated_points_size();
- if (eval_size < 2) {
+ const int eval_num = this->evaluated_points_num();
+ if (eval_num < 2) {
/* Two points are required for an edge. */
return 0;
}
- return this->is_cyclic_ ? eval_size : eval_size - 1;
+ return this->is_cyclic_ ? eval_num : eval_num - 1;
}
float Spline::length() const
@@ -133,11 +133,11 @@ float Spline::length() const
return lengths.is_empty() ? 0.0f : this->evaluated_lengths().last();
}
-int Spline::segments_size() const
+int Spline::segments_num() const
{
- const int size = this->size();
+ const int num = this->size();
- return is_cyclic_ ? size : size - 1;
+ return is_cyclic_ ? num : num - 1;
}
bool Spline::is_cyclic() const
@@ -177,7 +177,7 @@ Span<float> Spline::evaluated_lengths() const
return evaluated_lengths_cache_;
}
- const int total = evaluated_edges_size();
+ const int total = evaluated_edges_num();
evaluated_lengths_cache_.resize(total);
if (total != 0) {
Span<float3> positions = this->evaluated_positions();
@@ -242,8 +242,8 @@ Span<float3> Spline::evaluated_tangents() const
return evaluated_tangents_cache_;
}
- const int eval_size = this->evaluated_points_size();
- evaluated_tangents_cache_.resize(eval_size);
+ const int eval_num = this->evaluated_points_num();
+ evaluated_tangents_cache_.resize(eval_num);
Span<float3> positions = this->evaluated_positions();
@@ -369,8 +369,8 @@ Span<float3> Spline::evaluated_normals() const
return evaluated_normals_cache_;
}
- const int eval_size = this->evaluated_points_size();
- evaluated_normals_cache_.resize(eval_size);
+ const int eval_num = this->evaluated_points_num();
+ evaluated_normals_cache_.resize(eval_num);
Span<float3> tangents = this->evaluated_tangents();
MutableSpan<float3> normals = evaluated_normals_cache_;
@@ -410,7 +410,7 @@ Spline::LookupResult Spline::lookup_evaluated_length(const float length) const
const float *offset = std::lower_bound(lengths.begin(), lengths.end(), length);
const int index = offset - lengths.begin();
- const int next_index = (index == this->evaluated_points_size() - 1) ? 0 : index + 1;
+ const int next_index = (index == this->evaluated_points_num() - 1) ? 0 : index + 1;
const float previous_length = (index == 0) ? 0.0f : lengths[index - 1];
const float length_in_segment = length - previous_length;
@@ -420,30 +420,30 @@ Spline::LookupResult Spline::lookup_evaluated_length(const float length) const
return LookupResult{index, next_index, factor};
}
-Array<float> Spline::sample_uniform_index_factors(const int samples_size) const
+Array<float> Spline::sample_uniform_index_factors(const int samples_num) const
{
const Span<float> lengths = this->evaluated_lengths();
- BLI_assert(samples_size > 0);
- Array<float> samples(samples_size);
+ BLI_assert(samples_num > 0);
+ Array<float> samples(samples_num);
samples[0] = 0.0f;
- if (samples_size == 1) {
+ if (samples_num == 1) {
return samples;
}
const float total_length = this->length();
- const float sample_length = total_length / (samples_size - (is_cyclic_ ? 0 : 1));
+ const float sample_length = total_length / (samples_num - (is_cyclic_ ? 0 : 1));
/* Store the length at the previous evaluated point in a variable so it can
* start out at zero (the lengths array doesn't contain 0 for the first point). */
float prev_length = 0.0f;
int i_sample = 1;
- for (const int i_evaluated : IndexRange(this->evaluated_edges_size())) {
+ for (const int i_evaluated : IndexRange(this->evaluated_edges_num())) {
const float length = lengths[i_evaluated];
/* Add every sample that fits in this evaluated edge. */
- while ((sample_length * i_sample) < length && i_sample < samples_size) {
+ while ((sample_length * i_sample) < length && i_sample < samples_num) {
const float factor = (sample_length * i_sample - prev_length) / (length - prev_length);
samples[i_sample] = i_evaluated + factor;
i_sample++;
@@ -454,8 +454,8 @@ Array<float> Spline::sample_uniform_index_factors(const int samples_size) const
/* Zero lengths or float inaccuracies can cause invalid values, or simply
* skip some, so set the values that weren't completed in the main loop. */
- for (const int i : IndexRange(i_sample, samples_size - i_sample)) {
- samples[i] = float(samples_size);
+ for (const int i : IndexRange(i_sample, samples_num - i_sample)) {
+ samples[i] = float(samples_num);
}
if (!is_cyclic_) {
@@ -468,23 +468,23 @@ Array<float> Spline::sample_uniform_index_factors(const int samples_size) const
Spline::LookupResult Spline::lookup_data_from_index_factor(const float index_factor) const
{
- const int eval_size = this->evaluated_points_size();
+ const int eval_num = this->evaluated_points_num();
if (is_cyclic_) {
- if (index_factor < eval_size) {
+ if (index_factor < eval_num) {
const int index = std::floor(index_factor);
- const int next_index = (index < eval_size - 1) ? index + 1 : 0;
+ const int next_index = (index < eval_num - 1) ? index + 1 : 0;
return LookupResult{index, next_index, index_factor - index};
}
- return LookupResult{eval_size - 1, 0, 1.0f};
+ return LookupResult{eval_num - 1, 0, 1.0f};
}
- if (index_factor < eval_size - 1) {
+ if (index_factor < eval_num - 1) {
const int index = std::floor(index_factor);
const int next_index = index + 1;
return LookupResult{index, next_index, index_factor - index};
}
- return LookupResult{eval_size - 2, eval_size - 1, 1.0f};
+ return LookupResult{eval_num - 2, eval_num - 1, 1.0f};
}
void Spline::bounds_min_max(float3 &min, float3 &max, const bool use_evaluated) const
@@ -504,7 +504,7 @@ void Spline::sample_with_index_factors(const GVArray &src,
Span<float> index_factors,
GMutableSpan dst) const
{
- BLI_assert(src.size() == this->evaluated_points_size());
+ BLI_assert(src.size() == this->evaluated_points_num());
blender::attribute_math::convert_to_static_type(src.type(), [&](auto dummy) {
using T = decltype(dummy);
diff --git a/source/blender/blenkernel/intern/spline_bezier.cc b/source/blender/blenkernel/intern/spline_bezier.cc
index 8e207f93bf5..80515d0ef37 100644
--- a/source/blender/blenkernel/intern/spline_bezier.cc
+++ b/source/blender/blenkernel/intern/spline_bezier.cc
@@ -335,7 +335,7 @@ void BezierSpline::mark_cache_invalid()
auto_handles_dirty_ = true;
}
-int BezierSpline::evaluated_points_size() const
+int BezierSpline::evaluated_points_num() const
{
BLI_assert(this->size() > 0);
return this->control_point_offsets().last();
@@ -502,12 +502,12 @@ Span<float> BezierSpline::evaluated_mappings() const
return evaluated_mapping_cache_;
}
- const int size = this->size();
- const int eval_size = this->evaluated_points_size();
- evaluated_mapping_cache_.resize(eval_size);
+ const int num = this->size();
+ const int eval_num = this->evaluated_points_num();
+ evaluated_mapping_cache_.resize(eval_num);
MutableSpan<float> mappings = evaluated_mapping_cache_;
- if (eval_size == 1) {
+ if (eval_num == 1) {
mappings.first() = 0.0f;
mapping_cache_dirty_ = false;
return mappings;
@@ -517,7 +517,7 @@ Span<float> BezierSpline::evaluated_mappings() const
blender::threading::isolate_task([&]() {
/* Isolate the task, since this is function is multi-threaded and holds a lock. */
- calculate_mappings_linear_resolution(offsets, size, resolution_, is_cyclic_, mappings);
+ calculate_mappings_linear_resolution(offsets, num, resolution_, is_cyclic_, mappings);
});
mapping_cache_dirty_ = false;
@@ -535,15 +535,15 @@ Span<float3> BezierSpline::evaluated_positions() const
return evaluated_position_cache_;
}
- const int size = this->size();
- const int eval_size = this->evaluated_points_size();
- evaluated_position_cache_.resize(eval_size);
+ const int num = this->size();
+ const int eval_num = this->evaluated_points_num();
+ evaluated_position_cache_.resize(eval_num);
MutableSpan<float3> positions = evaluated_position_cache_;
- if (size == 1) {
+ if (num == 1) {
/* Use a special case for single point splines to avoid checking in #evaluate_segment. */
- BLI_assert(eval_size == 1);
+ BLI_assert(eval_num == 1);
positions.first() = positions_.first();
position_cache_dirty_ = false;
return positions;
@@ -556,7 +556,7 @@ Span<float3> BezierSpline::evaluated_positions() const
const int grain_size = std::max(512 / resolution_, 1);
blender::threading::isolate_task([&]() {
/* Isolate the task, since this is function is multi-threaded and holds a lock. */
- blender::threading::parallel_for(IndexRange(size - 1), grain_size, [&](IndexRange range) {
+ blender::threading::parallel_for(IndexRange(num - 1), grain_size, [&](IndexRange range) {
for (const int i : range) {
this->evaluate_segment(i, i + 1, positions.slice(offsets[i], offsets[i + 1] - offsets[i]));
}
@@ -564,7 +564,7 @@ Span<float3> BezierSpline::evaluated_positions() const
});
if (is_cyclic_) {
this->evaluate_segment(
- size - 1, 0, positions.slice(offsets[size - 1], offsets[size] - offsets[size - 1]));
+ num - 1, 0, positions.slice(offsets[num - 1], offsets[num] - offsets[num - 1]));
}
else {
/* Since evaluating the bezier segment doesn't add the final point,
@@ -579,23 +579,23 @@ Span<float3> BezierSpline::evaluated_positions() const
BezierSpline::InterpolationData BezierSpline::interpolation_data_from_index_factor(
const float index_factor) const
{
- const int size = this->size();
+ const int num = this->size();
if (is_cyclic_) {
- if (index_factor < size) {
+ if (index_factor < num) {
const int index = std::floor(index_factor);
- const int next_index = (index < size - 1) ? index + 1 : 0;
+ const int next_index = (index < num - 1) ? index + 1 : 0;
return InterpolationData{index, next_index, index_factor - index};
}
- return InterpolationData{size - 1, 0, 1.0f};
+ return InterpolationData{num - 1, 0, 1.0f};
}
- if (index_factor < size - 1) {
+ if (index_factor < num - 1) {
const int index = std::floor(index_factor);
const int next_index = index + 1;
return InterpolationData{index, next_index, index_factor - index};
}
- return InterpolationData{size - 2, size - 1, 1.0f};
+ return InterpolationData{num - 2, num - 1, 1.0f};
}
/* Use a spline argument to avoid adding this to the header. */
@@ -605,7 +605,7 @@ static void interpolate_to_evaluated_impl(const BezierSpline &spline,
MutableSpan<T> dst)
{
BLI_assert(src.size() == spline.size());
- BLI_assert(dst.size() == spline.evaluated_points_size());
+ BLI_assert(dst.size() == spline.evaluated_points_num());
Span<float> mappings = spline.evaluated_mappings();
for (const int i : dst.index_range()) {
@@ -627,8 +627,8 @@ GVArray BezierSpline::interpolate_to_evaluated(const GVArray &src) const
return src;
}
- const int eval_size = this->evaluated_points_size();
- if (eval_size == 1) {
+ const int eval_num = this->evaluated_points_num();
+ if (eval_num == 1) {
return src;
}
@@ -636,7 +636,7 @@ GVArray BezierSpline::interpolate_to_evaluated(const GVArray &src) const
blender::attribute_math::convert_to_static_type(src.type(), [&](auto dummy) {
using T = decltype(dummy);
if constexpr (!std::is_void_v<blender::attribute_math::DefaultMixer<T>>) {
- Array<T> values(eval_size);
+ Array<T> values(eval_num);
interpolate_to_evaluated_impl<T>(*this, src.typed<T>(), values);
new_varray = VArray<T>::ForContainer(std::move(values));
}
diff --git a/source/blender/blenkernel/intern/spline_nurbs.cc b/source/blender/blenkernel/intern/spline_nurbs.cc
index 9d1d5a53a43..a7eeb82d854 100644
--- a/source/blender/blenkernel/intern/spline_nurbs.cc
+++ b/source/blender/blenkernel/intern/spline_nurbs.cc
@@ -124,19 +124,19 @@ void NURBSpline::mark_cache_invalid()
length_cache_dirty_ = true;
}
-int NURBSpline::evaluated_points_size() const
+int NURBSpline::evaluated_points_num() const
{
- if (!this->check_valid_size_and_order()) {
+ if (!this->check_valid_num_and_order()) {
return 0;
}
- return resolution_ * this->segments_size();
+ return resolution_ * this->segments_num();
}
void NURBSpline::correct_end_tangents() const
{
}
-bool NURBSpline::check_valid_size_and_order() const
+bool NURBSpline::check_valid_num_and_order() const
{
if (this->size() < order_) {
return false;
@@ -152,10 +152,10 @@ bool NURBSpline::check_valid_size_and_order() const
return true;
}
-int NURBSpline::knots_size() const
+int NURBSpline::knots_num() const
{
- const int size = this->size() + order_;
- return is_cyclic_ ? size + order_ - 1 : size;
+ const int num = this->size() + order_;
+ return is_cyclic_ ? num + order_ - 1 : num;
}
void NURBSpline::calculate_knots() const
@@ -173,7 +173,7 @@ void NURBSpline::calculate_knots() const
* Covers both Cyclic and EndPoint cases. */
const int tail = is_cyclic_ ? 2 * order - 1 : (is_end_point ? order : 0);
- knots_.resize(this->knots_size());
+ knots_.resize(this->knots_num());
MutableSpan<float> knots = knots_;
int r = head;
@@ -203,13 +203,13 @@ void NURBSpline::calculate_knots() const
Span<float> NURBSpline::knots() const
{
if (!knots_dirty_) {
- BLI_assert(knots_.size() == this->knots_size());
+ BLI_assert(knots_.size() == this->knots_num());
return knots_;
}
std::lock_guard lock{knots_mutex_};
if (!knots_dirty_) {
- BLI_assert(knots_.size() == this->knots_size());
+ BLI_assert(knots_.size() == this->knots_num());
return knots_;
}
@@ -221,7 +221,7 @@ Span<float> NURBSpline::knots() const
}
static void calculate_basis_for_point(const float parameter,
- const int size,
+ const int num,
const int degree,
const Span<float> knots,
MutableSpan<float> r_weights,
@@ -231,7 +231,7 @@ static void calculate_basis_for_point(const float parameter,
int start = 0;
int end = 0;
- for (const int i : IndexRange(size + degree)) {
+ for (const int i : IndexRange(num + degree)) {
const bool knots_equal = knots[i] == knots[i + 1];
if (knots_equal || parameter < knots[i] || parameter > knots[i + 1]) {
continue;
@@ -248,7 +248,7 @@ static void calculate_basis_for_point(const float parameter,
for (const int i_order : IndexRange(2, degree)) {
if (end + i_order >= knots.size()) {
- end = size + degree - i_order;
+ end = num + degree - i_order;
}
for (const int i : IndexRange(end - start + 1)) {
const int knot_index = start + i;
@@ -284,16 +284,16 @@ const NURBSpline::BasisCache &NURBSpline::calculate_basis_cache() const
return basis_cache_;
}
- const int size = this->size();
- const int eval_size = this->evaluated_points_size();
+ const int num = this->size();
+ const int eval_num = this->evaluated_points_num();
const int order = this->order();
const int degree = order - 1;
- basis_cache_.weights.resize(eval_size * order);
- basis_cache_.start_indices.resize(eval_size);
+ basis_cache_.weights.resize(eval_num * order);
+ basis_cache_.start_indices.resize(eval_num);
- if (eval_size == 0) {
+ if (eval_num == 0) {
return basis_cache_;
}
@@ -303,14 +303,14 @@ const NURBSpline::BasisCache &NURBSpline::calculate_basis_cache() const
const Span<float> control_weights = this->weights();
const Span<float> knots = this->knots();
- const int last_control_point_index = is_cyclic_ ? size + degree : size;
+ const int last_control_point_index = is_cyclic_ ? num + degree : num;
const float start = knots[degree];
const float end = knots[last_control_point_index];
- const float step = (end - start) / this->evaluated_edges_size();
- for (const int i : IndexRange(eval_size)) {
+ const float step = (end - start) / this->evaluated_edges_num();
+ for (const int i : IndexRange(eval_num)) {
/* Clamp parameter due to floating point inaccuracy. */
- const float parameter = std::clamp(start + step * i, knots[0], knots[size + degree]);
+ const float parameter = std::clamp(start + step * i, knots[0], knots[num + degree]);
MutableSpan<float> point_weights = basis_weights.slice(i * order, order);
@@ -318,7 +318,7 @@ const NURBSpline::BasisCache &NURBSpline::calculate_basis_cache() const
parameter, last_control_point_index, degree, knots, point_weights, basis_start_indices[i]);
for (const int j : point_weights.index_range()) {
- const int point_index = (basis_start_indices[i] + j) % size;
+ const int point_index = (basis_start_indices[i] + j) % num;
point_weights[j] *= control_weights[point_index];
}
}
@@ -333,7 +333,7 @@ void interpolate_to_evaluated_impl(const NURBSpline::BasisCache &basis_cache,
const blender::VArray<T> &src,
MutableSpan<T> dst)
{
- const int size = src.size();
+ const int num = src.size();
blender::attribute_math::DefaultMixer<T> mixer(dst);
for (const int i : dst.index_range()) {
@@ -341,7 +341,7 @@ void interpolate_to_evaluated_impl(const NURBSpline::BasisCache &basis_cache,
const int start_index = basis_cache.start_indices[i];
for (const int j : point_weights.index_range()) {
- const int point_index = (start_index + j) % size;
+ const int point_index = (start_index + j) % num;
mixer.mix_in(i, src[point_index], point_weights[j]);
}
}
@@ -363,7 +363,7 @@ GVArray NURBSpline::interpolate_to_evaluated(const GVArray &src) const
blender::attribute_math::convert_to_static_type(src.type(), [&](auto dummy) {
using T = decltype(dummy);
if constexpr (!std::is_void_v<blender::attribute_math::DefaultMixer<T>>) {
- Array<T> values(this->evaluated_points_size());
+ Array<T> values(this->evaluated_points_num());
interpolate_to_evaluated_impl<T>(basis_cache, this->order(), src.typed<T>(), values);
new_varray = VArray<T>::ForContainer(std::move(values));
}
@@ -383,8 +383,8 @@ Span<float3> NURBSpline::evaluated_positions() const
return evaluated_position_cache_;
}
- const int eval_size = this->evaluated_points_size();
- evaluated_position_cache_.resize(eval_size);
+ const int eval_num = this->evaluated_points_num();
+ evaluated_position_cache_.resize(eval_num);
/* TODO: Avoid copying the evaluated data from the temporary array. */
VArray<float3> evaluated = Spline::interpolate_to_evaluated(positions_.as_span());
diff --git a/source/blender/blenkernel/intern/spline_poly.cc b/source/blender/blenkernel/intern/spline_poly.cc
index 122f7f6c059..c3cc268c81c 100644
--- a/source/blender/blenkernel/intern/spline_poly.cc
+++ b/source/blender/blenkernel/intern/spline_poly.cc
@@ -76,7 +76,7 @@ void PolySpline::mark_cache_invalid()
length_cache_dirty_ = true;
}
-int PolySpline::evaluated_points_size() const
+int PolySpline::evaluated_points_num() const
{
return this->size();
}
diff --git a/source/blender/blenkernel/intern/subdiv.c b/source/blender/blenkernel/intern/subdiv.c
index ee1976d5946..9098c010747 100644
--- a/source/blender/blenkernel/intern/subdiv.c
+++ b/source/blender/blenkernel/intern/subdiv.c
@@ -25,7 +25,9 @@
#include "opensubdiv_evaluator_capi.h"
#include "opensubdiv_topology_refiner_capi.h"
-/* =================----====--===== MODULE ==========================------== */
+/* --------------------------------------------------------------------
+ * Module.
+ */
void BKE_subdiv_init()
{
@@ -37,7 +39,9 @@ void BKE_subdiv_exit()
openSubdiv_cleanup();
}
-/* ========================== CONVERSION HELPERS ============================ */
+/* --------------------------------------------------------------------
+ * Conversion helpers.
+ */
eSubdivFVarLinearInterpolation BKE_subdiv_fvar_interpolation_from_uv_smooth(int uv_smooth)
{
@@ -72,7 +76,9 @@ eSubdivVtxBoundaryInterpolation BKE_subdiv_vtx_boundary_interpolation_from_subsu
return SUBDIV_VTX_BOUNDARY_EDGE_ONLY;
}
-/* ================================ SETTINGS ================================ */
+/* --------------------------------------------------------------------
+ * Settings.
+ */
bool BKE_subdiv_settings_equal(const SubdivSettings *settings_a, const SubdivSettings *settings_b)
{
@@ -83,7 +89,9 @@ bool BKE_subdiv_settings_equal(const SubdivSettings *settings_a, const SubdivSet
settings_a->fvar_linear_interpolation == settings_b->fvar_linear_interpolation);
}
-/* ============================== CONSTRUCTION ============================== */
+/* --------------------------------------------------------------------
+ * Construction.
+ */
/* Creation from scratch. */
@@ -194,7 +202,9 @@ void BKE_subdiv_free(Subdiv *subdiv)
MEM_freeN(subdiv);
}
-/* =========================== PTEX FACES AND GRIDS ========================= */
+/* --------------------------------------------------------------------
+ * Topology helpers.
+ */
int *BKE_subdiv_face_ptex_offset_get(Subdiv *subdiv)
{
diff --git a/source/blender/blenkernel/intern/subdiv_ccg_mask.c b/source/blender/blenkernel/intern/subdiv_ccg_mask.c
index 83f76f85a67..1290f1e0834 100644
--- a/source/blender/blenkernel/intern/subdiv_ccg_mask.c
+++ b/source/blender/blenkernel/intern/subdiv_ccg_mask.c
@@ -155,8 +155,7 @@ static void mask_init_functions(SubdivCCGMaskEvaluator *mask_evaluator)
bool BKE_subdiv_ccg_mask_init_from_paint(SubdivCCGMaskEvaluator *mask_evaluator,
const struct Mesh *mesh)
{
- GridPaintMask *grid_paint_mask = CustomData_get_layer(&mesh->ldata, CD_GRID_PAINT_MASK);
- if (grid_paint_mask == NULL) {
+ if (!CustomData_get_layer(&mesh->ldata, CD_GRID_PAINT_MASK)) {
return false;
}
/* Allocate all required memory. */
diff --git a/source/blender/blenkernel/intern/subdiv_ccg_material.c b/source/blender/blenkernel/intern/subdiv_ccg_material.c
index 9fbc99cb4f1..cf49db15b7b 100644
--- a/source/blender/blenkernel/intern/subdiv_ccg_material.c
+++ b/source/blender/blenkernel/intern/subdiv_ccg_material.c
@@ -10,6 +10,7 @@
#include "MEM_guardedalloc.h"
#include "DNA_mesh_types.h"
+#include "DNA_meshdata_types.h"
typedef struct CCGMaterialFromMeshData {
const Mesh *mesh;
diff --git a/source/blender/blenkernel/intern/subdiv_eval.c b/source/blender/blenkernel/intern/subdiv_eval.c
index 9edd9815400..fda833ffd27 100644
--- a/source/blender/blenkernel/intern/subdiv_eval.c
+++ b/source/blender/blenkernel/intern/subdiv_eval.c
@@ -23,7 +23,9 @@
#include "opensubdiv_evaluator_capi.h"
#include "opensubdiv_topology_refiner_capi.h"
-/* ============================ Helper Function ============================ */
+/* --------------------------------------------------------------------
+ * Helper functions.
+ */
static eOpenSubdivEvaluator opensubdiv_evalutor_from_subdiv_evaluator_type(
eSubdivEvaluatorType evaluator_type)
@@ -40,11 +42,14 @@ static eOpenSubdivEvaluator opensubdiv_evalutor_from_subdiv_evaluator_type(
return OPENSUBDIV_EVALUATOR_CPU;
}
-/* ====================== Main Subdivision Evaluation ====================== */
+/* --------------------------------------------------------------------
+ * Main subdivision evaluation.
+ */
bool BKE_subdiv_eval_begin(Subdiv *subdiv,
eSubdivEvaluatorType evaluator_type,
- OpenSubdiv_EvaluatorCache *evaluator_cache)
+ OpenSubdiv_EvaluatorCache *evaluator_cache,
+ const OpenSubdiv_EvaluatorSettings *settings)
{
BKE_subdiv_stats_reset(&subdiv->stats, SUBDIV_STATS_EVALUATOR_CREATE);
if (subdiv->topology_refiner == NULL) {
@@ -66,6 +71,7 @@ bool BKE_subdiv_eval_begin(Subdiv *subdiv,
else {
/* TODO(sergey): Check for topology change. */
}
+ subdiv->evaluator->setSettings(subdiv->evaluator, settings);
BKE_subdiv_eval_init_displacement(subdiv);
return true;
}
@@ -179,13 +185,52 @@ static void set_face_varying_data_from_uv(Subdiv *subdiv,
MEM_freeN(buffer);
}
+static void set_vertex_data_from_orco(Subdiv *subdiv, const Mesh *mesh)
+{
+ const float(*orco)[3] = CustomData_get_layer(&mesh->vdata, CD_ORCO);
+ const float(*cloth_orco)[3] = CustomData_get_layer(&mesh->vdata, CD_CLOTH_ORCO);
+
+ if (orco || cloth_orco) {
+ OpenSubdiv_TopologyRefiner *topology_refiner = subdiv->topology_refiner;
+ OpenSubdiv_Evaluator *evaluator = subdiv->evaluator;
+ const int num_verts = topology_refiner->getNumVertices(topology_refiner);
+
+ if (orco && cloth_orco) {
+ /* Set one by one if have both. */
+ for (int i = 0; i < num_verts; i++) {
+ float data[6];
+ copy_v3_v3(data, orco[i]);
+ copy_v3_v3(data + 3, cloth_orco[i]);
+ evaluator->setVertexData(evaluator, data, i, 1);
+ }
+ }
+ else {
+ /* Faster single call if we have either. */
+ if (orco) {
+ evaluator->setVertexData(evaluator, orco[0], 0, num_verts);
+ }
+ else if (cloth_orco) {
+ evaluator->setVertexData(evaluator, cloth_orco[0], 0, num_verts);
+ }
+ }
+ }
+}
+
+static void get_mesh_evaluator_settings(OpenSubdiv_EvaluatorSettings *settings, const Mesh *mesh)
+{
+ settings->num_vertex_data = (CustomData_has_layer(&mesh->vdata, CD_ORCO) ? 3 : 0) +
+ (CustomData_has_layer(&mesh->vdata, CD_CLOTH_ORCO) ? 3 : 0);
+}
+
bool BKE_subdiv_eval_begin_from_mesh(Subdiv *subdiv,
const Mesh *mesh,
const float (*coarse_vertex_cos)[3],
eSubdivEvaluatorType evaluator_type,
OpenSubdiv_EvaluatorCache *evaluator_cache)
{
- if (!BKE_subdiv_eval_begin(subdiv, evaluator_type, evaluator_cache)) {
+ OpenSubdiv_EvaluatorSettings settings = {0};
+ get_mesh_evaluator_settings(&settings, mesh);
+ if (!BKE_subdiv_eval_begin(subdiv, evaluator_type, evaluator_cache, &settings)) {
return false;
}
return BKE_subdiv_eval_refine_from_mesh(subdiv, mesh, coarse_vertex_cos);
@@ -202,12 +247,14 @@ bool BKE_subdiv_eval_refine_from_mesh(Subdiv *subdiv,
}
/* Set coordinates of base mesh vertices. */
set_coarse_positions(subdiv, mesh, coarse_vertex_cos);
- /* Set face-varyign data to UV maps. */
+ /* Set face-varying data to UV maps. */
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, mesh, mloopuv, layer_index);
}
+ /* Set vertex data to orco. */
+ set_vertex_data_from_orco(subdiv, mesh);
/* Update evaluator to the new coarse geometry. */
BKE_subdiv_stats_begin(&subdiv->stats, SUBDIV_STATS_EVALUATOR_REFINE);
subdiv->evaluator->refine(subdiv->evaluator);
@@ -226,7 +273,9 @@ void BKE_subdiv_eval_init_displacement(Subdiv *subdiv)
subdiv->displacement_evaluator->initialize(subdiv->displacement_evaluator);
}
-/* ========================== Single point queries ========================== */
+/* --------------------------------------------------------------------
+ * Single point queries.
+ */
void BKE_subdiv_eval_limit_point(
Subdiv *subdiv, const int ptex_face_index, const float u, const float v, float r_P[3])
@@ -281,6 +330,12 @@ void BKE_subdiv_eval_limit_point_and_normal(Subdiv *subdiv,
normalize_v3(r_N);
}
+void BKE_subdiv_eval_vertex_data(
+ Subdiv *subdiv, const int ptex_face_index, const float u, const float v, float r_vertex_data[])
+{
+ subdiv->evaluator->evaluateVertexData(subdiv->evaluator, ptex_face_index, u, v, r_vertex_data);
+}
+
void BKE_subdiv_eval_face_varying(Subdiv *subdiv,
const int face_varying_channel,
const int ptex_face_index,
diff --git a/source/blender/blenkernel/intern/subdiv_mesh.c b/source/blender/blenkernel/intern/subdiv_mesh.c
index 83427adcb43..433bad34479 100644
--- a/source/blender/blenkernel/intern/subdiv_mesh.c
+++ b/source/blender/blenkernel/intern/subdiv_mesh.c
@@ -5,9 +5,6 @@
* \ingroup bke
*/
-#include "BKE_mesh.h"
-#include "BKE_subdiv_mesh.h"
-
#include "atomic_ops.h"
#include "DNA_key_types.h"
@@ -24,6 +21,7 @@
#include "BKE_subdiv.h"
#include "BKE_subdiv_eval.h"
#include "BKE_subdiv_foreach.h"
+#include "BKE_subdiv_mesh.h"
#include "MEM_guardedalloc.h"
@@ -44,6 +42,9 @@ typedef struct SubdivMeshContext {
/* UV layers interpolation. */
int num_uv_layers;
MLoopUV *uv_layers[MAX_MTFACE];
+ /* Original coordinates (ORCO) interpolation. */
+ float (*orco)[3];
+ float (*cloth_orco)[3];
/* Per-subdivided vertex counter of averaged values. */
int *accumulated_counters;
bool have_displacement;
@@ -69,6 +70,9 @@ static void subdiv_mesh_ctx_cache_custom_data_layers(SubdivMeshContext *ctx)
ctx->poly_origindex = CustomData_get_layer(&subdiv_mesh->pdata, CD_ORIGINDEX);
/* UV layers interpolation. */
subdiv_mesh_ctx_cache_uv_layers(ctx);
+ /* Orco interpolation. */
+ ctx->orco = CustomData_get_layer(&subdiv_mesh->vdata, CD_ORCO);
+ ctx->cloth_orco = CustomData_get_layer(&subdiv_mesh->vdata, CD_CLOTH_ORCO);
}
static void subdiv_mesh_prepare_accumulator(SubdivMeshContext *ctx, int num_vertices)
@@ -417,6 +421,34 @@ static void subdiv_mesh_tls_free(void *tls_v)
/** \} */
/* -------------------------------------------------------------------- */
+/** \name Evaluation helper functions
+ * \{ */
+
+static void subdiv_vertex_orco_evaluate(const SubdivMeshContext *ctx,
+ const int ptex_face_index,
+ const float u,
+ const float v,
+ const int subdiv_vertex_index)
+{
+ if (ctx->orco || ctx->cloth_orco) {
+ float vertex_data[6];
+ BKE_subdiv_eval_vertex_data(ctx->subdiv, ptex_face_index, u, v, vertex_data);
+
+ if (ctx->orco) {
+ copy_v3_v3(ctx->orco[subdiv_vertex_index], vertex_data);
+ if (ctx->cloth_orco) {
+ copy_v3_v3(ctx->orco[subdiv_vertex_index], vertex_data + 3);
+ }
+ }
+ else if (ctx->cloth_orco) {
+ copy_v3_v3(ctx->orco[subdiv_vertex_index], vertex_data);
+ }
+ }
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
/** \name Accumulation helpers
* \{ */
@@ -530,6 +562,8 @@ 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);
+ /* Evaluate undeformed texture coordinate. */
+ subdiv_vertex_orco_evaluate(ctx, ptex_face_index, u, v, subdiv_vertex_index);
/* Remove facedot flag. This can happen if there is more than one subsurf modifier. */
BLI_BITMAP_DISABLE(ctx->subdiv_mesh->runtime.subsurf_face_dot_tags, subdiv_vertex_index);
}
@@ -556,6 +590,8 @@ 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);
+ /* Evaluate undeformed texture coordinate. */
+ subdiv_vertex_orco_evaluate(ctx, ptex_face_index, u, v, subdiv_vertex_index);
}
static void subdiv_mesh_vertex_displacement_every_corner_or_edge(
@@ -723,6 +759,7 @@ static void subdiv_mesh_vertex_inner(const SubdivForeachContext *foreach_context
subdiv_vertex_data_interpolate(ctx, subdiv_vert, &tls->vertex_interpolation, u, v);
BKE_subdiv_eval_final_point(subdiv, ptex_face_index, u, v, subdiv_vert->co);
subdiv_mesh_tag_center_vertex(coarse_poly, subdiv_vertex_index, u, v, subdiv_mesh);
+ subdiv_vertex_orco_evaluate(ctx, ptex_face_index, u, v, subdiv_vertex_index);
}
/** \} */
diff --git a/source/blender/blenkernel/intern/subdiv_modifier.c b/source/blender/blenkernel/intern/subdiv_modifier.c
index 83772f153d9..f5423dccc0f 100644
--- a/source/blender/blenkernel/intern/subdiv_modifier.c
+++ b/source/blender/blenkernel/intern/subdiv_modifier.c
@@ -19,22 +19,40 @@
#include "opensubdiv_capi.h"
-void BKE_subsurf_modifier_subdiv_settings_init(SubdivSettings *settings,
- const SubsurfModifierData *smd,
- const bool use_render_params)
+bool BKE_subsurf_modifier_runtime_init(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(
+ SubdivSettings settings;
+ 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(
+ settings.fvar_linear_interpolation = BKE_subdiv_fvar_interpolation_from_uv_smooth(
smd->uv_smooth);
+
+ SubsurfRuntimeData *runtime_data = (SubsurfRuntimeData *)smd->modifier.runtime;
+ if (settings.level == 0) {
+ /* Modifier is effectively disabled, but still update settings if runtime data
+ * was already allocated. */
+ if (runtime_data) {
+ runtime_data->settings = settings;
+ }
+
+ return false;
+ }
+ else {
+ /* Allocate runtime data if it did not exist yet. */
+ if (runtime_data == NULL) {
+ runtime_data = MEM_callocN(sizeof(*runtime_data), "subsurf runtime");
+ smd->modifier.runtime = runtime_data;
+ }
+ runtime_data->settings = settings;
+ return true;
+ }
}
static ModifierData *modifier_get_last_enabled_for_mode(const Scene *scene,
@@ -77,7 +95,7 @@ static bool is_subdivision_evaluation_possible_on_gpu(void)
return false;
}
- if (GPU_max_shader_storage_buffer_bindings() < MAX_GPU_SUBDIV_SSBOS) {
+ if (GPU_max_compute_shader_storage_blocks() < MAX_GPU_SUBDIV_SSBOS) {
return false;
}
@@ -105,12 +123,11 @@ bool BKE_subsurf_modifier_force_disable_gpu_evaluation_for_mesh(const SubsurfMod
return subsurf_modifier_use_autosmooth_or_split_normals(smd, mesh);
}
-bool BKE_subsurf_modifier_can_do_gpu_subdiv_ex(const Scene *scene,
- const Object *ob,
- const Mesh *mesh,
- const SubsurfModifierData *smd,
- int required_mode,
- bool skip_check_is_last)
+bool BKE_subsurf_modifier_can_do_gpu_subdiv(const Scene *scene,
+ const Object *ob,
+ const Mesh *mesh,
+ const SubsurfModifierData *smd,
+ int required_mode)
{
if ((U.gpu_flag & USER_GPU_FLAG_SUBDIVISION_EVALUATION) == 0) {
return false;
@@ -122,63 +139,37 @@ bool BKE_subsurf_modifier_can_do_gpu_subdiv_ex(const Scene *scene,
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;
- }
+ ModifierData *md = modifier_get_last_enabled_for_mode(scene, ob, required_mode);
+ if (md != (const ModifierData *)smd) {
+ return false;
}
return is_subdivision_evaluation_possible_on_gpu();
}
-bool BKE_subsurf_modifier_can_do_gpu_subdiv(const Scene *scene,
- const Object *ob,
- const Mesh *mesh,
- int required_mode)
+bool BKE_subsurf_modifier_has_gpu_subdiv(const Mesh *mesh)
{
- 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, mesh, (SubsurfModifierData *)md, required_mode, true);
+ SubsurfRuntimeData *runtime_data = mesh->runtime.subsurf_runtime_data;
+ return runtime_data && runtime_data->has_gpu_subdiv;
}
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,
+Subdiv *BKE_subsurf_modifier_subdiv_descriptor_ensure(SubsurfRuntimeData *runtime_data,
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);
+ Subdiv *subdiv = BKE_subdiv_update_from_mesh(
+ runtime_data->subdiv, &runtime_data->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) {
diff --git a/source/blender/blenkernel/intern/subsurf_ccg.c b/source/blender/blenkernel/intern/subsurf_ccg.c
index 5e7a0fc116b..efabb4f039a 100644
--- a/source/blender/blenkernel/intern/subsurf_ccg.c
+++ b/source/blender/blenkernel/intern/subsurf_ccg.c
@@ -259,7 +259,10 @@ static void get_face_uv_map_vert(
}
}
-static int ss_sync_from_uv(CCGSubSurf *ss, CCGSubSurf *origss, DerivedMesh *dm, MLoopUV *mloopuv)
+static int ss_sync_from_uv(CCGSubSurf *ss,
+ CCGSubSurf *origss,
+ DerivedMesh *dm,
+ const MLoopUV *mloopuv)
{
MPoly *mpoly = dm->getPolyArray(dm);
MLoop *mloop = dm->getLoopArray(dm);
@@ -381,13 +384,9 @@ static int ss_sync_from_uv(CCGSubSurf *ss, CCGSubSurf *origss, DerivedMesh *dm,
static void set_subsurf_legacy_uv(CCGSubSurf *ss, DerivedMesh *dm, DerivedMesh *result, int n)
{
- CCGSubSurf *uvss;
- CCGFace **faceMap;
- MTFace *tf;
- MLoopUV *mluv;
CCGFaceIterator fi;
int index, gridSize, gridFaces, /*edgeSize,*/ totface, x, y, S;
- MLoopUV *dmloopuv = CustomData_get_layer_n(&dm->loopData, CD_MLOOPUV, n);
+ const MLoopUV *dmloopuv = CustomData_get_layer_n(&dm->loopData, CD_MLOOPUV, n);
/* need to update both CD_MTFACE & CD_MLOOPUV, hrmf, we could get away with
* just tface except applying the modifier then looses subsurf UV */
MTFace *tface = CustomData_get_layer_n(&result->faceData, CD_MTFACE, n);
@@ -398,7 +397,7 @@ static void set_subsurf_legacy_uv(CCGSubSurf *ss, DerivedMesh *dm, DerivedMesh *
}
/* create a CCGSubSurf from uv's */
- uvss = _getSubSurf(NULL, ccgSubSurf_getSubdivisionLevels(ss), 2, CCG_USE_ARENA);
+ CCGSubSurf *uvss = _getSubSurf(NULL, ccgSubSurf_getSubdivisionLevels(ss), 2, CCG_USE_ARENA);
if (!ss_sync_from_uv(uvss, ss, dm, dmloopuv)) {
ccgSubSurf_free(uvss);
@@ -412,7 +411,7 @@ static void set_subsurf_legacy_uv(CCGSubSurf *ss, DerivedMesh *dm, DerivedMesh *
gridFaces = gridSize - 1;
/* make a map from original faces to CCGFaces */
- faceMap = MEM_mallocN(totface * sizeof(*faceMap), "facemapuv");
+ CCGFace **faceMap = MEM_mallocN(totface * sizeof(*faceMap), "facemapuv");
for (ccgSubSurf_initFaceIterator(uvss, &fi); !ccgFaceIterator_isStopped(&fi);
ccgFaceIterator_next(&fi)) {
CCGFace *f = ccgFaceIterator_getCurrent(&fi);
@@ -420,8 +419,8 @@ static void set_subsurf_legacy_uv(CCGSubSurf *ss, DerivedMesh *dm, DerivedMesh *
}
/* load coordinates from uvss into tface */
- tf = tface;
- mluv = mloopuv;
+ MTFace *tf = tface;
+ MLoopUV *mluv = mloopuv;
for (index = 0; index < totface; index++) {
CCGFace *f = faceMap[index];
@@ -568,11 +567,8 @@ static void ss_sync_ccg_from_derivedmesh(CCGSubSurf *ss,
MEdge *me;
MLoop *mloop = dm->getLoopArray(dm), *ml;
MPoly *mpoly = dm->getPolyArray(dm), *mp;
- // MFace *mf; /* UNUSED */
int totvert = dm->getNumVerts(dm);
int totedge = dm->getNumEdges(dm);
- // int totface = dm->getNumTessFaces(dm); /* UNUSED */
- // int totpoly = dm->getNumFaces(dm); /* UNUSED */
int i, j;
int *index;
@@ -773,11 +769,6 @@ static int ccgDM_getNumPolys(DerivedMesh *dm)
return ccgSubSurf_getNumFinalFaces(ccgdm->ss);
}
-static int ccgDM_getNumTessFaces(DerivedMesh *dm)
-{
- return dm->numTessFaceData;
-}
-
static int ccgDM_getNumLoops(DerivedMesh *dm)
{
CCGDerivedMesh *ccgdm = (CCGDerivedMesh *)dm;
@@ -883,86 +874,6 @@ static void ccgDM_getFinalVertNo(DerivedMesh *dm, int vertNum, float r_no[3])
copy_v3_v3(r_no, CCG_elem_no(&key, vd));
}
-void subsurf_copy_grid_hidden(DerivedMesh *dm,
- const MPoly *mpoly,
- MVert *mvert,
- const MDisps *mdisps)
-{
- CCGDerivedMesh *ccgdm = (CCGDerivedMesh *)dm;
- CCGSubSurf *ss = ccgdm->ss;
- int level = ccgSubSurf_getSubdivisionLevels(ss);
- int gridSize = ccgSubSurf_getGridSize(ss);
- int edgeSize = ccgSubSurf_getEdgeSize(ss);
- int totface = ccgSubSurf_getNumFaces(ss);
- int i, j, x, y;
-
- for (i = 0; i < totface; i++) {
- CCGFace *f = ccgdm->faceMap[i].face;
-
- for (j = 0; j < mpoly[i].totloop; j++) {
- const MDisps *md = &mdisps[mpoly[i].loopstart + j];
- int hidden_gridsize = BKE_ccg_gridsize(md->level);
- int factor = BKE_ccg_factor(level, md->level);
- BLI_bitmap *hidden = md->hidden;
-
- if (!hidden) {
- continue;
- }
-
- for (y = 0; y < gridSize; y++) {
- for (x = 0; x < gridSize; x++) {
- int vndx, offset;
-
- vndx = getFaceIndex(ss, f, j, x, y, edgeSize, gridSize);
- offset = (y * factor) * hidden_gridsize + (x * factor);
- if (BLI_BITMAP_TEST(hidden, offset)) {
- mvert[vndx].flag |= ME_HIDE;
- }
- }
- }
- }
- }
-}
-
-void subsurf_copy_grid_paint_mask(DerivedMesh *dm,
- const MPoly *mpoly,
- float *paint_mask,
- const GridPaintMask *grid_paint_mask)
-{
- CCGDerivedMesh *ccgdm = (CCGDerivedMesh *)dm;
- CCGSubSurf *ss = ccgdm->ss;
- int level = ccgSubSurf_getSubdivisionLevels(ss);
- int gridSize = ccgSubSurf_getGridSize(ss);
- int edgeSize = ccgSubSurf_getEdgeSize(ss);
- int totface = ccgSubSurf_getNumFaces(ss);
- int i, j, x, y, factor, gpm_gridsize;
-
- for (i = 0; i < totface; i++) {
- CCGFace *f = ccgdm->faceMap[i].face;
- const MPoly *p = &mpoly[i];
-
- for (j = 0; j < p->totloop; j++) {
- const GridPaintMask *gpm = &grid_paint_mask[p->loopstart + j];
- if (!gpm->data) {
- continue;
- }
-
- factor = BKE_ccg_factor(level, gpm->level);
- gpm_gridsize = BKE_ccg_gridsize(gpm->level);
-
- for (y = 0; y < gridSize; y++) {
- for (x = 0; x < gridSize; x++) {
- int vndx, offset;
-
- vndx = getFaceIndex(ss, f, j, x, y, edgeSize, gridSize);
- offset = y * factor * gpm_gridsize + x * factor;
- paint_mask[vndx] = gpm->data[offset];
- }
- }
- }
- }
-}
-
/* utility function */
BLI_INLINE void ccgDM_to_MVert(MVert *mv, const CCGKey *key, CCGElem *elem)
{
@@ -1015,11 +926,9 @@ static void ccgDM_copyFinalVertArray(DerivedMesh *dm, MVert *mvert)
int x;
for (x = 1; x < edgeSize - 1; x++) {
- /* This gives errors with -debug-fpe
- * the normals don't seem to be unit length.
- * this is most likely caused by edges with no
- * faces which are now zerod out, see comment in:
- * ccgSubSurf__calcVertNormals(), - campbell */
+ /* NOTE(@campbellbarton): This gives errors with `--debug-fpe` the normals don't seem to be
+ * unit length. This is most likely caused by edges with no faces which are now zeroed out,
+ * see comment in: `ccgSubSurf__calcVertNormals()`. */
vd = ccgSubSurf_getEdgeData(ss, e, x);
ccgDM_to_MVert(&mvert[i++], &key, vd);
}
@@ -1336,8 +1245,9 @@ static void *ccgDM_get_vert_data_layer(DerivedMesh *dm, int type)
}
BLI_rw_mutex_lock(&ccgdm->origindex_cache_rwlock, THREAD_LOCK_WRITE);
- DM_add_vert_layer(dm, CD_ORIGINDEX, CD_CALLOC, NULL);
- origindex = DM_get_vert_data_layer(dm, CD_ORIGINDEX);
+
+ origindex = CustomData_add_layer(
+ &dm->vertData, CD_ORIGINDEX, CD_CALLOC, NULL, dm->numVertData);
totorig = ccgSubSurf_getNumVerts(ss);
totnone = dm->numVertData - totorig;
@@ -1375,8 +1285,8 @@ static void *ccgDM_get_edge_data_layer(DerivedMesh *dm, int type)
return origindex;
}
- DM_add_edge_layer(dm, CD_ORIGINDEX, CD_CALLOC, NULL);
- origindex = DM_get_edge_data_layer(dm, CD_ORIGINDEX);
+ origindex = CustomData_add_layer(
+ &dm->edgeData, CD_ORIGINDEX, CD_CALLOC, NULL, dm->numEdgeData);
totedge = ccgSubSurf_getNumEdges(ss);
totorig = totedge * (edgeSize - 1);
@@ -1418,8 +1328,8 @@ static void *ccgDM_get_poly_data_layer(DerivedMesh *dm, int type)
return origindex;
}
- DM_add_poly_layer(dm, CD_ORIGINDEX, CD_CALLOC, NULL);
- origindex = DM_get_poly_data_layer(dm, CD_ORIGINDEX);
+ origindex = CustomData_add_layer(
+ &dm->polyData, CD_ORIGINDEX, CD_CALLOC, NULL, dm->numPolyData);
totface = ccgSubSurf_getNumFaces(ss);
@@ -1592,10 +1502,7 @@ static void set_default_ccgdm_callbacks(CCGDerivedMesh *ccgdm)
ccgdm->dm.getNumVerts = ccgDM_getNumVerts;
ccgdm->dm.getNumEdges = ccgDM_getNumEdges;
ccgdm->dm.getNumLoops = ccgDM_getNumLoops;
- /* reuse of ccgDM_getNumTessFaces is intentional here:
- * subsurf polys are just created from tessfaces */
ccgdm->dm.getNumPolys = ccgDM_getNumPolys;
- ccgdm->dm.getNumTessFaces = ccgDM_getNumTessFaces;
ccgdm->dm.getVertCo = ccgDM_getFinalVertCo;
ccgdm->dm.getVertNo = ccgDM_getFinalVertNo;
@@ -1670,7 +1577,6 @@ static void set_ccgdm_all_geometry(CCGDerivedMesh *ccgdm,
int index;
int i;
int vertNum = 0, edgeNum = 0, faceNum = 0;
- int *vertOrigIndex, *polyOrigIndex, *base_polyOrigIndex, *edgeOrigIndex;
short *edgeFlags = ccgdm->edgeFlags;
DMFlagMat *faceFlags = ccgdm->faceFlags;
int *polyidx = NULL;
@@ -1687,7 +1593,6 @@ static void set_ccgdm_all_geometry(CCGDerivedMesh *ccgdm,
int gridInternalEdges;
WeightTable wtable = {NULL};
MEdge *medge = NULL;
- MPoly *mpoly = NULL;
bool has_edge_cd;
edgeSize = ccgSubSurf_getEdgeSize(ss);
@@ -1700,13 +1605,13 @@ static void set_ccgdm_all_geometry(CCGDerivedMesh *ccgdm,
medge = dm->getEdgeArray(dm);
- mpoly = CustomData_get_layer(&dm->polyData, CD_MPOLY);
- base_polyOrigIndex = CustomData_get_layer(&dm->polyData, CD_ORIGINDEX);
+ const MPoly *mpoly = CustomData_get_layer(&dm->polyData, CD_MPOLY);
+ const int *base_polyOrigIndex = CustomData_get_layer(&dm->polyData, CD_ORIGINDEX);
- vertOrigIndex = DM_get_vert_data_layer(&ccgdm->dm, CD_ORIGINDEX);
- edgeOrigIndex = DM_get_edge_data_layer(&ccgdm->dm, CD_ORIGINDEX);
+ int *vertOrigIndex = DM_get_vert_data_layer(&ccgdm->dm, CD_ORIGINDEX);
+ int *edgeOrigIndex = DM_get_edge_data_layer(&ccgdm->dm, CD_ORIGINDEX);
- polyOrigIndex = DM_get_poly_data_layer(&ccgdm->dm, CD_ORIGINDEX);
+ int *polyOrigIndex = DM_get_poly_data_layer(&ccgdm->dm, CD_ORIGINDEX);
has_edge_cd = ((ccgdm->dm.edgeData.totlayer - (edgeOrigIndex ? 1 : 0)) != 0);
@@ -2160,13 +2065,3 @@ void subsurf_calculate_limit_positions(Mesh *me, float (*r_positions)[3])
dm->release(dm);
}
-
-bool subsurf_has_edges(DerivedMesh *dm)
-{
- return dm->getNumEdges(dm) != 0;
-}
-
-bool subsurf_has_faces(DerivedMesh *dm)
-{
- return dm->getNumPolys(dm) != 0;
-}
diff --git a/source/blender/blenkernel/intern/text.c b/source/blender/blenkernel/intern/text.c
index ec6387c9cf6..9acf387b930 100644
--- a/source/blender/blenkernel/intern/text.c
+++ b/source/blender/blenkernel/intern/text.c
@@ -1425,11 +1425,15 @@ void txt_from_buf_for_undo(Text *text, const char *buf, size_t buf_len)
char *txt_to_buf(Text *text, size_t *r_buf_strlen)
{
+ const bool has_data = !BLI_listbase_is_empty(&text->lines);
/* Identical to #txt_to_buf_for_undo except that the string is nil terminated. */
size_t buf_len = 0;
LISTBASE_FOREACH (const TextLine *, l, &text->lines) {
buf_len += l->len + 1;
}
+ if (has_data) {
+ buf_len -= 1;
+ }
char *buf = MEM_mallocN(buf_len + 1, __func__);
char *buf_step = buf;
LISTBASE_FOREACH (const TextLine *, l, &text->lines) {
@@ -1437,6 +1441,11 @@ char *txt_to_buf(Text *text, size_t *r_buf_strlen)
buf_step += l->len;
*buf_step++ = '\n';
}
+ /* Remove the trailing new-line so a round-trip doesn't add a newline:
+ * Python for e.g. `text.from_string(text.as_string())`. */
+ if (has_data) {
+ buf_step--;
+ }
*buf_step = '\0';
*r_buf_strlen = buf_len;
return buf;
diff --git a/source/blender/blenkernel/intern/tracking.c b/source/blender/blenkernel/intern/tracking.c
index 348d6a91eb8..8b462cba7ed 100644
--- a/source/blender/blenkernel/intern/tracking.c
+++ b/source/blender/blenkernel/intern/tracking.c
@@ -60,7 +60,9 @@ static struct {
ListBase tracks;
} tracking_clipboard;
-/*********************** Common functions *************************/
+/* --------------------------------------------------------------------
+ * Common functions.
+ */
/* Free the whole list of tracks, list's head and tail are set to NULL. */
static void tracking_tracks_free(ListBase *tracks)
@@ -334,7 +336,11 @@ void BKE_tracking_settings_init(MovieTracking *tracking)
tracking->stabilization.filter = TRACKING_FILTER_BILINEAR;
tracking->stabilization.flag |= TRACKING_SHOW_STAB_TRACKS;
- BKE_tracking_object_add(tracking, "Camera");
+ /* Descending order of average error: tracks with the highest error are on top. */
+ tracking->dopesheet.sort_method = TRACKING_DOPE_SORT_AVERAGE_ERROR;
+ tracking->dopesheet.flag |= TRACKING_DOPE_SORT_INVERSE;
+
+ BKE_tracking_object_add(tracking, DATA_("Camera"));
}
ListBase *BKE_tracking_get_active_tracks(MovieTracking *tracking)
@@ -435,7 +441,9 @@ void BKE_tracking_get_projection_matrix(MovieTracking *tracking,
}
}
-/*********************** clipboard *************************/
+/* --------------------------------------------------------------------
+ * Clipboard.
+ */
void BKE_tracking_clipboard_free(void)
{
@@ -496,7 +504,9 @@ void BKE_tracking_clipboard_paste_tracks(MovieTracking *tracking, MovieTrackingO
}
}
-/*********************** Tracks *************************/
+/* --------------------------------------------------------------------
+ * Tracks.
+ */
MovieTrackingTrack *BKE_tracking_track_add_empty(MovieTracking *tracking, ListBase *tracks_list)
{
@@ -721,67 +731,76 @@ bool BKE_tracking_track_has_enabled_marker_at_frame(MovieTrackingTrack *track, i
return marker && (marker->flag & MARKER_DISABLED) == 0;
}
-void BKE_tracking_track_path_clear(MovieTrackingTrack *track, int ref_frame, int action)
+static void path_clear_remained(MovieTrackingTrack *track, const int ref_frame)
{
- int a;
+ for (int a = 1; a < track->markersnr; a++) {
+ if (track->markers[a].framenr > ref_frame) {
+ track->markersnr = a;
+ track->markers = MEM_reallocN(track->markers,
+ sizeof(MovieTrackingMarker) * track->markersnr);
- if (action == TRACK_CLEAR_REMAINED) {
- a = 1;
-
- while (a < track->markersnr) {
- if (track->markers[a].framenr > ref_frame) {
- track->markersnr = a;
- track->markers = MEM_reallocN(track->markers,
- sizeof(MovieTrackingMarker) * track->markersnr);
-
- break;
- }
-
- a++;
- }
-
- if (track->markersnr) {
- tracking_marker_insert_disabled(track, &track->markers[track->markersnr - 1], false, true);
+ break;
}
}
- else if (action == TRACK_CLEAR_UPTO) {
- a = track->markersnr - 1;
- while (a >= 0) {
- if (track->markers[a].framenr <= ref_frame) {
- memmove(track->markers,
- track->markers + a,
- (track->markersnr - a) * sizeof(MovieTrackingMarker));
+ if (track->markersnr) {
+ tracking_marker_insert_disabled(track, &track->markers[track->markersnr - 1], false, true);
+ }
+}
- track->markersnr = track->markersnr - a;
- track->markers = MEM_reallocN(track->markers,
- sizeof(MovieTrackingMarker) * track->markersnr);
+static void path_clear_up_to(MovieTrackingTrack *track, const int ref_frame)
+{
+ for (int a = track->markersnr - 1; a >= 0; a--) {
+ if (track->markers[a].framenr <= ref_frame) {
+ memmove(track->markers,
+ track->markers + a,
+ (track->markersnr - a) * sizeof(MovieTrackingMarker));
- break;
- }
+ track->markersnr = track->markersnr - a;
+ track->markers = MEM_reallocN(track->markers,
+ sizeof(MovieTrackingMarker) * track->markersnr);
- a--;
+ break;
}
+ }
- if (track->markersnr) {
- tracking_marker_insert_disabled(track, &track->markers[0], true, true);
- }
+ if (track->markersnr) {
+ tracking_marker_insert_disabled(track, &track->markers[0], true, true);
}
- else if (action == TRACK_CLEAR_ALL) {
- MovieTrackingMarker *marker, marker_new;
+}
- marker = BKE_tracking_marker_get(track, ref_frame);
- marker_new = *marker;
+static void path_clear_all(MovieTrackingTrack *track, const int ref_frame)
+{
+ MovieTrackingMarker *marker, marker_new;
- MEM_freeN(track->markers);
- track->markers = NULL;
- track->markersnr = 0;
+ marker = BKE_tracking_marker_get(track, ref_frame);
+ marker_new = *marker;
- BKE_tracking_marker_insert(track, &marker_new);
+ MEM_freeN(track->markers);
+ track->markers = NULL;
+ track->markersnr = 0;
- tracking_marker_insert_disabled(track, &marker_new, true, true);
- tracking_marker_insert_disabled(track, &marker_new, false, true);
- }
+ BKE_tracking_marker_insert(track, &marker_new);
+
+ tracking_marker_insert_disabled(track, &marker_new, true, true);
+ tracking_marker_insert_disabled(track, &marker_new, false, true);
+}
+
+void BKE_tracking_track_path_clear(MovieTrackingTrack *track,
+ const int ref_frame,
+ const eTrackClearAction action)
+{
+ switch (action) {
+ case TRACK_CLEAR_REMAINED:
+ path_clear_remained(track, ref_frame);
+ break;
+ case TRACK_CLEAR_UPTO:
+ path_clear_up_to(track, ref_frame);
+ break;
+ case TRACK_CLEAR_ALL:
+ path_clear_all(track, ref_frame);
+ break;
+ };
}
void BKE_tracking_tracks_join(MovieTracking *tracking,
@@ -1276,7 +1295,9 @@ void BKE_tracking_tracks_deselect_all(ListBase *tracksbase)
}
}
-/*********************** Marker *************************/
+/* --------------------------------------------------------------------
+ * Marker.
+ */
MovieTrackingMarker *BKE_tracking_marker_insert(MovieTrackingTrack *track,
MovieTrackingMarker *marker)
@@ -1350,60 +1371,52 @@ void BKE_tracking_marker_delete(MovieTrackingTrack *track, int framenr)
}
}
-void BKE_tracking_marker_clamp(MovieTrackingMarker *marker, int event)
+void BKE_tracking_marker_clamp_pattern_position(MovieTrackingMarker *marker)
{
float pat_min[2], pat_max[2];
-
BKE_tracking_marker_pattern_minmax(marker, pat_min, pat_max);
- if (event == CLAMP_PAT_DIM) {
- for (int a = 0; a < 2; a++) {
- /* search shouldn't be resized smaller than pattern */
- marker->search_min[a] = min_ff(pat_min[a], marker->search_min[a]);
- marker->search_max[a] = max_ff(pat_max[a], marker->search_max[a]);
- }
- }
- else if (event == CLAMP_PAT_POS) {
- float dim[2];
-
- sub_v2_v2v2(dim, pat_max, pat_min);
-
- for (int a = 0; a < 2; a++) {
- /* pattern shouldn't be moved outside of search */
- if (pat_min[a] < marker->search_min[a]) {
- for (int b = 0; b < 4; b++) {
- marker->pattern_corners[b][a] += marker->search_min[a] - pat_min[a];
- }
+ for (int a = 0; a < 2; a++) {
+ if (pat_min[a] < marker->search_min[a]) {
+ for (int b = 0; b < 4; b++) {
+ marker->pattern_corners[b][a] += marker->search_min[a] - pat_min[a];
}
- if (pat_max[a] > marker->search_max[a]) {
- for (int b = 0; b < 4; b++) {
- marker->pattern_corners[b][a] -= pat_max[a] - marker->search_max[a];
- }
+ }
+ if (pat_max[a] > marker->search_max[a]) {
+ for (int b = 0; b < 4; b++) {
+ marker->pattern_corners[b][a] -= pat_max[a] - marker->search_max[a];
}
}
}
- else if (event == CLAMP_SEARCH_DIM) {
- for (int a = 0; a < 2; a++) {
- /* search shouldn't be resized smaller than pattern */
- marker->search_min[a] = min_ff(pat_min[a], marker->search_min[a]);
- marker->search_max[a] = max_ff(pat_max[a], marker->search_max[a]);
- }
+}
+
+void BKE_tracking_marker_clamp_search_size(MovieTrackingMarker *marker)
+{
+ float pat_min[2], pat_max[2];
+ BKE_tracking_marker_pattern_minmax(marker, pat_min, pat_max);
+
+ for (int a = 0; a < 2; a++) {
+ marker->search_min[a] = min_ff(pat_min[a], marker->search_min[a]);
+ marker->search_max[a] = max_ff(pat_max[a], marker->search_max[a]);
}
- else if (event == CLAMP_SEARCH_POS) {
- float dim[2];
+}
- sub_v2_v2v2(dim, marker->search_max, marker->search_min);
+void BKE_tracking_marker_clamp_search_position(MovieTrackingMarker *marker)
+{
+ float pat_min[2], pat_max[2];
+ BKE_tracking_marker_pattern_minmax(marker, pat_min, pat_max);
- for (int a = 0; a < 2; a++) {
- /* search shouldn't be moved inside pattern */
- if (marker->search_min[a] > pat_min[a]) {
- marker->search_min[a] = pat_min[a];
- marker->search_max[a] = marker->search_min[a] + dim[a];
- }
- if (marker->search_max[a] < pat_max[a]) {
- marker->search_max[a] = pat_max[a];
- marker->search_min[a] = marker->search_max[a] - dim[a];
- }
+ float dim[2];
+ sub_v2_v2v2(dim, marker->search_max, marker->search_min);
+
+ for (int a = 0; a < 2; a++) {
+ if (marker->search_min[a] > pat_min[a]) {
+ marker->search_min[a] = pat_min[a];
+ marker->search_max[a] = marker->search_min[a] + dim[a];
+ }
+ if (marker->search_max[a] < pat_max[a]) {
+ marker->search_max[a] = pat_max[a];
+ marker->search_min[a] = marker->search_max[a] - dim[a];
}
}
}
@@ -1591,7 +1604,9 @@ void BKE_tracking_marker_get_subframe_position(MovieTrackingTrack *track,
add_v2_v2(pos, track->offset);
}
-/*********************** Plane Track *************************/
+/* --------------------------------------------------------------------
+ * Plane track.
+ */
MovieTrackingPlaneTrack *BKE_tracking_plane_track_add(MovieTracking *tracking,
ListBase *plane_tracks_base,
@@ -1796,7 +1811,9 @@ void BKE_tracking_plane_tracks_replace_point_track(MovieTracking *tracking,
}
}
-/*********************** Plane Marker *************************/
+/* --------------------------------------------------------------------
+ * Plane marker.
+ */
MovieTrackingPlaneMarker *BKE_tracking_plane_marker_insert(MovieTrackingPlaneTrack *plane_track,
MovieTrackingPlaneMarker *plane_marker)
@@ -1974,7 +1991,9 @@ void BKE_tracking_plane_marker_get_subframe_corners(MovieTrackingPlaneTrack *pla
}
}
-/*********************** Object *************************/
+/* --------------------------------------------------------------------
+ * Object.
+ */
MovieTrackingObject *BKE_tracking_object_add(MovieTracking *tracking, const char *name)
{
@@ -2119,7 +2138,9 @@ MovieTrackingReconstruction *BKE_tracking_object_get_reconstruction(MovieTrackin
return &object->reconstruction;
}
-/*********************** Camera *************************/
+/* --------------------------------------------------------------------
+ * Camera.
+ */
static int reconstructed_camera_index_get(MovieTrackingReconstruction *reconstruction,
int framenr,
@@ -2275,7 +2296,9 @@ void BKE_tracking_camera_get_reconstructed_interpolate(MovieTracking *tracking,
reconstructed_camera_scale_set(object, mat);
}
-/*********************** Distortion/Undistortion *************************/
+/* --------------------------------------------------------------------
+ * (Un)distortion.
+ */
MovieDistortion *BKE_tracking_distortion_new(MovieTracking *tracking,
int calibration_width,
@@ -2588,7 +2611,9 @@ void BKE_tracking_max_distortion_delta_across_bound(MovieTracking *tracking,
}
}
-/*********************** Image sampling *************************/
+/* --------------------------------------------------------------------
+ * Image sampling.
+ */
static void disable_imbuf_channels(ImBuf *ibuf, MovieTrackingTrack *track, bool grayscale)
{
@@ -2832,7 +2857,9 @@ void BKE_tracking_disable_channels(
}
}
-/*********************** Dopesheet functions *************************/
+/* --------------------------------------------------------------------
+ * Dopesheet functions.
+ */
/* ** Channels sort comparators ** */
@@ -2881,6 +2908,10 @@ static int channels_average_error_sort(const void *a, const void *b)
return 1;
}
+ if (channel_a->track->error == channel_b->track->error) {
+ return channels_alpha_sort(a, b);
+ }
+
return 0;
}
diff --git a/source/blender/blenkernel/intern/tracking_stabilize.c b/source/blender/blenkernel/intern/tracking_stabilize.c
index d86a0c10f01..e2e0b4227e3 100644
--- a/source/blender/blenkernel/intern/tracking_stabilize.c
+++ b/source/blender/blenkernel/intern/tracking_stabilize.c
@@ -362,7 +362,7 @@ static MovieTrackingMarker *get_tracking_data_point(StabContext *ctx,
*
* As a simple default, we use the weighted average of the location markers
* of the current frame as pivot point. TODO: It is planned to add further
- * options, like e.g. anchoring the pivot point at the canvas. Moreover,
+ * options, like e.g. anchoring the pivot point at the canvas. Moreover,
* it is planned to allow for a user controllable offset.
*/
static void setup_pivot(const float ref_pos[2], float r_pivot[2])
diff --git a/source/blender/blenkernel/intern/unit.c b/source/blender/blenkernel/intern/unit.c
index 02134623a31..b31632f0234 100644
--- a/source/blender/blenkernel/intern/unit.c
+++ b/source/blender/blenkernel/intern/unit.c
@@ -268,7 +268,7 @@ static struct bUnitCollection buImperialAclCollection = {buImperialAclDef, 0, 0,
/* Time. */
static struct bUnitDef buNaturalTimeDef[] = {
/* Weeks? - probably not needed for Blender. */
- {"day", "days", "d", NULL, "Days", "DAYS", 90000.0, 0.0, B_UNIT_DEF_NONE},
+ {"day", "days", "d", NULL, "Days", "DAYS", 86400.0, 0.0, B_UNIT_DEF_NONE},
{"hour", "hours", "hr", "h", "Hours", "HOURS", 3600.0, 0.0, B_UNIT_DEF_NONE},
{"minute", "minutes", "min", "m", "Minutes", "MINUTES", 60.0, 0.0, B_UNIT_DEF_NONE},
{"second", "seconds", "sec", "s", "Seconds", "SECONDS", 1.0, 0.0, B_UNIT_DEF_NONE}, /* Base unit. */
@@ -460,11 +460,20 @@ static size_t unit_as_string(char *str,
}
double value_conv = (value / unit->scalar) - unit->bias;
+ bool strip_skip = false;
+
+ /* Negative precision is used to disable stripping of zeroes.
+ * This reduces text jumping when changing values. */
+ if (prec < 0) {
+ strip_skip = true;
+ prec *= -1;
+ }
/* Adjust precision to expected number of significant digits.
* Note that here, we shall not have to worry about very big/small numbers, units are expected
* to replace 'scientific notation' in those cases. */
prec -= integer_digits_d(value_conv);
+
CLAMP(prec, 0, 6);
/* Convert to a string. */
@@ -478,12 +487,14 @@ static size_t unit_as_string(char *str,
size_t i = len - 1;
if (prec > 0) {
- while (i > 0 && str[i] == '0') { /* 4.300 -> 4.3 */
- str[i--] = pad;
- }
+ if (!strip_skip) {
+ while (i > 0 && str[i] == '0') { /* 4.300 -> 4.3 */
+ str[i--] = pad;
+ }
- if (i > 0 && str[i] == '.') { /* 10. -> 10 */
- str[i--] = pad;
+ if (i > 0 && str[i] == '.') { /* 10. -> 10 */
+ str[i--] = pad;
+ }
}
}
diff --git a/source/blender/blenkernel/intern/volume.cc b/source/blender/blenkernel/intern/volume.cc
index 307466d7dc9..82405830437 100644
--- a/source/blender/blenkernel/intern/volume.cc
+++ b/source/blender/blenkernel/intern/volume.cc
@@ -97,12 +97,7 @@ static struct VolumeFileCache {
/* Cache Entry */
struct Entry {
Entry(const std::string &filepath, const openvdb::GridBase::Ptr &grid)
- : filepath(filepath),
- grid_name(grid->getName()),
- grid(grid),
- is_loaded(false),
- num_metadata_users(0),
- num_tree_users(0)
+ : filepath(filepath), grid_name(grid->getName()), grid(grid)
{
}
@@ -110,9 +105,7 @@ static struct VolumeFileCache {
: filepath(other.filepath),
grid_name(other.grid_name),
grid(other.grid),
- is_loaded(other.is_loaded),
- num_metadata_users(0),
- num_tree_users(0)
+ is_loaded(other.is_loaded)
{
}
@@ -151,12 +144,12 @@ static struct VolumeFileCache {
blender::Map<int, openvdb::GridBase::Ptr> simplified_grids;
/* Has the grid tree been loaded? */
- mutable bool is_loaded;
+ mutable bool is_loaded = false;
/* Error message if an error occurred while loading. */
std::string error_msg;
/* User counting. */
- int num_metadata_users;
- int num_tree_users;
+ int num_metadata_users = 0;
+ int num_tree_users = 0;
/* Mutex for on-demand reading of tree. */
mutable std::mutex mutex;
};
diff --git a/source/blender/blenlib/BLI_any.hh b/source/blender/blenlib/BLI_any.hh
index ca3d5756c52..e80dad82d01 100644
--- a/source/blender/blenlib/BLI_any.hh
+++ b/source/blender/blenlib/BLI_any.hh
@@ -184,7 +184,7 @@ class Any {
}
/**
- * \note: Only needed because the template below does not count as copy assignment operator.
+ * \note Only needed because the template below does not count as copy assignment operator.
*/
Any &operator=(const Any &other)
{
diff --git a/source/blender/blenlib/BLI_array.hh b/source/blender/blenlib/BLI_array.hh
index 91dfc81ae27..813277d9968 100644
--- a/source/blender/blenlib/BLI_array.hh
+++ b/source/blender/blenlib/BLI_array.hh
@@ -64,10 +64,10 @@ class Array {
int64_t size_;
/** Used for allocations when the inline buffer is too small. */
- Allocator allocator_;
+ BLI_NO_UNIQUE_ADDRESS Allocator allocator_;
/** A placeholder buffer that will remain uninitialized until it is used. */
- TypedBuffer<T, InlineBufferCapacity> inline_buffer_;
+ BLI_NO_UNIQUE_ADDRESS TypedBuffer<T, InlineBufferCapacity> inline_buffer_;
public:
/**
diff --git a/source/blender/blenlib/BLI_assert.h b/source/blender/blenlib/BLI_assert.h
index 9bb7f3bfa8b..4a7fae6e98c 100644
--- a/source/blender/blenlib/BLI_assert.h
+++ b/source/blender/blenlib/BLI_assert.h
@@ -73,7 +73,7 @@ void _BLI_assert_unreachable_print(const char *file, int line, const char *funct
# define BLI_STATIC_ASSERT(a, msg) _STATIC_ASSERT(a);
# endif
#elif defined(__COVERITY__)
-/* Workaround error with coverity */
+/* Workaround error with COVERITY. */
# define BLI_STATIC_ASSERT(a, msg)
#elif defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 201112L)
/* C11 */
diff --git a/source/blender/blenlib/BLI_bitmap.h b/source/blender/blenlib/BLI_bitmap.h
index ca11cd6574e..19d8525311c 100644
--- a/source/blender/blenlib/BLI_bitmap.h
+++ b/source/blender/blenlib/BLI_bitmap.h
@@ -15,7 +15,7 @@ extern "C" {
typedef unsigned int BLI_bitmap;
-/* warning: the bitmap does not keep track of its own size or check
+/* WARNING: the bitmap does not keep track of its own size or check
* for out-of-bounds access */
/* internal use */
diff --git a/source/blender/blenlib/BLI_bounds.hh b/source/blender/blenlib/BLI_bounds.hh
index d20382ed500..f5a18a0ea48 100644
--- a/source/blender/blenlib/BLI_bounds.hh
+++ b/source/blender/blenlib/BLI_bounds.hh
@@ -28,10 +28,11 @@ template<typename T> static std::optional<MinMaxResult<T>> min_max(Span<T> value
if (values.is_empty()) {
return std::nullopt;
}
+ const MinMaxResult<T> init{values.first(), values.first()};
return threading::parallel_reduce(
values.index_range(),
1024,
- MinMaxResult<T>(),
+ init,
[&](IndexRange range, const MinMaxResult<T> &init) {
MinMaxResult<T> result = init;
for (const int i : range) {
@@ -55,10 +56,11 @@ static std::optional<MinMaxResult<T>> min_max_with_radii(Span<T> values, Span<Ra
if (values.is_empty()) {
return std::nullopt;
}
+ const MinMaxResult<T> init{values.first(), values.first()};
return threading::parallel_reduce(
values.index_range(),
1024,
- MinMaxResult<T>(),
+ init,
[&](IndexRange range, const MinMaxResult<T> &init) {
MinMaxResult<T> result = init;
for (const int i : range) {
diff --git a/source/blender/blenlib/BLI_color.hh b/source/blender/blenlib/BLI_color.hh
index 98fd7d0f15d..b1b9aeb17f1 100644
--- a/source/blender/blenlib/BLI_color.hh
+++ b/source/blender/blenlib/BLI_color.hh
@@ -79,7 +79,7 @@ enum class eSpace {
};
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;
@@ -167,7 +167,7 @@ class ColorSceneLinear4f final : public ColorRGBA<float, eSpace::SceneLinear, Al
}
/**
- * Convert to its byte encoded counter space.
+ * Convert to its byte encoded counterpart.
*/
ColorSceneLinearByteEncoded4b<Alpha> encode() const
{
@@ -179,7 +179,7 @@ class ColorSceneLinear4f final : public ColorRGBA<float, eSpace::SceneLinear, Al
/**
* Convert color and alpha association to premultiplied alpha.
*
- * Does nothing when color has already a premultiplied alpha.
+ * Does nothing when color already has a premultiplied alpha.
*/
ColorSceneLinear4f<eAlpha::Premultiplied> premultiply_alpha() const
{
@@ -196,7 +196,7 @@ class ColorSceneLinear4f final : public ColorRGBA<float, eSpace::SceneLinear, Al
/**
* Convert color and alpha association to straight alpha.
*
- * Does nothing when color has straighten alpha.
+ * Does nothing when color has straight alpha.
*/
ColorSceneLinear4f<eAlpha::Straight> unpremultiply_alpha() const
{
@@ -228,7 +228,7 @@ class ColorSceneLinearByteEncoded4b final
}
/**
- * Convert to back to float color.
+ * Convert to a float color.
*/
ColorSceneLinear4f<Alpha> decode() const
{
diff --git a/source/blender/blenlib/BLI_color_mix.hh b/source/blender/blenlib/BLI_color_mix.hh
index 4989ddc609e..322da2bf112 100644
--- a/source/blender/blenlib/BLI_color_mix.hh
+++ b/source/blender/blenlib/BLI_color_mix.hh
@@ -1042,7 +1042,7 @@ BLI_INLINE Color BLI_mix_colors(const IMB_BlendMode tool,
case IMB_BLEND_COLOR:
return mix_color<Color, Traits>(a, b, alpha);
default:
- BLI_assert(0);
+ BLI_assert_unreachable();
return Color(0, 0, 0, 0);
}
}
diff --git a/source/blender/blenlib/BLI_fileops.h b/source/blender/blenlib/BLI_fileops.h
index 3ce2b90e729..063e60ecf03 100644
--- a/source/blender/blenlib/BLI_fileops.h
+++ b/source/blender/blenlib/BLI_fileops.h
@@ -178,7 +178,7 @@ 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,
- uint64_t sz,
+ uint64_t st_size_fallback,
bool compact,
char r_size[FILELIST_DIRENTRY_SIZE_LEN]);
/**
@@ -215,10 +215,10 @@ void BLI_filelist_entry_datetime_to_string(const struct stat *st,
/** \name Files
* \{ */
-FILE *BLI_fopen(const char *filename, const char *mode) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
-void *BLI_gzopen(const char *filename, const char *mode) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
-int BLI_open(const char *filename, int oflag, int pmode) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
-int BLI_access(const char *filename, int mode) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
+FILE *BLI_fopen(const char *filepath, const char *mode) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
+void *BLI_gzopen(const char *filepath, const char *mode) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
+int BLI_open(const char *filepath, int oflag, int pmode) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
+int BLI_access(const char *filepath, int mode) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
/**
* Returns true if the file with the specified name can be written.
@@ -226,7 +226,7 @@ int BLI_access(const char *filename, int mode) ATTR_WARN_UNUSED_RESULT ATTR_NONN
* to the real UID and GID of the process, not its effective UID and GID.
* This shouldn't matter for Blender, which is not going to run privileged anyway.
*/
-bool BLI_file_is_writable(const char *file) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
+bool BLI_file_is_writable(const char *filepath) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
/**
* Creates the file with nothing in it, or updates its last-modified date if it already exists.
* Returns true if successful (like the unix touch command).
@@ -319,7 +319,7 @@ const char *BLI_expand_tilde(const char *path_with_tilde);
# define O_BINARY 0
# endif
#else
-void BLI_get_short_name(char short_name[256], const char *filename);
+void BLI_get_short_name(char short_name[256], const char *filepath);
#endif
/** \} */
diff --git a/source/blender/blenlib/BLI_float3x3.hh b/source/blender/blenlib/BLI_float3x3.hh
new file mode 100644
index 00000000000..62478556d9b
--- /dev/null
+++ b/source/blender/blenlib/BLI_float3x3.hh
@@ -0,0 +1,192 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+
+#pragma once
+
+#include <cmath>
+#include <cstdint>
+
+#include "BLI_assert.h"
+#include "BLI_math_base.h"
+#include "BLI_math_matrix.h"
+#include "BLI_math_vec_types.hh"
+#include "BLI_math_vector.h"
+
+namespace blender {
+
+struct float3x3 {
+ /* A 3x3 matrix in column major order. */
+ float values[3][3];
+
+ float3x3() = default;
+
+ float3x3(const float *matrix)
+ {
+ memcpy(values, matrix, sizeof(float) * 3 * 3);
+ }
+
+ float3x3(const float matrix[3][3]) : float3x3(static_cast<const float *>(matrix[0]))
+ {
+ }
+
+ static float3x3 zero()
+ {
+ float3x3 result;
+ zero_m3(result.values);
+ return result;
+ }
+
+ static float3x3 identity()
+ {
+ float3x3 result;
+ unit_m3(result.values);
+ return result;
+ }
+
+ static float3x3 from_translation(const float2 translation)
+ {
+ float3x3 result = identity();
+ result.values[2][0] = translation.x;
+ result.values[2][1] = translation.y;
+ return result;
+ }
+
+ static float3x3 from_rotation(float rotation)
+ {
+ float3x3 result = zero();
+ const float cosine = std::cos(rotation);
+ const float sine = std::sin(rotation);
+ result.values[0][0] = cosine;
+ result.values[0][1] = sine;
+ result.values[1][0] = -sine;
+ result.values[1][1] = cosine;
+ result.values[2][2] = 1.0f;
+ return result;
+ }
+
+ static float3x3 from_translation_rotation_scale(const float2 translation,
+ float rotation,
+ const float2 scale)
+ {
+ float3x3 result;
+ const float cosine = std::cos(rotation);
+ const float sine = std::sin(rotation);
+ result.values[0][0] = scale.x * cosine;
+ result.values[0][1] = scale.x * sine;
+ result.values[0][2] = 0.0f;
+ result.values[1][0] = scale.y * -sine;
+ result.values[1][1] = scale.y * cosine;
+ result.values[1][2] = 0.0f;
+ result.values[2][0] = translation.x;
+ result.values[2][1] = translation.y;
+ result.values[2][2] = 1.0f;
+ return result;
+ }
+
+ static float3x3 from_normalized_axes(const float2 translation,
+ const float2 horizontal,
+ const float2 vertical)
+ {
+ BLI_ASSERT_UNIT_V2(horizontal);
+ BLI_ASSERT_UNIT_V2(vertical);
+
+ float3x3 result;
+ result.values[0][0] = horizontal.x;
+ result.values[0][1] = horizontal.y;
+ result.values[0][2] = 0.0f;
+ result.values[1][0] = vertical.x;
+ result.values[1][1] = vertical.y;
+ result.values[1][2] = 0.0f;
+ result.values[2][0] = translation.x;
+ result.values[2][1] = translation.y;
+ result.values[2][2] = 1.0f;
+ return result;
+ }
+
+ /* Construct a transformation that is pivoted around the given origin point. So for instance,
+ * from_origin_transformation(from_rotation(M_PI_2), float2(0.0f, 2.0f))
+ * will construct a transformation representing a 90 degree rotation around the point (0, 2). */
+ static float3x3 from_origin_transformation(const float3x3 &transformation, const float2 origin)
+ {
+ return from_translation(origin) * transformation * from_translation(-origin);
+ }
+
+ operator float *()
+ {
+ return &values[0][0];
+ }
+
+ operator const float *() const
+ {
+ return &values[0][0];
+ }
+
+ float *operator[](const int64_t index)
+ {
+ BLI_assert(index >= 0);
+ BLI_assert(index < 3);
+ return &values[index][0];
+ }
+
+ const float *operator[](const int64_t index) const
+ {
+ BLI_assert(index >= 0);
+ BLI_assert(index < 3);
+ return &values[index][0];
+ }
+
+ using c_style_float3x3 = float[3][3];
+ c_style_float3x3 &ptr()
+ {
+ return values;
+ }
+
+ const c_style_float3x3 &ptr() const
+ {
+ return values;
+ }
+
+ friend float3x3 operator*(const float3x3 &a, const float3x3 &b)
+ {
+ float3x3 result;
+ mul_m3_m3m3(result.values, a.values, b.values);
+ return result;
+ }
+
+ void operator*=(const float3x3 &other)
+ {
+ mul_m3_m3_post(values, other.values);
+ }
+
+ friend float2 operator*(const float3x3 &transformation, const float2 &vector)
+ {
+ float2 result;
+ mul_v2_m3v2(result, transformation.values, vector);
+ return result;
+ }
+
+ friend float2 operator*(const float3x3 &transformation, const float (*vector)[2])
+ {
+ return transformation * float2(vector);
+ }
+
+ float3x3 transposed() const
+ {
+ float3x3 result;
+ transpose_m3_m3(result.values, values);
+ return result;
+ }
+
+ float3x3 inverted() const
+ {
+ float3x3 result;
+ invert_m3_m3(result.values, values);
+ return result;
+ }
+
+ friend bool operator==(const float3x3 &a, const float3x3 &b)
+ {
+ return equals_m3m3(a.values, b.values);
+ }
+};
+
+} // namespace blender
diff --git a/source/blender/blenlib/BLI_float4x4.hh b/source/blender/blenlib/BLI_float4x4.hh
index 9f7fbffc692..64e6e68432f 100644
--- a/source/blender/blenlib/BLI_float4x4.hh
+++ b/source/blender/blenlib/BLI_float4x4.hh
@@ -147,6 +147,16 @@ struct float4x4 {
return m * float3(v);
}
+ friend bool operator==(const float4x4 &a, const float4x4 &b)
+ {
+ return equals_m4m4(a.ptr(), b.ptr());
+ }
+
+ friend bool operator!=(const float4x4 &a, const float4x4 &b)
+ {
+ return !(a == b);
+ }
+
float3 translation() const
{
return float3(values[3]);
@@ -246,6 +256,25 @@ struct float4x4 {
}
return h;
}
+
+ friend std::ostream &operator<<(std::ostream &stream, const float4x4 &mat)
+ {
+ char fchar[16];
+ stream << "(\n";
+ for (int i = 0; i < 4; i++) {
+ stream << "(";
+ for (int j = 0; j < 4; j++) {
+ snprintf(fchar, sizeof(fchar), "%11.6f", mat[j][i]);
+ stream << fchar;
+ if (i != 3) {
+ stream << ", ";
+ }
+ }
+ stream << ")\n";
+ }
+ stream << ")\n";
+ return stream;
+ }
};
} // namespace blender
diff --git a/source/blender/blenlib/BLI_generic_array.hh b/source/blender/blenlib/BLI_generic_array.hh
index e1b6b29874a..4b917434264 100644
--- a/source/blender/blenlib/BLI_generic_array.hh
+++ b/source/blender/blenlib/BLI_generic_array.hh
@@ -33,7 +33,7 @@ class GArray {
void *data_ = nullptr;
int64_t size_ = 0;
- Allocator allocator_;
+ BLI_NO_UNIQUE_ADDRESS Allocator allocator_;
public:
/**
diff --git a/source/blender/blenlib/BLI_generic_virtual_array.hh b/source/blender/blenlib/BLI_generic_virtual_array.hh
index d02760d9178..985d914f4a4 100644
--- a/source/blender/blenlib/BLI_generic_virtual_array.hh
+++ b/source/blender/blenlib/BLI_generic_virtual_array.hh
@@ -61,7 +61,9 @@ class GVArrayImpl {
/* A generic version of #VMutableArrayImpl. */
class GVMutableArrayImpl : public GVArrayImpl {
public:
- GVMutableArrayImpl(const CPPType &type, int64_t size);
+ GVMutableArrayImpl(const CPPType &type, int64_t size) : GVArrayImpl(type, size)
+ {
+ }
virtual void set_by_copy(int64_t index, const void *value);
virtual void set_by_relocate(int64_t index, void *value);
@@ -105,7 +107,7 @@ class GVArrayCommon {
Storage storage_;
protected:
- GVArrayCommon();
+ GVArrayCommon() = default;
GVArrayCommon(const GVArrayCommon &other);
GVArrayCommon(GVArrayCommon &&other) noexcept;
GVArrayCommon(const GVArrayImpl *impl);
@@ -186,6 +188,10 @@ class GVArray : public GVArrayCommon {
GVArray(const GVArrayImpl *impl);
GVArray(std::shared_ptr<const GVArrayImpl> impl);
+ GVArray(varray_tag::span /* tag */, GSpan span);
+ GVArray(varray_tag::single_ref /* tag */, const CPPType &type, int64_t size, const void *value);
+ GVArray(varray_tag::single /* tag */, const CPPType &type, int64_t size, const void *value);
+
template<typename T> GVArray(const VArray<T> &varray);
template<typename T> VArray<T> typed() const;
@@ -643,10 +649,18 @@ class GVArrayImpl_For_GSpan : public GVMutableArrayImpl {
const int64_t element_size_;
public:
- GVArrayImpl_For_GSpan(const GMutableSpan span);
+ GVArrayImpl_For_GSpan(const GMutableSpan span)
+ : GVMutableArrayImpl(span.type(), span.size()),
+ data_(span.data()),
+ element_size_(span.type().size())
+ {
+ }
protected:
- GVArrayImpl_For_GSpan(const CPPType &type, int64_t size);
+ GVArrayImpl_For_GSpan(const CPPType &type, int64_t size)
+ : GVMutableArrayImpl(type, size), element_size_(type.size())
+ {
+ }
public:
void get(int64_t index, void *r_value) const override;
@@ -667,6 +681,61 @@ class GVArrayImpl_For_GSpan : public GVMutableArrayImpl {
void *dst) const override;
};
+class GVArrayImpl_For_GSpan_final final : public GVArrayImpl_For_GSpan {
+ public:
+ using GVArrayImpl_For_GSpan::GVArrayImpl_For_GSpan;
+
+ private:
+ bool may_have_ownership() const override
+ {
+ return false;
+ }
+};
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name #GVArrayImpl_For_SingleValueRef.
+ * \{ */
+
+class GVArrayImpl_For_SingleValueRef : public GVArrayImpl {
+ protected:
+ const void *value_ = nullptr;
+
+ public:
+ GVArrayImpl_For_SingleValueRef(const CPPType &type, const int64_t size, const void *value)
+ : GVArrayImpl(type, size), value_(value)
+ {
+ }
+
+ protected:
+ GVArrayImpl_For_SingleValueRef(const CPPType &type, const int64_t size) : GVArrayImpl(type, size)
+ {
+ }
+
+ void get(const int64_t index, void *r_value) const override;
+ void get_to_uninitialized(const int64_t index, void *r_value) const override;
+ bool is_span() const override;
+ GSpan get_internal_span() const override;
+ bool is_single() const override;
+ void get_internal_single(void *r_value) const override;
+ void materialize(const IndexMask mask, void *dst) const override;
+ void materialize_to_uninitialized(const IndexMask mask, void *dst) const override;
+ void materialize_compressed(const IndexMask mask, void *dst) const override;
+ void materialize_compressed_to_uninitialized(const IndexMask mask, void *dst) const override;
+};
+
+class GVArrayImpl_For_SingleValueRef_final final : public GVArrayImpl_For_SingleValueRef {
+ public:
+ using GVArrayImpl_For_SingleValueRef::GVArrayImpl_For_SingleValueRef;
+
+ private:
+ bool may_have_ownership() const override
+ {
+ return false;
+ }
+};
+
/** \} */
/* -------------------------------------------------------------------- */
@@ -809,6 +878,22 @@ inline bool GVArrayCommon::is_empty() const
/** \name Inline methods for #GVArray.
* \{ */
+inline GVArray::GVArray(varray_tag::span /* tag */, const GSpan span)
+{
+ /* Use const-cast because the underlying virtual array implementation is shared between const
+ * and non const data. */
+ GMutableSpan mutable_span{span.type(), const_cast<void *>(span.data()), span.size()};
+ this->emplace<GVArrayImpl_For_GSpan_final>(mutable_span);
+}
+
+inline GVArray::GVArray(varray_tag::single_ref /* tag */,
+ const CPPType &type,
+ const int64_t size,
+ const void *value)
+{
+ this->emplace<GVArrayImpl_For_SingleValueRef_final>(type, size, value);
+}
+
namespace detail {
template<typename StorageT> constexpr GVArrayAnyExtraInfo GVArrayAnyExtraInfo::get()
{
@@ -849,15 +934,15 @@ template<typename T> inline GVArray::GVArray(const VArray<T> &varray)
if (varray.try_assign_GVArray(*this)) {
return;
}
- /* Need to check this before the span/single special cases, because otherwise we might loose
- * ownership to the referenced data when #varray goes out of scope. */
- if (varray.may_have_ownership()) {
- *this = GVArray::For<GVArrayImpl_For_VArray<T>>(varray);
- }
- else if (varray.is_single()) {
+ if (varray.is_single()) {
T value = varray.get_internal_single();
*this = GVArray::ForSingle(CPPType::get<T>(), varray.size(), &value);
}
+ /* Need to check this before the span special case, because otherwise we might loose
+ * ownership to the referenced data when #varray goes out of scope. */
+ else if (varray.may_have_ownership()) {
+ *this = GVArray::For<GVArrayImpl_For_VArray<T>>(varray);
+ }
else if (varray.is_span()) {
Span<T> data = varray.get_internal_span();
*this = GVArray::ForSpan(data);
@@ -877,14 +962,14 @@ template<typename T> inline VArray<T> GVArray::typed() const
if (this->try_assign_VArray(varray)) {
return varray;
}
- if (this->may_have_ownership()) {
- return VArray<T>::template For<VArrayImpl_For_GVArray<T>>(*this);
- }
if (this->is_single()) {
T value;
this->get_internal_single(&value);
return VArray<T>::ForSingle(value, this->size());
}
+ if (this->may_have_ownership()) {
+ return VArray<T>::template For<VArrayImpl_For_GVArray<T>>(*this);
+ }
if (this->is_span()) {
const Span<T> span = this->get_internal_span().typed<T>();
return VArray<T>::ForSpan(span);
diff --git a/source/blender/blenlib/BLI_ghash.h b/source/blender/blenlib/BLI_ghash.h
index 7f90ec20b66..8743b135dff 100644
--- a/source/blender/blenlib/BLI_ghash.h
+++ b/source/blender/blenlib/BLI_ghash.h
@@ -562,7 +562,7 @@ bool BLI_ghashutil_ptrcmp(const void *a, const void *b);
/**
* This function implements the widely used `djb` hash apparently posted
- * by Daniel Bernstein to `comp.lang.c` some time ago. The 32 bit
+ * by Daniel Bernstein to `comp.lang.c` some time ago. The 32 bit
* unsigned hash value starts at 5381 and for each byte 'c' in the
* string, is updated: `hash = hash * 33 + c`.
* This function uses the signed value of each byte.
diff --git a/source/blender/blenlib/BLI_hash_tables.hh b/source/blender/blenlib/BLI_hash_tables.hh
index 334634613a2..156fe481828 100644
--- a/source/blender/blenlib/BLI_hash_tables.hh
+++ b/source/blender/blenlib/BLI_hash_tables.hh
@@ -209,11 +209,11 @@ template<typename Key, Key EmptyValue, Key RemovedValue> struct TemplatedKeyInfo
};
/**
- * 0xffff...ffff indicates an empty slot.
- * 0xffff...fffe indicates a removed slot.
+ * `0xffff...ffff` indicates an empty slot.
+ * `0xffff...fffe` indicates a removed slot.
*
* Those specific values are used, because with them a single comparison is enough to check whether
- * a slot is occupied. The keys 0x0000...0000 and 0x0000...0001 also satisfy this constraint.
+ * a slot is occupied. The keys `0x0000...0000` and `0x0000...0001` also satisfy this constraint.
* However, nullptr is much more likely to be used as valid key.
*/
template<typename Pointer> struct PointerKeyInfo {
diff --git a/source/blender/blenlib/BLI_index_mask.hh b/source/blender/blenlib/BLI_index_mask.hh
index b87ab0afc98..22bdf090181 100644
--- a/source/blender/blenlib/BLI_index_mask.hh
+++ b/source/blender/blenlib/BLI_index_mask.hh
@@ -278,7 +278,7 @@ class IndexMask {
* before each range in the return value starts.
*/
Vector<IndexRange> extract_ranges_invert(const IndexRange full_range,
- Vector<int64_t> *r_skip_amounts) const;
+ Vector<int64_t> *r_skip_amounts = nullptr) const;
};
} // namespace blender
diff --git a/source/blender/blenlib/BLI_length_parameterize.hh b/source/blender/blenlib/BLI_length_parameterize.hh
index 6fe1c6513a2..ec0fabb75b4 100644
--- a/source/blender/blenlib/BLI_length_parameterize.hh
+++ b/source/blender/blenlib/BLI_length_parameterize.hh
@@ -17,7 +17,7 @@ namespace blender::length_parameterize {
* Return the size of the necessary lengths array for a group of points, taking into account the
* possible last cyclic segment.
*
- * \note This is the same as #bke::curves::curve_segment_size.
+ * \note This is the same as #bke::curves::curve_segment_num.
*/
inline int lengths_num(const int points_num, const bool cyclic)
{
@@ -84,7 +84,7 @@ void create_uniform_samples(Span<float> lengths,
* Could be calculated by #accumulate_lengths.
* \param sample_lengths: Sampled locations in the #lengths array. Must be sorted and is expected
* to be within the range of the #lengths values.
- * \param cyclic: Whether the points described by the #lenghts input is cyclic. This is likely
+ * \param cyclic: Whether the points described by the #lengths input is cyclic. This is likely
* redundant information theoretically.
* \param indices: The index of the previous point at each sample.
* \param factors: The portion of the length in each segment at each sample.
diff --git a/source/blender/blenlib/BLI_linear_allocator.hh b/source/blender/blenlib/BLI_linear_allocator.hh
index 6532c59a846..deb6ea3b5fd 100644
--- a/source/blender/blenlib/BLI_linear_allocator.hh
+++ b/source/blender/blenlib/BLI_linear_allocator.hh
@@ -18,7 +18,7 @@ namespace blender {
template<typename Allocator = GuardedAllocator> class LinearAllocator : NonCopyable, NonMovable {
private:
- Allocator allocator_;
+ BLI_NO_UNIQUE_ADDRESS Allocator allocator_;
Vector<void *> owned_buffers_;
Vector<Span<char>> unused_borrowed_buffers_;
diff --git a/source/blender/blenlib/BLI_map.hh b/source/blender/blenlib/BLI_map.hh
index d76aa46502d..55233676ed8 100644
--- a/source/blender/blenlib/BLI_map.hh
+++ b/source/blender/blenlib/BLI_map.hh
@@ -130,10 +130,10 @@ class Map {
uint64_t slot_mask_;
/** This is called to hash incoming keys. */
- Hash hash_;
+ BLI_NO_UNIQUE_ADDRESS Hash hash_;
/** This is called to check equality of two keys. */
- IsEqual is_equal_;
+ BLI_NO_UNIQUE_ADDRESS IsEqual is_equal_;
/** The max load factor is 1/2 = 50% by default. */
#define LOAD_FACTOR 1, 2
diff --git a/source/blender/blenlib/BLI_math_base.h b/source/blender/blenlib/BLI_math_base.h
index f9c05fb116e..f072a17f384 100644
--- a/source/blender/blenlib/BLI_math_base.h
+++ b/source/blender/blenlib/BLI_math_base.h
@@ -204,13 +204,17 @@ MINLINE int integer_digits_i(int i);
/* These don't really fit anywhere but were being copied about a lot. */
MINLINE int is_power_of_2_i(int n);
+
+MINLINE unsigned int log2_floor_u(unsigned int x);
+MINLINE unsigned int log2_ceil_u(unsigned int x);
+
+/**
+ * Returns next (or previous) power of 2 or the input number if it is already a power of 2.
+ */
MINLINE int power_of_2_max_i(int n);
MINLINE int power_of_2_min_i(int n);
-
MINLINE unsigned int power_of_2_max_u(unsigned int x);
MINLINE unsigned int power_of_2_min_u(unsigned int x);
-MINLINE unsigned int log2_floor_u(unsigned int x);
-MINLINE unsigned int log2_ceil_u(unsigned int x);
/**
* Integer division that rounds 0.5 up, particularly useful for color blending
diff --git a/source/blender/blenlib/BLI_math_base.hh b/source/blender/blenlib/BLI_math_base.hh
index 81f5343056e..b15179f75b6 100644
--- a/source/blender/blenlib/BLI_math_base.hh
+++ b/source/blender/blenlib/BLI_math_base.hh
@@ -14,19 +14,9 @@
#include "BLI_math_base_safe.h"
#include "BLI_utildefines.h"
-#ifdef WITH_GMP
-# include "BLI_math_mpq.hh"
-#endif
-
namespace blender::math {
-template<typename T>
-inline constexpr bool is_math_float_type = (std::is_floating_point_v<T>
-#ifdef WITH_GMP
- || std::is_same_v<T, mpq_class>
-#endif
-);
-
+template<typename T> inline constexpr bool is_math_float_type = std::is_floating_point_v<T>;
template<typename T> inline constexpr bool is_math_integral_type = std::is_integral_v<T>;
template<typename T> inline bool is_zero(const T &a)
@@ -54,6 +44,16 @@ template<typename T> inline T max(const T &a, const T &b)
return std::max(a, b);
}
+template<typename T> inline void max_inplace(T &a, const T &b)
+{
+ a = math::max(a, b);
+}
+
+template<typename T> inline void min_inplace(T &a, const T &b)
+{
+ a = math::min(a, b);
+}
+
template<typename T> inline T clamp(const T &a, const T &min, const T &max)
{
return std::clamp(a, min, max);
@@ -108,12 +108,20 @@ template<typename T,
BLI_ENABLE_IF((is_math_float_type<FactorT>))>
inline T interpolate(const T &a, const T &b, const FactorT &t)
{
- return a * (1 - t) + b * t;
+ auto result = a * (1 - t) + b * t;
+ if constexpr (std::is_integral_v<T> && std::is_floating_point_v<FactorT>) {
+ result = std::round(result);
+ }
+ return result;
}
template<typename T> inline T midpoint(const T &a, const T &b)
{
- return (a + b) * T(0.5);
+ auto result = (a + b) * T(0.5);
+ if constexpr (std::is_integral_v<T>) {
+ result = std::round(result);
+ }
+ return result;
}
} // namespace blender::math
diff --git a/source/blender/blenlib/BLI_math_color.h b/source/blender/blenlib/BLI_math_color.h
index dcc00064e47..6386a7f76f8 100644
--- a/source/blender/blenlib/BLI_math_color.h
+++ b/source/blender/blenlib/BLI_math_color.h
@@ -123,7 +123,7 @@ MINLINE void premul_float_to_straight_uchar(unsigned char *result, const float c
* one of the primaries, it lies outside the color gamut
* accessible from the given triple of primaries. Desaturate
* it by adding white, equal quantities of R, G, and B, enough
- * to make RGB all positive. The function returns 1 if the
+ * to make RGB all positive. The function returns 1 if the
* components were modified, zero otherwise.
*/
int constrain_rgb(float *r, float *g, float *b);
@@ -186,9 +186,6 @@ 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 5c1b6c8d774..93b413ab755 100644
--- a/source/blender/blenlib/BLI_math_geom.h
+++ b/source/blender/blenlib/BLI_math_geom.h
@@ -136,7 +136,7 @@ bool is_quad_convex_v2(const float v1[2], const float v2[2], const float v3[2],
bool is_poly_convex_v2(const float verts[][2], unsigned int nr);
/**
* Check if either of the diagonals along this quad create flipped triangles
- * (normals pointing away from eachother).
+ * (normals pointing away from each other).
* - (1 << 0): (v1-v3) is flipped.
* - (1 << 1): (v2-v4) is flipped.
*/
diff --git a/source/blender/blenlib/BLI_math_matrix.h b/source/blender/blenlib/BLI_math_matrix.h
index edfe53bc938..2cd2a299d53 100644
--- a/source/blender/blenlib/BLI_math_matrix.h
+++ b/source/blender/blenlib/BLI_math_matrix.h
@@ -374,7 +374,7 @@ void invert_m3_m3_safe_ortho(float Ainv[3][3], const float A[3][3]);
* A safe version of invert that uses valid axes, calculating the zero'd axis
* based on the non-zero ones.
*
- * This works well for transformation matrices, when a single axis is zerod.
+ * This works well for transformation matrices, when a single axis is zeroed.
*/
void invert_m4_m4_safe_ortho(float Ainv[4][4], const float A[4][4]);
diff --git a/source/blender/blenlib/BLI_math_mpq.hh b/source/blender/blenlib/BLI_math_mpq.hh
index 7b43c90da84..02c92705323 100644
--- a/source/blender/blenlib/BLI_math_mpq.hh
+++ b/source/blender/blenlib/BLI_math_mpq.hh
@@ -19,4 +19,10 @@
*/
# include "gmpxx.h"
+# include "BLI_math_base.hh"
+
+namespace blender::math {
+template<> inline constexpr bool is_math_float_type<mpq_class> = true;
+}
+
#endif /* WITH_GMP */
diff --git a/source/blender/blenlib/BLI_math_rotation.h b/source/blender/blenlib/BLI_math_rotation.h
index 7d10e52f699..192ad482a69 100644
--- a/source/blender/blenlib/BLI_math_rotation.h
+++ b/source/blender/blenlib/BLI_math_rotation.h
@@ -7,6 +7,7 @@
* \ingroup bli
*/
+#include "BLI_math_base.h"
#include "BLI_utildefines.h"
#include "DNA_vec_types.h"
diff --git a/source/blender/blenlib/BLI_math_vec_types.hh b/source/blender/blenlib/BLI_math_vec_types.hh
index e36bbedee32..7f20881dfa3 100644
--- a/source/blender/blenlib/BLI_math_vec_types.hh
+++ b/source/blender/blenlib/BLI_math_vec_types.hh
@@ -14,10 +14,6 @@
#include "BLI_utildefines.h"
-#ifdef WITH_GMP
-# include "BLI_math_mpq.hh"
-#endif
-
namespace blender {
/* clang-format off */
diff --git a/source/blender/blenlib/BLI_math_vector.hh b/source/blender/blenlib/BLI_math_vector.hh
index b9f0939674e..384c4b49070 100644
--- a/source/blender/blenlib/BLI_math_vector.hh
+++ b/source/blender/blenlib/BLI_math_vector.hh
@@ -49,6 +49,20 @@ template<typename T, int Size> inline bool is_any_zero(const vec_base<T, Size> &
return false;
}
+template<typename T, int Size>
+inline bool almost_equal_relative(const vec_base<T, Size> &a,
+ const vec_base<T, Size> &b,
+ const T &epsilon_factor)
+{
+ for (int i = 0; i < Size; i++) {
+ const float epsilon = epsilon_factor * math::abs(a[i]);
+ if (math::distance(a[i], b[i]) > epsilon) {
+ return false;
+ }
+ }
+ return true;
+}
+
template<typename T, int Size> inline vec_base<T, Size> abs(const vec_base<T, Size> &a)
{
vec_base<T, Size> result;
@@ -145,6 +159,39 @@ inline T safe_mod(const vec_base<T, Size> &a, const T &b)
return result;
}
+/**
+ * Returns \a a if it is a multiple of \a b or the next multiple or \a b after \b a .
+ * In other words, it is equivalent to `divide_ceil(a, b) * b`.
+ * It is undefined if \a a is negative or \b b is not strictly positive.
+ */
+template<typename T, int Size, BLI_ENABLE_IF((is_math_integral_type<T>))>
+inline vec_base<T, Size> ceil_to_multiple(const vec_base<T, Size> &a, const vec_base<T, Size> &b)
+{
+ vec_base<T, Size> result;
+ for (int i = 0; i < Size; i++) {
+ BLI_assert(a[i] >= 0);
+ BLI_assert(b[i] > 0);
+ result[i] = ((a[i] + b[i] - 1) / b[i]) * b[i];
+ }
+ return result;
+}
+
+/**
+ * Integer division that returns the ceiling, instead of flooring like normal C division.
+ * It is undefined if \a a is negative or \b b is not strictly positive.
+ */
+template<typename T, int Size, BLI_ENABLE_IF((is_math_integral_type<T>))>
+inline vec_base<T, Size> divide_ceil(const vec_base<T, Size> &a, const vec_base<T, Size> &b)
+{
+ vec_base<T, Size> result;
+ for (int i = 0; i < Size; i++) {
+ BLI_assert(a[i] >= 0);
+ BLI_assert(b[i] > 0);
+ result[i] = (a[i] + b[i] - 1) / b[i];
+ }
+ return result;
+}
+
template<typename T, int Size>
inline void min_max(const vec_base<T, Size> &vector,
vec_base<T, Size> &min,
diff --git a/source/blender/blenlib/BLI_memory_utils.hh b/source/blender/blenlib/BLI_memory_utils.hh
index d7c41ae88a8..940542c9f1d 100644
--- a/source/blender/blenlib/BLI_memory_utils.hh
+++ b/source/blender/blenlib/BLI_memory_utils.hh
@@ -317,30 +317,36 @@ template<typename T> using destruct_ptr = std::unique_ptr<T, DestructValueAtAddr
* An `AlignedBuffer` is a byte array with at least the given size and alignment. The buffer will
* not be initialized by the default constructor.
*/
-template<size_t Size, size_t Alignment> class alignas(Alignment) AlignedBuffer {
- private:
- /* Don't create an empty array. This causes problems with some compilers. */
- char buffer_[(Size > 0) ? Size : 1];
+template<size_t Size, size_t Alignment> class AlignedBuffer {
+ struct Empty {
+ };
+ struct alignas(Alignment) Sized {
+ /* Don't create an empty array. This causes problems with some compilers. */
+ std::byte buffer_[Size > 0 ? Size : 1];
+ };
+
+ using BufferType = std::conditional_t<Size == 0, Empty, Sized>;
+ BLI_NO_UNIQUE_ADDRESS BufferType buffer_;
public:
operator void *()
{
- return buffer_;
+ return this;
}
operator const void *() const
{
- return buffer_;
+ return this;
}
void *ptr()
{
- return buffer_;
+ return this;
}
const void *ptr() const
{
- return buffer_;
+ return this;
}
};
@@ -351,7 +357,7 @@ template<size_t Size, size_t Alignment> class alignas(Alignment) AlignedBuffer {
*/
template<typename T, int64_t Size = 1> class TypedBuffer {
private:
- AlignedBuffer<sizeof(T) * (size_t)Size, alignof(T)> buffer_;
+ BLI_NO_UNIQUE_ADDRESS AlignedBuffer<sizeof(T) * (size_t)Size, alignof(T)> buffer_;
public:
operator T *()
diff --git a/source/blender/blenlib/BLI_set.hh b/source/blender/blenlib/BLI_set.hh
index 391d31c2228..62de4b79e41 100644
--- a/source/blender/blenlib/BLI_set.hh
+++ b/source/blender/blenlib/BLI_set.hh
@@ -136,10 +136,10 @@ class Set {
uint64_t slot_mask_;
/** This is called to hash incoming keys. */
- Hash hash_;
+ BLI_NO_UNIQUE_ADDRESS Hash hash_;
/** This is called to check equality of two keys. */
- IsEqual is_equal_;
+ BLI_NO_UNIQUE_ADDRESS IsEqual is_equal_;
/** The max load factor is 1/2 = 50% by default. */
#define LOAD_FACTOR 1, 2
@@ -483,10 +483,10 @@ class Set {
* while iterating over the set. However, after this method has been called, the removed element
* must not be accessed anymore.
*/
- void remove(const Iterator &iterator)
+ void remove(const Iterator &it)
{
/* The const cast is valid because this method itself is not const. */
- Slot &slot = const_cast<Slot &>(iterator.current_slot());
+ Slot &slot = const_cast<Slot &>(it.current_slot());
BLI_assert(slot.is_occupied());
slot.remove();
removed_slots_++;
diff --git a/source/blender/blenlib/BLI_stack.hh b/source/blender/blenlib/BLI_stack.hh
index a06515a7781..ed123f43a6b 100644
--- a/source/blender/blenlib/BLI_stack.hh
+++ b/source/blender/blenlib/BLI_stack.hh
@@ -96,7 +96,7 @@ class Stack {
int64_t size_;
/** The buffer used to implement small object optimization. */
- TypedBuffer<T, InlineBufferCapacity> inline_buffer_;
+ BLI_NO_UNIQUE_ADDRESS TypedBuffer<T, InlineBufferCapacity> inline_buffer_;
/**
* A chunk referencing the inline buffer. This is always the bottom-most chunk.
@@ -105,7 +105,7 @@ class Stack {
Chunk inline_chunk_;
/** Used for allocations when the inline buffer is not large enough. */
- Allocator allocator_;
+ BLI_NO_UNIQUE_ADDRESS Allocator allocator_;
public:
/**
diff --git a/source/blender/blenlib/BLI_string.h b/source/blender/blenlib/BLI_string.h
index 45abac33795..15926e8f2d2 100644
--- a/source/blender/blenlib/BLI_string.h
+++ b/source/blender/blenlib/BLI_string.h
@@ -307,7 +307,7 @@ void BLI_str_format_byte_unit(char dst[15], long long int bytes, bool base_10) A
*
* Length of 7 is the maximum of the resulting string, for example, `-15.5K\0`.
*/
-void BLI_str_format_attribute_domain_size(char dst[7], int number_to_format) ATTR_NONNULL();
+void BLI_str_format_decimal_unit(char dst[7], int number_to_format) ATTR_NONNULL();
/**
* Compare two strings without regard to case.
*
@@ -343,8 +343,16 @@ int BLI_strcmp_ignore_pad(const char *str1, const char *str2, char pad) ATTR_WAR
*/
size_t BLI_strnlen(const char *str, size_t maxlen) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
+/**
+ * String case conversion, not affected by locale.
+ */
+
void BLI_str_tolower_ascii(char *str, size_t len) ATTR_NONNULL();
void BLI_str_toupper_ascii(char *str, size_t len) ATTR_NONNULL();
+
+char BLI_tolower_ascii(const char c);
+char BLI_toupper_ascii(const char c);
+
/**
* Strip white-space from end of the string.
*/
diff --git a/source/blender/blenlib/BLI_task.hh b/source/blender/blenlib/BLI_task.hh
index d87a86ce696..904dea66f7a 100644
--- a/source/blender/blenlib/BLI_task.hh
+++ b/source/blender/blenlib/BLI_task.hh
@@ -77,17 +77,19 @@ Value parallel_reduce(IndexRange range,
const Reduction &reduction)
{
#ifdef WITH_TBB
- return tbb::parallel_reduce(
- tbb::blocked_range<int64_t>(range.first(), range.one_after_last(), grain_size),
- identity,
- [&](const tbb::blocked_range<int64_t> &subrange, const Value &ident) {
- return function(IndexRange(subrange.begin(), subrange.size()), ident);
- },
- reduction);
+ if (range.size() >= grain_size) {
+ return tbb::parallel_reduce(
+ tbb::blocked_range<int64_t>(range.first(), range.one_after_last(), grain_size),
+ identity,
+ [&](const tbb::blocked_range<int64_t> &subrange, const Value &ident) {
+ return function(IndexRange(subrange.begin(), subrange.size()), ident);
+ },
+ reduction);
+ }
#else
UNUSED_VARS(grain_size, reduction);
- return function(range, identity);
#endif
+ return function(range, identity);
}
/**
diff --git a/source/blender/blenlib/BLI_utildefines.h b/source/blender/blenlib/BLI_utildefines.h
index b8407a5453f..7f9470a9111 100644
--- a/source/blender/blenlib/BLI_utildefines.h
+++ b/source/blender/blenlib/BLI_utildefines.h
@@ -843,6 +843,18 @@ extern bool BLI_memory_is_zero(const void *arr, size_t arr_size);
*/
#define BLI_ENABLE_IF(condition) typename std::enable_if_t<(condition)> * = nullptr
+#if defined(_MSC_VER)
+# define BLI_NO_UNIQUE_ADDRESS [[msvc::no_unique_address]]
+#elif defined(__has_cpp_attribute)
+# if __has_cpp_attribute(no_unique_address)
+# define BLI_NO_UNIQUE_ADDRESS [[no_unique_address]]
+# else
+# define BLI_NO_UNIQUE_ADDRESS
+# endif
+#else
+# define BLI_NO_UNIQUE_ADDRESS [[no_unique_address]]
+#endif
+
/** \} */
#ifdef __cplusplus
diff --git a/source/blender/blenlib/BLI_utildefines_iter.h b/source/blender/blenlib/BLI_utildefines_iter.h
index 870e90bd971..03dc775a66b 100644
--- a/source/blender/blenlib/BLI_utildefines_iter.h
+++ b/source/blender/blenlib/BLI_utildefines_iter.h
@@ -21,7 +21,7 @@
* (100, 3) -> [16, 49, 83]
* (100, 100) -> [0..99]
* </pre>
- * \note this is mainly useful for numbers that might not divide evenly into eachother.
+ * \note this is mainly useful for numbers that might not divide evenly into each other.
*/
#define BLI_FOREACH_SPARSE_RANGE(src, dst, i) \
for (int _src = (src), _src2 = _src * 2, _dst2 = (dst)*2, _error = _dst2 - _src, i = 0, _delta; \
diff --git a/source/blender/blenlib/BLI_vector.hh b/source/blender/blenlib/BLI_vector.hh
index acf47f67168..c23d846d277 100644
--- a/source/blender/blenlib/BLI_vector.hh
+++ b/source/blender/blenlib/BLI_vector.hh
@@ -84,10 +84,10 @@ class Vector {
T *capacity_end_;
/** Used for allocations when the inline buffer is too small. */
- Allocator allocator_;
+ BLI_NO_UNIQUE_ADDRESS Allocator allocator_;
/** A placeholder buffer that will remain uninitialized until it is used. */
- TypedBuffer<T, InlineBufferCapacity> inline_buffer_;
+ BLI_NO_UNIQUE_ADDRESS TypedBuffer<T, InlineBufferCapacity> inline_buffer_;
/**
* Store the size of the vector explicitly in debug builds. Otherwise you'd always have to call
diff --git a/source/blender/blenlib/BLI_vector_set.hh b/source/blender/blenlib/BLI_vector_set.hh
index 4ae1bf9000d..b0a3696f245 100644
--- a/source/blender/blenlib/BLI_vector_set.hh
+++ b/source/blender/blenlib/BLI_vector_set.hh
@@ -117,10 +117,10 @@ class VectorSet {
uint64_t slot_mask_;
/** This is called to hash incoming keys. */
- Hash hash_;
+ BLI_NO_UNIQUE_ADDRESS Hash hash_;
/** This is called to check equality of two keys. */
- IsEqual is_equal_;
+ BLI_NO_UNIQUE_ADDRESS IsEqual is_equal_;
/** The max load factor is 1/2 = 50% by default. */
#define LOAD_FACTOR 1, 2
diff --git a/source/blender/blenlib/BLI_virtual_array.hh b/source/blender/blenlib/BLI_virtual_array.hh
index 7aa221f62ce..8f228ea188e 100644
--- a/source/blender/blenlib/BLI_virtual_array.hh
+++ b/source/blender/blenlib/BLI_virtual_array.hh
@@ -463,7 +463,7 @@ template<typename T, typename GetFunc> class VArrayImpl_For_Func final : public
};
/**
- * \note: This is `final` so that #may_have_ownership can be implemented reliably.
+ * \note This is `final` so that #may_have_ownership can be implemented reliably.
*/
template<typename StructT,
typename ElemT,
@@ -725,7 +725,7 @@ template<typename T> class VArrayCommon {
/**
* Get the element at a specific index.
- * \note: This can't return a reference because the value may be computed on the fly. This also
+ * \note This can't return a reference because the value may be computed on the fly. This also
* implies that one can not use this method for assignments.
*/
T operator[](const int64_t index) const
@@ -872,6 +872,22 @@ template<typename T> class VArrayCommon {
template<typename T> class VMutableArray;
/**
+ * Various tags to disambiguate constructors of virtual arrays.
+ * Generally it is easier to use `VArray::For*` functions to construct virtual arrays, but
+ * sometimes being able to use the constructor can result in better performance For example, when
+ * constructing the virtual array directly in a vector. Without the constructor one would have to
+ * construct the virtual array first and then move it into the vector.
+ */
+namespace varray_tag {
+struct span {
+};
+struct single_ref {
+};
+struct single {
+};
+} // namespace varray_tag
+
+/**
* A #VArray wraps a virtual array implementation and provides easy access to its elements. It can
* be copied and moved. While it is relatively small, it should still be passed by reference if
* possible (other than e.g. #Span).
@@ -892,6 +908,19 @@ template<typename T> class VArray : public VArrayCommon<T> {
{
}
+ VArray(varray_tag::span /* tag */, Span<T> span)
+ {
+ /* Cast const away, because the virtual array implementation for const and non const spans is
+ * shared. */
+ MutableSpan<T> mutable_span{const_cast<T *>(span.data()), span.size()};
+ this->template emplace<VArrayImpl_For_Span_final<T>>(mutable_span);
+ }
+
+ VArray(varray_tag::single /* tag */, T value, const int64_t size)
+ {
+ this->template emplace<VArrayImpl_For_Single<T>>(std::move(value), size);
+ }
+
/**
* Construct a new virtual array for a custom #VArrayImpl.
*/
@@ -908,7 +937,7 @@ template<typename T> class VArray : public VArrayCommon<T> {
*/
static VArray ForSingle(T value, const int64_t size)
{
- return VArray::For<VArrayImpl_For_Single<T>>(std::move(value), size);
+ return VArray(varray_tag::single{}, std::move(value), size);
}
/**
@@ -917,10 +946,7 @@ template<typename T> class VArray : public VArrayCommon<T> {
*/
static VArray ForSpan(Span<T> values)
{
- /* Cast const away, because the virtual array implementation for const and non const spans is
- * shared. */
- MutableSpan<T> span{const_cast<T *>(values.data()), values.size()};
- return VArray::For<VArrayImpl_For_Span_final<T>>(span);
+ return VArray(varray_tag::span{}, values);
}
/**
@@ -1112,6 +1138,8 @@ template<typename T> class VArray_Span final : public Span<T> {
Array<T> owned_data_;
public:
+ VArray_Span() = default;
+
VArray_Span(VArray<T> varray) : Span<T>(), varray_(std::move(varray))
{
this->size_ = varray_.size();
@@ -1125,6 +1153,30 @@ template<typename T> class VArray_Span final : public Span<T> {
this->data_ = owned_data_.data();
}
}
+
+ VArray_Span(VArray_Span &&other)
+ : varray_(std::move(other.varray_)), owned_data_(std::move(other.owned_data_))
+ {
+ this->size_ = varray_.size();
+ if (varray_.is_span()) {
+ this->data_ = varray_.get_internal_span().data();
+ }
+ else {
+ this->data_ = owned_data_.data();
+ }
+ other.data_ = nullptr;
+ other.size_ = 0;
+ }
+
+ VArray_Span &operator=(VArray_Span &&other)
+ {
+ if (this == &other) {
+ return *this;
+ }
+ std::destroy_at(this);
+ new (this) VArray_Span(std::move(other));
+ return *this;
+ }
};
/**
diff --git a/source/blender/blenlib/CMakeLists.txt b/source/blender/blenlib/CMakeLists.txt
index 4e76ae3e855..95b4987596e 100644
--- a/source/blender/blenlib/CMakeLists.txt
+++ b/source/blender/blenlib/CMakeLists.txt
@@ -199,6 +199,7 @@ set(SRC
BLI_fileops.hh
BLI_fileops_types.h
BLI_filereader.h
+ BLI_float3x3.hh
BLI_float4x4.hh
BLI_fnmatch.h
BLI_function_ref.hh
@@ -431,6 +432,7 @@ if(WITH_GTESTS)
tests/BLI_edgehash_test.cc
tests/BLI_expr_pylike_eval_test.cc
tests/BLI_fileops_test.cc
+ tests/BLI_float3x3_test.cc
tests/BLI_function_ref_test.cc
tests/BLI_generic_array_test.cc
tests/BLI_generic_span_test.cc
@@ -443,6 +445,7 @@ if(WITH_GTESTS)
tests/BLI_index_range_test.cc
tests/BLI_inplace_priority_queue_test.cc
tests/BLI_kdopbvh_test.cc
+ tests/BLI_kdtree_test.cc
tests/BLI_length_parameterize_test.cc
tests/BLI_linear_allocator_test.cc
tests/BLI_linklist_lockfree_test.cc
diff --git a/source/blender/blenlib/intern/BLI_assert.c b/source/blender/blenlib/intern/BLI_assert.c
index 2ebeba43dbe..96c16b47214 100644
--- a/source/blender/blenlib/intern/BLI_assert.c
+++ b/source/blender/blenlib/intern/BLI_assert.c
@@ -40,7 +40,7 @@ void _BLI_assert_abort(void)
/* Wrap to remove 'noreturn' attribute since this suppresses missing return statements,
* allowing changes to debug builds to accidentally to break release builds.
*
- * For example `BLI_assert(0);` at the end of a function that returns a value,
+ * For example `BLI_assert_unreachable();` at the end of a function that returns a value,
* will hide that it's missing a return. */
abort();
diff --git a/source/blender/blenlib/intern/BLI_filelist.c b/source/blender/blenlib/intern/BLI_filelist.c
index 76fc5b6342a..c6178ebb3a0 100644
--- a/source/blender/blenlib/intern/BLI_filelist.c
+++ b/source/blender/blenlib/intern/BLI_filelist.c
@@ -237,7 +237,7 @@ unsigned int BLI_filelist_dir_contents(const char *dirname, struct direntry **r_
}
void BLI_filelist_entry_size_to_string(const struct stat *st,
- const uint64_t sz,
+ const uint64_t st_size_fallback,
/* Used to change MB -> M, etc. - is that really useful? */
const bool UNUSED(compact),
char r_size[FILELIST_DIRENTRY_SIZE_LEN])
@@ -247,7 +247,7 @@ void BLI_filelist_entry_size_to_string(const struct stat *st,
* will buy us some time until files get bigger than 4GB or until
* everyone starts using __USE_FILE_OFFSET64 or equivalent.
*/
- double size = (double)(st ? st->st_size : sz);
+ double size = (double)(st ? st->st_size : st_size_fallback);
#ifdef WIN32
BLI_str_format_byte_unit(r_size, size, false);
#else
diff --git a/source/blender/blenlib/intern/BLI_ghash.c b/source/blender/blenlib/intern/BLI_ghash.c
index 57e05233efa..e6ff5bab8a1 100644
--- a/source/blender/blenlib/intern/BLI_ghash.c
+++ b/source/blender/blenlib/intern/BLI_ghash.c
@@ -173,7 +173,7 @@ BLI_INLINE uint ghash_find_next_bucket_index(const GHash *gh, uint curr_bucket)
return curr_bucket;
}
}
- BLI_assert(0);
+ BLI_assert_unreachable();
return 0;
}
diff --git a/source/blender/blenlib/intern/BLI_kdopbvh.c b/source/blender/blenlib/intern/BLI_kdopbvh.c
index 0f52c84c45e..62bf17bd415 100644
--- a/source/blender/blenlib/intern/BLI_kdopbvh.c
+++ b/source/blender/blenlib/intern/BLI_kdopbvh.c
@@ -893,7 +893,7 @@ BVHTree *BLI_bvhtree_new(int maxsize, float epsilon, char tree_type, char axis)
}
else {
/* should never happen! */
- BLI_assert(0);
+ BLI_assert_unreachable();
goto fail;
}
diff --git a/source/blender/blenlib/intern/array_utils.c b/source/blender/blenlib/intern/array_utils.c
index f1f1dd60ddf..a401059755d 100644
--- a/source/blender/blenlib/intern/array_utils.c
+++ b/source/blender/blenlib/intern/array_utils.c
@@ -53,7 +53,7 @@ void _bli_array_wrap(void *arr_v, uint arr_len, size_t arr_stride, int dir)
memcpy(arr, buf, arr_stride);
}
else {
- BLI_assert(0);
+ BLI_assert_unreachable();
}
}
diff --git a/source/blender/blenlib/intern/delaunay_2d.cc b/source/blender/blenlib/intern/delaunay_2d.cc
index ece22bcf82e..db6cb0824dc 100644
--- a/source/blender/blenlib/intern/delaunay_2d.cc
+++ b/source/blender/blenlib/intern/delaunay_2d.cc
@@ -2637,6 +2637,7 @@ void prepare_cdt_for_output(CDT_state<T> *cdt_state, const CDT_output_type outpu
remove_faces_in_holes(cdt_state);
}
else if (output_type == CDT_CONSTRAINTS_VALID_BMESH_WITH_HOLES) {
+ remove_outer_edges_until_constraints(cdt_state);
remove_non_constraint_edges_leave_valid_bmesh(cdt_state);
remove_faces_in_holes(cdt_state);
}
diff --git a/source/blender/blenlib/intern/fileops.c b/source/blender/blenlib/intern/fileops.c
index 5ca6fe2efd0..3abd482d6b3 100644
--- a/source/blender/blenlib/intern/fileops.c
+++ b/source/blender/blenlib/intern/fileops.c
@@ -164,10 +164,10 @@ bool BLI_file_magic_is_zstd(const char header[4])
return false;
}
-bool BLI_file_is_writable(const char *filename)
+bool BLI_file_is_writable(const char *filepath)
{
bool writable;
- if (BLI_access(filename, W_OK) == 0) {
+ if (BLI_access(filepath, W_OK) == 0) {
/* file exists and I can write to it */
writable = true;
}
@@ -178,7 +178,7 @@ bool BLI_file_is_writable(const char *filename)
else {
/* file doesn't exist -- check I can create it in parent directory */
char parent[FILE_MAX];
- BLI_split_dirfile(filename, parent, NULL, sizeof(parent), 0);
+ BLI_split_dirfile(filepath, parent, NULL, sizeof(parent), 0);
#ifdef WIN32
/* windows does not have X_OK */
writable = BLI_access(parent, W_OK) == 0;
@@ -224,38 +224,38 @@ static void callLocalErrorCallBack(const char *err)
printf("%s\n", err);
}
-FILE *BLI_fopen(const char *filename, const char *mode)
+FILE *BLI_fopen(const char *filepath, const char *mode)
{
- BLI_assert(!BLI_path_is_rel(filename));
+ BLI_assert(!BLI_path_is_rel(filepath));
- return ufopen(filename, mode);
+ return ufopen(filepath, mode);
}
-void BLI_get_short_name(char short_name[256], const char *filename)
+void BLI_get_short_name(char short_name[256], const char *filepath)
{
wchar_t short_name_16[256];
int i = 0;
- UTF16_ENCODE(filename);
+ UTF16_ENCODE(filepath);
- GetShortPathNameW(filename_16, short_name_16, 256);
+ GetShortPathNameW(filepath_16, short_name_16, 256);
for (i = 0; i < 256; i++) {
short_name[i] = (char)short_name_16[i];
}
- UTF16_UN_ENCODE(filename);
+ UTF16_UN_ENCODE(filepath);
}
-void *BLI_gzopen(const char *filename, const char *mode)
+void *BLI_gzopen(const char *filepath, const char *mode)
{
gzFile gzfile;
- BLI_assert(!BLI_path_is_rel(filename));
+ BLI_assert(!BLI_path_is_rel(filepath));
/* XXX: Creates file before transcribing the path. */
if (mode[0] == 'w') {
- FILE *file = ufopen(filename, "a");
+ FILE *file = ufopen(filepath, "a");
if (file == NULL) {
/* File couldn't be opened, e.g. due to permission error. */
return NULL;
@@ -266,15 +266,15 @@ void *BLI_gzopen(const char *filename, const char *mode)
/* temporary #if until we update all libraries to 1.2.7
* for correct wide char path handling */
# if ZLIB_VERNUM >= 0x1270
- UTF16_ENCODE(filename);
+ UTF16_ENCODE(filepath);
- gzfile = gzopen_w(filename_16, mode);
+ gzfile = gzopen_w(filepath_16, mode);
- UTF16_UN_ENCODE(filename);
+ UTF16_UN_ENCODE(filepath);
# else
{
char short_name[256];
- BLI_get_short_name(short_name, filename);
+ BLI_get_short_name(short_name, filepath);
gzfile = gzopen(short_name, mode);
}
# endif
@@ -282,18 +282,18 @@ void *BLI_gzopen(const char *filename, const char *mode)
return gzfile;
}
-int BLI_open(const char *filename, int oflag, int pmode)
+int BLI_open(const char *filepath, int oflag, int pmode)
{
- BLI_assert(!BLI_path_is_rel(filename));
+ BLI_assert(!BLI_path_is_rel(filepath));
- return uopen(filename, oflag, pmode);
+ return uopen(filepath, oflag, pmode);
}
-int BLI_access(const char *filename, int mode)
+int BLI_access(const char *filepath, int mode)
{
- BLI_assert(!BLI_path_is_rel(filename));
+ BLI_assert(!BLI_path_is_rel(filepath));
- return uaccess(filename, mode);
+ return uaccess(filepath, mode);
}
static bool delete_soft(const wchar_t *path_16, const char **error_message)
@@ -466,8 +466,8 @@ int BLI_move(const char *file, const char *to)
int err;
/* windows doesn't support moving to a directory
- * it has to be 'mv filename filename' and not
- * 'mv filename destination_directory' */
+ * it has to be 'mv filepath filepath' and not
+ * 'mv filepath destination_directory' */
BLI_strncpy(str, to, sizeof(str));
/* points 'to' to a directory ? */
@@ -498,8 +498,8 @@ int BLI_copy(const char *file, const char *to)
int err;
/* windows doesn't support copying to a directory
- * it has to be 'cp filename filename' and not
- * 'cp filename destdir' */
+ * it has to be 'cp filepath filepath' and not
+ * 'cp filepath destdir' */
BLI_strncpy(str, to, sizeof(str));
/* points 'to' to a directory ? */
@@ -587,7 +587,7 @@ int BLI_rename(const char *from, const char *to)
return 0;
}
- /* make sure the filenames are different (case insensitive) before removing */
+ /* Make sure `from` & `to` are different (case insensitive) before removing. */
if (BLI_exists(to) && BLI_strcasecmp(from, to)) {
if (BLI_delete(to, false, false)) {
return 1;
@@ -728,9 +728,9 @@ static int recursive_operation(const char *startfrom,
# ifdef __HAIKU__
{
struct stat st_dir;
- char filename[FILE_MAX];
- BLI_path_join(filename, sizeof(filename), startfrom, dirent->d_name, NULL);
- lstat(filename, &st_dir);
+ char filepath[FILE_MAX];
+ BLI_path_join(filepath, sizeof(filepath), startfrom, dirent->d_name, NULL);
+ lstat(filepath, &st_dir);
is_dir = S_ISDIR(st_dir.st_mode);
}
# else
@@ -903,32 +903,32 @@ static int delete_soft(const char *file, const char **error_message)
}
# endif
-FILE *BLI_fopen(const char *filename, const char *mode)
+FILE *BLI_fopen(const char *filepath, const char *mode)
{
- BLI_assert(!BLI_path_is_rel(filename));
+ BLI_assert(!BLI_path_is_rel(filepath));
- return fopen(filename, mode);
+ return fopen(filepath, mode);
}
-void *BLI_gzopen(const char *filename, const char *mode)
+void *BLI_gzopen(const char *filepath, const char *mode)
{
- BLI_assert(!BLI_path_is_rel(filename));
+ BLI_assert(!BLI_path_is_rel(filepath));
- return gzopen(filename, mode);
+ return gzopen(filepath, mode);
}
-int BLI_open(const char *filename, int oflag, int pmode)
+int BLI_open(const char *filepath, int oflag, int pmode)
{
- BLI_assert(!BLI_path_is_rel(filename));
+ BLI_assert(!BLI_path_is_rel(filepath));
- return open(filename, oflag, pmode);
+ return open(filepath, oflag, pmode);
}
-int BLI_access(const char *filename, int mode)
+int BLI_access(const char *filepath, int mode)
{
- BLI_assert(!BLI_path_is_rel(filename));
+ BLI_assert(!BLI_path_is_rel(filepath));
- return access(filename, mode);
+ return access(filepath, mode);
}
int BLI_delete(const char *file, bool dir, bool recursive)
diff --git a/source/blender/blenlib/intern/generic_virtual_array.cc b/source/blender/blenlib/intern/generic_virtual_array.cc
index a3a17952a97..a6fbf4bff5b 100644
--- a/source/blender/blenlib/intern/generic_virtual_array.cc
+++ b/source/blender/blenlib/intern/generic_virtual_array.cc
@@ -85,11 +85,6 @@ bool GVArrayImpl::may_have_ownership() const
/** \name #GVMutableArrayImpl
* \{ */
-GVMutableArrayImpl::GVMutableArrayImpl(const CPPType &type, const int64_t size)
- : GVArrayImpl(type, size)
-{
-}
-
void GVMutableArrayImpl::set_by_copy(const int64_t index, const void *value)
{
BUFFER_FOR_CPP_TYPE_VALUE(*type_, buffer);
@@ -141,18 +136,6 @@ bool GVMutableArrayImpl::try_assign_VMutableArray(void *UNUSED(varray)) const
/** \name #GVArrayImpl_For_GSpan
* \{ */
-GVArrayImpl_For_GSpan::GVArrayImpl_For_GSpan(const GMutableSpan span)
- : GVMutableArrayImpl(span.type(), span.size()),
- data_(span.data()),
- element_size_(span.type().size())
-{
-}
-
-GVArrayImpl_For_GSpan::GVArrayImpl_For_GSpan(const CPPType &type, const int64_t size)
- : GVMutableArrayImpl(type, size), element_size_(type.size())
-{
-}
-
void GVArrayImpl_For_GSpan::get(const int64_t index, void *r_value) const
{
type_->copy_assign(POINTER_OFFSET(data_, element_size_ * index), r_value);
@@ -209,17 +192,6 @@ void GVArrayImpl_For_GSpan::materialize_compressed_to_uninitialized(const IndexM
type_->copy_construct_compressed(data_, dst, mask);
}
-class GVArrayImpl_For_GSpan_final final : public GVArrayImpl_For_GSpan {
- public:
- using GVArrayImpl_For_GSpan::GVArrayImpl_For_GSpan;
-
- private:
- bool may_have_ownership() const override
- {
- return false;
- }
-};
-
/** \} */
/* -------------------------------------------------------------------- */
@@ -227,79 +199,56 @@ class GVArrayImpl_For_GSpan_final final : public GVArrayImpl_For_GSpan {
* \{ */
/* Generic virtual array where each element has the same value. The value is not owned. */
-class GVArrayImpl_For_SingleValueRef : public GVArrayImpl {
- protected:
- const void *value_ = nullptr;
- public:
- GVArrayImpl_For_SingleValueRef(const CPPType &type, const int64_t size, const void *value)
- : GVArrayImpl(type, size), value_(value)
- {
- }
-
- protected:
- GVArrayImpl_For_SingleValueRef(const CPPType &type, const int64_t size) : GVArrayImpl(type, size)
- {
- }
-
- void get(const int64_t UNUSED(index), void *r_value) const override
- {
- type_->copy_assign(value_, r_value);
- }
- void get_to_uninitialized(const int64_t UNUSED(index), void *r_value) const override
- {
- type_->copy_construct(value_, r_value);
- }
-
- bool is_span() const override
- {
- return size_ == 1;
- }
- GSpan get_internal_span() const override
- {
- return GSpan{*type_, value_, 1};
- }
-
- bool is_single() const override
- {
- return true;
- }
- void get_internal_single(void *r_value) const override
- {
- type_->copy_assign(value_, r_value);
- }
+void GVArrayImpl_For_SingleValueRef::get(const int64_t UNUSED(index), void *r_value) const
+{
+ type_->copy_assign(value_, r_value);
+}
+void GVArrayImpl_For_SingleValueRef::get_to_uninitialized(const int64_t UNUSED(index),
+ void *r_value) const
+{
+ type_->copy_construct(value_, r_value);
+}
- void materialize(const IndexMask mask, void *dst) const override
- {
- type_->fill_assign_indices(value_, dst, mask);
- }
+bool GVArrayImpl_For_SingleValueRef::is_span() const
+{
+ return size_ == 1;
+}
+GSpan GVArrayImpl_For_SingleValueRef::get_internal_span() const
+{
+ return GSpan{*type_, value_, 1};
+}
- void materialize_to_uninitialized(const IndexMask mask, void *dst) const override
- {
- type_->fill_construct_indices(value_, dst, mask);
- }
+bool GVArrayImpl_For_SingleValueRef::is_single() const
+{
+ return true;
+}
+void GVArrayImpl_For_SingleValueRef::get_internal_single(void *r_value) const
+{
+ type_->copy_assign(value_, r_value);
+}
- void materialize_compressed(const IndexMask mask, void *dst) const override
- {
- type_->fill_assign_n(value_, dst, mask.size());
- }
+void GVArrayImpl_For_SingleValueRef::materialize(const IndexMask mask, void *dst) const
+{
+ type_->fill_assign_indices(value_, dst, mask);
+}
- void materialize_compressed_to_uninitialized(const IndexMask mask, void *dst) const override
- {
- type_->fill_construct_n(value_, dst, mask.size());
- }
-};
+void GVArrayImpl_For_SingleValueRef::materialize_to_uninitialized(const IndexMask mask,
+ void *dst) const
+{
+ type_->fill_construct_indices(value_, dst, mask);
+}
-class GVArrayImpl_For_SingleValueRef_final final : public GVArrayImpl_For_SingleValueRef {
- public:
- using GVArrayImpl_For_SingleValueRef::GVArrayImpl_For_SingleValueRef;
+void GVArrayImpl_For_SingleValueRef::materialize_compressed(const IndexMask mask, void *dst) const
+{
+ type_->fill_assign_n(value_, dst, mask.size());
+}
- private:
- bool may_have_ownership() const override
- {
- return false;
- }
-};
+void GVArrayImpl_For_SingleValueRef::materialize_compressed_to_uninitialized(const IndexMask mask,
+ void *dst) const
+{
+ type_->fill_construct_n(value_, dst, mask.size());
+}
/** \} */
@@ -529,8 +478,6 @@ class GVArrayImpl_For_SlicedGVArray : public GVArrayImpl {
/** \name #GVArrayCommon
* \{ */
-GVArrayCommon::GVArrayCommon() = default;
-
GVArrayCommon::GVArrayCommon(const GVArrayCommon &other) : storage_(other.storage_)
{
impl_ = this->impl_from_storage();
@@ -672,17 +619,27 @@ GVArray::GVArray(std::shared_ptr<const GVArrayImpl> impl) : GVArrayCommon(std::m
{
}
-GVArray GVArray::ForSingle(const CPPType &type, const int64_t size, const void *value)
+GVArray::GVArray(varray_tag::single /* tag */,
+ const CPPType &type,
+ int64_t size,
+ const void *value)
{
if (type.is_trivial() && type.size() <= 16 && type.alignment() <= 8) {
- return GVArray::For<GVArrayImpl_For_SmallTrivialSingleValue<16>>(type, size, value);
+ this->emplace<GVArrayImpl_For_SmallTrivialSingleValue<16>>(type, size, value);
}
- return GVArray::For<GVArrayImpl_For_SingleValue>(type, size, value);
+ else {
+ this->emplace<GVArrayImpl_For_SingleValue>(type, size, value);
+ }
+}
+
+GVArray GVArray::ForSingle(const CPPType &type, const int64_t size, const void *value)
+{
+ return GVArray(varray_tag::single{}, type, size, value);
}
GVArray GVArray::ForSingleRef(const CPPType &type, const int64_t size, const void *value)
{
- return GVArray::For<GVArrayImpl_For_SingleValueRef_final>(type, size, value);
+ return GVArray(varray_tag::single_ref{}, type, size, value);
}
GVArray GVArray::ForSingleDefault(const CPPType &type, const int64_t size)
@@ -692,10 +649,7 @@ GVArray GVArray::ForSingleDefault(const CPPType &type, const int64_t size)
GVArray GVArray::ForSpan(GSpan span)
{
- /* Use const-cast because the underlying virtual array implementation is shared between const
- * and non const data. */
- GMutableSpan mutable_span{span.type(), const_cast<void *>(span.data()), span.size()};
- return GVArray::For<GVArrayImpl_For_GSpan_final>(mutable_span);
+ return GVArray(varray_tag::span{}, span);
}
class GVArrayImpl_For_GArray : public GVArrayImpl_For_GSpan {
diff --git a/source/blender/blenlib/intern/hash_md5.c b/source/blender/blenlib/intern/hash_md5.c
index cc59662b6de..d57f859eb1b 100644
--- a/source/blender/blenlib/intern/hash_md5.c
+++ b/source/blender/blenlib/intern/hash_md5.c
@@ -143,7 +143,7 @@ static void md5_process_block(const void *buffer, size_t len, struct md5_ctx *ct
(void)0
/* Before we start, one word to the strange constants. They are defined in RFC 1321 as:
- * T[i] = (int) (4294967296.0 * fabs (sin (i))), i=1..64
+ * `T[i] = (int) (4294967296.0 * fabs (sin (i))), i=1..64`
*/
/* Round 1. */
@@ -271,7 +271,7 @@ static void *md5_read_ctx(const struct md5_ctx *ctx, void *resbuf)
int BLI_hash_md5_stream(FILE *stream, void *resblock)
{
-#define BLOCKSIZE 4096 /* Important: must be a multiple of 64. */
+#define BLOCKSIZE 4096 /* IMPORTANT: must be a multiple of 64. */
struct md5_ctx ctx;
md5_uint32 len[2];
char buffer[BLOCKSIZE + 72];
@@ -315,7 +315,7 @@ int BLI_hash_md5_stream(FILE *stream, void *resblock)
break;
}
- /* Process buffer with BLOCKSIZE bytes. Note that BLOCKSIZE % 64 == 0. */
+ /* Process buffer with BLOCKSIZE bytes. Note that `BLOCKSIZE % 64 == 0`. */
md5_process_block(buffer, BLOCKSIZE, &ctx);
}
@@ -323,7 +323,7 @@ int BLI_hash_md5_stream(FILE *stream, void *resblock)
* 'fillbuf' contains the needed bits. */
memcpy(&buffer[sum], fillbuf, 64);
- /* Compute amount of padding bytes needed. Alignment is done to (N + PAD) % 64 == 56.
+ /* Compute amount of padding bytes needed. Alignment is done to `(N + PAD) % 64 == 56`.
* There is always at least one byte padded, i.e. if the alignment is correctly aligned,
* 64 padding bytes are added.
*/
diff --git a/source/blender/blenlib/intern/kdtree_impl.h b/source/blender/blenlib/intern/kdtree_impl.h
index d9ae826093c..6614f1bf964 100644
--- a/source/blender/blenlib/intern/kdtree_impl.h
+++ b/source/blender/blenlib/intern/kdtree_impl.h
@@ -927,6 +927,14 @@ int BLI_kdtree_nd_(calc_duplicates_fast)(const KDTree *tree,
/** \name BLI_kdtree_3d_deduplicate
* \{ */
+static int kdtree_cmp_bool(const bool a, const bool b)
+{
+ if (a == b) {
+ return 0;
+ }
+ return b ? -1 : 1;
+}
+
static int kdtree_node_cmp_deduplicate(const void *n0_p, const void *n1_p)
{
const KDTreeNode *n0 = n0_p;
@@ -939,17 +947,16 @@ static int kdtree_node_cmp_deduplicate(const void *n0_p, const void *n1_p)
return 1;
}
}
- /* Sort by pointer so the first added will be used.
- * assignment below ignores const correctness,
- * however the values aren't used for sorting and are to be discarded. */
- if (n0 < n1) {
- ((KDTreeNode *)n1)->d = KD_DIMS; /* tag invalid */
- return -1;
- }
- else {
- ((KDTreeNode *)n0)->d = KD_DIMS; /* tag invalid */
- return 1;
+
+ if (n0->d != KD_DIMS && n1->d != KD_DIMS) {
+ /* Two nodes share identical `co`
+ * Both are still valid.
+ * Cast away `const` and tag one of them as invalid. */
+ ((KDTreeNode *)n1)->d = KD_DIMS;
}
+
+ /* Keep sorting until each unique value has one and only one valid node. */
+ return kdtree_cmp_bool(n0->d == KD_DIMS, n1->d == KD_DIMS);
}
/**
diff --git a/source/blender/blenlib/intern/listbase.c b/source/blender/blenlib/intern/listbase.c
index e2044955e48..3932e5eb051 100644
--- a/source/blender/blenlib/intern/listbase.c
+++ b/source/blender/blenlib/intern/listbase.c
@@ -193,9 +193,19 @@ void BLI_listbases_swaplinks(ListBase *listbasea, ListBase *listbaseb, void *vli
return;
}
+ /* The reference to `linkc` assigns NULL, not a dangling pointer so it can be ignored. */
+#if defined(__GNUC__) && (__GNUC__ * 100 + __GNUC_MINOR__) >= 1201 /* gcc12.1+ only */
+# pragma GCC diagnostic push
+# pragma GCC diagnostic ignored "-Wdangling-pointer"
+#endif
+
/* Temporary link to use as placeholder of the links positions */
BLI_insertlinkafter(listbasea, linka, &linkc);
+#if defined(__GNUC__) && (__GNUC__ * 100 + __GNUC_MINOR__) >= 1201 /* gcc12.1+ only */
+# pragma GCC diagnostic pop
+#endif
+
/* Bring linka into linkb position */
BLI_remlink(listbasea, linka);
BLI_insertlinkafter(listbaseb, linkb, linka);
diff --git a/source/blender/blenlib/intern/math_base_inline.c b/source/blender/blenlib/intern/math_base_inline.c
index a983821f15e..4a213f5fe74 100644
--- a/source/blender/blenlib/intern/math_base_inline.c
+++ b/source/blender/blenlib/intern/math_base_inline.c
@@ -767,6 +767,20 @@ MALWAYS_INLINE __m128 _bli_math_fastpow24(const __m128 arg)
return _mm_mul_ps(x, _mm_mul_ps(x, x));
}
+MALWAYS_INLINE __m128 _bli_math_rsqrt(__m128 in)
+{
+ __m128 r = _mm_rsqrt_ps(in);
+ /* Only do additional Newton-Raphson iterations when using actual SSE
+ * code path. When we are emulating SSE on NEON via sse2neon, the
+ * additional NR iterations are already done inside _mm_rsqrt_ps
+ * emulation. */
+# if defined(__SSE2__)
+ r = _mm_add_ps(_mm_mul_ps(_mm_set1_ps(1.5f), r),
+ _mm_mul_ps(_mm_mul_ps(_mm_mul_ps(in, _mm_set1_ps(-0.5f)), r), _mm_mul_ps(r, r)));
+# endif
+ return r;
+}
+
/* Calculate powf(x, 1.0f / 2.4) */
MALWAYS_INLINE __m128 _bli_math_fastpow512(const __m128 arg)
{
@@ -776,14 +790,14 @@ MALWAYS_INLINE __m128 _bli_math_fastpow512(const __m128 arg)
*/
__m128 xf = _bli_math_fastpow(0x3f2aaaab, 0x5eb504f3, arg);
__m128 xover = _mm_mul_ps(arg, xf);
- __m128 xfm1 = _mm_rsqrt_ps(xf);
+ __m128 xfm1 = _bli_math_rsqrt(xf);
__m128 x2 = _mm_mul_ps(arg, arg);
__m128 xunder = _mm_mul_ps(x2, xfm1);
/* sqrt2 * over + 2 * sqrt2 * under */
__m128 xavg = _mm_mul_ps(_mm_set1_ps(1.0f / (3.0f * 0.629960524947437f) * 0.999852f),
_mm_add_ps(xover, xunder));
- xavg = _mm_mul_ps(xavg, _mm_rsqrt_ps(xavg));
- xavg = _mm_mul_ps(xavg, _mm_rsqrt_ps(xavg));
+ xavg = _mm_mul_ps(xavg, _bli_math_rsqrt(xavg));
+ xavg = _mm_mul_ps(xavg, _bli_math_rsqrt(xavg));
return xavg;
}
diff --git a/source/blender/blenlib/intern/math_color.c b/source/blender/blenlib/intern/math_color.c
index 07e9eaf0f42..bdcf52ec521 100644
--- a/source/blender/blenlib/intern/math_color.c
+++ b/source/blender/blenlib/intern/math_color.c
@@ -166,7 +166,7 @@ void ycc_to_rgb(float y, float cb, float cr, float *r_r, float *r_g, float *r_b,
b = y + 1.772f * cb - 226.816f;
break;
default:
- BLI_assert(0);
+ BLI_assert_unreachable();
break;
}
*r_r = r / 255.0f;
@@ -597,158 +597,3 @@ void BLI_init_srgb_conversion(void)
BLI_color_to_srgb_table[i] = (unsigned short)(b * 0x100);
}
}
-
-/* ****************************** blackbody ******************************** */
-
-/* Calculate color in range 800..12000 using an approximation
- * a/x+bx+c for R and G and ((at + b)t + c)t + d) for B
- * Max absolute error for RGB is (0.00095, 0.00077, 0.00057),
- * which is enough to get the same 8 bit/channel color.
- */
-
-static const float blackbody_table_r[6][3] = {
- {2.52432244e+03f, -1.06185848e-03f, 3.11067539e+00f},
- {3.37763626e+03f, -4.34581697e-04f, 1.64843306e+00f},
- {4.10671449e+03f, -8.61949938e-05f, 6.41423749e-01f},
- {4.66849800e+03f, 2.85655028e-05f, 1.29075375e-01f},
- {4.60124770e+03f, 2.89727618e-05f, 1.48001316e-01f},
- {3.78765709e+03f, 9.36026367e-06f, 3.98995841e-01f},
-};
-
-static const float blackbody_table_g[6][3] = {
- {-7.50343014e+02f, 3.15679613e-04f, 4.73464526e-01f},
- {-1.00402363e+03f, 1.29189794e-04f, 9.08181524e-01f},
- {-1.22075471e+03f, 2.56245413e-05f, 1.20753416e+00f},
- {-1.42546105e+03f, -4.01730887e-05f, 1.44002695e+00f},
- {-1.18134453e+03f, -2.18913373e-05f, 1.30656109e+00f},
- {-5.00279505e+02f, -4.59745390e-06f, 1.09090465e+00f},
-};
-
-static const float blackbody_table_b[6][4] = {
- {0.0f, 0.0f, 0.0f, 0.0f},
- {0.0f, 0.0f, 0.0f, 0.0f},
- {0.0f, 0.0f, 0.0f, 0.0f},
- {-2.02524603e-11f, 1.79435860e-07f, -2.60561875e-04f, -1.41761141e-02f},
- {-2.22463426e-13f, -1.55078698e-08f, 3.81675160e-04f, -7.30646033e-01f},
- {6.72595954e-13f, -2.73059993e-08f, 4.24068546e-04f, -7.52204323e-01f},
-};
-
-static void blackbody_temperature_to_rgb(float rgb[3], float t)
-{
- if (t >= 12000.0f) {
- rgb[0] = 0.826270103f;
- rgb[1] = 0.994478524f;
- rgb[2] = 1.56626022f;
- }
- else if (t < 965.0f) {
- rgb[0] = 4.70366907f;
- rgb[1] = 0.0f;
- rgb[2] = 0.0f;
- }
- else {
- int i = (t >= 6365.0f) ? 5 :
- (t >= 3315.0f) ? 4 :
- (t >= 1902.0f) ? 3 :
- (t >= 1449.0f) ? 2 :
- (t >= 1167.0f) ? 1 :
- 0;
-
- const float *r = blackbody_table_r[i];
- const float *g = blackbody_table_g[i];
- const float *b = blackbody_table_b[i];
-
- const float t_inv = 1.0f / t;
- rgb[0] = r[0] * t_inv + r[1] * t + r[2];
- rgb[1] = g[0] * t_inv + g[1] * t + g[2];
- rgb[2] = ((b[0] * t + b[1]) * t + b[2]) * t + b[3];
- }
-}
-
-void blackbody_temperature_to_rgb_table(float *r_table, int width, float min, float max)
-{
- for (int i = 0; i < width; i++) {
- float temperature = min + (max - min) / (float)width * (float)i;
-
- float rgb[3];
- blackbody_temperature_to_rgb(rgb, temperature);
-
- copy_v3_v3(&r_table[i * 4], rgb);
- r_table[i * 4 + 3] = 0.0f;
- }
-}
-
-/* ****************************** wavelength ******************************** */
-/* Wavelength to RGB. */
-
-/**
- * CIE color matching functions `xBar`, `yBar`, and `zBar` for
- * wavelengths from 380 through 780 nanometers, every 5 nanometers.
- *
- * For a wavelength lambda in this range:
- * \code{.txt}
- * cie_color_match[(lambda - 380) / 5][0] = xBar
- * cie_color_match[(lambda - 380) / 5][1] = yBar
- * cie_color_match[(lambda - 380) / 5][2] = zBar
- * \endcode
- */
-
-static float cie_colour_match[81][3] = {
- {0.0014f, 0.0000f, 0.0065f}, {0.0022f, 0.0001f, 0.0105f}, {0.0042f, 0.0001f, 0.0201f},
- {0.0076f, 0.0002f, 0.0362f}, {0.0143f, 0.0004f, 0.0679f}, {0.0232f, 0.0006f, 0.1102f},
- {0.0435f, 0.0012f, 0.2074f}, {0.0776f, 0.0022f, 0.3713f}, {0.1344f, 0.0040f, 0.6456f},
- {0.2148f, 0.0073f, 1.0391f}, {0.2839f, 0.0116f, 1.3856f}, {0.3285f, 0.0168f, 1.6230f},
- {0.3483f, 0.0230f, 1.7471f}, {0.3481f, 0.0298f, 1.7826f}, {0.3362f, 0.0380f, 1.7721f},
- {0.3187f, 0.0480f, 1.7441f}, {0.2908f, 0.0600f, 1.6692f}, {0.2511f, 0.0739f, 1.5281f},
- {0.1954f, 0.0910f, 1.2876f}, {0.1421f, 0.1126f, 1.0419f}, {0.0956f, 0.1390f, 0.8130f},
- {0.0580f, 0.1693f, 0.6162f}, {0.0320f, 0.2080f, 0.4652f}, {0.0147f, 0.2586f, 0.3533f},
- {0.0049f, 0.3230f, 0.2720f}, {0.0024f, 0.4073f, 0.2123f}, {0.0093f, 0.5030f, 0.1582f},
- {0.0291f, 0.6082f, 0.1117f}, {0.0633f, 0.7100f, 0.0782f}, {0.1096f, 0.7932f, 0.0573f},
- {0.1655f, 0.8620f, 0.0422f}, {0.2257f, 0.9149f, 0.0298f}, {0.2904f, 0.9540f, 0.0203f},
- {0.3597f, 0.9803f, 0.0134f}, {0.4334f, 0.9950f, 0.0087f}, {0.5121f, 1.0000f, 0.0057f},
- {0.5945f, 0.9950f, 0.0039f}, {0.6784f, 0.9786f, 0.0027f}, {0.7621f, 0.9520f, 0.0021f},
- {0.8425f, 0.9154f, 0.0018f}, {0.9163f, 0.8700f, 0.0017f}, {0.9786f, 0.8163f, 0.0014f},
- {1.0263f, 0.7570f, 0.0011f}, {1.0567f, 0.6949f, 0.0010f}, {1.0622f, 0.6310f, 0.0008f},
- {1.0456f, 0.5668f, 0.0006f}, {1.0026f, 0.5030f, 0.0003f}, {0.9384f, 0.4412f, 0.0002f},
- {0.8544f, 0.3810f, 0.0002f}, {0.7514f, 0.3210f, 0.0001f}, {0.6424f, 0.2650f, 0.0000f},
- {0.5419f, 0.2170f, 0.0000f}, {0.4479f, 0.1750f, 0.0000f}, {0.3608f, 0.1382f, 0.0000f},
- {0.2835f, 0.1070f, 0.0000f}, {0.2187f, 0.0816f, 0.0000f}, {0.1649f, 0.0610f, 0.0000f},
- {0.1212f, 0.0446f, 0.0000f}, {0.0874f, 0.0320f, 0.0000f}, {0.0636f, 0.0232f, 0.0000f},
- {0.0468f, 0.0170f, 0.0000f}, {0.0329f, 0.0119f, 0.0000f}, {0.0227f, 0.0082f, 0.0000f},
- {0.0158f, 0.0057f, 0.0000f}, {0.0114f, 0.0041f, 0.0000f}, {0.0081f, 0.0029f, 0.0000f},
- {0.0058f, 0.0021f, 0.0000f}, {0.0041f, 0.0015f, 0.0000f}, {0.0029f, 0.0010f, 0.0000f},
- {0.0020f, 0.0007f, 0.0000f}, {0.0014f, 0.0005f, 0.0000f}, {0.0010f, 0.0004f, 0.0000f},
- {0.0007f, 0.0002f, 0.0000f}, {0.0005f, 0.0002f, 0.0000f}, {0.0003f, 0.0001f, 0.0000f},
- {0.0002f, 0.0001f, 0.0000f}, {0.0002f, 0.0001f, 0.0000f}, {0.0001f, 0.0000f, 0.0000f},
- {0.0001f, 0.0000f, 0.0000f}, {0.0001f, 0.0000f, 0.0000f}, {0.0000f, 0.0000f, 0.0000f}};
-
-static void wavelength_to_xyz(float xyz[3], float lambda_nm)
-{
- float ii = (lambda_nm - 380.0f) * (1.0f / 5.0f); /* Scaled 0..80. */
- int i = (int)ii;
-
- if (i < 0 || i >= 80) {
- xyz[0] = 0.0f;
- xyz[1] = 0.0f;
- xyz[2] = 0.0f;
- }
- else {
- ii -= (float)i;
- const float *c = cie_colour_match[i];
- xyz[0] = c[0] + ii * (c[3] - c[0]);
- xyz[1] = c[1] + ii * (c[4] - c[1]);
- xyz[2] = c[2] + ii * (c[5] - c[2]);
- }
-}
-
-void wavelength_to_xyz_table(float *r_table, int width)
-{
- for (int i = 0; i < width; i++) {
- float temperature = 380 + 400 / (float)width * (float)i;
-
- float rgb[3];
- wavelength_to_xyz(rgb, temperature);
-
- copy_v3_v3(&r_table[i * 4], rgb);
- r_table[i * 4 + 3] = 0.0f;
- }
-}
diff --git a/source/blender/blenlib/intern/math_matrix.c b/source/blender/blenlib/intern/math_matrix.c
index f295734706f..ce9abc36cad 100644
--- a/source/blender/blenlib/intern/math_matrix.c
+++ b/source/blender/blenlib/intern/math_matrix.c
@@ -1496,7 +1496,7 @@ void orthogonalize_m3(float R[3][3], int axis)
}
break;
default:
- BLI_assert(0);
+ BLI_assert_unreachable();
break;
}
mul_v3_fl(R[0], size[0]);
@@ -1580,7 +1580,7 @@ void orthogonalize_m4(float R[4][4], int axis)
}
break;
default:
- BLI_assert(0);
+ BLI_assert_unreachable();
break;
}
mul_v3_fl(R[0], size[0]);
@@ -1654,7 +1654,7 @@ void orthogonalize_m3_stable(float R[3][3], int axis, bool normalize)
orthogonalize_stable(R[2], R[0], R[1], normalize);
break;
default:
- BLI_assert(0);
+ BLI_assert_unreachable();
break;
}
}
@@ -1672,7 +1672,7 @@ void orthogonalize_m4_stable(float R[4][4], int axis, bool normalize)
orthogonalize_stable(R[2], R[0], R[1], normalize);
break;
default:
- BLI_assert(0);
+ BLI_assert_unreachable();
break;
}
}
@@ -1734,7 +1734,7 @@ static bool orthogonalize_m3_zero_axes_impl(float *mat[3], const float unit_leng
break;
}
default: {
- BLI_assert(0); /* Unreachable! */
+ BLI_assert_unreachable();
}
}
@@ -2338,7 +2338,7 @@ void rotate_m4(float mat[4][4], const char axis, const float angle)
}
break;
default:
- BLI_assert(0);
+ BLI_assert_unreachable();
break;
}
}
diff --git a/source/blender/blenlib/intern/math_rotation.c b/source/blender/blenlib/intern/math_rotation.c
index 4cd377b109e..92223bdf1d5 100644
--- a/source/blender/blenlib/intern/math_rotation.c
+++ b/source/blender/blenlib/intern/math_rotation.c
@@ -1143,7 +1143,7 @@ void axis_angle_to_mat3_single(float R[3][3], const char axis, const float angle
R[2][2] = 1.0f;
break;
default:
- BLI_assert(0);
+ BLI_assert_unreachable();
break;
}
}
diff --git a/source/blender/blenlib/intern/math_solvers.c b/source/blender/blenlib/intern/math_solvers.c
index 2352d687061..b5650410a70 100644
--- a/source/blender/blenlib/intern/math_solvers.c
+++ b/source/blender/blenlib/intern/math_solvers.c
@@ -99,8 +99,8 @@ bool BLI_tridiagonal_solve_cyclic(
/* Degenerate case that works but can be simplified. */
if (count == 2) {
- float a2[2] = {0, a[1] + c[1]};
- float c2[2] = {a[0] + c[0], 0};
+ const float a2[2] = {0, a[1] + c[1]};
+ const float c2[2] = {a[0] + c[0], 0};
return BLI_tridiagonal_solve(a2, b, c2, d, r_x, count);
}
diff --git a/source/blender/blenlib/intern/scanfill.c b/source/blender/blenlib/intern/scanfill.c
index bc07669687e..92fd7f5937b 100644
--- a/source/blender/blenlib/intern/scanfill.c
+++ b/source/blender/blenlib/intern/scanfill.c
@@ -871,7 +871,7 @@ unsigned int BLI_scanfill_calc_ex(ScanFillContext *sf_ctx, const int flag, const
/* Similar code used elsewhere, but this checks for double ups
* which historically this function supports so better not change */
- /* warning: this only gives stable direction with single polygons,
+ /* WARNING: this only gives stable direction with single polygons,
* ideally we'd calculate connectivity and each polys normal, see T41047 */
const float *v_prev;
diff --git a/source/blender/blenlib/intern/string.c b/source/blender/blenlib/intern/string.c
index 74559751d91..976b9a5cd02 100644
--- a/source/blender/blenlib/intern/string.c
+++ b/source/blender/blenlib/intern/string.c
@@ -914,14 +914,22 @@ size_t BLI_strnlen(const char *s, const size_t maxlen)
/** \name String Case Conversion
* \{ */
+char BLI_tolower_ascii(const char c)
+{
+ return (c >= 'A' && c <= 'Z') ? c + ('a' - 'A') : c;
+}
+
+char BLI_toupper_ascii(const char c)
+{
+ return (c >= 'a' && c <= 'z') ? c - ('a' - 'A') : c;
+}
+
void BLI_str_tolower_ascii(char *str, const size_t len)
{
size_t i;
for (i = 0; (i < len) && str[i]; i++) {
- if (str[i] >= 'A' && str[i] <= 'Z') {
- str[i] += 'a' - 'A';
- }
+ str[i] = BLI_tolower_ascii(str[i]);
}
}
@@ -930,9 +938,7 @@ void BLI_str_toupper_ascii(char *str, const size_t len)
size_t i;
for (i = 0; (i < len) && str[i]; i++) {
- if (str[i] >= 'a' && str[i] <= 'z') {
- str[i] -= 'a' - 'A';
- }
+ str[i] = BLI_toupper_ascii(str[i]);
}
}
@@ -1149,7 +1155,7 @@ void BLI_str_format_byte_unit(char dst[15], long long int bytes, const bool base
BLI_strncpy(dst + len, base_10 ? units_base_10[order] : units_base_2[order], dst_len - len);
}
-void BLI_str_format_attribute_domain_size(char dst[7], int number_to_format)
+void BLI_str_format_decimal_unit(char dst[7], int number_to_format)
{
float number_to_format_converted = number_to_format;
int order = 0;
diff --git a/source/blender/blenlib/intern/string_cursor_utf8.c b/source/blender/blenlib/intern/string_cursor_utf8.c
index a6e68401368..7a23b4bb4ad 100644
--- a/source/blender/blenlib/intern/string_cursor_utf8.c
+++ b/source/blender/blenlib/intern/string_cursor_utf8.c
@@ -198,7 +198,7 @@ void BLI_str_cursor_step_utf8(const char *str,
}
}
else {
- BLI_assert(0);
+ BLI_assert_unreachable();
}
}
@@ -296,6 +296,6 @@ void BLI_str_cursor_step_utf32(const char32_t *str,
}
}
else {
- BLI_assert(0);
+ BLI_assert_unreachable();
}
}
diff --git a/source/blender/blenlib/intern/string_utf8.c b/source/blender/blenlib/intern/string_utf8.c
index 94efb0dd9e7..0cbf62cce03 100644
--- a/source/blender/blenlib/intern/string_utf8.c
+++ b/source/blender/blenlib/intern/string_utf8.c
@@ -363,6 +363,10 @@ size_t BLI_strncpy_wchar_from_utf8(wchar_t *__restrict dst_w,
int BLI_wcwidth(char32_t ucs)
{
+ /* Treat private use areas (icon fonts), symbols, and emoticons as double-width. */
+ if (ucs >= 0xf0000 || (ucs >= 0xe000 && ucs < 0xf8ff) || (ucs >= 0x1f300 && ucs < 0x1fbff)) {
+ return 2;
+ }
return mk_wcwidth(ucs);
}
diff --git a/source/blender/blenlib/intern/threads.cc b/source/blender/blenlib/intern/threads.cc
index 70c1e701348..37fccf6f4fe 100644
--- a/source/blender/blenlib/intern/threads.cc
+++ b/source/blender/blenlib/intern/threads.cc
@@ -348,7 +348,7 @@ static ThreadMutex *global_mutex_from_type(const int type)
case LOCK_VIEW3D:
return &_view3d_lock;
default:
- BLI_assert(0);
+ BLI_assert_unreachable();
return nullptr;
}
}
diff --git a/source/blender/blenlib/tests/BLI_array_store_test.cc b/source/blender/blenlib/tests/BLI_array_store_test.cc
index aa7291e1b41..20e2a4d88f8 100644
--- a/source/blender/blenlib/tests/BLI_array_store_test.cc
+++ b/source/blender/blenlib/tests/BLI_array_store_test.cc
@@ -644,7 +644,7 @@ static void testbuffer_list_state_random_data(ListBase *lb,
break;
}
default:
- BLI_assert(0);
+ BLI_assert_unreachable();
}
}
}
diff --git a/source/blender/blenlib/tests/BLI_bounds_test.cc b/source/blender/blenlib/tests/BLI_bounds_test.cc
index 9c123d4705c..5aa4e710e90 100644
--- a/source/blender/blenlib/tests/BLI_bounds_test.cc
+++ b/source/blender/blenlib/tests/BLI_bounds_test.cc
@@ -33,6 +33,13 @@ TEST(bounds, MinMaxFloat)
EXPECT_EQ(result->max, 3.0f);
}
+TEST(bounds, MinGreaterThanZero)
+{
+ Array<float> data = {1.5f, 3.0f, 1.1f, 100.0f};
+ auto result = bounds::min_max(data.as_span());
+ EXPECT_GT(result->min, 1.0f);
+}
+
TEST(bounds, MinMaxRadii)
{
Array<int2> data = {int2(0, 1), int2(3, -1), int2(0, -2), int2(-1, 1)};
diff --git a/source/blender/blenlib/tests/BLI_float3x3_test.cc b/source/blender/blenlib/tests/BLI_float3x3_test.cc
new file mode 100644
index 00000000000..d22993ee69e
--- /dev/null
+++ b/source/blender/blenlib/tests/BLI_float3x3_test.cc
@@ -0,0 +1,119 @@
+/* SPDX-License-Identifier: Apache-2.0 */
+
+#include "testing/testing.h"
+
+#include "BLI_float3x3.hh"
+#include "BLI_math_base.h"
+#include "BLI_math_vec_types.hh"
+
+namespace blender::tests {
+
+TEST(float3x3, Identity)
+{
+ float2 point(1.0f, 2.0f);
+ float3x3 transformation = float3x3::identity();
+ float2 result = transformation * point;
+ EXPECT_EQ(result, point);
+}
+
+TEST(float3x3, Translation)
+{
+ float2 point(1.0f, 2.0f);
+ float3x3 transformation = float3x3::from_translation(float2(5.0f, 3.0f));
+ float2 result = transformation * point;
+ EXPECT_FLOAT_EQ(result[0], 6.0f);
+ EXPECT_FLOAT_EQ(result[1], 5.0f);
+}
+
+TEST(float3x3, Rotation)
+{
+ float2 point(1.0f, 2.0f);
+ float3x3 transformation = float3x3::from_rotation(M_PI_2);
+ float2 result = transformation * point;
+ EXPECT_FLOAT_EQ(result[0], -2.0f);
+ EXPECT_FLOAT_EQ(result[1], 1.0f);
+}
+
+TEST(float3x3, TranslationRotationScale)
+{
+ float2 point(1.0f, 2.0f);
+ float3x3 transformation = float3x3::from_translation_rotation_scale(
+ float2(1.0f, 3.0f), M_PI_2, float2(2.0f, 3.0f));
+ float2 result = transformation * point;
+ EXPECT_FLOAT_EQ(result[0], -5.0f);
+ EXPECT_FLOAT_EQ(result[1], 5.0f);
+}
+
+TEST(float3x3, NormalizedAxes)
+{
+ float2 point(1.0f, 2.0f);
+
+ /* The horizontal is aligned with (1, 1) and vertical is aligned with (-1, 1), in other words, a
+ * Pi / 4 rotation. */
+ float value = std::sqrt(2.0f) / 2.0f;
+ float3x3 transformation = float3x3::from_normalized_axes(
+ float2(1.0f, 3.0f), float2(value), float2(-value, value));
+ float2 result = transformation * point;
+
+ float3x3 expected_transformation = float3x3::from_translation_rotation_scale(
+ float2(1.0f, 3.0f), M_PI_4, float2(1.0f));
+ float2 expected = expected_transformation * point;
+
+ EXPECT_FLOAT_EQ(result[0], expected[0]);
+ EXPECT_FLOAT_EQ(result[1], expected[1]);
+}
+
+TEST(float3x3, PostTransformationMultiplication)
+{
+ float2 point(1.0f, 2.0f);
+ float3x3 translation = float3x3::from_translation(float2(5.0f, 3.0f));
+ float3x3 rotation = float3x3::from_rotation(M_PI_2);
+ float3x3 transformation = translation * rotation;
+ float2 result = transformation * point;
+ EXPECT_FLOAT_EQ(result[0], 3.0f);
+ EXPECT_FLOAT_EQ(result[1], 4.0f);
+}
+
+TEST(float3x3, PreTransformationMultiplication)
+{
+ float2 point(1.0f, 2.0f);
+ float3x3 translation = float3x3::from_translation(float2(5.0f, 3.0f));
+ float3x3 rotation = float3x3::from_rotation(M_PI_2);
+ float3x3 transformation = rotation * translation;
+ float2 result = transformation * point;
+ EXPECT_FLOAT_EQ(result[0], -5.0f);
+ EXPECT_FLOAT_EQ(result[1], 6.0f);
+}
+
+TEST(float3x3, TransformationMultiplicationAssignment)
+{
+ float2 point(1.0f, 2.0f);
+ float3x3 transformation = float3x3::from_translation(float2(5.0f, 3.0f));
+ transformation *= float3x3::from_rotation(M_PI_2);
+ float2 result = transformation * point;
+ EXPECT_FLOAT_EQ(result[0], 3.0f);
+ EXPECT_FLOAT_EQ(result[1], 4.0f);
+}
+
+TEST(float3x3, Inverted)
+{
+ float2 point(1.0f, 2.0f);
+ float3x3 transformation = float3x3::from_translation_rotation_scale(
+ float2(1.0f, 3.0f), M_PI_4, float2(1.0f));
+ transformation *= transformation.inverted();
+ float2 result = transformation * point;
+ EXPECT_FLOAT_EQ(result[0], 1.0f);
+ EXPECT_FLOAT_EQ(result[1], 2.0f);
+}
+
+TEST(float3x3, Origin)
+{
+ float2 point(1.0f, 2.0f);
+ float3x3 rotation = float3x3::from_rotation(M_PI_2);
+ float3x3 transformation = float3x3::from_origin_transformation(rotation, float2(0.0f, 2.0f));
+ float2 result = transformation * point;
+ EXPECT_FLOAT_EQ(result[0], 0.0f);
+ EXPECT_FLOAT_EQ(result[1], 3.0f);
+}
+
+} // namespace blender::tests
diff --git a/source/blender/blenlib/tests/BLI_kdtree_test.cc b/source/blender/blenlib/tests/BLI_kdtree_test.cc
new file mode 100644
index 00000000000..f8675ef332d
--- /dev/null
+++ b/source/blender/blenlib/tests/BLI_kdtree_test.cc
@@ -0,0 +1,63 @@
+/* SPDX-License-Identifier: Apache-2.0 */
+
+#include "testing/testing.h"
+
+#include "BLI_kdtree.h"
+
+#include <math.h>
+
+/* -------------------------------------------------------------------- */
+/* Tests */
+
+static void standard_test()
+{
+ for (int tree_size = 30; tree_size < 500; tree_size++) {
+ int tree_index = 0;
+ KDTree_1d *tree = BLI_kdtree_1d_new(tree_size);
+ int mask = tree_size & 31;
+ bool occupied[32] = {false};
+
+ for (int i = 0; i < tree_size; i++) {
+ int index = i & mask;
+ occupied[index] = true;
+ float value = fmodf(index * 7.121f, 0.6037f); /* Co-prime. */
+ float key[1] = {value};
+ BLI_kdtree_1d_insert(tree, tree_index++, key);
+ }
+ int expected = 0;
+ for (int j = 0; j < 32; j++) {
+ if (occupied[j]) {
+ expected++;
+ }
+ }
+
+ int dedup_count = BLI_kdtree_1d_deduplicate(tree);
+ EXPECT_EQ(dedup_count, expected);
+ BLI_kdtree_1d_free(tree);
+ }
+}
+
+static void deduplicate_test()
+{
+ for (int tree_size = 1; tree_size < 40; tree_size++) {
+ int tree_index = 0;
+ KDTree_1d *tree = BLI_kdtree_1d_new(tree_size);
+ for (int i = 0; i < tree_size; i++) {
+ float key[1] = {1.0f};
+ BLI_kdtree_1d_insert(tree, tree_index++, key);
+ }
+ int dedup_count = BLI_kdtree_1d_deduplicate(tree);
+ EXPECT_EQ(dedup_count, 1);
+ BLI_kdtree_1d_free(tree);
+ }
+}
+
+TEST(kdtree, Standard)
+{
+ standard_test();
+}
+
+TEST(kdtree, Deduplicate)
+{
+ deduplicate_test();
+}
diff --git a/source/blender/blenlib/tests/BLI_math_color_test.cc b/source/blender/blenlib/tests/BLI_math_color_test.cc
index 7f2c0a3f1ca..4d928477870 100644
--- a/source/blender/blenlib/tests/BLI_math_color_test.cc
+++ b/source/blender/blenlib/tests/BLI_math_color_test.cc
@@ -74,3 +74,71 @@ TEST(math_color, LinearRGBTosRGBRoundtrip)
EXPECT_NEAR(orig_linear_color, linear_color, 1e-5);
}
}
+
+TEST(math_color, linearrgb_to_srgb_v3_v3)
+{
+ float srgb_color[3];
+ {
+ const float kTolerance = 1.0e-8f;
+ const float linear_color[3] = {0.0023f, 0.0024f, 0.0025f};
+ linearrgb_to_srgb_v3_v3(srgb_color, linear_color);
+ EXPECT_NEAR(0.029716f, srgb_color[0], kTolerance);
+ EXPECT_NEAR(0.031008f, srgb_color[1], kTolerance);
+ EXPECT_NEAR(0.032300f, srgb_color[2], kTolerance);
+ }
+
+ {
+ /* SIMD implementation of linear->srgb for larger inputs
+ * is less accurate; use larger tolerance. */
+ const float kTolerance = 3.6e-5f;
+ const float linear_color[3] = {0.71f, 0.75f, 0.78f};
+ linearrgb_to_srgb_v3_v3(srgb_color, linear_color);
+ EXPECT_NEAR(0.859696f, srgb_color[0], kTolerance);
+ EXPECT_NEAR(0.880825f, srgb_color[1], kTolerance);
+ EXPECT_NEAR(0.896244f, srgb_color[2], kTolerance);
+ }
+
+ {
+ /* Not a common, but possible case: values beyond 1.0 range. */
+ const float kTolerance = 2.3e-4f;
+ const float linear_color[3] = {1.5f, 2.8f, 5.6f};
+ linearrgb_to_srgb_v3_v3(srgb_color, linear_color);
+ EXPECT_NEAR(1.19418f, srgb_color[0], kTolerance);
+ EXPECT_NEAR(1.56520f, srgb_color[1], kTolerance);
+ EXPECT_NEAR(2.10771f, srgb_color[2], kTolerance);
+ }
+}
+
+TEST(math_color, srgb_to_linearrgb_v3_v3)
+{
+ float linear_color[3];
+ {
+ const float kTolerance = 1.0e-8f;
+ const float srgb_color[3] = {0.0023f, 0.0024f, 0.0025f};
+ srgb_to_linearrgb_v3_v3(linear_color, srgb_color);
+ EXPECT_NEAR(0.000178019f, linear_color[0], kTolerance);
+ EXPECT_NEAR(0.000185759f, linear_color[1], kTolerance);
+ EXPECT_NEAR(0.000193498f, linear_color[2], kTolerance);
+ }
+
+ {
+ /* SIMD implementation of linear->srgb for larger inputs
+ * is less accurate; use larger tolerance. */
+ const float kTolerance = 1.5e-7f;
+ const float srgb_color[3] = {0.71f, 0.72f, 0.73f};
+ srgb_to_linearrgb_v3_v3(linear_color, srgb_color);
+ EXPECT_NEAR(0.4623615f, linear_color[0], kTolerance);
+ EXPECT_NEAR(0.4770000f, linear_color[1], kTolerance);
+ EXPECT_NEAR(0.4919052f, linear_color[2], kTolerance);
+ }
+
+ {
+ /* Not a common, but possible case: values beyond 1.0 range. */
+ const float kTolerance = 7.7e-6f;
+ const float srgb_color[3] = {1.1f, 2.5f, 5.6f};
+ srgb_to_linearrgb_v3_v3(linear_color, srgb_color);
+ EXPECT_NEAR(1.24277f, linear_color[0], kTolerance);
+ EXPECT_NEAR(8.35473f, linear_color[1], kTolerance);
+ EXPECT_NEAR(56.23833f, linear_color[2], kTolerance);
+ }
+}
diff --git a/source/blender/blenlib/tests/BLI_math_vector_test.cc b/source/blender/blenlib/tests/BLI_math_vector_test.cc
index 282be5f1963..5686be975b5 100644
--- a/source/blender/blenlib/tests/BLI_math_vector_test.cc
+++ b/source/blender/blenlib/tests/BLI_math_vector_test.cc
@@ -105,4 +105,24 @@ TEST(math_vector, InterpolateFloat)
EXPECT_FLOAT_EQ(result.z, 75.0f);
}
+TEST(math_vector, CeilToMultiple)
+{
+ const int3 a(21, 16, 0);
+ const int3 b(8, 16, 15);
+ const int3 result = math::ceil_to_multiple(a, b);
+ EXPECT_FLOAT_EQ(result.x, 24);
+ EXPECT_FLOAT_EQ(result.y, 16);
+ EXPECT_FLOAT_EQ(result.z, 0);
+}
+
+TEST(math_vector, DivideCeil)
+{
+ const int3 a(21, 16, 0);
+ const int3 b(8, 16, 15);
+ const int3 result = math::divide_ceil(a, b);
+ EXPECT_FLOAT_EQ(result.x, 3);
+ EXPECT_FLOAT_EQ(result.y, 1);
+ EXPECT_FLOAT_EQ(result.z, 0);
+}
+
} // namespace blender::tests
diff --git a/source/blender/blenlib/tests/BLI_path_util_test.cc b/source/blender/blenlib/tests/BLI_path_util_test.cc
index bfd297214c0..4f6f4a5c413 100644
--- a/source/blender/blenlib/tests/BLI_path_util_test.cc
+++ b/source/blender/blenlib/tests/BLI_path_util_test.cc
@@ -663,7 +663,7 @@ TEST(path_util, PathContains)
EXPECT_TRUE(BLI_path_contains("/some/path", "/some/path/inside"))
<< "A path contains its subdirectory";
EXPECT_TRUE(BLI_path_contains("/some/path", "/some/path/../path/inside"))
- << "Paths should be normalised";
+ << "Paths should be normalized";
EXPECT_TRUE(BLI_path_contains("C:\\some\\path", "C:\\some\\path\\inside"))
<< "Windows paths should be supported as well";
@@ -672,7 +672,7 @@ TEST(path_util, PathContains)
EXPECT_FALSE(BLI_path_contains("/some/path", "/"))
<< "Root directory not be contained in a subdirectory";
EXPECT_FALSE(BLI_path_contains("/some/path", "/some/path/../outside"))
- << "Paths should be normalised";
+ << "Paths should be normalized";
EXPECT_FALSE(BLI_path_contains("/some/path", "/some/path_library"))
<< "Just sharing a suffix is not enough, path semantics should be followed";
EXPECT_FALSE(BLI_path_contains("/some/path", "./contents"))
diff --git a/source/blender/blenlib/tests/BLI_string_test.cc b/source/blender/blenlib/tests/BLI_string_test.cc
index 6c16af5767c..eaaa65dd39f 100644
--- a/source/blender/blenlib/tests/BLI_string_test.cc
+++ b/source/blender/blenlib/tests/BLI_string_test.cc
@@ -420,98 +420,98 @@ TEST(string, StrFormatByteUnits)
EXPECT_STREQ("-8191.8472 PiB", size_str);
}
-/* BLI_str_format_attribute_domain_size */
-TEST(string, StrFormatAttributeDomainSize)
+/* BLI_str_format_decimal_unit */
+TEST(string, StrFormatDecimalUnits)
{
char size_str[7];
int size;
- BLI_str_format_attribute_domain_size(size_str, size = 0);
+ BLI_str_format_decimal_unit(size_str, size = 0);
EXPECT_STREQ("0", size_str);
- BLI_str_format_attribute_domain_size(size_str, size = 1);
+ BLI_str_format_decimal_unit(size_str, size = 1);
EXPECT_STREQ("1", size_str);
- BLI_str_format_attribute_domain_size(size_str, size = 10);
+ BLI_str_format_decimal_unit(size_str, size = 10);
EXPECT_STREQ("10", size_str);
- BLI_str_format_attribute_domain_size(size_str, size = 15);
+ BLI_str_format_decimal_unit(size_str, size = 15);
EXPECT_STREQ("15", size_str);
- BLI_str_format_attribute_domain_size(size_str, size = 100);
+ BLI_str_format_decimal_unit(size_str, size = 100);
EXPECT_STREQ("100", size_str);
- BLI_str_format_attribute_domain_size(size_str, size = 155);
+ BLI_str_format_decimal_unit(size_str, size = 155);
EXPECT_STREQ("155", size_str);
- BLI_str_format_attribute_domain_size(size_str, size = 1000);
+ BLI_str_format_decimal_unit(size_str, size = 1000);
EXPECT_STREQ("1.0K", size_str);
- BLI_str_format_attribute_domain_size(size_str, size = 1555);
+ BLI_str_format_decimal_unit(size_str, size = 1555);
EXPECT_STREQ("1.6K", size_str);
- BLI_str_format_attribute_domain_size(size_str, size = 10000);
+ BLI_str_format_decimal_unit(size_str, size = 10000);
EXPECT_STREQ("10.0K", size_str);
- BLI_str_format_attribute_domain_size(size_str, size = 15555);
+ BLI_str_format_decimal_unit(size_str, size = 15555);
EXPECT_STREQ("15.6K", size_str);
- BLI_str_format_attribute_domain_size(size_str, size = 100000);
+ BLI_str_format_decimal_unit(size_str, size = 100000);
EXPECT_STREQ("100K", size_str);
- BLI_str_format_attribute_domain_size(size_str, size = 100000);
+ BLI_str_format_decimal_unit(size_str, size = 100000);
EXPECT_STREQ("100K", size_str);
- BLI_str_format_attribute_domain_size(size_str, size = 155555);
+ BLI_str_format_decimal_unit(size_str, size = 155555);
EXPECT_STREQ("156K", size_str);
- BLI_str_format_attribute_domain_size(size_str, size = 1000000);
+ BLI_str_format_decimal_unit(size_str, size = 1000000);
EXPECT_STREQ("1.0M", size_str);
- BLI_str_format_attribute_domain_size(size_str, size = 1555555);
+ BLI_str_format_decimal_unit(size_str, size = 1555555);
EXPECT_STREQ("1.6M", size_str);
- BLI_str_format_attribute_domain_size(size_str, size = 10000000);
+ BLI_str_format_decimal_unit(size_str, size = 10000000);
EXPECT_STREQ("10.0M", size_str);
- BLI_str_format_attribute_domain_size(size_str, size = 15555555);
+ BLI_str_format_decimal_unit(size_str, size = 15555555);
EXPECT_STREQ("15.6M", size_str);
- BLI_str_format_attribute_domain_size(size_str, size = 100000000);
+ BLI_str_format_decimal_unit(size_str, size = 100000000);
EXPECT_STREQ("100M", size_str);
- BLI_str_format_attribute_domain_size(size_str, size = 155555555);
+ BLI_str_format_decimal_unit(size_str, size = 155555555);
EXPECT_STREQ("156M", size_str);
- BLI_str_format_attribute_domain_size(size_str, size = 1000000000);
+ BLI_str_format_decimal_unit(size_str, size = 1000000000);
EXPECT_STREQ("1.0B", size_str);
/* Largest possible value. */
- BLI_str_format_attribute_domain_size(size_str, size = INT32_MAX);
+ BLI_str_format_decimal_unit(size_str, size = INT32_MAX);
EXPECT_STREQ("2.1B", size_str);
- BLI_str_format_attribute_domain_size(size_str, size = -0);
+ BLI_str_format_decimal_unit(size_str, size = -0);
EXPECT_STREQ("0", size_str);
- BLI_str_format_attribute_domain_size(size_str, size = -1);
+ BLI_str_format_decimal_unit(size_str, size = -1);
EXPECT_STREQ("-1", size_str);
- BLI_str_format_attribute_domain_size(size_str, size = -10);
+ BLI_str_format_decimal_unit(size_str, size = -10);
EXPECT_STREQ("-10", size_str);
- BLI_str_format_attribute_domain_size(size_str, size = -15);
+ BLI_str_format_decimal_unit(size_str, size = -15);
EXPECT_STREQ("-15", size_str);
- BLI_str_format_attribute_domain_size(size_str, size = -100);
+ BLI_str_format_decimal_unit(size_str, size = -100);
EXPECT_STREQ("-100", size_str);
- BLI_str_format_attribute_domain_size(size_str, size = -155);
+ BLI_str_format_decimal_unit(size_str, size = -155);
EXPECT_STREQ("-155", size_str);
- BLI_str_format_attribute_domain_size(size_str, size = -1000);
+ BLI_str_format_decimal_unit(size_str, size = -1000);
EXPECT_STREQ("-1.0K", size_str);
- BLI_str_format_attribute_domain_size(size_str, size = -1555);
+ BLI_str_format_decimal_unit(size_str, size = -1555);
EXPECT_STREQ("-1.6K", size_str);
- BLI_str_format_attribute_domain_size(size_str, size = -10000);
+ BLI_str_format_decimal_unit(size_str, size = -10000);
EXPECT_STREQ("-10.0K", size_str);
- BLI_str_format_attribute_domain_size(size_str, size = -15555);
+ BLI_str_format_decimal_unit(size_str, size = -15555);
EXPECT_STREQ("-15.6K", size_str);
- BLI_str_format_attribute_domain_size(size_str, size = -100000);
+ BLI_str_format_decimal_unit(size_str, size = -100000);
EXPECT_STREQ("-100K", size_str);
- BLI_str_format_attribute_domain_size(size_str, size = -155555);
+ BLI_str_format_decimal_unit(size_str, size = -155555);
EXPECT_STREQ("-156K", size_str);
- BLI_str_format_attribute_domain_size(size_str, size = -1000000);
+ BLI_str_format_decimal_unit(size_str, size = -1000000);
EXPECT_STREQ("-1.0M", size_str);
- BLI_str_format_attribute_domain_size(size_str, size = -1555555);
+ BLI_str_format_decimal_unit(size_str, size = -1555555);
EXPECT_STREQ("-1.6M", size_str);
- BLI_str_format_attribute_domain_size(size_str, size = -10000000);
+ BLI_str_format_decimal_unit(size_str, size = -10000000);
EXPECT_STREQ("-10.0M", size_str);
- BLI_str_format_attribute_domain_size(size_str, size = -15555555);
+ BLI_str_format_decimal_unit(size_str, size = -15555555);
EXPECT_STREQ("-15.6M", size_str);
- BLI_str_format_attribute_domain_size(size_str, size = -100000000);
+ BLI_str_format_decimal_unit(size_str, size = -100000000);
EXPECT_STREQ("-100M", size_str);
- BLI_str_format_attribute_domain_size(size_str, size = -155555555);
+ BLI_str_format_decimal_unit(size_str, size = -155555555);
EXPECT_STREQ("-156M", size_str);
- BLI_str_format_attribute_domain_size(size_str, size = -1000000000);
+ BLI_str_format_decimal_unit(size_str, size = -1000000000);
EXPECT_STREQ("-1.0B", size_str);
/* Smallest possible value. */
- BLI_str_format_attribute_domain_size(size_str, size = -INT32_MAX);
+ BLI_str_format_decimal_unit(size_str, size = -INT32_MAX);
EXPECT_STREQ("-2.1B", size_str);
}
diff --git a/source/blender/blenlib/tests/performance/BLI_ghash_performance_test.cc b/source/blender/blenlib/tests/performance/BLI_ghash_performance_test.cc
index 0ff488202c2..09bb1e7239f 100644
--- a/source/blender/blenlib/tests/performance/BLI_ghash_performance_test.cc
+++ b/source/blender/blenlib/tests/performance/BLI_ghash_performance_test.cc
@@ -57,23 +57,23 @@ static void str_ghash_tests(GHash *ghash, const char *id)
printf("\n========== STARTING %s ==========\n", id);
#ifdef TEXT_CORPUS_PATH
- size_t sz = 0;
+ size_t data_size = 0;
char *data;
{
struct stat st;
if (stat(TEXT_CORPUS_PATH, &st) == 0)
- sz = st.st_size;
+ data_size = st.st_size;
}
- if (sz != 0) {
+ if (data_size != 0) {
FILE *f = fopen(TEXT_CORPUS_PATH, "r");
- data = (char *)MEM_mallocN(sz + 1, __func__);
- if (fread(data, sizeof(*data), sz, f) != sz) {
+ data = (char *)MEM_mallocN(data_size + 1, __func__);
+ if (fread(data, sizeof(*data), data_size, f) != data_size) {
printf("ERROR in reading file %s!", TEXT_CORPUS_PATH);
MEM_freeN(data);
data = BLI_strdup(words10k);
}
- data[sz] = '\0';
+ data[data_size] = '\0';
fclose(f);
}
else {
diff --git a/source/blender/blenloader/BLO_readfile.h b/source/blender/blenloader/BLO_readfile.h
index c1274de034d..043f9ffd723 100644
--- a/source/blender/blenloader/BLO_readfile.h
+++ b/source/blender/blenloader/BLO_readfile.h
@@ -156,10 +156,11 @@ BlendFileData *BLO_read_from_memory(const void *mem,
*
* \param oldmain: old main,
* from which we will keep libraries and other data-blocks that should not have changed.
- * \param filename: current file, only for retrieving library data.
+ * \param filepath: current file, only for retrieving library data.
+ * Typically `BKE_main_blendfile_path(oldmain)`.
*/
BlendFileData *BLO_read_from_memfile(struct Main *oldmain,
- const char *filename,
+ const char *filepath,
struct MemFile *memfile,
const struct BlendFileReadParams *params,
struct ReportList *reports);
diff --git a/source/blender/blenloader/BLO_undofile.h b/source/blender/blenloader/BLO_undofile.h
index 48334444c4c..0584f95d85f 100644
--- a/source/blender/blenloader/BLO_undofile.h
+++ b/source/blender/blenloader/BLO_undofile.h
@@ -46,7 +46,7 @@ typedef struct MemFileWriteData {
} MemFileWriteData;
typedef struct MemFileUndoData {
- char filename[1024]; /* FILE_MAX */
+ char filepath[1024]; /* FILE_MAX */
MemFile memfile;
size_t undo_size;
} MemFileUndoData;
@@ -98,6 +98,6 @@ extern struct Main *BLO_memfile_main_get(struct MemFile *memfile,
*
* \return success.
*/
-extern bool BLO_memfile_write_file(struct MemFile *memfile, const char *filename);
+extern bool BLO_memfile_write_file(struct MemFile *memfile, const char *filepath);
FileReader *BLO_memfile_new_filereader(MemFile *memfile, int undo_direction);
diff --git a/source/blender/blenloader/intern/readblenentry.c b/source/blender/blenloader/intern/readblenentry.c
index 10b69b67fa1..1bfa3b0e2bb 100644
--- a/source/blender/blenloader/intern/readblenentry.c
+++ b/source/blender/blenloader/intern/readblenentry.c
@@ -388,7 +388,7 @@ BlendFileData *BLO_read_from_memory(const void *mem,
}
BlendFileData *BLO_read_from_memfile(Main *oldmain,
- const char *filename,
+ const char *filepath,
MemFile *memfile,
const struct BlendFileReadParams *params,
ReportList *reports)
@@ -401,7 +401,7 @@ BlendFileData *BLO_read_from_memfile(Main *oldmain,
fd = blo_filedata_from_memfile(memfile, params, &bf_reports);
if (fd) {
fd->skip_flags = params->skip_flags;
- BLI_strncpy(fd->relabase, filename, sizeof(fd->relabase));
+ BLI_strncpy(fd->relabase, filepath, sizeof(fd->relabase));
/* separate libraries from old main */
blo_split_main(&old_mainlist, oldmain);
@@ -420,7 +420,7 @@ BlendFileData *BLO_read_from_memfile(Main *oldmain,
* read IDs whenever possible. */
blo_cache_storage_init(fd, oldmain);
- bfd = blo_read_file_internal(fd, filename);
+ bfd = blo_read_file_internal(fd, filepath);
/* Ensure relinked caches are not freed together with their old IDs. */
blo_cache_storage_old_bmain_clear(fd, oldmain);
diff --git a/source/blender/blenloader/intern/readfile.c b/source/blender/blenloader/intern/readfile.c
index 6ba97caa0ae..973965ada50 100644
--- a/source/blender/blenloader/intern/readfile.c
+++ b/source/blender/blenloader/intern/readfile.c
@@ -477,7 +477,6 @@ static void split_libdata(ListBase *lb_src, Main **lib_main_array, const uint li
}
else {
CLOG_ERROR(&LOG, "Invalid library for '%s'", id->name);
- BLI_assert(0);
}
}
}
@@ -1477,14 +1476,14 @@ BlendThumbnail *BLO_thumbnail_from_file(const char *filepath)
const int width = fd_data[0];
const int height = fd_data[1];
if (BLEN_THUMB_MEMSIZE_IS_VALID(width, height)) {
- const size_t sz = BLEN_THUMB_MEMSIZE(width, height);
- data = MEM_mallocN(sz, __func__);
+ const size_t data_size = BLEN_THUMB_MEMSIZE(width, height);
+ data = MEM_mallocN(data_size, __func__);
if (data) {
- BLI_assert((sz - sizeof(*data)) ==
+ BLI_assert((data_size - sizeof(*data)) ==
(BLEN_THUMB_MEMSIZE_FILE(width, height) - (sizeof(*fd_data) * 2)));
data->width = width;
data->height = height;
- memcpy(data->rect, &fd_data[2], sz - sizeof(*data));
+ memcpy(data->rect, &fd_data[2], data_size - sizeof(*data));
}
}
}
@@ -2413,7 +2412,7 @@ static int lib_link_main_data_restore_cb(LibraryIDLinkCallbackData *cb_data)
if (collection->flag & COLLECTION_IS_MASTER) {
/* We should never reach that point anymore, since master collection private ID should be
* properly tagged with IDWALK_CB_EMBEDDED. */
- BLI_assert(0);
+ BLI_assert_unreachable();
return IDWALK_RET_NOP;
}
}
@@ -3857,14 +3856,14 @@ BlendFileData *blo_read_file_internal(FileData *fd, const char *filepath)
const int width = data[0];
const int height = data[1];
if (BLEN_THUMB_MEMSIZE_IS_VALID(width, height)) {
- const size_t sz = BLEN_THUMB_MEMSIZE(width, height);
- bfd->main->blen_thumb = MEM_mallocN(sz, __func__);
+ const size_t data_size = BLEN_THUMB_MEMSIZE(width, height);
+ bfd->main->blen_thumb = MEM_mallocN(data_size, __func__);
- BLI_assert((sz - sizeof(*bfd->main->blen_thumb)) ==
+ BLI_assert((data_size - sizeof(*bfd->main->blen_thumb)) ==
(BLEN_THUMB_MEMSIZE_FILE(width, height) - (sizeof(*data) * 2)));
bfd->main->blen_thumb->width = width;
bfd->main->blen_thumb->height = height;
- memcpy(bfd->main->blen_thumb->rect, &data[2], sz - sizeof(*bfd->main->blen_thumb));
+ memcpy(bfd->main->blen_thumb->rect, &data[2], data_size - sizeof(*bfd->main->blen_thumb));
}
}
}
diff --git a/source/blender/blenloader/intern/undofile.c b/source/blender/blenloader/intern/undofile.c
index 5c4598b85c5..b5c2a73c268 100644
--- a/source/blender/blenloader/intern/undofile.c
+++ b/source/blender/blenloader/intern/undofile.c
@@ -120,7 +120,7 @@ void BLO_memfile_write_init(MemFileWriteData *mem_data,
*entry = mem_chunk;
}
else {
- BLI_assert(0);
+ BLI_assert_unreachable();
}
}
}
@@ -195,7 +195,7 @@ struct Main *BLO_memfile_main_get(struct MemFile *memfile,
return bmain_undo;
}
-bool BLO_memfile_write_file(struct MemFile *memfile, const char *filename)
+bool BLO_memfile_write_file(struct MemFile *memfile, const char *filepath)
{
MemFileChunk *chunk;
int file, oflags;
@@ -216,12 +216,12 @@ bool BLO_memfile_write_file(struct MemFile *memfile, const char *filename)
# warning "Symbolic links will be followed on undo save, possibly causing CVE-2008-1103"
# endif
#endif
- file = BLI_open(filename, oflags, 0666);
+ file = BLI_open(filepath, oflags, 0666);
if (file == -1) {
fprintf(stderr,
"Unable to save '%s': %s\n",
- filename,
+ filepath,
errno ? strerror(errno) : "Unknown error opening file");
return false;
}
@@ -242,7 +242,7 @@ bool BLO_memfile_write_file(struct MemFile *memfile, const char *filename)
if (chunk) {
fprintf(stderr,
"Unable to save '%s': %s\n",
- filename,
+ filepath,
errno ? strerror(errno) : "Unknown error writing file");
return false;
}
diff --git a/source/blender/blenloader/intern/versioning_280.c b/source/blender/blenloader/intern/versioning_280.c
index d992d426b9a..e542bc46a28 100644
--- a/source/blender/blenloader/intern/versioning_280.c
+++ b/source/blender/blenloader/intern/versioning_280.c
@@ -1569,8 +1569,8 @@ void do_versions_after_linking_280(Main *bmain, ReportList *UNUSED(reports))
if (!MAIN_VERSION_ATLEAST(bmain, 281, 2)) {
/* Replace Multiply and Additive blend mode by Alpha Blend
- * now that we use dualsource blending. */
- /* We take care of doing only nodetrees that are always part of materials
+ * now that we use dual-source blending. */
+ /* We take care of doing only node-trees that are always part of materials
* with old blending modes. */
for (Material *ma = bmain->materials.first; ma; ma = ma->id.next) {
bNodeTree *ntree = ma->nodetree;
@@ -4102,7 +4102,7 @@ void blo_do_versions_280(FileData *fd, Library *UNUSED(lib), Main *bmain)
LISTBASE_FOREACH (Object *, ob, &bmain->objects) {
LISTBASE_FOREACH (ModifierData *, md, &ob->modifiers) {
if (md->type == eModifierType_DataTransfer) {
- /* Now datatransfer's mix factor is multiplied with weights when any,
+ /* Now data-transfer's mix factor is multiplied with weights when any,
* instead of being ignored,
* we need to take care of that to keep 'old' files compatible. */
DataTransferModifierData *dtmd = (DataTransferModifierData *)md;
@@ -4892,7 +4892,7 @@ void blo_do_versions_280(FileData *fd, Library *UNUSED(lib), Main *bmain)
/* Default Face Set Color. */
for (Mesh *me = bmain->meshes.first; me != NULL; me = me->id.next) {
if (me->totpoly > 0) {
- int *face_sets = CustomData_get_layer(&me->pdata, CD_SCULPT_FACE_SETS);
+ const int *face_sets = CustomData_get_layer(&me->pdata, CD_SCULPT_FACE_SETS);
if (face_sets) {
me->face_sets_color_default = abs(face_sets[0]);
}
diff --git a/source/blender/blenloader/intern/versioning_290.c b/source/blender/blenloader/intern/versioning_290.c
index 2f6f0d5c9fa..a15ddc75aa2 100644
--- a/source/blender/blenloader/intern/versioning_290.c
+++ b/source/blender/blenloader/intern/versioning_290.c
@@ -347,8 +347,9 @@ static void seq_convert_transform_crop_lb_2(const Scene *scene,
}
}
-static void seq_update_meta_disp_range(Editing *ed)
+static void seq_update_meta_disp_range(Scene *scene)
{
+ Editing *ed = SEQ_editing_get(scene);
if (ed == NULL) {
return;
}
@@ -356,21 +357,14 @@ static void seq_update_meta_disp_range(Editing *ed)
LISTBASE_FOREACH_BACKWARD (MetaStack *, ms, &ed->metastack) {
/* Update ms->disp_range from meta. */
if (ms->disp_range[0] == ms->disp_range[1]) {
- copy_v2_v2_int(ms->disp_range, &ms->parseq->startdisp);
+ ms->disp_range[0] = SEQ_time_left_handle_frame_get(ms->parseq);
+ ms->disp_range[1] = SEQ_time_right_handle_frame_get(ms->parseq);
}
/* Update meta strip endpoints. */
- SEQ_transform_set_left_handle_frame(ms->parseq, ms->disp_range[0]);
- SEQ_transform_set_right_handle_frame(ms->parseq, ms->disp_range[1]);
- SEQ_transform_fix_single_image_seq_offsets(ms->parseq);
-
- /* Recalculate effects using meta strip. */
- LISTBASE_FOREACH (Sequence *, seq, ms->oldbasep) {
- if (seq->seq2) {
- seq->start = seq->startdisp = max_ii(seq->seq1->startdisp, seq->seq2->startdisp);
- seq->enddisp = min_ii(seq->seq1->enddisp, seq->seq2->enddisp);
- }
- }
+ SEQ_time_left_handle_frame_set(scene, ms->parseq, ms->disp_range[0]);
+ SEQ_time_right_handle_frame_set(scene, ms->parseq, ms->disp_range[1]);
+ SEQ_transform_fix_single_image_seq_offsets(scene, ms->parseq);
/* Ensure that active seqbase points to active meta strip seqbase. */
MetaStack *active_ms = SEQ_meta_stack_active_get(ed);
@@ -647,7 +641,7 @@ void do_versions_after_linking_290(Main *bmain, ReportList *UNUSED(reports))
if (!MAIN_VERSION_ATLEAST(bmain, 293, 16)) {
LISTBASE_FOREACH (Scene *, scene, &bmain->scenes) {
- seq_update_meta_disp_range(SEQ_editing_get(scene));
+ seq_update_meta_disp_range(scene);
}
/* Add a separate socket for Grid node X and Y size. */
@@ -1446,7 +1440,7 @@ void blo_do_versions_290(FileData *fd, Library *UNUSED(lib), Main *bmain)
view_layer->eevee.render_passes &= ~EEVEE_RENDER_PASS_UNUSED_8;
}
- /* Rename Renderlayer Socket `VolumeScatterCol` to `VolumeDir` */
+ /* Rename Render-layer Socket `VolumeScatterCol` to `VolumeDir`. */
if (scene->nodetree) {
LISTBASE_FOREACH (bNode *, node, &scene->nodetree->nodes) {
if (node->type == CMP_NODE_R_LAYERS) {
@@ -1666,13 +1660,8 @@ void blo_do_versions_290(FileData *fd, Library *UNUSED(lib), Main *bmain)
LISTBASE_FOREACH (bScreen *, screen, &bmain->screens) {
LISTBASE_FOREACH (ScrArea *, area, &screen->areabase) {
LISTBASE_FOREACH (SpaceLink *, space, &area->spacedata) {
- /* UV/Image Max resolution images in image editor. */
- if (space->spacetype == SPACE_IMAGE) {
- SpaceImage *sima = (SpaceImage *)space;
- sima->iuser.flag |= IMA_SHOW_MAX_RESOLUTION;
- }
/* Enable Outliner render visibility column. */
- else if (space->spacetype == SPACE_OUTLINER) {
+ if (space->spacetype == SPACE_OUTLINER) {
SpaceOutliner *space_outliner = (SpaceOutliner *)space;
space_outliner->show_restrict_flags |= SO_RESTRICT_RENDER;
}
diff --git a/source/blender/blenloader/intern/versioning_300.c b/source/blender/blenloader/intern/versioning_300.c
index 7fd72fec3d0..eac27bc57ed 100644
--- a/source/blender/blenloader/intern/versioning_300.c
+++ b/source/blender/blenloader/intern/versioning_300.c
@@ -25,10 +25,12 @@
#include "DNA_collection_types.h"
#include "DNA_constraint_types.h"
#include "DNA_curve_types.h"
+#include "DNA_curves_types.h"
#include "DNA_genfile.h"
#include "DNA_gpencil_modifier_types.h"
#include "DNA_lineart_types.h"
#include "DNA_listBase.h"
+#include "DNA_mask_types.h"
#include "DNA_material_types.h"
#include "DNA_mesh_types.h"
#include "DNA_modifier_types.h"
@@ -63,7 +65,7 @@
#include "RNA_prototypes.h"
#include "BLO_readfile.h"
-#include "MEM_guardedalloc.h"
+
#include "readfile.h"
#include "SEQ_channels.h"
@@ -71,8 +73,6 @@
#include "SEQ_sequencer.h"
#include "SEQ_time.h"
-#include "RNA_access.h"
-
#include "versioning_common.h"
static CLG_LogRef LOG = {"blo.readfile.doversion"};
@@ -407,7 +407,9 @@ static void do_versions_sequencer_speed_effect_recursive(Scene *scene, const Lis
v->speed_control_type = SEQ_SPEED_MULTIPLY;
v->speed_fader = globalSpeed *
((float)seq->seq1->len /
- max_ff((float)(seq->seq1->enddisp - seq->seq1->start), 1.0f));
+ max_ff((float)(SEQ_time_right_handle_frame_get(seq->seq1) -
+ seq->seq1->start),
+ 1.0f));
}
}
else if (v->flags & SEQ_SPEED_INTEGRATE) {
@@ -1000,6 +1002,9 @@ static void do_version_subsurface_methods(bNode *node)
static void version_geometry_nodes_add_attribute_input_settings(NodesModifierData *nmd)
{
+ if (nmd->settings.properties == NULL) {
+ return;
+ }
/* Before versioning the properties, make sure it hasn't been done already. */
LISTBASE_FOREACH (const IDProperty *, property, &nmd->settings.properties->data.group) {
if (strstr(property->name, "_use_attribute") || strstr(property->name, "_attribute_name")) {
@@ -1217,6 +1222,15 @@ static bool version_fix_seq_meta_range(Sequence *seq, void *user_data)
return true;
}
+static bool version_merge_still_offsets(Sequence *seq, void *UNUSED(user_data))
+{
+ seq->startofs -= seq->startstill;
+ seq->endofs -= seq->endstill;
+ seq->startstill = 0;
+ seq->endstill = 0;
+ return true;
+}
+
/* Those `version_liboverride_rnacollections_*` functions mimic the old, pre-3.0 code to find
* anchor and source items in the given list of modifiers, constraints etc., using only the
* `subitem_local` data of the override property operation.
@@ -1362,6 +1376,250 @@ static void version_liboverride_rnacollections_insertion_animdata(ID *id)
}
}
+static void versioning_replace_legacy_combined_and_separate_color_nodes(bNodeTree *ntree)
+{
+ /* In geometry nodes, replace shader combine/separate color nodes with function nodes */
+ if (ntree->type == NTREE_GEOMETRY) {
+ version_node_input_socket_name(ntree, SH_NODE_COMBRGB_LEGACY, "R", "Red");
+ version_node_input_socket_name(ntree, SH_NODE_COMBRGB_LEGACY, "G", "Green");
+ version_node_input_socket_name(ntree, SH_NODE_COMBRGB_LEGACY, "B", "Blue");
+ version_node_output_socket_name(ntree, SH_NODE_COMBRGB_LEGACY, "Image", "Color");
+
+ version_node_output_socket_name(ntree, SH_NODE_SEPRGB_LEGACY, "R", "Red");
+ version_node_output_socket_name(ntree, SH_NODE_SEPRGB_LEGACY, "G", "Green");
+ version_node_output_socket_name(ntree, SH_NODE_SEPRGB_LEGACY, "B", "Blue");
+ version_node_input_socket_name(ntree, SH_NODE_SEPRGB_LEGACY, "Image", "Color");
+
+ LISTBASE_FOREACH (bNode *, node, &ntree->nodes) {
+ switch (node->type) {
+ case SH_NODE_COMBRGB_LEGACY: {
+ node->type = FN_NODE_COMBINE_COLOR;
+ NodeCombSepColor *storage = (NodeCombSepColor *)MEM_callocN(sizeof(NodeCombSepColor),
+ __func__);
+ storage->mode = NODE_COMBSEP_COLOR_RGB;
+ strcpy(node->idname, "FunctionNodeCombineColor");
+ node->storage = storage;
+ break;
+ }
+ case SH_NODE_SEPRGB_LEGACY: {
+ node->type = FN_NODE_SEPARATE_COLOR;
+ NodeCombSepColor *storage = (NodeCombSepColor *)MEM_callocN(sizeof(NodeCombSepColor),
+ __func__);
+ storage->mode = NODE_COMBSEP_COLOR_RGB;
+ strcpy(node->idname, "FunctionNodeSeparateColor");
+ node->storage = storage;
+ break;
+ }
+ }
+ }
+ }
+
+ /* In compositing nodes, replace combine/separate RGBA/HSVA/YCbCrA/YCCA nodes with
+ * combine/separate color */
+ if (ntree->type == NTREE_COMPOSIT) {
+ version_node_input_socket_name(ntree, CMP_NODE_COMBRGBA_LEGACY, "R", "Red");
+ version_node_input_socket_name(ntree, CMP_NODE_COMBRGBA_LEGACY, "G", "Green");
+ version_node_input_socket_name(ntree, CMP_NODE_COMBRGBA_LEGACY, "B", "Blue");
+ version_node_input_socket_name(ntree, CMP_NODE_COMBRGBA_LEGACY, "A", "Alpha");
+
+ version_node_input_socket_name(ntree, CMP_NODE_COMBHSVA_LEGACY, "H", "Red");
+ version_node_input_socket_name(ntree, CMP_NODE_COMBHSVA_LEGACY, "S", "Green");
+ version_node_input_socket_name(ntree, CMP_NODE_COMBHSVA_LEGACY, "V", "Blue");
+ version_node_input_socket_name(ntree, CMP_NODE_COMBHSVA_LEGACY, "A", "Alpha");
+
+ version_node_input_socket_name(ntree, CMP_NODE_COMBYCCA_LEGACY, "Y", "Red");
+ version_node_input_socket_name(ntree, CMP_NODE_COMBYCCA_LEGACY, "Cb", "Green");
+ version_node_input_socket_name(ntree, CMP_NODE_COMBYCCA_LEGACY, "Cr", "Blue");
+ version_node_input_socket_name(ntree, CMP_NODE_COMBYCCA_LEGACY, "A", "Alpha");
+
+ version_node_input_socket_name(ntree, CMP_NODE_COMBYUVA_LEGACY, "Y", "Red");
+ version_node_input_socket_name(ntree, CMP_NODE_COMBYUVA_LEGACY, "U", "Green");
+ version_node_input_socket_name(ntree, CMP_NODE_COMBYUVA_LEGACY, "V", "Blue");
+ version_node_input_socket_name(ntree, CMP_NODE_COMBYUVA_LEGACY, "A", "Alpha");
+
+ version_node_output_socket_name(ntree, CMP_NODE_SEPRGBA_LEGACY, "R", "Red");
+ version_node_output_socket_name(ntree, CMP_NODE_SEPRGBA_LEGACY, "G", "Green");
+ version_node_output_socket_name(ntree, CMP_NODE_SEPRGBA_LEGACY, "B", "Blue");
+ version_node_output_socket_name(ntree, CMP_NODE_SEPRGBA_LEGACY, "A", "Alpha");
+
+ version_node_output_socket_name(ntree, CMP_NODE_SEPHSVA_LEGACY, "H", "Red");
+ version_node_output_socket_name(ntree, CMP_NODE_SEPHSVA_LEGACY, "S", "Green");
+ version_node_output_socket_name(ntree, CMP_NODE_SEPHSVA_LEGACY, "V", "Blue");
+ version_node_output_socket_name(ntree, CMP_NODE_SEPHSVA_LEGACY, "A", "Alpha");
+
+ version_node_output_socket_name(ntree, CMP_NODE_SEPYCCA_LEGACY, "Y", "Red");
+ version_node_output_socket_name(ntree, CMP_NODE_SEPYCCA_LEGACY, "Cb", "Green");
+ version_node_output_socket_name(ntree, CMP_NODE_SEPYCCA_LEGACY, "Cr", "Blue");
+ version_node_output_socket_name(ntree, CMP_NODE_SEPYCCA_LEGACY, "A", "Alpha");
+
+ version_node_output_socket_name(ntree, CMP_NODE_SEPYUVA_LEGACY, "Y", "Red");
+ version_node_output_socket_name(ntree, CMP_NODE_SEPYUVA_LEGACY, "U", "Green");
+ version_node_output_socket_name(ntree, CMP_NODE_SEPYUVA_LEGACY, "V", "Blue");
+ version_node_output_socket_name(ntree, CMP_NODE_SEPYUVA_LEGACY, "A", "Alpha");
+
+ LISTBASE_FOREACH (bNode *, node, &ntree->nodes) {
+ switch (node->type) {
+ case CMP_NODE_COMBRGBA_LEGACY: {
+ node->type = CMP_NODE_COMBINE_COLOR;
+ NodeCMPCombSepColor *storage = (NodeCMPCombSepColor *)MEM_callocN(
+ sizeof(NodeCMPCombSepColor), __func__);
+ storage->mode = CMP_NODE_COMBSEP_COLOR_RGB;
+ strcpy(node->idname, "CompositorNodeCombineColor");
+ node->storage = storage;
+ break;
+ }
+ case CMP_NODE_COMBHSVA_LEGACY: {
+ node->type = CMP_NODE_COMBINE_COLOR;
+ NodeCMPCombSepColor *storage = (NodeCMPCombSepColor *)MEM_callocN(
+ sizeof(NodeCMPCombSepColor), __func__);
+ storage->mode = CMP_NODE_COMBSEP_COLOR_HSV;
+ strcpy(node->idname, "CompositorNodeCombineColor");
+ node->storage = storage;
+ break;
+ }
+ case CMP_NODE_COMBYCCA_LEGACY: {
+ node->type = CMP_NODE_COMBINE_COLOR;
+ NodeCMPCombSepColor *storage = (NodeCMPCombSepColor *)MEM_callocN(
+ sizeof(NodeCMPCombSepColor), __func__);
+ storage->mode = CMP_NODE_COMBSEP_COLOR_YCC;
+ storage->ycc_mode = node->custom1;
+ strcpy(node->idname, "CompositorNodeCombineColor");
+ node->storage = storage;
+ break;
+ }
+ case CMP_NODE_COMBYUVA_LEGACY: {
+ node->type = CMP_NODE_COMBINE_COLOR;
+ NodeCMPCombSepColor *storage = (NodeCMPCombSepColor *)MEM_callocN(
+ sizeof(NodeCMPCombSepColor), __func__);
+ storage->mode = CMP_NODE_COMBSEP_COLOR_YUV;
+ strcpy(node->idname, "CompositorNodeCombineColor");
+ node->storage = storage;
+ break;
+ }
+ case CMP_NODE_SEPRGBA_LEGACY: {
+ node->type = CMP_NODE_SEPARATE_COLOR;
+ NodeCMPCombSepColor *storage = (NodeCMPCombSepColor *)MEM_callocN(
+ sizeof(NodeCMPCombSepColor), __func__);
+ storage->mode = CMP_NODE_COMBSEP_COLOR_RGB;
+ strcpy(node->idname, "CompositorNodeSeparateColor");
+ node->storage = storage;
+ break;
+ }
+ case CMP_NODE_SEPHSVA_LEGACY: {
+ node->type = CMP_NODE_SEPARATE_COLOR;
+ NodeCMPCombSepColor *storage = (NodeCMPCombSepColor *)MEM_callocN(
+ sizeof(NodeCMPCombSepColor), __func__);
+ storage->mode = CMP_NODE_COMBSEP_COLOR_HSV;
+ strcpy(node->idname, "CompositorNodeSeparateColor");
+ node->storage = storage;
+ break;
+ }
+ case CMP_NODE_SEPYCCA_LEGACY: {
+ node->type = CMP_NODE_SEPARATE_COLOR;
+ NodeCMPCombSepColor *storage = (NodeCMPCombSepColor *)MEM_callocN(
+ sizeof(NodeCMPCombSepColor), __func__);
+ storage->mode = CMP_NODE_COMBSEP_COLOR_YCC;
+ storage->ycc_mode = node->custom1;
+ strcpy(node->idname, "CompositorNodeSeparateColor");
+ node->storage = storage;
+ break;
+ }
+ case CMP_NODE_SEPYUVA_LEGACY: {
+ node->type = CMP_NODE_SEPARATE_COLOR;
+ NodeCMPCombSepColor *storage = (NodeCMPCombSepColor *)MEM_callocN(
+ sizeof(NodeCMPCombSepColor), __func__);
+ storage->mode = CMP_NODE_COMBSEP_COLOR_YUV;
+ strcpy(node->idname, "CompositorNodeSeparateColor");
+ node->storage = storage;
+ break;
+ }
+ }
+ }
+ }
+
+ /* In texture nodes, replace combine/separate RGBA with combine/separate color */
+ if (ntree->type == NTREE_TEXTURE) {
+ LISTBASE_FOREACH (bNode *, node, &ntree->nodes) {
+ switch (node->type) {
+ case TEX_NODE_COMPOSE_LEGACY: {
+ node->type = TEX_NODE_COMBINE_COLOR;
+ node->custom1 = NODE_COMBSEP_COLOR_RGB;
+ strcpy(node->idname, "TextureNodeCombineColor");
+ break;
+ }
+ case TEX_NODE_DECOMPOSE_LEGACY: {
+ node->type = TEX_NODE_SEPARATE_COLOR;
+ node->custom1 = NODE_COMBSEP_COLOR_RGB;
+ strcpy(node->idname, "TextureNodeSeparateColor");
+ break;
+ }
+ }
+ }
+ }
+
+ /* In shader nodes, replace combine/separate RGB/HSV with combine/separate color */
+ if (ntree->type == NTREE_SHADER) {
+ version_node_input_socket_name(ntree, SH_NODE_COMBRGB_LEGACY, "R", "Red");
+ version_node_input_socket_name(ntree, SH_NODE_COMBRGB_LEGACY, "G", "Green");
+ version_node_input_socket_name(ntree, SH_NODE_COMBRGB_LEGACY, "B", "Blue");
+ version_node_output_socket_name(ntree, SH_NODE_COMBRGB_LEGACY, "Image", "Color");
+
+ version_node_input_socket_name(ntree, SH_NODE_COMBHSV_LEGACY, "H", "Red");
+ version_node_input_socket_name(ntree, SH_NODE_COMBHSV_LEGACY, "S", "Green");
+ version_node_input_socket_name(ntree, SH_NODE_COMBHSV_LEGACY, "V", "Blue");
+
+ version_node_output_socket_name(ntree, SH_NODE_SEPRGB_LEGACY, "R", "Red");
+ version_node_output_socket_name(ntree, SH_NODE_SEPRGB_LEGACY, "G", "Green");
+ version_node_output_socket_name(ntree, SH_NODE_SEPRGB_LEGACY, "B", "Blue");
+ version_node_input_socket_name(ntree, SH_NODE_SEPRGB_LEGACY, "Image", "Color");
+
+ version_node_output_socket_name(ntree, SH_NODE_SEPHSV_LEGACY, "H", "Red");
+ version_node_output_socket_name(ntree, SH_NODE_SEPHSV_LEGACY, "S", "Green");
+ version_node_output_socket_name(ntree, SH_NODE_SEPHSV_LEGACY, "V", "Blue");
+
+ LISTBASE_FOREACH (bNode *, node, &ntree->nodes) {
+ switch (node->type) {
+ case SH_NODE_COMBRGB_LEGACY: {
+ node->type = SH_NODE_COMBINE_COLOR;
+ NodeCombSepColor *storage = (NodeCombSepColor *)MEM_callocN(sizeof(NodeCombSepColor),
+ __func__);
+ storage->mode = NODE_COMBSEP_COLOR_RGB;
+ strcpy(node->idname, "ShaderNodeCombineColor");
+ node->storage = storage;
+ break;
+ }
+ case SH_NODE_COMBHSV_LEGACY: {
+ node->type = SH_NODE_COMBINE_COLOR;
+ NodeCombSepColor *storage = (NodeCombSepColor *)MEM_callocN(sizeof(NodeCombSepColor),
+ __func__);
+ storage->mode = NODE_COMBSEP_COLOR_HSV;
+ strcpy(node->idname, "ShaderNodeCombineColor");
+ node->storage = storage;
+ break;
+ }
+ case SH_NODE_SEPRGB_LEGACY: {
+ node->type = SH_NODE_SEPARATE_COLOR;
+ NodeCombSepColor *storage = (NodeCombSepColor *)MEM_callocN(sizeof(NodeCombSepColor),
+ __func__);
+ storage->mode = NODE_COMBSEP_COLOR_RGB;
+ strcpy(node->idname, "ShaderNodeSeparateColor");
+ node->storage = storage;
+ break;
+ }
+ case SH_NODE_SEPHSV_LEGACY: {
+ node->type = SH_NODE_SEPARATE_COLOR;
+ NodeCombSepColor *storage = (NodeCombSepColor *)MEM_callocN(sizeof(NodeCombSepColor),
+ __func__);
+ storage->mode = NODE_COMBSEP_COLOR_HSV;
+ strcpy(node->idname, "ShaderNodeSeparateColor");
+ node->storage = storage;
+ break;
+ }
+ }
+ }
+ }
+}
+
/* NOLINTNEXTLINE: readability-function-size */
void blo_do_versions_300(FileData *fd, Library *UNUSED(lib), Main *bmain)
{
@@ -2480,8 +2738,8 @@ void blo_do_versions_300(FileData *fd, Library *UNUSED(lib), Main *bmain)
/* Rebuild active/render color attribute references. */
if (!MAIN_VERSION_ATLEAST(bmain, 302, 6)) {
LISTBASE_FOREACH (Brush *, br, &bmain->brushes) {
- /* buggy code in wm_toolsystem broke smear in old files,
- reset to defaults */
+ /* Buggy code in wm_toolsystem broke smear in old files,
+ * reset to defaults. */
if (br->sculpt_tool == SCULPT_TOOL_SMEAR) {
br->alpha = 1.0f;
br->spacing = 5;
@@ -2768,271 +3026,102 @@ void blo_do_versions_300(FileData *fd, Library *UNUSED(lib), Main *bmain)
}
}
- /**
- * Versioning code until next subversion bump goes here.
- *
- * \note Be sure to check when bumping the version:
- * - "versioning_userdef.c", #blo_do_versions_userdef
- * - "versioning_userdef.c", #do_versions_theme
- *
- * \note Keep this message at the bottom of the function.
- */
- {
- /* Keep this block, even when empty. */
-
- /* Replace legacy combine/separate color nodes */
+ if (!MAIN_VERSION_ATLEAST(bmain, 303, 1)) {
FOREACH_NODETREE_BEGIN (bmain, ntree, id) {
- /* In geometry nodes, replace shader combine/separate color nodes with function nodes */
- if (ntree->type == NTREE_GEOMETRY) {
- version_node_input_socket_name(ntree, SH_NODE_COMBRGB_LEGACY, "R", "Red");
- version_node_input_socket_name(ntree, SH_NODE_COMBRGB_LEGACY, "G", "Green");
- version_node_input_socket_name(ntree, SH_NODE_COMBRGB_LEGACY, "B", "Blue");
- version_node_output_socket_name(ntree, SH_NODE_COMBRGB_LEGACY, "Image", "Color");
+ versioning_replace_legacy_combined_and_separate_color_nodes(ntree);
+ }
+ FOREACH_NODETREE_END;
- version_node_output_socket_name(ntree, SH_NODE_SEPRGB_LEGACY, "R", "Red");
- version_node_output_socket_name(ntree, SH_NODE_SEPRGB_LEGACY, "G", "Green");
- version_node_output_socket_name(ntree, SH_NODE_SEPRGB_LEGACY, "B", "Blue");
- version_node_input_socket_name(ntree, SH_NODE_SEPRGB_LEGACY, "Image", "Color");
+ /* Initialize brush curves sculpt settings. */
+ LISTBASE_FOREACH (Brush *, brush, &bmain->brushes) {
+ if (brush->ob_mode != OB_MODE_SCULPT_CURVES) {
+ continue;
+ }
+ if (brush->curves_sculpt_settings->points_per_curve == 0) {
+ brush->curves_sculpt_settings->points_per_curve = 8;
+ }
+ }
- LISTBASE_FOREACH (bNode *, node, &ntree->nodes) {
- switch (node->type) {
- case SH_NODE_COMBRGB_LEGACY: {
- node->type = FN_NODE_COMBINE_COLOR;
- NodeCombSepColor *storage = (NodeCombSepColor *)MEM_callocN(sizeof(NodeCombSepColor),
- __func__);
- storage->mode = NODE_COMBSEP_COLOR_RGB;
- strcpy(node->idname, "FunctionNodeCombineColor");
- node->storage = storage;
- break;
- }
- case SH_NODE_SEPRGB_LEGACY: {
- node->type = FN_NODE_SEPARATE_COLOR;
- NodeCombSepColor *storage = (NodeCombSepColor *)MEM_callocN(sizeof(NodeCombSepColor),
- __func__);
- storage->mode = NODE_COMBSEP_COLOR_RGB;
- strcpy(node->idname, "FunctionNodeSeparateColor");
- node->storage = storage;
- break;
- }
- }
+ /* UDIM Packing. */
+ if (!DNA_struct_elem_find(fd->filesdna, "ImagePackedFile", "int", "tile_number")) {
+ for (Image *ima = bmain->images.first; ima; ima = ima->id.next) {
+ int view;
+ LISTBASE_FOREACH_INDEX (ImagePackedFile *, imapf, &ima->packedfiles, view) {
+ imapf->view = view;
+ imapf->tile_number = 1001;
}
}
+ }
- /* In compositing nodes, replace combine/separate RGBA/HSVA/YCbCrA/YCCA nodes with
- * combine/separate color */
- if (ntree->type == NTREE_COMPOSIT) {
- version_node_input_socket_name(ntree, CMP_NODE_COMBRGBA_LEGACY, "R", "Red");
- version_node_input_socket_name(ntree, CMP_NODE_COMBRGBA_LEGACY, "G", "Green");
- version_node_input_socket_name(ntree, CMP_NODE_COMBRGBA_LEGACY, "B", "Blue");
- version_node_input_socket_name(ntree, CMP_NODE_COMBRGBA_LEGACY, "A", "Alpha");
-
- version_node_input_socket_name(ntree, CMP_NODE_COMBHSVA_LEGACY, "H", "Red");
- version_node_input_socket_name(ntree, CMP_NODE_COMBHSVA_LEGACY, "S", "Green");
- version_node_input_socket_name(ntree, CMP_NODE_COMBHSVA_LEGACY, "V", "Blue");
- version_node_input_socket_name(ntree, CMP_NODE_COMBHSVA_LEGACY, "A", "Alpha");
-
- version_node_input_socket_name(ntree, CMP_NODE_COMBYCCA_LEGACY, "Y", "Red");
- version_node_input_socket_name(ntree, CMP_NODE_COMBYCCA_LEGACY, "Cb", "Green");
- version_node_input_socket_name(ntree, CMP_NODE_COMBYCCA_LEGACY, "Cr", "Blue");
- version_node_input_socket_name(ntree, CMP_NODE_COMBYCCA_LEGACY, "A", "Alpha");
-
- version_node_input_socket_name(ntree, CMP_NODE_COMBYUVA_LEGACY, "Y", "Red");
- version_node_input_socket_name(ntree, CMP_NODE_COMBYUVA_LEGACY, "U", "Green");
- version_node_input_socket_name(ntree, CMP_NODE_COMBYUVA_LEGACY, "V", "Blue");
- version_node_input_socket_name(ntree, CMP_NODE_COMBYUVA_LEGACY, "A", "Alpha");
-
- version_node_output_socket_name(ntree, CMP_NODE_SEPRGBA_LEGACY, "R", "Red");
- version_node_output_socket_name(ntree, CMP_NODE_SEPRGBA_LEGACY, "G", "Green");
- version_node_output_socket_name(ntree, CMP_NODE_SEPRGBA_LEGACY, "B", "Blue");
- version_node_output_socket_name(ntree, CMP_NODE_SEPRGBA_LEGACY, "A", "Alpha");
-
- version_node_output_socket_name(ntree, CMP_NODE_SEPHSVA_LEGACY, "H", "Red");
- version_node_output_socket_name(ntree, CMP_NODE_SEPHSVA_LEGACY, "S", "Green");
- version_node_output_socket_name(ntree, CMP_NODE_SEPHSVA_LEGACY, "V", "Blue");
- version_node_output_socket_name(ntree, CMP_NODE_SEPHSVA_LEGACY, "A", "Alpha");
-
- version_node_output_socket_name(ntree, CMP_NODE_SEPYCCA_LEGACY, "Y", "Red");
- version_node_output_socket_name(ntree, CMP_NODE_SEPYCCA_LEGACY, "Cb", "Green");
- version_node_output_socket_name(ntree, CMP_NODE_SEPYCCA_LEGACY, "Cr", "Blue");
- version_node_output_socket_name(ntree, CMP_NODE_SEPYCCA_LEGACY, "A", "Alpha");
-
- version_node_output_socket_name(ntree, CMP_NODE_SEPYUVA_LEGACY, "Y", "Red");
- version_node_output_socket_name(ntree, CMP_NODE_SEPYUVA_LEGACY, "U", "Green");
- version_node_output_socket_name(ntree, CMP_NODE_SEPYUVA_LEGACY, "V", "Blue");
- version_node_output_socket_name(ntree, CMP_NODE_SEPYUVA_LEGACY, "A", "Alpha");
+ /* Merge still offsets into start/end offsets. */
+ LISTBASE_FOREACH (Scene *, scene, &bmain->scenes) {
+ Editing *ed = SEQ_editing_get(scene);
+ if (ed != NULL) {
+ SEQ_for_each_callback(&ed->seqbase, version_merge_still_offsets, NULL);
+ }
+ }
+ /* Use the curves type enum for the set spline type node, instead of a special one. */
+ FOREACH_NODETREE_BEGIN (bmain, ntree, id) {
+ if (ntree->type == NTREE_GEOMETRY) {
LISTBASE_FOREACH (bNode *, node, &ntree->nodes) {
- switch (node->type) {
- case CMP_NODE_COMBRGBA_LEGACY: {
- node->type = CMP_NODE_COMBINE_COLOR;
- NodeCMPCombSepColor *storage = (NodeCMPCombSepColor *)MEM_callocN(
- sizeof(NodeCMPCombSepColor), __func__);
- storage->mode = CMP_NODE_COMBSEP_COLOR_RGB;
- strcpy(node->idname, "CompositorNodeCombineColor");
- node->storage = storage;
- break;
- }
- case CMP_NODE_COMBHSVA_LEGACY: {
- node->type = CMP_NODE_COMBINE_COLOR;
- NodeCMPCombSepColor *storage = (NodeCMPCombSepColor *)MEM_callocN(
- sizeof(NodeCMPCombSepColor), __func__);
- storage->mode = CMP_NODE_COMBSEP_COLOR_HSV;
- strcpy(node->idname, "CompositorNodeCombineColor");
- node->storage = storage;
- break;
- }
- case CMP_NODE_COMBYCCA_LEGACY: {
- node->type = CMP_NODE_COMBINE_COLOR;
- NodeCMPCombSepColor *storage = (NodeCMPCombSepColor *)MEM_callocN(
- sizeof(NodeCMPCombSepColor), __func__);
- storage->mode = CMP_NODE_COMBSEP_COLOR_YCC;
- storage->ycc_mode = node->custom1;
- strcpy(node->idname, "CompositorNodeCombineColor");
- node->storage = storage;
- break;
- }
- case CMP_NODE_COMBYUVA_LEGACY: {
- node->type = CMP_NODE_COMBINE_COLOR;
- NodeCMPCombSepColor *storage = (NodeCMPCombSepColor *)MEM_callocN(
- sizeof(NodeCMPCombSepColor), __func__);
- storage->mode = CMP_NODE_COMBSEP_COLOR_YUV;
- strcpy(node->idname, "CompositorNodeCombineColor");
- node->storage = storage;
- break;
- }
- case CMP_NODE_SEPRGBA_LEGACY: {
- node->type = CMP_NODE_SEPARATE_COLOR;
- NodeCMPCombSepColor *storage = (NodeCMPCombSepColor *)MEM_callocN(
- sizeof(NodeCMPCombSepColor), __func__);
- storage->mode = CMP_NODE_COMBSEP_COLOR_RGB;
- strcpy(node->idname, "CompositorNodeSeparateColor");
- node->storage = storage;
- break;
- }
- case CMP_NODE_SEPHSVA_LEGACY: {
- node->type = CMP_NODE_SEPARATE_COLOR;
- NodeCMPCombSepColor *storage = (NodeCMPCombSepColor *)MEM_callocN(
- sizeof(NodeCMPCombSepColor), __func__);
- storage->mode = CMP_NODE_COMBSEP_COLOR_HSV;
- strcpy(node->idname, "CompositorNodeSeparateColor");
- node->storage = storage;
- break;
- }
- case CMP_NODE_SEPYCCA_LEGACY: {
- node->type = CMP_NODE_SEPARATE_COLOR;
- NodeCMPCombSepColor *storage = (NodeCMPCombSepColor *)MEM_callocN(
- sizeof(NodeCMPCombSepColor), __func__);
- storage->mode = CMP_NODE_COMBSEP_COLOR_YCC;
- storage->ycc_mode = node->custom1;
- strcpy(node->idname, "CompositorNodeSeparateColor");
- node->storage = storage;
- break;
- }
- case CMP_NODE_SEPYUVA_LEGACY: {
- node->type = CMP_NODE_SEPARATE_COLOR;
- NodeCMPCombSepColor *storage = (NodeCMPCombSepColor *)MEM_callocN(
- sizeof(NodeCMPCombSepColor), __func__);
- storage->mode = CMP_NODE_COMBSEP_COLOR_YUV;
- strcpy(node->idname, "CompositorNodeSeparateColor");
- node->storage = storage;
- break;
+ if (node->type == GEO_NODE_CURVE_SPLINE_TYPE) {
+ NodeGeometryCurveSplineType *storage = (NodeGeometryCurveSplineType *)node->storage;
+ switch (storage->spline_type) {
+ case 0: /* GEO_NODE_SPLINE_TYPE_BEZIER */
+ storage->spline_type = CURVE_TYPE_BEZIER;
+ break;
+ case 1: /* GEO_NODE_SPLINE_TYPE_NURBS */
+ storage->spline_type = CURVE_TYPE_NURBS;
+ break;
+ case 2: /* GEO_NODE_SPLINE_TYPE_POLY */
+ storage->spline_type = CURVE_TYPE_POLY;
+ break;
}
}
}
}
+ }
+ FOREACH_NODETREE_END;
+ }
- /* In texture nodes, replace combine/separate RGBA with combine/separate color */
- if (ntree->type == NTREE_TEXTURE) {
- LISTBASE_FOREACH (bNode *, node, &ntree->nodes) {
- switch (node->type) {
- case TEX_NODE_COMPOSE_LEGACY: {
- node->type = TEX_NODE_COMBINE_COLOR;
- node->custom1 = NODE_COMBSEP_COLOR_RGB;
- strcpy(node->idname, "TextureNodeCombineColor");
- break;
- }
- case TEX_NODE_DECOMPOSE_LEGACY: {
- node->type = TEX_NODE_SEPARATE_COLOR;
- node->custom1 = NODE_COMBSEP_COLOR_RGB;
- strcpy(node->idname, "TextureNodeSeparateColor");
- break;
- }
+ if (!MAIN_VERSION_ATLEAST(bmain, 303, 2)) {
+ LISTBASE_FOREACH (bScreen *, screen, &bmain->screens) {
+ LISTBASE_FOREACH (ScrArea *, area, &screen->areabase) {
+ LISTBASE_FOREACH (SpaceLink *, sl, &area->spacedata) {
+ if (sl->spacetype == SPACE_CLIP) {
+ ((SpaceClip *)sl)->mask_info.blend_factor = 1.0;
}
}
}
+ }
+ }
- /* In shader nodes, replace combine/separate RGB/HSV with combine/separate color */
- if (ntree->type == NTREE_SHADER) {
- version_node_input_socket_name(ntree, SH_NODE_COMBRGB_LEGACY, "R", "Red");
- version_node_input_socket_name(ntree, SH_NODE_COMBRGB_LEGACY, "G", "Green");
- version_node_input_socket_name(ntree, SH_NODE_COMBRGB_LEGACY, "B", "Blue");
- version_node_output_socket_name(ntree, SH_NODE_COMBRGB_LEGACY, "Image", "Color");
-
- version_node_input_socket_name(ntree, SH_NODE_COMBHSV_LEGACY, "H", "Red");
- version_node_input_socket_name(ntree, SH_NODE_COMBHSV_LEGACY, "S", "Green");
- version_node_input_socket_name(ntree, SH_NODE_COMBHSV_LEGACY, "V", "Blue");
-
- version_node_output_socket_name(ntree, SH_NODE_SEPRGB_LEGACY, "R", "Red");
- version_node_output_socket_name(ntree, SH_NODE_SEPRGB_LEGACY, "G", "Green");
- version_node_output_socket_name(ntree, SH_NODE_SEPRGB_LEGACY, "B", "Blue");
- version_node_input_socket_name(ntree, SH_NODE_SEPRGB_LEGACY, "Image", "Color");
-
- version_node_output_socket_name(ntree, SH_NODE_SEPHSV_LEGACY, "H", "Red");
- version_node_output_socket_name(ntree, SH_NODE_SEPHSV_LEGACY, "S", "Green");
- version_node_output_socket_name(ntree, SH_NODE_SEPHSV_LEGACY, "V", "Blue");
-
- LISTBASE_FOREACH (bNode *, node, &ntree->nodes) {
- switch (node->type) {
- case SH_NODE_COMBRGB_LEGACY: {
- node->type = SH_NODE_COMBINE_COLOR;
- NodeCombSepColor *storage = (NodeCombSepColor *)MEM_callocN(sizeof(NodeCombSepColor),
- __func__);
- storage->mode = NODE_COMBSEP_COLOR_RGB;
- strcpy(node->idname, "ShaderNodeCombineColor");
- node->storage = storage;
- break;
- }
- case SH_NODE_COMBHSV_LEGACY: {
- node->type = SH_NODE_COMBINE_COLOR;
- NodeCombSepColor *storage = (NodeCombSepColor *)MEM_callocN(sizeof(NodeCombSepColor),
- __func__);
- storage->mode = NODE_COMBSEP_COLOR_HSV;
- strcpy(node->idname, "ShaderNodeCombineColor");
- node->storage = storage;
- break;
- }
- case SH_NODE_SEPRGB_LEGACY: {
- node->type = SH_NODE_SEPARATE_COLOR;
- NodeCombSepColor *storage = (NodeCombSepColor *)MEM_callocN(sizeof(NodeCombSepColor),
- __func__);
- storage->mode = NODE_COMBSEP_COLOR_RGB;
- strcpy(node->idname, "ShaderNodeSeparateColor");
- node->storage = storage;
- break;
- }
- case SH_NODE_SEPHSV_LEGACY: {
- node->type = SH_NODE_SEPARATE_COLOR;
- NodeCombSepColor *storage = (NodeCombSepColor *)MEM_callocN(sizeof(NodeCombSepColor),
- __func__);
- storage->mode = NODE_COMBSEP_COLOR_HSV;
- strcpy(node->idname, "ShaderNodeSeparateColor");
- node->storage = storage;
- break;
- }
+ if (!MAIN_VERSION_ATLEAST(bmain, 303, 3)) {
+ LISTBASE_FOREACH (bScreen *, screen, &bmain->screens) {
+ LISTBASE_FOREACH (ScrArea *, area, &screen->areabase) {
+ LISTBASE_FOREACH (SpaceLink *, sl, &area->spacedata) {
+ if (sl->spacetype == SPACE_CLIP) {
+ ((SpaceClip *)sl)->mask_info.draw_flag |= MASK_DRAWFLAG_SPLINE;
+ }
+ else if (sl->spacetype == SPACE_IMAGE) {
+ ((SpaceImage *)sl)->mask_info.draw_flag |= MASK_DRAWFLAG_SPLINE;
}
}
}
}
- FOREACH_NODETREE_END;
+ }
- /* Initialize brush curves sculpt settings. */
- LISTBASE_FOREACH (Brush *, brush, &bmain->brushes) {
- if (brush->ob_mode != OB_MODE_SCULPT_CURVES) {
- continue;
- }
- if (brush->curves_sculpt_settings->points_per_curve == 0) {
- brush->curves_sculpt_settings->points_per_curve = 8;
- }
- }
+ /**
+ * Versioning code until next subversion bump goes here.
+ *
+ * \note Be sure to check when bumping the version:
+ * - "versioning_userdef.c", #blo_do_versions_userdef
+ * - "versioning_userdef.c", #do_versions_theme
+ *
+ * \note Keep this message at the bottom of the function.
+ */
+ {
+ /* Keep this block, even when empty. */
}
}
diff --git a/source/blender/blenloader/intern/versioning_defaults.c b/source/blender/blenloader/intern/versioning_defaults.c
index f65976ee55f..6ce53e4a648 100644
--- a/source/blender/blenloader/intern/versioning_defaults.c
+++ b/source/blender/blenloader/intern/versioning_defaults.c
@@ -23,6 +23,7 @@
#include "DNA_curveprofile_types.h"
#include "DNA_gpencil_types.h"
#include "DNA_light_types.h"
+#include "DNA_mask_types.h"
#include "DNA_material_types.h"
#include "DNA_mesh_types.h"
#include "DNA_meshdata_types.h"
@@ -184,6 +185,8 @@ static void blo_update_defaults_screen(bScreen *screen,
else if (area->spacetype == SPACE_CLIP) {
SpaceClip *sclip = area->spacedata.first;
sclip->around = V3D_AROUND_CENTER_MEDIAN;
+ sclip->mask_info.blend_factor = 0.7f;
+ sclip->mask_info.draw_flag = MASK_DRAWFLAG_SPLINE;
}
}
diff --git a/source/blender/blenloader/intern/versioning_userdef.c b/source/blender/blenloader/intern/versioning_userdef.c
index b3f3b9cbf7d..40359500d3c 100644
--- a/source/blender/blenloader/intern/versioning_userdef.c
+++ b/source/blender/blenloader/intern/versioning_userdef.c
@@ -347,6 +347,7 @@ static void do_versions_theme(const UserDef *userdef, bTheme *btheme)
*/
{
/* Keep this block, even when empty. */
+ btheme->tui.wcol_view_item = U_theme_default.tui.wcol_view_item;
}
#undef FROM_DEFAULT_V4_UCHAR
diff --git a/source/blender/blenloader/intern/writefile.c b/source/blender/blenloader/intern/writefile.c
index 2ae660ab1b6..68171f26a66 100644
--- a/source/blender/blenloader/intern/writefile.c
+++ b/source/blender/blenloader/intern/writefile.c
@@ -73,6 +73,8 @@
#include "BLI_utildefines.h"
+#include "CLG_log.h"
+
/* allow writefile to use deprecated functionality (for forward compatibility code) */
#define DNA_DEPRECATED_ALLOW
@@ -133,6 +135,8 @@
#define ZSTD_COMPRESSION_LEVEL 3
+static CLG_LogRef LOG = {"blo.writefile"};
+
/** Use if we want to store how many bytes have been written to the file. */
// #define USE_WRITE_DATA_LEN
@@ -973,7 +977,7 @@ static void write_libraries(WriteData *wd, Main *main)
if (main->curlib->packedfile) {
BKE_packedfile_blend_write(&writer, main->curlib->packedfile);
if (wd->use_memfile == false) {
- printf("write packed .blend: %s\n", main->curlib->filepath);
+ CLOG_INFO(&LOG, 2, "Write packed .blend: %s", main->curlib->filepath);
}
}
@@ -984,12 +988,11 @@ static void write_libraries(WriteData *wd, Main *main)
((id->tag & LIB_TAG_EXTERN) ||
((id->tag & LIB_TAG_INDIRECT) && (id->flag & LIB_INDIRECT_WEAK_LINK)))) {
if (!BKE_idtype_idcode_is_linkable(GS(id->name))) {
- printf(
- "ERROR: write file: data-block '%s' from lib '%s' is not linkable "
- "but is flagged as directly linked\n",
- id->name,
- main->curlib->filepath_abs);
- BLI_assert(0);
+ CLOG_ERROR(&LOG,
+ "Data-block '%s' from lib '%s' is not linkable, but is flagged as "
+ "directly linked",
+ id->name,
+ main->curlib->filepath_abs);
}
writestruct(wd, ID_LINK_PLACEHOLDER, ID, 1, id);
}
@@ -1129,9 +1132,15 @@ static bool write_file_handle(Main *mainvar,
char id_buffer_static[ID_BUFFER_STATIC_SIZE];
void *id_buffer = id_buffer_static;
- const size_t idtype_struct_size = BKE_idtype_get_info_from_id(id)->struct_size;
+ const IDTypeInfo *id_type = BKE_idtype_get_info_from_id(id);
+ const size_t idtype_struct_size = id_type->struct_size;
if (idtype_struct_size > ID_BUFFER_STATIC_SIZE) {
- BLI_assert(0);
+ CLOG_ERROR(&LOG,
+ "ID maximum buffer size (%d bytes) is not big enough to fit IDs of type %s, "
+ "which needs %lu bytes",
+ ID_BUFFER_STATIC_SIZE,
+ id_type->name,
+ id_type->struct_size);
id_buffer = MEM_mallocN(idtype_struct_size, __func__);
}
@@ -1200,7 +1209,6 @@ static bool write_file_handle(Main *mainvar,
* #direct_link_id_common in `readfile.c` anyway, */
((ID *)id_buffer)->py_instance = NULL;
- const IDTypeInfo *id_type = BKE_idtype_get_info_from_id(id);
if (id_type->blend_write != NULL) {
id_type->blend_write(&writer, (ID *)id_buffer, id);
}
@@ -1349,7 +1357,6 @@ bool BLO_write_file(Main *mainvar,
/* 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 (relbase_valid == false) {
@@ -1388,6 +1395,13 @@ bool BLO_write_file(Main *mainvar,
}
if (remap_mode != BLO_WRITE_PATH_REMAP_NONE) {
+ /* Some path processing (e.g. with libraries) may use the current `main->filepath`, if this
+ * is not matching the path currently used for saving, unexpected paths corruptions can
+ * happen. See T98201. */
+ char mainvar_filepath_orig[FILE_MAX];
+ STRNCPY(mainvar_filepath_orig, mainvar->filepath);
+ STRNCPY(mainvar->filepath, filepath);
+
/* Check if we need to backup and restore paths. */
if (UNLIKELY(use_save_as_copy)) {
path_list_backup = BKE_bpath_list_backup(mainvar, path_list_flag);
@@ -1409,9 +1423,11 @@ bool BLO_write_file(Main *mainvar,
BKE_bpath_absolute_convert(mainvar, dir_src, NULL);
break;
case BLO_WRITE_PATH_REMAP_NONE:
- BLI_assert(0); /* Unreachable. */
+ BLI_assert_unreachable(); /* Unreachable. */
break;
}
+
+ STRNCPY(mainvar->filepath, mainvar_filepath_orig);
}
}
@@ -1482,7 +1498,7 @@ void BLO_write_struct_array_by_name(BlendWriter *writer,
{
int struct_id = BLO_get_struct_id_by_name(writer, struct_name);
if (UNLIKELY(struct_id == -1)) {
- printf("error: can't find SDNA code <%s>\n", struct_name);
+ CLOG_ERROR(&LOG, "Can't find SDNA code <%s>", struct_name);
return;
}
BLO_write_struct_array_by_id(writer, struct_id, array_size, data_ptr);
@@ -1530,7 +1546,7 @@ void BLO_write_struct_list_by_name(BlendWriter *writer, const char *struct_name,
{
int struct_id = BLO_get_struct_id_by_name(writer, struct_name);
if (UNLIKELY(struct_id == -1)) {
- printf("error: can't find SDNA code <%s>\n", struct_name);
+ CLOG_ERROR(&LOG, "Can't find SDNA code <%s>", struct_name);
return;
}
BLO_write_struct_list_by_id(writer, struct_id, list);
diff --git a/source/blender/blentranslation/BLT_translation.h b/source/blender/blentranslation/BLT_translation.h
index ebb0f604df7..129eba3de2f 100644
--- a/source/blender/blentranslation/BLT_translation.h
+++ b/source/blender/blentranslation/BLT_translation.h
@@ -28,13 +28,6 @@ const char *BLT_translate_do_iface(const char *msgctxt, const char *msgid);
const char *BLT_translate_do_tooltip(const char *msgctxt, const char *msgid);
const char *BLT_translate_do_new_dataname(const char *msgctxt, const char *msgid);
-/**
- * Note that "lang" here is the _output_ display language. We used to restrict
- * IME for keyboard _input_ language because our multilingual font was only used
- * when some output languages were selected. That font is used all the time now.
- */
-bool BLT_lang_is_ime_supported(void);
-
/* The "translation-marker" macro. */
#define N_(msgid) msgid
#define CTX_N_(context, msgid) msgid
diff --git a/source/blender/blentranslation/intern/blt_lang.c b/source/blender/blentranslation/intern/blt_lang.c
index b015057ad2d..cb04b3ac0dc 100644
--- a/source/blender/blentranslation/intern/blt_lang.c
+++ b/source/blender/blentranslation/intern/blt_lang.c
@@ -345,12 +345,3 @@ void BLT_lang_locale_explode(const char *locale,
MEM_freeN(_t);
}
}
-
-bool BLT_lang_is_ime_supported(void)
-{
-#ifdef WITH_INPUT_IME
- return true;
-#else
- return false;
-#endif
-}
diff --git a/source/blender/bmesh/intern/bmesh_construct.c b/source/blender/bmesh/intern/bmesh_construct.c
index ff8506f1868..a7637d2712c 100644
--- a/source/blender/bmesh/intern/bmesh_construct.c
+++ b/source/blender/bmesh/intern/bmesh_construct.c
@@ -60,8 +60,11 @@ void BM_edges_from_verts_ensure(BMesh *bm, BMEdge **edge_arr, BMVert **vert_arr,
}
/* prototypes */
-static void bm_loop_attrs_copy(
- BMesh *bm_src, BMesh *bm_dst, const BMLoop *l_src, BMLoop *l_dst, CustomDataMask mask_exclude);
+static void bm_loop_attrs_copy(BMesh *bm_src,
+ BMesh *bm_dst,
+ const BMLoop *l_src,
+ BMLoop *l_dst,
+ eCustomDataMask mask_exclude);
BMFace *BM_face_create_quad_tri(BMesh *bm,
BMVert *v1,
@@ -321,7 +324,7 @@ void BM_verts_sort_radial_plane(BMVert **vert_arr, int len)
/*************************************************************/
static void bm_vert_attrs_copy(
- BMesh *bm_src, BMesh *bm_dst, const BMVert *v_src, BMVert *v_dst, CustomDataMask mask_exclude)
+ BMesh *bm_src, BMesh *bm_dst, const BMVert *v_src, BMVert *v_dst, eCustomDataMask mask_exclude)
{
if ((bm_src == bm_dst) && (v_src == v_dst)) {
BLI_assert_msg(0, "BMVert: source and target match");
@@ -336,7 +339,7 @@ static void bm_vert_attrs_copy(
}
static void bm_edge_attrs_copy(
- BMesh *bm_src, BMesh *bm_dst, const BMEdge *e_src, BMEdge *e_dst, CustomDataMask mask_exclude)
+ BMesh *bm_src, BMesh *bm_dst, const BMEdge *e_src, BMEdge *e_dst, eCustomDataMask mask_exclude)
{
if ((bm_src == bm_dst) && (e_src == e_dst)) {
BLI_assert_msg(0, "BMEdge: source and target match");
@@ -348,7 +351,7 @@ static void bm_edge_attrs_copy(
}
static void bm_loop_attrs_copy(
- BMesh *bm_src, BMesh *bm_dst, const BMLoop *l_src, BMLoop *l_dst, CustomDataMask mask_exclude)
+ BMesh *bm_src, BMesh *bm_dst, const BMLoop *l_src, BMLoop *l_dst, eCustomDataMask mask_exclude)
{
if ((bm_src == bm_dst) && (l_src == l_dst)) {
BLI_assert_msg(0, "BMLoop: source and target match");
@@ -360,7 +363,7 @@ static void bm_loop_attrs_copy(
}
static void bm_face_attrs_copy(
- BMesh *bm_src, BMesh *bm_dst, const BMFace *f_src, BMFace *f_dst, CustomDataMask mask_exclude)
+ BMesh *bm_src, BMesh *bm_dst, const BMFace *f_src, BMFace *f_dst, eCustomDataMask mask_exclude)
{
if ((bm_src == bm_dst) && (f_src == f_dst)) {
BLI_assert_msg(0, "BMFace: source and target match");
diff --git a/source/blender/bmesh/intern/bmesh_core.c b/source/blender/bmesh/intern/bmesh_core.c
index d6bf556f14b..4d84d558cd7 100644
--- a/source/blender/bmesh/intern/bmesh_core.c
+++ b/source/blender/bmesh/intern/bmesh_core.c
@@ -1460,7 +1460,7 @@ BMFace *bmesh_kernel_split_face_make_edge(BMesh *bm,
}
else {
/* this code is not significant until holes actually work */
- // printf("warning: call to split face euler without holes argument; holes will be tossed.\n");
+ // printf("WARNING: call to split face euler without holes argument; holes will be tossed.\n");
for (lst = f->loops.last; lst != f->loops.first; lst = lst2) {
lst2 = lst->prev;
BLI_mempool_free(bm->looplistpool, lst);
diff --git a/source/blender/bmesh/intern/bmesh_edgeloop.c b/source/blender/bmesh/intern/bmesh_edgeloop.c
index ee8c22df630..4391a6a92d7 100644
--- a/source/blender/bmesh/intern/bmesh_edgeloop.c
+++ b/source/blender/bmesh/intern/bmesh_edgeloop.c
@@ -460,7 +460,7 @@ void BM_mesh_edgeloops_calc_order(BMesh *UNUSED(bm), ListBase *eloops, const boo
for (el_store = eloops->first; el_store; el_store = el_store->next) {
float len_sq;
if (use_normals) {
- /* scale the length by how close the loops are to pointing at eachother */
+ /* Scale the length by how close the loops are to pointing at each other. */
float dir[3];
sub_v3_v3v3(dir, co, el_store->co);
len_sq = normalize_v3(dir);
diff --git a/source/blender/bmesh/intern/bmesh_interp.c b/source/blender/bmesh/intern/bmesh_interp.c
index 2f5827bdc4c..0c3db31dd1f 100644
--- a/source/blender/bmesh/intern/bmesh_interp.c
+++ b/source/blender/bmesh/intern/bmesh_interp.c
@@ -894,6 +894,27 @@ void BM_data_layer_free(BMesh *bm, CustomData *data, int type)
}
}
+bool BM_data_layer_free_named(BMesh *bm, CustomData *data, const char *name)
+{
+ CustomData olddata = *data;
+ olddata.layers = (olddata.layers) ? MEM_dupallocN(olddata.layers) : NULL;
+
+ /* the pool is now owned by olddata and must not be shared */
+ data->pool = NULL;
+
+ const bool has_layer = CustomData_free_layer_named(data, name, 0);
+
+ if (has_layer) {
+ update_data_blocks(bm, &olddata, data);
+ }
+
+ if (olddata.layers) {
+ MEM_freeN(olddata.layers);
+ }
+
+ return has_layer;
+}
+
void BM_data_layer_free_n(BMesh *bm, CustomData *data, int type, int n)
{
CustomData olddata;
diff --git a/source/blender/bmesh/intern/bmesh_interp.h b/source/blender/bmesh/intern/bmesh_interp.h
index a2f1dfc706d..2cf9dffceec 100644
--- a/source/blender/bmesh/intern/bmesh_interp.h
+++ b/source/blender/bmesh/intern/bmesh_interp.h
@@ -59,6 +59,10 @@ void BM_data_interp_face_vert_edge(
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);
+/**
+ * Remove a named custom data layer, if it existed. Return true if the layer was removed.
+ */
+bool BM_data_layer_free_named(BMesh *bm, CustomData *data, const char *name);
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);
diff --git a/source/blender/bmesh/intern/bmesh_log.c b/source/blender/bmesh/intern/bmesh_log.c
index a398f14b312..a81ae934629 100644
--- a/source/blender/bmesh/intern/bmesh_log.c
+++ b/source/blender/bmesh/intern/bmesh_log.c
@@ -288,6 +288,8 @@ static void bm_log_verts_restore(BMesh *bm, BMLog *log, GHash *verts)
static void bm_log_faces_restore(BMesh *bm, BMLog *log, GHash *faces)
{
GHashIterator gh_iter;
+ const int cd_face_sets = CustomData_get_offset(&bm->pdata, CD_SCULPT_FACE_SETS);
+
GHASH_ITER (gh_iter, faces) {
void *key = BLI_ghashIterator_getKey(&gh_iter);
BMLogFace *lf = BLI_ghashIterator_getValue(&gh_iter);
@@ -301,6 +303,11 @@ static void bm_log_faces_restore(BMesh *bm, BMLog *log, GHash *faces)
f = BM_face_create_verts(bm, v, 3, NULL, BM_CREATE_NOP, true);
f->head.hflag = lf->hflag;
bm_log_face_id_set(log, f, POINTER_AS_UINT(key));
+
+ /* Ensure face sets have valid values. Fixes T80174. */
+ if (cd_face_sets != -1) {
+ BM_ELEM_CD_SET_INT(f, cd_face_sets, 1);
+ }
}
}
diff --git a/source/blender/bmesh/intern/bmesh_mesh_convert.cc b/source/blender/bmesh/intern/bmesh_mesh_convert.cc
index 40f1d7c496d..884f6b5388a 100644
--- a/source/blender/bmesh/intern/bmesh_mesh_convert.cc
+++ b/source/blender/bmesh/intern/bmesh_mesh_convert.cc
@@ -225,9 +225,6 @@ 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 (params->calc_vert_normal) {
vert_normals = BKE_mesh_vertex_normals_ensure(me);
@@ -934,7 +931,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 == nullptr which can crash T28625. */
+ * end up with 'me->totface' and `me->mface == nullptr` which can crash T28625. */
me->totface = 0;
me->act_face = -1;
diff --git a/source/blender/bmesh/intern/bmesh_mods.c b/source/blender/bmesh/intern/bmesh_mods.c
index 70710edea5c..8b56e08c22b 100644
--- a/source/blender/bmesh/intern/bmesh_mods.c
+++ b/source/blender/bmesh/intern/bmesh_mods.c
@@ -597,7 +597,7 @@ bool BM_face_validate(BMFace *face, FILE *err)
bool ret = true;
if (face->len == 2) {
- fprintf(err, "warning: found two-edged face. face ptr: %p\n", face);
+ fprintf(err, "WARNING: found two-edged face. face ptr: %p\n", face);
fflush(err);
}
diff --git a/source/blender/bmesh/intern/bmesh_polygon.c b/source/blender/bmesh/intern/bmesh_polygon.c
index 9ea16c8b61c..6df446a377c 100644
--- a/source/blender/bmesh/intern/bmesh_polygon.c
+++ b/source/blender/bmesh/intern/bmesh_polygon.c
@@ -415,7 +415,7 @@ void BM_face_calc_tangent_edge_diagonal(const BMFace *f, float r_tangent[3])
/* In case of degenerate faces. */
zero_v3(r_tangent);
- /* warning: O(n^2) loop here, take care! */
+ /* WARNING: O(n^2) loop here, take care! */
float dist_max_sq = 0.0f;
do {
BMLoop *l_iter_other = l_iter->next;
@@ -447,7 +447,7 @@ void BM_face_calc_tangent_vert_diagonal(const BMFace *f, float r_tangent[3])
/* In case of degenerate faces. */
zero_v3(r_tangent);
- /* warning: O(n^2) loop here, take care! */
+ /* WARNING: O(n^2) loop here, take care! */
float dist_max_sq = 0.0f;
do {
BMLoop *l_iter_other = l_iter->next;
diff --git a/source/blender/bmesh/operators/bmo_join_triangles.c b/source/blender/bmesh/operators/bmo_join_triangles.c
index aa7f0f511ec..1339efb3057 100644
--- a/source/blender/bmesh/operators/bmo_join_triangles.c
+++ b/source/blender/bmesh/operators/bmo_join_triangles.c
@@ -145,7 +145,7 @@ static bool bm_edge_is_contiguous_loop_cd_all(const BMEdge *e,
}
static bool bm_edge_delimit_cdata(CustomData *ldata,
- CustomDataType type,
+ eCustomDataType type,
struct DelimitData_CD *r_delim_cd)
{
const int layer_len = CustomData_number_of_layers(ldata, type);
diff --git a/source/blender/bmesh/tools/bmesh_bevel.c b/source/blender/bmesh/tools/bmesh_bevel.c
index 8f32f878c58..fa852cdd6da 100644
--- a/source/blender/bmesh/tools/bmesh_bevel.c
+++ b/source/blender/bmesh/tools/bmesh_bevel.c
@@ -5354,7 +5354,7 @@ static BMEdge *snap_edge_for_center_vmesh_vert(int i,
* so the arguments bndv_rep_faces is an array of size n_bndv give the freps for each i,
* and center_frep is the frep for the center.
*
- * Note: this function is for edge bevels only, at the moment.
+ * NOTE: this function is for edge bevels only, at the moment.
*/
static void snap_edges_for_vmesh_vert(int i,
int j,
diff --git a/source/blender/compositor/intern/COM_Debug.cc b/source/blender/compositor/intern/COM_Debug.cc
index 66dbabe71b5..d0f0be590f6 100644
--- a/source/blender/compositor/intern/COM_Debug.cc
+++ b/source/blender/compositor/intern/COM_Debug.cc
@@ -420,7 +420,7 @@ void DebugInfo::graphviz(const ExecutionSystem *system, StringRefNull name)
char *str = (char *)MEM_mallocN(max_textlength, __func__);
if (graphviz_system(system, str, max_textlength - 1)) {
char basename[FILE_MAX];
- char filename[FILE_MAX];
+ char filepath[FILE_MAX];
if (name.is_empty()) {
BLI_snprintf(basename, sizeof(basename), "compositor_%d.dot", file_index_);
@@ -428,12 +428,12 @@ void DebugInfo::graphviz(const ExecutionSystem *system, StringRefNull name)
else {
BLI_strncpy(basename, (name + ".dot").c_str(), sizeof(basename));
}
- BLI_join_dirfile(filename, sizeof(filename), BKE_tempdir_session(), basename);
+ BLI_join_dirfile(filepath, sizeof(filepath), BKE_tempdir_session(), basename);
file_index_++;
- std::cout << "Writing compositor debug to: " << filename << "\n";
+ std::cout << "Writing compositor debug to: " << filepath << "\n";
- FILE *fp = BLI_fopen(filename, "wb");
+ FILE *fp = BLI_fopen(filepath, "wb");
fputs(str, fp);
fclose(fp);
}
diff --git a/source/blender/compositor/operations/COM_FastGaussianBlurOperation.cc b/source/blender/compositor/operations/COM_FastGaussianBlurOperation.cc
index 573a740dac8..725751d15af 100644
--- a/source/blender/compositor/operations/COM_FastGaussianBlurOperation.cc
+++ b/source/blender/compositor/operations/COM_FastGaussianBlurOperation.cc
@@ -112,7 +112,7 @@ void FastGaussianBlurOperation::IIR_gauss(MemoryBuffer *src,
double *X, *Y, *W;
const unsigned int src_width = src->get_width();
const unsigned int src_height = src->get_height();
- unsigned int x, y, sz;
+ unsigned int x, y, src_dim_max;
unsigned int i;
float *buffer = src->get_buffer();
const uint8_t num_channels = src->get_num_channels();
@@ -202,10 +202,10 @@ void FastGaussianBlurOperation::IIR_gauss(MemoryBuffer *src,
(void)0
/* Intermediate buffers. */
- sz = MAX2(src_width, src_height);
- X = (double *)MEM_callocN(sz * sizeof(double), "IIR_gauss X buf");
- Y = (double *)MEM_callocN(sz * sizeof(double), "IIR_gauss Y buf");
- W = (double *)MEM_callocN(sz * sizeof(double), "IIR_gauss W buf");
+ src_dim_max = MAX2(src_width, src_height);
+ X = (double *)MEM_callocN(src_dim_max * sizeof(double), "IIR_gauss X buf");
+ Y = (double *)MEM_callocN(src_dim_max * sizeof(double), "IIR_gauss Y buf");
+ W = (double *)MEM_callocN(src_dim_max * sizeof(double), "IIR_gauss W buf");
if (xy & 1) { /* H. */
int offset;
for (y = 0; y < src_height; y++) {
diff --git a/source/blender/compositor/operations/COM_OutputFileMultiViewOperation.cc b/source/blender/compositor/operations/COM_OutputFileMultiViewOperation.cc
index aeaf6b659e3..341541b4cdd 100644
--- a/source/blender/compositor/operations/COM_OutputFileMultiViewOperation.cc
+++ b/source/blender/compositor/operations/COM_OutputFileMultiViewOperation.cc
@@ -325,7 +325,6 @@ void OutputStereoOperation::deinit_execution()
/* do colormanagement in the individual views, so it doesn't need to do in the stereo */
IMB_colormanagement_imbuf_for_write(ibuf[i], true, false, &format_);
- IMB_prepare_write_ImBuf(IMB_isfloat(ibuf[i]), ibuf[i]);
}
/* create stereo buffer */
diff --git a/source/blender/compositor/operations/COM_OutputFileOperation.cc b/source/blender/compositor/operations/COM_OutputFileOperation.cc
index 372e0736cd2..49de275c256 100644
--- a/source/blender/compositor/operations/COM_OutputFileOperation.cc
+++ b/source/blender/compositor/operations/COM_OutputFileOperation.cc
@@ -219,6 +219,12 @@ OutputSingleLayerOperation::OutputSingleLayerOperation(const Scene *scene,
image_input_ = nullptr;
BKE_image_format_init_for_write(&format_, scene, format);
+ if (!save_as_render) {
+ /* If not saving as render, stop IMB_colormanagement_imbuf_for_write using this
+ * colorspace for conversion. */
+ format_.linear_colorspace_settings.name[0] = '\0';
+ }
+
BLI_strncpy(path_, path, sizeof(path_));
view_name_ = view_name;
diff --git a/source/blender/compositor/operations/COM_TonemapOperation.h b/source/blender/compositor/operations/COM_TonemapOperation.h
index 84ee9c563fd..7868aa140dc 100644
--- a/source/blender/compositor/operations/COM_TonemapOperation.h
+++ b/source/blender/compositor/operations/COM_TonemapOperation.h
@@ -81,8 +81,8 @@ class TonemapOperation : public MultiThreadedOperation {
};
/**
- * \brief class of tonemap, implementing the photoreceptor tonemap
- * most parts have already been done in TonemapOperation
+ * \brief class of tone-map, implementing the photo-receptor tone-map
+ * most parts have already been done in #TonemapOperation.
* \ingroup operation
*/
diff --git a/source/blender/datatoc/datatoc_icon.py b/source/blender/datatoc/datatoc_icon.py
index cce464dbc41..7373df71318 100755
--- a/source/blender/datatoc/datatoc_icon.py
+++ b/source/blender/datatoc/datatoc_icon.py
@@ -1,7 +1,5 @@
#!/usr/bin/env python3
# SPDX-License-Identifier: GPL-2.0-or-later
-
-# <pep8 compliant>
_IS_BIG_ENDIAN = (__import__("sys").byteorder != 'little')
diff --git a/source/blender/datatoc/datatoc_icon_split.py b/source/blender/datatoc/datatoc_icon_split.py
index fcfd63f8707..8edafeda328 100755
--- a/source/blender/datatoc/datatoc_icon_split.py
+++ b/source/blender/datatoc/datatoc_icon_split.py
@@ -1,7 +1,5 @@
# SPDX-License-Identifier: GPL-2.0-or-later
-# <pep8 compliant>
-
"""
This script dices up PNG into small files to store in version control.
diff --git a/source/blender/depsgraph/CMakeLists.txt b/source/blender/depsgraph/CMakeLists.txt
index a5693cb0fd7..3d539018cef 100644
--- a/source/blender/depsgraph/CMakeLists.txt
+++ b/source/blender/depsgraph/CMakeLists.txt
@@ -40,6 +40,7 @@ set(SRC
intern/builder/deg_builder_relations_view_layer.cc
intern/builder/deg_builder_remove_noop.cc
intern/builder/deg_builder_rna.cc
+ intern/builder/deg_builder_stack.cc
intern/builder/deg_builder_transitive.cc
intern/builder/pipeline.cc
intern/builder/pipeline_all_objects.cc
@@ -103,6 +104,7 @@ set(SRC
intern/builder/deg_builder_relations_impl.h
intern/builder/deg_builder_remove_noop.h
intern/builder/deg_builder_rna.h
+ intern/builder/deg_builder_stack.h
intern/builder/deg_builder_transitive.h
intern/builder/pipeline.h
intern/builder/pipeline_all_objects.h
diff --git a/source/blender/depsgraph/DEG_depsgraph_query.h b/source/blender/depsgraph/DEG_depsgraph_query.h
index ade75fa2f6f..12663e74d24 100644
--- a/source/blender/depsgraph/DEG_depsgraph_query.h
+++ b/source/blender/depsgraph/DEG_depsgraph_query.h
@@ -64,7 +64,7 @@ bool DEG_id_type_any_updated(const struct Depsgraph *depsgraph);
bool DEG_id_type_any_exists(const struct Depsgraph *depsgraph, short id_type);
/** Get additional evaluation flags for the given ID. */
-uint32_t DEG_get_eval_flags_for_id(const struct Depsgraph *graph, struct ID *id);
+uint32_t DEG_get_eval_flags_for_id(const struct Depsgraph *graph, const struct ID *id);
/** Get additional mesh CustomData_MeshMasks flags for the given object. */
void DEG_get_customdata_mask_for_object(const struct Depsgraph *graph,
diff --git a/source/blender/depsgraph/intern/builder/deg_builder.cc b/source/blender/depsgraph/intern/builder/deg_builder.cc
index 8ee94ab0a34..a3cd821e82f 100644
--- a/source/blender/depsgraph/intern/builder/deg_builder.cc
+++ b/source/blender/depsgraph/intern/builder/deg_builder.cc
@@ -54,9 +54,9 @@ bool deg_check_base_in_depsgraph(const Depsgraph *graph, Base *base)
return id_node->has_base;
}
-/*******************************************************************************
- * Base class for builders.
- */
+/* -------------------------------------------------------------------- */
+/** \name Base Class for Builders
+ * \{ */
DepsgraphBuilder::DepsgraphBuilder(Main *bmain, Depsgraph *graph, DepsgraphBuilderCache *cache)
: bmain_(bmain), graph_(graph), cache_(cache)
@@ -120,9 +120,11 @@ bool DepsgraphBuilder::check_pchan_has_bbone_segments(Object *object, const char
return check_pchan_has_bbone_segments(object, pchan);
}
-/*******************************************************************************
- * Builder finalizer.
- */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Builder Finalizer.
+ * \{ */
namespace {
@@ -136,8 +138,22 @@ void deg_graph_build_flush_visibility(Depsgraph *graph)
for (IDNode *id_node : graph->id_nodes) {
for (ComponentNode *comp_node : id_node->components.values()) {
comp_node->affects_directly_visible |= id_node->is_directly_visible;
+
+ /* Enforce "visibility" of the synchronization component.
+ *
+ * This component is never connected to other ID nodes, and hence can not be handled in the
+ * same way as other components needed for evaluation. It is only needed for proper
+ * evaluation of the ID node it belongs to.
+ *
+ * The design is such that the synchronization is supposed to happen whenever any part of the
+ * ID changed/evaluated. Here we mark the component as "visible" so that genetic recalc flag
+ * flushing and scheduling will handle the component in a generic manner. */
+ if (comp_node->type == NodeType::SYNCHRONIZATION) {
+ comp_node->affects_directly_visible = true;
+ }
}
}
+
for (OperationNode *op_node : graph->operations) {
op_node->custom_flags = 0;
op_node->num_links_pending = 0;
@@ -151,6 +167,7 @@ void deg_graph_build_flush_visibility(Depsgraph *graph)
op_node->custom_flags |= DEG_NODE_VISITED;
}
}
+
while (!BLI_stack_is_empty(stack)) {
OperationNode *op_node;
BLI_stack_pop(stack, &op_node);
@@ -198,7 +215,7 @@ void deg_graph_build_flush_visibility(Depsgraph *graph)
void deg_graph_build_finalize(Main *bmain, Depsgraph *graph)
{
- /* Make sure dependencies of visible ID datablocks are visible. */
+ /* Make sure dependencies of visible ID data-blocks are visible. */
deg_graph_build_flush_visibility(graph);
deg_graph_remove_unused_noops(graph);
@@ -233,4 +250,6 @@ void deg_graph_build_finalize(Main *bmain, Depsgraph *graph)
}
}
+/** \} */
+
} // namespace blender::deg
diff --git a/source/blender/depsgraph/intern/builder/deg_builder_cycle.cc b/source/blender/depsgraph/intern/builder/deg_builder_cycle.cc
index d632c4e2f7e..8ba6c840a59 100644
--- a/source/blender/depsgraph/intern/builder/deg_builder_cycle.cc
+++ b/source/blender/depsgraph/intern/builder/deg_builder_cycle.cc
@@ -42,9 +42,7 @@ struct StackEntry {
struct CyclesSolverState {
CyclesSolverState(Depsgraph *graph)
- : graph(graph),
- traversal_stack(BLI_stack_new(sizeof(StackEntry), "DEG detect cycles stack")),
- num_cycles(0)
+ : graph(graph), traversal_stack(BLI_stack_new(sizeof(StackEntry), "DEG detect cycles stack"))
{
/* pass */
}
@@ -57,7 +55,7 @@ struct CyclesSolverState {
}
Depsgraph *graph;
BLI_Stack *traversal_stack;
- int num_cycles;
+ int num_cycles = 0;
};
inline void set_node_visited_state(Node *node, eCyclicCheckVisitedState state)
diff --git a/source/blender/depsgraph/intern/builder/deg_builder_nodes.cc b/source/blender/depsgraph/intern/builder/deg_builder_nodes.cc
index 4782f1c4a5d..657bc3eb25c 100644
--- a/source/blender/depsgraph/intern/builder/deg_builder_nodes.cc
+++ b/source/blender/depsgraph/intern/builder/deg_builder_nodes.cc
@@ -78,6 +78,7 @@
#include "BKE_modifier.h"
#include "BKE_movieclip.h"
#include "BKE_node.h"
+#include "BKE_node_runtime.hh"
#include "BKE_object.h"
#include "BKE_particle.h"
#include "BKE_pointcache.h"
@@ -1078,14 +1079,18 @@ void DepsgraphNodeBuilder::build_animdata_nlastrip_targets(ListBase *strips)
void DepsgraphNodeBuilder::build_animation_images(ID *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);
+ /* GPU materials might use an animated image. However, these materials have no been built yet so
+ * we have to check if they might be created during evaluation. */
+ bool has_image_animation = false;
+ if (ELEM(GS(id->name), ID_MA, ID_WO)) {
+ bNodeTree *ntree = *BKE_ntree_ptr_from_id(id);
+ if (ntree != nullptr &&
+ ntree->runtime->runtime_flag & NTREE_RUNTIME_FLAG_HAS_IMAGE_ANIMATION) {
+ has_image_animation = true;
+ }
+ }
- if (can_have_gpu_material || BKE_image_user_id_has_animation(id)) {
+ if (has_image_animation || BKE_image_user_id_has_animation(id)) {
ID *id_cow = get_cow_id(id);
add_operation_node(
id,
diff --git a/source/blender/depsgraph/intern/builder/deg_builder_relations.cc b/source/blender/depsgraph/intern/builder/deg_builder_relations.cc
index 23147b63e27..c13c6d2f870 100644
--- a/source/blender/depsgraph/intern/builder/deg_builder_relations.cc
+++ b/source/blender/depsgraph/intern/builder/deg_builder_relations.cc
@@ -71,6 +71,7 @@
#include "BKE_mball.h"
#include "BKE_modifier.h"
#include "BKE_node.h"
+#include "BKE_node_runtime.hh"
#include "BKE_object.h"
#include "BKE_particle.h"
#include "BKE_pointcache.h"
@@ -586,11 +587,12 @@ void DepsgraphRelationBuilder::build_id(ID *id)
void DepsgraphRelationBuilder::build_generic_id(ID *id)
{
-
if (built_map_.checkIsBuiltAndTag(id)) {
return;
}
+ const BuilderStack::ScopedEntry stack_entry = stack_.trace(*id);
+
build_idproperties(id->properties);
build_animdata(id);
build_parameters(id);
@@ -621,6 +623,9 @@ void DepsgraphRelationBuilder::build_collection(LayerCollection *from_layer_coll
* recurses into all the nested objects and collections. */
return;
}
+
+ const BuilderStack::ScopedEntry stack_entry = stack_.trace(collection->id);
+
const bool group_done = built_map_.checkIsBuiltAndTag(collection);
OperationKey object_transform_final_key(object != nullptr ? &object->id : nullptr,
NodeType::TRANSFORM,
@@ -684,6 +689,9 @@ void DepsgraphRelationBuilder::build_object(Object *object)
if (built_map_.checkIsBuiltAndTag(object)) {
return;
}
+
+ const BuilderStack::ScopedEntry stack_entry = stack_.trace(object->id);
+
/* Object Transforms */
OperationCode base_op = (object->parent) ? OperationCode::TRANSFORM_PARENT :
OperationCode::TRANSFORM_LOCAL;
@@ -1129,10 +1137,14 @@ void DepsgraphRelationBuilder::build_constraints(ID *id,
/* Add dependencies for each constraint in turn. */
for (bConstraint *con = (bConstraint *)constraints->first; con; con = con->next) {
const bConstraintTypeInfo *cti = BKE_constraint_typeinfo_get(con);
+ ListBase targets = {nullptr, nullptr};
/* Invalid constraint type. */
if (cti == nullptr) {
continue;
}
+
+ const BuilderStack::ScopedEntry stack_entry = stack_.trace(*con);
+
/* Special case for camera tracking -- it doesn't use targets to
* define relations. */
/* TODO: we can now represent dependencies in a much richer manner,
@@ -1177,9 +1189,7 @@ void DepsgraphRelationBuilder::build_constraints(ID *id,
add_relation(cache_key, constraint_op_key, cti->name);
}
}
- else if (cti->get_constraint_targets) {
- ListBase targets = {nullptr, nullptr};
- cti->get_constraint_targets(con, &targets);
+ else if (BKE_constraint_targets_get(con, &targets)) {
LISTBASE_FOREACH (bConstraintTarget *, ct, &targets) {
if (ct->tar == nullptr) {
continue;
@@ -1289,9 +1299,7 @@ void DepsgraphRelationBuilder::build_constraints(ID *id,
add_relation(target_transform_key, constraint_op_key, cti->name);
}
}
- if (cti->flush_constraint_targets) {
- cti->flush_constraint_targets(con, &targets, true);
- }
+ BKE_constraint_targets_flush(con, &targets, true);
}
}
}
@@ -1446,10 +1454,16 @@ 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);
+ bool has_image_animation = false;
+ if (ELEM(GS(id->name), ID_MA, ID_WO)) {
+ bNodeTree *ntree = *BKE_ntree_ptr_from_id(id);
+ if (ntree != nullptr &&
+ ntree->runtime->runtime_flag & NTREE_RUNTIME_FLAG_HAS_IMAGE_ANIMATION) {
+ has_image_animation = true;
+ }
+ }
- /* TODO: can we check for existence of node for performance? */
- if (can_have_gpu_material || BKE_image_user_id_has_animation(id)) {
+ if (has_image_animation || BKE_image_user_id_has_animation(id)) {
OperationKey image_animation_key(
id, NodeType::IMAGE_ANIMATION, OperationCode::IMAGE_ANIMATION);
TimeSourceKey time_src_key;
@@ -1495,6 +1509,9 @@ void DepsgraphRelationBuilder::build_action(bAction *action)
if (built_map_.checkIsBuiltAndTag(action)) {
return;
}
+
+ const BuilderStack::ScopedEntry stack_entry = stack_.trace(action->id);
+
build_idproperties(action->id.properties);
if (!BLI_listbase_is_empty(&action->curves)) {
TimeSourceKey time_src_key;
@@ -1693,6 +1710,53 @@ void DepsgraphRelationBuilder::build_driver_variables(ID *id, FCurve *fcu)
continue;
}
add_relation(variable_exit_key, driver_key, "RNA Target -> Driver");
+
+ /* It is possible that RNA path points to a property of a different ID than the target_id:
+ * for example, paths like "data" on Object, "camera" on Scene.
+ *
+ * For the demonstration purposes lets consider a driver variable uses Scene ID as target
+ * and "camera.location.x" as its RNA path. If the scene has 2 different cameras at
+ * 2 different locations changing the active scene camera is expected to immediately be
+ * reflected in the variable value. In order to achieve this behavior we create a relation
+ * from the target ID to the driver so that if the ID property of the target ID changes the
+ * driver is re-evaluated.
+ *
+ * The most straightforward (at the moment of writing this comment) way of figuring out
+ * such relation is to use copy-on-write operation of the target ID. There are two down
+ * sides of this approach which are considered a design limitation as there is a belief
+ * that they are not common in practice or are not reliable due to other issues:
+ *
+ * - IDs which are not covered with the copy-on-write mechanism.
+ *
+ * Such IDs are either do not have ID properties, or are not part of the dependency
+ * graph.
+ *
+ * - Modifications of evaluated IDs from a Python handler.
+ * Such modifications are not fully integrated in the dependency graph evaluation as it
+ * has issues with copy-on-write tagging and the fact that relations are defined by the
+ * original main database status. */
+ if (target_id != variable_exit_key.ptr.owner_id) {
+ if (deg_copy_on_write_is_needed(GS(target_id->name))) {
+ ComponentKey target_id_key(target_id, NodeType::COPY_ON_WRITE);
+ add_relation(target_id_key, driver_key, "Target ID -> Driver");
+ }
+ }
+
+ /* The RNA getter for `object.data` can write to the mesh datablock due
+ * to the call to `BKE_mesh_wrapper_ensure_subdivision()`. This relation
+ * ensures it is safe to call when the driver is evaluated.
+ *
+ * For the sake of making the code more generic/defensive, the relation
+ * is added for any geometry type.
+ *
+ * See T96289 for more info. */
+ if (object != nullptr && OB_TYPE_IS_GEOMETRY(object->type)) {
+ StringRef rna_path(dtar->rna_path);
+ if (rna_path == "data" || rna_path.startswith("data.")) {
+ ComponentKey ob_key(target_id, NodeType::GEOMETRY);
+ add_relation(ob_key, driver_key, "ID -> Driver");
+ }
+ }
}
else {
/* If rna_path is nullptr, and DTAR_FLAG_STRUCT_REF isn't set, this
@@ -1766,6 +1830,9 @@ void DepsgraphRelationBuilder::build_world(World *world)
if (built_map_.checkIsBuiltAndTag(world)) {
return;
}
+
+ const BuilderStack::ScopedEntry stack_entry = stack_.trace(world->id);
+
build_idproperties(world->id.properties);
/* animation */
build_animdata(&world->id);
@@ -1991,6 +2058,9 @@ void DepsgraphRelationBuilder::build_particle_settings(ParticleSettings *part)
if (built_map_.checkIsBuiltAndTag(part)) {
return;
}
+
+ const BuilderStack::ScopedEntry stack_entry = stack_.trace(part->id);
+
/* Animation data relations. */
build_animdata(&part->id);
build_parameters(&part->id);
@@ -2049,6 +2119,9 @@ void DepsgraphRelationBuilder::build_shapekeys(Key *key)
if (built_map_.checkIsBuiltAndTag(key)) {
return;
}
+
+ const BuilderStack::ScopedEntry stack_entry = stack_.trace(key->id);
+
build_idproperties(key->id.properties);
/* Attach animdata to geometry. */
build_animdata(&key->id);
@@ -2110,6 +2183,8 @@ void DepsgraphRelationBuilder::build_object_data_geometry(Object *object)
LISTBASE_FOREACH (ModifierData *, md, &object->modifiers) {
const ModifierTypeInfo *mti = BKE_modifier_get_info((ModifierType)md->type);
if (mti->updateDepsgraph) {
+ const BuilderStack::ScopedEntry stack_entry = stack_.trace(*md);
+
DepsNodeHandle handle = create_node_handle(obdata_ubereval_key);
ctx.node = reinterpret_cast<::DepsNodeHandle *>(&handle);
mti->updateDepsgraph(md, &ctx);
@@ -2230,6 +2305,9 @@ void DepsgraphRelationBuilder::build_object_data_geometry_datablock(ID *obdata)
if (built_map_.checkIsBuiltAndTag(obdata)) {
return;
}
+
+ const BuilderStack::ScopedEntry stack_entry = stack_.trace(*obdata);
+
build_idproperties(obdata->properties);
/* Animation. */
build_animdata(obdata);
@@ -2348,6 +2426,9 @@ void DepsgraphRelationBuilder::build_armature(bArmature *armature)
if (built_map_.checkIsBuiltAndTag(armature)) {
return;
}
+
+ const BuilderStack::ScopedEntry stack_entry = stack_.trace(armature->id);
+
build_idproperties(armature->id.properties);
build_animdata(&armature->id);
build_parameters(&armature->id);
@@ -2367,6 +2448,9 @@ void DepsgraphRelationBuilder::build_camera(Camera *camera)
if (built_map_.checkIsBuiltAndTag(camera)) {
return;
}
+
+ const BuilderStack::ScopedEntry stack_entry = stack_.trace(camera->id);
+
build_idproperties(camera->id.properties);
build_animdata(&camera->id);
build_parameters(&camera->id);
@@ -2384,6 +2468,9 @@ void DepsgraphRelationBuilder::build_light(Light *lamp)
if (built_map_.checkIsBuiltAndTag(lamp)) {
return;
}
+
+ const BuilderStack::ScopedEntry stack_entry = stack_.trace(lamp->id);
+
build_idproperties(lamp->id.properties);
build_animdata(&lamp->id);
build_parameters(&lamp->id);
@@ -2448,6 +2535,9 @@ void DepsgraphRelationBuilder::build_nodetree(bNodeTree *ntree)
if (built_map_.checkIsBuiltAndTag(ntree)) {
return;
}
+
+ const BuilderStack::ScopedEntry stack_entry = stack_.trace(ntree->id);
+
build_idproperties(ntree->id.properties);
build_animdata(&ntree->id);
build_parameters(&ntree->id);
@@ -2553,6 +2643,9 @@ void DepsgraphRelationBuilder::build_material(Material *material)
if (built_map_.checkIsBuiltAndTag(material)) {
return;
}
+
+ const BuilderStack::ScopedEntry stack_entry = stack_.trace(material->id);
+
build_idproperties(material->id.properties);
/* animation */
build_animdata(&material->id);
@@ -2589,6 +2682,9 @@ void DepsgraphRelationBuilder::build_texture(Tex *texture)
if (built_map_.checkIsBuiltAndTag(texture)) {
return;
}
+
+ const BuilderStack::ScopedEntry stack_entry = stack_.trace(texture->id);
+
/* texture itself */
ComponentKey texture_key(&texture->id, NodeType::GENERIC_DATABLOCK);
build_idproperties(texture->id.properties);
@@ -2630,6 +2726,9 @@ void DepsgraphRelationBuilder::build_image(Image *image)
if (built_map_.checkIsBuiltAndTag(image)) {
return;
}
+
+ const BuilderStack::ScopedEntry stack_entry = stack_.trace(image->id);
+
build_idproperties(image->id.properties);
build_parameters(&image->id);
}
@@ -2639,6 +2738,9 @@ void DepsgraphRelationBuilder::build_cachefile(CacheFile *cache_file)
if (built_map_.checkIsBuiltAndTag(cache_file)) {
return;
}
+
+ const BuilderStack::ScopedEntry stack_entry = stack_.trace(cache_file->id);
+
build_idproperties(cache_file->id.properties);
/* Animation. */
build_animdata(&cache_file->id);
@@ -2668,6 +2770,9 @@ void DepsgraphRelationBuilder::build_mask(Mask *mask)
if (built_map_.checkIsBuiltAndTag(mask)) {
return;
}
+
+ const BuilderStack::ScopedEntry stack_entry = stack_.trace(mask->id);
+
ID *mask_id = &mask->id;
build_idproperties(mask_id->properties);
/* F-Curve animation. */
@@ -2706,6 +2811,8 @@ void DepsgraphRelationBuilder::build_freestyle_linestyle(FreestyleLineStyle *lin
return;
}
+ const BuilderStack::ScopedEntry stack_entry = stack_.trace(linestyle->id);
+
ID *linestyle_id = &linestyle->id;
build_parameters(linestyle_id);
build_idproperties(linestyle_id->properties);
@@ -2718,6 +2825,9 @@ void DepsgraphRelationBuilder::build_movieclip(MovieClip *clip)
if (built_map_.checkIsBuiltAndTag(clip)) {
return;
}
+
+ const BuilderStack::ScopedEntry stack_entry = stack_.trace(clip->id);
+
/* Animation. */
build_idproperties(clip->id.properties);
build_animdata(&clip->id);
@@ -2729,6 +2839,9 @@ void DepsgraphRelationBuilder::build_lightprobe(LightProbe *probe)
if (built_map_.checkIsBuiltAndTag(probe)) {
return;
}
+
+ const BuilderStack::ScopedEntry stack_entry = stack_.trace(probe->id);
+
build_idproperties(probe->id.properties);
build_animdata(&probe->id);
build_parameters(&probe->id);
@@ -2739,6 +2852,9 @@ void DepsgraphRelationBuilder::build_speaker(Speaker *speaker)
if (built_map_.checkIsBuiltAndTag(speaker)) {
return;
}
+
+ const BuilderStack::ScopedEntry stack_entry = stack_.trace(speaker->id);
+
build_idproperties(speaker->id.properties);
build_animdata(&speaker->id);
build_parameters(&speaker->id);
@@ -2755,6 +2871,9 @@ void DepsgraphRelationBuilder::build_sound(bSound *sound)
if (built_map_.checkIsBuiltAndTag(sound)) {
return;
}
+
+ const BuilderStack::ScopedEntry stack_entry = stack_.trace(sound->id);
+
build_idproperties(sound->id.properties);
build_animdata(&sound->id);
build_parameters(&sound->id);
@@ -2765,6 +2884,9 @@ void DepsgraphRelationBuilder::build_simulation(Simulation *simulation)
if (built_map_.checkIsBuiltAndTag(simulation)) {
return;
}
+
+ const BuilderStack::ScopedEntry stack_entry = stack_.trace(simulation->id);
+
build_idproperties(simulation->id.properties);
build_animdata(&simulation->id);
build_parameters(&simulation->id);
@@ -2829,6 +2951,9 @@ void DepsgraphRelationBuilder::build_scene_sequencer(Scene *scene)
if (built_map_.checkIsBuiltAndTag(scene, BuilderMap::TAG_SCENE_SEQUENCER)) {
return;
}
+
+ /* TODO(sergey): Trace as a scene sequencer. */
+
build_scene_audio(scene);
ComponentKey scene_audio_key(&scene->id, NodeType::AUDIO);
/* Make sure dependencies from sequences data goes to the sequencer evaluation. */
@@ -2872,6 +2997,9 @@ void DepsgraphRelationBuilder::build_vfont(VFont *vfont)
if (built_map_.checkIsBuiltAndTag(vfont)) {
return;
}
+
+ const BuilderStack::ScopedEntry stack_entry = stack_.trace(vfont->id);
+
build_parameters(&vfont->id);
build_idproperties(vfont->id.properties);
}
diff --git a/source/blender/depsgraph/intern/builder/deg_builder_relations.h b/source/blender/depsgraph/intern/builder/deg_builder_relations.h
index 1ccecc9a3f2..64bdd2334d8 100644
--- a/source/blender/depsgraph/intern/builder/deg_builder_relations.h
+++ b/source/blender/depsgraph/intern/builder/deg_builder_relations.h
@@ -23,6 +23,7 @@
#include "intern/builder/deg_builder.h"
#include "intern/builder/deg_builder_map.h"
#include "intern/builder/deg_builder_rna.h"
+#include "intern/builder/deg_builder_stack.h"
#include "intern/depsgraph.h"
#include "intern/node/deg_node.h"
#include "intern/node/deg_node_component.h"
@@ -363,6 +364,7 @@ class DepsgraphRelationBuilder : public DepsgraphBuilder {
BuilderMap built_map_;
RNANodeQuery rna_node_query_;
+ BuilderStack stack_;
};
struct DepsNodeHandle {
diff --git a/source/blender/depsgraph/intern/builder/deg_builder_relations_impl.h b/source/blender/depsgraph/intern/builder/deg_builder_relations_impl.h
index 5cbd8c8dd75..aba4a011e72 100644
--- a/source/blender/depsgraph/intern/builder/deg_builder_relations_impl.h
+++ b/source/blender/depsgraph/intern/builder/deg_builder_relations_impl.h
@@ -9,6 +9,8 @@
#include "intern/node/deg_node_id.h"
+#include <iostream>
+
#include "DNA_ID.h"
#include "DNA_object_types.h"
#include "DNA_rigidbody_types.h"
@@ -33,37 +35,30 @@ Relation *DepsgraphRelationBuilder::add_relation(const KeyFrom &key_from,
Node *node_to = get_node(key_to);
OperationNode *op_from = node_from ? node_from->get_exit_operation() : nullptr;
OperationNode *op_to = node_to ? node_to->get_entry_operation() : nullptr;
+
if (op_from && op_to) {
return add_operation_relation(op_from, op_to, description, flags);
}
- else {
- if (!op_from) {
- /* XXX TODO: handle as error or report if needed. */
- fprintf(stderr,
- "add_relation(%s) - Could not find op_from (%s)\n",
- description,
- key_from.identifier().c_str());
- }
- else {
- fprintf(stderr,
- "add_relation(%s) - Failed, but op_from (%s) was ok\n",
- description,
- key_from.identifier().c_str());
- }
- if (!op_to) {
- /* XXX TODO: handle as error or report if needed. */
- fprintf(stderr,
- "add_relation(%s) - Could not find op_to (%s)\n",
- description,
- key_to.identifier().c_str());
- }
- else {
- fprintf(stderr,
- "add_relation(%s) - Failed, but op_to (%s) was ok\n",
- description,
- key_to.identifier().c_str());
- }
+
+ /* TODO(sergey): Report error in the interface. */
+
+ std::cerr << "--------------------------------------------------------------------\n";
+ std::cerr << "Failed to add relation \"" << description << "\"\n";
+
+ if (!op_from) {
+ std::cerr << "Could not find op_from: " << key_from.identifier() << "\n";
+ }
+
+ if (!op_to) {
+ std::cerr << "Could not find op_to: " << key_to.identifier() << "\n";
}
+
+ if (!stack_.is_empty()) {
+ std::cerr << "\nTrace:\n\n";
+ stack_.print_backtrace(std::cerr);
+ std::cerr << "\n";
+ }
+
return nullptr;
}
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 65cf0e7d9df..2e491cd37a6 100644
--- a/source/blender/depsgraph/intern/builder/deg_builder_relations_rig.cc
+++ b/source/blender/depsgraph/intern/builder/deg_builder_relations_rig.cc
@@ -322,7 +322,11 @@ void DepsgraphRelationBuilder::build_rig(Object *object)
RootPChanMap root_map;
bool pose_depends_on_local_transform = false;
LISTBASE_FOREACH (bPoseChannel *, pchan, &object->pose->chanbase) {
+ const BuilderStack::ScopedEntry stack_entry = stack_.trace(*pchan);
+
LISTBASE_FOREACH (bConstraint *, con, &pchan->constraints) {
+ const BuilderStack::ScopedEntry stack_entry = stack_.trace(*con);
+
switch (con->type) {
case CONSTRAINT_TYPE_KINEMATIC:
build_ik_pose(object, pchan, con, &root_map);
@@ -356,6 +360,8 @@ void DepsgraphRelationBuilder::build_rig(Object *object)
}
/* Links between operations for each bone. */
LISTBASE_FOREACH (bPoseChannel *, pchan, &object->pose->chanbase) {
+ const BuilderStack::ScopedEntry stack_entry = stack_.trace(*pchan);
+
build_idproperties(pchan->prop);
OperationKey bone_local_key(
&object->id, NodeType::BONE, pchan->name, OperationCode::BONE_LOCAL);
diff --git a/source/blender/depsgraph/intern/builder/deg_builder_relations_scene.cc b/source/blender/depsgraph/intern/builder/deg_builder_relations_scene.cc
index cdb7361afc0..cd1917cb607 100644
--- a/source/blender/depsgraph/intern/builder/deg_builder_relations_scene.cc
+++ b/source/blender/depsgraph/intern/builder/deg_builder_relations_scene.cc
@@ -36,6 +36,9 @@ void DepsgraphRelationBuilder::build_scene_parameters(Scene *scene)
if (built_map_.checkIsBuiltAndTag(scene, BuilderMap::TAG_PARAMETERS)) {
return;
}
+
+ /* TODO(sergey): Trace as a scene parameters. */
+
build_idproperties(scene->id.properties);
build_parameters(&scene->id);
OperationKey parameters_eval_key(
@@ -56,6 +59,9 @@ void DepsgraphRelationBuilder::build_scene_compositor(Scene *scene)
if (scene->nodetree == nullptr) {
return;
}
+
+ /* TODO(sergey): Trace as a scene compositor. */
+
build_nodetree(scene->nodetree);
}
diff --git a/source/blender/depsgraph/intern/builder/deg_builder_rna.cc b/source/blender/depsgraph/intern/builder/deg_builder_rna.cc
index 8a81adf0aeb..ac7a5bc2f30 100644
--- a/source/blender/depsgraph/intern/builder/deg_builder_rna.cc
+++ b/source/blender/depsgraph/intern/builder/deg_builder_rna.cc
@@ -39,7 +39,7 @@ namespace blender::deg {
class RNANodeQueryIDData {
public:
- explicit RNANodeQueryIDData(const ID *id) : id_(id), constraint_to_pchan_map_(nullptr)
+ explicit RNANodeQueryIDData(const ID *id) : id_(id)
{
}
@@ -77,7 +77,7 @@ class RNANodeQueryIDData {
/* indexed by bConstraint*, returns pose channel which contains that
* constraint. */
- Map<const bConstraint *, const bPoseChannel *> *constraint_to_pchan_map_;
+ Map<const bConstraint *, const bPoseChannel *> *constraint_to_pchan_map_ = nullptr;
};
/* ***************************** Node Identifier **************************** */
diff --git a/source/blender/depsgraph/intern/builder/deg_builder_stack.cc b/source/blender/depsgraph/intern/builder/deg_builder_stack.cc
new file mode 100644
index 00000000000..de0a5198a8a
--- /dev/null
+++ b/source/blender/depsgraph/intern/builder/deg_builder_stack.cc
@@ -0,0 +1,94 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later
+ * Copyright 2022 Blender Foundation. All rights reserved. */
+
+/** \file
+ * \ingroup depsgraph
+ */
+
+#include "intern/builder/deg_builder_stack.h"
+
+#include <iomanip>
+#include <ios>
+#include <iostream>
+
+#include "BKE_idtype.h"
+
+#include "DNA_ID.h"
+#include "DNA_action_types.h"
+#include "DNA_constraint_types.h"
+#include "DNA_modifier_types.h"
+
+namespace blender::deg {
+
+/* Spacing between adjacent columns, in number of spaces. */
+constexpr int kColumnSpacing = 4;
+
+/* Width of table columns including column padding.
+ * The type column width is a guesstimate based on "Particle Settings" with some extra padding. */
+constexpr int kPrintDepthWidth = 5 + kColumnSpacing;
+constexpr int kPrintTypeWidth = 21 + kColumnSpacing;
+
+namespace {
+
+/* NOTE: Depth column printing is already taken care of. */
+
+void print(std::ostream &stream, const ID *id)
+{
+ const IDTypeInfo *id_type_info = BKE_idtype_get_info_from_id(id);
+ stream << std::setw(kPrintTypeWidth) << id_type_info->name << (id->name + 2) << "\n";
+}
+
+void print(std::ostream &stream, const bConstraint *constraint)
+{
+ stream << std::setw(kPrintTypeWidth) << ("Constraint") << constraint->name << "\n";
+}
+
+void print(std::ostream &stream, const ModifierData *modifier_data)
+{
+ stream << std::setw(kPrintTypeWidth) << ("Modifier") << modifier_data->name << "\n";
+}
+
+void print(std::ostream &stream, const bPoseChannel *pchan)
+{
+ stream << std::setw(kPrintTypeWidth) << ("Pose Channel") << pchan->name << "\n";
+}
+
+} // namespace
+
+void BuilderStack::print_backtrace(std::ostream &stream)
+{
+ const std::ios_base::fmtflags old_flags(stream.flags());
+
+ stream << std::left;
+
+ stream << std::setw(kPrintDepthWidth) << "Depth" << std::setw(kPrintTypeWidth) << "Type"
+ << "Name"
+ << "\n";
+
+ stream << std::setw(kPrintDepthWidth) << "-----" << std::setw(kPrintTypeWidth) << "----"
+ << "----"
+ << "\n";
+
+ int depth = 1;
+ for (const Entry &entry : stack_) {
+ stream << std::setw(kPrintDepthWidth) << depth;
+ ++depth;
+
+ if (entry.id_ != nullptr) {
+ print(stream, entry.id_);
+ }
+ else if (entry.constraint_ != nullptr) {
+ print(stream, entry.constraint_);
+ }
+ else if (entry.modifier_data_ != nullptr) {
+ print(stream, entry.modifier_data_);
+ }
+ else if (entry.pchan_ != nullptr) {
+ print(stream, entry.pchan_);
+ }
+ }
+
+ stream.flags(old_flags);
+}
+
+} // namespace blender::deg
diff --git a/source/blender/depsgraph/intern/builder/deg_builder_stack.h b/source/blender/depsgraph/intern/builder/deg_builder_stack.h
new file mode 100644
index 00000000000..3f9cc83928a
--- /dev/null
+++ b/source/blender/depsgraph/intern/builder/deg_builder_stack.h
@@ -0,0 +1,140 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later
+ * Copyright 2022 Blender Foundation. All rights reserved. */
+
+/** \file
+ * \ingroup depsgraph
+ */
+
+#pragma once
+
+#include "BLI_utildefines.h"
+#include "BLI_vector.hh"
+
+struct ID;
+struct bConstraint;
+struct bPoseChannel;
+struct ModifierData;
+
+namespace blender::deg {
+
+/* This class keeps track of the builder calls nesting, allowing to unroll them back and provide a
+ * clue about how the builder made it to its current state.
+ *
+ * The tracing is based on the builder giving a trace clues to the stack. Typical usage is:
+ *
+ * void DepsgraphRelationBuilder::my_id_builder(ID *id)
+ * {
+ * if (built_map_.checkIsBuiltAndTag(id)) {
+ * return;
+ * }
+ *
+ * const BuilderStack::ScopedEntry stack_entry = stack_.trace(*id);
+ *
+ * ...
+ * }
+ */
+class BuilderStack {
+ public:
+ /* Entry of the backtrace.
+ * A cheap-to-construct wrapper which allows to gather a proper string representation whenever
+ * the stack is printed. */
+ class Entry {
+ public:
+ explicit Entry(const ID &id) : id_(&id)
+ {
+ }
+
+ explicit Entry(const bConstraint &constraint) : constraint_(&constraint)
+ {
+ }
+
+ explicit Entry(const bPoseChannel &pchan) : pchan_(&pchan)
+ {
+ }
+
+ explicit Entry(const ModifierData &modifier_data) : modifier_data_(&modifier_data)
+ {
+ }
+
+ private:
+ friend class BuilderStack;
+
+ const ID *id_ = nullptr;
+ const bConstraint *constraint_ = nullptr;
+ const ModifierData *modifier_data_ = nullptr;
+ const bPoseChannel *pchan_ = nullptr;
+ };
+
+ using Stack = Vector<Entry>;
+
+ /* A helper class to provide a RAII style of tracing. It is constructed by the
+ * `BuilderStack::trace` (which pushes entry to the stack), and upon destruction of this object
+ * the corresponding entry is popped from the stack.
+ *
+ * The goal of this `ScopedEntry` is to free developers from worrying about removing entries from
+ * the stack whenever leaving a builder step scope. */
+ class ScopedEntry {
+ public:
+ /* Delete copy constructor and operator: scoped entries are only supposed to be constructed
+ * once and never copied. */
+ ScopedEntry(const ScopedEntry &other) = delete;
+ ScopedEntry &operator=(const ScopedEntry &other) = delete;
+
+ /* Move semantic. */
+ ScopedEntry(ScopedEntry &&other) noexcept : stack_(other.stack_)
+ {
+ other.stack_ = nullptr;
+ }
+ ScopedEntry &operator=(ScopedEntry &&other)
+ {
+ if (this == &other) {
+ return *this;
+ }
+
+ stack_ = other.stack_;
+ other.stack_ = nullptr;
+
+ return *this;
+ }
+
+ ~ScopedEntry()
+ {
+ /* Stack will become nullptr when the entry was moved somewhere else. */
+ if (stack_ != nullptr) {
+ BLI_assert(!stack_->is_empty());
+ stack_->pop_last();
+ }
+ }
+
+ private:
+ friend BuilderStack;
+
+ explicit ScopedEntry(Stack &stack) : stack_(&stack)
+ {
+ }
+
+ Stack *stack_;
+ };
+
+ BuilderStack() = default;
+ ~BuilderStack() = default;
+
+ bool is_empty() const
+ {
+ return stack_.is_empty();
+ }
+
+ void print_backtrace(std::ostream &stream);
+
+ template<class... Args> ScopedEntry trace(const Args &...args)
+ {
+ stack_.append_as(args...);
+
+ return ScopedEntry(stack_);
+ }
+
+ private:
+ Stack stack_;
+};
+
+} // namespace blender::deg
diff --git a/source/blender/depsgraph/intern/depsgraph_query.cc b/source/blender/depsgraph/intern/depsgraph_query.cc
index fd569599b8b..6ffc711a475 100644
--- a/source/blender/depsgraph/intern/depsgraph_query.cc
+++ b/source/blender/depsgraph/intern/depsgraph_query.cc
@@ -32,6 +32,49 @@
#include "intern/eval/deg_eval_copy_on_write.h"
#include "intern/node/deg_node_id.h"
+namespace blender::deg {
+
+static const ID *get_original_id(const ID *id)
+{
+ if (id == nullptr) {
+ return nullptr;
+ }
+ if (id->orig_id == nullptr) {
+ return id;
+ }
+ BLI_assert((id->tag & LIB_TAG_COPIED_ON_WRITE) != 0);
+ return (ID *)id->orig_id;
+}
+
+static ID *get_original_id(ID *id)
+{
+ const ID *const_id = id;
+ return const_cast<ID *>(get_original_id(const_id));
+}
+
+static const ID *get_evaluated_id(const Depsgraph *deg_graph, const ID *id)
+{
+ if (id == nullptr) {
+ return nullptr;
+ }
+ /* TODO(sergey): This is a duplicate of Depsgraph::get_cow_id(),
+ * but here we never do assert, since we don't know nature of the
+ * incoming ID data-block. */
+ const IDNode *id_node = deg_graph->find_id_node(id);
+ if (id_node == nullptr) {
+ return id;
+ }
+ return id_node->id_cow;
+}
+
+static ID *get_evaluated_id(const Depsgraph *deg_graph, ID *id)
+{
+ const ID *const_id = id;
+ return const_cast<ID *>(get_evaluated_id(deg_graph, const_id));
+}
+
+} // namespace blender::deg
+
namespace deg = blender::deg;
struct Scene *DEG_get_input_scene(const Depsgraph *graph)
@@ -90,7 +133,7 @@ bool DEG_id_type_any_exists(const Depsgraph *depsgraph, short id_type)
return deg_graph->id_type_exist[BKE_idtype_idcode_to_index(id_type)] != 0;
}
-uint32_t DEG_get_eval_flags_for_id(const Depsgraph *graph, ID *id)
+uint32_t DEG_get_eval_flags_for_id(const Depsgraph *graph, const ID *id)
{
if (graph == nullptr) {
/* Happens when converting objects to mesh from a python script
@@ -102,7 +145,7 @@ uint32_t DEG_get_eval_flags_for_id(const Depsgraph *graph, ID *id)
}
const deg::Depsgraph *deg_graph = reinterpret_cast<const deg::Depsgraph *>(graph);
- const deg::IDNode *id_node = deg_graph->find_id_node(DEG_get_original_id(id));
+ const deg::IDNode *id_node = deg_graph->find_id_node(deg::get_original_id(id));
if (id_node == nullptr) {
/* TODO(sergey): Does it mean we need to check set scene? */
return 0;
@@ -171,18 +214,7 @@ Object *DEG_get_evaluated_object(const Depsgraph *depsgraph, Object *object)
ID *DEG_get_evaluated_id(const Depsgraph *depsgraph, ID *id)
{
- if (id == nullptr) {
- return nullptr;
- }
- /* TODO(sergey): This is a duplicate of Depsgraph::get_cow_id(),
- * but here we never do assert, since we don't know nature of the
- * incoming ID data-block. */
- const deg::Depsgraph *deg_graph = (const deg::Depsgraph *)depsgraph;
- const deg::IDNode *id_node = deg_graph->find_id_node(id);
- if (id_node == nullptr) {
- return id;
- }
- return id_node->id_cow;
+ return deg::get_evaluated_id(reinterpret_cast<const deg::Depsgraph *>(depsgraph), id);
}
void DEG_get_evaluated_rna_pointer(const Depsgraph *depsgraph,
@@ -249,14 +281,7 @@ Object *DEG_get_original_object(Object *object)
ID *DEG_get_original_id(ID *id)
{
- if (id == nullptr) {
- return nullptr;
- }
- if (id->orig_id == nullptr) {
- return id;
- }
- BLI_assert((id->tag & LIB_TAG_COPIED_ON_WRITE) != 0);
- return (ID *)id->orig_id;
+ return deg::get_original_id(id);
}
bool DEG_is_original_id(const ID *id)
diff --git a/source/blender/draw/CMakeLists.txt b/source/blender/draw/CMakeLists.txt
index f72112d7c54..9cb3743dd02 100644
--- a/source/blender/draw/CMakeLists.txt
+++ b/source/blender/draw/CMakeLists.txt
@@ -39,8 +39,8 @@ set(INC
set(SRC
intern/draw_cache.c
intern/draw_cache_extract_mesh.cc
- intern/draw_cache_extract_mesh_render_data.c
- intern/mesh_extractors/extract_mesh.c
+ intern/draw_cache_extract_mesh_render_data.cc
+ intern/mesh_extractors/extract_mesh.cc
intern/mesh_extractors/extract_mesh_ibo_edituv.cc
intern/mesh_extractors/extract_mesh_ibo_fdots.cc
intern/mesh_extractors/extract_mesh_ibo_lines.cc
@@ -69,12 +69,13 @@ set(SRC
intern/mesh_extractors/extract_mesh_vbo_uv.cc
intern/mesh_extractors/extract_mesh_vbo_vcol.cc
intern/mesh_extractors/extract_mesh_vbo_weights.cc
+ intern/draw_attributes.cc
intern/draw_cache_impl_curve.cc
intern/draw_cache_impl_curves.cc
intern/draw_cache_impl_displist.c
intern/draw_cache_impl_gpencil.c
intern/draw_cache_impl_lattice.c
- intern/draw_cache_impl_mesh.c
+ intern/draw_cache_impl_mesh.cc
intern/draw_cache_impl_metaball.c
intern/draw_cache_impl_particles.c
intern/draw_cache_impl_pointcloud.c
@@ -85,7 +86,7 @@ set(SRC
intern/draw_curves.cc
intern/draw_debug.c
intern/draw_fluid.c
- intern/draw_hair.c
+ intern/draw_hair.cc
intern/draw_instance_data.c
intern/draw_manager.c
intern/draw_manager_data.c
@@ -95,7 +96,7 @@ set(SRC
intern/draw_manager_text.c
intern/draw_manager_texture.c
intern/draw_select_buffer.c
- intern/draw_shader.c
+ intern/draw_shader.cc
intern/draw_texture_pool.cc
intern/draw_view.c
intern/draw_view_data.cc
@@ -133,12 +134,14 @@ set(SRC
engines/eevee/eevee_subsurface.c
engines/eevee/eevee_temporal_sampling.c
engines/eevee/eevee_volumes.c
+ engines/eevee_next/eevee_camera.cc
engines/eevee_next/eevee_engine.cc
engines/eevee_next/eevee_instance.cc
engines/eevee_next/eevee_material.cc
engines/eevee_next/eevee_pipeline.cc
engines/eevee_next/eevee_shader.cc
engines/eevee_next/eevee_sync.cc
+ engines/eevee_next/eevee_velocity.cc
engines/eevee_next/eevee_view.cc
engines/eevee_next/eevee_world.cc
engines/workbench/workbench_data.c
@@ -196,8 +199,9 @@ set(SRC
DRW_select_buffer.h
intern/DRW_gpu_wrapper.hh
intern/DRW_render.h
+ intern/draw_attributes.h
intern/draw_cache.h
- intern/draw_cache_extract.h
+ intern/draw_cache_extract.hh
intern/draw_cache_impl.h
intern/draw_cache_inline.h
intern/draw_color_management.h
@@ -217,7 +221,7 @@ set(SRC
intern/draw_texture_pool.h
intern/draw_view.h
intern/draw_view_data.h
- intern/mesh_extractors/extract_mesh.h
+ intern/mesh_extractors/extract_mesh.hh
intern/smaa_textures.h
engines/basic/basic_engine.h
engines/basic/basic_private.h
@@ -333,6 +337,7 @@ set(GLSL_SRC
engines/eevee/shaders/renderpass_lib.glsl
engines/eevee/shaders/renderpass_postprocess_frag.glsl
engines/eevee/shaders/cryptomatte_frag.glsl
+ engines/eevee/shaders/cryptomatte_vert.glsl
engines/eevee/shaders/ltc_lib.glsl
engines/eevee/shaders/ssr_lib.glsl
engines/eevee/shaders/surface_frag.glsl
@@ -351,6 +356,7 @@ set(GLSL_SRC
engines/eevee/shaders/world_vert.glsl
engines/eevee_next/shaders/eevee_attributes_lib.glsl
+ engines/eevee_next/shaders/eevee_camera_lib.glsl
engines/eevee_next/shaders/eevee_geom_curves_vert.glsl
engines/eevee_next/shaders/eevee_geom_gpencil_vert.glsl
engines/eevee_next/shaders/eevee_geom_mesh_vert.glsl
@@ -361,6 +367,11 @@ set(GLSL_SRC
engines/eevee_next/shaders/eevee_surf_forward_frag.glsl
engines/eevee_next/shaders/eevee_surf_lib.glsl
engines/eevee_next/shaders/eevee_surf_world_frag.glsl
+ engines/eevee_next/shaders/eevee_velocity_lib.glsl
+ engines/eevee_next/shaders/eevee_velocity_resolve_comp.glsl
+
+ engines/eevee_next/eevee_defines.hh
+ engines/eevee_next/eevee_shader_shared.hh
engines/workbench/shaders/workbench_cavity_lib.glsl
engines/workbench/shaders/workbench_common_lib.glsl
@@ -441,108 +452,113 @@ set(GLSL_SRC
engines/select/shaders/select_id_vert.glsl
engines/select/shaders/select_id_frag.glsl
- engines/basic/shaders/conservative_depth_geom.glsl
- engines/basic/shaders/depth_vert.glsl
- engines/basic/shaders/depth_pointcloud_vert.glsl
- engines/basic/shaders/depth_frag.glsl
-
- engines/overlay/shaders/common_overlay_lib.glsl
- engines/overlay/shaders/antialiasing_frag.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_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_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_gpencil_frag.glsl
- engines/overlay/shaders/outline_prepass_geom.glsl
- engines/overlay/shaders/outline_prepass_gpencil_vert.glsl
- engines/overlay/shaders/outline_prepass_pointcloud_vert.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/basic/shaders/basic_conservative_depth_geom.glsl
+ engines/basic/shaders/basic_depth_vert.glsl
+ engines/basic/shaders/basic_depth_pointcloud_vert.glsl
+ engines/basic/shaders/basic_depth_frag.glsl
+
+ engines/overlay/shaders/overlay_antialiasing_frag.glsl
+ engines/overlay/shaders/overlay_armature_dof_solid_frag.glsl
+ engines/overlay/shaders/overlay_armature_dof_vert.glsl
+ engines/overlay/shaders/overlay_armature_envelope_outline_vert.glsl
+ engines/overlay/shaders/overlay_armature_envelope_solid_frag.glsl
+ engines/overlay/shaders/overlay_armature_envelope_solid_vert.glsl
+ engines/overlay/shaders/overlay_armature_shape_outline_geom.glsl
+ engines/overlay/shaders/overlay_armature_shape_outline_vert.glsl
+ engines/overlay/shaders/overlay_armature_shape_solid_frag.glsl
+ engines/overlay/shaders/overlay_armature_shape_solid_vert.glsl
+ engines/overlay/shaders/overlay_armature_shape_wire_vert.glsl
+ engines/overlay/shaders/overlay_armature_sphere_outline_vert.glsl
+ engines/overlay/shaders/overlay_armature_sphere_solid_frag.glsl
+ engines/overlay/shaders/overlay_armature_sphere_solid_vert.glsl
+ engines/overlay/shaders/overlay_armature_stick_frag.glsl
+ engines/overlay/shaders/overlay_armature_stick_vert.glsl
+ engines/overlay/shaders/overlay_armature_wire_frag.glsl
+ engines/overlay/shaders/overlay_armature_wire_vert.glsl
+ engines/overlay/shaders/overlay_background_frag.glsl
+ engines/overlay/shaders/overlay_clipbound_vert.glsl
+ engines/overlay/shaders/overlay_common_lib.glsl
+ engines/overlay/shaders/overlay_depth_only_frag.glsl
+ engines/overlay/shaders/overlay_depth_only_vert.glsl
+ engines/overlay/shaders/overlay_edit_curve_handle_geom.glsl
+ engines/overlay/shaders/overlay_edit_curve_handle_vert.glsl
+ engines/overlay/shaders/overlay_edit_curve_point_vert.glsl
+ engines/overlay/shaders/overlay_edit_curve_wire_vert.glsl
+ engines/overlay/shaders/overlay_edit_gpencil_canvas_vert.glsl
+ engines/overlay/shaders/overlay_edit_gpencil_guide_vert.glsl
+ engines/overlay/shaders/overlay_edit_gpencil_vert.glsl
+ engines/overlay/shaders/overlay_edit_lattice_point_vert.glsl
+ engines/overlay/shaders/overlay_edit_lattice_wire_vert.glsl
+ engines/overlay/shaders/overlay_edit_mesh_analysis_frag.glsl
+ engines/overlay/shaders/overlay_edit_mesh_analysis_vert.glsl
+ engines/overlay/shaders/overlay_edit_mesh_common_lib.glsl
+ engines/overlay/shaders/overlay_edit_mesh_frag.glsl
+ engines/overlay/shaders/overlay_edit_mesh_geom.glsl
+ engines/overlay/shaders/overlay_edit_mesh_normal_vert.glsl
+ engines/overlay/shaders/overlay_edit_mesh_skin_root_vert.glsl
+ engines/overlay/shaders/overlay_edit_mesh_vert.glsl
+ engines/overlay/shaders/overlay_edit_particle_point_vert.glsl
+ engines/overlay/shaders/overlay_edit_particle_strand_vert.glsl
+ engines/overlay/shaders/overlay_edit_uv_edges_frag.glsl
+ engines/overlay/shaders/overlay_edit_uv_edges_geom.glsl
+ engines/overlay/shaders/overlay_edit_uv_edges_vert.glsl
+ engines/overlay/shaders/overlay_edit_uv_face_dots_vert.glsl
+ engines/overlay/shaders/overlay_edit_uv_faces_vert.glsl
+ engines/overlay/shaders/overlay_edit_uv_image_mask_frag.glsl
+ engines/overlay/shaders/overlay_edit_uv_image_vert.glsl
+ engines/overlay/shaders/overlay_edit_uv_stretching_vert.glsl
+ engines/overlay/shaders/overlay_edit_uv_tiled_image_borders_vert.glsl
+ engines/overlay/shaders/overlay_edit_uv_verts_frag.glsl
+ engines/overlay/shaders/overlay_edit_uv_verts_vert.glsl
+ engines/overlay/shaders/overlay_extra_frag.glsl
+ engines/overlay/shaders/overlay_extra_groundline_vert.glsl
+ engines/overlay/shaders/overlay_extra_lightprobe_grid_vert.glsl
+ engines/overlay/shaders/overlay_extra_loose_point_frag.glsl
+ engines/overlay/shaders/overlay_extra_loose_point_vert.glsl
+ engines/overlay/shaders/overlay_extra_point_vert.glsl
+ engines/overlay/shaders/overlay_extra_vert.glsl
+ engines/overlay/shaders/overlay_extra_wire_frag.glsl
+ engines/overlay/shaders/overlay_extra_wire_vert.glsl
+ engines/overlay/shaders/overlay_facing_frag.glsl
+ engines/overlay/shaders/overlay_facing_vert.glsl
+ engines/overlay/shaders/overlay_grid_background_frag.glsl
+ engines/overlay/shaders/overlay_grid_frag.glsl
+ engines/overlay/shaders/overlay_grid_vert.glsl
+ engines/overlay/shaders/overlay_image_frag.glsl
+ engines/overlay/shaders/overlay_image_vert.glsl
+ engines/overlay/shaders/overlay_motion_path_line_frag.glsl
+ engines/overlay/shaders/overlay_motion_path_line_geom.glsl
+ engines/overlay/shaders/overlay_motion_path_line_vert.glsl
+ engines/overlay/shaders/overlay_motion_path_point_vert.glsl
+ engines/overlay/shaders/overlay_outline_detect_frag.glsl
+ engines/overlay/shaders/overlay_outline_prepass_frag.glsl
+ engines/overlay/shaders/overlay_outline_prepass_geom.glsl
+ engines/overlay/shaders/overlay_outline_prepass_gpencil_frag.glsl
+ engines/overlay/shaders/overlay_outline_prepass_gpencil_vert.glsl
+ engines/overlay/shaders/overlay_outline_prepass_pointcloud_vert.glsl
+ engines/overlay/shaders/overlay_outline_prepass_vert.glsl
+ engines/overlay/shaders/overlay_paint_face_vert.glsl
+ engines/overlay/shaders/overlay_paint_point_vert.glsl
+ engines/overlay/shaders/overlay_paint_texture_frag.glsl
+ engines/overlay/shaders/overlay_paint_texture_vert.glsl
+ engines/overlay/shaders/overlay_paint_vertcol_frag.glsl
+ engines/overlay/shaders/overlay_paint_vertcol_vert.glsl
+ engines/overlay/shaders/overlay_paint_weight_frag.glsl
+ engines/overlay/shaders/overlay_paint_weight_vert.glsl
+ engines/overlay/shaders/overlay_paint_wire_vert.glsl
+ engines/overlay/shaders/overlay_particle_frag.glsl
+ engines/overlay/shaders/overlay_particle_vert.glsl
+ engines/overlay/shaders/overlay_point_varying_color_frag.glsl
+ engines/overlay/shaders/overlay_point_varying_color_varying_outline_aa_frag.glsl
+ engines/overlay/shaders/overlay_sculpt_mask_frag.glsl
+ engines/overlay/shaders/overlay_sculpt_mask_vert.glsl
+ engines/overlay/shaders/overlay_uniform_color_frag.glsl
+ engines/overlay/shaders/overlay_varying_color.glsl
+ engines/overlay/shaders/overlay_volume_gridlines_vert.glsl
+ engines/overlay/shaders/overlay_volume_velocity_vert.glsl
+ engines/overlay/shaders/overlay_wireframe_frag.glsl
+ engines/overlay/shaders/overlay_wireframe_vert.glsl
+ engines/overlay/shaders/overlay_xray_fade_frag.glsl
engines/overlay/overlay_shader_shared.h
diff --git a/source/blender/draw/DRW_engine.h b/source/blender/draw/DRW_engine.h
index 00822946fe5..dec7a22aadb 100644
--- a/source/blender/draw/DRW_engine.h
+++ b/source/blender/draw/DRW_engine.h
@@ -23,6 +23,9 @@ struct DrawEngineType;
struct GHash;
struct GPUMaterial;
struct GPUOffScreen;
+struct GPUVertFormat;
+struct CustomDataLayer;
+struct CustomData;
struct GPUViewport;
struct ID;
struct Main;
@@ -218,6 +221,12 @@ void DRW_opengl_context_activate(bool drw_state);
*/
void DRW_draw_cursor_2d_ex(const struct ARegion *region, const float cursor[2]);
+void DRW_cdlayer_attr_aliases_add(struct GPUVertFormat *format,
+ const char *base_name,
+ const struct CustomData *data,
+ const struct CustomDataLayer *cl,
+ bool is_active_render,
+ bool is_active_layer);
#ifdef __cplusplus
}
#endif
diff --git a/source/blender/draw/DRW_select_buffer.h b/source/blender/draw/DRW_select_buffer.h
index 324ebebfbe6..5bc7aee92ba 100644
--- a/source/blender/draw/DRW_select_buffer.h
+++ b/source/blender/draw/DRW_select_buffer.h
@@ -9,6 +9,10 @@
#include "BLI_sys_types.h" /* for bool and uint */
+#ifdef __cplusplus
+extern "C" {
+#endif
+
struct ARegion;
struct Base;
struct Depsgraph;
@@ -133,3 +137,7 @@ uint DRW_select_buffer_find_nearest_to_point(struct Depsgraph *depsgraph,
uint id_max,
uint *dist);
void DRW_select_buffer_context_create(struct Base **bases, uint bases_len, short select_mode);
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/source/blender/draw/engines/basic/basic_shader.c b/source/blender/draw/engines/basic/basic_shader.c
index d7a8f23e3b3..3d40c627fff 100644
--- a/source/blender/draw/engines/basic/basic_shader.c
+++ b/source/blender/draw/engines/basic/basic_shader.c
@@ -11,9 +11,9 @@
#include "basic_private.h"
-extern char datatoc_depth_frag_glsl[];
-extern char datatoc_depth_vert_glsl[];
-extern char datatoc_conservative_depth_geom_glsl[];
+extern char datatoc_basic_depth_frag_glsl[];
+extern char datatoc_basic_depth_vert_glsl[];
+extern char datatoc_basic_conservative_depth_geom_glsl[];
extern char datatoc_common_view_lib_glsl[];
extern char datatoc_common_pointcloud_lib_glsl[];
diff --git a/source/blender/draw/engines/basic/shaders/conservative_depth_geom.glsl b/source/blender/draw/engines/basic/shaders/basic_conservative_depth_geom.glsl
index d478f37691e..d478f37691e 100644
--- a/source/blender/draw/engines/basic/shaders/conservative_depth_geom.glsl
+++ b/source/blender/draw/engines/basic/shaders/basic_conservative_depth_geom.glsl
diff --git a/source/blender/draw/engines/basic/shaders/depth_frag.glsl b/source/blender/draw/engines/basic/shaders/basic_depth_frag.glsl
index ff4a015c335..ff4a015c335 100644
--- a/source/blender/draw/engines/basic/shaders/depth_frag.glsl
+++ b/source/blender/draw/engines/basic/shaders/basic_depth_frag.glsl
diff --git a/source/blender/draw/engines/basic/shaders/depth_pointcloud_vert.glsl b/source/blender/draw/engines/basic/shaders/basic_depth_pointcloud_vert.glsl
index b82edc61cee..b82edc61cee 100644
--- a/source/blender/draw/engines/basic/shaders/depth_pointcloud_vert.glsl
+++ b/source/blender/draw/engines/basic/shaders/basic_depth_pointcloud_vert.glsl
diff --git a/source/blender/draw/engines/basic/shaders/depth_vert.glsl b/source/blender/draw/engines/basic/shaders/basic_depth_vert.glsl
index 7046979cf97..7046979cf97 100644
--- a/source/blender/draw/engines/basic/shaders/depth_vert.glsl
+++ b/source/blender/draw/engines/basic/shaders/basic_depth_vert.glsl
diff --git a/source/blender/draw/engines/basic/shaders/infos/basic_depth_info.hh b/source/blender/draw/engines/basic/shaders/infos/basic_depth_info.hh
index 9914d264c63..bae50eb48fa 100644
--- a/source/blender/draw/engines/basic/shaders/infos/basic_depth_info.hh
+++ b/source/blender/draw/engines/basic/shaders/infos/basic_depth_info.hh
@@ -10,7 +10,7 @@
GPU_SHADER_CREATE_INFO(basic_conservative)
.geometry_layout(PrimitiveIn::TRIANGLES, PrimitiveOut::TRIANGLE_STRIP, 3)
- .geometry_source("conservative_depth_geom.glsl");
+ .geometry_source("basic_conservative_depth_geom.glsl");
/** \} */
@@ -20,11 +20,11 @@ GPU_SHADER_CREATE_INFO(basic_conservative)
GPU_SHADER_CREATE_INFO(basic_mesh)
.vertex_in(0, Type::VEC3, "pos")
- .vertex_source("depth_vert.glsl")
+ .vertex_source("basic_depth_vert.glsl")
.additional_info("draw_mesh");
GPU_SHADER_CREATE_INFO(basic_pointcloud)
- .vertex_source("depth_pointcloud_vert.glsl")
+ .vertex_source("basic_depth_pointcloud_vert.glsl")
.additional_info("draw_pointcloud");
/** \} */
@@ -54,7 +54,7 @@ GPU_SHADER_CREATE_INFO(basic_pointcloud)
/** \name Depth shader types.
* \{ */
-GPU_SHADER_CREATE_INFO(basic_depth).fragment_source("depth_frag.glsl");
+GPU_SHADER_CREATE_INFO(basic_depth).fragment_source("basic_depth_frag.glsl");
BASIC_OBTYPE_VARIATIONS(basic_depth, "basic_depth");
diff --git a/source/blender/draw/engines/eevee/eevee_bloom.c b/source/blender/draw/engines/eevee/eevee_bloom.c
index d12ce7213f9..4528027a9ea 100644
--- a/source/blender/draw/engines/eevee/eevee_bloom.c
+++ b/source/blender/draw/engines/eevee/eevee_bloom.c
@@ -125,7 +125,8 @@ static DRWShadingGroup *eevee_create_bloom_pass(const char *name,
struct GPUShader *sh,
DRWPass **pass,
bool upsample,
- bool resolve)
+ bool resolve,
+ bool resolve_add_base)
{
struct GPUBatch *quad = DRW_cache_fullscreen_quad_get();
@@ -141,7 +142,7 @@ static DRWShadingGroup *eevee_create_bloom_pass(const char *name,
}
if (resolve) {
DRW_shgroup_uniform_vec3(grp, "bloomColor", effects->bloom_color, 1);
- DRW_shgroup_uniform_bool_copy(grp, "bloomAddBase", true);
+ DRW_shgroup_uniform_bool_copy(grp, "bloomAddBase", resolve_add_base);
}
return grp;
@@ -193,18 +194,21 @@ void EEVEE_bloom_cache_init(EEVEE_ViewLayerData *UNUSED(sldata), EEVEE_Data *ved
EEVEE_shaders_bloom_downsample_get(use_antiflicker),
&psl->bloom_downsample_first,
false,
+ false,
false);
eevee_create_bloom_pass("Bloom Downsample",
effects,
EEVEE_shaders_bloom_downsample_get(false),
&psl->bloom_downsample,
false,
+ false,
false);
eevee_create_bloom_pass("Bloom Upsample",
effects,
EEVEE_shaders_bloom_upsample_get(use_highres),
&psl->bloom_upsample,
true,
+ false,
false);
grp = eevee_create_bloom_pass("Bloom Blit",
@@ -212,6 +216,7 @@ void EEVEE_bloom_cache_init(EEVEE_ViewLayerData *UNUSED(sldata), EEVEE_Data *ved
EEVEE_shaders_bloom_blit_get(use_antiflicker),
&psl->bloom_blit,
false,
+ false,
false);
DRW_shgroup_uniform_vec4(grp, "curveThreshold", effects->bloom_curve_threshold, 1);
DRW_shgroup_uniform_float(grp, "clampIntensity", &effects->bloom_clamp, 1);
@@ -221,6 +226,7 @@ void EEVEE_bloom_cache_init(EEVEE_ViewLayerData *UNUSED(sldata), EEVEE_Data *ved
EEVEE_shaders_bloom_resolve_get(use_highres),
&psl->bloom_resolve,
true,
+ true,
true);
}
}
@@ -304,13 +310,13 @@ void EEVEE_bloom_output_init(EEVEE_ViewLayerData *UNUSED(sldata),
{GPU_ATTACHMENT_NONE, GPU_ATTACHMENT_TEXTURE(txl->bloom_accum)});
/* Create Pass and shgroup. */
- DRWShadingGroup *grp = eevee_create_bloom_pass("Bloom Accumulate",
- effects,
- EEVEE_shaders_bloom_resolve_get(use_highres),
- &psl->bloom_accum_ps,
- true,
- true);
- DRW_shgroup_uniform_bool_copy(grp, "bloomAddBase", false);
+ eevee_create_bloom_pass("Bloom Accumulate",
+ effects,
+ EEVEE_shaders_bloom_resolve_get(use_highres),
+ &psl->bloom_accum_ps,
+ true,
+ true,
+ false);
}
void EEVEE_bloom_output_accumulate(EEVEE_ViewLayerData *UNUSED(sldata), EEVEE_Data *vedata)
diff --git a/source/blender/draw/engines/eevee/eevee_cryptomatte.c b/source/blender/draw/engines/eevee/eevee_cryptomatte.c
index 161555208f3..33063e14c03 100644
--- a/source/blender/draw/engines/eevee/eevee_cryptomatte.c
+++ b/source/blender/draw/engines/eevee/eevee_cryptomatte.c
@@ -189,11 +189,8 @@ void EEVEE_cryptomatte_cache_init(EEVEE_ViewLayerData *UNUSED(sldata), EEVEE_Dat
}
}
-static DRWShadingGroup *eevee_cryptomatte_shading_group_create(EEVEE_Data *vedata,
- EEVEE_ViewLayerData *UNUSED(sldata),
- Object *ob,
- Material *material,
- bool is_hair)
+static DRWShadingGroup *eevee_cryptomatte_shading_group_create(
+ EEVEE_Data *vedata, EEVEE_ViewLayerData *sldata, Object *ob, Material *material, bool is_hair)
{
const DRWContextState *draw_ctx = DRW_context_state_get();
const ViewLayer *view_layer = draw_ctx->view_layer;
@@ -229,6 +226,7 @@ static DRWShadingGroup *eevee_cryptomatte_shading_group_create(EEVEE_Data *vedat
DRWShadingGroup *grp = DRW_shgroup_create(EEVEE_shaders_cryptomatte_sh_get(is_hair),
psl->cryptomatte_ps);
DRW_shgroup_uniform_vec4_copy(grp, "cryptohash", cryptohash);
+ DRW_shgroup_uniform_block(grp, "shadow_block", sldata->shadow_ubo);
return grp;
}
diff --git a/source/blender/draw/engines/eevee/eevee_data.c b/source/blender/draw/engines/eevee/eevee_data.c
index 0c56b67ca99..1a1e3b80bad 100644
--- a/source/blender/draw/engines/eevee/eevee_data.c
+++ b/source/blender/draw/engines/eevee/eevee_data.c
@@ -114,7 +114,9 @@ void EEVEE_motion_blur_data_free(EEVEE_MotionBlurData *mb)
}
}
-EEVEE_ObjectMotionData *EEVEE_motion_blur_object_data_get(EEVEE_MotionBlurData *mb, Object *ob)
+EEVEE_ObjectMotionData *EEVEE_motion_blur_object_data_get(EEVEE_MotionBlurData *mb,
+ Object *ob,
+ bool is_psys)
{
if (mb->object == NULL) {
return NULL;
@@ -123,14 +125,16 @@ EEVEE_ObjectMotionData *EEVEE_motion_blur_object_data_get(EEVEE_MotionBlurData *
EEVEE_ObjectKey key, *key_p;
/* Assumes that all instances have the same object pointer. This is currently the case because
* instance objects are temporary objects on the stack. */
- key.ob = ob;
+ /* WORKAROUND: Duplicate object key for particle system (hairs) to be able to store dupli offset
+ * matrix along with the emitter obmat. (see T97380) */
+ key.ob = (void *)((char *)ob + is_psys);
DupliObject *dup = DRW_object_get_dupli(ob);
if (dup) {
key.parent = DRW_object_get_dupli_parent(ob);
memcpy(key.id, dup->persistent_id, sizeof(key.id));
}
else {
- key.parent = key.ob;
+ key.parent = ob;
memset(key.id, 0, sizeof(key.id));
}
diff --git a/source/blender/draw/engines/eevee/eevee_lightcache.c b/source/blender/draw/engines/eevee/eevee_lightcache.c
index 4f562dd9804..7f722ff1764 100644
--- a/source/blender/draw/engines/eevee/eevee_lightcache.c
+++ b/source/blender/draw/engines/eevee/eevee_lightcache.c
@@ -95,7 +95,7 @@ typedef struct EEVEE_LightBake {
/** Target layer to store the data to. */
int layer;
/** Sample count for the convolution. */
- float samples_ct, invsamples_ct;
+ float samples_count, invsamples_count;
/** Sampling bias during convolution step. */
float lod_factor;
/** Max cube-map LOD to sample when convolving. */
@@ -282,14 +282,14 @@ static void irradiance_pool_size_get(int visibility_size, int total_samples, int
(visibility_size / IRRADIANCE_SAMPLE_SIZE_Y);
/* The irradiance itself take one layer, hence the +1 */
- int layer_ct = MIN2(irr_per_vis + 1, IRRADIANCE_MAX_POOL_LAYER);
+ int layer_count = MIN2(irr_per_vis + 1, IRRADIANCE_MAX_POOL_LAYER);
- int texel_ct = (int)ceilf((float)total_samples / (float)(layer_ct - 1));
+ int texel_count = (int)ceilf((float)total_samples / (float)(layer_count - 1));
r_size[0] = visibility_size *
- max_ii(1, min_ii(texel_ct, (IRRADIANCE_MAX_POOL_SIZE / visibility_size)));
+ max_ii(1, min_ii(texel_count, (IRRADIANCE_MAX_POOL_SIZE / visibility_size)));
r_size[1] = visibility_size *
- max_ii(1, (texel_ct / (IRRADIANCE_MAX_POOL_SIZE / visibility_size)));
- r_size[2] = layer_ct;
+ max_ii(1, (texel_count / (IRRADIANCE_MAX_POOL_SIZE / visibility_size)));
+ r_size[2] = layer_count;
}
static bool EEVEE_lightcache_validate(const LightCache *light_cache,
@@ -1118,7 +1118,7 @@ static void eevee_lightbake_render_grid_sample(void *ved, void *user_data)
SWAP(GPUTexture *, lbake->grid_prev, lcache->grid_tx.tex);
/* TODO: do this once for the whole bake when we have independent DRWManagers.
- * Warning: Some of the things above require this. */
+ * WARNING: Some of the things above require this. */
eevee_lightbake_cache_create(vedata, lbake);
/* Compute sample position */
diff --git a/source/blender/draw/engines/eevee/eevee_lookdev.c b/source/blender/draw/engines/eevee/eevee_lookdev.c
index e6c33feeeb9..a4bd789438d 100644
--- a/source/blender/draw/engines/eevee/eevee_lookdev.c
+++ b/source/blender/draw/engines/eevee/eevee_lookdev.c
@@ -64,7 +64,7 @@ static void eevee_lookdev_hdri_preview_init(EEVEE_Data *vedata, EEVEE_ViewLayerD
DRW_PASS_CREATE(psl->lookdev_diffuse_pass, state);
grp = DRW_shgroup_create(sh, psl->lookdev_diffuse_pass);
- EEVEE_material_bind_resources(grp, gpumat, sldata, vedata, NULL, NULL, false, false);
+ EEVEE_material_bind_resources(grp, gpumat, sldata, vedata, NULL, NULL, -1.0f, false, false);
DRW_shgroup_add_material_resources(grp, gpumat);
DRW_shgroup_call(grp, sphere, NULL);
}
@@ -75,7 +75,7 @@ static void eevee_lookdev_hdri_preview_init(EEVEE_Data *vedata, EEVEE_ViewLayerD
DRW_PASS_CREATE(psl->lookdev_glossy_pass, state);
grp = DRW_shgroup_create(sh, psl->lookdev_glossy_pass);
- EEVEE_material_bind_resources(grp, gpumat, sldata, vedata, NULL, NULL, false, false);
+ EEVEE_material_bind_resources(grp, gpumat, sldata, vedata, NULL, NULL, -1.0f, false, false);
DRW_shgroup_add_material_resources(grp, gpumat);
DRW_shgroup_call(grp, sphere, NULL);
}
@@ -112,7 +112,7 @@ void EEVEE_lookdev_init(EEVEE_Data *vedata)
if (sphere_size != effects->sphere_size || rect->xmax != effects->anchor[0] ||
rect->ymin != effects->anchor[1]) {
- /* Make sphere resolution adaptive to viewport_scale, dpi and lookdev_sphere_size */
+ /* Make sphere resolution adaptive to viewport_scale, DPI and #U.lookdev_sphere_size. */
float res_scale = clamp_f(
(U.lookdev_sphere_size / 400.0f) * viewport_scale * U.dpi_fac, 0.1f, 1.0f);
diff --git a/source/blender/draw/engines/eevee/eevee_materials.c b/source/blender/draw/engines/eevee/eevee_materials.c
index a81d3e56673..efd27c19654 100644
--- a/source/blender/draw/engines/eevee/eevee_materials.c
+++ b/source/blender/draw/engines/eevee/eevee_materials.c
@@ -67,6 +67,7 @@ void EEVEE_material_bind_resources(DRWShadingGroup *shgrp,
EEVEE_Data *vedata,
const int *ssr_id,
const float *refract_depth,
+ const float alpha_clip_threshold,
bool use_ssrefraction,
bool use_alpha_blend)
{
@@ -91,6 +92,8 @@ void EEVEE_material_bind_resources(DRWShadingGroup *shgrp,
DRW_shgroup_uniform_block(shgrp, "common_block", sldata->common_ubo);
DRW_shgroup_uniform_block_ref(shgrp, "renderpass_block", &pd->renderpass_ubo);
+ DRW_shgroup_uniform_float_copy(shgrp, "alphaClipThreshold", alpha_clip_threshold);
+
DRW_shgroup_uniform_int_copy(shgrp, "outputSssId", 1);
DRW_shgroup_uniform_texture(shgrp, "utilTex", e_data.util_tex);
if (use_diffuse || use_glossy || use_refract) {
@@ -480,6 +483,8 @@ BLI_INLINE void material_shadow(EEVEE_Data *vedata,
/* Shadow Pass */
const bool use_shadow_shader = ma->use_nodes && ma->nodetree &&
ELEM(ma->blend_shadow, MA_BS_CLIP, MA_BS_HASHED);
+ float alpha_clip_threshold = (ma->blend_shadow == MA_BS_CLIP) ? ma->alpha_threshold : -1.0f;
+
int mat_options = VAR_MAT_MESH | VAR_MAT_DEPTH;
SET_FLAG_FROM_TEST(mat_options, use_shadow_shader, VAR_MAT_HASH);
SET_FLAG_FROM_TEST(mat_options, is_hair, VAR_MAT_HAIR);
@@ -503,7 +508,8 @@ BLI_INLINE void material_shadow(EEVEE_Data *vedata,
}
else {
*grp_p = grp = DRW_shgroup_create(sh, psl->shadow_pass);
- EEVEE_material_bind_resources(grp, gpumat, sldata, vedata, NULL, NULL, false, false);
+ EEVEE_material_bind_resources(
+ grp, gpumat, sldata, vedata, NULL, NULL, alpha_clip_threshold, false, false);
}
DRW_shgroup_add_material_resources(grp, gpumat);
@@ -533,6 +539,7 @@ static EeveeMaterialCache material_opaque(EEVEE_Data *vedata,
const bool use_ssrefract = use_gpumat && ((ma->blend_flag & MA_BL_SS_REFRACTION) != 0) &&
((effects->enabled_effects & EFFECT_REFRACT) != 0);
const bool use_depth_shader = use_gpumat && ELEM(ma->blend_method, MA_BM_CLIP, MA_BM_HASHED);
+ float alpha_clip_threshold = (ma->blend_method == MA_BM_CLIP) ? ma->alpha_threshold : -1.0f;
/* HACK: Assume the struct will never be smaller than our variations.
* This allow us to only keep one ghash and avoid bigger keys comparisons/hashing. */
@@ -581,7 +588,8 @@ static EeveeMaterialCache material_opaque(EEVEE_Data *vedata,
}
else {
*grp_p = grp = DRW_shgroup_create(sh, depth_ps);
- EEVEE_material_bind_resources(grp, gpumat, sldata, vedata, NULL, NULL, false, false);
+ EEVEE_material_bind_resources(
+ grp, gpumat, sldata, vedata, NULL, NULL, alpha_clip_threshold, false, false);
}
DRW_shgroup_add_material_resources(grp, gpumat);
@@ -630,8 +638,15 @@ static EeveeMaterialCache material_opaque(EEVEE_Data *vedata,
}
else {
*grp_p = grp = DRW_shgroup_create(sh, shading_pass);
- EEVEE_material_bind_resources(
- grp, gpumat, sldata, vedata, &ssr_id, &ma->refract_depth, use_ssrefract, false);
+ EEVEE_material_bind_resources(grp,
+ gpumat,
+ sldata,
+ vedata,
+ &ssr_id,
+ &ma->refract_depth,
+ alpha_clip_threshold,
+ use_ssrefract,
+ false);
}
DRW_shgroup_add_material_resources(grp, gpumat);
@@ -677,7 +692,7 @@ static EeveeMaterialCache material_transparent(EEVEE_Data *vedata,
DRWShadingGroup *grp = DRW_shgroup_create(sh, psl->transparent_pass);
- EEVEE_material_bind_resources(grp, gpumat, sldata, vedata, NULL, NULL, false, true);
+ EEVEE_material_bind_resources(grp, gpumat, sldata, vedata, NULL, NULL, -1.0f, false, true);
DRW_shgroup_add_material_resources(grp, gpumat);
cur_state = DRW_STATE_WRITE_DEPTH | DRW_STATE_DEPTH_LESS_EQUAL;
@@ -699,7 +714,7 @@ static EeveeMaterialCache material_transparent(EEVEE_Data *vedata,
psl->transparent_pass);
EEVEE_material_bind_resources(
- grp, gpumat, sldata, vedata, &ssr_id, &ma->refract_depth, use_ssrefract, true);
+ grp, gpumat, sldata, vedata, &ssr_id, &ma->refract_depth, -1.0f, use_ssrefract, true);
DRW_shgroup_add_material_resources(grp, gpumat);
cur_state = DRW_STATE_WRITE_COLOR | DRW_STATE_BLEND_CUSTOM;
diff --git a/source/blender/draw/engines/eevee/eevee_motion_blur.c b/source/blender/draw/engines/eevee/eevee_motion_blur.c
index 2e0937dbe49..a3ca19c88e1 100644
--- a/source/blender/draw/engines/eevee/eevee_motion_blur.c
+++ b/source/blender/draw/engines/eevee/eevee_motion_blur.c
@@ -226,7 +226,8 @@ void EEVEE_motion_blur_hair_cache_populate(EEVEE_ViewLayerData *UNUSED(sldata),
}
/* For now we assume hair objects are always moving. */
- EEVEE_ObjectMotionData *mb_data = EEVEE_motion_blur_object_data_get(&effects->motion_blur, ob);
+ EEVEE_ObjectMotionData *mb_data = EEVEE_motion_blur_object_data_get(
+ &effects->motion_blur, ob, true);
if (mb_data) {
int mb_step = effects->motion_blur_step;
@@ -283,7 +284,8 @@ void EEVEE_motion_blur_curves_cache_populate(EEVEE_ViewLayerData *UNUSED(sldata)
}
/* For now we assume curves objects are always moving. */
- EEVEE_ObjectMotionData *mb_data = EEVEE_motion_blur_object_data_get(&effects->motion_blur, ob);
+ EEVEE_ObjectMotionData *mb_data = EEVEE_motion_blur_object_data_get(
+ &effects->motion_blur, ob, false);
if (mb_data == NULL) {
return;
}
@@ -354,7 +356,8 @@ void EEVEE_motion_blur_cache_populate(EEVEE_ViewLayerData *UNUSED(sldata),
return;
}
- EEVEE_ObjectMotionData *mb_data = EEVEE_motion_blur_object_data_get(&effects->motion_blur, ob);
+ EEVEE_ObjectMotionData *mb_data = EEVEE_motion_blur_object_data_get(
+ &effects->motion_blur, ob, false);
if (mb_data) {
int mb_step = effects->motion_blur_step;
diff --git a/source/blender/draw/engines/eevee/eevee_private.h b/source/blender/draw/engines/eevee/eevee_private.h
index 3a86640134c..ad218d80cdf 100644
--- a/source/blender/draw/engines/eevee/eevee_private.h
+++ b/source/blender/draw/engines/eevee/eevee_private.h
@@ -644,8 +644,10 @@ typedef struct EEVEE_MotionBlurData {
} EEVEE_MotionBlurData;
typedef struct EEVEE_ObjectKey {
- /** Object or source object for duplis */
- struct Object *ob;
+ /** Object or source object for duplis. */
+ /** WORKAROUND: The pointer is different for particle systems and do not point to the real
+ * object. (See T97380) */
+ void *ob;
/** Parent object for duplis */
struct Object *parent;
/** Dupli objects recursive unique identifier */
@@ -669,7 +671,7 @@ typedef struct EEVEE_HairMotionData {
/** Allocator will alloc enough slot for all particle systems. Or 1 if it's a curves object. */
int psys_len;
struct {
- /* The vbos and textures are not owned. */
+ /* The VBO's and textures are not owned. */
EEVEE_HairMotionStepData step_data[2]; /* Data for time = t +/- step. */
} psys[0];
} EEVEE_HairMotionData;
@@ -680,7 +682,7 @@ typedef struct EEVEE_GeometryMotionData {
/** To disable deform mb if vertcount mismatch. */
int use_deform;
- /* The batch and vbos are not owned. */
+ /* The batch and VBOs are not owned. */
struct GPUBatch *batch; /* Batch for time = t. */
struct GPUVertBuf *vbo[2]; /* VBO for time = t +/- step. */
} EEVEE_GeometryMotionData;
@@ -1093,7 +1095,9 @@ EEVEE_ViewLayerData *EEVEE_view_layer_data_ensure_ex(struct ViewLayer *view_laye
EEVEE_ViewLayerData *EEVEE_view_layer_data_ensure(void);
EEVEE_ObjectEngineData *EEVEE_object_data_get(Object *ob);
EEVEE_ObjectEngineData *EEVEE_object_data_ensure(Object *ob);
-EEVEE_ObjectMotionData *EEVEE_motion_blur_object_data_get(EEVEE_MotionBlurData *mb, Object *ob);
+EEVEE_ObjectMotionData *EEVEE_motion_blur_object_data_get(EEVEE_MotionBlurData *mb,
+ Object *ob,
+ bool is_psys);
EEVEE_GeometryMotionData *EEVEE_motion_blur_geometry_data_get(EEVEE_ObjectMotionData *mb_data);
EEVEE_HairMotionData *EEVEE_motion_blur_hair_data_get(EEVEE_ObjectMotionData *mb_data, Object *ob);
EEVEE_HairMotionData *EEVEE_motion_blur_curves_data_get(EEVEE_ObjectMotionData *mb_data);
@@ -1141,6 +1145,7 @@ void EEVEE_material_bind_resources(DRWShadingGroup *shgrp,
EEVEE_Data *vedata,
const int *ssr_id,
const float *refract_depth,
+ const float alpha_clip_threshold,
bool use_ssrefraction,
bool use_alpha_blend);
/* eevee_lights.c */
diff --git a/source/blender/draw/engines/eevee/eevee_shaders.c b/source/blender/draw/engines/eevee/eevee_shaders.c
index 85cc7f65126..5709621fc05 100644
--- a/source/blender/draw/engines/eevee/eevee_shaders.c
+++ b/source/blender/draw/engines/eevee/eevee_shaders.c
@@ -169,7 +169,6 @@ extern char datatoc_common_hair_lib_glsl[];
extern char datatoc_common_math_lib_glsl[];
extern char datatoc_common_math_geom_lib_glsl[];
extern char datatoc_common_view_lib_glsl[];
-extern char datatoc_gpu_shader_common_obinfos_lib_glsl[];
extern char datatoc_gpu_shader_codegen_lib_glsl[];
extern char datatoc_ambient_occlusion_lib_glsl[];
@@ -183,6 +182,7 @@ extern char datatoc_closure_eval_volume_lib_glsl[];
extern char datatoc_common_uniforms_lib_glsl[];
extern char datatoc_common_utiltex_lib_glsl[];
extern char datatoc_cryptomatte_frag_glsl[];
+extern char datatoc_cryptomatte_vert_glsl[];
extern char datatoc_cubemap_lib_glsl[];
extern char datatoc_default_frag_glsl[];
extern char datatoc_lookdev_world_frag_glsl[];
@@ -277,7 +277,6 @@ static void eevee_shader_library_ensure(void)
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_uniforms_lib);
- DRW_SHADER_LIB_ADD(e_data.lib, gpu_shader_common_obinfos_lib);
DRW_SHADER_LIB_ADD(e_data.lib, gpu_shader_codegen_lib);
DRW_SHADER_LIB_ADD(e_data.lib, random_lib);
DRW_SHADER_LIB_ADD(e_data.lib, renderpass_lib);
@@ -305,6 +304,7 @@ static void eevee_shader_library_ensure(void)
DRW_SHADER_LIB_ADD(e_data.lib, closure_eval_refraction_lib);
DRW_SHADER_LIB_ADD(e_data.lib, closure_eval_surface_lib);
DRW_SHADER_LIB_ADD(e_data.lib, closure_eval_volume_lib);
+ DRW_SHADER_LIB_ADD(e_data.lib, surface_vert);
e_data.surface_lit_frag = DRW_shader_library_create_shader_string(e_data.lib,
datatoc_surface_frag_glsl);
@@ -718,7 +718,7 @@ GPUShader *EEVEE_shaders_cryptomatte_sh_get(bool is_hair)
if (e_data.cryptomatte_sh[index] == NULL) {
DynStr *ds = BLI_dynstr_new();
BLI_dynstr_append(ds, SHADER_DEFINES);
-
+ BLI_dynstr_append(ds, "#define attrib_load() \n");
if (is_hair) {
BLI_dynstr_append(ds, "#define HAIR_SHADER\n");
}
@@ -727,7 +727,7 @@ GPUShader *EEVEE_shaders_cryptomatte_sh_get(bool is_hair)
}
char *defines = BLI_dynstr_get_cstring(ds);
e_data.cryptomatte_sh[index] = DRW_shader_create_with_shaderlib(
- datatoc_surface_vert_glsl, NULL, datatoc_cryptomatte_frag_glsl, e_data.lib, defines);
+ datatoc_cryptomatte_vert_glsl, NULL, datatoc_cryptomatte_frag_glsl, e_data.lib, defines);
BLI_dynstr_free(ds);
MEM_freeN(defines);
}
diff --git a/source/blender/draw/engines/eevee/eevee_shaders_extra.cc b/source/blender/draw/engines/eevee/eevee_shaders_extra.cc
index 05577944140..216a15de2b9 100644
--- a/source/blender/draw/engines/eevee/eevee_shaders_extra.cc
+++ b/source/blender/draw/engines/eevee/eevee_shaders_extra.cc
@@ -118,6 +118,10 @@ void eevee_shader_material_create_info_amend(GPUMaterial *gpumat,
info.vertex_inputs_.clear();
}
+ if (is_hair) {
+ info.additional_info("draw_curves_infos");
+ }
+
if (!is_volume) {
info.define("EEVEE_GENERATED_INTERFACE");
info.vertex_out(*stage_interface);
diff --git a/source/blender/draw/engines/eevee/shaders/closure_eval_surface_lib.glsl b/source/blender/draw/engines/eevee/shaders/closure_eval_surface_lib.glsl
index fa94b5ed272..ffca97b6b8f 100644
--- a/source/blender/draw/engines/eevee/shaders/closure_eval_surface_lib.glsl
+++ b/source/blender/draw/engines/eevee/shaders/closure_eval_surface_lib.glsl
@@ -5,7 +5,7 @@
#pragma BLENDER_REQUIRE(closure_eval_translucent_lib.glsl)
#pragma BLENDER_REQUIRE(renderpass_lib.glsl)
-#ifdef USE_SHADER_TO_RGBA
+#if defined(USE_SHADER_TO_RGBA) || defined(USE_ALPHA_BLEND)
bool do_sss = false;
bool do_ssr = false;
#else
@@ -181,6 +181,8 @@ Closure closure_eval(ClosureDiffuse diffuse, ClosureReflection reflection)
/* Glue with the old system. */
CLOSURE_VARS_DECLARE_2(Diffuse, Glossy);
+ /* WORKAROUND: This is to avoid regression in 3.2 and avoid messing with EEVEE-Next. */
+ in_common.occlusion = (diffuse.sss_radius.g == -1.0) ? diffuse.sss_radius.r : 1.0;
in_Diffuse_0.N = diffuse.N;
in_Diffuse_0.albedo = diffuse.color;
in_Glossy_1.N = reflection.N;
@@ -207,6 +209,8 @@ Closure closure_eval(ClosureDiffuse diffuse,
/* Glue with the old system. */
CLOSURE_VARS_DECLARE_3(Diffuse, Glossy, Glossy);
+ /* WORKAROUND: This is to avoid regression in 3.2 and avoid messing with EEVEE-Next. */
+ in_common.occlusion = (diffuse.sss_radius.g == -1.0) ? diffuse.sss_radius.r : 1.0;
in_Diffuse_0.N = diffuse.N;
in_Diffuse_0.albedo = diffuse.color;
in_Glossy_1.N = reflection.N;
@@ -309,16 +313,19 @@ vec4 closure_to_rgba(Closure closure)
return vec4(closure.radiance, 1.0 - saturate(avg(closure.transmittance)));
}
-Closure closure_add(Closure cl1, Closure cl2)
+Closure closure_add(inout Closure cl1, inout Closure cl2)
{
Closure cl;
cl.radiance = cl1.radiance + cl2.radiance;
cl.transmittance = cl1.transmittance + cl2.transmittance;
cl.holdout = cl1.holdout + cl2.holdout;
+ /* Make sure each closure is only added once to the result. */
+ cl1 = CLOSURE_DEFAULT;
+ cl2 = CLOSURE_DEFAULT;
return cl;
}
-Closure closure_mix(Closure cl1, Closure cl2, float fac)
+Closure closure_mix(inout Closure cl1, inout Closure cl2, float fac)
{
/* Weights have already been applied. */
return closure_add(cl1, cl2);
diff --git a/source/blender/draw/engines/eevee/shaders/closure_eval_volume_lib.glsl b/source/blender/draw/engines/eevee/shaders/closure_eval_volume_lib.glsl
index e450b8ad3c8..5e34d654cfd 100644
--- a/source/blender/draw/engines/eevee/shaders/closure_eval_volume_lib.glsl
+++ b/source/blender/draw/engines/eevee/shaders/closure_eval_volume_lib.glsl
@@ -92,7 +92,7 @@ vec4 closure_to_rgba(Closure closure)
return vec4(0.0);
}
-Closure closure_mix(Closure cl1, Closure cl2, float fac)
+Closure closure_mix(inout Closure cl1, inout Closure cl2, float fac)
{
Closure cl;
cl.absorption = mix(cl1.absorption, cl2.absorption, fac);
@@ -102,7 +102,7 @@ Closure closure_mix(Closure cl1, Closure cl2, float fac)
return cl;
}
-Closure closure_add(Closure cl1, Closure cl2)
+Closure closure_add(inout Closure cl1, inout Closure cl2)
{
Closure cl;
cl.absorption = cl1.absorption + cl2.absorption;
diff --git a/source/blender/draw/engines/eevee/shaders/closure_type_lib.glsl b/source/blender/draw/engines/eevee/shaders/closure_type_lib.glsl
index 492b78a20b6..4070ede116b 100644
--- a/source/blender/draw/engines/eevee/shaders/closure_type_lib.glsl
+++ b/source/blender/draw/engines/eevee/shaders/closure_type_lib.glsl
@@ -24,7 +24,7 @@ struct Closure {
float holdout;
#endif
-/* Metal Default Constructor - Requred for C++ constructor syntax. */
+/* Metal Default Constructor - Required for C++ constructor syntax. */
#ifdef GPU_METAL
inline Closure() = default;
# ifdef VOLUMETRICS
@@ -49,7 +49,7 @@ struct Closure {
#ifndef GPU_METAL
/* Prototype */
Closure nodetree_exec();
-vec4 closure_to_rgba(Closure);
+vec4 closure_to_rgba(Closure cl);
void output_aov(vec4 color, float value, uint hash);
vec3 coordinate_camera(vec3 P);
vec3 coordinate_screen(vec3 P);
@@ -87,8 +87,8 @@ Closure closure_eval(ClosureDiffuse diffuse,
ClosureReflection clearcoat,
ClosureRefraction refraction);
-Closure closure_add(Closure cl1, Closure cl2);
-Closure closure_mix(Closure cl1, Closure cl2, float fac);
+Closure closure_add(inout Closure cl1, inout Closure cl2);
+Closure closure_mix(inout Closure cl1, inout Closure cl2, float fac);
float ambient_occlusion_eval(vec3 normal,
float distance,
diff --git a/source/blender/draw/engines/eevee/shaders/cryptomatte_vert.glsl b/source/blender/draw/engines/eevee/shaders/cryptomatte_vert.glsl
new file mode 100644
index 00000000000..f8dbc4772e9
--- /dev/null
+++ b/source/blender/draw/engines/eevee/shaders/cryptomatte_vert.glsl
@@ -0,0 +1,6 @@
+
+#pragma BLENDER_REQUIRE(closure_type_lib.glsl)
+#pragma BLENDER_REQUIRE(common_view_lib.glsl)
+#pragma BLENDER_REQUIRE(common_math_lib.glsl)
+#pragma BLENDER_REQUIRE(common_attribute_lib.glsl)
+#pragma BLENDER_REQUIRE(surface_vert.glsl)
diff --git a/source/blender/draw/engines/eevee/shaders/prepass_frag.glsl b/source/blender/draw/engines/eevee/shaders/prepass_frag.glsl
index c8eea8d7860..15c68dc5829 100644
--- a/source/blender/draw/engines/eevee/shaders/prepass_frag.glsl
+++ b/source/blender/draw/engines/eevee/shaders/prepass_frag.glsl
@@ -11,6 +11,8 @@
#pragma BLENDER_REQUIRE(surface_lib.glsl)
#ifdef USE_ALPHA_HASH
+/* A value of -1.0 will disable alpha clip and use alpha hash. */
+uniform float alphaClipThreshold;
/* From the paper "Hashed Alpha Testing" by Chris Wyman and Morgan McGuire */
float hash(vec2 a)
@@ -76,9 +78,16 @@ void main()
float opacity = saturate(1.0 - avg(cl.transmittance));
- /* Hashed Alpha Testing */
- if (opacity < hashed_alpha_threshold(worldPosition)) {
- discard;
+ if (alphaClipThreshold == -1.0) {
+ /* NOTE: uniform control flow required for dFdx(). */
+ if (opacity < hashed_alpha_threshold(worldPosition)) {
+ discard;
+ }
+ }
+ else {
+ if (opacity <= alphaClipThreshold) {
+ discard;
+ }
}
#endif
}
diff --git a/source/blender/draw/engines/eevee/shaders/shadow_vert.glsl b/source/blender/draw/engines/eevee/shaders/shadow_vert.glsl
index 5295a05b965..2926f8c5a89 100644
--- a/source/blender/draw/engines/eevee/shaders/shadow_vert.glsl
+++ b/source/blender/draw/engines/eevee/shaders/shadow_vert.glsl
@@ -65,6 +65,22 @@ vec3 attr_load_orco(samplerBuffer cd_buf)
}
# endif
+/* Per attribute scope follows loading order. */
+int g_curves_attr_id = 0;
+
+/* Return the index to use for looking up the attribute value in the sampler
+ * based on the attribute scope (point or spline). */
+int curves_attribute_element_id()
+{
+ int id = hairStrandID;
+ if (drw_curves.is_point_attribute[g_curves_attr_id] != 0) {
+ id = hair_get_base_id();
+ }
+
+ g_curves_attr_id += 1;
+ return id;
+}
+
vec4 attr_load_tangent(samplerBuffer cd_buf)
{
/* Not supported. */
@@ -73,22 +89,22 @@ vec4 attr_load_tangent(samplerBuffer cd_buf)
vec4 attr_load_vec4(samplerBuffer cd_buf)
{
- return texelFetch(cd_buf, hairStrandID).rgba;
+ return texelFetch(cd_buf, curves_attribute_element_id()).rgba;
}
vec3 attr_load_vec3(samplerBuffer cd_buf)
{
- return texelFetch(cd_buf, hairStrandID).rgb;
+ return texelFetch(cd_buf, curves_attribute_element_id()).rgb;
}
vec2 attr_load_vec2(samplerBuffer cd_buf)
{
- return texelFetch(cd_buf, hairStrandID).rg;
+ return texelFetch(cd_buf, curves_attribute_element_id()).rg;
}
float attr_load_float(samplerBuffer cd_buf)
{
- return texelFetch(cd_buf, hairStrandID).r;
+ return texelFetch(cd_buf, curves_attribute_element_id()).r;
}
#else
diff --git a/source/blender/draw/engines/eevee/shaders/surface_lib.glsl b/source/blender/draw/engines/eevee/shaders/surface_lib.glsl
index 1f2f7cb65cc..8e1bafe8d92 100644
--- a/source/blender/draw/engines/eevee/shaders/surface_lib.glsl
+++ b/source/blender/draw/engines/eevee/shaders/surface_lib.glsl
@@ -108,10 +108,9 @@ GlobalData init_globals(void)
# endif
surf.barycentric_coords = vec2(0.0);
surf.barycentric_dists = vec3(0.0);
- if (!FrontFacing) {
- surf.N = -surf.N;
- }
+ surf.N = (FrontFacing) ? surf.N : -surf.N;
# ifdef HAIR_SHADER
+ vec3 V = cameraVec(surf.P);
/* Shade as a cylinder. */
vec3 B = normalize(cross(worldNormal, hairTangent));
float cos_theta;
@@ -125,7 +124,10 @@ GlobalData init_globals(void)
}
float sin_theta = sqrt(max(0.0, 1.0 - cos_theta * cos_theta));
surf.N = safe_normalize(worldNormal * sin_theta + B * cos_theta);
- surf.T = hairTangent;
+ surf.curve_T = -hairTangent;
+ /* Costly, but follows cycles per pixel tangent space (not following curve shape). */
+ surf.curve_B = cross(V, surf.curve_T);
+ surf.curve_N = safe_normalize(cross(surf.curve_T, surf.curve_B));
surf.is_strand = true;
surf.hair_time = hairTime;
surf.hair_thickness = hairThickness;
@@ -134,7 +136,7 @@ GlobalData init_globals(void)
surf.barycentric_coords = hair_resolve_barycentric(hairBary);
# endif
# else
- surf.T = vec3(0.0);
+ surf.curve_T = surf.curve_B = surf.curve_N = vec3(0.0);
surf.is_strand = false;
surf.hair_time = 0.0;
surf.hair_thickness = 0.0;
@@ -199,4 +201,4 @@ vec3 coordinate_incoming(vec3 P)
#else
return cameraVec(P);
#endif
-} \ No newline at end of file
+}
diff --git a/source/blender/draw/engines/eevee/shaders/surface_vert.glsl b/source/blender/draw/engines/eevee/shaders/surface_vert.glsl
index 7cb4d7ac25c..a8e95e13b12 100644
--- a/source/blender/draw/engines/eevee/shaders/surface_vert.glsl
+++ b/source/blender/draw/engines/eevee/shaders/surface_vert.glsl
@@ -72,6 +72,22 @@ vec3 attr_load_orco(samplerBuffer cd_buf)
}
# endif
+/* Per attribute scope follows loading order. */
+int g_curves_attr_id = 0;
+
+/* Return the index to use for looking up the attribute value in the sampler
+ * based on the attribute scope (point or spline). */
+int curves_attribute_element_id()
+{
+ int id = hairStrandID;
+ if (drw_curves.is_point_attribute[g_curves_attr_id] != 0) {
+ id = hair_get_base_id();
+ }
+
+ g_curves_attr_id += 1;
+ return id;
+}
+
vec4 attr_load_tangent(samplerBuffer cd_buf)
{
return vec4(hairTangent, 1.0);
@@ -79,22 +95,22 @@ vec4 attr_load_tangent(samplerBuffer cd_buf)
vec4 attr_load_vec4(samplerBuffer cd_buf)
{
- return texelFetch(cd_buf, hairStrandID).rgba;
+ return texelFetch(cd_buf, curves_attribute_element_id()).rgba;
}
vec3 attr_load_vec3(samplerBuffer cd_buf)
{
- return texelFetch(cd_buf, hairStrandID).rgb;
+ return texelFetch(cd_buf, curves_attribute_element_id()).rgb;
}
vec2 attr_load_vec2(samplerBuffer cd_buf)
{
- return texelFetch(cd_buf, hairStrandID).rg;
+ return texelFetch(cd_buf, curves_attribute_element_id()).rg;
}
float attr_load_float(samplerBuffer cd_buf)
{
- return texelFetch(cd_buf, hairStrandID).r;
+ return texelFetch(cd_buf, curves_attribute_element_id()).r;
}
#else
@@ -117,7 +133,7 @@ vec3 attr_load_orco(vec4 orco)
vec4 attr_load_tangent(vec4 tangent)
{
- tangent.xyz = normal_object_to_world(tangent.xyz);
+ tangent.xyz = safe_normalize(normal_object_to_world(tangent.xyz));
return tangent;
}
diff --git a/source/blender/draw/engines/eevee/shaders/volumetric_frag.glsl b/source/blender/draw/engines/eevee/shaders/volumetric_frag.glsl
index d6eeedd8640..88ade8451a4 100644
--- a/source/blender/draw/engines/eevee/shaders/volumetric_frag.glsl
+++ b/source/blender/draw/engines/eevee/shaders/volumetric_frag.glsl
@@ -8,7 +8,7 @@
flat in int slice;
-/* Warning: these are not attributes, these are global vars. */
+/* WARNING: these are not attributes, these are global vars. */
vec3 worldPosition = vec3(0.0);
vec3 objectPosition = vec3(0.0);
vec3 viewPosition = vec3(0.0);
@@ -80,8 +80,8 @@ void main()
volumeOrco = OrcoTexCoFactors[0].xyz + objectPosition * OrcoTexCoFactors[1].xyz;
if (any(lessThan(volumeOrco, vec3(0.0))) || any(greaterThan(volumeOrco, vec3(1.0)))) {
- /* Note: Discard is not an explicit return in Metal prior to versions 2.3.
- * adding return after discard ensures consistent behaviour and avoids GPU
+ /* NOTE: Discard is not an explicit return in Metal prior to versions 2.3.
+ * adding return after discard ensures consistent behavior and avoids GPU
* side-effects where control flow continues with undefined values. */
discard;
return;
@@ -157,7 +157,7 @@ float attr_load_float(sampler3D tex)
}
/* TODO(@fclem): These implementation details should concern the DRWManager and not be a fix on
- * the engine side. But as of now, the engines are reponsible for loading the attributes. */
+ * the engine side. But as of now, the engines are responsible for loading the attributes. */
float attr_load_temperature_post(float attr)
{
#ifdef MESH_SHADER
diff --git a/source/blender/draw/engines/eevee/shaders/volumetric_integration_frag.glsl b/source/blender/draw/engines/eevee/shaders/volumetric_integration_frag.glsl
index 527bbd18896..3ce54b3122a 100644
--- a/source/blender/draw/engines/eevee/shaders/volumetric_integration_frag.glsl
+++ b/source/blender/draw/engines/eevee/shaders/volumetric_integration_frag.glsl
@@ -70,7 +70,7 @@ void main()
vec3 Tr = exp(-s_extinction * s_len);
/* integrate along the current step segment */
- /* Note: Original calculation carries precision issues when compiling for AMD GPUs
+ /* NOTE: Original calculation carries precision issues when compiling for AMD GPUs
* and running Metal. This version of the equation retains precision well for all
* macOS HW configurations. */
Lscat = (Lscat * (1.0f - Tr)) / max(vec3(1e-8), s_extinction);
diff --git a/source/blender/draw/engines/eevee/shaders/volumetric_vert.glsl b/source/blender/draw/engines/eevee/shaders/volumetric_vert.glsl
index b574e8cdb4c..b3b9c7af19c 100644
--- a/source/blender/draw/engines/eevee/shaders/volumetric_vert.glsl
+++ b/source/blender/draw/engines/eevee/shaders/volumetric_vert.glsl
@@ -57,3 +57,33 @@ float F_eta(float a, float b)
{
return 0.0;
}
+
+vec3 coordinate_camera(vec3 P)
+{
+ return vec3(0.0);
+}
+
+vec3 coordinate_screen(vec3 P)
+{
+ return vec3(0.0);
+}
+
+vec3 coordinate_reflect(vec3 P, vec3 N)
+{
+ return vec3(0.0);
+}
+
+vec3 coordinate_incoming(vec3 P)
+{
+ return vec3(0.0);
+}
+
+float attr_load_temperature_post(float attr)
+{
+ return attr;
+}
+
+vec4 attr_load_color_post(vec4 attr)
+{
+ return attr;
+}
diff --git a/source/blender/draw/engines/eevee_next/eevee_camera.cc b/source/blender/draw/engines/eevee_next/eevee_camera.cc
new file mode 100644
index 00000000000..e6d2e2db764
--- /dev/null
+++ b/source/blender/draw/engines/eevee_next/eevee_camera.cc
@@ -0,0 +1,152 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later
+ * Copyright 2021 Blender Foundation.
+ */
+
+/** \file
+ * \ingroup eevee
+ */
+
+#include <array>
+
+#include "DRW_render.h"
+
+#include "DNA_camera_types.h"
+#include "DNA_view3d_types.h"
+
+#include "BKE_camera.h"
+#include "DEG_depsgraph_query.h"
+#include "RE_pipeline.h"
+
+#include "eevee_camera.hh"
+#include "eevee_instance.hh"
+
+namespace blender::eevee {
+
+/* -------------------------------------------------------------------- */
+/** \name Camera
+ * \{ */
+
+void Camera::init()
+{
+ const Object *camera_eval = inst_.camera_eval_object;
+ synced_ = false;
+ data_.swap();
+
+ CameraData &data = data_.current();
+
+ if (camera_eval) {
+ const ::Camera *cam = reinterpret_cast<const ::Camera *>(camera_eval->data);
+ switch (cam->type) {
+ default:
+ case CAM_PERSP:
+ data.type = CAMERA_PERSP;
+ break;
+ case CAM_ORTHO:
+ data.type = CAMERA_ORTHO;
+ break;
+#if 0 /* TODO(fclem): Make fisheye properties inside blender. */
+ case CAM_PANO: {
+ switch (cam->panorama_type) {
+ default:
+ case CAM_PANO_EQUIRECTANGULAR:
+ data.type = CAMERA_PANO_EQUIRECT;
+ break;
+ case CAM_PANO_FISHEYE_EQUIDISTANT:
+ data.type = CAMERA_PANO_EQUIDISTANT;
+ break;
+ case CAM_PANO_FISHEYE_EQUISOLID:
+ data.type = CAMERA_PANO_EQUISOLID;
+ break;
+ case CAM_PANO_MIRRORBALL:
+ data.type = CAMERA_PANO_MIRROR;
+ break;
+ }
+ }
+#endif
+ }
+ }
+ else if (inst_.drw_view) {
+ data.type = DRW_view_is_persp_get(inst_.drw_view) ? CAMERA_PERSP : CAMERA_ORTHO;
+ }
+ else {
+ /* Light-probe baking. */
+ data.type = CAMERA_PERSP;
+ }
+}
+
+void Camera::sync()
+{
+ const Object *camera_eval = inst_.camera_eval_object;
+ CameraData &data = data_.current();
+
+ data.filter_size = inst_.scene->r.gauss;
+
+ if (inst_.drw_view) {
+ DRW_view_viewmat_get(inst_.drw_view, data.viewmat.ptr(), false);
+ DRW_view_viewmat_get(inst_.drw_view, data.viewinv.ptr(), true);
+ DRW_view_winmat_get(inst_.drw_view, data.winmat.ptr(), false);
+ DRW_view_winmat_get(inst_.drw_view, data.wininv.ptr(), true);
+ DRW_view_persmat_get(inst_.drw_view, data.persmat.ptr(), false);
+ DRW_view_persmat_get(inst_.drw_view, data.persinv.ptr(), true);
+ DRW_view_camtexco_get(inst_.drw_view, data.uv_scale);
+ }
+ else if (inst_.render) {
+ /* TODO(@fclem): Over-scan. */
+ // RE_GetCameraWindowWithOverscan(inst_.render->re, g_data->overscan, data.winmat);
+ RE_GetCameraWindow(inst_.render->re, camera_eval, data.winmat.ptr());
+ RE_GetCameraModelMatrix(inst_.render->re, camera_eval, data.viewinv.ptr());
+ invert_m4_m4(data.viewmat.ptr(), data.viewinv.ptr());
+ invert_m4_m4(data.wininv.ptr(), data.winmat.ptr());
+ mul_m4_m4m4(data.persmat.ptr(), data.winmat.ptr(), data.viewmat.ptr());
+ invert_m4_m4(data.persinv.ptr(), data.persmat.ptr());
+ data.uv_scale = float2(1.0f);
+ data.uv_bias = float2(0.0f);
+ }
+ else {
+ data.viewmat = float4x4::identity();
+ data.viewinv = float4x4::identity();
+ perspective_m4(data.winmat.ptr(), -0.1f, 0.1f, -0.1f, 0.1f, 0.1f, 1.0f);
+ data.wininv = data.winmat.inverted();
+ data.persmat = data.winmat * data.viewmat;
+ data.persinv = data.persmat.inverted();
+ }
+
+ if (camera_eval) {
+ const ::Camera *cam = reinterpret_cast<const ::Camera *>(camera_eval->data);
+ data.clip_near = cam->clip_start;
+ data.clip_far = cam->clip_end;
+#if 0 /* TODO(fclem): Make fisheye properties inside blender. */
+ data.fisheye_fov = cam->fisheye_fov;
+ data.fisheye_lens = cam->fisheye_lens;
+ data.equirect_bias.x = -cam->longitude_min + M_PI_2;
+ data.equirect_bias.y = -cam->latitude_min + M_PI_2;
+ data.equirect_scale.x = cam->longitude_min - cam->longitude_max;
+ data.equirect_scale.y = cam->latitude_min - cam->latitude_max;
+ /* Combine with uv_scale/bias to avoid doing extra computation. */
+ data.equirect_bias += data.uv_bias * data.equirect_scale;
+ data.equirect_scale *= data.uv_scale;
+
+ data.equirect_scale_inv = 1.0f / data.equirect_scale;
+#endif
+ }
+ else if (inst_.drw_view) {
+ data.clip_near = DRW_view_near_distance_get(inst_.drw_view);
+ data.clip_far = DRW_view_far_distance_get(inst_.drw_view);
+ data.fisheye_fov = data.fisheye_lens = -1.0f;
+ data.equirect_bias = float2(0.0f);
+ data.equirect_scale = float2(0.0f);
+ }
+
+ data_.current().push_update();
+
+ synced_ = true;
+
+ /* Detect changes in parameters. */
+ if (data_.current() != data_.previous()) {
+ // inst_.sampling.reset();
+ }
+}
+
+/** \} */
+
+} // namespace blender::eevee
diff --git a/source/blender/draw/engines/eevee_next/eevee_camera.hh b/source/blender/draw/engines/eevee_next/eevee_camera.hh
index 3db343703e0..dfec738b1f3 100644
--- a/source/blender/draw/engines/eevee_next/eevee_camera.hh
+++ b/source/blender/draw/engines/eevee_next/eevee_camera.hh
@@ -1,11 +1,14 @@
/* SPDX-License-Identifier: GPL-2.0-or-later
- * Copyright 2021 Blender Foundation.
- */
+ * Copyright 2021 Blender Foundation. */
+
+#pragma once
/** \file
* \ingroup eevee
*/
+#include "eevee_shader_shared.hh"
+
namespace blender::eevee {
class Instance;
@@ -43,4 +46,85 @@ static const float cubeface_mat[6][4][4] = {
{0.0f, 0.0f, 0.0f, 1.0f}},
};
+inline void cubeface_winmat_get(float4x4 &winmat, float near, float far)
+{
+ /* Simple 90° FOV projection. */
+ perspective_m4(winmat.ptr(), -near, near, -near, near, near, far);
+}
+
+/* -------------------------------------------------------------------- */
+/** \name CameraData operators
+ * \{ */
+
+inline bool operator==(const CameraData &a, const CameraData &b)
+{
+ return compare_m4m4(a.persmat.ptr(), b.persmat.ptr(), FLT_MIN) && (a.uv_scale == b.uv_scale) &&
+ (a.uv_bias == b.uv_bias) && (a.equirect_scale == b.equirect_scale) &&
+ (a.equirect_bias == b.equirect_bias) && (a.fisheye_fov == b.fisheye_fov) &&
+ (a.fisheye_lens == b.fisheye_lens) && (a.filter_size == b.filter_size) &&
+ (a.type == b.type);
+}
+
+inline bool operator!=(const CameraData &a, const CameraData &b)
+{
+ return !(a == b);
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Camera
+ * \{ */
+
+/**
+ * Point of view in the scene. Can be init from viewport or camera object.
+ */
+class Camera {
+ private:
+ Instance &inst_;
+
+ /** Double buffered to detect changes and have history for re-projection. */
+ SwapChain<CameraDataBuf, 2> data_;
+ /** Detects wrong usage. */
+ bool synced_ = false;
+
+ public:
+ Camera(Instance &inst) : inst_(inst){};
+ ~Camera(){};
+
+ void init();
+ void sync();
+
+ /**
+ * Getters
+ **/
+ const CameraData &data_get() const
+ {
+ BLI_assert(synced_);
+ return data_.current();
+ }
+ const GPUUniformBuf *ubo_get() const
+ {
+ return data_.current();
+ }
+ bool is_panoramic() const
+ {
+ return eevee::is_panoramic(data_.current().type);
+ }
+ bool is_orthographic() const
+ {
+ return data_.current().type == CAMERA_ORTHO;
+ }
+ const float3 &position() const
+ {
+ return *reinterpret_cast<const float3 *>(data_.current().viewinv[3]);
+ }
+ const float3 &forward() const
+ {
+ return *reinterpret_cast<const float3 *>(data_.current().viewinv[2]);
+ }
+};
+
+/** \} */
+
} // namespace blender::eevee
diff --git a/source/blender/draw/engines/eevee_next/eevee_defines.hh b/source/blender/draw/engines/eevee_next/eevee_defines.hh
index 7141928a20d..f75ebd2bd13 100644
--- a/source/blender/draw/engines/eevee_next/eevee_defines.hh
+++ b/source/blender/draw/engines/eevee_next/eevee_defines.hh
@@ -12,7 +12,7 @@
#pragma once
/**
- Number of items in a culling batch. Needs to be Power of 2. Must be <= to 65536.
+ * Number of items in a culling batch. Needs to be Power of 2. Must be <= to 65536.
* Current limiting factor is the sorting phase which is single pass and only sort within a
* thread-group which maximum size is 1024.
*/
diff --git a/source/blender/draw/engines/eevee_next/eevee_engine.cc b/source/blender/draw/engines/eevee_next/eevee_engine.cc
index a7d183c1c88..be0adfad568 100644
--- a/source/blender/draw/engines/eevee_next/eevee_engine.cc
+++ b/source/blender/draw/engines/eevee_next/eevee_engine.cc
@@ -5,6 +5,7 @@
#include "BKE_global.h"
#include "BLI_rect.h"
+#include "GPU_capabilities.h"
#include "GPU_framebuffer.h"
#include "ED_view3d.h"
@@ -24,10 +25,17 @@ struct EEVEE_Data {
DRWViewportEmptyList *psl;
DRWViewportEmptyList *stl;
eevee::Instance *instance;
+
+ char info[GPU_INFO_SIZE];
};
static void eevee_engine_init(void *vedata)
{
+ /* TODO(fclem): Remove once it is minimum required. */
+ if (!GPU_shader_storage_buffer_objects_support()) {
+ return;
+ }
+
EEVEE_Data *ved = reinterpret_cast<EEVEE_Data *>(vedata);
if (ved->instance == nullptr) {
ved->instance = new eevee::Instance();
@@ -81,31 +89,50 @@ static void eevee_engine_init(void *vedata)
static void eevee_draw_scene(void *vedata)
{
+ EEVEE_Data *ved = reinterpret_cast<EEVEE_Data *>(vedata);
+ if (!GPU_shader_storage_buffer_objects_support()) {
+ STRNCPY(ved->info, "Error: No shader storage buffer support");
+ return;
+ }
DefaultFramebufferList *dfbl = DRW_viewport_framebuffer_list_get();
- reinterpret_cast<EEVEE_Data *>(vedata)->instance->draw_viewport(dfbl);
+ ved->instance->draw_viewport(dfbl);
+ STRNCPY(ved->info, ved->instance->info.c_str());
}
static void eevee_cache_init(void *vedata)
{
+ if (!GPU_shader_storage_buffer_objects_support()) {
+ return;
+ }
reinterpret_cast<EEVEE_Data *>(vedata)->instance->begin_sync();
}
static void eevee_cache_populate(void *vedata, Object *object)
{
+ if (!GPU_shader_storage_buffer_objects_support()) {
+ return;
+ }
reinterpret_cast<EEVEE_Data *>(vedata)->instance->object_sync(object);
}
static void eevee_cache_finish(void *vedata)
{
+ if (!GPU_shader_storage_buffer_objects_support()) {
+ return;
+ }
reinterpret_cast<EEVEE_Data *>(vedata)->instance->end_sync();
}
static void eevee_engine_free()
{
+ eevee::ShaderModule::module_free();
}
static void eevee_instance_free(void *instance)
{
+ if (!GPU_shader_storage_buffer_objects_support()) {
+ return;
+ }
delete reinterpret_cast<eevee::Instance *>(instance);
}
@@ -114,11 +141,17 @@ static void eevee_render_to_image(void *UNUSED(vedata),
struct RenderLayer *layer,
const struct rcti *UNUSED(rect))
{
+ if (!GPU_shader_storage_buffer_objects_support()) {
+ return;
+ }
UNUSED_VARS(engine, layer);
}
static void eevee_render_update_passes(RenderEngine *engine, Scene *scene, ViewLayer *view_layer)
{
+ if (!GPU_shader_storage_buffer_objects_support()) {
+ return;
+ }
UNUSED_VARS(engine, scene, view_layer);
}
diff --git a/source/blender/draw/engines/eevee_next/eevee_instance.cc b/source/blender/draw/engines/eevee_next/eevee_instance.cc
index 8fef1cf7fc5..606630bcdef 100644
--- a/source/blender/draw/engines/eevee_next/eevee_instance.cc
+++ b/source/blender/draw/engines/eevee_next/eevee_instance.cc
@@ -8,6 +8,8 @@
* An instance contains all structures needed to do a complete render.
*/
+#include <sstream>
+
#include "BKE_global.h"
#include "BKE_object.h"
#include "BLI_rect.h"
@@ -41,26 +43,36 @@ void Instance::init(const int2 &output_res,
const View3D *v3d_,
const RegionView3D *rv3d_)
{
- UNUSED_VARS(light_probe_, camera_object_, output_rect);
+ UNUSED_VARS(light_probe_, output_rect);
render = render_;
depsgraph = depsgraph_;
+ camera_orig_object = camera_object_;
render_layer = render_layer_;
drw_view = drw_view_;
v3d = v3d_;
rv3d = rv3d_;
+ info = "";
+
update_eval_members();
main_view.init(output_res);
}
+void Instance::set_time(float time)
+{
+ BLI_assert(render);
+ DRW_render_set_time(render, depsgraph, floorf(time), fractf(time));
+ update_eval_members();
+}
+
void Instance::update_eval_members()
{
scene = DEG_get_evaluated_scene(depsgraph);
view_layer = DEG_get_evaluated_view_layer(depsgraph);
- // camera_eval_object = (camera_orig_object) ?
- // DEG_get_evaluated_object(depsgraph, camera_orig_object) :
- // nullptr;
+ camera_eval_object = (camera_orig_object) ?
+ DEG_get_evaluated_object(depsgraph, camera_orig_object) :
+ nullptr;
}
/** \} */
@@ -76,6 +88,7 @@ void Instance::update_eval_members()
void Instance::begin_sync()
{
materials.begin_sync();
+ velocity.begin_sync();
pipelines.sync();
main_view.sync();
@@ -135,6 +148,7 @@ void Instance::object_sync(Object *ob)
void Instance::end_sync()
{
+ velocity.end_sync();
}
void Instance::render_sync()
@@ -171,6 +185,13 @@ void Instance::draw_viewport(DefaultFramebufferList *dfbl)
{
UNUSED_VARS(dfbl);
render_sample();
+ velocity.step_swap();
+
+ if (materials.queued_shaders_count > 0) {
+ std::stringstream ss;
+ ss << "Compiling Shaders " << materials.queued_shaders_count;
+ info = ss.str();
+ }
}
/** \} */
diff --git a/source/blender/draw/engines/eevee_next/eevee_instance.hh b/source/blender/draw/engines/eevee_next/eevee_instance.hh
index c3cf08c8390..84be59fc5f0 100644
--- a/source/blender/draw/engines/eevee_next/eevee_instance.hh
+++ b/source/blender/draw/engines/eevee_next/eevee_instance.hh
@@ -15,6 +15,7 @@
#include "DNA_lightprobe_types.h"
#include "DRW_render.h"
+#include "eevee_camera.hh"
#include "eevee_material.hh"
#include "eevee_pipeline.hh"
#include "eevee_shader.hh"
@@ -29,11 +30,15 @@ namespace blender::eevee {
* \brief A running instance of the engine.
*/
class Instance {
+ friend VelocityModule;
+
public:
ShaderModule &shaders;
SyncModule sync;
MaterialModule materials;
PipelineModule pipelines;
+ VelocityModule velocity;
+ Camera camera;
MainView main_view;
World world;
@@ -42,6 +47,8 @@ class Instance {
/** Evaluated IDs. */
Scene *scene;
ViewLayer *view_layer;
+ Object *camera_eval_object;
+ Object *camera_orig_object;
/** Only available when rendering for final render. */
const RenderLayer *render_layer;
RenderEngine *render;
@@ -51,7 +58,7 @@ class Instance {
const RegionView3D *rv3d;
/* Info string displayed at the top of the render / viewport. */
- char info[64];
+ std::string info = "";
public:
Instance()
@@ -59,6 +66,8 @@ class Instance {
sync(*this),
materials(*this),
pipelines(*this),
+ velocity(*this),
+ camera(*this),
main_view(*this),
world(*this){};
~Instance(){};
@@ -83,12 +92,37 @@ class Instance {
void draw_viewport(DefaultFramebufferList *dfbl);
+ bool is_viewport(void)
+ {
+ return !DRW_state_is_scene_render();
+ }
+
+ bool use_scene_lights(void) const
+ {
+ return (!v3d) ||
+ ((v3d->shading.type == OB_MATERIAL) &&
+ (v3d->shading.flag & V3D_SHADING_SCENE_LIGHTS)) ||
+ ((v3d->shading.type == OB_RENDER) &&
+ (v3d->shading.flag & V3D_SHADING_SCENE_LIGHTS_RENDER));
+ }
+
+ /* Light the scene using the selected HDRI in the viewport shading pop-over. */
+ bool use_studio_light(void) const
+ {
+ return (v3d) && (((v3d->shading.type == OB_MATERIAL) &&
+ ((v3d->shading.flag & V3D_SHADING_SCENE_WORLD) == 0)) ||
+ ((v3d->shading.type == OB_RENDER) &&
+ ((v3d->shading.flag & V3D_SHADING_SCENE_WORLD_RENDER) == 0)));
+ }
+
private:
void render_sample();
void mesh_sync(Object *ob, ObjectHandle &ob_handle);
void update_eval_members();
+
+ void set_time(float time);
};
} // namespace blender::eevee
diff --git a/source/blender/draw/engines/eevee_next/eevee_material.cc b/source/blender/draw/engines/eevee_next/eevee_material.cc
index 7452e5c26a4..1676c89d679 100644
--- a/source/blender/draw/engines/eevee_next/eevee_material.cc
+++ b/source/blender/draw/engines/eevee_next/eevee_material.cc
@@ -51,7 +51,6 @@ DefaultSurfaceNodeTree::~DefaultSurfaceNodeTree()
MEM_SAFE_FREE(ntree_);
}
-/* Configure a default nodetree with the given material. */
bNodeTree *DefaultSurfaceNodeTree::nodetree_get(::Material *ma)
{
/* WARNING: This function is not threadsafe. Which is not a problem for the moment. */
@@ -75,11 +74,11 @@ MaterialModule::MaterialModule(Instance &inst) : inst_(inst)
{
bNodeTree *ntree = ntreeAddTree(nullptr, "Shader Nodetree", ntreeType_Shader->idname);
- diffuse_mat_ = (::Material *)BKE_id_new_nomain(ID_MA, "EEVEE default diffuse");
- diffuse_mat_->nodetree = ntree;
- diffuse_mat_->use_nodes = true;
+ diffuse_mat = (::Material *)BKE_id_new_nomain(ID_MA, "EEVEE default diffuse");
+ diffuse_mat->nodetree = ntree;
+ diffuse_mat->use_nodes = true;
/* To use the forward pipeline. */
- diffuse_mat_->blend_method = MA_BM_BLEND;
+ diffuse_mat->blend_method = MA_BM_BLEND;
bNode *bsdf = nodeAddStaticNode(nullptr, ntree, SH_NODE_BSDF_DIFFUSE);
bNodeSocket *base_color = nodeFindSocket(bsdf, SOCK_IN, "Color");
@@ -98,11 +97,11 @@ MaterialModule::MaterialModule(Instance &inst) : inst_(inst)
{
bNodeTree *ntree = ntreeAddTree(nullptr, "Shader Nodetree", ntreeType_Shader->idname);
- glossy_mat_ = (::Material *)BKE_id_new_nomain(ID_MA, "EEVEE default metal");
- glossy_mat_->nodetree = ntree;
- glossy_mat_->use_nodes = true;
+ glossy_mat = (::Material *)BKE_id_new_nomain(ID_MA, "EEVEE default metal");
+ glossy_mat->nodetree = ntree;
+ glossy_mat->use_nodes = true;
/* To use the forward pipeline. */
- glossy_mat_->blend_method = MA_BM_BLEND;
+ glossy_mat->blend_method = MA_BM_BLEND;
bNode *bsdf = nodeAddStaticNode(nullptr, ntree, SH_NODE_BSDF_GLOSSY);
bNodeSocket *base_color = nodeFindSocket(bsdf, SOCK_IN, "Color");
@@ -149,14 +148,14 @@ MaterialModule::~MaterialModule()
for (Material *mat : material_map_.values()) {
delete mat;
}
- BKE_id_free(nullptr, glossy_mat_);
- BKE_id_free(nullptr, diffuse_mat_);
+ BKE_id_free(nullptr, glossy_mat);
+ BKE_id_free(nullptr, diffuse_mat);
BKE_id_free(nullptr, error_mat_);
}
void MaterialModule::begin_sync()
{
- queued_shaders_count_ = 0;
+ queued_shaders_count = 0;
for (Material *mat : material_map_.values()) {
mat->init = false;
@@ -180,7 +179,7 @@ MaterialPass MaterialModule::material_pass_get(::Material *blender_mat,
case GPU_MAT_SUCCESS:
break;
case GPU_MAT_QUEUED:
- queued_shaders_count_++;
+ queued_shaders_count++;
blender_mat = (geometry_type == MAT_GEOM_VOLUME) ? BKE_material_default_volume() :
BKE_material_default_surface();
matpass.gpumat = inst_.shaders.material_shader_get(
@@ -223,7 +222,7 @@ MaterialPass MaterialModule::material_pass_get(::Material *blender_mat,
/* IMPORTANT: We always create a subgroup so that all subgroups are inserted after the
* first "empty" shgroup. This avoids messing the order of subgroups when there is more
* nested subgroup (i.e: hair drawing). */
- /* TODO(fclem) Remove material resource binding from the first group creation. */
+ /* TODO(@fclem): Remove material resource binding from the first group creation. */
matpass.shgrp = DRW_shgroup_create_sub(grp);
DRW_shgroup_add_material_resources(matpass.shgrp, matpass.gpumat);
}
@@ -232,21 +231,25 @@ MaterialPass MaterialModule::material_pass_get(::Material *blender_mat,
return matpass;
}
-Material &MaterialModule::material_sync(::Material *blender_mat, eMaterialGeometry geometry_type)
+Material &MaterialModule::material_sync(::Material *blender_mat,
+ eMaterialGeometry geometry_type,
+ bool has_motion)
{
eMaterialPipeline surface_pipe = (blender_mat->blend_method == MA_BM_BLEND) ? MAT_PIPE_FORWARD :
MAT_PIPE_DEFERRED;
eMaterialPipeline prepass_pipe = (blender_mat->blend_method == MA_BM_BLEND) ?
- MAT_PIPE_FORWARD_PREPASS :
- MAT_PIPE_DEFERRED_PREPASS;
+ (has_motion ? MAT_PIPE_FORWARD_PREPASS_VELOCITY :
+ MAT_PIPE_FORWARD_PREPASS) :
+ (has_motion ? MAT_PIPE_DEFERRED_PREPASS_VELOCITY :
+ MAT_PIPE_DEFERRED_PREPASS);
- /* Test */
+ /* TEST until we have deferred pipeline up and running. */
surface_pipe = MAT_PIPE_FORWARD;
- prepass_pipe = MAT_PIPE_FORWARD_PREPASS;
+ prepass_pipe = has_motion ? MAT_PIPE_FORWARD_PREPASS_VELOCITY : MAT_PIPE_FORWARD_PREPASS;
MaterialKey material_key(blender_mat, geometry_type, surface_pipe);
- /* TODO allocate in blocks to avoid memory fragmentation. */
+ /* TODO: allocate in blocks to avoid memory fragmentation. */
auto add_cb = [&]() { return new Material(); };
Material &mat = *material_map_.lookup_or_add_cb(material_key, add_cb);
@@ -270,7 +273,6 @@ Material &MaterialModule::material_sync(::Material *blender_mat, eMaterialGeomet
return mat;
}
-/* Return correct material or empty default material if slot is empty. */
::Material *MaterialModule::material_from_slot(Object *ob, int slot)
{
if (ob->base_flag & BASE_HOLDOUT) {
@@ -281,16 +283,12 @@ Material &MaterialModule::material_sync(::Material *blender_mat, eMaterialGeomet
if (ob->type == OB_VOLUME) {
return BKE_material_default_volume();
}
- else {
- return BKE_material_default_surface();
- }
+ return BKE_material_default_surface();
}
return ma;
}
-/* Returned Material references are valid until the next call to this function or
- * material_get(). */
-MaterialArray &MaterialModule::material_array_get(Object *ob)
+MaterialArray &MaterialModule::material_array_get(Object *ob, bool has_motion)
{
material_array_.materials.clear();
material_array_.gpu_materials.clear();
@@ -299,22 +297,23 @@ MaterialArray &MaterialModule::material_array_get(Object *ob)
for (auto i : IndexRange(materials_len)) {
::Material *blender_mat = material_from_slot(ob, i);
- Material &mat = material_sync(blender_mat, to_material_geometry(ob));
+ Material &mat = material_sync(blender_mat, to_material_geometry(ob), has_motion);
material_array_.materials.append(&mat);
material_array_.gpu_materials.append(mat.shading.gpumat);
}
return material_array_;
}
-/* Returned Material references are valid until the next call to this function or
- * material_array_get(). */
-Material &MaterialModule::material_get(Object *ob, int mat_nr, eMaterialGeometry geometry_type)
+Material &MaterialModule::material_get(Object *ob,
+ bool has_motion,
+ int mat_nr,
+ eMaterialGeometry geometry_type)
{
::Material *blender_mat = material_from_slot(ob, mat_nr);
- Material &mat = material_sync(blender_mat, geometry_type);
+ Material &mat = material_sync(blender_mat, geometry_type, has_motion);
return mat;
}
/** \} */
-} // namespace blender::eevee \ No newline at end of file
+} // namespace blender::eevee
diff --git a/source/blender/draw/engines/eevee_next/eevee_material.hh b/source/blender/draw/engines/eevee_next/eevee_material.hh
index af9ff6bf6ba..23165a741b9 100644
--- a/source/blender/draw/engines/eevee_next/eevee_material.hh
+++ b/source/blender/draw/engines/eevee_next/eevee_material.hh
@@ -27,19 +27,21 @@ class Instance;
enum eMaterialPipeline {
MAT_PIPE_DEFERRED = 0,
- MAT_PIPE_FORWARD = 1,
- MAT_PIPE_DEFERRED_PREPASS = 2,
- MAT_PIPE_FORWARD_PREPASS = 3,
- MAT_PIPE_VOLUME = 4,
- MAT_PIPE_SHADOW = 5,
+ MAT_PIPE_FORWARD,
+ MAT_PIPE_DEFERRED_PREPASS,
+ MAT_PIPE_DEFERRED_PREPASS_VELOCITY,
+ MAT_PIPE_FORWARD_PREPASS,
+ MAT_PIPE_FORWARD_PREPASS_VELOCITY,
+ MAT_PIPE_VOLUME,
+ MAT_PIPE_SHADOW,
};
enum eMaterialGeometry {
MAT_GEOM_MESH = 0,
- MAT_GEOM_CURVES = 1,
- MAT_GEOM_GPENCIL = 2,
- MAT_GEOM_VOLUME = 3,
- MAT_GEOM_WORLD = 4,
+ MAT_GEOM_CURVES,
+ MAT_GEOM_GPENCIL,
+ MAT_GEOM_VOLUME,
+ MAT_GEOM_WORLD,
};
static inline void material_type_from_shader_uuid(uint64_t shader_uuid,
@@ -189,6 +191,7 @@ class DefaultSurfaceNodeTree {
DefaultSurfaceNodeTree();
~DefaultSurfaceNodeTree();
+ /** Configure a default node-tree with the given material. */
bNodeTree *nodetree_get(::Material *ma);
};
@@ -217,8 +220,10 @@ struct MaterialArray {
class MaterialModule {
public:
- ::Material *diffuse_mat_;
- ::Material *glossy_mat_;
+ ::Material *diffuse_mat;
+ ::Material *glossy_mat;
+
+ int64_t queued_shaders_count = 0;
private:
Instance &inst_;
@@ -232,20 +237,28 @@ class MaterialModule {
::Material *error_mat_;
- int64_t queued_shaders_count_ = 0;
-
public:
MaterialModule(Instance &inst);
~MaterialModule();
void begin_sync();
- MaterialArray &material_array_get(Object *ob);
- Material &material_get(Object *ob, int mat_nr, eMaterialGeometry geometry_type);
+ /**
+ * Returned Material references are valid until the next call to this function or material_get().
+ */
+ MaterialArray &material_array_get(Object *ob, bool has_motion);
+ /**
+ * Returned Material references are valid until the next call to this function or
+ * material_array_get().
+ */
+ Material &material_get(Object *ob, bool has_motion, int mat_nr, eMaterialGeometry geometry_type);
private:
- Material &material_sync(::Material *blender_mat, eMaterialGeometry geometry_type);
+ Material &material_sync(::Material *blender_mat,
+ eMaterialGeometry geometry_type,
+ bool has_motion);
+ /** Return correct material or empty default material if slot is empty. */
::Material *material_from_slot(Object *ob, int slot);
MaterialPass material_pass_get(::Material *blender_mat,
eMaterialPipeline pipeline_type,
diff --git a/source/blender/draw/engines/eevee_next/eevee_pipeline.cc b/source/blender/draw/engines/eevee_next/eevee_pipeline.cc
index e31372e770d..33853eba06c 100644
--- a/source/blender/draw/engines/eevee_next/eevee_pipeline.cc
+++ b/source/blender/draw/engines/eevee_next/eevee_pipeline.cc
@@ -54,11 +54,17 @@ void ForwardPipeline::sync()
{
DRWState state = DRW_STATE_WRITE_DEPTH | DRW_STATE_DEPTH_LESS;
prepass_ps_ = DRW_pass_create("Forward.Opaque.Prepass", state);
+ prepass_velocity_ps_ = DRW_pass_create("Forward.Opaque.Prepass.Velocity",
+ state | DRW_STATE_WRITE_COLOR);
state |= DRW_STATE_CULL_BACK;
prepass_culled_ps_ = DRW_pass_create("Forward.Opaque.Prepass.Culled", state);
+ prepass_culled_velocity_ps_ = DRW_pass_create("Forward.Opaque.Prepass.Velocity",
+ state | DRW_STATE_WRITE_COLOR);
- DRW_pass_link(prepass_ps_, prepass_culled_ps_);
+ DRW_pass_link(prepass_ps_, prepass_velocity_ps_);
+ DRW_pass_link(prepass_velocity_ps_, prepass_culled_ps_);
+ DRW_pass_link(prepass_culled_ps_, prepass_culled_velocity_ps_);
}
{
DRWState state = DRW_STATE_WRITE_COLOR | DRW_STATE_DEPTH_EQUAL;
@@ -110,11 +116,17 @@ DRWShadingGroup *ForwardPipeline::material_opaque_add(::Material *blender_mat, G
return grp;
}
-DRWShadingGroup *ForwardPipeline::prepass_opaque_add(::Material *blender_mat, GPUMaterial *gpumat)
+DRWShadingGroup *ForwardPipeline::prepass_opaque_add(::Material *blender_mat,
+ GPUMaterial *gpumat,
+ bool has_motion)
{
- DRWPass *pass = (blender_mat->blend_flag & MA_BL_CULL_BACKFACE) ? prepass_culled_ps_ :
- prepass_ps_;
+ DRWPass *pass = (blender_mat->blend_flag & MA_BL_CULL_BACKFACE) ?
+ (has_motion ? prepass_culled_velocity_ps_ : prepass_culled_ps_) :
+ (has_motion ? prepass_velocity_ps_ : prepass_ps_);
DRWShadingGroup *grp = DRW_shgroup_material_create(gpumat, pass);
+ if (has_motion) {
+ inst_.velocity.bind_resources(grp);
+ }
return grp;
}
@@ -181,15 +193,19 @@ DRWShadingGroup *ForwardPipeline::prepass_transparent_add(::Material *blender_ma
}
void ForwardPipeline::render(const DRWView *view,
+ Framebuffer &prepass_fb,
+ Framebuffer &combined_fb,
GPUTexture *depth_tx,
GPUTexture *UNUSED(combined_tx))
{
- UNUSED_VARS(view, depth_tx);
+ UNUSED_VARS(view, depth_tx, prepass_fb, combined_fb);
// HiZBuffer &hiz = inst_.hiz_front;
DRW_stats_group_start("ForwardOpaque");
+ GPU_framebuffer_bind(prepass_fb);
DRW_draw_pass(prepass_ps_);
+
// hiz.set_dirty();
// if (inst_.raytracing.enabled()) {
@@ -199,6 +215,7 @@ void ForwardPipeline::render(const DRWView *view,
// inst_.shadows.set_view(view, depth_tx);
+ GPU_framebuffer_bind(combined_fb);
DRW_draw_pass(opaque_ps_);
DRW_stats_group_end();
@@ -218,4 +235,4 @@ void ForwardPipeline::render(const DRWView *view,
/** \} */
-} // namespace blender::eevee \ No newline at end of file
+} // namespace blender::eevee
diff --git a/source/blender/draw/engines/eevee_next/eevee_pipeline.hh b/source/blender/draw/engines/eevee_next/eevee_pipeline.hh
index a5a6847f62e..3bdc718767b 100644
--- a/source/blender/draw/engines/eevee_next/eevee_pipeline.hh
+++ b/source/blender/draw/engines/eevee_next/eevee_pipeline.hh
@@ -53,7 +53,9 @@ class ForwardPipeline {
Instance &inst_;
DRWPass *prepass_ps_ = nullptr;
+ DRWPass *prepass_velocity_ps_ = nullptr;
DRWPass *prepass_culled_ps_ = nullptr;
+ DRWPass *prepass_culled_velocity_ps_ = nullptr;
DRWPass *opaque_ps_ = nullptr;
DRWPass *opaque_culled_ps_ = nullptr;
DRWPass *transparent_ps_ = nullptr;
@@ -72,19 +74,25 @@ class ForwardPipeline {
material_opaque_add(blender_mat, gpumat);
}
- DRWShadingGroup *prepass_add(::Material *blender_mat, GPUMaterial *gpumat)
+ DRWShadingGroup *prepass_add(::Material *blender_mat, GPUMaterial *gpumat, bool has_motion)
{
return (GPU_material_flag_get(gpumat, GPU_MATFLAG_TRANSPARENT)) ?
prepass_transparent_add(blender_mat, gpumat) :
- prepass_opaque_add(blender_mat, gpumat);
+ prepass_opaque_add(blender_mat, gpumat, has_motion);
}
DRWShadingGroup *material_opaque_add(::Material *blender_mat, GPUMaterial *gpumat);
- DRWShadingGroup *prepass_opaque_add(::Material *blender_mat, GPUMaterial *gpumat);
+ DRWShadingGroup *prepass_opaque_add(::Material *blender_mat,
+ GPUMaterial *gpumat,
+ bool has_motion);
DRWShadingGroup *material_transparent_add(::Material *blender_mat, GPUMaterial *gpumat);
DRWShadingGroup *prepass_transparent_add(::Material *blender_mat, GPUMaterial *gpumat);
- void render(const DRWView *view, GPUTexture *depth_tx, GPUTexture *combined_tx);
+ void render(const DRWView *view,
+ Framebuffer &prepass_fb,
+ Framebuffer &combined_fb,
+ GPUTexture *depth_tx,
+ GPUTexture *combined_tx);
};
/** \} */
@@ -191,10 +199,15 @@ class PipelineModule {
{
switch (pipeline_type) {
case MAT_PIPE_DEFERRED_PREPASS:
- // return deferred.prepass_add(blender_mat, gpumat);
+ // return deferred.prepass_add(blender_mat, gpumat, false);
+ break;
+ case MAT_PIPE_DEFERRED_PREPASS_VELOCITY:
+ // return deferred.prepass_add(blender_mat, gpumat, true);
break;
case MAT_PIPE_FORWARD_PREPASS:
- return forward.prepass_add(blender_mat, gpumat);
+ return forward.prepass_add(blender_mat, gpumat, false);
+ case MAT_PIPE_FORWARD_PREPASS_VELOCITY:
+ return forward.prepass_add(blender_mat, gpumat, true);
case MAT_PIPE_DEFERRED:
// return deferred.material_add(blender_mat, gpumat);
break;
@@ -213,4 +226,4 @@ class PipelineModule {
/** \} */
-} // namespace blender::eevee \ No newline at end of file
+} // namespace blender::eevee
diff --git a/source/blender/draw/engines/eevee_next/eevee_shader.cc b/source/blender/draw/engines/eevee_next/eevee_shader.cc
index 39c5cf6a536..09aa97e49e9 100644
--- a/source/blender/draw/engines/eevee_next/eevee_shader.cc
+++ b/source/blender/draw/engines/eevee_next/eevee_shader.cc
@@ -78,6 +78,8 @@ ShaderModule::~ShaderModule()
const char *ShaderModule::static_shader_create_info_name_get(eShaderType shader_type)
{
switch (shader_type) {
+ case VELOCITY_RESOLVE:
+ return "eevee_velocity_resolve";
/* To avoid compiler warning about missing case. */
case MAX_SHADER_TYPE:
return "";
@@ -159,6 +161,7 @@ void ShaderModule::material_create_info_ammend(GPUMaterial *gpumat, GPUCodegenOu
}
}
info.vertex_inputs_.clear();
+ info.additional_info("draw_curves_infos");
break;
case MAT_GEOM_WORLD:
/**
@@ -190,7 +193,7 @@ void ShaderModule::material_create_info_ammend(GPUMaterial *gpumat, GPUCodegenOu
const StageInterfaceInfo &iface = *info.vertex_out_interfaces_.first();
/* Globals the attrib_load() can write to when it is in the fragment shader. */
global_vars << "struct " << iface.name << " {\n";
- for (auto &inout : iface.inouts) {
+ for (const auto &inout : iface.inouts) {
global_vars << " " << inout.type << " " << inout.name << ";\n";
}
global_vars << "};\n";
@@ -289,6 +292,10 @@ void ShaderModule::material_create_info_ammend(GPUMaterial *gpumat, GPUCodegenOu
break;
default:
switch (pipeline_type) {
+ case MAT_PIPE_FORWARD_PREPASS_VELOCITY:
+ case MAT_PIPE_DEFERRED_PREPASS_VELOCITY:
+ info.additional_info("eevee_surf_depth", "eevee_velocity_geom");
+ break;
case MAT_PIPE_FORWARD_PREPASS:
case MAT_PIPE_DEFERRED_PREPASS:
case MAT_PIPE_SHADOW:
diff --git a/source/blender/draw/engines/eevee_next/eevee_shader.hh b/source/blender/draw/engines/eevee_next/eevee_shader.hh
index 29fcbafb167..0f42e880a10 100644
--- a/source/blender/draw/engines/eevee_next/eevee_shader.hh
+++ b/source/blender/draw/engines/eevee_next/eevee_shader.hh
@@ -26,7 +26,9 @@ namespace blender::eevee {
/* Keep alphabetical order and clean prefix. */
enum eShaderType {
- MAX_SHADER_TYPE = 0,
+ VELOCITY_RESOLVE = 0,
+
+ MAX_SHADER_TYPE,
};
/**
diff --git a/source/blender/draw/engines/eevee_next/eevee_shader_shared.hh b/source/blender/draw/engines/eevee_next/eevee_shader_shared.hh
index 45b067d203e..eb409f076f3 100644
--- a/source/blender/draw/engines/eevee_next/eevee_shader_shared.hh
+++ b/source/blender/draw/engines/eevee_next/eevee_shader_shared.hh
@@ -19,6 +19,7 @@
namespace blender::eevee {
using draw::Framebuffer;
+using draw::SwapChain;
using draw::Texture;
using draw::TextureFromPool;
@@ -27,11 +28,105 @@ using draw::TextureFromPool;
#define UBO_MIN_MAX_SUPPORTED_SIZE 1 << 14
/* -------------------------------------------------------------------- */
+/** \name Camera
+ * \{ */
+
+enum eCameraType : uint32_t {
+ CAMERA_PERSP = 0u,
+ CAMERA_ORTHO = 1u,
+ CAMERA_PANO_EQUIRECT = 2u,
+ CAMERA_PANO_EQUISOLID = 3u,
+ CAMERA_PANO_EQUIDISTANT = 4u,
+ CAMERA_PANO_MIRROR = 5u
+};
+
+static inline bool is_panoramic(eCameraType type)
+{
+ return type > CAMERA_ORTHO;
+}
+
+struct CameraData {
+ /* View Matrices of the camera, not from any view! */
+ float4x4 persmat;
+ float4x4 persinv;
+ float4x4 viewmat;
+ float4x4 viewinv;
+ float4x4 winmat;
+ float4x4 wininv;
+ /** Camera UV scale and bias. Also known as `viewcamtexcofac`. */
+ float2 uv_scale;
+ float2 uv_bias;
+ /** Panorama parameters. */
+ float2 equirect_scale;
+ float2 equirect_scale_inv;
+ float2 equirect_bias;
+ float fisheye_fov;
+ float fisheye_lens;
+ /** Clipping distances. */
+ float clip_near;
+ float clip_far;
+ /** Film pixel filter radius. */
+ float filter_size;
+ eCameraType type;
+};
+BLI_STATIC_ASSERT_ALIGN(CameraData, 16)
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name VelocityModule
+ * \{ */
+
+#define VELOCITY_INVALID 512.0
+
+enum eVelocityStep : uint32_t {
+ STEP_PREVIOUS = 0,
+ STEP_NEXT = 1,
+ STEP_CURRENT = 2,
+};
+
+struct VelocityObjectIndex {
+ /** Offset inside #VelocityObjectBuf for each timestep. Indexed using eVelocityStep. */
+ int3 ofs;
+ /** Temporary index to copy this to the #VelocityIndexBuf. */
+ uint resource_id;
+
+#ifdef __cplusplus
+ VelocityObjectIndex() : ofs(-1, -1, -1), resource_id(-1){};
+#endif
+};
+BLI_STATIC_ASSERT_ALIGN(VelocityObjectIndex, 16)
+
+struct VelocityGeometryIndex {
+ /** Offset inside #VelocityGeometryBuf for each timestep. Indexed using eVelocityStep. */
+ int3 ofs;
+ /** If true, compute deformation motion blur. */
+ bool1 do_deform;
+ /** Length of data inside #VelocityGeometryBuf for each timestep. Indexed using eVelocityStep. */
+ int3 len;
+
+ int _pad0;
+
+#ifdef __cplusplus
+ VelocityGeometryIndex() : ofs(-1, -1, -1), do_deform(false), len(-1, -1, -1), _pad0(1){};
+#endif
+};
+BLI_STATIC_ASSERT_ALIGN(VelocityGeometryIndex, 16)
+
+struct VelocityIndex {
+ VelocityObjectIndex obj;
+ VelocityGeometryIndex geo;
+};
+BLI_STATIC_ASSERT_ALIGN(VelocityGeometryIndex, 16)
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
/** \name Ray-Tracing
* \{ */
enum eClosureBits : uint32_t {
- /** NOTE: Theses are used as stencil bits. So we are limited to 8bits. */
+ /** NOTE: These are used as stencil bits. So we are limited to 8bits. */
CLOSURE_DIFFUSE = (1u << 0u),
CLOSURE_SSS = (1u << 1u),
CLOSURE_REFLECTION = (1u << 2u),
@@ -83,5 +178,10 @@ float4 utility_tx_sample(sampler2DArray util_tx, float2 uv, float layer)
#ifdef __cplusplus
+using CameraDataBuf = draw::UniformBuffer<CameraData>;
+using VelocityIndexBuf = draw::StorageArrayBuffer<VelocityIndex, 16>;
+using VelocityObjectBuf = draw::StorageArrayBuffer<float4x4, 16>;
+using VelocityGeometryBuf = draw::StorageArrayBuffer<float4, 16, true>;
+
} // namespace blender::eevee
#endif
diff --git a/source/blender/draw/engines/eevee_next/eevee_sync.cc b/source/blender/draw/engines/eevee_next/eevee_sync.cc
index efa5fdc89ab..42af251d770 100644
--- a/source/blender/draw/engines/eevee_next/eevee_sync.cc
+++ b/source/blender/draw/engines/eevee_next/eevee_sync.cc
@@ -104,7 +104,9 @@ static inline void shgroup_geometry_call(DRWShadingGroup *grp,
void SyncModule::sync_mesh(Object *ob, ObjectHandle &ob_handle)
{
- MaterialArray &material_array = inst_.materials.material_array_get(ob);
+ bool has_motion = inst_.velocity.step_object_sync(ob, ob_handle.object_key, ob_handle.recalc);
+
+ MaterialArray &material_array = inst_.materials.material_array_get(ob, has_motion);
GPUBatch **mat_geom = DRW_cache_object_surface_material_get(
ob, material_array.gpu_materials.data(), material_array.gpu_materials.size());
@@ -129,9 +131,6 @@ void SyncModule::sync_mesh(Object *ob, ObjectHandle &ob_handle)
is_alpha_blend = is_alpha_blend || material->is_alpha_blend_transparent;
}
- UNUSED_VARS(ob_handle);
- // shading_passes.velocity.mesh_add(ob, ob_handle);
-
// shadows.sync_object(ob, ob_handle, is_shadow_caster, is_alpha_blend);
}
@@ -156,8 +155,11 @@ struct gpIterData {
int vcount = 0;
bool instancing = false;
- gpIterData(Instance &inst_, Object *ob_)
- : inst(inst_), ob(ob_), material_array(inst_.materials.material_array_get(ob_))
+ gpIterData(Instance &inst_, Object *ob_, ObjectHandle &ob_handle)
+ : inst(inst_),
+ ob(ob_),
+ material_array(inst_.materials.material_array_get(
+ ob_, inst_.velocity.step_object_sync(ob, ob_handle.object_key, ob_handle.recalc)))
{
cfra = DEG_get_ctime(inst.depsgraph);
};
@@ -253,16 +255,12 @@ void SyncModule::sync_gpencil(Object *ob, ObjectHandle &ob_handle)
/* TODO(fclem): Waiting for a user option to use the render engine instead of gpencil engine. */
return;
- gpIterData iter(inst_, ob);
+ gpIterData iter(inst_, ob, ob_handle);
BKE_gpencil_visible_stroke_iter((bGPdata *)ob->data, nullptr, gpencil_stroke_sync, &iter);
gpencil_drawcall_flush(iter);
- UNUSED_VARS(ob_handle);
- /* TODO(fclem) Gpencil velocity. */
- // shading_passes.velocity.gpencil_add(ob, ob_handle);
-
// bool is_caster = true; /* TODO material.shadow.shgrp. */
// bool is_alpha_blend = true; /* TODO material.is_alpha_blend. */
// shadows.sync_object(ob, ob_handle, is_caster, is_alpha_blend);
@@ -304,12 +302,13 @@ void SyncModule::sync_curves(Object *ob, ObjectHandle &ob_handle, ModifierData *
mat_nr = part_settings->omat;
}
- Material &material = inst_.materials.material_get(ob, mat_nr - 1, MAT_GEOM_CURVES);
+ bool has_motion = inst_.velocity.step_object_sync(ob, ob_handle.object_key, ob_handle.recalc);
+ Material &material = inst_.materials.material_get(ob, has_motion, mat_nr - 1, MAT_GEOM_CURVES);
shgroup_curves_call(material.shading, ob, part_sys, modifier_data);
shgroup_curves_call(material.prepass, ob, part_sys, modifier_data);
shgroup_curves_call(material.shadow, ob, part_sys, modifier_data);
- UNUSED_VARS(ob_handle);
+
/* TODO(fclem) Hair velocity. */
// shading_passes.velocity.gpencil_add(ob, ob_handle);
diff --git a/source/blender/draw/engines/eevee_next/eevee_sync.hh b/source/blender/draw/engines/eevee_next/eevee_sync.hh
index 34357193d3e..bd8147a2882 100644
--- a/source/blender/draw/engines/eevee_next/eevee_sync.hh
+++ b/source/blender/draw/engines/eevee_next/eevee_sync.hh
@@ -28,6 +28,7 @@ class Instance;
/** \name ObjectKey
*
* Unique key to identify each object in the hash-map.
+ * Note that we get a unique key for each object component.
* \{ */
struct ObjectKey {
diff --git a/source/blender/draw/engines/eevee_next/eevee_velocity.cc b/source/blender/draw/engines/eevee_next/eevee_velocity.cc
new file mode 100644
index 00000000000..ceae9df44d0
--- /dev/null
+++ b/source/blender/draw/engines/eevee_next/eevee_velocity.cc
@@ -0,0 +1,420 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later
+ * Copyright 2021 Blender Foundation.
+ */
+
+/** \file
+ * \ingroup eevee
+ *
+ * The velocity pass outputs motion vectors to use for either
+ * temporal re-projection or motion blur.
+ *
+ * It is the module that tracks the objects between frames updates.
+ *
+ * #VelocityModule contains all motion steps data and logic.
+ * #VelocityPass contains the resolve pass for static geometry.
+ * #VelocityView is a per view instance that contain the velocity buffer.
+ */
+
+#include "BKE_duplilist.h"
+#include "BKE_object.h"
+#include "BLI_map.hh"
+#include "DEG_depsgraph_query.h"
+#include "DNA_rigidbody_types.h"
+
+#include "eevee_instance.hh"
+// #include "eevee_renderpasses.hh"
+#include "eevee_shader.hh"
+#include "eevee_shader_shared.hh"
+#include "eevee_velocity.hh"
+
+namespace blender::eevee {
+
+/* -------------------------------------------------------------------- */
+/** \name VelocityModule
+ *
+ * \{ */
+
+void VelocityModule::init()
+{
+#if 0 /* TODO renderpasses */
+ if (inst_.render && (inst_.render_passes.vector != nullptr)) {
+ /* No motion blur and the vector pass was requested. Do the step sync here. */
+ const Scene *scene = inst_.scene;
+ float initial_time = scene->r.cfra + scene->r.subframe;
+ step_sync(STEP_PREVIOUS, initial_time - 1.0f);
+ step_sync(STEP_NEXT, initial_time + 1.0f);
+ inst_.set_time(initial_time);
+ }
+#endif
+}
+
+static void step_object_sync_render(void *velocity,
+ Object *ob,
+ RenderEngine *UNUSED(engine),
+ Depsgraph *UNUSED(depsgraph))
+{
+ ObjectKey object_key(ob);
+ reinterpret_cast<VelocityModule *>(velocity)->step_object_sync(ob, object_key);
+}
+
+void VelocityModule::step_sync(eVelocityStep step, float time)
+{
+ inst_.set_time(time);
+ step_ = step;
+ object_steps_usage[step_] = 0;
+ step_camera_sync();
+ DRW_render_object_iter(this, inst_.render, inst_.depsgraph, step_object_sync_render);
+}
+
+void VelocityModule::step_camera_sync()
+{
+ inst_.camera.sync();
+ *camera_steps[step_] = inst_.camera.data_get();
+}
+
+bool VelocityModule::step_object_sync(Object *ob,
+ ObjectKey &object_key,
+ int /*IDRecalcFlag*/ recalc)
+{
+ bool has_motion = object_has_velocity(ob) || (recalc & ID_RECALC_TRANSFORM);
+ /* NOTE: Fragile. This will only work with 1 frame of lag since we can't record every geometry
+ * just in case there might be an update the next frame. */
+ bool has_deform = object_is_deform(ob) || (recalc & ID_RECALC_GEOMETRY);
+
+ if (!has_motion && !has_deform) {
+ return false;
+ }
+
+ uint32_t resource_id = DRW_object_resource_id_get(ob);
+
+ /* Object motion. */
+ /* FIXME(fclem) As we are using original objects pointers, there is a chance the previous
+ * object key matches a totally different object if the scene was changed by user or python
+ * callback. In this case, we cannot correctly match objects between updates.
+ * What this means is that there will be incorrect motion vectors for these objects.
+ * We live with that until we have a correct way of identifying new objects. */
+ VelocityObjectData &vel = velocity_map.lookup_or_add_default(object_key);
+ vel.obj.ofs[step_] = object_steps_usage[step_]++;
+ vel.obj.resource_id = resource_id;
+ vel.id = (ID *)ob->data;
+ object_steps[step_]->get_or_resize(vel.obj.ofs[step_]) = ob->obmat;
+ if (step_ == STEP_CURRENT) {
+ /* Replace invalid steps. Can happen if object was hidden in one of those steps. */
+ if (vel.obj.ofs[STEP_PREVIOUS] == -1) {
+ vel.obj.ofs[STEP_PREVIOUS] = object_steps_usage[STEP_PREVIOUS]++;
+ object_steps[STEP_PREVIOUS]->get_or_resize(vel.obj.ofs[STEP_PREVIOUS]) = ob->obmat;
+ }
+ if (vel.obj.ofs[STEP_NEXT] == -1) {
+ vel.obj.ofs[STEP_NEXT] = object_steps_usage[STEP_NEXT]++;
+ object_steps[STEP_NEXT]->get_or_resize(vel.obj.ofs[STEP_NEXT]) = ob->obmat;
+ }
+ }
+
+ /* Geometry motion. */
+ if (has_deform) {
+ auto add_cb = [&]() {
+ VelocityGeometryData data;
+ switch (ob->type) {
+ case OB_CURVES:
+ data.pos_buf = DRW_curves_pos_buffer_get(ob);
+ break;
+ default:
+ data.pos_buf = DRW_cache_object_pos_vertbuf_get(ob);
+ break;
+ }
+ return data;
+ };
+
+ const VelocityGeometryData &data = geometry_map.lookup_or_add_cb(vel.id, add_cb);
+
+ if (data.pos_buf == nullptr) {
+ has_deform = false;
+ }
+ }
+
+ /* Avoid drawing object that has no motions but were tagged as such. */
+ if (step_ == STEP_CURRENT && has_motion == true && has_deform == false) {
+ float4x4 &obmat_curr = (*object_steps[STEP_CURRENT])[vel.obj.ofs[STEP_CURRENT]];
+ float4x4 &obmat_prev = (*object_steps[STEP_PREVIOUS])[vel.obj.ofs[STEP_PREVIOUS]];
+ float4x4 &obmat_next = (*object_steps[STEP_NEXT])[vel.obj.ofs[STEP_NEXT]];
+ if (inst_.is_viewport()) {
+ has_motion = (obmat_curr != obmat_prev);
+ }
+ else {
+ has_motion = (obmat_curr != obmat_prev || obmat_curr != obmat_next);
+ }
+ }
+
+#if 0
+ if (!has_motion && !has_deform) {
+ std::cout << "Detected no motion on " << ob->id.name << std::endl;
+ }
+ if (has_deform) {
+ std::cout << "Geometry Motion on " << ob->id.name << std::endl;
+ }
+ if (has_motion) {
+ std::cout << "Object Motion on " << ob->id.name << std::endl;
+ }
+#endif
+
+ if (!has_motion && !has_deform) {
+ return false;
+ }
+
+ /* TODO(@fclem): Reset sampling here? Should ultimately be covered by depsgraph update tags. */
+ // inst_.sampling.reset();
+
+ return true;
+}
+
+/**
+ * Moves next frame data to previous frame data. Nullify next frame data.
+ * IMPORTANT: This runs AFTER drawing in the viewport (so after `begin_sync()`) but BEFORE drawing
+ * in render mode (so before `begin_sync()`). In viewport the data will be used the next frame.
+ */
+void VelocityModule::step_swap()
+{
+ {
+ /* Now that vertex buffers are guaranteed to be updated, proceed with
+ * offset computation and copy into the geometry step buffer. */
+ uint dst_ofs = 0;
+ for (VelocityGeometryData &geom : geometry_map.values()) {
+ uint src_len = GPU_vertbuf_get_vertex_len(geom.pos_buf);
+ geom.len = src_len;
+ geom.ofs = dst_ofs;
+ dst_ofs += src_len;
+ }
+ /* TODO(@fclem): Fail gracefully (disable motion blur + warning print) if
+ * `tot_len * sizeof(float4)` is greater than max SSBO size. */
+ geometry_steps[step_]->resize(max_ii(16, dst_ofs));
+
+ for (VelocityGeometryData &geom : geometry_map.values()) {
+ GPU_storagebuf_copy_sub_from_vertbuf(*geometry_steps[step_],
+ geom.pos_buf,
+ geom.ofs * sizeof(float4),
+ 0,
+ geom.len * sizeof(float4));
+ }
+ /* Copy back the #VelocityGeometryIndex into #VelocityObjectData which are
+ * indexed using persistent keys (unlike geometries which are indexed by volatile ID). */
+ for (VelocityObjectData &vel : velocity_map.values()) {
+ const VelocityGeometryData &geom = geometry_map.lookup_default(vel.id,
+ VelocityGeometryData());
+ vel.geo.len[step_] = geom.len;
+ vel.geo.ofs[step_] = geom.ofs;
+ /* Avoid reuse. */
+ vel.id = nullptr;
+ }
+
+ geometry_map.clear();
+ }
+
+ auto swap_steps = [&](eVelocityStep step_a, eVelocityStep step_b) {
+ SWAP(VelocityObjectBuf *, object_steps[step_a], object_steps[step_b]);
+ SWAP(VelocityGeometryBuf *, geometry_steps[step_a], geometry_steps[step_b]);
+ SWAP(CameraDataBuf *, camera_steps[step_a], camera_steps[step_b]);
+
+ for (VelocityObjectData &vel : velocity_map.values()) {
+ vel.obj.ofs[step_a] = vel.obj.ofs[step_b];
+ vel.obj.ofs[step_b] = (uint)-1;
+ vel.geo.ofs[step_a] = vel.geo.ofs[step_b];
+ vel.geo.len[step_a] = vel.geo.len[step_b];
+ vel.geo.ofs[step_b] = (uint)-1;
+ vel.geo.len[step_b] = (uint)-1;
+ }
+ };
+
+ if (inst_.is_viewport()) {
+ /* For viewport we only use the last rendered redraw as previous frame.
+ * We swap current with previous step at the end of a redraw.
+ * We do not support motion blur as it is rendered to avoid conflicting motions
+ * for temporal reprojection. */
+ swap_steps(eVelocityStep::STEP_PREVIOUS, eVelocityStep::STEP_CURRENT);
+ }
+ else {
+ /* Render case: The STEP_CURRENT is left untouched. */
+ swap_steps(eVelocityStep::STEP_PREVIOUS, eVelocityStep::STEP_NEXT);
+ }
+}
+
+void VelocityModule::begin_sync()
+{
+ if (inst_.is_viewport()) {
+ /* Viewport always evaluate current step. */
+ step_ = STEP_CURRENT;
+ }
+ step_camera_sync();
+ object_steps_usage[step_] = 0;
+}
+
+/* This is the end of the current frame sync. Not the step_sync. */
+void VelocityModule::end_sync()
+{
+ Vector<ObjectKey, 0> deleted_obj;
+
+ uint32_t max_resource_id_ = 0u;
+
+ for (Map<ObjectKey, VelocityObjectData>::Item item : velocity_map.items()) {
+ if (item.value.obj.resource_id == (uint)-1) {
+ deleted_obj.append(item.key);
+ }
+ else {
+ max_resource_id_ = max_uu(max_resource_id_, item.value.obj.resource_id);
+ }
+ }
+
+ if (deleted_obj.size() > 0) {
+ // inst_.sampling.reset();
+ }
+
+ for (auto key : deleted_obj) {
+ velocity_map.remove(key);
+ }
+
+ indirection_buf.resize(power_of_2_max_u(max_resource_id_ + 1));
+
+ /* Avoid uploading more data to the GPU as well as an extra level of
+ * indirection on the GPU by copying back offsets the to VelocityIndex. */
+ for (VelocityObjectData &vel : velocity_map.values()) {
+ /* Disable deform if vertex count mismatch. */
+ if (inst_.is_viewport()) {
+ /* Current geometry step will be copied at the end of the frame.
+ * Thus vel.geo.len[STEP_CURRENT] is not yet valid and the current length is manually
+ * retrieved. */
+ GPUVertBuf *pos_buf = geometry_map.lookup_default(vel.id, VelocityGeometryData()).pos_buf;
+ vel.geo.do_deform = pos_buf != nullptr &&
+ (vel.geo.len[STEP_PREVIOUS] == GPU_vertbuf_get_vertex_len(pos_buf));
+ }
+ else {
+ vel.geo.do_deform = (vel.geo.len[STEP_PREVIOUS] == vel.geo.len[STEP_CURRENT]) &&
+ (vel.geo.len[STEP_NEXT] == vel.geo.len[STEP_CURRENT]);
+ }
+ indirection_buf[vel.obj.resource_id] = vel;
+ /* Reset for next sync. */
+ vel.obj.resource_id = (uint)-1;
+ }
+
+ object_steps[STEP_PREVIOUS]->push_update();
+ object_steps[STEP_NEXT]->push_update();
+ camera_steps[STEP_PREVIOUS]->push_update();
+ camera_steps[STEP_CURRENT]->push_update();
+ camera_steps[STEP_NEXT]->push_update();
+ indirection_buf.push_update();
+
+ {
+ resolve_ps_ = DRW_pass_create("Velocity.Resolve", (DRWState)0);
+ GPUShader *sh = inst_.shaders.static_shader_get(VELOCITY_RESOLVE);
+ DRWShadingGroup *grp = DRW_shgroup_create(sh, resolve_ps_);
+ DRW_shgroup_uniform_texture_ref(grp, "depth_tx", &input_depth_tx_);
+ DRW_shgroup_uniform_image_ref(grp, "velocity_view_img", &velocity_view_tx_);
+ DRW_shgroup_uniform_image_ref(grp, "velocity_camera_img", &velocity_camera_tx_);
+ DRW_shgroup_uniform_block(grp, "camera_prev", *camera_steps[STEP_PREVIOUS]);
+ DRW_shgroup_uniform_block(grp, "camera_curr", *camera_steps[STEP_CURRENT]);
+ DRW_shgroup_uniform_block(grp, "camera_next", *camera_steps[STEP_NEXT]);
+ DRW_shgroup_call_compute_ref(grp, resolve_dispatch_size_);
+ }
+}
+
+bool VelocityModule::object_has_velocity(const Object *ob)
+{
+#if 0
+ RigidBodyOb *rbo = ob->rigidbody_object;
+ /* Active rigidbody objects only, as only those are affected by sim. */
+ const bool has_rigidbody = (rbo && (rbo->type == RBO_TYPE_ACTIVE));
+ /* For now we assume dupli objects are moving. */
+ const bool is_dupli = (ob->base_flag & BASE_FROM_DUPLI) != 0;
+ const bool object_moves = is_dupli || has_rigidbody || BKE_object_moves_in_time(ob, true);
+#else
+ UNUSED_VARS(ob);
+ /* BKE_object_moves_in_time does not work in some cases.
+ * Better detect non moving object after evaluation. */
+ const bool object_moves = true;
+#endif
+ return object_moves;
+}
+
+bool VelocityModule::object_is_deform(const Object *ob)
+{
+ RigidBodyOb *rbo = ob->rigidbody_object;
+ /* Active rigidbody objects only, as only those are affected by sim. */
+ const bool has_rigidbody = (rbo && (rbo->type == RBO_TYPE_ACTIVE));
+ const bool is_deform = BKE_object_is_deform_modified(inst_.scene, (Object *)ob) ||
+ (has_rigidbody && (rbo->flag & RBO_FLAG_USE_DEFORM) != 0);
+
+ return is_deform;
+}
+
+void VelocityModule::bind_resources(DRWShadingGroup *grp)
+{
+ /* For viewport, only previous motion is supported.
+ * Still bind previous step to avoid undefined behavior. */
+ eVelocityStep next = inst_.is_viewport() ? STEP_PREVIOUS : STEP_NEXT;
+ DRW_shgroup_storage_block_ref(grp, "velocity_obj_prev_buf", &(*object_steps[STEP_PREVIOUS]));
+ DRW_shgroup_storage_block_ref(grp, "velocity_obj_next_buf", &(*object_steps[next]));
+ DRW_shgroup_storage_block_ref(grp, "velocity_geo_prev_buf", &(*geometry_steps[STEP_PREVIOUS]));
+ DRW_shgroup_storage_block_ref(grp, "velocity_geo_next_buf", &(*geometry_steps[next]));
+ DRW_shgroup_uniform_block_ref(grp, "camera_prev", &(*camera_steps[STEP_PREVIOUS]));
+ DRW_shgroup_uniform_block_ref(grp, "camera_curr", &(*camera_steps[STEP_CURRENT]));
+ DRW_shgroup_uniform_block_ref(grp, "camera_next", &(*camera_steps[next]));
+ DRW_shgroup_storage_block_ref(grp, "velocity_indirection_buf", &indirection_buf);
+}
+
+/* Resolve pass for static geometry and to camera space projection. */
+void VelocityModule::resolve_camera_motion(GPUTexture *depth_tx,
+ GPUTexture *velocity_view_tx,
+ GPUTexture *velocity_camera_tx)
+{
+ input_depth_tx_ = depth_tx;
+ velocity_view_tx_ = velocity_view_tx;
+ velocity_camera_tx_ = velocity_camera_tx;
+
+ resolve_dispatch_size_.x = divide_ceil_u(GPU_texture_width(depth_tx), 8);
+ resolve_dispatch_size_.y = divide_ceil_u(GPU_texture_height(depth_tx), 8);
+
+ DRW_draw_pass(resolve_ps_);
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Velocity View
+ * \{ */
+
+void VelocityView::sync()
+{
+ /* TODO: Remove. */
+ velocity_view_tx_.sync();
+ velocity_camera_tx_.sync();
+}
+
+void VelocityView::acquire(int2 extent)
+{
+ /* WORKAROUND: View name should be unique and static.
+ * With this, we can reuse the same texture across views. */
+ DrawEngineType *owner = (DrawEngineType *)view_name_.c_str();
+
+ /* Only RG16F when only doing only reprojection or motion blur. */
+ eGPUTextureFormat format = inst_.is_viewport() ? GPU_RG16F : GPU_RGBA16F;
+ velocity_view_tx_.acquire(extent, format, owner);
+ if (false /* TODO(fclem): Panoramic camera. */) {
+ velocity_camera_tx_.acquire(extent, format, owner);
+ }
+ else {
+ velocity_camera_tx_.acquire(int2(1), format, owner);
+ }
+}
+
+void VelocityView::resolve(GPUTexture *depth_tx)
+{
+ inst_.velocity.resolve_camera_motion(depth_tx, velocity_view_tx_, velocity_camera_tx_);
+}
+
+void VelocityView::release()
+{
+ velocity_view_tx_.release();
+ velocity_camera_tx_.release();
+}
+
+/** \} */
+
+} // namespace blender::eevee
diff --git a/source/blender/draw/engines/eevee_next/eevee_velocity.hh b/source/blender/draw/engines/eevee_next/eevee_velocity.hh
new file mode 100644
index 00000000000..e2606c061e1
--- /dev/null
+++ b/source/blender/draw/engines/eevee_next/eevee_velocity.hh
@@ -0,0 +1,178 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later
+ * Copyright 2021 Blender Foundation.
+ */
+
+/** \file
+ * \ingroup eevee
+ *
+ * The velocity pass outputs motion vectors to use for either
+ * temporal re-projection or motion blur.
+ *
+ * It is the module that tracks the objects data between frames updates.
+ */
+
+#pragma once
+
+#include "BLI_map.hh"
+
+#include "eevee_shader_shared.hh"
+#include "eevee_sync.hh"
+
+namespace blender::eevee {
+
+/* -------------------------------------------------------------------- */
+/** \name VelocityModule
+ *
+ * \{ */
+
+/** Container for scene velocity data. */
+class VelocityModule {
+ friend class VelocityView;
+
+ public:
+ struct VelocityObjectData : public VelocityIndex {
+ /** ID to retrieve the corresponding #VelocityGeometryData after copy. */
+ ID *id;
+ };
+ struct VelocityGeometryData {
+ /** VertBuf not yet ready to be copied to the #VelocityGeometryBuf. */
+ GPUVertBuf *pos_buf = nullptr;
+ /* Offset in the #VelocityGeometryBuf to the start of the data. In vertex. */
+ int ofs;
+ /* Length of the vertex buffer. In vertex. */
+ int len;
+ };
+ /**
+ * The map contains indirection indices to the obmat and geometry in each step buffer.
+ * Note that each object component gets its own resource id so one component correspond to one
+ * geometry offset.
+ */
+ Map<ObjectKey, VelocityObjectData> velocity_map;
+ /** Geometry to be copied to VelocityGeometryBuf. Indexed by evaluated ID *. Empty after */
+ Map<ID *, VelocityGeometryData> geometry_map;
+ /** Contains all objects matrices for each time step. */
+ std::array<VelocityObjectBuf *, 3> object_steps;
+ /** Contains all Geometry steps from deforming objects for each time step. */
+ std::array<VelocityGeometryBuf *, 3> geometry_steps;
+ /** Number of occupied slot in each `object_steps`. */
+ int3 object_steps_usage = int3(0);
+ /** Buffer of all #VelocityIndex used in this frame. Indexed by draw manager resource id. */
+ VelocityIndexBuf indirection_buf;
+
+ /**
+ * Copies of camera data. One for previous and one for next time step.
+ */
+ std::array<CameraDataBuf *, 3> camera_steps;
+
+ private:
+ Instance &inst_;
+
+ eVelocityStep step_ = STEP_CURRENT;
+
+ DRWPass *resolve_ps_ = nullptr;
+
+ /** Reference only. Not owned. */
+ GPUTexture *input_depth_tx_;
+ GPUTexture *velocity_view_tx_;
+ GPUTexture *velocity_camera_tx_;
+
+ int3 resolve_dispatch_size_ = int3(1, 1, 1);
+
+ public:
+ VelocityModule(Instance &inst) : inst_(inst)
+ {
+ for (VelocityObjectBuf *&step_buf : object_steps) {
+ step_buf = new VelocityObjectBuf();
+ }
+ for (VelocityGeometryBuf *&step_buf : geometry_steps) {
+ step_buf = new VelocityGeometryBuf();
+ }
+ for (CameraDataBuf *&step_buf : camera_steps) {
+ step_buf = new CameraDataBuf();
+ }
+ };
+
+ ~VelocityModule()
+ {
+ for (VelocityObjectBuf *step_buf : object_steps) {
+ delete step_buf;
+ }
+ for (VelocityGeometryBuf *step_buf : geometry_steps) {
+ delete step_buf;
+ }
+ for (CameraDataBuf *step_buf : camera_steps) {
+ delete step_buf;
+ }
+ }
+
+ void init();
+
+ void step_camera_sync();
+ void step_sync(eVelocityStep step, float time);
+
+ /* Gather motion data. Returns true if the object **can** have motion. */
+ bool step_object_sync(Object *ob, ObjectKey &object_key, int recalc = 0);
+
+ /* Moves next frame data to previous frame data. Nullify next frame data. */
+ void step_swap();
+
+ void begin_sync();
+ void end_sync();
+
+ void bind_resources(DRWShadingGroup *grp);
+
+ private:
+ bool object_has_velocity(const Object *ob);
+ bool object_is_deform(const Object *ob);
+
+ void resolve_camera_motion(GPUTexture *depth_tx,
+ GPUTexture *velocity_view_tx,
+ GPUTexture *velocity_camera_tx);
+};
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Velocity
+ *
+ * \{ */
+
+/**
+ * Per view module.
+ */
+class VelocityView {
+ private:
+ Instance &inst_;
+
+ StringRefNull view_name_;
+
+ TextureFromPool velocity_camera_tx_ = {"velocity_camera_tx_"};
+ TextureFromPool velocity_view_tx_ = {"velocity_view_tx_"};
+
+ public:
+ VelocityView(Instance &inst, const char *name) : inst_(inst), view_name_(name){};
+ ~VelocityView(){};
+
+ void sync();
+
+ void acquire(int2 extent);
+ void release();
+
+ void resolve(GPUTexture *depth_tx);
+
+ /**
+ * Getters
+ **/
+ GPUTexture *view_vectors_get() const
+ {
+ return velocity_view_tx_;
+ }
+ GPUTexture *camera_vectors_get() const
+ {
+ return (velocity_camera_tx_.is_valid()) ? velocity_camera_tx_ : velocity_view_tx_;
+ }
+};
+
+/** \} */
+
+} // namespace blender::eevee
diff --git a/source/blender/draw/engines/eevee_next/eevee_view.cc b/source/blender/draw/engines/eevee_next/eevee_view.cc
index de7341f814b..e21342c5ef6 100644
--- a/source/blender/draw/engines/eevee_next/eevee_view.cc
+++ b/source/blender/draw/engines/eevee_next/eevee_view.cc
@@ -86,7 +86,7 @@ void ShadingView::sync(int2 render_extent_)
// dof_.sync(winmat_p, extent_);
// mb_.sync(extent_);
- // velocity_.sync(extent_);
+ velocity_.sync();
// rt_buffer_opaque_.sync(extent_);
// rt_buffer_refract_.sync(extent_);
// inst_.hiz_back.view_sync(extent_);
@@ -108,22 +108,30 @@ void ShadingView::render()
* With this, we can reuse the same texture across views. */
DrawEngineType *owner = (DrawEngineType *)name_;
+ DefaultTextureList *dtxl = DRW_viewport_texture_list_get();
+
depth_tx_.ensure_2d(GPU_DEPTH24_STENCIL8, extent_);
combined_tx_.acquire(extent_, GPU_RGBA16F, owner);
- view_fb_.ensure(GPU_ATTACHMENT_TEXTURE(depth_tx_), GPU_ATTACHMENT_TEXTURE(combined_tx_));
+ velocity_.acquire(extent_);
+ // combined_fb_.ensure(GPU_ATTACHMENT_TEXTURE(depth_tx_), GPU_ATTACHMENT_TEXTURE(combined_tx_));
+ // prepass_fb_.ensure(GPU_ATTACHMENT_TEXTURE(depth_tx_),
+ // GPU_ATTACHMENT_TEXTURE(velocity_.view_vectors_get()));
+ combined_fb_.ensure(GPU_ATTACHMENT_TEXTURE(dtxl->depth), GPU_ATTACHMENT_TEXTURE(dtxl->color));
+ prepass_fb_.ensure(GPU_ATTACHMENT_TEXTURE(dtxl->depth),
+ GPU_ATTACHMENT_TEXTURE(velocity_.view_vectors_get()));
update_view();
DRW_stats_group_start(name_);
// DRW_view_set_active(render_view_);
+ float4 clear_velocity(VELOCITY_INVALID);
+ GPU_framebuffer_bind(prepass_fb_);
+ GPU_framebuffer_clear_color(prepass_fb_, clear_velocity);
/* Alpha stores transmittance. So start at 1. */
float4 clear_color = {0.0f, 0.0f, 0.0f, 1.0f};
- // GPU_framebuffer_bind(view_fb_);
- // GPU_framebuffer_clear_color_depth(view_fb_, clear_color, 1.0f);
- DefaultFramebufferList *dfbl = DRW_viewport_framebuffer_list_get();
- GPU_framebuffer_bind(dfbl->default_fb);
- GPU_framebuffer_clear_color_depth(dfbl->default_fb, clear_color, 1.0f);
+ GPU_framebuffer_bind(combined_fb_);
+ GPU_framebuffer_clear_color_depth(combined_fb_, clear_color, 1.0f);
inst_.pipelines.world.render();
@@ -134,12 +142,13 @@ void ShadingView::render()
// inst_.lookdev.render_overlay(view_fb_);
- inst_.pipelines.forward.render(render_view_, depth_tx_, combined_tx_);
+ inst_.pipelines.forward.render(render_view_, prepass_fb_, combined_fb_, depth_tx_, combined_tx_);
// inst_.lights.debug_draw(view_fb_);
// inst_.shadows.debug_draw(view_fb_);
- // velocity_.render(depth_tx_);
+ // velocity_.resolve(depth_tx_);
+ velocity_.resolve(dtxl->depth);
// if (inst_.render_passes.vector) {
// inst_.render_passes.vector->accumulate(velocity_.camera_vectors_get(), sub_view_);
@@ -159,6 +168,7 @@ void ShadingView::render()
combined_tx_.release();
postfx_tx_.release();
+ velocity_.release();
}
GPUTexture *ShadingView::render_post(GPUTexture *input_tx)
diff --git a/source/blender/draw/engines/eevee_next/eevee_view.hh b/source/blender/draw/engines/eevee_next/eevee_view.hh
index e78a3222d8b..fb74412f557 100644
--- a/source/blender/draw/engines/eevee_next/eevee_view.hh
+++ b/source/blender/draw/engines/eevee_next/eevee_view.hh
@@ -21,6 +21,7 @@
#include "eevee_camera.hh"
#include "eevee_pipeline.hh"
#include "eevee_shader.hh"
+#include "eevee_velocity.hh"
namespace blender::eevee {
@@ -40,16 +41,17 @@ class ShadingView {
/** Matrix to apply to the viewmat. */
const float (*face_matrix_)[4];
- /** Post-fx modules. */
+ /** Post-FX modules. */
// DepthOfField dof_;
// MotionBlur mb_;
- // Velocity velocity_;
+ VelocityView velocity_;
/** Raytracing persistent buffers. Only opaque and refraction can have surface tracing. */
// RaytraceBuffer rt_buffer_opaque_;
// RaytraceBuffer rt_buffer_refract_;
- Framebuffer view_fb_;
+ Framebuffer prepass_fb_;
+ Framebuffer combined_fb_;
Texture depth_tx_;
TextureFromPool combined_tx_;
TextureFromPool postfx_tx_;
@@ -69,7 +71,7 @@ class ShadingView {
public:
ShadingView(Instance &inst, const char *name, const float (*face_matrix)[4])
- : inst_(inst), name_(name), face_matrix_(face_matrix){};
+ : inst_(inst), name_(name), face_matrix_(face_matrix), velocity_(inst, name){};
~ShadingView(){};
diff --git a/source/blender/draw/engines/eevee_next/eevee_world.cc b/source/blender/draw/engines/eevee_next/eevee_world.cc
index 939f6087137..b9cb24fe30a 100644
--- a/source/blender/draw/engines/eevee_next/eevee_world.cc
+++ b/source/blender/draw/engines/eevee_next/eevee_world.cc
@@ -64,19 +64,17 @@ void World::sync()
// }
::World *bl_world = inst_.scene->world;
-
if (bl_world == nullptr) {
// bl_world = BKE_world_default();
return;
}
- else {
- WorldHandle &wo_handle = inst_.sync.sync_world(bl_world);
- if (wo_handle.recalc != 0) {
- // inst_.lightprobes.set_world_dirty();
- }
- wo_handle.reset_recalc_flag();
+ WorldHandle &wo_handle = inst_.sync.sync_world(bl_world);
+
+ if (wo_handle.recalc != 0) {
+ // inst_.lightprobes.set_world_dirty();
}
+ wo_handle.reset_recalc_flag();
/* TODO(fclem) This should be detected to scene level. */
::World *orig_world = (::World *)DEG_get_original_id(&bl_world->id);
diff --git a/source/blender/draw/engines/eevee_next/shaders/eevee_attributes_lib.glsl b/source/blender/draw/engines/eevee_next/shaders/eevee_attributes_lib.glsl
index abecb373995..a65bb7decb6 100644
--- a/source/blender/draw/engines/eevee_next/shaders/eevee_attributes_lib.glsl
+++ b/source/blender/draw/engines/eevee_next/shaders/eevee_attributes_lib.glsl
@@ -112,6 +112,7 @@ float attr_load_float(float attr)
/** \name Curve
*
* Curve objects loads attributes from buffers through sampler buffers.
+ * Per attribute scope follows loading order.
* \{ */
# ifdef OBINFO_LIB
@@ -122,6 +123,24 @@ vec3 attr_load_orco(vec4 orco)
return OrcoTexCoFactors[0].xyz + lP * OrcoTexCoFactors[1].xyz;
}
# endif
+
+int g_curves_attr_id = 0;
+
+/* Return the index to use for looking up the attribute value in the sampler
+ * based on the attribute scope (point or spline). */
+int curves_attribute_element_id()
+{
+ int id = interp.curves_strand_id;
+ if (drw_curves.is_point_attribute[g_curves_attr_id] != 0) {
+# ifdef COMMON_HAIR_LIB
+ id = hair_get_base_id();
+# endif
+ }
+
+ g_curves_attr_id += 1;
+ return id;
+}
+
vec4 attr_load_tangent(samplerBuffer cd_buf)
{
/* Not supported for the moment. */
@@ -137,19 +156,19 @@ vec4 attr_load_color(samplerBuffer cd_buf)
}
vec4 attr_load_vec4(samplerBuffer cd_buf)
{
- return texelFetch(cd_buf, interp.curves_strand_id).rgba;
+ return texelFetch(cd_buf, curves_attribute_element_id()).rgba;
}
vec3 attr_load_vec3(samplerBuffer cd_buf)
{
- return texelFetch(cd_buf, interp.curves_strand_id).rgb;
+ return texelFetch(cd_buf, curves_attribute_element_id()).rgb;
}
vec2 attr_load_vec2(samplerBuffer cd_buf)
{
- return texelFetch(cd_buf, interp.curves_strand_id).rg;
+ return texelFetch(cd_buf, curves_attribute_element_id()).rg;
}
float attr_load_float(samplerBuffer cd_buf)
{
- return texelFetch(cd_buf, interp.curves_strand_id).r;
+ return texelFetch(cd_buf, curves_attribute_element_id()).r;
}
/** \} */
@@ -164,7 +183,7 @@ float attr_load_float(samplerBuffer cd_buf)
* \{ */
# ifndef OBINFO_LIB
-# error "draw_object_infos is mandatory for volume objects"
+# error draw_object_infos is mandatory for volume objects
# endif
vec3 g_orco;
@@ -268,7 +287,7 @@ vec3 attr_load_uv(vec3 attr)
/** \name Volume Attribute post
*
* TODO(@fclem): These implementation details should concern the DRWManager and not be a fix on
- * the engine side. But as of now, the engines are reponsible for loading the attributes.
+ * the engine side. But as of now, the engines are responsible for loading the attributes.
*
* \{ */
diff --git a/source/blender/draw/engines/eevee_next/shaders/eevee_camera_lib.glsl b/source/blender/draw/engines/eevee_next/shaders/eevee_camera_lib.glsl
new file mode 100644
index 00000000000..f79e9102d76
--- /dev/null
+++ b/source/blender/draw/engines/eevee_next/shaders/eevee_camera_lib.glsl
@@ -0,0 +1,166 @@
+
+/**
+ * Camera projection / uv functions and utils.
+ **/
+
+#pragma BLENDER_REQUIRE(common_math_lib.glsl)
+
+/* -------------------------------------------------------------------- */
+/** \name Panoramic Projections
+ *
+ * Adapted from Cycles to match EEVEE's coordinate system.
+ * \{ */
+
+vec2 camera_equirectangular_from_direction(CameraData cam, vec3 dir)
+{
+ float phi = atan(-dir.z, dir.x);
+ float theta = acos(dir.y / length(dir));
+ return (vec2(phi, theta) - cam.equirect_bias) * cam.equirect_scale_inv;
+}
+
+vec3 camera_equirectangular_to_direction(CameraData cam, vec2 uv)
+{
+ uv = uv * cam.equirect_scale + cam.equirect_bias;
+ float phi = uv.x;
+ float theta = uv.y;
+ float sin_theta = sin(theta);
+ return vec3(sin_theta * cos(phi), cos(theta), -sin_theta * sin(phi));
+}
+
+vec2 camera_fisheye_from_direction(CameraData cam, vec3 dir)
+{
+ float r = atan(length(dir.xy), -dir.z) / cam.fisheye_fov;
+ float phi = atan(dir.y, dir.x);
+ vec2 uv = r * vec2(cos(phi), sin(phi)) + 0.5;
+ return (uv - cam.uv_bias) / cam.uv_scale;
+}
+
+vec3 camera_fisheye_to_direction(CameraData cam, vec2 uv)
+{
+ uv = uv * cam.uv_scale + cam.uv_bias;
+ uv = (uv - 0.5) * 2.0;
+ float r = length(uv);
+ if (r > 1.0) {
+ return vec3(0.0);
+ }
+ float phi = safe_acos(uv.x * safe_rcp(r));
+ float theta = r * cam.fisheye_fov * 0.5;
+ if (uv.y < 0.0) {
+ phi = -phi;
+ }
+ return vec3(cos(phi) * sin(theta), sin(phi) * sin(theta), -cos(theta));
+}
+
+vec2 camera_mirror_ball_from_direction(CameraData cam, vec3 dir)
+{
+ dir = normalize(dir);
+ dir.z -= 1.0;
+ dir *= safe_rcp(2.0 * safe_sqrt(-0.5 * dir.z));
+ vec2 uv = 0.5 * dir.xy + 0.5;
+ return (uv - cam.uv_bias) / cam.uv_scale;
+}
+
+vec3 camera_mirror_ball_to_direction(CameraData cam, vec2 uv)
+{
+ uv = uv * cam.uv_scale + cam.uv_bias;
+ vec3 dir;
+ dir.xy = uv * 2.0 - 1.0;
+ if (len_squared(dir.xy) > 1.0) {
+ return vec3(0.0);
+ }
+ dir.z = -safe_sqrt(1.0 - sqr(dir.x) - sqr(dir.y));
+ const vec3 I = vec3(0.0, 0.0, 1.0);
+ return reflect(I, dir);
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Regular projections
+ * \{ */
+
+vec3 camera_view_from_uv(mat4 projmat, vec2 uv)
+{
+ return project_point(projmat, vec3(uv * 2.0 - 1.0, 0.0));
+}
+
+vec2 camera_uv_from_view(mat4 projmat, bool is_persp, vec3 vV)
+{
+ vec4 tmp = projmat * vec4(vV, 1.0);
+ if (is_persp && tmp.w <= 0.0) {
+ /* Return invalid coordinates for points behind the camera.
+ * This can happen with panoramic projections. */
+ return vec2(-1.0);
+ }
+ return (tmp.xy / tmp.w) * 0.5 + 0.5;
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name General functions handling all projections
+ * \{ */
+
+vec3 camera_view_from_uv(CameraData cam, vec2 uv)
+{
+ vec3 vV;
+ switch (cam.type) {
+ default:
+ case CAMERA_ORTHO:
+ case CAMERA_PERSP:
+ return camera_view_from_uv(cam.wininv, uv);
+ case CAMERA_PANO_EQUIRECT:
+ vV = camera_equirectangular_to_direction(cam, uv);
+ break;
+ case CAMERA_PANO_EQUIDISTANT:
+ /* ATTR_FALLTHROUGH; */
+ case CAMERA_PANO_EQUISOLID:
+ vV = camera_fisheye_to_direction(cam, uv);
+ break;
+ case CAMERA_PANO_MIRROR:
+ vV = camera_mirror_ball_to_direction(cam, uv);
+ break;
+ }
+ return vV;
+}
+
+vec2 camera_uv_from_view(CameraData cam, vec3 vV)
+{
+ switch (cam.type) {
+ default:
+ case CAMERA_ORTHO:
+ return camera_uv_from_view(cam.winmat, false, vV);
+ case CAMERA_PERSP:
+ return camera_uv_from_view(cam.winmat, true, vV);
+ case CAMERA_PANO_EQUIRECT:
+ return camera_equirectangular_from_direction(cam, vV);
+ case CAMERA_PANO_EQUISOLID:
+ /* ATTR_FALLTHROUGH; */
+ case CAMERA_PANO_EQUIDISTANT:
+ return camera_fisheye_from_direction(cam, vV);
+ case CAMERA_PANO_MIRROR:
+ return camera_mirror_ball_from_direction(cam, vV);
+ }
+}
+
+vec2 camera_uv_from_world(CameraData cam, vec3 V)
+{
+ vec3 vV = transform_point(cam.viewmat, V);
+ switch (cam.type) {
+ default:
+ case CAMERA_ORTHO:
+ return camera_uv_from_view(cam.persmat, false, V);
+ case CAMERA_PERSP:
+ return camera_uv_from_view(cam.persmat, true, V);
+ case CAMERA_PANO_EQUIRECT:
+ return camera_equirectangular_from_direction(cam, vV);
+ case CAMERA_PANO_EQUISOLID:
+ /* ATTR_FALLTHROUGH; */
+ case CAMERA_PANO_EQUIDISTANT:
+ return camera_fisheye_from_direction(cam, vV);
+ case CAMERA_PANO_MIRROR:
+ return camera_mirror_ball_from_direction(cam, vV);
+ }
+}
+
+/** \} */
diff --git a/source/blender/draw/engines/eevee_next/shaders/eevee_geom_curves_vert.glsl b/source/blender/draw/engines/eevee_next/shaders/eevee_geom_curves_vert.glsl
index 11f93ad0d14..87154ba6db1 100644
--- a/source/blender/draw/engines/eevee_next/shaders/eevee_geom_curves_vert.glsl
+++ b/source/blender/draw/engines/eevee_next/shaders/eevee_geom_curves_vert.glsl
@@ -5,6 +5,7 @@
#pragma BLENDER_REQUIRE(eevee_attributes_lib.glsl)
#pragma BLENDER_REQUIRE(eevee_nodetree_lib.glsl)
#pragma BLENDER_REQUIRE(eevee_surf_lib.glsl)
+#pragma BLENDER_REQUIRE(eevee_velocity_lib.glsl)
void main()
{
@@ -18,7 +19,7 @@ void main()
ViewMatrixInverse[3].xyz,
ViewMatrixInverse[2].xyz,
interp.P,
- T,
+ interp.curves_tangent,
interp.curves_binormal,
interp.curves_time,
interp.curves_thickness,
@@ -27,6 +28,19 @@ void main()
interp.N = cross(T, interp.curves_binormal);
interp.curves_strand_id = hair_get_strand_id();
interp.barycentric_coords = hair_get_barycentric();
+#ifdef MAT_VELOCITY
+ /* Due to the screen space nature of the vertex positioning, we compute only the motion of curve
+ * strand, not its cylinder. Otherwise we would add the rotation velocity. */
+ int vert_idx = hair_get_base_id();
+ vec3 prv, nxt, pos = texelFetch(hairPointBuffer, vert_idx).point_position;
+ velocity_local_pos_get(pos, vert_idx, prv, nxt);
+ /* FIXME(fclem): Evaluating before displacement avoid displacement being treated as motion but
+ * ignores motion from animated displacement. Supporting animated displacement motion vectors
+ * would require evaluating the nodetree multiple time with different nodetree UBOs evaluated at
+ * different times, but also with different attributes (maybe we could assume static attribute at
+ * least). */
+ velocity_vertex(prv, pos, nxt, motion.prev, motion.next);
+#endif
init_globals();
attrib_load();
diff --git a/source/blender/draw/engines/eevee_next/shaders/eevee_geom_gpencil_vert.glsl b/source/blender/draw/engines/eevee_next/shaders/eevee_geom_gpencil_vert.glsl
index 5b404ec5237..c60527162f7 100644
--- a/source/blender/draw/engines/eevee_next/shaders/eevee_geom_gpencil_vert.glsl
+++ b/source/blender/draw/engines/eevee_next/shaders/eevee_geom_gpencil_vert.glsl
@@ -3,6 +3,7 @@
#pragma BLENDER_REQUIRE(common_view_lib.glsl)
#pragma BLENDER_REQUIRE(eevee_attributes_lib.glsl)
#pragma BLENDER_REQUIRE(eevee_surf_lib.glsl)
+#pragma BLENDER_REQUIRE(eevee_velocity_lib.glsl)
void main()
{
@@ -38,6 +39,16 @@ void main()
aspect,
thickness,
hardness);
+#ifdef MAT_VELOCITY
+ /* GPencil do not support deformation motion blur. */
+ vec3 lP_curr = transform_point(ModelMatrixInverse, interp.P);
+ /* FIXME(fclem): Evaluating before displacement avoid displacement being treated as motion but
+ * ignores motion from animated displacement. Supporting animated displacement motion vectors
+ * would require evaluating the nodetree multiple time with different nodetree UBOs evaluated at
+ * different times, but also with different attributes (maybe we could assume static attribute at
+ * least). */
+ velocity_vertex(lP_curr, lP_curr, lP_curr, motion.prev, motion.next);
+#endif
init_globals();
attrib_load();
diff --git a/source/blender/draw/engines/eevee_next/shaders/eevee_geom_mesh_vert.glsl b/source/blender/draw/engines/eevee_next/shaders/eevee_geom_mesh_vert.glsl
index 7b38057f41a..c07a8ae0eea 100644
--- a/source/blender/draw/engines/eevee_next/shaders/eevee_geom_mesh_vert.glsl
+++ b/source/blender/draw/engines/eevee_next/shaders/eevee_geom_mesh_vert.glsl
@@ -3,6 +3,7 @@
#pragma BLENDER_REQUIRE(eevee_attributes_lib.glsl)
#pragma BLENDER_REQUIRE(eevee_nodetree_lib.glsl)
#pragma BLENDER_REQUIRE(eevee_surf_lib.glsl)
+#pragma BLENDER_REQUIRE(eevee_velocity_lib.glsl)
void main()
{
@@ -10,6 +11,16 @@ void main()
interp.P = point_object_to_world(pos);
interp.N = normal_object_to_world(nor);
+#ifdef MAT_VELOCITY
+ vec3 prv, nxt;
+ velocity_local_pos_get(pos, gl_VertexID, prv, nxt);
+ /* FIXME(fclem): Evaluating before displacement avoid displacement being treated as motion but
+ * ignores motion from animated displacement. Supporting animated displacement motion vectors
+ * would require evaluating the nodetree multiple time with different nodetree UBOs evaluated at
+ * different times, but also with different attributes (maybe we could assume static attribute at
+ * least). */
+ velocity_vertex(prv, pos, nxt, motion.prev, motion.next);
+#endif
init_globals();
attrib_load();
diff --git a/source/blender/draw/engines/eevee_next/shaders/eevee_nodetree_lib.glsl b/source/blender/draw/engines/eevee_next/shaders/eevee_nodetree_lib.glsl
index 06191a5c007..0ccf06a9e14 100644
--- a/source/blender/draw/engines/eevee_next/shaders/eevee_nodetree_lib.glsl
+++ b/source/blender/draw/engines/eevee_next/shaders/eevee_nodetree_lib.glsl
@@ -9,6 +9,7 @@ float g_holdout;
/* The Closure type is never used. Use float as dummy type. */
#define Closure float
+#define CLOSURE_DEFAULT 0.0
/* Sampled closure parameters. */
ClosureDiffuse g_diffuse_data;
@@ -28,7 +29,7 @@ bool closure_select(float weight, inout float total_weight, inout float r)
float x = weight / total_weight;
bool chosen = (r < x);
/* Assuming that if r is in the interval [0,x] or [x,1], it's still uniformly distributed within
- * that interval, so you remaping to [0,1] again to explore this space of probability. */
+ * that interval, so you remapping to [0,1] again to explore this space of probability. */
r = (chosen) ? (r / x) : ((r - x) / (1.0 - x));
return chosen;
}
@@ -332,7 +333,7 @@ vec3 coordinate_screen(vec3 P)
window.xy = vec2(0.5);
}
else {
- /* TODO(fclem): Actual camera tranform. */
+ /* TODO(fclem): Actual camera transform. */
window.xy = project_point(ViewProjectionMatrix, P).xy * 0.5 + 0.5;
window.xy = window.xy * CameraTexCoFactors.xy + CameraTexCoFactors.zw;
}
diff --git a/source/blender/draw/engines/eevee_next/shaders/eevee_surf_depth_frag.glsl b/source/blender/draw/engines/eevee_next/shaders/eevee_surf_depth_frag.glsl
index 002eed91130..7ddf941df7c 100644
--- a/source/blender/draw/engines/eevee_next/shaders/eevee_surf_depth_frag.glsl
+++ b/source/blender/draw/engines/eevee_next/shaders/eevee_surf_depth_frag.glsl
@@ -8,6 +8,7 @@
#pragma BLENDER_REQUIRE(common_hair_lib.glsl)
#pragma BLENDER_REQUIRE(eevee_nodetree_lib.glsl)
#pragma BLENDER_REQUIRE(eevee_surf_lib.glsl)
+#pragma BLENDER_REQUIRE(eevee_velocity_lib.glsl)
/* From the paper "Hashed Alpha Testing" by Chris Wyman and Morgan McGuire. */
float hash(vec2 a)
@@ -69,4 +70,16 @@ void main()
discard;
}
#endif
+
+#ifdef MAT_VELOCITY
+ vec4 out_velocity_camera; /* TODO(fclem): Panoramic cameras. */
+ velocity_camera(interp.P + motion.prev,
+ interp.P,
+ interp.P - motion.next,
+ out_velocity_camera,
+ out_velocity_view);
+
+ /* For testing in viewport. */
+ out_velocity_view.zw = vec2(0.0);
+#endif
}
diff --git a/source/blender/draw/engines/eevee_next/shaders/eevee_surf_lib.glsl b/source/blender/draw/engines/eevee_next/shaders/eevee_surf_lib.glsl
index 0d8644c9901..30b48edaa78 100644
--- a/source/blender/draw/engines/eevee_next/shaders/eevee_surf_lib.glsl
+++ b/source/blender/draw/engines/eevee_next/shaders/eevee_surf_lib.glsl
@@ -42,6 +42,12 @@ void init_globals_curves()
float sin_theta = sqrt(max(0.0, 1.0 - cos_theta * cos_theta));
g_data.N = normalize(interp.N * sin_theta + interp.curves_binormal * cos_theta);
+ /* Costly, but follows cycles per pixel tangent space (not following curve shape). */
+ vec3 V = cameraVec(g_data.P);
+ g_data.curve_T = -interp.curves_tangent;
+ g_data.curve_B = cross(V, g_data.curve_T);
+ g_data.curve_N = safe_normalize(cross(g_data.curve_T, g_data.curve_B));
+
g_data.is_strand = true;
g_data.hair_time = interp.curves_time;
g_data.hair_thickness = interp.curves_thickness;
@@ -94,6 +100,7 @@ void init_interface()
interp.P = vec3(0.0);
interp.N = vec3(0.0);
interp.barycentric_coords = vec2(0.0);
+ interp.curves_tangent = vec3(0.0);
interp.curves_binormal = vec3(0.0);
interp.curves_time = 0.0;
interp.curves_time_width = 0.0;
diff --git a/source/blender/draw/engines/eevee_next/shaders/eevee_velocity_lib.glsl b/source/blender/draw/engines/eevee_next/shaders/eevee_velocity_lib.glsl
new file mode 100644
index 00000000000..435ae6658c9
--- /dev/null
+++ b/source/blender/draw/engines/eevee_next/shaders/eevee_velocity_lib.glsl
@@ -0,0 +1,101 @@
+
+#pragma BLENDER_REQUIRE(common_view_lib.glsl)
+#pragma BLENDER_REQUIRE(eevee_camera_lib.glsl)
+
+#ifdef VELOCITY_CAMERA
+
+/**
+ * Given a triple of position, compute the previous and next motion vectors.
+ * Returns uv space motion vectors in pairs (motion_prev.xy, motion_next.xy)
+ */
+vec4 velocity_view(vec3 P_prev, vec3 P, vec3 P_next)
+{
+ vec2 prev_uv, curr_uv, next_uv;
+
+ prev_uv = transform_point(ProjectionMatrix, transform_point(camera_prev.viewmat, P_prev)).xy;
+ curr_uv = transform_point(ViewProjectionMatrix, P).xy;
+ next_uv = transform_point(ProjectionMatrix, transform_point(camera_next.viewmat, P_next)).xy;
+
+ vec4 motion;
+ motion.xy = prev_uv - curr_uv;
+ motion.zw = curr_uv - next_uv;
+ /* Convert NDC velocity to UV velocity */
+ motion *= 0.5;
+
+ return motion;
+}
+
+/**
+ * Given a triple of position, compute the previous and next motion vectors.
+ * Returns uv space motion vectors in pairs (motion_prev.xy, motion_next.xy)
+ * \a velocity_camera is the motion in film UV space after camera projection.
+ * \a velocity_view is the motion in ShadingView UV space. It is different
+ * from velocity_camera for multi-view rendering.
+ */
+void velocity_camera(vec3 P_prev, vec3 P, vec3 P_next, out vec4 vel_camera, out vec4 vel_view)
+{
+ vec2 prev_uv, curr_uv, next_uv;
+ prev_uv = camera_uv_from_world(camera_prev, P_prev);
+ curr_uv = camera_uv_from_world(camera_curr, P);
+ next_uv = camera_uv_from_world(camera_next, P_next);
+
+ vel_camera.xy = prev_uv - curr_uv;
+ vel_camera.zw = curr_uv - next_uv;
+
+ if (is_panoramic(camera_curr.type)) {
+ /* This path is only used if using using panoramic projections. Since the views always have
+ * the same 45° aperture angle, we can safely reuse the projection matrix. */
+ prev_uv = transform_point(ProjectionMatrix, transform_point(camera_prev.viewmat, P_prev)).xy;
+ curr_uv = transform_point(ViewProjectionMatrix, P).xy;
+ next_uv = transform_point(ProjectionMatrix, transform_point(camera_next.viewmat, P_next)).xy;
+
+ vel_view.xy = prev_uv - curr_uv;
+ vel_view.zw = curr_uv - next_uv;
+ /* Convert NDC velocity to UV velocity */
+ vel_view *= 0.5;
+ }
+ else {
+ vel_view = vel_camera;
+ }
+}
+
+#endif
+
+#ifdef MAT_VELOCITY
+
+/**
+ * Given a triple of position, compute the previous and next motion vectors.
+ * Returns a tuple of world space motion deltas.
+ */
+void velocity_local_pos_get(vec3 lP, int vert_id, out vec3 lP_prev, out vec3 lP_next)
+{
+ VelocityIndex vel = velocity_indirection_buf[resource_id];
+ lP_next = lP_prev = lP;
+ if (vel.geo.do_deform) {
+ if (vel.geo.ofs[STEP_PREVIOUS] != -1) {
+ lP_prev = velocity_geo_prev_buf[vel.geo.ofs[STEP_PREVIOUS] + vert_id].xyz;
+ }
+ if (vel.geo.ofs[STEP_NEXT] != -1) {
+ lP_next = velocity_geo_next_buf[vel.geo.ofs[STEP_NEXT] + vert_id].xyz;
+ }
+ }
+}
+
+/**
+ * Given a triple of position, compute the previous and next motion vectors.
+ * Returns a tuple of world space motion deltas.
+ */
+void velocity_vertex(
+ vec3 lP_prev, vec3 lP, vec3 lP_next, out vec3 motion_prev, out vec3 motion_next)
+{
+ VelocityIndex vel = velocity_indirection_buf[resource_id];
+ mat4 obmat_prev = velocity_obj_prev_buf[vel.obj.ofs[STEP_PREVIOUS]];
+ mat4 obmat_next = velocity_obj_next_buf[vel.obj.ofs[STEP_NEXT]];
+ vec3 P_prev = transform_point(obmat_prev, lP_prev);
+ vec3 P_next = transform_point(obmat_next, lP_next);
+ vec3 P = transform_point(ModelMatrix, lP);
+ motion_prev = P_prev - P;
+ motion_next = P_next - P;
+}
+
+#endif
diff --git a/source/blender/draw/engines/eevee_next/shaders/eevee_velocity_resolve_comp.glsl b/source/blender/draw/engines/eevee_next/shaders/eevee_velocity_resolve_comp.glsl
new file mode 100644
index 00000000000..b68b2eaf117
--- /dev/null
+++ b/source/blender/draw/engines/eevee_next/shaders/eevee_velocity_resolve_comp.glsl
@@ -0,0 +1,58 @@
+
+/**
+ * Fullscreen pass that compute motion vector for static geometry.
+ * Animated geometry has already written correct motion vectors.
+ */
+
+#pragma BLENDER_REQUIRE(common_view_lib.glsl)
+#pragma BLENDER_REQUIRE(eevee_velocity_lib.glsl)
+
+#define is_valid_output(img_) (imageSize(img_).x > 1)
+
+void main()
+{
+ ivec2 texel = ivec2(gl_GlobalInvocationID.xy);
+ vec4 motion = imageLoad(velocity_view_img, texel);
+
+ bool pixel_has_valid_motion = (motion.x != VELOCITY_INVALID);
+ float depth = texelFetch(depth_tx, texel, 0).r;
+ bool is_background = (depth == 1.0f);
+
+ vec2 uv = vec2(texel) * drw_view.viewport_size_inverse;
+ vec3 P_next, P_prev, P_curr;
+
+ if (pixel_has_valid_motion) {
+ /* Animated geometry. View motion already computed during prepass. Convert only to camera. */
+ // P_prev = get_world_space_from_depth(uv + motion.xy, 0.5);
+ // P_curr = get_world_space_from_depth(uv, 0.5);
+ // P_next = get_world_space_from_depth(uv + motion.zw, 0.5);
+ return;
+ }
+ else if (is_background) {
+ /* NOTE: Use viewCameraVec to avoid imprecision if camera is far from origin. */
+ vec3 vV = viewCameraVec(get_view_space_from_depth(uv, 1.0));
+ vec3 V = transform_direction(ViewMatrixInverse, vV);
+ /* Background has no motion under camera translation. Translate view vector with the camera. */
+ /* WATCH(fclem): Might create precision issues. */
+ P_next = camera_next.viewinv[3].xyz + V;
+ P_curr = camera_curr.viewinv[3].xyz + V;
+ P_prev = camera_prev.viewinv[3].xyz + V;
+ }
+ else {
+ /* Static geometry. No translation in world space. */
+ P_curr = get_world_space_from_depth(uv, depth);
+ P_prev = P_curr;
+ P_next = P_curr;
+ }
+
+ vec4 vel_camera, vel_view;
+ velocity_camera(P_prev, P_curr, P_next, vel_camera, vel_view);
+
+ if (in_texture_range(texel, depth_tx)) {
+ imageStore(velocity_view_img, texel, vel_view);
+
+ if (is_valid_output(velocity_camera_img)) {
+ imageStore(velocity_camera_img, texel, vel_camera);
+ }
+ }
+}
diff --git a/source/blender/draw/engines/eevee_next/shaders/infos/eevee_material_info.hh b/source/blender/draw/engines/eevee_next/shaders/infos/eevee_material_info.hh
index cd297de5719..a944bea402e 100644
--- a/source/blender/draw/engines/eevee_next/shaders/infos/eevee_material_info.hh
+++ b/source/blender/draw/engines/eevee_next/shaders/infos/eevee_material_info.hh
@@ -22,6 +22,7 @@ GPU_SHADER_CREATE_INFO(eevee_sampling_data)
* \{ */
GPU_SHADER_CREATE_INFO(eevee_geom_mesh)
+ .additional_info("eevee_shared")
.define("MAT_GEOM_MESH")
.vertex_in(0, Type::VEC3, "pos")
.vertex_in(1, Type::VEC3, "nor")
@@ -29,16 +30,22 @@ GPU_SHADER_CREATE_INFO(eevee_geom_mesh)
.additional_info("draw_mesh", "draw_resource_id_varying", "draw_resource_handle");
GPU_SHADER_CREATE_INFO(eevee_geom_gpencil)
+ .additional_info("eevee_shared")
.define("MAT_GEOM_GPENCIL")
.vertex_source("eevee_geom_gpencil_vert.glsl")
.additional_info("draw_gpencil", "draw_resource_id_varying", "draw_resource_handle");
GPU_SHADER_CREATE_INFO(eevee_geom_curves)
+ .additional_info("eevee_shared")
.define("MAT_GEOM_CURVES")
.vertex_source("eevee_geom_curves_vert.glsl")
- .additional_info("draw_hair", "draw_resource_id_varying", "draw_resource_handle");
+ .additional_info("draw_hair",
+ "draw_curves_infos",
+ "draw_resource_id_varying",
+ "draw_resource_handle");
GPU_SHADER_CREATE_INFO(eevee_geom_world)
+ .additional_info("eevee_shared")
.define("MAT_GEOM_WORLD")
.builtins(BuiltinBits::VERTEX_ID)
.vertex_source("eevee_geom_world_vert.glsl")
@@ -54,6 +61,7 @@ GPU_SHADER_INTERFACE_INFO(eevee_surf_iface, "interp")
.smooth(Type::VEC3, "P")
.smooth(Type::VEC3, "N")
.smooth(Type::VEC2, "barycentric_coords")
+ .smooth(Type::VEC3, "curves_tangent")
.smooth(Type::VEC3, "curves_binormal")
.smooth(Type::FLOAT, "curves_time")
.smooth(Type::FLOAT, "curves_time_width")
@@ -65,7 +73,7 @@ GPU_SHADER_INTERFACE_INFO(eevee_surf_iface, "interp")
GPU_SHADER_CREATE_INFO(eevee_surf_deferred)
.vertex_out(eevee_surf_iface)
- /* Note: This removes the possibility of using gl_FragDepth. */
+ /* NOTE: This removes the possibility of using gl_FragDepth. */
// .early_fragment_test(true)
/* Direct output. */
.fragment_out(0, Type::VEC4, "out_radiance", DualBlend::SRC_0)
@@ -161,7 +169,7 @@ GPU_SHADER_CREATE_INFO(eevee_material_stub).define("EEVEE_MATERIAL_STUBS");
# define EEVEE_MAT_GEOM_VARIATIONS(prefix, ...) \
EEVEE_MAT_FINAL_VARIATION(prefix##_world, "eevee_geom_world", __VA_ARGS__) \
EEVEE_MAT_FINAL_VARIATION(prefix##_gpencil, "eevee_geom_gpencil", __VA_ARGS__) \
- EEVEE_MAT_FINAL_VARIATION(prefix##_hair, "eevee_geom_curves", __VA_ARGS__) \
+ EEVEE_MAT_FINAL_VARIATION(prefix##_curves, "eevee_geom_curves", __VA_ARGS__) \
EEVEE_MAT_FINAL_VARIATION(prefix##_mesh, "eevee_geom_mesh", __VA_ARGS__)
# define EEVEE_MAT_PIPE_VARIATIONS(name, ...) \
diff --git a/source/blender/draw/engines/eevee_next/shaders/infos/eevee_velocity_info.hh b/source/blender/draw/engines/eevee_next/shaders/infos/eevee_velocity_info.hh
new file mode 100644
index 00000000000..a5f16363466
--- /dev/null
+++ b/source/blender/draw/engines/eevee_next/shaders/infos/eevee_velocity_info.hh
@@ -0,0 +1,55 @@
+
+#include "gpu_shader_create_info.hh"
+
+/* -------------------------------------------------------------------- */
+/** \name Surface Velocity
+ *
+ * Combined with the depth prepass shader.
+ * Outputs the view motion vectors for animated objects.
+ * \{ */
+
+/* Pass world space deltas to the fragment shader.
+ * This is to make sure that the resulting motion vectors are valid even with displacement. */
+GPU_SHADER_INTERFACE_INFO(eevee_velocity_surface_iface, "motion")
+ .smooth(Type::VEC3, "prev")
+ .smooth(Type::VEC3, "next");
+
+GPU_SHADER_CREATE_INFO(eevee_velocity_camera)
+ .define("VELOCITY_CAMERA")
+ .uniform_buf(1, "CameraData", "camera_prev")
+ .uniform_buf(2, "CameraData", "camera_curr")
+ .uniform_buf(3, "CameraData", "camera_next");
+
+GPU_SHADER_CREATE_INFO(eevee_velocity_geom)
+ .define("MAT_VELOCITY")
+ .auto_resource_location(true)
+ .storage_buf(4, Qualifier::READ, "mat4", "velocity_obj_prev_buf[]", Frequency::PASS)
+ .storage_buf(5, Qualifier::READ, "mat4", "velocity_obj_next_buf[]", Frequency::PASS)
+ .storage_buf(6, Qualifier::READ, "vec4", "velocity_geo_prev_buf[]", Frequency::PASS)
+ .storage_buf(7, Qualifier::READ, "vec4", "velocity_geo_next_buf[]", Frequency::PASS)
+ .storage_buf(
+ 7, Qualifier::READ, "VelocityIndex", "velocity_indirection_buf[]", Frequency::PASS)
+ .vertex_out(eevee_velocity_surface_iface)
+ .fragment_out(0, Type::VEC4, "out_velocity_view")
+ .additional_info("eevee_velocity_camera");
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Velocity Resolve
+ *
+ * Computes velocity for static objects.
+ * Also converts motion to camera space (as opposed to view space) if needed.
+ * \{ */
+
+GPU_SHADER_CREATE_INFO(eevee_velocity_resolve)
+ .do_static_compilation(true)
+ .local_group_size(8, 8)
+ .sampler(0, ImageType::DEPTH_2D, "depth_tx")
+ .image(0, GPU_RG16F, Qualifier::READ_WRITE, ImageType::FLOAT_2D, "velocity_view_img")
+ .image(1, GPU_RG16F, Qualifier::WRITE, ImageType::FLOAT_2D, "velocity_camera_img")
+ .additional_info("eevee_shared")
+ .compute_source("eevee_velocity_resolve_comp.glsl")
+ .additional_info("draw_view", "eevee_velocity_camera");
+
+/** \} */
diff --git a/source/blender/draw/engines/external/external_engine.c b/source/blender/draw/engines/external/external_engine.c
index 9f2f2b4b23d..b9c09e2bc4f 100644
--- a/source/blender/draw/engines/external/external_engine.c
+++ b/source/blender/draw/engines/external/external_engine.c
@@ -36,8 +36,8 @@
#define EXTERNAL_ENGINE "BLENDER_EXTERNAL"
-extern char datatoc_depth_frag_glsl[];
-extern char datatoc_depth_vert_glsl[];
+extern char datatoc_basic_depth_frag_glsl[];
+extern char datatoc_basic_depth_vert_glsl[];
extern char datatoc_common_view_lib_glsl[];
diff --git a/source/blender/draw/engines/gpencil/gpencil_cache_utils.c b/source/blender/draw/engines/gpencil/gpencil_cache_utils.c
index 40ebd262df5..ec44fdf42d5 100644
--- a/source/blender/draw/engines/gpencil/gpencil_cache_utils.c
+++ b/source/blender/draw/engines/gpencil/gpencil_cache_utils.c
@@ -290,7 +290,7 @@ GPENCIL_tLayer *gpencil_layer_cache_add(GPENCIL_PrivateData *pd,
/* Masking: Go through mask list and extract valid masks in a bitmap. */
if (is_masked) {
bool valid_mask = false;
- /* Warning: only GP_MAX_MASKBITS amount of bits.
+ /* WARNING: only #GP_MAX_MASKBITS amount of bits.
* TODO(fclem): Find a better system without any limitation. */
tgp_layer->mask_bits = BLI_memblock_alloc(pd->gp_maskbit_pool);
tgp_layer->mask_invert_bits = BLI_memblock_alloc(pd->gp_maskbit_pool);
diff --git a/source/blender/draw/engines/gpencil/gpencil_render.c b/source/blender/draw/engines/gpencil/gpencil_render.c
index 19afdb3de5a..c7ef8677336 100644
--- a/source/blender/draw/engines/gpencil/gpencil_render.c
+++ b/source/blender/draw/engines/gpencil/gpencil_render.c
@@ -61,10 +61,10 @@ void GPENCIL_render_init(GPENCIL_Data *vedata,
/* Depth need to be remapped to [0..1] range. */
pix_z = MEM_dupallocN(pix_z);
- int pix_ct = rpass_z_src->rectx * rpass_z_src->recty;
+ int pix_num = rpass_z_src->rectx * rpass_z_src->recty;
if (DRW_view_is_persp_get(view)) {
- for (int i = 0; i < pix_ct; i++) {
+ for (int i = 0; i < pix_num; i++) {
pix_z[i] = (-winmat[3][2] / -pix_z[i]) - winmat[2][2];
pix_z[i] = clamp_f(pix_z[i] * 0.5f + 0.5f, 0.0f, 1.0f);
}
@@ -74,7 +74,7 @@ void GPENCIL_render_init(GPENCIL_Data *vedata,
float near = DRW_view_near_distance_get(view);
float far = DRW_view_far_distance_get(view);
float range_inv = 1.0f / fabsf(far - near);
- for (int i = 0; i < pix_ct; i++) {
+ for (int i = 0; i < pix_num; i++) {
pix_z[i] = (pix_z[i] + near) * range_inv;
pix_z[i] = clamp_f(pix_z[i], 0.0f, 1.0f);
}
@@ -172,11 +172,11 @@ static void GPENCIL_render_result_z(struct RenderLayer *rl,
float winmat[4][4];
DRW_view_winmat_get(NULL, winmat, false);
- int pix_ct = BLI_rcti_size_x(rect) * BLI_rcti_size_y(rect);
+ int pix_num = BLI_rcti_size_x(rect) * BLI_rcti_size_y(rect);
/* Convert GPU depth [0..1] to view Z [near..far] */
if (DRW_view_is_persp_get(NULL)) {
- for (int i = 0; i < pix_ct; i++) {
+ for (int i = 0; i < pix_num; i++) {
if (rp->rect[i] == 1.0f) {
rp->rect[i] = 1e10f; /* Background */
}
@@ -192,7 +192,7 @@ static void GPENCIL_render_result_z(struct RenderLayer *rl,
float far = DRW_view_far_distance_get(NULL);
float range = fabsf(far - near);
- for (int i = 0; i < pix_ct; i++) {
+ for (int i = 0; i < pix_num; i++) {
if (rp->rect[i] == 1.0f) {
rp->rect[i] = 1e10f; /* Background */
}
diff --git a/source/blender/draw/engines/image/image_instance_data.hh b/source/blender/draw/engines/image/image_instance_data.hh
index cb84c7f14ad..358e6fd3bd9 100644
--- a/source/blender/draw/engines/image/image_instance_data.hh
+++ b/source/blender/draw/engines/image/image_instance_data.hh
@@ -75,8 +75,10 @@ struct IMAGE_InstanceData {
TextureInfo &info = texture_infos[i];
const bool is_allocated = info.texture != nullptr;
const bool is_visible = info.visible;
- const bool should_be_freed = !is_visible && is_allocated;
- const bool should_be_created = is_visible && !is_allocated;
+ const bool resolution_changed = assign_if_different(info.last_viewport_size,
+ float2(DRW_viewport_size_get()));
+ const bool should_be_freed = is_allocated && (!is_visible || resolution_changed);
+ const bool should_be_created = is_visible && (!is_allocated || resolution_changed);
if (should_be_freed) {
GPU_texture_free(info.texture);
diff --git a/source/blender/draw/engines/image/image_texture_info.hh b/source/blender/draw/engines/image/image_texture_info.hh
index cd51cdaff3c..9a75941c533 100644
--- a/source/blender/draw/engines/image/image_texture_info.hh
+++ b/source/blender/draw/engines/image/image_texture_info.hh
@@ -46,6 +46,8 @@ struct TextureInfo {
*/
GPUTexture *texture;
+ float2 last_viewport_size = float2(0.0f, 0.0f);
+
~TextureInfo()
{
if (batch != nullptr) {
diff --git a/source/blender/draw/engines/overlay/overlay_edit_uv.c b/source/blender/draw/engines/overlay/overlay_edit_uv.c
index acfd2f98044..4cfe9fcea4e 100644
--- a/source/blender/draw/engines/overlay/overlay_edit_uv.c
+++ b/source/blender/draw/engines/overlay/overlay_edit_uv.c
@@ -115,7 +115,7 @@ void OVERLAY_edit_uv_init(OVERLAY_Data *vedata)
const bool is_tiled_image = image && (image->source == IMA_SRC_TILED);
const bool do_edges_only = (ts->uv_flag & UV_SYNC_SELECTION) ?
/* NOTE: Ignore #SCE_SELECT_EDGE because a single selected edge
- * on the mesh may cause singe UV vertices to be selected. */
+ * on the mesh may cause single UV vertices to be selected. */
false :
(ts->uv_selectmode == UV_SELECT_EDGE);
const bool do_faces = ((sima->flag & SI_NO_DRAWFACES) == 0);
diff --git a/source/blender/draw/engines/overlay/overlay_extra.c b/source/blender/draw/engines/overlay/overlay_extra.c
index 5d8ba06e181..f875254a685 100644
--- a/source/blender/draw/engines/overlay/overlay_extra.c
+++ b/source/blender/draw/engines/overlay/overlay_extra.c
@@ -1310,13 +1310,11 @@ static void OVERLAY_relationship_lines(OVERLAY_ExtraCallBuffers *cb,
}
else {
const bConstraintTypeInfo *cti = BKE_constraint_typeinfo_get(curcon);
+ ListBase targets = {NULL, NULL};
- if ((cti && cti->get_constraint_targets) && (curcon->ui_expand_flag & (1 << 0))) {
- ListBase targets = {NULL, NULL};
+ if ((curcon->ui_expand_flag & (1 << 0)) && BKE_constraint_targets_get(curcon, &targets)) {
bConstraintTarget *ct;
- cti->get_constraint_targets(curcon, &targets);
-
for (ct = targets.first; ct; ct = ct->next) {
/* calculate target's matrix */
if (cti->get_target_matrix) {
@@ -1328,9 +1326,7 @@ static void OVERLAY_relationship_lines(OVERLAY_ExtraCallBuffers *cb,
OVERLAY_extra_line_dashed(cb, ct->matrix[3], ob->obmat[3], constraint_color);
}
- if (cti->flush_constraint_targets) {
- cti->flush_constraint_targets(curcon, &targets, 1);
- }
+ BKE_constraint_targets_flush(curcon, &targets, 1);
}
}
}
diff --git a/source/blender/draw/engines/overlay/overlay_gpencil.c b/source/blender/draw/engines/overlay/overlay_gpencil.c
index 072d32c41cd..9531b0dd983 100644
--- a/source/blender/draw/engines/overlay/overlay_gpencil.c
+++ b/source/blender/draw/engines/overlay/overlay_gpencil.c
@@ -297,7 +297,7 @@ void OVERLAY_gpencil_cache_init(OVERLAY_Data *vedata)
}
const int gridlines = (gpd->grid.lines <= 0) ? 1 : gpd->grid.lines;
- int line_ct = gridlines * 4 + 2;
+ const int line_count = gridlines * 4 + 2;
DRWState state = DRW_STATE_WRITE_COLOR | DRW_STATE_BLEND_ALPHA;
state |= (grid_xray) ? DRW_STATE_DEPTH_ALWAYS : DRW_STATE_DEPTH_LESS_EQUAL;
@@ -311,8 +311,8 @@ void OVERLAY_gpencil_cache_init(OVERLAY_Data *vedata)
DRW_shgroup_uniform_vec3_copy(grp, "xAxis", mat[0]);
DRW_shgroup_uniform_vec3_copy(grp, "yAxis", mat[1]);
DRW_shgroup_uniform_vec3_copy(grp, "origin", mat[3]);
- DRW_shgroup_uniform_int_copy(grp, "halfLineCount", line_ct / 2);
- DRW_shgroup_call_procedural_lines(grp, NULL, line_ct);
+ DRW_shgroup_uniform_int_copy(grp, "halfLineCount", line_count / 2);
+ DRW_shgroup_call_procedural_lines(grp, NULL, line_count);
}
}
diff --git a/source/blender/draw/engines/overlay/overlay_shader.c b/source/blender/draw/engines/overlay/overlay_shader.c
index d63ae6750d6..48146fbddfb 100644
--- a/source/blender/draw/engines/overlay/overlay_shader.c
+++ b/source/blender/draw/engines/overlay/overlay_shader.c
@@ -893,7 +893,7 @@ GPUShader *OVERLAY_shader_edit_uv_edges_get(void)
{
OVERLAY_Shaders *sh_data = &e_data.sh_data[0];
if (!sh_data->edit_uv_edges) {
- sh_data->edit_uv_edges = GPU_shader_create_from_info_name("overlay_edit_uv_edges_select");
+ sh_data->edit_uv_edges = GPU_shader_create_from_info_name("overlay_edit_uv_edges");
}
return sh_data->edit_uv_edges;
}
@@ -903,7 +903,7 @@ GPUShader *OVERLAY_shader_edit_uv_edges_for_edge_select_get(void)
OVERLAY_Shaders *sh_data = &e_data.sh_data[0];
if (!sh_data->edit_uv_edges_for_edge_select) {
sh_data->edit_uv_edges_for_edge_select = GPU_shader_create_from_info_name(
- "overlay_edit_uv_edges");
+ "overlay_edit_uv_edges_select");
}
return sh_data->edit_uv_edges_for_edge_select;
}
diff --git a/source/blender/draw/engines/overlay/overlay_shader_shared.h b/source/blender/draw/engines/overlay/overlay_shader_shared.h
index 99700cdcec4..339b6f02e1a 100644
--- a/source/blender/draw/engines/overlay/overlay_shader_shared.h
+++ b/source/blender/draw/engines/overlay/overlay_shader_shared.h
@@ -24,19 +24,19 @@ typedef struct OVERLAY_GridData OVERLAY_GridData;
#define BG_MASK 5
enum OVERLAY_GridBits {
- SHOW_AXIS_X = (1 << 0),
- SHOW_AXIS_Y = (1 << 1),
- SHOW_AXIS_Z = (1 << 2),
- SHOW_GRID = (1 << 3),
- PLANE_XY = (1 << 4),
- PLANE_XZ = (1 << 5),
- PLANE_YZ = (1 << 6),
- CLIP_ZPOS = (1 << 7),
- CLIP_ZNEG = (1 << 8),
- GRID_BACK = (1 << 9),
- GRID_CAMERA = (1 << 10),
- PLANE_IMAGE = (1 << 11),
- CUSTOM_GRID = (1 << 12),
+ SHOW_AXIS_X = (1u << 0u),
+ SHOW_AXIS_Y = (1u << 1u),
+ SHOW_AXIS_Z = (1u << 2u),
+ SHOW_GRID = (1u << 3u),
+ PLANE_XY = (1u << 4u),
+ PLANE_XZ = (1u << 5u),
+ PLANE_YZ = (1u << 6u),
+ CLIP_ZPOS = (1u << 7u),
+ CLIP_ZNEG = (1u << 8u),
+ GRID_BACK = (1u << 9u),
+ GRID_CAMERA = (1u << 10u),
+ PLANE_IMAGE = (1u << 11u),
+ CUSTOM_GRID = (1u << 12u),
};
/* Match: #SI_GRID_STEPS_LEN */
diff --git a/source/blender/draw/engines/overlay/shaders/infos/antialiasing_info.hh b/source/blender/draw/engines/overlay/shaders/infos/overlay_antialiasing_info.hh
index fe67dd473b7..0dba8b54e35 100644
--- a/source/blender/draw/engines/overlay/shaders/infos/antialiasing_info.hh
+++ b/source/blender/draw/engines/overlay/shaders/infos/overlay_antialiasing_info.hh
@@ -9,7 +9,7 @@ GPU_SHADER_CREATE_INFO(overlay_antialiasing)
.sampler(2, ImageType::FLOAT_2D, "lineTex")
.push_constant(Type::BOOL, "doSmoothLines")
.fragment_out(0, Type::VEC4, "fragColor")
- .fragment_source("antialiasing_frag.glsl")
+ .fragment_source("overlay_antialiasing_frag.glsl")
.additional_info("draw_fullscreen", "draw_globals");
GPU_SHADER_CREATE_INFO(overlay_xray_fade)
@@ -18,5 +18,5 @@ GPU_SHADER_CREATE_INFO(overlay_xray_fade)
.sampler(1, ImageType::DEPTH_2D, "xrayDepthTex")
.push_constant(Type::FLOAT, "opacity")
.fragment_out(0, Type::VEC4, "fragColor")
- .fragment_source("xray_fade_frag.glsl")
+ .fragment_source("overlay_xray_fade_frag.glsl")
.additional_info("draw_fullscreen");
diff --git a/source/blender/draw/engines/overlay/shaders/infos/armature_info.hh b/source/blender/draw/engines/overlay/shaders/infos/overlay_armature_info.hh
index d89272a50cf..9f2acceed97 100644
--- a/source/blender/draw/engines/overlay/shaders/infos/armature_info.hh
+++ b/source/blender/draw/engines/overlay/shaders/infos/overlay_armature_info.hh
@@ -25,8 +25,8 @@ GPU_SHADER_CREATE_INFO(overlay_armature_sphere_outline)
/* Per instance. */
.vertex_in(1, Type::MAT4, "inst_obmat")
.vertex_out(overlay_armature_wire_iface)
- .vertex_source("armature_sphere_outline_vert.glsl")
- .fragment_source("armature_wire_frag.glsl")
+ .vertex_source("overlay_armature_sphere_outline_vert.glsl")
+ .fragment_source("overlay_armature_wire_frag.glsl")
.additional_info("overlay_frag_output", "overlay_armature_common", "draw_globals");
GPU_SHADER_CREATE_INFO(overlay_armature_sphere_outline_clipped)
@@ -47,8 +47,8 @@ GPU_SHADER_CREATE_INFO(overlay_armature_sphere_solid)
.vertex_in(2, Type::MAT4, "inst_obmat")
// .depth_layout(DepthLayout::GREATER) /* TODO */
.vertex_out(overlay_armature_sphere_solid_iface)
- .vertex_source("armature_sphere_solid_vert.glsl")
- .fragment_source("armature_sphere_solid_frag.glsl")
+ .vertex_source("overlay_armature_sphere_solid_vert.glsl")
+ .fragment_source("overlay_armature_sphere_solid_frag.glsl")
.additional_info("overlay_frag_output", "overlay_armature_common", "draw_globals");
GPU_SHADER_CREATE_INFO(overlay_armature_sphere_solid_clipped)
@@ -79,9 +79,9 @@ GPU_SHADER_CREATE_INFO(overlay_armature_shape_outline)
.vertex_out(overlay_armature_shape_outline_iface)
.geometry_layout(PrimitiveIn::LINES_ADJACENCY, PrimitiveOut::LINE_STRIP, 2)
.geometry_out(overlay_armature_wire_iface)
- .vertex_source("armature_shape_outline_vert.glsl")
- .geometry_source("armature_shape_outline_geom.glsl")
- .fragment_source("armature_wire_frag.glsl")
+ .vertex_source("overlay_armature_shape_outline_vert.glsl")
+ .geometry_source("overlay_armature_shape_outline_geom.glsl")
+ .fragment_source("overlay_armature_wire_frag.glsl")
.additional_info("overlay_frag_output", "overlay_armature_common", "draw_globals");
GPU_SHADER_CREATE_INFO(overlay_armature_shape_outline_clipped)
@@ -100,8 +100,8 @@ GPU_SHADER_CREATE_INFO(overlay_armature_shape_solid)
.vertex_in(2, Type::MAT4, "inst_obmat")
.depth_write(DepthWrite::GREATER)
.vertex_out(overlay_armature_shape_solid_iface)
- .vertex_source("armature_shape_solid_vert.glsl")
- .fragment_source("armature_shape_solid_frag.glsl")
+ .vertex_source("overlay_armature_shape_solid_vert.glsl")
+ .fragment_source("overlay_armature_shape_solid_frag.glsl")
.additional_info("overlay_frag_output", "overlay_armature_common", "draw_globals");
GPU_SHADER_CREATE_INFO(overlay_armature_shape_solid_clipped)
@@ -115,8 +115,8 @@ GPU_SHADER_CREATE_INFO(overlay_armature_shape_wire)
/* Per instance. */
.vertex_in(2, Type::MAT4, "inst_obmat")
.vertex_out(overlay_armature_wire_iface)
- .vertex_source("armature_shape_wire_vert.glsl")
- .fragment_source("armature_wire_frag.glsl")
+ .vertex_source("overlay_armature_shape_wire_vert.glsl")
+ .fragment_source("overlay_armature_wire_frag.glsl")
.additional_info("overlay_frag_output", "overlay_armature_common", "draw_globals");
GPU_SHADER_CREATE_INFO(overlay_armature_shape_wire_clipped)
@@ -140,8 +140,8 @@ GPU_SHADER_CREATE_INFO(overlay_armature_envelope_outline)
.vertex_in(5, Type::VEC4, "outlineColorSize")
.vertex_in(6, Type::VEC3, "xAxis")
.vertex_out(overlay_armature_wire_iface)
- .vertex_source("armature_envelope_outline_vert.glsl")
- .fragment_source("armature_wire_frag.glsl")
+ .vertex_source("overlay_armature_envelope_outline_vert.glsl")
+ .fragment_source("overlay_armature_wire_frag.glsl")
.additional_info("overlay_frag_output", "overlay_armature_common", "draw_globals");
GPU_SHADER_CREATE_INFO(overlay_armature_envelope_outline_clipped)
@@ -164,8 +164,8 @@ GPU_SHADER_CREATE_INFO(overlay_armature_envelope_solid)
.vertex_in(5, Type::VEC3, "boneColor")
.vertex_out(overlay_armature_envelope_solid_iface)
.push_constant(Type::BOOL, "isDistance")
- .vertex_source("armature_envelope_solid_vert.glsl")
- .fragment_source("armature_envelope_solid_frag.glsl")
+ .vertex_source("overlay_armature_envelope_solid_vert.glsl")
+ .fragment_source("overlay_armature_envelope_solid_frag.glsl")
.additional_info("overlay_frag_output", "overlay_armature_common");
GPU_SHADER_CREATE_INFO(overlay_armature_envelope_solid_clipped)
@@ -198,8 +198,8 @@ GPU_SHADER_CREATE_INFO(overlay_armature_stick)
.vertex_in(7, Type::VEC4, "tailColor")
.define("do_wire", "(wireColor.a > 0.0)")
.vertex_out(overlay_armature_stick_iface)
- .vertex_source("armature_stick_vert.glsl")
- .fragment_source("armature_stick_frag.glsl")
+ .vertex_source("overlay_armature_stick_vert.glsl")
+ .fragment_source("overlay_armature_stick_frag.glsl")
.additional_info("overlay_frag_output", "overlay_armature_common", "draw_globals");
GPU_SHADER_CREATE_INFO(overlay_armature_stick_clipped)
@@ -218,12 +218,12 @@ GPU_SHADER_CREATE_INFO(overlay_armature_dof)
.vertex_in(1, Type::VEC4, "color")
.vertex_in(2, Type::MAT4, "inst_obmat")
.vertex_out(overlay_armature_wire_iface)
- .vertex_source("armature_dof_vert.glsl")
+ .vertex_source("overlay_armature_dof_vert.glsl")
.additional_info("overlay_frag_output", "overlay_armature_common", "draw_globals");
GPU_SHADER_CREATE_INFO(overlay_armature_dof_wire)
.do_static_compilation(true)
- .fragment_source("armature_dof_solid_frag.glsl")
+ .fragment_source("overlay_armature_dof_solid_frag.glsl")
.additional_info("overlay_armature_dof");
GPU_SHADER_CREATE_INFO(overlay_armature_dof_wire_clipped)
@@ -232,7 +232,7 @@ GPU_SHADER_CREATE_INFO(overlay_armature_dof_wire_clipped)
GPU_SHADER_CREATE_INFO(overlay_armature_dof_solid)
.do_static_compilation(true)
- .fragment_source("armature_dof_solid_frag.glsl")
+ .fragment_source("overlay_armature_dof_solid_frag.glsl")
.additional_info("overlay_armature_dof");
GPU_SHADER_CREATE_INFO(overlay_armature_dof_solid_clipped)
@@ -251,8 +251,8 @@ GPU_SHADER_CREATE_INFO(overlay_armature_wire)
.vertex_in(1, Type::VEC4, "color")
.push_constant(Type::FLOAT, "alpha")
.vertex_out(overlay_armature_wire_iface)
- .vertex_source("armature_wire_vert.glsl")
- .fragment_source("armature_wire_frag.glsl")
+ .vertex_source("overlay_armature_wire_vert.glsl")
+ .fragment_source("overlay_armature_wire_frag.glsl")
.additional_info("overlay_frag_output", "draw_mesh", "draw_globals");
GPU_SHADER_CREATE_INFO(overlay_armature_wire_clipped)
diff --git a/source/blender/draw/engines/overlay/shaders/infos/background_info.hh b/source/blender/draw/engines/overlay/shaders/infos/overlay_background_info.hh
index c96d302d861..88a012c35c9 100644
--- a/source/blender/draw/engines/overlay/shaders/infos/background_info.hh
+++ b/source/blender/draw/engines/overlay/shaders/infos/overlay_background_info.hh
@@ -9,17 +9,15 @@ GPU_SHADER_CREATE_INFO(overlay_background)
.sampler(1, ImageType::DEPTH_2D, "depthBuffer")
.push_constant(Type::INT, "bgType")
.push_constant(Type::VEC4, "colorOverride")
- .fragment_source("background_frag.glsl")
+ .fragment_source("overlay_background_frag.glsl")
.fragment_out(0, Type::VEC4, "fragColor")
.additional_info("draw_fullscreen", "draw_globals");
GPU_SHADER_CREATE_INFO(overlay_clipbound)
.do_static_compilation(true)
- /* NOTE: Color already in Linear space. Which is what we want. */
- .define("srgbTarget", "false")
.push_constant(Type::VEC4, "color")
.push_constant(Type::VEC3, "boundbox", 8)
- .vertex_source("clipbound_vert.glsl")
+ .vertex_source("overlay_clipbound_vert.glsl")
.fragment_out(0, Type::VEC4, "fragColor")
- .fragment_source("gpu_shader_uniform_color_frag.glsl")
+ .fragment_source("overlay_uniform_color_frag.glsl")
.additional_info("draw_view");
diff --git a/source/blender/draw/engines/overlay/shaders/infos/edit_mode_info.hh b/source/blender/draw/engines/overlay/shaders/infos/overlay_edit_mode_info.hh
index e6f15046838..58f96110887 100644
--- a/source/blender/draw/engines/overlay/shaders/infos/edit_mode_info.hh
+++ b/source/blender/draw/engines/overlay/shaders/infos/overlay_edit_mode_info.hh
@@ -19,7 +19,7 @@ GPU_SHADER_CREATE_INFO(overlay_edit_mesh_common)
.push_constant(Type::BOOL, "selectEdges")
.push_constant(Type::FLOAT, "alpha")
.push_constant(Type::IVEC4, "dataMask")
- .vertex_source("edit_mesh_vert.glsl")
+ .vertex_source("overlay_edit_mesh_vert.glsl")
.additional_info("draw_modelmat", "draw_globals");
GPU_SHADER_INTERFACE_INFO(overlay_edit_mesh_vert_iface, "")
@@ -29,13 +29,12 @@ GPU_SHADER_INTERFACE_INFO(overlay_edit_mesh_vert_iface, "")
GPU_SHADER_CREATE_INFO(overlay_edit_mesh_vert)
.do_static_compilation(true)
.builtins(BuiltinBits::POINT_SIZE)
- .define("srgbTarget", "false") /* Colors are already in linear space. */
.define("VERT")
.vertex_in(0, Type::VEC3, "pos")
.vertex_in(1, Type::IVEC4, "data")
.vertex_in(2, Type::VEC3, "vnor")
.vertex_out(overlay_edit_mesh_vert_iface)
- .fragment_source("gpu_shader_point_varying_color_frag.glsl")
+ .fragment_source("overlay_point_varying_color_frag.glsl")
.additional_info("overlay_edit_mesh_common");
GPU_SHADER_INTERFACE_INFO(overlay_edit_mesh_edge_iface, "geometry_in")
@@ -58,8 +57,8 @@ GPU_SHADER_CREATE_INFO(overlay_edit_mesh_edge)
.vertex_out(overlay_edit_mesh_edge_iface)
.geometry_out(overlay_edit_mesh_edge_geom_iface)
.geometry_layout(PrimitiveIn::LINES, PrimitiveOut::TRIANGLE_STRIP, 4)
- .geometry_source("edit_mesh_geom.glsl")
- .fragment_source("edit_mesh_frag.glsl")
+ .geometry_source("overlay_edit_mesh_geom.glsl")
+ .fragment_source("overlay_edit_mesh_frag.glsl")
.additional_info("overlay_edit_mesh_common");
GPU_SHADER_CREATE_INFO(overlay_edit_mesh_edge_flat)
@@ -69,13 +68,12 @@ GPU_SHADER_CREATE_INFO(overlay_edit_mesh_edge_flat)
GPU_SHADER_CREATE_INFO(overlay_edit_mesh_face)
.do_static_compilation(true)
- .define("srgbTarget", "false") /* Colors are already in linear space. */
.define("FACE")
.vertex_in(0, Type::VEC3, "pos")
.vertex_in(1, Type::IVEC4, "data")
.vertex_in(2, Type::VEC3, "vnor")
.vertex_out(overlay_edit_flat_color_iface)
- .fragment_source("gpu_shader_3D_smooth_color_frag.glsl")
+ .fragment_source("overlay_varying_color.glsl")
.additional_info("overlay_edit_mesh_common");
GPU_SHADER_CREATE_INFO(overlay_edit_mesh_facedot)
@@ -86,12 +84,11 @@ GPU_SHADER_CREATE_INFO(overlay_edit_mesh_facedot)
.vertex_in(2, Type::VEC4, "norAndFlag")
.define("vnor", "norAndFlag.xyz")
.vertex_out(overlay_edit_flat_color_iface)
- .fragment_source("gpu_shader_point_varying_color_frag.glsl")
+ .fragment_source("overlay_point_varying_color_frag.glsl")
.additional_info("overlay_edit_mesh_common");
GPU_SHADER_CREATE_INFO(overlay_edit_mesh_normal)
.do_static_compilation(true)
- .define("srgbTarget", "false") /* Colors are already in linear space. */
.vertex_in(0, Type::VEC3, "pos")
.vertex_in(1, Type::VEC4, "lnor")
.vertex_in(2, Type::VEC4, "vnor")
@@ -103,8 +100,8 @@ GPU_SHADER_CREATE_INFO(overlay_edit_mesh_normal)
.push_constant(Type::BOOL, "isConstantScreenSizeNormals")
.vertex_out(overlay_edit_flat_color_iface)
.fragment_out(0, Type::VEC4, "fragColor")
- .vertex_source("edit_mesh_normal_vert.glsl")
- .fragment_source("gpu_shader_flat_color_frag.glsl")
+ .vertex_source("overlay_edit_mesh_normal_vert.glsl")
+ .fragment_source("overlay_varying_color.glsl")
.additional_info("draw_modelmat_instanced_attr", "draw_globals");
GPU_SHADER_INTERFACE_INFO(overlay_edit_mesh_analysis_iface, "").smooth(Type::VEC4, "weightColor");
@@ -116,20 +113,19 @@ GPU_SHADER_CREATE_INFO(overlay_edit_mesh_analysis)
.sampler(0, ImageType::FLOAT_1D, "weightTex")
.fragment_out(0, Type::VEC4, "fragColor")
.vertex_out(overlay_edit_mesh_analysis_iface)
- .vertex_source("edit_mesh_analysis_vert.glsl")
- .fragment_source("edit_mesh_analysis_frag.glsl")
+ .vertex_source("overlay_edit_mesh_analysis_vert.glsl")
+ .fragment_source("overlay_edit_mesh_analysis_frag.glsl")
.additional_info("draw_modelmat");
GPU_SHADER_CREATE_INFO(overlay_edit_mesh_skin_root)
.do_static_compilation(true)
- .define("srgbTarget", "false") /* Colors are already in linear space. */
.vertex_in(0, Type::VEC3, "pos")
.vertex_in(1, Type::FLOAT, "size")
.vertex_in(2, Type::VEC3, "local_pos")
.vertex_out(overlay_edit_flat_color_iface)
.fragment_out(0, Type::VEC4, "fragColor")
- .vertex_source("edit_mesh_skin_root_vert.glsl")
- .fragment_source("gpu_shader_flat_color_frag.glsl")
+ .vertex_source("overlay_edit_mesh_skin_root_vert.glsl")
+ .fragment_source("overlay_varying_color.glsl")
.additional_info("draw_modelmat_instanced_attr", "draw_globals");
GPU_SHADER_CREATE_INFO(overlay_edit_mesh_vert_clipped)
@@ -193,9 +189,9 @@ GPU_SHADER_CREATE_INFO(overlay_edit_uv_edges)
.push_constant(Type::FLOAT, "alpha")
.push_constant(Type::FLOAT, "dashLength")
.fragment_out(0, Type::VEC4, "fragColor")
- .vertex_source("edit_uv_edges_vert.glsl")
- .geometry_source("edit_uv_edges_geom.glsl")
- .fragment_source("edit_uv_edges_frag.glsl")
+ .vertex_source("overlay_edit_uv_edges_vert.glsl")
+ .geometry_source("overlay_edit_uv_edges_geom.glsl")
+ .fragment_source("overlay_edit_uv_edges_frag.glsl")
.additional_info("draw_mesh", "draw_globals");
GPU_SHADER_CREATE_INFO(overlay_edit_uv_edges_select)
@@ -205,28 +201,24 @@ GPU_SHADER_CREATE_INFO(overlay_edit_uv_edges_select)
GPU_SHADER_CREATE_INFO(overlay_edit_uv_faces)
.do_static_compilation(true)
- /* NOTE: Color already in Linear space. Which is what we want. */
- .define("srgbTarget", "false")
.vertex_in(0, Type::VEC2, "au")
.vertex_in(1, Type::INT, "flag")
.push_constant(Type::FLOAT, "uvOpacity")
.vertex_out(overlay_edit_flat_color_iface)
.fragment_out(0, Type::VEC4, "fragColor")
- .vertex_source("edit_uv_faces_vert.glsl")
- .fragment_source("gpu_shader_flat_color_frag.glsl")
+ .vertex_source("overlay_edit_uv_faces_vert.glsl")
+ .fragment_source("overlay_varying_color.glsl")
.additional_info("draw_mesh", "draw_globals");
GPU_SHADER_CREATE_INFO(overlay_edit_uv_face_dots)
.do_static_compilation(true)
- /* NOTE: Color already in Linear space. Which is what we want. */
- .define("srgbTarget", "false")
.vertex_in(0, Type::VEC2, "au")
.vertex_in(1, Type::INT, "flag")
.push_constant(Type::FLOAT, "pointSize")
.vertex_out(overlay_edit_flat_color_iface)
.fragment_out(0, Type::VEC4, "fragColor")
- .vertex_source("edit_uv_face_dots_vert.glsl")
- .fragment_source("gpu_shader_flat_color_frag.glsl")
+ .vertex_source("overlay_edit_uv_face_dots_vert.glsl")
+ .fragment_source("overlay_varying_color.glsl")
.additional_info("draw_mesh", "draw_globals");
GPU_SHADER_INTERFACE_INFO(overlay_edit_uv_vert_iface, "")
@@ -236,8 +228,6 @@ GPU_SHADER_INTERFACE_INFO(overlay_edit_uv_vert_iface, "")
GPU_SHADER_CREATE_INFO(overlay_edit_uv_verts)
.do_static_compilation(true)
- /* NOTE: Color already in Linear space. Which is what we want. */
- .define("srgbTarget", "false")
.vertex_in(0, Type::VEC2, "au")
.vertex_in(1, Type::INT, "flag")
.push_constant(Type::FLOAT, "pointSize")
@@ -245,19 +235,17 @@ GPU_SHADER_CREATE_INFO(overlay_edit_uv_verts)
.push_constant(Type::VEC4, "color")
.vertex_out(overlay_edit_uv_vert_iface)
.fragment_out(0, Type::VEC4, "fragColor")
- .vertex_source("edit_uv_verts_vert.glsl")
- .fragment_source("edit_uv_verts_frag.glsl")
+ .vertex_source("overlay_edit_uv_verts_vert.glsl")
+ .fragment_source("overlay_edit_uv_verts_frag.glsl")
.additional_info("draw_mesh", "draw_globals");
GPU_SHADER_CREATE_INFO(overlay_edit_uv_tiled_image_borders)
.do_static_compilation(true)
- /* NOTE: Color already in Linear space. Which is what we want. */
- .define("srgbTarget", "false")
.vertex_in(0, Type::VEC3, "pos")
.push_constant(Type::VEC4, "color")
.fragment_out(0, Type::VEC4, "fragColor")
- .vertex_source("edit_uv_tiled_image_borders_vert.glsl")
- .fragment_source("gpu_shader_uniform_color_frag.glsl")
+ .vertex_source("overlay_edit_uv_tiled_image_borders_vert.glsl")
+ .fragment_source("overlay_uniform_color_frag.glsl")
.additional_info("draw_mesh");
GPU_SHADER_INTERFACE_INFO(edit_uv_image_iface, "").smooth(Type::VEC2, "uvs");
@@ -266,13 +254,13 @@ GPU_SHADER_CREATE_INFO(overlay_edit_uv_stencil_image)
.do_static_compilation(true)
.vertex_in(0, Type::VEC3, "pos")
.vertex_out(edit_uv_image_iface)
- .vertex_source("edit_uv_image_vert.glsl")
+ .vertex_source("overlay_edit_uv_image_vert.glsl")
.sampler(0, ImageType::FLOAT_2D, "imgTexture")
.push_constant(Type::BOOL, "imgPremultiplied")
.push_constant(Type::BOOL, "imgAlphaBlend")
.push_constant(Type::VEC4, "color")
.fragment_out(0, Type::VEC4, "fragColor")
- .fragment_source("image_frag.glsl")
+ .fragment_source("overlay_image_frag.glsl")
.additional_info("draw_mesh");
GPU_SHADER_CREATE_INFO(overlay_edit_uv_mask_image)
@@ -282,8 +270,8 @@ GPU_SHADER_CREATE_INFO(overlay_edit_uv_mask_image)
.sampler(0, ImageType::FLOAT_2D, "imgTexture")
.push_constant(Type::VEC4, "color")
.fragment_out(0, Type::VEC4, "fragColor")
- .vertex_source("edit_uv_image_vert.glsl")
- .fragment_source("edit_uv_image_mask_frag.glsl")
+ .vertex_source("overlay_edit_uv_image_vert.glsl")
+ .fragment_source("overlay_edit_uv_image_mask_frag.glsl")
.additional_info("draw_mesh");
/** \} */
@@ -293,14 +281,12 @@ GPU_SHADER_CREATE_INFO(overlay_edit_uv_mask_image)
* \{ */
GPU_SHADER_CREATE_INFO(overlay_edit_uv_stretching)
- /* NOTE: Color already in Linear space. Which is what we want. */
- .define("srgbTarget", "false")
.vertex_in(0, Type::VEC2, "pos")
.push_constant(Type::VEC2, "aspect")
.vertex_out(overlay_edit_nopersp_color_iface)
.fragment_out(0, Type::VEC4, "fragColor")
- .vertex_source("edit_uv_stretching_vert.glsl")
- .fragment_source("gpu_shader_2D_smooth_color_frag.glsl")
+ .vertex_source("overlay_edit_uv_stretching_vert.glsl")
+ .fragment_source("overlay_varying_color.glsl")
.additional_info("draw_mesh", "draw_globals");
GPU_SHADER_CREATE_INFO(overlay_edit_uv_stretching_area)
@@ -328,8 +314,6 @@ GPU_SHADER_INTERFACE_INFO(overlay_edit_curve_handle_iface, "vert").flat(Type::IN
GPU_SHADER_CREATE_INFO(overlay_edit_curve_handle)
.do_static_compilation(true)
.typedef_source("overlay_shader_shared.h")
- /* NOTE: Color already in Linear space. Which is what we want. */
- .define("srgbTarget", "false")
.vertex_in(0, Type::VEC3, "pos")
.vertex_in(1, Type::INT, "data")
.vertex_out(overlay_edit_curve_handle_iface)
@@ -338,9 +322,9 @@ GPU_SHADER_CREATE_INFO(overlay_edit_curve_handle)
.push_constant(Type::BOOL, "showCurveHandles")
.push_constant(Type::INT, "curveHandleDisplay")
.fragment_out(0, Type::VEC4, "fragColor")
- .vertex_source("edit_curve_handle_vert.glsl")
- .geometry_source("edit_curve_handle_geom.glsl")
- .fragment_source("gpu_shader_3D_smooth_color_frag.glsl")
+ .vertex_source("overlay_edit_curve_handle_vert.glsl")
+ .geometry_source("overlay_edit_curve_handle_geom.glsl")
+ .fragment_source("overlay_varying_color.glsl")
.additional_info("draw_mesh", "draw_globals");
GPU_SHADER_CREATE_INFO(overlay_edit_curve_handle_clipped)
@@ -350,16 +334,14 @@ GPU_SHADER_CREATE_INFO(overlay_edit_curve_handle_clipped)
GPU_SHADER_CREATE_INFO(overlay_edit_curve_point)
.do_static_compilation(true)
.typedef_source("overlay_shader_shared.h")
- /* NOTE: Color already in Linear space. Which is what we want. */
- .define("srgbTarget", "false")
.vertex_in(0, Type::VEC3, "pos")
.vertex_in(1, Type::INT, "data")
.vertex_out(overlay_edit_flat_color_iface)
.push_constant(Type::BOOL, "showCurveHandles")
.push_constant(Type::INT, "curveHandleDisplay")
.fragment_out(0, Type::VEC4, "fragColor")
- .vertex_source("edit_curve_point_vert.glsl")
- .fragment_source("gpu_shader_point_varying_color_frag.glsl")
+ .vertex_source("overlay_edit_curve_point_vert.glsl")
+ .fragment_source("overlay_point_varying_color_frag.glsl")
.additional_info("draw_mesh", "draw_globals");
GPU_SHADER_CREATE_INFO(overlay_edit_curve_point_clipped)
@@ -368,8 +350,6 @@ GPU_SHADER_CREATE_INFO(overlay_edit_curve_point_clipped)
GPU_SHADER_CREATE_INFO(overlay_edit_curve_wire)
.do_static_compilation(true)
- /* NOTE: Color already in Linear space. Which is what we want. */
- .define("srgbTarget", "false")
.vertex_in(0, Type::VEC3, "pos")
.vertex_in(1, Type::VEC3, "nor")
.vertex_in(2, Type::VEC3, "tan")
@@ -377,8 +357,8 @@ GPU_SHADER_CREATE_INFO(overlay_edit_curve_wire)
.push_constant(Type::FLOAT, "normalSize")
.vertex_out(overlay_edit_flat_color_iface)
.fragment_out(0, Type::VEC4, "fragColor")
- .vertex_source("edit_curve_wire_vert.glsl")
- .fragment_source("gpu_shader_flat_color_frag.glsl")
+ .vertex_source("overlay_edit_curve_wire_vert.glsl")
+ .fragment_source("overlay_varying_color.glsl")
.additional_info("draw_modelmat", "draw_resource_id_uniform", "draw_globals");
GPU_SHADER_CREATE_INFO(overlay_edit_curve_wire_clipped)
@@ -393,14 +373,12 @@ GPU_SHADER_CREATE_INFO(overlay_edit_curve_wire_clipped)
GPU_SHADER_CREATE_INFO(overlay_edit_lattice_point)
.do_static_compilation(true)
- /* NOTE: Color already in Linear space. Which is what we want. */
- .define("srgbTarget", "false")
.vertex_in(0, Type::VEC3, "pos")
.vertex_in(1, Type::INT, "data")
.vertex_out(overlay_edit_flat_color_iface)
.fragment_out(0, Type::VEC4, "fragColor")
- .vertex_source("edit_lattice_point_vert.glsl")
- .fragment_source("gpu_shader_point_varying_color_frag.glsl")
+ .vertex_source("overlay_edit_lattice_point_vert.glsl")
+ .fragment_source("overlay_point_varying_color_frag.glsl")
.additional_info("draw_mesh", "draw_globals");
GPU_SHADER_CREATE_INFO(overlay_edit_lattice_point_clipped)
@@ -409,15 +387,13 @@ GPU_SHADER_CREATE_INFO(overlay_edit_lattice_point_clipped)
GPU_SHADER_CREATE_INFO(overlay_edit_lattice_wire)
.do_static_compilation(true)
- /* NOTE: Color already in Linear space. Which is what we want. */
- .define("srgbTarget", "false")
.vertex_in(0, Type::VEC3, "pos")
.vertex_in(1, Type::FLOAT, "weight")
.sampler(0, ImageType::FLOAT_1D, "weightTex")
.vertex_out(overlay_edit_smooth_color_iface)
.fragment_out(0, Type::VEC4, "fragColor")
- .vertex_source("edit_lattice_wire_vert.glsl")
- .fragment_source("gpu_shader_3D_smooth_color_frag.glsl")
+ .vertex_source("overlay_edit_lattice_wire_vert.glsl")
+ .fragment_source("overlay_varying_color.glsl")
.additional_info("draw_mesh", "draw_globals");
GPU_SHADER_CREATE_INFO(overlay_edit_lattice_wire_clipped)
@@ -432,16 +408,14 @@ GPU_SHADER_CREATE_INFO(overlay_edit_lattice_wire_clipped)
GPU_SHADER_CREATE_INFO(overlay_edit_particle_strand)
.do_static_compilation(true)
- /* NOTE: Color already in Linear space. Which is what we want. */
- .define("srgbTarget", "false")
.vertex_in(0, Type::VEC3, "pos")
.vertex_in(1, Type::FLOAT, "color")
.sampler(0, ImageType::FLOAT_1D, "weightTex")
.push_constant(Type::BOOL, "useWeight")
.vertex_out(overlay_edit_smooth_color_iface)
.fragment_out(0, Type::VEC4, "fragColor")
- .vertex_source("edit_particle_strand_vert.glsl")
- .fragment_source("gpu_shader_3D_smooth_color_frag.glsl")
+ .vertex_source("overlay_edit_particle_strand_vert.glsl")
+ .fragment_source("overlay_varying_color.glsl")
.additional_info("draw_mesh", "draw_globals");
GPU_SHADER_CREATE_INFO(overlay_edit_particle_strand_clipped)
@@ -450,14 +424,12 @@ GPU_SHADER_CREATE_INFO(overlay_edit_particle_strand_clipped)
GPU_SHADER_CREATE_INFO(overlay_edit_particle_point)
.do_static_compilation(true)
- /* NOTE: Color already in Linear space. Which is what we want. */
- .define("srgbTarget", "false")
.vertex_in(0, Type::VEC3, "pos")
.vertex_in(1, Type::FLOAT, "color")
.vertex_out(overlay_edit_flat_color_iface)
.fragment_out(0, Type::VEC4, "fragColor")
- .vertex_source("edit_particle_point_vert.glsl")
- .fragment_source("gpu_shader_point_varying_color_frag.glsl")
+ .vertex_source("overlay_edit_particle_point_vert.glsl")
+ .fragment_source("overlay_point_varying_color_frag.glsl")
.additional_info("draw_mesh", "draw_globals");
GPU_SHADER_CREATE_INFO(overlay_edit_particle_point_clipped)
@@ -472,8 +444,6 @@ GPU_SHADER_CREATE_INFO(overlay_edit_particle_point_clipped)
GPU_SHADER_CREATE_INFO(overlay_edit_gpencil)
.typedef_source("overlay_shader_shared.h")
- /* NOTE: Color already in Linear space. Which is what we want. */
- .define("srgbTarget", "false")
.vertex_in(0, Type::VEC3, "pos")
.vertex_in(1, Type::INT, "ma")
.vertex_in(2, Type::UINT, "vflag")
@@ -487,13 +457,13 @@ GPU_SHADER_CREATE_INFO(overlay_edit_gpencil)
.push_constant(Type::VEC4, "gpEditColor")
.sampler(0, ImageType::FLOAT_1D, "weightTex")
.fragment_out(0, Type::VEC4, "fragColor")
- .vertex_source("edit_gpencil_vert.glsl")
+ .vertex_source("overlay_edit_gpencil_vert.glsl")
.additional_info("draw_mesh", "draw_globals");
GPU_SHADER_CREATE_INFO(overlay_edit_gpencil_wire)
.do_static_compilation(true)
.vertex_out(overlay_edit_smooth_color_iface)
- .fragment_source("gpu_shader_3D_smooth_color_frag.glsl")
+ .fragment_source("overlay_varying_color.glsl")
.additional_info("overlay_edit_gpencil");
GPU_SHADER_CREATE_INFO(overlay_edit_gpencil_wire_clipped)
@@ -504,7 +474,7 @@ GPU_SHADER_CREATE_INFO(overlay_edit_gpencil_point)
.do_static_compilation(true)
.define("USE_POINTS")
.vertex_out(overlay_edit_flat_color_iface)
- .fragment_source("gpu_shader_point_varying_color_frag.glsl")
+ .fragment_source("overlay_point_varying_color_frag.glsl")
.additional_info("overlay_edit_gpencil");
GPU_SHADER_CREATE_INFO(overlay_edit_gpencil_point_clipped)
@@ -514,8 +484,6 @@ GPU_SHADER_CREATE_INFO(overlay_edit_gpencil_point_clipped)
/* TODO(fclem): Refactor this to take list of point instead of drawing 1 point per drawcall. */
GPU_SHADER_CREATE_INFO(overlay_edit_gpencil_guide_point)
.do_static_compilation(true)
- /* NOTE: Color already in Linear space. Which is what we want. */
- .define("srgbTarget", "false")
.vertex_in(0, Type::VEC3, "pos")
.vertex_in(1, Type::INT, "data")
.vertex_out(overlay_edit_flat_color_iface)
@@ -523,8 +491,8 @@ GPU_SHADER_CREATE_INFO(overlay_edit_gpencil_guide_point)
.push_constant(Type::FLOAT, "pSize")
.push_constant(Type::VEC4, "pColor")
.fragment_out(0, Type::VEC4, "fragColor")
- .vertex_source("edit_gpencil_guide_vert.glsl")
- .fragment_source("gpu_shader_point_varying_color_frag.glsl")
+ .vertex_source("overlay_edit_gpencil_guide_vert.glsl")
+ .fragment_source("overlay_point_varying_color_frag.glsl")
.additional_info("draw_mesh", "draw_globals");
GPU_SHADER_CREATE_INFO(overlay_edit_gpencil_guide_point_clipped)
@@ -542,8 +510,8 @@ GPU_SHADER_CREATE_INFO(overlay_edit_gpencil_guide_point_clipped)
GPU_SHADER_CREATE_INFO(overlay_depth_only)
.do_static_compilation(true)
.vertex_in(0, Type::VEC3, "pos")
- .vertex_source("depth_only_vert.glsl")
- .fragment_source("gpu_shader_depth_only_frag.glsl")
+ .vertex_source("overlay_depth_only_vert.glsl")
+ .fragment_source("overlay_depth_only_frag.glsl")
.additional_info("draw_mesh");
GPU_SHADER_CREATE_INFO(overlay_depth_only_clipped)
@@ -558,13 +526,11 @@ GPU_SHADER_CREATE_INFO(overlay_depth_only_clipped)
GPU_SHADER_CREATE_INFO(overlay_uniform_color)
.do_static_compilation(true)
- /* NOTE: Color already in Linear space. Which is what we want. */
- .define("srgbTarget", "false")
.vertex_in(0, Type::VEC3, "pos")
.push_constant(Type::VEC4, "color")
.fragment_out(0, Type::VEC4, "fragColor")
- .vertex_source("depth_only_vert.glsl")
- .fragment_source("gpu_shader_uniform_color_frag.glsl")
+ .vertex_source("overlay_depth_only_vert.glsl")
+ .fragment_source("overlay_uniform_color_frag.glsl")
.additional_info("draw_mesh");
GPU_SHADER_CREATE_INFO(overlay_uniform_color_clipped)
diff --git a/source/blender/draw/engines/overlay/shaders/infos/extra_info.hh b/source/blender/draw/engines/overlay/shaders/infos/overlay_extra_info.hh
index b9b1b73dbd4..5b50bbcaa55 100644
--- a/source/blender/draw/engines/overlay/shaders/infos/extra_info.hh
+++ b/source/blender/draw/engines/overlay/shaders/infos/overlay_extra_info.hh
@@ -21,8 +21,8 @@ GPU_SHADER_CREATE_INFO(overlay_extra)
.vertex_out(overlay_extra_iface)
.fragment_out(0, Type::VEC4, "fragColor")
.fragment_out(1, Type::VEC4, "lineOutput")
- .vertex_source("extra_vert.glsl")
- .fragment_source("extra_frag.glsl")
+ .vertex_source("overlay_extra_vert.glsl")
+ .fragment_source("overlay_extra_frag.glsl")
.additional_info("draw_view", "draw_globals");
GPU_SHADER_CREATE_INFO(overlay_extra_select)
@@ -53,8 +53,8 @@ GPU_SHADER_CREATE_INFO(overlay_extra_grid)
.push_constant(Type::BOOL, "isTransform")
.vertex_out(overlay_extra_grid_iface)
.fragment_out(0, Type::VEC4, "fragColor")
- .vertex_source("extra_lightprobe_grid_vert.glsl")
- .fragment_source("gpu_shader_point_varying_color_frag.glsl")
+ .vertex_source("overlay_extra_lightprobe_grid_vert.glsl")
+ .fragment_source("overlay_point_varying_color_frag.glsl")
.additional_info("draw_view", "draw_globals");
GPU_SHADER_CREATE_INFO(overlay_extra_grid_clipped)
@@ -75,8 +75,8 @@ GPU_SHADER_CREATE_INFO(overlay_extra_groundline)
.vertex_out(overlay_extra_iface)
.fragment_out(0, Type::VEC4, "fragColor")
.fragment_out(1, Type::VEC4, "lineOutput")
- .vertex_source("extra_groundline_vert.glsl")
- .fragment_source("extra_frag.glsl")
+ .vertex_source("overlay_extra_groundline_vert.glsl")
+ .fragment_source("overlay_extra_frag.glsl")
.additional_info("draw_view", "draw_globals");
GPU_SHADER_CREATE_INFO(overlay_extra_groundline_clipped)
@@ -103,8 +103,8 @@ GPU_SHADER_CREATE_INFO(overlay_extra_wire)
.vertex_out(overlay_extra_wire_iface)
.fragment_out(0, Type::VEC4, "fragColor")
.fragment_out(1, Type::VEC4, "lineOutput")
- .vertex_source("extra_wire_vert.glsl")
- .fragment_source("extra_wire_frag.glsl")
+ .vertex_source("overlay_extra_wire_vert.glsl")
+ .fragment_source("overlay_extra_wire_frag.glsl")
.additional_info("draw_modelmat", "draw_globals");
GPU_SHADER_CREATE_INFO(overlay_extra_wire_select)
@@ -148,8 +148,8 @@ GPU_SHADER_CREATE_INFO(overlay_extra_point)
.push_constant(Type::VEC4, "color")
.vertex_out(overlay_extra_point_iface)
.fragment_out(0, Type::VEC4, "fragColor")
- .vertex_source("extra_point_vert.glsl")
- .fragment_source("gpu_shader_point_varying_color_varying_outline_aa_frag.glsl")
+ .vertex_source("overlay_extra_point_vert.glsl")
+ .fragment_source("overlay_point_varying_color_varying_outline_aa_frag.glsl")
.additional_info("draw_modelmat", "draw_globals");
GPU_SHADER_CREATE_INFO(overlay_extra_point_clipped)
@@ -165,8 +165,8 @@ GPU_SHADER_CREATE_INFO(overlay_extra_loose_point)
.vertex_out(overlay_extra_loose_point_iface)
.fragment_out(0, Type::VEC4, "fragColor")
.fragment_out(1, Type::VEC4, "lineOutput")
- .vertex_source("extra_loose_point_vert.glsl")
- .fragment_source("extra_loose_point_frag.glsl")
+ .vertex_source("overlay_extra_loose_point_vert.glsl")
+ .fragment_source("overlay_extra_loose_point_frag.glsl")
.additional_info("draw_modelmat", "draw_globals");
GPU_SHADER_CREATE_INFO(overlay_extra_loose_point_clipped)
@@ -194,9 +194,9 @@ GPU_SHADER_CREATE_INFO(overlay_motion_path_line)
.geometry_out(overlay_motion_path_line_iface)
.geometry_layout(PrimitiveIn::LINES, PrimitiveOut::TRIANGLE_STRIP, 4)
.fragment_out(0, Type::VEC4, "fragColor")
- .vertex_source("motion_path_line_vert.glsl")
- .geometry_source("motion_path_line_geom.glsl")
- .fragment_source("motion_path_line_frag.glsl")
+ .vertex_source("overlay_motion_path_line_vert.glsl")
+ .geometry_source("overlay_motion_path_line_geom.glsl")
+ .fragment_source("overlay_motion_path_line_frag.glsl")
.additional_info("draw_view", "draw_globals");
GPU_SHADER_CREATE_INFO(overlay_motion_path_line_clipped)
@@ -215,8 +215,8 @@ GPU_SHADER_CREATE_INFO(overlay_motion_path_point)
.push_constant(Type::VEC3, "customColor")
.vertex_out(overlay_motion_path_point_iface)
.fragment_out(0, Type::VEC4, "fragColor")
- .vertex_source("motion_path_point_vert.glsl")
- .fragment_source("gpu_shader_point_varying_color_frag.glsl")
+ .vertex_source("overlay_motion_path_point_vert.glsl")
+ .fragment_source("overlay_point_varying_color_frag.glsl")
.additional_info("draw_view", "draw_globals");
GPU_SHADER_CREATE_INFO(overlay_motion_path_point_clipped)
@@ -242,8 +242,8 @@ GPU_SHADER_CREATE_INFO(overlay_image)
.vertex_out(overlay_image_iface)
.sampler(0, ImageType::FLOAT_2D, "imgTexture")
.fragment_out(0, Type::VEC4, "fragColor")
- .vertex_source("image_vert.glsl")
- .fragment_source("image_frag.glsl")
+ .vertex_source("overlay_image_vert.glsl")
+ .fragment_source("overlay_image_frag.glsl")
.additional_info("draw_mesh");
GPU_SHADER_CREATE_INFO(overlay_image_clipped)
@@ -266,8 +266,8 @@ GPU_SHADER_CREATE_INFO(overlay_gpencil_canvas)
.push_constant(Type::INT, "halfLineCount")
.fragment_out(0, Type::VEC4, "fragColor")
.fragment_out(1, Type::VEC4, "lineOutput")
- .vertex_source("edit_gpencil_canvas_vert.glsl")
- .fragment_source("extra_frag.glsl")
+ .vertex_source("overlay_edit_gpencil_canvas_vert.glsl")
+ .fragment_source("overlay_extra_frag.glsl")
.additional_info("draw_mesh", "draw_globals");
GPU_SHADER_CREATE_INFO(overlay_gpencil_canvas_clipped)
@@ -289,7 +289,7 @@ GPU_SHADER_CREATE_INFO(overlay_particle)
.vertex_in(1, Type::VEC4, "part_rot")
.vertex_in(2, Type::FLOAT, "part_val")
.vertex_out(overlay_particle_iface)
- .vertex_source("particle_vert.glsl")
+ .vertex_source("overlay_particle_vert.glsl")
.additional_info("draw_globals");
GPU_SHADER_CREATE_INFO(overlay_particle_dot)
@@ -299,7 +299,7 @@ GPU_SHADER_CREATE_INFO(overlay_particle_dot)
.define("pos", "vec3(0.0)")
.fragment_out(0, Type::VEC4, "fragColor")
.fragment_out(1, Type::VEC4, "lineOutput")
- .fragment_source("particle_frag.glsl")
+ .fragment_source("overlay_particle_frag.glsl")
.additional_info("overlay_particle", "draw_mesh");
GPU_SHADER_CREATE_INFO(overlay_particle_dot_clipped)
@@ -308,13 +308,11 @@ GPU_SHADER_CREATE_INFO(overlay_particle_dot_clipped)
GPU_SHADER_CREATE_INFO(overlay_particle_shape)
.do_static_compilation(true)
- /* NOTE: Color already in Linear space. Which is what we want. */
- .define("srgbTarget", "false")
/* Instantiated Attrs. */
.vertex_in(3, Type::VEC3, "pos")
.vertex_in(4, Type::INT, "vclass")
.fragment_out(0, Type::VEC4, "fragColor")
- .fragment_source("gpu_shader_flat_color_frag.glsl")
+ .fragment_source("overlay_varying_color.glsl")
.additional_info("overlay_particle", "draw_modelmat", "draw_resource_id_uniform");
GPU_SHADER_CREATE_INFO(overlay_particle_shape_clipped)
diff --git a/source/blender/draw/engines/overlay/shaders/infos/facing_info.hh b/source/blender/draw/engines/overlay/shaders/infos/overlay_facing_info.hh
index 6d6806eaa80..6d528bbba62 100644
--- a/source/blender/draw/engines/overlay/shaders/infos/facing_info.hh
+++ b/source/blender/draw/engines/overlay/shaders/infos/overlay_facing_info.hh
@@ -5,8 +5,8 @@
GPU_SHADER_CREATE_INFO(overlay_facing)
.do_static_compilation(true)
.vertex_in(0, Type::VEC3, "pos")
- .vertex_source("facing_vert.glsl")
- .fragment_source("facing_frag.glsl")
+ .vertex_source("overlay_facing_vert.glsl")
+ .fragment_source("overlay_facing_frag.glsl")
.fragment_out(0, Type::VEC4, "fragColor")
.additional_info("draw_mesh", "draw_globals");
diff --git a/source/blender/draw/engines/overlay/shaders/infos/grid_info.hh b/source/blender/draw/engines/overlay/shaders/infos/overlay_grid_info.hh
index d02014c98a0..a8f1281d53a 100644
--- a/source/blender/draw/engines/overlay/shaders/infos/grid_info.hh
+++ b/source/blender/draw/engines/overlay/shaders/infos/overlay_grid_info.hh
@@ -15,8 +15,8 @@ GPU_SHADER_CREATE_INFO(overlay_grid)
.uniform_buf(3, "OVERLAY_GridData", "grid_buf")
.push_constant(Type::VEC3, "plane_axes")
.push_constant(Type::INT, "grid_flag")
- .vertex_source("grid_vert.glsl")
- .fragment_source("grid_frag.glsl")
+ .vertex_source("overlay_grid_vert.glsl")
+ .fragment_source("overlay_grid_frag.glsl")
.additional_info("draw_view", "draw_globals");
GPU_SHADER_CREATE_INFO(overlay_grid_background)
@@ -25,17 +25,15 @@ GPU_SHADER_CREATE_INFO(overlay_grid_background)
.sampler(0, ImageType::DEPTH_2D, "depthBuffer")
.push_constant(Type::VEC4, "color")
.fragment_out(0, Type::VEC4, "fragColor")
- .vertex_source("edit_uv_tiled_image_borders_vert.glsl")
- .fragment_source("grid_background_frag.glsl")
+ .vertex_source("overlay_edit_uv_tiled_image_borders_vert.glsl")
+ .fragment_source("overlay_grid_background_frag.glsl")
.additional_info("draw_modelmat");
GPU_SHADER_CREATE_INFO(overlay_grid_image)
.do_static_compilation(true)
- /* NOTE: Color already in Linear space. Which is what we want. */
- .define("srgbTarget", "false")
.vertex_in(0, Type::VEC3, "pos")
.push_constant(Type::VEC4, "color")
.fragment_out(0, Type::VEC4, "fragColor")
- .vertex_source("edit_uv_tiled_image_borders_vert.glsl")
- .fragment_source("gpu_shader_uniform_color_frag.glsl")
+ .vertex_source("overlay_edit_uv_tiled_image_borders_vert.glsl")
+ .fragment_source("overlay_uniform_color_frag.glsl")
.additional_info("draw_modelmat");
diff --git a/source/blender/draw/engines/overlay/shaders/infos/outline_info.hh b/source/blender/draw/engines/overlay/shaders/infos/overlay_outline_info.hh
index 21575747efa..6f6a9c1622d 100644
--- a/source/blender/draw/engines/overlay/shaders/infos/outline_info.hh
+++ b/source/blender/draw/engines/overlay/shaders/infos/overlay_outline_info.hh
@@ -13,13 +13,13 @@ GPU_SHADER_CREATE_INFO(overlay_outline_prepass)
.vertex_out(overlay_outline_prepass_iface)
/* Using uint because 16bit uint can contain more ids than int. */
.fragment_out(0, Type::UINT, "out_object_id")
- .fragment_source("outline_prepass_frag.glsl")
+ .fragment_source("overlay_outline_prepass_frag.glsl")
.additional_info("draw_resource_handle");
GPU_SHADER_CREATE_INFO(overlay_outline_prepass_mesh)
.do_static_compilation(true)
.vertex_in(0, Type::VEC3, "pos")
- .vertex_source("outline_prepass_vert.glsl")
+ .vertex_source("overlay_outline_prepass_vert.glsl")
.additional_info("draw_mesh", "overlay_outline_prepass")
.additional_info("draw_object_infos");
@@ -36,8 +36,8 @@ GPU_SHADER_CREATE_INFO(overlay_outline_prepass_wire)
.vertex_out(overlay_outline_prepass_wire_iface)
.geometry_layout(PrimitiveIn::LINES_ADJACENCY, PrimitiveOut::LINE_STRIP, 2)
.geometry_out(overlay_outline_prepass_iface)
- .vertex_source("outline_prepass_vert.glsl")
- .geometry_source("outline_prepass_geom.glsl")
+ .vertex_source("overlay_outline_prepass_vert.glsl")
+ .geometry_source("overlay_outline_prepass_geom.glsl")
.additional_info("draw_mesh", "overlay_outline_prepass")
.additional_info("draw_object_infos");
@@ -56,12 +56,12 @@ GPU_SHADER_CREATE_INFO(overlay_outline_prepass_gpencil)
.push_constant(Type::BOOL, "isTransform")
.vertex_out(overlay_outline_prepass_iface)
.vertex_out(overlay_outline_prepass_gpencil_iface)
- .vertex_source("outline_prepass_gpencil_vert.glsl")
+ .vertex_source("overlay_outline_prepass_gpencil_vert.glsl")
.push_constant(Type::BOOL, "gpStrokeOrder3d") /* TODO(fclem): Move to a GPencil object UBO. */
.push_constant(Type::VEC4, "gpDepthPlane") /* TODO(fclem): Move to a GPencil object UBO. */
/* Using uint because 16bit uint can contain more ids than int. */
.fragment_out(0, Type::UINT, "out_object_id")
- .fragment_source("outline_prepass_gpencil_frag.glsl")
+ .fragment_source("overlay_outline_prepass_gpencil_frag.glsl")
.additional_info("draw_gpencil", "draw_resource_handle");
GPU_SHADER_CREATE_INFO(overlay_outline_prepass_gpencil_clipped)
@@ -70,7 +70,7 @@ GPU_SHADER_CREATE_INFO(overlay_outline_prepass_gpencil_clipped)
GPU_SHADER_CREATE_INFO(overlay_outline_prepass_pointcloud)
.do_static_compilation(true)
- .vertex_source("outline_prepass_pointcloud_vert.glsl")
+ .vertex_source("overlay_outline_prepass_pointcloud_vert.glsl")
.additional_info("draw_pointcloud", "overlay_outline_prepass")
.additional_info("draw_object_infos");
@@ -95,7 +95,7 @@ GPU_SHADER_CREATE_INFO(overlay_outline_detect)
.sampler(2, ImageType::DEPTH_2D, "sceneDepth")
.fragment_out(0, Type::VEC4, "fragColor")
.fragment_out(1, Type::VEC4, "lineOutput")
- .fragment_source("outline_detect_frag.glsl")
+ .fragment_source("overlay_outline_detect_frag.glsl")
.additional_info("draw_fullscreen", "draw_view", "draw_globals");
/** \} */
diff --git a/source/blender/draw/engines/overlay/shaders/infos/paint_info.hh b/source/blender/draw/engines/overlay/shaders/infos/overlay_paint_info.hh
index bbec79d515f..3083d5a463b 100644
--- a/source/blender/draw/engines/overlay/shaders/infos/paint_info.hh
+++ b/source/blender/draw/engines/overlay/shaders/infos/overlay_paint_info.hh
@@ -10,13 +10,12 @@
GPU_SHADER_CREATE_INFO(overlay_paint_face)
.do_static_compilation(true)
- .define("srgbTarget", "false") /* NOTE: Color already in Linear space. */
.vertex_in(0, Type::VEC3, "pos")
.vertex_in(1, Type::VEC4, "nor") /* Select flag on the 4th component. */
.push_constant(Type::VEC4, "color")
.fragment_out(0, Type::VEC4, "fragColor")
- .vertex_source("paint_face_vert.glsl")
- .fragment_source("gpu_shader_uniform_color_frag.glsl")
+ .vertex_source("overlay_paint_face_vert.glsl")
+ .fragment_source("overlay_uniform_color_frag.glsl")
.additional_info("draw_modelmat");
GPU_SHADER_CREATE_INFO(overlay_paint_face_clipped)
@@ -40,8 +39,8 @@ GPU_SHADER_CREATE_INFO(overlay_paint_point)
.vertex_in(1, Type::VEC4, "nor") /* Select flag on the 4th component. */
.vertex_out(overlay_overlay_paint_point_iface)
.fragment_out(0, Type::VEC4, "fragColor")
- .vertex_source("paint_point_vert.glsl")
- .fragment_source("gpu_shader_point_varying_color_frag.glsl")
+ .vertex_source("overlay_paint_point_vert.glsl")
+ .fragment_source("overlay_point_varying_color_frag.glsl")
.additional_info("draw_modelmat", "draw_globals");
GPU_SHADER_CREATE_INFO(overlay_paint_point_clipped)
@@ -70,8 +69,8 @@ GPU_SHADER_CREATE_INFO(overlay_paint_texture)
.push_constant(Type::BOOL, "maskInvertStencil")
.push_constant(Type::BOOL, "maskImagePremultiplied")
.fragment_out(0, Type::VEC4, "fragColor")
- .vertex_source("paint_texture_vert.glsl")
- .fragment_source("paint_texture_frag.glsl")
+ .vertex_source("overlay_paint_texture_vert.glsl")
+ .fragment_source("overlay_paint_texture_frag.glsl")
.additional_info("draw_modelmat");
GPU_SHADER_CREATE_INFO(overlay_paint_texture_clipped)
@@ -97,8 +96,8 @@ GPU_SHADER_CREATE_INFO(overlay_paint_vertcol)
.push_constant(Type::FLOAT, "opacity") /* `1.0` by default. */
.push_constant(Type::BOOL, "useAlphaBlend") /* `false` by default. */
.fragment_out(0, Type::VEC4, "fragColor")
- .vertex_source("paint_vertcol_vert.glsl")
- .fragment_source("paint_vertcol_frag.glsl")
+ .vertex_source("overlay_paint_vertcol_vert.glsl")
+ .fragment_source("overlay_paint_vertcol_frag.glsl")
.additional_info("draw_modelmat");
GPU_SHADER_CREATE_INFO(overlay_paint_vertcol_clipped)
@@ -129,8 +128,8 @@ GPU_SHADER_CREATE_INFO(overlay_paint_weight)
.push_constant(Type::FLOAT, "opacity") /* `1.0` by default. */
.push_constant(Type::BOOL, "drawContours") /* `false` by default. */
.fragment_out(0, Type::VEC4, "fragColor")
- .vertex_source("paint_weight_vert.glsl")
- .fragment_source("paint_weight_frag.glsl")
+ .vertex_source("overlay_paint_weight_vert.glsl")
+ .fragment_source("overlay_paint_weight_frag.glsl")
.additional_info("draw_modelmat", "draw_globals");
GPU_SHADER_CREATE_INFO(overlay_paint_weight_fake_shading)
@@ -162,14 +161,13 @@ GPU_SHADER_INTERFACE_INFO(overlay_paint_wire_iface, "").flat(Type::VEC4, "finalC
GPU_SHADER_CREATE_INFO(overlay_paint_wire)
.do_static_compilation(true)
- .define("srgbTarget", "false") /* NOTE: Color already in Linear space. */
.vertex_in(0, Type::VEC3, "pos")
.vertex_in(1, Type::VEC4, "nor") /* flag stored in w */
.vertex_out(overlay_paint_wire_iface)
.push_constant(Type::BOOL, "useSelect")
.fragment_out(0, Type::VEC4, "fragColor")
- .vertex_source("paint_wire_vert.glsl")
- .fragment_source("gpu_shader_flat_color_frag.glsl")
+ .vertex_source("overlay_paint_wire_vert.glsl")
+ .fragment_source("overlay_varying_color.glsl")
.additional_info("draw_modelmat", "draw_globals");
GPU_SHADER_CREATE_INFO(overlay_paint_wire_clipped)
diff --git a/source/blender/draw/engines/overlay/shaders/infos/sculpt_info.hh b/source/blender/draw/engines/overlay/shaders/infos/overlay_sculpt_info.hh
index d4f1ca44362..3a53bd388a6 100644
--- a/source/blender/draw/engines/overlay/shaders/infos/sculpt_info.hh
+++ b/source/blender/draw/engines/overlay/shaders/infos/overlay_sculpt_info.hh
@@ -15,8 +15,8 @@ GPU_SHADER_CREATE_INFO(overlay_sculpt_mask)
.vertex_in(1, Type::VEC3, "fset")
.vertex_in(2, Type::FLOAT, "msk")
.vertex_out(overlay_sculpt_mask_iface)
- .vertex_source("sculpt_mask_vert.glsl")
- .fragment_source("sculpt_mask_frag.glsl")
+ .vertex_source("overlay_sculpt_mask_vert.glsl")
+ .fragment_source("overlay_sculpt_mask_frag.glsl")
.fragment_out(0, Type::VEC4, "fragColor")
.additional_info("draw_mesh", "draw_object_infos", "draw_globals");
diff --git a/source/blender/draw/engines/overlay/shaders/infos/volume_info.hh b/source/blender/draw/engines/overlay/shaders/infos/overlay_volume_info.hh
index 5853e974eeb..3740b42ba26 100644
--- a/source/blender/draw/engines/overlay/shaders/infos/volume_info.hh
+++ b/source/blender/draw/engines/overlay/shaders/infos/overlay_volume_info.hh
@@ -10,8 +10,6 @@ GPU_SHADER_INTERFACE_INFO(overlay_volume_velocity_iface, "").smooth(Type::VEC4,
GPU_SHADER_CREATE_INFO(overlay_volume_velocity)
.do_static_compilation(true)
- /* Colors are already in linear space. */
- .define("srgbTarget", "false")
.sampler(0, ImageType::FLOAT_3D, "velocityX")
.sampler(1, ImageType::FLOAT_3D, "velocityY")
.sampler(2, ImageType::FLOAT_3D, "velocityZ")
@@ -28,8 +26,8 @@ GPU_SHADER_CREATE_INFO(overlay_volume_velocity)
.push_constant(Type::IVEC3, "adaptiveCellOffset")
.vertex_out(overlay_volume_velocity_iface)
.fragment_out(0, Type::VEC4, "fragColor")
- .vertex_source("volume_velocity_vert.glsl")
- .fragment_source("gpu_shader_3D_smooth_color_frag.glsl")
+ .vertex_source("overlay_volume_velocity_vert.glsl")
+ .fragment_source("overlay_varying_color.glsl")
.additional_info("draw_volume");
GPU_SHADER_CREATE_INFO(overlay_volume_velocity_mac)
@@ -55,8 +53,6 @@ GPU_SHADER_INTERFACE_INFO(overlay_volume_gridlines_iface, "").flat(Type::VEC4, "
GPU_SHADER_CREATE_INFO(overlay_volume_gridlines)
.do_static_compilation(true)
- /* Colors are already in linear space. */
- .define("srgbTarget", "false")
.push_constant(Type::FLOAT, "slicePosition")
.push_constant(Type::INT, "sliceAxis")
/* FluidDomainSettings.res */
@@ -69,8 +65,8 @@ GPU_SHADER_CREATE_INFO(overlay_volume_gridlines)
.push_constant(Type::IVEC3, "adaptiveCellOffset")
.vertex_out(overlay_volume_gridlines_iface)
.fragment_out(0, Type::VEC4, "fragColor")
- .vertex_source("volume_gridlines_vert.glsl")
- .fragment_source("gpu_shader_flat_color_frag.glsl")
+ .vertex_source("overlay_volume_gridlines_vert.glsl")
+ .fragment_source("overlay_varying_color.glsl")
.additional_info("draw_volume");
GPU_SHADER_CREATE_INFO(overlay_volume_gridlines_flags)
diff --git a/source/blender/draw/engines/overlay/shaders/infos/wireframe_info.hh b/source/blender/draw/engines/overlay/shaders/infos/overlay_wireframe_info.hh
index 16b59f6bb7d..1899b191741 100644
--- a/source/blender/draw/engines/overlay/shaders/infos/wireframe_info.hh
+++ b/source/blender/draw/engines/overlay/shaders/infos/overlay_wireframe_info.hh
@@ -23,8 +23,8 @@ GPU_SHADER_CREATE_INFO(overlay_wireframe)
.vertex_in(1, Type::VEC3, "nor")
.vertex_in(2, Type::FLOAT, "wd") /* wire-data. */
.vertex_out(overlay_wireframe_iface)
- .vertex_source("wireframe_vert.glsl")
- .fragment_source("wireframe_frag.glsl")
+ .vertex_source("overlay_wireframe_vert.glsl")
+ .fragment_source("overlay_wireframe_frag.glsl")
.fragment_out(0, Type::VEC4, "fragColor")
.fragment_out(1, Type::VEC4, "lineOutput")
.additional_info("draw_mesh", "draw_object_infos", "draw_globals");
diff --git a/source/blender/draw/engines/overlay/shaders/antialiasing_frag.glsl b/source/blender/draw/engines/overlay/shaders/overlay_antialiasing_frag.glsl
index f28a809fdab..f28a809fdab 100644
--- a/source/blender/draw/engines/overlay/shaders/antialiasing_frag.glsl
+++ b/source/blender/draw/engines/overlay/shaders/overlay_antialiasing_frag.glsl
diff --git a/source/blender/draw/engines/overlay/shaders/armature_dof_solid_frag.glsl b/source/blender/draw/engines/overlay/shaders/overlay_armature_dof_solid_frag.glsl
index d46abbf79ee..d46abbf79ee 100644
--- a/source/blender/draw/engines/overlay/shaders/armature_dof_solid_frag.glsl
+++ b/source/blender/draw/engines/overlay/shaders/overlay_armature_dof_solid_frag.glsl
diff --git a/source/blender/draw/engines/overlay/shaders/armature_dof_vert.glsl b/source/blender/draw/engines/overlay/shaders/overlay_armature_dof_vert.glsl
index b3c9ce5dfd2..b3c9ce5dfd2 100644
--- a/source/blender/draw/engines/overlay/shaders/armature_dof_vert.glsl
+++ b/source/blender/draw/engines/overlay/shaders/overlay_armature_dof_vert.glsl
diff --git a/source/blender/draw/engines/overlay/shaders/armature_envelope_outline_vert.glsl b/source/blender/draw/engines/overlay/shaders/overlay_armature_envelope_outline_vert.glsl
index 0a8e279e9b0..0a8e279e9b0 100644
--- a/source/blender/draw/engines/overlay/shaders/armature_envelope_outline_vert.glsl
+++ b/source/blender/draw/engines/overlay/shaders/overlay_armature_envelope_outline_vert.glsl
diff --git a/source/blender/draw/engines/overlay/shaders/armature_envelope_solid_frag.glsl b/source/blender/draw/engines/overlay/shaders/overlay_armature_envelope_solid_frag.glsl
index a90d2e3e406..a90d2e3e406 100644
--- a/source/blender/draw/engines/overlay/shaders/armature_envelope_solid_frag.glsl
+++ b/source/blender/draw/engines/overlay/shaders/overlay_armature_envelope_solid_frag.glsl
diff --git a/source/blender/draw/engines/overlay/shaders/armature_envelope_solid_vert.glsl b/source/blender/draw/engines/overlay/shaders/overlay_armature_envelope_solid_vert.glsl
index 2dd86a57dfd..2dd86a57dfd 100644
--- a/source/blender/draw/engines/overlay/shaders/armature_envelope_solid_vert.glsl
+++ b/source/blender/draw/engines/overlay/shaders/overlay_armature_envelope_solid_vert.glsl
diff --git a/source/blender/draw/engines/overlay/shaders/armature_shape_outline_geom.glsl b/source/blender/draw/engines/overlay/shaders/overlay_armature_shape_outline_geom.glsl
index 47c5dada708..47c5dada708 100644
--- a/source/blender/draw/engines/overlay/shaders/armature_shape_outline_geom.glsl
+++ b/source/blender/draw/engines/overlay/shaders/overlay_armature_shape_outline_geom.glsl
diff --git a/source/blender/draw/engines/overlay/shaders/armature_shape_outline_vert.glsl b/source/blender/draw/engines/overlay/shaders/overlay_armature_shape_outline_vert.glsl
index 29319b3f7ac..29319b3f7ac 100644
--- a/source/blender/draw/engines/overlay/shaders/armature_shape_outline_vert.glsl
+++ b/source/blender/draw/engines/overlay/shaders/overlay_armature_shape_outline_vert.glsl
diff --git a/source/blender/draw/engines/overlay/shaders/armature_shape_solid_frag.glsl b/source/blender/draw/engines/overlay/shaders/overlay_armature_shape_solid_frag.glsl
index 8e1768846dc..8e1768846dc 100644
--- a/source/blender/draw/engines/overlay/shaders/armature_shape_solid_frag.glsl
+++ b/source/blender/draw/engines/overlay/shaders/overlay_armature_shape_solid_frag.glsl
diff --git a/source/blender/draw/engines/overlay/shaders/armature_shape_solid_vert.glsl b/source/blender/draw/engines/overlay/shaders/overlay_armature_shape_solid_vert.glsl
index cdbe8c3d7df..cdbe8c3d7df 100644
--- a/source/blender/draw/engines/overlay/shaders/armature_shape_solid_vert.glsl
+++ b/source/blender/draw/engines/overlay/shaders/overlay_armature_shape_solid_vert.glsl
diff --git a/source/blender/draw/engines/overlay/shaders/armature_shape_wire_vert.glsl b/source/blender/draw/engines/overlay/shaders/overlay_armature_shape_wire_vert.glsl
index cee86956c43..cee86956c43 100644
--- a/source/blender/draw/engines/overlay/shaders/armature_shape_wire_vert.glsl
+++ b/source/blender/draw/engines/overlay/shaders/overlay_armature_shape_wire_vert.glsl
diff --git a/source/blender/draw/engines/overlay/shaders/armature_sphere_outline_vert.glsl b/source/blender/draw/engines/overlay/shaders/overlay_armature_sphere_outline_vert.glsl
index 31369e0c3df..31369e0c3df 100644
--- a/source/blender/draw/engines/overlay/shaders/armature_sphere_outline_vert.glsl
+++ b/source/blender/draw/engines/overlay/shaders/overlay_armature_sphere_outline_vert.glsl
diff --git a/source/blender/draw/engines/overlay/shaders/armature_sphere_solid_frag.glsl b/source/blender/draw/engines/overlay/shaders/overlay_armature_sphere_solid_frag.glsl
index e60b6e94492..e60b6e94492 100644
--- a/source/blender/draw/engines/overlay/shaders/armature_sphere_solid_frag.glsl
+++ b/source/blender/draw/engines/overlay/shaders/overlay_armature_sphere_solid_frag.glsl
diff --git a/source/blender/draw/engines/overlay/shaders/armature_sphere_solid_vert.glsl b/source/blender/draw/engines/overlay/shaders/overlay_armature_sphere_solid_vert.glsl
index abbaad8cd10..abbaad8cd10 100644
--- a/source/blender/draw/engines/overlay/shaders/armature_sphere_solid_vert.glsl
+++ b/source/blender/draw/engines/overlay/shaders/overlay_armature_sphere_solid_vert.glsl
diff --git a/source/blender/draw/engines/overlay/shaders/armature_stick_frag.glsl b/source/blender/draw/engines/overlay/shaders/overlay_armature_stick_frag.glsl
index 2e42cdf0517..2e42cdf0517 100644
--- a/source/blender/draw/engines/overlay/shaders/armature_stick_frag.glsl
+++ b/source/blender/draw/engines/overlay/shaders/overlay_armature_stick_frag.glsl
diff --git a/source/blender/draw/engines/overlay/shaders/armature_stick_vert.glsl b/source/blender/draw/engines/overlay/shaders/overlay_armature_stick_vert.glsl
index b5edcd2858b..b5edcd2858b 100644
--- a/source/blender/draw/engines/overlay/shaders/armature_stick_vert.glsl
+++ b/source/blender/draw/engines/overlay/shaders/overlay_armature_stick_vert.glsl
diff --git a/source/blender/draw/engines/overlay/shaders/armature_wire_frag.glsl b/source/blender/draw/engines/overlay/shaders/overlay_armature_wire_frag.glsl
index 2c454a8becd..2c454a8becd 100644
--- a/source/blender/draw/engines/overlay/shaders/armature_wire_frag.glsl
+++ b/source/blender/draw/engines/overlay/shaders/overlay_armature_wire_frag.glsl
diff --git a/source/blender/draw/engines/overlay/shaders/armature_wire_vert.glsl b/source/blender/draw/engines/overlay/shaders/overlay_armature_wire_vert.glsl
index c89d0249e4f..c89d0249e4f 100644
--- a/source/blender/draw/engines/overlay/shaders/armature_wire_vert.glsl
+++ b/source/blender/draw/engines/overlay/shaders/overlay_armature_wire_vert.glsl
diff --git a/source/blender/draw/engines/overlay/shaders/background_frag.glsl b/source/blender/draw/engines/overlay/shaders/overlay_background_frag.glsl
index b25dcae9fca..b25dcae9fca 100644
--- a/source/blender/draw/engines/overlay/shaders/background_frag.glsl
+++ b/source/blender/draw/engines/overlay/shaders/overlay_background_frag.glsl
diff --git a/source/blender/draw/engines/overlay/shaders/clipbound_vert.glsl b/source/blender/draw/engines/overlay/shaders/overlay_clipbound_vert.glsl
index c065a66414f..c065a66414f 100644
--- a/source/blender/draw/engines/overlay/shaders/clipbound_vert.glsl
+++ b/source/blender/draw/engines/overlay/shaders/overlay_clipbound_vert.glsl
diff --git a/source/blender/draw/engines/overlay/shaders/common_overlay_lib.glsl b/source/blender/draw/engines/overlay/shaders/overlay_common_lib.glsl
index 65aeb81a4ef..65aeb81a4ef 100644
--- a/source/blender/draw/engines/overlay/shaders/common_overlay_lib.glsl
+++ b/source/blender/draw/engines/overlay/shaders/overlay_common_lib.glsl
diff --git a/source/blender/draw/engines/overlay/shaders/overlay_depth_only_frag.glsl b/source/blender/draw/engines/overlay/shaders/overlay_depth_only_frag.glsl
new file mode 100644
index 00000000000..59efdd8d538
--- /dev/null
+++ b/source/blender/draw/engines/overlay/shaders/overlay_depth_only_frag.glsl
@@ -0,0 +1,6 @@
+
+void main()
+{
+ /* No color output, only depth (line below is implicit). */
+ // gl_FragDepth = gl_FragCoord.z;
+}
diff --git a/source/blender/draw/engines/overlay/shaders/depth_only_vert.glsl b/source/blender/draw/engines/overlay/shaders/overlay_depth_only_vert.glsl
index d403890f44e..d403890f44e 100644
--- a/source/blender/draw/engines/overlay/shaders/depth_only_vert.glsl
+++ b/source/blender/draw/engines/overlay/shaders/overlay_depth_only_vert.glsl
diff --git a/source/blender/draw/engines/overlay/shaders/edit_curve_handle_geom.glsl b/source/blender/draw/engines/overlay/shaders/overlay_edit_curve_handle_geom.glsl
index 7d92baea595..7d92baea595 100644
--- a/source/blender/draw/engines/overlay/shaders/edit_curve_handle_geom.glsl
+++ b/source/blender/draw/engines/overlay/shaders/overlay_edit_curve_handle_geom.glsl
diff --git a/source/blender/draw/engines/overlay/shaders/edit_curve_handle_vert.glsl b/source/blender/draw/engines/overlay/shaders/overlay_edit_curve_handle_vert.glsl
index 186cc010f45..186cc010f45 100644
--- a/source/blender/draw/engines/overlay/shaders/edit_curve_handle_vert.glsl
+++ b/source/blender/draw/engines/overlay/shaders/overlay_edit_curve_handle_vert.glsl
diff --git a/source/blender/draw/engines/overlay/shaders/edit_curve_point_vert.glsl b/source/blender/draw/engines/overlay/shaders/overlay_edit_curve_point_vert.glsl
index a30496177c3..a30496177c3 100644
--- a/source/blender/draw/engines/overlay/shaders/edit_curve_point_vert.glsl
+++ b/source/blender/draw/engines/overlay/shaders/overlay_edit_curve_point_vert.glsl
diff --git a/source/blender/draw/engines/overlay/shaders/edit_curve_wire_vert.glsl b/source/blender/draw/engines/overlay/shaders/overlay_edit_curve_wire_vert.glsl
index 183df7e5450..183df7e5450 100644
--- a/source/blender/draw/engines/overlay/shaders/edit_curve_wire_vert.glsl
+++ b/source/blender/draw/engines/overlay/shaders/overlay_edit_curve_wire_vert.glsl
diff --git a/source/blender/draw/engines/overlay/shaders/edit_gpencil_canvas_vert.glsl b/source/blender/draw/engines/overlay/shaders/overlay_edit_gpencil_canvas_vert.glsl
index 47d9439ed80..47d9439ed80 100644
--- a/source/blender/draw/engines/overlay/shaders/edit_gpencil_canvas_vert.glsl
+++ b/source/blender/draw/engines/overlay/shaders/overlay_edit_gpencil_canvas_vert.glsl
diff --git a/source/blender/draw/engines/overlay/shaders/edit_gpencil_guide_vert.glsl b/source/blender/draw/engines/overlay/shaders/overlay_edit_gpencil_guide_vert.glsl
index a5091345539..a5091345539 100644
--- a/source/blender/draw/engines/overlay/shaders/edit_gpencil_guide_vert.glsl
+++ b/source/blender/draw/engines/overlay/shaders/overlay_edit_gpencil_guide_vert.glsl
diff --git a/source/blender/draw/engines/overlay/shaders/edit_gpencil_vert.glsl b/source/blender/draw/engines/overlay/shaders/overlay_edit_gpencil_vert.glsl
index f5d6e89d016..f5d6e89d016 100644
--- a/source/blender/draw/engines/overlay/shaders/edit_gpencil_vert.glsl
+++ b/source/blender/draw/engines/overlay/shaders/overlay_edit_gpencil_vert.glsl
diff --git a/source/blender/draw/engines/overlay/shaders/edit_lattice_point_vert.glsl b/source/blender/draw/engines/overlay/shaders/overlay_edit_lattice_point_vert.glsl
index 38ba80a981a..38ba80a981a 100644
--- a/source/blender/draw/engines/overlay/shaders/edit_lattice_point_vert.glsl
+++ b/source/blender/draw/engines/overlay/shaders/overlay_edit_lattice_point_vert.glsl
diff --git a/source/blender/draw/engines/overlay/shaders/edit_lattice_wire_vert.glsl b/source/blender/draw/engines/overlay/shaders/overlay_edit_lattice_wire_vert.glsl
index 440dfdc1482..440dfdc1482 100644
--- a/source/blender/draw/engines/overlay/shaders/edit_lattice_wire_vert.glsl
+++ b/source/blender/draw/engines/overlay/shaders/overlay_edit_lattice_wire_vert.glsl
diff --git a/source/blender/draw/engines/overlay/shaders/edit_mesh_analysis_frag.glsl b/source/blender/draw/engines/overlay/shaders/overlay_edit_mesh_analysis_frag.glsl
index 430ace8726a..430ace8726a 100644
--- a/source/blender/draw/engines/overlay/shaders/edit_mesh_analysis_frag.glsl
+++ b/source/blender/draw/engines/overlay/shaders/overlay_edit_mesh_analysis_frag.glsl
diff --git a/source/blender/draw/engines/overlay/shaders/edit_mesh_analysis_vert.glsl b/source/blender/draw/engines/overlay/shaders/overlay_edit_mesh_analysis_vert.glsl
index 1e163dc9a9a..1e163dc9a9a 100644
--- a/source/blender/draw/engines/overlay/shaders/edit_mesh_analysis_vert.glsl
+++ b/source/blender/draw/engines/overlay/shaders/overlay_edit_mesh_analysis_vert.glsl
diff --git a/source/blender/draw/engines/overlay/shaders/edit_mesh_common_lib.glsl b/source/blender/draw/engines/overlay/shaders/overlay_edit_mesh_common_lib.glsl
index 72b0a43cdb4..72b0a43cdb4 100644
--- a/source/blender/draw/engines/overlay/shaders/edit_mesh_common_lib.glsl
+++ b/source/blender/draw/engines/overlay/shaders/overlay_edit_mesh_common_lib.glsl
diff --git a/source/blender/draw/engines/overlay/shaders/edit_mesh_frag.glsl b/source/blender/draw/engines/overlay/shaders/overlay_edit_mesh_frag.glsl
index 2fd155f715c..2fd155f715c 100644
--- a/source/blender/draw/engines/overlay/shaders/edit_mesh_frag.glsl
+++ b/source/blender/draw/engines/overlay/shaders/overlay_edit_mesh_frag.glsl
diff --git a/source/blender/draw/engines/overlay/shaders/edit_mesh_geom.glsl b/source/blender/draw/engines/overlay/shaders/overlay_edit_mesh_geom.glsl
index 82f957b2071..82f957b2071 100644
--- a/source/blender/draw/engines/overlay/shaders/edit_mesh_geom.glsl
+++ b/source/blender/draw/engines/overlay/shaders/overlay_edit_mesh_geom.glsl
diff --git a/source/blender/draw/engines/overlay/shaders/edit_mesh_normal_vert.glsl b/source/blender/draw/engines/overlay/shaders/overlay_edit_mesh_normal_vert.glsl
index 6ff8d0665d1..6ff8d0665d1 100644
--- a/source/blender/draw/engines/overlay/shaders/edit_mesh_normal_vert.glsl
+++ b/source/blender/draw/engines/overlay/shaders/overlay_edit_mesh_normal_vert.glsl
diff --git a/source/blender/draw/engines/overlay/shaders/edit_mesh_skin_root_vert.glsl b/source/blender/draw/engines/overlay/shaders/overlay_edit_mesh_skin_root_vert.glsl
index f1fbdac7847..f1fbdac7847 100644
--- a/source/blender/draw/engines/overlay/shaders/edit_mesh_skin_root_vert.glsl
+++ b/source/blender/draw/engines/overlay/shaders/overlay_edit_mesh_skin_root_vert.glsl
diff --git a/source/blender/draw/engines/overlay/shaders/edit_mesh_vert.glsl b/source/blender/draw/engines/overlay/shaders/overlay_edit_mesh_vert.glsl
index 166ac1a37b0..374fb50af75 100644
--- a/source/blender/draw/engines/overlay/shaders/edit_mesh_vert.glsl
+++ b/source/blender/draw/engines/overlay/shaders/overlay_edit_mesh_vert.glsl
@@ -1,7 +1,7 @@
#pragma BLENDER_REQUIRE(common_view_clipping_lib.glsl)
#pragma BLENDER_REQUIRE(common_view_lib.glsl)
-#pragma BLENDER_REQUIRE(edit_mesh_common_lib.glsl)
+#pragma BLENDER_REQUIRE(overlay_edit_mesh_common_lib.glsl)
#ifdef EDGE
/* Ugly but needed to keep the same vertex shader code for other passes. */
diff --git a/source/blender/draw/engines/overlay/shaders/edit_particle_point_vert.glsl b/source/blender/draw/engines/overlay/shaders/overlay_edit_particle_point_vert.glsl
index 956b27e948d..956b27e948d 100644
--- a/source/blender/draw/engines/overlay/shaders/edit_particle_point_vert.glsl
+++ b/source/blender/draw/engines/overlay/shaders/overlay_edit_particle_point_vert.glsl
diff --git a/source/blender/draw/engines/overlay/shaders/edit_particle_strand_vert.glsl b/source/blender/draw/engines/overlay/shaders/overlay_edit_particle_strand_vert.glsl
index 6a92206d524..6a92206d524 100644
--- a/source/blender/draw/engines/overlay/shaders/edit_particle_strand_vert.glsl
+++ b/source/blender/draw/engines/overlay/shaders/overlay_edit_particle_strand_vert.glsl
diff --git a/source/blender/draw/engines/overlay/shaders/edit_uv_edges_frag.glsl b/source/blender/draw/engines/overlay/shaders/overlay_edit_uv_edges_frag.glsl
index 9c0ce4ecc8a..a849cb5160a 100644
--- a/source/blender/draw/engines/overlay/shaders/edit_uv_edges_frag.glsl
+++ b/source/blender/draw/engines/overlay/shaders/overlay_edit_uv_edges_frag.glsl
@@ -1,4 +1,4 @@
-#pragma BLENDER_REQUIRE(common_overlay_lib.glsl)
+#pragma BLENDER_REQUIRE(overlay_common_lib.glsl)
/**
* We want to know how much a pixel is covered by a line.
diff --git a/source/blender/draw/engines/overlay/shaders/edit_uv_edges_geom.glsl b/source/blender/draw/engines/overlay/shaders/overlay_edit_uv_edges_geom.glsl
index 1012b50e0e1..8b19f671139 100644
--- a/source/blender/draw/engines/overlay/shaders/edit_uv_edges_geom.glsl
+++ b/source/blender/draw/engines/overlay/shaders/overlay_edit_uv_edges_geom.glsl
@@ -1,7 +1,4 @@
-#pragma BLENDER_REQUIRE(common_overlay_lib.glsl)
-
-layout(lines) in;
-layout(triangle_strip, max_vertices = 4) out;
+#pragma BLENDER_REQUIRE(overlay_common_lib.glsl)
void do_vertex(
vec4 pos, float selection_fac, vec2 stipple_start, vec2 stipple_pos, float coord, vec2 offset)
diff --git a/source/blender/draw/engines/overlay/shaders/edit_uv_edges_vert.glsl b/source/blender/draw/engines/overlay/shaders/overlay_edit_uv_edges_vert.glsl
index 23f1a44c321..23f1a44c321 100644
--- a/source/blender/draw/engines/overlay/shaders/edit_uv_edges_vert.glsl
+++ b/source/blender/draw/engines/overlay/shaders/overlay_edit_uv_edges_vert.glsl
diff --git a/source/blender/draw/engines/overlay/shaders/edit_uv_face_dots_vert.glsl b/source/blender/draw/engines/overlay/shaders/overlay_edit_uv_face_dots_vert.glsl
index 280b31ea463..c0d4393f2da 100644
--- a/source/blender/draw/engines/overlay/shaders/edit_uv_face_dots_vert.glsl
+++ b/source/blender/draw/engines/overlay/shaders/overlay_edit_uv_face_dots_vert.glsl
@@ -5,6 +5,6 @@ void main()
vec3 world_pos = point_object_to_world(vec3(au, 0.0));
gl_Position = point_world_to_ndc(world_pos);
- finalColor = ((flag & FACE_UV_SELECT) != 0) ? colorVertexSelect : vec4(colorWire.rgb, 1.0);
+ finalColor = ((flag & FACE_UV_SELECT) != 0) ? colorFaceDot : vec4(colorWire.rgb, 1.0);
gl_PointSize = pointSize;
}
diff --git a/source/blender/draw/engines/overlay/shaders/edit_uv_faces_vert.glsl b/source/blender/draw/engines/overlay/shaders/overlay_edit_uv_faces_vert.glsl
index 80ea6228675..80ea6228675 100644
--- a/source/blender/draw/engines/overlay/shaders/edit_uv_faces_vert.glsl
+++ b/source/blender/draw/engines/overlay/shaders/overlay_edit_uv_faces_vert.glsl
diff --git a/source/blender/draw/engines/overlay/shaders/edit_uv_image_mask_frag.glsl b/source/blender/draw/engines/overlay/shaders/overlay_edit_uv_image_mask_frag.glsl
index a1392abbb92..a1392abbb92 100644
--- a/source/blender/draw/engines/overlay/shaders/edit_uv_image_mask_frag.glsl
+++ b/source/blender/draw/engines/overlay/shaders/overlay_edit_uv_image_mask_frag.glsl
diff --git a/source/blender/draw/engines/overlay/shaders/edit_uv_image_vert.glsl b/source/blender/draw/engines/overlay/shaders/overlay_edit_uv_image_vert.glsl
index 7ecbb513265..7ecbb513265 100644
--- a/source/blender/draw/engines/overlay/shaders/edit_uv_image_vert.glsl
+++ b/source/blender/draw/engines/overlay/shaders/overlay_edit_uv_image_vert.glsl
diff --git a/source/blender/draw/engines/overlay/shaders/edit_uv_stretching_vert.glsl b/source/blender/draw/engines/overlay/shaders/overlay_edit_uv_stretching_vert.glsl
index bb086e8d9f5..bb086e8d9f5 100644
--- a/source/blender/draw/engines/overlay/shaders/edit_uv_stretching_vert.glsl
+++ b/source/blender/draw/engines/overlay/shaders/overlay_edit_uv_stretching_vert.glsl
diff --git a/source/blender/draw/engines/overlay/shaders/edit_uv_tiled_image_borders_vert.glsl b/source/blender/draw/engines/overlay/shaders/overlay_edit_uv_tiled_image_borders_vert.glsl
index bc5235b9cab..bc5235b9cab 100644
--- a/source/blender/draw/engines/overlay/shaders/edit_uv_tiled_image_borders_vert.glsl
+++ b/source/blender/draw/engines/overlay/shaders/overlay_edit_uv_tiled_image_borders_vert.glsl
diff --git a/source/blender/draw/engines/overlay/shaders/edit_uv_verts_frag.glsl b/source/blender/draw/engines/overlay/shaders/overlay_edit_uv_verts_frag.glsl
index c0ea6aebe10..c0ea6aebe10 100644
--- a/source/blender/draw/engines/overlay/shaders/edit_uv_verts_frag.glsl
+++ b/source/blender/draw/engines/overlay/shaders/overlay_edit_uv_verts_frag.glsl
diff --git a/source/blender/draw/engines/overlay/shaders/edit_uv_verts_vert.glsl b/source/blender/draw/engines/overlay/shaders/overlay_edit_uv_verts_vert.glsl
index 9f9b02ce19d..9f9b02ce19d 100644
--- a/source/blender/draw/engines/overlay/shaders/edit_uv_verts_vert.glsl
+++ b/source/blender/draw/engines/overlay/shaders/overlay_edit_uv_verts_vert.glsl
diff --git a/source/blender/draw/engines/overlay/shaders/extra_frag.glsl b/source/blender/draw/engines/overlay/shaders/overlay_extra_frag.glsl
index bf29b2b057e..bf29b2b057e 100644
--- a/source/blender/draw/engines/overlay/shaders/extra_frag.glsl
+++ b/source/blender/draw/engines/overlay/shaders/overlay_extra_frag.glsl
diff --git a/source/blender/draw/engines/overlay/shaders/extra_groundline_vert.glsl b/source/blender/draw/engines/overlay/shaders/overlay_extra_groundline_vert.glsl
index ff7aae523e7..ff7aae523e7 100644
--- a/source/blender/draw/engines/overlay/shaders/extra_groundline_vert.glsl
+++ b/source/blender/draw/engines/overlay/shaders/overlay_extra_groundline_vert.glsl
diff --git a/source/blender/draw/engines/overlay/shaders/extra_lightprobe_grid_vert.glsl b/source/blender/draw/engines/overlay/shaders/overlay_extra_lightprobe_grid_vert.glsl
index 1eee7ab251b..1eee7ab251b 100644
--- a/source/blender/draw/engines/overlay/shaders/extra_lightprobe_grid_vert.glsl
+++ b/source/blender/draw/engines/overlay/shaders/overlay_extra_lightprobe_grid_vert.glsl
diff --git a/source/blender/draw/engines/overlay/shaders/extra_loose_point_frag.glsl b/source/blender/draw/engines/overlay/shaders/overlay_extra_loose_point_frag.glsl
index d92b947ef89..d92b947ef89 100644
--- a/source/blender/draw/engines/overlay/shaders/extra_loose_point_frag.glsl
+++ b/source/blender/draw/engines/overlay/shaders/overlay_extra_loose_point_frag.glsl
diff --git a/source/blender/draw/engines/overlay/shaders/extra_loose_point_vert.glsl b/source/blender/draw/engines/overlay/shaders/overlay_extra_loose_point_vert.glsl
index f283934816c..f283934816c 100644
--- a/source/blender/draw/engines/overlay/shaders/extra_loose_point_vert.glsl
+++ b/source/blender/draw/engines/overlay/shaders/overlay_extra_loose_point_vert.glsl
diff --git a/source/blender/draw/engines/overlay/shaders/extra_point_vert.glsl b/source/blender/draw/engines/overlay/shaders/overlay_extra_point_vert.glsl
index de999c241c0..de999c241c0 100644
--- a/source/blender/draw/engines/overlay/shaders/extra_point_vert.glsl
+++ b/source/blender/draw/engines/overlay/shaders/overlay_extra_point_vert.glsl
diff --git a/source/blender/draw/engines/overlay/shaders/extra_vert.glsl b/source/blender/draw/engines/overlay/shaders/overlay_extra_vert.glsl
index b2578970c9b..b2578970c9b 100644
--- a/source/blender/draw/engines/overlay/shaders/extra_vert.glsl
+++ b/source/blender/draw/engines/overlay/shaders/overlay_extra_vert.glsl
diff --git a/source/blender/draw/engines/overlay/shaders/extra_wire_frag.glsl b/source/blender/draw/engines/overlay/shaders/overlay_extra_wire_frag.glsl
index f32e3a8564e..f32e3a8564e 100644
--- a/source/blender/draw/engines/overlay/shaders/extra_wire_frag.glsl
+++ b/source/blender/draw/engines/overlay/shaders/overlay_extra_wire_frag.glsl
diff --git a/source/blender/draw/engines/overlay/shaders/extra_wire_vert.glsl b/source/blender/draw/engines/overlay/shaders/overlay_extra_wire_vert.glsl
index cd217021e8f..cd217021e8f 100644
--- a/source/blender/draw/engines/overlay/shaders/extra_wire_vert.glsl
+++ b/source/blender/draw/engines/overlay/shaders/overlay_extra_wire_vert.glsl
diff --git a/source/blender/draw/engines/overlay/shaders/facing_frag.glsl b/source/blender/draw/engines/overlay/shaders/overlay_facing_frag.glsl
index 8208689d113..8208689d113 100644
--- a/source/blender/draw/engines/overlay/shaders/facing_frag.glsl
+++ b/source/blender/draw/engines/overlay/shaders/overlay_facing_frag.glsl
diff --git a/source/blender/draw/engines/overlay/shaders/facing_vert.glsl b/source/blender/draw/engines/overlay/shaders/overlay_facing_vert.glsl
index d98caee6a25..d98caee6a25 100644
--- a/source/blender/draw/engines/overlay/shaders/facing_vert.glsl
+++ b/source/blender/draw/engines/overlay/shaders/overlay_facing_vert.glsl
diff --git a/source/blender/draw/engines/overlay/shaders/grid_background_frag.glsl b/source/blender/draw/engines/overlay/shaders/overlay_grid_background_frag.glsl
index 37958319b44..37958319b44 100644
--- a/source/blender/draw/engines/overlay/shaders/grid_background_frag.glsl
+++ b/source/blender/draw/engines/overlay/shaders/overlay_grid_background_frag.glsl
diff --git a/source/blender/draw/engines/overlay/shaders/grid_frag.glsl b/source/blender/draw/engines/overlay/shaders/overlay_grid_frag.glsl
index 25f4984f119..25f4984f119 100644
--- a/source/blender/draw/engines/overlay/shaders/grid_frag.glsl
+++ b/source/blender/draw/engines/overlay/shaders/overlay_grid_frag.glsl
diff --git a/source/blender/draw/engines/overlay/shaders/grid_vert.glsl b/source/blender/draw/engines/overlay/shaders/overlay_grid_vert.glsl
index b81f1a24358..b81f1a24358 100644
--- a/source/blender/draw/engines/overlay/shaders/grid_vert.glsl
+++ b/source/blender/draw/engines/overlay/shaders/overlay_grid_vert.glsl
diff --git a/source/blender/draw/engines/overlay/shaders/image_frag.glsl b/source/blender/draw/engines/overlay/shaders/overlay_image_frag.glsl
index e0339507e0f..e0339507e0f 100644
--- a/source/blender/draw/engines/overlay/shaders/image_frag.glsl
+++ b/source/blender/draw/engines/overlay/shaders/overlay_image_frag.glsl
diff --git a/source/blender/draw/engines/overlay/shaders/image_vert.glsl b/source/blender/draw/engines/overlay/shaders/overlay_image_vert.glsl
index 45cddb3610d..45cddb3610d 100644
--- a/source/blender/draw/engines/overlay/shaders/image_vert.glsl
+++ b/source/blender/draw/engines/overlay/shaders/overlay_image_vert.glsl
diff --git a/source/blender/draw/engines/overlay/shaders/motion_path_line_frag.glsl b/source/blender/draw/engines/overlay/shaders/overlay_motion_path_line_frag.glsl
index 324d22501f9..324d22501f9 100644
--- a/source/blender/draw/engines/overlay/shaders/motion_path_line_frag.glsl
+++ b/source/blender/draw/engines/overlay/shaders/overlay_motion_path_line_frag.glsl
diff --git a/source/blender/draw/engines/overlay/shaders/motion_path_line_geom.glsl b/source/blender/draw/engines/overlay/shaders/overlay_motion_path_line_geom.glsl
index 29346a44863..29346a44863 100644
--- a/source/blender/draw/engines/overlay/shaders/motion_path_line_geom.glsl
+++ b/source/blender/draw/engines/overlay/shaders/overlay_motion_path_line_geom.glsl
diff --git a/source/blender/draw/engines/overlay/shaders/motion_path_line_vert.glsl b/source/blender/draw/engines/overlay/shaders/overlay_motion_path_line_vert.glsl
index bc74a436f5e..bc74a436f5e 100644
--- a/source/blender/draw/engines/overlay/shaders/motion_path_line_vert.glsl
+++ b/source/blender/draw/engines/overlay/shaders/overlay_motion_path_line_vert.glsl
diff --git a/source/blender/draw/engines/overlay/shaders/motion_path_point_vert.glsl b/source/blender/draw/engines/overlay/shaders/overlay_motion_path_point_vert.glsl
index 5027525b9b3..5027525b9b3 100644
--- a/source/blender/draw/engines/overlay/shaders/motion_path_point_vert.glsl
+++ b/source/blender/draw/engines/overlay/shaders/overlay_motion_path_point_vert.glsl
diff --git a/source/blender/draw/engines/overlay/shaders/outline_detect_frag.glsl b/source/blender/draw/engines/overlay/shaders/overlay_outline_detect_frag.glsl
index c33bb474d96..472a589f441 100644
--- a/source/blender/draw/engines/overlay/shaders/outline_detect_frag.glsl
+++ b/source/blender/draw/engines/overlay/shaders/overlay_outline_detect_frag.glsl
@@ -36,7 +36,7 @@ bvec4 gather_edges(vec2 uv, uint ref)
#ifdef GPU_ARB_texture_gather
ids = textureGather(outlineId, uv);
#else
- vec3 ofs = vec3(0.5, 0.5, -0.5) * drw_view.viewport_size_inversey;
+ vec3 ofs = vec3(0.5, 0.5, -0.5) * drw_view.viewport_size_inverse.xyy;
ids.x = textureLod(outlineId, uv - ofs.xz, 0.0).r;
ids.y = textureLod(outlineId, uv + ofs.xy, 0.0).r;
ids.z = textureLod(outlineId, uv + ofs.xz, 0.0).r;
@@ -347,7 +347,7 @@ void main()
line_end = vec2(0.0, 0.5);
break;
default:
- /* Ensure values are assigned to, avoids undefined behaviour for
+ /* Ensure values are assigned to, avoids undefined behavior for
* divergent control-flow. This can occur if discard is called
* as discard is not treated as a return in Metal 2.2. So
* side-effects can still cause problems. */
diff --git a/source/blender/draw/engines/overlay/shaders/outline_prepass_frag.glsl b/source/blender/draw/engines/overlay/shaders/overlay_outline_prepass_frag.glsl
index d1abd74a7b3..d1abd74a7b3 100644
--- a/source/blender/draw/engines/overlay/shaders/outline_prepass_frag.glsl
+++ b/source/blender/draw/engines/overlay/shaders/overlay_outline_prepass_frag.glsl
diff --git a/source/blender/draw/engines/overlay/shaders/outline_prepass_geom.glsl b/source/blender/draw/engines/overlay/shaders/overlay_outline_prepass_geom.glsl
index 8a196620af9..8a196620af9 100644
--- a/source/blender/draw/engines/overlay/shaders/outline_prepass_geom.glsl
+++ b/source/blender/draw/engines/overlay/shaders/overlay_outline_prepass_geom.glsl
diff --git a/source/blender/draw/engines/overlay/shaders/outline_prepass_gpencil_frag.glsl b/source/blender/draw/engines/overlay/shaders/overlay_outline_prepass_gpencil_frag.glsl
index b6d5cd96c12..b6d5cd96c12 100644
--- a/source/blender/draw/engines/overlay/shaders/outline_prepass_gpencil_frag.glsl
+++ b/source/blender/draw/engines/overlay/shaders/overlay_outline_prepass_gpencil_frag.glsl
diff --git a/source/blender/draw/engines/overlay/shaders/outline_prepass_gpencil_vert.glsl b/source/blender/draw/engines/overlay/shaders/overlay_outline_prepass_gpencil_vert.glsl
index 4b1470e5723..4b1470e5723 100644
--- a/source/blender/draw/engines/overlay/shaders/outline_prepass_gpencil_vert.glsl
+++ b/source/blender/draw/engines/overlay/shaders/overlay_outline_prepass_gpencil_vert.glsl
diff --git a/source/blender/draw/engines/overlay/shaders/outline_prepass_pointcloud_vert.glsl b/source/blender/draw/engines/overlay/shaders/overlay_outline_prepass_pointcloud_vert.glsl
index 371ff628c59..371ff628c59 100644
--- a/source/blender/draw/engines/overlay/shaders/outline_prepass_pointcloud_vert.glsl
+++ b/source/blender/draw/engines/overlay/shaders/overlay_outline_prepass_pointcloud_vert.glsl
diff --git a/source/blender/draw/engines/overlay/shaders/outline_prepass_vert.glsl b/source/blender/draw/engines/overlay/shaders/overlay_outline_prepass_vert.glsl
index 1d0b08f51b2..1d0b08f51b2 100644
--- a/source/blender/draw/engines/overlay/shaders/outline_prepass_vert.glsl
+++ b/source/blender/draw/engines/overlay/shaders/overlay_outline_prepass_vert.glsl
diff --git a/source/blender/draw/engines/overlay/shaders/paint_face_vert.glsl b/source/blender/draw/engines/overlay/shaders/overlay_paint_face_vert.glsl
index 22906bf1526..22906bf1526 100644
--- a/source/blender/draw/engines/overlay/shaders/paint_face_vert.glsl
+++ b/source/blender/draw/engines/overlay/shaders/overlay_paint_face_vert.glsl
diff --git a/source/blender/draw/engines/overlay/shaders/paint_point_vert.glsl b/source/blender/draw/engines/overlay/shaders/overlay_paint_point_vert.glsl
index 8736b2a87db..8736b2a87db 100644
--- a/source/blender/draw/engines/overlay/shaders/paint_point_vert.glsl
+++ b/source/blender/draw/engines/overlay/shaders/overlay_paint_point_vert.glsl
diff --git a/source/blender/draw/engines/overlay/shaders/paint_texture_frag.glsl b/source/blender/draw/engines/overlay/shaders/overlay_paint_texture_frag.glsl
index e5af0e7bd88..e5af0e7bd88 100644
--- a/source/blender/draw/engines/overlay/shaders/paint_texture_frag.glsl
+++ b/source/blender/draw/engines/overlay/shaders/overlay_paint_texture_frag.glsl
diff --git a/source/blender/draw/engines/overlay/shaders/paint_texture_vert.glsl b/source/blender/draw/engines/overlay/shaders/overlay_paint_texture_vert.glsl
index f93d0050950..f93d0050950 100644
--- a/source/blender/draw/engines/overlay/shaders/paint_texture_vert.glsl
+++ b/source/blender/draw/engines/overlay/shaders/overlay_paint_texture_vert.glsl
diff --git a/source/blender/draw/engines/overlay/shaders/paint_vertcol_frag.glsl b/source/blender/draw/engines/overlay/shaders/overlay_paint_vertcol_frag.glsl
index 193fabc65cb..193fabc65cb 100644
--- a/source/blender/draw/engines/overlay/shaders/paint_vertcol_frag.glsl
+++ b/source/blender/draw/engines/overlay/shaders/overlay_paint_vertcol_frag.glsl
diff --git a/source/blender/draw/engines/overlay/shaders/paint_vertcol_vert.glsl b/source/blender/draw/engines/overlay/shaders/overlay_paint_vertcol_vert.glsl
index 650070dcfd5..650070dcfd5 100644
--- a/source/blender/draw/engines/overlay/shaders/paint_vertcol_vert.glsl
+++ b/source/blender/draw/engines/overlay/shaders/overlay_paint_vertcol_vert.glsl
diff --git a/source/blender/draw/engines/overlay/shaders/paint_weight_frag.glsl b/source/blender/draw/engines/overlay/shaders/overlay_paint_weight_frag.glsl
index 1befe7506c4..1befe7506c4 100644
--- a/source/blender/draw/engines/overlay/shaders/paint_weight_frag.glsl
+++ b/source/blender/draw/engines/overlay/shaders/overlay_paint_weight_frag.glsl
diff --git a/source/blender/draw/engines/overlay/shaders/paint_weight_vert.glsl b/source/blender/draw/engines/overlay/shaders/overlay_paint_weight_vert.glsl
index cff79d606d6..cff79d606d6 100644
--- a/source/blender/draw/engines/overlay/shaders/paint_weight_vert.glsl
+++ b/source/blender/draw/engines/overlay/shaders/overlay_paint_weight_vert.glsl
diff --git a/source/blender/draw/engines/overlay/shaders/paint_wire_vert.glsl b/source/blender/draw/engines/overlay/shaders/overlay_paint_wire_vert.glsl
index 749cc92f082..749cc92f082 100644
--- a/source/blender/draw/engines/overlay/shaders/paint_wire_vert.glsl
+++ b/source/blender/draw/engines/overlay/shaders/overlay_paint_wire_vert.glsl
diff --git a/source/blender/draw/engines/overlay/shaders/particle_frag.glsl b/source/blender/draw/engines/overlay/shaders/overlay_particle_frag.glsl
index a2bcca7b820..a2bcca7b820 100644
--- a/source/blender/draw/engines/overlay/shaders/particle_frag.glsl
+++ b/source/blender/draw/engines/overlay/shaders/overlay_particle_frag.glsl
diff --git a/source/blender/draw/engines/overlay/shaders/particle_vert.glsl b/source/blender/draw/engines/overlay/shaders/overlay_particle_vert.glsl
index fb981a8167a..fb981a8167a 100644
--- a/source/blender/draw/engines/overlay/shaders/particle_vert.glsl
+++ b/source/blender/draw/engines/overlay/shaders/overlay_particle_vert.glsl
diff --git a/source/blender/draw/engines/overlay/shaders/overlay_point_varying_color_frag.glsl b/source/blender/draw/engines/overlay/shaders/overlay_point_varying_color_frag.glsl
new file mode 100644
index 00000000000..b0da035ef09
--- /dev/null
+++ b/source/blender/draw/engines/overlay/shaders/overlay_point_varying_color_frag.glsl
@@ -0,0 +1,23 @@
+
+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;
+ }
+
+#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/draw/engines/overlay/shaders/overlay_point_varying_color_varying_outline_aa_frag.glsl b/source/blender/draw/engines/overlay/shaders/overlay_point_varying_color_varying_outline_aa_frag.glsl
new file mode 100644
index 00000000000..c0ea6aebe10
--- /dev/null
+++ b/source/blender/draw/engines/overlay/shaders/overlay_point_varying_color_varying_outline_aa_frag.glsl
@@ -0,0 +1,27 @@
+
+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/draw/engines/overlay/shaders/sculpt_mask_frag.glsl b/source/blender/draw/engines/overlay/shaders/overlay_sculpt_mask_frag.glsl
index 9650af755c5..9650af755c5 100644
--- a/source/blender/draw/engines/overlay/shaders/sculpt_mask_frag.glsl
+++ b/source/blender/draw/engines/overlay/shaders/overlay_sculpt_mask_frag.glsl
diff --git a/source/blender/draw/engines/overlay/shaders/sculpt_mask_vert.glsl b/source/blender/draw/engines/overlay/shaders/overlay_sculpt_mask_vert.glsl
index 36c0e6a0acf..36c0e6a0acf 100644
--- a/source/blender/draw/engines/overlay/shaders/sculpt_mask_vert.glsl
+++ b/source/blender/draw/engines/overlay/shaders/overlay_sculpt_mask_vert.glsl
diff --git a/source/blender/draw/engines/overlay/shaders/overlay_uniform_color_frag.glsl b/source/blender/draw/engines/overlay/shaders/overlay_uniform_color_frag.glsl
new file mode 100644
index 00000000000..0a498471b46
--- /dev/null
+++ b/source/blender/draw/engines/overlay/shaders/overlay_uniform_color_frag.glsl
@@ -0,0 +1,4 @@
+void main()
+{
+ fragColor = color;
+} \ No newline at end of file
diff --git a/source/blender/draw/engines/overlay/shaders/overlay_varying_color.glsl b/source/blender/draw/engines/overlay/shaders/overlay_varying_color.glsl
new file mode 100644
index 00000000000..a27e2849bb3
--- /dev/null
+++ b/source/blender/draw/engines/overlay/shaders/overlay_varying_color.glsl
@@ -0,0 +1,4 @@
+void main()
+{
+ fragColor = finalColor;
+}
diff --git a/source/blender/draw/engines/overlay/shaders/volume_gridlines_vert.glsl b/source/blender/draw/engines/overlay/shaders/overlay_volume_gridlines_vert.glsl
index 11a04dddd2a..11a04dddd2a 100644
--- a/source/blender/draw/engines/overlay/shaders/volume_gridlines_vert.glsl
+++ b/source/blender/draw/engines/overlay/shaders/overlay_volume_gridlines_vert.glsl
diff --git a/source/blender/draw/engines/overlay/shaders/volume_velocity_vert.glsl b/source/blender/draw/engines/overlay/shaders/overlay_volume_velocity_vert.glsl
index a33d27676c3..a33d27676c3 100644
--- a/source/blender/draw/engines/overlay/shaders/volume_velocity_vert.glsl
+++ b/source/blender/draw/engines/overlay/shaders/overlay_volume_velocity_vert.glsl
diff --git a/source/blender/draw/engines/overlay/shaders/wireframe_frag.glsl b/source/blender/draw/engines/overlay/shaders/overlay_wireframe_frag.glsl
index bc28d7a8a36..bc28d7a8a36 100644
--- a/source/blender/draw/engines/overlay/shaders/wireframe_frag.glsl
+++ b/source/blender/draw/engines/overlay/shaders/overlay_wireframe_frag.glsl
diff --git a/source/blender/draw/engines/overlay/shaders/wireframe_vert.glsl b/source/blender/draw/engines/overlay/shaders/overlay_wireframe_vert.glsl
index 41bd7791dd7..41bd7791dd7 100644
--- a/source/blender/draw/engines/overlay/shaders/wireframe_vert.glsl
+++ b/source/blender/draw/engines/overlay/shaders/overlay_wireframe_vert.glsl
diff --git a/source/blender/draw/engines/overlay/shaders/xray_fade_frag.glsl b/source/blender/draw/engines/overlay/shaders/overlay_xray_fade_frag.glsl
index 9aa2fdc3796..9aa2fdc3796 100644
--- a/source/blender/draw/engines/overlay/shaders/xray_fade_frag.glsl
+++ b/source/blender/draw/engines/overlay/shaders/overlay_xray_fade_frag.glsl
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
index e2a54788c72..735e7b6d867 100644
--- a/source/blender/draw/engines/workbench/shaders/infos/workbench_prepass_info.hh
+++ b/source/blender/draw/engines/workbench/shaders/infos/workbench_prepass_info.hh
@@ -91,7 +91,7 @@ GPU_SHADER_CREATE_INFO(workbench_material)
* \{ */
GPU_SHADER_CREATE_INFO(workbench_transparent_accum)
- /* Note: Blending will be skipped on objectId because output is a
+ /* 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")
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 36059b6076f..49e26cd3e0c 100644
--- a/source/blender/draw/engines/workbench/shaders/workbench_volume_frag.glsl
+++ b/source/blender/draw/engines/workbench/shaders/workbench_volume_frag.glsl
@@ -218,13 +218,13 @@ void main()
/* Manual depth test. TODO: remove. */
float depth = texelFetch(depthBuffer, ivec2(gl_FragCoord.xy), 0).r;
if (gl_FragCoord.z >= depth) {
- /* Note: In the Metal API, prior to Metal 2.3, Discard is not an explicit return and can
- * produce undefined behaviour. This is especially prominent with derivatives if control-flow
+ /* NOTE: In the Metal API, prior to Metal 2.3, Discard is not an explicit return and can
+ * produce undefined behavior. This is especially prominent with derivatives if control-flow
* divergence is present.
*
- * Adding a return call eliminates undefined behaviour and a later out-of-bounds read causing
+ * Adding a return call eliminates undefined behavior and a later out-of-bounds read causing
* a crash on AMD platforms.
- * This behaviour can also affect OpenGL on certain devices. */
+ * This behavior can also affect OpenGL on certain devices. */
discard;
return;
}
diff --git a/source/blender/draw/engines/workbench/workbench_engine.c b/source/blender/draw/engines/workbench/workbench_engine.c
index fb20bde2f65..9eb35c25bf4 100644
--- a/source/blender/draw/engines/workbench/workbench_engine.c
+++ b/source/blender/draw/engines/workbench/workbench_engine.c
@@ -97,7 +97,7 @@ static void workbench_cache_sculpt_populate(WORKBENCH_PrivateData *wpd,
{
const bool use_single_drawcall = !ELEM(color_type, V3D_SHADING_MATERIAL_COLOR);
if (use_single_drawcall) {
- DRWShadingGroup *grp = workbench_material_setup(wpd, ob, 0, color_type, NULL);
+ DRWShadingGroup *grp = workbench_material_setup(wpd, ob, ob->actcol, color_type, NULL);
DRW_shgroup_call_sculpt(grp, ob, false, false);
}
else {
@@ -323,7 +323,8 @@ static eV3DShadingColorType workbench_color_type_get(WORKBENCH_PrivateData *wpd,
}
}
- if (is_sculpt_pbvh && color_type == V3D_SHADING_TEXTURE_COLOR) {
+ if (is_sculpt_pbvh && color_type == V3D_SHADING_TEXTURE_COLOR &&
+ BKE_pbvh_type(ob->sculpt->pbvh) != PBVH_FACES) {
/* Force use of material color for sculpt. */
color_type = V3D_SHADING_MATERIAL_COLOR;
}
diff --git a/source/blender/draw/engines/workbench/workbench_render.c b/source/blender/draw/engines/workbench/workbench_render.c
index 1279682e899..e5dcf6c5624 100644
--- a/source/blender/draw/engines/workbench/workbench_render.c
+++ b/source/blender/draw/engines/workbench/workbench_render.c
@@ -115,11 +115,11 @@ static void workbench_render_result_z(struct RenderLayer *rl,
float winmat[4][4];
DRW_view_winmat_get(NULL, winmat, false);
- int pix_ct = BLI_rcti_size_x(rect) * BLI_rcti_size_y(rect);
+ int pix_num = BLI_rcti_size_x(rect) * BLI_rcti_size_y(rect);
/* Convert ogl depth [0..1] to view Z [near..far] */
if (DRW_view_is_persp_get(NULL)) {
- for (int i = 0; i < pix_ct; i++) {
+ for (int i = 0; i < pix_num; i++) {
if (rp->rect[i] == 1.0f) {
rp->rect[i] = 1e10f; /* Background */
}
@@ -135,7 +135,7 @@ static void workbench_render_result_z(struct RenderLayer *rl,
float far = DRW_view_far_distance_get(NULL);
float range = fabsf(far - near);
- for (int i = 0; i < pix_ct; i++) {
+ for (int i = 0; i < pix_num; i++) {
if (rp->rect[i] == 1.0f) {
rp->rect[i] = 1e10f; /* Background */
}
diff --git a/source/blender/draw/engines/workbench/workbench_volume.c b/source/blender/draw/engines/workbench/workbench_volume.c
index 2c902e9b627..ce7773e7439 100644
--- a/source/blender/draw/engines/workbench/workbench_volume.c
+++ b/source/blender/draw/engines/workbench/workbench_volume.c
@@ -124,12 +124,12 @@ static void workbench_volume_modifier_cache_populate(WORKBENCH_Data *vedata,
double noise_ofs;
BLI_halton_1d(3, 0.0, wpd->taa_sample, &noise_ofs);
float dim[3], step_length, max_slice;
- float slice_ct[3] = {fds->res[0], fds->res[1], fds->res[2]};
- mul_v3_fl(slice_ct, max_ff(0.001f, fds->slice_per_voxel));
- max_slice = max_fff(slice_ct[0], slice_ct[1], slice_ct[2]);
+ float slice_count[3] = {fds->res[0], fds->res[1], fds->res[2]};
+ mul_v3_fl(slice_count, max_ff(0.001f, fds->slice_per_voxel));
+ max_slice = max_fff(slice_count[0], slice_count[1], slice_count[2]);
BKE_object_dimensions_get(ob, dim);
- invert_v3(slice_ct);
- mul_v3_v3(dim, slice_ct);
+ invert_v3(slice_count);
+ mul_v3_v3(dim, slice_count);
step_length = len_v3(dim);
grp = DRW_shgroup_create(sh, vedata->psl->volume_ps);
@@ -273,12 +273,12 @@ static void workbench_volume_object_cache_populate(WORKBENCH_Data *vedata,
float step_length, max_slice;
int resolution[3];
GPU_texture_get_mipmap_size(grid->texture, 0, resolution);
- float slice_ct[3] = {resolution[0], resolution[1], resolution[2]};
- mul_v3_fl(slice_ct, max_ff(0.001f, 5.0f));
- max_slice = max_fff(slice_ct[0], slice_ct[1], slice_ct[2]);
- invert_v3(slice_ct);
- mul_v3_v3(slice_ct, world_size);
- step_length = len_v3(slice_ct);
+ float slice_count[3] = {resolution[0], resolution[1], resolution[2]};
+ mul_v3_fl(slice_count, max_ff(0.001f, 5.0f));
+ max_slice = max_fff(slice_count[0], slice_count[1], slice_count[2]);
+ invert_v3(slice_count);
+ mul_v3_v3(slice_count, world_size);
+ step_length = len_v3(slice_count);
/* Set uniforms. */
grp = DRW_shgroup_create(sh, vedata->psl->volume_ps);
diff --git a/source/blender/draw/intern/DRW_gpu_wrapper.hh b/source/blender/draw/intern/DRW_gpu_wrapper.hh
index d7e752a43f4..257f01a5562 100644
--- a/source/blender/draw/intern/DRW_gpu_wrapper.hh
+++ b/source/blender/draw/intern/DRW_gpu_wrapper.hh
@@ -102,7 +102,7 @@ class DataBuffer {
{
BLI_STATIC_ASSERT(!device_only, "");
BLI_assert(index >= 0);
- BLI_assert(index < len);
+ BLI_assert(index < len_);
return data_[index];
}
@@ -110,7 +110,7 @@ class DataBuffer {
{
BLI_STATIC_ASSERT(!device_only, "");
BLI_assert(index >= 0);
- BLI_assert(index < len);
+ BLI_assert(index < len_);
return data_[index];
}
@@ -139,7 +139,7 @@ class DataBuffer {
const T *end() const
{
BLI_STATIC_ASSERT(!device_only, "");
- return data_ + len;
+ return data_ + len_;
}
T *begin()
@@ -150,13 +150,13 @@ class DataBuffer {
T *end()
{
BLI_STATIC_ASSERT(!device_only, "");
- return data_ + len;
+ return data_ + len_;
}
operator Span<T>() const
{
BLI_STATIC_ASSERT(!device_only, "");
- return Span<T>(data_, len);
+ return Span<T>(data_, len_);
}
};
@@ -217,7 +217,9 @@ class StorageCommon : public DataBuffer<T, len, false>, NonMovable, NonCopyable
if (name) {
name_ = name;
}
- init(len);
+ this->len_ = len;
+ constexpr GPUUsageType usage = device_only ? GPU_USAGE_DEVICE_ONLY : GPU_USAGE_DYNAMIC;
+ ssbo_ = GPU_storagebuf_create_ex(sizeof(T) * this->len_, nullptr, usage, this->name_);
}
~StorageCommon()
@@ -225,15 +227,6 @@ class StorageCommon : public DataBuffer<T, len, false>, NonMovable, NonCopyable
GPU_storagebuf_free(ssbo_);
}
- void resize(int64_t new_size)
- {
- BLI_assert(new_size > 0);
- if (new_size != this->len_) {
- GPU_storagebuf_free(ssbo_);
- this->init(new_size);
- }
- }
-
void push_update(void)
{
BLI_assert(device_only == false);
@@ -249,14 +242,6 @@ class StorageCommon : public DataBuffer<T, len, false>, NonMovable, NonCopyable
{
return &ssbo_;
}
-
- private:
- void init(int64_t new_size)
- {
- this->len_ = new_size;
- GPUUsageType usage = device_only ? GPU_USAGE_DEVICE_ONLY : GPU_USAGE_DYNAMIC;
- ssbo_ = GPU_storagebuf_create_ex(sizeof(T) * this->len_, nullptr, usage, this->name_);
- }
};
} // namespace detail
@@ -333,6 +318,34 @@ class StorageArrayBuffer : public detail::StorageCommon<T, len, device_only> {
{
MEM_freeN(this->data_);
}
+
+ void resize(int64_t new_size)
+ {
+ BLI_assert(new_size > 0);
+ if (new_size != this->len_) {
+ /* Manual realloc since MEM_reallocN_aligned does not exists. */
+ T *new_data_ = (T *)MEM_mallocN_aligned(new_size * sizeof(T), 16, this->name_);
+ memcpy(new_data_, this->data_, min_uu(this->len_, new_size) * sizeof(T));
+ MEM_freeN(this->data_);
+ this->data_ = new_data_;
+ GPU_storagebuf_free(this->ssbo_);
+
+ this->len_ = new_size;
+ constexpr GPUUsageType usage = device_only ? GPU_USAGE_DEVICE_ONLY : GPU_USAGE_DYNAMIC;
+ this->ssbo_ = GPU_storagebuf_create_ex(sizeof(T) * this->len_, nullptr, usage, this->name_);
+ }
+ }
+
+ /* Resize on access. */
+ T &get_or_resize(int64_t index)
+ {
+ BLI_assert(index >= 0);
+ if (index >= this->len_) {
+ size_t size = power_of_2_max_u(index + 1);
+ this->resize(size);
+ }
+ return this->data_[index];
+ }
};
template<
@@ -880,4 +893,56 @@ class Framebuffer : NonCopyable {
/** \} */
+/* -------------------------------------------------------------------- */
+/** \name Double & Triple buffering util
+ *
+ * This is not strictly related to a GPU type and could be moved elsewhere.
+ * \{ */
+
+template<typename T, int64_t len> class SwapChain {
+ private:
+ std::array<T, len> chain_;
+ int64_t index_ = 0;
+
+ public:
+ void swap()
+ {
+ index_ = (index_ + 1) % len;
+ }
+
+ T &current()
+ {
+ return chain_[index_];
+ }
+
+ T &previous()
+ {
+ /* Avoid modulo operation with negative numbers. */
+ return chain_[(index_ + len - 1) % len];
+ }
+
+ T &next()
+ {
+ return chain_[(index_ + 1) % len];
+ }
+
+ const T &current() const
+ {
+ return chain_[index_];
+ }
+
+ const T &previous() const
+ {
+ /* Avoid modulo operation with negative numbers. */
+ return chain_[(index_ + len - 1) % len];
+ }
+
+ const T &next() const
+ {
+ return chain_[(index_ + 1) % len];
+ }
+};
+
+/** \} */
+
} // namespace blender::draw
diff --git a/source/blender/draw/intern/DRW_render.h b/source/blender/draw/intern/DRW_render.h
index 712118e8282..fa4a1d93d3e 100644
--- a/source/blender/draw/intern/DRW_render.h
+++ b/source/blender/draw/intern/DRW_render.h
@@ -296,6 +296,8 @@ void DRW_shader_library_free(DRWShaderLibrary *lib);
* therefore they aren't ordered as a bit mask.
*/
typedef enum {
+ /** To be used for compute passes. */
+ DRW_STATE_NO_DRAW = 0,
/** Write mask */
DRW_STATE_WRITE_DEPTH = (1 << 0),
DRW_STATE_WRITE_COLOR = (1 << 1),
@@ -430,12 +432,12 @@ void DRW_shgroup_call_ex(DRWShadingGroup *shgroup,
DRW_shgroup_call_ex(shgroup, ob, NULL, geom, true, NULL)
void DRW_shgroup_call_range(
- DRWShadingGroup *shgroup, Object *ob, struct GPUBatch *geom, uint v_sta, uint v_ct);
+ DRWShadingGroup *shgroup, Object *ob, struct GPUBatch *geom, uint v_sta, uint v_num);
/**
* A count of 0 instance will use the default number of instance in the batch.
*/
void DRW_shgroup_call_instance_range(
- DRWShadingGroup *shgroup, Object *ob, struct GPUBatch *geom, uint i_sta, uint i_ct);
+ DRWShadingGroup *shgroup, Object *ob, struct GPUBatch *geom, uint i_sta, uint i_num);
void DRW_shgroup_call_compute(DRWShadingGroup *shgroup,
int groups_x_len,
@@ -621,6 +623,12 @@ void DRW_shgroup_vertex_buffer_ex(DRWShadingGroup *shgroup,
void DRW_shgroup_vertex_buffer_ref_ex(DRWShadingGroup *shgroup,
const char *name,
struct GPUVertBuf **vertex_buffer DRW_DEBUG_FILE_LINE_ARGS);
+void DRW_shgroup_buffer_texture(DRWShadingGroup *shgroup,
+ const char *name,
+ struct GPUVertBuf *vertex_buffer);
+void DRW_shgroup_buffer_texture_ref(DRWShadingGroup *shgroup,
+ const char *name,
+ struct GPUVertBuf **vertex_buffer);
#ifdef DRW_UNUSED_RESOURCE_TRACKING
# define DRW_shgroup_vertex_buffer(shgroup, name, vert) \
@@ -738,6 +746,7 @@ const DRWView *DRW_view_get_active(void);
*/
void DRW_view_clip_planes_set(DRWView *view, float (*planes)[4], int plane_len);
void DRW_view_camtexco_set(DRWView *view, float texco[4]);
+void DRW_view_camtexco_get(const DRWView *view, float r_texco[4]);
/* For all getters, if view is NULL, default view is assumed. */
@@ -828,7 +837,7 @@ void DRW_render_viewport_size_set(const int size[2]);
/**
* Assume a valid GL context is bound (and that the gl_context_mutex has been acquired).
* This function only setup DST and execute the given function.
- * \warning similar to DRW_render_to_image you cannot use default lists (dfbl & dtxl).
+ * \warning similar to DRW_render_to_image you cannot use default lists (`dfbl` & `dtxl`).
*/
void DRW_custom_pipeline(DrawEngineType *draw_engine_type,
struct Depsgraph *depsgraph,
@@ -841,6 +850,7 @@ void DRW_custom_pipeline(DrawEngineType *draw_engine_type,
void DRW_cache_restart(void);
/* ViewLayers */
+
void *DRW_view_layer_engine_data_get(DrawEngineType *engine_type);
void **DRW_view_layer_engine_data_ensure_ex(struct ViewLayer *view_layer,
DrawEngineType *engine_type,
@@ -849,6 +859,7 @@ void **DRW_view_layer_engine_data_ensure(DrawEngineType *engine_type,
void (*callback)(void *storage));
/* DrawData */
+
DrawData *DRW_drawdata_get(ID *id, DrawEngineType *engine_type);
DrawData *DRW_drawdata_ensure(ID *id,
DrawEngineType *engine_type,
diff --git a/source/blender/draw/intern/draw_attributes.cc b/source/blender/draw/intern/draw_attributes.cc
new file mode 100644
index 00000000000..3f187aef8e6
--- /dev/null
+++ b/source/blender/draw/intern/draw_attributes.cc
@@ -0,0 +1,114 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later
+ * Copyright 2022 Blender Foundation. All rights reserved. */
+
+#include "draw_attributes.h"
+
+/* Return true if the given DRW_AttributeRequest is already in the requests. */
+static bool drw_attributes_has_request(const DRW_Attributes *requests, DRW_AttributeRequest req)
+{
+ for (int i = 0; i < requests->num_requests; i++) {
+ const DRW_AttributeRequest src_req = requests->requests[i];
+ if (src_req.domain != req.domain) {
+ continue;
+ }
+ if (src_req.layer_index != req.layer_index) {
+ continue;
+ }
+ if (src_req.cd_type != req.cd_type) {
+ continue;
+ }
+ return true;
+ }
+ return false;
+}
+
+static void drw_attributes_merge_requests(const DRW_Attributes *src_requests,
+ DRW_Attributes *dst_requests)
+{
+ for (int i = 0; i < src_requests->num_requests; i++) {
+ if (dst_requests->num_requests == GPU_MAX_ATTR) {
+ return;
+ }
+
+ if (drw_attributes_has_request(dst_requests, src_requests->requests[i])) {
+ continue;
+ }
+
+ dst_requests->requests[dst_requests->num_requests] = src_requests->requests[i];
+ dst_requests->num_requests += 1;
+ }
+}
+
+void drw_attributes_clear(DRW_Attributes *attributes)
+{
+ memset(attributes, 0, sizeof(DRW_Attributes));
+}
+
+void drw_attributes_merge(DRW_Attributes *dst,
+ const DRW_Attributes *src,
+ ThreadMutex *render_mutex)
+{
+ BLI_mutex_lock(render_mutex);
+ drw_attributes_merge_requests(src, dst);
+ BLI_mutex_unlock(render_mutex);
+}
+
+bool drw_attributes_overlap(const DRW_Attributes *a, const DRW_Attributes *b)
+{
+ for (int i = 0; i < b->num_requests; i++) {
+ if (!drw_attributes_has_request(a, b->requests[i])) {
+ return false;
+ }
+ }
+
+ return true;
+}
+
+DRW_AttributeRequest *drw_attributes_add_request(DRW_Attributes *attrs,
+ const char *name,
+ const eCustomDataType type,
+ const int layer_index,
+ const eAttrDomain domain)
+{
+ if (attrs->num_requests >= GPU_MAX_ATTR) {
+ return nullptr;
+ }
+
+ DRW_AttributeRequest *req = &attrs->requests[attrs->num_requests];
+ req->cd_type = type;
+ BLI_strncpy(req->attribute_name, name, sizeof(req->attribute_name));
+ req->layer_index = layer_index;
+ req->domain = domain;
+ attrs->num_requests += 1;
+ return req;
+}
+
+bool drw_custom_data_match_attribute(const CustomData *custom_data,
+ const char *name,
+ int *r_layer_index,
+ eCustomDataType *r_type)
+{
+ const eCustomDataType possible_attribute_types[7] = {
+ CD_PROP_BOOL,
+ CD_PROP_INT8,
+ CD_PROP_INT32,
+ CD_PROP_FLOAT,
+ CD_PROP_FLOAT2,
+ CD_PROP_FLOAT3,
+ CD_PROP_COLOR,
+ };
+
+ for (int i = 0; i < ARRAY_SIZE(possible_attribute_types); i++) {
+ const eCustomDataType attr_type = possible_attribute_types[i];
+ int layer_index = CustomData_get_named_layer(custom_data, attr_type, name);
+ if (layer_index == -1) {
+ continue;
+ }
+
+ *r_layer_index = layer_index;
+ *r_type = attr_type;
+ return true;
+ }
+
+ return false;
+}
diff --git a/source/blender/draw/intern/draw_attributes.h b/source/blender/draw/intern/draw_attributes.h
new file mode 100644
index 00000000000..b577c6c4162
--- /dev/null
+++ b/source/blender/draw/intern/draw_attributes.h
@@ -0,0 +1,61 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later
+ * Copyright 2022 Blender Foundation. All rights reserved. */
+
+/** \file
+ * \ingroup draw
+ *
+ * \brief Utilities for rendering attributes.
+ */
+
+#pragma once
+
+#include "DNA_customdata_types.h"
+#include "DNA_meshdata_types.h"
+
+#include "BKE_attribute.h"
+
+#include "BLI_sys_types.h"
+#include "BLI_threads.h"
+
+#include "GPU_shader.h"
+#include "GPU_vertex_format.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef struct DRW_AttributeRequest {
+ eCustomDataType cd_type;
+ int layer_index;
+ eAttrDomain domain;
+ char attribute_name[64];
+} DRW_AttributeRequest;
+
+typedef struct DRW_Attributes {
+ DRW_AttributeRequest requests[GPU_MAX_ATTR];
+ int num_requests;
+} DRW_Attributes;
+
+void drw_attributes_clear(DRW_Attributes *attributes);
+
+void drw_attributes_merge(DRW_Attributes *dst,
+ const DRW_Attributes *src,
+ ThreadMutex *render_mutex);
+
+/* Return true if all requests in b are in a. */
+bool drw_attributes_overlap(const DRW_Attributes *a, const DRW_Attributes *b);
+
+DRW_AttributeRequest *drw_attributes_add_request(DRW_Attributes *attrs,
+ const char *name,
+ eCustomDataType data_type,
+ int layer_index,
+ eAttrDomain domain);
+
+bool drw_custom_data_match_attribute(const CustomData *custom_data,
+ const char *name,
+ int *r_layer_index,
+ eCustomDataType *r_type);
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/source/blender/draw/intern/draw_cache.c b/source/blender/draw/intern/draw_cache.c
index 67700a4274f..f846251c66b 100644
--- a/source/blender/draw/intern/draw_cache.c
+++ b/source/blender/draw/intern/draw_cache.c
@@ -3400,6 +3400,9 @@ void DRW_batch_cache_free_old(Object *ob, int ctime)
case OB_MESH:
DRW_mesh_batch_cache_free_old((Mesh *)ob->data, ctime);
break;
+ case OB_CURVES:
+ DRW_curves_batch_cache_free_old((Curves *)ob->data, ctime);
+ break;
/* TODO: all cases. */
default:
break;
@@ -3407,3 +3410,35 @@ void DRW_batch_cache_free_old(Object *ob, int ctime)
}
/** \} */
+
+void DRW_cdlayer_attr_aliases_add(GPUVertFormat *format,
+ const char *base_name,
+ const CustomData *UNUSED(data),
+ const CustomDataLayer *cl,
+ bool is_active_render,
+ bool is_active_layer)
+{
+ char attr_name[32], attr_safe_name[GPU_MAX_SAFE_ATTR_NAME];
+ const char *layer_name = cl->name;
+
+ GPU_vertformat_safe_attr_name(layer_name, attr_safe_name, GPU_MAX_SAFE_ATTR_NAME);
+
+ /* Attribute layer name. */
+ BLI_snprintf(attr_name, sizeof(attr_name), "%s%s", base_name, attr_safe_name);
+ GPU_vertformat_alias_add(format, attr_name);
+
+ /* Auto layer name. */
+ BLI_snprintf(attr_name, sizeof(attr_name), "a%s", attr_safe_name);
+ GPU_vertformat_alias_add(format, attr_name);
+
+ /* Active render layer name. */
+ if (is_active_render) {
+ GPU_vertformat_alias_add(format, base_name);
+ }
+
+ /* Active display layer name. */
+ if (is_active_layer) {
+ BLI_snprintf(attr_name, sizeof(attr_name), "a%s", base_name);
+ GPU_vertformat_alias_add(format, attr_name);
+ }
+}
diff --git a/source/blender/draw/intern/draw_cache_extract.h b/source/blender/draw/intern/draw_cache_extract.hh
index 4567e470146..c7127d169e1 100644
--- a/source/blender/draw/intern/draw_cache_extract.h
+++ b/source/blender/draw/intern/draw_cache_extract.hh
@@ -7,11 +7,13 @@
#pragma once
-struct DRWSubdivCache;
-struct MeshRenderData;
-struct TaskGraph;
+#include <algorithm>
+
+#include "BLI_utildefines.h"
#include "DNA_customdata_types.h"
+#include "DNA_mesh_types.h"
+#include "DNA_view3d_enums.h"
#include "BKE_attribute.h"
#include "BKE_object.h"
@@ -20,8 +22,14 @@ struct TaskGraph;
#include "GPU_index_buffer.h"
#include "GPU_vertex_buffer.h"
+#include "draw_attributes.h"
+
+struct DRWSubdivCache;
+struct MeshRenderData;
+struct TaskGraph;
+
/* Vertex Group Selection and display options */
-typedef struct DRW_MeshWeightState {
+struct DRW_MeshWeightState {
int defgroup_active;
int defgroup_len;
@@ -29,13 +37,13 @@ typedef struct DRW_MeshWeightState {
char alert_mode;
/* Set of all selected bones for Multi-paint. */
- bool *defgroup_sel; /* [defgroup_len] */
+ bool *defgroup_sel; /* #defgroup_len */
int defgroup_sel_count;
/* Set of all locked and unlocked deform bones for Lock Relative mode. */
- bool *defgroup_locked; /* [defgroup_len] */
- bool *defgroup_unlocked; /* [defgroup_len] */
-} DRW_MeshWeightState;
+ bool *defgroup_locked; /* #defgroup_len */
+ bool *defgroup_unlocked; /* #defgroup_len */
+};
/* DRW_MeshWeightState.flags */
enum {
@@ -44,41 +52,32 @@ enum {
DRW_MESH_WEIGHT_STATE_LOCK_RELATIVE = (1 << 2),
};
-typedef struct DRW_MeshCDMask {
+struct DRW_MeshCDMask {
uint32_t uv : 8;
uint32_t tan : 8;
uint32_t vcol : 8;
uint32_t orco : 1;
uint32_t tan_orco : 1;
uint32_t sculpt_overlays : 1;
- /** Edit uv layer is from the base edit mesh as
- * modifiers could remove it. (see T68857) */
+ /**
+ * Edit uv layer is from the base edit mesh as modifiers could remove it. (see T68857)
+ */
uint32_t edit_uv : 1;
-} DRW_MeshCDMask;
-/* Keep `DRW_MeshCDMask` struct within an `uint32_t`.
+};
+/* Keep `DRW_MeshCDMask` struct within a `uint32_t`.
* bit-wise and atomic operations are used to compare and update the struct.
* See `mesh_cd_layers_type_*` functions. */
BLI_STATIC_ASSERT(sizeof(DRW_MeshCDMask) <= sizeof(uint32_t), "DRW_MeshCDMask exceeds 32 bits")
-typedef enum eMRIterType {
+
+enum eMRIterType {
MR_ITER_LOOPTRI = 1 << 0,
MR_ITER_POLY = 1 << 1,
MR_ITER_LEDGE = 1 << 2,
MR_ITER_LVERT = 1 << 3,
-} eMRIterType;
+};
ENUM_OPERATORS(eMRIterType, MR_ITER_LVERT)
-typedef struct DRW_AttributeRequest {
- CustomDataType cd_type;
- int layer_index;
- AttributeDomain domain;
-} DRW_AttributeRequest;
-
-typedef struct DRW_MeshAttributes {
- DRW_AttributeRequest requests[GPU_MAX_ATTR];
- int num_requests;
-} DRW_MeshAttributes;
-
-typedef enum eMRDataType {
+enum eMRDataType {
MR_DATA_NONE = 0,
MR_DATA_POLY_NOR = 1 << 1,
MR_DATA_LOOP_NOR = 1 << 2,
@@ -87,29 +86,24 @@ typedef enum eMRDataType {
/** Force loop normals calculation. */
MR_DATA_TAN_LOOP_NOR = 1 << 5,
MR_DATA_POLYS_SORTED = 1 << 6,
-} eMRDataType;
+};
ENUM_OPERATORS(eMRDataType, MR_DATA_POLYS_SORTED)
-#ifdef __cplusplus
-extern "C" {
-#endif
-
BLI_INLINE int mesh_render_mat_len_get(const Object *object, const Mesh *me)
{
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 std::max<int>(1, editmesh_eval_final->totcol);
}
}
- return MAX2(1, me->totcol);
+ return std::max<int>(1, me->totcol);
}
-typedef struct MeshBufferList {
- /* Every VBO below contains at least enough
- * data for every loops in the mesh (except fdots and skin roots).
- * For some VBOs, it extends to (in this exact order) :
- * loops + loose_edges*2 + loose_verts */
+struct MeshBufferList {
+ /* Every VBO below contains at least enough data for every loop in the mesh
+ * (except fdots and skin roots). For some VBOs, it extends to (in this exact order) :
+ * loops + loose_edges * 2 + loose_verts */
struct {
GPUVertBuf *pos_nor; /* extend */
GPUVertBuf *lnor; /* extend */
@@ -142,14 +136,17 @@ typedef struct MeshBufferList {
/* Index Buffers:
* Only need to be updated when topology changes. */
struct {
- /* Indices to vloops. */
- GPUIndexBuf *tris; /* Ordered per material. */
- GPUIndexBuf *lines; /* Loose edges last. */
- GPUIndexBuf *lines_loose; /* sub buffer of `lines` only containing the loose edges. */
+ /* Indices to vloops. Ordered per material. */
+ GPUIndexBuf *tris;
+ /* Loose edges last. */
+ GPUIndexBuf *lines;
+ /* Sub buffer of `lines` only containing the loose edges. */
+ GPUIndexBuf *lines_loose;
GPUIndexBuf *points;
GPUIndexBuf *fdots;
/* 3D overlays. */
- GPUIndexBuf *lines_paint_mask; /* no loose edges. */
+ /* no loose edges. */
+ GPUIndexBuf *lines_paint_mask;
GPUIndexBuf *lines_adjacency;
/* Uv overlays. (visibility can differ from 3D view) */
GPUIndexBuf *edituv_tris;
@@ -157,9 +154,9 @@ typedef struct MeshBufferList {
GPUIndexBuf *edituv_points;
GPUIndexBuf *edituv_fdots;
} ibo;
-} MeshBufferList;
+};
-typedef struct MeshBatchList {
+struct MeshBatchList {
/* Surfaces / Render */
GPUBatch *surface;
GPUBatch *surface_weights;
@@ -189,19 +186,22 @@ typedef struct MeshBatchList {
GPUBatch *all_edges;
GPUBatch *loose_edges;
GPUBatch *edge_detection;
- GPUBatch *wire_edges; /* Individual edges with face normals. */
- GPUBatch *wire_loops; /* Loops around faces. no edges between selected faces */
- GPUBatch *wire_loops_uvs; /* Same as wire_loops but only has uvs. */
+ /* Individual edges with face normals. */
+ GPUBatch *wire_edges;
+ /* Loops around faces. no edges between selected faces */
+ GPUBatch *wire_loops;
+ /* Same as wire_loops but only has uvs. */
+ GPUBatch *wire_loops_uvs;
GPUBatch *sculpt_overlays;
-} MeshBatchList;
+};
#define MBC_BATCH_LEN (sizeof(MeshBatchList) / sizeof(void *))
-#define MBC_VBO_LEN (sizeof(((MeshBufferList){0}).vbo) / sizeof(void *))
-#define MBC_IBO_LEN (sizeof(((MeshBufferList){0}).ibo) / sizeof(void *))
+#define MBC_VBO_LEN (sizeof(MeshBufferList::vbo) / sizeof(void *))
+#define MBC_IBO_LEN (sizeof(MeshBufferList::ibo) / sizeof(void *))
#define MBC_BATCH_INDEX(batch) (offsetof(MeshBatchList, batch) / sizeof(void *))
-typedef enum DRWBatchFlag {
+enum DRWBatchFlag {
MBC_SURFACE = (1u << MBC_BATCH_INDEX(surface)),
MBC_SURFACE_WEIGHTS = (1u << MBC_BATCH_INDEX(surface_weights)),
MBC_EDIT_TRIANGLES = (1u << MBC_BATCH_INDEX(edit_triangles)),
@@ -230,23 +230,25 @@ typedef enum DRWBatchFlag {
MBC_WIRE_LOOPS = (1u << MBC_BATCH_INDEX(wire_loops)),
MBC_WIRE_LOOPS_UVS = (1u << MBC_BATCH_INDEX(wire_loops_uvs)),
MBC_SCULPT_OVERLAYS = (1u << MBC_BATCH_INDEX(sculpt_overlays)),
-} DRWBatchFlag;
+ MBC_SURFACE_PER_MAT = (1u << MBC_BATCH_LEN),
+};
+ENUM_OPERATORS(DRWBatchFlag, MBC_SURFACE_PER_MAT);
BLI_STATIC_ASSERT(MBC_BATCH_LEN < 32, "Number of batches exceeded the limit of bit fields");
-typedef struct MeshExtractLooseGeom {
+struct MeshExtractLooseGeom {
int edge_len;
int vert_len;
int *verts;
int *edges;
-} MeshExtractLooseGeom;
+};
/**
* Data that are kept around between extractions to reduce rebuilding time.
*
* - Loose geometry.
*/
-typedef struct MeshBufferCache {
+struct MeshBufferCache {
MeshBufferList buff;
MeshExtractLooseGeom loose_geom;
@@ -256,7 +258,7 @@ typedef struct MeshBufferCache {
int *mat_tri_len;
int visible_tri_len;
} poly_sorted;
-} MeshBufferCache;
+};
#define FOREACH_MESH_BUFFER_CACHE(batch_cache, mbc) \
for (MeshBufferCache *mbc = &batch_cache->final; \
@@ -265,7 +267,7 @@ typedef struct MeshBufferCache {
&batch_cache->cage : \
((mbc == &batch_cache->cage) ? &batch_cache->uv_cage : NULL))
-typedef struct MeshBatchCache {
+struct MeshBatchCache {
MeshBufferCache final, cage, uv_cage;
MeshBatchList batch;
@@ -275,26 +277,27 @@ typedef struct MeshBatchCache {
GPUBatch **surface_per_mat;
- struct DRWSubdivCache *subdiv_cache;
+ DRWSubdivCache *subdiv_cache;
- DRWBatchFlag batch_requested; /* DRWBatchFlag */
- DRWBatchFlag batch_ready; /* DRWBatchFlag */
+ DRWBatchFlag batch_requested;
+ DRWBatchFlag batch_ready;
- /* settings to determine if cache is invalid */
+ /* Settings to determine if cache is invalid. */
int edge_len;
int tri_len;
int poly_len;
int vert_len;
int mat_len;
- bool is_dirty; /* Instantly invalidates cache, skipping mesh check */
+ /* Instantly invalidates cache, skipping mesh check */
+ bool is_dirty;
bool is_editmode;
bool is_uvsyncsel;
- struct DRW_MeshWeightState weight_state;
+ DRW_MeshWeightState weight_state;
DRW_MeshCDMask cd_used, cd_needed, cd_used_over_time;
- DRW_MeshAttributes attr_used, attr_needed, attr_used_over_time;
+ DRW_Attributes attr_used, attr_needed, attr_used_over_time;
int lastmatch;
@@ -311,13 +314,15 @@ typedef struct MeshBatchCache {
eV3DShadingColorType color_type;
bool pbvh_is_drawing;
-} MeshBatchCache;
+};
#define MBC_EDITUV \
(MBC_EDITUV_FACES_STRETCH_AREA | MBC_EDITUV_FACES_STRETCH_ANGLE | MBC_EDITUV_FACES | \
MBC_EDITUV_EDGES | MBC_EDITUV_VERTS | MBC_EDITUV_FACEDOTS | MBC_WIRE_LOOPS_UVS)
-void mesh_buffer_cache_create_requested(struct TaskGraph *task_graph,
+namespace blender::draw {
+
+void mesh_buffer_cache_create_requested(TaskGraph *task_graph,
MeshBatchCache *cache,
MeshBufferCache *mbc,
Object *object,
@@ -328,16 +333,13 @@ void mesh_buffer_cache_create_requested(struct TaskGraph *task_graph,
const float obmat[4][4],
bool do_final,
bool do_uvedit,
- bool use_subsurf_fdots,
const Scene *scene,
- const struct ToolSettings *ts,
+ const ToolSettings *ts,
bool use_hide);
void mesh_buffer_cache_create_requested_subdiv(MeshBatchCache *cache,
MeshBufferCache *mbc,
- struct DRWSubdivCache *subdiv_cache,
- struct MeshRenderData *mr);
+ DRWSubdivCache *subdiv_cache,
+ MeshRenderData *mr);
-#ifdef __cplusplus
-}
-#endif
+} // namespace blender::draw
diff --git a/source/blender/draw/intern/draw_cache_extract_mesh.cc b/source/blender/draw/intern/draw_cache_extract_mesh.cc
index 8a7b4fc9703..380736ef656 100644
--- a/source/blender/draw/intern/draw_cache_extract_mesh.cc
+++ b/source/blender/draw/intern/draw_cache_extract_mesh.cc
@@ -24,11 +24,11 @@
#include "GPU_capabilities.h"
-#include "draw_cache_extract.h"
+#include "draw_cache_extract.hh"
#include "draw_cache_inline.h"
#include "draw_subdivision.h"
-#include "mesh_extractors/extract_mesh.h"
+#include "mesh_extractors/extract_mesh.hh"
// #define DEBUG_TIME
@@ -155,7 +155,7 @@ struct ExtractTaskData {
bool use_threading = false;
ExtractTaskData(const MeshRenderData *mr,
- struct MeshBatchCache *cache,
+ MeshBatchCache *cache,
ExtractorRunDatas *extractors,
MeshBufferList *mbuflist,
const bool use_threading)
@@ -193,7 +193,7 @@ static void extract_task_data_free(void *data)
* \{ */
BLI_INLINE void extract_init(const MeshRenderData *mr,
- struct MeshBatchCache *cache,
+ MeshBatchCache *cache,
ExtractorRunDatas &extractors,
MeshBufferList *mbuflist,
void *data_stack)
@@ -209,7 +209,7 @@ BLI_INLINE void extract_init(const MeshRenderData *mr,
}
BLI_INLINE void extract_finish(const MeshRenderData *mr,
- struct MeshBatchCache *cache,
+ MeshBatchCache *cache,
const ExtractorRunDatas &extractors,
void *data_stack)
{
@@ -551,22 +551,21 @@ static struct TaskNode *mesh_extract_render_data_node_create(struct TaskGraph *t
/** \name Extract Loop
* \{ */
-static 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,
- const float obmat[4][4],
- const bool do_final,
- const bool do_uvedit,
- const bool use_subsurf_fdots,
- const Scene *scene,
- const ToolSettings *ts,
- const bool use_hide)
+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,
+ const float obmat[4][4],
+ const bool do_final,
+ const bool do_uvedit,
+ const Scene *scene,
+ const ToolSettings *ts,
+ const bool use_hide)
{
/* For each mesh where batches needs to be updated a sub-graph will be added to the task_graph.
* This sub-graph starts with an extract_render_data_node. This fills/converts the required
@@ -687,7 +686,7 @@ static void mesh_buffer_cache_create_requested(struct TaskGraph *task_graph,
MeshRenderData *mr = mesh_render_data_create(
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_subsurf_fdots = mr->me && mr->me->runtime.subsurf_face_dot_tags != nullptr;
mr->use_final_mesh = do_final;
#ifdef DEBUG_TIME
@@ -773,10 +772,10 @@ 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,
- MeshRenderData *mr)
+void mesh_buffer_cache_create_requested_subdiv(MeshBatchCache *cache,
+ MeshBufferCache *mbc,
+ DRWSubdivCache *subdiv_cache,
+ MeshRenderData *mr)
{
/* Create an array containing all the extractors that needs to be executed. */
ExtractorRunDatas extractors;
@@ -794,7 +793,12 @@ static void mesh_buffer_cache_create_requested_subdiv(MeshBatchCache *cache,
/* 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);
+
+ /* Orcos are extracted at the same time as positions. */
+ if (DRW_vbo_requested(mbuflist->vbo.pos_nor) || DRW_vbo_requested(mbuflist->vbo.orco)) {
+ extractors.append(&extract_pos_nor);
+ }
+
EXTRACT_ADD_REQUESTED(vbo, lnor);
for (int i = 0; i < GPU_MAX_ATTR; i++) {
EXTRACT_ADD_REQUESTED(vbo, attr[i]);
@@ -844,7 +848,6 @@ static void mesh_buffer_cache_create_requested_subdiv(MeshBatchCache *cache,
EXTRACT_ADD_REQUESTED(vbo, edituv_stretch_angle);
EXTRACT_ADD_REQUESTED(ibo, lines_paint_mask);
EXTRACT_ADD_REQUESTED(ibo, lines_adjacency);
- EXTRACT_ADD_REQUESTED(vbo, orco);
EXTRACT_ADD_REQUESTED(vbo, vcol);
EXTRACT_ADD_REQUESTED(vbo, weights);
EXTRACT_ADD_REQUESTED(vbo, sculpt_data);
@@ -905,48 +908,3 @@ static void mesh_buffer_cache_create_requested_subdiv(MeshBatchCache *cache,
/** \} */
} // 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,
- const bool is_paint_mode,
- const bool is_mode_active,
- const float obmat[4][4],
- const bool do_final,
- const bool do_uvedit,
- const bool use_subsurf_fdots,
- const Scene *scene,
- const ToolSettings *ts,
- const bool use_hide)
-{
- blender::draw::mesh_buffer_cache_create_requested(task_graph,
- cache,
- mbc,
- object,
- me,
- is_editmode,
- is_paint_mode,
- is_mode_active,
- obmat,
- do_final,
- do_uvedit,
- use_subsurf_fdots,
- scene,
- ts,
- use_hide);
-}
-
-void mesh_buffer_cache_create_requested_subdiv(MeshBatchCache *cache,
- MeshBufferCache *mbc,
- DRWSubdivCache *subdiv_cache,
- MeshRenderData *mr)
-{
- blender::draw::mesh_buffer_cache_create_requested_subdiv(cache, mbc, subdiv_cache, mr);
-}
-
-} // 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.cc
index 0a93f346b37..baea0c7b646 100644
--- a/source/blender/draw/intern/draw_cache_extract_mesh_render_data.c
+++ b/source/blender/draw/intern/draw_cache_extract_mesh_render_data.cc
@@ -9,7 +9,7 @@
#include "MEM_guardedalloc.h"
-#include "BLI_alloca.h"
+#include "BLI_array.hh"
#include "BLI_bitmap.h"
#include "BLI_math.h"
#include "BLI_task.h"
@@ -22,7 +22,7 @@
#include "ED_mesh.h"
-#include "mesh_extractors/extract_mesh.h"
+#include "mesh_extractors/extract_mesh.hh"
/* ---------------------------------------------------------------------- */
/** \name Update Loose Geometry
@@ -78,7 +78,8 @@ static void mesh_render_data_loose_geom_mesh(const MeshRenderData *mr, MeshBuffe
{
BLI_bitmap *lvert_map = BLI_BITMAP_NEW(mr->vert_len, __func__);
- cache->loose_geom.edges = MEM_mallocN(mr->edge_len * sizeof(*cache->loose_geom.edges), __func__);
+ cache->loose_geom.edges = static_cast<int *>(
+ MEM_mallocN(mr->edge_len * sizeof(*cache->loose_geom.edges), __func__));
const MEdge *med = mr->medge;
for (int med_index = 0; med_index < mr->edge_len; med_index++, med++) {
if (med->flag & ME_LOOSEEDGE) {
@@ -89,19 +90,20 @@ static void mesh_render_data_loose_geom_mesh(const MeshRenderData *mr, MeshBuffe
BLI_BITMAP_ENABLE(lvert_map, med->v2);
}
if (cache->loose_geom.edge_len < mr->edge_len) {
- cache->loose_geom.edges = MEM_reallocN(
- cache->loose_geom.edges, cache->loose_geom.edge_len * sizeof(*cache->loose_geom.edges));
+ cache->loose_geom.edges = static_cast<int *>(MEM_reallocN(
+ cache->loose_geom.edges, cache->loose_geom.edge_len * sizeof(*cache->loose_geom.edges)));
}
- cache->loose_geom.verts = MEM_mallocN(mr->vert_len * sizeof(*cache->loose_geom.verts), __func__);
+ cache->loose_geom.verts = static_cast<int *>(
+ MEM_mallocN(mr->vert_len * sizeof(*cache->loose_geom.verts), __func__));
for (int v = 0; v < mr->vert_len; v++) {
if (!BLI_BITMAP_TEST(lvert_map, v)) {
cache->loose_geom.verts[cache->loose_geom.vert_len++] = v;
}
}
if (cache->loose_geom.vert_len < mr->vert_len) {
- cache->loose_geom.verts = MEM_reallocN(
- cache->loose_geom.verts, cache->loose_geom.vert_len * sizeof(*cache->loose_geom.verts));
+ cache->loose_geom.verts = static_cast<int *>(MEM_reallocN(
+ cache->loose_geom.verts, cache->loose_geom.vert_len * sizeof(*cache->loose_geom.verts)));
}
MEM_freeN(lvert_map);
@@ -112,15 +114,16 @@ static void mesh_render_data_lverts_bm(const MeshRenderData *mr, MeshBufferCache
int elem_id;
BMIter iter;
BMVert *eve;
- cache->loose_geom.verts = MEM_mallocN(mr->vert_len * sizeof(*cache->loose_geom.verts), __func__);
+ cache->loose_geom.verts = static_cast<int *>(
+ MEM_mallocN(mr->vert_len * sizeof(*cache->loose_geom.verts), __func__));
BM_ITER_MESH_INDEX (eve, &iter, bm, BM_VERTS_OF_MESH, elem_id) {
- if (eve->e == NULL) {
+ if (eve->e == nullptr) {
cache->loose_geom.verts[cache->loose_geom.vert_len++] = elem_id;
}
}
if (cache->loose_geom.vert_len < mr->vert_len) {
- cache->loose_geom.verts = MEM_reallocN(
- cache->loose_geom.verts, cache->loose_geom.vert_len * sizeof(*cache->loose_geom.verts));
+ cache->loose_geom.verts = static_cast<int *>(MEM_reallocN(
+ cache->loose_geom.verts, cache->loose_geom.vert_len * sizeof(*cache->loose_geom.verts)));
}
}
@@ -129,15 +132,16 @@ static void mesh_render_data_ledges_bm(const MeshRenderData *mr, MeshBufferCache
int elem_id;
BMIter iter;
BMEdge *ede;
- cache->loose_geom.edges = MEM_mallocN(mr->edge_len * sizeof(*cache->loose_geom.edges), __func__);
+ cache->loose_geom.edges = static_cast<int *>(
+ MEM_mallocN(mr->edge_len * sizeof(*cache->loose_geom.edges), __func__));
BM_ITER_MESH_INDEX (ede, &iter, bm, BM_EDGES_OF_MESH, elem_id) {
- if (ede->l == NULL) {
+ if (ede->l == nullptr) {
cache->loose_geom.edges[cache->loose_geom.edge_len++] = elem_id;
}
}
if (cache->loose_geom.edge_len < mr->edge_len) {
- cache->loose_geom.edges = MEM_reallocN(
- cache->loose_geom.edges, cache->loose_geom.edge_len * sizeof(*cache->loose_geom.edges));
+ cache->loose_geom.edges = static_cast<int *>(MEM_reallocN(
+ cache->loose_geom.edges, cache->loose_geom.edge_len * sizeof(*cache->loose_geom.edges)));
}
}
@@ -192,12 +196,13 @@ static void mesh_render_data_polys_sorted_ensure(MeshRenderData *mr, MeshBufferC
static void mesh_render_data_polys_sorted_build(MeshRenderData *mr, MeshBufferCache *cache)
{
- int *tri_first_index = MEM_mallocN(sizeof(*tri_first_index) * mr->poly_len, __func__);
+ int *tri_first_index = static_cast<int *>(
+ MEM_mallocN(sizeof(*tri_first_index) * mr->poly_len, __func__));
int *mat_tri_len = mesh_render_data_mat_tri_len_build(mr);
/* Apply offset. */
int visible_tri_len = 0;
- int *mat_tri_offs = BLI_array_alloca(mat_tri_offs, mr->mat_len);
+ blender::Array<int, 32> mat_tri_offs(mr->mat_len);
{
for (int i = 0; i < mr->mat_len; i++) {
mat_tri_offs[i] = visible_tri_len;
@@ -245,8 +250,8 @@ static void mesh_render_data_mat_tri_len_bm_range_fn(void *__restrict userdata,
const int iter,
const TaskParallelTLS *__restrict tls)
{
- MeshRenderData *mr = userdata;
- int *mat_tri_len = tls->userdata_chunk;
+ MeshRenderData *mr = static_cast<MeshRenderData *>(userdata);
+ int *mat_tri_len = static_cast<int *>(tls->userdata_chunk);
BMesh *bm = mr->bm;
BMFace *efa = BM_face_at_index(bm, iter);
@@ -260,8 +265,8 @@ static void mesh_render_data_mat_tri_len_mesh_range_fn(void *__restrict userdata
const int iter,
const TaskParallelTLS *__restrict tls)
{
- MeshRenderData *mr = userdata;
- int *mat_tri_len = tls->userdata_chunk;
+ MeshRenderData *mr = static_cast<MeshRenderData *>(userdata);
+ int *mat_tri_len = static_cast<int *>(tls->userdata_chunk);
const MPoly *mp = &mr->mpoly[iter];
if (!(mr->use_hide && (mp->flag & ME_HIDE))) {
@@ -274,9 +279,9 @@ static void mesh_render_data_mat_tri_len_reduce_fn(const void *__restrict userda
void *__restrict chunk_join,
void *__restrict chunk)
{
- const MeshRenderData *mr = userdata;
- int *dst_mat_len = chunk_join;
- int *src_mat_len = chunk;
+ const MeshRenderData *mr = static_cast<const MeshRenderData *>(userdata);
+ int *dst_mat_len = static_cast<int *>(chunk_join);
+ int *src_mat_len = static_cast<int *>(chunk);
for (int i = 0; i < mr->mat_len; i++) {
dst_mat_len[i] += src_mat_len[i];
}
@@ -288,7 +293,7 @@ static int *mesh_render_data_mat_tri_len_build_threaded(MeshRenderData *mr,
{
/* Extending the #MatOffsetUserData with an int per material slot. */
size_t mat_tri_len_size = sizeof(int) * mr->mat_len;
- int *mat_tri_len = MEM_callocN(mat_tri_len_size, __func__);
+ int *mat_tri_len = static_cast<int *>(MEM_callocN(mat_tri_len_size, __func__));
TaskParallelSettings settings;
BLI_parallel_range_settings_defaults(&settings);
@@ -330,8 +335,9 @@ void mesh_render_data_update_looptris(MeshRenderData *mr,
/* NOTE(campbell): It's possible to skip allocating tessellation,
* the tessellation can be calculated as part of the iterator, see: P2188.
* The overall advantage is small (around 1%), so keep this as-is. */
- mr->mlooptri = MEM_mallocN(sizeof(*mr->mlooptri) * mr->tri_len, "MR_DATATYPE_LOOPTRI");
- if (mr->poly_normals != NULL) {
+ mr->mlooptri = static_cast<MLoopTri *>(
+ MEM_mallocN(sizeof(*mr->mlooptri) * mr->tri_len, "MR_DATATYPE_LOOPTRI"));
+ if (mr->poly_normals != nullptr) {
BKE_mesh_recalc_looptri_with_normals(me->mloop,
me->mpoly,
me->mvert,
@@ -350,7 +356,7 @@ void mesh_render_data_update_looptris(MeshRenderData *mr,
/* #BMesh */
if ((iter_type & MR_ITER_LOOPTRI) || (data_flag & MR_DATA_LOOPTRI)) {
/* Edit mode ensures this is valid, no need to calculate. */
- BLI_assert((mr->bm->totloop == 0) || (mr->edit_bmesh->looptris != NULL));
+ BLI_assert((mr->bm->totloop == 0) || (mr->edit_bmesh->looptris != nullptr));
}
}
}
@@ -368,8 +374,10 @@ void mesh_render_data_update_normals(MeshRenderData *mr, const eMRDataType data_
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);
+ mr->loop_normals = static_cast<float(*)[3]>(
+ MEM_mallocN(sizeof(*mr->loop_normals) * mr->loop_len, __func__));
+ short(*clnors)[2] = static_cast<short(*)[2]>(
+ CustomData_get_layer(&mr->me->ldata, CD_CUSTOMLOOPNORMAL));
BKE_mesh_normals_loop_split(mr->me->mvert,
mr->vert_normals,
mr->vert_len,
@@ -383,9 +391,9 @@ void mesh_render_data_update_normals(MeshRenderData *mr, const eMRDataType data_
mr->poly_len,
is_auto_smooth,
split_angle,
- NULL,
+ nullptr,
clnors,
- NULL);
+ nullptr);
}
}
else {
@@ -395,9 +403,9 @@ void mesh_render_data_update_normals(MeshRenderData *mr, const eMRDataType data_
}
if (((data_flag & MR_DATA_LOOP_NOR) && is_auto_smooth) || (data_flag & MR_DATA_TAN_LOOP_NOR)) {
- const float(*vert_coords)[3] = NULL;
- const float(*vert_normals)[3] = NULL;
- const float(*poly_normals)[3] = NULL;
+ const float(*vert_coords)[3] = nullptr;
+ const float(*vert_normals)[3] = nullptr;
+ const float(*poly_normals)[3] = nullptr;
if (mr->edit_data && mr->edit_data->vertexCos) {
vert_coords = mr->bm_vert_coords;
@@ -405,7 +413,8 @@ void mesh_render_data_update_normals(MeshRenderData *mr, const eMRDataType data_
poly_normals = mr->bm_poly_normals;
}
- mr->loop_normals = MEM_mallocN(sizeof(*mr->loop_normals) * mr->loop_len, __func__);
+ mr->loop_normals = static_cast<float(*)[3]>(
+ MEM_mallocN(sizeof(*mr->loop_normals) * mr->loop_len, __func__));
const int clnors_offset = CustomData_get_offset(&mr->bm->ldata, CD_CUSTOMLOOPNORMAL);
BM_loops_calc_normal_vcos(mr->bm,
vert_coords,
@@ -414,8 +423,8 @@ void mesh_render_data_update_normals(MeshRenderData *mr, const eMRDataType data_
is_auto_smooth,
split_angle,
mr->loop_normals,
- NULL,
- NULL,
+ nullptr,
+ nullptr,
clnors_offset,
false);
}
@@ -432,7 +441,7 @@ MeshRenderData *mesh_render_data_create(Object *object,
const bool do_uvedit,
const ToolSettings *ts)
{
- MeshRenderData *mr = MEM_callocN(sizeof(*mr), __func__);
+ MeshRenderData *mr = static_cast<MeshRenderData *>(MEM_callocN(sizeof(*mr), __func__));
mr->toolsettings = ts;
mr->mat_len = mesh_render_mat_len_get(object, me);
@@ -446,7 +455,7 @@ MeshRenderData *mesh_render_data_create(Object *object,
mr->bm = me->edit_mesh->bm;
mr->edit_bmesh = me->edit_mesh;
mr->me = (do_final) ? editmesh_eval_final : editmesh_eval_cage;
- mr->edit_data = is_mode_active ? mr->me->runtime.edit_data : NULL;
+ mr->edit_data = is_mode_active ? mr->me->runtime.edit_data : nullptr;
if (mr->edit_data) {
EditMeshData *emd = mr->edit_data;
@@ -491,9 +500,12 @@ MeshRenderData *mesh_render_data_create(Object *object,
#endif
if (use_mapped) {
- mr->v_origindex = CustomData_get_layer(&mr->me->vdata, CD_ORIGINDEX);
- mr->e_origindex = CustomData_get_layer(&mr->me->edata, CD_ORIGINDEX);
- mr->p_origindex = CustomData_get_layer(&mr->me->pdata, CD_ORIGINDEX);
+ mr->v_origindex = static_cast<const int *>(
+ CustomData_get_layer(&mr->me->vdata, CD_ORIGINDEX));
+ mr->e_origindex = static_cast<const int *>(
+ CustomData_get_layer(&mr->me->edata, CD_ORIGINDEX));
+ mr->p_origindex = static_cast<const int *>(
+ CustomData_get_layer(&mr->me->pdata, CD_ORIGINDEX));
use_mapped = (mr->v_origindex || mr->e_origindex || mr->p_origindex);
}
@@ -503,19 +515,22 @@ MeshRenderData *mesh_render_data_create(Object *object,
/* Seems like the mesh_eval_final do not have the right origin indices.
* Force not mapped in this case. */
if (has_mdata && do_final && editmesh_eval_final != editmesh_eval_cage) {
- // mr->edit_bmesh = NULL;
+ // mr->edit_bmesh = nullptr;
mr->extract_type = MR_EXTRACT_MESH;
}
}
else {
mr->me = me;
- mr->edit_bmesh = NULL;
+ mr->edit_bmesh = nullptr;
bool use_mapped = is_paint_mode && mr->me && !mr->me->runtime.is_original;
if (use_mapped) {
- mr->v_origindex = CustomData_get_layer(&mr->me->vdata, CD_ORIGINDEX);
- mr->e_origindex = CustomData_get_layer(&mr->me->edata, CD_ORIGINDEX);
- mr->p_origindex = CustomData_get_layer(&mr->me->pdata, CD_ORIGINDEX);
+ mr->v_origindex = static_cast<const int *>(
+ CustomData_get_layer(&mr->me->vdata, CD_ORIGINDEX));
+ mr->e_origindex = static_cast<const int *>(
+ CustomData_get_layer(&mr->me->edata, CD_ORIGINDEX));
+ mr->p_origindex = static_cast<const int *>(
+ CustomData_get_layer(&mr->me->pdata, CD_ORIGINDEX));
use_mapped = (mr->v_origindex || mr->e_origindex || mr->p_origindex);
}
@@ -531,14 +546,14 @@ MeshRenderData *mesh_render_data_create(Object *object,
mr->poly_len = mr->me->totpoly;
mr->tri_len = poly_to_tri_count(mr->poly_len, mr->loop_len);
- mr->mvert = CustomData_get_layer(&mr->me->vdata, CD_MVERT);
- mr->medge = CustomData_get_layer(&mr->me->edata, CD_MEDGE);
- mr->mloop = CustomData_get_layer(&mr->me->ldata, CD_MLOOP);
- mr->mpoly = CustomData_get_layer(&mr->me->pdata, CD_MPOLY);
+ mr->mvert = static_cast<MVert *>(CustomData_get_layer(&mr->me->vdata, CD_MVERT));
+ mr->medge = static_cast<MEdge *>(CustomData_get_layer(&mr->me->edata, CD_MEDGE));
+ mr->mloop = static_cast<MLoop *>(CustomData_get_layer(&mr->me->ldata, CD_MLOOP));
+ mr->mpoly = static_cast<MPoly *>(CustomData_get_layer(&mr->me->pdata, CD_MPOLY));
- mr->v_origindex = CustomData_get_layer(&mr->me->vdata, CD_ORIGINDEX);
- mr->e_origindex = CustomData_get_layer(&mr->me->edata, CD_ORIGINDEX);
- mr->p_origindex = CustomData_get_layer(&mr->me->pdata, CD_ORIGINDEX);
+ mr->v_origindex = static_cast<const int *>(CustomData_get_layer(&mr->me->vdata, CD_ORIGINDEX));
+ mr->e_origindex = static_cast<const int *>(CustomData_get_layer(&mr->me->edata, CD_ORIGINDEX));
+ mr->p_origindex = static_cast<const int *>(CustomData_get_layer(&mr->me->pdata, CD_ORIGINDEX));
}
else {
/* #BMesh */
@@ -560,8 +575,8 @@ void mesh_render_data_free(MeshRenderData *mr)
MEM_SAFE_FREE(mr->loop_normals);
/* Loose geometry are owned by #MeshBufferCache. */
- mr->ledges = NULL;
- mr->lverts = NULL;
+ mr->ledges = nullptr;
+ mr->lverts = nullptr;
MEM_freeN(mr);
}
diff --git a/source/blender/draw/intern/draw_cache_impl.h b/source/blender/draw/intern/draw_cache_impl.h
index f877c94208f..4fa5813d476 100644
--- a/source/blender/draw/intern/draw_cache_impl.h
+++ b/source/blender/draw/intern/draw_cache_impl.h
@@ -83,6 +83,7 @@ void DRW_batch_cache_free_old(struct Object *ob, int ctime);
* \note For now this only free the shading batches / VBO if any cd layers is not needed anymore.
*/
void DRW_mesh_batch_cache_free_old(struct Mesh *me, int ctime);
+void DRW_curves_batch_cache_free_old(struct Curves *curves, int ctime);
/** \} */
@@ -155,11 +156,15 @@ struct GPUBatch *DRW_lattice_batch_cache_get_edit_verts(struct Lattice *lt);
/** \} */
/* -------------------------------------------------------------------- */
-/** \name Hair
+/** \name Curves
* \{ */
int DRW_curves_material_count_get(struct Curves *curves);
+struct GPUBatch *DRW_curves_batch_cache_get_edit_points(struct Curves *curves);
+
+void DRW_curves_batch_cache_create_requested(struct Object *ob);
+
/** \} */
/* -------------------------------------------------------------------- */
@@ -351,16 +356,6 @@ struct GPUBatch *DRW_particles_batch_cache_get_edit_tip_points(struct Object *ob
/** \} */
-/* -------------------------------------------------------------------- */
-/** \name Curves
- * \{ */
-
-struct GPUBatch *DRW_curves_batch_cache_get_edit_points(struct Curves *curves);
-
-void DRW_curves_batch_cache_create_requested(const struct Object *ob);
-
-/** \} */
-
#ifdef __cplusplus
}
#endif
diff --git a/source/blender/draw/intern/draw_cache_impl_curve.cc b/source/blender/draw/intern/draw_cache_impl_curve.cc
index 7b8f34b999c..ebcdabe4942 100644
--- a/source/blender/draw/intern/draw_cache_impl_curve.cc
+++ b/source/blender/draw/intern/draw_cache_impl_curve.cc
@@ -108,7 +108,7 @@ static void curve_eval_render_wire_verts_edges_len_get(const blender::bke::Curve
const blender::VArray<bool> cyclic = curves.cyclic();
for (const int i : curves.curves_range()) {
const IndexRange points = curves.evaluated_points_for_curve(i);
- *r_edge_len += blender::bke::curves::curve_segment_size(points.size(), cyclic[i]);
+ *r_edge_len += blender::bke::curves::curve_segment_num(points.size(), cyclic[i]);
}
}
diff --git a/source/blender/draw/intern/draw_cache_impl_curves.cc b/source/blender/draw/intern/draw_cache_impl_curves.cc
index f2742f3bcc7..ee81f74ca26 100644
--- a/source/blender/draw/intern/draw_cache_impl_curves.cc
+++ b/source/blender/draw/intern/draw_cache_impl_curves.cc
@@ -24,6 +24,7 @@
#include "DNA_scene_types.h"
#include "BKE_curves.hh"
+#include "BKE_geometry_set.hh"
#include "GPU_batch.h"
#include "GPU_material.h"
@@ -31,12 +32,16 @@
#include "DRW_render.h"
+#include "draw_attributes.h"
#include "draw_cache_impl.h" /* own include */
#include "draw_cache_inline.h"
#include "draw_curves_private.h" /* own include */
+#include "draw_shader.h"
+using blender::ColorGeometry4f;
using blender::float3;
using blender::IndexRange;
+using blender::MutableSpan;
using blender::Span;
/* ---------------------------------------------------------------------- */
@@ -47,8 +52,15 @@ struct CurvesBatchCache {
GPUBatch *edit_points;
- /* To determine if cache is invalid. */
+ /* Whether the cache is invalid. */
bool is_dirty;
+
+ /**
+ * The draw cache extraction is currently not multi-threaded for multiple objects, but if it was,
+ * some locking would be necessary because multiple objects can use the same curves data with
+ * different materials, etc. This is a placeholder to make multi-threading easier in the future.
+ */
+ ThreadMutex render_mutex;
};
static bool curves_batch_cache_valid(const Curves &curves)
@@ -63,6 +75,7 @@ static void curves_batch_cache_init(Curves &curves)
if (!cache) {
cache = MEM_cnew<CurvesBatchCache>(__func__);
+ BLI_mutex_init(&cache->render_mutex);
curves.batch_cache = cache;
}
else {
@@ -72,6 +85,23 @@ static void curves_batch_cache_init(Curves &curves)
cache->is_dirty = false;
}
+static void curves_discard_attributes(CurvesEvalCache &curves_cache)
+{
+ for (const int i : IndexRange(GPU_MAX_ATTR)) {
+ GPU_VERTBUF_DISCARD_SAFE(curves_cache.proc_attributes_buf[i]);
+ DRW_TEXTURE_FREE_SAFE(curves_cache.proc_attributes_tex[i]);
+ }
+
+ for (const int i : IndexRange(MAX_HAIR_SUBDIV)) {
+ for (const int j : IndexRange(GPU_MAX_ATTR)) {
+ GPU_VERTBUF_DISCARD_SAFE(curves_cache.final[i].attributes_buf[j]);
+ DRW_TEXTURE_FREE_SAFE(curves_cache.final[i].attributes_tex[j]);
+ }
+
+ drw_attributes_clear(&curves_cache.final[i].attr_used);
+ }
+}
+
static void curves_batch_cache_clear_data(CurvesEvalCache &curves_cache)
{
/* TODO: more granular update tagging. */
@@ -85,13 +115,15 @@ static void curves_batch_cache_clear_data(CurvesEvalCache &curves_cache)
DRW_TEXTURE_FREE_SAFE(curves_cache.strand_tex);
DRW_TEXTURE_FREE_SAFE(curves_cache.strand_seg_tex);
- for (int i = 0; i < MAX_HAIR_SUBDIV; i++) {
+ for (const int i : IndexRange(MAX_HAIR_SUBDIV)) {
GPU_VERTBUF_DISCARD_SAFE(curves_cache.final[i].proc_buf);
DRW_TEXTURE_FREE_SAFE(curves_cache.final[i].proc_tex);
- for (int j = 0; j < MAX_THICKRES; j++) {
+ for (const int j : IndexRange(MAX_THICKRES)) {
GPU_BATCH_DISCARD_SAFE(curves_cache.final[i].proc_hairs[j]);
}
}
+
+ curves_discard_attributes(curves_cache);
}
static void curves_batch_cache_clear(Curves &curves)
@@ -131,62 +163,96 @@ void DRW_curves_batch_cache_dirty_tag(Curves *curves, int mode)
cache->is_dirty = true;
break;
default:
- BLI_assert(0);
+ BLI_assert_unreachable();
}
}
void DRW_curves_batch_cache_free(Curves *curves)
{
curves_batch_cache_clear(*curves);
+ CurvesBatchCache *cache = static_cast<CurvesBatchCache *>(curves->batch_cache);
+ BLI_mutex_end(&cache->render_mutex);
MEM_SAFE_FREE(curves->batch_cache);
}
+void DRW_curves_batch_cache_free_old(Curves *curves, int ctime)
+{
+ CurvesBatchCache *cache = static_cast<CurvesBatchCache *>(curves->batch_cache);
+ if (cache == nullptr) {
+ return;
+ }
+
+ bool do_discard = false;
+
+ for (const int i : IndexRange(MAX_HAIR_SUBDIV)) {
+ CurvesEvalFinalCache &final_cache = cache->curves_cache.final[i];
+
+ if (drw_attributes_overlap(&final_cache.attr_used_over_time, &final_cache.attr_used)) {
+ final_cache.last_attr_matching_time = ctime;
+ }
+
+ if (ctime - final_cache.last_attr_matching_time > U.vbotimeout) {
+ do_discard = true;
+ }
+
+ drw_attributes_clear(&final_cache.attr_used_over_time);
+ }
+
+ if (do_discard) {
+ curves_discard_attributes(cache->curves_cache);
+ }
+}
+
static void ensure_seg_pt_count(const Curves &curves, CurvesEvalCache &curves_cache)
{
if (curves_cache.proc_point_buf != nullptr) {
return;
}
- curves_cache.strands_len = curves.geometry.curve_size;
- curves_cache.elems_len = curves.geometry.point_size + curves.geometry.curve_size;
- curves_cache.point_len = curves.geometry.point_size;
+ curves_cache.strands_len = curves.geometry.curve_num;
+ curves_cache.elems_len = curves.geometry.point_num + curves.geometry.curve_num;
+ curves_cache.point_len = curves.geometry.point_num;
}
-static void curves_batch_cache_fill_segments_proc_pos(const Curves &curves_id,
- GPUVertBufRaw &attr_step,
- GPUVertBufRaw &length_step)
+struct PositionAndParameter {
+ float3 position;
+ float parameter;
+};
+
+static void curves_batch_cache_fill_segments_proc_pos(
+ const Curves &curves_id,
+ MutableSpan<PositionAndParameter> posTime_data,
+ MutableSpan<float> hairLength_data)
{
/* TODO: use hair radius layer if available. */
- const int curve_size = curves_id.geometry.curve_size;
+ const int curve_num = curves_id.geometry.curve_num;
const blender::bke::CurvesGeometry &curves = blender::bke::CurvesGeometry::wrap(
curves_id.geometry);
Span<float3> positions = curves.positions();
- for (const int i : IndexRange(curve_size)) {
- const IndexRange curve_range = curves.points_for_curve(i);
+ for (const int i_curve : IndexRange(curve_num)) {
+ const IndexRange points = curves.points_for_curve(i_curve);
+
+ Span<float3> curve_positions = positions.slice(points);
+ MutableSpan<PositionAndParameter> curve_posTime_data = posTime_data.slice(points);
- Span<float3> curve_positions = positions.slice(curve_range);
float total_len = 0.0f;
- float *seg_data_first;
- for (const int i_curve : curve_positions.index_range()) {
- float *seg_data = (float *)GPU_vertbuf_raw_step(&attr_step);
- copy_v3_v3(seg_data, curve_positions[i_curve]);
- if (i_curve == 0) {
- seg_data_first = seg_data;
- }
- else {
- total_len += blender::math::distance(curve_positions[i_curve - 1],
- curve_positions[i_curve]);
+ for (const int i_point : curve_positions.index_range()) {
+ if (i_point > 0) {
+ total_len += blender::math::distance(curve_positions[i_point - 1],
+ curve_positions[i_point]);
}
- seg_data[3] = total_len;
+ curve_posTime_data[i_point].position = curve_positions[i_point];
+ curve_posTime_data[i_point].parameter = total_len;
}
+ hairLength_data[i_curve] = total_len;
+
/* Assign length value. */
- *(float *)GPU_vertbuf_raw_step(&length_step) = total_len;
if (total_len > 0.0f) {
+ const float factor = 1.0f / total_len;
/* Divide by total length to have a [0-1] number. */
- for ([[maybe_unused]] const int i_curve : curve_positions.index_range()) {
- seg_data_first[3] /= total_len;
- seg_data_first += 4;
+ for (const int i_point : curve_positions.index_range()) {
+ curve_posTime_data[i_point].parameter *= factor;
}
}
}
@@ -199,26 +265,26 @@ static void curves_batch_cache_ensure_procedural_pos(Curves &curves,
if (cache.proc_point_buf == nullptr || DRW_vbo_requested(cache.proc_point_buf)) {
/* Initialize vertex format. */
GPUVertFormat format = {0};
- uint pos_id = GPU_vertformat_attr_add(&format, "posTime", GPU_COMP_F32, 4, GPU_FETCH_FLOAT);
+ GPU_vertformat_attr_add(&format, "posTime", GPU_COMP_F32, 4, GPU_FETCH_FLOAT);
GPU_vertformat_alias_add(&format, "pos");
cache.proc_point_buf = GPU_vertbuf_create_with_format(&format);
GPU_vertbuf_data_alloc(cache.proc_point_buf, cache.point_len);
- GPUVertBufRaw point_step;
- GPU_vertbuf_attr_get_raw_data(cache.proc_point_buf, pos_id, &point_step);
+ MutableSpan posTime_data{
+ reinterpret_cast<PositionAndParameter *>(GPU_vertbuf_get_data(cache.proc_point_buf)),
+ cache.point_len};
GPUVertFormat length_format = {0};
- uint length_id = GPU_vertformat_attr_add(
- &length_format, "hairLength", GPU_COMP_F32, 1, GPU_FETCH_FLOAT);
+ GPU_vertformat_attr_add(&length_format, "hairLength", GPU_COMP_F32, 1, GPU_FETCH_FLOAT);
cache.proc_length_buf = GPU_vertbuf_create_with_format(&length_format);
GPU_vertbuf_data_alloc(cache.proc_length_buf, cache.strands_len);
- GPUVertBufRaw length_step;
- GPU_vertbuf_attr_get_raw_data(cache.proc_length_buf, length_id, &length_step);
+ MutableSpan hairLength_data{
+ reinterpret_cast<float *>(GPU_vertbuf_get_data(cache.proc_length_buf)), cache.strands_len};
- curves_batch_cache_fill_segments_proc_pos(curves, point_step, length_step);
+ curves_batch_cache_fill_segments_proc_pos(curves, posTime_data, hairLength_data);
/* Create vbo immediately to bind to texture buffer. */
GPU_vertbuf_use(cache.proc_point_buf);
@@ -237,6 +303,88 @@ static void curves_batch_cache_ensure_procedural_pos(Curves &curves,
}
}
+void drw_curves_get_attribute_sampler_name(const char *layer_name, char r_sampler_name[32])
+{
+ char attr_safe_name[GPU_MAX_SAFE_ATTR_NAME];
+ GPU_vertformat_safe_attr_name(layer_name, attr_safe_name, GPU_MAX_SAFE_ATTR_NAME);
+ /* Attributes use auto-name. */
+ BLI_snprintf(r_sampler_name, 32, "a%s", attr_safe_name);
+}
+
+static void curves_batch_cache_ensure_procedural_final_attr(
+ CurvesEvalCache &cache, GPUVertFormat *format, int subdiv, int index, const char *name)
+{
+ CurvesEvalFinalCache &final_cache = cache.final[subdiv];
+ final_cache.attributes_buf[index] = GPU_vertbuf_create_with_format_ex(format,
+ GPU_USAGE_DEVICE_ONLY);
+
+ /* Create a destination buffer for the transform feedback. Sized appropriately */
+ /* Those are points! not line segments. */
+ GPU_vertbuf_data_alloc(final_cache.attributes_buf[index],
+ final_cache.strands_res * cache.strands_len);
+
+ /* Create vbo immediately to bind to texture buffer. */
+ GPU_vertbuf_use(final_cache.attributes_buf[index]);
+
+ final_cache.attributes_tex[index] = GPU_texture_create_from_vertbuf(
+ name, final_cache.attributes_buf[index]);
+}
+
+static void curves_batch_ensure_attribute(const Curves &curves,
+ CurvesEvalCache &cache,
+ const DRW_AttributeRequest &request,
+ int subdiv,
+ int index)
+{
+ GPU_VERTBUF_DISCARD_SAFE(cache.proc_attributes_buf[index]);
+ DRW_TEXTURE_FREE_SAFE(cache.proc_attributes_tex[index]);
+
+ char sampler_name[32];
+ drw_curves_get_attribute_sampler_name(request.attribute_name, sampler_name);
+
+ GPUVertFormat format = {0};
+ GPU_vertformat_deinterleave(&format);
+ /* All attributes use vec4, see comment below. */
+ GPU_vertformat_attr_add(&format, sampler_name, GPU_COMP_F32, 4, GPU_FETCH_FLOAT);
+
+ cache.proc_attributes_buf[index] = GPU_vertbuf_create_with_format(&format);
+ GPUVertBuf *attr_vbo = cache.proc_attributes_buf[index];
+
+ GPU_vertbuf_data_alloc(attr_vbo,
+ request.domain == ATTR_DOMAIN_POINT ? curves.geometry.point_num :
+ curves.geometry.curve_num);
+
+ CurveComponent component;
+ component.replace(const_cast<Curves *>(&curves), GeometryOwnershipType::ReadOnly);
+
+ /* TODO(@kevindietrich): float4 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 Blender convention, it should be `vec4(s, s, s, 1)`. This could be resolved using a
+ * similar texture state swizzle to map the attribute correctly as for volume attributes, so we
+ * can control the conversion ourselves. */
+ blender::VArray<ColorGeometry4f> attribute = component.attribute_get_for_read<ColorGeometry4f>(
+ request.attribute_name, request.domain, {0.0f, 0.0f, 0.0f, 1.0f});
+
+ MutableSpan<ColorGeometry4f> vbo_span{
+ static_cast<ColorGeometry4f *>(GPU_vertbuf_get_data(attr_vbo)),
+ component.attribute_domain_num(request.domain)};
+
+ attribute.materialize(vbo_span);
+
+ GPU_vertbuf_use(attr_vbo);
+ cache.proc_attributes_tex[index] = GPU_texture_create_from_vertbuf(sampler_name, attr_vbo);
+
+ /* Existing final data may have been for a different attribute (with a different name or domain),
+ * free the data. */
+ GPU_VERTBUF_DISCARD_SAFE(cache.final[subdiv].attributes_buf[index]);
+ DRW_TEXTURE_FREE_SAFE(cache.final[subdiv].attributes_tex[index]);
+
+ /* Ensure final data for points. */
+ if (request.domain == ATTR_DOMAIN_POINT) {
+ curves_batch_cache_ensure_procedural_final_attr(cache, &format, subdiv, index, sampler_name);
+ }
+}
+
static void curves_batch_cache_fill_strands_data(const Curves &curves_id,
GPUVertBufRaw &data_step,
GPUVertBufRaw &seg_step)
@@ -307,7 +455,7 @@ static void curves_batch_cache_fill_segments_indices(const Curves &curves,
const int res,
GPUIndexBufBuilder &elb)
{
- const int curves_num = curves.geometry.curve_size;
+ const int curves_num = curves.geometry.curve_num;
uint curr_point = 0;
@@ -353,6 +501,68 @@ static void curves_batch_cache_ensure_procedural_indices(Curves &curves,
prim_type, vbo, GPU_indexbuf_build(&elb), GPU_BATCH_OWNS_VBO | GPU_BATCH_OWNS_INDEX);
}
+static bool curves_ensure_attributes(const Curves &curves,
+ CurvesBatchCache &cache,
+ GPUMaterial *gpu_material,
+ int subdiv)
+{
+ ThreadMutex *render_mutex = &cache.render_mutex;
+ const CustomData *cd_curve = &curves.geometry.curve_data;
+ const CustomData *cd_point = &curves.geometry.point_data;
+
+ DRW_Attributes attrs_needed;
+ drw_attributes_clear(&attrs_needed);
+ ListBase gpu_attrs = GPU_material_attributes(gpu_material);
+ LISTBASE_FOREACH (GPUMaterialAttribute *, gpu_attr, &gpu_attrs) {
+ const char *name = gpu_attr->name;
+
+ int layer_index;
+ eCustomDataType type;
+ eAttrDomain domain;
+ if (drw_custom_data_match_attribute(cd_curve, name, &layer_index, &type)) {
+ domain = ATTR_DOMAIN_CURVE;
+ }
+ else if (drw_custom_data_match_attribute(cd_point, name, &layer_index, &type)) {
+ domain = ATTR_DOMAIN_POINT;
+ }
+ else {
+ continue;
+ }
+
+ drw_attributes_add_request(&attrs_needed, name, type, layer_index, domain);
+ }
+
+ CurvesEvalFinalCache &final_cache = cache.curves_cache.final[subdiv];
+
+ if (!drw_attributes_overlap(&final_cache.attr_used, &attrs_needed)) {
+ /* Some new attributes have been added, free all and start over. */
+ for (const int i : IndexRange(GPU_MAX_ATTR)) {
+ GPU_VERTBUF_DISCARD_SAFE(cache.curves_cache.proc_attributes_buf[i]);
+ DRW_TEXTURE_FREE_SAFE(cache.curves_cache.proc_attributes_tex[i]);
+ }
+ drw_attributes_merge(&final_cache.attr_used, &attrs_needed, render_mutex);
+ }
+ drw_attributes_merge(&final_cache.attr_used_over_time, &attrs_needed, render_mutex);
+
+ bool need_tf_update = false;
+
+ for (const int i : IndexRange(final_cache.attr_used.num_requests)) {
+ const DRW_AttributeRequest &request = final_cache.attr_used.requests[i];
+
+ if (cache.curves_cache.proc_attributes_buf[i] != nullptr) {
+ continue;
+ }
+
+ if (request.domain == ATTR_DOMAIN_POINT) {
+ need_tf_update = true;
+ }
+
+ curves_batch_ensure_attribute(curves, cache.curves_cache, request, subdiv, i);
+ }
+
+ return need_tf_update;
+}
+
bool curves_ensure_procedural_data(Object *object,
CurvesEvalCache **r_hair_cache,
GPUMaterial *gpu_material,
@@ -390,6 +600,10 @@ bool curves_ensure_procedural_data(Object *object,
curves, cache.curves_cache, thickness_res, subdiv);
}
+ if (gpu_material) {
+ need_ft_update |= curves_ensure_attributes(curves, cache, gpu_material, subdiv);
+ }
+
return need_ft_update;
}
@@ -404,7 +618,7 @@ GPUBatch *DRW_curves_batch_cache_get_edit_points(Curves *curves)
return DRW_batch_request(&cache.edit_points);
}
-void DRW_curves_batch_cache_create_requested(const Object *ob)
+void DRW_curves_batch_cache_create_requested(Object *ob)
{
Curves *curves = static_cast<Curves *>(ob->data);
CurvesBatchCache &cache = curves_batch_cache_get(*curves);
diff --git a/source/blender/draw/intern/draw_cache_impl_mesh.c b/source/blender/draw/intern/draw_cache_impl_mesh.cc
index 917216b92e6..e93b1a66b66 100644
--- a/source/blender/draw/intern/draw_cache_impl_mesh.c
+++ b/source/blender/draw/intern/draw_cache_impl_mesh.cc
@@ -7,15 +7,19 @@
* \brief Mesh API for render engines
*/
+#include <optional>
+
#include "MEM_guardedalloc.h"
-#include "BLI_alloca.h"
#include "BLI_bitmap.h"
#include "BLI_buffer.h"
#include "BLI_edgehash.h"
+#include "BLI_index_range.hh"
#include "BLI_listbase.h"
+#include "BLI_map.hh"
#include "BLI_math_bits.h"
#include "BLI_math_vector.h"
+#include "BLI_span.hh"
#include "BLI_string.h"
#include "BLI_task.h"
#include "BLI_utildefines.h"
@@ -52,13 +56,17 @@
#include "ED_mesh.h"
#include "ED_uvedit.h"
-#include "draw_cache_extract.h"
+#include "draw_cache_extract.hh"
#include "draw_cache_inline.h"
#include "draw_subdivision.h"
#include "draw_cache_impl.h" /* own include */
-#include "mesh_extractors/extract_mesh.h"
+#include "mesh_extractors/extract_mesh.hh"
+
+using blender::IndexRange;
+using blender::Map;
+using blender::Span;
/* ---------------------------------------------------------------------- */
/** \name Dependencies between buffer and batch
@@ -69,21 +77,7 @@
#define BUFFER_INDEX(buff_name) ((offsetof(MeshBufferList, buff_name) - offsetof(MeshBufferList, vbo)) / sizeof(void *))
#define BUFFER_LEN (sizeof(MeshBufferList) / sizeof(void *))
-#define _BATCH_FLAG1(b) (1u << MBC_BATCH_INDEX(b))
-#define _BATCH_FLAG2(b1, b2) _BATCH_FLAG1(b1) | _BATCH_FLAG1(b2)
-#define _BATCH_FLAG3(b1, b2, b3) _BATCH_FLAG2(b1, b2) | _BATCH_FLAG1(b3)
-#define _BATCH_FLAG4(b1, b2, b3, b4) _BATCH_FLAG3(b1, b2, b3) | _BATCH_FLAG1(b4)
-#define _BATCH_FLAG5(b1, b2, b3, b4, b5) _BATCH_FLAG4(b1, b2, b3, b4) | _BATCH_FLAG1(b5)
-#define _BATCH_FLAG6(b1, b2, b3, b4, b5, b6) _BATCH_FLAG5(b1, b2, b3, b4, b5) | _BATCH_FLAG1(b6)
-#define _BATCH_FLAG7(b1, b2, b3, b4, b5, b6, b7) _BATCH_FLAG6(b1, b2, b3, b4, b5, b6) | _BATCH_FLAG1(b7)
-#define _BATCH_FLAG8(b1, b2, b3, b4, b5, b6, b7, b8) _BATCH_FLAG7(b1, b2, b3, b4, b5, b6, b7) | _BATCH_FLAG1(b8)
-#define _BATCH_FLAG9(b1, b2, b3, b4, b5, b6, b7, b8, b9) _BATCH_FLAG8(b1, b2, b3, b4, b5, b6, b7, b8) | _BATCH_FLAG1(b9)
-#define _BATCH_FLAG10(b1, b2, b3, b4, b5, b6, b7, b8, b9, b10) _BATCH_FLAG9(b1, b2, b3, b4, b5, b6, b7, b8, b9) | _BATCH_FLAG1(b10)
-#define _BATCH_FLAG18(b1, b2, b3, b4, b5, b6, b7, b8, b9, b10, b11, b12, b13, b14, b15, b16, b17, b18) _BATCH_FLAG10(b1, b2, b3, b4, b5, b6, b7, b8, b9, b10) | _BATCH_FLAG8(b11, b12, b13, b14, b15, b16, b17, b18)
-
-#define BATCH_FLAG(...) VA_NARGS_CALL_OVERLOAD(_BATCH_FLAG, __VA_ARGS__)
-
-#define _BATCH_MAP1(a) g_buffer_deps[BUFFER_INDEX(a)]
+#define _BATCH_MAP1(a) batches_that_use_buffer(BUFFER_INDEX(a))
#define _BATCH_MAP2(a, b) _BATCH_MAP1(a) | _BATCH_MAP1(b)
#define _BATCH_MAP3(a, b, c) _BATCH_MAP2(a, b) | _BATCH_MAP1(c)
#define _BATCH_MAP4(a, b, c, d) _BATCH_MAP3(a, b, c) | _BATCH_MAP1(d)
@@ -96,132 +90,110 @@
#define BATCH_MAP(...) VA_NARGS_CALL_OVERLOAD(_BATCH_MAP, __VA_ARGS__)
-#ifndef NDEBUG
-# define MDEPS_ASSERT_INDEX(buffer_index, batch_flag) \
- g_buffer_deps_d[buffer_index] |= batch_flag; \
- BLI_assert(g_buffer_deps[buffer_index] & batch_flag)
-
-# define _MDEPS_ASSERT2(b, n1) MDEPS_ASSERT_INDEX(BUFFER_INDEX(n1), b)
-# define _MDEPS_ASSERT3(b, n1, n2) _MDEPS_ASSERT2(b, n1); _MDEPS_ASSERT2(b, n2)
-# define _MDEPS_ASSERT4(b, n1, n2, n3) _MDEPS_ASSERT3(b, n1, n2); _MDEPS_ASSERT2(b, n3)
-# define _MDEPS_ASSERT5(b, n1, n2, n3, n4) _MDEPS_ASSERT4(b, n1, n2, n3); _MDEPS_ASSERT2(b, n4)
-# define _MDEPS_ASSERT6(b, n1, n2, n3, n4, n5) _MDEPS_ASSERT5(b, n1, n2, n3, n4); _MDEPS_ASSERT2(b, n5)
-# define _MDEPS_ASSERT7(b, n1, n2, n3, n4, n5, n6) _MDEPS_ASSERT6(b, n1, n2, n3, n4, n5); _MDEPS_ASSERT2(b, n6)
-# define _MDEPS_ASSERT8(b, n1, n2, n3, n4, n5, n6, n7) _MDEPS_ASSERT7(b, n1, n2, n3, n4, n5, n6); _MDEPS_ASSERT2(b, n7)
-# define _MDEPS_ASSERT21(b, n1, n2, n3, n4, n5, n6, n7, n8, n9, n10, n11, n12, n13, n14, n15, n16, n17, n18, n19, n20) _MDEPS_ASSERT8(b, n1, n2, n3, n4, n5, n6, n7); _MDEPS_ASSERT8(b, n8, n9, n10, n11, n12, n13, n14); _MDEPS_ASSERT7(b, n15, n16, n17, n18, n19, n20)
-# define _MDEPS_ASSERT22(b, n1, n2, n3, n4, n5, n6, n7, n8, n9, n10, n11, n12, n13, n14, n15, n16, n17, n18, n19, n20, n21) _MDEPS_ASSERT21(b, n1, n2, n3, n4, n5, n6, n7, n8, n9, n10, n11, n12, n13, n14, n15, n16, n17, n18, n19, n20); _MDEPS_ASSERT2(b, n21);
-
-# define MDEPS_ASSERT_FLAG(...) VA_NARGS_CALL_OVERLOAD(_MDEPS_ASSERT, __VA_ARGS__)
-# define MDEPS_ASSERT(batch_name, ...) MDEPS_ASSERT_FLAG(BATCH_FLAG(batch_name), __VA_ARGS__)
-# define MDEPS_ASSERT_MAP_INDEX(buff_index) BLI_assert(g_buffer_deps_d[buff_index] == g_buffer_deps[buff_index])
-# define MDEPS_ASSERT_MAP(buff_name) MDEPS_ASSERT_MAP_INDEX(BUFFER_INDEX(buff_name))
-#else
-# define MDEPS_ASSERT_INDEX(buffer_index, batch_flag)
-# define MDEPS_ASSERT_FLAG(...)
-# define MDEPS_ASSERT(batch_name, ...)
-# define MDEPS_ASSERT_MAP_INDEX(buff_index)
-# define MDEPS_ASSERT_MAP(buff_name)
-#endif
-
/* clang-format on */
#define TRIS_PER_MAT_INDEX BUFFER_LEN
-#define SURFACE_PER_MAT_FLAG (1u << MBC_BATCH_LEN)
-
-static const DRWBatchFlag g_buffer_deps[] = {
- [BUFFER_INDEX(vbo.pos_nor)] = BATCH_FLAG(surface,
- surface_weights,
- edit_triangles,
- edit_vertices,
- edit_edges,
- edit_vnor,
- edit_lnor,
- edit_mesh_analysis,
- edit_selection_verts,
- edit_selection_edges,
- edit_selection_faces,
- all_verts,
- all_edges,
- loose_edges,
- edge_detection,
- wire_edges,
- wire_loops,
- sculpt_overlays) |
- SURFACE_PER_MAT_FLAG,
- [BUFFER_INDEX(vbo.lnor)] = BATCH_FLAG(surface, edit_lnor, wire_loops) | SURFACE_PER_MAT_FLAG,
- [BUFFER_INDEX(vbo.edge_fac)] = BATCH_FLAG(wire_edges),
- [BUFFER_INDEX(vbo.weights)] = BATCH_FLAG(surface_weights),
- [BUFFER_INDEX(vbo.uv)] = BATCH_FLAG(surface,
- edituv_faces_stretch_area,
- edituv_faces_stretch_angle,
- edituv_faces,
- edituv_edges,
- edituv_verts,
- wire_loops_uvs) |
- SURFACE_PER_MAT_FLAG,
- [BUFFER_INDEX(vbo.tan)] = SURFACE_PER_MAT_FLAG,
- [BUFFER_INDEX(vbo.vcol)] = BATCH_FLAG(surface) | SURFACE_PER_MAT_FLAG,
- [BUFFER_INDEX(vbo.sculpt_data)] = BATCH_FLAG(sculpt_overlays),
- [BUFFER_INDEX(vbo.orco)] = SURFACE_PER_MAT_FLAG,
- [BUFFER_INDEX(vbo.edit_data)] = BATCH_FLAG(edit_triangles, edit_edges, edit_vertices),
- [BUFFER_INDEX(vbo.edituv_data)] = BATCH_FLAG(edituv_faces,
- edituv_faces_stretch_area,
- edituv_faces_stretch_angle,
- edituv_edges,
- edituv_verts),
- [BUFFER_INDEX(vbo.edituv_stretch_area)] = BATCH_FLAG(edituv_faces_stretch_area),
- [BUFFER_INDEX(vbo.edituv_stretch_angle)] = BATCH_FLAG(edituv_faces_stretch_angle),
- [BUFFER_INDEX(vbo.mesh_analysis)] = BATCH_FLAG(edit_mesh_analysis),
- [BUFFER_INDEX(vbo.fdots_pos)] = BATCH_FLAG(edit_fdots, edit_selection_fdots),
- [BUFFER_INDEX(vbo.fdots_nor)] = BATCH_FLAG(edit_fdots),
- [BUFFER_INDEX(vbo.fdots_uv)] = BATCH_FLAG(edituv_fdots),
- [BUFFER_INDEX(vbo.fdots_edituv_data)] = BATCH_FLAG(edituv_fdots),
- [BUFFER_INDEX(vbo.skin_roots)] = BATCH_FLAG(edit_skin_roots),
- [BUFFER_INDEX(vbo.vert_idx)] = BATCH_FLAG(edit_selection_verts),
- [BUFFER_INDEX(vbo.edge_idx)] = BATCH_FLAG(edit_selection_edges),
- [BUFFER_INDEX(vbo.poly_idx)] = BATCH_FLAG(edit_selection_faces),
- [BUFFER_INDEX(vbo.fdot_idx)] = BATCH_FLAG(edit_selection_fdots),
- [BUFFER_INDEX(vbo.attr) + 0] = BATCH_FLAG(surface) | SURFACE_PER_MAT_FLAG,
- [BUFFER_INDEX(vbo.attr) + 1] = BATCH_FLAG(surface) | SURFACE_PER_MAT_FLAG,
- [BUFFER_INDEX(vbo.attr) + 2] = BATCH_FLAG(surface) | SURFACE_PER_MAT_FLAG,
- [BUFFER_INDEX(vbo.attr) + 3] = BATCH_FLAG(surface) | SURFACE_PER_MAT_FLAG,
- [BUFFER_INDEX(vbo.attr) + 4] = BATCH_FLAG(surface) | SURFACE_PER_MAT_FLAG,
- [BUFFER_INDEX(vbo.attr) + 5] = BATCH_FLAG(surface) | SURFACE_PER_MAT_FLAG,
- [BUFFER_INDEX(vbo.attr) + 6] = BATCH_FLAG(surface) | SURFACE_PER_MAT_FLAG,
- [BUFFER_INDEX(vbo.attr) + 7] = BATCH_FLAG(surface) | SURFACE_PER_MAT_FLAG,
- [BUFFER_INDEX(vbo.attr) + 8] = BATCH_FLAG(surface) | SURFACE_PER_MAT_FLAG,
- [BUFFER_INDEX(vbo.attr) + 9] = BATCH_FLAG(surface) | SURFACE_PER_MAT_FLAG,
- [BUFFER_INDEX(vbo.attr) + 10] = BATCH_FLAG(surface) | SURFACE_PER_MAT_FLAG,
- [BUFFER_INDEX(vbo.attr) + 11] = BATCH_FLAG(surface) | SURFACE_PER_MAT_FLAG,
- [BUFFER_INDEX(vbo.attr) + 12] = BATCH_FLAG(surface) | SURFACE_PER_MAT_FLAG,
- [BUFFER_INDEX(vbo.attr) + 13] = BATCH_FLAG(surface) | SURFACE_PER_MAT_FLAG,
- [BUFFER_INDEX(vbo.attr) + 14] = BATCH_FLAG(surface) | SURFACE_PER_MAT_FLAG,
-
- [BUFFER_INDEX(ibo.tris)] = BATCH_FLAG(surface,
- surface_weights,
- edit_triangles,
- edit_lnor,
- edit_mesh_analysis,
- edit_selection_faces,
- sculpt_overlays),
- [BUFFER_INDEX(ibo.lines)] = BATCH_FLAG(
- edit_edges, edit_selection_edges, all_edges, wire_edges),
- [BUFFER_INDEX(ibo.lines_loose)] = BATCH_FLAG(loose_edges),
- [BUFFER_INDEX(ibo.points)] = BATCH_FLAG(edit_vnor, edit_vertices, edit_selection_verts),
- [BUFFER_INDEX(ibo.fdots)] = BATCH_FLAG(edit_fdots, edit_selection_fdots),
- [BUFFER_INDEX(ibo.lines_paint_mask)] = BATCH_FLAG(wire_loops),
- [BUFFER_INDEX(ibo.lines_adjacency)] = BATCH_FLAG(edge_detection),
- [BUFFER_INDEX(ibo.edituv_tris)] = BATCH_FLAG(
- edituv_faces, edituv_faces_stretch_area, edituv_faces_stretch_angle),
- [BUFFER_INDEX(ibo.edituv_lines)] = BATCH_FLAG(edituv_edges, wire_loops_uvs),
- [BUFFER_INDEX(ibo.edituv_points)] = BATCH_FLAG(edituv_verts),
- [BUFFER_INDEX(ibo.edituv_fdots)] = BATCH_FLAG(edituv_fdots),
- [TRIS_PER_MAT_INDEX] = SURFACE_PER_MAT_FLAG,
-};
-
-#ifndef NDEBUG
-static DRWBatchFlag g_buffer_deps_d[ARRAY_SIZE(g_buffer_deps)] = {0};
-#endif
+
+static constexpr DRWBatchFlag batches_that_use_buffer(const int buffer_index)
+{
+ switch (buffer_index) {
+ case BUFFER_INDEX(vbo.pos_nor):
+ return MBC_SURFACE | MBC_SURFACE_WEIGHTS | MBC_EDIT_TRIANGLES | MBC_EDIT_VERTICES |
+ MBC_EDIT_EDGES | MBC_EDIT_VNOR | MBC_EDIT_LNOR | MBC_EDIT_MESH_ANALYSIS |
+ MBC_EDIT_SELECTION_VERTS | MBC_EDIT_SELECTION_EDGES | MBC_EDIT_SELECTION_FACES |
+ MBC_ALL_VERTS | MBC_ALL_EDGES | MBC_LOOSE_EDGES | MBC_EDGE_DETECTION |
+ MBC_WIRE_EDGES | MBC_WIRE_LOOPS | MBC_SCULPT_OVERLAYS | MBC_SURFACE_PER_MAT;
+ case BUFFER_INDEX(vbo.lnor):
+ return MBC_SURFACE | MBC_EDIT_LNOR | MBC_WIRE_LOOPS | MBC_SURFACE_PER_MAT;
+ case BUFFER_INDEX(vbo.edge_fac):
+ return MBC_WIRE_EDGES;
+ case BUFFER_INDEX(vbo.weights):
+ return MBC_SURFACE_WEIGHTS;
+ case BUFFER_INDEX(vbo.uv):
+ return MBC_SURFACE | MBC_EDITUV_FACES_STRETCH_AREA | MBC_EDITUV_FACES_STRETCH_ANGLE |
+ MBC_EDITUV_FACES | MBC_EDITUV_EDGES | MBC_EDITUV_VERTS | MBC_WIRE_LOOPS_UVS |
+ MBC_SURFACE_PER_MAT;
+ case BUFFER_INDEX(vbo.tan):
+ return MBC_SURFACE_PER_MAT;
+ case BUFFER_INDEX(vbo.vcol):
+ return MBC_SURFACE | MBC_SURFACE_PER_MAT;
+ case BUFFER_INDEX(vbo.sculpt_data):
+ return MBC_SCULPT_OVERLAYS;
+ case BUFFER_INDEX(vbo.orco):
+ return MBC_SURFACE_PER_MAT;
+ case BUFFER_INDEX(vbo.edit_data):
+ return MBC_EDIT_TRIANGLES | MBC_EDIT_EDGES | MBC_EDIT_VERTICES;
+ case BUFFER_INDEX(vbo.edituv_data):
+ return MBC_EDITUV_FACES | MBC_EDITUV_FACES_STRETCH_AREA | MBC_EDITUV_FACES_STRETCH_ANGLE |
+ MBC_EDITUV_EDGES | MBC_EDITUV_VERTS;
+ case BUFFER_INDEX(vbo.edituv_stretch_area):
+ return MBC_EDITUV_FACES_STRETCH_AREA;
+ case BUFFER_INDEX(vbo.edituv_stretch_angle):
+ return MBC_EDITUV_FACES_STRETCH_ANGLE;
+ case BUFFER_INDEX(vbo.mesh_analysis):
+ return MBC_EDIT_MESH_ANALYSIS;
+ case BUFFER_INDEX(vbo.fdots_pos):
+ return MBC_EDIT_FACEDOTS | MBC_EDIT_SELECTION_FACEDOTS;
+ case BUFFER_INDEX(vbo.fdots_nor):
+ return MBC_EDIT_FACEDOTS;
+ case BUFFER_INDEX(vbo.fdots_uv):
+ return MBC_EDITUV_FACEDOTS;
+ case BUFFER_INDEX(vbo.fdots_edituv_data):
+ return MBC_EDITUV_FACEDOTS;
+ case BUFFER_INDEX(vbo.skin_roots):
+ return MBC_SKIN_ROOTS;
+ case BUFFER_INDEX(vbo.vert_idx):
+ return MBC_EDIT_SELECTION_VERTS;
+ case BUFFER_INDEX(vbo.edge_idx):
+ return MBC_EDIT_SELECTION_EDGES;
+ case BUFFER_INDEX(vbo.poly_idx):
+ return MBC_EDIT_SELECTION_FACES;
+ case BUFFER_INDEX(vbo.fdot_idx):
+ return MBC_EDIT_SELECTION_FACEDOTS;
+ case BUFFER_INDEX(vbo.attr[0]):
+ case BUFFER_INDEX(vbo.attr[1]):
+ case BUFFER_INDEX(vbo.attr[2]):
+ case BUFFER_INDEX(vbo.attr[3]):
+ case BUFFER_INDEX(vbo.attr[4]):
+ case BUFFER_INDEX(vbo.attr[5]):
+ case BUFFER_INDEX(vbo.attr[6]):
+ case BUFFER_INDEX(vbo.attr[7]):
+ case BUFFER_INDEX(vbo.attr[8]):
+ case BUFFER_INDEX(vbo.attr[9]):
+ case BUFFER_INDEX(vbo.attr[10]):
+ case BUFFER_INDEX(vbo.attr[11]):
+ case BUFFER_INDEX(vbo.attr[12]):
+ case BUFFER_INDEX(vbo.attr[13]):
+ case BUFFER_INDEX(vbo.attr[14]):
+ return MBC_SURFACE | MBC_SURFACE_PER_MAT;
+ case BUFFER_INDEX(ibo.tris):
+ return MBC_SURFACE | MBC_SURFACE_WEIGHTS | MBC_EDIT_TRIANGLES | MBC_EDIT_LNOR |
+ MBC_EDIT_MESH_ANALYSIS | MBC_EDIT_SELECTION_FACES | MBC_SCULPT_OVERLAYS;
+ case BUFFER_INDEX(ibo.lines):
+ return MBC_EDIT_EDGES | MBC_EDIT_SELECTION_EDGES | MBC_ALL_EDGES | MBC_WIRE_EDGES;
+ case BUFFER_INDEX(ibo.lines_loose):
+ return MBC_LOOSE_EDGES;
+ case BUFFER_INDEX(ibo.points):
+ return MBC_EDIT_VNOR | MBC_EDIT_VERTICES | MBC_EDIT_SELECTION_VERTS;
+ case BUFFER_INDEX(ibo.fdots):
+ return MBC_EDIT_FACEDOTS | MBC_EDIT_SELECTION_FACEDOTS;
+ case BUFFER_INDEX(ibo.lines_paint_mask):
+ return MBC_WIRE_LOOPS;
+ case BUFFER_INDEX(ibo.lines_adjacency):
+ return MBC_EDGE_DETECTION;
+ case BUFFER_INDEX(ibo.edituv_tris):
+ return MBC_EDITUV_FACES | MBC_EDITUV_FACES_STRETCH_AREA | MBC_EDITUV_FACES_STRETCH_ANGLE;
+ case BUFFER_INDEX(ibo.edituv_lines):
+ return MBC_EDITUV_EDGES | MBC_WIRE_LOOPS_UVS;
+ case BUFFER_INDEX(ibo.edituv_points):
+ return MBC_EDITUV_VERTS;
+ case BUFFER_INDEX(ibo.edituv_fdots):
+ return MBC_EDITUV_FACEDOTS;
+ case TRIS_PER_MAT_INDEX:
+ return MBC_SURFACE_PER_MAT;
+ }
+ return (DRWBatchFlag)0;
+}
static void mesh_batch_cache_discard_surface_batches(MeshBatchCache *cache);
static void mesh_batch_cache_clear(Mesh *me);
@@ -229,14 +201,14 @@ static void mesh_batch_cache_clear(Mesh *me);
static void mesh_batch_cache_discard_batch(MeshBatchCache *cache, const DRWBatchFlag batch_map)
{
for (int i = 0; i < MBC_BATCH_LEN; i++) {
- DRWBatchFlag batch_requested = (1u << i);
+ DRWBatchFlag batch_requested = (DRWBatchFlag)(1u << i);
if (batch_map & batch_requested) {
GPU_BATCH_DISCARD_SAFE(((GPUBatch **)&cache->batch)[i]);
cache->batch_ready &= ~batch_requested;
}
}
- if (batch_map & SURFACE_PER_MAT_FLAG) {
+ if (batch_map & MBC_SURFACE_PER_MAT) {
mesh_batch_cache_discard_surface_batches(cache);
}
}
@@ -266,9 +238,9 @@ BLI_INLINE void mesh_cd_layers_type_clear(DRW_MeshCDMask *a)
BLI_INLINE const Mesh *editmesh_final_or_this(const Object *object, const Mesh *me)
{
- if (me->edit_mesh != NULL) {
+ if (me->edit_mesh != nullptr) {
Mesh *editmesh_eval_final = BKE_object_get_editmesh_eval_final(object);
- if (editmesh_eval_final != NULL) {
+ if (editmesh_eval_final != nullptr) {
return editmesh_eval_final;
}
}
@@ -281,91 +253,6 @@ static void mesh_cd_calc_edit_uv_layer(const Mesh *UNUSED(me), DRW_MeshCDMask *c
cd_used->edit_uv = 1;
}
-/** \name DRW_MeshAttributes
- *
- * Utilities for handling requested attributes.
- * \{ */
-
-/* Return true if the given DRW_AttributeRequest is already in the requests. */
-static bool has_request(const DRW_MeshAttributes *requests, DRW_AttributeRequest req)
-{
- for (int i = 0; i < requests->num_requests; i++) {
- const DRW_AttributeRequest src_req = requests->requests[i];
- if (src_req.domain != req.domain) {
- continue;
- }
- if (src_req.layer_index != req.layer_index) {
- continue;
- }
- if (src_req.cd_type != req.cd_type) {
- continue;
- }
- return true;
- }
- return false;
-}
-
-static void mesh_attrs_merge_requests(const DRW_MeshAttributes *src_requests,
- DRW_MeshAttributes *dst_requests)
-{
- for (int i = 0; i < src_requests->num_requests; i++) {
- if (dst_requests->num_requests == GPU_MAX_ATTR) {
- return;
- }
-
- if (has_request(dst_requests, src_requests->requests[i])) {
- continue;
- }
-
- dst_requests->requests[dst_requests->num_requests] = src_requests->requests[i];
- dst_requests->num_requests += 1;
- }
-}
-
-static void drw_mesh_attributes_clear(DRW_MeshAttributes *attributes)
-{
- memset(attributes, 0, sizeof(DRW_MeshAttributes));
-}
-
-static void drw_mesh_attributes_merge(DRW_MeshAttributes *dst,
- const DRW_MeshAttributes *src,
- ThreadMutex *mesh_render_mutex)
-{
- BLI_mutex_lock(mesh_render_mutex);
- mesh_attrs_merge_requests(src, dst);
- BLI_mutex_unlock(mesh_render_mutex);
-}
-
-/* Return true if all requests in b are in a. */
-static bool drw_mesh_attributes_overlap(DRW_MeshAttributes *a, DRW_MeshAttributes *b)
-{
- for (int i = 0; i < b->num_requests; i++) {
- if (!has_request(a, b->requests[i])) {
- return false;
- }
- }
-
- return true;
-}
-
-static void drw_mesh_attributes_add_request(DRW_MeshAttributes *attrs,
- CustomDataType type,
- int layer,
- AttributeDomain domain)
-{
- if (attrs->num_requests >= GPU_MAX_ATTR) {
- return;
- }
-
- DRW_AttributeRequest *req = &attrs->requests[attrs->num_requests];
- req->cd_type = type;
- req->layer_index = layer;
- req->domain = domain;
- attrs->num_requests += 1;
-}
-
-/** \} */
-
BLI_INLINE const CustomData *mesh_cd_ldata_get_from_mesh(const Mesh *me)
{
switch ((eMeshWrapperType)me->runtime.wrapper_type) {
@@ -459,14 +346,15 @@ static void mesh_cd_calc_active_mloopcol_layer(const Object *object,
DRW_MeshCDMask *cd_used)
{
const Mesh *me_final = editmesh_final_or_this(object, me);
- Mesh me_query = {0};
+ Mesh me_query = blender::dna::shallow_zero_initialize();
const CustomData *cd_vdata = mesh_cd_vdata_get_from_mesh(me_final);
const CustomData *cd_ldata = mesh_cd_ldata_get_from_mesh(me_final);
- BKE_id_attribute_copy_domains_temp(ID_ME, cd_vdata, NULL, cd_ldata, NULL, NULL, &me_query.id);
+ BKE_id_attribute_copy_domains_temp(
+ ID_ME, cd_vdata, nullptr, cd_ldata, nullptr, nullptr, &me_query.id);
- CustomDataLayer *layer = BKE_id_attributes_active_color_get(&me_query.id);
+ const CustomDataLayer *layer = BKE_id_attributes_active_color_get(&me_query.id);
int layer_i = BKE_id_attribute_to_index(
&me_query.id, layer, ATTR_DOMAIN_MASK_COLOR, CD_MASK_COLOR_ALL);
@@ -475,43 +363,13 @@ static void mesh_cd_calc_active_mloopcol_layer(const Object *object,
}
}
-static bool custom_data_match_attribute(const CustomData *custom_data,
- const char *name,
- int *r_layer_index,
- int *r_type)
-{
- const int possible_attribute_types[7] = {
- CD_PROP_BOOL,
- CD_PROP_INT8,
- CD_PROP_INT32,
- CD_PROP_FLOAT,
- CD_PROP_FLOAT2,
- CD_PROP_FLOAT3,
- CD_PROP_COLOR,
- };
-
- for (int i = 0; i < ARRAY_SIZE(possible_attribute_types); i++) {
- const int attr_type = possible_attribute_types[i];
- int layer_index = CustomData_get_named_layer(custom_data, attr_type, name);
- if (layer_index == -1) {
- continue;
- }
-
- *r_layer_index = layer_index;
- *r_type = attr_type;
- return true;
- }
-
- return false;
-}
-
static uint mesh_cd_calc_gpu_layers_vcol_used(const Mesh *me_query,
const CustomData *cd_vdata,
const CustomData *cd_ldata,
const char name[])
{
- CustomDataLayer *layer = NULL;
- AttributeDomain domain;
+ const CustomDataLayer *layer = nullptr;
+ eAttrDomain domain;
if (name[0]) {
int layer_i = 0;
@@ -531,7 +389,7 @@ static uint mesh_cd_calc_gpu_layers_vcol_used(const Mesh *me_query,
layer_i;
}
- /* Note: this is not the same as the layer_i below. */
+ /* NOTE: this is not the same as the layer_i below. */
if (layer_i != -1) {
layer = (domain == ATTR_DOMAIN_POINT ? cd_vdata : cd_ldata)->layers + layer_i;
}
@@ -544,7 +402,7 @@ static uint mesh_cd_calc_gpu_layers_vcol_used(const Mesh *me_query,
return -1;
}
- /* Note: this is the logical index into the color attribute list,
+ /* NOTE: this is the logical index into the color attribute list,
* not the customdata index. */
int vcol_i = BKE_id_attribute_to_index(
(ID *)me_query, layer, ATTR_DOMAIN_MASK_COLOR, CD_MASK_COLOR_ALL);
@@ -556,7 +414,7 @@ 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)
+ DRW_Attributes *attributes)
{
const Mesh *me_final = editmesh_final_or_this(object, me);
const CustomData *cd_ldata = mesh_cd_ldata_get_from_mesh(me_final);
@@ -566,10 +424,10 @@ static DRW_MeshCDMask mesh_cd_calc_used_gpu_layers(const Object *object,
/* Create a mesh with final customdata domains
* we can query with attribute API. */
- Mesh me_query = {0};
+ Mesh me_query = blender::dna::shallow_zero_initialize();
BKE_id_attribute_copy_domains_temp(
- ID_ME, cd_vdata, cd_edata, cd_ldata, cd_pdata, NULL, &me_query.id);
+ ID_ME, cd_vdata, cd_edata, cd_ldata, cd_pdata, nullptr, &me_query.id);
/* See: DM_vertex_attributes_from_gpu for similar logic */
DRW_MeshCDMask cd_used;
@@ -581,10 +439,9 @@ static DRW_MeshCDMask mesh_cd_calc_used_gpu_layers(const Object *object,
ListBase gpu_attrs = GPU_material_attributes(gpumat);
LISTBASE_FOREACH (GPUMaterialAttribute *, gpu_attr, &gpu_attrs) {
const char *name = gpu_attr->name;
- int type = gpu_attr->type;
+ eCustomDataType type = static_cast<eCustomDataType>(gpu_attr->type);
int layer = -1;
- /* ATTR_DOMAIN_NUM is standard for "invalid value". */
- AttributeDomain domain = ATTR_DOMAIN_NUM;
+ std::optional<eAttrDomain> domain;
if (type == CD_AUTO_FROM_NAME) {
/* We need to deduce what exact layer is used.
@@ -636,21 +493,20 @@ static DRW_MeshCDMask mesh_cd_calc_used_gpu_layers(const Object *object,
if (layer == -1) {
/* Try to match a generic attribute, we use the first attribute domain with a
* matching name. */
- if (custom_data_match_attribute(cd_vdata, name, &layer, &type)) {
+ if (drw_custom_data_match_attribute(cd_vdata, name, &layer, &type)) {
domain = ATTR_DOMAIN_POINT;
}
- else if (custom_data_match_attribute(cd_ldata, name, &layer, &type)) {
+ else if (drw_custom_data_match_attribute(cd_ldata, name, &layer, &type)) {
domain = ATTR_DOMAIN_CORNER;
}
- else if (custom_data_match_attribute(cd_pdata, name, &layer, &type)) {
+ else if (drw_custom_data_match_attribute(cd_pdata, name, &layer, &type)) {
domain = ATTR_DOMAIN_FACE;
}
- else if (custom_data_match_attribute(cd_edata, name, &layer, &type)) {
+ else if (drw_custom_data_match_attribute(cd_edata, name, &layer, &type)) {
domain = ATTR_DOMAIN_EDGE;
}
else {
layer = -1;
- domain = ATTR_DOMAIN_NUM;
}
}
@@ -701,19 +557,25 @@ static DRW_MeshCDMask mesh_cd_calc_used_gpu_layers(const Object *object,
break;
}
- /* Note: attr->type will always be CD_PROP_COLOR even for
+ /* NOTE: attr->type will always be CD_PROP_COLOR even for
* CD_PROP_BYTE_COLOR layers, see node_shader_gpu_vertex_color in
* node_shader_vertex_color.cc.
*/
case CD_MCOL:
case CD_PROP_BYTE_COLOR:
case CD_PROP_COLOR: {
+ /* First check Color attributes, when not found check mesh attributes. Geometry nodes
+ * can generate those layers. */
int vcol_bit = mesh_cd_calc_gpu_layers_vcol_used(&me_query, cd_vdata, cd_ldata, name);
if (vcol_bit != -1) {
cd_used.vcol |= 1UL << (uint)vcol_bit;
+ break;
}
+ if (layer != -1 && domain.has_value()) {
+ drw_attributes_add_request(attributes, name, type, layer, *domain);
+ }
break;
}
case CD_PROP_FLOAT3:
@@ -722,11 +584,13 @@ static DRW_MeshCDMask mesh_cd_calc_used_gpu_layers(const Object *object,
case CD_PROP_INT32:
case CD_PROP_FLOAT:
case CD_PROP_FLOAT2: {
- if (layer != -1 && domain != ATTR_DOMAIN_NUM) {
- drw_mesh_attributes_add_request(attributes, type, layer, domain);
+ if (layer != -1 && domain.has_value()) {
+ drw_attributes_add_request(attributes, name, type, layer, *domain);
}
break;
}
+ default:
+ break;
}
}
}
@@ -763,13 +627,14 @@ static void drw_mesh_weight_state_copy(struct DRW_MeshWeightState *wstate_dst,
memcpy(wstate_dst, wstate_src, sizeof(*wstate_dst));
if (wstate_src->defgroup_sel) {
- wstate_dst->defgroup_sel = MEM_dupallocN(wstate_src->defgroup_sel);
+ wstate_dst->defgroup_sel = static_cast<bool *>(MEM_dupallocN(wstate_src->defgroup_sel));
}
if (wstate_src->defgroup_locked) {
- wstate_dst->defgroup_locked = MEM_dupallocN(wstate_src->defgroup_locked);
+ wstate_dst->defgroup_locked = static_cast<bool *>(MEM_dupallocN(wstate_src->defgroup_locked));
}
if (wstate_src->defgroup_unlocked) {
- wstate_dst->defgroup_unlocked = MEM_dupallocN(wstate_src->defgroup_unlocked);
+ wstate_dst->defgroup_unlocked = static_cast<bool *>(
+ MEM_dupallocN(wstate_src->defgroup_unlocked));
}
}
@@ -873,14 +738,15 @@ BLI_INLINE void mesh_batch_cache_add_request(MeshBatchCache *cache, DRWBatchFlag
static bool mesh_batch_cache_valid(Object *object, Mesh *me)
{
- MeshBatchCache *cache = me->runtime.batch_cache;
+ MeshBatchCache *cache = static_cast<MeshBatchCache *>(me->runtime.batch_cache);
- if (cache == NULL) {
+ if (cache == nullptr) {
return false;
}
if (object->sculpt && object->sculpt->pbvh) {
- if (cache->pbvh_is_drawing != BKE_pbvh_is_drawing(object->sculpt->pbvh)) {
+ if (cache->pbvh_is_drawing != BKE_pbvh_is_drawing(object->sculpt->pbvh) ||
+ BKE_pbvh_draw_cache_invalid(object->sculpt->pbvh)) {
return false;
}
@@ -890,7 +756,7 @@ static bool mesh_batch_cache_valid(Object *object, Mesh *me)
}
}
- if (cache->is_editmode != (me->edit_mesh != NULL)) {
+ if (cache->is_editmode != (me->edit_mesh != nullptr)) {
return false;
}
@@ -907,16 +773,17 @@ static bool mesh_batch_cache_valid(Object *object, Mesh *me)
static void mesh_batch_cache_init(Object *object, Mesh *me)
{
- MeshBatchCache *cache = me->runtime.batch_cache;
+ MeshBatchCache *cache = static_cast<MeshBatchCache *>(me->runtime.batch_cache);
if (!cache) {
- cache = me->runtime.batch_cache = MEM_callocN(sizeof(*cache), __func__);
+ me->runtime.batch_cache = MEM_cnew<MeshBatchCache>(__func__);
+ cache = static_cast<MeshBatchCache *>(me->runtime.batch_cache);
}
else {
memset(cache, 0, sizeof(*cache));
}
- cache->is_editmode = me->edit_mesh != NULL;
+ cache->is_editmode = me->edit_mesh != nullptr;
if (object->sculpt && object->sculpt->pbvh) {
cache->pbvh_is_drawing = BKE_pbvh_is_drawing(object->sculpt->pbvh);
@@ -930,12 +797,14 @@ static void mesh_batch_cache_init(Object *object, Mesh *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__);
+ cache->surface_per_mat = static_cast<GPUBatch **>(
+ MEM_callocN(sizeof(*cache->surface_per_mat) * cache->mat_len, __func__));
+ cache->tris_per_mat = static_cast<GPUIndexBuf **>(
+ MEM_callocN(sizeof(*cache->tris_per_mat) * cache->mat_len, __func__));
cache->is_dirty = false;
- cache->batch_ready = 0;
- cache->batch_requested = 0;
+ cache->batch_ready = (DRWBatchFlag)0;
+ cache->batch_requested = (DRWBatchFlag)0;
drw_mesh_weight_state_clear(&cache->weight_state);
}
@@ -950,7 +819,7 @@ void DRW_mesh_batch_cache_validate(Object *object, Mesh *me)
static MeshBatchCache *mesh_batch_cache_get(Mesh *me)
{
- return me->runtime.batch_cache;
+ return static_cast<MeshBatchCache *>(me->runtime.batch_cache);
}
static void mesh_batch_cache_check_vertex_group(MeshBatchCache *cache,
@@ -1059,8 +928,8 @@ static void mesh_batch_cache_discard_uvedit_select(MeshBatchCache *cache)
void DRW_mesh_batch_cache_dirty_tag(Mesh *me, eMeshBatchDirtyMode mode)
{
- MeshBatchCache *cache = me->runtime.batch_cache;
- if (cache == NULL) {
+ MeshBatchCache *cache = static_cast<MeshBatchCache *>(me->runtime.batch_cache);
+ if (cache == nullptr) {
return;
}
DRWBatchFlag batch_map;
@@ -1141,13 +1010,13 @@ 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;
+ cache->subdiv_cache = nullptr;
}
}
static void mesh_batch_cache_clear(Mesh *me)
{
- MeshBatchCache *cache = me->runtime.batch_cache;
+ MeshBatchCache *cache = static_cast<MeshBatchCache *>(me->runtime.batch_cache);
if (!cache) {
return;
}
@@ -1170,7 +1039,7 @@ static void mesh_batch_cache_clear(Mesh *me)
MEM_SAFE_FREE(cache->surface_per_mat);
cache->mat_len = 0;
- cache->batch_ready = 0;
+ cache->batch_ready = (DRWBatchFlag)0;
drw_mesh_weight_state_clear(&cache->weight_state);
mesh_batch_cache_free_subdiv_cache(cache);
@@ -1219,11 +1088,12 @@ static void sculpt_request_active_vcol(MeshBatchCache *cache, Object *object, Me
const CustomData *cd_vdata = mesh_cd_vdata_get_from_mesh(me_final);
const CustomData *cd_ldata = mesh_cd_ldata_get_from_mesh(me_final);
- Mesh me_query = {0};
- BKE_id_attribute_copy_domains_temp(ID_ME, cd_vdata, NULL, cd_ldata, NULL, NULL, &me_query.id);
+ Mesh me_query = blender::dna::shallow_zero_initialize();
+ BKE_id_attribute_copy_domains_temp(
+ ID_ME, cd_vdata, nullptr, cd_ldata, nullptr, nullptr, &me_query.id);
- CustomDataLayer *active = BKE_id_attributes_active_color_get(&me_query.id);
- CustomDataLayer *render = BKE_id_attributes_render_color_get(&me_query.id);
+ const CustomDataLayer *active = BKE_id_attributes_active_color_get(&me_query.id);
+ const CustomDataLayer *render = BKE_id_attributes_render_color_get(&me_query.id);
int active_i = BKE_id_attribute_to_index(
&me_query.id, active, ATTR_DOMAIN_MASK_COLOR, CD_MASK_COLOR_ALL);
@@ -1231,11 +1101,11 @@ static void sculpt_request_active_vcol(MeshBatchCache *cache, Object *object, Me
&me_query.id, render, ATTR_DOMAIN_MASK_COLOR, CD_MASK_COLOR_ALL);
if (active_i >= 0) {
- cache->cd_used.vcol |= 1UL << (uint)active_i;
+ cache->cd_needed.vcol |= 1UL << (uint)active_i;
}
if (render_i >= 0) {
- cache->cd_used.vcol |= 1UL << (uint)render_i;
+ cache->cd_needed.vcol |= 1UL << (uint)render_i;
}
}
@@ -1266,7 +1136,7 @@ GPUBatch *DRW_mesh_batch_cache_get_loose_edges(Mesh *me)
MeshBatchCache *cache = mesh_batch_cache_get(me);
mesh_batch_cache_add_request(cache, MBC_LOOSE_EDGES);
if (cache->no_loose_wire) {
- return NULL;
+ return nullptr;
}
return DRW_batch_request(&cache->batch.loose_edges);
@@ -1311,8 +1181,8 @@ GPUBatch **DRW_mesh_batch_cache_get_surface_shaded(Object *object,
uint gpumat_array_len)
{
MeshBatchCache *cache = mesh_batch_cache_get(me);
- DRW_MeshAttributes attrs_needed;
- drw_mesh_attributes_clear(&attrs_needed);
+ DRW_Attributes attrs_needed;
+ drw_attributes_clear(&attrs_needed);
DRW_MeshCDMask cd_needed = mesh_cd_calc_used_gpu_layers(
object, me, gpumat_array, gpumat_array_len, &attrs_needed);
@@ -1320,7 +1190,7 @@ GPUBatch **DRW_mesh_batch_cache_get_surface_shaded(Object *object,
mesh_cd_layers_type_merge(&cache->cd_needed, cd_needed);
ThreadMutex *mesh_render_mutex = (ThreadMutex *)me->runtime.render_mutex;
- drw_mesh_attributes_merge(&cache->attr_needed, &attrs_needed, mesh_render_mutex);
+ drw_attributes_merge(&cache->attr_needed, &attrs_needed, mesh_render_mutex);
mesh_batch_cache_request_surface_batches(cache);
return cache->surface_per_mat;
}
@@ -1385,7 +1255,7 @@ GPUVertBuf *DRW_mesh_batch_cache_pos_vertbuf_get(Mesh *me)
/* Request surface to trigger the vbo filling. Otherwise it may do nothing. */
mesh_batch_cache_request_surface_batches(cache);
- DRW_vbo_request(NULL, &cache->final.buff.vbo.pos_nor);
+ DRW_vbo_request(nullptr, &cache->final.buff.vbo.pos_nor);
return cache->final.buff.vbo.pos_nor;
}
@@ -1507,10 +1377,10 @@ GPUBatch *DRW_mesh_batch_cache_get_edituv_faces_stretch_area(Object *object,
edituv_request_active_uv(cache, object, me);
mesh_batch_cache_add_request(cache, MBC_EDITUV_FACES_STRETCH_AREA);
- if (tot_area != NULL) {
+ if (tot_area != nullptr) {
*tot_area = &cache->tot_area;
}
- if (tot_uv_area != NULL) {
+ if (tot_uv_area != nullptr) {
*tot_uv_area = &cache->tot_uv_area;
}
return DRW_batch_request(&cache->batch.edituv_faces_stretch_area);
@@ -1580,9 +1450,9 @@ GPUBatch *DRW_mesh_batch_cache_get_surface_edges(Object *object, Mesh *me)
void DRW_mesh_batch_cache_free_old(Mesh *me, int ctime)
{
- MeshBatchCache *cache = me->runtime.batch_cache;
+ MeshBatchCache *cache = static_cast<MeshBatchCache *>(me->runtime.batch_cache);
- if (cache == NULL) {
+ if (cache == nullptr) {
return;
}
@@ -1590,7 +1460,7 @@ void DRW_mesh_batch_cache_free_old(Mesh *me, int ctime)
cache->lastmatch = ctime;
}
- if (drw_mesh_attributes_overlap(&cache->attr_used_over_time, &cache->attr_used)) {
+ if (drw_attributes_overlap(&cache->attr_used_over_time, &cache->attr_used)) {
cache->lastmatch = ctime;
}
@@ -1599,12 +1469,12 @@ void DRW_mesh_batch_cache_free_old(Mesh *me, int ctime)
}
mesh_cd_layers_type_clear(&cache->cd_used_over_time);
- drw_mesh_attributes_clear(&cache->attr_used_over_time);
+ drw_attributes_clear(&cache->attr_used_over_time);
}
static void drw_add_attributes_vbo(GPUBatch *batch,
MeshBufferList *mbuflist,
- DRW_MeshAttributes *attr_used)
+ DRW_Attributes *attr_used)
{
for (int i = 0; i < attr_used->num_requests; i++) {
DRW_vbo_request(batch, &mbuflist->vbo.attr[i]);
@@ -1622,7 +1492,7 @@ static void drw_mesh_batch_cache_check_available(struct TaskGraph *task_graph, M
* happening in release builds). */
BLI_task_graph_work_and_wait(task_graph);
for (int i = 0; i < MBC_BATCH_LEN; i++) {
- BLI_assert(!DRW_batch_requested(((GPUBatch **)&cache->batch)[i], 0));
+ BLI_assert(!DRW_batch_requested(((GPUBatch **)&cache->batch)[i], (GPUPrimType)0));
}
for (int i = 0; i < MBC_VBO_LEN; i++) {
BLI_assert(!DRW_vbo_requested(((GPUVertBuf **)&cache->final.buff.vbo)[i]));
@@ -1653,7 +1523,7 @@ void DRW_mesh_batch_cache_create_requested(struct TaskGraph *task_graph,
const bool use_hide)
{
BLI_assert(task_graph);
- const ToolSettings *ts = NULL;
+ const ToolSettings *ts = nullptr;
if (scene) {
ts = scene->toolsettings;
}
@@ -1668,24 +1538,43 @@ void DRW_mesh_batch_cache_create_requested(struct TaskGraph *task_graph,
return;
}
+#ifdef DEBUG
+ /* Map the index of a buffer to a flag containing all batches that use it. */
+ Map<int, DRWBatchFlag> batches_that_use_buffer_local;
+
+ auto assert_deps_valid = [&](DRWBatchFlag batch_flag, Span<int> used_buffer_indices) {
+ for (const int buffer_index : used_buffer_indices) {
+ batches_that_use_buffer_local.add_or_modify(
+ buffer_index,
+ [&](DRWBatchFlag *value) { *value = batch_flag; },
+ [&](DRWBatchFlag *value) { *value |= batch_flag; });
+ BLI_assert(batches_that_use_buffer(buffer_index) & batch_flag);
+ }
+ };
+#else
+ auto assert_deps_valid = [&](DRWBatchFlag UNUSED(batch_flag),
+ Span<int> UNUSED(used_buffer_indices)) {};
+
+#endif
+
/* Sanity check. */
- if ((me->edit_mesh != NULL) && (ob->mode & OB_MODE_EDIT)) {
- BLI_assert(BKE_object_get_editmesh_eval_final(ob) != NULL);
+ if ((me->edit_mesh != nullptr) && (ob->mode & OB_MODE_EDIT)) {
+ BLI_assert(BKE_object_get_editmesh_eval_final(ob) != nullptr);
}
- const bool is_editmode = (me->edit_mesh != NULL) &&
- (BKE_object_get_editmesh_eval_final(ob) != NULL) &&
+ const bool is_editmode = (me->edit_mesh != nullptr) &&
+ (BKE_object_get_editmesh_eval_final(ob) != nullptr) &&
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);
DRWBatchFlag batch_requested = cache->batch_requested;
- cache->batch_requested = 0;
+ cache->batch_requested = (DRWBatchFlag)0;
if (batch_requested & MBC_SURFACE_WEIGHTS) {
/* Check vertex weights. */
- if ((cache->batch.surface_weights != NULL) && (ts != NULL)) {
+ if ((cache->batch.surface_weights != nullptr) && (ts != nullptr)) {
struct DRW_MeshWeightState wstate;
BLI_assert(ob->type == OB_MESH);
drw_mesh_weight_state_extract(ob, me, ts, is_paint_mode, &wstate);
@@ -1702,7 +1591,7 @@ void DRW_mesh_batch_cache_create_requested(struct TaskGraph *task_graph,
if (cache->cd_needed.orco != 0) {
/* Orco is always extracted from final mesh. */
Mesh *me_final = (me->edit_mesh) ? BKE_object_get_editmesh_eval_final(ob) : me;
- if (CustomData_get_layer(&me_final->vdata, CD_ORCO) == NULL) {
+ if (CustomData_get_layer(&me_final->vdata, CD_ORCO) == nullptr) {
/* Skip orco calculation */
cache->cd_needed.orco = 0;
}
@@ -1715,7 +1604,7 @@ void DRW_mesh_batch_cache_create_requested(struct TaskGraph *task_graph,
/* TODO(fclem): We could be a bit smarter here and only do it per
* material. */
bool cd_overlap = mesh_cd_layers_type_overlap(cache->cd_used, cache->cd_needed);
- bool attr_overlap = drw_mesh_attributes_overlap(&cache->attr_used, &cache->attr_needed);
+ bool attr_overlap = drw_attributes_overlap(&cache->attr_used, &cache->attr_needed);
if (cd_overlap == false || attr_overlap == false) {
FOREACH_MESH_BUFFER_CACHE (cache, mbc) {
if ((cache->cd_used.uv & cache->cd_needed.uv) != cache->cd_needed.uv) {
@@ -1735,7 +1624,7 @@ void DRW_mesh_batch_cache_create_requested(struct TaskGraph *task_graph,
if ((cache->cd_used.vcol & cache->cd_needed.vcol) != cache->cd_needed.vcol) {
GPU_VERTBUF_DISCARD_SAFE(mbc->buff.vbo.vcol);
}
- if (!drw_mesh_attributes_overlap(&cache->attr_used, &cache->attr_needed)) {
+ if (!drw_attributes_overlap(&cache->attr_used, &cache->attr_needed)) {
for (int i = 0; i < GPU_MAX_ATTR; i++) {
GPU_VERTBUF_DISCARD_SAFE(mbc->buff.vbo.attr[i]);
}
@@ -1750,13 +1639,13 @@ void DRW_mesh_batch_cache_create_requested(struct TaskGraph *task_graph,
cache->batch_ready &= ~(MBC_SURFACE);
mesh_cd_layers_type_merge(&cache->cd_used, cache->cd_needed);
- drw_mesh_attributes_merge(&cache->attr_used, &cache->attr_needed, mesh_render_mutex);
+ drw_attributes_merge(&cache->attr_used, &cache->attr_needed, mesh_render_mutex);
}
mesh_cd_layers_type_merge(&cache->cd_used_over_time, cache->cd_needed);
mesh_cd_layers_type_clear(&cache->cd_needed);
- drw_mesh_attributes_merge(&cache->attr_used_over_time, &cache->attr_needed, mesh_render_mutex);
- drw_mesh_attributes_clear(&cache->attr_needed);
+ drw_attributes_merge(&cache->attr_used_over_time, &cache->attr_needed, mesh_render_mutex);
+ drw_attributes_clear(&cache->attr_needed);
}
if (batch_requested & MBC_EDITUV) {
@@ -1801,7 +1690,7 @@ void DRW_mesh_batch_cache_create_requested(struct TaskGraph *task_graph,
* per redraw when smooth shading is enabled. */
const bool do_update_sculpt_normals = ob->sculpt && ob->sculpt->pbvh;
if (do_update_sculpt_normals) {
- Mesh *mesh = ob->data;
+ Mesh *mesh = static_cast<Mesh *>(ob->data);
BKE_pbvh_update_normals(ob->sculpt->pbvh, mesh->runtime.subdiv_ccg);
}
@@ -1816,34 +1705,20 @@ void DRW_mesh_batch_cache_create_requested(struct TaskGraph *task_graph,
do_uvcage = !editmesh_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, me, required_mode);
+ const bool do_subdivision = BKE_subsurf_modifier_has_gpu_subdiv(me);
MeshBufferList *mbuflist = &cache->final.buff;
/* Initialize batches and request VBO's & IBO's. */
- MDEPS_ASSERT(surface,
- ibo.tris,
- vbo.lnor,
- vbo.pos_nor,
- vbo.uv,
- vbo.vcol,
- vbo.attr[0],
- vbo.attr[1],
- vbo.attr[2],
- vbo.attr[3],
- vbo.attr[4],
- vbo.attr[5],
- vbo.attr[6],
- vbo.attr[7],
- vbo.attr[8],
- vbo.attr[9],
- vbo.attr[10],
- vbo.attr[11],
- vbo.attr[12],
- vbo.attr[13],
- vbo.attr[14]);
+ assert_deps_valid(
+ MBC_SURFACE,
+ {BUFFER_INDEX(ibo.tris), BUFFER_INDEX(vbo.lnor), BUFFER_INDEX(vbo.pos_nor),
+ BUFFER_INDEX(vbo.uv), BUFFER_INDEX(vbo.vcol), BUFFER_INDEX(vbo.attr[0]),
+ BUFFER_INDEX(vbo.attr[1]), BUFFER_INDEX(vbo.attr[2]), BUFFER_INDEX(vbo.attr[3]),
+ BUFFER_INDEX(vbo.attr[4]), BUFFER_INDEX(vbo.attr[5]), BUFFER_INDEX(vbo.attr[6]),
+ BUFFER_INDEX(vbo.attr[7]), BUFFER_INDEX(vbo.attr[8]), BUFFER_INDEX(vbo.attr[9]),
+ BUFFER_INDEX(vbo.attr[10]), BUFFER_INDEX(vbo.attr[11]), BUFFER_INDEX(vbo.attr[12]),
+ BUFFER_INDEX(vbo.attr[13]), BUFFER_INDEX(vbo.attr[14])});
if (DRW_batch_requested(cache->batch.surface, GPU_PRIM_TRIS)) {
DRW_ibo_request(cache->batch.surface, &mbuflist->ibo.tris);
/* Order matters. First ones override latest VBO's attributes. */
@@ -1857,52 +1732,61 @@ void DRW_mesh_batch_cache_create_requested(struct TaskGraph *task_graph,
}
drw_add_attributes_vbo(cache->batch.surface, mbuflist, &cache->attr_used);
}
- MDEPS_ASSERT(all_verts, vbo.pos_nor);
+ assert_deps_valid(MBC_ALL_VERTS, {BUFFER_INDEX(vbo.pos_nor)});
if (DRW_batch_requested(cache->batch.all_verts, GPU_PRIM_POINTS)) {
DRW_vbo_request(cache->batch.all_verts, &mbuflist->vbo.pos_nor);
}
- MDEPS_ASSERT(sculpt_overlays, ibo.tris, vbo.pos_nor, vbo.sculpt_data);
+ assert_deps_valid(
+ MBC_SCULPT_OVERLAYS,
+ {BUFFER_INDEX(ibo.tris), BUFFER_INDEX(vbo.pos_nor), BUFFER_INDEX(vbo.sculpt_data)});
if (DRW_batch_requested(cache->batch.sculpt_overlays, GPU_PRIM_TRIS)) {
DRW_ibo_request(cache->batch.sculpt_overlays, &mbuflist->ibo.tris);
DRW_vbo_request(cache->batch.sculpt_overlays, &mbuflist->vbo.pos_nor);
DRW_vbo_request(cache->batch.sculpt_overlays, &mbuflist->vbo.sculpt_data);
}
- MDEPS_ASSERT(all_edges, ibo.lines, vbo.pos_nor);
+ assert_deps_valid(MBC_ALL_EDGES, {BUFFER_INDEX(ibo.lines), BUFFER_INDEX(vbo.pos_nor)});
if (DRW_batch_requested(cache->batch.all_edges, GPU_PRIM_LINES)) {
DRW_ibo_request(cache->batch.all_edges, &mbuflist->ibo.lines);
DRW_vbo_request(cache->batch.all_edges, &mbuflist->vbo.pos_nor);
}
- MDEPS_ASSERT(loose_edges, ibo.lines_loose, vbo.pos_nor);
+ assert_deps_valid(MBC_LOOSE_EDGES, {BUFFER_INDEX(ibo.lines_loose), BUFFER_INDEX(vbo.pos_nor)});
if (DRW_batch_requested(cache->batch.loose_edges, GPU_PRIM_LINES)) {
- DRW_ibo_request(NULL, &mbuflist->ibo.lines);
+ DRW_ibo_request(nullptr, &mbuflist->ibo.lines);
DRW_ibo_request(cache->batch.loose_edges, &mbuflist->ibo.lines_loose);
DRW_vbo_request(cache->batch.loose_edges, &mbuflist->vbo.pos_nor);
}
- MDEPS_ASSERT(edge_detection, ibo.lines_adjacency, vbo.pos_nor);
+ assert_deps_valid(MBC_EDGE_DETECTION,
+ {BUFFER_INDEX(ibo.lines_adjacency), BUFFER_INDEX(vbo.pos_nor)});
if (DRW_batch_requested(cache->batch.edge_detection, GPU_PRIM_LINES_ADJ)) {
DRW_ibo_request(cache->batch.edge_detection, &mbuflist->ibo.lines_adjacency);
DRW_vbo_request(cache->batch.edge_detection, &mbuflist->vbo.pos_nor);
}
- MDEPS_ASSERT(surface_weights, ibo.tris, vbo.pos_nor, vbo.weights);
+ assert_deps_valid(
+ MBC_SURFACE_WEIGHTS,
+ {BUFFER_INDEX(ibo.tris), BUFFER_INDEX(vbo.pos_nor), BUFFER_INDEX(vbo.weights)});
if (DRW_batch_requested(cache->batch.surface_weights, GPU_PRIM_TRIS)) {
DRW_ibo_request(cache->batch.surface_weights, &mbuflist->ibo.tris);
DRW_vbo_request(cache->batch.surface_weights, &mbuflist->vbo.pos_nor);
DRW_vbo_request(cache->batch.surface_weights, &mbuflist->vbo.weights);
}
- MDEPS_ASSERT(wire_loops, ibo.lines_paint_mask, vbo.lnor, vbo.pos_nor);
+ assert_deps_valid(
+ MBC_WIRE_LOOPS,
+ {BUFFER_INDEX(ibo.lines_paint_mask), BUFFER_INDEX(vbo.lnor), BUFFER_INDEX(vbo.pos_nor)});
if (DRW_batch_requested(cache->batch.wire_loops, GPU_PRIM_LINES)) {
DRW_ibo_request(cache->batch.wire_loops, &mbuflist->ibo.lines_paint_mask);
/* Order matters. First ones override latest VBO's attributes. */
DRW_vbo_request(cache->batch.wire_loops, &mbuflist->vbo.lnor);
DRW_vbo_request(cache->batch.wire_loops, &mbuflist->vbo.pos_nor);
}
- MDEPS_ASSERT(wire_edges, ibo.lines, vbo.pos_nor, vbo.edge_fac);
+ assert_deps_valid(
+ MBC_WIRE_EDGES,
+ {BUFFER_INDEX(ibo.lines), BUFFER_INDEX(vbo.pos_nor), BUFFER_INDEX(vbo.edge_fac)});
if (DRW_batch_requested(cache->batch.wire_edges, GPU_PRIM_LINES)) {
DRW_ibo_request(cache->batch.wire_edges, &mbuflist->ibo.lines);
DRW_vbo_request(cache->batch.wire_edges, &mbuflist->vbo.pos_nor);
DRW_vbo_request(cache->batch.wire_edges, &mbuflist->vbo.edge_fac);
}
- MDEPS_ASSERT(wire_loops_uvs, ibo.edituv_lines, vbo.uv);
+ assert_deps_valid(MBC_WIRE_LOOPS_UVS, {BUFFER_INDEX(ibo.edituv_lines), BUFFER_INDEX(vbo.uv)});
if (DRW_batch_requested(cache->batch.wire_loops_uvs, GPU_PRIM_LINES)) {
DRW_ibo_request(cache->batch.wire_loops_uvs, &mbuflist->ibo.edituv_lines);
/* For paint overlay. Active layer should have been queried. */
@@ -1910,7 +1794,9 @@ void DRW_mesh_batch_cache_create_requested(struct TaskGraph *task_graph,
DRW_vbo_request(cache->batch.wire_loops_uvs, &mbuflist->vbo.uv);
}
}
- MDEPS_ASSERT(edit_mesh_analysis, ibo.tris, vbo.pos_nor, vbo.mesh_analysis);
+ assert_deps_valid(
+ MBC_EDIT_MESH_ANALYSIS,
+ {BUFFER_INDEX(ibo.tris), BUFFER_INDEX(vbo.pos_nor), BUFFER_INDEX(vbo.mesh_analysis)});
if (DRW_batch_requested(cache->batch.edit_mesh_analysis, GPU_PRIM_TRIS)) {
DRW_ibo_request(cache->batch.edit_mesh_analysis, &mbuflist->ibo.tris);
DRW_vbo_request(cache->batch.edit_mesh_analysis, &mbuflist->vbo.pos_nor);
@@ -1918,29 +1804,16 @@ void DRW_mesh_batch_cache_create_requested(struct TaskGraph *task_graph,
}
/* Per Material */
- MDEPS_ASSERT_FLAG(SURFACE_PER_MAT_FLAG,
- vbo.lnor,
- vbo.pos_nor,
- vbo.uv,
- vbo.tan,
- vbo.vcol,
- vbo.orco,
- vbo.attr[0],
- vbo.attr[1],
- vbo.attr[2],
- vbo.attr[3],
- vbo.attr[4],
- vbo.attr[5],
- vbo.attr[6],
- vbo.attr[7],
- vbo.attr[8],
- vbo.attr[9],
- vbo.attr[10],
- vbo.attr[11],
- vbo.attr[12],
- vbo.attr[13],
- vbo.attr[14]);
- MDEPS_ASSERT_INDEX(TRIS_PER_MAT_INDEX, SURFACE_PER_MAT_FLAG);
+ assert_deps_valid(
+ MBC_SURFACE_PER_MAT,
+ {BUFFER_INDEX(vbo.lnor), BUFFER_INDEX(vbo.pos_nor), BUFFER_INDEX(vbo.uv),
+ BUFFER_INDEX(vbo.tan), BUFFER_INDEX(vbo.vcol), BUFFER_INDEX(vbo.orco),
+ BUFFER_INDEX(vbo.attr[0]), BUFFER_INDEX(vbo.attr[1]), BUFFER_INDEX(vbo.attr[2]),
+ BUFFER_INDEX(vbo.attr[3]), BUFFER_INDEX(vbo.attr[4]), BUFFER_INDEX(vbo.attr[5]),
+ BUFFER_INDEX(vbo.attr[6]), BUFFER_INDEX(vbo.attr[7]), BUFFER_INDEX(vbo.attr[8]),
+ BUFFER_INDEX(vbo.attr[9]), BUFFER_INDEX(vbo.attr[10]), BUFFER_INDEX(vbo.attr[11]),
+ BUFFER_INDEX(vbo.attr[12]), BUFFER_INDEX(vbo.attr[13]), BUFFER_INDEX(vbo.attr[14])});
+ assert_deps_valid(MBC_SURFACE_PER_MAT, {TRIS_PER_MAT_INDEX});
for (int i = 0; i < cache->mat_len; i++) {
if (DRW_batch_requested(cache->surface_per_mat[i], GPU_PRIM_TRIS)) {
DRW_ibo_request(cache->surface_per_mat[i], &cache->tris_per_mat[i]);
@@ -1966,66 +1839,83 @@ void DRW_mesh_batch_cache_create_requested(struct TaskGraph *task_graph,
mbuflist = (do_cage) ? &cache->cage.buff : &cache->final.buff;
/* Edit Mesh */
- MDEPS_ASSERT(edit_triangles, ibo.tris, vbo.pos_nor, vbo.edit_data);
+ assert_deps_valid(
+ MBC_EDIT_TRIANGLES,
+ {BUFFER_INDEX(ibo.tris), BUFFER_INDEX(vbo.pos_nor), BUFFER_INDEX(vbo.edit_data)});
if (DRW_batch_requested(cache->batch.edit_triangles, GPU_PRIM_TRIS)) {
DRW_ibo_request(cache->batch.edit_triangles, &mbuflist->ibo.tris);
DRW_vbo_request(cache->batch.edit_triangles, &mbuflist->vbo.pos_nor);
DRW_vbo_request(cache->batch.edit_triangles, &mbuflist->vbo.edit_data);
}
- MDEPS_ASSERT(edit_vertices, ibo.points, vbo.pos_nor, vbo.edit_data);
+ assert_deps_valid(
+ MBC_EDIT_VERTICES,
+ {BUFFER_INDEX(ibo.points), BUFFER_INDEX(vbo.pos_nor), BUFFER_INDEX(vbo.edit_data)});
if (DRW_batch_requested(cache->batch.edit_vertices, GPU_PRIM_POINTS)) {
DRW_ibo_request(cache->batch.edit_vertices, &mbuflist->ibo.points);
DRW_vbo_request(cache->batch.edit_vertices, &mbuflist->vbo.pos_nor);
DRW_vbo_request(cache->batch.edit_vertices, &mbuflist->vbo.edit_data);
}
- MDEPS_ASSERT(edit_edges, ibo.lines, vbo.pos_nor, vbo.edit_data);
+ assert_deps_valid(
+ MBC_EDIT_EDGES,
+ {BUFFER_INDEX(ibo.lines), BUFFER_INDEX(vbo.pos_nor), BUFFER_INDEX(vbo.edit_data)});
if (DRW_batch_requested(cache->batch.edit_edges, GPU_PRIM_LINES)) {
DRW_ibo_request(cache->batch.edit_edges, &mbuflist->ibo.lines);
DRW_vbo_request(cache->batch.edit_edges, &mbuflist->vbo.pos_nor);
DRW_vbo_request(cache->batch.edit_edges, &mbuflist->vbo.edit_data);
}
- MDEPS_ASSERT(edit_vnor, ibo.points, vbo.pos_nor);
+ assert_deps_valid(MBC_EDIT_VNOR, {BUFFER_INDEX(ibo.points), BUFFER_INDEX(vbo.pos_nor)});
if (DRW_batch_requested(cache->batch.edit_vnor, GPU_PRIM_POINTS)) {
DRW_ibo_request(cache->batch.edit_vnor, &mbuflist->ibo.points);
DRW_vbo_request(cache->batch.edit_vnor, &mbuflist->vbo.pos_nor);
}
- MDEPS_ASSERT(edit_lnor, ibo.tris, vbo.pos_nor, vbo.lnor);
+ assert_deps_valid(MBC_EDIT_LNOR,
+ {BUFFER_INDEX(ibo.tris), BUFFER_INDEX(vbo.pos_nor), BUFFER_INDEX(vbo.lnor)});
if (DRW_batch_requested(cache->batch.edit_lnor, GPU_PRIM_POINTS)) {
DRW_ibo_request(cache->batch.edit_lnor, &mbuflist->ibo.tris);
DRW_vbo_request(cache->batch.edit_lnor, &mbuflist->vbo.pos_nor);
DRW_vbo_request(cache->batch.edit_lnor, &mbuflist->vbo.lnor);
}
- MDEPS_ASSERT(edit_fdots, ibo.fdots, vbo.fdots_pos, vbo.fdots_nor);
+ assert_deps_valid(
+ MBC_EDIT_FACEDOTS,
+ {BUFFER_INDEX(ibo.fdots), BUFFER_INDEX(vbo.fdots_pos), BUFFER_INDEX(vbo.fdots_nor)});
if (DRW_batch_requested(cache->batch.edit_fdots, GPU_PRIM_POINTS)) {
DRW_ibo_request(cache->batch.edit_fdots, &mbuflist->ibo.fdots);
DRW_vbo_request(cache->batch.edit_fdots, &mbuflist->vbo.fdots_pos);
DRW_vbo_request(cache->batch.edit_fdots, &mbuflist->vbo.fdots_nor);
}
- MDEPS_ASSERT(edit_skin_roots, vbo.skin_roots);
+ assert_deps_valid(MBC_SKIN_ROOTS, {BUFFER_INDEX(vbo.skin_roots)});
if (DRW_batch_requested(cache->batch.edit_skin_roots, GPU_PRIM_POINTS)) {
DRW_vbo_request(cache->batch.edit_skin_roots, &mbuflist->vbo.skin_roots);
}
/* Selection */
- MDEPS_ASSERT(edit_selection_verts, ibo.points, vbo.pos_nor, vbo.vert_idx);
+ assert_deps_valid(
+ MBC_EDIT_SELECTION_VERTS,
+ {BUFFER_INDEX(ibo.points), BUFFER_INDEX(vbo.pos_nor), BUFFER_INDEX(vbo.vert_idx)});
if (DRW_batch_requested(cache->batch.edit_selection_verts, GPU_PRIM_POINTS)) {
DRW_ibo_request(cache->batch.edit_selection_verts, &mbuflist->ibo.points);
DRW_vbo_request(cache->batch.edit_selection_verts, &mbuflist->vbo.pos_nor);
DRW_vbo_request(cache->batch.edit_selection_verts, &mbuflist->vbo.vert_idx);
}
- MDEPS_ASSERT(edit_selection_edges, ibo.lines, vbo.pos_nor, vbo.edge_idx);
+ assert_deps_valid(
+ MBC_EDIT_SELECTION_EDGES,
+ {BUFFER_INDEX(ibo.lines), BUFFER_INDEX(vbo.pos_nor), BUFFER_INDEX(vbo.edge_idx)});
if (DRW_batch_requested(cache->batch.edit_selection_edges, GPU_PRIM_LINES)) {
DRW_ibo_request(cache->batch.edit_selection_edges, &mbuflist->ibo.lines);
DRW_vbo_request(cache->batch.edit_selection_edges, &mbuflist->vbo.pos_nor);
DRW_vbo_request(cache->batch.edit_selection_edges, &mbuflist->vbo.edge_idx);
}
- MDEPS_ASSERT(edit_selection_faces, ibo.tris, vbo.pos_nor, vbo.poly_idx);
+ assert_deps_valid(
+ MBC_EDIT_SELECTION_FACES,
+ {BUFFER_INDEX(ibo.tris), BUFFER_INDEX(vbo.pos_nor), BUFFER_INDEX(vbo.poly_idx)});
if (DRW_batch_requested(cache->batch.edit_selection_faces, GPU_PRIM_TRIS)) {
DRW_ibo_request(cache->batch.edit_selection_faces, &mbuflist->ibo.tris);
DRW_vbo_request(cache->batch.edit_selection_faces, &mbuflist->vbo.pos_nor);
DRW_vbo_request(cache->batch.edit_selection_faces, &mbuflist->vbo.poly_idx);
}
- MDEPS_ASSERT(edit_selection_fdots, ibo.fdots, vbo.fdots_pos, vbo.fdot_idx);
+ assert_deps_valid(
+ MBC_EDIT_SELECTION_FACEDOTS,
+ {BUFFER_INDEX(ibo.fdots), BUFFER_INDEX(vbo.fdots_pos), BUFFER_INDEX(vbo.fdot_idx)});
if (DRW_batch_requested(cache->batch.edit_selection_fdots, GPU_PRIM_POINTS)) {
DRW_ibo_request(cache->batch.edit_selection_fdots, &mbuflist->ibo.fdots);
DRW_vbo_request(cache->batch.edit_selection_fdots, &mbuflist->vbo.fdots_pos);
@@ -2040,135 +1930,145 @@ void DRW_mesh_batch_cache_create_requested(struct TaskGraph *task_graph,
mbuflist = (do_uvcage) ? &cache->uv_cage.buff : &cache->final.buff;
/* Edit UV */
- MDEPS_ASSERT(edituv_faces, ibo.edituv_tris, vbo.uv, vbo.edituv_data);
+ assert_deps_valid(
+ MBC_EDITUV_FACES,
+ {BUFFER_INDEX(ibo.edituv_tris), BUFFER_INDEX(vbo.uv), BUFFER_INDEX(vbo.edituv_data)});
if (DRW_batch_requested(cache->batch.edituv_faces, GPU_PRIM_TRIS)) {
DRW_ibo_request(cache->batch.edituv_faces, &mbuflist->ibo.edituv_tris);
DRW_vbo_request(cache->batch.edituv_faces, &mbuflist->vbo.uv);
DRW_vbo_request(cache->batch.edituv_faces, &mbuflist->vbo.edituv_data);
}
- MDEPS_ASSERT(edituv_faces_stretch_area,
- ibo.edituv_tris,
- vbo.uv,
- vbo.edituv_data,
- vbo.edituv_stretch_area);
+ assert_deps_valid(MBC_EDITUV_FACES_STRETCH_AREA,
+ {BUFFER_INDEX(ibo.edituv_tris),
+ BUFFER_INDEX(vbo.uv),
+ BUFFER_INDEX(vbo.edituv_data),
+ BUFFER_INDEX(vbo.edituv_stretch_area)});
if (DRW_batch_requested(cache->batch.edituv_faces_stretch_area, GPU_PRIM_TRIS)) {
DRW_ibo_request(cache->batch.edituv_faces_stretch_area, &mbuflist->ibo.edituv_tris);
DRW_vbo_request(cache->batch.edituv_faces_stretch_area, &mbuflist->vbo.uv);
DRW_vbo_request(cache->batch.edituv_faces_stretch_area, &mbuflist->vbo.edituv_data);
DRW_vbo_request(cache->batch.edituv_faces_stretch_area, &mbuflist->vbo.edituv_stretch_area);
}
- MDEPS_ASSERT(edituv_faces_stretch_angle,
- ibo.edituv_tris,
- vbo.uv,
- vbo.edituv_data,
- vbo.edituv_stretch_angle);
+ assert_deps_valid(MBC_EDITUV_FACES_STRETCH_ANGLE,
+ {BUFFER_INDEX(ibo.edituv_tris),
+ BUFFER_INDEX(vbo.uv),
+ BUFFER_INDEX(vbo.edituv_data),
+ BUFFER_INDEX(vbo.edituv_stretch_angle)});
if (DRW_batch_requested(cache->batch.edituv_faces_stretch_angle, GPU_PRIM_TRIS)) {
DRW_ibo_request(cache->batch.edituv_faces_stretch_angle, &mbuflist->ibo.edituv_tris);
DRW_vbo_request(cache->batch.edituv_faces_stretch_angle, &mbuflist->vbo.uv);
DRW_vbo_request(cache->batch.edituv_faces_stretch_angle, &mbuflist->vbo.edituv_data);
DRW_vbo_request(cache->batch.edituv_faces_stretch_angle, &mbuflist->vbo.edituv_stretch_angle);
}
- MDEPS_ASSERT(edituv_edges, ibo.edituv_lines, vbo.uv, vbo.edituv_data);
+ assert_deps_valid(
+ MBC_EDITUV_EDGES,
+ {BUFFER_INDEX(ibo.edituv_lines), BUFFER_INDEX(vbo.uv), BUFFER_INDEX(vbo.edituv_data)});
if (DRW_batch_requested(cache->batch.edituv_edges, GPU_PRIM_LINES)) {
DRW_ibo_request(cache->batch.edituv_edges, &mbuflist->ibo.edituv_lines);
DRW_vbo_request(cache->batch.edituv_edges, &mbuflist->vbo.uv);
DRW_vbo_request(cache->batch.edituv_edges, &mbuflist->vbo.edituv_data);
}
- MDEPS_ASSERT(edituv_verts, ibo.edituv_points, vbo.uv, vbo.edituv_data);
+ assert_deps_valid(
+ MBC_EDITUV_VERTS,
+ {BUFFER_INDEX(ibo.edituv_points), BUFFER_INDEX(vbo.uv), BUFFER_INDEX(vbo.edituv_data)});
if (DRW_batch_requested(cache->batch.edituv_verts, GPU_PRIM_POINTS)) {
DRW_ibo_request(cache->batch.edituv_verts, &mbuflist->ibo.edituv_points);
DRW_vbo_request(cache->batch.edituv_verts, &mbuflist->vbo.uv);
DRW_vbo_request(cache->batch.edituv_verts, &mbuflist->vbo.edituv_data);
}
- MDEPS_ASSERT(edituv_fdots, ibo.edituv_fdots, vbo.fdots_uv, vbo.fdots_edituv_data);
+ assert_deps_valid(MBC_EDITUV_FACEDOTS,
+ {BUFFER_INDEX(ibo.edituv_fdots),
+ BUFFER_INDEX(vbo.fdots_uv),
+ BUFFER_INDEX(vbo.fdots_edituv_data)});
if (DRW_batch_requested(cache->batch.edituv_fdots, GPU_PRIM_POINTS)) {
DRW_ibo_request(cache->batch.edituv_fdots, &mbuflist->ibo.edituv_fdots);
DRW_vbo_request(cache->batch.edituv_fdots, &mbuflist->vbo.fdots_uv);
DRW_vbo_request(cache->batch.edituv_fdots, &mbuflist->vbo.fdots_edituv_data);
}
- MDEPS_ASSERT_MAP(vbo.lnor);
- MDEPS_ASSERT_MAP(vbo.pos_nor);
- MDEPS_ASSERT_MAP(vbo.uv);
- MDEPS_ASSERT_MAP(vbo.vcol);
- MDEPS_ASSERT_MAP(vbo.sculpt_data);
- MDEPS_ASSERT_MAP(vbo.weights);
- MDEPS_ASSERT_MAP(vbo.edge_fac);
- MDEPS_ASSERT_MAP(vbo.mesh_analysis);
- MDEPS_ASSERT_MAP(vbo.tan);
- MDEPS_ASSERT_MAP(vbo.orco);
- MDEPS_ASSERT_MAP(vbo.edit_data);
- MDEPS_ASSERT_MAP(vbo.fdots_pos);
- MDEPS_ASSERT_MAP(vbo.fdots_nor);
- MDEPS_ASSERT_MAP(vbo.skin_roots);
- MDEPS_ASSERT_MAP(vbo.vert_idx);
- MDEPS_ASSERT_MAP(vbo.edge_idx);
- MDEPS_ASSERT_MAP(vbo.poly_idx);
- MDEPS_ASSERT_MAP(vbo.fdot_idx);
- MDEPS_ASSERT_MAP(vbo.edituv_data);
- MDEPS_ASSERT_MAP(vbo.edituv_stretch_area);
- MDEPS_ASSERT_MAP(vbo.edituv_stretch_angle);
- MDEPS_ASSERT_MAP(vbo.fdots_uv);
- MDEPS_ASSERT_MAP(vbo.fdots_edituv_data);
- for (int i = 0; i < GPU_MAX_ATTR; i++) {
- MDEPS_ASSERT_MAP(vbo.attr[i]);
- }
-
- MDEPS_ASSERT_MAP(ibo.tris);
- MDEPS_ASSERT_MAP(ibo.lines);
- MDEPS_ASSERT_MAP(ibo.lines_loose);
- MDEPS_ASSERT_MAP(ibo.lines_adjacency);
- MDEPS_ASSERT_MAP(ibo.lines_paint_mask);
- MDEPS_ASSERT_MAP(ibo.points);
- MDEPS_ASSERT_MAP(ibo.fdots);
- MDEPS_ASSERT_MAP(ibo.edituv_tris);
- MDEPS_ASSERT_MAP(ibo.edituv_lines);
- MDEPS_ASSERT_MAP(ibo.edituv_points);
- MDEPS_ASSERT_MAP(ibo.edituv_fdots);
-
- MDEPS_ASSERT_MAP_INDEX(TRIS_PER_MAT_INDEX);
-
- const bool use_subsurf_fdots = me->runtime.subsurf_face_dot_tags != NULL;
+#ifdef DEBUG
+ auto assert_final_deps_valid = [&](const int buffer_index) {
+ BLI_assert(batches_that_use_buffer(buffer_index) ==
+ batches_that_use_buffer_local.lookup(buffer_index));
+ };
+ assert_final_deps_valid(BUFFER_INDEX(vbo.lnor));
+ assert_final_deps_valid(BUFFER_INDEX(vbo.pos_nor));
+ assert_final_deps_valid(BUFFER_INDEX(vbo.uv));
+ assert_final_deps_valid(BUFFER_INDEX(vbo.vcol));
+ assert_final_deps_valid(BUFFER_INDEX(vbo.sculpt_data));
+ assert_final_deps_valid(BUFFER_INDEX(vbo.weights));
+ assert_final_deps_valid(BUFFER_INDEX(vbo.edge_fac));
+ assert_final_deps_valid(BUFFER_INDEX(vbo.mesh_analysis));
+ assert_final_deps_valid(BUFFER_INDEX(vbo.tan));
+ assert_final_deps_valid(BUFFER_INDEX(vbo.orco));
+ assert_final_deps_valid(BUFFER_INDEX(vbo.edit_data));
+ assert_final_deps_valid(BUFFER_INDEX(vbo.fdots_pos));
+ assert_final_deps_valid(BUFFER_INDEX(vbo.fdots_nor));
+ assert_final_deps_valid(BUFFER_INDEX(vbo.skin_roots));
+ assert_final_deps_valid(BUFFER_INDEX(vbo.vert_idx));
+ assert_final_deps_valid(BUFFER_INDEX(vbo.edge_idx));
+ assert_final_deps_valid(BUFFER_INDEX(vbo.poly_idx));
+ assert_final_deps_valid(BUFFER_INDEX(vbo.fdot_idx));
+ assert_final_deps_valid(BUFFER_INDEX(vbo.edituv_data));
+ assert_final_deps_valid(BUFFER_INDEX(vbo.edituv_stretch_area));
+ assert_final_deps_valid(BUFFER_INDEX(vbo.edituv_stretch_angle));
+ assert_final_deps_valid(BUFFER_INDEX(vbo.fdots_uv));
+ assert_final_deps_valid(BUFFER_INDEX(vbo.fdots_edituv_data));
+ for (const int i : IndexRange(GPU_MAX_ATTR)) {
+ assert_final_deps_valid(BUFFER_INDEX(vbo.attr[i]));
+ }
+
+ assert_final_deps_valid(BUFFER_INDEX(ibo.tris));
+ assert_final_deps_valid(BUFFER_INDEX(ibo.lines));
+ assert_final_deps_valid(BUFFER_INDEX(ibo.lines_loose));
+ assert_final_deps_valid(BUFFER_INDEX(ibo.lines_adjacency));
+ assert_final_deps_valid(BUFFER_INDEX(ibo.lines_paint_mask));
+ assert_final_deps_valid(BUFFER_INDEX(ibo.points));
+ assert_final_deps_valid(BUFFER_INDEX(ibo.fdots));
+ assert_final_deps_valid(BUFFER_INDEX(ibo.edituv_tris));
+ assert_final_deps_valid(BUFFER_INDEX(ibo.edituv_lines));
+ assert_final_deps_valid(BUFFER_INDEX(ibo.edituv_points));
+ assert_final_deps_valid(BUFFER_INDEX(ibo.edituv_fdots));
+
+ assert_final_deps_valid(TRIS_PER_MAT_INDEX);
+#endif
if (do_uvcage) {
- mesh_buffer_cache_create_requested(task_graph,
- cache,
- &cache->uv_cage,
- ob,
- me,
- is_editmode,
- is_paint_mode,
- is_mode_active,
- ob->obmat,
- false,
- true,
- false,
- scene,
- ts,
- true);
+ blender::draw::mesh_buffer_cache_create_requested(task_graph,
+ cache,
+ &cache->uv_cage,
+ ob,
+ me,
+ is_editmode,
+ is_paint_mode,
+ is_mode_active,
+ ob->obmat,
+ false,
+ true,
+ scene,
+ ts,
+ true);
}
if (do_cage) {
- mesh_buffer_cache_create_requested(task_graph,
- cache,
- &cache->cage,
- ob,
- me,
- is_editmode,
- is_paint_mode,
- is_mode_active,
- ob->obmat,
- false,
- false,
- use_subsurf_fdots,
- scene,
- ts,
- true);
+ blender::draw::mesh_buffer_cache_create_requested(task_graph,
+ cache,
+ &cache->cage,
+ ob,
+ me,
+ is_editmode,
+ is_paint_mode,
+ is_mode_active,
+ ob->obmat,
+ false,
+ false,
+ scene,
+ ts,
+ true);
}
if (do_subdivision) {
- DRW_create_subdivision(scene,
- ob,
+ DRW_create_subdivision(ob,
me,
cache,
&cache->final,
@@ -2178,7 +2078,6 @@ void DRW_mesh_batch_cache_create_requested(struct TaskGraph *task_graph,
ob->obmat,
true,
false,
- use_subsurf_fdots,
ts,
use_hide);
}
@@ -2188,21 +2087,20 @@ void DRW_mesh_batch_cache_create_requested(struct TaskGraph *task_graph,
mesh_batch_cache_free_subdiv_cache(cache);
}
- mesh_buffer_cache_create_requested(task_graph,
- cache,
- &cache->final,
- ob,
- me,
- is_editmode,
- is_paint_mode,
- is_mode_active,
- ob->obmat,
- true,
- false,
- use_subsurf_fdots,
- scene,
- ts,
- use_hide);
+ blender::draw::mesh_buffer_cache_create_requested(task_graph,
+ cache,
+ &cache->final,
+ ob,
+ me,
+ is_editmode,
+ is_paint_mode,
+ is_mode_active,
+ ob->obmat,
+ true,
+ false,
+ scene,
+ ts,
+ use_hide);
/* Ensure that all requested batches have finished.
* Ideally we want to remove this sync, but there are cases where this doesn't work.
diff --git a/source/blender/draw/intern/draw_cache_impl_particles.c b/source/blender/draw/intern/draw_cache_impl_particles.c
index a1c0a42ba6f..c1d609bf648 100644
--- a/source/blender/draw/intern/draw_cache_impl_particles.c
+++ b/source/blender/draw/intern/draw_cache_impl_particles.c
@@ -277,7 +277,7 @@ static void particle_calculate_parent_uvs(ParticleSystem *psys,
ParticleSystemModifierData *psmd,
const int num_uv_layers,
const int parent_index,
- /*const*/ MTFace **mtfaces,
+ const MTFace **mtfaces,
float (*r_uv)[2])
{
if (psmd == NULL) {
@@ -306,7 +306,7 @@ static void particle_calculate_parent_mcol(ParticleSystem *psys,
ParticleSystemModifierData *psmd,
const int num_col_layers,
const int parent_index,
- /*const*/ MCol **mcols,
+ const MCol **mcols,
MCol *r_mcol)
{
if (psmd == NULL) {
@@ -337,7 +337,7 @@ static void particle_interpolate_children_uvs(ParticleSystem *psys,
ParticleSystemModifierData *psmd,
const int num_uv_layers,
const int child_index,
- /*const*/ MTFace **mtfaces,
+ const MTFace **mtfaces,
float (*r_uv)[2])
{
if (psmd == NULL) {
@@ -361,7 +361,7 @@ static void particle_interpolate_children_mcol(ParticleSystem *psys,
ParticleSystemModifierData *psmd,
const int num_col_layers,
const int child_index,
- /*const*/ MCol **mcols,
+ const MCol **mcols,
MCol *r_mcol)
{
if (psmd == NULL) {
@@ -388,7 +388,7 @@ static void particle_calculate_uvs(ParticleSystem *psys,
const int num_uv_layers,
const int parent_index,
const int child_index,
- /*const*/ MTFace **mtfaces,
+ const MTFace **mtfaces,
float (**r_parent_uvs)[2],
float (**r_uv)[2])
{
@@ -431,7 +431,7 @@ static void particle_calculate_mcol(ParticleSystem *psys,
const int num_col_layers,
const int parent_index,
const int child_index,
- /*const*/ MCol **mcols,
+ const MCol **mcols,
MCol **r_parent_mcol,
MCol **r_mcol)
{
@@ -482,8 +482,8 @@ static int particle_batch_cache_fill_segments(ParticleSystem *psys,
const int num_path_keys,
const int num_uv_layers,
const int num_col_layers,
- /*const*/ MTFace **mtfaces,
- /*const*/ MCol **mcols,
+ const MTFace **mtfaces,
+ const MCol **mcols,
uint *uv_id,
uint *col_id,
float (***r_parent_uvs)[2],
@@ -713,11 +713,11 @@ static int particle_batch_cache_fill_strands_data(ParticleSystem *psys,
GPUVertBufRaw *seg_step,
float (***r_parent_uvs)[2],
GPUVertBufRaw *uv_step,
- MTFace **mtfaces,
+ const MTFace **mtfaces,
int num_uv_layers,
MCol ***r_parent_mcol,
GPUVertBufRaw *col_step,
- MCol **mcols,
+ const MCol **mcols,
int num_col_layers)
{
const bool is_simple = (psys->part->childtype == PART_CHILD_PARTICLES);
@@ -834,8 +834,8 @@ static void particle_batch_cache_ensure_procedural_strand_data(PTCacheEdit *edit
GPUVertBufRaw uv_step[MAX_MTFACE];
GPUVertBufRaw col_step[MAX_MCOL];
- MTFace *mtfaces[MAX_MTFACE] = {NULL};
- MCol *mcols[MAX_MCOL] = {NULL};
+ const MTFace *mtfaces[MAX_MTFACE] = {NULL};
+ const MCol *mcols[MAX_MCOL] = {NULL};
float(**parent_uvs)[2] = NULL;
MCol **parent_mcol = NULL;
@@ -909,12 +909,13 @@ static void particle_batch_cache_ensure_procedural_strand_data(PTCacheEdit *edit
BKE_mesh_tessface_ensure(psmd->mesh_final);
if (cache->num_uv_layers) {
for (int j = 0; j < cache->num_uv_layers; j++) {
- mtfaces[j] = (MTFace *)CustomData_get_layer_n(&psmd->mesh_final->fdata, CD_MTFACE, j);
+ mtfaces[j] = (const MTFace *)CustomData_get_layer_n(
+ &psmd->mesh_final->fdata, CD_MTFACE, j);
}
}
if (cache->num_col_layers) {
for (int j = 0; j < cache->num_col_layers; j++) {
- mcols[j] = (MCol *)CustomData_get_layer_n(&psmd->mesh_final->fdata, CD_MCOL, j);
+ mcols[j] = (const MCol *)CustomData_get_layer_n(&psmd->mesh_final->fdata, CD_MCOL, j);
}
}
}
@@ -930,11 +931,11 @@ static void particle_batch_cache_ensure_procedural_strand_data(PTCacheEdit *edit
&seg_step,
&parent_uvs,
uv_step,
- (MTFace **)mtfaces,
+ mtfaces,
cache->num_uv_layers,
&parent_mcol,
col_step,
- (MCol **)mcols,
+ mcols,
cache->num_col_layers);
}
else {
@@ -951,11 +952,11 @@ static void particle_batch_cache_ensure_procedural_strand_data(PTCacheEdit *edit
&seg_step,
&parent_uvs,
uv_step,
- (MTFace **)mtfaces,
+ mtfaces,
cache->num_uv_layers,
&parent_mcol,
col_step,
- (MCol **)mcols,
+ mcols,
cache->num_col_layers);
}
if (psys->childcache) {
@@ -970,11 +971,11 @@ static void particle_batch_cache_ensure_procedural_strand_data(PTCacheEdit *edit
&seg_step,
&parent_uvs,
uv_step,
- (MTFace **)mtfaces,
+ mtfaces,
cache->num_uv_layers,
&parent_mcol,
col_step,
- (MCol **)mcols,
+ mcols,
cache->num_col_layers);
}
}
@@ -1147,8 +1148,8 @@ static void particle_batch_cache_ensure_pos_and_seg(PTCacheEdit *edit,
int num_col_layers = 0;
int active_uv = 0;
int active_col = 0;
- MTFace **mtfaces = NULL;
- MCol **mcols = NULL;
+ const MTFace **mtfaces = NULL;
+ const MCol **mcols = NULL;
float(**parent_uvs)[2] = NULL;
MCol **parent_mcol = NULL;
@@ -1214,13 +1215,14 @@ static void particle_batch_cache_ensure_pos_and_seg(PTCacheEdit *edit,
if (num_uv_layers) {
mtfaces = MEM_mallocN(sizeof(*mtfaces) * num_uv_layers, "Faces UV layers");
for (int i = 0; i < num_uv_layers; i++) {
- mtfaces[i] = (MTFace *)CustomData_get_layer_n(&psmd->mesh_final->fdata, CD_MTFACE, i);
+ mtfaces[i] = (const MTFace *)CustomData_get_layer_n(
+ &psmd->mesh_final->fdata, CD_MTFACE, i);
}
}
if (num_col_layers) {
mcols = MEM_mallocN(sizeof(*mcols) * num_col_layers, "Color layers");
for (int i = 0; i < num_col_layers; i++) {
- mcols[i] = (MCol *)CustomData_get_layer_n(&psmd->mesh_final->fdata, CD_MCOL, i);
+ mcols[i] = (const MCol *)CustomData_get_layer_n(&psmd->mesh_final->fdata, CD_MCOL, i);
}
}
}
@@ -1304,10 +1306,10 @@ static void particle_batch_cache_ensure_pos_and_seg(PTCacheEdit *edit,
MEM_freeN(parent_mcol);
}
if (num_uv_layers) {
- MEM_freeN(mtfaces);
+ MEM_freeN((void *)mtfaces);
}
if (num_col_layers) {
- MEM_freeN(mcols);
+ MEM_freeN((void *)mcols);
}
if (psmd != NULL) {
MEM_freeN(uv_id);
diff --git a/source/blender/draw/intern/draw_cache_impl_subdivision.cc b/source/blender/draw/intern/draw_cache_impl_subdivision.cc
index 7d245f4158b..afec92a894d 100644
--- a/source/blender/draw/intern/draw_cache_impl_subdivision.cc
+++ b/source/blender/draw/intern/draw_cache_impl_subdivision.cc
@@ -39,10 +39,10 @@
#include "opensubdiv_evaluator_capi.h"
#include "opensubdiv_topology_refiner_capi.h"
-#include "draw_cache_extract.h"
+#include "draw_cache_extract.hh"
#include "draw_cache_impl.h"
#include "draw_cache_inline.h"
-#include "mesh_extractors/extract_mesh.h"
+#include "mesh_extractors/extract_mesh.hh"
extern "C" char datatoc_common_subdiv_custom_data_interp_comp_glsl[];
extern "C" char datatoc_common_subdiv_ibo_lines_comp_glsl[];
@@ -69,6 +69,8 @@ enum {
SHADER_PATCH_EVALUATION,
SHADER_PATCH_EVALUATION_FVAR,
SHADER_PATCH_EVALUATION_FACE_DOTS,
+ SHADER_PATCH_EVALUATION_FACE_DOTS_WITH_NORMALS,
+ SHADER_PATCH_EVALUATION_ORCO,
SHADER_COMP_CUSTOM_DATA_INTERP_1D,
SHADER_COMP_CUSTOM_DATA_INTERP_2D,
SHADER_COMP_CUSTOM_DATA_INTERP_3D,
@@ -107,7 +109,9 @@ static const char *get_shader_code(int shader_type)
}
case SHADER_PATCH_EVALUATION:
case SHADER_PATCH_EVALUATION_FVAR:
- case SHADER_PATCH_EVALUATION_FACE_DOTS: {
+ case SHADER_PATCH_EVALUATION_FACE_DOTS:
+ case SHADER_PATCH_EVALUATION_FACE_DOTS_WITH_NORMALS:
+ case SHADER_PATCH_EVALUATION_ORCO: {
return datatoc_common_subdiv_patch_evaluation_comp_glsl;
}
case SHADER_COMP_CUSTOM_DATA_INTERP_1D:
@@ -163,6 +167,12 @@ static const char *get_shader_name(int shader_type)
case SHADER_PATCH_EVALUATION_FACE_DOTS: {
return "subdiv patch evaluation face dots";
}
+ case SHADER_PATCH_EVALUATION_FACE_DOTS_WITH_NORMALS: {
+ return "subdiv patch evaluation face dots with normals";
+ }
+ case SHADER_PATCH_EVALUATION_ORCO: {
+ return "subdiv patch evaluation orco";
+ }
case SHADER_COMP_CUSTOM_DATA_INTERP_1D: {
return "subdiv custom data interp 1D";
}
@@ -206,6 +216,19 @@ static GPUShader *get_patch_evaluation_shader(int shader_type)
"#define OPENSUBDIV_GLSL_COMPUTE_USE_1ST_DERIVATIVES\n"
"#define FDOTS_EVALUATION\n";
}
+ else if (shader_type == SHADER_PATCH_EVALUATION_FACE_DOTS_WITH_NORMALS) {
+ defines =
+ "#define OSD_PATCH_BASIS_GLSL\n"
+ "#define OPENSUBDIV_GLSL_COMPUTE_USE_1ST_DERIVATIVES\n"
+ "#define FDOTS_EVALUATION\n"
+ "#define FDOTS_NORMALS\n";
+ }
+ else if (shader_type == SHADER_PATCH_EVALUATION_ORCO) {
+ defines =
+ "#define OSD_PATCH_BASIS_GLSL\n"
+ "#define OPENSUBDIV_GLSL_COMPUTE_USE_1ST_DERIVATIVES\n"
+ "#define ORCO_EVALUATION\n";
+ }
else {
defines =
"#define OSD_PATCH_BASIS_GLSL\n"
@@ -236,7 +259,8 @@ static GPUShader *get_subdiv_shader(int shader_type, const char *defines)
if (ELEM(shader_type,
SHADER_PATCH_EVALUATION,
SHADER_PATCH_EVALUATION_FVAR,
- SHADER_PATCH_EVALUATION_FACE_DOTS)) {
+ SHADER_PATCH_EVALUATION_FACE_DOTS,
+ SHADER_PATCH_EVALUATION_ORCO)) {
return get_patch_evaluation_shader(shader_type);
}
if (g_subdiv_shaders[shader_type] == nullptr) {
@@ -551,6 +575,7 @@ static void draw_subdiv_free_edit_mode_cache(DRWSubdivCache *cache)
void draw_subdiv_cache_free(DRWSubdivCache *cache)
{
GPU_VERTBUF_DISCARD_SAFE(cache->patch_coords);
+ GPU_VERTBUF_DISCARD_SAFE(cache->corner_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);
@@ -588,8 +613,9 @@ void draw_subdiv_cache_free(DRWSubdivCache *cache)
#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_HIDDEN 8u
-#define SUBDIV_COARSE_FACE_FLAG_OFFSET 29u
+#define SUBDIV_COARSE_FACE_FLAG_OFFSET 28u
#define SUBDIV_COARSE_FACE_FLAG_SMOOTH_MASK \
(SUBDIV_COARSE_FACE_FLAG_SMOOTH << SUBDIV_COARSE_FACE_FLAG_OFFSET)
@@ -597,10 +623,12 @@ void draw_subdiv_cache_free(DRWSubdivCache *cache)
(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_FLAG_HIDDEN_MASK \
+ (SUBDIV_COARSE_FACE_FLAG_HIDDEN << 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_ACTIVE | SUBDIV_COARSE_FACE_FLAG_HIDDEN) \
<< SUBDIV_COARSE_FACE_FLAG_OFFSET)
static uint32_t compute_coarse_face_flag(BMFace *f, BMFace *efa_act)
@@ -617,6 +645,9 @@ static uint32_t compute_coarse_face_flag(BMFace *f, BMFace *efa_act)
if (BM_elem_flag_test(f, BM_ELEM_SELECT)) {
flag |= SUBDIV_COARSE_FACE_FLAG_SELECT;
}
+ if (BM_elem_flag_test(f, BM_ELEM_HIDDEN)) {
+ flag |= SUBDIV_COARSE_FACE_FLAG_HIDDEN;
+ }
if (f == efa_act) {
flag |= SUBDIV_COARSE_FACE_FLAG_ACTIVE;
}
@@ -647,6 +678,9 @@ static void draw_subdiv_cache_extra_coarse_face_data_mesh(Mesh *mesh, uint32_t *
if ((mesh->mpoly[i].flag & ME_FACE_SEL) != 0) {
flag |= SUBDIV_COARSE_FACE_FLAG_SELECT;
}
+ if ((mesh->mpoly[i].flag & ME_HIDE) != 0) {
+ flag |= SUBDIV_COARSE_FACE_FLAG_HIDDEN;
+ }
flags_data[i] = (uint)(mesh->mpoly[i].loopstart) | (flag << SUBDIV_COARSE_FACE_FLAG_OFFSET);
}
}
@@ -710,6 +744,23 @@ static DRWSubdivCache *mesh_batch_cache_ensure_subdiv_cache(MeshBatchCache *mbc)
return subdiv_cache;
}
+static void draw_subdiv_invalidate_evaluator_for_orco(Subdiv *subdiv, Mesh *mesh)
+{
+ const bool has_orco = CustomData_has_layer(&mesh->vdata, CD_ORCO);
+ if (has_orco && subdiv->evaluator && !subdiv->evaluator->hasVertexData(subdiv->evaluator)) {
+ /* If we suddenly have/need original coordinates, recreate the evaluator if the extra
+ * source was not created yet. The refiner also has to be recreated as refinement for source
+ * and vertex data is done only once. */
+ openSubdiv_deleteEvaluator(subdiv->evaluator);
+ subdiv->evaluator = nullptr;
+
+ if (subdiv->topology_refiner != nullptr) {
+ openSubdiv_deleteTopologyRefiner(subdiv->topology_refiner);
+ subdiv->topology_refiner = nullptr;
+ }
+ }
+}
+
/** \} */
/* -------------------------------------------------------------------- */
@@ -730,7 +781,7 @@ struct DRWCacheBuildingContext {
DRWSubdivCache *cache;
- /* Pointers into DRWSubdivCache buffers for easier access during traversal. */
+ /* Pointers into #DRWSubdivCache buffers for easier access during traversal. */
CompressedPatchCoord *patch_coords;
int *subdiv_loop_vert_index;
int *subdiv_loop_subdiv_vert_index;
@@ -742,11 +793,11 @@ struct DRWCacheBuildingContext {
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;
+ /* #CD_ORIGINDEX layers from the mesh to directly look up during traversal the original-index
+ * 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. */
+ const int *v_origindex;
+ const int *e_origindex;
};
static bool draw_subdiv_topology_info_cb(const SubdivForeachContext *foreach_context,
@@ -784,6 +835,11 @@ static bool draw_subdiv_topology_info_cb(const SubdivForeachContext *foreach_con
cache->patch_coords, get_blender_patch_coords_format(), GPU_USAGE_DYNAMIC);
GPU_vertbuf_data_alloc(cache->patch_coords, cache->num_subdiv_loops);
+ cache->corner_patch_coords = GPU_vertbuf_calloc();
+ GPU_vertbuf_init_with_format_ex(
+ cache->corner_patch_coords, get_blender_patch_coords_format(), GPU_USAGE_DYNAMIC);
+ GPU_vertbuf_data_alloc(cache->corner_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);
@@ -811,10 +867,10 @@ static bool draw_subdiv_topology_info_cb(const SubdivForeachContext *foreach_con
ctx->subdiv_loop_subdiv_edge_index = cache->subdiv_loop_subdiv_edge_index;
ctx->subdiv_loop_poly_index = cache->subdiv_loop_poly_index;
- ctx->v_origindex = static_cast<int *>(
+ ctx->v_origindex = static_cast<const int *>(
CustomData_get_layer(&ctx->coarse_mesh->vdata, CD_ORIGINDEX));
- ctx->e_origindex = static_cast<int *>(
+ ctx->e_origindex = static_cast<const int *>(
CustomData_get_layer(&ctx->coarse_mesh->edata, CD_ORIGINDEX));
if (cache->num_subdiv_verts) {
@@ -996,14 +1052,10 @@ static void build_vertex_face_adjacency_maps(DRWSubdivCache *cache)
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 SubsurfRuntimeData *runtime_data)
{
- 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.resolution = runtime_data->resolution;
to_mesh_settings.use_optimal_display = false;
if (cache->resolution != to_mesh_settings.resolution) {
@@ -1074,6 +1126,31 @@ static bool draw_subdiv_build_cache(DRWSubdivCache *cache,
cache->resolution = to_mesh_settings.resolution;
cache->num_coarse_poly = mesh_eval->totpoly;
+ /* To avoid floating point precision issues when evaluating patches at patch boundaries,
+ * ensure that all loops sharing a vertex use the same patch coordinate. This could cause
+ * the mesh to not be watertight, leading to shadowing artifacts (see T97877). */
+ blender::Vector<int> first_loop_index(cache->num_subdiv_verts, -1);
+
+ /* Save coordinates for corners, as attributes may vary for each loop connected to the same
+ * vertex. */
+ memcpy(GPU_vertbuf_get_data(cache->corner_patch_coords),
+ cache_building_context.patch_coords,
+ sizeof(CompressedPatchCoord) * cache->num_subdiv_loops);
+
+ for (int i = 0; i < cache->num_subdiv_loops; i++) {
+ const int vertex = cache_building_context.subdiv_loop_subdiv_vert_index[i];
+ if (first_loop_index[vertex] != -1) {
+ continue;
+ }
+ first_loop_index[vertex] = i;
+ }
+
+ for (int i = 0; i < cache->num_subdiv_loops; i++) {
+ const int vertex = cache_building_context.subdiv_loop_subdiv_vert_index[i];
+ cache_building_context.patch_coords[i] =
+ cache_building_context.patch_coords[first_loop_index[vertex]];
+ }
+
/* Cleanup. */
MEM_SAFE_FREE(cache_building_context.vert_origindex_map);
MEM_SAFE_FREE(cache_building_context.edge_origindex_map);
@@ -1119,12 +1196,17 @@ struct DRWSubdivUboStorage {
uint coarse_face_select_mask;
uint coarse_face_smooth_mask;
uint coarse_face_active_mask;
+ uint coarse_face_hidden_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;
+
+ int is_edit_mode;
+ int use_hide;
+ int _pad3;
};
static_assert((sizeof(DRWSubdivUboStorage) % 16) == 0,
@@ -1151,8 +1233,11 @@ static void draw_subdiv_init_ubo_storage(const DRWSubdivCache *cache,
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_hidden_mask = SUBDIV_COARSE_FACE_FLAG_HIDDEN_MASK;
ubo->coarse_face_loopstart_mask = SUBDIV_COARSE_FACE_LOOP_START_MASK;
ubo->total_dispatch_size = total_dispatch_size;
+ ubo->is_edit_mode = cache->is_edit_mode;
+ ubo->use_hide = cache->use_hide;
}
static void draw_subdiv_ubo_update_and_bind(const DRWSubdivCache *cache,
@@ -1230,7 +1315,9 @@ static void drw_subdiv_compute_dispatch(const DRWSubdivCache *cache,
GPU_compute_dispatch(shader, dispatch_rx, dispatch_ry, 1);
}
-void draw_subdiv_extract_pos_nor(const DRWSubdivCache *cache, GPUVertBuf *pos_nor)
+void draw_subdiv_extract_pos_nor(const DRWSubdivCache *cache,
+ GPUVertBuf *pos_nor,
+ GPUVertBuf *orco)
{
if (!draw_subdiv_cache_need_polygon_data(cache)) {
/* Happens on meshes with only loose geometry. */
@@ -1245,6 +1332,14 @@ void draw_subdiv_extract_pos_nor(const DRWSubdivCache *cache, GPUVertBuf *pos_no
get_subdiv_vertex_format());
evaluator->wrapSrcBuffer(evaluator, &src_buffer_interface);
+ GPUVertBuf *src_extra_buffer = nullptr;
+ if (orco) {
+ OpenSubdiv_Buffer src_extra_buffer_interface;
+ src_extra_buffer = create_buffer_and_interface(&src_extra_buffer_interface,
+ get_subdiv_vertex_format());
+ evaluator->wrapSrcVertexDataBuffer(evaluator, &src_extra_buffer_interface);
+ }
+
OpenSubdiv_Buffer patch_arrays_buffer_interface;
GPUVertBuf *patch_arrays_buffer = create_buffer_and_interface(&patch_arrays_buffer_interface,
get_patch_array_format());
@@ -1260,7 +1355,8 @@ void draw_subdiv_extract_pos_nor(const DRWSubdivCache *cache, GPUVertBuf *pos_no
get_patch_param_format());
evaluator->wrapPatchParamBuffer(evaluator, &patch_param_buffer_interface);
- GPUShader *shader = get_patch_evaluation_shader(SHADER_PATCH_EVALUATION);
+ GPUShader *shader = get_patch_evaluation_shader(orco ? SHADER_PATCH_EVALUATION_ORCO :
+ SHADER_PATCH_EVALUATION);
GPU_shader_bind(shader);
int binding_point = 0;
@@ -1273,6 +1369,10 @@ void draw_subdiv_extract_pos_nor(const DRWSubdivCache *cache, GPUVertBuf *pos_no
GPU_vertbuf_bind_as_ssbo(patch_index_buffer, binding_point++);
GPU_vertbuf_bind_as_ssbo(patch_param_buffer, binding_point++);
GPU_vertbuf_bind_as_ssbo(pos_nor, binding_point++);
+ if (orco) {
+ GPU_vertbuf_bind_as_ssbo(src_extra_buffer, binding_point++);
+ GPU_vertbuf_bind_as_ssbo(orco, binding_point++);
+ }
BLI_assert(binding_point <= MAX_GPU_SUBDIV_SSBOS);
drw_subdiv_compute_dispatch(cache, shader, 0, 0, cache->num_subdiv_quads);
@@ -1289,6 +1389,7 @@ void draw_subdiv_extract_pos_nor(const DRWSubdivCache *cache, GPUVertBuf *pos_no
GPU_vertbuf_discard(patch_param_buffer);
GPU_vertbuf_discard(patch_arrays_buffer);
GPU_vertbuf_discard(src_buffer);
+ GPU_VERTBUF_DISCARD_SAFE(src_extra_buffer);
}
void draw_subdiv_extract_uvs(const DRWSubdivCache *cache,
@@ -1333,7 +1434,7 @@ void draw_subdiv_extract_uvs(const DRWSubdivCache *cache,
GPU_vertbuf_bind_as_ssbo(src_buffer, binding_point++);
GPU_vertbuf_bind_as_ssbo(cache->gpu_patch_map.patch_map_handles, binding_point++);
GPU_vertbuf_bind_as_ssbo(cache->gpu_patch_map.patch_map_quadtree, binding_point++);
- GPU_vertbuf_bind_as_ssbo(cache->patch_coords, binding_point++);
+ GPU_vertbuf_bind_as_ssbo(cache->corner_patch_coords, binding_point++);
GPU_vertbuf_bind_as_ssbo(cache->verts_orig_index, binding_point++);
GPU_vertbuf_bind_as_ssbo(patch_arrays_buffer, binding_point++);
GPU_vertbuf_bind_as_ssbo(patch_index_buffer, binding_point++);
@@ -1408,7 +1509,7 @@ void draw_subdiv_interp_custom_data(const DRWSubdivCache *cache,
GPU_vertbuf_bind_as_ssbo(cache->subdiv_polygon_offset_buffer, binding_point++);
GPU_vertbuf_bind_as_ssbo(src_data, binding_point++);
GPU_vertbuf_bind_as_ssbo(cache->face_ptex_offset_buffer, binding_point++);
- GPU_vertbuf_bind_as_ssbo(cache->patch_coords, binding_point++);
+ GPU_vertbuf_bind_as_ssbo(cache->corner_patch_coords, binding_point++);
GPU_vertbuf_bind_as_ssbo(cache->extra_coarse_face_data, binding_point++);
GPU_vertbuf_bind_as_ssbo(dst_data, binding_point++);
BLI_assert(binding_point <= MAX_GPU_SUBDIV_SSBOS);
@@ -1552,12 +1653,11 @@ void draw_subdiv_build_tris_buffer(const DRWSubdivCache *cache,
do_single_material ? SHADER_BUFFER_TRIS : SHADER_BUFFER_TRIS_MULTIPLE_MATERIALS, defines);
GPU_shader_bind(shader);
- if (!do_single_material) {
- /* subdiv_polygon_offset is always at binding point 0 for each shader using it. */
- GPU_vertbuf_bind_as_ssbo(cache->subdiv_polygon_offset_buffer, 0);
- }
+ int binding_point = 0;
- int binding_point = 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, binding_point++);
+ GPU_vertbuf_bind_as_ssbo(cache->extra_coarse_face_data, binding_point++);
/* Outputs */
GPU_indexbuf_bind_as_ssbo(subdiv_tris, binding_point++);
@@ -1611,7 +1711,9 @@ void draw_subdiv_build_fdots_buffers(const DRWSubdivCache *cache,
get_patch_param_format());
evaluator->wrapPatchParamBuffer(evaluator, &patch_param_buffer_interface);
- GPUShader *shader = get_patch_evaluation_shader(SHADER_PATCH_EVALUATION_FACE_DOTS);
+ GPUShader *shader = get_patch_evaluation_shader(
+ fdots_nor ? SHADER_PATCH_EVALUATION_FACE_DOTS_WITH_NORMALS :
+ SHADER_PATCH_EVALUATION_FACE_DOTS);
GPU_shader_bind(shader);
int binding_point = 0;
@@ -1624,7 +1726,11 @@ void draw_subdiv_build_fdots_buffers(const DRWSubdivCache *cache,
GPU_vertbuf_bind_as_ssbo(patch_index_buffer, binding_point++);
GPU_vertbuf_bind_as_ssbo(patch_param_buffer, binding_point++);
GPU_vertbuf_bind_as_ssbo(fdots_pos, binding_point++);
- GPU_vertbuf_bind_as_ssbo(fdots_nor, binding_point++);
+ /* F-dots normals may not be requested, still reserve the binding point. */
+ if (fdots_nor) {
+ GPU_vertbuf_bind_as_ssbo(fdots_nor, binding_point);
+ }
+ binding_point++;
GPU_indexbuf_bind_as_ssbo(fdots_indices, binding_point++);
GPU_vertbuf_bind_as_ssbo(cache->extra_coarse_face_data, binding_point++);
BLI_assert(binding_point <= MAX_GPU_SUBDIV_SSBOS);
@@ -1646,11 +1752,13 @@ void draw_subdiv_build_fdots_buffers(const DRWSubdivCache *cache,
void draw_subdiv_build_lines_buffer(const DRWSubdivCache *cache, GPUIndexBuf *lines_indices)
{
- GPUShader *shader = get_subdiv_shader(SHADER_BUFFER_LINES, nullptr);
+ GPUShader *shader = get_subdiv_shader(SHADER_BUFFER_LINES, "#define SUBDIV_POLYGON_OFFSET\n");
GPU_shader_bind(shader);
int binding_point = 0;
+ GPU_vertbuf_bind_as_ssbo(cache->subdiv_polygon_offset_buffer, binding_point++);
GPU_vertbuf_bind_as_ssbo(cache->edges_orig_index, binding_point++);
+ GPU_vertbuf_bind_as_ssbo(cache->extra_coarse_face_data, binding_point++);
GPU_indexbuf_bind_as_ssbo(lines_indices, binding_point++);
BLI_assert(binding_point <= MAX_GPU_SUBDIV_SSBOS);
@@ -1665,12 +1773,14 @@ void draw_subdiv_build_lines_buffer(const DRWSubdivCache *cache, GPUIndexBuf *li
void draw_subdiv_build_lines_loose_buffer(const DRWSubdivCache *cache,
GPUIndexBuf *lines_indices,
+ GPUVertBuf *lines_flags,
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);
+ GPU_indexbuf_bind_as_ssbo(lines_indices, 3);
+ GPU_vertbuf_bind_as_ssbo(lines_flags, 4);
drw_subdiv_compute_dispatch(cache, shader, 0, 0, num_loose_edges);
@@ -1725,6 +1835,7 @@ void draw_subdiv_build_lnor_buffer(const DRWSubdivCache *cache,
GPU_vertbuf_bind_as_ssbo(cache->subdiv_polygon_offset_buffer, binding_point++);
GPU_vertbuf_bind_as_ssbo(pos_nor, binding_point++);
GPU_vertbuf_bind_as_ssbo(cache->extra_coarse_face_data, binding_point++);
+ GPU_vertbuf_bind_as_ssbo(cache->verts_orig_index, binding_point++);
/* Outputs */
GPU_vertbuf_bind_as_ssbo(lnor, binding_point++);
@@ -1893,10 +2004,9 @@ static void draw_subdiv_cache_ensure_mat_offsets(DRWSubdivCache *cache,
MEM_freeN(per_polygon_mat_offset);
}
-static bool draw_subdiv_create_requested_buffers(const Scene *scene,
- Object *ob,
+static bool draw_subdiv_create_requested_buffers(Object *ob,
Mesh *mesh,
- struct MeshBatchCache *batch_cache,
+ MeshBatchCache *batch_cache,
MeshBufferCache *mbc,
const bool is_editmode,
const bool is_paint_mode,
@@ -1904,21 +2014,14 @@ static bool draw_subdiv_create_requested_buffers(const Scene *scene,
const float obmat[4][4],
const bool do_final,
const bool do_uvedit,
- const bool /*use_subsurf_fdots*/,
const ToolSettings *ts,
- const bool /*use_hide*/,
+ const bool use_hide,
OpenSubdiv_EvaluatorCache *evaluator_cache)
{
- SubsurfModifierData *smd = reinterpret_cast<SubsurfModifierData *>(
- BKE_modifiers_findby_session_uuid(ob, &mesh->runtime.subsurf_session_uuid));
- BLI_assert(smd);
+ SubsurfRuntimeData *runtime_data = mesh->runtime.subsurf_runtime_data;
+ BLI_assert(runtime_data && runtime_data->has_gpu_subdiv);
- 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) {
+ if (runtime_data->settings.level == 0) {
return false;
}
@@ -1929,13 +2032,13 @@ static bool draw_subdiv_create_requested_buffers(const Scene *scene,
bm = mesh->edit_mesh->bm;
}
- BKE_subsurf_modifier_ensure_runtime(smd);
-
- Subdiv *subdiv = BKE_subsurf_modifier_subdiv_descriptor_ensure(smd, &settings, mesh_eval, true);
+ Subdiv *subdiv = BKE_subsurf_modifier_subdiv_descriptor_ensure(runtime_data, mesh_eval, true);
if (!subdiv) {
return false;
}
+ draw_subdiv_invalidate_evaluator_for_orco(subdiv, mesh_eval);
+
if (!BKE_subdiv_eval_begin_from_mesh(
subdiv, mesh_eval, nullptr, SUBDIV_EVALUATOR_TYPE_GLSL_COMPUTE, evaluator_cache)) {
/* This could happen in two situations:
@@ -1950,13 +2053,13 @@ static bool draw_subdiv_create_requested_buffers(const Scene *scene,
}
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)) {
+ if (!draw_subdiv_build_cache(draw_cache, subdiv, mesh_eval, runtime_data)) {
return false;
}
/* Edges which do not come from coarse edges should not be drawn in edit mode, only in object
* mode when optimal display in turned off. */
- const bool optimal_display = (smd->flags & eSubsurfModifierFlag_ControlEdges) || is_editmode;
+ const bool optimal_display = runtime_data->use_optimal_display || is_editmode;
draw_cache->bm = bm;
draw_cache->mesh = mesh_eval;
@@ -1964,14 +2067,13 @@ static bool draw_subdiv_create_requested_buffers(const Scene *scene,
draw_cache->optimal_display = optimal_display;
draw_cache->num_subdiv_triangles = tris_count_from_number_of_loops(draw_cache->num_subdiv_loops);
- /* Copy topology information for stats display. Use `mesh` directly, as `mesh_eval` could be the
- * edit mesh. */
- mesh->runtime.subsurf_totvert = draw_cache->num_subdiv_verts;
- mesh->runtime.subsurf_totedge = draw_cache->num_subdiv_edges;
- mesh->runtime.subsurf_totpoly = draw_cache->num_subdiv_quads;
- mesh->runtime.subsurf_totloop = draw_cache->num_subdiv_loops;
+ /* Copy topology information for stats display. */
+ runtime_data->stats_totvert = draw_cache->num_subdiv_verts;
+ runtime_data->stats_totedge = draw_cache->num_subdiv_edges;
+ runtime_data->stats_totpoly = draw_cache->num_subdiv_quads;
+ runtime_data->stats_totloop = draw_cache->num_subdiv_loops;
- draw_cache->use_custom_loop_normals = (smd->flags & eSubsurfModifierFlag_UseCustomNormals) &&
+ draw_cache->use_custom_loop_normals = (runtime_data->use_loop_normals) &&
(mesh_eval->flag & ME_AUTOSMOOTH) &&
CustomData_has_layer(&mesh_eval->ldata,
CD_CUSTOMLOOPNORMAL);
@@ -1982,10 +2084,17 @@ static bool draw_subdiv_create_requested_buffers(const Scene *scene,
MeshRenderData *mr = mesh_render_data_create(
ob, mesh, is_editmode, is_paint_mode, is_mode_active, obmat, do_final, do_uvedit, ts);
+ mr->use_hide = use_hide;
+ draw_cache->use_hide = use_hide;
+
+ /* Used for setting loop normals flags. Mapped extraction is only used during edit mode.
+ * See comments in #extract_lnor_iter_poly_mesh.
+ */
+ draw_cache->is_edit_mode = mr->edit_bmesh != nullptr;
draw_subdiv_cache_update_extra_coarse_face_data(draw_cache, mesh_eval, mr);
- mesh_buffer_cache_create_requested_subdiv(batch_cache, mbc, draw_cache, mr);
+ blender::draw::mesh_buffer_cache_create_requested_subdiv(batch_cache, mbc, draw_cache, mr);
mesh_render_data_free(mr);
@@ -2092,10 +2201,9 @@ blender::Span<DRWSubdivLooseVertex> draw_subdiv_cache_get_loose_verts(const DRWS
static OpenSubdiv_EvaluatorCache *g_evaluator_cache = nullptr;
-void DRW_create_subdivision(const Scene *scene,
- Object *ob,
+void DRW_create_subdivision(Object *ob,
Mesh *mesh,
- struct MeshBatchCache *batch_cache,
+ MeshBatchCache *batch_cache,
MeshBufferCache *mbc,
const bool is_editmode,
const bool is_paint_mode,
@@ -2103,7 +2211,6 @@ void DRW_create_subdivision(const Scene *scene,
const float obmat[4][4],
const bool do_final,
const bool do_uvedit,
- const bool use_subsurf_fdots,
const ToolSettings *ts,
const bool use_hide)
{
@@ -2117,8 +2224,7 @@ void DRW_create_subdivision(const Scene *scene,
const double begin_time = PIL_check_seconds_timer();
#endif
- if (!draw_subdiv_create_requested_buffers(scene,
- ob,
+ if (!draw_subdiv_create_requested_buffers(ob,
mesh,
batch_cache,
mbc,
@@ -2128,7 +2234,6 @@ void DRW_create_subdivision(const Scene *scene,
obmat,
do_final,
do_uvedit,
- use_subsurf_fdots,
ts,
use_hide,
g_evaluator_cache)) {
diff --git a/source/blender/draw/intern/draw_common.h b/source/blender/draw/intern/draw_common.h
index 779ac43178c..d31c98e0dee 100644
--- a/source/blender/draw/intern/draw_common.h
+++ b/source/blender/draw/intern/draw_common.h
@@ -13,6 +13,7 @@
extern "C" {
#endif
+struct CurvesUniformBufPool;
struct DRWShadingGroup;
struct FluidModifierData;
struct GPUMaterial;
@@ -44,7 +45,7 @@ float *DRW_color_background_blend_get(int theme_id);
bool DRW_object_is_flat(struct Object *ob, int *r_axis);
bool DRW_object_axis_orthogonal_to_view(struct Object *ob, int axis);
-/* draw_hair.c */
+/* draw_hair.cc */
/**
* This creates a shading group with display hairs.
@@ -82,7 +83,8 @@ struct DRWShadingGroup *DRW_shgroup_curves_create_sub(struct Object *object,
struct DRWShadingGroup *shgrp,
struct GPUMaterial *gpu_material);
-void DRW_curves_init(void);
+void DRW_curves_init(struct DRWData *drw_data);
+void DRW_curves_ubos_pool_free(struct CurvesUniformBufPool *pool);
void DRW_curves_update(void);
void DRW_curves_free(void);
@@ -91,7 +93,7 @@ void DRW_curves_free(void);
/**
* Add attributes bindings of volume grids to an existing shading group.
* No draw call is added so the caller can decide how to use the data.
- * \return nullptr if there is something to draw.
+ * \return nullptr if there is nothing to draw.
*/
struct DRWShadingGroup *DRW_shgroup_volume_create_sub(struct Scene *scene,
struct Object *ob,
diff --git a/source/blender/draw/intern/draw_curves.cc b/source/blender/draw/intern/draw_curves.cc
index 88118361115..c40f2275968 100644
--- a/source/blender/draw/intern/draw_curves.cc
+++ b/source/blender/draw/intern/draw_curves.cc
@@ -10,8 +10,12 @@
#include "BLI_string_utils.h"
#include "BLI_utildefines.h"
+#include "DNA_curves_types.h"
#include "DNA_customdata_types.h"
+#include "BKE_curves.hh"
+#include "BKE_geometry_set.hh"
+
#include "GPU_batch.h"
#include "GPU_capabilities.h"
#include "GPU_compute.h"
@@ -20,9 +24,13 @@
#include "GPU_texture.h"
#include "GPU_vertex_buffer.h"
+#include "DRW_gpu_wrapper.hh"
#include "DRW_render.h"
+#include "draw_cache_impl.h"
+#include "draw_curves_private.h"
#include "draw_hair_private.h"
+#include "draw_manager.h"
#include "draw_shader.h"
#ifndef __APPLE__
@@ -61,16 +69,43 @@ static GPUVertBuf *g_dummy_vbo = nullptr;
static GPUTexture *g_dummy_texture = nullptr;
static DRWPass *g_tf_pass; /* XXX can be a problem with multiple DRWManager in the future */
+using CurvesInfosBuf = blender::draw::UniformBuffer<CurvesInfos>;
+
+struct CurvesUniformBufPool {
+ blender::Vector<std::unique_ptr<CurvesInfosBuf>> ubos;
+ int used = 0;
+
+ void reset()
+ {
+ used = 0;
+ }
+
+ CurvesInfosBuf &alloc()
+ {
+ if (used >= ubos.size()) {
+ ubos.append(std::make_unique<CurvesInfosBuf>());
+ return *ubos.last();
+ }
+ return *ubos[used++];
+ }
+};
+
static GPUShader *curves_eval_shader_get(CurvesEvalShader type)
{
return DRW_shader_curves_refine_get(type, drw_curves_shader_type_get());
}
-void DRW_curves_init(void)
+void DRW_curves_init(DRWData *drw_data)
{
/* Initialize legacy hair too, to avoid verbosity in callers. */
DRW_hair_init();
+ if (drw_data->curves_ubos == nullptr) {
+ drw_data->curves_ubos = MEM_new<CurvesUniformBufPool>("CurvesUniformBufPool");
+ }
+ CurvesUniformBufPool *pool = drw_data->curves_ubos;
+ pool->reset();
+
#if defined(USE_TRANSFORM_FEEDBACK) || defined(USE_COMPUTE_SHADERS)
g_tf_pass = DRW_pass_create("Update Curves Pass", (DRWState)0);
#else
@@ -94,63 +129,120 @@ void DRW_curves_init(void)
}
}
+void DRW_curves_ubos_pool_free(CurvesUniformBufPool *pool)
+{
+ MEM_delete(pool);
+}
+
static void drw_curves_cache_shgrp_attach_resources(DRWShadingGroup *shgrp,
CurvesEvalCache *cache,
+ GPUTexture *tex,
const int subdiv)
{
- DRW_shgroup_uniform_texture(shgrp, "hairPointBuffer", cache->point_tex);
+ DRW_shgroup_uniform_texture(shgrp, "hairPointBuffer", tex);
DRW_shgroup_uniform_texture(shgrp, "hairStrandBuffer", cache->strand_tex);
DRW_shgroup_uniform_texture(shgrp, "hairStrandSegBuffer", cache->strand_seg_tex);
DRW_shgroup_uniform_int(shgrp, "hairStrandsRes", &cache->final[subdiv].strands_res, 1);
}
+static void drw_curves_cache_update_compute(CurvesEvalCache *cache,
+ const int subdiv,
+ const int strands_len,
+ GPUVertBuf *buffer,
+ GPUTexture *tex)
+{
+ GPUShader *shader = curves_eval_shader_get(CURVES_EVAL_CATMULL_ROM);
+ DRWShadingGroup *shgrp = DRW_shgroup_create(shader, g_tf_pass);
+ drw_curves_cache_shgrp_attach_resources(shgrp, cache, tex, subdiv);
+ DRW_shgroup_vertex_buffer(shgrp, "posTime", buffer);
+
+ const int max_strands_per_call = GPU_max_work_group_count(0);
+ int strands_start = 0;
+ while (strands_start < strands_len) {
+ int batch_strands_len = MIN2(strands_len - strands_start, max_strands_per_call);
+ DRWShadingGroup *subgroup = DRW_shgroup_create_sub(shgrp);
+ DRW_shgroup_uniform_int_copy(subgroup, "hairStrandOffset", strands_start);
+ DRW_shgroup_call_compute(subgroup, batch_strands_len, cache->final[subdiv].strands_res, 1);
+ strands_start += batch_strands_len;
+ }
+}
+
static void drw_curves_cache_update_compute(CurvesEvalCache *cache, const int subdiv)
{
const int strands_len = cache->strands_len;
const int final_points_len = cache->final[subdiv].strands_res * strands_len;
- if (final_points_len > 0) {
- GPUShader *shader = curves_eval_shader_get(CURVES_EVAL_CATMULL_ROM);
- DRWShadingGroup *shgrp = DRW_shgroup_create(shader, g_tf_pass);
- drw_curves_cache_shgrp_attach_resources(shgrp, cache, subdiv);
- 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;
- while (strands_start < strands_len) {
- int batch_strands_len = MIN2(strands_len - strands_start, max_strands_per_call);
- DRWShadingGroup *subgroup = DRW_shgroup_create_sub(shgrp);
- DRW_shgroup_uniform_int_copy(subgroup, "hairStrandOffset", strands_start);
- DRW_shgroup_call_compute(subgroup, batch_strands_len, cache->final[subdiv].strands_res, 1);
- strands_start += batch_strands_len;
+ if (final_points_len == 0) {
+ return;
+ }
+
+ drw_curves_cache_update_compute(
+ cache, subdiv, strands_len, cache->final[subdiv].proc_buf, cache->point_tex);
+
+ const DRW_Attributes &attrs = cache->final[subdiv].attr_used;
+ for (int i = 0; i < attrs.num_requests; i++) {
+ /* Only refine point attributes. */
+ if (attrs.requests[i].domain == ATTR_DOMAIN_CURVE) {
+ continue;
}
+
+ drw_curves_cache_update_compute(cache,
+ subdiv,
+ strands_len,
+ cache->final[subdiv].attributes_buf[i],
+ cache->proc_attributes_tex[i]);
}
}
-static void drw_curves_cache_update_transform_feedback(CurvesEvalCache *cache, const int subdiv)
+static void drw_curves_cache_update_transform_feedback(CurvesEvalCache *cache,
+ GPUVertBuf *vbo,
+ GPUTexture *tex,
+ const int subdiv,
+ const int final_points_len)
{
- const int final_points_len = cache->final[subdiv].strands_res * cache->strands_len;
- if (final_points_len > 0) {
- GPUShader *tf_shader = curves_eval_shader_get(CURVES_EVAL_CATMULL_ROM);
+ GPUShader *tf_shader = curves_eval_shader_get(CURVES_EVAL_CATMULL_ROM);
#ifdef USE_TRANSFORM_FEEDBACK
- DRWShadingGroup *tf_shgrp = DRW_shgroup_transform_feedback_create(
- tf_shader, g_tf_pass, cache->final[subdiv].proc_buf);
+ DRWShadingGroup *tf_shgrp = DRW_shgroup_transform_feedback_create(tf_shader, g_tf_pass, vbo);
#else
- DRWShadingGroup *tf_shgrp = DRW_shgroup_create(tf_shader, g_tf_pass);
-
- CurvesEvalCall *pr_call = MEM_new<CurvesEvalCall>(__func__);
- pr_call->next = g_tf_calls;
- pr_call->vbo = cache->final[subdiv].proc_buf;
- pr_call->shgrp = tf_shgrp;
- pr_call->vert_len = final_points_len;
- g_tf_calls = pr_call;
- DRW_shgroup_uniform_int(tf_shgrp, "targetHeight", &g_tf_target_height, 1);
- DRW_shgroup_uniform_int(tf_shgrp, "targetWidth", &g_tf_target_width, 1);
- DRW_shgroup_uniform_int(tf_shgrp, "idOffset", &g_tf_id_offset, 1);
+ DRWShadingGroup *tf_shgrp = DRW_shgroup_create(tf_shader, g_tf_pass);
+
+ CurvesEvalCall *pr_call = MEM_new<CurvesEvalCall>(__func__);
+ pr_call->next = g_tf_calls;
+ pr_call->vbo = vbo;
+ pr_call->shgrp = tf_shgrp;
+ pr_call->vert_len = final_points_len;
+ g_tf_calls = pr_call;
+ DRW_shgroup_uniform_int(tf_shgrp, "targetHeight", &g_tf_target_height, 1);
+ DRW_shgroup_uniform_int(tf_shgrp, "targetWidth", &g_tf_target_width, 1);
+ DRW_shgroup_uniform_int(tf_shgrp, "idOffset", &g_tf_id_offset, 1);
#endif
- drw_curves_cache_shgrp_attach_resources(tf_shgrp, cache, subdiv);
- DRW_shgroup_call_procedural_points(tf_shgrp, nullptr, final_points_len);
+ drw_curves_cache_shgrp_attach_resources(tf_shgrp, cache, tex, subdiv);
+ DRW_shgroup_call_procedural_points(tf_shgrp, nullptr, final_points_len);
+}
+
+static void drw_curves_cache_update_transform_feedback(CurvesEvalCache *cache, const int subdiv)
+{
+ const int final_points_len = cache->final[subdiv].strands_res * cache->strands_len;
+ if (final_points_len == 0) {
+ return;
+ }
+
+ drw_curves_cache_update_transform_feedback(
+ cache, cache->final[subdiv].proc_buf, cache->point_tex, subdiv, final_points_len);
+
+ const DRW_Attributes &attrs = cache->final[subdiv].attr_used;
+ for (int i = 0; i < attrs.num_requests; i++) {
+ /* Only refine point attributes. */
+ if (attrs.requests[i].domain == ATTR_DOMAIN_CURVE) {
+ continue;
+ }
+
+ drw_curves_cache_update_transform_feedback(cache,
+ cache->final[subdiv].attributes_buf[i],
+ cache->proc_attributes_tex[i],
+ subdiv,
+ final_points_len);
}
}
@@ -186,12 +278,34 @@ GPUVertBuf *DRW_curves_pos_buffer_get(Object *object)
return cache->final[subdiv].proc_buf;
}
+static int attribute_index_in_material(GPUMaterial *gpu_material, const char *name)
+{
+ if (!gpu_material) {
+ return -1;
+ }
+
+ int index = 0;
+
+ ListBase gpu_attrs = GPU_material_attributes(gpu_material);
+ LISTBASE_FOREACH (GPUMaterialAttribute *, gpu_attr, &gpu_attrs) {
+ if (STREQ(gpu_attr->name, name)) {
+ return index;
+ }
+
+ index++;
+ }
+
+ return -1;
+}
+
DRWShadingGroup *DRW_shgroup_curves_create_sub(Object *object,
DRWShadingGroup *shgrp_parent,
GPUMaterial *gpu_material)
{
const DRWContextState *draw_ctx = DRW_context_state_get();
Scene *scene = draw_ctx->scene;
+ CurvesUniformBufPool *pool = DST.vmempool->curves_ubos;
+ CurvesInfosBuf &curves_infos = pool->alloc();
int subdiv = scene->r.hair_subdiv;
int thickness_res = (scene->r.hair_type == SCE_HAIR_SHAPE_STRAND) ? 1 : 2;
@@ -209,15 +323,74 @@ DRWShadingGroup *DRW_shgroup_curves_create_sub(Object *object,
DRW_shgroup_uniform_texture(shgrp, "ac", g_dummy_texture);
/* TODO: Generalize radius implementation for curves data type. */
- float hair_rad_shape = 1.0f;
+ float hair_rad_shape = 0.0f;
float hair_rad_root = 0.005f;
float hair_rad_tip = 0.0f;
bool hair_close_tip = true;
+ /* Use the radius of the root and tip of the first curve for now. This is a workaround that we
+ * use for now because we can't use a per-point radius yet. */
+ Curves &curves_id = *static_cast<Curves *>(object->data);
+ const blender::bke::CurvesGeometry &curves = blender::bke::CurvesGeometry::wrap(
+ curves_id.geometry);
+ if (curves.curves_num() >= 1) {
+ CurveComponent curves_component;
+ curves_component.replace(&curves_id, GeometryOwnershipType::ReadOnly);
+ blender::VArray<float> radii = curves_component.attribute_get_for_read(
+ "radius", ATTR_DOMAIN_POINT, 0.005f);
+ const blender::IndexRange first_curve_points = curves.points_for_curve(0);
+ const float first_radius = radii[first_curve_points.first()];
+ const float last_radius = radii[first_curve_points.last()];
+ const float middle_radius = radii[first_curve_points.size() / 2];
+ hair_rad_root = radii[first_curve_points.first()];
+ hair_rad_tip = radii[first_curve_points.last()];
+ hair_rad_shape = std::clamp(
+ safe_divide(middle_radius - first_radius, last_radius - first_radius) * 2.0f - 1.0f,
+ -1.0f,
+ 1.0f);
+ }
+
DRW_shgroup_uniform_texture(shgrp, "hairPointBuffer", curves_cache->final[subdiv].proc_tex);
if (curves_cache->length_tex) {
DRW_shgroup_uniform_texture(shgrp, "hairLen", curves_cache->length_tex);
}
+
+ const DRW_Attributes &attrs = curves_cache->final[subdiv].attr_used;
+ for (int i = 0; i < attrs.num_requests; i++) {
+ const DRW_AttributeRequest &request = attrs.requests[i];
+
+ char sampler_name[32];
+ drw_curves_get_attribute_sampler_name(request.attribute_name, sampler_name);
+
+ if (request.domain == ATTR_DOMAIN_CURVE) {
+ if (!curves_cache->proc_attributes_tex[i]) {
+ continue;
+ }
+
+ DRW_shgroup_uniform_texture(shgrp, sampler_name, curves_cache->proc_attributes_tex[i]);
+ }
+ else {
+ if (!curves_cache->final[subdiv].attributes_tex[i]) {
+ continue;
+ }
+ DRW_shgroup_uniform_texture(
+ shgrp, sampler_name, curves_cache->final[subdiv].attributes_tex[i]);
+ }
+
+ /* Some attributes may not be used in the shader anymore and were not garbage collected yet, so
+ * we need to find the right index for this attribute as uniforms defining the scope of the
+ * attributes are based on attribute loading order, which is itself based on the material's
+ * attributes. */
+ const int index = attribute_index_in_material(gpu_material, request.attribute_name);
+ if (index != -1) {
+ curves_infos.is_point_attribute[index] = request.domain == ATTR_DOMAIN_POINT;
+ }
+ }
+
+ curves_infos.push_update();
+
+ DRW_shgroup_uniform_block(shgrp, "drw_curves", curves_infos);
+
DRW_shgroup_uniform_int(shgrp, "hairStrandsRes", &curves_cache->final[subdiv].strands_res, 1);
DRW_shgroup_uniform_int_copy(shgrp, "hairThicknessRes", thickness_res);
DRW_shgroup_uniform_float_copy(shgrp, "hairRadShape", hair_rad_shape);
diff --git a/source/blender/draw/intern/draw_curves_private.h b/source/blender/draw/intern/draw_curves_private.h
index 76d5f15319d..7d54e1089d6 100644
--- a/source/blender/draw/intern/draw_curves_private.h
+++ b/source/blender/draw/intern/draw_curves_private.h
@@ -7,6 +7,11 @@
#pragma once
+#include "BKE_attribute.h"
+#include "GPU_shader.h"
+
+#include "draw_attributes.h"
+
#ifdef __cplusplus
extern "C" {
#endif
@@ -30,16 +35,37 @@ typedef struct CurvesEvalFinalCache {
GPUVertBuf *proc_buf;
GPUTexture *proc_tex;
- /* Just contains a huge index buffer used to draw the final curves. */
+ /** Just contains a huge index buffer used to draw the final curves. */
GPUBatch *proc_hairs[MAX_THICKRES];
- /* Points per curve, at least 2. */
+ /** Points per curve, at least 2. */
int strands_res;
+
+ /** Attributes currently being drawn or about to be drawn. */
+ DRW_Attributes attr_used;
+
+ /**
+ * Attributes that were used at some point. This is used for garbage collection, to remove
+ * attributes that are not used in shaders anymore due to user edits.
+ */
+ DRW_Attributes attr_used_over_time;
+
+ /**
+ * The last time in seconds that the `attr_used` and `attr_used_over_time` were exactly the same.
+ * If the delta between this time and the current scene time is greater than the timeout set in
+ * user preferences (`U.vbotimeout`) then garbage collection is performed.
+ */
+ int last_attr_matching_time;
+
+ /* Output of the subdivision stage: vertex buffers sized to subdiv level. This is only attributes
+ * on point domain. */
+ GPUVertBuf *attributes_buf[GPU_MAX_ATTR];
+ GPUTexture *attributes_tex[GPU_MAX_ATTR];
} CurvesEvalFinalCache;
/* Curves procedural display: Evaluation is done on the GPU. */
typedef struct CurvesEvalCache {
- /* Input control points */
+ /* Input control point positions combined with parameter data. */
GPUVertBuf *proc_point_buf;
GPUTexture *point_tex;
@@ -56,13 +82,18 @@ typedef struct CurvesEvalCache {
CurvesEvalFinalCache final[MAX_HAIR_SUBDIV];
+ /* For point attributes, which need subdivision, these buffers contain the input data.
+ * For curve domain attributes, which do not need subdivision, these are the final data. */
+ GPUVertBuf *proc_attributes_buf[GPU_MAX_ATTR];
+ GPUTexture *proc_attributes_tex[GPU_MAX_ATTR];
+
int strands_len;
int elems_len;
int point_len;
} CurvesEvalCache;
/**
- * Ensure all textures and buffers needed for GPU accelerated drawing.
+ * Ensure all necessary textures and buffers exist for GPU accelerated drawing.
*/
bool curves_ensure_procedural_data(struct Object *object,
struct CurvesEvalCache **r_hair_cache,
@@ -70,6 +101,8 @@ bool curves_ensure_procedural_data(struct Object *object,
int subdiv,
int thickness_res);
+void drw_curves_get_attribute_sampler_name(const char *layer_name, char r_sampler_name[32]);
+
#ifdef __cplusplus
}
#endif
diff --git a/source/blender/draw/intern/draw_fluid.c b/source/blender/draw/intern/draw_fluid.c
index d3d4bbf505e..c34025ebe52 100644
--- a/source/blender/draw/intern/draw_fluid.c
+++ b/source/blender/draw/intern/draw_fluid.c
@@ -20,6 +20,8 @@
#include "BKE_colorband.h"
+#include "IMB_colormanagement.h"
+
#include "GPU_texture.h"
#include "draw_manager.h"
@@ -52,7 +54,7 @@ static void create_flame_spectrum_texture(float *data)
float *spec_pixels = (float *)MEM_mallocN(TFUNC_WIDTH * 4 * 16 * 16 * sizeof(float),
"spec_pixels");
- blackbody_temperature_to_rgb_table(data, TFUNC_WIDTH, 1500, 3000);
+ IMB_colormanagement_blackbody_temperature_to_rgb_table(data, TFUNC_WIDTH, 1500, 3000);
for (int i = 0; i < 16; i++) {
for (int j = 0; j < 16; j++) {
diff --git a/source/blender/draw/intern/draw_hair.c b/source/blender/draw/intern/draw_hair.cc
index 8351452769d..0a3c16e0d71 100644
--- a/source/blender/draw/intern/draw_hair.c
+++ b/source/blender/draw/intern/draw_hair.cc
@@ -35,7 +35,7 @@
# define USE_COMPUTE_SHADERS
#endif
-BLI_INLINE eParticleRefineShaderType drw_hair_shader_type_get(void)
+BLI_INLINE eParticleRefineShaderType drw_hair_shader_type_get()
{
#ifdef USE_COMPUTE_SHADERS
if (GPU_compute_shader_support() && GPU_shader_storage_buffer_objects_support()) {
@@ -49,21 +49,21 @@ BLI_INLINE eParticleRefineShaderType drw_hair_shader_type_get(void)
}
#ifndef USE_TRANSFORM_FEEDBACK
-typedef struct ParticleRefineCall {
+struct ParticleRefineCall {
struct ParticleRefineCall *next;
GPUVertBuf *vbo;
DRWShadingGroup *shgrp;
uint vert_len;
-} ParticleRefineCall;
+};
-static ParticleRefineCall *g_tf_calls = NULL;
+static ParticleRefineCall *g_tf_calls = nullptr;
static int g_tf_id_offset;
static int g_tf_target_width;
static int g_tf_target_height;
#endif
-static GPUVertBuf *g_dummy_vbo = NULL;
-static GPUTexture *g_dummy_texture = NULL;
+static GPUVertBuf *g_dummy_vbo = nullptr;
+static GPUTexture *g_dummy_texture = nullptr;
static DRWPass *g_tf_pass; /* XXX can be a problem with multiple DRWManager in the future */
static GPUShader *hair_refine_shader_get(ParticleRefineShader refinement)
@@ -74,12 +74,12 @@ static GPUShader *hair_refine_shader_get(ParticleRefineShader refinement)
void DRW_hair_init(void)
{
#if defined(USE_TRANSFORM_FEEDBACK) || defined(USE_COMPUTE_SHADERS)
- g_tf_pass = DRW_pass_create("Update Hair Pass", 0);
+ g_tf_pass = DRW_pass_create("Update Hair Pass", DRW_STATE_NO_DRAW);
#else
g_tf_pass = DRW_pass_create("Update Hair Pass", DRW_STATE_WRITE_COLOR);
#endif
- if (g_dummy_vbo == NULL) {
+ if (g_dummy_vbo == nullptr) {
/* initialize vertex format */
GPUVertFormat format = {0};
uint dummy_id = GPU_vertformat_attr_add(&format, "dummy", GPU_COMP_F32, 4, GPU_FETCH_FLOAT);
@@ -141,7 +141,7 @@ static void drw_hair_particle_cache_update_transform_feedback(ParticleHairCache
#else
DRWShadingGroup *tf_shgrp = DRW_shgroup_create(tf_shader, g_tf_pass);
- ParticleRefineCall *pr_call = MEM_mallocN(sizeof(*pr_call), __func__);
+ ParticleRefineCall *pr_call = (ParticleRefineCall *)MEM_mallocN(sizeof(*pr_call), __func__);
pr_call->next = g_tf_calls;
pr_call->vbo = cache->final[subdiv].proc_buf;
pr_call->shgrp = tf_shgrp;
@@ -153,7 +153,7 @@ static void drw_hair_particle_cache_update_transform_feedback(ParticleHairCache
#endif
drw_hair_particle_cache_shgrp_attach_resources(tf_shgrp, cache, subdiv);
- DRW_shgroup_call_procedural_points(tf_shgrp, NULL, final_points_len);
+ DRW_shgroup_call_procedural_points(tf_shgrp, nullptr, final_points_len);
}
}
@@ -188,7 +188,7 @@ GPUVertBuf *DRW_hair_pos_buffer_get(Object *object, ParticleSystem *psys, Modifi
int thickness_res = (scene->r.hair_type == SCE_HAIR_SHAPE_STRAND) ? 1 : 2;
ParticleHairCache *cache = drw_hair_particle_cache_get(
- object, psys, md, NULL, subdiv, thickness_res);
+ object, psys, md, nullptr, subdiv, thickness_res);
return cache->final[subdiv].proc_buf;
}
@@ -201,11 +201,11 @@ void DRW_hair_duplimat_get(Object *object,
Object *dupli_parent = DRW_object_get_dupli_parent(object);
DupliObject *dupli_object = DRW_object_get_dupli(object);
- if ((dupli_parent != NULL) && (dupli_object != NULL)) {
+ if ((dupli_parent != nullptr) && (dupli_object != nullptr)) {
if (dupli_object->type & OB_DUPLICOLLECTION) {
unit_m4(dupli_mat);
Collection *collection = dupli_parent->instance_collection;
- if (collection != NULL) {
+ if (collection != nullptr) {
sub_v3_v3(dupli_mat[3], collection->instance_offset);
}
mul_m4_m4m4(dupli_mat, dupli_parent->obmat, dupli_mat);
@@ -291,7 +291,7 @@ DRWShadingGroup *DRW_shgroup_hair_create_sub(Object *object,
return shgrp;
}
-void DRW_hair_update(void)
+void DRW_hair_update()
{
#ifndef USE_TRANSFORM_FEEDBACK
/**
@@ -304,7 +304,7 @@ void DRW_hair_update(void)
* and the most local workaround that still uses the power of the GPU.
*/
- if (g_tf_calls == NULL) {
+ if (g_tf_calls == nullptr) {
return;
}
@@ -319,21 +319,22 @@ void DRW_hair_update(void)
* Do chunks of maximum 2048 * 2048 hair points. */
int width = 2048;
int height = min_ii(width, 1 + max_size / width);
- GPUTexture *tex = DRW_texture_pool_query_2d(width, height, GPU_RGBA32F, (void *)DRW_hair_update);
+ GPUTexture *tex = DRW_texture_pool_query_2d(
+ width, height, GPU_RGBA32F, (DrawEngineType *)DRW_hair_update);
g_tf_target_height = height;
g_tf_target_width = width;
- GPUFrameBuffer *fb = NULL;
+ GPUFrameBuffer *fb = nullptr;
GPU_framebuffer_ensure_config(&fb,
{
GPU_ATTACHMENT_NONE,
GPU_ATTACHMENT_TEXTURE(tex),
});
- float *data = MEM_mallocN(sizeof(float[4]) * width * height, "tf fallback buffer");
+ float *data = (float *)MEM_mallocN(sizeof(float[4]) * width * height, "tf fallback buffer");
GPU_framebuffer_bind(fb);
- while (g_tf_calls != NULL) {
+ while (g_tf_calls != nullptr) {
ParticleRefineCall *pr_call = g_tf_calls;
g_tf_calls = g_tf_calls->next;
@@ -342,7 +343,7 @@ void DRW_hair_update(void)
int max_read_px_len = min_ii(width * height, pr_call->vert_len);
DRW_draw_pass_subset(g_tf_pass, pr_call->shgrp, pr_call->shgrp);
- /* Readback result to main memory. */
+ /* Read back result to main memory. */
GPU_framebuffer_read_color(fb, 0, 0, width, height, 4, 0, GPU_DATA_FLOAT, data);
/* Upload back to VBO. */
GPU_vertbuf_use(pr_call->vbo);
diff --git a/source/blender/draw/intern/draw_manager.c b/source/blender/draw/intern/draw_manager.c
index 6ab8d30109e..bc9d0a3d02a 100644
--- a/source/blender/draw/intern/draw_manager.c
+++ b/source/blender/draw/intern/draw_manager.c
@@ -44,7 +44,6 @@
#include "DNA_mesh_types.h"
#include "DNA_meshdata_types.h"
#include "DNA_world_types.h"
-#include "draw_manager.h"
#include "ED_gpencil.h"
#include "ED_screen.h"
@@ -479,6 +478,7 @@ void DRW_viewport_data_free(DRWData *drw_data)
MEM_freeN(drw_data->obinfos_ubo);
}
DRW_volume_ubos_pool_free(drw_data->volume_grids_ubos);
+ DRW_curves_ubos_pool_free(drw_data->curves_ubos);
MEM_freeN(drw_data);
}
@@ -501,7 +501,7 @@ static DRWData *drw_viewport_data_ensure(GPUViewport *viewport)
* - size can be NULL to get it from viewport.
* - if viewport and size are NULL, size is set to (1, 1).
*
- * Important: drw_manager_init can be called multiple times before drw_manager_exit.
+ * IMPORTANT: #drw_manager_init can be called multiple times before #drw_manager_exit.
*/
static void drw_manager_init(DRWManager *dst, GPUViewport *viewport, const int size[2])
{
@@ -529,7 +529,7 @@ static void drw_manager_init(DRWManager *dst, GPUViewport *viewport, const int s
dst->view_data_active = dst->vmempool->view_data[view];
dst->resource_handle = 0;
dst->pass_handle = 0;
- dst->primary_view_ct = 0;
+ dst->primary_view_num = 0;
drw_viewport_data_reset(dst->vmempool);
@@ -1287,7 +1287,7 @@ void DRW_notify_view_update(const DRWUpdateContext *update_ctx)
const bool gpencil_engine_needed = drw_gpencil_engine_needed(depsgraph, v3d);
- if (G.is_rendering) {
+ if (G.is_rendering && U.experimental.use_draw_manager_acquire_lock) {
return;
}
@@ -1650,7 +1650,7 @@ void DRW_draw_render_loop_ex(struct Depsgraph *depsgraph,
DRW_globals_update();
drw_debug_init();
- DRW_curves_init();
+ DRW_curves_init(DST.vmempool);
DRW_volume_init(DST.vmempool);
DRW_smoke_init(DST.vmempool);
@@ -2022,7 +2022,7 @@ void DRW_render_object_iter(
void (*callback)(void *vedata, Object *ob, RenderEngine *engine, struct Depsgraph *depsgraph))
{
const DRWContextState *draw_ctx = DRW_context_state_get();
- DRW_curves_init();
+ DRW_curves_init(DST.vmempool);
DRW_volume_init(DST.vmempool);
DRW_smoke_init(DST.vmempool);
@@ -2079,7 +2079,7 @@ void DRW_custom_pipeline(DrawEngineType *draw_engine_type,
drw_manager_init(&DST, NULL, NULL);
- DRW_curves_init();
+ DRW_curves_init(DST.vmempool);
DRW_volume_init(DST.vmempool);
DRW_smoke_init(DST.vmempool);
@@ -2114,7 +2114,7 @@ void DRW_cache_restart(void)
DST.buffer_finish_called = false;
- DRW_curves_init();
+ DRW_curves_init(DST.vmempool);
DRW_volume_init(DST.vmempool);
DRW_smoke_init(DST.vmempool);
}
@@ -2433,7 +2433,7 @@ void DRW_draw_select_loop(struct Depsgraph *depsgraph,
/* Init engines */
drw_engines_init();
- DRW_curves_init();
+ DRW_curves_init(DST.vmempool);
DRW_volume_init(DST.vmempool);
DRW_smoke_init(DST.vmempool);
@@ -2607,7 +2607,7 @@ static void drw_draw_depth_loop_impl(struct Depsgraph *depsgraph,
/* Init engines */
drw_engines_init();
- DRW_curves_init();
+ DRW_curves_init(DST.vmempool);
DRW_volume_init(DST.vmempool);
DRW_smoke_init(DST.vmempool);
diff --git a/source/blender/draw/intern/draw_manager.h b/source/blender/draw/intern/draw_manager.h
index 7a9585262ff..6d384c599d8 100644
--- a/source/blender/draw/intern/draw_manager.h
+++ b/source/blender/draw/intern/draw_manager.h
@@ -319,6 +319,8 @@ typedef enum {
DRW_UNIFORM_STORAGE_BLOCK,
DRW_UNIFORM_STORAGE_BLOCK_REF,
DRW_UNIFORM_TFEEDBACK_TARGET,
+ DRW_UNIFORM_VERTEX_BUFFER_AS_TEXTURE,
+ DRW_UNIFORM_VERTEX_BUFFER_AS_TEXTURE_REF,
DRW_UNIFORM_VERTEX_BUFFER_AS_STORAGE,
DRW_UNIFORM_VERTEX_BUFFER_AS_STORAGE_REF,
/** Per drawcall uniforms/UBO */
@@ -536,6 +538,8 @@ typedef struct DRWData {
struct DRWTexturePool *texture_pool;
/** Per stereo view data. Contains engine data and default framebuffers. */
struct DRWViewData *view_data[2];
+ /** Per draw-call curves object data. */
+ struct CurvesUniformBufPool *curves_ubos;
} DRWData;
/* ------------- DRAW MANAGER ------------ */
@@ -617,7 +621,7 @@ typedef struct DRWManager {
DRWView *view_default;
DRWView *view_active;
DRWView *view_previous;
- uint primary_view_ct;
+ uint primary_view_num;
/** TODO(@fclem): Remove this. Only here to support
* shaders without common_view_lib.glsl */
ViewInfos view_storage_cpy;
diff --git a/source/blender/draw/intern/draw_manager_data.c b/source/blender/draw/intern/draw_manager_data.c
index b5432da0957..188d9114cd7 100644
--- a/source/blender/draw/intern/draw_manager_data.c
+++ b/source/blender/draw/intern/draw_manager_data.c
@@ -547,6 +547,29 @@ void DRW_shgroup_vertex_buffer_ref_ex(DRWShadingGroup *shgroup,
shgroup, location, DRW_UNIFORM_VERTEX_BUFFER_AS_STORAGE_REF, vertex_buffer, 0, 0, 1);
}
+void DRW_shgroup_buffer_texture(DRWShadingGroup *shgroup,
+ const char *name,
+ GPUVertBuf *vertex_buffer)
+{
+ int location = GPU_shader_get_ssbo(shgroup->shader, name);
+ if (location == -1) {
+ return;
+ }
+ drw_shgroup_uniform_create_ex(
+ shgroup, location, DRW_UNIFORM_VERTEX_BUFFER_AS_TEXTURE, vertex_buffer, 0, 0, 1);
+}
+
+void DRW_shgroup_buffer_texture_ref(DRWShadingGroup *shgroup,
+ const char *name,
+ GPUVertBuf **vertex_buffer)
+{
+ int location = GPU_shader_get_ssbo(shgroup->shader, name);
+ if (location == -1) {
+ return;
+ }
+ drw_shgroup_uniform_create_ex(
+ shgroup, location, DRW_UNIFORM_VERTEX_BUFFER_AS_TEXTURE_REF, vertex_buffer, 0, 0, 1);
+}
/** \} */
/* -------------------------------------------------------------------- */
@@ -937,25 +960,25 @@ void DRW_shgroup_call_ex(DRWShadingGroup *shgroup,
}
void DRW_shgroup_call_range(
- DRWShadingGroup *shgroup, struct Object *ob, GPUBatch *geom, uint v_sta, uint v_ct)
+ DRWShadingGroup *shgroup, struct Object *ob, GPUBatch *geom, uint v_sta, uint v_num)
{
BLI_assert(geom != NULL);
if (G.f & G_FLAG_PICKSEL) {
drw_command_set_select_id(shgroup, NULL, DST.select_id);
}
DRWResourceHandle handle = drw_resource_handle(shgroup, ob ? ob->obmat : NULL, ob);
- drw_command_draw_range(shgroup, geom, handle, v_sta, v_ct);
+ drw_command_draw_range(shgroup, geom, handle, v_sta, v_num);
}
void DRW_shgroup_call_instance_range(
- DRWShadingGroup *shgroup, Object *ob, struct GPUBatch *geom, uint i_sta, uint i_ct)
+ DRWShadingGroup *shgroup, Object *ob, struct GPUBatch *geom, uint i_sta, uint i_num)
{
BLI_assert(geom != NULL);
if (G.f & G_FLAG_PICKSEL) {
drw_command_set_select_id(shgroup, NULL, DST.select_id);
}
DRWResourceHandle handle = drw_resource_handle(shgroup, ob ? ob->obmat : NULL, ob);
- drw_command_draw_intance_range(shgroup, geom, handle, i_sta, i_ct);
+ drw_command_draw_intance_range(shgroup, geom, handle, i_sta, i_num);
}
void DRW_shgroup_call_compute(DRWShadingGroup *shgroup,
@@ -1215,7 +1238,8 @@ static void drw_sculpt_generate_calls(DRWSculptCallbackData *scd)
&update_frustum,
&draw_frustum,
(void (*)(void *, GPU_PBVH_Buffers *))sculpt_draw_cb,
- scd);
+ scd,
+ scd->use_mats);
if (SCULPT_DEBUG_BUFFERS) {
int debug_node_nr = 0;
@@ -1905,8 +1929,8 @@ DRWView *DRW_view_create(const float viewmat[4][4],
{
DRWView *view = BLI_memblock_alloc(DST.vmempool->views);
- if (DST.primary_view_ct < MAX_CULLED_VIEWS) {
- view->culling_mask = 1u << DST.primary_view_ct++;
+ if (DST.primary_view_num < MAX_CULLED_VIEWS) {
+ view->culling_mask = 1u << DST.primary_view_num++;
}
else {
BLI_assert(0);
@@ -2058,6 +2082,11 @@ void DRW_view_camtexco_set(DRWView *view, float texco[4])
copy_v4_v4(view->storage.viewcamtexcofac, texco);
}
+void DRW_view_camtexco_get(const DRWView *view, float r_texco[4])
+{
+ copy_v4_v4(r_texco, view->storage.viewcamtexcofac);
+}
+
void DRW_view_frustum_corners_get(const DRWView *view, BoundBox *corners)
{
memcpy(corners, &view->frustum_corners, sizeof(view->frustum_corners));
diff --git a/source/blender/draw/intern/draw_manager_exec.c b/source/blender/draw/intern/draw_manager_exec.c
index 2c5b02f88a9..e7e0e0ce41f 100644
--- a/source/blender/draw/intern/draw_manager_exec.c
+++ b/source/blender/draw/intern/draw_manager_exec.c
@@ -693,6 +693,12 @@ static void draw_update_uniforms(DRWShadingGroup *shgroup,
*use_tfeedback = GPU_shader_transform_feedback_enable(shgroup->shader,
((GPUVertBuf *)uni->pvalue));
break;
+ case DRW_UNIFORM_VERTEX_BUFFER_AS_TEXTURE_REF:
+ GPU_vertbuf_bind_as_texture(*uni->vertbuf_ref, uni->location);
+ break;
+ case DRW_UNIFORM_VERTEX_BUFFER_AS_TEXTURE:
+ GPU_vertbuf_bind_as_texture(uni->vertbuf, uni->location);
+ break;
case DRW_UNIFORM_VERTEX_BUFFER_AS_STORAGE_REF:
GPU_vertbuf_bind_as_ssbo(*uni->vertbuf_ref, uni->location);
break;
diff --git a/source/blender/draw/intern/draw_shader.c b/source/blender/draw/intern/draw_shader.cc
index 063aec24b94..001ceb0ae8d 100644
--- a/source/blender/draw/intern/draw_shader.c
+++ b/source/blender/draw/intern/draw_shader.cc
@@ -16,15 +16,15 @@
#include "draw_shader.h"
-extern char datatoc_common_hair_lib_glsl[];
+extern "C" char datatoc_common_hair_lib_glsl[];
-extern char datatoc_common_hair_refine_vert_glsl[];
-extern char datatoc_common_hair_refine_comp_glsl[];
-extern char datatoc_gpu_shader_3D_smooth_color_frag_glsl[];
+extern "C" char datatoc_common_hair_refine_vert_glsl[];
+extern "C" char datatoc_common_hair_refine_comp_glsl[];
+extern "C" char datatoc_gpu_shader_3D_smooth_color_frag_glsl[];
static struct {
struct GPUShader *hair_refine_sh[PART_REFINE_MAX_SHADER];
-} e_data = {{NULL}};
+} e_data = {{nullptr}};
/* -------------------------------------------------------------------- */
/** \name Hair refinement
@@ -38,19 +38,19 @@ static GPUShader *hair_refine_shader_compute_create(ParticleRefineShader UNUSED(
static GPUShader *hair_refine_shader_transform_feedback_create(
ParticleRefineShader UNUSED(refinement))
{
- GPUShader *sh = NULL;
+ GPUShader *sh = nullptr;
+
+ std::string shader_src = std::string(datatoc_common_hair_lib_glsl) +
+ std::string(datatoc_common_hair_refine_vert_glsl);
- char *shader_src = BLI_string_joinN(datatoc_common_hair_lib_glsl,
- datatoc_common_hair_refine_vert_glsl);
const char *var_names[1] = {"finalColor"};
- sh = DRW_shader_create_with_transform_feedback(shader_src,
- NULL,
+ sh = DRW_shader_create_with_transform_feedback(shader_src.c_str(),
+ nullptr,
"#define HAIR_PHASE_SUBDIV\n"
"#define USE_TF\n",
GPU_SHADER_TFB_POINTS,
var_names,
1);
- MEM_freeN(shader_src);
return sh;
}
@@ -64,8 +64,8 @@ static GPUShader *hair_refine_shader_transform_feedback_workaround_create(
GPUShader *DRW_shader_hair_refine_get(ParticleRefineShader refinement,
eParticleRefineShaderType sh_type)
{
- if (e_data.hair_refine_sh[refinement] == NULL) {
- GPUShader *sh = NULL;
+ if (e_data.hair_refine_sh[refinement] == nullptr) {
+ GPUShader *sh = nullptr;
switch (sh_type) {
case PART_REFINE_SHADER_COMPUTE:
sh = hair_refine_shader_compute_create(refinement);
@@ -88,8 +88,8 @@ GPUShader *DRW_shader_hair_refine_get(ParticleRefineShader refinement,
GPUShader *DRW_shader_curves_refine_get(CurvesEvalShader type, eParticleRefineShaderType sh_type)
{
/* TODO: Implement curves evaluation types (Bezier and Catmull Rom). */
- if (e_data.hair_refine_sh[type] == NULL) {
- GPUShader *sh = NULL;
+ if (e_data.hair_refine_sh[type] == nullptr) {
+ GPUShader *sh = nullptr;
switch (sh_type) {
case PART_REFINE_SHADER_COMPUTE:
sh = hair_refine_shader_compute_create(PART_REFINE_CATMULL_ROM);
@@ -111,7 +111,7 @@ GPUShader *DRW_shader_curves_refine_get(CurvesEvalShader type, eParticleRefineSh
/** \} */
-void DRW_shaders_free(void)
+void DRW_shaders_free()
{
for (int i = 0; i < PART_REFINE_MAX_SHADER; i++) {
DRW_SHADER_FREE_SAFE(e_data.hair_refine_sh[i]);
diff --git a/source/blender/draw/intern/draw_shader.h b/source/blender/draw/intern/draw_shader.h
index 650e78c9362..63d755cc334 100644
--- a/source/blender/draw/intern/draw_shader.h
+++ b/source/blender/draw/intern/draw_shader.h
@@ -22,7 +22,7 @@ typedef enum eParticleRefineShaderType {
PART_REFINE_SHADER_COMPUTE,
} eParticleRefineShaderType;
-/* draw_shader.c */
+/* draw_shader.cc */
struct GPUShader *DRW_shader_hair_refine_get(ParticleRefineShader refinement,
eParticleRefineShaderType sh_type);
diff --git a/source/blender/draw/intern/draw_shader_shared.h b/source/blender/draw/intern/draw_shader_shared.h
index db128fffde7..94c0c53dab7 100644
--- a/source/blender/draw/intern/draw_shader_shared.h
+++ b/source/blender/draw/intern/draw_shader_shared.h
@@ -1,12 +1,14 @@
/* SPDX-License-Identifier: GPL-2.0-or-later */
#ifndef GPU_SHADER
+# include "GPU_shader.h"
# include "GPU_shader_shared_utils.h"
typedef struct ViewInfos ViewInfos;
typedef struct ObjectMatrices ObjectMatrices;
typedef struct ObjectInfos ObjectInfos;
typedef struct VolumeInfos VolumeInfos;
+typedef struct CurvesInfos CurvesInfos;
#endif
#define DRW_SHADER_SHARED_H
@@ -16,6 +18,10 @@ typedef struct VolumeInfos VolumeInfos;
/* Define the maximum number of grid we allow in a volume UBO. */
#define DRW_GRID_PER_VOLUME_MAX 16
+/* Define the maximum number of attribute we allow in a curves UBO.
+ * This should be kept in sync with `GPU_ATTR_MAX` */
+#define DRW_ATTRIBUTE_PER_CURVES_MAX 15
+
struct ViewInfos {
/* View matrices */
float4x4 persmat;
@@ -79,6 +85,14 @@ struct VolumeInfos {
};
BLI_STATIC_ASSERT_ALIGN(VolumeInfos, 16)
+struct CurvesInfos {
+ /* Per attribute scope, follows loading order.
+ * NOTE: uint as bool in GLSL is 4 bytes. */
+ uint is_point_attribute[DRW_ATTRIBUTE_PER_CURVES_MAX];
+ int _pad;
+};
+BLI_STATIC_ASSERT_ALIGN(CurvesInfos, 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
index 6f571084620..ef580fc116a 100644
--- a/source/blender/draw/intern/draw_subdivision.h
+++ b/source/blender/draw/intern/draw_subdivision.h
@@ -104,8 +104,10 @@ typedef struct DRWSubdivCache {
bool optimal_display;
bool use_custom_loop_normals;
- /* Coordinates used to evaluate patches for UVs, positions, and normals. */
+ /* Coordinates used to evaluate patches for positions and normals. */
struct GPUVertBuf *patch_coords;
+ /* Coordinates used to evaluate patches for attributes. */
+ struct GPUVertBuf *corner_patch_coords;
/* Coordinates used to evaluate patches for the face centers (or face dots) in edit-mode. */
struct GPUVertBuf *fdots_patch_coords;
@@ -175,6 +177,10 @@ typedef struct DRWSubdivCache {
/* UBO to store settings for the various compute shaders. */
struct GPUUniformBuf *ubo;
+
+ /* Extra flags, passed to the UBO. */
+ bool is_edit_mode;
+ bool use_hide;
} DRWSubdivCache;
/* Only frees the data of the cache, caller is responsible to free the cache itself if necessary.
@@ -183,8 +189,7 @@ void draw_subdiv_cache_free(DRWSubdivCache *cache);
/** \} */
-void DRW_create_subdivision(const struct Scene *scene,
- struct Object *ob,
+void DRW_create_subdivision(struct Object *ob,
struct Mesh *mesh,
struct MeshBatchCache *batch_cache,
struct MeshBufferCache *mbc,
@@ -194,7 +199,6 @@ void DRW_create_subdivision(const struct Scene *scene,
const float obmat[4][4],
const bool do_final,
const bool do_uvedit,
- const bool use_subsurf_fdots,
const ToolSettings *ts,
const bool use_hide);
@@ -236,7 +240,9 @@ void draw_subdiv_finalize_custom_normals(const DRWSubdivCache *cache,
GPUVertBuf *src_custom_normals,
GPUVertBuf *pos_nor);
-void draw_subdiv_extract_pos_nor(const DRWSubdivCache *cache, struct GPUVertBuf *pos_nor);
+void draw_subdiv_extract_pos_nor(const DRWSubdivCache *cache,
+ struct GPUVertBuf *pos_nor,
+ struct GPUVertBuf *orco);
void draw_subdiv_interp_custom_data(const DRWSubdivCache *cache,
struct GPUVertBuf *src_data,
@@ -264,6 +270,7 @@ void draw_subdiv_build_lines_buffer(const DRWSubdivCache *cache,
void draw_subdiv_build_lines_loose_buffer(const DRWSubdivCache *cache,
struct GPUIndexBuf *lines_indices,
+ GPUVertBuf *lines_flags,
uint num_loose_edges);
void draw_subdiv_build_fdots_buffers(const DRWSubdivCache *cache,
diff --git a/source/blender/draw/intern/draw_view_data.cc b/source/blender/draw/intern/draw_view_data.cc
index 0e55d28f6df..3dc28dc9a9a 100644
--- a/source/blender/draw/intern/draw_view_data.cc
+++ b/source/blender/draw/intern/draw_view_data.cc
@@ -88,7 +88,7 @@ void DRW_view_data_default_lists_from_viewport(DRWViewData *view_data, GPUViewpo
});
}
-static void draw_viewport_engines_data_clear(ViewportEngineData *data)
+static void draw_viewport_engines_data_clear(ViewportEngineData *data, bool clear_instance_data)
{
DrawEngineType *engine_type = data->engine_type->draw_engine;
const DrawEngineDataSize *data_size = engine_type->vedata_size;
@@ -103,7 +103,7 @@ static void draw_viewport_engines_data_clear(ViewportEngineData *data)
MEM_SAFE_FREE(data->stl->storage[i]);
}
- if (data->instance_data) {
+ if (clear_instance_data && data->instance_data) {
BLI_assert(engine_type->instance_free != nullptr);
engine_type->instance_free(data->instance_data);
data->instance_data = nullptr;
@@ -120,7 +120,7 @@ static void draw_viewport_engines_data_clear(ViewportEngineData *data)
}
}
-static void draw_view_data_clear(DRWViewData *view_data)
+static void draw_view_data_clear(DRWViewData *view_data, bool free_instance_data)
{
GPU_FRAMEBUFFER_FREE_SAFE(view_data->dfbl.default_fb);
GPU_FRAMEBUFFER_FREE_SAFE(view_data->dfbl.overlay_fb);
@@ -137,23 +137,20 @@ static void draw_view_data_clear(DRWViewData *view_data)
GPU_TEXTURE_FREE_SAFE(view_data->dtxl.depth_in_front);
for (ViewportEngineData &engine : view_data->engines) {
- draw_viewport_engines_data_clear(&engine);
+ draw_viewport_engines_data_clear(&engine, free_instance_data);
}
-
- view_data->texture_list_size[0] = view_data->texture_list_size[1] = 0;
- view_data->cache_time = 0.0f;
}
void DRW_view_data_free(DRWViewData *view_data)
{
- draw_view_data_clear(view_data);
+ draw_view_data_clear(view_data, true);
delete view_data;
}
void DRW_view_data_texture_list_size_validate(DRWViewData *view_data, const int size[2])
{
if (!equals_v2v2_int(view_data->texture_list_size, size)) {
- draw_view_data_clear(view_data);
+ draw_view_data_clear(view_data, false);
copy_v2_v2_int(view_data->texture_list_size, size);
}
}
@@ -195,7 +192,7 @@ void DRW_view_data_free_unused(DRWViewData *view_data)
{
for (ViewportEngineData &engine : view_data->engines) {
if (view_data->enabled_engines.first_index_of_try(&engine) == -1) {
- draw_viewport_engines_data_clear(&engine);
+ draw_viewport_engines_data_clear(&engine, false);
}
}
}
diff --git a/source/blender/draw/intern/draw_volume.cc b/source/blender/draw/intern/draw_volume.cc
index 8d9a6f486e2..c4e58ab24cb 100644
--- a/source/blender/draw/intern/draw_volume.cc
+++ b/source/blender/draw/intern/draw_volume.cc
@@ -129,12 +129,14 @@ static DRWShadingGroup *drw_volume_object_grids_init(Object *ob,
volume_infos.temperature_bias = 0.0f;
/* Bind volume grid textures. */
- int grid_id = 0;
+ int grid_id = 0, grids_len = 0;
LISTBASE_FOREACH (GPUMaterialAttribute *, attr, attrs) {
const VolumeGrid *volume_grid = BKE_volume_grid_find_for_read(volume, attr->name);
const DRWVolumeGrid *drw_grid = (volume_grid) ?
DRW_volume_batch_cache_get_grid(volume, volume_grid) :
nullptr;
+ /* Count number of valid attributes. */
+ grids_len += int(volume_grid != nullptr);
/* Handle 3 cases here:
* - Grid exists and texture was loaded -> use texture.
@@ -145,7 +147,13 @@ static DRWShadingGroup *drw_volume_object_grids_init(Object *ob,
grid_default_texture(attr->default_value);
DRW_shgroup_uniform_texture(grp, attr->input_name, grid_tex);
- copy_m4_m4(volume_infos.grids_xform[grid_id++].ptr(), drw_grid->object_to_texture);
+ copy_m4_m4(volume_infos.grids_xform[grid_id++].ptr(),
+ (drw_grid) ? drw_grid->object_to_texture : g_data.dummy_grid_mat);
+ }
+ /* Render nothing if there is no attribute for the shader to render.
+ * This also avoids an assert caused by the bounding box being zero in size. */
+ if (grids_len == 0) {
+ return nullptr;
}
volume_infos.push_update();
diff --git a/source/blender/draw/intern/mesh_extractors/extract_mesh.c b/source/blender/draw/intern/mesh_extractors/extract_mesh.cc
index 9dc82fa3d32..ec7d3a933b4 100644
--- a/source/blender/draw/intern/mesh_extractors/extract_mesh.c
+++ b/source/blender/draw/intern/mesh_extractors/extract_mesh.cc
@@ -13,7 +13,7 @@
#include "ED_uvedit.h"
-#include "extract_mesh.h"
+#include "extract_mesh.hh"
#include "draw_cache_impl.h"
@@ -29,7 +29,7 @@ void *mesh_extract_buffer_get(const MeshExtract *extractor, MeshBufferList *mbuf
eMRIterType mesh_extract_iter_type(const MeshExtract *ext)
{
- eMRIterType type = 0;
+ eMRIterType type = (eMRIterType)0;
SET_FLAG_FROM_TEST(type, (ext->iter_looptri_bm || ext->iter_looptri_mesh), MR_ITER_LOOPTRI);
SET_FLAG_FROM_TEST(type, (ext->iter_poly_bm || ext->iter_poly_mesh), MR_ITER_POLY);
SET_FLAG_FROM_TEST(type, (ext->iter_ledge_bm || ext->iter_ledge_mesh), MR_ITER_LEDGE);
@@ -128,7 +128,7 @@ void mesh_render_data_loop_flag(const MeshRenderData *mr,
return;
}
MLoopUV *luv = (MLoopUV *)BM_ELEM_CD_GET_VOID_P(l, cd_ofs);
- if (luv != NULL && (luv->flag & MLOOPUV_PINNED)) {
+ if (luv != nullptr && (luv->flag & MLOOPUV_PINNED)) {
eattr->v_flag |= VFLAG_VERT_UV_PINNED;
}
if (uvedit_uv_select_test_ex(mr->toolsettings, l, cd_ofs)) {
diff --git a/source/blender/draw/intern/mesh_extractors/extract_mesh.h b/source/blender/draw/intern/mesh_extractors/extract_mesh.hh
index d55386dfd7d..8052b277d45 100644
--- a/source/blender/draw/intern/mesh_extractors/extract_mesh.h
+++ b/source/blender/draw/intern/mesh_extractors/extract_mesh.hh
@@ -17,11 +17,7 @@
#include "BKE_customdata.h"
#include "BKE_editmesh.h"
-#include "draw_cache_extract.h"
-
-#ifdef __cplusplus
-extern "C" {
-#endif
+#include "draw_cache_extract.hh"
struct DRWSubdivCache;
@@ -31,13 +27,13 @@ struct DRWSubdivCache;
/** \name Mesh Render Data
* \{ */
-typedef enum eMRExtractType {
+enum eMRExtractType {
MR_EXTRACT_BMESH,
MR_EXTRACT_MAPPED,
MR_EXTRACT_MESH,
-} eMRExtractType;
+};
-typedef struct MeshRenderData {
+struct MeshRenderData {
eMRExtractType extract_type;
int poly_len, edge_len, vert_len, loop_len;
@@ -67,7 +63,7 @@ typedef struct MeshRenderData {
const float (*bm_poly_normals)[3];
const float (*bm_poly_centers)[3];
- int *v_origindex, *e_origindex, *p_origindex;
+ const int *v_origindex, *e_origindex, *p_origindex;
int edge_crease_ofs;
int vert_crease_ofs;
int bweight_ofs;
@@ -95,7 +91,7 @@ typedef struct MeshRenderData {
int *mat_tri_len;
int visible_tri_len;
} poly_sorted;
-} MeshRenderData;
+};
BLI_INLINE BMFace *bm_original_face_get(const MeshRenderData *mr, int idx)
{
@@ -159,71 +155,71 @@ 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, int elt_index, void *data);
-typedef void(ExtractTriMeshFn)(const MeshRenderData *mr,
- const MLoopTri *mlt,
- int elt_index,
- void *data);
-typedef void(ExtractPolyBMeshFn)(const MeshRenderData *mr,
- const BMFace *f,
- int f_index,
- void *data);
-typedef void(ExtractPolyMeshFn)(const MeshRenderData *mr,
- const MPoly *mp,
- int mp_index,
+using ExtractTriBMeshFn = void(const MeshRenderData *mr, BMLoop **elt, int elt_index, void *data);
+using ExtractTriMeshFn = void(const MeshRenderData *mr,
+ const MLoopTri *mlt,
+ int elt_index,
+ void *data);
+using ExtractPolyBMeshFn = void(const MeshRenderData *mr,
+ const BMFace *f,
+ int f_index,
void *data);
-typedef void(ExtractLEdgeBMeshFn)(const MeshRenderData *mr,
- const BMEdge *eed,
- int ledge_index,
- void *data);
-typedef void(ExtractLEdgeMeshFn)(const MeshRenderData *mr,
- const MEdge *med,
+using ExtractPolyMeshFn = void(const MeshRenderData *mr,
+ const MPoly *mp,
+ int mp_index,
+ void *data);
+using ExtractLEdgeBMeshFn = void(const MeshRenderData *mr,
+ const BMEdge *eed,
int ledge_index,
void *data);
-typedef void(ExtractLVertBMeshFn)(const MeshRenderData *mr,
- const BMVert *eve,
- int lvert_index,
- void *data);
-typedef void(ExtractLVertMeshFn)(const MeshRenderData *mr,
- const MVert *mv,
+using ExtractLEdgeMeshFn = void(const MeshRenderData *mr,
+ const MEdge *med,
+ int ledge_index,
+ void *data);
+using ExtractLVertBMeshFn = void(const MeshRenderData *mr,
+ const BMVert *eve,
int lvert_index,
void *data);
-typedef void(ExtractLooseGeomSubdivFn)(const struct DRWSubdivCache *subdiv_cache,
- const MeshRenderData *mr,
- void *buffer,
- void *data);
-typedef void(ExtractInitFn)(const MeshRenderData *mr,
- struct MeshBatchCache *cache,
- void *buffer,
- void *r_data);
-typedef void(ExtractFinishFn)(const MeshRenderData *mr,
- struct MeshBatchCache *cache,
- void *buffer,
- 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,
+using ExtractLVertMeshFn = void(const MeshRenderData *mr,
+ const MVert *mv,
+ int lvert_index,
+ void *data);
+using ExtractLooseGeomSubdivFn = void(const DRWSubdivCache *subdiv_cache,
+ const MeshRenderData *mr,
+ void *buffer,
+ void *data);
+using ExtractInitFn = void(const MeshRenderData *mr,
+ MeshBatchCache *cache,
+ void *buffer,
+ void *r_data);
+using ExtractFinishFn = void(const MeshRenderData *mr,
+ MeshBatchCache *cache,
+ void *buffer,
+ void *data);
+using ExtractTaskReduceFn = void(void *userdata, void *task_userdata);
+
+using ExtractInitSubdivFn = void(const DRWSubdivCache *subdiv_cache,
+ const MeshRenderData *mr,
+ MeshBatchCache *cache,
+ void *buf,
+ void *data);
+using ExtractIterSubdivBMeshFn = void(const 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 {
+ const BMFace *coarse_quad);
+using ExtractIterSubdivMeshFn = void(const DRWSubdivCache *subdiv_cache,
+ const MeshRenderData *mr,
+ void *data,
+ uint subdiv_quad_index,
+ const MPoly *coarse_quad);
+using ExtractFinishSubdivFn = void(const DRWSubdivCache *subdiv_cache,
+ const MeshRenderData *mr,
+ MeshBatchCache *cache,
+ void *buf,
+ void *data);
+
+struct MeshExtract {
/** Executed on main thread and return user data for iteration functions. */
ExtractInitFn *init;
/** Executed on one (or more if use_threading) worker thread(s). */
@@ -254,7 +250,7 @@ typedef struct MeshExtract {
* buffer.
*/
size_t mesh_buffer_offset;
-} MeshExtract;
+};
/** \} */
@@ -291,14 +287,14 @@ void mesh_render_data_update_looptris(MeshRenderData *mr,
/* draw_cache_extract_mesh_extractors.c */
-typedef struct EditLoopData {
+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;
+};
void *mesh_extract_buffer_get(const MeshExtract *extractor, MeshBufferList *mbuflist);
eMRIterType mesh_extract_iter_type(const MeshExtract *ext);
@@ -359,7 +355,3 @@ extern const MeshExtract extract_edge_idx;
extern const MeshExtract extract_vert_idx;
extern const MeshExtract extract_fdot_idx;
extern const MeshExtract extract_attr[GPU_MAX_ATTR];
-
-#ifdef __cplusplus
-}
-#endif
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 43aa52f08c8..2ff093d0bd8 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
@@ -7,7 +7,7 @@
#include "BLI_bitmap.h"
-#include "extract_mesh.h"
+#include "extract_mesh.hh"
#include "draw_subdivision.h"
@@ -22,7 +22,7 @@ struct MeshExtract_EditUvElem_Data {
};
static void extract_edituv_tris_init(const MeshRenderData *mr,
- struct MeshBatchCache *UNUSED(cache),
+ MeshBatchCache *UNUSED(cache),
void *UNUSED(ibo),
void *tls_data)
{
@@ -69,7 +69,7 @@ static void extract_edituv_tris_iter_looptri_mesh(const MeshRenderData *mr,
}
static void extract_edituv_tris_finish(const MeshRenderData *UNUSED(mr),
- struct MeshBatchCache *UNUSED(cache),
+ MeshBatchCache *UNUSED(cache),
void *buf,
void *_data)
{
@@ -142,7 +142,7 @@ static void extract_edituv_tris_iter_subdiv_mesh(const DRWSubdivCache *UNUSED(su
static void extract_edituv_tris_finish_subdiv(const struct DRWSubdivCache *UNUSED(subdiv_cache),
const MeshRenderData *UNUSED(mr),
- struct MeshBatchCache *UNUSED(cache),
+ MeshBatchCache *UNUSED(cache),
void *buf,
void *_data)
{
@@ -176,7 +176,7 @@ constexpr MeshExtract create_extractor_edituv_tris()
* \{ */
static void extract_edituv_lines_init(const MeshRenderData *mr,
- struct MeshBatchCache *UNUSED(cache),
+ MeshBatchCache *UNUSED(cache),
void *UNUSED(ibo),
void *tls_data)
{
@@ -236,7 +236,7 @@ static void extract_edituv_lines_iter_poly_mesh(const MeshRenderData *mr,
}
static void extract_edituv_lines_finish(const MeshRenderData *UNUSED(mr),
- struct MeshBatchCache *UNUSED(cache),
+ MeshBatchCache *UNUSED(cache),
void *buf,
void *_data)
{
@@ -307,7 +307,7 @@ static void extract_edituv_lines_iter_subdiv_mesh(const DRWSubdivCache *subdiv_c
static void extract_edituv_lines_finish_subdiv(const struct DRWSubdivCache *UNUSED(subdiv_cache),
const MeshRenderData *UNUSED(mr),
- struct MeshBatchCache *UNUSED(cache),
+ MeshBatchCache *UNUSED(cache),
void *buf,
void *_data)
{
@@ -341,7 +341,7 @@ constexpr MeshExtract create_extractor_edituv_lines()
* \{ */
static void extract_edituv_points_init(const MeshRenderData *mr,
- struct MeshBatchCache *UNUSED(cache),
+ MeshBatchCache *UNUSED(cache),
void *UNUSED(ibo),
void *tls_data)
{
@@ -387,15 +387,14 @@ static void extract_edituv_points_iter_poly_mesh(const MeshRenderData *mr,
for (int ml_index = mp->loopstart; ml_index < ml_index_end; ml_index += 1) {
const MLoop *ml = &mloop[ml_index];
- const bool real_vert = (mr->extract_type == MR_EXTRACT_MAPPED && (mr->v_origindex) &&
- mr->v_origindex[ml->v] != ORIGINDEX_NONE);
+ const bool real_vert = !mr->v_origindex || mr->v_origindex[ml->v] != ORIGINDEX_NONE;
edituv_point_add(
data, ((mp->flag & ME_HIDE) != 0) || !real_vert, (mp->flag & ME_FACE_SEL) != 0, ml_index);
}
}
static void extract_edituv_points_finish(const MeshRenderData *UNUSED(mr),
- struct MeshBatchCache *UNUSED(cache),
+ MeshBatchCache *UNUSED(cache),
void *buf,
void *_data)
{
@@ -449,9 +448,8 @@ static void extract_edituv_points_iter_subdiv_mesh(const DRWSubdivCache *subdiv_
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);
+ const bool real_vert = !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,
@@ -461,7 +459,7 @@ static void extract_edituv_points_iter_subdiv_mesh(const DRWSubdivCache *subdiv_
static void extract_edituv_points_finish_subdiv(const struct DRWSubdivCache *UNUSED(subdiv_cache),
const MeshRenderData *UNUSED(mr),
- struct MeshBatchCache *UNUSED(cache),
+ MeshBatchCache *UNUSED(cache),
void *buf,
void *_data)
{
@@ -495,7 +493,7 @@ constexpr MeshExtract create_extractor_edituv_points()
* \{ */
static void extract_edituv_fdots_init(const MeshRenderData *mr,
- struct MeshBatchCache *UNUSED(cache),
+ MeshBatchCache *UNUSED(cache),
void *UNUSED(ibo),
void *tls_data)
{
@@ -543,8 +541,7 @@ static void extract_edituv_fdots_iter_poly_mesh(const MeshRenderData *mr,
for (int ml_index = mp->loopstart; ml_index < ml_index_end; ml_index += 1) {
const MLoop *ml = &mloop[ml_index];
- const bool real_fdot = (mr->extract_type == MR_EXTRACT_MAPPED && mr->p_origindex &&
- mr->p_origindex[mp_index] != ORIGINDEX_NONE);
+ const bool real_fdot = !mr->p_origindex || (mr->p_origindex[mp_index] != ORIGINDEX_NONE);
const bool subd_fdot = BLI_BITMAP_TEST(facedot_tags, ml->v);
edituv_facedot_add(data,
((mp->flag & ME_HIDE) != 0) || !real_fdot || !subd_fdot,
@@ -553,15 +550,14 @@ static void extract_edituv_fdots_iter_poly_mesh(const MeshRenderData *mr,
}
}
else {
- const bool real_fdot = (mr->extract_type == MR_EXTRACT_MAPPED && mr->p_origindex &&
- mr->p_origindex[mp_index] != ORIGINDEX_NONE);
+ const bool real_fdot = !mr->p_origindex || (mr->p_origindex[mp_index] != ORIGINDEX_NONE);
edituv_facedot_add(
data, ((mp->flag & ME_HIDE) != 0) || !real_fdot, (mp->flag & ME_FACE_SEL) != 0, mp_index);
}
}
static void extract_edituv_fdots_finish(const MeshRenderData *UNUSED(mr),
- struct MeshBatchCache *UNUSED(cache),
+ MeshBatchCache *UNUSED(cache),
void *buf,
void *_data)
{
@@ -588,9 +584,7 @@ constexpr MeshExtract create_extractor_edituv_fdots()
} // namespace blender::draw
-extern "C" {
const MeshExtract extract_edituv_tris = blender::draw::create_extractor_edituv_tris();
const MeshExtract extract_edituv_lines = blender::draw::create_extractor_edituv_lines();
const MeshExtract extract_edituv_points = blender::draw::create_extractor_edituv_points();
const MeshExtract extract_edituv_fdots = blender::draw::create_extractor_edituv_fdots();
-}
diff --git a/source/blender/draw/intern/mesh_extractors/extract_mesh_ibo_fdots.cc b/source/blender/draw/intern/mesh_extractors/extract_mesh_ibo_fdots.cc
index 4bf732caf0a..cc0b383f12b 100644
--- a/source/blender/draw/intern/mesh_extractors/extract_mesh_ibo_fdots.cc
+++ b/source/blender/draw/intern/mesh_extractors/extract_mesh_ibo_fdots.cc
@@ -7,7 +7,7 @@
#include "BLI_bitmap.h"
-#include "extract_mesh.h"
+#include "extract_mesh.hh"
namespace blender::draw {
/* ---------------------------------------------------------------------- */
@@ -15,7 +15,7 @@ namespace blender::draw {
* \{ */
static void extract_fdots_init(const MeshRenderData *mr,
- struct MeshBatchCache *UNUSED(cache),
+ MeshBatchCache *UNUSED(cache),
void *UNUSED(buf),
void *tls_data)
{
@@ -68,7 +68,7 @@ static void extract_fdots_iter_poly_mesh(const MeshRenderData *mr,
}
static void extract_fdots_finish(const MeshRenderData *UNUSED(mr),
- struct MeshBatchCache *UNUSED(cache),
+ MeshBatchCache *UNUSED(cache),
void *buf,
void *_userdata)
{
@@ -95,6 +95,4 @@ constexpr MeshExtract create_extractor_fdots()
} // namespace blender::draw
-extern "C" {
const MeshExtract extract_fdots = blender::draw::create_extractor_fdots();
-}
diff --git a/source/blender/draw/intern/mesh_extractors/extract_mesh_ibo_lines.cc b/source/blender/draw/intern/mesh_extractors/extract_mesh_ibo_lines.cc
index ce3ca428469..51d98d1ff26 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
@@ -7,7 +7,7 @@
#include "MEM_guardedalloc.h"
-#include "extract_mesh.h"
+#include "extract_mesh.hh"
#include "draw_subdivision.h"
@@ -18,7 +18,7 @@ namespace blender::draw {
* \{ */
static void extract_lines_init(const MeshRenderData *mr,
- struct MeshBatchCache *UNUSED(cache),
+ MeshBatchCache *UNUSED(cache),
void *UNUSED(buf),
void *tls_data)
{
@@ -132,7 +132,7 @@ static void extract_lines_task_reduce(void *_userdata_to, void *_userdata_from)
}
static void extract_lines_finish(const MeshRenderData *UNUSED(mr),
- struct MeshBatchCache *UNUSED(cache),
+ MeshBatchCache *UNUSED(cache),
void *buf,
void *data)
{
@@ -143,7 +143,7 @@ static void extract_lines_finish(const MeshRenderData *UNUSED(mr),
static void extract_lines_init_subdiv(const DRWSubdivCache *subdiv_cache,
const MeshRenderData *UNUSED(mr),
- struct MeshBatchCache *UNUSED(cache),
+ MeshBatchCache *UNUSED(cache),
void *buffer,
void *UNUSED(data))
{
@@ -160,7 +160,7 @@ static void extract_lines_init_subdiv(const DRWSubdivCache *subdiv_cache,
}
static void extract_lines_loose_geom_subdiv(const DRWSubdivCache *subdiv_cache,
- const MeshRenderData *UNUSED(mr),
+ const MeshRenderData *mr,
void *buffer,
void *UNUSED(data))
{
@@ -169,8 +169,39 @@ static void extract_lines_loose_geom_subdiv(const DRWSubdivCache *subdiv_cache,
return;
}
+ /* Update flags for loose edges, points are already handled. */
+ static GPUVertFormat format;
+ if (format.attr_len == 0) {
+ GPU_vertformat_attr_add(&format, "data", GPU_COMP_U32, 1, GPU_FETCH_INT);
+ }
+
+ GPUVertBuf *flags = GPU_vertbuf_calloc();
+ GPU_vertbuf_init_with_format(flags, &format);
+
+ Span<DRWSubdivLooseEdge> loose_edges = draw_subdiv_cache_get_loose_edges(subdiv_cache);
+ GPU_vertbuf_data_alloc(flags, loose_edges.size());
+
+ uint *flags_data = static_cast<uint *>(GPU_vertbuf_get_data(flags));
+
+ if (mr->extract_type == MR_EXTRACT_MESH) {
+ const MEdge *medge = mr->medge;
+ for (DRWSubdivLooseEdge edge : loose_edges) {
+ *flags_data++ = (medge[edge.coarse_edge_index].flag & ME_HIDE) != 0;
+ }
+ }
+ else {
+ BMesh *bm = mr->bm;
+ for (DRWSubdivLooseEdge edge : loose_edges) {
+ const BMEdge *bm_edge = BM_edge_at_index(bm, edge.coarse_edge_index);
+ *flags_data++ = BM_elem_flag_test_bool(bm_edge, BM_ELEM_HIDDEN) != 0;
+ }
+ }
+
GPUIndexBuf *ibo = static_cast<GPUIndexBuf *>(buffer);
- draw_subdiv_build_lines_loose_buffer(subdiv_cache, ibo, static_cast<uint>(loose_geom.edge_len));
+ draw_subdiv_build_lines_loose_buffer(
+ subdiv_cache, ibo, flags, static_cast<uint>(loose_geom.edge_len));
+
+ GPU_vertbuf_discard(flags);
}
constexpr MeshExtract create_extractor_lines()
@@ -198,7 +229,7 @@ constexpr MeshExtract create_extractor_lines()
/** \name Extract Lines and Loose Edges Sub Buffer
* \{ */
-static void extract_lines_loose_subbuffer(const MeshRenderData *mr, struct MeshBatchCache *cache)
+static void extract_lines_loose_subbuffer(const MeshRenderData *mr, MeshBatchCache *cache)
{
BLI_assert(cache->final.buff.ibo.lines);
/* Multiply by 2 because these are edges indices. */
@@ -210,7 +241,7 @@ static void extract_lines_loose_subbuffer(const MeshRenderData *mr, struct MeshB
}
static void extract_lines_with_lines_loose_finish(const MeshRenderData *mr,
- struct MeshBatchCache *cache,
+ MeshBatchCache *cache,
void *buf,
void *data)
{
@@ -222,7 +253,7 @@ static void extract_lines_with_lines_loose_finish(const MeshRenderData *mr,
static void extract_lines_with_lines_loose_finish_subdiv(const struct DRWSubdivCache *subdiv_cache,
const MeshRenderData *UNUSED(mr),
- struct MeshBatchCache *cache,
+ MeshBatchCache *cache,
void *UNUSED(buf),
void *UNUSED(_data))
{
@@ -261,7 +292,7 @@ constexpr MeshExtract create_extractor_lines_with_lines_loose()
* \{ */
static void extract_lines_loose_only_init(const MeshRenderData *mr,
- struct MeshBatchCache *cache,
+ MeshBatchCache *cache,
void *buf,
void *UNUSED(tls_data))
{
@@ -272,7 +303,7 @@ static void extract_lines_loose_only_init(const MeshRenderData *mr,
static void extract_lines_loose_only_init_subdiv(const DRWSubdivCache *UNUSED(subdiv_cache),
const MeshRenderData *mr,
- struct MeshBatchCache *cache,
+ MeshBatchCache *cache,
void *buffer,
void *UNUSED(data))
{
@@ -297,9 +328,7 @@ constexpr MeshExtract create_extractor_lines_loose_only()
} // namespace blender::draw
-extern "C" {
const MeshExtract extract_lines = blender::draw::create_extractor_lines();
const MeshExtract extract_lines_with_lines_loose =
blender::draw::create_extractor_lines_with_lines_loose();
const MeshExtract extract_lines_loose_only = blender::draw::create_extractor_lines_loose_only();
-}
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 de464fb286f..c2cfb66ec28 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
@@ -11,7 +11,7 @@
#include "MEM_guardedalloc.h"
#include "draw_subdivision.h"
-#include "extract_mesh.h"
+#include "extract_mesh.hh"
namespace blender::draw {
@@ -42,7 +42,7 @@ static void line_adjacency_data_init(MeshExtract_LineAdjacency_Data *data,
}
static void extract_lines_adjacency_init(const MeshRenderData *mr,
- struct MeshBatchCache *UNUSED(cache),
+ MeshBatchCache *UNUSED(cache),
void *UNUSED(buf),
void *tls_data)
{
@@ -132,7 +132,7 @@ static void extract_lines_adjacency_iter_looptri_mesh(const MeshRenderData *mr,
}
static void extract_lines_adjacency_finish(const MeshRenderData *UNUSED(mr),
- struct MeshBatchCache *cache,
+ MeshBatchCache *cache,
void *buf,
void *_data)
{
@@ -166,7 +166,7 @@ static void extract_lines_adjacency_finish(const MeshRenderData *UNUSED(mr),
static void extract_lines_adjacency_init_subdiv(const DRWSubdivCache *subdiv_cache,
const MeshRenderData *UNUSED(mr),
- struct MeshBatchCache *UNUSED(cache),
+ MeshBatchCache *UNUSED(cache),
void *UNUSED(buf),
void *_data)
{
@@ -222,7 +222,7 @@ static void extract_lines_adjacency_iter_subdiv_mesh(const DRWSubdivCache *subdi
static void extract_lines_adjacency_finish_subdiv(const DRWSubdivCache *UNUSED(subdiv_cache),
const MeshRenderData *mr,
- struct MeshBatchCache *cache,
+ MeshBatchCache *cache,
void *buf,
void *_data)
{
@@ -253,6 +253,4 @@ constexpr MeshExtract create_extractor_lines_adjacency()
} // namespace blender::draw
-extern "C" {
const MeshExtract extract_lines_adjacency = blender::draw::create_extractor_lines_adjacency();
-}
diff --git a/source/blender/draw/intern/mesh_extractors/extract_mesh_ibo_lines_paint_mask.cc b/source/blender/draw/intern/mesh_extractors/extract_mesh_ibo_lines_paint_mask.cc
index 286c7ea9c43..11c71d61775 100644
--- a/source/blender/draw/intern/mesh_extractors/extract_mesh_ibo_lines_paint_mask.cc
+++ b/source/blender/draw/intern/mesh_extractors/extract_mesh_ibo_lines_paint_mask.cc
@@ -12,7 +12,7 @@
#include "MEM_guardedalloc.h"
#include "draw_subdivision.h"
-#include "extract_mesh.h"
+#include "extract_mesh.hh"
namespace blender::draw {
/* ---------------------------------------------------------------------- */
@@ -26,7 +26,7 @@ struct MeshExtract_LinePaintMask_Data {
};
static void extract_lines_paint_mask_init(const MeshRenderData *mr,
- struct MeshBatchCache *UNUSED(cache),
+ MeshBatchCache *UNUSED(cache),
void *UNUSED(ibo),
void *tls_data)
{
@@ -78,7 +78,7 @@ static void extract_lines_paint_mask_iter_poly_mesh(const MeshRenderData *mr,
}
static void extract_lines_paint_mask_finish(const MeshRenderData *UNUSED(mr),
- struct MeshBatchCache *UNUSED(cache),
+ MeshBatchCache *UNUSED(cache),
void *buf,
void *_data)
{
@@ -126,7 +126,8 @@ static void extract_lines_paint_mask_iter_subdiv_mesh(const DRWSubdivCache *subd
if (!((mr->use_hide && (me->flag & ME_HIDE)) ||
((mr->extract_type == MR_EXTRACT_MAPPED) && (mr->e_origindex) &&
(mr->e_origindex[coarse_edge_index] == ORIGINDEX_NONE)))) {
- const uint ml_index_other = (loop_idx == end_loop_idx) ? start_loop_idx : loop_idx + 1;
+ const uint ml_index_other = (loop_idx == (end_loop_idx - 1)) ? start_loop_idx :
+ loop_idx + 1;
if (coarse_quad->flag & ME_FACE_SEL) {
if (BLI_BITMAP_TEST_AND_SET_ATOMIC(data->select_map, coarse_edge_index)) {
/* Hide edge as it has more than 2 selected loop. */
@@ -154,7 +155,7 @@ static void extract_lines_paint_mask_iter_subdiv_mesh(const DRWSubdivCache *subd
static void extract_lines_paint_mask_finish_subdiv(
const struct DRWSubdivCache *UNUSED(subdiv_cache),
const MeshRenderData *mr,
- struct MeshBatchCache *cache,
+ MeshBatchCache *cache,
void *buf,
void *_data)
{
@@ -181,6 +182,4 @@ constexpr MeshExtract create_extractor_lines_paint_mask()
} // namespace blender::draw
-extern "C" {
const MeshExtract extract_lines_paint_mask = blender::draw::create_extractor_lines_paint_mask();
-}
diff --git a/source/blender/draw/intern/mesh_extractors/extract_mesh_ibo_points.cc b/source/blender/draw/intern/mesh_extractors/extract_mesh_ibo_points.cc
index 272963f3fd5..f7c5505422b 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
@@ -10,7 +10,7 @@
#include "MEM_guardedalloc.h"
#include "draw_subdivision.h"
-#include "extract_mesh.h"
+#include "extract_mesh.hh"
namespace blender::draw {
@@ -19,7 +19,7 @@ namespace blender::draw {
* \{ */
static void extract_points_init(const MeshRenderData *mr,
- struct MeshBatchCache *UNUSED(cache),
+ MeshBatchCache *UNUSED(cache),
void *UNUSED(buf),
void *tls_data)
{
@@ -131,7 +131,7 @@ static void extract_points_task_reduce(void *_userdata_to, void *_userdata_from)
}
static void extract_points_finish(const MeshRenderData *UNUSED(mr),
- struct MeshBatchCache *UNUSED(cache),
+ MeshBatchCache *UNUSED(cache),
void *buf,
void *_userdata)
{
@@ -142,7 +142,7 @@ static void extract_points_finish(const MeshRenderData *UNUSED(mr),
static void extract_points_init_subdiv(const DRWSubdivCache *subdiv_cache,
const MeshRenderData *mr,
- struct MeshBatchCache *UNUSED(cache),
+ MeshBatchCache *UNUSED(cache),
void *UNUSED(buffer),
void *data)
{
@@ -156,7 +156,8 @@ static void extract_points_init_subdiv(const DRWSubdivCache *subdiv_cache,
static void extract_points_iter_subdiv_common(GPUIndexBufBuilder *elb,
const MeshRenderData *mr,
const DRWSubdivCache *subdiv_cache,
- uint subdiv_quad_index)
+ uint subdiv_quad_index,
+ bool for_bmesh)
{
int *subdiv_loop_vert_index = (int *)GPU_vertbuf_get_data(subdiv_cache->verts_orig_index);
uint start_loop_idx = subdiv_quad_index * 4;
@@ -172,6 +173,21 @@ static void extract_points_iter_subdiv_common(GPUIndexBufBuilder *elb,
continue;
}
+ if (for_bmesh) {
+ const BMVert *mv = BM_vert_at_index(mr->bm, coarse_vertex_index);
+ if (BM_elem_flag_test(mv, BM_ELEM_HIDDEN)) {
+ GPU_indexbuf_set_point_restart(elb, coarse_vertex_index);
+ continue;
+ }
+ }
+ else {
+ const MVert *mv = &mr->mvert[coarse_vertex_index];
+ if (mr->use_hide && (mv->flag & ME_HIDE)) {
+ GPU_indexbuf_set_point_restart(elb, coarse_vertex_index);
+ continue;
+ }
+ }
+
GPU_indexbuf_set_point_vert(elb, coarse_vertex_index, i);
}
}
@@ -183,7 +199,7 @@ static void extract_points_iter_subdiv_bm(const DRWSubdivCache *subdiv_cache,
const BMFace *UNUSED(coarse_quad))
{
GPUIndexBufBuilder *elb = static_cast<GPUIndexBufBuilder *>(_data);
- extract_points_iter_subdiv_common(elb, mr, subdiv_cache, subdiv_quad_index);
+ extract_points_iter_subdiv_common(elb, mr, subdiv_cache, subdiv_quad_index, true);
}
static void extract_points_iter_subdiv_mesh(const DRWSubdivCache *subdiv_cache,
@@ -193,7 +209,7 @@ static void extract_points_iter_subdiv_mesh(const DRWSubdivCache *subdiv_cache,
const MPoly *UNUSED(coarse_quad))
{
GPUIndexBufBuilder *elb = static_cast<GPUIndexBufBuilder *>(_data);
- extract_points_iter_subdiv_common(elb, mr, subdiv_cache, subdiv_quad_index);
+ extract_points_iter_subdiv_common(elb, mr, subdiv_cache, subdiv_quad_index, false);
}
static void extract_points_loose_geom_subdiv(const DRWSubdivCache *subdiv_cache,
@@ -269,7 +285,7 @@ static void extract_points_loose_geom_subdiv(const DRWSubdivCache *subdiv_cache,
static void extract_points_finish_subdiv(const DRWSubdivCache *UNUSED(subdiv_cache),
const MeshRenderData *UNUSED(mr),
- struct MeshBatchCache *UNUSED(cache),
+ MeshBatchCache *UNUSED(cache),
void *buf,
void *_userdata)
{
@@ -306,6 +322,4 @@ constexpr MeshExtract create_extractor_points()
} // namespace blender::draw
-extern "C" {
const MeshExtract extract_points = blender::draw::create_extractor_points();
-}
diff --git a/source/blender/draw/intern/mesh_extractors/extract_mesh_ibo_tris.cc b/source/blender/draw/intern/mesh_extractors/extract_mesh_ibo_tris.cc
index 6ca5692f387..9fc18620d11 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
@@ -7,7 +7,7 @@
#include "MEM_guardedalloc.h"
-#include "extract_mesh.h"
+#include "extract_mesh.hh"
#include "draw_subdivision.h"
@@ -25,7 +25,7 @@ static void extract_tris_mat_task_reduce(void *_userdata_to, void *_userdata_fro
* \{ */
static void extract_tris_init(const MeshRenderData *mr,
- struct MeshBatchCache *UNUSED(cache),
+ MeshBatchCache *UNUSED(cache),
void *UNUSED(ibo),
void *tls_data)
{
@@ -81,7 +81,7 @@ static void extract_tris_iter_poly_mesh(const MeshRenderData *mr,
}
static void extract_tris_finish(const MeshRenderData *mr,
- struct MeshBatchCache *cache,
+ MeshBatchCache *cache,
void *buf,
void *_data)
{
@@ -111,7 +111,7 @@ 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,
+ MeshBatchCache *cache,
void *buffer,
void *UNUSED(data))
{
@@ -157,7 +157,7 @@ constexpr MeshExtract create_extractor_tris()
* \{ */
static void extract_tris_single_mat_init(const MeshRenderData *mr,
- struct MeshBatchCache *UNUSED(cache),
+ MeshBatchCache *UNUSED(cache),
void *UNUSED(ibo),
void *tls_data)
{
@@ -199,7 +199,7 @@ static void extract_tris_single_mat_iter_looptri_mesh(const MeshRenderData *mr,
}
static void extract_tris_single_mat_finish(const MeshRenderData *mr,
- struct MeshBatchCache *cache,
+ MeshBatchCache *cache,
void *buf,
void *_data)
{
@@ -243,7 +243,5 @@ constexpr MeshExtract create_extractor_tris_single_mat()
} // namespace blender::draw
-extern "C" {
const MeshExtract extract_tris = blender::draw::create_extractor_tris();
const MeshExtract extract_tris_single_mat = blender::draw::create_extractor_tris_single_mat();
-}
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 f9e58709c6e..ff86bc768a3 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
@@ -14,8 +14,9 @@
#include "BKE_attribute.h"
+#include "draw_attributes.h"
#include "draw_subdivision.h"
-#include "extract_mesh.h"
+#include "extract_mesh.hh"
namespace blender::draw {
@@ -23,24 +24,19 @@ namespace blender::draw {
/** \name Extract Attributes
* \{ */
-static CustomData *get_custom_data_for_domain(const MeshRenderData *mr, AttributeDomain domain)
+static CustomData *get_custom_data_for_domain(const MeshRenderData *mr, eAttrDomain domain)
{
switch (domain) {
- default: {
- return nullptr;
- }
- case ATTR_DOMAIN_POINT: {
+ case ATTR_DOMAIN_POINT:
return (mr->extract_type == MR_EXTRACT_BMESH) ? &mr->bm->vdata : &mr->me->vdata;
- }
- case ATTR_DOMAIN_CORNER: {
+ case ATTR_DOMAIN_CORNER:
return (mr->extract_type == MR_EXTRACT_BMESH) ? &mr->bm->ldata : &mr->me->ldata;
- }
- case ATTR_DOMAIN_FACE: {
+ case ATTR_DOMAIN_FACE:
return (mr->extract_type == MR_EXTRACT_BMESH) ? &mr->bm->pdata : &mr->me->pdata;
- }
- case ATTR_DOMAIN_EDGE: {
+ case ATTR_DOMAIN_EDGE:
return (mr->extract_type == MR_EXTRACT_BMESH) ? &mr->bm->edata : &mr->me->edata;
- }
+ default:
+ return nullptr;
}
}
@@ -49,7 +45,7 @@ static CustomData *get_custom_data_for_domain(const MeshRenderData *mr, Attribut
* etc.) directly map to available GPU types. Booleans are still converted as attributes are vec4
* in the shader.
*/
-template<typename AttributeType, typename VBOType> struct attribute_type_converter {
+template<typename AttributeType, typename VBOType> struct AttributeTypeConverter {
static VBOType convert_value(AttributeType value)
{
if constexpr (std::is_same_v<AttributeType, VBOType>) {
@@ -66,7 +62,7 @@ struct gpuMeshCol {
ushort r, g, b, a;
};
-template<> struct attribute_type_converter<MPropCol, gpuMeshCol> {
+template<> struct AttributeTypeConverter<MPropCol, gpuMeshCol> {
static gpuMeshCol convert_value(MPropCol value)
{
gpuMeshCol result;
@@ -79,64 +75,52 @@ template<> struct attribute_type_converter<MPropCol, gpuMeshCol> {
};
/* Return the number of component for the attribute's value type, or 0 if is it unsupported. */
-static uint gpu_component_size_for_attribute_type(CustomDataType type)
+static uint gpu_component_size_for_attribute_type(eCustomDataType type)
{
switch (type) {
case CD_PROP_BOOL:
case CD_PROP_INT8:
case CD_PROP_INT32:
- case CD_PROP_FLOAT: {
+ case CD_PROP_FLOAT:
/* TODO(@kevindietrich): should be 1 when scalar attributes conversion is handled by us. See
* comment #extract_attr_init. */
return 3;
- }
- case CD_PROP_FLOAT2: {
+ case CD_PROP_FLOAT2:
return 2;
- }
- case CD_PROP_FLOAT3: {
+ case CD_PROP_FLOAT3:
return 3;
- }
- case CD_PROP_COLOR: {
+ case CD_PROP_COLOR:
return 4;
- }
- default: {
+ default:
return 0;
- }
}
}
-static GPUVertFetchMode get_fetch_mode_for_type(CustomDataType type)
+static GPUVertFetchMode get_fetch_mode_for_type(eCustomDataType type)
{
switch (type) {
- case CD_PROP_INT32: {
+ case CD_PROP_INT32:
return GPU_FETCH_INT_TO_FLOAT;
- }
- case CD_PROP_COLOR: {
+ case CD_PROP_COLOR:
return GPU_FETCH_INT_TO_FLOAT_UNIT;
- }
- default: {
+ default:
return GPU_FETCH_FLOAT;
- }
}
}
-static GPUVertCompType get_comp_type_for_type(CustomDataType type)
+static GPUVertCompType get_comp_type_for_type(eCustomDataType type)
{
switch (type) {
- case CD_PROP_INT32: {
+ case CD_PROP_INT32:
return GPU_COMP_I32;
- }
- case CD_PROP_COLOR: {
+ case CD_PROP_COLOR:
return GPU_COMP_U16;
- }
- default: {
+ default:
return GPU_COMP_F32;
- }
}
}
-static void init_vbo_for_attribute(const MeshRenderData *mr,
- GPUVertBuf *vbo,
+static void init_vbo_for_attribute(GPUVertBuf *vbo,
const DRW_AttributeRequest &request,
bool build_on_device,
uint32_t len)
@@ -147,11 +131,8 @@ static void init_vbo_for_attribute(const MeshRenderData *mr,
/* We should not be here if the attribute type is not supported. */
BLI_assert(comp_size != 0);
- const CustomData *custom_data = get_custom_data_for_domain(mr, request.domain);
char attr_name[32], attr_safe_name[GPU_MAX_SAFE_ATTR_NAME];
- const char *layer_name = CustomData_get_layer_name(
- custom_data, request.cd_type, request.layer_index);
- GPU_vertformat_safe_attr_name(layer_name, attr_safe_name, GPU_MAX_SAFE_ATTR_NAME);
+ GPU_vertformat_safe_attr_name(request.attribute_name, attr_safe_name, GPU_MAX_SAFE_ATTR_NAME);
/* Attributes use auto-name. */
BLI_snprintf(attr_name, sizeof(attr_name), "a%s", attr_safe_name);
@@ -180,44 +161,39 @@ static void fill_vertbuf_with_attribute(const MeshRenderData *mr,
const MPoly *mpoly = mr->mpoly;
const MLoop *mloop = mr->mloop;
- const AttributeType *attr_data = static_cast<AttributeType *>(
+ const AttributeType *attr_data = static_cast<const AttributeType *>(
CustomData_get_layer_n(custom_data, request.cd_type, layer_index));
- using converter = attribute_type_converter<AttributeType, VBOType>;
+ using Converter = AttributeTypeConverter<AttributeType, VBOType>;
switch (request.domain) {
- default: {
- BLI_assert(false);
- break;
- }
- case ATTR_DOMAIN_POINT: {
+ case ATTR_DOMAIN_POINT:
for (int ml_index = 0; ml_index < mr->loop_len; ml_index++, vbo_data++, mloop++) {
- *vbo_data = converter::convert_value(attr_data[mloop->v]);
+ *vbo_data = Converter::convert_value(attr_data[mloop->v]);
}
break;
- }
- case ATTR_DOMAIN_CORNER: {
+ case ATTR_DOMAIN_CORNER:
for (int ml_index = 0; ml_index < mr->loop_len; ml_index++, vbo_data++) {
- *vbo_data = converter::convert_value(attr_data[ml_index]);
+ *vbo_data = Converter::convert_value(attr_data[ml_index]);
}
break;
- }
- case ATTR_DOMAIN_EDGE: {
+ case ATTR_DOMAIN_EDGE:
for (int ml_index = 0; ml_index < mr->loop_len; ml_index++, vbo_data++, mloop++) {
- *vbo_data = converter::convert_value(attr_data[mloop->e]);
+ *vbo_data = Converter::convert_value(attr_data[mloop->e]);
}
break;
- }
- case ATTR_DOMAIN_FACE: {
+ case ATTR_DOMAIN_FACE:
for (int mp_index = 0; mp_index < mr->poly_len; mp_index++) {
const MPoly &poly = mpoly[mp_index];
- const VBOType value = converter::convert_value(attr_data[mp_index]);
+ const VBOType value = Converter::convert_value(attr_data[mp_index]);
for (int l = 0; l < poly.totloop; l++) {
*vbo_data++ = value;
}
}
break;
- }
+ default:
+ BLI_assert_unreachable();
+ break;
}
}
@@ -230,9 +206,9 @@ static void fill_vertbuf_with_attribute_bm(const MeshRenderData *mr,
BLI_assert(custom_data);
const int layer_index = request.layer_index;
- int cd_ofs = CustomData_get_n_offset(custom_data, request.cd_type, layer_index);
+ const int cd_ofs = CustomData_get_n_offset(custom_data, request.cd_type, layer_index);
- using converter = attribute_type_converter<AttributeType, VBOType>;
+ using Converter = AttributeTypeConverter<AttributeType, VBOType>;
BMIter f_iter;
BMFace *efa;
@@ -254,10 +230,10 @@ static void fill_vertbuf_with_attribute_bm(const MeshRenderData *mr,
attr_data = static_cast<const AttributeType *>(BM_ELEM_CD_GET_VOID_P(l_iter->e, cd_ofs));
}
else {
- BLI_assert(false);
+ BLI_assert_unreachable();
continue;
}
- *vbo_data = converter::convert_value(*attr_data);
+ *vbo_data = Converter::convert_value(*attr_data);
vbo_data++;
} while ((l_iter = l_iter->next) != l_first);
}
@@ -278,55 +254,44 @@ static void extract_attr_generic(const MeshRenderData *mr,
}
}
-static void extract_attr_init(const MeshRenderData *mr,
- struct MeshBatchCache *cache,
- void *buf,
- void *UNUSED(tls_data),
- int index)
+static void extract_attr_init(
+ const MeshRenderData *mr, MeshBatchCache *cache, void *buf, void *UNUSED(tls_data), int index)
{
- const DRW_MeshAttributes *attrs_used = &cache->attr_used;
+ const DRW_Attributes *attrs_used = &cache->attr_used;
const DRW_AttributeRequest &request = attrs_used->requests[index];
GPUVertBuf *vbo = static_cast<GPUVertBuf *>(buf);
- init_vbo_for_attribute(mr, vbo, request, false, static_cast<uint32_t>(mr->loop_len));
+ init_vbo_for_attribute(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
* Blender convention, it should be `vec4(s, s, s, 1)`. This could be resolved using a similar
* texture as for volume attribute, so we can control the conversion ourselves. */
switch (request.cd_type) {
- case CD_PROP_BOOL: {
+ case CD_PROP_BOOL:
extract_attr_generic<bool, float3>(mr, vbo, request);
break;
- }
- case CD_PROP_INT8: {
+ case CD_PROP_INT8:
extract_attr_generic<int8_t, float3>(mr, vbo, request);
break;
- }
- case CD_PROP_INT32: {
+ case CD_PROP_INT32:
extract_attr_generic<int32_t, float3>(mr, vbo, request);
break;
- }
- case CD_PROP_FLOAT: {
+ case CD_PROP_FLOAT:
extract_attr_generic<float, float3>(mr, vbo, request);
break;
- }
- case CD_PROP_FLOAT2: {
+ case CD_PROP_FLOAT2:
extract_attr_generic<float2>(mr, vbo, request);
break;
- }
- case CD_PROP_FLOAT3: {
+ case CD_PROP_FLOAT3:
extract_attr_generic<float3>(mr, vbo, request);
break;
- }
- case CD_PROP_COLOR: {
+ case CD_PROP_COLOR:
extract_attr_generic<MPropCol, gpuMeshCol>(mr, vbo, request);
break;
- }
- default: {
- BLI_assert(false);
- }
+ default:
+ BLI_assert_unreachable();
}
}
@@ -337,7 +302,7 @@ static void extract_attr_init_subdiv(const DRWSubdivCache *subdiv_cache,
void *UNUSED(tls_data),
int index)
{
- const DRW_MeshAttributes *attrs_used = &cache->attr_used;
+ const DRW_Attributes *attrs_used = &cache->attr_used;
const DRW_AttributeRequest &request = attrs_used->requests[index];
Mesh *coarse_mesh = subdiv_cache->mesh;
@@ -346,47 +311,39 @@ static void extract_attr_init_subdiv(const DRWSubdivCache *subdiv_cache,
/* Prepare VBO for coarse data. The compute shader only expects floats. */
GPUVertBuf *src_data = GPU_vertbuf_calloc();
- static GPUVertFormat coarse_format = {0};
+ 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: {
+ case CD_PROP_BOOL:
extract_attr_generic<bool, float3>(mr, src_data, request);
break;
- }
- case CD_PROP_INT8: {
+ case CD_PROP_INT8:
extract_attr_generic<int8_t, float3>(mr, src_data, request);
break;
- }
- case CD_PROP_INT32: {
+ case CD_PROP_INT32:
extract_attr_generic<int32_t, float3>(mr, src_data, request);
break;
- }
- case CD_PROP_FLOAT: {
+ case CD_PROP_FLOAT:
extract_attr_generic<float, float3>(mr, src_data, request);
break;
- }
- case CD_PROP_FLOAT2: {
+ case CD_PROP_FLOAT2:
extract_attr_generic<float2>(mr, src_data, request);
break;
- }
- case CD_PROP_FLOAT3: {
+ case CD_PROP_FLOAT3:
extract_attr_generic<float3>(mr, src_data, request);
break;
- }
- case CD_PROP_COLOR: {
+ case CD_PROP_COLOR:
extract_attr_generic<MPropCol, gpuMeshCol>(mr, src_data, request);
break;
- }
- default: {
- BLI_assert(false);
- }
+ default:
+ BLI_assert_unreachable();
}
GPUVertBuf *dst_buffer = static_cast<GPUVertBuf *>(buffer);
- init_vbo_for_attribute(mr, dst_buffer, request, true, subdiv_cache->num_subdiv_loops);
+ init_vbo_for_attribute(dst_buffer, request, true, subdiv_cache->num_subdiv_loops);
/* Ensure data is uploaded properly. */
GPU_vertbuf_tag_dirty(src_data);
@@ -400,13 +357,13 @@ static void extract_attr_init_subdiv(const DRWSubdivCache *subdiv_cache,
* extract. The overall API does not allow us to pass this in a convenient way. */
#define EXTRACT_INIT_WRAPPER(index) \
static void extract_attr_init##index( \
- const MeshRenderData *mr, struct MeshBatchCache *cache, void *buf, void *tls_data) \
+ const MeshRenderData *mr, 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, \
+ MeshBatchCache *cache, \
void *buf, \
void *tls_data) \
{ \
@@ -429,7 +386,7 @@ EXTRACT_INIT_WRAPPER(12)
EXTRACT_INIT_WRAPPER(13)
EXTRACT_INIT_WRAPPER(14)
-template<int index>
+template<int Index>
constexpr MeshExtract create_extractor_attr(ExtractInitFn fn, ExtractInitSubdivFn subdiv_fn)
{
MeshExtract extractor = {nullptr};
@@ -438,7 +395,7 @@ constexpr MeshExtract create_extractor_attr(ExtractInitFn fn, ExtractInitSubdivF
extractor.data_type = MR_DATA_NONE;
extractor.data_size = 0;
extractor.use_threading = false;
- extractor.mesh_buffer_offset = offsetof(MeshBufferList, vbo.attr[index]);
+ extractor.mesh_buffer_offset = offsetof(MeshBufferList, vbo.attr[Index]);
return extractor;
}
@@ -446,7 +403,6 @@ constexpr MeshExtract create_extractor_attr(ExtractInitFn fn, ExtractInitSubdivF
} // namespace blender::draw
-extern "C" {
#define CREATE_EXTRACTOR_ATTR(index) \
blender::draw::create_extractor_attr<index>(blender::draw::extract_attr_init##index, \
blender::draw::extract_attr_init_subdiv##index)
@@ -468,4 +424,3 @@ const MeshExtract extract_attr[GPU_MAX_ATTR] = {
CREATE_EXTRACTOR_ATTR(13),
CREATE_EXTRACTOR_ATTR(14),
};
-}
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 f3b41efe1c3..eb6e800023a 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
@@ -10,7 +10,7 @@
#include "GPU_capabilities.h"
#include "draw_subdivision.h"
-#include "extract_mesh.h"
+#include "extract_mesh.hh"
namespace blender::draw {
@@ -43,7 +43,7 @@ static float loop_edge_factor_get(const float f_no[3],
}
static void extract_edge_fac_init(const MeshRenderData *mr,
- struct MeshBatchCache *UNUSED(cache),
+ MeshBatchCache *UNUSED(cache),
void *buf,
void *tls_data)
{
@@ -167,7 +167,7 @@ static void extract_edge_fac_iter_ledge_mesh(const MeshRenderData *mr,
}
static void extract_edge_fac_finish(const MeshRenderData *mr,
- struct MeshBatchCache *UNUSED(cache),
+ MeshBatchCache *UNUSED(cache),
void *buf,
void *_data)
{
@@ -218,7 +218,7 @@ static GPUVertFormat *get_subdiv_edge_fac_format()
static void extract_edge_fac_init_subdiv(const DRWSubdivCache *subdiv_cache,
const MeshRenderData *UNUSED(mr),
- struct MeshBatchCache *cache,
+ MeshBatchCache *cache,
void *buffer,
void *UNUSED(data))
{
@@ -303,6 +303,4 @@ constexpr MeshExtract create_extractor_edge_fac()
} // namespace blender::draw
-extern "C" {
const MeshExtract extract_edge_fac = blender::draw::create_extractor_edge_fac();
-}
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 1e158a7e6d7..27fd6546b8c 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
@@ -5,7 +5,7 @@
* \ingroup draw
*/
-#include "extract_mesh.h"
+#include "extract_mesh.hh"
#include "draw_cache_impl.h"
@@ -112,7 +112,7 @@ static GPUVertFormat *get_edit_data_format()
}
static void extract_edit_data_init(const MeshRenderData *mr,
- struct MeshBatchCache *UNUSED(cache),
+ MeshBatchCache *UNUSED(cache),
void *buf,
void *tls_data)
{
@@ -367,6 +367,4 @@ constexpr MeshExtract create_extractor_edit_data()
} // namespace blender::draw
-extern "C" {
const MeshExtract extract_edit_data = blender::draw::create_extractor_edit_data();
-}
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 f79fe345f5a..0b9043e3289 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
@@ -5,7 +5,7 @@
* \ingroup draw
*/
-#include "extract_mesh.h"
+#include "extract_mesh.hh"
#include "draw_cache_impl.h"
@@ -43,7 +43,7 @@ static void extract_edituv_data_init_common(const MeshRenderData *mr,
}
static void extract_edituv_data_init(const MeshRenderData *mr,
- struct MeshBatchCache *UNUSED(cache),
+ MeshBatchCache *UNUSED(cache),
void *buf,
void *tls_data)
{
@@ -199,6 +199,4 @@ constexpr MeshExtract create_extractor_edituv_data()
} // namespace blender::draw
-extern "C" {
const MeshExtract extract_edituv_data = blender::draw::create_extractor_edituv_data();
-}
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 4ced14ab11a..969ff9f6f09 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
@@ -9,7 +9,7 @@
#include "BKE_mesh.h"
-#include "extract_mesh.h"
+#include "extract_mesh.hh"
#include "draw_subdivision.h"
@@ -26,7 +26,7 @@ struct UVStretchAngle {
struct MeshExtract_StretchAngle_Data {
UVStretchAngle *vbo_data;
- MLoopUV *luv;
+ const MLoopUV *luv;
float auv[2][2], last_auv[2];
float av[2][3], last_av[3];
int cd_ofs;
@@ -74,7 +74,7 @@ static void edituv_get_edituv_stretch_angle(float auv[2][2],
}
static void extract_edituv_stretch_angle_init(const MeshRenderData *mr,
- struct MeshBatchCache *UNUSED(cache),
+ MeshBatchCache *UNUSED(cache),
void *buf,
void *tls_data)
{
@@ -98,7 +98,7 @@ static void extract_edituv_stretch_angle_init(const MeshRenderData *mr,
}
else {
BLI_assert(ELEM(mr->extract_type, MR_EXTRACT_MAPPED, MR_EXTRACT_MESH));
- data->luv = (MLoopUV *)CustomData_get_layer(&mr->me->ldata, CD_MLOOPUV);
+ data->luv = (const MLoopUV *)CustomData_get_layer(&mr->me->ldata, CD_MLOOPUV);
}
}
@@ -212,7 +212,7 @@ static GPUVertFormat *get_edituv_stretch_angle_format_subdiv()
static void extract_edituv_stretch_angle_init_subdiv(const DRWSubdivCache *subdiv_cache,
const MeshRenderData *mr,
- struct MeshBatchCache *cache,
+ MeshBatchCache *cache,
void *buffer,
void *UNUSED(tls_data))
{
@@ -236,7 +236,7 @@ static void extract_edituv_stretch_angle_init_subdiv(const DRWSubdivCache *subdi
draw_subdiv_get_pos_nor_format(),
subdiv_cache->num_subdiv_loops + loose_geom.loop_len);
- draw_subdiv_extract_pos_nor(subdiv_cache, pos_nor);
+ draw_subdiv_extract_pos_nor(subdiv_cache, pos_nor, nullptr);
}
/* UVs are stored contiguously so we need to compute the offset in the UVs buffer for the active
@@ -292,7 +292,5 @@ constexpr MeshExtract create_extractor_edituv_edituv_stretch_angle()
} // namespace blender::draw
-extern "C" {
const MeshExtract extract_edituv_stretch_angle =
blender::draw::create_extractor_edituv_edituv_stretch_angle();
-}
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 ab397cc1717..2bb786303c4 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
@@ -9,7 +9,7 @@
#include "BKE_mesh.h"
-#include "extract_mesh.h"
+#include "extract_mesh.hh"
#include "draw_subdivision.h"
@@ -20,7 +20,7 @@ namespace blender::draw {
* \{ */
static void extract_edituv_stretch_area_init(const MeshRenderData *mr,
- struct MeshBatchCache *UNUSED(cache),
+ MeshBatchCache *UNUSED(cache),
void *buf,
void *UNUSED(tls_data))
{
@@ -89,7 +89,7 @@ static void compute_area_ratio(const MeshRenderData *mr,
}
static void extract_edituv_stretch_area_finish(const MeshRenderData *mr,
- struct MeshBatchCache *cache,
+ MeshBatchCache *cache,
void *buf,
void *UNUSED(data))
{
@@ -131,7 +131,7 @@ static void extract_edituv_stretch_area_finish(const MeshRenderData *mr,
static void extract_edituv_stretch_area_init_subdiv(const DRWSubdivCache *subdiv_cache,
const MeshRenderData *mr,
- struct MeshBatchCache *cache,
+ MeshBatchCache *cache,
void *buffer,
void *UNUSED(data))
{
@@ -180,7 +180,5 @@ constexpr MeshExtract create_extractor_edituv_stretch_area()
} // namespace blender::draw
-extern "C" {
const MeshExtract extract_edituv_stretch_area =
blender::draw::create_extractor_edituv_stretch_area();
-}
diff --git a/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_fdots_edituv_data.cc b/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_fdots_edituv_data.cc
index 1c4f6112877..27d1975d67b 100644
--- a/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_fdots_edituv_data.cc
+++ b/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_fdots_edituv_data.cc
@@ -5,7 +5,7 @@
* \ingroup draw
*/
-#include "extract_mesh.h"
+#include "extract_mesh.hh"
#include "draw_cache_impl.h"
@@ -21,7 +21,7 @@ struct MeshExtract_EditUVFdotData_Data {
};
static void extract_fdots_edituv_data_init(const MeshRenderData *mr,
- struct MeshBatchCache *UNUSED(cache),
+ MeshBatchCache *UNUSED(cache),
void *buf,
void *tls_data)
{
@@ -81,6 +81,4 @@ constexpr MeshExtract create_extractor_fdots_edituv_data()
} // namespace blender::draw
-extern "C" {
const MeshExtract extract_fdots_edituv_data = blender::draw::create_extractor_fdots_edituv_data();
-}
diff --git a/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_fdots_nor.cc b/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_fdots_nor.cc
index 909c9ac2300..c2af7f2c9bd 100644
--- a/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_fdots_nor.cc
+++ b/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_fdots_nor.cc
@@ -5,7 +5,7 @@
* \ingroup draw
*/
-#include "extract_mesh.h"
+#include "extract_mesh.hh"
namespace blender::draw {
@@ -19,7 +19,7 @@ namespace blender::draw {
#define NOR_AND_FLAG_HIDDEN -2
static void extract_fdots_nor_init(const MeshRenderData *mr,
- struct MeshBatchCache *UNUSED(cache),
+ MeshBatchCache *UNUSED(cache),
void *buf,
void *UNUSED(tls_data))
{
@@ -34,7 +34,7 @@ static void extract_fdots_nor_init(const MeshRenderData *mr,
}
static void extract_fdots_nor_finish(const MeshRenderData *mr,
- struct MeshBatchCache *UNUSED(cache),
+ MeshBatchCache *UNUSED(cache),
void *buf,
void *UNUSED(data))
{
@@ -101,7 +101,7 @@ constexpr MeshExtract create_extractor_fdots_nor()
* \{ */
static void extract_fdots_nor_hq_init(const MeshRenderData *mr,
- struct MeshBatchCache *UNUSED(cache),
+ MeshBatchCache *UNUSED(cache),
void *buf,
void *UNUSED(tls_data))
{
@@ -116,7 +116,7 @@ static void extract_fdots_nor_hq_init(const MeshRenderData *mr,
}
static void extract_fdots_nor_hq_finish(const MeshRenderData *mr,
- struct MeshBatchCache *UNUSED(cache),
+ MeshBatchCache *UNUSED(cache),
void *buf,
void *UNUSED(data))
{
@@ -180,7 +180,5 @@ constexpr MeshExtract create_extractor_fdots_nor_hq()
} // namespace blender::draw
-extern "C" {
const MeshExtract extract_fdots_nor = blender::draw::create_extractor_fdots_nor();
const MeshExtract extract_fdots_nor_hq = blender::draw::create_extractor_fdots_nor_hq();
-}
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 c2b4d389b7c..c391cb6ca5a 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
@@ -7,7 +7,7 @@
#include "BLI_bitmap.h"
-#include "extract_mesh.h"
+#include "extract_mesh.hh"
#include "draw_subdivision.h"
@@ -36,7 +36,7 @@ static GPUVertFormat *get_fdots_nor_format_subdiv()
}
static void extract_fdots_pos_init(const MeshRenderData *mr,
- struct MeshBatchCache *UNUSED(cache),
+ MeshBatchCache *UNUSED(cache),
void *buf,
void *tls_data)
{
@@ -101,7 +101,7 @@ 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,
+ MeshBatchCache *cache,
void *buffer,
void *UNUSED(data))
{
@@ -110,8 +110,11 @@ static void extract_fdots_init_subdiv(const DRWSubdivCache *subdiv_cache,
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);
+ /* The normals may not be requested. */
+ if (fdots_nor_vbo) {
+ 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);
@@ -136,6 +139,4 @@ constexpr MeshExtract create_extractor_fdots_pos()
} // namespace blender::draw
-extern "C" {
const MeshExtract extract_fdots_pos = blender::draw::create_extractor_fdots_pos();
-}
diff --git a/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_fdots_uv.cc b/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_fdots_uv.cc
index 26f0b07f676..b0403cf7c4c 100644
--- a/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_fdots_uv.cc
+++ b/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_fdots_uv.cc
@@ -7,7 +7,7 @@
#include "BLI_bitmap.h"
-#include "extract_mesh.h"
+#include "extract_mesh.hh"
namespace blender::draw {
@@ -17,12 +17,12 @@ namespace blender::draw {
struct MeshExtract_FdotUV_Data {
float (*vbo_data)[2];
- MLoopUV *uv_data;
+ const MLoopUV *uv_data;
int cd_ofs;
};
static void extract_fdots_uv_init(const MeshRenderData *mr,
- struct MeshBatchCache *UNUSED(cache),
+ MeshBatchCache *UNUSED(cache),
void *buf,
void *tls_data)
{
@@ -49,7 +49,7 @@ static void extract_fdots_uv_init(const MeshRenderData *mr,
data->cd_ofs = CustomData_get_offset(&mr->bm->ldata, CD_MLOOPUV);
}
else {
- data->uv_data = (MLoopUV *)CustomData_get_layer(&mr->me->ldata, CD_MLOOPUV);
+ data->uv_data = (const MLoopUV *)CustomData_get_layer(&mr->me->ldata, CD_MLOOPUV);
}
}
@@ -109,6 +109,4 @@ constexpr MeshExtract create_extractor_fdots_uv()
} // namespace blender::draw
-extern "C" {
const MeshExtract extract_fdots_uv = blender::draw::create_extractor_fdots_uv();
-}
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 8bc8b32fdf3..ac517269e7d 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
@@ -5,7 +5,7 @@
* \ingroup draw
*/
-#include "extract_mesh.h"
+#include "extract_mesh.hh"
#include "draw_subdivision.h"
@@ -16,7 +16,7 @@ namespace blender::draw {
* \{ */
static void extract_lnor_init(const MeshRenderData *mr,
- struct MeshBatchCache *UNUSED(cache),
+ MeshBatchCache *UNUSED(cache),
void *buf,
void *tls_data)
{
@@ -105,7 +105,7 @@ static GPUVertFormat *get_subdiv_lnor_format()
static void extract_lnor_init_subdiv(const DRWSubdivCache *subdiv_cache,
const MeshRenderData *UNUSED(mr),
- struct MeshBatchCache *cache,
+ MeshBatchCache *cache,
void *buffer,
void *UNUSED(data))
{
@@ -141,7 +141,7 @@ struct gpuHQNor {
};
static void extract_lnor_hq_init(const MeshRenderData *mr,
- struct MeshBatchCache *UNUSED(cache),
+ MeshBatchCache *UNUSED(cache),
void *buf,
void *tls_data)
{
@@ -234,7 +234,5 @@ constexpr MeshExtract create_extractor_lnor_hq()
} // namespace blender::draw
-extern "C" {
const MeshExtract extract_lnor = blender::draw::create_extractor_lnor();
const MeshExtract extract_lnor_hq = blender::draw::create_extractor_lnor_hq();
-}
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 968c1f693fb..951990466d0 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
@@ -14,7 +14,7 @@
#include "BKE_editmesh_bvh.h"
#include "BKE_editmesh_cache.h"
-#include "extract_mesh.h"
+#include "extract_mesh.hh"
namespace blender::draw {
@@ -23,7 +23,7 @@ namespace blender::draw {
* \{ */
static void extract_mesh_analysis_init(const MeshRenderData *mr,
- struct MeshBatchCache *UNUSED(cache),
+ MeshBatchCache *UNUSED(cache),
void *buf,
void *UNUSED(tls_data))
{
@@ -587,7 +587,7 @@ static void statvis_calc_sharp(const MeshRenderData *mr, float *r_sharp)
}
static void extract_analysis_iter_finish_mesh(const MeshRenderData *mr,
- struct MeshBatchCache *UNUSED(cache),
+ MeshBatchCache *UNUSED(cache),
void *buf,
void *UNUSED(data))
{
@@ -633,6 +633,4 @@ constexpr MeshExtract create_extractor_mesh_analysis()
} // namespace blender::draw
-extern "C" {
const MeshExtract extract_mesh_analysis = blender::draw::create_extractor_mesh_analysis();
-}
diff --git a/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_orco.cc b/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_orco.cc
index ed1a0ccd178..4fcbdb1fc7c 100644
--- a/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_orco.cc
+++ b/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_orco.cc
@@ -5,9 +5,7 @@
* \ingroup draw
*/
-#include "extract_mesh.h"
-
-#include "draw_subdivision.h"
+#include "extract_mesh.hh"
namespace blender::draw {
@@ -17,11 +15,11 @@ namespace blender::draw {
struct MeshExtract_Orco_Data {
float (*vbo_data)[4];
- float (*orco)[3];
+ const float (*orco)[3];
};
static void extract_orco_init(const MeshRenderData *mr,
- struct MeshBatchCache *UNUSED(cache),
+ MeshBatchCache *UNUSED(cache),
void *buf,
void *tls_data)
{
@@ -42,7 +40,7 @@ static void extract_orco_init(const MeshRenderData *mr,
MeshExtract_Orco_Data *data = static_cast<MeshExtract_Orco_Data *>(tls_data);
data->vbo_data = (float(*)[4])GPU_vertbuf_get_data(vbo);
- data->orco = static_cast<float(*)[3]>(CustomData_get_layer(cd_vdata, CD_ORCO));
+ data->orco = static_cast<const float(*)[3]>(CustomData_get_layer(cd_vdata, CD_ORCO));
/* Make sure `orco` layer was requested only if needed! */
BLI_assert(data->orco);
}
@@ -79,77 +77,12 @@ static void extract_orco_iter_poly_mesh(const MeshRenderData *mr,
}
}
-static void extract_orco_init_subdiv(const DRWSubdivCache *subdiv_cache,
- const MeshRenderData *mr,
- struct MeshBatchCache *UNUSED(cache),
- void *buffer,
- void *UNUSED(data))
-{
- static GPUVertFormat format = {0};
- if (format.attr_len == 0) {
- /* FIXME(fclem): We use the last component as a way to differentiate from generic vertex
- * attributes. This is a substantial waste of video-ram and should be done another way.
- * Unfortunately, at the time of writing, I did not found any other "non disruptive"
- * alternative. */
- GPU_vertformat_attr_add(&format, "orco", GPU_COMP_F32, 4, GPU_FETCH_FLOAT);
- }
-
- GPUVertBuf *dst_buffer = static_cast<GPUVertBuf *>(buffer);
- GPU_vertbuf_init_build_on_device(dst_buffer, &format, subdiv_cache->num_subdiv_loops);
-
- GPUVertBuf *coarse_vbo = GPU_vertbuf_calloc();
- /* Dynamic as we upload and interpolate layers one at a time. */
- GPU_vertbuf_init_with_format_ex(coarse_vbo, &format, GPU_USAGE_DYNAMIC);
- GPU_vertbuf_data_alloc(coarse_vbo, mr->loop_len);
-
- float(*coarse_vbo_data)[4] = static_cast<float(*)[4]>(GPU_vertbuf_get_data(coarse_vbo));
-
- CustomData *cd_vdata = &mr->me->vdata;
- float(*orco)[3] = static_cast<float(*)[3]>(CustomData_get_layer(cd_vdata, CD_ORCO));
-
- if (mr->extract_type == MR_EXTRACT_MESH) {
- const MLoop *mloop = mr->mloop;
- const MPoly *mp = mr->mpoly;
-
- int ml_index = 0;
- for (int i = 0; i < mr->poly_len; i++, mp++) {
- const MLoop *ml = &mloop[mp->loopstart];
-
- for (int j = 0; j < mp->totloop; j++, ml++, ml_index++) {
- float *loop_orco = coarse_vbo_data[ml_index];
- copy_v3_v3(loop_orco, orco[ml->v]);
- loop_orco[3] = 0.0; /* Tag as not a generic attribute. */
- }
- }
- }
- else {
- BMIter iter;
- BMFace *f;
- BM_ITER_MESH (f, &iter, mr->bm, BM_FACES_OF_MESH) {
- BMLoop *l_iter;
- BMLoop *l_first;
- l_iter = l_first = BM_FACE_FIRST_LOOP(f);
- do {
- const int l_index = BM_elem_index_get(l_iter);
- float *loop_orco = coarse_vbo_data[l_index];
- copy_v3_v3(loop_orco, orco[BM_elem_index_get(l_iter->v)]);
- loop_orco[3] = 0.0; /* Tag as not a generic attribute. */
- } while ((l_iter = l_iter->next) != l_first);
- }
- }
-
- draw_subdiv_interp_custom_data(subdiv_cache, coarse_vbo, dst_buffer, 4, 0, false);
-
- GPU_vertbuf_discard(coarse_vbo);
-}
-
constexpr MeshExtract create_extractor_orco()
{
MeshExtract extractor = {nullptr};
extractor.init = extract_orco_init;
extractor.iter_poly_bm = extract_orco_iter_poly_bm;
extractor.iter_poly_mesh = extract_orco_iter_poly_mesh;
- extractor.init_subdiv = extract_orco_init_subdiv;
extractor.data_type = MR_DATA_NONE;
extractor.data_size = sizeof(MeshExtract_Orco_Data);
extractor.use_threading = true;
@@ -161,6 +94,4 @@ constexpr MeshExtract create_extractor_orco()
} // namespace blender::draw
-extern "C" {
const MeshExtract extract_orco = blender::draw::create_extractor_orco();
-}
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 ea46d9c4caa..9788beabeb5 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
@@ -7,7 +7,7 @@
#include "MEM_guardedalloc.h"
-#include "extract_mesh.h"
+#include "extract_mesh.hh"
#include "draw_subdivision.h"
@@ -28,7 +28,7 @@ struct MeshExtract_PosNor_Data {
};
static void extract_pos_nor_init(const MeshRenderData *mr,
- struct MeshBatchCache *UNUSED(cache),
+ MeshBatchCache *UNUSED(cache),
void *buf,
void *tls_data)
{
@@ -171,7 +171,7 @@ static void extract_pos_nor_iter_lvert_mesh(const MeshRenderData *mr,
}
static void extract_pos_nor_finish(const MeshRenderData *UNUSED(mr),
- struct MeshBatchCache *UNUSED(cache),
+ MeshBatchCache *UNUSED(cache),
void *UNUSED(buf),
void *_data)
{
@@ -201,7 +201,7 @@ static GPUVertFormat *get_custom_normals_format()
static void extract_pos_nor_init_subdiv(const DRWSubdivCache *subdiv_cache,
const MeshRenderData *UNUSED(mr),
- struct MeshBatchCache *UNUSED(cache),
+ MeshBatchCache *cache,
void *buffer,
void *UNUSED(data))
{
@@ -216,11 +216,25 @@ static void extract_pos_nor_init_subdiv(const DRWSubdivCache *subdiv_cache,
return;
}
- draw_subdiv_extract_pos_nor(subdiv_cache, vbo);
+ GPUVertBuf *orco_vbo = cache->final.buff.vbo.orco;
+
+ if (orco_vbo) {
+ static GPUVertFormat format = {0};
+ if (format.attr_len == 0) {
+ /* FIXME(fclem): We use the last component as a way to differentiate from generic vertex
+ * attributes. This is a substantial waste of video-ram and should be done another way.
+ * Unfortunately, at the time of writing, I did not found any other "non disruptive"
+ * alternative. */
+ GPU_vertformat_attr_add(&format, "orco", GPU_COMP_F32, 4, GPU_FETCH_FLOAT);
+ }
+ GPU_vertbuf_init_build_on_device(orco_vbo, &format, subdiv_cache->num_subdiv_loops);
+ }
+
+ draw_subdiv_extract_pos_nor(subdiv_cache, vbo, orco_vbo);
if (subdiv_cache->use_custom_loop_normals) {
Mesh *coarse_mesh = subdiv_cache->mesh;
- float(*lnors)[3] = static_cast<float(*)[3]>(
+ const float(*lnors)[3] = static_cast<const float(*)[3]>(
CustomData_get_layer(&coarse_mesh->ldata, CD_NORMAL));
BLI_assert(lnors != nullptr);
@@ -358,7 +372,7 @@ struct MeshExtract_PosNorHQ_Data {
};
static void extract_pos_nor_hq_init(const MeshRenderData *mr,
- struct MeshBatchCache *UNUSED(cache),
+ MeshBatchCache *UNUSED(cache),
void *buf,
void *tls_data)
{
@@ -507,7 +521,7 @@ static void extract_pos_nor_hq_iter_lvert_mesh(const MeshRenderData *mr,
}
static void extract_pos_nor_hq_finish(const MeshRenderData *UNUSED(mr),
- struct MeshBatchCache *UNUSED(cache),
+ MeshBatchCache *UNUSED(cache),
void *UNUSED(buf),
void *_data)
{
@@ -538,7 +552,5 @@ constexpr MeshExtract create_extractor_pos_nor_hq()
} // namespace blender::draw
-extern "C" {
const MeshExtract extract_pos_nor = blender::draw::create_extractor_pos_nor();
const MeshExtract extract_pos_nor_hq = blender::draw::create_extractor_pos_nor_hq();
-}
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 96595df9276..492721b4853 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
@@ -12,7 +12,7 @@
#include "BKE_paint.h"
#include "draw_subdivision.h"
-#include "extract_mesh.h"
+#include "extract_mesh.hh"
namespace blender::draw {
@@ -31,7 +31,7 @@ static GPUVertFormat *get_sculpt_data_format()
}
static void extract_sculpt_data_init(const MeshRenderData *mr,
- struct MeshBatchCache *UNUSED(cache),
+ MeshBatchCache *UNUSED(cache),
void *buf,
void *UNUSED(tls_data))
{
@@ -42,8 +42,8 @@ static void extract_sculpt_data_init(const MeshRenderData *mr,
CustomData *cd_vdata = (mr->extract_type == MR_EXTRACT_BMESH) ? &mr->bm->vdata : &mr->me->vdata;
CustomData *cd_pdata = (mr->extract_type == MR_EXTRACT_BMESH) ? &mr->bm->pdata : &mr->me->pdata;
- 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);
+ const float *cd_mask = (const float *)CustomData_get_layer(cd_vdata, CD_PAINT_MASK);
+ const int *cd_face_set = (const int *)CustomData_get_layer(cd_pdata, CD_SCULPT_FACE_SETS);
GPU_vertbuf_init_with_format(vbo, format);
GPU_vertbuf_data_alloc(vbo, mr->loop_len);
@@ -54,7 +54,7 @@ static void extract_sculpt_data_init(const MeshRenderData *mr,
};
gpuSculptData *vbo_data = (gpuSculptData *)GPU_vertbuf_get_data(vbo);
- MLoop *loops = (MLoop *)CustomData_get_layer(cd_ldata, CD_MLOOP);
+ const MLoop *loops = (const MLoop *)CustomData_get_layer(cd_ldata, CD_MLOOP);
if (mr->extract_type == MR_EXTRACT_BMESH) {
int cd_mask_ofs = CustomData_get_offset(cd_vdata, CD_PAINT_MASK);
@@ -113,7 +113,7 @@ 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),
+ MeshBatchCache *UNUSED(cache),
void *buffer,
void *UNUSED(data))
{
@@ -126,7 +126,7 @@ static void extract_sculpt_data_init_subdiv(const DRWSubdivCache *subdiv_cache,
/* 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);
+ const float *cd_mask = (const float *)CustomData_get_layer(cd_vdata, CD_PAINT_MASK);
if (cd_mask) {
GPUVertFormat mask_format = {0};
@@ -167,7 +167,7 @@ static void extract_sculpt_data_init_subdiv(const DRWSubdivCache *subdiv_cache,
};
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);
+ const int *cd_face_set = (const 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);
@@ -215,6 +215,4 @@ constexpr MeshExtract create_extractor_sculpt_data()
} // namespace blender::draw
-extern "C" {
const MeshExtract extract_sculpt_data = blender::draw::create_extractor_sculpt_data();
-}
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 f4c54b2f881..9e0d171c9e4 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
@@ -6,7 +6,7 @@
*/
#include "draw_subdivision.h"
-#include "extract_mesh.h"
+#include "extract_mesh.hh"
namespace blender::draw {
@@ -30,7 +30,7 @@ static void extract_select_idx_init_impl(const MeshRenderData *UNUSED(mr),
}
static void extract_select_idx_init(const MeshRenderData *mr,
- struct MeshBatchCache *UNUSED(cache),
+ MeshBatchCache *UNUSED(cache),
void *buf,
void *tls_data)
{
@@ -366,7 +366,7 @@ constexpr MeshExtract create_extractor_vert_idx()
}
static void extract_fdot_idx_init(const MeshRenderData *mr,
- struct MeshBatchCache *UNUSED(cache),
+ MeshBatchCache *UNUSED(cache),
void *buf,
void *tls_data)
{
@@ -411,9 +411,7 @@ constexpr MeshExtract create_extractor_fdot_idx()
} // namespace blender::draw
-extern "C" {
const MeshExtract extract_poly_idx = blender::draw::create_extractor_poly_idx();
const MeshExtract extract_edge_idx = blender::draw::create_extractor_edge_idx();
const MeshExtract extract_vert_idx = blender::draw::create_extractor_vert_idx();
const MeshExtract extract_fdot_idx = blender::draw::create_extractor_fdot_idx();
-}
diff --git a/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_skin_roots.cc b/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_skin_roots.cc
index bb6331dd377..f7655658bdd 100644
--- a/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_skin_roots.cc
+++ b/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_skin_roots.cc
@@ -5,7 +5,7 @@
* \ingroup draw
*/
-#include "extract_mesh.h"
+#include "extract_mesh.hh"
namespace blender::draw {
@@ -19,7 +19,7 @@ struct SkinRootData {
};
static void extract_skin_roots_init(const MeshRenderData *mr,
- struct MeshBatchCache *UNUSED(cache),
+ MeshBatchCache *UNUSED(cache),
void *buf,
void *UNUSED(tls_data))
{
@@ -72,6 +72,4 @@ constexpr MeshExtract create_extractor_skin_roots()
} // namespace blender::draw
-extern "C" {
const MeshExtract extract_skin_roots = blender::draw::create_extractor_skin_roots();
-}
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 25f78d68914..049fa416523 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
@@ -14,7 +14,7 @@
#include "BKE_mesh.h"
#include "BKE_mesh_tangent.h"
-#include "extract_mesh.h"
+#include "extract_mesh.hh"
#include "draw_subdivision.h"
@@ -25,7 +25,7 @@ namespace blender::draw {
* \{ */
static void extract_tan_init_common(const MeshRenderData *mr,
- struct MeshBatchCache *cache,
+ MeshBatchCache *cache,
GPUVertFormat *format,
GPUVertCompType comp_type,
GPUVertFetchMode fetch_mode,
@@ -161,7 +161,7 @@ static void extract_tan_init_common(const MeshRenderData *mr,
}
static void extract_tan_ex_init(const MeshRenderData *mr,
- struct MeshBatchCache *cache,
+ MeshBatchCache *cache,
GPUVertBuf *vbo,
const bool do_hq)
{
@@ -235,7 +235,7 @@ static void extract_tan_ex_init(const MeshRenderData *mr,
}
static void extract_tan_init(const MeshRenderData *mr,
- struct MeshBatchCache *cache,
+ MeshBatchCache *cache,
void *buf,
void *UNUSED(tls_data))
{
@@ -254,7 +254,7 @@ static GPUVertFormat *get_coarse_tan_format()
static void extract_tan_init_subdiv(const DRWSubdivCache *subdiv_cache,
const MeshRenderData *mr,
- struct MeshBatchCache *cache,
+ MeshBatchCache *cache,
void *buffer,
void *UNUSED(data))
{
@@ -291,7 +291,8 @@ static void extract_tan_init_subdiv(const DRWSubdivCache *subdiv_cache,
for (int i = 0; i < tan_len; i++) {
float(*tan_data)[4] = (float(*)[4])GPU_vertbuf_get_data(coarse_vbo);
const char *name = tangent_names[i];
- float(*layer_data)[4] = (float(*)[4])CustomData_get_layer_named(&loop_data, CD_TANGENT, name);
+ const float(*layer_data)[4] = (float(*)[4])CustomData_get_layer_named(
+ &loop_data, CD_TANGENT, name);
for (int ml_index = 0; ml_index < mr->loop_len; ml_index++) {
copy_v3_v3(*tan_data, layer_data[ml_index]);
(*tan_data)[3] = (layer_data[ml_index][3] > 0.0f) ? 1.0f : -1.0f;
@@ -306,7 +307,7 @@ static void extract_tan_init_subdiv(const DRWSubdivCache *subdiv_cache,
}
if (use_orco_tan) {
float(*tan_data)[4] = (float(*)[4])GPU_vertbuf_get_data(coarse_vbo);
- float(*layer_data)[4] = (float(*)[4])CustomData_get_layer_n(&loop_data, CD_TANGENT, 0);
+ const float(*layer_data)[4] = (float(*)[4])CustomData_get_layer_n(&loop_data, CD_TANGENT, 0);
for (int ml_index = 0; ml_index < mr->loop_len; ml_index++) {
copy_v3_v3(*tan_data, layer_data[ml_index]);
(*tan_data)[3] = (layer_data[ml_index][3] > 0.0f) ? 1.0f : -1.0f;
@@ -343,7 +344,7 @@ constexpr MeshExtract create_extractor_tan()
* \{ */
static void extract_tan_hq_init(const MeshRenderData *mr,
- struct MeshBatchCache *cache,
+ MeshBatchCache *cache,
void *buf,
void *UNUSED(tls_data))
{
@@ -366,7 +367,5 @@ constexpr MeshExtract create_extractor_tan_hq()
} // namespace blender::draw
-extern "C" {
const MeshExtract extract_tan = blender::draw::create_extractor_tan();
const MeshExtract extract_tan_hq = blender::draw::create_extractor_tan_hq();
-}
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 5fb4b401ae3..6606912850d 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
@@ -8,7 +8,7 @@
#include "BLI_string.h"
#include "draw_subdivision.h"
-#include "extract_mesh.h"
+#include "extract_mesh.hh"
namespace blender::draw {
@@ -19,7 +19,7 @@ namespace blender::draw {
/* 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,
+ MeshBatchCache *cache,
CustomData *cd_ldata,
eMRExtractType extract_type,
uint32_t &r_uv_layers)
@@ -72,7 +72,7 @@ static bool mesh_extract_uv_format_init(GPUVertFormat *format,
}
static void extract_uv_init(const MeshRenderData *mr,
- struct MeshBatchCache *cache,
+ MeshBatchCache *cache,
void *buf,
void *UNUSED(tls_data))
{
@@ -108,7 +108,8 @@ static void extract_uv_init(const MeshRenderData *mr,
}
}
else {
- MLoopUV *layer_data = (MLoopUV *)CustomData_get_layer_n(cd_ldata, CD_MLOOPUV, i);
+ const MLoopUV *layer_data = (const MLoopUV *)CustomData_get_layer_n(
+ cd_ldata, CD_MLOOPUV, i);
for (int ml_index = 0; ml_index < mr->loop_len; ml_index++, uv_data++, layer_data++) {
memcpy(uv_data, layer_data->uv, sizeof(*uv_data));
}
@@ -119,7 +120,7 @@ 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,
+ MeshBatchCache *cache,
void *buffer,
void *UNUSED(data))
{
@@ -167,6 +168,4 @@ constexpr MeshExtract create_extractor_uv()
} // namespace blender::draw
-extern "C" {
const MeshExtract extract_uv = blender::draw::create_extractor_uv();
-}
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 e5dd025787d..419cbb0267f 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
@@ -12,11 +12,13 @@
#include "BLI_vector.hh"
#include "draw_subdivision.h"
-#include "extract_mesh.h"
+#include "extract_mesh.hh"
+
+namespace blender::draw {
struct VColRef {
const CustomDataLayer *layer;
- AttributeDomain domain;
+ eAttrDomain domain;
};
/** Get all vcol layers as AttributeRefs.
@@ -25,14 +27,14 @@ struct VColRef {
* corresponds to the integer position of the attribute
* within the global color attribute list.
*/
-static blender::Vector<VColRef> get_vcol_refs(const CustomData *cd_vdata,
- const CustomData *cd_ldata,
- const uint vcol_layers)
+static Vector<VColRef> get_vcol_refs(const CustomData *cd_vdata,
+ const CustomData *cd_ldata,
+ const uint vcol_layers)
{
- blender::Vector<VColRef> refs;
+ Vector<VColRef> refs;
uint layeri = 0;
- auto buildList = [&](const CustomData *cdata, AttributeDomain domain) {
+ auto buildList = [&](const CustomData *cdata, eAttrDomain domain) {
for (int i = 0; i < cdata->totlayer; i++) {
const CustomDataLayer *layer = cdata->layers + i;
@@ -64,8 +66,6 @@ static blender::Vector<VColRef> get_vcol_refs(const CustomData *cd_vdata,
return refs;
}
-namespace blender::draw {
-
/* ---------------------------------------------------------------------- */
/** \name Extract VCol
* \{ */
@@ -73,16 +73,16 @@ namespace blender::draw {
/* Initialize the common vertex format for vcol for coarse and subdivided meshes. */
static void init_vcol_format(GPUVertFormat *format,
const MeshBatchCache *cache,
- CustomData *cd_vdata,
- CustomData *cd_ldata,
- CustomDataLayer *active,
- CustomDataLayer *render)
+ const CustomData *cd_vdata,
+ const CustomData *cd_ldata,
+ const CustomDataLayer *active,
+ const CustomDataLayer *render)
{
GPU_vertformat_deinterleave(format);
const uint32_t vcol_layers = cache->cd_used.vcol;
- blender::Vector<VColRef> refs = get_vcol_refs(cd_vdata, cd_ldata, vcol_layers);
+ Vector<VColRef> refs = get_vcol_refs(cd_vdata, cd_ldata, vcol_layers);
for (const VColRef &ref : refs) {
char attr_name[32], attr_safe_name[GPU_MAX_SAFE_ATTR_NAME];
@@ -111,35 +111,37 @@ 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_attr_add(&format, "cCol", GPU_COMP_U16, 4, GPU_FETCH_INT_TO_FLOAT_UNIT);
GPU_vertformat_alias_add(&format, "c");
GPU_vertformat_alias_add(&format, "ac");
}
return &format;
}
-using gpuMeshVcol = struct gpuMeshVcol {
+struct gpuMeshVcol {
ushort r, g, b, a;
};
static void extract_vcol_init(const MeshRenderData *mr,
- struct MeshBatchCache *cache,
+ MeshBatchCache *cache,
void *buf,
void *UNUSED(tls_data))
{
GPUVertBuf *vbo = static_cast<GPUVertBuf *>(buf);
GPUVertFormat format = {0};
- CustomData *cd_vdata = (mr->extract_type == MR_EXTRACT_BMESH) ? &mr->bm->vdata : &mr->me->vdata;
- CustomData *cd_ldata = (mr->extract_type == MR_EXTRACT_BMESH) ? &mr->bm->ldata : &mr->me->ldata;
+ const CustomData *cd_vdata = (mr->extract_type == MR_EXTRACT_BMESH) ? &mr->bm->vdata :
+ &mr->me->vdata;
+ const CustomData *cd_ldata = (mr->extract_type == MR_EXTRACT_BMESH) ? &mr->bm->ldata :
+ &mr->me->ldata;
Mesh me_query = blender::dna::shallow_zero_initialize();
BKE_id_attribute_copy_domains_temp(
ID_ME, cd_vdata, nullptr, cd_ldata, nullptr, nullptr, &me_query.id);
- CustomDataLayer *active_color = BKE_id_attributes_active_color_get(&me_query.id);
- CustomDataLayer *render_color = BKE_id_attributes_render_color_get(&me_query.id);
+ const CustomDataLayer *active_color = BKE_id_attributes_active_color_get(&me_query.id);
+ const CustomDataLayer *render_color = BKE_id_attributes_render_color_get(&me_query.id);
const uint32_t vcol_layers = cache->cd_used.vcol;
init_vcol_format(&format, cache, cd_vdata, cd_ldata, active_color, render_color);
@@ -149,10 +151,10 @@ static void extract_vcol_init(const MeshRenderData *mr,
gpuMeshVcol *vcol_data = (gpuMeshVcol *)GPU_vertbuf_get_data(vbo);
- blender::Vector<VColRef> refs = get_vcol_refs(cd_vdata, cd_ldata, vcol_layers);
+ Vector<VColRef> refs = get_vcol_refs(cd_vdata, cd_ldata, vcol_layers);
for (const VColRef &ref : refs) {
- CustomData *cdata = ref.domain == ATTR_DOMAIN_POINT ? cd_vdata : cd_ldata;
+ const CustomData *cdata = ref.domain == ATTR_DOMAIN_POINT ? cd_vdata : cd_ldata;
if (mr->extract_type == MR_EXTRACT_BMESH) {
int cd_ofs = ref.layer->offset;
@@ -168,10 +170,10 @@ static void extract_vcol_init(const MeshRenderData *mr,
BMFace *f;
BM_ITER_MESH (f, &iter, mr->bm, BM_FACES_OF_MESH) {
- BMLoop *l_iter = f->l_first;
+ const BMLoop *l_iter = f->l_first;
do {
- BMElem *elem = is_point ? reinterpret_cast<BMElem *>(l_iter->v) :
- reinterpret_cast<BMElem *>(l_iter);
+ const BMElem *elem = is_point ? reinterpret_cast<const BMElem *>(l_iter->v) :
+ reinterpret_cast<const BMElem *>(l_iter);
if (is_byte) {
const MLoopCol *mloopcol = (const MLoopCol *)BM_ELEM_CD_GET_VOID_P(elem, cd_ofs);
vcol_data->r = unit_float_to_ushort_clamp(BLI_color_from_srgb_table[mloopcol->r]);
@@ -193,17 +195,17 @@ static void extract_vcol_init(const MeshRenderData *mr,
}
else {
int totloop = mr->loop_len;
- int idx = CustomData_get_named_layer_index(cdata, ref.layer->type, ref.layer->name);
+ const int idx = CustomData_get_named_layer_index(cdata, ref.layer->type, ref.layer->name);
- MLoopCol *mcol = nullptr;
- MPropCol *pcol = nullptr;
+ const MLoopCol *mcol = nullptr;
+ const MPropCol *pcol = nullptr;
const MLoop *mloop = mr->mloop;
if (ref.layer->type == CD_PROP_COLOR) {
- pcol = static_cast<MPropCol *>(cdata->layers[idx].data);
+ pcol = static_cast<const MPropCol *>(cdata->layers[idx].data);
}
else {
- mcol = static_cast<MLoopCol *>(cdata->layers[idx].data);
+ mcol = static_cast<const MLoopCol *>(cdata->layers[idx].data);
}
const bool is_corner = ref.domain == ATTR_DOMAIN_CORNER;
@@ -232,12 +234,12 @@ static void extract_vcol_init(const MeshRenderData *mr,
static void extract_vcol_init_subdiv(const DRWSubdivCache *subdiv_cache,
const MeshRenderData *mr,
- struct MeshBatchCache *cache,
+ MeshBatchCache *cache,
void *buffer,
void *UNUSED(data))
{
GPUVertBuf *dst_buffer = static_cast<GPUVertBuf *>(buffer);
- Mesh *coarse_mesh = subdiv_cache->mesh;
+ const Mesh *coarse_mesh = subdiv_cache->mesh;
bool extract_bmesh = mr->extract_type == MR_EXTRACT_BMESH;
@@ -245,13 +247,14 @@ static void extract_vcol_init_subdiv(const DRWSubdivCache *subdiv_cache,
&coarse_mesh->vdata;
const CustomData *cd_ldata = extract_bmesh ? &coarse_mesh->edit_mesh->bm->ldata :
&coarse_mesh->ldata;
+ const int totloop = extract_bmesh ? coarse_mesh->edit_mesh->bm->totloop : coarse_mesh->totloop;
Mesh me_query = blender::dna::shallow_copy(*coarse_mesh);
BKE_id_attribute_copy_domains_temp(
ID_ME, cd_vdata, nullptr, cd_ldata, nullptr, nullptr, &me_query.id);
- CustomDataLayer *active_color = BKE_id_attributes_active_color_get(&me_query.id);
- CustomDataLayer *render_color = BKE_id_attributes_render_color_get(&me_query.id);
+ const CustomDataLayer *active_color = BKE_id_attributes_active_color_get(&me_query.id);
+ const CustomDataLayer *render_color = BKE_id_attributes_render_color_get(&me_query.id);
GPUVertFormat format = {0};
init_vcol_format(
@@ -263,15 +266,13 @@ static void extract_vcol_init_subdiv(const DRWSubdivCache *subdiv_cache,
/* 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);
+ GPU_vertbuf_data_alloc(src_data, totloop);
gpuMeshVcol *mesh_vcol = (gpuMeshVcol *)GPU_vertbuf_get_data(src_data);
const uint vcol_layers = cache->cd_used.vcol;
- blender::Vector<VColRef> refs = get_vcol_refs(cd_vdata, cd_ldata, vcol_layers);
-
- gpuMeshVcol *vcol = mesh_vcol;
+ Vector<VColRef> refs = get_vcol_refs(cd_vdata, cd_ldata, vcol_layers);
/* Index of the vertex color layer in the compact buffer. Used vertex color layers are stored in
* a single buffer. */
@@ -281,25 +282,14 @@ static void extract_vcol_init_subdiv(const DRWSubdivCache *subdiv_cache,
const int dst_offset = (int)subdiv_cache->num_subdiv_loops * 2 * pack_layer_index++;
const CustomData *cdata = ref.domain == ATTR_DOMAIN_POINT ? cd_vdata : cd_ldata;
- const MLoop *ml = coarse_mesh->mloop;
-
int layer_i = CustomData_get_named_layer_index(cdata, ref.layer->type, ref.layer->name);
if (layer_i == -1) {
printf("%s: missing color layer %s\n", __func__, ref.layer->name);
- vcol += coarse_mesh->totloop;
continue;
}
- MLoopCol *mcol = nullptr;
- MPropCol *pcol = nullptr;
-
- if (ref.layer->type == CD_PROP_COLOR) {
- pcol = static_cast<MPropCol *>(cdata->layers[layer_i].data);
- }
- else {
- mcol = static_cast<MLoopCol *>(cdata->layers[layer_i].data);
- }
+ gpuMeshVcol *vcol = mesh_vcol;
const bool is_vert = ref.domain == ATTR_DOMAIN_POINT;
@@ -311,14 +301,15 @@ static void extract_vcol_init_subdiv(const DRWSubdivCache *subdiv_cache,
const bool is_byte = ref.layer->type == CD_PROP_BYTE_COLOR;
BM_ITER_MESH (f, &iter, bm, BM_FACES_OF_MESH) {
- BMLoop *l_iter = f->l_first;
+ const BMLoop *l_iter = f->l_first;
do {
- BMElem *elem = is_vert ? reinterpret_cast<BMElem *>(l_iter->v) :
- reinterpret_cast<BMElem *>(l_iter);
+ const BMElem *elem = is_vert ? reinterpret_cast<const BMElem *>(l_iter->v) :
+ reinterpret_cast<const BMElem *>(l_iter);
if (is_byte) {
- MLoopCol *mcol2 = static_cast<MLoopCol *>(BM_ELEM_CD_GET_VOID_P(elem, cd_ofs));
+ const MLoopCol *mcol2 = static_cast<const MLoopCol *>(
+ BM_ELEM_CD_GET_VOID_P(elem, cd_ofs));
vcol->r = unit_float_to_ushort_clamp(BLI_color_from_srgb_table[mcol2->r]);
vcol->g = unit_float_to_ushort_clamp(BLI_color_from_srgb_table[mcol2->g]);
@@ -326,17 +317,31 @@ static void extract_vcol_init_subdiv(const DRWSubdivCache *subdiv_cache,
vcol->a = unit_float_to_ushort_clamp(mcol2->a * (1.0f / 255.0f));
}
else {
- MPropCol *pcol2 = static_cast<MPropCol *>(BM_ELEM_CD_GET_VOID_P(elem, cd_ofs));
+ const MPropCol *pcol2 = static_cast<const MPropCol *>(
+ BM_ELEM_CD_GET_VOID_P(elem, cd_ofs));
vcol->r = unit_float_to_ushort_clamp(pcol2->color[0]);
vcol->g = unit_float_to_ushort_clamp(pcol2->color[1]);
vcol->b = unit_float_to_ushort_clamp(pcol2->color[2]);
vcol->a = unit_float_to_ushort_clamp(pcol2->color[3]);
}
+
+ vcol++;
} while ((l_iter = l_iter->next) != f->l_first);
}
}
else {
+ const MLoop *ml = coarse_mesh->mloop;
+ const MLoopCol *mcol = nullptr;
+ const MPropCol *pcol = nullptr;
+
+ if (ref.layer->type == CD_PROP_COLOR) {
+ pcol = static_cast<const MPropCol *>(cdata->layers[layer_i].data);
+ }
+ else {
+ mcol = static_cast<const MLoopCol *>(cdata->layers[layer_i].data);
+ }
+
for (int ml_index = 0; ml_index < coarse_mesh->totloop; ml_index++, vcol++, ml++) {
int idx = is_vert ? ml->v : ml_index;
@@ -379,6 +384,4 @@ constexpr MeshExtract create_extractor_vcol()
} // namespace blender::draw
-extern "C" {
const MeshExtract extract_vcol = blender::draw::create_extractor_vcol();
-}
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 89aa16ca0c7..ba194a4b167 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
@@ -10,7 +10,7 @@
#include "BKE_deform.h"
#include "draw_subdivision.h"
-#include "extract_mesh.h"
+#include "extract_mesh.hh"
namespace blender::draw {
@@ -79,7 +79,7 @@ static float evaluate_vertex_weight(const MDeformVert *dvert, const DRW_MeshWeig
}
static void extract_weights_init(const MeshRenderData *mr,
- struct MeshBatchCache *cache,
+ MeshBatchCache *cache,
void *buf,
void *tls_data)
{
@@ -154,7 +154,7 @@ static void extract_weights_iter_poly_mesh(const MeshRenderData *mr,
static void extract_weights_init_subdiv(const DRWSubdivCache *subdiv_cache,
const MeshRenderData *mr,
- struct MeshBatchCache *cache,
+ MeshBatchCache *cache,
void *buffer,
void *_data)
{
@@ -208,6 +208,4 @@ constexpr MeshExtract create_extractor_weights()
} // namespace blender::draw
-extern "C" {
const MeshExtract extract_weights = blender::draw::create_extractor_weights();
-}
diff --git a/source/blender/draw/intern/shaders/common_globals_lib.glsl b/source/blender/draw/intern/shaders/common_globals_lib.glsl
index 0460ba56e4c..a8931292064 100644
--- a/source/blender/draw/intern/shaders/common_globals_lib.glsl
+++ b/source/blender/draw/intern/shaders/common_globals_lib.glsl
@@ -110,7 +110,7 @@ layout(std140) uniform globalsBlock
vec4 screenVecs[2];
vec4 sizeViewport; /* Inverted size in zw. */
- float sizePixel; /* This one is for dpi scaling */
+ float sizePixel; /* This one is for DPI scaling. */
float pixelFac; /* To use with mul_project_m4_v3_zfac() */
float sizeObjectCenter;
float sizeLightCenter;
diff --git a/source/blender/draw/intern/shaders/common_gpencil_lib.glsl b/source/blender/draw/intern/shaders/common_gpencil_lib.glsl
index e58cfaae40d..123c493b572 100644
--- a/source/blender/draw/intern/shaders/common_gpencil_lib.glsl
+++ b/source/blender/draw/intern/shaders/common_gpencil_lib.glsl
@@ -393,7 +393,7 @@ vec4 gpencil_vertex(ivec4 ma,
col2,
fcol1,
viewport_size,
- 0,
+ 0u,
vec2(1.0, 0.0),
out_P,
out_N,
diff --git a/source/blender/draw/intern/shaders/common_hair_lib.glsl b/source/blender/draw/intern/shaders/common_hair_lib.glsl
index ff52b483d77..e235da91e8d 100644
--- a/source/blender/draw/intern/shaders/common_hair_lib.glsl
+++ b/source/blender/draw/intern/shaders/common_hair_lib.glsl
@@ -5,6 +5,8 @@
* of data the CPU has to precompute and transfer for each update.
*/
+#define COMMON_HAIR_LIB
+
/* TODO(fclem): Keep documentation but remove the uniform declaration. */
#ifndef USE_GPU_SHADER_CREATE_INFO
@@ -212,8 +214,8 @@ void hair_get_pos_tan_binor_time(bool is_persp,
wpos += wbinor * thick_time * scale;
}
else {
- /* Note: Ensures 'hairThickTime' is initialised -
- * avoids undefined behaviour on certain macOS configurations. */
+ /* NOTE: Ensures 'hairThickTime' is initialized -
+ * avoids undefined behavior on certain macOS configurations. */
thick_time = 0.0;
}
}
diff --git a/source/blender/draw/intern/shaders/common_math_lib.glsl b/source/blender/draw/intern/shaders/common_math_lib.glsl
index 1ac26c91b93..51f3c890df8 100644
--- a/source/blender/draw/intern/shaders/common_math_lib.glsl
+++ b/source/blender/draw/intern/shaders/common_math_lib.glsl
@@ -110,6 +110,7 @@ float len_squared(vec3 a) { return dot(a, a); }
float len_squared(vec2 a) { return dot(a, a); }
bool flag_test(uint flag, uint val) { return (flag & val) != 0u; }
+bool flag_test(int flag, uint val) { return flag_test(uint(flag), val); }
bool flag_test(int flag, int val) { return (flag & val) != 0; }
void set_flag_from_test(inout uint value, bool test, uint flag) { if (test) { value |= flag; } else { value &= ~flag; } }
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
index 3cbb9f980f3..eacdf8e6333 100644
--- a/source/blender/draw/intern/shaders/common_subdiv_ibo_lines_comp.glsl
+++ b/source/blender/draw/intern/shaders/common_subdiv_ibo_lines_comp.glsl
@@ -1,22 +1,42 @@
/* To be compiled with common_subdiv_lib.glsl */
-layout(std430, binding = 0) readonly buffer inputEdgeOrigIndex
+layout(std430, binding = 1) readonly buffer inputEdgeOrigIndex
{
int input_origindex[];
};
-layout(std430, binding = 1) writeonly buffer outputLinesIndices
+layout(std430, binding = 2) readonly restrict buffer extraCoarseFaceData
+{
+ uint extra_coarse_face_data[];
+};
+
+layout(std430, binding = 3) writeonly buffer outputLinesIndices
{
uint output_lines[];
};
+layout(std430, binding = 4) readonly buffer LinesLooseFlags
+{
+ uint lines_loose_flags[];
+};
+
#ifndef LINES_LOOSE
-void emit_line(uint line_offset, uint start_loop_index, uint corner_index)
+
+bool is_face_hidden(uint coarse_quad_index)
+{
+ return (extra_coarse_face_data[coarse_quad_index] & coarse_face_hidden_mask) != 0;
+}
+
+void emit_line(uint line_offset, uint quad_index, uint start_loop_index, uint corner_index)
{
uint vertex_index = start_loop_index + corner_index;
- if (input_origindex[vertex_index] == ORIGINDEX_NONE && optimal_display) {
+ uint coarse_quad_index = coarse_polygon_index_from_subdiv_quad_index(quad_index,
+ coarse_poly_count);
+
+ if (use_hide && is_face_hidden(coarse_quad_index) ||
+ (input_origindex[vertex_index] == ORIGINDEX_NONE && optimal_display)) {
output_lines[line_offset + 0] = 0xffffffff;
output_lines[line_offset + 1] = 0xffffffff;
}
@@ -41,8 +61,17 @@ void main()
/* 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;
+
+ if (lines_loose_flags[index] != 0) {
+ /* Line is hidden. */
+ output_lines[line_offset] = 0xffffffff;
+ output_lines[line_offset + 1] = 0xffffffff;
+ }
+ else {
+ 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;
@@ -51,7 +80,7 @@ void main()
uint start_line_index = index * 8;
for (int i = 0; i < 4; i++) {
- emit_line(start_line_index + i * 2, start_loop_index, i);
+ emit_line(start_line_index + i * 2, index, 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
index 3dccc82541e..a46d69eca88 100644
--- a/source/blender/draw/intern/shaders/common_subdiv_ibo_tris_comp.glsl
+++ b/source/blender/draw/intern/shaders/common_subdiv_ibo_tris_comp.glsl
@@ -3,18 +3,28 @@
/* Generate triangles from subdivision quads indices. */
-layout(std430, binding = 1) writeonly buffer outputTriangles
+layout(std430, binding = 1) readonly restrict buffer extraCoarseFaceData
+{
+ uint extra_coarse_face_data[];
+};
+
+layout(std430, binding = 2) writeonly buffer outputTriangles
{
uint output_tris[];
};
#ifndef SINGLE_MATERIAL
-layout(std430, binding = 2) readonly buffer inputPolygonMatOffset
+layout(std430, binding = 3) readonly buffer inputPolygonMatOffset
{
int polygon_mat_offset[];
};
#endif
+bool is_face_hidden(uint coarse_quad_index)
+{
+ return (extra_coarse_face_data[coarse_quad_index] & coarse_face_hidden_mask) != 0;
+}
+
void main()
{
uint quad_index = get_global_invocation_index();
@@ -24,20 +34,31 @@ void main()
uint loop_index = quad_index * 4;
+ uint coarse_quad_index = coarse_polygon_index_from_subdiv_quad_index(quad_index,
+ coarse_poly_count);
+
#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;
+ if (use_hide && is_face_hidden(coarse_quad_index)) {
+ output_tris[triangle_loop_index + 0] = 0xffffffff;
+ output_tris[triangle_loop_index + 1] = 0xffffffff;
+ output_tris[triangle_loop_index + 2] = 0xffffffff;
+ output_tris[triangle_loop_index + 3] = 0xffffffff;
+ output_tris[triangle_loop_index + 4] = 0xffffffff;
+ output_tris[triangle_loop_index + 5] = 0xffffffff;
+ }
+ else {
+ 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
index ce324249446..4183b4a1cd3 100644
--- a/source/blender/draw/intern/shaders/common_subdiv_lib.glsl
+++ b/source/blender/draw/intern/shaders/common_subdiv_lib.glsl
@@ -31,10 +31,15 @@ layout(std140) uniform shader_data
uint coarse_face_select_mask;
uint coarse_face_smooth_mask;
uint coarse_face_active_mask;
+ uint coarse_face_hidden_mask;
uint coarse_face_loopstart_mask;
/* Total number of elements to process. */
uint total_dispatch_size;
+
+ bool is_edit_mode;
+
+ bool use_hide;
};
uint get_global_invocation_index()
@@ -138,20 +143,20 @@ void set_vertex_pos(inout PosNorLoop vertex_data, vec3 pos)
vertex_data.z = pos.z;
}
-void set_vertex_nor(inout PosNorLoop vertex_data, vec3 nor, uint 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)
{
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)
+void set_vertex_nor(inout PosNorLoop vertex_data, vec3 nor, float flag)
{
- set_vertex_nor(vertex_data, nor, 0);
+ set_vertex_nor(vertex_data, nor);
+ vertex_data.flag = flag;
}
void add_newell_cross_v3_v3v3(inout vec3 n, vec3 v_prev, vec3 v_curr)
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
index 65cf4ebb90f..81e346863c2 100644
--- a/source/blender/draw/intern/shaders/common_subdiv_patch_evaluation_comp.glsl
+++ b/source/blender/draw/intern/shaders/common_subdiv_patch_evaluation_comp.glsl
@@ -70,10 +70,12 @@ layout(std430, binding = 8) writeonly buffer outputVertices
FDotVert output_verts[];
};
+# ifdef FDOTS_NORMALS
layout(std430, binding = 9) writeonly buffer outputNormals
{
FDotNor output_nors[];
};
+# endif
layout(std430, binding = 10) writeonly buffer outputFdotsIndices
{
@@ -89,6 +91,16 @@ layout(std430, binding = 8) writeonly buffer outputVertexData
{
PosNorLoop output_verts[];
};
+# if defined(ORCO_EVALUATION)
+layout(std430, binding = 9) buffer src_extra_buffer
+{
+ float srcExtraVertexBuffer[];
+};
+layout(std430, binding = 10) writeonly buffer outputOrcoData
+{
+ vec4 output_orcos[];
+};
+# endif
#endif
vec2 read_vec2(int index)
@@ -108,6 +120,17 @@ vec3 read_vec3(int index)
return result;
}
+#if defined(ORCO_EVALUATION)
+vec3 read_vec3_extra(int index)
+{
+ vec3 result;
+ result.x = srcExtraVertexBuffer[index * 3];
+ result.y = srcExtraVertexBuffer[index * 3 + 1];
+ result.z = srcExtraVertexBuffer[index * 3 + 2];
+ return result;
+}
+#endif
+
OsdPatchArray GetPatchArray(int arrayIndex)
{
return patchArrayBuffer[arrayIndex];
@@ -290,6 +313,31 @@ void evaluate_patches_limits(
dv += src_vertex * wDv[cv];
}
}
+
+# if defined(ORCO_EVALUATION)
+/* Evaluate the patches limits from the extra source vertex buffer. */
+void evaluate_patches_limits_extra(int patch_index, float u, float v, inout vec3 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];
+ vec3 src_vertex = read_vec3_extra(index);
+
+ dst += src_vertex * wP[cv];
+ }
+}
+# endif
#endif
/* ------------------------------------------------------------------------------
@@ -341,6 +389,11 @@ float get_face_flag(uint coarse_quad_index)
return 0.0;
}
+bool is_face_hidden(uint coarse_quad_index)
+{
+ return (extra_coarse_face_data[coarse_quad_index] & coarse_face_hidden_mask) != 0;
+}
+
void main()
{
/* We execute for each coarse quad. */
@@ -370,8 +423,16 @@ void main()
fnor.flag = get_face_flag(coarse_quad_index);
output_verts[coarse_quad_index] = vert;
+# ifdef FDOTS_NORMALS
output_nors[coarse_quad_index] = fnor;
- output_indices[coarse_quad_index] = coarse_quad_index;
+# endif
+
+ if (use_hide && is_face_hidden(coarse_quad_index)) {
+ output_indices[coarse_quad_index] = 0xffffffff;
+ }
+ else {
+ output_indices[coarse_quad_index] = coarse_quad_index;
+ }
}
#else
void main()
@@ -398,15 +459,25 @@ void main()
vec3 nor = vec3(0.0);
int origindex = input_vert_origindex[loop_index];
- uint flag = 0;
+ float flag = 0.0;
if (origindex == -1) {
- flag = -1;
+ flag = -1.0;
}
PosNorLoop vertex_data;
set_vertex_pos(vertex_data, pos);
set_vertex_nor(vertex_data, nor, flag);
output_verts[loop_index] = vertex_data;
+
+# if defined(ORCO_EVALUATION)
+ pos = vec3(0.0);
+ evaluate_patches_limits_extra(patch_co.patch_index, uv.x, uv.y, pos);
+
+ /* Set w = 0.0 to indicate that this is not a generic attribute.
+ * See comments in `extract_mesh_vbo_orco.cc`. */
+ vec4 orco_data = vec4(pos, 0.0);
+ output_orcos[loop_index] = orco_data;
+# endif
}
}
#endif
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
index b7bcfd2d369..97c07704c06 100644
--- a/source/blender/draw/intern/shaders/common_subdiv_vbo_lnor_comp.glsl
+++ b/source/blender/draw/intern/shaders/common_subdiv_vbo_lnor_comp.glsl
@@ -11,7 +11,12 @@ layout(std430, binding = 2) readonly buffer extraCoarseFaceData
uint extra_coarse_face_data[];
};
-layout(std430, binding = 3) writeonly buffer outputLoopNormals
+layout(std430, binding = 3) readonly buffer inputVertOrigIndices
+{
+ int input_vert_origindex[];
+};
+
+layout(std430, binding = 4) writeonly buffer outputLoopNormals
{
LoopNormal output_lnor[];
};
@@ -21,6 +26,23 @@ bool is_face_selected(uint coarse_quad_index)
return (extra_coarse_face_data[coarse_quad_index] & coarse_face_select_mask) != 0;
}
+bool is_face_hidden(uint coarse_quad_index)
+{
+ return (extra_coarse_face_data[coarse_quad_index] & coarse_face_hidden_mask) != 0;
+}
+
+/* Flag for paint mode overlay and normals drawing in edit-mode. */
+float get_loop_flag(uint coarse_quad_index, int vert_origindex)
+{
+ if (is_face_hidden(coarse_quad_index) || (is_edit_mode && vert_origindex == -1)) {
+ return -1.0;
+ }
+ if (is_face_selected(coarse_quad_index)) {
+ return 1.0;
+ }
+ return 0.0;
+}
+
void main()
{
/* We execute for each quad. */
@@ -39,7 +61,11 @@ void main()
/* 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_normal_and_flag(pos_nor_loop);
+ int origindex = input_vert_origindex[start_loop_index + i];
+ LoopNormal loop_normal = get_normal_and_flag(pos_nor_loop);
+ loop_normal.flag = get_loop_flag(coarse_quad_index, origindex);
+
+ output_lnor[start_loop_index + i] = loop_normal;
}
}
else {
@@ -60,13 +86,11 @@ void main()
loop_normal.nx = face_normal.x;
loop_normal.ny = face_normal.y;
loop_normal.nz = face_normal.z;
- loop_normal.flag = 0.0;
-
- if (is_face_selected(coarse_quad_index)) {
- loop_normal.flag = 1.0;
- }
for (int i = 0; i < 4; i++) {
+ int origindex = input_vert_origindex[start_loop_index + i];
+ loop_normal.flag = get_loop_flag(coarse_quad_index, origindex);
+
output_lnor[start_loop_index + i] = loop_normal;
}
}
diff --git a/source/blender/draw/intern/shaders/draw_object_infos_info.hh b/source/blender/draw/intern/shaders/draw_object_infos_info.hh
index c74a043ec97..8fd55ea351f 100644
--- a/source/blender/draw/intern/shaders/draw_object_infos_info.hh
+++ b/source/blender/draw/intern/shaders/draw_object_infos_info.hh
@@ -10,3 +10,7 @@ GPU_SHADER_CREATE_INFO(draw_object_infos)
GPU_SHADER_CREATE_INFO(draw_volume_infos)
.typedef_source("draw_shader_shared.h")
.uniform_buf(2, "VolumeInfos", "drw_volume", Frequency::BATCH);
+
+GPU_SHADER_CREATE_INFO(draw_curves_infos)
+ .typedef_source("draw_shader_shared.h")
+ .uniform_buf(2, "CurvesInfos", "drw_curves", Frequency::BATCH);
diff --git a/source/blender/editors/animation/anim_channels_defines.c b/source/blender/editors/animation/anim_channels_defines.c
index c2d517588b2..9eeabf2d05e 100644
--- a/source/blender/editors/animation/anim_channels_defines.c
+++ b/source/blender/editors/animation/anim_channels_defines.c
@@ -4351,15 +4351,15 @@ void ANIM_channel_setting_set(bAnimContext *ac,
/* --------------------------- */
-/* size of icons */
+/** Size of icons. */
#define ICON_WIDTH (0.85f * U.widget_unit)
-/* width of sliders */
+/** Width of sliders. */
#define SLIDER_WIDTH (4 * U.widget_unit)
-/* min-width of rename textboxes */
+/** Min-width of rename text-boxes. */
#define RENAME_TEXT_MIN_WIDTH (U.widget_unit)
-/* width of graph editor color bands */
+/** Width of graph editor color bands. */
#define GRAPH_COLOR_BAND_WIDTH (0.3f * U.widget_unit)
-/* extra offset for the visibility icons in the graph editor */
+/** Extra offset for the visibility icons in the graph editor. */
#define GRAPH_ICON_VISIBILITY_OFFSET (GRAPH_COLOR_BAND_WIDTH * 1.5f)
/* Helper - Check if a channel needs renaming */
diff --git a/source/blender/editors/animation/anim_channels_edit.c b/source/blender/editors/animation/anim_channels_edit.c
index f148bb5b77d..b223a1493fd 100644
--- a/source/blender/editors/animation/anim_channels_edit.c
+++ b/source/blender/editors/animation/anim_channels_edit.c
@@ -711,14 +711,14 @@ static bool animedit_poll_channels_active(bContext *C)
/* channels region test */
/* TODO: could enhance with actually testing if channels region? */
if (ELEM(NULL, area, CTX_wm_region(C))) {
- return 0;
+ return false;
}
/* animation editor test */
if (ELEM(area->spacetype, SPACE_ACTION, SPACE_GRAPH, SPACE_NLA) == 0) {
- return 0;
+ return false;
}
- return 1;
+ return true;
}
/* Poll callback for Animation Editor channels list region + not in NLA-tweak-mode for NLA. */
@@ -730,21 +730,21 @@ static bool animedit_poll_channels_nla_tweakmode_off(bContext *C)
/* channels region test */
/* TODO: could enhance with actually testing if channels region? */
if (ELEM(NULL, area, CTX_wm_region(C))) {
- return 0;
+ return false;
}
/* animation editor test */
if (ELEM(area->spacetype, SPACE_ACTION, SPACE_GRAPH, SPACE_NLA) == 0) {
- return 0;
+ return false;
}
/* NLA tweak-mode test. */
if (area->spacetype == SPACE_NLA) {
if ((scene == NULL) || (scene->flag & SCE_NLA_EDIT_ON)) {
- return 0;
+ return false;
}
}
- return 1;
+ return true;
}
/* ****************** Rearrange Channels Operator ******************* */
@@ -791,7 +791,7 @@ static bool rearrange_island_ok(tReorderChannelIsland *island)
{
/* island must not be untouchable */
if (island->flag & REORDER_ISLAND_UNTOUCHABLE) {
- return 0;
+ return false;
}
/* island should be selected to be moved */
@@ -809,10 +809,10 @@ static bool rearrange_island_top(ListBase *list, tReorderChannelIsland *island)
/* make it first element */
BLI_insertlinkbefore(list, list->first, island);
- return 1;
+ return true;
}
- return 0;
+ return false;
}
static bool rearrange_island_up(ListBase *list, tReorderChannelIsland *island)
@@ -833,11 +833,11 @@ static bool rearrange_island_up(ListBase *list, tReorderChannelIsland *island)
/* push it up */
BLI_insertlinkbefore(list, prev, island);
- return 1;
+ return true;
}
}
- return 0;
+ return false;
}
static bool rearrange_island_down(ListBase *list, tReorderChannelIsland *island)
@@ -1083,7 +1083,7 @@ static bool rearrange_animchannel_islands(ListBase *list,
/* don't waste effort on an empty list */
if (BLI_listbase_is_empty(list)) {
- return 0;
+ return false;
}
/* group channels into islands */
@@ -1589,7 +1589,7 @@ static bool animchannels_grouping_poll(bContext *C)
/* channels region test */
/* TODO: could enhance with actually testing if channels region? */
if (ELEM(NULL, area, CTX_wm_region(C))) {
- return 0;
+ return false;
}
/* animation editor test - must be suitable modes only */
@@ -1602,7 +1602,7 @@ static bool animchannels_grouping_poll(bContext *C)
/* dopesheet and action only - all others are for other datatypes or have no groups */
if (ELEM(saction->mode, SACTCONT_ACTION, SACTCONT_DOPESHEET) == 0) {
- return 0;
+ return false;
}
break;
@@ -1612,17 +1612,17 @@ static bool animchannels_grouping_poll(bContext *C)
/* drivers can't have groups... */
if (sipo->mode != SIPO_MODE_ANIMATION) {
- return 0;
+ return false;
}
break;
}
/* unsupported... */
default:
- return 0;
+ return false;
}
- return 1;
+ return true;
}
/* ----------------------------------------------------------- */
@@ -2428,15 +2428,15 @@ static bool animchannels_enable_poll(bContext *C)
/* channels region test */
/* TODO: could enhance with actually testing if channels region? */
if (ELEM(NULL, area, CTX_wm_region(C))) {
- return 0;
+ return false;
}
/* animation editor test - Action/Dopesheet/etc. and Graph only */
if (ELEM(area->spacetype, SPACE_ACTION, SPACE_GRAPH) == 0) {
- return 0;
+ return false;
}
- return 1;
+ return true;
}
static int animchannels_enable_exec(bContext *C, wmOperator *UNUSED(op))
@@ -2504,7 +2504,7 @@ static bool animchannels_select_filter_poll(bContext *C)
ScrArea *area = CTX_wm_area(C);
if (area == NULL) {
- return 0;
+ return false;
}
/* animation editor with dopesheet */
@@ -2791,13 +2791,35 @@ static bool rename_anim_channels(bAnimContext *ac, int channel_index)
return false;
}
- /* don't allow renaming linked channels */
- if ((ale->fcurve_owner_id != NULL &&
- (ID_IS_LINKED(ale->fcurve_owner_id) || ID_IS_OVERRIDE_LIBRARY(ale->fcurve_owner_id))) ||
- (ale->id != NULL && (ID_IS_LINKED(ale->id) || ID_IS_OVERRIDE_LIBRARY(ale->id)))) {
+ /* Don't allow renaming linked/liboverride channels. */
+ if (ale->fcurve_owner_id != NULL &&
+ (ID_IS_LINKED(ale->fcurve_owner_id) || ID_IS_OVERRIDE_LIBRARY(ale->fcurve_owner_id))) {
ANIM_animdata_freelist(&anim_data);
return false;
}
+ if (ale->id != NULL) {
+ if (ID_IS_LINKED(ale->id)) {
+ ANIM_animdata_freelist(&anim_data);
+ return false;
+ }
+ /* There is one exception to not allowing renaming on liboverride channels: locally-inserted
+ * NLA tracks. */
+ if (ID_IS_OVERRIDE_LIBRARY(ale->id)) {
+ switch (ale->type) {
+ case ANIMTYPE_NLATRACK: {
+ NlaTrack *nlt = (NlaTrack *)ale->data;
+ if ((nlt->flag & NLATRACK_OVERRIDELIBRARY_LOCAL) == 0) {
+ ANIM_animdata_freelist(&anim_data);
+ return false;
+ }
+ break;
+ }
+ default:
+ ANIM_animdata_freelist(&anim_data);
+ return false;
+ }
+ }
+ }
/* check that channel can be renamed */
acf = ANIM_channel_get_typeinfo(ale);
diff --git a/source/blender/editors/animation/anim_markers.c b/source/blender/editors/animation/anim_markers.c
index 1a3ab100768..ad06b185132 100644
--- a/source/blender/editors/animation/anim_markers.c
+++ b/source/blender/editors/animation/anim_markers.c
@@ -543,6 +543,8 @@ void ED_markers_draw(const bContext *C, int flag)
View2D *v2d = UI_view2d_fromcontext(C);
int cfra = CTX_data_scene(C)->r.cfra;
+ GPU_line_width(1.0f);
+
rctf markers_region_rect;
get_marker_region_rect(v2d, &markers_region_rect);
diff --git a/source/blender/editors/animation/anim_ops.c b/source/blender/editors/animation/anim_ops.c
index 5b0c5eac11b..84f99ec0ac0 100644
--- a/source/blender/editors/animation/anim_ops.c
+++ b/source/blender/editors/animation/anim_ops.c
@@ -38,7 +38,6 @@
#include "SEQ_iterator.h"
#include "SEQ_sequencer.h"
#include "SEQ_time.h"
-#include "SEQ_transform.h"
#include "anim_intern.h"
@@ -112,9 +111,9 @@ static int seq_frame_apply_snap(bContext *C, Scene *scene, const int timeline_fr
Sequence *seq;
SEQ_ITERATOR_FOREACH (seq, strips) {
seq_frame_snap_update_best(
- SEQ_transform_get_left_handle_frame(seq), timeline_frame, &best_frame, &best_distance);
+ SEQ_time_left_handle_frame_get(seq), timeline_frame, &best_frame, &best_distance);
seq_frame_snap_update_best(
- SEQ_transform_get_right_handle_frame(seq), timeline_frame, &best_frame, &best_distance);
+ SEQ_time_right_handle_frame_get(seq), timeline_frame, &best_frame, &best_distance);
}
SEQ_collection_free(strips);
diff --git a/source/blender/editors/animation/drivers.c b/source/blender/editors/animation/drivers.c
index 1b759f5dfa2..c6f68228807 100644
--- a/source/blender/editors/animation/drivers.c
+++ b/source/blender/editors/animation/drivers.c
@@ -180,7 +180,7 @@ static int add_driver_with_target(ReportList *UNUSED(reports),
}
else if ((RNA_property_unit(src_prop) == PROP_UNIT_ROTATION) &&
(RNA_property_unit(dst_prop) != PROP_UNIT_ROTATION)) {
- /* Rotation Source: radians -> normal, so convert src to degrees
+ /* Rotation Source: radians -> normal, so convert src to degrees
* (However, if both input and output is a rotation, don't apply such corrections)
*/
BLI_strncpy(driver->expression, "degrees(var)", sizeof(driver->expression));
diff --git a/source/blender/editors/animation/keyframes_draw.c b/source/blender/editors/animation/keyframes_draw.c
index 58d093c678d..786204a52ed 100644
--- a/source/blender/editors/animation/keyframes_draw.c
+++ b/source/blender/editors/animation/keyframes_draw.c
@@ -168,11 +168,11 @@ void draw_keyframe_shape(float x,
/* Common attributes shared between the draw calls. */
typedef struct DrawKeylistUIData {
float alpha;
- float icon_sz;
- float half_icon_sz;
- float smaller_sz;
- float ipo_sz;
- float gpencil_sz;
+ float icon_size;
+ float half_icon_size;
+ float smaller_size;
+ float ipo_size;
+ float gpencil_size;
float screenspace_margin;
float sel_color[4];
float unsel_color[4];
@@ -195,11 +195,11 @@ static void draw_keylist_ui_data_init(DrawKeylistUIData *ctx,
/* TODO: allow this opacity factor to be themed? */
ctx->alpha = channel_locked ? 0.25f : 1.0f;
- ctx->icon_sz = U.widget_unit * 0.5f * yscale_fac;
- ctx->half_icon_sz = 0.5f * ctx->icon_sz;
- ctx->smaller_sz = 0.35f * ctx->icon_sz;
- ctx->ipo_sz = 0.1f * ctx->icon_sz;
- ctx->gpencil_sz = ctx->smaller_sz * 0.8f;
+ ctx->icon_size = U.widget_unit * 0.5f * yscale_fac;
+ ctx->half_icon_size = 0.5f * ctx->icon_size;
+ ctx->smaller_size = 0.35f * ctx->icon_size;
+ ctx->ipo_size = 0.1f * ctx->icon_size;
+ ctx->gpencil_size = ctx->smaller_size * 0.8f;
ctx->screenspace_margin = (0.35f * (float)UI_UNIT_X) / UI_view2d_scale_get_x(v2d);
ctx->show_ipo = (saction_flag & SACTION_SHOW_INTERPOLATION) != 0;
@@ -242,8 +242,8 @@ static void draw_keylist_block_gpencil(const DrawKeylistUIData *ctx,
&(const rctf){
.xmin = ab->cfra,
.xmax = min_ff(ab->next->cfra - (ctx->screenspace_margin * size), ab->next->cfra),
- .ymin = ypos - ctx->gpencil_sz,
- .ymax = ypos + ctx->gpencil_sz,
+ .ymin = ypos - ctx->gpencil_size,
+ .ymax = ypos + ctx->gpencil_size,
},
true,
0.25f * (float)UI_UNIT_X,
@@ -259,8 +259,8 @@ static void draw_keylist_block_moving_hold(const DrawKeylistUIData *ctx,
&(const rctf){
.xmin = ab->cfra,
.xmax = ab->next->cfra,
- .ymin = ypos - ctx->smaller_sz,
- .ymax = ypos + ctx->smaller_sz,
+ .ymin = ypos - ctx->smaller_size,
+ .ymax = ypos + ctx->smaller_size,
},
true,
3.0f,
@@ -275,8 +275,8 @@ static void draw_keylist_block_standard(const DrawKeylistUIData *ctx,
&(const rctf){
.xmin = ab->cfra,
.xmax = ab->next->cfra,
- .ymin = ypos - ctx->half_icon_sz,
- .ymax = ypos + ctx->half_icon_sz,
+ .ymin = ypos - ctx->half_icon_size,
+ .ymax = ypos + ctx->half_icon_size,
},
true,
3.0f,
@@ -291,8 +291,8 @@ static void draw_keylist_block_interpolation_line(const DrawKeylistUIData *ctx,
&(const rctf){
.xmin = ab->cfra,
.xmax = ab->next->cfra,
- .ymin = ypos - ctx->ipo_sz,
- .ymax = ypos + ctx->ipo_sz,
+ .ymin = ypos - ctx->ipo_size,
+ .ymax = ypos + ctx->ipo_size,
},
true,
3.0f,
@@ -367,7 +367,7 @@ static void draw_keylist_keys(const DrawKeylistUIData *ctx,
draw_keyframe_shape(ak->cfra,
ypos,
- ctx->icon_sz,
+ ctx->icon_size,
(ak->sel & SELECT),
ak->key_type,
KEYFRAME_SHAPE_BOTH,
diff --git a/source/blender/editors/animation/keyframes_keylist.cc b/source/blender/editors/animation/keyframes_keylist.cc
index 3356ef4d47d..8dc598e6e2d 100644
--- a/source/blender/editors/animation/keyframes_keylist.cc
+++ b/source/blender/editors/animation/keyframes_keylist.cc
@@ -132,7 +132,7 @@ static void ED_keylist_runtime_init_listbase(AnimKeylist *keylist)
return;
}
- keylist->runtime.list_wrapper.first = &keylist->runtime.key_columns[0];
+ keylist->runtime.list_wrapper.first = keylist->runtime.key_columns.data();
keylist->runtime.list_wrapper.last = &keylist->runtime.key_columns[keylist->column_len - 1];
}
@@ -309,7 +309,7 @@ static void keylist_first_last(const struct AnimKeylist *keylist,
const struct ActKeyColumn **last_column)
{
if (keylist->is_runtime_initialized) {
- *first_column = &keylist->runtime.key_columns[0];
+ *first_column = keylist->runtime.key_columns.data();
*last_column = &keylist->runtime.key_columns[keylist->column_len - 1];
}
else {
diff --git a/source/blender/editors/animation/keyframing.c b/source/blender/editors/animation/keyframing.c
index 14a3b958ea6..aa99a4e50c3 100644
--- a/source/blender/editors/animation/keyframing.c
+++ b/source/blender/editors/animation/keyframing.c
@@ -2051,6 +2051,8 @@ void ANIM_OT_keyframe_insert_by_name(wmOperatorType *ot)
/* keyingset to use (idname) */
prop = RNA_def_string(
ot->srna, "type", NULL, MAX_ID_NAME - 2, "Keying Set", "The Keying Set to use");
+ RNA_def_property_string_search_func_runtime(
+ prop, ANIM_keyingset_visit_for_search_no_poll, PROP_STRING_SEARCH_SUGGESTION);
RNA_def_property_flag(prop, PROP_HIDDEN);
ot->prop = prop;
}
@@ -2246,6 +2248,8 @@ void ANIM_OT_keyframe_delete_by_name(wmOperatorType *ot)
/* keyingset to use (idname) */
prop = RNA_def_string(
ot->srna, "type", NULL, MAX_ID_NAME - 2, "Keying Set", "The Keying Set to use");
+ RNA_def_property_string_search_func_runtime(
+ prop, ANIM_keyingset_visit_for_search_no_poll, PROP_STRING_SEARCH_SUGGESTION);
RNA_def_property_flag(prop, PROP_HIDDEN);
ot->prop = prop;
}
@@ -3090,8 +3094,13 @@ bool ED_autokeyframe_pchan(
return false;
}
-bool ED_autokeyframe_property(
- bContext *C, Scene *scene, PointerRNA *ptr, PropertyRNA *prop, int rnaindex, float cfra)
+bool ED_autokeyframe_property(bContext *C,
+ Scene *scene,
+ PointerRNA *ptr,
+ PropertyRNA *prop,
+ int rnaindex,
+ float cfra,
+ const bool only_if_property_keyed)
{
Main *bmain = CTX_data_main(C);
Depsgraph *depsgraph = CTX_data_depsgraph_pointer(C);
@@ -3110,7 +3119,9 @@ bool ED_autokeyframe_property(
fcu = BKE_fcurve_find_by_rna_context_ui(
C, ptr, prop, rnaindex_check, NULL, &action, &driven, &special);
- if (fcu == NULL) {
+ /* Only early out when we actually want an existing F-curve already
+ * (e.g. auto-keyframing from buttons). */
+ if (fcu == NULL && (driven || special || only_if_property_keyed)) {
return changed;
}
@@ -3146,23 +3157,28 @@ bool ED_autokeyframe_property(
ReportList *reports = CTX_wm_reports(C);
ToolSettings *ts = scene->toolsettings;
const eInsertKeyFlags flag = ANIM_get_keyframing_flags(scene, true);
+ char *path = RNA_path_from_ID_to_property(ptr, prop);
- /* NOTE: We use rnaindex instead of fcu->array_index,
- * because a button may control all items of an array at once.
- * E.g., color wheels (see T42567). */
- BLI_assert((fcu->array_index == rnaindex) || (rnaindex == -1));
+ if (only_if_property_keyed) {
+ /* NOTE: We use rnaindex instead of fcu->array_index,
+ * because a button may control all items of an array at once.
+ * E.g., color wheels (see T42567). */
+ BLI_assert((fcu->array_index == rnaindex) || (rnaindex == -1));
+ }
changed = insert_keyframe(bmain,
reports,
id,
action,
- ((fcu->grp) ? (fcu->grp->name) : (NULL)),
- fcu->rna_path,
+ (fcu && fcu->grp) ? fcu->grp->name : NULL,
+ fcu ? fcu->rna_path : path,
rnaindex,
&anim_eval_context,
ts->keyframe_type,
NULL,
flag) != 0;
-
+ if (path) {
+ MEM_freeN(path);
+ }
WM_event_add_notifier(C, NC_ANIMATION | ND_KEYFRAME | NA_EDITED, NULL);
}
}
diff --git a/source/blender/editors/animation/keyingsets.c b/source/blender/editors/animation/keyingsets.c
index 6fcdd21bad8..97b81277008 100644
--- a/source/blender/editors/animation/keyingsets.c
+++ b/source/blender/editors/animation/keyingsets.c
@@ -708,6 +708,72 @@ KeyingSet *ANIM_get_keyingset_for_autokeying(const Scene *scene, const char *tra
return ANIM_builtin_keyingset_get_named(NULL, transformKSName);
}
+static void anim_keyingset_visit_for_search_impl(const bContext *C,
+ StringPropertySearchVisitFunc visit_fn,
+ void *visit_user_data,
+ const bool use_poll)
+{
+ /* Poll requires context. */
+ if (use_poll && (C == NULL)) {
+ return;
+ }
+
+ Scene *scene = C ? CTX_data_scene(C) : NULL;
+ KeyingSet *ks;
+
+ /* Active Keying Set. */
+ if (!use_poll || (scene && scene->active_keyingset)) {
+ StringPropertySearchVisitParams visit_params = {NULL};
+ visit_params.text = "__ACTIVE__";
+ visit_params.info = "Active Keying Set";
+ visit_fn(visit_user_data, &visit_params);
+ }
+
+ /* User-defined Keying Sets. */
+ if (scene && scene->keyingsets.first) {
+ for (ks = scene->keyingsets.first; ks; ks = ks->next) {
+ if (use_poll && !ANIM_keyingset_context_ok_poll((bContext *)C, ks)) {
+ continue;
+ }
+ StringPropertySearchVisitParams visit_params = {NULL};
+ visit_params.text = ks->idname;
+ visit_params.info = ks->name;
+ visit_fn(visit_user_data, &visit_params);
+ }
+ }
+
+ /* Builtin Keying Sets. */
+ for (ks = builtin_keyingsets.first; ks; ks = ks->next) {
+ if (use_poll && !ANIM_keyingset_context_ok_poll((bContext *)C, ks)) {
+ continue;
+ }
+ StringPropertySearchVisitParams visit_params = {NULL};
+ visit_params.text = ks->idname;
+ visit_params.info = ks->name;
+ visit_fn(visit_user_data, &visit_params);
+ }
+}
+
+void ANIM_keyingset_visit_for_search(const bContext *C,
+ PointerRNA *UNUSED(ptr),
+ PropertyRNA *UNUSED(prop),
+ const char *UNUSED(edit_text),
+ StringPropertySearchVisitFunc visit_fn,
+ void *visit_user_data)
+{
+ anim_keyingset_visit_for_search_impl(C, visit_fn, visit_user_data, false);
+}
+
+void ANIM_keyingset_visit_for_search_no_poll(const bContext *C,
+ PointerRNA *UNUSED(ptr),
+ PropertyRNA *UNUSED(prop),
+ const char *UNUSED(edit_text),
+ StringPropertySearchVisitFunc visit_fn,
+ void *visit_user_data)
+{
+ anim_keyingset_visit_for_search_impl(C, visit_fn, visit_user_data, true);
+}
+
/* Menu of All Keying Sets ----------------------------- */
const EnumPropertyItem *ANIM_keying_sets_enum_itemf(bContext *C,
diff --git a/source/blender/editors/armature/armature_add.c b/source/blender/editors/armature/armature_add.c
index f9b973733af..dd43e3e6613 100644
--- a/source/blender/editors/armature/armature_add.c
+++ b/source/blender/editors/armature/armature_add.c
@@ -375,13 +375,10 @@ static void updateDuplicateSubtarget(EditBone *dup_bone,
/* does this constraint have a subtarget in
* this armature?
*/
- const bConstraintTypeInfo *cti = BKE_constraint_typeinfo_get(curcon);
ListBase targets = {NULL, NULL};
bConstraintTarget *ct;
- if (cti && cti->get_constraint_targets) {
- cti->get_constraint_targets(curcon, &targets);
-
+ if (BKE_constraint_targets_get(curcon, &targets)) {
for (ct = targets.first; ct; ct = ct->next) {
if ((ct->tar == ob) && (ct->subtarget[0])) {
oldtarget = get_named_editbone(editbones, ct->subtarget);
@@ -409,9 +406,7 @@ static void updateDuplicateSubtarget(EditBone *dup_bone,
}
}
- if (cti->flush_constraint_targets) {
- cti->flush_constraint_targets(curcon, &targets, 0);
- }
+ BKE_constraint_targets_flush(curcon, &targets, 0);
}
}
}
@@ -1152,7 +1147,7 @@ static int armature_symmetrize_exec(bContext *C, wmOperator *op)
}
if (axis_delta == 0.0f) {
- /* both mirrored bones exist and point to eachother and overlap exactly.
+ /* Both mirrored bones exist and point to each other and overlap exactly.
*
* in this case there's no well defined solution, so de-select both and skip.
*/
diff --git a/source/blender/editors/armature/armature_edit.c b/source/blender/editors/armature/armature_edit.c
index 963d7ea1149..3c445f46902 100644
--- a/source/blender/editors/armature/armature_edit.c
+++ b/source/blender/editors/armature/armature_edit.c
@@ -229,7 +229,7 @@ typedef enum eCalcRollTypes {
} eCalcRollTypes;
static const EnumPropertyItem prop_calc_roll_types[] = {
- {0, "", 0, N_("Positive"), ""},
+ RNA_ENUM_ITEM_HEADING(N_("Positive"), NULL),
{CALC_ROLL_TAN_POS_X, "POS_X", 0, "Local +X Tangent", ""},
{CALC_ROLL_TAN_POS_Z, "POS_Z", 0, "Local +Z Tangent", ""},
@@ -237,8 +237,7 @@ static const EnumPropertyItem prop_calc_roll_types[] = {
{CALC_ROLL_POS_Y, "GLOBAL_POS_Y", 0, "Global +Y Axis", ""},
{CALC_ROLL_POS_Z, "GLOBAL_POS_Z", 0, "Global +Z Axis", ""},
- {0, "", 0, N_("Negative"), ""},
-
+ RNA_ENUM_ITEM_HEADING(N_("Negative"), NULL),
{CALC_ROLL_TAN_NEG_X, "NEG_X", 0, "Local -X Tangent", ""},
{CALC_ROLL_TAN_NEG_Z, "NEG_Z", 0, "Local -Z Tangent", ""},
@@ -246,7 +245,7 @@ static const EnumPropertyItem prop_calc_roll_types[] = {
{CALC_ROLL_NEG_Y, "GLOBAL_NEG_Y", 0, "Global -Y Axis", ""},
{CALC_ROLL_NEG_Z, "GLOBAL_NEG_Z", 0, "Global -Z Axis", ""},
- {0, "", 0, N_("Other"), ""},
+ RNA_ENUM_ITEM_HEADING(N_("Other"), NULL),
{CALC_ROLL_ACTIVE, "ACTIVE", 0, "Active Bone", ""},
{CALC_ROLL_VIEW, "VIEW", 0, "View Axis", ""},
{CALC_ROLL_CURSOR, "CURSOR", 0, "Cursor", ""},
diff --git a/source/blender/editors/armature/armature_naming.c b/source/blender/editors/armature/armature_naming.c
index e1f2605481f..1f02e24666d 100644
--- a/source/blender/editors/armature/armature_naming.c
+++ b/source/blender/editors/armature/armature_naming.c
@@ -109,13 +109,10 @@ static void constraint_bone_name_fix(Object *ob,
bConstraintTarget *ct;
for (curcon = conlist->first; curcon; curcon = curcon->next) {
- const bConstraintTypeInfo *cti = BKE_constraint_typeinfo_get(curcon);
ListBase targets = {NULL, NULL};
/* constraint targets */
- if (cti && cti->get_constraint_targets) {
- cti->get_constraint_targets(curcon, &targets);
-
+ if (BKE_constraint_targets_get(curcon, &targets)) {
for (ct = targets.first; ct; ct = ct->next) {
if (ct->tar == ob) {
if (STREQ(ct->subtarget, oldname)) {
@@ -124,9 +121,7 @@ static void constraint_bone_name_fix(Object *ob,
}
}
- if (cti->flush_constraint_targets) {
- cti->flush_constraint_targets(curcon, &targets, 0);
- }
+ BKE_constraint_targets_flush(curcon, &targets, 0);
}
/* action constraints */
diff --git a/source/blender/editors/armature/armature_relations.c b/source/blender/editors/armature/armature_relations.c
index be4829c02be..950178e865d 100644
--- a/source/blender/editors/armature/armature_relations.c
+++ b/source/blender/editors/armature/armature_relations.c
@@ -68,14 +68,11 @@ static void joined_armature_fix_links_constraints(Main *bmain,
bool changed = false;
for (con = lb->first; con; con = con->next) {
- const bConstraintTypeInfo *cti = BKE_constraint_typeinfo_get(con);
ListBase targets = {NULL, NULL};
bConstraintTarget *ct;
/* constraint targets */
- if (cti && cti->get_constraint_targets) {
- cti->get_constraint_targets(con, &targets);
-
+ if (BKE_constraint_targets_get(con, &targets)) {
for (ct = targets.first; ct; ct = ct->next) {
if (ct->tar == srcArm) {
if (ct->subtarget[0] == '\0') {
@@ -90,9 +87,7 @@ static void joined_armature_fix_links_constraints(Main *bmain,
}
}
- if (cti->flush_constraint_targets) {
- cti->flush_constraint_targets(con, &targets, 0);
- }
+ BKE_constraint_targets_flush(con, &targets, 0);
}
/* action constraint? (pose constraints only) */
@@ -459,14 +454,11 @@ static void separated_armature_fix_links(Main *bmain, Object *origArm, Object *n
if (ob->type == OB_ARMATURE) {
for (pchan = ob->pose->chanbase.first; pchan; pchan = pchan->next) {
for (con = pchan->constraints.first; con; con = con->next) {
- const bConstraintTypeInfo *cti = BKE_constraint_typeinfo_get(con);
ListBase targets = {NULL, NULL};
bConstraintTarget *ct;
/* constraint targets */
- if (cti && cti->get_constraint_targets) {
- cti->get_constraint_targets(con, &targets);
-
+ if (BKE_constraint_targets_get(con, &targets)) {
for (ct = targets.first; ct; ct = ct->next) {
/* Any targets which point to original armature
* are redirected to the new one only if:
@@ -487,9 +479,7 @@ static void separated_armature_fix_links(Main *bmain, Object *origArm, Object *n
}
}
- if (cti->flush_constraint_targets) {
- cti->flush_constraint_targets(con, &targets, 0);
- }
+ BKE_constraint_targets_flush(con, &targets, 0);
}
}
}
@@ -498,14 +488,11 @@ static void separated_armature_fix_links(Main *bmain, Object *origArm, Object *n
/* fix object-level constraints */
if (ob != origArm) {
for (con = ob->constraints.first; con; con = con->next) {
- const bConstraintTypeInfo *cti = BKE_constraint_typeinfo_get(con);
ListBase targets = {NULL, NULL};
bConstraintTarget *ct;
/* constraint targets */
- if (cti && cti->get_constraint_targets) {
- cti->get_constraint_targets(con, &targets);
-
+ if (BKE_constraint_targets_get(con, &targets)) {
for (ct = targets.first; ct; ct = ct->next) {
/* any targets which point to original armature are redirected to the new one only if:
* - the target isn't origArm/newArm itself
@@ -525,9 +512,7 @@ static void separated_armature_fix_links(Main *bmain, Object *origArm, Object *n
}
}
- if (cti->flush_constraint_targets) {
- cti->flush_constraint_targets(con, &targets, 0);
- }
+ BKE_constraint_targets_flush(con, &targets, 0);
}
}
}
diff --git a/source/blender/editors/armature/armature_skinning.c b/source/blender/editors/armature/armature_skinning.c
index 64035732a39..3a1e7419d3c 100644
--- a/source/blender/editors/armature/armature_skinning.c
+++ b/source/blender/editors/armature/armature_skinning.c
@@ -9,6 +9,7 @@
#include "DNA_armature_types.h"
#include "DNA_mesh_types.h"
+#include "DNA_meshdata_types.h"
#include "DNA_object_types.h"
#include "DNA_scene_types.h"
diff --git a/source/blender/editors/armature/pose_lib.c b/source/blender/editors/armature/pose_lib.c
index e0e5693c79b..ea54c3014ca 100644
--- a/source/blender/editors/armature/pose_lib.c
+++ b/source/blender/editors/armature/pose_lib.c
@@ -1431,7 +1431,7 @@ static int poselib_preview_handle_event(bContext *UNUSED(C), wmOperator *op, con
ret = OPERATOR_PASS_THROUGH;
break;
- /* quicky compare to original */
+ /* Quickly compare to original. */
case EVT_TABKEY:
pld->flag &= ~PL_PREVIEW_SHOWORIGINAL;
pld->redraw = PL_PREVIEW_REDRAWALL;
diff --git a/source/blender/editors/armature/pose_select.c b/source/blender/editors/armature/pose_select.c
index 8790a10f3e5..b6b5d3ee495 100644
--- a/source/blender/editors/armature/pose_select.c
+++ b/source/blender/editors/armature/pose_select.c
@@ -680,13 +680,10 @@ static int pose_select_constraint_target_exec(bContext *C, wmOperator *UNUSED(op
CTX_DATA_BEGIN (C, bPoseChannel *, pchan, visible_pose_bones) {
if (pchan->bone->flag & BONE_SELECTED) {
for (con = pchan->constraints.first; con; con = con->next) {
- const bConstraintTypeInfo *cti = BKE_constraint_typeinfo_get(con);
ListBase targets = {NULL, NULL};
bConstraintTarget *ct;
- if (cti && cti->get_constraint_targets) {
- cti->get_constraint_targets(con, &targets);
-
+ if (BKE_constraint_targets_get(con, &targets)) {
for (ct = targets.first; ct; ct = ct->next) {
Object *ob = ct->tar;
@@ -702,9 +699,7 @@ static int pose_select_constraint_target_exec(bContext *C, wmOperator *UNUSED(op
}
}
- if (cti->flush_constraint_targets) {
- cti->flush_constraint_targets(con, &targets, 1);
- }
+ BKE_constraint_targets_flush(con, &targets, 1);
}
}
}
diff --git a/source/blender/editors/curve/editcurve.c b/source/blender/editors/curve/editcurve.c
index 9da9845116d..4c0df48f65b 100644
--- a/source/blender/editors/curve/editcurve.c
+++ b/source/blender/editors/curve/editcurve.c
@@ -4729,6 +4729,7 @@ void CURVE_OT_make_segment(wmOperatorType *ot)
bool ED_curve_editnurb_select_pick(bContext *C,
const int mval[2],
const int dist_px,
+ const bool vert_without_handles,
const struct SelectPick_Params *params)
{
Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C);
@@ -4744,6 +4745,9 @@ bool ED_curve_editnurb_select_pick(bContext *C,
ED_view3d_viewcontext_init(C, &vc, depsgraph);
copy_v2_v2_int(vc.mval, mval);
+ const bool use_handle_select = vert_without_handles &&
+ (vc.v3d->overlay.handle_display != CURVE_HANDLE_NONE);
+
bool found = ED_curve_pick_vert_ex(&vc, 1, dist_px, &nu, &bezt, &bp, &hand, &basact);
if (params->sel_op == SEL_OP_SET) {
@@ -4779,7 +4783,12 @@ bool ED_curve_editnurb_select_pick(bContext *C,
case SEL_OP_ADD: {
if (bezt) {
if (hand == 1) {
- select_beztriple(bezt, SELECT, SELECT, HIDDEN);
+ if (use_handle_select) {
+ bezt->f2 |= SELECT;
+ }
+ else {
+ select_beztriple(bezt, SELECT, SELECT, HIDDEN);
+ }
}
else {
if (hand == 0) {
@@ -4800,7 +4809,12 @@ bool ED_curve_editnurb_select_pick(bContext *C,
case SEL_OP_SUB: {
if (bezt) {
if (hand == 1) {
- select_beztriple(bezt, DESELECT, SELECT, HIDDEN);
+ if (use_handle_select) {
+ bezt->f2 &= ~SELECT;
+ }
+ else {
+ select_beztriple(bezt, DESELECT, SELECT, HIDDEN);
+ }
if (bezt == vert) {
cu->actvert = CU_ACT_NONE;
}
@@ -4824,13 +4838,23 @@ bool ED_curve_editnurb_select_pick(bContext *C,
if (bezt) {
if (hand == 1) {
if (bezt->f2 & SELECT) {
- select_beztriple(bezt, DESELECT, SELECT, HIDDEN);
+ if (use_handle_select) {
+ bezt->f2 &= ~SELECT;
+ }
+ else {
+ select_beztriple(bezt, DESELECT, SELECT, HIDDEN);
+ }
if (bezt == vert) {
cu->actvert = CU_ACT_NONE;
}
}
else {
- select_beztriple(bezt, SELECT, SELECT, HIDDEN);
+ if (use_handle_select) {
+ bezt->f2 |= SELECT;
+ }
+ else {
+ select_beztriple(bezt, SELECT, SELECT, HIDDEN);
+ }
BKE_curve_nurb_vert_active_set(cu, nu, bezt);
}
}
@@ -4861,7 +4885,12 @@ bool ED_curve_editnurb_select_pick(bContext *C,
if (bezt) {
if (hand == 1) {
- select_beztriple(bezt, SELECT, SELECT, HIDDEN);
+ if (use_handle_select) {
+ bezt->f2 |= SELECT;
+ }
+ else {
+ select_beztriple(bezt, SELECT, SELECT, HIDDEN);
+ }
}
else {
if (hand == 0) {
@@ -5568,7 +5597,8 @@ static int add_vertex_invoke(bContext *C, wmOperator *op, const wmEvent *event)
vc.v3d,
SCE_SNAP_MODE_FACE,
&(const struct SnapObjectParams){
- .snap_select = (vc.obedit != NULL) ? SNAP_NOT_ACTIVE : SNAP_ALL,
+ .snap_target_select = (vc.obedit != NULL) ? SCE_SNAP_TARGET_NOT_ACTIVE :
+ SCE_SNAP_TARGET_ALL,
.edit_mode_type = SNAP_GEOM_FINAL,
},
mval,
diff --git a/source/blender/editors/curve/editcurve_paint.c b/source/blender/editors/curve/editcurve_paint.c
index 598779c6ace..6946c09e6f1 100644
--- a/source/blender/editors/curve/editcurve_paint.c
+++ b/source/blender/editors/curve/editcurve_paint.c
@@ -105,7 +105,7 @@ struct CurveDrawData {
} radius;
struct {
- float mouse[2];
+ float mval[2];
/* Used in case we can't calculate the depth. */
float location_world[3];
@@ -463,8 +463,8 @@ static void curve_draw_event_add(wmOperator *op, const wmEvent *event)
}
copy_v3_v3(cdd->prev.location_world, selem->location_world);
- float len_sq = len_squared_v2v2(cdd->prev.mouse, selem->mval);
- copy_v2_v2(cdd->prev.mouse, selem->mval);
+ float len_sq = len_squared_v2v2(cdd->prev.mval, selem->mval);
+ copy_v2_v2(cdd->prev.mval, selem->mval);
if (cdd->sample.use_substeps && cdd->prev.selem) {
const struct StrokeElem selem_target = *selem;
@@ -1165,7 +1165,7 @@ static int curve_draw_modal(bContext *C, wmOperator *op, const wmEvent *event)
else if (ELEM(event->type, MOUSEMOVE, INBETWEEN_MOUSEMOVE)) {
if (cdd->state == CURVE_DRAW_PAINTING) {
const float mval_fl[2] = {UNPACK2(event->mval)};
- if (len_squared_v2v2(mval_fl, cdd->prev.mouse) > square_f(STROKE_SAMPLE_DIST_MIN_PX)) {
+ if (len_squared_v2v2(mval_fl, cdd->prev.mval) > square_f(STROKE_SAMPLE_DIST_MIN_PX)) {
curve_draw_event_add(op, event);
}
}
diff --git a/source/blender/editors/curve/editcurve_pen.c b/source/blender/editors/curve/editcurve_pen.c
index fca850076ae..729ad46877a 100644
--- a/source/blender/editors/curve/editcurve_pen.c
+++ b/source/blender/editors/curve/editcurve_pen.c
@@ -843,7 +843,7 @@ static bool insert_point_to_segment(const ViewContext *vc, const wmEvent *event)
{
Curve *cu = vc->obedit->data;
CutData cd = init_cut_data(event);
- float mval[2] = {UNPACK2(event->mval)};
+ const float mval[2] = {UNPACK2(event->mval)};
const float threshold_dist_px = ED_view3d_select_dist_px() * SEL_DIST_FACTOR;
const bool near_spline = update_cut_data_for_all_nurbs(
vc, BKE_curve_editNurbs_get(cu), mval, threshold_dist_px, &cd);
@@ -985,7 +985,7 @@ static void extrude_vertices_from_selected_endpoints(EditNurb *editnurb,
else {
BPoint *last_bp = nu1->bp + nu1->pntsu - 1;
const bool first_sel = nu1->bp->f1 & SELECT;
- const bool last_sel = last_bp->f1 & SELECT;
+ const bool last_sel = last_bp->f1 & SELECT && nu1->pntsu > 1;
if (first_sel) {
if (last_sel) {
BPoint *new_bp = (BPoint *)MEM_mallocN((nu1->pntsu + 2) * sizeof(BPoint), __func__);
@@ -1134,7 +1134,7 @@ static bool is_spline_nearby(ViewContext *vc,
ListBase *nurbs = BKE_curve_editNurbs_get(cu);
CutData cd = init_cut_data(event);
- float mval[2] = {UNPACK2(event->mval)};
+ const float mval[2] = {UNPACK2(event->mval)};
const bool nearby = update_cut_data_for_all_nurbs(vc, nurbs, mval, sel_dist, &cd);
if (nearby) {
@@ -1655,7 +1655,7 @@ static int curve_pen_modal(bContext *C, wmOperator *op, const wmEvent *event)
else if (ELEM(event->type, LEFTMOUSE)) {
if (ELEM(event->val, KM_RELEASE, KM_DBL_CLICK)) {
if (delete_point && !cpd->new_point && !cpd->dragging) {
- if (ED_curve_editnurb_select_pick(C, event->mval, threshold_dist_px, &params)) {
+ if (ED_curve_editnurb_select_pick(C, event->mval, threshold_dist_px, false, &params)) {
cpd->acted = delete_point_under_mouse(&vc, event);
}
}
@@ -1714,7 +1714,7 @@ static int curve_pen_modal(bContext *C, wmOperator *op, const wmEvent *event)
}
}
else if (select_point) {
- ED_curve_editnurb_select_pick(C, event->mval, threshold_dist_px, &params);
+ ED_curve_editnurb_select_pick(C, event->mval, threshold_dist_px, false, &params);
}
}
diff --git a/source/blender/editors/curves/CMakeLists.txt b/source/blender/editors/curves/CMakeLists.txt
index 1731d224b3e..3c31e8014ff 100644
--- a/source/blender/editors/curves/CMakeLists.txt
+++ b/source/blender/editors/curves/CMakeLists.txt
@@ -7,10 +7,14 @@ set(INC
../../blentranslation
../../depsgraph
../../functions
+ ../../geometry
../../makesdna
../../makesrna
../../windowmanager
../../../../intern/guardedalloc
+
+ # RNA_prototypes.h
+ ${CMAKE_BINARY_DIR}/source/blender/makesrna
)
set(SRC
@@ -24,3 +28,4 @@ set(LIB
)
blender_add_lib(bf_editor_curves "${SRC}" "${INC}" "${INC_SYS}" "${LIB}")
+add_dependencies(bf_editor_curves bf_rna)
diff --git a/source/blender/editors/curves/intern/curves_add.cc b/source/blender/editors/curves/intern/curves_add.cc
index 7d9e663c444..552ef1d96c8 100644
--- a/source/blender/editors/curves/intern/curves_add.cc
+++ b/source/blender/editors/curves/intern/curves_add.cc
@@ -20,7 +20,7 @@ bke::CurvesGeometry primitive_random_sphere(const int curves_size, const int poi
MutableSpan<float3> positions = curves.positions_for_write();
float *radius_data = (float *)CustomData_add_layer_named(
- &curves.point_data, CD_PROP_FLOAT, CD_DEFAULT, nullptr, curves.point_size, "radius");
+ &curves.point_data, CD_PROP_FLOAT, CD_DEFAULT, nullptr, curves.point_num, "radius");
MutableSpan<float> radii{radius_data, curves.points_num()};
for (const int i : offsets.index_range()) {
diff --git a/source/blender/editors/curves/intern/curves_ops.cc b/source/blender/editors/curves/intern/curves_ops.cc
index 7d07c211542..25bcba6cfb3 100644
--- a/source/blender/editors/curves/intern/curves_ops.cc
+++ b/source/blender/editors/curves/intern/curves_ops.cc
@@ -6,20 +6,27 @@
#include <atomic>
+#include "BLI_devirtualize_parameters.hh"
#include "BLI_utildefines.h"
+#include "BLI_vector_set.hh"
#include "ED_curves.h"
#include "ED_object.h"
#include "ED_screen.h"
+#include "ED_select_utils.h"
#include "WM_api.h"
+#include "BKE_attribute_math.hh"
#include "BKE_bvhutils.h"
#include "BKE_context.h"
#include "BKE_curves.hh"
+#include "BKE_geometry_set.hh"
#include "BKE_layer.h"
+#include "BKE_lib_id.h"
#include "BKE_mesh.h"
#include "BKE_mesh_runtime.h"
+#include "BKE_object.h"
#include "BKE_paint.h"
#include "BKE_particle.h"
#include "BKE_report.h"
@@ -32,9 +39,14 @@
#include "DNA_scene_types.h"
#include "DEG_depsgraph.h"
+#include "DEG_depsgraph_query.h"
#include "RNA_access.h"
#include "RNA_define.h"
+#include "RNA_enum_types.h"
+#include "RNA_prototypes.h"
+
+#include "GEO_reverse_uv_sampler.hh"
/**
* The code below uses a suffix naming convention to indicate the coordinate space:
@@ -46,6 +58,41 @@
namespace blender::ed::curves {
+static bool object_has_editable_curves(const Main &bmain, const Object &object)
+{
+ if (object.type != OB_CURVES) {
+ return false;
+ }
+ if (!ELEM(object.mode, OB_MODE_SCULPT_CURVES, OB_MODE_EDIT)) {
+ return false;
+ }
+ if (!BKE_id_is_editable(&bmain, static_cast<const ID *>(object.data))) {
+ return false;
+ }
+ return true;
+}
+
+static VectorSet<Curves *> get_unique_editable_curves(const bContext &C)
+{
+ VectorSet<Curves *> unique_curves;
+
+ const Main &bmain = *CTX_data_main(&C);
+
+ Object *object = CTX_data_active_object(&C);
+ if (object && object_has_editable_curves(bmain, *object)) {
+ unique_curves.add_new(static_cast<Curves *>(object->data));
+ }
+
+ CTX_DATA_BEGIN (&C, Object *, object, selected_objects) {
+ if (object_has_editable_curves(bmain, *object)) {
+ unique_curves.add(static_cast<Curves *>(object->data));
+ }
+ }
+ CTX_DATA_END;
+
+ return unique_curves;
+}
+
using bke::CurvesGeometry;
namespace convert_to_particle_system {
@@ -140,25 +187,20 @@ static void try_convert_single_object(Object &curves_ob,
}
Mesh &surface_me = *static_cast<Mesh *>(surface_ob.data);
+ BVHTreeFromMesh surface_bvh;
+ BKE_bvhtree_from_mesh_get(&surface_bvh, &surface_me, BVHTREE_FROM_LOOPTRI, 2);
+ BLI_SCOPED_DEFER([&]() { free_bvhtree_from_mesh(&surface_bvh); });
+
const Span<float3> positions_cu = curves.positions();
- const VArray<int> looptri_indices = curves.surface_triangle_indices();
const Span<MLoopTri> looptris{BKE_mesh_runtime_looptri_ensure(&surface_me),
BKE_mesh_runtime_looptri_len(&surface_me)};
- /* Find indices of curves that can be transferred to the old hair system. */
- Vector<int> curves_indices_to_transfer;
- for (const int curve_i : curves.curves_range()) {
- const int looptri_i = looptri_indices[curve_i];
- if (looptri_i >= 0 && looptri_i < looptris.size()) {
- curves_indices_to_transfer.append(curve_i);
- }
- else {
- *r_could_not_convert_some_curves = true;
- }
+ if (looptris.is_empty()) {
+ *r_could_not_convert_some_curves = true;
}
- const int hairs_num = curves_indices_to_transfer.size();
- if (hairs_num == 0) {
+ const int hair_num = curves.curves_num();
+ if (hair_num == 0) {
return;
}
@@ -184,15 +226,15 @@ static void try_convert_single_object(Object &curves_ob,
psys_changed_type(&surface_ob, particle_system);
MutableSpan<ParticleData> particles{
- static_cast<ParticleData *>(MEM_calloc_arrayN(hairs_num, sizeof(ParticleData), __func__)),
- hairs_num};
+ static_cast<ParticleData *>(MEM_calloc_arrayN(hair_num, sizeof(ParticleData), __func__)),
+ hair_num};
/* The old hair system still uses #MFace, so make sure those are available on the mesh. */
BKE_mesh_tessface_calc(&surface_me);
- /* Prepare utility data structure to map hair roots to mfaces. */
+ /* Prepare utility data structure to map hair roots to #MFace's. */
const Span<int> mface_to_poly_map{
- static_cast<int *>(CustomData_get_layer(&surface_me.fdata, CD_ORIGINDEX)),
+ static_cast<const int *>(CustomData_get_layer(&surface_me.fdata, CD_ORIGINDEX)),
surface_me.totface};
Array<Vector<int>> poly_to_mface_map(surface_me.totpoly);
for (const int mface_i : mface_to_poly_map.index_range()) {
@@ -206,17 +248,23 @@ static void try_convert_single_object(Object &curves_ob,
const float4x4 world_to_surface_mat = surface_to_world_mat.inverted();
const float4x4 curves_to_surface_mat = world_to_surface_mat * curves_to_world_mat;
- for (const int new_hair_i : curves_indices_to_transfer.index_range()) {
- const int curve_i = curves_indices_to_transfer[new_hair_i];
+ for (const int new_hair_i : IndexRange(hair_num)) {
+ const int curve_i = new_hair_i;
const IndexRange points = curves.points_for_curve(curve_i);
- const int looptri_i = looptri_indices[curve_i];
- const MLoopTri &looptri = looptris[looptri_i];
- const int poly_i = looptri.poly;
-
const float3 &root_pos_cu = positions_cu[points.first()];
const float3 root_pos_su = curves_to_surface_mat * root_pos_cu;
+ BVHTreeNearest nearest;
+ nearest.dist_sq = FLT_MAX;
+ BLI_bvhtree_find_nearest(
+ surface_bvh.tree, root_pos_su, &nearest, surface_bvh.nearest_callback, &surface_bvh);
+ BLI_assert(nearest.index >= 0);
+
+ const int looptri_i = nearest.index;
+ const MLoopTri &looptri = looptris[looptri_i];
+ const int poly_i = looptri.poly;
+
const int mface_i = find_mface_for_root_position(
surface_me, poly_to_mface_map[poly_i], root_pos_su);
const MFace &mface = surface_me.mface[mface_i];
@@ -315,6 +363,140 @@ static void CURVES_OT_convert_to_particle_system(wmOperatorType *ot)
ot->flag = OPTYPE_UNDO | OPTYPE_REGISTER;
}
+namespace convert_from_particle_system {
+
+static bke::CurvesGeometry particles_to_curves(Object &object, ParticleSystem &psys)
+{
+ ParticleSettings &settings = *psys.part;
+ if (psys.part->type != PART_HAIR) {
+ return {};
+ }
+
+ const bool transfer_parents = (settings.draw & PART_DRAW_PARENT) || settings.childtype == 0;
+
+ const Span<ParticleCacheKey *> parents_cache{psys.pathcache, psys.totcached};
+ const Span<ParticleCacheKey *> children_cache{psys.childcache, psys.totchildcache};
+
+ int points_num = 0;
+ Vector<int> curve_offsets;
+ Vector<int> parents_to_transfer;
+ Vector<int> children_to_transfer;
+ if (transfer_parents) {
+ for (const int parent_i : parents_cache.index_range()) {
+ const int segments = parents_cache[parent_i]->segments;
+ if (segments <= 0) {
+ continue;
+ }
+ parents_to_transfer.append(parent_i);
+ curve_offsets.append(points_num);
+ points_num += segments + 1;
+ }
+ }
+ for (const int child_i : children_cache.index_range()) {
+ const int segments = children_cache[child_i]->segments;
+ if (segments <= 0) {
+ continue;
+ }
+ children_to_transfer.append(child_i);
+ curve_offsets.append(points_num);
+ points_num += segments + 1;
+ }
+ const int curves_num = parents_to_transfer.size() + children_to_transfer.size();
+ curve_offsets.append(points_num);
+ BLI_assert(curve_offsets.size() == curves_num + 1);
+ bke::CurvesGeometry curves(points_num, curves_num);
+ curves.offsets_for_write().copy_from(curve_offsets);
+
+ const float4x4 object_to_world_mat = object.obmat;
+ const float4x4 world_to_object_mat = object_to_world_mat.inverted();
+
+ MutableSpan<float3> positions = curves.positions_for_write();
+
+ const auto copy_hair_to_curves = [&](const Span<ParticleCacheKey *> hair_cache,
+ const Span<int> indices_to_transfer,
+ const int curve_index_offset) {
+ threading::parallel_for(indices_to_transfer.index_range(), 256, [&](const IndexRange range) {
+ for (const int i : range) {
+ const int hair_i = indices_to_transfer[i];
+ const int curve_i = i + curve_index_offset;
+ const IndexRange points = curves.points_for_curve(curve_i);
+ const Span<ParticleCacheKey> keys{hair_cache[hair_i], points.size()};
+ for (const int key_i : keys.index_range()) {
+ const float3 key_pos_wo = keys[key_i].co;
+ positions[points[key_i]] = world_to_object_mat * key_pos_wo;
+ }
+ }
+ });
+ };
+
+ if (transfer_parents) {
+ copy_hair_to_curves(parents_cache, parents_to_transfer, 0);
+ }
+ copy_hair_to_curves(children_cache, children_to_transfer, parents_to_transfer.size());
+
+ curves.update_curve_types();
+ curves.tag_topology_changed();
+ return curves;
+}
+
+static int curves_convert_from_particle_system_exec(bContext *C, wmOperator *UNUSED(op))
+{
+ Main &bmain = *CTX_data_main(C);
+ ViewLayer &view_layer = *CTX_data_view_layer(C);
+ Depsgraph &depsgraph = *CTX_data_depsgraph_pointer(C);
+ Object *ob_from_orig = ED_object_active_context(C);
+ ParticleSystem *psys_orig = static_cast<ParticleSystem *>(
+ CTX_data_pointer_get_type(C, "particle_system", &RNA_ParticleSystem).data);
+ if (psys_orig == nullptr) {
+ psys_orig = psys_get_current(ob_from_orig);
+ }
+ if (psys_orig == nullptr) {
+ return OPERATOR_CANCELLED;
+ }
+ Object *ob_from_eval = DEG_get_evaluated_object(&depsgraph, ob_from_orig);
+ ParticleSystem *psys_eval = nullptr;
+ LISTBASE_FOREACH (ModifierData *, md, &ob_from_eval->modifiers) {
+ if (md->type != eModifierType_ParticleSystem) {
+ continue;
+ }
+ ParticleSystemModifierData *psmd = reinterpret_cast<ParticleSystemModifierData *>(md);
+ if (!STREQ(psmd->psys->name, psys_orig->name)) {
+ continue;
+ }
+ psys_eval = psmd->psys;
+ }
+
+ Object *ob_new = BKE_object_add(&bmain, &view_layer, OB_CURVES, psys_eval->name);
+ ob_new->dtx |= OB_DRAWBOUNDOX; /* TODO: Remove once there is actual drawing. */
+ Curves *curves_id = static_cast<Curves *>(ob_new->data);
+ BKE_object_apply_mat4(ob_new, ob_from_orig->obmat, true, false);
+ bke::CurvesGeometry::wrap(curves_id->geometry) = particles_to_curves(*ob_from_eval, *psys_eval);
+
+ DEG_relations_tag_update(&bmain);
+ WM_main_add_notifier(NC_OBJECT | ND_DRAW, nullptr);
+
+ return OPERATOR_FINISHED;
+}
+
+static bool curves_convert_from_particle_system_poll(bContext *C)
+{
+ return ED_object_active_context(C) != nullptr;
+}
+
+} // namespace convert_from_particle_system
+
+static void CURVES_OT_convert_from_particle_system(wmOperatorType *ot)
+{
+ ot->name = "Convert Particle System to Curves";
+ ot->idname = "CURVES_OT_convert_from_particle_system";
+ ot->description = "Add a new curves object based on the current state of the particle system";
+
+ ot->poll = convert_from_particle_system::curves_convert_from_particle_system_poll;
+ ot->exec = convert_from_particle_system::curves_convert_from_particle_system_exec;
+
+ ot->flag = OPTYPE_UNDO | OPTYPE_REGISTER;
+}
+
namespace snap_curves_to_surface {
enum class AttachMode {
@@ -342,7 +524,7 @@ static int snap_curves_to_surface_exec(bContext *C, wmOperator *op)
{
const AttachMode attach_mode = static_cast<AttachMode>(RNA_enum_get(op->ptr, "attach_mode"));
- std::atomic<bool> found_invalid_looptri_index = false;
+ std::atomic<bool> found_invalid_uv = false;
CTX_DATA_BEGIN (C, Object *, curves_ob, selected_objects) {
if (curves_ob->type != OB_CURVES) {
@@ -359,9 +541,19 @@ static int snap_curves_to_surface_exec(bContext *C, wmOperator *op)
}
Mesh &surface_mesh = *static_cast<Mesh *>(surface_ob.data);
+ MeshComponent surface_mesh_component;
+ surface_mesh_component.replace(&surface_mesh, GeometryOwnershipType::ReadOnly);
+
+ VArray_Span<float2> surface_uv_map;
+ if (curves_id.surface_uv_map != nullptr) {
+ surface_uv_map = surface_mesh_component
+ .attribute_try_get_for_read(
+ curves_id.surface_uv_map, ATTR_DOMAIN_CORNER, CD_PROP_FLOAT2)
+ .typed<float2>();
+ }
+
MutableSpan<float3> positions_cu = curves.positions_for_write();
- MutableSpan<int> surface_triangle_indices = curves.surface_triangle_indices_for_write();
- MutableSpan<float2> surface_triangle_coords = curves.surface_triangle_coords_for_write();
+ MutableSpan<float2> surface_uv_coords = curves.surface_uv_coords_for_write();
const Span<MLoopTri> surface_looptris = {BKE_mesh_runtime_looptri_ensure(&surface_mesh),
BKE_mesh_runtime_looptri_len(&surface_mesh)};
@@ -407,36 +599,51 @@ static int snap_curves_to_surface_exec(bContext *C, wmOperator *op)
pos_cu += pos_diff_cu;
}
- surface_triangle_indices[curve_i] = looptri_index;
-
- const MLoopTri &looptri = surface_looptris[looptri_index];
- const float3 &p0_su = surface_mesh.mvert[surface_mesh.mloop[looptri.tri[0]].v].co;
- const float3 &p1_su = surface_mesh.mvert[surface_mesh.mloop[looptri.tri[1]].v].co;
- const float3 &p2_su = surface_mesh.mvert[surface_mesh.mloop[looptri.tri[2]].v].co;
- float3 bary_coords;
- interp_weights_tri_v3(bary_coords, p0_su, p1_su, p2_su, new_first_point_pos_su);
- surface_triangle_coords[curve_i] = bke::curves::encode_surface_bary_coord(bary_coords);
+ if (!surface_uv_map.is_empty()) {
+ const MLoopTri &looptri = surface_looptris[looptri_index];
+ const int corner0 = looptri.tri[0];
+ const int corner1 = looptri.tri[1];
+ const int corner2 = looptri.tri[2];
+ const float2 &uv0 = surface_uv_map[corner0];
+ const float2 &uv1 = surface_uv_map[corner1];
+ const float2 &uv2 = surface_uv_map[corner2];
+ const float3 &p0_su = surface_mesh.mvert[surface_mesh.mloop[corner0].v].co;
+ const float3 &p1_su = surface_mesh.mvert[surface_mesh.mloop[corner1].v].co;
+ const float3 &p2_su = surface_mesh.mvert[surface_mesh.mloop[corner2].v].co;
+ float3 bary_coords;
+ interp_weights_tri_v3(bary_coords, p0_su, p1_su, p2_su, new_first_point_pos_su);
+ const float2 uv = attribute_math::mix3(bary_coords, uv0, uv1, uv2);
+ surface_uv_coords[curve_i] = uv;
+ }
}
});
break;
}
case AttachMode::Deform: {
+ if (surface_uv_map.is_empty()) {
+ BKE_report(op->reports,
+ RPT_ERROR,
+ "Curves do not have attachment information that can be used for deformation");
+ break;
+ }
+ using geometry::ReverseUVSampler;
+ ReverseUVSampler reverse_uv_sampler{surface_uv_map, surface_looptris};
+
threading::parallel_for(curves.curves_range(), 256, [&](const IndexRange curves_range) {
for (const int curve_i : curves_range) {
const IndexRange points = curves.points_for_curve(curve_i);
const int first_point_i = points.first();
const float3 old_first_point_pos_cu = positions_cu[first_point_i];
- const int looptri_index = surface_triangle_indices[curve_i];
- if (!surface_looptris.index_range().contains(looptri_index)) {
- found_invalid_looptri_index = true;
+ const float2 uv = surface_uv_coords[curve_i];
+ ReverseUVSampler::Result lookup_result = reverse_uv_sampler.sample(uv);
+ if (lookup_result.type != ReverseUVSampler::ResultType::Ok) {
+ found_invalid_uv = true;
continue;
}
- const MLoopTri &looptri = surface_looptris[looptri_index];
-
- const float3 bary_coords = bke::curves::decode_surface_bary_coord(
- surface_triangle_coords[curve_i]);
+ const MLoopTri &looptri = *lookup_result.looptri;
+ const float3 &bary_coords = lookup_result.bary_weights;
const float3 &p0_su = surface_mesh.mvert[surface_mesh.mloop[looptri.tri[0]].v].co;
const float3 &p1_su = surface_mesh.mvert[surface_mesh.mloop[looptri.tri[1]].v].co;
@@ -460,7 +667,7 @@ static int snap_curves_to_surface_exec(bContext *C, wmOperator *op)
}
CTX_DATA_END;
- if (found_invalid_looptri_index) {
+ if (found_invalid_uv) {
BKE_report(op->reports, RPT_INFO, "Could not snap some curves to the surface");
}
@@ -508,11 +715,231 @@ static void CURVES_OT_snap_curves_to_surface(wmOperatorType *ot)
"How to find the point on the surface to attach to");
}
+static bool selection_poll(bContext *C)
+{
+ const Object *object = CTX_data_active_object(C);
+ if (object == nullptr) {
+ return false;
+ }
+ if (object->type != OB_CURVES) {
+ return false;
+ }
+ if (!BKE_id_is_editable(CTX_data_main(C), static_cast<const ID *>(object->data))) {
+ return false;
+ }
+ return true;
+}
+
+namespace set_selection_domain {
+
+static int curves_set_selection_domain_exec(bContext *C, wmOperator *op)
+{
+ const eAttrDomain domain = eAttrDomain(RNA_enum_get(op->ptr, "domain"));
+
+ for (Curves *curves_id : get_unique_editable_curves(*C)) {
+ if (curves_id->selection_domain == domain && (curves_id->flag & CV_SCULPT_SELECTION_ENABLED)) {
+ continue;
+ }
+
+ const eAttrDomain old_domain = eAttrDomain(curves_id->selection_domain);
+ curves_id->selection_domain = domain;
+ curves_id->flag |= CV_SCULPT_SELECTION_ENABLED;
+
+ CurveComponent component;
+ component.replace(curves_id, GeometryOwnershipType::Editable);
+ CurvesGeometry &curves = CurvesGeometry::wrap(curves_id->geometry);
+
+ if (old_domain == ATTR_DOMAIN_POINT && domain == ATTR_DOMAIN_CURVE) {
+ VArray<float> curve_selection = curves.adapt_domain(
+ curves.selection_point_float(), ATTR_DOMAIN_POINT, ATTR_DOMAIN_CURVE);
+ curve_selection.materialize(curves.selection_curve_float_for_write());
+ component.attribute_try_delete(".selection_point_float");
+ }
+ else if (old_domain == ATTR_DOMAIN_CURVE && domain == ATTR_DOMAIN_POINT) {
+ VArray<float> point_selection = curves.adapt_domain(
+ curves.selection_curve_float(), ATTR_DOMAIN_CURVE, ATTR_DOMAIN_POINT);
+ point_selection.materialize(curves.selection_point_float_for_write());
+ component.attribute_try_delete(".selection_curve_float");
+ }
+
+ /* Use #ID_RECALC_GEOMETRY instead of #ID_RECALC_SELECT because it is handled as a generic
+ * attribute for now. */
+ DEG_id_tag_update(&curves_id->id, ID_RECALC_GEOMETRY);
+ WM_event_add_notifier(C, NC_GEOM | ND_DATA, curves_id);
+ }
+
+ WM_main_add_notifier(NC_SPACE | ND_SPACE_VIEW3D, nullptr);
+
+ return OPERATOR_FINISHED;
+}
+
+} // namespace set_selection_domain
+
+static void CURVES_OT_set_selection_domain(wmOperatorType *ot)
+{
+ PropertyRNA *prop;
+
+ ot->name = "Set Select Mode";
+ ot->idname = __func__;
+ ot->description = "Change the mode used for selection masking in curves sculpt mode";
+
+ ot->exec = set_selection_domain::curves_set_selection_domain_exec;
+ ot->poll = selection_poll;
+
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+
+ ot->prop = prop = RNA_def_enum(
+ ot->srna, "domain", rna_enum_attribute_curves_domain_items, 0, "Domain", "");
+ RNA_def_property_flag(prop, (PropertyFlag)(PROP_HIDDEN | PROP_SKIP_SAVE));
+}
+
+namespace disable_selection {
+
+static int curves_disable_selection_exec(bContext *C, wmOperator *UNUSED(op))
+{
+ for (Curves *curves_id : get_unique_editable_curves(*C)) {
+ curves_id->flag &= ~CV_SCULPT_SELECTION_ENABLED;
+
+ /* Use #ID_RECALC_GEOMETRY instead of #ID_RECALC_SELECT because it is handled as a generic
+ * attribute for now. */
+ DEG_id_tag_update(&curves_id->id, ID_RECALC_GEOMETRY);
+ WM_event_add_notifier(C, NC_GEOM | ND_DATA, curves_id);
+ }
+
+ WM_main_add_notifier(NC_SPACE | ND_SPACE_VIEW3D, nullptr);
+
+ return OPERATOR_FINISHED;
+}
+
+} // namespace disable_selection
+
+static void CURVES_OT_disable_selection(wmOperatorType *ot)
+{
+ ot->name = "Disable Selection";
+ ot->idname = __func__;
+ ot->description = "Disable the drawing of influence of selection in sculpt mode";
+
+ ot->exec = disable_selection::curves_disable_selection_exec;
+ ot->poll = selection_poll;
+
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+}
+
+namespace select_all {
+
+static bool varray_contains_nonzero(const VArray<float> &data)
+{
+ bool contains_nonzero = false;
+ devirtualize_varray(data, [&](const auto array) {
+ for (const int i : data.index_range()) {
+ if (array[i] != 0.0f) {
+ contains_nonzero = true;
+ break;
+ }
+ }
+ });
+ return contains_nonzero;
+}
+
+static bool any_point_selected(const CurvesGeometry &curves)
+{
+ return varray_contains_nonzero(curves.selection_point_float());
+}
+
+static bool any_point_selected(const Span<Curves *> curves_ids)
+{
+ for (const Curves *curves_id : curves_ids) {
+ if (any_point_selected(CurvesGeometry::wrap(curves_id->geometry))) {
+ return true;
+ }
+ }
+ return false;
+}
+
+static void invert_selection(MutableSpan<float> selection)
+{
+ threading::parallel_for(selection.index_range(), 2048, [&](IndexRange range) {
+ for (const int i : range) {
+ selection[i] = 1.0f - selection[i];
+ }
+ });
+}
+
+static int select_all_exec(bContext *C, wmOperator *op)
+{
+ int action = RNA_enum_get(op->ptr, "action");
+
+ VectorSet<Curves *> unique_curves = get_unique_editable_curves(*C);
+
+ if (action == SEL_TOGGLE) {
+ action = any_point_selected(unique_curves) ? SEL_DESELECT : SEL_SELECT;
+ }
+
+ for (Curves *curves_id : unique_curves) {
+ if (action == SEL_SELECT) {
+ /* The optimization to avoid storing the selection when everything is selected causes too
+ * many problems at the moment, since there is no proper visualization yet. Keep the code but
+ * disable it for now. */
+#if 0
+ CurveComponent component;
+ component.replace(curves_id, GeometryOwnershipType::Editable);
+ component.attribute_try_delete(".selection_point_float");
+ component.attribute_try_delete(".selection_curve_float");
+#else
+ CurvesGeometry &curves = CurvesGeometry::wrap(curves_id->geometry);
+ MutableSpan<float> selection = curves_id->selection_domain == ATTR_DOMAIN_POINT ?
+ curves.selection_point_float_for_write() :
+ curves.selection_curve_float_for_write();
+ selection.fill(1.0f);
+#endif
+ }
+ else {
+ CurvesGeometry &curves = CurvesGeometry::wrap(curves_id->geometry);
+ MutableSpan<float> selection = curves_id->selection_domain == ATTR_DOMAIN_POINT ?
+ curves.selection_point_float_for_write() :
+ curves.selection_curve_float_for_write();
+ if (action == SEL_DESELECT) {
+ selection.fill(0.0f);
+ }
+ else if (action == SEL_INVERT) {
+ invert_selection(selection);
+ }
+ }
+
+ /* Use #ID_RECALC_GEOMETRY instead of #ID_RECALC_SELECT because it is handled as a generic
+ * attribute for now. */
+ DEG_id_tag_update(&curves_id->id, ID_RECALC_GEOMETRY);
+ WM_event_add_notifier(C, NC_GEOM | ND_DATA, curves_id);
+ }
+
+ return OPERATOR_FINISHED;
+}
+
+} // namespace select_all
+
+static void SCULPT_CURVES_OT_select_all(wmOperatorType *ot)
+{
+ ot->name = "(De)select All";
+ ot->idname = __func__;
+ ot->description = "(De)select all control points";
+
+ ot->exec = select_all::select_all_exec;
+ ot->poll = selection_poll;
+
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+
+ WM_operator_properties_select_all(ot);
+}
+
} // namespace blender::ed::curves
void ED_operatortypes_curves()
{
using namespace blender::ed::curves;
WM_operatortype_append(CURVES_OT_convert_to_particle_system);
+ WM_operatortype_append(CURVES_OT_convert_from_particle_system);
WM_operatortype_append(CURVES_OT_snap_curves_to_surface);
+ WM_operatortype_append(CURVES_OT_set_selection_domain);
+ WM_operatortype_append(SCULPT_CURVES_OT_select_all);
+ WM_operatortype_append(CURVES_OT_disable_selection);
}
diff --git a/source/blender/editors/datafiles/CMakeLists.txt b/source/blender/editors/datafiles/CMakeLists.txt
index d8ecb2c5ae0..9da2c4819a3 100644
--- a/source/blender/editors/datafiles/CMakeLists.txt
+++ b/source/blender/editors/datafiles/CMakeLists.txt
@@ -776,14 +776,19 @@ set_property(GLOBAL PROPERTY ICON_GEOM_NAMES
ops.curves.sculpt_comb
ops.curves.sculpt_cut
ops.curves.sculpt_delete
+ ops.curves.sculpt_density
ops.curves.sculpt_grow_shrink
+ ops.curves.sculpt_pinch
ops.curves.sculpt_puff
+ ops.curves.sculpt_slide
+ ops.curves.sculpt_smooth
ops.curves.sculpt_snake_hook
ops.generic.cursor
ops.generic.select
ops.generic.select_box
ops.generic.select_circle
ops.generic.select_lasso
+ ops.generic.select_paint
ops.gpencil.draw
ops.gpencil.draw.eraser
ops.gpencil.draw.line
@@ -928,6 +933,7 @@ if(WITH_BLENDER)
data_to_c_simple(../../../../release/datafiles/brushicons/mask.png SRC)
data_to_c_simple(../../../../release/datafiles/brushicons/mix.png SRC)
data_to_c_simple(../../../../release/datafiles/brushicons/nudge.png SRC)
+ data_to_c_simple(../../../../release/datafiles/brushicons/paint_select.png SRC)
data_to_c_simple(../../../../release/datafiles/brushicons/pinch.png SRC)
data_to_c_simple(../../../../release/datafiles/brushicons/scrape.png SRC)
data_to_c_simple(../../../../release/datafiles/brushicons/smear.png SRC)
@@ -965,6 +971,19 @@ if(WITH_BLENDER)
data_to_c_simple(../../../../release/datafiles/brushicons/gp_brush_erase_hard.png SRC)
data_to_c_simple(../../../../release/datafiles/brushicons/gp_brush_erase_stroke.png SRC)
+ # curve sculpt
+ data_to_c_simple(../../../../release/datafiles/brushicons/curves_sculpt_add.png SRC)
+ data_to_c_simple(../../../../release/datafiles/brushicons/curves_sculpt_comb.png SRC)
+ data_to_c_simple(../../../../release/datafiles/brushicons/curves_sculpt_cut.png SRC)
+ data_to_c_simple(../../../../release/datafiles/brushicons/curves_sculpt_delete.png SRC)
+ data_to_c_simple(../../../../release/datafiles/brushicons/curves_sculpt_density.png SRC)
+ data_to_c_simple(../../../../release/datafiles/brushicons/curves_sculpt_grow_shrink.png SRC)
+ data_to_c_simple(../../../../release/datafiles/brushicons/curves_sculpt_pinch.png SRC)
+ data_to_c_simple(../../../../release/datafiles/brushicons/curves_sculpt_puff.png SRC)
+ data_to_c_simple(../../../../release/datafiles/brushicons/curves_sculpt_slide.png SRC)
+ data_to_c_simple(../../../../release/datafiles/brushicons/curves_sculpt_smooth.png SRC)
+ data_to_c_simple(../../../../release/datafiles/brushicons/curves_sculpt_snake_hook.png SRC)
+
endif()
data_to_c_simple(../../../../release/datafiles/startup.blend SRC)
diff --git a/source/blender/editors/geometry/geometry_attributes.cc b/source/blender/editors/geometry/geometry_attributes.cc
index cfc158b117f..c7e782b7b89 100644
--- a/source/blender/editors/geometry/geometry_attributes.cc
+++ b/source/blender/editors/geometry/geometry_attributes.cc
@@ -33,6 +33,7 @@
#include "UI_interface.h"
#include "UI_resources.h"
+#include "ED_geometry.h"
#include "ED_object.h"
#include "geometry_intern.hh"
@@ -43,9 +44,9 @@ namespace blender::ed::geometry {
static bool geometry_attributes_poll(bContext *C)
{
- Object *ob = ED_object_context(C);
- Main *bmain = CTX_data_main(C);
- ID *data = (ob) ? static_cast<ID *>(ob->data) : nullptr;
+ const Object *ob = ED_object_context(C);
+ const Main *bmain = CTX_data_main(C);
+ const ID *data = (ob) ? static_cast<ID *>(ob->data) : nullptr;
return (ob && BKE_id_is_editable(bmain, &ob->id) && data && BKE_id_is_editable(bmain, data)) &&
BKE_id_attributes_supported(data);
}
@@ -89,8 +90,8 @@ static int geometry_attribute_add_exec(bContext *C, wmOperator *op)
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");
+ eCustomDataType type = (eCustomDataType)RNA_enum_get(op->ptr, "data_type");
+ eAttrDomain domain = (eAttrDomain)RNA_enum_get(op->ptr, "domain");
CustomDataLayer *layer = BKE_id_attribute_new(id, name, type, domain, op->reports);
if (layer == nullptr) {
@@ -105,7 +106,7 @@ static int geometry_attribute_add_exec(bContext *C, wmOperator *op)
return OPERATOR_FINISHED;
}
-static void next_color_attribute(struct ID *id, CustomDataLayer *layer, bool is_render)
+static void next_color_attribute(ID *id, CustomDataLayer *layer, bool is_render)
{
int index = BKE_id_attribute_to_index(id, layer, ATTR_DOMAIN_MASK_COLOR, CD_MASK_COLOR_ALL);
@@ -128,7 +129,7 @@ static void next_color_attribute(struct ID *id, CustomDataLayer *layer, bool is_
}
}
-static void next_color_attributes(struct ID *id, CustomDataLayer *layer)
+static void next_color_attributes(ID *id, CustomDataLayer *layer)
{
next_color_attribute(id, layer, false); /* active */
next_color_attribute(id, layer, true); /* render */
@@ -181,7 +182,7 @@ static int geometry_attribute_remove_exec(bContext *C, wmOperator *op)
next_color_attributes(id, layer);
- if (!BKE_id_attribute_remove(id, layer, op->reports)) {
+ if (!BKE_id_attribute_remove(id, layer->name, op->reports)) {
return OPERATOR_CANCELLED;
}
@@ -218,8 +219,8 @@ static int geometry_color_attribute_add_exec(bContext *C, wmOperator *op)
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");
+ eCustomDataType type = (eCustomDataType)RNA_enum_get(op->ptr, "data_type");
+ eAttrDomain domain = (eAttrDomain)RNA_enum_get(op->ptr, "domain");
CustomDataLayer *layer = BKE_id_attribute_new(id, name, type, domain, op->reports);
float color[4];
@@ -260,8 +261,11 @@ static bool geometry_attribute_convert_poll(bContext *C)
if (GS(data->name) != ID_ME) {
return false;
}
- CustomDataLayer *layer = BKE_id_attributes_active_get(data);
- if (layer == nullptr) {
+ if (CTX_data_edit_object(C) != nullptr) {
+ CTX_wm_operator_poll_msg_set(C, "Operation is not allowed in edit mode");
+ return false;
+ }
+ if (BKE_id_attributes_active_get(data) == nullptr) {
return false;
}
return true;
@@ -288,9 +292,8 @@ static int geometry_attribute_convert_exec(bContext *C, wmOperator *op)
* 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>(
+ const eAttrDomain dst_domain = static_cast<eAttrDomain>(RNA_enum_get(op->ptr, "domain"));
+ const eCustomDataType dst_type = static_cast<eCustomDataType>(
RNA_enum_get(op->ptr, "data_type"));
if (ELEM(dst_type, CD_PROP_STRING)) {
@@ -402,7 +405,7 @@ void GEOMETRY_OT_color_attribute_add(wmOperatorType *ot)
static float default_color[4] = {0.0f, 0.0f, 0.0f, 1.0f};
prop = RNA_def_float_color(
- ot->srna, "color", 4, NULL, 0.0f, FLT_MAX, "Color", "Default fill color", 0.0f, 1.0f);
+ ot->srna, "color", 4, nullptr, 0.0f, FLT_MAX, "Color", "Default fill color", 0.0f, 1.0f);
RNA_def_property_subtype(prop, PROP_COLOR_GAMMA);
RNA_def_property_float_array_default(prop, default_color);
}
@@ -465,7 +468,7 @@ static int geometry_color_attribute_remove_exec(bContext *C, wmOperator *op)
next_color_attributes(id, layer);
- if (!BKE_id_attribute_remove(id, layer, op->reports)) {
+ if (!BKE_id_attribute_remove(id, layer->name, op->reports)) {
return OPERATOR_CANCELLED;
}
@@ -495,6 +498,7 @@ static bool geometry_color_attributes_remove_poll(bContext *C)
return false;
}
+
void GEOMETRY_OT_color_attribute_remove(wmOperatorType *ot)
{
/* identifiers */
@@ -510,6 +514,64 @@ void GEOMETRY_OT_color_attribute_remove(wmOperatorType *ot)
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
}
+static int geometry_color_attribute_duplicate_exec(bContext *C, wmOperator *op)
+{
+ Object *ob = ED_object_context(C);
+ ID *id = static_cast<ID *>(ob->data);
+ const CustomDataLayer *layer = BKE_id_attributes_active_color_get(id);
+
+ if (layer == nullptr) {
+ return OPERATOR_CANCELLED;
+ }
+
+ CustomDataLayer *new_layer = BKE_id_attribute_duplicate(id, layer->name, op->reports);
+ if (new_layer == nullptr) {
+ return OPERATOR_CANCELLED;
+ }
+
+ BKE_id_attributes_active_color_set(id, new_layer);
+
+ DEG_id_tag_update(id, ID_RECALC_GEOMETRY);
+ WM_main_add_notifier(NC_GEOM | ND_DATA, id);
+
+ return OPERATOR_FINISHED;
+}
+
+static bool geometry_color_attributes_duplicate_poll(bContext *C)
+{
+ if (!geometry_attributes_poll(C)) {
+ return false;
+ }
+ if (CTX_data_edit_object(C) != nullptr) {
+ CTX_wm_operator_poll_msg_set(C, "Operation is not allowed in edit mode");
+ return false;
+ }
+
+ Object *ob = ED_object_context(C);
+ ID *data = ob ? static_cast<ID *>(ob->data) : nullptr;
+
+ if (BKE_id_attributes_active_color_get(data) != nullptr) {
+ return true;
+ }
+
+ return false;
+}
+
+void GEOMETRY_OT_color_attribute_duplicate(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Duplicate Color Attribute";
+ ot->description = "Duplicate color attribute";
+ ot->idname = "GEOMETRY_OT_color_attribute_duplicate";
+
+ /* api callbacks */
+ ot->exec = geometry_color_attribute_duplicate_exec;
+ ot->poll = geometry_color_attributes_duplicate_poll;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+}
+
static void geometry_attribute_convert_ui(bContext *UNUSED(C), wmOperator *op)
{
uiLayout *layout = op->layout;
@@ -572,3 +634,38 @@ void GEOMETRY_OT_attribute_convert(wmOperatorType *ot)
}
} // namespace blender::ed::geometry
+
+using blender::CPPType;
+using blender::GVArray;
+
+bool ED_geometry_attribute_convert(Mesh *mesh,
+ const char *layer_name,
+ eCustomDataType old_type,
+ eAttrDomain old_domain,
+ eCustomDataType new_type,
+ eAttrDomain new_domain)
+{
+ CustomDataLayer *layer = BKE_id_attribute_find(&mesh->id, layer_name, old_type, old_domain);
+ const std::string name = layer->name;
+
+ if (!layer) {
+ return false;
+ }
+
+ MeshComponent mesh_component;
+ mesh_component.replace(mesh, GeometryOwnershipType::Editable);
+ GVArray src_varray = mesh_component.attribute_get_for_read(name, new_domain, new_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, new_domain, new_type, AttributeInitMove(new_data));
+
+ int *active_index = BKE_id_attributes_active_index_p(&mesh->id);
+ if (*active_index > 0) {
+ *active_index -= 1;
+ }
+
+ return true;
+}
diff --git a/source/blender/editors/geometry/geometry_intern.hh b/source/blender/editors/geometry/geometry_intern.hh
index bbcb682d6bf..a1000a5d01f 100644
--- a/source/blender/editors/geometry/geometry_intern.hh
+++ b/source/blender/editors/geometry/geometry_intern.hh
@@ -17,6 +17,7 @@ void GEOMETRY_OT_attribute_remove(struct wmOperatorType *ot);
void GEOMETRY_OT_color_attribute_add(struct wmOperatorType *ot);
void GEOMETRY_OT_color_attribute_remove(struct wmOperatorType *ot);
void GEOMETRY_OT_color_attribute_render_set(struct wmOperatorType *ot);
+void GEOMETRY_OT_color_attribute_duplicate(struct wmOperatorType *ot);
void GEOMETRY_OT_attribute_convert(struct wmOperatorType *ot);
} // namespace blender::ed::geometry
diff --git a/source/blender/editors/geometry/geometry_ops.cc b/source/blender/editors/geometry/geometry_ops.cc
index 23f6e6f29f4..acac757ecf1 100644
--- a/source/blender/editors/geometry/geometry_ops.cc
+++ b/source/blender/editors/geometry/geometry_ops.cc
@@ -22,5 +22,6 @@ void ED_operatortypes_geometry(void)
WM_operatortype_append(GEOMETRY_OT_color_attribute_add);
WM_operatortype_append(GEOMETRY_OT_color_attribute_remove);
WM_operatortype_append(GEOMETRY_OT_color_attribute_render_set);
+ WM_operatortype_append(GEOMETRY_OT_color_attribute_duplicate);
WM_operatortype_append(GEOMETRY_OT_attribute_convert);
}
diff --git a/source/blender/editors/gizmo_library/geometry/geom_arrow_gizmo.c b/source/blender/editors/gizmo_library/geometry/geom_arrow_gizmo.c
index 5b514e02099..429bf39234f 100644
--- a/source/blender/editors/gizmo_library/geometry/geom_arrow_gizmo.c
+++ b/source/blender/editors/gizmo_library/geometry/geom_arrow_gizmo.c
@@ -7,6 +7,8 @@
#include "../gizmo_geometry.h"
+/* The numerical values in the `verts` array are used in arrow3d_gizmo.c
+ * If you change this mesh geometry, update the selection code also. */
static float verts[][3] = {
{-0.000000, 0.012320, 0.000000}, {-0.000000, 0.012320, 0.974306},
{0.008711, 0.008711, 0.000000}, {0.008711, 0.008711, 0.974306},
diff --git a/source/blender/editors/gizmo_library/gizmo_draw_utils.c b/source/blender/editors/gizmo_library/gizmo_draw_utils.c
index c6303c197e7..178a2b52b62 100644
--- a/source/blender/editors/gizmo_library/gizmo_draw_utils.c
+++ b/source/blender/editors/gizmo_library/gizmo_draw_utils.c
@@ -95,7 +95,7 @@ void wm_gizmo_vec_draw(
immEnd();
}
else if (primitive_type == GPU_PRIM_TRI_FAN) {
- /* Note(Metal): Tri-fan alternative for Metal. Triangle List is more efficient for small
+ /* NOTE(Metal): Tri-fan alternative for Metal. Triangle List is more efficient for small
* primitive counts. */
int tri_count = vert_count - 2;
immBegin(GPU_PRIM_TRIS, tri_count * 3);
diff --git a/source/blender/editors/gizmo_library/gizmo_types/arrow3d_gizmo.c b/source/blender/editors/gizmo_library/gizmo_types/arrow3d_gizmo.c
index a1fb0e205b1..cde702294d0 100644
--- a/source/blender/editors/gizmo_library/gizmo_types/arrow3d_gizmo.c
+++ b/source/blender/editors/gizmo_library/gizmo_types/arrow3d_gizmo.c
@@ -50,16 +50,19 @@
/* to use custom arrows exported to geom_arrow_gizmo.c */
//#define USE_GIZMO_CUSTOM_ARROWS
-/** Margins to add when selecting the arrow stem. */
-#define ARROW_SELECT_THRESHOLD_PX_STEM (5 * UI_DPI_FAC)
-/** Margins to add when selecting the arrow head. */
-#define ARROW_SELECT_THRESHOLD_PX_HEAD (12 * UI_DPI_FAC)
+/* Margin to add when selecting the arrow. */
+#define ARROW_SELECT_THRESHOLD_PX (5)
typedef struct ArrowGizmo3D {
wmGizmo gizmo;
GizmoCommonData data;
} ArrowGizmo3D;
+typedef struct ArrowGizmoInteraction {
+ GizmoInteraction inter;
+ float init_arrow_length;
+} ArrowGizmoInteraction;
+
/* -------------------------------------------------------------------- */
static void gizmo_arrow_matrix_basis_get(const wmGizmo *gz, float r_matrix[4][4])
@@ -70,7 +73,10 @@ static void gizmo_arrow_matrix_basis_get(const wmGizmo *gz, float r_matrix[4][4]
madd_v3_v3fl(r_matrix[3], arrow->gizmo.matrix_basis[2], arrow->data.offset);
}
-static void arrow_draw_geom(const ArrowGizmo3D *arrow, const bool select, const float color[4])
+static void arrow_draw_geom(const ArrowGizmo3D *arrow,
+ const bool select,
+ const float color[4],
+ const float arrow_length)
{
uint pos = GPU_vertformat_attr_add(immVertexFormat(), "pos", GPU_COMP_F32, 3, GPU_FETCH_FLOAT);
bool unbind_shader = true;
@@ -113,16 +119,14 @@ static void arrow_draw_geom(const ArrowGizmo3D *arrow, const bool select, const
#ifdef USE_GIZMO_CUSTOM_ARROWS
wm_gizmo_geometryinfo_draw(&wm_gizmo_geom_data_arrow, select, color);
#else
- const float arrow_length = RNA_float_get(arrow->gizmo.ptr, "length");
-
const float vec[2][3] = {
{0.0f, 0.0f, 0.0f},
{0.0f, 0.0f, arrow_length},
};
if (draw_options & ED_GIZMO_ARROW_DRAW_FLAG_STEM) {
- const float stem_width = (arrow->gizmo.line_width * U.pixelsize) +
- (select ? ARROW_SELECT_THRESHOLD_PX_STEM : 0);
+ const float stem_width = arrow->gizmo.line_width * U.pixelsize +
+ (select ? ARROW_SELECT_THRESHOLD_PX * U.dpi_fac : 0);
immUniform1f("lineWidth", stem_width);
wm_gizmo_vec_draw(color, vec, ARRAY_SIZE(vec), pos, GPU_PRIM_LINE_STRIP);
}
@@ -134,7 +138,7 @@ static void arrow_draw_geom(const ArrowGizmo3D *arrow, const bool select, const
GPU_matrix_push();
- /* NOTE: ideally #ARROW_SELECT_THRESHOLD_PX_HEAD would be added here, however adding a
+ /* NOTE: ideally #ARROW_SELECT_THRESHOLD_PX would be added here, however adding a
* margin in pixel space isn't so simple, nor is it as important as for the arrow stem. */
if (draw_style == ED_GIZMO_ARROW_STYLE_BOX) {
const float size = 0.05f;
@@ -178,6 +182,7 @@ static void arrow_draw_geom(const ArrowGizmo3D *arrow, const bool select, const
static void arrow_draw_intern(ArrowGizmo3D *arrow, const bool select, const bool highlight)
{
wmGizmo *gz = &arrow->gizmo;
+ const float arrow_length = RNA_float_get(gz->ptr, "length");
float color[4];
float matrix_final[4][4];
@@ -188,19 +193,20 @@ static void arrow_draw_intern(ArrowGizmo3D *arrow, const bool select, const bool
GPU_matrix_push();
GPU_matrix_mul(matrix_final);
GPU_blend(GPU_BLEND_ALPHA);
- arrow_draw_geom(arrow, select, color);
+ arrow_draw_geom(arrow, select, color, arrow_length);
GPU_blend(GPU_BLEND_NONE);
GPU_matrix_pop();
if (gz->interaction_data) {
- GizmoInteraction *inter = gz->interaction_data;
+ ArrowGizmoInteraction *arrow_inter = gz->interaction_data;
GPU_matrix_push();
- GPU_matrix_mul(inter->init_matrix_final);
+ GPU_matrix_mul(arrow_inter->inter.init_matrix_final);
GPU_blend(GPU_BLEND_ALPHA);
- arrow_draw_geom(arrow, select, (const float[4]){0.5f, 0.5f, 0.5f, 0.5f});
+ arrow_draw_geom(
+ arrow, select, (const float[4]){0.5f, 0.5f, 0.5f, 0.5f}, arrow_inter->init_arrow_length);
GPU_blend(GPU_BLEND_NONE);
GPU_matrix_pop();
@@ -223,9 +229,15 @@ static void gizmo_arrow_draw(const bContext *UNUSED(C), wmGizmo *gz)
*/
static int gizmo_arrow_test_select(bContext *UNUSED(C), wmGizmo *gz, const int mval[2])
{
+ /* This following values are based on manual inspection of `verts[]` defined in
+ * geom_arrow_gizmo.c */
+ const float head_center_z = (0.974306f + 1.268098f) / 2;
+ const float head_geo_x = 0.051304f;
+ const float stem_geo_x = 0.012320f;
+
/* Project into 2D space since it simplifies pixel threshold tests. */
ArrowGizmo3D *arrow = (ArrowGizmo3D *)gz;
- const float arrow_length = RNA_float_get(arrow->gizmo.ptr, "length");
+ const float arrow_length = RNA_float_get(arrow->gizmo.ptr, "length") * head_center_z;
float matrix_final[4][4];
WM_gizmo_calc_matrix_final(gz, matrix_final);
@@ -239,12 +251,15 @@ static int gizmo_arrow_test_select(bContext *UNUSED(C), wmGizmo *gz, const int m
copy_v2_v2(arrow_end, co);
}
+ const float scale_final = mat4_to_scale(matrix_final);
+ const float head_width = ARROW_SELECT_THRESHOLD_PX * scale_final * head_geo_x;
+ const float stem_width = ARROW_SELECT_THRESHOLD_PX * scale_final * stem_geo_x;
+ float select_threshold_base = gz->line_width * U.pixelsize;
+
const float mval_fl[2] = {UNPACK2(mval)};
- const float arrow_stem_threshold_px = ARROW_SELECT_THRESHOLD_PX_STEM;
- const float arrow_head_threshold_px = ARROW_SELECT_THRESHOLD_PX_HEAD;
/* Distance to arrow head. */
- if (len_squared_v2v2(mval_fl, arrow_end) < square_f(arrow_head_threshold_px)) {
+ if (len_squared_v2v2(mval_fl, arrow_end) < square_f(select_threshold_base + head_width)) {
return 0;
}
@@ -253,8 +268,8 @@ static int gizmo_arrow_test_select(bContext *UNUSED(C), wmGizmo *gz, const int m
const float lambda = closest_to_line_v2(co_isect, mval_fl, arrow_start, arrow_end);
/* Clamp inside the line, to avoid overlapping with other gizmos,
* especially around the start of the arrow. */
- if (lambda >= 0.0 && lambda <= 1.0) {
- if (len_squared_v2v2(mval_fl, co_isect) < square_f(arrow_stem_threshold_px)) {
+ if (lambda >= 0.0f && lambda <= 1.0f) {
+ if (len_squared_v2v2(mval_fl, co_isect) < square_f(select_threshold_base + stem_width)) {
return 0;
}
}
@@ -373,7 +388,7 @@ static void gizmo_arrow_setup(wmGizmo *gz)
static int gizmo_arrow_invoke(bContext *UNUSED(C), wmGizmo *gz, const wmEvent *event)
{
ArrowGizmo3D *arrow = (ArrowGizmo3D *)gz;
- GizmoInteraction *inter = MEM_callocN(sizeof(GizmoInteraction), __func__);
+ GizmoInteraction *inter = MEM_callocN(sizeof(ArrowGizmoInteraction), __func__);
wmGizmoProperty *gz_prop = WM_gizmo_target_property_find(gz, "offset");
/* Some gizmos don't use properties. */
@@ -389,6 +404,8 @@ static int gizmo_arrow_invoke(bContext *UNUSED(C), wmGizmo *gz, const wmEvent *e
gizmo_arrow_matrix_basis_get(gz, inter->init_matrix_basis);
WM_gizmo_calc_matrix_final(gz, inter->init_matrix_final);
+ ((ArrowGizmoInteraction *)inter)->init_arrow_length = RNA_float_get(gz->ptr, "length");
+
gz->interaction_data = inter;
return OPERATOR_RUNNING_MODAL;
@@ -513,7 +530,8 @@ static void GIZMO_GT_arrow_3d(wmGizmoType *gzt)
"");
RNA_def_enum_flag(gzt->srna, "transform", rna_enum_transform_items, 0, "Transform", "");
- RNA_def_float(gzt->srna, "length", 1.0f, 0.0f, FLT_MAX, "Arrow Line Length", "", 0.0f, FLT_MAX);
+ RNA_def_float(
+ gzt->srna, "length", 1.0f, -FLT_MAX, FLT_MAX, "Arrow Line Length", "", -FLT_MAX, FLT_MAX);
RNA_def_float_vector(
gzt->srna, "aspect", 2, NULL, 0, FLT_MAX, "Aspect", "Cone/box style only", 0.0f, FLT_MAX);
diff --git a/source/blender/editors/gizmo_library/gizmo_types/button2d_gizmo.c b/source/blender/editors/gizmo_library/gizmo_types/button2d_gizmo.c
index b326d6d1859..11309402220 100644
--- a/source/blender/editors/gizmo_library/gizmo_types/button2d_gizmo.c
+++ b/source/blender/editors/gizmo_library/gizmo_types/button2d_gizmo.c
@@ -57,8 +57,6 @@ typedef struct ButtonGizmo2D {
GPUBatch *shape_batch[2];
} ButtonGizmo2D;
-#define CIRCLE_RESOLUTION 32
-
/** \} */
/* -------------------------------------------------------------------- */
@@ -68,27 +66,33 @@ typedef struct ButtonGizmo2D {
static void button2d_geom_draw_backdrop(const wmGizmo *gz,
const float color[4],
const float fill_alpha,
- const bool select)
+ const bool select,
+ const float screen_scale)
{
float viewport[4];
GPU_viewport_size_get_f(viewport);
+ const float max_pixel_error = 0.25f;
+ int nsegments = (int)(ceilf(M_PI / acosf(1.0f - max_pixel_error / screen_scale)));
+ nsegments = max_ff(nsegments, 8);
+ nsegments = min_ff(nsegments, 1000);
+
GPUVertFormat *format = immVertexFormat();
- /* Note(Metal): Prefer 3D coordinate for 2D rendering when using 3D shader. */
+ /* NOTE(Metal): Prefer 3D coordinate for 2D rendering when using 3D shader. */
uint pos = GPU_vertformat_attr_add(format, "pos", GPU_COMP_F32, 3, GPU_FETCH_FLOAT);
/* TODO: other draw styles. */
if (color[3] == 1.0 && fill_alpha == 1.0 && select == false) {
immBindBuiltinProgram(GPU_SHADER_3D_UNIFORM_COLOR);
immUniformColor4fv(color);
- imm_draw_circle_fill_3d(pos, 0.0f, 0.0f, 1.0f, CIRCLE_RESOLUTION);
+ imm_draw_circle_fill_3d(pos, 0.0f, 0.0f, 1.0f, nsegments);
immUnbindProgram();
immBindBuiltinProgram(GPU_SHADER_3D_POLYLINE_UNIFORM_COLOR);
immUniform2fv("viewportSize", &viewport[2]);
immUniform1f("lineWidth", gz->line_width * U.pixelsize);
immUniformColor4fv(color);
- imm_draw_circle_wire_3d(pos, 0.0f, 0.0f, 1.0f, CIRCLE_RESOLUTION);
+ imm_draw_circle_wire_3d(pos, 0.0f, 0.0f, 1.0f, nsegments);
immUnbindProgram();
}
else {
@@ -97,7 +101,7 @@ static void button2d_geom_draw_backdrop(const wmGizmo *gz,
const float fill_color[4] = {UNPACK3(color), fill_alpha * color[3]};
immBindBuiltinProgram(GPU_SHADER_3D_UNIFORM_COLOR);
immUniformColor4fv(fill_color);
- imm_draw_circle_fill_3d(pos, 0.0f, 0.0f, 1.0f, CIRCLE_RESOLUTION);
+ imm_draw_circle_fill_3d(pos, 0.0f, 0.0f, 1.0f, nsegments);
immUnbindProgram();
}
@@ -107,7 +111,7 @@ static void button2d_geom_draw_backdrop(const wmGizmo *gz,
immUniform2fv("viewportSize", &viewport[2]);
immUniform1f("lineWidth", gz->line_width * U.pixelsize);
immUniformColor4fv(color);
- imm_draw_circle_wire_3d(pos, 0.0f, 0.0f, 1.0f, CIRCLE_RESOLUTION);
+ imm_draw_circle_wire_3d(pos, 0.0f, 0.0f, 1.0f, nsegments);
immUnbindProgram();
}
}
@@ -184,9 +188,11 @@ static void button2d_draw_intern(const bContext *C,
GPU_matrix_mul(matrix_align);
}
+ const float screen_scale = mat4_to_scale(matrix_final);
+
if (select) {
BLI_assert(is_3d);
- button2d_geom_draw_backdrop(gz, color, 1.0, select);
+ button2d_geom_draw_backdrop(gz, color, 1.0, select, screen_scale);
}
else {
@@ -194,7 +200,7 @@ static void button2d_draw_intern(const bContext *C,
if (draw_options & ED_GIZMO_BUTTON_SHOW_BACKDROP) {
const float fill_alpha = RNA_float_get(gz->ptr, "backdrop_fill_alpha");
- button2d_geom_draw_backdrop(gz, color, fill_alpha, select);
+ button2d_geom_draw_backdrop(gz, color, fill_alpha, select, screen_scale);
}
if (button->shape_batch[0] != NULL) {
@@ -315,10 +321,11 @@ static int gizmo_button2d_cursor_get(wmGizmo *gz)
return WM_CURSOR_DEFAULT;
}
+#define CIRCLE_RESOLUTION_3D 32
static bool gizmo_button2d_bounds(bContext *C, wmGizmo *gz, rcti *r_bounding_box)
{
ScrArea *area = CTX_wm_area(C);
- float rad = CIRCLE_RESOLUTION * U.dpi_fac / 2.0f;
+ float rad = CIRCLE_RESOLUTION_3D * U.dpi_fac / 2.0f;
const float *co = NULL;
float matrix_final[4][4];
float co_proj[3];
@@ -342,6 +349,7 @@ static bool gizmo_button2d_bounds(bContext *C, wmGizmo *gz, rcti *r_bounding_box
}
}
else {
+ rad = mat4_to_scale(matrix_final);
co = matrix_final[3];
}
diff --git a/source/blender/editors/gizmo_library/gizmo_types/dial3d_gizmo.c b/source/blender/editors/gizmo_library/gizmo_types/dial3d_gizmo.c
index a76242404ba..9b7b157dc7e 100644
--- a/source/blender/editors/gizmo_library/gizmo_types/dial3d_gizmo.c
+++ b/source/blender/editors/gizmo_library/gizmo_types/dial3d_gizmo.c
@@ -77,6 +77,21 @@ typedef struct DialInteraction {
#define DIAL_CLIP_BIAS 0.02
/* -------------------------------------------------------------------- */
+struct Dial3dParams {
+ int draw_options;
+ float angle_ofs;
+ float angle_delta;
+ float angle_increment;
+ float arc_partial_angle;
+ float arc_inner_factor;
+ float *clip_plane;
+};
+static void dial_3d_draw_util(const float matrix_basis[4][4],
+ const float matrix_final[4][4],
+ const float line_width,
+ const float color[4],
+ const bool select,
+ struct Dial3dParams *params);
static void dial_geom_draw(const float color[4],
const float line_width,
@@ -96,7 +111,7 @@ static void dial_geom_draw(const float color[4],
ED_GIZMO_DIAL_DRAW_FLAG_FILL)));
GPUVertFormat *format = immVertexFormat();
- /* Note(Metal): Prefer using 3D coordinates with 3D shader, even if rendering 2D gizmo's. */
+ /* NOTE(Metal): Prefer using 3D coordinates with 3D shader, even if rendering 2D gizmo's. */
uint pos = GPU_vertformat_attr_add(format, "pos", GPU_COMP_F32, 3, GPU_FETCH_FLOAT);
if (clip_plane) {
@@ -411,23 +426,26 @@ static void dial_draw_intern(
if (WM_gizmo_target_property_is_valid(gz_prop)) {
angle_delta = WM_gizmo_target_property_float_get(gz, gz_prop);
}
+ if (gz->state & WM_GIZMO_STATE_MODAL) {
+ angle_increment = RNA_float_get(gz->ptr, "incremental_angle");
+ }
}
}
- ED_gizmotypes_dial_3d_draw_util(gz->matrix_basis,
- matrix_final,
- gz->line_width,
- color,
- select,
- &(struct Dial3dParams){
- .draw_options = draw_options,
- .angle_ofs = angle_ofs,
- .angle_delta = angle_delta,
- .angle_increment = angle_increment,
- .arc_partial_angle = arc_partial_angle,
- .arc_inner_factor = arc_inner_factor,
- .clip_plane = clip_plane,
- });
+ dial_3d_draw_util(gz->matrix_basis,
+ matrix_final,
+ gz->line_width,
+ color,
+ select,
+ &(struct Dial3dParams){
+ .draw_options = draw_options,
+ .angle_ofs = angle_ofs,
+ .angle_delta = angle_delta,
+ .angle_increment = angle_increment,
+ .arc_partial_angle = arc_partial_angle,
+ .arc_inner_factor = arc_inner_factor,
+ .clip_plane = clip_plane,
+ });
}
static void gizmo_dial_draw_select(const bContext *C, wmGizmo *gz, int select_id)
@@ -479,6 +497,10 @@ static int gizmo_dial_modal(bContext *C,
eWM_GizmoFlagTweak tweak_flag)
{
DialInteraction *inter = gz->interaction_data;
+ if (!inter) {
+ return OPERATOR_CANCELLED;
+ }
+
if ((event->type != MOUSEMOVE) && (inter->prev.tweak_flag == tweak_flag)) {
return OPERATOR_RUNNING_MODAL;
}
@@ -519,30 +541,33 @@ static int gizmo_dial_modal(bContext *C,
static void gizmo_dial_exit(bContext *C, wmGizmo *gz, const bool cancel)
{
DialInteraction *inter = gz->interaction_data;
- bool use_reset_value = false;
- float reset_value = 0.0f;
- if (cancel) {
- /* Set the property for the operator and call its modal function. */
- wmGizmoProperty *gz_prop = WM_gizmo_target_property_find(gz, "offset");
- if (WM_gizmo_target_property_is_valid(gz_prop)) {
- use_reset_value = true;
- reset_value = inter->init.prop_angle;
- }
- }
- else {
- if (inter->has_drag == false) {
- PropertyRNA *prop = RNA_struct_find_property(gz->ptr, "click_value");
- if (RNA_property_is_set(gz->ptr, prop)) {
+ if (inter) {
+ bool use_reset_value = false;
+ float reset_value = 0.0f;
+
+ if (cancel) {
+ /* Set the property for the operator and call its modal function. */
+ wmGizmoProperty *gz_prop = WM_gizmo_target_property_find(gz, "offset");
+ if (WM_gizmo_target_property_is_valid(gz_prop)) {
use_reset_value = true;
- reset_value = RNA_property_float_get(gz->ptr, prop);
+ reset_value = inter->init.prop_angle;
+ }
+ }
+ else {
+ if (inter->has_drag == false) {
+ PropertyRNA *prop = RNA_struct_find_property(gz->ptr, "click_value");
+ if (RNA_property_is_set(gz->ptr, prop)) {
+ use_reset_value = true;
+ reset_value = RNA_property_float_get(gz->ptr, prop);
+ }
}
}
- }
- if (use_reset_value) {
- wmGizmoProperty *gz_prop = WM_gizmo_target_property_find(gz, "offset");
- if (WM_gizmo_target_property_is_valid(gz_prop)) {
- WM_gizmo_target_property_float_set(C, gz, gz_prop, reset_value);
+ if (use_reset_value) {
+ wmGizmoProperty *gz_prop = WM_gizmo_target_property_find(gz, "offset");
+ if (WM_gizmo_target_property_is_valid(gz_prop)) {
+ WM_gizmo_target_property_float_set(C, gz, gz_prop, reset_value);
+ }
}
}
@@ -564,6 +589,11 @@ static void gizmo_dial_setup(wmGizmo *gz)
static int gizmo_dial_invoke(bContext *UNUSED(C), wmGizmo *gz, const wmEvent *event)
{
+ if (gz->custom_modal) {
+ /* #DialInteraction is only used for the inner modal. */
+ return OPERATOR_RUNNING_MODAL;
+ }
+
DialInteraction *inter = MEM_callocN(sizeof(DialInteraction), __func__);
inter->init.mval[0] = event->mval[0];
@@ -583,12 +613,12 @@ static int gizmo_dial_invoke(bContext *UNUSED(C), wmGizmo *gz, const wmEvent *ev
/** \name Dial Gizmo API
* \{ */
-void ED_gizmotypes_dial_3d_draw_util(const float matrix_basis[4][4],
- const float matrix_final[4][4],
- const float line_width,
- const float color[4],
- const bool select,
- struct Dial3dParams *params)
+static void dial_3d_draw_util(const float matrix_basis[4][4],
+ const float matrix_final[4][4],
+ const float line_width,
+ const float color[4],
+ const bool select,
+ struct Dial3dParams *params)
{
GPU_matrix_push();
GPU_matrix_mul(matrix_final);
diff --git a/source/blender/editors/gizmo_library/gizmo_types/move3d_gizmo.c b/source/blender/editors/gizmo_library/gizmo_types/move3d_gizmo.c
index 5fb1173521a..1ce67185c1e 100644
--- a/source/blender/editors/gizmo_library/gizmo_types/move3d_gizmo.c
+++ b/source/blender/editors/gizmo_library/gizmo_types/move3d_gizmo.c
@@ -98,7 +98,7 @@ static void move_geom_draw(const wmGizmo *gz,
ED_GIZMO_MOVE_DRAW_FLAG_FILL)));
GPUVertFormat *format = immVertexFormat();
- /* Note(Metal): Prefer using 3D coordinates with 3D shader, even if rendering 2D gizmo's. */
+ /* NOTE(Metal): Prefer using 3D coordinates with 3D shader, even if rendering 2D gizmo's. */
uint pos = GPU_vertformat_attr_add(format, "pos", GPU_COMP_F32, 3, GPU_FETCH_FLOAT);
immBindBuiltinProgram(filled ? GPU_SHADER_3D_UNIFORM_COLOR :
@@ -280,7 +280,7 @@ static int gizmo_move_modal(bContext *C,
CTX_wm_view3d(C),
(SCE_SNAP_MODE_VERTEX | SCE_SNAP_MODE_EDGE | SCE_SNAP_MODE_FACE),
&(const struct SnapObjectParams){
- .snap_select = SNAP_ALL,
+ .snap_target_select = SCE_SNAP_TARGET_ALL,
.edit_mode_type = SNAP_GEOM_EDIT,
.use_occlusion_test = true,
},
diff --git a/source/blender/editors/gizmo_library/gizmo_types/snap3d_gizmo.c b/source/blender/editors/gizmo_library/gizmo_types/snap3d_gizmo.c
index 1659afb1254..d468906f127 100644
--- a/source/blender/editors/gizmo_library/gizmo_types/snap3d_gizmo.c
+++ b/source/blender/editors/gizmo_library/gizmo_types/snap3d_gizmo.c
@@ -96,7 +96,7 @@ void ED_gizmotypes_snap_3d_data_get(const struct bContext *C,
float r_loc[3],
float r_nor[3],
int r_elem_index[3],
- int *r_snap_elem)
+ eSnapMode *r_snap_elem)
{
if (C) {
/* Snap values are updated too late at the cursor. Be sure to update ahead of time. */
@@ -283,7 +283,7 @@ static int snap_gizmo_test_select(bContext *C, wmGizmo *gz, const int mval[2])
ED_view3d_cursor_snap_data_update(snap_gizmo->snap_state, C, x, y);
V3DSnapCursorData *snap_data = ED_view3d_cursor_snap_data_get();
- if (snap_data->snap_elem) {
+ if (snap_data->snap_elem != SCE_SNAP_MODE_NONE) {
return 0;
}
return -1;
diff --git a/source/blender/editors/gpencil/drawgpencil.c b/source/blender/editors/gpencil/drawgpencil.c
index 011a5a66695..24de50db397 100644
--- a/source/blender/editors/gpencil/drawgpencil.c
+++ b/source/blender/editors/gpencil/drawgpencil.c
@@ -80,9 +80,9 @@ typedef enum eDrawStrokeFlags {
GP_DRAWDATA_ONLYI2D = (1 << 3),
/** special hack for drawing strokes in Image Editor (weird coordinates) */
GP_DRAWDATA_IEDITHACK = (1 << 4),
- /** don't draw xray in 3D view (which is default) */
+ /** Don't draw XRAY in 3D view (which is default). */
GP_DRAWDATA_NO_XRAY = (1 << 5),
- /** no onionskins should be drawn (for animation playback) */
+ /** No onion-skins should be drawn (for animation playback). */
GP_DRAWDATA_NO_ONIONS = (1 << 6),
/** draw strokes as "volumetric" circular billboards */
GP_DRAWDATA_VOLUMETRIC = (1 << 7),
diff --git a/source/blender/editors/gpencil/gpencil_bake_animation.cc b/source/blender/editors/gpencil/gpencil_bake_animation.cc
index dfc74f6d225..66f53bea326 100644
--- a/source/blender/editors/gpencil/gpencil_bake_animation.cc
+++ b/source/blender/editors/gpencil/gpencil_bake_animation.cc
@@ -320,6 +320,7 @@ static int gpencil_bake_grease_pencil_animation_exec(bContext *C, wmOperator *op
/* Update point location to new object space. */
for (int j = 0; j < gps->totpoints; j++) {
bGPDspoint *pt = &gps->points[j];
+ mul_m4_v3(ob_eval->obmat, &pt->x);
mul_m4_v3(invmat, &pt->x);
}
diff --git a/source/blender/editors/gpencil/gpencil_convert.c b/source/blender/editors/gpencil/gpencil_convert.c
index 4f9468cc9c4..0601d009bf7 100644
--- a/source/blender/editors/gpencil/gpencil_convert.c
+++ b/source/blender/editors/gpencil/gpencil_convert.c
@@ -1104,7 +1104,7 @@ static void gpencil_stroke_to_bezier(bContext *C,
rad_fac,
minmax_weights);
- /* shift coord vects */
+ /* Shift coord vectors. */
copy_v3_v3(p3d_prev, p3d_cur);
copy_v3_v3(p3d_cur, p3d_next);
diff --git a/source/blender/editors/gpencil/gpencil_edit.c b/source/blender/editors/gpencil/gpencil_edit.c
index 3c8e6d6e5f5..5028baf1589 100644
--- a/source/blender/editors/gpencil/gpencil_edit.c
+++ b/source/blender/editors/gpencil/gpencil_edit.c
@@ -1811,7 +1811,16 @@ static int gpencil_move_to_layer_exec(bContext *C, wmOperator *op)
}
else {
/* Create a new layer. */
- target_layer = BKE_gpencil_layer_addnew(gpd, "GP_Layer", true, false);
+ PropertyRNA *prop;
+ char name[128];
+ prop = RNA_struct_find_property(op->ptr, "new_layer_name");
+ if (RNA_property_is_set(op->ptr, prop)) {
+ RNA_property_string_get(op->ptr, prop, name);
+ }
+ else {
+ strcpy(name, "GP_Layer");
+ }
+ target_layer = BKE_gpencil_layer_addnew(gpd, name, true, false);
}
if (target_layer == NULL) {
@@ -1888,8 +1897,46 @@ static int gpencil_move_to_layer_exec(bContext *C, wmOperator *op)
return OPERATOR_FINISHED;
}
+static void layer_new_name_get(bGPdata *gpd, char *rname)
+{
+ int index = 0;
+ LISTBASE_FOREACH (bGPDlayer *, gpl, &gpd->layers) {
+ if (strstr(gpl->info, "GP_Layer")) {
+ index++;
+ }
+ }
+
+ if (index == 0) {
+ BLI_strncpy(rname, "GP_Layer", 128);
+ return;
+ }
+ char *name = BLI_sprintfN("%.*s.%03d", 128, "GP_Layer", index);
+ BLI_strncpy(rname, name, 128);
+ MEM_freeN(name);
+}
+
+static int gpencil_move_to_layer_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
+{
+ Object *ob = CTX_data_active_object(C);
+ PropertyRNA *prop;
+ if (RNA_int_get(op->ptr, "layer") == -1) {
+ prop = RNA_struct_find_property(op->ptr, "new_layer_name");
+ if (!RNA_property_is_set(op->ptr, prop)) {
+ char name[MAX_NAME];
+ bGPdata *gpd = ob->data;
+ layer_new_name_get(gpd, name);
+ RNA_property_string_set(op->ptr, prop, name);
+ return WM_operator_props_dialog_popup(C, op, 200);
+ }
+ }
+
+ return gpencil_move_to_layer_exec(C, op);
+}
+
void GPENCIL_OT_move_to_layer(wmOperatorType *ot)
{
+ PropertyRNA *prop;
+
/* identifiers */
ot->name = "Move Strokes to Layer";
ot->idname = "GPENCIL_OT_move_to_layer";
@@ -1898,15 +1945,20 @@ void GPENCIL_OT_move_to_layer(wmOperatorType *ot)
/* callbacks */
ot->exec = gpencil_move_to_layer_exec;
- ot->poll = gpencil_stroke_edit_poll; /* XXX? */
+ ot->invoke = gpencil_move_to_layer_invoke;
+ ot->poll = gpencil_stroke_edit_poll;
/* flags */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
/* GPencil layer to use. */
- ot->prop = RNA_def_int(
- ot->srna, "layer", 0, -1, INT_MAX, "Grease Pencil Layer", "", -1, INT_MAX);
- RNA_def_property_flag(ot->prop, PROP_HIDDEN | PROP_SKIP_SAVE);
+ prop = RNA_def_int(ot->srna, "layer", 0, -1, INT_MAX, "Grease Pencil Layer", "", -1, INT_MAX);
+ RNA_def_property_flag(prop, PROP_HIDDEN | PROP_SKIP_SAVE);
+
+ prop = RNA_def_string(
+ ot->srna, "new_layer_name", NULL, MAX_NAME, "Name", "Name of the newly added layer");
+ RNA_def_property_flag(prop, PROP_SKIP_SAVE);
+ ot->prop = prop;
}
/** \} */
diff --git a/source/blender/editors/gpencil/gpencil_intern.h b/source/blender/editors/gpencil/gpencil_intern.h
index 56c94e4494d..d656241c463 100644
--- a/source/blender/editors/gpencil/gpencil_intern.h
+++ b/source/blender/editors/gpencil/gpencil_intern.h
@@ -726,16 +726,16 @@ struct GP_EditableStrokes_Iter {
(void)0
/**
- * Iterate over all editable editcurves in the current context,
- * stopping on each usable layer + stroke + curve pair (i.e. gpl, gps and gpc)
+ * Iterate over all editable edit-curves in the current context,
+ * stopping on each usable layer + stroke + curve pair (i.e. `gpl`, `gps` and `gpc`)
* to perform some operations on the curve.
*
* \param gpl: The identifier to use for the layer of the stroke being processed.
- * Choose a suitable value to avoid name clashes.
+ * Choose a suitable value to avoid name clashes.
* \param gps: The identifier to use for current stroke being processed.
- * Choose a suitable value to avoid name clashes.
+ * Choose a suitable value to avoid name clashes.
* \param gpc: The identifier to use for current editcurve being processed.
- * Choose a suitable value to avoid name clashes.
+ * Choose a suitable value to avoid name clashes.
*/
#define GP_EDITABLE_CURVES_BEGIN(gpstroke_iter, C, gpl, gps, gpc) \
{ \
diff --git a/source/blender/editors/gpencil/gpencil_interpolate.c b/source/blender/editors/gpencil/gpencil_interpolate.c
index 8630b7f23d4..0039dbae674 100644
--- a/source/blender/editors/gpencil/gpencil_interpolate.c
+++ b/source/blender/editors/gpencil/gpencil_interpolate.c
@@ -1482,8 +1482,8 @@ void GPENCIL_OT_interpolate_sequence(wmOperatorType *ot)
* Changes here will likely apply there too.
*/
static const EnumPropertyItem gpencil_interpolation_type_items[] = {
- /* interpolation */
- {0, "", 0, N_("Interpolation"), "Standard transitions between keyframes"},
+ /* Interpolation. */
+ RNA_ENUM_ITEM_HEADING(N_("Interpolation"), "Standard transitions between keyframes"),
{GP_IPO_LINEAR,
"LINEAR",
ICON_IPO_LINEAR,
@@ -1495,13 +1495,10 @@ void GPENCIL_OT_interpolate_sequence(wmOperatorType *ot)
"Custom",
"Custom interpolation defined using a curve map"},
- /* easing */
- {0,
- "",
- 0,
- N_("Easing (by strength)"),
- "Predefined inertial transitions, useful for motion graphics (from least to most "
- "''dramatic'')"},
+ /* Easing. */
+ RNA_ENUM_ITEM_HEADING(N_("Easing (by strength)"),
+ "Predefined inertial transitions, useful for motion graphics "
+ "(from least to most \"dramatic\")"),
{GP_IPO_SINE,
"SINE",
ICON_IPO_SINE,
@@ -1518,7 +1515,7 @@ void GPENCIL_OT_interpolate_sequence(wmOperatorType *ot)
"Circular",
"Circular easing (strongest and most dynamic)"},
- {0, "", 0, N_("Dynamic Effects"), "Simple physics-inspired easing effects"},
+ RNA_ENUM_ITEM_HEADING(N_("Dynamic Effects"), "Simple physics-inspired easing effects"),
{GP_IPO_BACK, "BACK", ICON_IPO_BACK, "Back", "Cubic easing with overshoot and settle"},
{GP_IPO_BOUNCE,
"BOUNCE",
diff --git a/source/blender/editors/gpencil/gpencil_sculpt_paint.c b/source/blender/editors/gpencil/gpencil_sculpt_paint.c
index 01ac02a9a1d..6d0848de36d 100644
--- a/source/blender/editors/gpencil/gpencil_sculpt_paint.c
+++ b/source/blender/editors/gpencil/gpencil_sculpt_paint.c
@@ -829,7 +829,7 @@ static bool gpencil_brush_randomize_apply(tGP_BrushEditData *gso,
mul_v2_fl(svec, fac);
}
- /* convert to dataspace */
+ /* Convert to data-space. */
if (gps->flag & GP_STROKE_3DSPACE) {
/* 3D: Project to 3D space */
bool flip;
diff --git a/source/blender/editors/gpencil/gpencil_select.c b/source/blender/editors/gpencil/gpencil_select.c
index c4fd34212c3..e903d11a1e0 100644
--- a/source/blender/editors/gpencil/gpencil_select.c
+++ b/source/blender/editors/gpencil/gpencil_select.c
@@ -1701,7 +1701,7 @@ static int gpencil_circle_select_exec(bContext *C, wmOperator *op)
const bool select = (sel_op != SEL_OP_SUB);
bool changed = false;
- /* for bounding rect around circle (for quicky intersection testing) */
+ /* For bounding `rect` around circle (for quickly intersection testing). */
rcti rect = {0};
rect.xmin = mx - radius;
rect.ymin = my - radius;
@@ -2681,6 +2681,7 @@ void GPENCIL_OT_select(wmOperatorType *ot)
ot->invoke = gpencil_select_invoke;
ot->exec = gpencil_select_exec;
ot->poll = gpencil_select_poll;
+ ot->get_name = ED_select_pick_get_name;
/* flag */
ot->flag = OPTYPE_UNDO;
diff --git a/source/blender/editors/gpencil/gpencil_utils.c b/source/blender/editors/gpencil/gpencil_utils.c
index 2dc12125f40..7b659511aaa 100644
--- a/source/blender/editors/gpencil/gpencil_utils.c
+++ b/source/blender/editors/gpencil/gpencil_utils.c
@@ -388,6 +388,17 @@ const EnumPropertyItem *ED_gpencil_layers_with_new_enum_itemf(bContext *C,
/* Create new layer */
/* TODO: have some way of specifying that we don't want this? */
+ {
+ /* "New Layer" entry */
+ item_tmp.identifier = "__CREATE__";
+ item_tmp.name = "New Layer";
+ item_tmp.value = -1;
+ item_tmp.icon = ICON_ADD;
+ RNA_enum_item_add(&item, &totitem, &item_tmp);
+
+ /* separator */
+ RNA_enum_item_add_separator(&item, &totitem);
+ }
const int tot = BLI_listbase_count(&gpd->layers);
/* Existing layers */
@@ -405,17 +416,6 @@ const EnumPropertyItem *ED_gpencil_layers_with_new_enum_itemf(bContext *C,
RNA_enum_item_add(&item, &totitem, &item_tmp);
}
- {
- /* separator */
- RNA_enum_item_add_separator(&item, &totitem);
-
- /* "New Layer" entry */
- item_tmp.identifier = "__CREATE__";
- item_tmp.name = "New Layer";
- item_tmp.value = -1;
- item_tmp.icon = ICON_ADD;
- RNA_enum_item_add(&item, &totitem, &item_tmp);
- }
RNA_enum_item_end(&item, &totitem);
*r_free = true;
@@ -525,7 +525,7 @@ bool ED_gpencil_stroke_can_use_direct(const ScrArea *area, const bGPDstroke *gps
return (area->spacetype == SPACE_IMAGE);
}
if (gps->flag & GP_STROKE_2DSPACE) {
- /* 2D strokes (dataspace) - for any 2D view (i.e. everything other than 3D view) */
+ /* 2D strokes (data-space) - for any 2D view (i.e. everything other than 3D view). */
return (area->spacetype != SPACE_VIEW3D);
}
/* view aligned - anything goes */
@@ -1149,7 +1149,7 @@ void ED_gpencil_stroke_reproject(Depsgraph *depsgraph,
depsgraph,
v3d,
&(const struct SnapObjectParams){
- .snap_select = SNAP_ALL,
+ .snap_target_select = SCE_SNAP_TARGET_ALL,
},
&ray_start[0],
&ray_normal[0],
@@ -1747,7 +1747,7 @@ static void gpencil_brush_cursor_draw(bContext *C, int x, int y, void *customdat
float darkcolor[3];
float radius = 3.0f;
- int mval_i[2] = {x, y};
+ const int mval_i[2] = {x, y};
/* Check if cursor is in drawing region and has valid data-block. */
if ((!gpencil_check_cursor_region(C, mval_i)) || (gpd == NULL)) {
return;
@@ -2962,7 +2962,7 @@ void ED_gpencil_projected_2d_bound_box(const GP_SpaceConversion *gsc,
bool ED_gpencil_stroke_check_collision(const GP_SpaceConversion *gsc,
bGPDstroke *gps,
- const float mouse[2],
+ const float mval[2],
const int radius,
const float diff_mat[4][4])
{
@@ -2980,7 +2980,7 @@ bool ED_gpencil_stroke_check_collision(const GP_SpaceConversion *gsc,
rcti rect_stroke = {boundbox_min[0], boundbox_max[0], boundbox_min[1], boundbox_max[1]};
/* For mouse, add a small offset to avoid false negative in corners. */
- rcti rect_mouse = {mouse[0] - offset, mouse[0] + offset, mouse[1] - offset, mouse[1] + offset};
+ rcti rect_mouse = {mval[0] - offset, mval[0] + offset, mval[1] - offset, mval[1] + offset};
/* Check collision between both rectangles. */
return BLI_rcti_isect(&rect_stroke, &rect_mouse, NULL);
@@ -2988,7 +2988,7 @@ bool ED_gpencil_stroke_check_collision(const GP_SpaceConversion *gsc,
bool ED_gpencil_stroke_point_is_inside(const bGPDstroke *gps,
const GP_SpaceConversion *gsc,
- const int mouse[2],
+ const int mval[2],
const float diff_mat[4][4])
{
bool hit = false;
@@ -3014,9 +3014,8 @@ bool ED_gpencil_stroke_point_is_inside(const bGPDstroke *gps,
BLI_lasso_boundbox(&rect, mcoords, len);
/* Test if point inside stroke. */
- hit = ((!ELEM(V2D_IS_CLIPPED, mouse[0], mouse[1])) &&
- BLI_rcti_isect_pt(&rect, mouse[0], mouse[1]) &&
- BLI_lasso_is_point_inside(mcoords, len, mouse[0], mouse[1], INT_MAX));
+ hit = ((!ELEM(V2D_IS_CLIPPED, mval[0], mval[1])) && BLI_rcti_isect_pt(&rect, mval[0], mval[1]) &&
+ BLI_lasso_is_point_inside(mcoords, len, mval[0], mval[1], INT_MAX));
/* Free memory. */
MEM_SAFE_FREE(mcoords);
@@ -3077,6 +3076,11 @@ bGPDstroke *ED_gpencil_stroke_nearest_to_ends(bContext *C,
continue;
}
+ /* Check that stroke is not closed. Closed strokes must not be included in the merge. */
+ if (gps_target->flag & GP_STROKE_CYCLIC) {
+ continue;
+ }
+
/* Check if one of the ends is inside target stroke bounding box. */
if ((!ED_gpencil_stroke_check_collision(gsc, gps_target, pt2d_start, radius, diff_mat)) &&
(!ED_gpencil_stroke_check_collision(gsc, gps_target, pt2d_end, radius, diff_mat))) {
diff --git a/source/blender/editors/gpencil/gpencil_vertex_ops.c b/source/blender/editors/gpencil/gpencil_vertex_ops.c
index c0888968a2d..865c4e360b5 100644
--- a/source/blender/editors/gpencil/gpencil_vertex_ops.c
+++ b/source/blender/editors/gpencil/gpencil_vertex_ops.c
@@ -587,7 +587,7 @@ static int gpencil_vertexpaint_set_exec(bContext *C, wmOperator *op)
srgb_to_linearrgb_v4(color, color);
for (i = 0, pt = gps->points; i < gps->totpoints; i++, pt++) {
if ((!any_selected) || (pt->flag & GP_SPOINT_SELECT)) {
- copy_v3_v3(pt->vert_color, color);
+ copy_v4_v4(pt->vert_color, color);
}
}
}
diff --git a/source/blender/editors/include/BIF_glutil.h b/source/blender/editors/include/BIF_glutil.h
index 3f1b8d6ecda..84512653a24 100644
--- a/source/blender/editors/include/BIF_glutil.h
+++ b/source/blender/editors/include/BIF_glutil.h
@@ -55,17 +55,17 @@ IMMDrawPixelsTexState immDrawPixelsTexSetup(int builtin);
* 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,
+ float x,
+ float y,
+ int img_w,
+ int img_h,
+ eGPUTextureFormat gpu_format,
+ bool use_filter,
const void *rect,
- const float scaleX,
- const float scaleY,
- const float xzoom,
- const float yzoom,
+ float scaleX,
+ float scaleY,
+ float xzoom,
+ float yzoom,
const float color[4]);
/**
diff --git a/source/blender/editors/include/ED_anim_api.h b/source/blender/editors/include/ED_anim_api.h
index 60af05baed7..da40eef87fd 100644
--- a/source/blender/editors/include/ED_anim_api.h
+++ b/source/blender/editors/include/ED_anim_api.h
@@ -549,7 +549,7 @@ typedef enum eAnimChannels_SetFlag {
/* types of settings for AnimChannels */
typedef enum eAnimChannel_Settings {
ACHANNEL_SETTING_SELECT = 0,
- /** warning: for drawing UI's, need to check if this is off (maybe inverse this later) */
+ /** WARNING: for drawing UI's, need to check if this is off (maybe inverse this later). */
ACHANNEL_SETTING_PROTECT = 1,
ACHANNEL_SETTING_MUTE = 2,
ACHANNEL_SETTING_EXPAND = 3,
diff --git a/source/blender/editors/include/ED_clip.h b/source/blender/editors/include/ED_clip.h
index 2c67b02611b..0f981e270a0 100644
--- a/source/blender/editors/include/ED_clip.h
+++ b/source/blender/editors/include/ED_clip.h
@@ -22,15 +22,53 @@ struct bScreen;
/* ** clip_editor.c ** */
-/* common poll functions */
+/* Returns true when the following conditions are met:
+ * - Current space is Space Clip.
+ * - There is a movie clip opened in it. */
bool ED_space_clip_poll(struct bContext *C);
+/* Returns true when the following conditions are met:
+ * - Current space is Space Clip.
+ * - It is set to Clip view.
+ *
+ * It is not required to have movie clip opened for editing. */
bool ED_space_clip_view_clip_poll(struct bContext *C);
+/* Returns true when the following conditions are met:
+ * - Current space is Space Clip.
+ * - It is set to Tracking mode.
+ *
+ * It is not required to have movie clip opened for editing. */
bool ED_space_clip_tracking_poll(struct bContext *C);
+
+/* Returns true when the following conditions are met:
+ * - Current space is Space Clip.
+ * - It is set to Mask mode.
+ *
+ * It is not required to have mask opened for editing. */
bool ED_space_clip_maskedit_poll(struct bContext *C);
+
+/* Returns true when the following conditions are met:
+ * - Current space is Space Clip.
+ * - It is set to Mask mode.
+ * - Mask has visible and editable splines.
+ *
+ * It is not required to have mask opened for editing. */
+bool ED_space_clip_maskedit_visible_splines_poll(struct bContext *C);
+
+/* Returns true when the following conditions are met:
+ * - Current space is Space Clip.
+ * - It is set to Mask mode.
+ * - The space has mask opened. */
bool ED_space_clip_maskedit_mask_poll(struct bContext *C);
+/* Returns true when the following conditions are met:
+ * - Current space is Space Clip.
+ * - It is set to Mask mode.
+ * - The space has mask opened.
+ * - Mask has visible and editable splines. */
+bool ED_space_clip_maskedit_mask_visible_splines_poll(struct bContext *C);
+
void ED_space_clip_get_size(struct SpaceClip *sc, int *width, int *height);
void ED_space_clip_get_size_fl(struct SpaceClip *sc, float size[2]);
void ED_space_clip_get_zoom(struct SpaceClip *sc,
@@ -60,7 +98,7 @@ bool ED_space_clip_get_position(struct SpaceClip *sc,
*/
bool ED_space_clip_color_sample(struct SpaceClip *sc,
struct ARegion *region,
- int mval[2],
+ const int mval[2],
float r_col[3]);
void ED_clip_update_frame(const struct Main *mainp, int cfra);
diff --git a/source/blender/editors/include/ED_curve.h b/source/blender/editors/include/ED_curve.h
index 9f4833bf1d7..061b783797d 100644
--- a/source/blender/editors/include/ED_curve.h
+++ b/source/blender/editors/include/ED_curve.h
@@ -49,10 +49,12 @@ void ED_curve_editnurb_free(struct Object *obedit);
/**
* \param dist_px: Maximum distance to pick (in pixels).
+ * \param vert_without_handles: When true, selecting the knot doesn't select the handles.
*/
bool ED_curve_editnurb_select_pick(struct bContext *C,
const int mval[2],
int dist_px,
+ bool vert_without_handles,
const struct SelectPick_Params *params);
struct Nurb *ED_curve_add_nurbs_primitive(
diff --git a/source/blender/editors/include/ED_datafiles.h b/source/blender/editors/include/ED_datafiles.h
index c3a66e4a7dd..e3b091430e8 100644
--- a/source/blender/editors/include/ED_datafiles.h
+++ b/source/blender/editors/include/ED_datafiles.h
@@ -103,6 +103,9 @@ extern const char datatoc_multiply_png[];
extern int datatoc_nudge_png_size;
extern const char datatoc_nudge_png[];
+extern int datatoc_paint_select_png_size;
+extern const char datatoc_paint_select_png[];
+
extern int datatoc_pinch_png_size;
extern const char datatoc_pinch_png[];
@@ -284,6 +287,41 @@ extern const char datatoc_gp_brush_erase_hard_png[];
extern int datatoc_gp_brush_erase_stroke_png_size;
extern const char datatoc_gp_brush_erase_stroke_png[];
+/* curves sculpt brushes files */
+
+extern int datatoc_curves_sculpt_add_png_size;
+extern const char datatoc_curves_sculpt_add_png[];
+
+extern int datatoc_curves_sculpt_comb_png_size;
+extern const char datatoc_curves_sculpt_comb_png[];
+
+extern int datatoc_curves_sculpt_cut_png_size;
+extern const char datatoc_curves_sculpt_cut_png[];
+
+extern int datatoc_curves_sculpt_delete_png_size;
+extern const char datatoc_curves_sculpt_delete_png[];
+
+extern int datatoc_curves_sculpt_density_png_size;
+extern const char datatoc_curves_sculpt_density_png[];
+
+extern int datatoc_curves_sculpt_grow_shrink_png_size;
+extern const char datatoc_curves_sculpt_grow_shrink_png[];
+
+extern int datatoc_curves_sculpt_pinch_png_size;
+extern const char datatoc_curves_sculpt_pinch_png[];
+
+extern int datatoc_curves_sculpt_puff_png_size;
+extern const char datatoc_curves_sculpt_puff_png[];
+
+extern int datatoc_curves_sculpt_slide_png_size;
+extern const char datatoc_curves_sculpt_slide_png[];
+
+extern int datatoc_curves_sculpt_smooth_png_size;
+extern const char datatoc_curves_sculpt_smooth_png[];
+
+extern int datatoc_curves_sculpt_snake_hook_png_size;
+extern const char datatoc_curves_sculpt_snake_hook_png[];
+
#ifdef __cplusplus
}
#endif
diff --git a/source/blender/editors/include/ED_fileselect.h b/source/blender/editors/include/ED_fileselect.h
index c367072e6e7..e9fcd2bd5fe 100644
--- a/source/blender/editors/include/ED_fileselect.h
+++ b/source/blender/editors/include/ED_fileselect.h
@@ -164,8 +164,16 @@ void ED_fileselect_window_params_get(const struct wmWindow *win,
int win_size[2],
bool *is_maximized);
+/**
+ * Return the File Browser area in which \a file_operator is active.
+ */
struct ScrArea *ED_fileselect_handler_area_find(const struct wmWindow *win,
const struct wmOperator *file_operator);
+/**
+ * Check if there is any area in \a win that acts as a modal File Browser (#SpaceFile.op is set)
+ * and return it.
+ */
+struct ScrArea *ED_fileselect_handler_area_find_any_with_op(const struct wmWindow *win);
/* TODO: Maybe we should move this to BLI?
* On the other hand, it's using defines from space-file area, so not sure... */
diff --git a/source/blender/editors/include/ED_geometry.h b/source/blender/editors/include/ED_geometry.h
index 74ff968828c..4620181894a 100644
--- a/source/blender/editors/include/ED_geometry.h
+++ b/source/blender/editors/include/ED_geometry.h
@@ -7,12 +7,22 @@
#pragma once
+#include "BKE_attribute.h"
+#include "DNA_customdata_types.h"
+
#ifdef __cplusplus
extern "C" {
#endif
-void ED_operatortypes_geometry(void);
+struct Mesh;
+void ED_operatortypes_geometry(void);
+bool ED_geometry_attribute_convert(struct Mesh *mesh,
+ const char *layer_name,
+ eCustomDataType old_type,
+ eAttrDomain old_domain,
+ eCustomDataType new_type,
+ eAttrDomain new_domain);
#ifdef __cplusplus
}
#endif
diff --git a/source/blender/editors/include/ED_gizmo_library.h b/source/blender/editors/include/ED_gizmo_library.h
index 067e5ba4d7f..31c1f93f5bc 100644
--- a/source/blender/editors/include/ED_gizmo_library.h
+++ b/source/blender/editors/include/ED_gizmo_library.h
@@ -14,6 +14,8 @@
extern "C" {
#endif
+#include "DNA_scene_types.h"
+
/* initialize gizmos */
void ED_gizmotypes_arrow_3d(void);
void ED_gizmotypes_button_2d(void);
@@ -223,24 +225,6 @@ enum {
/* -------------------------------------------------------------------- */
/* Specific gizmos utils */
-/* dial3d_gizmo.c */
-
-struct Dial3dParams {
- int draw_options;
- float angle_ofs;
- float angle_delta;
- float angle_increment;
- float arc_partial_angle;
- float arc_inner_factor;
- float *clip_plane;
-};
-void ED_gizmotypes_dial_3d_draw_util(const float matrix_basis[4][4],
- const float matrix_final[4][4],
- float line_width,
- const float color[4],
- bool select,
- struct Dial3dParams *params);
-
/* snap3d_gizmo.c */
struct SnapObjectContext *ED_gizmotypes_snap_3d_context_ensure(struct Scene *scene,
@@ -258,7 +242,7 @@ void ED_gizmotypes_snap_3d_data_get(const struct bContext *C,
float r_loc[3],
float r_nor[3],
int r_elem_index[3],
- int *r_snap_elem);
+ eSnapMode *r_snap_elem);
#ifdef __cplusplus
}
diff --git a/source/blender/editors/include/ED_gpencil.h b/source/blender/editors/include/ED_gpencil.h
index 01f60a81288..0943636a452 100644
--- a/source/blender/editors/include/ED_gpencil.h
+++ b/source/blender/editors/include/ED_gpencil.h
@@ -579,7 +579,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 float mval[2],
int radius,
const float diff_mat[4][4]);
/**
@@ -587,13 +587,13 @@ bool ED_gpencil_stroke_check_collision(const struct GP_SpaceConversion *gsc,
*
* \param gps: Stroke to check.
* \param gsc: Space conversion data.
- * \param mouse: Mouse position.
+ * \param mval: Region relative cursor position.
* \param diff_mat: View matrix.
* \return True if the point is inside.
*/
bool ED_gpencil_stroke_point_is_inside(const struct bGPDstroke *gps,
const struct GP_SpaceConversion *gsc,
- const int mouse[2],
+ const int mval[2],
const float diff_mat[4][4]);
/**
* Get the bigger 2D bound box points.
diff --git a/source/blender/editors/include/ED_image.h b/source/blender/editors/include/ED_image.h
index f79d3ce205d..91ae8286531 100644
--- a/source/blender/editors/include/ED_image.h
+++ b/source/blender/editors/include/ED_image.h
@@ -24,6 +24,7 @@ struct Scene;
struct SpaceImage;
struct View2D;
struct bContext;
+struct Paint;
struct wmOperator;
struct wmWindowManager;
@@ -63,8 +64,11 @@ bool ED_space_image_get_position(struct SpaceImage *sima,
/**
* Returns color in linear space, matching #ED_space_node_color_sample().
*/
-bool ED_space_image_color_sample(
- struct SpaceImage *sima, struct ARegion *region, int mval[2], float r_col[3], bool *r_is_data);
+bool ED_space_image_color_sample(struct SpaceImage *sima,
+ struct ARegion *region,
+ const int mval[2],
+ float r_col[3],
+ bool *r_is_data);
struct ImBuf *ED_space_image_acquire_buffer(struct SpaceImage *sima, void **r_lock, int tile);
/**
* Get the #SpaceImage flag that is valid for the given ibuf.
@@ -133,8 +137,39 @@ bool ED_space_image_paint_curve(const struct bContext *C);
* Matches clip function.
*/
bool ED_space_image_check_show_maskedit(struct SpaceImage *sima, struct Object *obedit);
+
+/* Returns true when the following conditions are met:
+ * - Current space is Image Editor.
+ * - The image editor is not a UV Editor.
+ * - It is set to Mask mode.
+ *
+ * It is not required to have mask opened for editing. */
bool ED_space_image_maskedit_poll(struct bContext *C);
+
+/* Returns true when the following conditions are met:
+ * - Current space is Image Editor.
+ * - The image editor is not a UV Editor.
+ * - It is set to Mask mode.
+ * - Mask has visible and editable splines.
+ *
+ * It is not required to have mask opened for editing. */
+bool ED_space_image_maskedit_visible_splines_poll(struct bContext *C);
+
+/* Returns true when the following conditions are met:
+ * - Current space is Image Editor.
+ * - The image editor is not an UV Editor.
+ * - It is set to Mask mode.
+ * - The space has mask opened. */
bool ED_space_image_maskedit_mask_poll(struct bContext *C);
+
+/* Returns true when the following conditions are met:
+ * - Current space is Image Editor.
+ * - The image editor is not an UV Editor.
+ * - It is set to Mask mode.
+ * - The space has mask opened.
+ * - Mask has visible and editable splines. */
+bool ED_space_image_maskedit_mask_visible_splines_poll(struct bContext *C);
+
bool ED_space_image_cursor_poll(struct bContext *C);
/**
@@ -173,6 +208,7 @@ typedef struct ImageFrameRange {
int length;
int offset;
/* UDIM tiles. */
+ bool udims_detected;
ListBase udim_tiles;
/* Temporary data. */
@@ -186,6 +222,9 @@ ListBase ED_image_filesel_detect_sequences(struct Main *bmain,
struct wmOperator *op,
bool detect_udim);
+bool ED_image_tools_paint_poll(struct bContext *C);
+void ED_paint_cursor_start(struct Paint *p, bool (*poll)(struct bContext *C));
+
#ifdef __cplusplus
}
#endif
diff --git a/source/blender/editors/include/ED_keyframing.h b/source/blender/editors/include/ED_keyframing.h
index 6a730225da9..a53042b70d6 100644
--- a/source/blender/editors/include/ED_keyframing.h
+++ b/source/blender/editors/include/ED_keyframing.h
@@ -351,6 +351,19 @@ int ANIM_scene_get_keyingset_index(struct Scene *scene, struct KeyingSet *ks);
struct KeyingSet *ANIM_get_keyingset_for_autokeying(const struct Scene *scene,
const char *transformKSName);
+void ANIM_keyingset_visit_for_search(const struct bContext *C,
+ struct PointerRNA *ptr,
+ struct PropertyRNA *prop,
+ const char *edit_text,
+ StringPropertySearchVisitFunc visit_fn,
+ void *visit_user_data);
+
+void ANIM_keyingset_visit_for_search_no_poll(const struct bContext *C,
+ struct PointerRNA *ptr,
+ struct PropertyRNA *prop,
+ const char *edit_text,
+ StringPropertySearchVisitFunc visit_fn,
+ void *visit_user_data);
/**
* Dynamically populate an enum of Keying Sets.
*/
@@ -645,15 +658,20 @@ bool ED_autokeyframe_pchan(struct bContext *C,
struct Object *ob,
struct bPoseChannel *pchan,
struct KeyingSet *ks);
+
/**
- * Use for auto-key-framing from the UI.
+ * Use for auto-key-framing
+ * \param only_if_property_keyed: if true, auto-key-framing only creates keyframes on already keyed
+ * properties. This is by design when using buttons. For other callers such as gizmos or VSE
+ * preview transform, creating new animation/keyframes also on non-keyed properties is desired.
*/
bool ED_autokeyframe_property(struct bContext *C,
struct Scene *scene,
PointerRNA *ptr,
PropertyRNA *prop,
int rnaindex,
- float cfra);
+ float cfra,
+ bool only_if_property_keyed);
/* Names for builtin keying sets so we don't confuse these with labels/text,
* defined in python script: `keyingsets_builtins.py`. */
diff --git a/source/blender/editors/include/ED_mask.h b/source/blender/editors/include/ED_mask.h
index 7039d6d9fc7..8cadbfde185 100644
--- a/source/blender/editors/include/ED_mask.h
+++ b/source/blender/editors/include/ED_mask.h
@@ -22,6 +22,34 @@ struct wmKeyConfig;
/* mask_edit.c */
+/* Returns true when the following conditions are met:
+ * - Current space supports mask editing.
+ * - The space is configured to interact with mask.
+ *
+ * It is not required to have mask opened for editing. */
+bool ED_maskedit_poll(struct bContext *C);
+
+/* Returns true when the following conditions are met:
+ * - Current space supports mask editing.
+ * - The space is configured to interact with mask.
+ * - Mask has visible and editable splines.
+ *
+ * It is not required to have mask opened for editing. */
+bool ED_maskedit_visible_splines_poll(struct bContext *C);
+
+/* Returns true when the following conditions are met:
+ * - Current space supports mask editing.
+ * - The space is configured to interact with mask.
+ * - The space has mask open for editing. */
+bool ED_maskedit_mask_poll(struct bContext *C);
+
+/* Returns true when the following conditions are met:
+ * - Current space supports mask editing.
+ * - The space is configured to interact with mask.
+ * - The space has mask opened.
+ * - Mask has visible and editable splines. */
+bool ED_maskedit_mask_visible_splines_poll(struct bContext *C);
+
void ED_mask_deselect_all(const struct bContext *C);
void ED_operatortypes_mask(void);
@@ -73,6 +101,7 @@ void ED_mask_draw_region(struct Depsgraph *depsgraph,
char draw_flag,
char draw_type,
eMaskOverlayMode overlay_mode,
+ float blend_factor,
int width_i,
int height_i,
float aspx,
diff --git a/source/blender/editors/include/ED_mesh.h b/source/blender/editors/include/ED_mesh.h
index 59a24ed22b6..30a98129ee6 100644
--- a/source/blender/editors/include/ED_mesh.h
+++ b/source/blender/editors/include/ED_mesh.h
@@ -384,7 +384,7 @@ void ED_operatormacros_mesh(void);
*/
void ED_keymap_mesh(struct wmKeyConfig *keyconf);
-/* editface.c */
+/* editface.cc */
/**
* Copy the face flags, most importantly selection from the mesh to the final derived mesh,
@@ -520,7 +520,7 @@ float ED_vgroup_vert_weight(struct Object *ob, struct bDeformGroup *dg, int vert
*/
void ED_vgroup_vert_active_mirror(struct Object *ob, int def_nr);
-/* mesh_data.c */
+/* mesh_data.cc */
void ED_mesh_verts_add(struct Mesh *mesh, struct ReportList *reports, int count);
void ED_mesh_edges_add(struct Mesh *mesh, struct ReportList *reports, int count);
@@ -536,12 +536,12 @@ 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(
+void ED_mesh_uv_ensure(struct Mesh *me, const char *name);
+int ED_mesh_uv_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);
+bool ED_mesh_uv_remove_index(struct Mesh *me, int n);
+bool ED_mesh_uv_remove_active(struct Mesh *me);
+bool ED_mesh_uv_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.
@@ -591,7 +591,7 @@ void EDBM_redo_state_restore_and_free(struct BMBackup *backup,
bool recalc_looptri) ATTR_NONNULL(1, 2);
void EDBM_redo_state_free(struct BMBackup *backup) ATTR_NONNULL(1);
-/* *** meshtools.c *** */
+/* *** meshtools.cc *** */
int ED_mesh_join_objects_exec(struct bContext *C, struct wmOperator *op);
int ED_mesh_shapes_join_objects_exec(struct bContext *C, struct wmOperator *op);
diff --git a/source/blender/editors/include/ED_object.h b/source/blender/editors/include/ED_object.h
index 28452ba8db9..39c7ad3556c 100644
--- a/source/blender/editors/include/ED_object.h
+++ b/source/blender/editors/include/ED_object.h
@@ -234,7 +234,7 @@ struct Base *ED_object_add_duplicate(struct Main *bmain,
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 char *name,
const int mval[2]);
/* bitflags for enter/exit editmode */
@@ -536,12 +536,12 @@ bool ED_object_modifier_move_to_index(struct ReportList *reports,
struct ModifierData *md,
int index);
-bool ED_object_modifier_convert(struct ReportList *reports,
- struct Main *bmain,
- struct Depsgraph *depsgraph,
- struct ViewLayer *view_layer,
- struct Object *ob,
- struct ModifierData *md);
+bool ED_object_modifier_convert_psys_to_mesh(struct ReportList *reports,
+ struct Main *bmain,
+ struct Depsgraph *depsgraph,
+ struct ViewLayer *view_layer,
+ struct Object *ob,
+ struct ModifierData *md);
bool ED_object_modifier_apply(struct Main *bmain,
struct ReportList *reports,
struct Depsgraph *depsgraph,
diff --git a/source/blender/editors/include/ED_scene.h b/source/blender/editors/include/ED_scene.h
index f1a2e5795ee..f67bdb9c1d7 100644
--- a/source/blender/editors/include/ED_scene.h
+++ b/source/blender/editors/include/ED_scene.h
@@ -18,6 +18,11 @@ struct Scene *ED_scene_add(struct Main *bmain,
struct bContext *C,
struct wmWindow *win,
enum eSceneCopyMethod method) ATTR_NONNULL();
+/** Special mode for adding a scene assigned to sequencer strip. */
+struct Scene *ED_scene_sequencer_add(struct Main *bmain,
+ struct bContext *C,
+ enum eSceneCopyMethod method,
+ const bool assign_strip);
/**
* \note Only call outside of area/region loops.
* \return true if successful.
diff --git a/source/blender/editors/include/ED_screen.h b/source/blender/editors/include/ED_screen.h
index 41123aff79f..a24c8625a63 100644
--- a/source/blender/editors/include/ED_screen.h
+++ b/source/blender/editors/include/ED_screen.h
@@ -595,8 +595,7 @@ bool ED_operator_object_active_local_editable_posemode_exclusive(struct bContext
bool ED_operator_posemode_context(struct bContext *C);
bool ED_operator_posemode(struct bContext *C);
bool ED_operator_posemode_local(struct bContext *C);
-bool ED_operator_mask(struct bContext *C);
-bool ED_operator_camera(struct bContext *C);
+bool ED_operator_camera_poll(struct bContext *C);
/* screen_user_menu.c */
@@ -666,7 +665,7 @@ bool ED_region_panel_category_gutter_calc_rect(const ARegion *region, rcti *r_re
bool ED_region_panel_category_gutter_isect_xy(const ARegion *region, const int event_xy[2]);
/**
- * \note: This may return true for multiple overlapping regions.
+ * \note This may return true for multiple overlapping regions.
* If it matters, check overlapped regions first (#ARegion.overlap).
*/
bool ED_region_contains_xy(const struct ARegion *region, const int event_xy[2]);
diff --git a/source/blender/editors/include/ED_sculpt.h b/source/blender/editors/include/ED_sculpt.h
index 54d67c50d5c..550040d2bc6 100644
--- a/source/blender/editors/include/ED_sculpt.h
+++ b/source/blender/editors/include/ED_sculpt.h
@@ -51,7 +51,7 @@ 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,
- const float mval[2]);
+ const float mval_fl[2]);
/* Undo for changes happening on a base mesh for multires sculpting.
* if there is no multi-res sculpt active regular undo is used. */
diff --git a/source/blender/editors/include/ED_select_utils.h b/source/blender/editors/include/ED_select_utils.h
index dbe1b582132..8c856794ec8 100644
--- a/source/blender/editors/include/ED_select_utils.h
+++ b/source/blender/editors/include/ED_select_utils.h
@@ -14,6 +14,7 @@ extern "C" {
struct KDTree_1d;
struct wmOperator;
+struct wmOperatorType;
enum {
SEL_TOGGLE = 0,
@@ -39,11 +40,11 @@ typedef enum {
} eSelectOp;
/* Select Similar */
-enum {
+typedef enum {
SIM_CMP_EQ = 0,
SIM_CMP_GT,
SIM_CMP_LT,
-};
+} eSimilarCmp;
#define SEL_OP_USE_OUTSIDE(sel_op) (ELEM(sel_op, SEL_OP_AND))
#define SEL_OP_USE_PRE_DESELECT(sel_op) (ELEM(sel_op, SEL_OP_SET))
@@ -62,11 +63,11 @@ int ED_select_op_action(eSelectOp sel_op, bool is_select, bool is_inside);
*/
int ED_select_op_action_deselected(eSelectOp sel_op, bool is_select, bool is_inside);
-int ED_select_similar_compare_float(float delta, float thresh, int compare);
+bool ED_select_similar_compare_float(float delta, float thresh, eSimilarCmp compare);
bool ED_select_similar_compare_float_tree(const struct KDTree_1d *tree,
float length,
float thresh,
- int compare);
+ eSimilarCmp compare);
/**
* Utility to use for selection operations that run multiple times (circle select).
@@ -96,16 +97,23 @@ struct SelectPick_Params {
/**
* Utility to get #eSelectPickMode from booleans for convenience.
*/
-eSelectOp ED_select_op_from_operator(struct wmOperator *op)
+eSelectOp ED_select_op_from_operator(struct PointerRNA *ptr)
ATTR_NONNULL(1) ATTR_WARN_UNUSED_RESULT;
/**
* Initialize `params` from `op`,
* these properties are defined by #WM_operator_properties_mouse_select.
*/
-void ED_select_pick_params_from_operator(struct wmOperator *op, struct SelectPick_Params *params)
+void ED_select_pick_params_from_operator(struct PointerRNA *ptr, struct SelectPick_Params *params)
ATTR_NONNULL(1, 2);
+/**
+ * Get-name callback for #wmOperatorType.get_name, this is mainly useful so the selection
+ * action is shown in the status-bar.
+ */
+const char *ED_select_pick_get_name(struct wmOperatorType *ot, PointerRNA *ptr);
+const char *ED_select_circle_get_name(struct wmOperatorType *ot, PointerRNA *ptr);
+
#ifdef __cplusplus
}
#endif
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 2919001c5ce..20353c21f93 100644
--- a/source/blender/editors/include/ED_transform_snap_object_context.h
+++ b/source/blender/editors/include/ED_transform_snap_object_context.h
@@ -6,6 +6,8 @@
#pragma once
+#include "DNA_scene_types.h"
+
#ifdef __cplusplus
extern "C" {
#endif
@@ -25,14 +27,6 @@ struct View3D;
/* ED_transform_snap_object_*** API */
-typedef enum eSnapSelect {
- SNAP_ALL = 0,
- SNAP_NOT_SELECTED = 1,
- SNAP_NOT_ACTIVE = 2,
- SNAP_NOT_EDITED = 3,
- SNAP_SELECTABLE = 4,
-} eSnapSelect;
-
typedef enum eSnapEditType {
SNAP_GEOM_FINAL = 0,
SNAP_GEOM_CAGE = 1,
@@ -59,7 +53,7 @@ struct SnapObjectHitDepth {
/** parameters that define which objects will be used to snap. */
struct SnapObjectParams {
/* Special context sensitive handling for the active or selected object. */
- eSnapSelect snap_select;
+ eSnapTargetSelect snap_target_select;
/* Geometry for snapping in edit mode. */
eSnapEditType edit_mode_type;
/* snap to the closest element, use when using more than one snap type */
@@ -120,21 +114,21 @@ bool ED_transform_snap_object_project_ray_all(SnapObjectContext *sctx,
bool sort,
struct ListBase *r_hit_list);
-short ED_transform_snap_object_project_view3d_ex(struct SnapObjectContext *sctx,
- struct Depsgraph *depsgraph,
- const ARegion *region,
- const View3D *v3d,
- unsigned short snap_to,
- const struct SnapObjectParams *params,
- const float mval[2],
- const float prev_co[3],
- float *dist_px,
- float r_loc[3],
- float r_no[3],
- int *r_index,
- struct Object **r_ob,
- float r_obmat[4][4],
- float r_face_nor[3]);
+eSnapMode ED_transform_snap_object_project_view3d_ex(struct SnapObjectContext *sctx,
+ struct Depsgraph *depsgraph,
+ const ARegion *region,
+ const View3D *v3d,
+ eSnapMode snap_to,
+ const struct SnapObjectParams *params,
+ const float mval[2],
+ const float prev_co[3],
+ float *dist_px,
+ float r_loc[3],
+ float r_no[3],
+ int *r_index,
+ struct Object **r_ob,
+ float r_obmat[4][4],
+ float r_face_nor[3]);
/**
* Convenience function for performing snapping.
*
@@ -148,18 +142,18 @@ short ED_transform_snap_object_project_view3d_ex(struct SnapObjectContext *sctx,
* \param r_no: hit normal (optional).
* \return Snap success.
*/
-short ED_transform_snap_object_project_view3d(struct SnapObjectContext *sctx,
- struct Depsgraph *depsgraph,
- const ARegion *region,
- const View3D *v3d,
- unsigned short snap_to,
- const struct SnapObjectParams *params,
- const float mval[2],
- const float prev_co[3],
- float *dist_px,
- /* return args */
- float r_loc[3],
- float r_no[3]);
+eSnapMode ED_transform_snap_object_project_view3d(struct SnapObjectContext *sctx,
+ struct Depsgraph *depsgraph,
+ const ARegion *region,
+ const View3D *v3d,
+ eSnapMode snap_to,
+ const struct SnapObjectParams *params,
+ const float mval[2],
+ const float prev_co[3],
+ float *dist_px,
+ /* return args */
+ float r_loc[3],
+ float r_no[3]);
/**
* see: #ED_transform_snap_object_project_ray_all
diff --git a/source/blender/editors/include/ED_uvedit.h b/source/blender/editors/include/ED_uvedit.h
index 54d36f44f82..80a75da27f8 100644
--- a/source/blender/editors/include/ED_uvedit.h
+++ b/source/blender/editors/include/ED_uvedit.h
@@ -266,6 +266,10 @@ struct BMLoop **ED_uvedit_selected_verts(const struct Scene *scene,
int *r_verts_len);
void ED_uvedit_get_aspect(struct Object *obedit, float *r_aspx, float *r_aspy);
+void ED_uvedit_get_aspect_from_material(Object *ob,
+ const int material_index,
+ float *r_aspx,
+ float *r_aspy);
void ED_uvedit_active_vert_loop_set(struct BMesh *bm, struct BMLoop *l);
struct BMLoop *ED_uvedit_active_vert_loop_get(struct BMesh *bm);
diff --git a/source/blender/editors/include/ED_view3d.h b/source/blender/editors/include/ED_view3d.h
index 414643dd0d6..0298983ed26 100644
--- a/source/blender/editors/include/ED_view3d.h
+++ b/source/blender/editors/include/ED_view3d.h
@@ -7,6 +7,9 @@
#pragma once
+#include "BLI_utildefines.h"
+#include "DNA_scene_types.h"
+
#ifdef __cplusplus
extern "C" {
#endif
@@ -256,6 +259,7 @@ typedef enum {
*/
V3D_PROJ_TEST_CLIP_CONTENT = (1 << 5),
} eV3DProjTest;
+ENUM_OPERATORS(eV3DProjTest, V3D_PROJ_TEST_CLIP_CONTENT);
#define V3D_PROJ_TEST_CLIP_DEFAULT \
(V3D_PROJ_TEST_CLIP_BB | V3D_PROJ_TEST_CLIP_WIN | V3D_PROJ_TEST_CLIP_NEAR)
@@ -296,7 +300,7 @@ typedef enum {
} eV3DPlaceOrient;
typedef struct V3DSnapCursorData {
- short snap_elem;
+ eSnapMode snap_elem;
float loc[3];
float nor[3];
float obmat[4][4];
@@ -319,7 +323,7 @@ typedef struct V3DSnapCursorState {
struct wmGizmoGroupType *gzgrp_type; /* Force cursor to be drawn only when gizmo is available. */
float *prevpoint;
float box_dimensions[3];
- short snap_elem_force; /* If zero, use scene settings. */
+ eSnapMode snap_elem_force; /* If SCE_SNAP_MODE_NONE, use scene settings. */
short plane_axis;
bool use_plane_axis_auto;
bool draw_point;
@@ -344,7 +348,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],
- short snap_elem_type);
+ eSnapMode snap_elem_type);
/* view3d_iterators.c */
@@ -443,14 +447,14 @@ void pose_foreachScreenBone(struct ViewContext *vc,
void ED_view3d_project_float_v2_m4(const struct ARegion *region,
const float co[3],
float r_co[2],
- float mat[4][4]);
+ const float mat[4][4]);
/**
* \note use #ED_view3d_ob_project_mat_get to get projecting mat
*/
void ED_view3d_project_float_v3_m4(const struct ARegion *region,
const float co[3],
float r_co[3],
- float mat[4][4]);
+ const float mat[4][4]);
eV3DProjStatus ED_view3d_project_base(const struct ARegion *region, struct Base *base);
@@ -700,9 +704,9 @@ void ED_view3d_win_to_vector(const struct ARegion *region, const float mval[2],
* \param do_clip_planes: Optionally clip the ray by the view clipping planes.
* \return success, false if the segment is totally clipped.
*/
-bool ED_view3d_win_to_segment_clipped(struct Depsgraph *depsgraph,
+bool ED_view3d_win_to_segment_clipped(const struct Depsgraph *depsgraph,
const struct ARegion *region,
- struct View3D *v3d,
+ const struct View3D *v3d,
const float mval[2],
float r_ray_start[3],
float r_ray_end[3],
@@ -733,7 +737,7 @@ void ED_view3d_dist_range_get(const struct View3D *v3d, float r_dist_range[2]);
/**
* \note copies logic of #ED_view3d_viewplane_get(), keep in sync.
*/
-bool ED_view3d_clip_range_get(struct Depsgraph *depsgraph,
+bool ED_view3d_clip_range_get(const struct Depsgraph *depsgraph,
const struct View3D *v3d,
const struct RegionView3D *rv3d,
float *r_clipsta,
@@ -1080,6 +1084,16 @@ bool ED_view3d_quat_to_axis_view(const float viewquat[4],
float epsilon,
char *r_view,
char *r_view_axis_rotation);
+/**
+ * A version of #ED_view3d_quat_to_axis_view that updates `viewquat`
+ * if it's within `epsilon` to an axis-view.
+ *
+ * \note Include the special case function since most callers need to perform these operations.
+ */
+bool ED_view3d_quat_to_axis_view_and_reset_quat(float viewquat[4],
+ float epsilon,
+ char *r_view,
+ char *r_view_axis_rotation);
char ED_view3d_lock_view_from_index(int index);
char ED_view3d_axis_view_opposite(char view);
diff --git a/source/blender/editors/include/UI_grid_view.hh b/source/blender/editors/include/UI_grid_view.hh
new file mode 100644
index 00000000000..6f553f4fad1
--- /dev/null
+++ b/source/blender/editors/include/UI_grid_view.hh
@@ -0,0 +1,264 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+
+/** \file
+ * \ingroup editorui
+ *
+ * API for simple creation of grid UIs, supporting typically needed features.
+ * https://wiki.blender.org/wiki/Source/Interface/Views/Grid_Views
+ */
+
+#pragma once
+
+#include "BLI_function_ref.hh"
+#include "BLI_map.hh"
+#include "BLI_vector.hh"
+
+#include "UI_resources.h"
+
+struct bContext;
+struct PreviewImage;
+struct uiBlock;
+struct uiButGridTile;
+struct uiLayout;
+struct View2D;
+struct wmNotifier;
+
+namespace blender::ui {
+
+class AbstractGridView;
+
+/* ---------------------------------------------------------------------- */
+/** \name Grid-View Item Type
+ * \{ */
+
+class AbstractGridViewItem {
+ friend class AbstractGridView;
+ friend class GridViewLayoutBuilder;
+
+ const AbstractGridView *view_;
+
+ bool is_active_ = false;
+
+ protected:
+ /** Reference to a string that uniquely identifies this item in the view. */
+ StringRef identifier_{};
+ /** Every visible item gets a button of type #UI_BTYPE_GRID_TILE during the layout building. */
+ uiButGridTile *grid_tile_but_ = nullptr;
+
+ public:
+ virtual ~AbstractGridViewItem() = default;
+
+ virtual void build_grid_tile(uiLayout &layout) const = 0;
+
+ /**
+ * Compare this item's identifier to \a other to check if they represent the same data.
+ * Used to recognize an item from a previous redraw, to be able to keep its state (e.g. active,
+ * renaming, etc.).
+ */
+ bool matches(const AbstractGridViewItem &other) const;
+
+ const AbstractGridView &get_view() const;
+
+ /**
+ * Requires the tree to have completed reconstruction, see #is_reconstructed(). Otherwise we
+ * can't be sure about the item state.
+ */
+ bool is_active() const;
+
+ protected:
+ AbstractGridViewItem(StringRef identifier);
+
+ /** Called when the item's state changes from inactive to active. */
+ virtual void on_activate();
+ /**
+ * If the result is not empty, it controls whether the item should be active or not,
+ * usually depending on the data that the view represents.
+ */
+ virtual std::optional<bool> should_be_active() const;
+
+ /**
+ * Copy persistent state (e.g. active, selection, etc.) from a matching item of
+ * the last redraw to this item. If sub-classes introduce more advanced state they should
+ * override this and make it update their state accordingly.
+ */
+ virtual void update_from_old(const AbstractGridViewItem &old);
+
+ /**
+ * Activates this item, deactivates other items, and calls the
+ * #AbstractGridViewItem::on_activate() function.
+ * Requires the tree to have completed reconstruction, see #is_reconstructed(). Otherwise the
+ * actual item state is unknown, possibly calling state-change update functions incorrectly.
+ */
+ void activate();
+ void deactivate();
+
+ private:
+ /** See #AbstractTreeView::change_state_delayed() */
+ void change_state_delayed();
+ static void grid_tile_click_fn(bContext *, void *but_arg1, void *);
+ void add_grid_tile_button(uiBlock &block);
+};
+
+/** \} */
+
+/* ---------------------------------------------------------------------- */
+/** \name Grid-View Base Class
+ * \{ */
+
+struct GridViewStyle {
+ GridViewStyle(int width, int height);
+ int tile_width = 0;
+ int tile_height = 0;
+};
+
+class AbstractGridView {
+ friend class AbstractGridViewItem;
+ friend class GridViewBuilder;
+ friend class GridViewLayoutBuilder;
+
+ protected:
+ Vector<std::unique_ptr<AbstractGridViewItem>> items_;
+ /** <identifier, item> map to lookup items by identifier, used for efficient lookups in
+ * #update_from_old(). */
+ Map<StringRef, AbstractGridViewItem *> item_map_;
+ GridViewStyle style_;
+ bool is_reconstructed_ = false;
+
+ public:
+ AbstractGridView();
+ virtual ~AbstractGridView() = default;
+
+ using ItemIterFn = FunctionRef<void(AbstractGridViewItem &)>;
+ void foreach_item(ItemIterFn iter_fn) const;
+
+ /** Listen to a notifier, returning true if a redraw is needed. */
+ virtual bool listen(const wmNotifier &) const;
+
+ /**
+ * Convenience wrapper constructing the item by forwarding given arguments to the constructor of
+ * the type (\a ItemT).
+ *
+ * E.g. if your grid-item type has the following constructor:
+ * \code{.cpp}
+ * MyGridItem(std::string str, int i);
+ * \endcode
+ * You can add an item like this:
+ * \code
+ * add_item<MyGridItem>("blabla", 42);
+ * \endcode
+ */
+ template<class ItemT, typename... Args> inline ItemT &add_item(Args &&...args);
+ const GridViewStyle &get_style() const;
+ int get_item_count() const;
+
+ protected:
+ virtual void build_items() = 0;
+
+ /**
+ * Check if the view is fully (re-)constructed. That means, both #build_items() and
+ * #update_from_old() have finished.
+ */
+ bool is_reconstructed() const;
+
+ private:
+ /**
+ * Match the grid-view against an earlier version of itself (if any) and copy the old UI state
+ * (e.g. active, selected, renaming, etc.) to the new one. See
+ * #AbstractGridViewItem.update_from_old().
+ */
+ void update_from_old(uiBlock &new_block);
+ AbstractGridViewItem *find_matching_item(const AbstractGridViewItem &item_to_match,
+ const AbstractGridView &view_to_search_in) const;
+ /**
+ * Items may want to do additional work when state changes. But these state changes can only be
+ * reliably detected after the view has completed reconstruction (see #is_reconstructed()). So
+ * the actual state changes are done in a delayed manner through this function.
+ */
+ void change_state_delayed();
+
+ /**
+ * Add an already constructed item, moving ownership to the grid-view.
+ * All items must be added through this, it handles important invariants!
+ */
+ AbstractGridViewItem &add_item(std::unique_ptr<AbstractGridViewItem> item);
+};
+
+/** \} */
+
+/* ---------------------------------------------------------------------- */
+/** \name Grid-View Builder
+ *
+ * TODO unify this with `TreeViewBuilder` and call view-specific functions via type erased view?
+ * \{ */
+
+class GridViewBuilder {
+ uiBlock &block_;
+
+ public:
+ GridViewBuilder(uiBlock &block);
+
+ /** Build \a grid_view into the previously provided block, clipped by \a view_bounds (view space,
+ * typically `View2D.cur`). */
+ void build_grid_view(AbstractGridView &grid_view, const View2D &v2d);
+};
+
+/** \} */
+
+/* ---------------------------------------------------------------------- */
+/** \name Predefined Grid-View Item Types
+ *
+ * Common, Basic Grid-View Item Types.
+ * \{ */
+
+/**
+ * A grid item that shows preview image icons at a nicely readable size (multiple of the normal UI
+ * unit size).
+ */
+class PreviewGridItem : public AbstractGridViewItem {
+ public:
+ using IsActiveFn = std::function<bool()>;
+ using ActivateFn = std::function<void(PreviewGridItem &new_active)>;
+
+ protected:
+ /** See #set_on_activate_fn() */
+ ActivateFn activate_fn_;
+ /** See #set_is_active_fn() */
+ IsActiveFn is_active_fn_;
+
+ public:
+ std::string label{};
+ int preview_icon_id = ICON_NONE;
+
+ PreviewGridItem(StringRef identifier, StringRef label, int preview_icon_id);
+
+ void build_grid_tile(uiLayout &layout) const override;
+
+ /**
+ * Set a custom callback to execute when activating this view item. This way users don't have to
+ * sub-class #PreviewGridItem, just to implement custom activation behavior (a common thing to
+ * do).
+ */
+ void set_on_activate_fn(ActivateFn fn);
+ /**
+ * Set a custom callback to check if this item should be active.
+ */
+ void set_is_active_fn(IsActiveFn fn);
+
+ private:
+ std::optional<bool> should_be_active() const override;
+ void on_activate() override;
+};
+
+/** \} */
+
+/* ---------------------------------------------------------------------- */
+
+template<class ItemT, typename... Args> inline ItemT &AbstractGridView::add_item(Args &&...args)
+{
+ static_assert(std::is_base_of<AbstractGridViewItem, ItemT>::value,
+ "Type must derive from and implement the AbstractGridViewItem interface");
+
+ return dynamic_cast<ItemT &>(add_item(std::make_unique<ItemT>(std::forward<Args>(args)...)));
+}
+
+} // namespace blender::ui
diff --git a/source/blender/editors/include/UI_icons.h b/source/blender/editors/include/UI_icons.h
index d1a6501408c..f1c0acf43f7 100644
--- a/source/blender/editors/include/UI_icons.h
+++ b/source/blender/editors/include/UI_icons.h
@@ -164,7 +164,7 @@ DEF_ICON(NLA)
DEF_ICON(PREFERENCES)
DEF_ICON(TIME)
DEF_ICON(NODETREE)
-DEF_ICON_BLANK(181)
+DEF_ICON(GEOMETRY_NODES)
DEF_ICON(CONSOLE)
DEF_ICON_BLANK(183)
DEF_ICON(TRACKER)
@@ -891,6 +891,7 @@ DEF_ICON_COLOR(BRUSH_LAYER)
DEF_ICON_COLOR(BRUSH_MASK)
DEF_ICON_COLOR(BRUSH_MIX)
DEF_ICON_COLOR(BRUSH_NUDGE)
+DEF_ICON_COLOR(BRUSH_PAINT_SELECT)
DEF_ICON_COLOR(BRUSH_PINCH)
DEF_ICON_COLOR(BRUSH_SCRAPE)
DEF_ICON_COLOR(BRUSH_SCULPT_DRAW)
@@ -903,7 +904,6 @@ DEF_ICON_COLOR(BRUSH_TEXFILL)
DEF_ICON_COLOR(BRUSH_TEXMASK)
DEF_ICON_COLOR(BRUSH_THUMB)
DEF_ICON_COLOR(BRUSH_ROTATE)
-DEF_ICON_COLOR(BRUSH_PAINT)
/* grease pencil sculpt */
DEF_ICON_COLOR(GPBRUSH_SMOOTH)
@@ -929,6 +929,19 @@ DEF_ICON_COLOR(GPBRUSH_ERASE_SOFT)
DEF_ICON_COLOR(GPBRUSH_ERASE_HARD)
DEF_ICON_COLOR(GPBRUSH_ERASE_STROKE)
+/* Curves sculpt. */
+DEF_ICON_COLOR(BRUSH_CURVES_ADD)
+DEF_ICON_COLOR(BRUSH_CURVES_COMB)
+DEF_ICON_COLOR(BRUSH_CURVES_CUT)
+DEF_ICON_COLOR(BRUSH_CURVES_DELETE)
+DEF_ICON_COLOR(BRUSH_CURVES_DENSITY)
+DEF_ICON_COLOR(BRUSH_CURVES_GROW_SHRINK)
+DEF_ICON_COLOR(BRUSH_CURVES_PINCH)
+DEF_ICON_COLOR(BRUSH_CURVES_PUFF)
+DEF_ICON_COLOR(BRUSH_CURVES_SLIDE)
+DEF_ICON_COLOR(BRUSH_CURVES_SMOOTH)
+DEF_ICON_COLOR(BRUSH_CURVES_SNAKE_HOOK)
+
/* Vector icons. */
DEF_ICON_VECTOR(KEYTYPE_KEYFRAME_VEC)
DEF_ICON_VECTOR(KEYTYPE_BREAKDOWN_VEC)
diff --git a/source/blender/editors/include/UI_interface.h b/source/blender/editors/include/UI_interface.h
index 301171a284d..b2ec2102ddd 100644
--- a/source/blender/editors/include/UI_interface.h
+++ b/source/blender/editors/include/UI_interface.h
@@ -64,6 +64,7 @@ struct wmKeyMapItem;
struct wmMsgBus;
struct wmOperator;
struct wmOperatorType;
+struct wmRegionListenerParams;
struct wmWindow;
typedef struct uiBlock uiBlock;
@@ -75,6 +76,10 @@ typedef struct uiPopupBlockHandle uiPopupBlockHandle;
typedef struct uiTreeViewHandle uiTreeViewHandle;
/* C handle for C++ #ui::AbstractTreeViewItem type. */
typedef struct uiTreeViewItemHandle uiTreeViewItemHandle;
+/* C handle for C++ #ui::AbstractGridView type. */
+typedef struct uiGridViewHandle uiGridViewHandle;
+/* C handle for C++ #ui::AbstractGridViewItem type. */
+typedef struct uiGridViewItemHandle uiGridViewItemHandle;
/* Defines */
@@ -184,26 +189,26 @@ enum {
/** #uiBut.flag general state flags. */
enum {
- /* WARNING: the first 7 flags are internal (see #UI_SELECT definition). */
- UI_BUT_ICON_SUBMENU = 1 << 7,
- UI_BUT_ICON_PREVIEW = 1 << 8,
+ /* WARNING: the first 8 flags are internal (see #UI_SELECT definition). */
+ UI_BUT_ICON_SUBMENU = 1 << 8,
+ UI_BUT_ICON_PREVIEW = 1 << 9,
- UI_BUT_NODE_LINK = 1 << 9,
- UI_BUT_NODE_ACTIVE = 1 << 10,
- UI_BUT_DRAG_LOCK = 1 << 11,
+ UI_BUT_NODE_LINK = 1 << 10,
+ UI_BUT_NODE_ACTIVE = 1 << 11,
+ UI_BUT_DRAG_LOCK = 1 << 12,
/** Grayed out and un-editable. */
- UI_BUT_DISABLED = 1 << 12,
+ UI_BUT_DISABLED = 1 << 13,
- UI_BUT_ANIMATED = 1 << 13,
- UI_BUT_ANIMATED_KEY = 1 << 14,
- UI_BUT_DRIVEN = 1 << 15,
- UI_BUT_REDALERT = 1 << 16,
+ UI_BUT_ANIMATED = 1 << 14,
+ UI_BUT_ANIMATED_KEY = 1 << 15,
+ UI_BUT_DRIVEN = 1 << 16,
+ UI_BUT_REDALERT = 1 << 17,
/** Grayed out but still editable. */
- UI_BUT_INACTIVE = 1 << 17,
- UI_BUT_LAST_ACTIVE = 1 << 18,
- UI_BUT_UNDO = 1 << 19,
- UI_BUT_IMMEDIATE = 1 << 20,
- UI_BUT_NO_UTF8 = 1 << 21,
+ UI_BUT_INACTIVE = 1 << 18,
+ UI_BUT_LAST_ACTIVE = 1 << 19,
+ UI_BUT_UNDO = 1 << 20,
+ /* UNUSED = 1 << 21, */
+ UI_BUT_NO_UTF8 = 1 << 22,
/** For popups, pressing return activates this button, overriding the highlighted button.
* For non-popups this is just used as a display hint for the user to let them
@@ -390,6 +395,8 @@ typedef enum {
UI_BTYPE_DECORATOR = 58 << 9,
/* An item in a tree view. Parent items may be collapsible. */
UI_BTYPE_TREEROW = 59 << 9,
+ /* An item in a grid view. */
+ UI_BTYPE_GRID_TILE = 60 << 9,
} eButType;
#define BUTTYPE (63 << 9)
@@ -454,7 +461,6 @@ void UI_draw_safe_areas(uint pos,
enum {
UI_SCROLL_PRESSED = 1 << 0,
UI_SCROLL_ARROWS = 1 << 1,
- UI_SCROLL_NO_OUTLINE = 1 << 2,
};
/**
* Function in use for buttons and for view2d sliders.
@@ -852,33 +858,6 @@ void UI_block_translate(uiBlock *block, int x, int y);
int UI_but_return_value_get(uiBut *but);
-void UI_but_drag_set_id(uiBut *but, struct ID *id);
-/**
- * Set an image to display while dragging. This works for any drag type (`WM_DRAG_XXX`).
- * Not to be confused with #UI_but_drag_set_image(), which sets up dragging of an image.
- */
-void UI_but_drag_attach_image(uiBut *but, struct ImBuf *imb, float scale);
-/**
- * \param asset: May be passed from a temporary variable, drag data only stores a copy of this.
- */
-void UI_but_drag_set_asset(uiBut *but,
- const struct AssetHandle *asset,
- const char *path,
- struct AssetMetaData *metadata,
- int import_type, /* eFileAssetImportType */
- int icon,
- 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, 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, bool use_free);
-
uiBut *UI_but_active_drop_name_button(const struct bContext *C);
/**
* Returns true if highlighted button allows drop of names.
@@ -1539,31 +1518,6 @@ uiBut *uiDefIconTextBlockBut(uiBlock *block,
short height,
const char *tip);
-uiBut *uiDefKeyevtButS(uiBlock *block,
- int retval,
- const char *str,
- int x,
- int y,
- short width,
- short height,
- short *spoin,
- const char *tip);
-
-/**
- * Short pointers hard-coded.
- * \param modkeypoin: will be set to #KM_SHIFT, #KM_ALT, #KM_CTRL, #KM_OSKEY bits.
- */
-uiBut *uiDefHotKeyevtButS(uiBlock *block,
- int retval,
- const char *str,
- int x,
- int y,
- short width,
- short height,
- short *keypoin,
- const short *modkeypoin,
- const char *tip);
-
/**
* \param arg: A pointer to string/name, use #UI_but_func_search_set() below to make this work.
* here `a1` and `a2`, if set, control thumbnail preview rows/cols.
@@ -1674,15 +1628,16 @@ void UI_but_func_identity_compare_set(uiBut *but, uiButIdentityCompareFunc cmp_f
* \param name: Text to display for the item.
* \param poin: Opaque pointer (for use by the caller).
* \param iconid: The icon, #ICON_NONE for no icon.
- * \param state: The buttons state flag, compatible with #uiBut.flag,
- * typically #UI_BUT_DISABLED / #UI_BUT_INACTIVE.
+ * \param but_flag: Button flags (#uiBut.flag) indicating the state of the item, typically
+ * #UI_BUT_DISABLED, #UI_BUT_INACTIVE or #UI_BUT_HAS_SEP_CHAR.
+ *
* \return false if there is nothing to add.
*/
bool UI_search_item_add(uiSearchItems *items,
const char *name,
void *poin,
int iconid,
- int state,
+ int but_flag,
uint8_t name_prefix_offset);
/**
@@ -1792,6 +1747,14 @@ struct PointerRNA *UI_but_extra_operator_icon_add(uiBut *but,
struct wmOperatorType *UI_but_extra_operator_icon_optype_get(struct uiButExtraOpIcon *extra_icon);
struct PointerRNA *UI_but_extra_operator_icon_opptr_get(struct uiButExtraOpIcon *extra_icon);
+/**
+ * A decent size for a button (typically #UI_BTYPE_PREVIEW_TILE) to display a nicely readable
+ * preview with label in.
+ */
+int UI_preview_tile_size_x(void);
+int UI_preview_tile_size_y(void);
+int UI_preview_tile_size_y_no_label(void);
+
/* Autocomplete
*
* Tab complete helper functions, for use in uiButCompleteFunc callbacks.
@@ -1808,6 +1771,38 @@ AutoComplete *UI_autocomplete_begin(const char *startname, size_t maxlen);
void UI_autocomplete_update_name(AutoComplete *autocpl, const char *name);
int UI_autocomplete_end(AutoComplete *autocpl, char *autoname);
+/* Button drag-data (interface_drag.cc).
+ *
+ * Functions to set drag data for buttons. This enables dragging support, whereby the drag data is
+ * "dragged", not the button itself. */
+
+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, float scale);
+/**
+ * \param asset: May be passed from a temporary variable, drag data only stores a copy of this.
+ */
+void UI_but_drag_set_asset(uiBut *but,
+ const struct AssetHandle *asset,
+ const char *path,
+ struct AssetMetaData *metadata,
+ int import_type, /* eFileAssetImportType */
+ int icon,
+ 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, 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, bool use_free);
+
/* Panels
*
* Functions for creating, freeing and drawing panels. The API here
@@ -1891,7 +1886,7 @@ struct PointerRNA *UI_region_panel_custom_data_under_cursor(const struct bContex
const struct wmEvent *event);
void UI_panel_custom_data_set(struct Panel *panel, struct PointerRNA *custom_data);
-/* Polyinstantiated panels for representing a list of data. */
+/* Poly-instantiated panels for representing a list of data. */
/**
* Called in situations where panels need to be added dynamically rather than
* having only one panel corresponding to each #PanelType.
@@ -3205,7 +3200,12 @@ void UI_interface_tag_script_reload(void);
/* Support click-drag motion which presses the button and closes a popover (like a menu). */
#define USE_UI_POPOVER_ONCE
+void UI_block_views_listen(const uiBlock *block,
+ const struct wmRegionListenerParams *listener_params);
+
+bool UI_grid_view_item_is_active(const uiGridViewItemHandle *item_handle);
bool UI_tree_view_item_is_active(const uiTreeViewItemHandle *item);
+bool UI_grid_view_item_matches(const uiGridViewItemHandle *a, const uiGridViewItemHandle *b);
bool UI_tree_view_item_matches(const uiTreeViewItemHandle *a, const uiTreeViewItemHandle *b);
/**
* Attempt to start dragging the tree-item \a item_. This will not work if the tree item doesn't
@@ -3243,6 +3243,15 @@ uiTreeViewItemHandle *UI_block_tree_view_find_item_at(const struct ARegion *regi
const int xy[2]) ATTR_NONNULL(1, 2);
uiTreeViewItemHandle *UI_block_tree_view_find_active_item(const struct ARegion *region);
+/**
+ * Listen to \a notifier, returning true if the region should redraw.
+ */
+bool UI_tree_view_listen_should_redraw(const uiTreeViewHandle *view, const wmNotifier *notifier);
+/**
+ * Listen to \a notifier, returning true if the region should redraw.
+ */
+bool UI_grid_view_listen_should_redraw(const uiGridViewHandle *view, const wmNotifier *notifier);
+
#ifdef __cplusplus
}
#endif
diff --git a/source/blender/editors/include/UI_interface.hh b/source/blender/editors/include/UI_interface.hh
index db43ec54431..3dc56b01993 100644
--- a/source/blender/editors/include/UI_interface.hh
+++ b/source/blender/editors/include/UI_interface.hh
@@ -23,6 +23,7 @@ struct uiSearchItems;
namespace blender::ui {
+class AbstractGridView;
class AbstractTreeView;
/**
@@ -55,6 +56,10 @@ void attribute_search_add_items(
/**
* Override this for all available tree types.
*/
+blender::ui::AbstractGridView *UI_block_add_view(
+ uiBlock &block,
+ blender::StringRef idname,
+ std::unique_ptr<blender::ui::AbstractGridView> tree_view);
blender::ui::AbstractTreeView *UI_block_add_view(
uiBlock &block,
blender::StringRef idname,
diff --git a/source/blender/editors/include/UI_interface_icons.h b/source/blender/editors/include/UI_interface_icons.h
index 6416421f4f5..a1a98a4b08c 100644
--- a/source/blender/editors/include/UI_interface_icons.h
+++ b/source/blender/editors/include/UI_interface_icons.h
@@ -92,7 +92,7 @@ void UI_icon_render_id_ex(const struct bContext *C,
int UI_icon_preview_to_render_size(enum eIconSizes size);
/**
- * Draws icon with dpi scale factor.
+ * Draws icon with DPI scale factor.
*/
void UI_icon_draw(float x, float y, int icon_id);
void UI_icon_draw_alpha(float x, float y, int icon_id, float alpha);
diff --git a/source/blender/editors/include/UI_tree_view.hh b/source/blender/editors/include/UI_tree_view.hh
index 5504e426f34..1aeb13ca5cc 100644
--- a/source/blender/editors/include/UI_tree_view.hh
+++ b/source/blender/editors/include/UI_tree_view.hh
@@ -28,6 +28,7 @@ struct uiButTreeRow;
struct uiLayout;
struct wmDrag;
struct wmEvent;
+struct wmNotifier;
namespace blender::ui {
@@ -128,6 +129,9 @@ class AbstractTreeView : public TreeViewItemContainer {
void foreach_item(ItemIterFn iter_fn, IterOptions options = IterOptions::None) const;
+ /** Listen to a notifier, returning true if a redraw is needed. */
+ virtual bool listen(const wmNotifier &) const;
+
/** Only one item can be renamed at a time. */
bool is_renaming() const;
@@ -185,7 +189,7 @@ class AbstractTreeViewItem : public TreeViewItemContainer {
bool is_renaming_ = false;
protected:
- /** This label is used for identifying an item within its parent. */
+ /** This label is used as the default way to identifying an item within its parent. */
std::string label_{};
/** Every visible item gets a button of type #UI_BTYPE_TREEROW during the layout building. */
uiButTreeRow *tree_row_but_ = nullptr;
diff --git a/source/blender/editors/interface/CMakeLists.txt b/source/blender/editors/interface/CMakeLists.txt
index 444bb08f3fb..2a1852bd6e7 100644
--- a/source/blender/editors/interface/CMakeLists.txt
+++ b/source/blender/editors/interface/CMakeLists.txt
@@ -25,12 +25,14 @@ set(INC
)
set(SRC
+ grid_view.cc
interface.cc
interface_align.c
interface_anim.c
interface_button_group.c
interface_context_menu.c
interface_context_path.cc
+ interface_drag.cc
interface_draw.c
interface_dropboxes.cc
interface_eyedropper.c
diff --git a/source/blender/editors/interface/grid_view.cc b/source/blender/editors/interface/grid_view.cc
new file mode 100644
index 00000000000..a82cb7798fe
--- /dev/null
+++ b/source/blender/editors/interface/grid_view.cc
@@ -0,0 +1,525 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+
+/** \file
+ * \ingroup edinterface
+ */
+
+#include <limits>
+#include <stdexcept>
+
+#include "BLI_index_range.hh"
+
+#include "WM_types.h"
+
+#include "UI_interface.h"
+#include "interface_intern.h"
+
+#include "UI_grid_view.hh"
+
+namespace blender::ui {
+
+/* ---------------------------------------------------------------------- */
+
+AbstractGridView::AbstractGridView() : style_(UI_preview_tile_size_x(), UI_preview_tile_size_y())
+{
+}
+
+AbstractGridViewItem &AbstractGridView::add_item(std::unique_ptr<AbstractGridViewItem> item)
+{
+ items_.append(std::move(item));
+
+ AbstractGridViewItem &added_item = *items_.last();
+ added_item.view_ = this;
+
+ item_map_.add(added_item.identifier_, &added_item);
+
+ return added_item;
+}
+
+void AbstractGridView::foreach_item(ItemIterFn iter_fn) const
+{
+ for (auto &item_ptr : items_) {
+ iter_fn(*item_ptr);
+ }
+}
+
+bool AbstractGridView::listen(const wmNotifier &) const
+{
+ /* Nothing by default. */
+ return false;
+}
+
+AbstractGridViewItem *AbstractGridView::find_matching_item(
+ const AbstractGridViewItem &item_to_match, const AbstractGridView &view_to_search_in) const
+{
+ AbstractGridViewItem *const *match = view_to_search_in.item_map_.lookup_ptr(
+ item_to_match.identifier_);
+ BLI_assert(!match || item_to_match.matches(**match));
+
+ return match ? *match : nullptr;
+}
+
+void AbstractGridView::change_state_delayed()
+{
+ BLI_assert_msg(
+ is_reconstructed(),
+ "These state changes are supposed to be delayed until reconstruction is completed");
+ foreach_item([](AbstractGridViewItem &item) { item.change_state_delayed(); });
+}
+
+void AbstractGridView::update_from_old(uiBlock &new_block)
+{
+ uiGridViewHandle *old_view_handle = ui_block_grid_view_find_matching_in_old_block(
+ &new_block, reinterpret_cast<uiGridViewHandle *>(this));
+ if (!old_view_handle) {
+ /* Initial construction, nothing to update. */
+ is_reconstructed_ = true;
+ return;
+ }
+
+ AbstractGridView &old_view = reinterpret_cast<AbstractGridView &>(*old_view_handle);
+
+ foreach_item([this, &old_view](AbstractGridViewItem &new_item) {
+ const AbstractGridViewItem *matching_old_item = find_matching_item(new_item, old_view);
+ if (!matching_old_item) {
+ return;
+ }
+
+ new_item.update_from_old(*matching_old_item);
+ });
+
+ /* Finished (re-)constructing the tree. */
+ is_reconstructed_ = true;
+}
+
+bool AbstractGridView::is_reconstructed() const
+{
+ return is_reconstructed_;
+}
+
+const GridViewStyle &AbstractGridView::get_style() const
+{
+ return style_;
+}
+
+int AbstractGridView::get_item_count() const
+{
+ return items_.size();
+}
+
+GridViewStyle::GridViewStyle(int width, int height) : tile_width(width), tile_height(height)
+{
+}
+
+/* ---------------------------------------------------------------------- */
+
+AbstractGridViewItem::AbstractGridViewItem(StringRef identifier) : identifier_(identifier)
+{
+}
+
+bool AbstractGridViewItem::matches(const AbstractGridViewItem &other) const
+{
+ return identifier_ == other.identifier_;
+}
+
+void AbstractGridViewItem::grid_tile_click_fn(struct bContext * /*C*/,
+ void *but_arg1,
+ void * /*arg2*/)
+{
+ uiButGridTile *grid_tile_but = (uiButGridTile *)but_arg1;
+ AbstractGridViewItem &grid_item = reinterpret_cast<AbstractGridViewItem &>(
+ *grid_tile_but->view_item);
+
+ grid_item.activate();
+}
+
+void AbstractGridViewItem::add_grid_tile_button(uiBlock &block)
+{
+ const GridViewStyle &style = get_view().get_style();
+ grid_tile_but_ = (uiButGridTile *)uiDefBut(&block,
+ UI_BTYPE_GRID_TILE,
+ 0,
+ "",
+ 0,
+ 0,
+ style.tile_width,
+ style.tile_height,
+ nullptr,
+ 0,
+ 0,
+ 0,
+ 0,
+ "");
+
+ grid_tile_but_->view_item = reinterpret_cast<uiGridViewItemHandle *>(this);
+ UI_but_func_set(&grid_tile_but_->but, grid_tile_click_fn, grid_tile_but_, nullptr);
+}
+
+bool AbstractGridViewItem::is_active() const
+{
+ BLI_assert_msg(get_view().is_reconstructed(),
+ "State can't be queried until reconstruction is completed");
+ return is_active_;
+}
+
+void AbstractGridViewItem::on_activate()
+{
+ /* Do nothing by default. */
+}
+
+std::optional<bool> AbstractGridViewItem::should_be_active() const
+{
+ return std::nullopt;
+}
+
+void AbstractGridViewItem::change_state_delayed()
+{
+ const std::optional<bool> should_be_active = this->should_be_active();
+ if (should_be_active.has_value() && *should_be_active) {
+ activate();
+ }
+}
+
+void AbstractGridViewItem::update_from_old(const AbstractGridViewItem &old)
+{
+ is_active_ = old.is_active_;
+}
+
+void AbstractGridViewItem::activate()
+{
+ BLI_assert_msg(get_view().is_reconstructed(),
+ "Item activation can't be done until reconstruction is completed");
+
+ if (is_active()) {
+ return;
+ }
+
+ /* Deactivate other items in the tree. */
+ get_view().foreach_item([](auto &item) { item.deactivate(); });
+
+ on_activate();
+
+ is_active_ = true;
+}
+
+void AbstractGridViewItem::deactivate()
+{
+ is_active_ = false;
+}
+
+const AbstractGridView &AbstractGridViewItem::get_view() const
+{
+ if (UNLIKELY(!view_)) {
+ throw std::runtime_error(
+ "Invalid state, item must be added through AbstractGridView::add_item()");
+ }
+ return *view_;
+}
+
+/* ---------------------------------------------------------------------- */
+
+/**
+ * Helper for only adding layout items for grid items that are actually in view. 3 main functions:
+ * - #is_item_visible(): Query if an item of a given index is visible in the view (others should be
+ * skipped when building the layout).
+ * - #fill_layout_before_visible(): Add empty space to the layout before a visible row is drawn, so
+ * the layout height is the same as if all items were added (important to get the correct scroll
+ * height).
+ * - #fill_layout_after_visible(): Same thing, just adds empty space for after the last visible
+ * row.
+ *
+ * Does two assumptions:
+ * - Top-to-bottom flow (ymax = 0 and ymin < 0). If that's not good enough, View2D should
+ * probably provide queries for the scroll offset.
+ * - Only vertical scrolling. For horizontal scrolling, spacers would have to be added on the
+ * side(s) as well.
+ */
+class BuildOnlyVisibleButtonsHelper {
+ const View2D &v2d_;
+ const AbstractGridView &grid_view_;
+ const GridViewStyle &style_;
+ const int cols_per_row_ = 0;
+ /* Indices of items within the view. Calculated by constructor */
+ IndexRange visible_items_range_{};
+
+ public:
+ BuildOnlyVisibleButtonsHelper(const View2D &,
+ const AbstractGridView &grid_view,
+ int cols_per_row);
+
+ bool is_item_visible(int item_idx) const;
+ void fill_layout_before_visible(uiBlock &) const;
+ void fill_layout_after_visible(uiBlock &) const;
+
+ private:
+ IndexRange get_visible_range() const;
+ void add_spacer_button(uiBlock &, int row_count) const;
+};
+
+BuildOnlyVisibleButtonsHelper::BuildOnlyVisibleButtonsHelper(const View2D &v2d,
+ const AbstractGridView &grid_view,
+ const int cols_per_row)
+ : v2d_(v2d), grid_view_(grid_view), style_(grid_view.get_style()), cols_per_row_(cols_per_row)
+{
+ visible_items_range_ = get_visible_range();
+}
+
+IndexRange BuildOnlyVisibleButtonsHelper::get_visible_range() const
+{
+ int first_idx_in_view = 0;
+ int max_items_in_view = 0;
+
+ const float scroll_ofs_y = abs(v2d_.cur.ymax - v2d_.tot.ymax);
+ if (!IS_EQF(scroll_ofs_y, 0)) {
+ const int scrolled_away_rows = (int)scroll_ofs_y / style_.tile_height;
+
+ first_idx_in_view = scrolled_away_rows * cols_per_row_;
+ }
+
+ const float view_height = BLI_rctf_size_y(&v2d_.cur);
+ const int count_rows_in_view = std::max(round_fl_to_int(view_height / style_.tile_height), 1);
+ max_items_in_view = (count_rows_in_view + 1) * cols_per_row_;
+
+ BLI_assert(max_items_in_view > 0);
+ return IndexRange(first_idx_in_view, max_items_in_view);
+}
+
+bool BuildOnlyVisibleButtonsHelper::is_item_visible(const int item_idx) const
+{
+ return visible_items_range_.contains(item_idx);
+}
+
+void BuildOnlyVisibleButtonsHelper::fill_layout_before_visible(uiBlock &block) const
+{
+ const float scroll_ofs_y = abs(v2d_.cur.ymax - v2d_.tot.ymax);
+
+ if (IS_EQF(scroll_ofs_y, 0)) {
+ return;
+ }
+
+ const int scrolled_away_rows = (int)scroll_ofs_y / style_.tile_height;
+ add_spacer_button(block, scrolled_away_rows);
+}
+
+void BuildOnlyVisibleButtonsHelper::fill_layout_after_visible(uiBlock &block) const
+{
+ const int last_item_idx = grid_view_.get_item_count() - 1;
+ const int last_visible_idx = visible_items_range_.last();
+
+ if (last_item_idx > last_visible_idx) {
+ const int remaining_rows = (cols_per_row_ > 0) ?
+ (last_item_idx - last_visible_idx) / cols_per_row_ :
+ 0;
+ BuildOnlyVisibleButtonsHelper::add_spacer_button(block, remaining_rows);
+ }
+}
+
+void BuildOnlyVisibleButtonsHelper::add_spacer_button(uiBlock &block, const int row_count) const
+{
+ /* UI code only supports button dimensions of `signed short` size, the layout height we want to
+ * fill may be bigger than that. So add multiple labels of the maximum size if necessary. */
+ for (int remaining_rows = row_count; remaining_rows > 0;) {
+ const short row_count_this_iter = std::min(
+ std::numeric_limits<short>::max() / style_.tile_height, remaining_rows);
+
+ uiDefBut(&block,
+ UI_BTYPE_LABEL,
+ 0,
+ "",
+ 0,
+ 0,
+ UI_UNIT_X,
+ row_count_this_iter * style_.tile_height,
+ nullptr,
+ 0,
+ 0,
+ 0,
+ 0,
+ "");
+ remaining_rows -= row_count_this_iter;
+ }
+}
+
+/* ---------------------------------------------------------------------- */
+
+class GridViewLayoutBuilder {
+ uiBlock &block_;
+
+ friend class GridViewBuilder;
+
+ public:
+ GridViewLayoutBuilder(uiBlock &block);
+
+ void build_from_view(const AbstractGridView &grid_view, const View2D &v2d) const;
+
+ private:
+ void build_grid_tile(uiLayout &grid_layout, AbstractGridViewItem &item) const;
+
+ uiLayout *current_layout() const;
+};
+
+GridViewLayoutBuilder::GridViewLayoutBuilder(uiBlock &block) : block_(block)
+{
+}
+
+void GridViewLayoutBuilder::build_grid_tile(uiLayout &grid_layout,
+ AbstractGridViewItem &item) const
+{
+ uiLayout *overlap = uiLayoutOverlap(&grid_layout);
+
+ item.add_grid_tile_button(block_);
+ item.build_grid_tile(*uiLayoutRow(overlap, false));
+}
+
+void GridViewLayoutBuilder::build_from_view(const AbstractGridView &grid_view,
+ const View2D &v2d) const
+{
+ uiLayout *prev_layout = current_layout();
+
+ uiLayout &layout = *uiLayoutColumn(current_layout(), false);
+ const GridViewStyle &style = grid_view.get_style();
+
+ const int cols_per_row = std::max(uiLayoutGetWidth(&layout) / style.tile_width, 1);
+
+ BuildOnlyVisibleButtonsHelper build_visible_helper(v2d, grid_view, cols_per_row);
+
+ build_visible_helper.fill_layout_before_visible(block_);
+
+ /* Use `-cols_per_row` because the grid layout uses a multiple of the passed absolute value for
+ * the number of columns then, rather than distributing the number of items evenly over rows and
+ * stretching the items to fit (see #uiLayoutItemGridFlow.columns_len). */
+ uiLayout *grid_layout = uiLayoutGridFlow(&layout, true, -cols_per_row, true, true, true);
+
+ int item_idx = 0;
+ grid_view.foreach_item([&](AbstractGridViewItem &item) {
+ /* Skip if item isn't visible. */
+ if (!build_visible_helper.is_item_visible(item_idx)) {
+ item_idx++;
+ return;
+ }
+
+ build_grid_tile(*grid_layout, item);
+ item_idx++;
+ });
+
+ /* If there are not enough items to fill the layout, add padding items so the layout doesn't
+ * stretch over the entire width. */
+ if (grid_view.get_item_count() < cols_per_row) {
+ for (int padding_item_idx = 0; padding_item_idx < (cols_per_row - grid_view.get_item_count());
+ padding_item_idx++) {
+ uiItemS(grid_layout);
+ }
+ }
+
+ UI_block_layout_set_current(&block_, prev_layout);
+
+ build_visible_helper.fill_layout_after_visible(block_);
+}
+
+uiLayout *GridViewLayoutBuilder::current_layout() const
+{
+ return block_.curlayout;
+}
+
+/* ---------------------------------------------------------------------- */
+
+GridViewBuilder::GridViewBuilder(uiBlock &block) : block_(block)
+{
+}
+
+void GridViewBuilder::build_grid_view(AbstractGridView &grid_view, const View2D &v2d)
+{
+ grid_view.build_items();
+ grid_view.update_from_old(block_);
+ grid_view.change_state_delayed();
+
+ GridViewLayoutBuilder builder(block_);
+ builder.build_from_view(grid_view, v2d);
+}
+
+/* ---------------------------------------------------------------------- */
+
+PreviewGridItem::PreviewGridItem(StringRef identifier, StringRef label, int preview_icon_id)
+ : AbstractGridViewItem(identifier), label(label), preview_icon_id(preview_icon_id)
+{
+}
+
+void PreviewGridItem::build_grid_tile(uiLayout &layout) const
+{
+ const GridViewStyle &style = get_view().get_style();
+ uiBlock *block = uiLayoutGetBlock(&layout);
+
+ uiBut *but = uiDefBut(block,
+ UI_BTYPE_PREVIEW_TILE,
+ 0,
+ label.c_str(),
+ 0,
+ 0,
+ style.tile_width,
+ style.tile_height,
+ nullptr,
+ 0,
+ 0,
+ 0,
+ 0,
+ "");
+ ui_def_but_icon(but,
+ preview_icon_id,
+ /* NOLINTNEXTLINE: bugprone-suspicious-enum-usage */
+ UI_HAS_ICON | UI_BUT_ICON_PREVIEW);
+}
+
+void PreviewGridItem::set_on_activate_fn(ActivateFn fn)
+{
+ activate_fn_ = fn;
+}
+
+void PreviewGridItem::set_is_active_fn(IsActiveFn fn)
+{
+ is_active_fn_ = fn;
+}
+
+void PreviewGridItem::on_activate()
+{
+ if (activate_fn_) {
+ activate_fn_(*this);
+ }
+}
+
+std::optional<bool> PreviewGridItem::should_be_active() const
+{
+ if (is_active_fn_) {
+ return is_active_fn_();
+ }
+ return std::nullopt;
+}
+
+} // namespace blender::ui
+
+using namespace blender::ui;
+
+/* ---------------------------------------------------------------------- */
+/* C-API */
+
+using namespace blender::ui;
+
+bool UI_grid_view_item_is_active(const uiGridViewItemHandle *item_handle)
+{
+ const AbstractGridViewItem &item = reinterpret_cast<const AbstractGridViewItem &>(*item_handle);
+ return item.is_active();
+}
+
+bool UI_grid_view_listen_should_redraw(const uiGridViewHandle *view_handle,
+ const wmNotifier *notifier)
+{
+ const AbstractGridView &view = *reinterpret_cast<const AbstractGridView *>(view_handle);
+ return view.listen(*notifier);
+}
+
+bool UI_grid_view_item_matches(const uiGridViewItemHandle *a_handle,
+ const uiGridViewItemHandle *b_handle)
+{
+ const AbstractGridViewItem &a = reinterpret_cast<const AbstractGridViewItem &>(*a_handle);
+ const AbstractGridViewItem &b = reinterpret_cast<const AbstractGridViewItem &>(*b_handle);
+ return a.matches(b);
+}
diff --git a/source/blender/editors/interface/interface.cc b/source/blender/editors/interface/interface.cc
index b7098c26bcd..3f623566807 100644
--- a/source/blender/editors/interface/interface.cc
+++ b/source/blender/editors/interface/interface.cc
@@ -778,6 +778,15 @@ static bool ui_but_equals_old(const uiBut *but, const uiBut *oldbut)
}
}
+ if ((but->type == UI_BTYPE_GRID_TILE) && (oldbut->type == UI_BTYPE_GRID_TILE)) {
+ uiButGridTile *but_gridtile = (uiButGridTile *)but;
+ uiButGridTile *oldbut_gridtile = (uiButGridTile *)oldbut;
+ if (!but_gridtile->view_item || !oldbut_gridtile->view_item ||
+ !UI_grid_view_item_matches(but_gridtile->view_item, oldbut_gridtile->view_item)) {
+ return false;
+ }
+ }
+
return true;
}
@@ -904,6 +913,12 @@ static void ui_but_update_old_active_from_new(uiBut *oldbut, uiBut *but)
SWAP(uiTreeViewItemHandle *, treerow_newbut->tree_item, treerow_oldbut->tree_item);
break;
}
+ case UI_BTYPE_GRID_TILE: {
+ uiButGridTile *gridtile_oldbut = (uiButGridTile *)oldbut;
+ uiButGridTile *gridtile_newbut = (uiButGridTile *)but;
+ SWAP(uiGridViewItemHandle *, gridtile_newbut->view_item, gridtile_oldbut->view_item);
+ break;
+ }
default:
break;
}
@@ -927,9 +942,12 @@ static void ui_but_update_old_active_from_new(uiBut *oldbut, uiBut *but)
BLI_strncpy(oldbut->strdata, but->strdata, sizeof(oldbut->strdata));
}
- if (but->dragpoin && (but->dragflag & UI_BUT_DRAGPOIN_FREE)) {
+ if (but->dragpoin) {
SWAP(void *, but->dragpoin, oldbut->dragpoin);
}
+ if (but->imb) {
+ SWAP(ImBuf *, but->imb, oldbut->imb);
+ }
/* NOTE: if layout hasn't been applied yet, it uses old button pointers... */
}
@@ -993,9 +1011,9 @@ static bool ui_but_update_from_old_block(const bContext *C,
else {
int flag_copy = UI_BUT_DRAG_MULTI;
- /* Stupid special case: The active button may be inside (as in, overlapped on top) a tree-row
+ /* Stupid special case: The active button may be inside (as in, overlapped on top) a view-item
* button which we also want to keep highlighted then. */
- if (but->type == UI_BTYPE_TREEROW) {
+ if (ui_but_is_view_item(but)) {
flag_copy |= UI_ACTIVE;
}
@@ -1861,15 +1879,32 @@ bool ui_but_context_poll_operator_ex(bContext *C,
const wmOperatorCallParams *optype_params)
{
bool result;
+ int old_but_flag = 0;
- if (but && but->context) {
- CTX_store_set(C, but->context);
+ if (but) {
+ old_but_flag = but->flag;
+
+ /* Temporarily make this button override the active one, in case the poll acts on the active
+ * button. */
+ const_cast<uiBut *>(but)->flag |= UI_BUT_ACTIVE_OVERRIDE;
+
+ if (but->context) {
+ CTX_store_set(C, but->context);
+ }
}
result = WM_operator_poll_context(C, optype_params->optype, optype_params->opcontext);
- if (but && but->context) {
- CTX_store_set(C, nullptr);
+ if (but) {
+ BLI_assert_msg((but->flag & ~UI_BUT_ACTIVE_OVERRIDE) ==
+ (old_but_flag & ~UI_BUT_ACTIVE_OVERRIDE),
+ "Operator polls shouldn't change button flags");
+
+ const_cast<uiBut *>(but)->flag = old_but_flag;
+
+ if (but->context) {
+ CTX_store_set(C, nullptr);
+ }
}
return result;
@@ -2219,6 +2254,15 @@ int ui_but_is_pushed_ex(uiBut *but, double *value)
}
break;
}
+ case UI_BTYPE_GRID_TILE: {
+ uiButGridTile *grid_tile_but = (uiButGridTile *)but;
+
+ is_push = -1;
+ if (grid_tile_but->view_item) {
+ is_push = UI_grid_view_item_is_active(grid_tile_but->view_item);
+ }
+ break;
+ }
default:
is_push = -1;
break;
@@ -3425,9 +3469,7 @@ static void ui_but_free(const bContext *C, uiBut *but)
IMB_freeImBuf((struct ImBuf *)but->poin);
}
- if (but->dragpoin && (but->dragflag & UI_BUT_DRAGPOIN_FREE)) {
- WM_drag_data_free(but->dragtype, but->dragpoin);
- }
+ ui_but_drag_free(but);
ui_but_extra_operator_icons_free(but);
BLI_assert(UI_butstore_is_registered(but->block, but) == false);
@@ -3832,21 +3874,22 @@ static void ui_but_update_ex(uiBut *but, const bool validate)
}
case UI_BTYPE_HOTKEY_EVENT:
if (but->flag & UI_SELECT) {
+ const uiButHotkeyEvent *hotkey_but = (uiButHotkeyEvent *)but;
- if (but->modifier_key) {
+ if (hotkey_but->modifier_key) {
char *str = but->drawstr;
but->drawstr[0] = '\0';
- if (but->modifier_key & KM_SHIFT) {
+ if (hotkey_but->modifier_key & KM_SHIFT) {
str += BLI_strcpy_rlen(str, "Shift ");
}
- if (but->modifier_key & KM_CTRL) {
+ if (hotkey_but->modifier_key & KM_CTRL) {
str += BLI_strcpy_rlen(str, "Ctrl ");
}
- if (but->modifier_key & KM_ALT) {
+ if (hotkey_but->modifier_key & KM_ALT) {
str += BLI_strcpy_rlen(str, "Alt ");
}
- if (but->modifier_key & KM_OSKEY) {
+ if (hotkey_but->modifier_key & KM_OSKEY) {
str += BLI_strcpy_rlen(str, "Cmd ");
}
@@ -3972,6 +4015,14 @@ static void ui_but_alloc_info(const eButType type,
alloc_size = sizeof(uiButTreeRow);
alloc_str = "uiButTreeRow";
break;
+ case UI_BTYPE_HOTKEY_EVENT:
+ alloc_size = sizeof(uiButHotkeyEvent);
+ alloc_str = "uiButHotkeyEvent";
+ break;
+ case UI_BTYPE_GRID_TILE:
+ alloc_size = sizeof(uiButGridTile);
+ alloc_str = "uiButGridTile";
+ break;
default:
alloc_size = sizeof(uiBut);
alloc_str = "uiBut";
@@ -4946,6 +4997,33 @@ int UI_autocomplete_end(AutoComplete *autocpl, char *autoname)
return match;
}
+#define PREVIEW_TILE_PAD (0.15f * UI_UNIT_X)
+
+int UI_preview_tile_size_x(void)
+{
+ const float pad = PREVIEW_TILE_PAD;
+ return round_fl_to_int((96.0f / 20.0f) * UI_UNIT_X + 2.0f * pad);
+}
+
+int UI_preview_tile_size_y(void)
+{
+ const uiStyle *style = UI_style_get();
+ const float font_height = style->widget.points * UI_DPI_FAC;
+ const float pad = PREVIEW_TILE_PAD;
+
+ return round_fl_to_int(UI_preview_tile_size_y_no_label() + font_height +
+ /* Add some extra padding to make things less tight vertically. */
+ pad);
+}
+
+int UI_preview_tile_size_y_no_label(void)
+{
+ const float pad = PREVIEW_TILE_PAD;
+ return round_fl_to_int((96.0f / 20.0f) * UI_UNIT_Y + 2.0f * pad);
+}
+
+#undef PREVIEW_TILE_PAD
+
static void ui_but_update_and_icon_set(uiBut *but, int icon)
{
if (icon) {
@@ -5856,104 +5934,6 @@ int UI_but_return_value_get(uiBut *but)
return but->retval;
}
-void UI_but_drag_set_id(uiBut *but, ID *id)
-{
- but->dragtype = WM_DRAG_ID;
- if (but->dragflag & UI_BUT_DRAGPOIN_FREE) {
- WM_drag_data_free(but->dragtype, but->dragpoin);
- but->dragflag &= ~UI_BUT_DRAGPOIN_FREE;
- }
- but->dragpoin = (void *)id;
-}
-
-void UI_but_drag_attach_image(uiBut *but, struct ImBuf *imb, const float scale)
-{
- but->imb = imb;
- but->imb_scale = scale;
-}
-
-void UI_but_drag_set_asset(uiBut *but,
- const AssetHandle *asset,
- const char *path,
- struct AssetMetaData *metadata,
- int import_type,
- int icon,
- struct ImBuf *imb,
- float scale)
-{
- wmDragAsset *asset_drag = WM_drag_create_asset_data(asset, metadata, path, import_type);
-
- /* FIXME: This is temporary evil solution to get scene/viewlayer/etc in the copy callback of the
- * #wmDropBox.
- * TODO: Handle link/append in operator called at the end of the drop process, and NOT in its
- * copy callback.
- * */
- asset_drag->evil_C = static_cast<bContext *>(but->block->evil_C);
-
- but->dragtype = WM_DRAG_ASSET;
- ui_def_but_icon(but, icon, 0); /* no flag UI_HAS_ICON, so icon doesn't draw in button */
- if (but->dragflag & UI_BUT_DRAGPOIN_FREE) {
- WM_drag_data_free(but->dragtype, but->dragpoin);
- }
- but->dragpoin = asset_drag;
- but->dragflag |= UI_BUT_DRAGPOIN_FREE;
- UI_but_drag_attach_image(but, imb, scale);
-}
-
-void UI_but_drag_set_rna(uiBut *but, PointerRNA *ptr)
-{
- but->dragtype = WM_DRAG_RNA;
- if (but->dragflag & UI_BUT_DRAGPOIN_FREE) {
- WM_drag_data_free(but->dragtype, but->dragpoin);
- but->dragflag &= ~UI_BUT_DRAGPOIN_FREE;
- }
- but->dragpoin = (void *)ptr;
-}
-
-void UI_but_drag_set_path(uiBut *but, const char *path, const bool use_free)
-{
- but->dragtype = WM_DRAG_PATH;
- if (but->dragflag & UI_BUT_DRAGPOIN_FREE) {
- WM_drag_data_free(but->dragtype, but->dragpoin);
- but->dragflag &= ~UI_BUT_DRAGPOIN_FREE;
- }
- but->dragpoin = (void *)path;
- if (use_free) {
- but->dragflag |= UI_BUT_DRAGPOIN_FREE;
- }
-}
-
-void UI_but_drag_set_name(uiBut *but, const char *name)
-{
- but->dragtype = WM_DRAG_NAME;
- if (but->dragflag & UI_BUT_DRAGPOIN_FREE) {
- WM_drag_data_free(but->dragtype, but->dragpoin);
- but->dragflag &= ~UI_BUT_DRAGPOIN_FREE;
- }
- but->dragpoin = (void *)name;
-}
-
-void UI_but_drag_set_value(uiBut *but)
-{
- but->dragtype = WM_DRAG_VALUE;
-}
-
-void UI_but_drag_set_image(
- uiBut *but, const char *path, int icon, struct ImBuf *imb, float scale, const bool use_free)
-{
- but->dragtype = WM_DRAG_PATH;
- ui_def_but_icon(but, icon, 0); /* no flag UI_HAS_ICON, so icon doesn't draw in button */
- if (but->dragflag & UI_BUT_DRAGPOIN_FREE) {
- WM_drag_data_free(but->dragtype, but->dragpoin);
- but->dragflag &= ~UI_BUT_DRAGPOIN_FREE;
- }
- but->dragpoin = (void *)path;
- if (use_free) {
- but->dragflag |= UI_BUT_DRAGPOIN_FREE;
- }
- UI_but_drag_attach_image(but, imb, scale);
-}
-
PointerRNA *UI_but_operator_ptr_get(uiBut *but)
{
if (but->optype && !but->opptr) {
@@ -6263,64 +6243,6 @@ uiBut *uiDefIconBlockBut(uiBlock *block,
return but;
}
-uiBut *uiDefKeyevtButS(uiBlock *block,
- int retval,
- const char *str,
- int x,
- int y,
- short width,
- short height,
- short *spoin,
- const char *tip)
-{
- uiBut *but = ui_def_but(block,
- UI_BTYPE_KEY_EVENT | UI_BUT_POIN_SHORT,
- retval,
- str,
- x,
- y,
- width,
- height,
- spoin,
- 0.0,
- 0.0,
- 0.0,
- 0.0,
- tip);
- ui_but_update(but);
- return but;
-}
-
-uiBut *uiDefHotKeyevtButS(uiBlock *block,
- int retval,
- const char *str,
- int x,
- int y,
- short width,
- short height,
- short *keypoin,
- const short *modkeypoin,
- const char *tip)
-{
- uiBut *but = ui_def_but(block,
- UI_BTYPE_HOTKEY_EVENT | UI_BUT_POIN_SHORT,
- retval,
- str,
- x,
- y,
- width,
- height,
- keypoin,
- 0.0,
- 0.0,
- 0.0,
- 0.0,
- tip);
- but->modifier_key = *modkeypoin;
- ui_but_update(but);
- return but;
-}
-
uiBut *uiDefSearchBut(uiBlock *block,
void *arg,
int retval,
diff --git a/source/blender/editors/interface/interface_anim.c b/source/blender/editors/interface/interface_anim.c
index e838ce37d8e..0e69b4bb358 100644
--- a/source/blender/editors/interface/interface_anim.c
+++ b/source/blender/editors/interface/interface_anim.c
@@ -293,7 +293,7 @@ bool ui_but_anim_expression_create(uiBut *but, const char *str)
void ui_but_anim_autokey(bContext *C, uiBut *but, Scene *scene, float cfra)
{
- ED_autokeyframe_property(C, scene, &but->rnapoin, but->rnaprop, but->rnaindex, cfra);
+ ED_autokeyframe_property(C, scene, &but->rnapoin, but->rnaprop, but->rnaindex, cfra, true);
}
void ui_but_anim_copy_driver(bContext *C)
diff --git a/source/blender/editors/interface/interface_drag.cc b/source/blender/editors/interface/interface_drag.cc
new file mode 100644
index 00000000000..4c68870b2c7
--- /dev/null
+++ b/source/blender/editors/interface/interface_drag.cc
@@ -0,0 +1,144 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+
+/** \file
+ * \ingroup edinterface
+ */
+
+#include "UI_interface.h"
+
+#include "WM_api.h"
+
+#include "interface_intern.h"
+
+void UI_but_drag_set_id(uiBut *but, ID *id)
+{
+ but->dragtype = WM_DRAG_ID;
+ if (but->dragflag & UI_BUT_DRAGPOIN_FREE) {
+ WM_drag_data_free(but->dragtype, but->dragpoin);
+ but->dragflag &= ~UI_BUT_DRAGPOIN_FREE;
+ }
+ but->dragpoin = (void *)id;
+}
+
+void UI_but_drag_attach_image(uiBut *but, struct ImBuf *imb, const float scale)
+{
+ but->imb = imb;
+ but->imb_scale = scale;
+}
+
+void UI_but_drag_set_asset(uiBut *but,
+ const AssetHandle *asset,
+ const char *path,
+ struct AssetMetaData *metadata,
+ int import_type,
+ int icon,
+ struct ImBuf *imb,
+ float scale)
+{
+ wmDragAsset *asset_drag = WM_drag_create_asset_data(asset, metadata, path, import_type);
+
+ /* FIXME: This is temporary evil solution to get scene/viewlayer/etc in the copy callback of the
+ * #wmDropBox.
+ * TODO: Handle link/append in operator called at the end of the drop process, and NOT in its
+ * copy callback.
+ * */
+ asset_drag->evil_C = static_cast<bContext *>(but->block->evil_C);
+
+ but->dragtype = WM_DRAG_ASSET;
+ ui_def_but_icon(but, icon, 0); /* no flag UI_HAS_ICON, so icon doesn't draw in button */
+ if (but->dragflag & UI_BUT_DRAGPOIN_FREE) {
+ WM_drag_data_free(but->dragtype, but->dragpoin);
+ }
+ but->dragpoin = asset_drag;
+ but->dragflag |= UI_BUT_DRAGPOIN_FREE;
+ UI_but_drag_attach_image(but, imb, scale);
+}
+
+void UI_but_drag_set_rna(uiBut *but, PointerRNA *ptr)
+{
+ but->dragtype = WM_DRAG_RNA;
+ if (but->dragflag & UI_BUT_DRAGPOIN_FREE) {
+ WM_drag_data_free(but->dragtype, but->dragpoin);
+ but->dragflag &= ~UI_BUT_DRAGPOIN_FREE;
+ }
+ but->dragpoin = (void *)ptr;
+}
+
+void UI_but_drag_set_path(uiBut *but, const char *path, const bool use_free)
+{
+ but->dragtype = WM_DRAG_PATH;
+ if (but->dragflag & UI_BUT_DRAGPOIN_FREE) {
+ WM_drag_data_free(but->dragtype, but->dragpoin);
+ but->dragflag &= ~UI_BUT_DRAGPOIN_FREE;
+ }
+ but->dragpoin = (void *)path;
+ if (use_free) {
+ but->dragflag |= UI_BUT_DRAGPOIN_FREE;
+ }
+}
+
+void UI_but_drag_set_name(uiBut *but, const char *name)
+{
+ but->dragtype = WM_DRAG_NAME;
+ if (but->dragflag & UI_BUT_DRAGPOIN_FREE) {
+ WM_drag_data_free(but->dragtype, but->dragpoin);
+ but->dragflag &= ~UI_BUT_DRAGPOIN_FREE;
+ }
+ but->dragpoin = (void *)name;
+}
+
+void UI_but_drag_set_value(uiBut *but)
+{
+ but->dragtype = WM_DRAG_VALUE;
+}
+
+void UI_but_drag_set_image(
+ uiBut *but, const char *path, int icon, struct ImBuf *imb, float scale, const bool use_free)
+{
+ but->dragtype = WM_DRAG_PATH;
+ ui_def_but_icon(but, icon, 0); /* no flag UI_HAS_ICON, so icon doesn't draw in button */
+ if (but->dragflag & UI_BUT_DRAGPOIN_FREE) {
+ WM_drag_data_free(but->dragtype, but->dragpoin);
+ but->dragflag &= ~UI_BUT_DRAGPOIN_FREE;
+ }
+ but->dragpoin = (void *)path;
+ if (use_free) {
+ but->dragflag |= UI_BUT_DRAGPOIN_FREE;
+ }
+ UI_but_drag_attach_image(but, imb, scale);
+}
+
+void ui_but_drag_free(uiBut *but)
+{
+ if (but->dragpoin && (but->dragflag & UI_BUT_DRAGPOIN_FREE)) {
+ WM_drag_data_free(but->dragtype, but->dragpoin);
+ }
+}
+
+bool ui_but_drag_is_draggable(const uiBut *but)
+{
+ return but->dragpoin != nullptr;
+}
+
+void ui_but_drag_start(bContext *C, uiBut *but)
+{
+ wmDrag *drag = WM_event_start_drag(C,
+ but->icon,
+ but->dragtype,
+ but->dragpoin,
+ ui_but_value_get(but),
+ (but->dragflag & UI_BUT_DRAGPOIN_FREE) ? WM_DRAG_FREE_DATA :
+ WM_DRAG_NOP);
+ /* wmDrag has ownership over dragpoin now, stop messing with it. */
+ but->dragpoin = NULL;
+
+ if (but->imb) {
+ WM_event_drag_image(drag, but->imb, but->imb_scale);
+ }
+
+ /* Special feature for assets: We add another drag item that supports multiple assets. It
+ * gets the assets from context. */
+ if (ELEM(but->dragtype, WM_DRAG_ASSET, WM_DRAG_ID)) {
+ WM_event_start_drag(C, ICON_NONE, WM_DRAG_ASSET_LIST, NULL, 0, WM_DRAG_NOP);
+ }
+}
diff --git a/source/blender/editors/interface/interface_draw.c b/source/blender/editors/interface/interface_draw.c
index 18bad7949ee..d201820fbb6 100644
--- a/source/blender/editors/interface/interface_draw.c
+++ b/source/blender/editors/interface/interface_draw.c
@@ -130,7 +130,7 @@ void UI_draw_roundbox_4fv_ex(const rctf *rect,
void UI_draw_roundbox_3ub_alpha(
const rctf *rect, bool filled, float rad, const uchar col[3], uchar alpha)
{
- float colv[4] = {
+ const float colv[4] = {
((float)col[0]) / 255,
((float)col[1]) / 255,
((float)col[2]) / 255,
@@ -142,7 +142,7 @@ void UI_draw_roundbox_3ub_alpha(
void UI_draw_roundbox_3fv_alpha(
const rctf *rect, bool filled, float rad, const float col[3], float alpha)
{
- float colv[4] = {col[0], col[1], col[2], alpha};
+ const float colv[4] = {col[0], col[1], col[2], alpha};
UI_draw_roundbox_4fv_ex(rect, (filled) ? colv : NULL, NULL, 1.0f, colv, U.pixelsize, rad);
}
diff --git a/source/blender/editors/interface/interface_eyedropper_color.c b/source/blender/editors/interface/interface_eyedropper_color.c
index 895f8d0d840..c015a60de89 100644
--- a/source/blender/editors/interface/interface_eyedropper_color.c
+++ b/source/blender/editors/interface/interface_eyedropper_color.c
@@ -50,8 +50,6 @@
#include "RE_pipeline.h"
-#include "RE_pipeline.h"
-
#include "interface_eyedropper_intern.h"
typedef struct Eyedropper {
@@ -329,7 +327,7 @@ void eyedropper_color_sample_fl(bContext *C, const int m_xy[2], float r_col[3])
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};
+ const int region_mval[2] = {mval[0] - region->winrct.xmin, mval[1] - region->winrct.ymin};
if (ED_space_image_color_sample(sima, region, region_mval, r_col, NULL)) {
return;
@@ -340,7 +338,7 @@ void eyedropper_color_sample_fl(bContext *C, const int m_xy[2], float r_col[3])
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};
+ const int region_mval[2] = {mval[0] - region->winrct.xmin, mval[1] - region->winrct.ymin};
if (ED_space_node_color_sample(bmain, snode, region, region_mval, r_col)) {
return;
@@ -351,7 +349,7 @@ void eyedropper_color_sample_fl(bContext *C, const int m_xy[2], float r_col[3])
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};
+ const int region_mval[2] = {mval[0] - region->winrct.xmin, mval[1] - region->winrct.ymin};
if (ED_space_clip_color_sample(sc, region, region_mval, r_col)) {
return;
diff --git a/source/blender/editors/interface/interface_eyedropper_datablock.c b/source/blender/editors/interface/interface_eyedropper_datablock.c
index aec8f56678a..01b958576b6 100644
--- a/source/blender/editors/interface/interface_eyedropper_datablock.c
+++ b/source/blender/editors/interface/interface_eyedropper_datablock.c
@@ -156,7 +156,7 @@ static void datadropper_id_sample_pt(
CTX_wm_area_set(C, area);
CTX_wm_region_set(C, region);
- /* grr, always draw else we leave stale text */
+ /* Unfortunately it's necessary to always draw else we leave stale text. */
ED_region_tag_redraw(region);
if (area->spacetype == SPACE_VIEW3D) {
diff --git a/source/blender/editors/interface/interface_eyedropper_depth.c b/source/blender/editors/interface/interface_eyedropper_depth.c
index 56bc1a6d956..3c6f127582a 100644
--- a/source/blender/editors/interface/interface_eyedropper_depth.c
+++ b/source/blender/editors/interface/interface_eyedropper_depth.c
@@ -171,7 +171,7 @@ static void depthdropper_depth_sample_pt(bContext *C,
CTX_wm_area_set(C, area);
CTX_wm_region_set(C, region);
- /* grr, always draw else we leave stale text */
+ /* Unfortunately it's necessary to always draw otherwise we leave stale text. */
ED_region_tag_redraw(region);
view3d_operator_needs_opengl(C);
diff --git a/source/blender/editors/interface/interface_handlers.c b/source/blender/editors/interface/interface_handlers.c
index 2c408619fe7..7c00c4f1875 100644
--- a/source/blender/editors/interface/interface_handlers.c
+++ b/source/blender/editors/interface/interface_handlers.c
@@ -384,6 +384,12 @@ typedef struct uiHandleButtonData {
/* True when alt is held and the preference for displaying tooltips should be ignored. */
bool tooltip_force;
+ /**
+ * Behave as if #UI_BUT_DISABLED is set (without drawing grayed out).
+ * Needed so non-interactive labels can be activated for the purpose of showing tool-tips,
+ * without them blocking interaction with nodes, see: T97386.
+ */
+ bool disable_force;
/* auto open */
bool used_mouse;
@@ -536,7 +542,7 @@ static bool but_copypaste_profile_alive = false;
bool ui_but_is_editing(const uiBut *but)
{
- uiHandleButtonData *data = but->active;
+ const uiHandleButtonData *data = but->active;
return (data && ELEM(data->state, BUTTON_STATE_TEXT_EDITING, BUTTON_STATE_NUM_EDITING));
}
@@ -654,21 +660,23 @@ static bool ui_but_dragedit_update_mval(uiHandleButtonData *data, int mx)
static bool ui_rna_is_userdef(PointerRNA *ptr, PropertyRNA *prop)
{
/* Not very elegant, but ensures preference changes force re-save. */
- bool tag = false;
- if (prop && !(RNA_property_flag(prop) & PROP_NO_DEG_UPDATE)) {
- StructRNA *base = RNA_struct_base(ptr->type);
- if (base == NULL) {
- base = ptr->type;
- }
- if (ELEM(base,
- &RNA_AddonPreferences,
- &RNA_KeyConfigPreferences,
- &RNA_KeyMapItem,
- &RNA_UserAssetLibrary)) {
- tag = true;
- }
+
+ if (!prop) {
+ return false;
}
- return tag;
+ if (RNA_property_flag(prop) & PROP_NO_DEG_UPDATE) {
+ return false;
+ }
+
+ StructRNA *base = RNA_struct_base(ptr->type);
+ if (base == NULL) {
+ base = ptr->type;
+ }
+ return ELEM(base,
+ &RNA_AddonPreferences,
+ &RNA_KeyConfigPreferences,
+ &RNA_KeyMapItem,
+ &RNA_UserAssetLibrary);
}
bool UI_but_is_userdef(const uiBut *but)
@@ -894,64 +902,66 @@ static void ui_apply_but_func(bContext *C, uiBut *but)
/* typically call ui_apply_but_undo(), ui_apply_but_autokey() */
static void ui_apply_but_undo(uiBut *but)
{
- if (but->flag & UI_BUT_UNDO) {
- const char *str = NULL;
- size_t str_len_clip = SIZE_MAX - 1;
- bool skip_undo = false;
+ if (!(but->flag & UI_BUT_UNDO)) {
+ return;
+ }
- /* define which string to use for undo */
- if (but->type == UI_BTYPE_MENU) {
- str = but->drawstr;
- str_len_clip = ui_but_drawstr_len_without_sep_char(but);
- }
- else if (but->drawstr[0]) {
- str = but->drawstr;
- str_len_clip = ui_but_drawstr_len_without_sep_char(but);
- }
- else {
- str = but->tip;
- str_len_clip = ui_but_tip_len_only_first_line(but);
- }
+ const char *str = NULL;
+ size_t str_len_clip = SIZE_MAX - 1;
+ bool skip_undo = false;
- /* fallback, else we don't get an undo! */
- if (str == NULL || str[0] == '\0' || str_len_clip == 0) {
- str = "Unknown Action";
- str_len_clip = strlen(str);
- }
+ /* define which string to use for undo */
+ if (but->type == UI_BTYPE_MENU) {
+ str = but->drawstr;
+ str_len_clip = ui_but_drawstr_len_without_sep_char(but);
+ }
+ else if (but->drawstr[0]) {
+ str = but->drawstr;
+ str_len_clip = ui_but_drawstr_len_without_sep_char(but);
+ }
+ else {
+ str = but->tip;
+ str_len_clip = ui_but_tip_len_only_first_line(but);
+ }
- /* Optionally override undo when undo system doesn't support storing properties. */
- if (but->rnapoin.owner_id) {
- /* Exception for renaming ID data, we always need undo pushes in this case,
- * because undo systems track data by their ID, see: T67002. */
- /* Exception for active shape-key, since changing this in edit-mode updates
- * the shape key from object mode data. */
- if (ELEM(but->rnaprop, &rna_ID_name, &rna_Object_active_shape_key_index)) {
- /* pass */
- }
- else {
- ID *id = but->rnapoin.owner_id;
- if (!ED_undo_is_legacy_compatible_for_property(but->block->evil_C, id)) {
- skip_undo = true;
- }
- }
- }
+ /* fallback, else we don't get an undo! */
+ if (str == NULL || str[0] == '\0' || str_len_clip == 0) {
+ str = "Unknown Action";
+ str_len_clip = strlen(str);
+ }
- if (skip_undo == false) {
- /* XXX: disable all undo pushes from UI changes from sculpt mode as they cause memfile undo
- * steps to be written which cause lag: T71434. */
- if (BKE_paintmode_get_active_from_context(but->block->evil_C) == PAINT_MODE_SCULPT) {
+ /* Optionally override undo when undo system doesn't support storing properties. */
+ if (but->rnapoin.owner_id) {
+ /* Exception for renaming ID data, we always need undo pushes in this case,
+ * because undo systems track data by their ID, see: T67002. */
+ /* Exception for active shape-key, since changing this in edit-mode updates
+ * the shape key from object mode data. */
+ if (ELEM(but->rnaprop, &rna_ID_name, &rna_Object_active_shape_key_index)) {
+ /* pass */
+ }
+ else {
+ ID *id = but->rnapoin.owner_id;
+ if (!ED_undo_is_legacy_compatible_for_property(but->block->evil_C, id)) {
skip_undo = true;
}
}
+ }
- if (skip_undo) {
- str = "";
+ if (skip_undo == false) {
+ /* XXX: disable all undo pushes from UI changes from sculpt mode as they cause memfile undo
+ * steps to be written which cause lag: T71434. */
+ if (BKE_paintmode_get_active_from_context(but->block->evil_C) == PAINT_MODE_SCULPT) {
+ skip_undo = true;
}
+ }
- /* delayed, after all other funcs run, popups are closed, etc */
- uiAfterFunc *after = ui_afterfunc_new();
- BLI_strncpy(after->undostr, str, min_zz(str_len_clip + 1, sizeof(after->undostr)));
+ if (skip_undo) {
+ str = "";
}
+
+ /* delayed, after all other funcs run, popups are closed, etc */
+ uiAfterFunc *after = ui_afterfunc_new();
+ BLI_strncpy(after->undostr, str, min_zz(str_len_clip + 1, sizeof(after->undostr)));
}
static void ui_apply_but_autokey(bContext *C, uiBut *but)
@@ -961,21 +971,21 @@ static void ui_apply_but_autokey(bContext *C, uiBut *but)
/* try autokey */
ui_but_anim_autokey(C, but, scene, scene->r.cfra);
- /* make a little report about what we've done! */
- if (but->rnaprop) {
- char *buf;
+ if (!but->rnaprop) {
+ return;
+ }
- if (RNA_property_subtype(but->rnaprop) == PROP_PASSWORD) {
- return;
- }
+ if (RNA_property_subtype(but->rnaprop) == PROP_PASSWORD) {
+ return;
+ }
- buf = WM_prop_pystring_assign(C, &but->rnapoin, but->rnaprop, but->rnaindex);
- if (buf) {
- BKE_report(CTX_wm_reports(C), RPT_PROPERTY, buf);
- MEM_freeN(buf);
+ /* make a little report about what we've done! */
+ char *buf = WM_prop_pystring_assign(C, &but->rnapoin, but->rnaprop, but->rnaindex);
+ if (buf) {
+ BKE_report(CTX_wm_reports(C), RPT_PROPERTY, buf);
+ MEM_freeN(buf);
- WM_event_add_notifier(C, NC_SPACE | ND_SPACE_INFO_REPORT, NULL);
- }
+ WM_event_add_notifier(C, NC_SPACE | ND_SPACE_INFO_REPORT, NULL);
}
}
@@ -1470,9 +1480,9 @@ static void ui_multibut_states_create(uiBut *but_active, uiHandleButtonData *dat
}
}
- /* edit buttons proportionally to eachother
+ /* Edit buttons proportionally to each other.
* NOTE: if we mix buttons which are proportional and others which are not,
- * this may work a bit strangely */
+ * this may work a bit strangely. */
if ((but_active->rnaprop && (RNA_property_flag(but_active->rnaprop) & PROP_PROPORTIONAL)) ||
ELEM(but_active->unit_type, RNA_SUBTYPE_UNIT_VALUE(PROP_UNIT_LENGTH))) {
if (data->origvalue != 0.0) {
@@ -1625,29 +1635,34 @@ static bool ui_drag_toggle_set_xy_xy(
LISTBASE_FOREACH (uiBut *, but, &block->buttons) {
/* NOTE: ctrl is always true here because (at least for now)
* we always want to consider text control in this case, even when not embossed. */
- if (ui_but_is_interactive(but, true)) {
- if (BLI_rctf_isect_segment(&but->rect, xy_a_block, xy_b_block)) {
-
- /* execute the button */
- if (ui_drag_toggle_but_is_supported(but)) {
- /* is it pressed? */
- const int pushed_state_but = ui_drag_toggle_but_pushed_state(but);
- if (pushed_state_but != pushed_state) {
- UI_but_execute(C, region, but);
- if (do_check) {
- ui_but_update_edited(but);
- }
- if (U.runtime.is_dirty == false) {
- ui_but_update_preferences_dirty(but);
- }
- changed = true;
- }
- }
- /* done */
- }
+
+ if (!ui_but_is_interactive(but, true)) {
+ continue;
}
+ if (!BLI_rctf_isect_segment(&but->rect, xy_a_block, xy_b_block)) {
+ continue;
+ }
+ if (!ui_drag_toggle_but_is_supported(but)) {
+ continue;
+ }
+ /* is it pressed? */
+ const int pushed_state_but = ui_drag_toggle_but_pushed_state(but);
+ if (pushed_state_but == pushed_state) {
+ continue;
+ }
+
+ /* execute the button */
+ UI_but_execute(C, region, but);
+ if (do_check) {
+ ui_but_update_edited(but);
+ }
+ if (U.runtime.is_dirty == false) {
+ ui_but_update_preferences_dirty(but);
+ }
+ changed = true;
}
}
+
if (changed) {
/* apply now, not on release (or if handlers are canceled for whatever reason) */
ui_apply_but_funcs_after(C);
@@ -1669,7 +1684,7 @@ static void ui_drag_toggle_set(bContext *C, uiDragToggleHandle *drag_info, const
*/
if (drag_info->is_xy_lock_init == false) {
/* first store the buttons original coords */
- uiBut *but = ui_but_find_mouse_over_ex(region, xy_input, true, NULL, NULL);
+ uiBut *but = ui_but_find_mouse_over_ex(region, xy_input, true, false, NULL, NULL);
if (but) {
if (but->flag & UI_BUT_DRAG_LOCK) {
@@ -1739,7 +1754,7 @@ static int ui_handler_region_drag_toggle(bContext *C, const wmEvent *event, void
if (done) {
wmWindow *win = CTX_wm_window(C);
const ARegion *region = CTX_wm_region(C);
- uiBut *but = ui_but_find_mouse_over_ex(region, drag_info->xy_init, true, NULL, NULL);
+ uiBut *but = ui_but_find_mouse_over_ex(region, drag_info->xy_init, true, false, NULL, NULL);
if (but) {
ui_apply_but_undo(but);
@@ -2120,25 +2135,7 @@ static bool ui_but_drag_init(bContext *C,
}
}
else {
- wmDrag *drag = WM_event_start_drag(
- C,
- but->icon,
- but->dragtype,
- but->dragpoin,
- ui_but_value_get(but),
- (but->dragflag & UI_BUT_DRAGPOIN_FREE) ? WM_DRAG_FREE_DATA : WM_DRAG_NOP);
- /* wmDrag has ownership over dragpoin now, stop messing with it. */
- but->dragpoin = NULL;
-
- if (but->imb) {
- WM_event_drag_image(drag, but->imb, but->imb_scale);
- }
-
- /* Special feature for assets: We add another drag item that supports multiple assets. It
- * gets the assets from context. */
- if (ELEM(but->dragtype, WM_DRAG_ASSET, WM_DRAG_ID)) {
- WM_event_start_drag(C, ICON_NONE, WM_DRAG_ASSET_LIST, NULL, 0, WM_DRAG_NOP);
- }
+ ui_but_drag_start(C, but);
}
return true;
}
@@ -2292,6 +2289,9 @@ static void ui_apply_but(
case UI_BTYPE_ROW:
ui_apply_but_ROW(C, block, but, data);
break;
+ case UI_BTYPE_GRID_TILE:
+ ui_apply_but_ROW(C, block, but, data);
+ break;
case UI_BTYPE_TREEROW:
ui_apply_but_TREEROW(C, block, but, data);
break;
@@ -2948,6 +2948,9 @@ void ui_but_text_password_hide(char password_str[UI_MAX_PASSWORD_STR],
void ui_but_set_string_interactive(bContext *C, uiBut *but, const char *value)
{
+ /* Caller should check. */
+ BLI_assert((but->flag & UI_BUT_DISABLED) == 0);
+
button_activate_state(C, but, BUTTON_STATE_TEXT_EDITING);
ui_textedit_string_set(but, but->active, value);
@@ -3492,7 +3495,7 @@ static void ui_textedit_begin(bContext *C, uiBut *but, uiHandleButtonData *data)
WM_cursor_modal_set(win, WM_CURSOR_TEXT_EDIT);
#ifdef WITH_INPUT_IME
- if (is_num_but == false && BLT_lang_is_ime_supported()) {
+ if (!is_num_but) {
ui_textedit_ime_begin(win, but);
}
#endif
@@ -3896,7 +3899,7 @@ static void ui_do_but_textedit(
if ((event->ascii || event->utf8_buf[0]) && (retval == WM_UI_HANDLER_CONTINUE)
#ifdef WITH_INPUT_IME
- && !is_ime_composing && (!WM_event_is_ime_switch(event) || !BLT_lang_is_ime_supported())
+ && !is_ime_composing && !WM_event_is_ime_switch(event)
#endif
) {
char ascii = event->ascii;
@@ -4324,7 +4327,7 @@ static uiBut *ui_but_list_row_text_activate(bContext *C,
uiButtonActivateType activate_type)
{
ARegion *region = CTX_wm_region(C);
- uiBut *labelbut = ui_but_find_mouse_over_ex(region, event->xy, true, NULL, NULL);
+ uiBut *labelbut = ui_but_find_mouse_over_ex(region, event->xy, true, false, NULL, NULL);
if (labelbut && labelbut->type == UI_BTYPE_TEXT && !(labelbut->flag & UI_BUT_DISABLED)) {
/* exit listrow */
@@ -4346,14 +4349,14 @@ static uiBut *ui_but_list_row_text_activate(bContext *C,
* \{ */
static uiButExtraOpIcon *ui_but_extra_operator_icon_mouse_over_get(uiBut *but,
- uiHandleButtonData *data,
+ ARegion *region,
const wmEvent *event)
{
float xmax = but->rect.xmax;
const float icon_size = 0.8f * BLI_rctf_size_y(&but->rect); /* ICON_SIZE_FROM_BUTRECT */
int x = event->xy[0], y = event->xy[1];
- ui_window_to_block(data->region, but->block, &x, &y);
+ ui_window_to_block(region, but->block, &x, &y);
if (!BLI_rctf_isect_pt(&but->rect, x, y)) {
return NULL;
}
@@ -4382,7 +4385,7 @@ static bool ui_do_but_extra_operator_icon(bContext *C,
uiHandleButtonData *data,
const wmEvent *event)
{
- uiButExtraOpIcon *op_icon = ui_but_extra_operator_icon_mouse_over_get(but, data, event);
+ uiButExtraOpIcon *op_icon = ui_but_extra_operator_icon_mouse_over_get(but, data->region, event);
if (!op_icon) {
return false;
@@ -4417,7 +4420,7 @@ static void ui_do_but_extra_operator_icons_mousemove(uiBut *but,
op_icon->highlighted = false;
}
- uiButExtraOpIcon *hovered = ui_but_extra_operator_icon_mouse_over_get(but, data, event);
+ uiButExtraOpIcon *hovered = ui_but_extra_operator_icon_mouse_over_get(but, data->region, event);
if (hovered) {
hovered->highlighted = true;
@@ -4501,10 +4504,14 @@ static int ui_do_but_HOTKEYEVT(bContext *C,
uiHandleButtonData *data,
const wmEvent *event)
{
+ uiButHotkeyEvent *hotkey_but = (uiButHotkeyEvent *)but;
+ BLI_assert(but->type == UI_BTYPE_HOTKEY_EVENT);
+
if (data->state == BUTTON_STATE_HIGHLIGHT) {
- if (ELEM(event->type, LEFTMOUSE, EVT_PADENTER, EVT_RETKEY) && event->val == KM_PRESS) {
+ if (ELEM(event->type, LEFTMOUSE, EVT_PADENTER, EVT_RETKEY, EVT_BUT_OPEN) &&
+ (event->val == KM_PRESS)) {
but->drawstr[0] = 0;
- but->modifier_key = 0;
+ hotkey_but->modifier_key = 0;
button_activate_state(C, but, BUTTON_STATE_WAIT_KEY_EVENT);
return WM_UI_HANDLER_BREAK;
}
@@ -4525,20 +4532,16 @@ static int ui_do_but_HOTKEYEVT(bContext *C,
if (event->type == LEFTMOUSE && event->val == KM_PRESS) {
/* only cancel if click outside the button */
if (ui_but_contains_point_px(but, but->active->region, event->xy) == false) {
- /* data->cancel doesn't work, this button opens immediate */
- if (but->flag & UI_BUT_IMMEDIATE) {
- ui_but_value_set(but, 0);
- }
- else {
- data->cancel = true;
- }
+ data->cancel = true;
+ /* Close the containing popup (if any). */
+ data->escapecancel = true;
button_activate_state(C, but, BUTTON_STATE_EXIT);
return WM_UI_HANDLER_BREAK;
}
}
/* always set */
- but->modifier_key = event->modifier;
+ hotkey_but->modifier_key = event->modifier;
ui_but_update(but);
ED_region_tag_redraw(data->region);
@@ -4656,7 +4659,7 @@ static int ui_do_but_TEX(
/* pass */
}
else {
- if (!ui_but_extra_operator_icon_mouse_over_get(but, data, event)) {
+ if (!ui_but_extra_operator_icon_mouse_over_get(but, data->region, event)) {
button_activate_state(C, but, BUTTON_STATE_TEXT_EDITING);
}
return WM_UI_HANDLER_BREAK;
@@ -4782,7 +4785,7 @@ static int ui_do_but_TREEROW(bContext *C,
switch (event->val) {
case KM_PRESS:
/* Extra icons have priority, don't mess with them. */
- if (ui_but_extra_operator_icon_mouse_over_get(but, data, event)) {
+ if (ui_but_extra_operator_icon_mouse_over_get(but, data->region, event)) {
return WM_UI_HANDLER_BREAK;
}
button_activate_state(C, but, BUTTON_STATE_WAIT_DRAG);
@@ -4810,12 +4813,53 @@ static int ui_do_but_TREEROW(bContext *C,
return WM_UI_HANDLER_CONTINUE;
}
+static int ui_do_but_GRIDTILE(bContext *C,
+ uiBut *but,
+ uiHandleButtonData *data,
+ const wmEvent *event)
+{
+ BLI_assert(but->type == UI_BTYPE_GRID_TILE);
+
+ if (data->state == BUTTON_STATE_HIGHLIGHT) {
+ if (event->type == LEFTMOUSE) {
+ switch (event->val) {
+ case KM_PRESS:
+ /* Extra icons have priority, don't mess with them. */
+ if (ui_but_extra_operator_icon_mouse_over_get(but, data->region, event)) {
+ return WM_UI_HANDLER_BREAK;
+ }
+ button_activate_state(C, but, BUTTON_STATE_WAIT_DRAG);
+ data->dragstartx = event->xy[0];
+ data->dragstarty = event->xy[1];
+ return WM_UI_HANDLER_CONTINUE;
+
+ case KM_CLICK:
+ button_activate_state(C, but, BUTTON_STATE_EXIT);
+ return WM_UI_HANDLER_BREAK;
+
+ case KM_DBL_CLICK:
+ data->cancel = true;
+ // uiButGridTile *grid_tile_but = (uiButGridTile *)but;
+ // UI_tree_view_item_begin_rename(grid_tile_but->tree_item);
+ ED_region_tag_redraw(CTX_wm_region(C));
+ return WM_UI_HANDLER_BREAK;
+ }
+ }
+ }
+ else if (data->state == BUTTON_STATE_WAIT_DRAG) {
+ /* Let "default" button handling take care of the drag logic. */
+ return ui_do_but_EXIT(C, but, data, event);
+ }
+
+ return WM_UI_HANDLER_CONTINUE;
+}
+
static int ui_do_but_EXIT(bContext *C, uiBut *but, uiHandleButtonData *data, const wmEvent *event)
{
if (data->state == BUTTON_STATE_HIGHLIGHT) {
/* First handle click on icon-drag type button. */
- if ((event->type == LEFTMOUSE) && (event->val == KM_PRESS) && but->dragpoin) {
+ if ((event->type == LEFTMOUSE) && (event->val == KM_PRESS) && ui_but_drag_is_draggable(but)) {
if (ui_but_contains_point_px_icon(but, data->region, event)) {
/* tell the button to wait and keep checking further events to
@@ -4838,7 +4882,8 @@ static int ui_do_but_EXIT(bContext *C, uiBut *but, uiHandleButtonData *data, con
if (ELEM(event->type, LEFTMOUSE, EVT_PADENTER, EVT_RETKEY) && event->val == KM_PRESS) {
int ret = WM_UI_HANDLER_BREAK;
/* XXX: (a bit ugly) Special case handling for file-browser drag button. */
- if (but->dragpoin && but->imb && ui_but_contains_point_px_icon(but, data->region, event)) {
+ if (ui_but_drag_is_draggable(but) && but->imb &&
+ ui_but_contains_point_px_icon(but, data->region, event)) {
ret = WM_UI_HANDLER_CONTINUE;
}
/* Same special case handling for UI lists. Return CONTINUE so that a tweak or CLICK event
@@ -4850,6 +4895,10 @@ static int ui_do_but_EXIT(bContext *C, uiBut *but, uiHandleButtonData *data, con
ret = WM_UI_HANDLER_CONTINUE;
}
}
+ const uiBut *view_but = ui_view_item_find_mouse_over(data->region, event->xy);
+ if (view_but) {
+ ret = WM_UI_HANDLER_CONTINUE;
+ }
button_activate_state(C, but, BUTTON_STATE_EXIT);
return ret;
}
@@ -5992,7 +6041,7 @@ static int ui_do_but_BLOCK(bContext *C, uiBut *but, uiHandleButtonData *data, co
if (data->state == BUTTON_STATE_HIGHLIGHT) {
/* First handle click on icon-drag type button. */
- if (event->type == LEFTMOUSE && but->dragpoin && event->val == KM_PRESS) {
+ if (event->type == LEFTMOUSE && ui_but_drag_is_draggable(but) && event->val == KM_PRESS) {
if (ui_but_contains_point_px_icon(but, data->region, event)) {
button_activate_state(C, but, BUTTON_STATE_WAIT_DRAG);
data->dragstartx = event->xy[0];
@@ -6178,7 +6227,7 @@ static int ui_do_but_COLOR(bContext *C, uiBut *but, uiHandleButtonData *data, co
if (data->state == BUTTON_STATE_HIGHLIGHT) {
/* First handle click on icon-drag type button. */
- if (event->type == LEFTMOUSE && but->dragpoin && event->val == KM_PRESS) {
+ if (event->type == LEFTMOUSE && ui_but_drag_is_draggable(but) && event->val == KM_PRESS) {
ui_palette_set_active(color_but);
if (ui_but_contains_point_px_icon(but, data->region, event)) {
button_activate_state(C, but, BUTTON_STATE_WAIT_DRAG);
@@ -6271,7 +6320,7 @@ static int ui_do_but_COLOR(bContext *C, uiBut *but, uiHandleButtonData *data, co
if (but->rnaprop && RNA_property_subtype(but->rnaprop) == PROP_COLOR_GAMMA) {
RNA_property_float_get_array(&but->rnapoin, but->rnaprop, target);
- IMB_colormanagement_srgb_to_scene_linear_v3(target);
+ IMB_colormanagement_srgb_to_scene_linear_v3(target, target);
}
else if (but->rnaprop && RNA_property_subtype(but->rnaprop) == PROP_COLOR) {
RNA_property_float_get_array(&but->rnapoin, but->rnaprop, target);
@@ -6288,7 +6337,7 @@ static int ui_do_but_COLOR(bContext *C, uiBut *but, uiHandleButtonData *data, co
}
else if (but->rnaprop && RNA_property_subtype(but->rnaprop) == PROP_COLOR) {
RNA_property_float_get_array(&but->rnapoin, but->rnaprop, color);
- IMB_colormanagement_scene_linear_to_srgb_v3(color);
+ IMB_colormanagement_scene_linear_to_srgb_v3(color, color);
BKE_brush_color_set(scene, brush, color);
updated = true;
}
@@ -7393,8 +7442,7 @@ static bool ui_numedit_but_CURVEPROFILE(uiBlock *block,
const float zoomy = BLI_rctf_size_y(&but->rect) / BLI_rctf_size_y(&profile->view_rect);
if (snap) {
- float d[2] = {mx - data->dragstartx, data->dragstarty};
-
+ const float d[2] = {mx - data->dragstartx, data->dragstarty};
if (len_squared_v2(d) < (9.0f * U.dpi_fac)) {
snap = false;
}
@@ -7899,7 +7947,7 @@ static int ui_do_button(bContext *C, uiBlock *block, uiBut *but, const wmEvent *
uiHandleButtonData *data = but->active;
int retval = WM_UI_HANDLER_CONTINUE;
- const bool is_disabled = but->flag & UI_BUT_DISABLED;
+ const bool is_disabled = but->flag & UI_BUT_DISABLED || data->disable_force;
/* if but->pointype is set, but->poin should be too */
BLI_assert(!but->pointype || but->poin);
@@ -8005,6 +8053,9 @@ static int ui_do_button(bContext *C, uiBlock *block, uiBut *but, const wmEvent *
case UI_BTYPE_ROW:
retval = ui_do_but_TOG(C, but, data, event);
break;
+ case UI_BTYPE_GRID_TILE:
+ retval = ui_do_but_GRIDTILE(C, but, data, event);
+ break;
case UI_BTYPE_TREEROW:
retval = ui_do_but_TREEROW(C, but, data, event);
break;
@@ -8216,7 +8267,7 @@ static ARegion *ui_but_tooltip_init(
if (but) {
const wmWindow *win = CTX_wm_window(C);
uiButExtraOpIcon *extra_icon = ui_but_extra_operator_icon_mouse_over_get(
- but, but->active, win->eventstate);
+ but, but->active ? but->active->region : region, win->eventstate);
return UI_tooltip_create_from_button_or_extra_icon(C, region, but, extra_icon, is_label);
}
@@ -8492,14 +8543,6 @@ static void button_activate_init(bContext *C,
}
button_activate_state(C, but, BUTTON_STATE_HIGHLIGHT);
- /* activate right away */
- if (but->flag & UI_BUT_IMMEDIATE) {
- if (but->type == UI_BTYPE_HOTKEY_EVENT) {
- button_activate_state(C, but, BUTTON_STATE_WAIT_KEY_EVENT);
- }
- /* .. more to be added here */
- }
-
if (type == BUTTON_ACTIVATE_OPEN) {
button_activate_state(C, but, BUTTON_STATE_MENU_OPEN);
@@ -8703,20 +8746,38 @@ static uiBut *ui_context_button_active(const ARegion *region, bool (*but_check_c
uiBut *but_found = NULL;
while (region) {
- uiBut *activebut = NULL;
+ /* Follow this exact priority (from highest to lowest priority):
+ * 1) Active-override button (#UI_BUT_ACTIVE_OVERRIDE).
+ * 2) The real active button.
+ * 3) The previously active button (#UI_BUT_LAST_ACTIVE).
+ */
+ uiBut *active_but_override = NULL;
+ uiBut *active_but_real = NULL;
+ uiBut *active_but_last = NULL;
/* find active button */
LISTBASE_FOREACH (uiBlock *, block, &region->uiblocks) {
LISTBASE_FOREACH (uiBut *, but, &block->buttons) {
+ if (but->flag & UI_BUT_ACTIVE_OVERRIDE) {
+ active_but_override = but;
+ }
if (but->active) {
- activebut = but;
+ active_but_real = but;
}
- else if (!activebut && (but->flag & UI_BUT_LAST_ACTIVE)) {
- activebut = but;
+ if (but->flag & UI_BUT_LAST_ACTIVE) {
+ active_but_last = but;
}
}
}
+ uiBut *activebut = active_but_override;
+ if (!activebut) {
+ activebut = active_but_real;
+ }
+ if (!activebut) {
+ activebut = active_but_last;
+ }
+
if (activebut && (but_check_cb == NULL || but_check_cb(activebut))) {
uiHandleButtonData *data = activebut->active;
@@ -8947,7 +9008,12 @@ static uiBut *ui_but_find_open_event(ARegion *region, const wmEvent *event)
static int ui_handle_button_over(bContext *C, const wmEvent *event, ARegion *region)
{
if (event->type == MOUSEMOVE) {
- uiBut *but = ui_but_find_mouse_over(region, event);
+ const bool labeledit = event->modifier & KM_CTRL;
+ /* Allow buttons to be activated to show the tool-tip,
+ * then force-disable them if they're not considered interactive
+ * so they don't swallow events but can still display tips. */
+ const bool for_tooltip = true;
+ uiBut *but = ui_but_find_mouse_over_ex(region, event->xy, labeledit, for_tooltip, NULL, NULL);
if (but) {
button_activate_init(C, region, but, BUTTON_ACTIVATE_OVER);
@@ -8956,6 +9022,10 @@ static int ui_handle_button_over(bContext *C, const wmEvent *event, ARegion *reg
* preferences. */
but->active->tooltip_force = true;
}
+
+ if (but->active && !ui_but_is_interactive(but, labeledit)) {
+ but->active->disable_force = true;
+ }
}
}
else if (event->type == EVT_BUT_OPEN) {
@@ -9435,7 +9505,7 @@ static bool ui_list_is_hovering_draggable_but(bContext *C,
int mouse_xy[2];
WM_event_drag_start_xy(event, mouse_xy);
- const uiBut *hovered_but = ui_but_find_mouse_over_ex(region, mouse_xy, false, NULL, NULL);
+ const uiBut *hovered_but = ui_but_find_mouse_over_ex(region, mouse_xy, false, false, NULL, NULL);
if (list->dyn_data->custom_drag_optype) {
if (ui_but_context_poll_operator(C, list->dyn_data->custom_drag_optype, hovered_but)) {
@@ -9443,7 +9513,7 @@ static bool ui_list_is_hovering_draggable_but(bContext *C,
}
}
- return (hovered_but && hovered_but->dragpoin);
+ return (hovered_but && ui_but_drag_is_draggable(hovered_but));
}
static int ui_list_handle_click_drag(bContext *C,
@@ -9653,31 +9723,31 @@ static int ui_handle_list_event(bContext *C, const wmEvent *event, ARegion *regi
return retval;
}
-static int ui_handle_tree_hover(const wmEvent *event, const ARegion *region)
+static int ui_handle_view_items_hover(const wmEvent *event, const ARegion *region)
{
- bool has_treerows = false;
+ bool has_view_item = false;
LISTBASE_FOREACH (uiBlock *, block, &region->uiblocks) {
- /* Avoid unnecessary work: Tree-rows are assumed to be inside tree-views. */
+ /* Avoid unnecessary work: view item buttons are assumed to be inside views. */
if (BLI_listbase_is_empty(&block->views)) {
continue;
}
LISTBASE_FOREACH (uiBut *, but, &block->buttons) {
- if (but->type == UI_BTYPE_TREEROW) {
+ if (ui_but_is_view_item(but)) {
but->flag &= ~UI_ACTIVE;
- has_treerows = true;
+ has_view_item = true;
}
}
}
- if (!has_treerows) {
+ if (!has_view_item) {
/* Avoid unnecessary lookup. */
return WM_UI_HANDLER_CONTINUE;
}
- /* Always highlight the hovered tree-row, even if the mouse hovers another button inside of it.
+ /* Always highlight the hovered view item, even if the mouse hovers another button inside of it.
*/
- uiBut *hovered_row_but = ui_tree_row_find_mouse_over(region, event->xy);
+ uiBut *hovered_row_but = ui_view_item_find_mouse_over(region, event->xy);
if (hovered_row_but) {
hovered_row_but->flag |= UI_ACTIVE;
}
@@ -9685,6 +9755,21 @@ static int ui_handle_tree_hover(const wmEvent *event, const ARegion *region)
return WM_UI_HANDLER_CONTINUE;
}
+static int ui_handle_view_item_event(bContext *C,
+ const wmEvent *event,
+ ARegion *region,
+ uiBut *view_but)
+{
+ BLI_assert(ui_but_is_view_item(view_but));
+ if (event->type == LEFTMOUSE) {
+ /* Will free active button if there already is one. */
+ ui_handle_button_activate(C, region, view_but, BUTTON_ACTIVATE_OVER);
+ return ui_do_button(C, view_but->block, view_but, event);
+ }
+
+ return WM_UI_HANDLER_CONTINUE;
+}
+
static void ui_handle_button_return_submenu(bContext *C, const wmEvent *event, uiBut *but)
{
uiHandleButtonData *data = but->active;
@@ -11285,9 +11370,15 @@ static int ui_region_handler(bContext *C, const wmEvent *event, void *UNUSED(use
ui_blocks_set_tooltips(region, true);
}
- /* Always do this, to reliably update tree-row highlighting, even if the mouse hovers a button
- * inside the row (it's an overlapping layout). */
- ui_handle_tree_hover(event, region);
+ /* Always do this, to reliably update view item highlighting, even if the mouse hovers a button
+ * nested in the item (it's an overlapping layout). */
+ ui_handle_view_items_hover(event, region);
+ if (retval == WM_UI_HANDLER_CONTINUE) {
+ uiBut *view_item = ui_view_item_find_mouse_over(region, event->xy);
+ if (view_item) {
+ retval = ui_handle_view_item_event(C, event, region, view_item);
+ }
+ }
/* delayed apply callbacks */
ui_apply_but_funcs_after(C);
diff --git a/source/blender/editors/interface/interface_icons.c b/source/blender/editors/interface/interface_icons.c
index 332b9b44b0a..c19e842aad8 100644
--- a/source/blender/editors/interface/interface_icons.c
+++ b/source/blender/editors/interface/interface_icons.c
@@ -546,6 +546,7 @@ static void init_brush_icons(void)
INIT_BRUSH_ICON(ICON_BRUSH_MASK, mask);
INIT_BRUSH_ICON(ICON_BRUSH_MIX, mix);
INIT_BRUSH_ICON(ICON_BRUSH_NUDGE, nudge);
+ INIT_BRUSH_ICON(ICON_BRUSH_PAINT_SELECT, paint_select);
INIT_BRUSH_ICON(ICON_BRUSH_PINCH, pinch);
INIT_BRUSH_ICON(ICON_BRUSH_SCRAPE, scrape);
INIT_BRUSH_ICON(ICON_BRUSH_SMEAR, smear);
@@ -584,6 +585,19 @@ static void init_brush_icons(void)
INIT_BRUSH_ICON(ICON_GPBRUSH_ERASE_HARD, gp_brush_erase_hard);
INIT_BRUSH_ICON(ICON_GPBRUSH_ERASE_STROKE, gp_brush_erase_stroke);
+ /* Curves sculpt. */
+ INIT_BRUSH_ICON(ICON_BRUSH_CURVES_ADD, curves_sculpt_add);
+ INIT_BRUSH_ICON(ICON_BRUSH_CURVES_COMB, curves_sculpt_comb);
+ INIT_BRUSH_ICON(ICON_BRUSH_CURVES_CUT, curves_sculpt_cut);
+ INIT_BRUSH_ICON(ICON_BRUSH_CURVES_DELETE, curves_sculpt_delete);
+ INIT_BRUSH_ICON(ICON_BRUSH_CURVES_DENSITY, curves_sculpt_density);
+ INIT_BRUSH_ICON(ICON_BRUSH_CURVES_GROW_SHRINK, curves_sculpt_grow_shrink);
+ INIT_BRUSH_ICON(ICON_BRUSH_CURVES_PINCH, curves_sculpt_pinch);
+ INIT_BRUSH_ICON(ICON_BRUSH_CURVES_PUFF, curves_sculpt_puff);
+ INIT_BRUSH_ICON(ICON_BRUSH_CURVES_SLIDE, curves_sculpt_slide);
+ INIT_BRUSH_ICON(ICON_BRUSH_CURVES_SMOOTH, curves_sculpt_smooth);
+ INIT_BRUSH_ICON(ICON_BRUSH_CURVES_SNAKE_HOOK, curves_sculpt_snake_hook);
+
# undef INIT_BRUSH_ICON
}
@@ -2034,6 +2048,9 @@ static int ui_id_brush_get_icon(const bContext *C, ID *id)
else if (ob->mode & OB_MODE_TEXTURE_PAINT) {
paint_mode = PAINT_MODE_TEXTURE_3D;
}
+ else if (ob->mode & OB_MODE_SCULPT_CURVES) {
+ paint_mode = PAINT_MODE_SCULPT_CURVES;
+ }
}
else if (space_type == SPACE_IMAGE) {
if (area->spacetype == space_type) {
diff --git a/source/blender/editors/interface/interface_icons_event.c b/source/blender/editors/interface/interface_icons_event.c
index 00c1bcb5f6e..6ad5fe805ab 100644
--- a/source/blender/editors/interface/interface_icons_event.c
+++ b/source/blender/editors/interface/interface_icons_event.c
@@ -145,10 +145,10 @@ void icon_draw_rect_input(float x,
SNPRINTF(str, "F%d", 1 + (event_type - EVT_F1KEY));
icon_draw_rect_input_text(&rect, color, str, event_type > EVT_F9KEY ? 8.0f : 10.0f);
}
- else if (event_type == EVT_LEFTSHIFTKEY) {
+ else if (event_type == EVT_LEFTSHIFTKEY) { /* Right Shift has already been converted to left. */
icon_draw_rect_input_symbol(&rect, color, (const char[]){0xe2, 0x87, 0xa7, 0x0});
}
- else if (event_type == EVT_LEFTCTRLKEY) {
+ else if (event_type == EVT_LEFTCTRLKEY) { /* Right Shift has already been converted to left. */
if (platform == MACOS) {
icon_draw_rect_input_symbol(&rect, color, (const char[]){0xe2, 0x8c, 0x83, 0x0});
}
@@ -156,7 +156,7 @@ void icon_draw_rect_input(float x,
icon_draw_rect_input_text(&rect, color, "Ctrl", 9.0f);
}
}
- else if (event_type == EVT_LEFTALTKEY) {
+ else if (event_type == EVT_LEFTALTKEY) { /* Right Alt has already been converted to left. */
if (platform == MACOS) {
icon_draw_rect_input_symbol(&rect, color, (const char[]){0xe2, 0x8c, 0xa5, 0x0});
}
diff --git a/source/blender/editors/interface/interface_intern.h b/source/blender/editors/interface/interface_intern.h
index c09ff68bbca..791e51b81a6 100644
--- a/source/blender/editors/interface/interface_intern.h
+++ b/source/blender/editors/interface/interface_intern.h
@@ -74,6 +74,12 @@ enum {
UI_SELECT_DRAW = (1 << 5),
/** Property search filter is active and the button does not match. */
UI_SEARCH_FILTER_NO_MATCH = (1 << 6),
+
+ /** Temporarily override the active button for lookups in context, regions, etc. (everything
+ * using #ui_context_button_active()). For example, so that operators normally acting on the
+ * active button can be polled on non-active buttons to (e.g. for disabling). */
+ UI_BUT_ACTIVE_OVERRIDE = (1 << 7),
+
/* WARNING: rest of #uiBut.flag in UI_interface.h */
};
@@ -223,7 +229,6 @@ struct uiBut {
bool changed;
/** so buttons can support unit systems which are not RNA */
uchar unit_type;
- short modifier_key;
short iconadd;
/** #UI_BTYPE_BLOCK data */
@@ -346,6 +351,13 @@ typedef struct uiButTreeRow {
int indentation;
} uiButTreeRow;
+/** Derived struct for #UI_BTYPE_GRID_TILE. */
+typedef struct uiButGridTile {
+ uiBut but;
+
+ uiGridViewItemHandle *view_item;
+} uiButGridTile;
+
/** Derived struct for #UI_BTYPE_HSVCUBE. */
typedef struct uiButHSVCube {
uiBut but;
@@ -375,6 +387,13 @@ typedef struct uiButCurveMapping {
eButGradientType gradient_type;
} uiButCurveMapping;
+/** Derived struct for #UI_BTYPE_HOTKEY_EVENT. */
+typedef struct uiButHotkeyEvent {
+ uiBut but;
+
+ short modifier_key;
+} uiButHotkeyEvent;
+
/**
* Additional, superimposed icon for a button, invoking an operator.
*/
@@ -1206,24 +1225,24 @@ typedef enum {
/**
* Helper call to draw a menu item without a button.
*
- * \param state: The state of the button,
- * typically #UI_ACTIVE, #UI_BUT_DISABLED, #UI_BUT_INACTIVE.
+ * \param but_flag: Button flags (#uiBut.flag) indicating the state of the item, typically
+ * #UI_ACTIVE, #UI_BUT_DISABLED, #UI_BUT_INACTIVE.
* \param separator_type: The kind of separator which controls if and how the string is clipped.
- * \param r_xmax: The right hand position of the text, this takes into the icon,
- * padding and text clipping when there is not enough room to display the full text.
+ * \param r_xmax: The right hand position of the text, this takes into the icon, padding and text
+ * clipping when there is not enough room to display the full text.
*/
void ui_draw_menu_item(const struct uiFontStyle *fstyle,
rcti *rect,
const char *name,
int iconid,
- int state,
+ int but_flag,
uiMenuItemSeparatorType separator_type,
int *r_xmax);
void ui_draw_preview_item(const struct uiFontStyle *fstyle,
rcti *rect,
const char *name,
int iconid,
- int state,
+ int but_flag,
eFontStyle_Align text_align);
/**
* Version of #ui_draw_preview_item() that does not draw the menu background and item text based on
@@ -1309,6 +1328,12 @@ void ui_button_group_add_but(uiBlock *block, uiBut *but);
void ui_button_group_replace_but_ptr(uiBlock *block, const void *old_but_ptr, uiBut *new_but);
void ui_block_free_button_groups(uiBlock *block);
+/* interface_drag.cc */
+
+void ui_but_drag_free(uiBut *but);
+bool ui_but_drag_is_draggable(const uiBut *but);
+void ui_but_drag_start(struct bContext *C, uiBut *but);
+
/* interface_align.c */
bool ui_but_can_align(const uiBut *but) ATTR_WARN_UNUSED_RESULT;
@@ -1347,11 +1372,13 @@ void ui_but_anim_decorate_update_from_flag(uiButDecorator *but);
bool ui_but_is_editable(const uiBut *but) ATTR_WARN_UNUSED_RESULT;
bool ui_but_is_editable_as_text(const uiBut *but) ATTR_WARN_UNUSED_RESULT;
bool ui_but_is_toggle(const uiBut *but) ATTR_WARN_UNUSED_RESULT;
+bool ui_but_is_view_item(const uiBut *but) ATTR_WARN_UNUSED_RESULT;
/**
* Can we mouse over the button or is it hidden/disabled/layout.
* \note ctrl is kind of a hack currently,
* so that non-embossed UI_BTYPE_TEXT button behaves as a label when ctrl is not pressed.
*/
+bool ui_but_is_interactive_ex(const uiBut *but, const bool labeledit, const bool for_tooltip);
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;
@@ -1377,6 +1404,8 @@ uiBut *ui_list_row_find_mouse_over(const struct ARegion *region, const int xy[2]
uiBut *ui_list_row_find_from_index(const struct ARegion *region,
int index,
uiBut *listbox) ATTR_WARN_UNUSED_RESULT;
+uiBut *ui_view_item_find_mouse_over(const struct ARegion *region, const int xy[2])
+ ATTR_NONNULL(1, 2);
uiBut *ui_tree_row_find_mouse_over(const struct ARegion *region, const int xy[2])
ATTR_NONNULL(1, 2);
uiBut *ui_tree_row_find_active(const struct ARegion *region);
@@ -1388,6 +1417,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],
bool labeledit,
+ bool for_tooltip,
const uiButFindPollFn find_poll,
const void *find_custom_data)
ATTR_NONNULL(1, 2) ATTR_WARN_UNUSED_RESULT;
@@ -1513,8 +1543,10 @@ void ui_interface_tag_script_reload_queries(void);
/* interface_view.cc */
void ui_block_free_views(struct uiBlock *block);
-uiTreeViewHandle *ui_block_view_find_matching_in_old_block(const uiBlock *new_block,
- const uiTreeViewHandle *new_view);
+uiTreeViewHandle *ui_block_tree_view_find_matching_in_old_block(const uiBlock *new_block,
+ const uiTreeViewHandle *new_view);
+uiGridViewHandle *ui_block_grid_view_find_matching_in_old_block(
+ const uiBlock *new_block, const uiGridViewHandle *new_view_handle);
uiButTreeRow *ui_block_view_find_treerow_in_old_block(const uiBlock *new_block,
const uiTreeViewItemHandle *new_item_handle);
diff --git a/source/blender/editors/interface/interface_layout.c b/source/blender/editors/interface/interface_layout.c
index c1bb2ed6d18..3465373c85d 100644
--- a/source/blender/editors/interface/interface_layout.c
+++ b/source/blender/editors/interface/interface_layout.c
@@ -961,11 +961,17 @@ static void ui_item_enum_expand_tabs(uiLayout *layout,
static void ui_keymap_but_cb(bContext *UNUSED(C), void *but_v, void *UNUSED(key_v))
{
uiBut *but = but_v;
+ BLI_assert(but->type == UI_BTYPE_HOTKEY_EVENT);
+ const uiButHotkeyEvent *hotkey_but = (uiButHotkeyEvent *)but;
- RNA_int_set(&but->rnapoin, "shift", (but->modifier_key & KM_SHIFT) ? KM_MOD_HELD : KM_NOTHING);
- RNA_int_set(&but->rnapoin, "ctrl", (but->modifier_key & KM_CTRL) ? KM_MOD_HELD : KM_NOTHING);
- RNA_int_set(&but->rnapoin, "alt", (but->modifier_key & KM_ALT) ? KM_MOD_HELD : KM_NOTHING);
- RNA_int_set(&but->rnapoin, "oskey", (but->modifier_key & KM_OSKEY) ? KM_MOD_HELD : KM_NOTHING);
+ RNA_int_set(
+ &but->rnapoin, "shift", (hotkey_but->modifier_key & KM_SHIFT) ? KM_MOD_HELD : KM_NOTHING);
+ RNA_int_set(
+ &but->rnapoin, "ctrl", (hotkey_but->modifier_key & KM_CTRL) ? KM_MOD_HELD : KM_NOTHING);
+ RNA_int_set(
+ &but->rnapoin, "alt", (hotkey_but->modifier_key & KM_ALT) ? KM_MOD_HELD : KM_NOTHING);
+ RNA_int_set(
+ &but->rnapoin, "oskey", (hotkey_but->modifier_key & KM_OSKEY) ? KM_MOD_HELD : KM_NOTHING);
}
/**
@@ -1101,7 +1107,7 @@ static uiBut *ui_item_with_label(uiLayout *layout,
NULL);
UI_but_func_set(but, ui_keymap_but_cb, but, NULL);
if (flag & UI_ITEM_R_IMMEDIATE) {
- UI_but_flag_enable(but, UI_BUT_IMMEDIATE);
+ UI_but_flag_enable(but, UI_BUT_ACTIVATE_ON_INIT);
}
}
else {
@@ -2332,7 +2338,14 @@ void uiItemFullR(uiLayout *layout,
/* property with separate label */
else if (ELEM(type, PROP_ENUM, PROP_STRING, PROP_POINTER)) {
but = ui_item_with_label(layout, block, name, icon, ptr, prop, index, 0, 0, w, h, flag);
- but = ui_but_add_search(but, ptr, prop, NULL, NULL, false);
+ bool results_are_suggestions = false;
+ if (type == PROP_STRING) {
+ const eStringPropertySearchFlag search_flag = RNA_property_string_search_flag(prop);
+ if (search_flag & PROP_STRING_SEARCH_SUGGESTION) {
+ results_are_suggestions = true;
+ }
+ }
+ but = ui_but_add_search(but, ptr, prop, NULL, NULL, results_are_suggestions);
if (layout->redalert) {
UI_but_flag_enable(but, UI_BUT_REDALERT);
@@ -2705,11 +2718,16 @@ uiBut *ui_but_add_search(uiBut *but,
PropertyRNA *prop,
PointerRNA *searchptr,
PropertyRNA *searchprop,
- bool results_are_suggestions)
+ const bool results_are_suggestions)
{
/* for ID's we do automatic lookup */
+ bool has_search_fn = false;
+
PointerRNA sptr;
if (!searchprop) {
+ if (RNA_property_type(prop) == PROP_STRING) {
+ has_search_fn = (RNA_property_string_search_flag(prop) != 0);
+ }
if (RNA_property_type(prop) == PROP_POINTER) {
StructRNA *ptype = RNA_property_pointer_type(ptr, prop);
search_id_collection(ptype, &sptr, &searchprop);
@@ -2718,14 +2736,18 @@ uiBut *ui_but_add_search(uiBut *but,
}
/* turn button into search button */
- if (searchprop) {
+ if (has_search_fn || searchprop) {
uiRNACollectionSearch *coll_search = MEM_mallocN(sizeof(*coll_search), __func__);
uiButSearch *search_but;
but = ui_but_change_type(but, UI_BTYPE_SEARCH_MENU);
search_but = (uiButSearch *)but;
- search_but->rnasearchpoin = *searchptr;
- search_but->rnasearchprop = searchprop;
+
+ if (searchptr) {
+ search_but->rnasearchpoin = *searchptr;
+ search_but->rnasearchprop = searchprop;
+ }
+
but->hardmax = MAX2(but->hardmax, 256.0f);
but->drawflag |= UI_BUT_ICON_LEFT | UI_BUT_TEXT_LEFT;
if (RNA_property_is_unlink(prop)) {
@@ -2734,8 +2756,17 @@ uiBut *ui_but_add_search(uiBut *but,
coll_search->target_ptr = *ptr;
coll_search->target_prop = prop;
- coll_search->search_ptr = *searchptr;
- coll_search->search_prop = searchprop;
+
+ if (searchptr) {
+ coll_search->search_ptr = *searchptr;
+ coll_search->search_prop = searchprop;
+ }
+ else {
+ /* Rely on `has_search_fn`. */
+ coll_search->search_ptr = PointerRNA_NULL;
+ coll_search->search_prop = NULL;
+ }
+
coll_search->search_but = but;
coll_search->butstore_block = but->block;
coll_search->butstore = UI_butstore_create(coll_search->butstore_block);
diff --git a/source/blender/editors/interface/interface_ops.c b/source/blender/editors/interface/interface_ops.c
index 5b97a80d513..aafb56119ae 100644
--- a/source/blender/editors/interface/interface_ops.c
+++ b/source/blender/editors/interface/interface_ops.c
@@ -1167,7 +1167,9 @@ static void UI_OT_copy_to_selected_button(wmOperatorType *ot)
/* identifiers */
ot->name = "Copy to Selected";
ot->idname = "UI_OT_copy_to_selected_button";
- ot->description = "Copy property from this object to selected objects or bones";
+ ot->description =
+ "Copy the property's value from the active item to the same property of all selected items "
+ "if the same property exists";
/* callbacks */
ot->poll = copy_to_selected_button_poll;
@@ -1895,14 +1897,14 @@ static int drop_color_invoke(bContext *C, wmOperator *op, const wmEvent *event)
if (RNA_property_subtype(but->rnaprop) == PROP_COLOR_GAMMA) {
if (!gamma) {
- IMB_colormanagement_scene_linear_to_srgb_v3(color);
+ IMB_colormanagement_scene_linear_to_srgb_v3(color, color);
}
RNA_property_float_set_array(&but->rnapoin, but->rnaprop, color);
RNA_property_update(C, &but->rnapoin, but->rnaprop);
}
else if (RNA_property_subtype(but->rnaprop) == PROP_COLOR) {
if (gamma) {
- IMB_colormanagement_srgb_to_scene_linear_v3(color);
+ IMB_colormanagement_srgb_to_scene_linear_v3(color, color);
}
RNA_property_float_set_array(&but->rnapoin, but->rnaprop, color);
RNA_property_update(C, &but->rnapoin, but->rnaprop);
@@ -1940,6 +1942,24 @@ static void UI_OT_drop_color(wmOperatorType *ot)
/** \name Drop Name Operator
* \{ */
+static bool drop_name_poll(bContext *C)
+{
+ if (!ED_operator_regionactive(C)) {
+ return false;
+ }
+
+ const uiBut *but = UI_but_active_drop_name_button(C);
+ if (!but) {
+ return false;
+ }
+
+ if (but->flag & UI_BUT_DISABLED) {
+ return false;
+ }
+
+ return true;
+}
+
static int drop_name_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
{
uiBut *but = UI_but_active_drop_name_button(C);
@@ -1959,7 +1979,7 @@ static void UI_OT_drop_name(wmOperatorType *ot)
ot->idname = "UI_OT_drop_name";
ot->description = "Drop name to button";
- ot->poll = ED_operator_regionactive;
+ ot->poll = drop_name_poll;
ot->invoke = drop_name_invoke;
ot->flag = OPTYPE_UNDO | OPTYPE_INTERNAL;
@@ -2142,11 +2162,8 @@ static int ui_drop_material_exec(bContext *C, wmOperator *op)
{
Main *bmain = CTX_data_main(C);
- if (!RNA_struct_property_is_set(op->ptr, "session_uuid")) {
- return OPERATOR_CANCELLED;
- }
- const uint32_t session_uuid = (uint32_t)RNA_int_get(op->ptr, "session_uuid");
- Material *ma = (Material *)BKE_libblock_find_session_uuid(bmain, ID_MA, session_uuid);
+ Material *ma = (Material *)WM_operator_properties_id_lookup_from_name_or_session_uuid(
+ bmain, op->ptr, ID_MA);
if (ma == NULL) {
return OPERATOR_CANCELLED;
}
@@ -2184,16 +2201,7 @@ static void UI_OT_drop_material(wmOperatorType *ot)
ot->exec = ui_drop_material_exec;
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_INTERNAL;
- PropertyRNA *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, PROP_SKIP_SAVE | PROP_HIDDEN);
+ WM_operator_properties_id_lookup(ot, false);
}
/** \} */
diff --git a/source/blender/editors/interface/interface_query.cc b/source/blender/editors/interface/interface_query.cc
index 337b2852d57..71cf60985df 100644
--- a/source/blender/editors/interface/interface_query.cc
+++ b/source/blender/editors/interface/interface_query.cc
@@ -58,12 +58,28 @@ bool ui_but_is_toggle(const uiBut *but)
UI_BTYPE_TREEROW);
}
-bool ui_but_is_interactive(const uiBut *but, const bool labeledit)
+bool ui_but_is_view_item(const uiBut *but)
+{
+ return ELEM(but->type, UI_BTYPE_TREEROW, UI_BTYPE_GRID_TILE);
+}
+
+bool ui_but_is_interactive_ex(const uiBut *but, const bool labeledit, const bool for_tooltip)
{
/* NOTE: #UI_BTYPE_LABEL is included for highlights, this allows drags. */
- if ((but->type == UI_BTYPE_LABEL) && but->dragpoin == nullptr && but->tip_func == nullptr) {
- return false;
+ if (but->type == UI_BTYPE_LABEL) {
+ if (for_tooltip) {
+ /* It's important labels are considered interactive for the purpose of showing tooltip. */
+ if (!ui_but_drag_is_draggable(but) && but->tip_func == nullptr) {
+ return false;
+ }
+ }
+ else {
+ if (!ui_but_drag_is_draggable(but)) {
+ return false;
+ }
+ }
}
+
if (ELEM(but->type, UI_BTYPE_ROUNDBOX, UI_BTYPE_SEPR, UI_BTYPE_SEPR_LINE, UI_BTYPE_LISTBOX)) {
return false;
}
@@ -84,6 +100,11 @@ bool ui_but_is_interactive(const uiBut *but, const bool labeledit)
return true;
}
+bool ui_but_is_interactive(const uiBut *but, const bool labeledit)
+{
+ return ui_but_is_interactive_ex(but, labeledit, false);
+}
+
bool UI_but_is_utf8(const uiBut *but)
{
if (but->rnaprop) {
@@ -266,6 +287,7 @@ static uiBut *ui_but_find(const ARegion *region,
uiBut *ui_but_find_mouse_over_ex(const ARegion *region,
const int xy[2],
const bool labeledit,
+ const bool for_tooltip,
const uiButFindPollFn find_poll,
const void *find_custom_data)
{
@@ -282,7 +304,7 @@ uiBut *ui_but_find_mouse_over_ex(const ARegion *region,
if (find_poll && find_poll(but, find_custom_data) == false) {
continue;
}
- if (ui_but_is_interactive(but, labeledit)) {
+ if (ui_but_is_interactive_ex(but, labeledit, for_tooltip)) {
if (but->pie_dir != UI_RADIAL_NONE) {
if (ui_but_isect_pie_seg(block, but)) {
butover = but;
@@ -310,7 +332,8 @@ uiBut *ui_but_find_mouse_over_ex(const ARegion *region,
uiBut *ui_but_find_mouse_over(const ARegion *region, const wmEvent *event)
{
- return ui_but_find_mouse_over_ex(region, event->xy, event->modifier & KM_CTRL, nullptr, nullptr);
+ return ui_but_find_mouse_over_ex(
+ region, event->xy, event->modifier & KM_CTRL, false, nullptr, nullptr);
}
uiBut *ui_but_find_rect_over(const struct ARegion *region, const rcti *rect_px)
@@ -414,7 +437,7 @@ static bool ui_but_is_listrow(const uiBut *but, const void *UNUSED(customdata))
uiBut *ui_list_row_find_mouse_over(const ARegion *region, const int xy[2])
{
- return ui_but_find_mouse_over_ex(region, xy, false, ui_but_is_listrow, nullptr);
+ return ui_but_find_mouse_over_ex(region, xy, false, false, ui_but_is_listrow, nullptr);
}
struct ListRowFindIndexData {
@@ -444,9 +467,19 @@ static bool ui_but_is_treerow(const uiBut *but, const void *UNUSED(customdata))
return but->type == UI_BTYPE_TREEROW;
}
+static bool ui_but_is_view_item_fn(const uiBut *but, const void *UNUSED(customdata))
+{
+ return ui_but_is_view_item(but);
+}
+
+uiBut *ui_view_item_find_mouse_over(const ARegion *region, const int xy[2])
+{
+ return ui_but_find_mouse_over_ex(region, xy, false, false, ui_but_is_view_item_fn, nullptr);
+}
+
uiBut *ui_tree_row_find_mouse_over(const ARegion *region, const int xy[2])
{
- return ui_but_find_mouse_over_ex(region, xy, false, ui_but_is_treerow, nullptr);
+ return ui_but_find_mouse_over_ex(region, xy, false, false, ui_but_is_treerow, nullptr);
}
static bool ui_but_is_active_treerow(const uiBut *but, const void *customdata)
diff --git a/source/blender/editors/interface/interface_region_color_picker.cc b/source/blender/editors/interface/interface_region_color_picker.cc
index ab0a6039cdc..db1e5e653de 100644
--- a/source/blender/editors/interface/interface_region_color_picker.cc
+++ b/source/blender/editors/interface/interface_region_color_picker.cc
@@ -116,7 +116,7 @@ void ui_scene_linear_to_perceptual_space(uiBut *but, float rgb[3])
* assuming it is more perceptually linear than the scene linear
* space for intuitive color picking. */
if (!ui_but_is_color_gamma(but)) {
- IMB_colormanagement_scene_linear_to_color_picking_v3(rgb);
+ IMB_colormanagement_scene_linear_to_color_picking_v3(rgb, rgb);
ui_color_picker_rgb_round(rgb);
}
}
@@ -124,7 +124,7 @@ void ui_scene_linear_to_perceptual_space(uiBut *but, float rgb[3])
void ui_perceptual_to_scene_linear_space(uiBut *but, float rgb[3])
{
if (!ui_but_is_color_gamma(but)) {
- IMB_colormanagement_color_picking_to_scene_linear_v3(rgb);
+ IMB_colormanagement_color_picking_to_scene_linear_v3(rgb, rgb);
ui_color_picker_rgb_round(rgb);
}
}
@@ -208,7 +208,7 @@ static void ui_update_color_picker_buts_rgb(uiBut *from_but,
* (coming from other applications, web, etc) */
copy_v3_v3(rgb_hex, rgb_scene_linear);
if (from_but && !ui_but_is_color_gamma(from_but)) {
- IMB_colormanagement_scene_linear_to_srgb_v3(rgb_hex);
+ IMB_colormanagement_scene_linear_to_srgb_v3(rgb_hex, rgb_hex);
ui_color_picker_rgb_round(rgb_hex);
}
@@ -291,7 +291,7 @@ static void ui_colorpicker_hex_rna_cb(bContext *UNUSED(C), void *bt1, void *hexc
/* Hex code is assumed to be in sRGB space (coming from other applications, web, etc) */
if (!ui_but_is_color_gamma(but)) {
- IMB_colormanagement_srgb_to_scene_linear_v3(rgb);
+ IMB_colormanagement_srgb_to_scene_linear_v3(rgb, rgb);
ui_color_picker_rgb_round(rgb);
}
@@ -777,7 +777,7 @@ static void ui_block_colorpicker(uiBlock *block,
copy_v3_v3(rgb_hex, rgba_scene_linear);
if (!ui_but_is_color_gamma(from_but)) {
- IMB_colormanagement_scene_linear_to_srgb_v3(rgb_hex);
+ IMB_colormanagement_scene_linear_to_srgb_v3(rgb_hex, rgb_hex);
ui_color_picker_rgb_round(rgb_hex);
}
diff --git a/source/blender/editors/interface/interface_region_menu_popup.cc b/source/blender/editors/interface/interface_region_menu_popup.cc
index e843a275d08..a22f7218203 100644
--- a/source/blender/editors/interface/interface_region_menu_popup.cc
+++ b/source/blender/editors/interface/interface_region_menu_popup.cc
@@ -129,6 +129,12 @@ static uiBut *ui_popup_menu_memory__internal(uiBlock *block, uiBut *but)
/* get */
LISTBASE_FOREACH (uiBut *, but_iter, &block->buttons) {
+ /* Prevent labels (typically headings), from being returned in the case the text
+ * happens to matches one of the menu items.
+ * Skip separators too as checking them is redundant. */
+ if (ELEM(but_iter->type, UI_BTYPE_LABEL, UI_BTYPE_SEPR, UI_BTYPE_SEPR_LINE)) {
+ continue;
+ }
if (mem[hash_mod] ==
ui_popup_string_hash(but_iter->str, but_iter->flag & UI_BUT_HAS_SEP_CHAR)) {
return but_iter;
diff --git a/source/blender/editors/interface/interface_region_search.cc b/source/blender/editors/interface/interface_region_search.cc
index bc497e2647c..81c0c29d09a 100644
--- a/source/blender/editors/interface/interface_region_search.cc
+++ b/source/blender/editors/interface/interface_region_search.cc
@@ -58,7 +58,7 @@ struct uiSearchItems {
char **names;
void **pointers;
int *icons;
- int *states;
+ int *but_flags;
uint8_t *name_prefix_offsets;
/** Is there any item with an icon? */
@@ -94,7 +94,7 @@ bool UI_search_item_add(uiSearchItems *items,
const char *name,
void *poin,
int iconid,
- int state,
+ const int but_flag,
const uint8_t name_prefix_offset)
{
/* hijack for autocomplete */
@@ -148,10 +148,10 @@ bool UI_search_item_add(uiSearchItems *items,
/* Limit flags that can be set so flags such as 'UI_SELECT' aren't accidentally set
* which will cause problems, add others as needed. */
- BLI_assert(
- (state & ~(UI_BUT_DISABLED | UI_BUT_INACTIVE | UI_BUT_REDALERT | UI_BUT_HAS_SEP_CHAR)) == 0);
- if (items->states) {
- items->states[items->totitem] = state;
+ BLI_assert((but_flag &
+ ~(UI_BUT_DISABLED | UI_BUT_INACTIVE | UI_BUT_REDALERT | UI_BUT_HAS_SEP_CHAR)) == 0);
+ if (items->but_flags) {
+ items->but_flags[items->totitem] = but_flag;
}
items->totitem++;
@@ -451,15 +451,16 @@ void ui_searchbox_update(bContext *C, ARegion *region, uiBut *but, const bool re
/* reset vars */
data->items.totitem = 0;
data->items.more = 0;
- if (reset == false) {
+ if (!reset) {
data->items.offset_i = data->items.offset;
}
else {
data->items.offset_i = data->items.offset = 0;
data->active = -1;
- /* handle active */
- if (search_but->items_update_fn && search_but->item_active) {
+ /* On init, find and center active item. */
+ const bool is_first_search = !search_but->but.changed;
+ if (is_first_search && search_but->items_update_fn && search_but->item_active) {
data->items.active = search_but->item_active;
ui_searchbox_update_fn(C, search_but, but->editstr, &data->items);
data->items.active = nullptr;
@@ -556,7 +557,7 @@ static void ui_searchbox_region_draw_fn(const bContext *C, ARegion *region)
if (data->preview) {
/* draw items */
for (int a = 0; a < data->items.totitem; a++) {
- const int state = ((a == data->active) ? UI_ACTIVE : 0) | data->items.states[a];
+ const int but_flag = ((a == data->active) ? UI_ACTIVE : 0) | data->items.but_flags[a];
/* ensure icon is up-to-date */
ui_icon_ensure_deferred(C, data->items.icons[a], data->preview);
@@ -568,7 +569,7 @@ static void ui_searchbox_region_draw_fn(const bContext *C, ARegion *region)
&rect,
data->items.names[a],
data->items.icons[a],
- state,
+ but_flag,
UI_STYLE_TEXT_LEFT);
}
@@ -590,7 +591,7 @@ static void ui_searchbox_region_draw_fn(const bContext *C, ARegion *region)
const int search_sep_len = data->sep_string ? strlen(data->sep_string) : 0;
/* draw items */
for (int a = 0; a < data->items.totitem; a++) {
- const int state = ((a == data->active) ? UI_ACTIVE : 0) | data->items.states[a];
+ const int but_flag = ((a == data->active) ? UI_ACTIVE : 0) | data->items.but_flags[a];
char *name = data->items.names[a];
int icon = data->items.icons[a];
char *name_sep_test = nullptr;
@@ -600,7 +601,7 @@ static void ui_searchbox_region_draw_fn(const bContext *C, ARegion *region)
separator_type = UI_MENU_ITEM_SEPARATOR_SHORTCUT;
}
/* Only set for displaying additional hint (e.g. library name of a linked data-block). */
- else if (state & UI_BUT_HAS_SEP_CHAR) {
+ else if (but_flag & UI_BUT_HAS_SEP_CHAR) {
separator_type = UI_MENU_ITEM_SEPARATOR_HINT;
}
@@ -615,7 +616,7 @@ static void ui_searchbox_region_draw_fn(const bContext *C, ARegion *region)
}
/* Simple menu item. */
- ui_draw_menu_item(&data->fstyle, &rect, name, icon, state, separator_type, nullptr);
+ ui_draw_menu_item(&data->fstyle, &rect, name, icon, but_flag, separator_type, nullptr);
}
else {
/* Split menu item, faded text before the separator. */
@@ -633,7 +634,7 @@ static void ui_searchbox_region_draw_fn(const bContext *C, ARegion *region)
&rect,
name,
0,
- state | UI_BUT_INACTIVE,
+ but_flag | UI_BUT_INACTIVE,
UI_MENU_ITEM_SEPARATOR_NONE,
&name_width);
*name_sep = name_sep_prev;
@@ -646,7 +647,8 @@ static void ui_searchbox_region_draw_fn(const bContext *C, ARegion *region)
}
/* The previous menu item draws the active selection. */
- ui_draw_menu_item(&data->fstyle, &rect, name_sep, icon, state, separator_type, nullptr);
+ ui_draw_menu_item(
+ &data->fstyle, &rect, name_sep, icon, but_flag, separator_type, nullptr);
}
}
/* indicate more */
@@ -677,7 +679,7 @@ static void ui_searchbox_region_free_fn(ARegion *region)
MEM_freeN(data->items.names);
MEM_freeN(data->items.pointers);
MEM_freeN(data->items.icons);
- MEM_freeN(data->items.states);
+ MEM_freeN(data->items.but_flags);
if (data->items.name_prefix_offsets != nullptr) {
MEM_freeN(data->items.name_prefix_offsets);
@@ -847,7 +849,7 @@ static ARegion *ui_searchbox_create_generic_ex(bContext *C,
data->items.names = (char **)MEM_callocN(data->items.maxitem * sizeof(void *), __func__);
data->items.pointers = (void **)MEM_callocN(data->items.maxitem * sizeof(void *), __func__);
data->items.icons = (int *)MEM_callocN(data->items.maxitem * sizeof(int), __func__);
- data->items.states = (int *)MEM_callocN(data->items.maxitem * sizeof(int), __func__);
+ data->items.but_flags = (int *)MEM_callocN(data->items.maxitem * sizeof(int), __func__);
data->items.name_prefix_offsets = nullptr; /* Lazy initialized as needed. */
for (int i = 0; i < data->items.maxitem; i++) {
data->items.names[i] = (char *)MEM_callocN(data->items.maxstrlen + 1, __func__);
@@ -913,7 +915,7 @@ static void ui_searchbox_region_draw_cb__operator(const bContext *UNUSED(C), ARe
/* widget itself */
/* NOTE: i18n messages extracting tool does the same, please keep it in sync. */
{
- const int state = ((a == data->active) ? UI_ACTIVE : 0) | data->items.states[a];
+ const int but_flag = ((a == data->active) ? UI_ACTIVE : 0) | data->items.but_flags[a];
wmOperatorType *ot = static_cast<wmOperatorType *>(data->items.pointers[a]);
char text_pre[128];
@@ -936,14 +938,14 @@ static void ui_searchbox_region_draw_cb__operator(const bContext *UNUSED(C), ARe
&rect_pre,
CTX_IFACE_(BLT_I18NCONTEXT_OPERATOR_DEFAULT, text_pre),
data->items.icons[a],
- state,
+ but_flag,
UI_MENU_ITEM_SEPARATOR_NONE,
nullptr);
ui_draw_menu_item(&data->fstyle,
&rect_post,
data->items.names[a],
0,
- state,
+ but_flag,
data->use_shortcut_sep ? UI_MENU_ITEM_SEPARATOR_SHORTCUT :
UI_MENU_ITEM_SEPARATOR_NONE,
nullptr);
diff --git a/source/blender/editors/interface/interface_region_tooltip.c b/source/blender/editors/interface/interface_region_tooltip.c
index c7ebecb178b..82d4405e1b5 100644
--- a/source/blender/editors/interface/interface_region_tooltip.c
+++ b/source/blender/editors/interface/interface_region_tooltip.c
@@ -800,7 +800,7 @@ static uiTooltipData *ui_tooltip_data_from_button_or_extra_icon(bContext *C,
.style = UI_TIP_STYLE_HEADER,
.color_id = UI_TIP_LC_NORMAL,
});
- field->text = BLI_sprintfN("%s", but_label.strinfo);
+ field->text = BLI_strdup(but_label.strinfo);
}
/* Tip */
diff --git a/source/blender/editors/interface/interface_style.cc b/source/blender/editors/interface/interface_style.cc
index 0156a943015..904765f6dc4 100644
--- a/source/blender/editors/interface/interface_style.cc
+++ b/source/blender/editors/interface/interface_style.cc
@@ -376,25 +376,14 @@ void uiStyleInit(void)
{
const uiStyle *style = static_cast<uiStyle *>(U.uistyles.first);
- /* recover from uninitialized dpi */
+ /* Recover from uninitialized DPI. */
if (U.dpi == 0) {
U.dpi = 72;
}
CLAMP(U.dpi, 48, 144);
- LISTBASE_FOREACH (uiFont *, font, &U.uifonts) {
- BLF_unload_id(font->blf_id);
- }
-
- if (blf_mono_font != -1) {
- BLF_unload_id(blf_mono_font);
- blf_mono_font = -1;
- }
-
- if (blf_mono_font_render != -1) {
- BLF_unload_id(blf_mono_font_render);
- blf_mono_font_render = -1;
- }
+ /* Needed so that custom fonts are always first. */
+ BLF_unload_all();
uiFont *font_first = static_cast<uiFont *>(U.uifonts.first);
@@ -498,6 +487,9 @@ void uiStyleInit(void)
const bool unique = true;
blf_mono_font_render = BLF_load_mono_default(unique);
}
+
+ /* Load the fallback fonts last. */
+ BLF_load_font_stack();
}
void UI_fontstyle_set(const uiFontStyle *fs)
diff --git a/source/blender/editors/interface/interface_template_attribute_search.cc b/source/blender/editors/interface/interface_template_attribute_search.cc
index 384e9d1794e..4e587bd5338 100644
--- a/source/blender/editors/interface/interface_template_attribute_search.cc
+++ b/source/blender/editors/interface/interface_template_attribute_search.cc
@@ -24,14 +24,14 @@ using blender::nodes::geometry_nodes_eval_log::GeometryAttributeInfo;
namespace blender::ui {
-static StringRef attribute_data_type_string(const CustomDataType type)
+static StringRef attribute_data_type_string(const eCustomDataType type)
{
const char *name = nullptr;
RNA_enum_name_from_value(rna_enum_attribute_type_items, type, &name);
return StringRef(IFACE_(name));
}
-static StringRef attribute_domain_string(const AttributeDomain domain)
+static StringRef attribute_domain_string(const eAttrDomain domain)
{
const char *name = nullptr;
RNA_enum_name_from_value(rna_enum_attribute_domain_items, domain, &name);
@@ -40,8 +40,8 @@ static StringRef attribute_domain_string(const AttributeDomain domain)
static bool attribute_search_item_add(uiSearchItems *items, const GeometryAttributeInfo &item)
{
- const StringRef data_type_name = attribute_data_type_string(item.data_type);
- const StringRef domain_name = attribute_domain_string(item.domain);
+ const StringRef data_type_name = attribute_data_type_string(*item.data_type);
+ const StringRef domain_name = attribute_domain_string(*item.domain);
std::string search_item_text = domain_name + " " + UI_MENU_ARROW_SEP + item.name + UI_SEP_CHAR +
data_type_name;
@@ -91,6 +91,9 @@ void attribute_search_add_items(StringRefNull str,
if (item->name == "normal" && item->domain == ATTR_DOMAIN_FACE) {
continue;
}
+ if (!bke::allow_procedural_attribute_access(item->name)) {
+ continue;
+ }
BLI_string_search_add(search, item->name.c_str(), (void *)item, 0);
}
diff --git a/source/blender/editors/interface/interface_template_list.cc b/source/blender/editors/interface/interface_template_list.cc
index 68a699c652a..e0b6bbb34c4 100644
--- a/source/blender/editors/interface/interface_template_list.cc
+++ b/source/blender/editors/interface/interface_template_list.cc
@@ -945,13 +945,8 @@ static void ui_template_list_layout_draw(bContext *C,
const bool show_names = (flags & UI_TEMPLATE_LIST_NO_NAMES) == 0;
- /* TODO ED_fileselect_init_layout(). Share somehow? */
- float size_x = (96.0f / 20.0f) * UI_UNIT_X;
- float size_y = (96.0f / 20.0f) * UI_UNIT_Y;
-
- if (!show_names) {
- size_y -= UI_UNIT_Y;
- }
+ const int size_x = UI_preview_tile_size_x();
+ const int size_y = show_names ? UI_preview_tile_size_y() : UI_preview_tile_size_y_no_label();
const int cols_per_row = MAX2((uiLayoutGetWidth(box) - V2D_SCROLL_WIDTH) / size_x, 1);
uiLayout *grid = uiLayoutGridFlow(row, true, cols_per_row, true, true, true);
diff --git a/source/blender/editors/interface/interface_templates.c b/source/blender/editors/interface/interface_templates.c
index 4e6437e043a..05ae5299e58 100644
--- a/source/blender/editors/interface/interface_templates.c
+++ b/source/blender/editors/interface/interface_templates.c
@@ -742,7 +742,7 @@ static void template_id_liboverride_hierarchy_create(bContext *C,
object_active->id.tag |= LIB_TAG_DOIT;
}
BKE_lib_override_library_create(
- bmain, scene, view_layer, NULL, id, &collection_active->id, NULL, &id_override);
+ bmain, scene, view_layer, NULL, id, &collection_active->id, NULL, &id_override, false);
}
else if (object_active != NULL && !ID_IS_LINKED(object_active) &&
&object_active->instance_collection->id == id) {
@@ -754,7 +754,8 @@ static void template_id_liboverride_hierarchy_create(bContext *C,
id,
&object_active->id,
&object_active->id,
- &id_override);
+ &id_override,
+ false);
}
break;
case ID_OB:
@@ -765,7 +766,7 @@ static void template_id_liboverride_hierarchy_create(bContext *C,
object_active->id.tag |= LIB_TAG_DOIT;
}
BKE_lib_override_library_create(
- bmain, scene, view_layer, NULL, id, &collection_active->id, NULL, &id_override);
+ bmain, scene, view_layer, NULL, id, &collection_active->id, NULL, &id_override, false);
}
break;
case ID_ME:
@@ -787,13 +788,20 @@ static void template_id_liboverride_hierarchy_create(bContext *C,
if (object_active != NULL) {
object_active->id.tag |= LIB_TAG_DOIT;
}
- BKE_lib_override_library_create(
- bmain, scene, view_layer, NULL, id, &collection_active->id, NULL, &id_override);
+ BKE_lib_override_library_create(bmain,
+ scene,
+ view_layer,
+ NULL,
+ id,
+ &collection_active->id,
+ NULL,
+ &id_override,
+ false);
}
else {
object_active->id.tag |= LIB_TAG_DOIT;
BKE_lib_override_library_create(
- bmain, scene, view_layer, NULL, id, &object_active->id, NULL, &id_override);
+ bmain, scene, view_layer, NULL, id, &object_active->id, NULL, &id_override, false);
}
}
break;
@@ -812,8 +820,11 @@ static void template_id_liboverride_hierarchy_create(bContext *C,
id_override->override_library->flag &= ~IDOVERRIDE_LIBRARY_FLAG_SYSTEM_DEFINED;
*r_undo_push_label = "Make Library Override Hierarchy";
- WM_event_add_notifier(C, NC_WINDOW, NULL);
- DEG_relations_tag_update(bmain);
+ /* Given `idptr` is re-assigned to owner property by caller to ensure proper updates etc. Here
+ * we also use it to ensure remapping of the owner property from the linked data to the newly
+ * created liboverride (note that in theory this remapping has already been done by code
+ * above). */
+ RNA_id_pointer_create(id_override, idptr);
}
}
@@ -1525,8 +1536,8 @@ static void template_ID_tabs(const bContext *C,
0.0f,
"");
UI_but_funcN_set(&tab->but, template_ID_set_property_exec_fn, MEM_dupallocN(template), id);
+ UI_but_drag_set_id(&tab->but, id);
tab->but.custom_data = (void *)id;
- tab->but.dragpoin = id;
tab->menu = mt;
UI_but_drawflag_enable(&tab->but, but_align);
diff --git a/source/blender/editors/interface/interface_utils.cc b/source/blender/editors/interface/interface_utils.cc
index 993ccdf92f7..b7ca2d9aa11 100644
--- a/source/blender/editors/interface/interface_utils.cc
+++ b/source/blender/editors/interface/interface_utils.cc
@@ -24,6 +24,7 @@
#include "BLT_translation.h"
#include "BKE_context.h"
+#include "BKE_global.h"
#include "BKE_lib_id.h"
#include "BKE_report.h"
@@ -516,71 +517,136 @@ void ui_rna_collection_search_update_fn(
StringSearch *search = skip_filter ? nullptr : BLI_string_search_new();
- /* build a temporary list of relevant items first */
- int item_index = 0;
- RNA_PROP_BEGIN (&data->search_ptr, itemptr, data->search_prop) {
+ if (data->search_prop != nullptr) {
+ /* build a temporary list of relevant items first */
+ int item_index = 0;
+ RNA_PROP_BEGIN (&data->search_ptr, itemptr, data->search_prop) {
- if (flag & PROP_ID_SELF_CHECK) {
- if (itemptr.data == data->target_ptr.owner_id) {
- continue;
+ if (flag & PROP_ID_SELF_CHECK) {
+ if (itemptr.data == data->target_ptr.owner_id) {
+ continue;
+ }
}
- }
- /* use filter */
- if (is_ptr_target) {
- if (RNA_property_pointer_poll(&data->target_ptr, data->target_prop, &itemptr) == 0) {
- continue;
+ /* use filter */
+ if (is_ptr_target) {
+ if (RNA_property_pointer_poll(&data->target_ptr, data->target_prop, &itemptr) == 0) {
+ continue;
+ }
}
- }
- int name_prefix_offset = 0;
- int iconid = ICON_NONE;
- bool has_sep_char = false;
- const bool is_id = itemptr.type && RNA_struct_is_ID(itemptr.type);
+ int name_prefix_offset = 0;
+ int iconid = ICON_NONE;
+ bool has_sep_char = false;
+ const bool is_id = itemptr.type && RNA_struct_is_ID(itemptr.type);
- if (is_id) {
- iconid = ui_id_icon_get(C, static_cast<ID *>(itemptr.data), false);
- if (!ELEM(iconid, 0, ICON_BLANK1)) {
- has_id_icon = true;
- }
+ if (is_id) {
+ iconid = ui_id_icon_get(C, static_cast<ID *>(itemptr.data), false);
+ if (!ELEM(iconid, 0, ICON_BLANK1)) {
+ has_id_icon = true;
+ }
- if (requires_exact_data_name) {
- name = RNA_struct_name_get_alloc(&itemptr, name_buf, sizeof(name_buf), nullptr);
+ if (requires_exact_data_name) {
+ name = RNA_struct_name_get_alloc(&itemptr, name_buf, sizeof(name_buf), nullptr);
+ }
+ else {
+ const ID *id = static_cast<ID *>(itemptr.data);
+ BKE_id_full_name_ui_prefix_get(name_buf, id, true, UI_SEP_CHAR, &name_prefix_offset);
+ BLI_STATIC_ASSERT(sizeof(name_buf) >= MAX_ID_FULL_NAME_UI,
+ "Name string buffer should be big enough to hold full UI ID name");
+ name = name_buf;
+ has_sep_char = ID_IS_LINKED(id);
+ }
}
else {
- const ID *id = static_cast<ID *>(itemptr.data);
- BKE_id_full_name_ui_prefix_get(name_buf, id, true, UI_SEP_CHAR, &name_prefix_offset);
- BLI_STATIC_ASSERT(sizeof(name_buf) >= MAX_ID_FULL_NAME_UI,
- "Name string buffer should be big enough to hold full UI ID name");
- name = name_buf;
- has_sep_char = ID_IS_LINKED(id);
+ name = RNA_struct_name_get_alloc(&itemptr, name_buf, sizeof(name_buf), nullptr);
}
- }
- else {
- name = RNA_struct_name_get_alloc(&itemptr, name_buf, sizeof(name_buf), nullptr);
- }
- if (name) {
- CollItemSearch *cis = MEM_cnew<CollItemSearch>(__func__);
- cis->data = itemptr.data;
- cis->name = BLI_strdup(name);
- cis->index = item_index;
- cis->iconid = iconid;
- cis->is_id = is_id;
- cis->name_prefix_offset = name_prefix_offset;
- cis->has_sep_char = has_sep_char;
- if (!skip_filter) {
- BLI_string_search_add(search, name, cis, 0);
+ if (name) {
+ CollItemSearch *cis = MEM_cnew<CollItemSearch>(__func__);
+ cis->data = itemptr.data;
+ cis->name = BLI_strdup(name);
+ cis->index = item_index;
+ cis->iconid = iconid;
+ cis->is_id = is_id;
+ cis->name_prefix_offset = name_prefix_offset;
+ cis->has_sep_char = has_sep_char;
+ if (!skip_filter) {
+ BLI_string_search_add(search, name, cis, 0);
+ }
+ BLI_addtail(items_list, cis);
+ if (name != name_buf) {
+ MEM_freeN(name);
+ }
}
- BLI_addtail(items_list, cis);
- if (name != name_buf) {
- MEM_freeN(name);
+
+ item_index++;
+ }
+ RNA_PROP_END;
+ }
+ else {
+ BLI_assert(RNA_property_type(data->target_prop) == PROP_STRING);
+ const eStringPropertySearchFlag search_flag = RNA_property_string_search_flag(
+ data->target_prop);
+ BLI_assert(search_flag & PROP_STRING_SEARCH_SUPPORTED);
+
+ struct SearchVisitUserData {
+ StringSearch *search;
+ bool skip_filter;
+ int item_index;
+ ListBase *items_list;
+ const char *func_id;
+ } user_data = {nullptr};
+
+ user_data.search = search;
+ user_data.skip_filter = skip_filter;
+ user_data.items_list = items_list;
+ user_data.func_id = __func__;
+
+ RNA_property_string_search(
+ C,
+ &data->target_ptr,
+ data->target_prop,
+ str,
+ [](void *user_data, const StringPropertySearchVisitParams *visit_params) {
+ const bool show_extra_info = (G.debug_value == 102);
+
+ SearchVisitUserData *search_data = (struct SearchVisitUserData *)user_data;
+ CollItemSearch *cis = MEM_cnew<CollItemSearch>(search_data->func_id);
+ cis->data = nullptr;
+ if (visit_params->info && show_extra_info) {
+ cis->name = BLI_sprintfN(
+ "%s" UI_SEP_CHAR_S "%s", visit_params->text, visit_params->info);
+ }
+ else {
+ cis->name = BLI_strdup(visit_params->text);
+ }
+ cis->index = search_data->item_index;
+ cis->iconid = ICON_NONE;
+ cis->is_id = false;
+ cis->name_prefix_offset = 0;
+ cis->has_sep_char = visit_params->info != nullptr;
+ if (!search_data->skip_filter) {
+ BLI_string_search_add(search_data->search, visit_params->text, cis, 0);
+ }
+ BLI_addtail(search_data->items_list, cis);
+ search_data->item_index++;
+ },
+ (void *)&user_data);
+
+ if (search_flag & PROP_STRING_SEARCH_SORT) {
+ BLI_listbase_sort(items_list, [](const void *a_, const void *b_) -> int {
+ const CollItemSearch *cis_a = (const CollItemSearch *)a_;
+ const CollItemSearch *cis_b = (const CollItemSearch *)b_;
+ return BLI_strcasecmp_natural(cis_a->name, cis_b->name);
+ });
+ int i = 0;
+ LISTBASE_FOREACH (CollItemSearch *, cis, items_list) {
+ cis->index = i;
+ i++;
}
}
-
- item_index++;
}
- RNA_PROP_END;
if (skip_filter) {
LISTBASE_FOREACH (CollItemSearch *, cis, items_list) {
diff --git a/source/blender/editors/interface/interface_view.cc b/source/blender/editors/interface/interface_view.cc
index 85e1dbe73a5..699ac0c2b53 100644
--- a/source/blender/editors/interface/interface_view.cc
+++ b/source/blender/editors/interface/interface_view.cc
@@ -10,15 +10,22 @@
*/
#include <memory>
+#include <type_traits>
#include <variant>
#include "DNA_screen_types.h"
+#include "BKE_screen.h"
+
#include "BLI_listbase.h"
+#include "ED_screen.h"
+
#include "interface_intern.h"
#include "UI_interface.hh"
+
+#include "UI_grid_view.hh"
#include "UI_tree_view.hh"
using namespace blender;
@@ -30,29 +37,51 @@ using namespace blender::ui;
*/
struct ViewLink : public Link {
using TreeViewPtr = std::unique_ptr<AbstractTreeView>;
+ using GridViewPtr = std::unique_ptr<AbstractGridView>;
std::string idname;
/* NOTE: Can't use std::get() on this until minimum macOS deployment target is 10.14. */
- std::variant<TreeViewPtr> view;
+ std::variant<TreeViewPtr, GridViewPtr> view;
};
+template<class T> constexpr void check_if_valid_view_type()
+{
+ static_assert(std::is_same_v<T, AbstractTreeView> || std::is_same_v<T, AbstractGridView>,
+ "Unsupported view type");
+}
+
template<class T> T *get_view_from_link(ViewLink &link)
{
auto *t_uptr = std::get_if<std::unique_ptr<T>>(&link.view);
return t_uptr ? t_uptr->get() : nullptr;
}
-AbstractTreeView *UI_block_add_view(uiBlock &block,
- StringRef idname,
- std::unique_ptr<AbstractTreeView> tree_view)
+template<class T>
+static T *ui_block_add_view_impl(uiBlock &block, StringRef idname, std::unique_ptr<T> view)
{
+ check_if_valid_view_type<T>();
+
ViewLink *view_link = MEM_new<ViewLink>(__func__);
BLI_addtail(&block.views, view_link);
- view_link->view = std::move(tree_view);
+ view_link->view = std::move(view);
view_link->idname = idname;
- return get_view_from_link<AbstractTreeView>(*view_link);
+ return get_view_from_link<T>(*view_link);
+}
+
+AbstractGridView *UI_block_add_view(uiBlock &block,
+ StringRef idname,
+ std::unique_ptr<AbstractGridView> tree_view)
+{
+ return ui_block_add_view_impl<AbstractGridView>(block, idname, std::move(tree_view));
+}
+
+AbstractTreeView *UI_block_add_view(uiBlock &block,
+ StringRef idname,
+ std::unique_ptr<AbstractTreeView> tree_view)
+{
+ return ui_block_add_view_impl<AbstractTreeView>(block, idname, std::move(tree_view));
}
void ui_block_free_views(uiBlock *block)
@@ -62,6 +91,26 @@ void ui_block_free_views(uiBlock *block)
}
}
+void UI_block_views_listen(const uiBlock *block, const wmRegionListenerParams *listener_params)
+{
+ ARegion *region = listener_params->region;
+
+ LISTBASE_FOREACH (ViewLink *, view_link, &block->views) {
+ if (AbstractGridView *grid_view = get_view_from_link<AbstractGridView>(*view_link)) {
+ if (UI_grid_view_listen_should_redraw(reinterpret_cast<uiGridViewHandle *>(grid_view),
+ listener_params->notifier)) {
+ ED_region_tag_redraw(region);
+ }
+ }
+ else if (AbstractTreeView *tree_view = get_view_from_link<AbstractTreeView>(*view_link)) {
+ if (UI_tree_view_listen_should_redraw(reinterpret_cast<uiTreeViewHandle *>(tree_view),
+ listener_params->notifier)) {
+ ED_region_tag_redraw(region);
+ }
+ }
+ }
+}
+
uiTreeViewItemHandle *UI_block_tree_view_find_item_at(const ARegion *region, const int xy[2])
{
uiButTreeRow *tree_row_but = (uiButTreeRow *)ui_tree_row_find_mouse_over(region, xy);
@@ -82,11 +131,13 @@ uiTreeViewItemHandle *UI_block_tree_view_find_active_item(const ARegion *region)
return tree_row_but->tree_item;
}
-static StringRef ui_block_view_find_idname(const uiBlock &block, const AbstractTreeView &view)
+template<class T> static StringRef ui_block_view_find_idname(const uiBlock &block, const T &view)
{
+ check_if_valid_view_type<T>();
+
/* First get the idname the of the view we're looking for. */
LISTBASE_FOREACH (ViewLink *, view_link, &block.views) {
- if (get_view_from_link<AbstractTreeView>(*view_link) == &view) {
+ if (get_view_from_link<T>(*view_link) == &view) {
return view_link->idname;
}
}
@@ -94,9 +145,11 @@ static StringRef ui_block_view_find_idname(const uiBlock &block, const AbstractT
return {};
}
-static AbstractTreeView *ui_block_view_find_matching_in_old_block(const uiBlock &new_block,
- const AbstractTreeView &new_view)
+template<class T>
+static T *ui_block_view_find_matching_in_old_block(const uiBlock &new_block, const T &new_view)
{
+ check_if_valid_view_type<T>();
+
uiBlock *old_block = new_block.oldblock;
if (!old_block) {
return nullptr;
@@ -109,15 +162,15 @@ static AbstractTreeView *ui_block_view_find_matching_in_old_block(const uiBlock
LISTBASE_FOREACH (ViewLink *, old_view_link, &old_block->views) {
if (old_view_link->idname == idname) {
- return get_view_from_link<AbstractTreeView>(*old_view_link);
+ return get_view_from_link<T>(*old_view_link);
}
}
return nullptr;
}
-uiTreeViewHandle *ui_block_view_find_matching_in_old_block(const uiBlock *new_block,
- const uiTreeViewHandle *new_view_handle)
+uiTreeViewHandle *ui_block_tree_view_find_matching_in_old_block(
+ const uiBlock *new_block, const uiTreeViewHandle *new_view_handle)
{
BLI_assert(new_block && new_view_handle);
const AbstractTreeView &new_view = reinterpret_cast<const AbstractTreeView &>(*new_view_handle);
@@ -126,6 +179,16 @@ uiTreeViewHandle *ui_block_view_find_matching_in_old_block(const uiBlock *new_bl
return reinterpret_cast<uiTreeViewHandle *>(old_view);
}
+uiGridViewHandle *ui_block_grid_view_find_matching_in_old_block(
+ const uiBlock *new_block, const uiGridViewHandle *new_view_handle)
+{
+ BLI_assert(new_block && new_view_handle);
+ const AbstractGridView &new_view = reinterpret_cast<const AbstractGridView &>(*new_view_handle);
+
+ AbstractGridView *old_view = ui_block_view_find_matching_in_old_block(*new_block, new_view);
+ return reinterpret_cast<uiGridViewHandle *>(old_view);
+}
+
uiButTreeRow *ui_block_view_find_treerow_in_old_block(const uiBlock *new_block,
const uiTreeViewItemHandle *new_item_handle)
{
diff --git a/source/blender/editors/interface/interface_widgets.c b/source/blender/editors/interface/interface_widgets.c
index 98ecf91adbc..e2df2d77817 100644
--- a/source/blender/editors/interface/interface_widgets.c
+++ b/source/blender/editors/interface/interface_widgets.c
@@ -105,24 +105,25 @@ typedef enum {
UI_WTYPE_PROGRESSBAR,
UI_WTYPE_NODESOCKET,
UI_WTYPE_TREEROW,
+ UI_WTYPE_GRID_TILE,
} uiWidgetTypeEnum;
-/* Button state argument shares bits with 'uiBut.flag'.
- * reuse flags that aren't needed for drawing to avoid collision. */
-enum {
- /* Show that holding the button opens a menu. */
- UI_STATE_HOLD_ACTION = UI_BUT_UPDATE_DELAY,
- UI_STATE_TEXT_INPUT = UI_BUT_UNDO,
- UI_STATE_ACTIVE_LEFT = UI_BUT_VALUE_CLEAR,
- UI_STATE_ACTIVE_RIGHT = UI_BUT_TEXTEDIT_UPDATE,
- UI_STATE_TEXT_BEFORE_WIDGET = UI_BUT_IMMEDIATE,
-
- UI_STATE_FLAGS_ALL = (UI_STATE_HOLD_ACTION | UI_STATE_TEXT_INPUT | UI_STATE_ACTIVE_LEFT |
- UI_STATE_ACTIVE_RIGHT | UI_STATE_TEXT_BEFORE_WIDGET),
-};
-/* Prevent accidental use. */
-#define UI_BUT_UPDATE_DELAY ((void)0)
-#define UI_BUT_UNDO ((void)0)
+/**
+ * The button's state information adapted for drawing. Use #STATE_INFO_NULL for empty state.
+ */
+typedef struct {
+ /** Copy of #uiBut.flag (possibly with overrides for drawing). */
+ int but_flag;
+ /** Copy of #uiBut.drawflag (possibly with overrides for drawing). */
+ int but_drawflag;
+
+ /** Show that holding the button opens a menu. */
+ bool has_hold_action : 1;
+ /** The button is in text input mode. */
+ bool is_text_input : 1;
+} uiWidgetStateInfo;
+
+static const uiWidgetStateInfo STATE_INFO_NULL = {0};
/** \} */
@@ -256,10 +257,21 @@ typedef struct uiWidgetType {
/* converted colors for state */
uiWidgetColors wcol;
- void (*state)(struct uiWidgetType *, int state, int drawflag, eUIEmbossType emboss);
- void (*draw)(uiWidgetColors *, rcti *, int state, int roundboxalign, const float zoom);
- void (*custom)(
- uiBut *, uiWidgetColors *, rcti *, int state, int roundboxalign, const float zoom);
+ void (*state)(struct uiWidgetType *, const uiWidgetStateInfo *state, eUIEmbossType emboss)
+ ATTR_NONNULL();
+ void (*draw)(uiWidgetColors *,
+ rcti *,
+ const uiWidgetStateInfo *,
+ int roundboxalign,
+ const float zoom) ATTR_NONNULL();
+ void (*custom)(uiBut *,
+ uiWidgetColors *,
+ rcti *,
+ const uiWidgetStateInfo *,
+ int roundboxalign,
+ const float zoom) ATTR_NONNULL();
+ void (*draw_block)(
+ uiWidgetColors *, rcti *, int block_flag, int roundboxalign, const float zoom);
void (*text)(const uiFontStyle *, const uiWidgetColors *, uiBut *, rcti *);
} uiWidgetType;
@@ -1289,16 +1301,16 @@ static void widgetbase_draw(uiWidgetBase *wtb, const uiWidgetColors *wcol)
#define PREVIEW_PAD 4
-static float widget_alpha_factor(const int state)
+static float widget_alpha_factor(const uiWidgetStateInfo *state)
{
- if (state & (UI_BUT_INACTIVE | UI_BUT_DISABLED)) {
- if (state & UI_SEARCH_FILTER_NO_MATCH) {
+ if (state->but_flag & (UI_BUT_INACTIVE | UI_BUT_DISABLED)) {
+ if (state->but_flag & UI_SEARCH_FILTER_NO_MATCH) {
return 0.25f;
}
return 0.5f;
}
- if (state & UI_SEARCH_FILTER_NO_MATCH) {
+ if (state->but_flag & UI_SEARCH_FILTER_NO_MATCH) {
return 0.5f;
}
@@ -1367,7 +1379,10 @@ static void widget_draw_icon(
}
}
else if (ELEM(but->type, UI_BTYPE_BUT, UI_BTYPE_DECORATOR)) {
- alpha *= widget_alpha_factor(but->flag);
+ uiWidgetStateInfo state = {0};
+ state.but_flag = but->flag;
+ state.but_drawflag = but->drawflag;
+ alpha *= widget_alpha_factor(&state);
}
GPU_blend(GPU_BLEND_ALPHA);
@@ -1405,7 +1420,7 @@ static void widget_draw_icon(
const bool has_theme = UI_icon_get_theme_color(icon, color);
/* to indicate draggable */
- if (but->dragpoin && (but->flag & UI_ACTIVE)) {
+ if (ui_but_drag_is_draggable(but) && (but->flag & UI_ACTIVE)) {
UI_icon_draw_ex(xs, ys, icon, aspect, 1.25f, 0.0f, color, has_theme);
}
else if ((but->flag & (UI_ACTIVE | UI_SELECT | UI_SELECT_DRAW))) {
@@ -2446,7 +2461,7 @@ static void widget_draw_text_icon(const uiFontStyle *fstyle,
* \{ */
/* put all widget colors on half alpha, use local storage */
-static void ui_widget_color_disabled(uiWidgetType *wt, const int state)
+static void ui_widget_color_disabled(uiWidgetType *wt, const uiWidgetStateInfo *state)
{
static uiWidgetColors wcol_theme_s;
@@ -2473,8 +2488,7 @@ static void widget_active_color(uiWidgetColors *wcol)
}
static const uchar *widget_color_blend_from_flags(const uiWidgetStateColors *wcol_state,
- int state,
- int drawflag,
+ const uiWidgetStateInfo *state,
const eUIEmbossType emboss)
{
/* Explicitly require #UI_EMBOSS_NONE_OR_STATUS for color blending with no emboss. */
@@ -2482,44 +2496,44 @@ static const uchar *widget_color_blend_from_flags(const uiWidgetStateColors *wco
return NULL;
}
- if (drawflag & UI_BUT_ANIMATED_CHANGED) {
+ if (state->but_drawflag & UI_BUT_ANIMATED_CHANGED) {
return wcol_state->inner_changed_sel;
}
- if (state & UI_BUT_ANIMATED_KEY) {
+ if (state->but_flag & UI_BUT_ANIMATED_KEY) {
return wcol_state->inner_key_sel;
}
- if (state & UI_BUT_ANIMATED) {
+ if (state->but_flag & UI_BUT_ANIMATED) {
return wcol_state->inner_anim_sel;
}
- if (state & UI_BUT_DRIVEN) {
+ if (state->but_flag & UI_BUT_DRIVEN) {
return wcol_state->inner_driven_sel;
}
- if (state & UI_BUT_OVERRIDDEN) {
+ if (state->but_flag & UI_BUT_OVERRIDDEN) {
return wcol_state->inner_overridden_sel;
}
return NULL;
}
/* copy colors from theme, and set changes in it based on state */
-static void widget_state(uiWidgetType *wt, int state, int drawflag, eUIEmbossType emboss)
+static void widget_state(uiWidgetType *wt, const uiWidgetStateInfo *state, eUIEmbossType emboss)
{
uiWidgetStateColors *wcol_state = wt->wcol_state;
- if (state & UI_BUT_LIST_ITEM) {
+ if (state->but_flag & UI_BUT_LIST_ITEM) {
/* Override default widget's colors. */
bTheme *btheme = UI_GetTheme();
wt->wcol_theme = &btheme->tui.wcol_list_item;
- if (state & (UI_BUT_DISABLED | UI_BUT_INACTIVE | UI_SEARCH_FILTER_NO_MATCH)) {
+ if (state->but_flag & (UI_BUT_DISABLED | UI_BUT_INACTIVE | UI_SEARCH_FILTER_NO_MATCH)) {
ui_widget_color_disabled(wt, state);
}
}
wt->wcol = *(wt->wcol_theme);
- const uchar *color_blend = widget_color_blend_from_flags(wcol_state, state, drawflag, emboss);
+ const uchar *color_blend = widget_color_blend_from_flags(wcol_state, state, emboss);
- if (state & UI_SELECT) {
+ if (state->but_flag & UI_SELECT) {
copy_v4_v4_uchar(wt->wcol.inner, wt->wcol.inner_sel);
if (color_blend != NULL) {
color_blend_v3_v3(wt->wcol.inner, color_blend, wcol_state->blend);
@@ -2527,12 +2541,12 @@ static void widget_state(uiWidgetType *wt, int state, int drawflag, eUIEmbossTyp
copy_v3_v3_uchar(wt->wcol.text, wt->wcol.text_sel);
- if (state & UI_SELECT) {
+ if (state->but_flag & UI_SELECT) {
SWAP(short, wt->wcol.shadetop, wt->wcol.shadedown);
}
}
else {
- if (state & UI_BUT_ACTIVE_DEFAULT) {
+ if (state->but_flag & UI_BUT_ACTIVE_DEFAULT) {
copy_v4_v4_uchar(wt->wcol.inner, wt->wcol.inner_sel);
copy_v4_v4_uchar(wt->wcol.text, wt->wcol.text_sel);
}
@@ -2544,12 +2558,12 @@ static void widget_state(uiWidgetType *wt, int state, int drawflag, eUIEmbossTyp
* even if UI_SELECT. But currently this causes some flickering
* as buttons can be created and updated without respect to mouse
* position and so can draw without UI_ACTIVE set. See D6503. */
- if (state & UI_ACTIVE) {
+ if (state->but_flag & UI_ACTIVE) {
widget_active_color(&wt->wcol);
}
}
- if (state & UI_BUT_REDALERT) {
+ if (state->but_flag & UI_BUT_REDALERT) {
const uchar red[4] = {255, 0, 0};
if (wt->draw && emboss != UI_EMBOSS_NONE) {
color_blend_v3_v3(wt->wcol.inner, red, 0.4f);
@@ -2559,14 +2573,14 @@ static void widget_state(uiWidgetType *wt, int state, int drawflag, eUIEmbossTyp
}
}
- if (state & UI_BUT_DRAG_MULTI) {
+ if (state->but_flag & UI_BUT_DRAG_MULTI) {
/* the button isn't SELECT but we're editing this so draw with sel color */
copy_v4_v4_uchar(wt->wcol.inner, wt->wcol.inner_sel);
SWAP(short, wt->wcol.shadetop, wt->wcol.shadedown);
color_blend_v3_v3(wt->wcol.text, wt->wcol.text_sel, 0.85f);
}
- if (state & UI_BUT_NODE_ACTIVE) {
+ if (state->but_flag & UI_BUT_NODE_ACTIVE) {
const uchar blue[4] = {86, 128, 194};
color_blend_v3_v3(wt->wcol.inner, blue, 0.3f);
}
@@ -2600,14 +2614,16 @@ static float widget_radius_from_rcti(const rcti *rect, const uiWidgetColors *wco
* \{ */
/* sliders use special hack which sets 'item' as inner when drawing filling */
-static void widget_state_numslider(uiWidgetType *wt, int state, int drawflag, eUIEmbossType emboss)
+static void widget_state_numslider(uiWidgetType *wt,
+ const uiWidgetStateInfo *state,
+ eUIEmbossType emboss)
{
uiWidgetStateColors *wcol_state = wt->wcol_state;
/* call this for option button */
- widget_state(wt, state, drawflag, emboss);
+ widget_state(wt, state, emboss);
- const uchar *color_blend = widget_color_blend_from_flags(wcol_state, state, drawflag, emboss);
+ const uchar *color_blend = widget_color_blend_from_flags(wcol_state, state, emboss);
if (color_blend != NULL) {
/* Set the slider 'item' so that it reflects state settings too.
* De-saturate so the color of the slider doesn't conflict with the blend color,
@@ -2617,15 +2633,14 @@ static void widget_state_numslider(uiWidgetType *wt, int state, int drawflag, eU
color_ensure_contrast_v3(wt->wcol.item, wt->wcol.inner, 30);
}
- if (state & UI_SELECT) {
+ if (state->but_flag & UI_SELECT) {
SWAP(short, wt->wcol.shadetop, wt->wcol.shadedown);
}
}
/* labels use theme colors for text */
static void widget_state_option_menu(uiWidgetType *wt,
- int state,
- int drawflag,
+ const uiWidgetStateInfo *state,
eUIEmbossType emboss)
{
const bTheme *btheme = UI_GetTheme();
@@ -2638,14 +2653,13 @@ static void widget_state_option_menu(uiWidgetType *wt,
copy_v3_v3_uchar(wcol_menu_option.text_sel, btheme->tui.wcol_menu_back.text_sel);
wt->wcol_theme = &wcol_menu_option;
- widget_state(wt, state, drawflag, emboss);
+ widget_state(wt, state, emboss);
wt->wcol_theme = old_wcol;
}
static void widget_state_nothing(uiWidgetType *wt,
- int UNUSED(state),
- int UNUSED(drawflag),
+ const uiWidgetStateInfo *UNUSED(state),
eUIEmbossType UNUSED(emboss))
{
wt->wcol = *(wt->wcol_theme);
@@ -2653,8 +2667,7 @@ static void widget_state_nothing(uiWidgetType *wt,
/* special case, button that calls pulldown */
static void widget_state_pulldown(uiWidgetType *wt,
- int UNUSED(state),
- int UNUSED(drawflag),
+ const uiWidgetStateInfo *UNUSED(state),
eUIEmbossType UNUSED(emboss))
{
wt->wcol = *(wt->wcol_theme);
@@ -2662,14 +2675,13 @@ static void widget_state_pulldown(uiWidgetType *wt,
/* special case, pie menu items */
static void widget_state_pie_menu_item(uiWidgetType *wt,
- int state,
- int UNUSED(drawflag),
+ const uiWidgetStateInfo *state,
eUIEmbossType UNUSED(emboss))
{
wt->wcol = *(wt->wcol_theme);
/* active and disabled (not so common) */
- if ((state & UI_BUT_DISABLED) && (state & UI_ACTIVE)) {
+ if ((state->but_flag & UI_BUT_DISABLED) && (state->but_flag & UI_ACTIVE)) {
color_blend_v3_v3(wt->wcol.text, wt->wcol.text_sel, 0.5f);
/* draw the backdrop at low alpha, helps navigating with keys
* when disabled items are active */
@@ -2678,18 +2690,18 @@ static void widget_state_pie_menu_item(uiWidgetType *wt,
}
else {
/* regular active */
- if (state & (UI_SELECT | UI_ACTIVE)) {
+ if (state->but_flag & (UI_SELECT | UI_ACTIVE)) {
copy_v3_v3_uchar(wt->wcol.text, wt->wcol.text_sel);
}
- else if (state & (UI_BUT_DISABLED | UI_BUT_INACTIVE)) {
+ else if (state->but_flag & (UI_BUT_DISABLED | UI_BUT_INACTIVE)) {
/* regular disabled */
color_blend_v3_v3(wt->wcol.text, wt->wcol.inner, 0.5f);
}
- if (state & UI_SELECT) {
+ if (state->but_flag & UI_SELECT) {
copy_v4_v4_uchar(wt->wcol.inner, wt->wcol.inner_sel);
}
- else if (state & UI_ACTIVE) {
+ else if (state->but_flag & UI_ACTIVE) {
copy_v4_v4_uchar(wt->wcol.inner, wt->wcol.item);
}
}
@@ -2697,14 +2709,13 @@ static void widget_state_pie_menu_item(uiWidgetType *wt,
/* special case, menu items */
static void widget_state_menu_item(uiWidgetType *wt,
- int state,
- int UNUSED(drawflag),
+ const uiWidgetStateInfo *state,
eUIEmbossType UNUSED(emboss))
{
wt->wcol = *(wt->wcol_theme);
/* active and disabled (not so common) */
- if ((state & UI_BUT_DISABLED) && (state & UI_ACTIVE)) {
+ if ((state->but_flag & UI_BUT_DISABLED) && (state->but_flag & UI_ACTIVE)) {
/* draw the backdrop at low alpha, helps navigating with keys
* when disabled items are active */
wt->wcol.text[3] = 128;
@@ -2713,15 +2724,15 @@ static void widget_state_menu_item(uiWidgetType *wt,
}
else {
/* regular active */
- if (state & UI_ACTIVE) {
+ if (state->but_flag & UI_ACTIVE) {
copy_v3_v3_uchar(wt->wcol.text, wt->wcol.text_sel);
}
- else if (state & (UI_BUT_DISABLED | UI_BUT_INACTIVE)) {
+ else if (state->but_flag & (UI_BUT_DISABLED | UI_BUT_INACTIVE)) {
/* regular disabled */
color_blend_v3_v3(wt->wcol.text, wt->wcol.inner, 0.5f);
}
- if (state & UI_ACTIVE) {
+ if (state->but_flag & UI_ACTIVE) {
copy_v4_v4_uchar(wt->wcol.inner, wt->wcol.inner_sel);
}
}
@@ -2787,7 +2798,7 @@ static void widget_softshadow(const rcti *rect, int roundboxalign, const float r
}
static void widget_menu_back(
- uiWidgetColors *wcol, rcti *rect, int flag, int direction, const float zoom)
+ uiWidgetColors *wcol, rcti *rect, const int block_flag, const int direction, const float zoom)
{
uiWidgetBase wtb;
int roundboxalign = UI_CNR_ALL;
@@ -2795,7 +2806,7 @@ static void widget_menu_back(
widget_init(&wtb);
/* menu is 2nd level or deeper */
- if (flag & UI_BLOCK_POPUP) {
+ if (block_flag & UI_BLOCK_POPUP) {
// rect->ymin -= 4.0;
// rect->ymax += 4.0;
}
@@ -3321,13 +3332,17 @@ static void ui_draw_separator(const rcti *rect, const uiWidgetColors *wcol)
#define NUM_BUT_PADDING_FACTOR 0.425f
-static void widget_numbut_draw(
- uiWidgetColors *wcol, rcti *rect, const float zoom, int state, int roundboxalign, bool emboss)
+static void widget_numbut_draw(uiWidgetColors *wcol,
+ rcti *rect,
+ const float zoom,
+ const uiWidgetStateInfo *state,
+ int roundboxalign,
+ bool emboss)
{
const float rad = widget_radius_from_zoom(zoom, wcol);
const int handle_width = min_ii(BLI_rcti_size_x(rect) / 3, BLI_rcti_size_y(rect) * 0.7f);
- if (state & UI_SELECT) {
+ if (state->but_flag & UI_SELECT) {
SWAP(short, wcol->shadetop, wcol->shadedown);
}
@@ -3343,7 +3358,7 @@ static void widget_numbut_draw(
}
/* decoration */
- if ((state & UI_ACTIVE) && !(state & UI_STATE_TEXT_INPUT)) {
+ if ((state->but_flag & UI_ACTIVE) && !state->is_text_input) {
uiWidgetColors wcol_zone;
uiWidgetBase wtb_zone;
rcti rect_zone;
@@ -3356,7 +3371,7 @@ static void widget_numbut_draw(
wcol_zone = *wcol;
copy_v3_v3_uchar(wcol_zone.item, wcol->text);
- if (state & UI_STATE_ACTIVE_LEFT) {
+ if (state->but_drawflag & UI_BUT_ACTIVE_LEFT) {
widget_active_color(&wcol_zone);
}
@@ -3376,7 +3391,7 @@ static void widget_numbut_draw(
wcol_zone = *wcol;
copy_v3_v3_uchar(wcol_zone.item, wcol->text);
- if (state & UI_STATE_ACTIVE_RIGHT) {
+ if (state->but_drawflag & UI_BUT_ACTIVE_RIGHT) {
widget_active_color(&wcol_zone);
}
@@ -3395,7 +3410,7 @@ static void widget_numbut_draw(
wcol_zone = *wcol;
copy_v3_v3_uchar(wcol_zone.item, wcol->text);
- if (!(state & (UI_STATE_ACTIVE_LEFT | UI_STATE_ACTIVE_RIGHT))) {
+ if (!(state->but_drawflag & (UI_BUT_ACTIVE_LEFT | UI_BUT_ACTIVE_RIGHT))) {
widget_active_color(&wcol_zone);
}
@@ -3414,7 +3429,7 @@ static void widget_numbut_draw(
widgetbase_draw(&wtb, wcol);
}
- if (!(state & UI_STATE_TEXT_INPUT)) {
+ if (!state->is_text_input) {
const float text_padding = NUM_BUT_PADDING_FACTOR * BLI_rcti_size_y(rect);
rect->xmin += text_padding;
@@ -3422,14 +3437,20 @@ static void widget_numbut_draw(
}
}
-static void widget_numbut(
- uiWidgetColors *wcol, rcti *rect, int state, int roundboxalign, const float zoom)
+static void widget_numbut(uiWidgetColors *wcol,
+ rcti *rect,
+ const uiWidgetStateInfo *state,
+ int roundboxalign,
+ const float zoom)
{
widget_numbut_draw(wcol, rect, zoom, state, roundboxalign, false);
}
-static void widget_menubut(
- uiWidgetColors *wcol, rcti *rect, int UNUSED(state), int roundboxalign, const float zoom)
+static void widget_menubut(uiWidgetColors *wcol,
+ rcti *rect,
+ const uiWidgetStateInfo *UNUSED(state),
+ int roundboxalign,
+ const float zoom)
{
uiWidgetBase wtb;
widget_init(&wtb);
@@ -3454,7 +3475,7 @@ static void widget_menubut(
static void widget_menubut_embossn(const uiBut *UNUSED(but),
uiWidgetColors *wcol,
rcti *rect,
- int UNUSED(state),
+ const uiWidgetStateInfo *UNUSED(state),
int UNUSED(roundboxalign))
{
uiWidgetBase wtb;
@@ -3476,7 +3497,7 @@ static void widget_menubut_embossn(const uiBut *UNUSED(but),
static void widget_numbut_embossn(const uiBut *UNUSED(but),
uiWidgetColors *wcol,
rcti *rect,
- int state,
+ const uiWidgetStateInfo *state,
int roundboxalign,
const float zoom)
{
@@ -3486,7 +3507,6 @@ static void widget_numbut_embossn(const uiBut *UNUSED(but),
void UI_draw_widget_scroll(uiWidgetColors *wcol, const rcti *rect, const rcti *slider, int state)
{
uiWidgetBase wtb;
- bool outline = false;
widget_init(&wtb);
@@ -3531,11 +3551,6 @@ void UI_draw_widget_scroll(uiWidgetColors *wcol, const rcti *rect, const rcti *s
/* draw */
wtb.draw_emboss = false; /* only emboss once */
- /* exception for progress bar */
- if (state & UI_SCROLL_NO_OUTLINE) {
- SWAP(bool, outline, wtb.draw_outline);
- }
-
round_box_edges(&wtb, UI_CNR_ALL, slider, rad);
if (state & UI_SCROLL_ARROWS) {
@@ -3563,17 +3578,13 @@ void UI_draw_widget_scroll(uiWidgetColors *wcol, const rcti *rect, const rcti *s
}
}
widgetbase_draw(&wtb, wcol);
-
- if (state & UI_SCROLL_NO_OUTLINE) {
- SWAP(bool, outline, wtb.draw_outline);
- }
}
}
static void widget_scroll(uiBut *but,
uiWidgetColors *wcol,
rcti *rect,
- int state,
+ const uiWidgetStateInfo *state,
int UNUSED(roundboxalign),
const float UNUSED(zoom))
{
@@ -3623,19 +3634,13 @@ static void widget_scroll(uiBut *but,
}
}
- if (state & UI_SELECT) {
- state = UI_SCROLL_PRESSED;
- }
- else {
- state = 0;
- }
- UI_draw_widget_scroll(wcol, rect, &rect1, state);
+ UI_draw_widget_scroll(wcol, rect, &rect1, (state->but_flag & UI_SELECT) ? UI_SCROLL_PRESSED : 0);
}
static void widget_progressbar(uiBut *but,
uiWidgetColors *wcol,
rcti *rect,
- int UNUSED(state),
+ const uiWidgetStateInfo *UNUSED(state),
int roundboxalign,
const float zoom)
{
@@ -3669,7 +3674,7 @@ static void widget_progressbar(uiBut *but,
static void widget_treerow_exec(uiWidgetColors *wcol,
rcti *rect,
- int state,
+ const uiWidgetStateInfo *state,
int UNUSED(roundboxalign),
int indentation,
const float zoom)
@@ -3682,7 +3687,7 @@ static void widget_treerow_exec(uiWidgetColors *wcol,
const float rad = widget_radius_from_zoom(zoom, wcol);
round_box_edges(&wtb, UI_CNR_ALL, rect, rad);
- if ((state & UI_ACTIVE) || (state & UI_SELECT)) {
+ if ((state->but_flag & UI_ACTIVE) || (state->but_flag & UI_SELECT)) {
widgetbase_draw(&wtb, wcol);
}
@@ -3690,18 +3695,32 @@ static void widget_treerow_exec(uiWidgetColors *wcol,
BLI_rcti_translate(rect, 0.5f * UI_UNIT_X * indentation, 0);
}
-static void widget_treerow(
- uiBut *but, uiWidgetColors *wcol, rcti *rect, int state, int roundboxalign, const float zoom)
+static void widget_treerow(uiBut *but,
+ uiWidgetColors *wcol,
+ rcti *rect,
+ const uiWidgetStateInfo *state,
+ int roundboxalign,
+ const float zoom)
{
uiButTreeRow *tree_row = (uiButTreeRow *)but;
BLI_assert(but->type == UI_BTYPE_TREEROW);
widget_treerow_exec(wcol, rect, state, roundboxalign, tree_row->indentation, zoom);
}
+static void widget_gridtile(uiWidgetColors *wcol,
+ rcti *rect,
+ const uiWidgetStateInfo *state,
+ int roundboxalign,
+ const float zoom)
+{
+ /* TODO Reuse tree-row drawing. */
+ widget_treerow_exec(wcol, rect, state, roundboxalign, 0, zoom);
+}
+
static void widget_nodesocket(uiBut *but,
uiWidgetColors *wcol,
rcti *rect,
- int UNUSED(state),
+ const uiWidgetStateInfo *UNUSED(state),
int UNUSED(roundboxalign),
const float UNUSED(zoom))
{
@@ -3737,8 +3756,12 @@ static void widget_nodesocket(uiBut *but,
copy_v3_v3_uchar(wcol->outline, old_outline);
}
-static void widget_numslider(
- uiBut *but, uiWidgetColors *wcol, rcti *rect, int state, int roundboxalign, const float zoom)
+static void widget_numslider(uiBut *but,
+ uiWidgetColors *wcol,
+ rcti *rect,
+ const uiWidgetStateInfo *state,
+ int roundboxalign,
+ const float zoom)
{
uiWidgetBase wtb, wtb1;
widget_init(&wtb);
@@ -3752,7 +3775,7 @@ static void widget_numslider(
widgetbase_draw(&wtb, wcol);
/* Draw slider part only when not in text editing. */
- if (!(state & UI_STATE_TEXT_INPUT)) {
+ if (!state->is_text_input) {
int roundboxalign_slider = roundboxalign;
uchar outline[3];
@@ -3760,7 +3783,7 @@ static void widget_numslider(
copy_v3_v3_uchar(wcol->outline, wcol->item);
copy_v3_v3_uchar(wcol->inner, wcol->item);
- if (!(state & UI_SELECT)) {
+ if (!(state->but_flag & UI_SELECT)) {
SWAP(short, wcol->shadetop, wcol->shadedown);
}
@@ -3828,7 +3851,7 @@ static void widget_numslider(
copy_v3_v3_uchar(wcol->outline, outline);
- if (!(state & UI_SELECT)) {
+ if (!(state->but_flag & UI_SELECT)) {
SWAP(short, wcol->shadetop, wcol->shadedown);
}
}
@@ -3840,7 +3863,7 @@ static void widget_numslider(
/* Add space at either side of the button so text aligns with number-buttons
* (which have arrow icons). */
- if (!(state & UI_STATE_TEXT_INPUT)) {
+ if (!state->is_text_input) {
const float text_padding = NUM_BUT_PADDING_FACTOR * BLI_rcti_size_y(rect);
rect->xmax -= text_padding;
rect->xmin += text_padding;
@@ -3850,8 +3873,12 @@ static void widget_numslider(
/* I think 3 is sufficient border to indicate keyed status */
#define SWATCH_KEYED_BORDER 3
-static void widget_swatch(
- uiBut *but, uiWidgetColors *wcol, rcti *rect, int state, int roundboxalign, const float zoom)
+static void widget_swatch(uiBut *but,
+ uiWidgetColors *wcol,
+ rcti *rect,
+ const uiWidgetStateInfo *state,
+ int roundboxalign,
+ const float zoom)
{
BLI_assert(but->type == UI_BTYPE_COLOR);
uiButColor *color_but = (uiButColor *)but;
@@ -3875,9 +3902,9 @@ static void widget_swatch(
ui_but_v3_get(but, col);
- if ((state & (UI_BUT_ANIMATED | UI_BUT_ANIMATED_KEY | UI_BUT_DRIVEN | UI_BUT_OVERRIDDEN |
- UI_BUT_REDALERT)) ||
- (but->drawflag & UI_BUT_ANIMATED_CHANGED)) {
+ if ((state->but_flag & (UI_BUT_ANIMATED | UI_BUT_ANIMATED_KEY | UI_BUT_DRIVEN |
+ UI_BUT_OVERRIDDEN | UI_BUT_REDALERT)) ||
+ (state->but_drawflag & UI_BUT_ANIMATED_CHANGED)) {
/* draw based on state - color for keyed etc */
widgetbase_draw(&wtb, wcol);
@@ -3938,7 +3965,7 @@ static void widget_swatch(
static void widget_unitvec(uiBut *but,
uiWidgetColors *wcol,
rcti *rect,
- int UNUSED(state),
+ const uiWidgetStateInfo *UNUSED(state),
int UNUSED(roundboxalign),
const float zoom)
{
@@ -3946,10 +3973,15 @@ static void widget_unitvec(uiBut *but,
ui_draw_but_UNITVEC(but, wcol, rect, rad);
}
-static void widget_icon_has_anim(
- uiBut *but, uiWidgetColors *wcol, rcti *rect, int state, int roundboxalign, const float zoom)
+static void widget_icon_has_anim(uiBut *but,
+ uiWidgetColors *wcol,
+ rcti *rect,
+ const uiWidgetStateInfo *state,
+ int roundboxalign,
+ const float zoom)
{
- if (state & (UI_BUT_ANIMATED | UI_BUT_ANIMATED_KEY | UI_BUT_DRIVEN | UI_BUT_REDALERT) &&
+ if (state->but_flag &
+ (UI_BUT_ANIMATED | UI_BUT_ANIMATED_KEY | UI_BUT_DRIVEN | UI_BUT_REDALERT) &&
but->emboss != UI_EMBOSS_NONE) {
uiWidgetBase wtb;
widget_init(&wtb);
@@ -3970,10 +4002,13 @@ static void widget_icon_has_anim(
}
}
-static void widget_textbut(
- uiWidgetColors *wcol, rcti *rect, int state, int roundboxalign, const float zoom)
+static void widget_textbut(uiWidgetColors *wcol,
+ rcti *rect,
+ const uiWidgetStateInfo *state,
+ int roundboxalign,
+ const float zoom)
{
- if (state & UI_SELECT) {
+ if (state->but_flag & UI_SELECT) {
SWAP(short, wcol->shadetop, wcol->shadedown);
}
@@ -3989,7 +4024,7 @@ static void widget_textbut(
static void widget_preview_tile(uiBut *but,
uiWidgetColors *wcol,
rcti *rect,
- int UNUSED(state),
+ const uiWidgetStateInfo *UNUSED(state),
int UNUSED(roundboxalign),
const float UNUSED(zoom))
{
@@ -3998,8 +4033,11 @@ static void widget_preview_tile(uiBut *but,
&style->widget, rect, but->drawstr, but->icon, wcol->text, UI_STYLE_TEXT_CENTER);
}
-static void widget_menuiconbut(
- uiWidgetColors *wcol, rcti *rect, int UNUSED(state), int roundboxalign, const float zoom)
+static void widget_menuiconbut(uiWidgetColors *wcol,
+ rcti *rect,
+ const uiWidgetStateInfo *UNUSED(state),
+ int roundboxalign,
+ const float zoom)
{
uiWidgetBase wtb;
widget_init(&wtb);
@@ -4011,17 +4049,20 @@ static void widget_menuiconbut(
widgetbase_draw(&wtb, wcol);
}
-static void widget_pulldownbut(
- uiWidgetColors *wcol, rcti *rect, int state, int roundboxalign, const float zoom)
+static void widget_pulldownbut(uiWidgetColors *wcol,
+ rcti *rect,
+ const uiWidgetStateInfo *state,
+ int roundboxalign,
+ const float zoom)
{
float back[4];
UI_GetThemeColor4fv(TH_BACK, back);
- if ((state & UI_ACTIVE) || (back[3] < 1.0f)) {
+ if ((state->but_flag & UI_ACTIVE) || (back[3] < 1.0f)) {
uiWidgetBase wtb;
const float rad = widget_radius_from_zoom(zoom, wcol);
- if (state & UI_ACTIVE) {
+ if (state->but_flag & UI_ACTIVE) {
copy_v4_v4_uchar(wcol->inner, wcol->inner_sel);
copy_v3_v3_uchar(wcol->text, wcol->text_sel);
copy_v3_v3_uchar(wcol->outline, wcol->inner);
@@ -4042,7 +4083,7 @@ static void widget_pulldownbut(
static void widget_menu_itembut(uiWidgetColors *wcol,
rcti *rect,
- int UNUSED(state),
+ const uiWidgetStateInfo *UNUSED(state),
int UNUSED(roundboxalign),
const float zoom)
{
@@ -4066,7 +4107,7 @@ static void widget_menu_itembut(uiWidgetColors *wcol,
static void widget_menu_itembut_unpadded(uiWidgetColors *wcol,
rcti *rect,
- int UNUSED(state),
+ const uiWidgetStateInfo *UNUSED(state),
int UNUSED(roundboxalign),
const float zoom)
{
@@ -4088,7 +4129,7 @@ static void widget_menu_itembut_unpadded(uiWidgetColors *wcol,
static void widget_menu_radial_itembut(uiBut *but,
uiWidgetColors *wcol,
rcti *rect,
- int UNUSED(state),
+ const uiWidgetStateInfo *UNUSED(state),
int UNUSED(roundboxalign),
const float zoom)
{
@@ -4114,7 +4155,7 @@ static void widget_menu_radial_itembut(uiBut *but,
static void widget_list_itembut(uiWidgetColors *wcol,
rcti *rect,
- int UNUSED(state),
+ const uiWidgetStateInfo *UNUSED(state),
int UNUSED(roundboxalign),
const float zoom)
{
@@ -4131,11 +4172,13 @@ static void widget_list_itembut(uiWidgetColors *wcol,
static void widget_optionbut(uiWidgetColors *wcol,
rcti *rect,
- int state,
+ const uiWidgetStateInfo *state,
int UNUSED(roundboxalign),
const float UNUSED(zoom))
{
- const bool text_before_widget = (state & UI_STATE_TEXT_BEFORE_WIDGET);
+ /* For a right aligned layout (signified by #UI_BUT_TEXT_RIGHT), draw the text on the left of the
+ * checkbox. */
+ const bool text_before_widget = (state->but_drawflag & UI_BUT_TEXT_RIGHT);
rcti recttemp = *rect;
uiWidgetBase wtb;
@@ -4160,7 +4203,7 @@ static void widget_optionbut(uiWidgetColors *wcol,
round_box_edges(&wtb, UI_CNR_ALL, &recttemp, rad);
/* decoration */
- if (state & UI_SELECT) {
+ if (state->but_flag & UI_SELECT) {
shape_preset_trias_from_rect_checkmark(&wtb.tria1, &recttemp);
}
@@ -4177,19 +4220,21 @@ static void widget_optionbut(uiWidgetColors *wcol,
}
/* labels use Editor theme colors for text */
-static void widget_state_label(uiWidgetType *wt, int state, int drawflag, eUIEmbossType emboss)
+static void widget_state_label(uiWidgetType *wt,
+ const uiWidgetStateInfo *state,
+ eUIEmbossType emboss)
{
- if (state & UI_BUT_LIST_ITEM) {
+ if (state->but_flag & UI_BUT_LIST_ITEM) {
/* Override default label theme's colors. */
bTheme *btheme = UI_GetTheme();
wt->wcol_theme = &btheme->tui.wcol_list_item;
/* call this for option button */
- widget_state(wt, state, drawflag, emboss);
+ widget_state(wt, state, emboss);
}
else {
/* call this for option button */
- widget_state(wt, state, drawflag, emboss);
- if (state & UI_SELECT) {
+ widget_state(wt, state, emboss);
+ if (state->but_flag & UI_SELECT) {
UI_GetThemeColor3ubv(TH_TEXT_HI, wt->wcol.text);
}
else {
@@ -4197,14 +4242,17 @@ static void widget_state_label(uiWidgetType *wt, int state, int drawflag, eUIEmb
}
}
- if (state & UI_BUT_REDALERT) {
+ if (state->but_flag & UI_BUT_REDALERT) {
const uchar red[4] = {255, 0, 0};
color_blend_v3_v3(wt->wcol.text, red, 0.4f);
}
}
-static void widget_radiobut(
- uiWidgetColors *wcol, rcti *rect, int UNUSED(state), int roundboxalign, const float zoom)
+static void widget_radiobut(uiWidgetColors *wcol,
+ rcti *rect,
+ const uiWidgetStateInfo *UNUSED(state),
+ int roundboxalign,
+ const float zoom)
{
uiWidgetBase wtb;
widget_init(&wtb);
@@ -4218,7 +4266,7 @@ static void widget_radiobut(
static void widget_box(uiBut *but,
uiWidgetColors *wcol,
rcti *rect,
- int UNUSED(state),
+ const uiWidgetStateInfo *UNUSED(state),
int roundboxalign,
const float zoom)
{
@@ -4244,8 +4292,11 @@ static void widget_box(uiBut *but,
copy_v3_v3_uchar(wcol->inner, old_col);
}
-static void widget_but(
- uiWidgetColors *wcol, rcti *rect, int UNUSED(state), int roundboxalign, const float zoom)
+static void widget_but(uiWidgetColors *wcol,
+ rcti *rect,
+ const uiWidgetStateInfo *UNUSED(state),
+ int roundboxalign,
+ const float zoom)
{
uiWidgetBase wtb;
widget_init(&wtb);
@@ -4271,13 +4322,16 @@ static void widget_roundbut(uiWidgetColors *wcol, rcti *rect, int UNUSED(state),
}
#endif
-static void widget_roundbut_exec(
- uiWidgetColors *wcol, rcti *rect, int state, int roundboxalign, const float zoom)
+static void widget_roundbut_exec(uiWidgetColors *wcol,
+ rcti *rect,
+ const uiWidgetStateInfo *state,
+ int roundboxalign,
+ const float zoom)
{
uiWidgetBase wtb;
widget_init(&wtb);
- if (state & UI_STATE_HOLD_ACTION) {
+ if (state->has_hold_action) {
/* Show that keeping pressed performs another action (typically a menu). */
shape_preset_init_hold_action(&wtb.tria1, rect, 0.75f, 'r');
}
@@ -4290,11 +4344,14 @@ static void widget_roundbut_exec(
widgetbase_draw(&wtb, wcol);
}
-static void widget_tab(
- uiWidgetColors *wcol, rcti *rect, int state, int roundboxalign, const float zoom)
+static void widget_tab(uiWidgetColors *wcol,
+ rcti *rect,
+ const uiWidgetStateInfo *state,
+ int roundboxalign,
+ const float zoom)
{
const float rad = widget_radius_from_zoom(zoom, wcol);
- const bool is_active = (state & UI_SELECT);
+ const bool is_active = (state->but_flag & UI_SELECT);
/* Draw shaded outline - Disabled for now,
* seems incorrect and also looks nicer without it IMHO ;). */
@@ -4442,7 +4499,7 @@ static uiWidgetType *widget_type(uiWidgetTypeEnum type)
case UI_WTYPE_TOOLTIP:
wt.wcol_theme = &btheme->tui.wcol_tooltip;
- wt.draw = widget_menu_back;
+ wt.draw_block = widget_menu_back;
break;
/* strings */
@@ -4498,7 +4555,7 @@ static uiWidgetType *widget_type(uiWidgetTypeEnum type)
case UI_WTYPE_MENU_BACK:
wt.wcol_theme = &btheme->tui.wcol_menu_back;
- wt.draw = widget_menu_back;
+ wt.draw_block = widget_menu_back;
break;
/* specials */
@@ -4552,9 +4609,15 @@ static uiWidgetType *widget_type(uiWidgetTypeEnum type)
break;
case UI_WTYPE_TREEROW:
+ wt.wcol_theme = &btheme->tui.wcol_view_item;
wt.custom = widget_treerow;
break;
+ case UI_WTYPE_GRID_TILE:
+ wt.wcol_theme = &btheme->tui.wcol_view_item;
+ wt.draw = widget_gridtile;
+ break;
+
case UI_WTYPE_NODESOCKET:
wt.custom = widget_nodesocket;
break;
@@ -4891,6 +4954,11 @@ void ui_draw_but(const bContext *C, struct ARegion *region, uiStyle *style, uiBu
fstyle = &style->widgetlabel;
break;
+ case UI_BTYPE_GRID_TILE:
+ wt = widget_type(UI_WTYPE_GRID_TILE);
+ fstyle = &style->widgetlabel;
+ break;
+
case UI_BTYPE_SCROLL:
wt = widget_type(UI_WTYPE_SCROLL);
break;
@@ -4921,62 +4989,50 @@ void ui_draw_but(const bContext *C, struct ARegion *region, uiStyle *style, uiBu
const int roundboxalign = widget_roundbox_set(but, rect);
- /* Mask out flags re-used for local state. */
- int state = but->flag & ~UI_STATE_FLAGS_ALL;
- const int drawflag = but->drawflag;
+ uiWidgetStateInfo state = {0};
+ state.but_flag = but->flag;
+ state.but_drawflag = but->drawflag;
- if (state & UI_SELECT_DRAW) {
- state |= UI_SELECT;
+ /* Override selected flag for drawing. */
+ if (but->flag & UI_SELECT_DRAW) {
+ state.but_flag |= UI_SELECT;
}
if ((but->editstr) ||
(UNLIKELY(but->flag & UI_BUT_DRAG_MULTI) && ui_but_drag_multi_edit_get(but))) {
- state |= UI_STATE_TEXT_INPUT;
+ state.is_text_input = true;
}
if (but->hold_func) {
- state |= UI_STATE_HOLD_ACTION;
- }
-
- if (state & UI_ACTIVE) {
- if (but->drawflag & UI_BUT_ACTIVE_LEFT) {
- state |= UI_STATE_ACTIVE_LEFT;
- }
- else if (but->drawflag & UI_BUT_ACTIVE_RIGHT) {
- state |= UI_STATE_ACTIVE_RIGHT;
- }
+ state.has_hold_action = true;
}
bool use_alpha_blend = false;
if (but->emboss != UI_EMBOSS_PULLDOWN) {
- if (state & (UI_BUT_DISABLED | UI_BUT_INACTIVE | UI_SEARCH_FILTER_NO_MATCH)) {
+ if (but->flag & (UI_BUT_DISABLED | UI_BUT_INACTIVE | UI_SEARCH_FILTER_NO_MATCH)) {
use_alpha_blend = true;
- ui_widget_color_disabled(wt, state);
+ ui_widget_color_disabled(wt, &state);
}
}
- if (drawflag & UI_BUT_TEXT_RIGHT) {
- state |= UI_STATE_TEXT_BEFORE_WIDGET;
- }
-
#ifdef USE_UI_POPOVER_ONCE
if (but->block->flag & UI_BLOCK_POPOVER_ONCE) {
- if ((state & UI_ACTIVE) && ui_but_is_popover_once_compat(but)) {
- state |= UI_BUT_ACTIVE_DEFAULT;
+ if ((but->flag & UI_ACTIVE) && ui_but_is_popover_once_compat(but)) {
+ state.but_flag |= UI_BUT_ACTIVE_DEFAULT;
}
}
#endif
if (but->block->flag & UI_BLOCK_NO_DRAW_OVERRIDDEN_STATE) {
- state &= ~UI_BUT_OVERRIDDEN;
+ state.but_flag &= ~UI_BUT_OVERRIDDEN;
}
const float zoom = 1.0f / but->block->aspect;
- wt->state(wt, state, drawflag, but->emboss);
+ wt->state(wt, &state, but->emboss);
if (wt->custom) {
- wt->custom(but, &wt->wcol, rect, state, roundboxalign, zoom);
+ wt->custom(but, &wt->wcol, rect, &state, roundboxalign, zoom);
}
else if (wt->draw) {
- wt->draw(&wt->wcol, rect, state, roundboxalign, zoom);
+ wt->draw(&wt->wcol, rect, &state, roundboxalign, zoom);
}
if (wt->text) {
@@ -5017,13 +5073,13 @@ void ui_draw_menu_back(uiStyle *UNUSED(style), uiBlock *block, rcti *rect)
{
uiWidgetType *wt = widget_type(UI_WTYPE_MENU_BACK);
- wt->state(wt, 0, 0, UI_EMBOSS_UNDEFINED);
+ wt->state(wt, &STATE_INFO_NULL, UI_EMBOSS_UNDEFINED);
if (block) {
const float zoom = 1.0f / block->aspect;
- wt->draw(&wt->wcol, rect, block->flag, block->direction, zoom);
+ wt->draw_block(&wt->wcol, rect, block->flag, block->direction, zoom);
}
else {
- wt->draw(&wt->wcol, rect, 0, 0, 1.0f);
+ wt->draw_block(&wt->wcol, rect, 0, 0, 1.0f);
}
ui_draw_clip_tri(block, rect, wt);
@@ -5118,8 +5174,8 @@ void ui_draw_popover_back(struct ARegion *region,
}
else {
const float zoom = 1.0f / block->aspect;
- wt->state(wt, 0, 0, UI_EMBOSS_UNDEFINED);
- wt->draw(&wt->wcol, rect, 0, 0, zoom);
+ wt->state(wt, &STATE_INFO_NULL, UI_EMBOSS_UNDEFINED);
+ wt->draw_block(&wt->wcol, rect, 0, 0, zoom);
}
ui_draw_clip_tri(block, rect, wt);
@@ -5307,11 +5363,20 @@ static void ui_draw_widget_back_color(uiWidgetTypeEnum type,
}
rcti rect_copy = *rect;
- wt->state(wt, 0, 0, UI_EMBOSS_UNDEFINED);
+ wt->state(wt, &STATE_INFO_NULL, UI_EMBOSS_UNDEFINED);
if (color) {
rgba_float_to_uchar(wt->wcol.inner, color);
}
- wt->draw(&wt->wcol, &rect_copy, 0, UI_CNR_ALL, 1.0f);
+
+ if (wt->draw_block) {
+ wt->draw_block(&wt->wcol, &rect_copy, 0, UI_CNR_ALL, 1.0f);
+ }
+ else if (wt->draw) {
+ wt->draw(&wt->wcol, &rect_copy, &STATE_INFO_NULL, UI_CNR_ALL, 1.0f);
+ }
+ else {
+ BLI_assert_unreachable();
+ }
}
void ui_draw_widget_menu_back_color(const rcti *rect, bool use_shadow, const float color[4])
{
@@ -5326,16 +5391,16 @@ void ui_draw_widget_menu_back(const rcti *rect, bool use_shadow)
void ui_draw_tooltip_background(const uiStyle *UNUSED(style), uiBlock *UNUSED(block), rcti *rect)
{
uiWidgetType *wt = widget_type(UI_WTYPE_TOOLTIP);
- wt->state(wt, 0, 0, UI_EMBOSS_UNDEFINED);
- /* wt->draw ends up using same function to draw the tooltip as menu_back */
- wt->draw(&wt->wcol, rect, 0, 0, 1.0f);
+ wt->state(wt, &STATE_INFO_NULL, UI_EMBOSS_UNDEFINED);
+ /* wt->draw_block ends up using same function to draw the tooltip as menu_back */
+ wt->draw_block(&wt->wcol, rect, 0, 0, 1.0f);
}
void ui_draw_menu_item(const uiFontStyle *fstyle,
rcti *rect,
const char *name,
int iconid,
- int state,
+ int but_flag,
uiMenuItemSeparatorType separator_type,
int *r_xmax)
{
@@ -5346,8 +5411,11 @@ void ui_draw_menu_item(const uiFontStyle *fstyle,
int padding = 0.25f * row_height;
char *cpoin = NULL;
- wt->state(wt, state, 0, UI_EMBOSS_UNDEFINED);
- wt->draw(&wt->wcol, rect, 0, 0, 1.0f);
+ uiWidgetStateInfo state = {0};
+ state.but_flag = but_flag;
+
+ wt->state(wt, &state, UI_EMBOSS_UNDEFINED);
+ wt->draw(&wt->wcol, rect, &STATE_INFO_NULL, 0, 1.0f);
UI_fontstyle_set(fstyle);
@@ -5442,8 +5510,12 @@ void ui_draw_menu_item(const uiFontStyle *fstyle,
/* part text right aligned */
if (separator_type != UI_MENU_ITEM_SEPARATOR_NONE) {
if (cpoin) {
+ /* State info for the hint drawing. */
+ uiWidgetStateInfo hint_state = state;
/* Set inactive state for grayed out text. */
- wt->state(wt, state | UI_BUT_INACTIVE, 0, UI_EMBOSS_UNDEFINED);
+ hint_state.but_flag |= UI_BUT_INACTIVE;
+
+ wt->state(wt, &hint_state, UI_EMBOSS_UNDEFINED);
char hint_drawstr[UI_MAX_DRAW_STR];
{
@@ -5528,14 +5600,17 @@ void ui_draw_preview_item(const uiFontStyle *fstyle,
rcti *rect,
const char *name,
int iconid,
- int state,
+ int but_flag,
eFontStyle_Align text_align)
{
uiWidgetType *wt = widget_type(UI_WTYPE_MENU_ITEM_UNPADDED);
+ uiWidgetStateInfo state = {0};
+ state.but_flag = but_flag;
+
/* drawing button background */
- wt->state(wt, state, 0, UI_EMBOSS_UNDEFINED);
- wt->draw(&wt->wcol, rect, 0, 0, 1.0f);
+ wt->state(wt, &state, UI_EMBOSS_UNDEFINED);
+ wt->draw(&wt->wcol, rect, &STATE_INFO_NULL, 0, 1.0f);
ui_draw_preview_item_stateless(fstyle, rect, name, iconid, wt->wcol.text, text_align);
}
diff --git a/source/blender/editors/interface/tree_view.cc b/source/blender/editors/interface/tree_view.cc
index bf756fb5838..f86d1c4d8bc 100644
--- a/source/blender/editors/interface/tree_view.cc
+++ b/source/blender/editors/interface/tree_view.cc
@@ -68,6 +68,12 @@ void AbstractTreeView::foreach_item(ItemIterFn iter_fn, IterOptions options) con
foreach_item_recursive(iter_fn, options);
}
+bool AbstractTreeView::listen(const wmNotifier &) const
+{
+ /* Nothing by default. */
+ return false;
+}
+
bool AbstractTreeView::is_renaming() const
{
return rename_buffer_ != nullptr;
@@ -82,7 +88,7 @@ void AbstractTreeView::update_from_old(uiBlock &new_block)
return;
}
- uiTreeViewHandle *old_view_handle = ui_block_view_find_matching_in_old_block(
+ uiTreeViewHandle *old_view_handle = ui_block_tree_view_find_matching_in_old_block(
&new_block, reinterpret_cast<uiTreeViewHandle *>(this));
if (old_view_handle == nullptr) {
is_reconstructed_ = true;
@@ -805,6 +811,13 @@ class TreeViewItemAPIWrapper {
using namespace blender::ui;
+bool UI_tree_view_listen_should_redraw(const uiTreeViewHandle *view_handle,
+ const wmNotifier *notifier)
+{
+ const AbstractTreeView &view = *reinterpret_cast<const AbstractTreeView *>(view_handle);
+ return view.listen(*notifier);
+}
+
bool UI_tree_view_item_is_active(const uiTreeViewItemHandle *item_handle)
{
const AbstractTreeViewItem &item = reinterpret_cast<const AbstractTreeViewItem &>(*item_handle);
diff --git a/source/blender/editors/interface/view2d.cc b/source/blender/editors/interface/view2d.cc
index 66171dc13e4..6ece7eb4ffa 100644
--- a/source/blender/editors/interface/view2d.cc
+++ b/source/blender/editors/interface/view2d.cc
@@ -2103,21 +2103,12 @@ void UI_view2d_text_cache_draw(ARegion *region)
col_pack_prev = v2s->col.pack;
}
- if (v2s->rect.xmin >= v2s->rect.xmax) {
- BLF_draw_default((float)(v2s->mval[0] + xofs),
- (float)(v2s->mval[1] + yofs),
- 0.0,
- v2s->str,
- BLF_DRAW_STR_DUMMY_MAX);
- }
- else {
- BLF_enable(font_id, BLF_CLIPPING);
- BLF_clipping(
- font_id, v2s->rect.xmin - 4, v2s->rect.ymin - 4, v2s->rect.xmax + 4, v2s->rect.ymax + 4);
- BLF_draw_default(
- v2s->rect.xmin + xofs, v2s->rect.ymin + yofs, 0.0f, v2s->str, BLF_DRAW_STR_DUMMY_MAX);
- BLF_disable(font_id, BLF_CLIPPING);
- }
+ BLF_enable(font_id, BLF_CLIPPING);
+ BLF_clipping(
+ font_id, v2s->rect.xmin - 4, v2s->rect.ymin - 4, v2s->rect.xmax + 4, v2s->rect.ymax + 4);
+ BLF_draw_default(
+ v2s->rect.xmin + xofs, v2s->rect.ymin + yofs, 0.0f, v2s->str, BLF_DRAW_STR_DUMMY_MAX);
+ BLF_disable(font_id, BLF_CLIPPING);
}
g_v2d_strings = nullptr;
diff --git a/source/blender/editors/io/CMakeLists.txt b/source/blender/editors/io/CMakeLists.txt
index 418a399db28..a716c00d5d9 100644
--- a/source/blender/editors/io/CMakeLists.txt
+++ b/source/blender/editors/io/CMakeLists.txt
@@ -9,9 +9,11 @@ set(INC
../../depsgraph
../../io/alembic
../../io/collada
+ ../../io/common
../../io/gpencil
../../io/usd
../../io/wavefront_obj
+ ../../io/stl
../../makesdna
../../makesrna
../../windowmanager
@@ -32,6 +34,7 @@ set(SRC
io_obj.c
io_ops.c
io_usd.c
+ io_stl_ops.c
io_alembic.h
io_cache.h
@@ -40,12 +43,12 @@ set(SRC
io_obj.h
io_ops.h
io_usd.h
+ io_stl_ops.h
)
set(LIB
bf_blenkernel
bf_blenlib
- bf_wavefront_obj
)
if(WITH_OPENCOLLADA)
@@ -55,6 +58,27 @@ if(WITH_OPENCOLLADA)
add_definitions(-DWITH_COLLADA)
endif()
+if(WITH_IO_WAVEFRONT_OBJ)
+ list(APPEND LIB
+ bf_wavefront_obj
+ )
+ add_definitions(-DWITH_IO_WAVEFRONT_OBJ)
+endif()
+
+if(WITH_IO_STL)
+ list(APPEND LIB
+ bf_stl
+ )
+ add_definitions(-DWITH_IO_STL)
+endif()
+
+if(WITH_IO_GPENCIL)
+ list(APPEND LIB
+ bf_gpencil
+ )
+ add_definitions(-DWITH_IO_GPENCIL)
+endif()
+
if(WITH_ALEMBIC)
list(APPEND LIB
bf_alembic
@@ -77,6 +101,4 @@ if(WITH_HARU)
add_definitions(-DWITH_HARU)
endif()
-list(APPEND LIB bf_gpencil)
-
blender_add_lib(bf_editor_io "${SRC}" "${INC}" "${INC_SYS}" "${LIB}")
diff --git a/source/blender/editors/io/io_alembic.c b/source/blender/editors/io/io_alembic.c
index 87923d9fdf8..0e8e0f83597 100644
--- a/source/blender/editors/io/io_alembic.c
+++ b/source/blender/editors/io/io_alembic.c
@@ -282,7 +282,7 @@ void WM_OT_alembic_export(wmOperatorType *ot)
ot->poll = WM_operator_winactive;
ot->ui = wm_alembic_export_draw;
ot->check = wm_alembic_export_check;
- ot->flag |= OPTYPE_PRESET;
+ ot->flag = OPTYPE_PRESET;
WM_operator_properties_filesel(ot,
FILE_TYPE_FOLDER | FILE_TYPE_ALEMBIC,
diff --git a/source/blender/editors/io/io_cache.c b/source/blender/editors/io/io_cache.c
index 624b85358f5..969049313c9 100644
--- a/source/blender/editors/io/io_cache.c
+++ b/source/blender/editors/io/io_cache.c
@@ -75,17 +75,17 @@ static void open_cancel(bContext *UNUSED(C), wmOperator *op)
static int cachefile_open_exec(bContext *C, wmOperator *op)
{
if (!RNA_struct_property_is_set(op->ptr, "filepath")) {
- BKE_report(op->reports, RPT_ERROR, "No filename given");
+ BKE_report(op->reports, RPT_ERROR, "No filepath given");
return OPERATOR_CANCELLED;
}
- char filename[FILE_MAX];
- RNA_string_get(op->ptr, "filepath", filename);
+ char filepath[FILE_MAX];
+ RNA_string_get(op->ptr, "filepath", filepath);
Main *bmain = CTX_data_main(C);
- CacheFile *cache_file = BKE_libblock_alloc(bmain, ID_CF, BLI_path_basename(filename), 0);
- BLI_strncpy(cache_file->filepath, filename, FILE_MAX);
+ CacheFile *cache_file = BKE_libblock_alloc(bmain, ID_CF, BLI_path_basename(filepath), 0);
+ BLI_strncpy(cache_file->filepath, filepath, FILE_MAX);
DEG_id_tag_update(&cache_file->id, ID_RECALC_COPY_ON_WRITE);
/* Will be set when running invoke, not exec directly. */
@@ -182,7 +182,7 @@ static int cachefile_layer_open_invoke(bContext *C, wmOperator *op, const wmEven
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");
+ BKE_report(op->reports, RPT_ERROR, "No filepath given");
return OPERATOR_CANCELLED;
}
@@ -192,10 +192,10 @@ static int cachefile_layer_add_exec(bContext *C, wmOperator *op)
return OPERATOR_CANCELLED;
}
- char filename[FILE_MAX];
- RNA_string_get(op->ptr, "filepath", filename);
+ char filepath[FILE_MAX];
+ RNA_string_get(op->ptr, "filepath", filepath);
- CacheFileLayer *layer = BKE_cachefile_add_layer(cache_file, filename);
+ CacheFileLayer *layer = BKE_cachefile_add_layer(cache_file, filepath);
if (!layer) {
WM_report(RPT_ERROR, "Could not add a layer to the cache file");
diff --git a/source/blender/editors/io/io_collada.c b/source/blender/editors/io/io_collada.c
index dc62212bf53..c491e7a5815 100644
--- a/source/blender/editors/io/io_collada.c
+++ b/source/blender/editors/io/io_collada.c
@@ -468,7 +468,7 @@ void WM_OT_collada_export(wmOperatorType *ot)
ot->poll = WM_operator_winactive;
ot->check = wm_collada_export_check;
- ot->flag |= OPTYPE_PRESET;
+ ot->flag = OPTYPE_PRESET;
ot->ui = wm_collada_export_draw;
@@ -786,7 +786,7 @@ void WM_OT_collada_import(wmOperatorType *ot)
ot->exec = wm_collada_import_exec;
ot->poll = WM_operator_winactive;
- // ot->flag |= OPTYPE_PRESET;
+ // ot->flag = OPTYPE_PRESET;
ot->ui = wm_collada_import_draw;
diff --git a/source/blender/editors/io/io_gpencil_export.c b/source/blender/editors/io/io_gpencil_export.c
index 7ac05fcca3e..6e5ae9f3cba 100644
--- a/source/blender/editors/io/io_gpencil_export.c
+++ b/source/blender/editors/io/io_gpencil_export.c
@@ -5,36 +5,38 @@
* \ingroup editor/io
*/
-#include "BLI_path_util.h"
-#include "BLI_string.h"
+#ifdef WITH_IO_GPENCIL
-#include "DNA_gpencil_types.h"
-#include "DNA_space_types.h"
+# include "BLI_path_util.h"
+# include "BLI_string.h"
-#include "BKE_gpencil.h"
-#include "BKE_main.h"
-#include "BKE_report.h"
-#include "BKE_screen.h"
+# include "DNA_gpencil_types.h"
+# include "DNA_space_types.h"
-#include "BLT_translation.h"
+# include "BKE_gpencil.h"
+# include "BKE_main.h"
+# include "BKE_report.h"
+# include "BKE_screen.h"
-#include "RNA_access.h"
-#include "RNA_define.h"
+# include "BLT_translation.h"
-#include "UI_interface.h"
-#include "UI_resources.h"
+# include "RNA_access.h"
+# include "RNA_define.h"
-#include "WM_api.h"
-#include "WM_types.h"
+# include "UI_interface.h"
+# include "UI_resources.h"
-#include "DEG_depsgraph.h"
-#include "DEG_depsgraph_query.h"
+# include "WM_api.h"
+# include "WM_types.h"
-#include "io_gpencil.h"
+# include "DEG_depsgraph.h"
+# include "DEG_depsgraph_query.h"
-#include "gpencil_io.h"
+# include "io_gpencil.h"
-#if defined(WITH_PUGIXML) || defined(WITH_HARU)
+# include "gpencil_io.h"
+
+# if defined(WITH_PUGIXML) || defined(WITH_HARU)
/* Definition of enum elements to export. */
/* Common props for exporting. */
static void gpencil_export_common_props_definition(wmOperatorType *ot)
@@ -87,10 +89,10 @@ static void set_export_filepath(bContext *C, wmOperator *op, const char *extensi
RNA_string_set(op->ptr, "filepath", filepath);
}
}
-#endif
+# endif
/* <-------- SVG single frame export. --------> */
-#ifdef WITH_PUGIXML
+# ifdef WITH_PUGIXML
static bool wm_gpencil_export_svg_common_check(bContext *UNUSED(C), wmOperator *op)
{
char filepath[FILE_MAX];
@@ -241,10 +243,10 @@ void WM_OT_gpencil_export_svg(wmOperatorType *ot)
"Clip Camera",
"Clip drawings to camera size when export in camera view");
}
-#endif
+# endif
/* <-------- PDF single frame export. --------> */
-#ifdef WITH_HARU
+# ifdef WITH_HARU
static bool wm_gpencil_export_pdf_common_check(bContext *UNUSED(C), wmOperator *op)
{
@@ -406,4 +408,6 @@ void WM_OT_gpencil_export_pdf(wmOperatorType *ot)
"Frames",
"Which frames to include in the export");
}
-#endif
+# endif /* WITH_HARU */
+
+#endif /* WITH_IO_GPENCIL */
diff --git a/source/blender/editors/io/io_gpencil_import.c b/source/blender/editors/io/io_gpencil_import.c
index 8bed32ad6c3..45f5441616f 100644
--- a/source/blender/editors/io/io_gpencil_import.c
+++ b/source/blender/editors/io/io_gpencil_import.c
@@ -5,34 +5,36 @@
* \ingroup editor/io
*/
-#include "BLI_path_util.h"
+#ifdef WITH_IO_GPENCIL
-#include "DNA_gpencil_types.h"
-#include "DNA_space_types.h"
+# include "BLI_path_util.h"
-#include "BKE_context.h"
-#include "BKE_gpencil.h"
-#include "BKE_report.h"
+# include "DNA_gpencil_types.h"
+# include "DNA_space_types.h"
-#include "BLT_translation.h"
+# include "BKE_context.h"
+# include "BKE_gpencil.h"
+# include "BKE_report.h"
-#include "RNA_access.h"
-#include "RNA_define.h"
+# include "BLT_translation.h"
-#include "UI_interface.h"
-#include "UI_resources.h"
+# include "RNA_access.h"
+# include "RNA_define.h"
-#include "WM_api.h"
-#include "WM_types.h"
+# include "UI_interface.h"
+# include "UI_resources.h"
-#include "DEG_depsgraph.h"
-#include "DEG_depsgraph_query.h"
+# include "WM_api.h"
+# include "WM_types.h"
-#include "ED_gpencil.h"
+# include "DEG_depsgraph.h"
+# include "DEG_depsgraph_query.h"
-#include "io_gpencil.h"
+# include "ED_gpencil.h"
-#include "gpencil_io.h"
+# include "io_gpencil.h"
+
+# include "gpencil_io.h"
/* <-------- SVG single frame import. --------> */
static bool wm_gpencil_import_svg_common_check(bContext *UNUSED(C), wmOperator *op)
@@ -174,3 +176,5 @@ void WM_OT_gpencil_import_svg(wmOperatorType *ot)
0.001f,
100.0f);
}
+
+#endif /* WITH_IO_GPENCIL */
diff --git a/source/blender/editors/io/io_gpencil_utils.c b/source/blender/editors/io/io_gpencil_utils.c
index fa5fcd79b96..9a88daef1a1 100644
--- a/source/blender/editors/io/io_gpencil_utils.c
+++ b/source/blender/editors/io/io_gpencil_utils.c
@@ -5,14 +5,16 @@
* \ingroup editor/io
*/
-#include "DNA_space_types.h"
+#ifdef WITH_IO_GPENCIL
-#include "BKE_context.h"
-#include "BKE_screen.h"
+# include "DNA_space_types.h"
-#include "WM_api.h"
+# include "BKE_context.h"
+# include "BKE_screen.h"
-#include "io_gpencil.h"
+# include "WM_api.h"
+
+# include "io_gpencil.h"
ARegion *get_invoke_region(bContext *C)
{
@@ -46,3 +48,5 @@ View3D *get_invoke_view3d(bContext *C)
return NULL;
}
+
+#endif /* WITH_IO_GPENCIL */
diff --git a/source/blender/editors/io/io_obj.c b/source/blender/editors/io/io_obj.c
index 3345d422bd1..53fa4788d0e 100644
--- a/source/blender/editors/io/io_obj.c
+++ b/source/blender/editors/io/io_obj.c
@@ -4,51 +4,39 @@
* \ingroup editor/io
*/
-#include "DNA_space_types.h"
+#ifdef WITH_IO_WAVEFRONT_OBJ
-#include "BKE_context.h"
-#include "BKE_main.h"
-#include "BKE_report.h"
+# include "DNA_space_types.h"
-#include "BLI_path_util.h"
-#include "BLI_string.h"
-#include "BLI_utildefines.h"
+# include "BKE_context.h"
+# include "BKE_main.h"
+# include "BKE_report.h"
-#include "BLT_translation.h"
+# include "BLI_path_util.h"
+# include "BLI_string.h"
+# include "BLI_utildefines.h"
-#include "MEM_guardedalloc.h"
+# include "BLT_translation.h"
-#include "RNA_access.h"
-#include "RNA_define.h"
+# include "ED_outliner.h"
-#include "UI_interface.h"
-#include "UI_resources.h"
+# include "MEM_guardedalloc.h"
-#include "WM_api.h"
-#include "WM_types.h"
+# include "RNA_access.h"
+# include "RNA_define.h"
-#include "DEG_depsgraph.h"
+# include "UI_interface.h"
+# include "UI_resources.h"
-#include "IO_wavefront_obj.h"
-#include "io_obj.h"
+# include "WM_api.h"
+# include "WM_types.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", "Negative Z axis"},
- {0, NULL, 0, NULL, NULL}};
+# include "DEG_depsgraph.h"
-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", "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}};
+# include "IO_orientation.h"
+# include "IO_path_util_types.h"
+# include "IO_wavefront_obj.h"
+# include "io_obj.h"
static const EnumPropertyItem io_obj_export_evaluation_mode[] = {
{DAG_EVAL_RENDER, "DAG_EVAL_RENDER", 0, "Render", "Export objects as they appear in render"},
@@ -59,6 +47,15 @@ static const EnumPropertyItem io_obj_export_evaluation_mode[] = {
"Export objects as they appear in the viewport"},
{0, NULL, 0, NULL, NULL}};
+static const EnumPropertyItem io_obj_path_mode[] = {
+ {PATH_REFERENCE_AUTO, "AUTO", 0, "Auto", "Use Relative paths with subdirectories only"},
+ {PATH_REFERENCE_ABSOLUTE, "ABSOLUTE", 0, "Absolute", "Always write absolute paths"},
+ {PATH_REFERENCE_RELATIVE, "RELATIVE", 0, "Relative", "Write relative paths where possible"},
+ {PATH_REFERENCE_MATCH, "MATCH", 0, "Match", "Match Absolute/Relative setting with input path"},
+ {PATH_REFERENCE_STRIP, "STRIP", 0, "Strip", "Write filename only"},
+ {PATH_REFERENCE_COPY, "COPY", 0, "Copy", "Copy the file to the destination path"},
+ {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")) {
@@ -87,6 +84,7 @@ static int wm_obj_export_exec(bContext *C, wmOperator *op)
return OPERATOR_CANCELLED;
}
struct OBJExportParams export_params;
+ export_params.file_base_for_tests[0] = '\0';
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");
@@ -102,7 +100,9 @@ static int wm_obj_export_exec(bContext *C, wmOperator *op)
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_colors = RNA_boolean_get(op->ptr, "export_colors");
export_params.export_materials = RNA_boolean_get(op->ptr, "export_materials");
+ export_params.path_mode = RNA_enum_get(op->ptr, "path_mode");
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");
@@ -119,9 +119,9 @@ static int wm_obj_export_exec(bContext *C, wmOperator *op)
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");
+ const bool export_materials = RNA_boolean_get(imfptr, "export_materials");
uiLayoutSetPropSep(layout, true);
uiLayoutSetPropDecorate(layout, false);
@@ -150,6 +150,9 @@ static void ui_obj_export_settings(uiLayout *layout, PointerRNA *imfptr)
uiItemR(sub, imfptr, "export_selected_objects", 0, IFACE_("Selected Only"), ICON_NONE);
uiItemR(sub, imfptr, "apply_modifiers", 0, IFACE_("Apply Modifiers"), ICON_NONE);
uiItemR(sub, imfptr, "export_eval_mode", 0, IFACE_("Properties"), ICON_NONE);
+ sub = uiLayoutColumn(sub, false);
+ uiLayoutSetEnabled(sub, export_materials);
+ uiItemR(sub, imfptr, "path_mode", 0, IFACE_("Path Mode"), ICON_NONE);
/* Options for what to write. */
box = uiLayoutBox(layout);
@@ -158,10 +161,12 @@ static void ui_obj_export_settings(uiLayout *layout, PointerRNA *imfptr)
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_colors", 0, IFACE_("Colors"), 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);
+ /* Grouping options. */
box = uiLayoutBox(layout);
uiItemL(box, IFACE_("Grouping"), ICON_GROUP);
col = uiLayoutColumn(box, false);
@@ -231,6 +236,8 @@ static bool wm_obj_export_check(bContext *C, wmOperator *op)
void WM_OT_obj_export(struct wmOperatorType *ot)
{
+ PropertyRNA *prop;
+
ot->name = "Export Wavefront OBJ";
ot->description = "Save the scene to a Wavefront OBJ file";
ot->idname = "WM_OT_obj_export";
@@ -241,10 +248,10 @@ void WM_OT_obj_export(struct wmOperatorType *ot)
ot->ui = wm_obj_export_draw;
ot->check = wm_obj_export_check;
- ot->flag |= OPTYPE_PRESET;
+ ot->flag = OPTYPE_PRESET;
WM_operator_properties_filesel(ot,
- FILE_TYPE_FOLDER | FILE_TYPE_OBJECT_IO,
+ FILE_TYPE_FOLDER,
FILE_BLENDER,
FILE_SAVE,
WM_FILESEL_FILEPATH | WM_FILESEL_SHOW_PROPS,
@@ -276,13 +283,9 @@ void WM_OT_obj_export(struct wmOperatorType *ot)
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_enum(
+ ot->srna, "forward_axis", io_transform_axis, IO_AXIS_NEGATIVE_Z, "Forward Axis", "");
+ RNA_def_enum(ot->srna, "up_axis", io_transform_axis, IO_AXIS_Y, "Up Axis", "");
RNA_def_float(ot->srna,
"scaling_factor",
1.0f,
@@ -314,12 +317,19 @@ void WM_OT_obj_export(struct wmOperatorType *ot)
"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_colors", false, "Export Colors", "Export per-vertex colors");
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_enum(ot->srna,
+ "path_mode",
+ io_obj_path_mode,
+ PATH_REFERENCE_AUTO,
+ "Path Mode",
+ "Method used to reference paths");
RNA_def_boolean(ot->srna,
"export_triangulated_mesh",
false,
@@ -358,6 +368,10 @@ void WM_OT_obj_export(struct wmOperatorType *ot)
"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", "");
+
+ /* Only show .obj or .mtl files by default. */
+ prop = RNA_def_string(ot->srna, "filter_glob", "*.obj;*.mtl", 0, "Extension Filter", "");
+ RNA_def_property_flag(prop, PROP_HIDDEN);
}
static int wm_obj_import_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
@@ -378,10 +392,17 @@ static int wm_obj_import_exec(bContext *C, wmOperator *op)
import_params.clamp_size = RNA_float_get(op->ptr, "clamp_size");
import_params.forward_axis = RNA_enum_get(op->ptr, "forward_axis");
import_params.up_axis = RNA_enum_get(op->ptr, "up_axis");
+ import_params.import_vertex_groups = RNA_boolean_get(op->ptr, "import_vertex_groups");
import_params.validate_meshes = RNA_boolean_get(op->ptr, "validate_meshes");
OBJ_import(C, &import_params);
+ Scene *scene = CTX_data_scene(C);
+ WM_event_add_notifier(C, NC_SCENE | ND_OB_SELECT, scene);
+ WM_event_add_notifier(C, NC_SCENE | ND_OB_ACTIVE, scene);
+ WM_event_add_notifier(C, NC_SCENE | ND_LAYER_CONTENT, scene);
+ ED_outliner_select_sync_from_object_tag(C);
+
return OPERATOR_FINISHED;
}
@@ -402,6 +423,7 @@ static void ui_obj_import_settings(uiLayout *layout, PointerRNA *imfptr)
box = uiLayoutBox(layout);
uiItemL(box, IFACE_("Options"), ICON_EXPORT);
col = uiLayoutColumn(box, false);
+ uiItemR(col, imfptr, "import_vertex_groups", 0, NULL, ICON_NONE);
uiItemR(col, imfptr, "validate_meshes", 0, NULL, ICON_NONE);
}
@@ -415,9 +437,12 @@ static void wm_obj_import_draw(bContext *C, wmOperator *op)
void WM_OT_obj_import(struct wmOperatorType *ot)
{
+ PropertyRNA *prop;
+
ot->name = "Import Wavefront OBJ";
ot->description = "Load a Wavefront OBJ scene";
ot->idname = "WM_OT_obj_import";
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
ot->invoke = wm_obj_import_invoke;
ot->exec = wm_obj_import_exec;
@@ -425,7 +450,7 @@ void WM_OT_obj_import(struct wmOperatorType *ot)
ot->ui = wm_obj_import_draw;
WM_operator_properties_filesel(ot,
- FILE_TYPE_FOLDER | FILE_TYPE_OBJECT_IO,
+ FILE_TYPE_FOLDER,
FILE_BLENDER,
FILE_OPENFILE,
WM_FILESEL_FILEPATH | WM_FILESEL_SHOW_PROPS,
@@ -441,16 +466,23 @@ void WM_OT_obj_import(struct wmOperatorType *ot)
"Resize the objects to keep bounding box under this value. Value 0 disables clamping",
0.0f,
1000.0f);
- 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_enum(
+ ot->srna, "forward_axis", io_transform_axis, IO_AXIS_NEGATIVE_Z, "Forward Axis", "");
+ RNA_def_enum(ot->srna, "up_axis", io_transform_axis, IO_AXIS_Y, "Up Axis", "");
+ RNA_def_boolean(ot->srna,
+ "import_vertex_groups",
+ false,
+ "Vertex Groups",
+ "Import OBJ groups as vertex groups");
RNA_def_boolean(ot->srna,
"validate_meshes",
false,
"Validate Meshes",
"Check imported mesh objects for invalid data (slow)");
+
+ /* Only show .obj or .mtl files by default. */
+ prop = RNA_def_string(ot->srna, "filter_glob", "*.obj;*.mtl", 0, "Extension Filter", "");
+ RNA_def_property_flag(prop, PROP_HIDDEN);
}
+
+#endif /* WITH_IO_WAVEFRONT_OBJ */
diff --git a/source/blender/editors/io/io_ops.c b/source/blender/editors/io/io_ops.c
index 094f89d1540..0340d0598d5 100644
--- a/source/blender/editors/io/io_ops.c
+++ b/source/blender/editors/io/io_ops.c
@@ -24,6 +24,7 @@
#include "io_cache.h"
#include "io_gpencil.h"
#include "io_obj.h"
+#include "io_stl_ops.h"
void ED_operatortypes_io(void)
{
@@ -41,14 +42,14 @@ void ED_operatortypes_io(void)
WM_operatortype_append(WM_OT_usd_export);
#endif
+#ifdef WITH_IO_GPENCIL
WM_operatortype_append(WM_OT_gpencil_import_svg);
-
-#ifdef WITH_PUGIXML
+# ifdef WITH_PUGIXML
WM_operatortype_append(WM_OT_gpencil_export_svg);
-#endif
-
-#ifdef WITH_HARU
+# endif
+# ifdef WITH_HARU
WM_operatortype_append(WM_OT_gpencil_export_pdf);
+# endif
#endif
WM_operatortype_append(CACHEFILE_OT_open);
@@ -58,6 +59,12 @@ void ED_operatortypes_io(void)
WM_operatortype_append(CACHEFILE_OT_layer_remove);
WM_operatortype_append(CACHEFILE_OT_layer_move);
+#ifdef WITH_IO_WAVEFRONT_OBJ
WM_operatortype_append(WM_OT_obj_export);
WM_operatortype_append(WM_OT_obj_import);
+#endif
+
+#ifdef WITH_IO_STL
+ WM_operatortype_append(WM_OT_stl_import);
+#endif
}
diff --git a/source/blender/editors/io/io_stl_ops.c b/source/blender/editors/io/io_stl_ops.c
new file mode 100644
index 00000000000..7db32cd6f18
--- /dev/null
+++ b/source/blender/editors/io/io_stl_ops.c
@@ -0,0 +1,133 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+
+/** \file
+ * \ingroup editor/io
+ */
+
+#ifdef WITH_IO_STL
+
+# include "BKE_context.h"
+# include "BKE_report.h"
+
+# include "WM_api.h"
+# include "WM_types.h"
+
+# include "DNA_space_types.h"
+
+# include "ED_outliner.h"
+
+# include "RNA_access.h"
+# include "RNA_define.h"
+
+# include "IO_stl.h"
+# include "io_stl_ops.h"
+
+static int wm_stl_import_invoke(bContext *C, wmOperator *op, const wmEvent *event)
+{
+ return WM_operator_filesel(C, op, event);
+}
+
+static int wm_stl_import_execute(bContext *C, wmOperator *op)
+{
+ struct STLImportParams params;
+ params.forward_axis = RNA_enum_get(op->ptr, "forward_axis");
+ params.up_axis = RNA_enum_get(op->ptr, "up_axis");
+ params.use_facet_normal = RNA_boolean_get(op->ptr, "use_facet_normal");
+ params.use_scene_unit = RNA_boolean_get(op->ptr, "use_scene_unit");
+ params.global_scale = RNA_float_get(op->ptr, "global_scale");
+ params.use_mesh_validate = RNA_boolean_get(op->ptr, "use_mesh_validate");
+
+ int files_len = RNA_collection_length(op->ptr, "files");
+
+ if (files_len) {
+ PointerRNA fileptr;
+ PropertyRNA *prop;
+ char dir_only[FILE_MAX], file_only[FILE_MAX];
+
+ RNA_string_get(op->ptr, "directory", dir_only);
+ prop = RNA_struct_find_property(op->ptr, "files");
+ for (int i = 0; i < files_len; i++) {
+ RNA_property_collection_lookup_int(op->ptr, prop, i, &fileptr);
+ RNA_string_get(&fileptr, "name", file_only);
+ BLI_join_dirfile(params.filepath, sizeof(params.filepath), dir_only, file_only);
+ STL_import(C, &params);
+ }
+ }
+ else if (RNA_struct_property_is_set(op->ptr, "filepath")) {
+ RNA_string_get(op->ptr, "filepath", params.filepath);
+ STL_import(C, &params);
+ }
+ else {
+ BKE_report(op->reports, RPT_ERROR, "No filename given");
+ return OPERATOR_CANCELLED;
+ }
+
+ Scene *scene = CTX_data_scene(C);
+ WM_event_add_notifier(C, NC_SCENE | ND_OB_SELECT, scene);
+ WM_event_add_notifier(C, NC_SCENE | ND_OB_ACTIVE, scene);
+ WM_event_add_notifier(C, NC_SCENE | ND_LAYER_CONTENT, scene);
+ ED_outliner_select_sync_from_object_tag(C);
+
+ return OPERATOR_FINISHED;
+}
+
+static bool wm_stl_import_check(bContext *UNUSED(C), wmOperator *op)
+{
+ const int num_axes = 3;
+ /* Both forward and up axes cannot be the same (or same except opposite sign). */
+ if (RNA_enum_get(op->ptr, "forward_axis") % num_axes ==
+ (RNA_enum_get(op->ptr, "up_axis") % num_axes)) {
+ RNA_enum_set(op->ptr, "up_axis", RNA_enum_get(op->ptr, "up_axis") % num_axes + 1);
+ return true;
+ }
+ return false;
+}
+
+void WM_OT_stl_import(struct wmOperatorType *ot)
+{
+ PropertyRNA *prop;
+
+ ot->name = "Import STL";
+ ot->description = "Import an STL file as an object";
+ ot->idname = "WM_OT_stl_import";
+
+ ot->invoke = wm_stl_import_invoke;
+ ot->exec = wm_stl_import_execute;
+ ot->poll = WM_operator_winactive;
+ ot->check = wm_stl_import_check;
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+
+ WM_operator_properties_filesel(ot,
+ FILE_TYPE_FOLDER,
+ FILE_BLENDER,
+ FILE_OPENFILE,
+ WM_FILESEL_FILEPATH | WM_FILESEL_FILES | WM_FILESEL_DIRECTORY |
+ WM_FILESEL_SHOW_PROPS,
+ FILE_DEFAULTDISPLAY,
+ FILE_SORT_ALPHA);
+
+ RNA_def_float(ot->srna, "global_scale", 1.0f, 1e-6f, 1e6f, "Scale", "", 0.001f, 1000.0f);
+ RNA_def_boolean(ot->srna,
+ "use_scene_unit",
+ false,
+ "Scene Unit",
+ "Apply current scene's unit (as defined by unit scale) to imported data");
+ RNA_def_boolean(ot->srna,
+ "use_facet_normal",
+ false,
+ "Facet Normals",
+ "Use (import) facet normals (note that this will still give flat shading)");
+ RNA_def_enum(ot->srna, "forward_axis", io_transform_axis, IO_AXIS_Y, "Forward Axis", "");
+ RNA_def_enum(ot->srna, "up_axis", io_transform_axis, IO_AXIS_Z, "Up Axis", "");
+ RNA_def_boolean(ot->srna,
+ "use_mesh_validate",
+ false,
+ "Validate Mesh",
+ "Validate and correct imported mesh (slow)");
+
+ /* Only show .stl files by default. */
+ prop = RNA_def_string(ot->srna, "filter_glob", "*.stl", 0, "Extension Filter", "");
+ RNA_def_property_flag(prop, PROP_HIDDEN);
+}
+
+#endif /* WITH_IO_STL */
diff --git a/source/blender/editors/io/io_stl_ops.h b/source/blender/editors/io/io_stl_ops.h
new file mode 100644
index 00000000000..8f548f75985
--- /dev/null
+++ b/source/blender/editors/io/io_stl_ops.h
@@ -0,0 +1,12 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+
+/** \file
+ * \ingroup editor/io
+ */
+
+#pragma once
+
+struct wmOperatorType;
+
+void WM_OT_stl_export(struct wmOperatorType *ot);
+void WM_OT_stl_import(struct wmOperatorType *ot);
diff --git a/source/blender/editors/io/io_usd.c b/source/blender/editors/io/io_usd.c
index e0616a0cec3..a59cdf60243 100644
--- a/source/blender/editors/io/io_usd.c
+++ b/source/blender/editors/io/io_usd.c
@@ -57,6 +57,20 @@ const EnumPropertyItem rna_enum_usd_export_evaluation_mode_items[] = {
{0, NULL, 0, NULL, NULL},
};
+const EnumPropertyItem rna_enum_usd_mtl_name_collision_mode_items[] = {
+ {USD_MTL_NAME_COLLISION_MAKE_UNIQUE,
+ "MAKE_UNIQUE",
+ 0,
+ "Make Unique",
+ "Import each USD material as a unique Blender material"},
+ {USD_MTL_NAME_COLLISION_REFERENCE_EXISTING,
+ "REFERENCE_EXISTING",
+ 0,
+ "Reference Existing",
+ "If a material with the same name already exists, reference that instead of importing"},
+ {0, NULL, 0, NULL, NULL},
+};
+
/* Stored in the wmOperator's customdata field to indicate it should run as a background job.
* This is set when the operator is invoked, and not set when it is only executed. */
enum { AS_BACKGROUND_JOB = 1 };
@@ -118,7 +132,7 @@ static int wm_usd_export_exec(bContext *C, wmOperator *op)
const bool generate_preview_surface = RNA_boolean_get(op->ptr, "generate_preview_surface");
const bool export_textures = RNA_boolean_get(op->ptr, "export_textures");
const bool overwrite_textures = RNA_boolean_get(op->ptr, "overwrite_textures");
- const bool relative_texture_paths = RNA_boolean_get(op->ptr, "relative_texture_paths");
+ const bool relative_paths = RNA_boolean_get(op->ptr, "relative_paths");
struct USDExportParams params = {
export_animation,
@@ -133,7 +147,7 @@ static int wm_usd_export_exec(bContext *C, wmOperator *op)
generate_preview_surface,
export_textures,
overwrite_textures,
- relative_texture_paths,
+ relative_paths,
};
bool ok = USD_export(C, filename, &params, as_background_job);
@@ -181,15 +195,29 @@ static void wm_usd_export_draw(bContext *UNUSED(C), wmOperator *op)
const bool export_tex = RNA_boolean_get(ptr, "export_textures");
uiLayoutSetActive(row, export_mtl && preview && export_tex);
- row = uiLayoutRow(col, true);
- uiItemR(row, ptr, "relative_texture_paths", 0, NULL, ICON_NONE);
- uiLayoutSetActive(row, export_mtl && preview);
+ box = uiLayoutBox(layout);
+ col = uiLayoutColumnWithHeading(box, true, IFACE_("File References"));
+ uiItemR(col, ptr, "relative_paths", 0, NULL, ICON_NONE);
box = uiLayoutBox(layout);
uiItemL(box, IFACE_("Experimental"), ICON_NONE);
uiItemR(box, ptr, "use_instancing", 0, NULL, ICON_NONE);
}
+static bool wm_usd_export_check(bContext *UNUSED(C), wmOperator *op)
+{
+ char filepath[FILE_MAX];
+ RNA_string_get(op->ptr, "filepath", filepath);
+
+ if (!BLI_path_extension_check_n(filepath, ".usd", ".usda", ".usdc", NULL)) {
+ BLI_path_extension_ensure(filepath, FILE_MAX, ".usdc");
+ RNA_string_set(op->ptr, "filepath", filepath);
+ return true;
+ }
+
+ return false;
+}
+
void WM_OT_usd_export(struct wmOperatorType *ot)
{
ot->name = "Export USD";
@@ -200,8 +228,9 @@ void WM_OT_usd_export(struct wmOperatorType *ot)
ot->exec = wm_usd_export_exec;
ot->poll = WM_operator_winactive;
ot->ui = wm_usd_export_draw;
+ ot->check = wm_usd_export_check;
- ot->flag = OPTYPE_REGISTER; /* No UNDO possible. */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_PRESET; /* No UNDO possible. */
WM_operator_properties_filesel(ot,
FILE_TYPE_FOLDER | FILE_TYPE_USD,
@@ -282,10 +311,11 @@ void WM_OT_usd_export(struct wmOperatorType *ot)
"Allow overwriting existing texture files when exporting textures");
RNA_def_boolean(ot->srna,
- "relative_texture_paths",
+ "relative_paths",
true,
- "Relative Texture Paths",
- "Make texture asset paths relative to the USD file");
+ "Relative Paths",
+ "Use relative paths to reference external files (i.e. textures, volumes) in "
+ "USD, otherwise use absolute paths");
}
/* ====== USD Import ====== */
@@ -355,6 +385,9 @@ static int wm_usd_import_exec(bContext *C, wmOperator *op)
const float light_intensity_scale = RNA_float_get(op->ptr, "light_intensity_scale");
+ const eUSDMtlNameCollisionMode mtl_name_collision_mode = RNA_enum_get(op->ptr,
+ "mtl_name_collision_mode");
+
/* TODO(makowalski): Add support for sequences. */
const bool is_sequence = false;
int offset = 0;
@@ -393,7 +426,8 @@ static int wm_usd_import_exec(bContext *C, wmOperator *op)
.use_instancing = use_instancing,
.import_usd_preview = import_usd_preview,
.set_material_blend = set_material_blend,
- .light_intensity_scale = light_intensity_scale};
+ .light_intensity_scale = light_intensity_scale,
+ .mtl_name_collision_mode = mtl_name_collision_mode};
const bool ok = USD_import(C, filename, &params, as_background_job);
@@ -436,6 +470,7 @@ static void wm_usd_import_draw(bContext *UNUSED(C), wmOperator *op)
uiItemR(col, ptr, "relative_path", 0, NULL, ICON_NONE);
uiItemR(col, ptr, "create_collection", 0, NULL, ICON_NONE);
uiItemR(box, ptr, "light_intensity_scale", 0, NULL, ICON_NONE);
+ uiItemR(box, ptr, "mtl_name_collision_mode", 0, NULL, ICON_NONE);
box = uiLayoutBox(layout);
col = uiLayoutColumnWithHeading(box, true, IFACE_("Experimental"));
@@ -559,6 +594,14 @@ void WM_OT_usd_import(struct wmOperatorType *ot)
"Scale for the intensity of imported lights",
0.0001f,
1000.0f);
+
+ RNA_def_enum(
+ ot->srna,
+ "mtl_name_collision_mode",
+ rna_enum_usd_mtl_name_collision_mode_items,
+ USD_MTL_NAME_COLLISION_MAKE_UNIQUE,
+ "Material Name Collision",
+ "Behavior when the name of an imported material conflicts with an existing material");
}
#endif /* WITH_USD */
diff --git a/source/blender/editors/mask/mask_add.c b/source/blender/editors/mask/mask_add.c
index 0b9261eac4f..37c1815fca3 100644
--- a/source/blender/editors/mask/mask_add.c
+++ b/source/blender/editors/mask/mask_add.c
@@ -31,7 +31,9 @@
#include "mask_intern.h" /* own include */
-/******************** add vertex *********************/
+/* -------------------------------------------------------------------- */
+/** \name Add Vertex
+ * \{ */
static void setup_vertex_point(Mask *mask,
MaskSpline *spline,
@@ -160,7 +162,11 @@ static void setup_vertex_point(Mask *mask,
ED_mask_select_flush_all(mask);
}
-/* **** add extrude vertex **** */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Add Extrude Vertex
+ * \{ */
static void finSelectedSplinePoint(MaskLayer *mask_layer,
MaskSpline **spline,
@@ -206,7 +212,11 @@ static void finSelectedSplinePoint(MaskLayer *mask_layer,
}
}
-/* **** add subdivide vertex **** */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Add Subdivide Vertex
+ * \{ */
static void mask_spline_add_point_at_index(MaskSpline *spline, int point_index)
{
@@ -230,7 +240,7 @@ static bool add_vertex_subdivide(const bContext *C, Mask *mask, const float co[2
MaskLayer *mask_layer;
MaskSpline *spline;
MaskSplinePoint *point = NULL;
- const float threshold = 9;
+ const float threshold = 12;
float tangent[2];
float u;
@@ -390,7 +400,7 @@ static bool add_vertex_new(const bContext *C, Mask *mask, MaskLayer *mask_layer,
MaskSplinePoint *new_point = NULL, *ref_point = NULL;
if (!mask_layer) {
- /* if there's no mask layer currently operationg on, create new one */
+ /* If there's no mask layer currently operating on, create new one. */
mask_layer = BKE_mask_layer_new(mask, "");
mask->masklay_act = mask->masklay_tot - 1;
}
@@ -492,6 +502,12 @@ static int add_vertex_handle_cyclic(
return OPERATOR_PASS_THROUGH;
}
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Add Vertex Operator
+ * \{ */
+
static int add_vertex_exec(bContext *C, wmOperator *op)
{
MaskViewLockState lock_state;
@@ -567,7 +583,7 @@ void MASK_OT_add_vertex(wmOperatorType *ot)
/* api callbacks */
ot->exec = add_vertex_exec;
ot->invoke = add_vertex_invoke;
- ot->poll = ED_operator_mask;
+ ot->poll = ED_maskedit_visible_splines_poll;
/* flags */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
@@ -585,7 +601,11 @@ void MASK_OT_add_vertex(wmOperatorType *ot)
1.0f);
}
-/******************** add feather vertex *********************/
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Add Feather Vertex Operator
+ * \{ */
static int add_feather_vertex_exec(bContext *C, wmOperator *op)
{
@@ -593,7 +613,7 @@ static int add_feather_vertex_exec(bContext *C, wmOperator *op)
MaskLayer *mask_layer;
MaskSpline *spline;
MaskSplinePoint *point = NULL;
- const float threshold = 9;
+ const float threshold = 12;
float co[2], u;
RNA_float_get_array(op->ptr, "location", co);
@@ -677,7 +697,11 @@ void MASK_OT_add_feather_vertex(wmOperatorType *ot)
1.0f);
}
-/******************** common primitive functions *********************/
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Common Primitive Functions
+ * \{ */
static BezTriple *points_to_bezier(const float (*points)[2],
const int num_points,
@@ -812,7 +836,11 @@ static void define_primitive_add_properties(wmOperatorType *ot)
FLT_MAX);
}
-/******************** primitive add circle *********************/
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Primitive Add Circle Operator
+ * \{ */
static int primitive_circle_add_exec(bContext *C, wmOperator *op)
{
@@ -834,7 +862,7 @@ void MASK_OT_primitive_circle_add(wmOperatorType *ot)
/* api callbacks */
ot->exec = primitive_circle_add_exec;
ot->invoke = primitive_add_invoke;
- ot->poll = ED_operator_mask;
+ ot->poll = ED_maskedit_visible_splines_poll;
/* flags */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
@@ -843,7 +871,11 @@ void MASK_OT_primitive_circle_add(wmOperatorType *ot)
define_primitive_add_properties(ot);
}
-/******************** primitive add suqare *********************/
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Primitive Add Suqare Operator
+ * \{ */
static int primitive_square_add_exec(bContext *C, wmOperator *op)
{
@@ -865,7 +897,7 @@ void MASK_OT_primitive_square_add(wmOperatorType *ot)
/* api callbacks */
ot->exec = primitive_square_add_exec;
ot->invoke = primitive_add_invoke;
- ot->poll = ED_operator_mask;
+ ot->poll = ED_maskedit_visible_splines_poll;
/* flags */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
@@ -873,3 +905,5 @@ void MASK_OT_primitive_square_add(wmOperatorType *ot)
/* properties */
define_primitive_add_properties(ot);
}
+
+/** \} */
diff --git a/source/blender/editors/mask/mask_draw.c b/source/blender/editors/mask/mask_draw.c
index aab4007854f..a18419ad422 100644
--- a/source/blender/editors/mask/mask_draw.c
+++ b/source/blender/editors/mask/mask_draw.c
@@ -663,6 +663,7 @@ void ED_mask_draw_region(
const char draw_flag,
const char draw_type,
const eMaskOverlayMode overlay_mode,
+ const float blend_factor,
/* convert directly into aspect corrected vars */
const int width_i,
const int height_i,
@@ -721,12 +722,14 @@ void ED_mask_draw_region(
}
if (draw_flag & MASK_DRAWFLAG_OVERLAY) {
- const float red[4] = {1.0f, 0.0f, 0.0f, 0.0f};
+ float buf_col[4] = {1.0f, 0.0f, 0.0f, 0.0f};
float *buffer = mask_rasterize(mask_eval, width, height);
if (overlay_mode != MASK_OVERLAY_ALPHACHANNEL) {
/* More blending types could be supported in the future. */
- GPU_blend(GPU_BLEND_MULTIPLY);
+ GPU_blend(GPU_BLEND_ALPHA);
+ buf_col[0] = -1.0f;
+ buf_col[3] = 1.0f;
}
GPU_matrix_push();
@@ -737,10 +740,18 @@ 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);
- immDrawPixelsTexTiled(
- &state, 0.0f, 0.0f, width, height, GPU_R16F, false, buffer, 1.0f, 1.0f, NULL);
+ state.shader, GPU_shader_get_uniform(state.shader, "shuffle"), 4, 1, buf_col);
+ if (overlay_mode == MASK_OVERLAY_COMBINED) {
+ const float blend_col[4] = {0.0f, 0.0f, 0.0f, blend_factor};
+
+ immDrawPixelsTexTiled(
+ &state, 0.0f, 0.0f, width, height, GPU_R16F, false, buffer, 1.0f, 1.0f, blend_col);
+ }
+ else {
+ immDrawPixelsTexTiled(
+ &state, 0.0f, 0.0f, width, height, GPU_R16F, false, buffer, 1.0f, 1.0f, NULL);
+ }
GPU_matrix_pop();
if (overlay_mode != MASK_OVERLAY_ALPHACHANNEL) {
@@ -765,7 +776,9 @@ void ED_mask_draw_region(
}
/* draw! */
- draw_mask_layers(C, mask_eval, draw_flag, draw_type, width, height);
+ if (draw_flag & MASK_DRAWFLAG_SPLINE) {
+ draw_mask_layers(C, mask_eval, draw_flag, draw_type, width, height);
+ }
if (do_draw_cb) {
ED_region_draw_cb_draw(C, region, REGION_DRAW_POST_VIEW);
diff --git a/source/blender/editors/mask/mask_edit.c b/source/blender/editors/mask/mask_edit.c
index b2d49bcc642..915f90a1537 100644
--- a/source/blender/editors/mask/mask_edit.c
+++ b/source/blender/editors/mask/mask_edit.c
@@ -42,6 +42,22 @@ bool ED_maskedit_poll(bContext *C)
return false;
}
+bool ED_maskedit_visible_splines_poll(bContext *C)
+{
+ ScrArea *area = CTX_wm_area(C);
+ if (area) {
+ switch (area->spacetype) {
+ case SPACE_CLIP:
+ return ED_space_clip_maskedit_visible_splines_poll(C);
+ case SPACE_SEQ:
+ return ED_space_sequencer_maskedit_poll(C);
+ case SPACE_IMAGE:
+ return ED_space_image_maskedit_visible_splines_poll(C);
+ }
+ }
+ return false;
+}
+
bool ED_maskedit_mask_poll(bContext *C)
{
ScrArea *area = CTX_wm_area(C);
@@ -58,6 +74,22 @@ bool ED_maskedit_mask_poll(bContext *C)
return false;
}
+bool ED_maskedit_mask_visible_splines_poll(bContext *C)
+{
+ const ScrArea *area = CTX_wm_area(C);
+ if (area) {
+ switch (area->spacetype) {
+ case SPACE_CLIP:
+ return ED_space_clip_maskedit_mask_visible_splines_poll(C);
+ case SPACE_SEQ:
+ return ED_space_sequencer_maskedit_mask_poll(C);
+ case SPACE_IMAGE:
+ return ED_space_image_maskedit_mask_visible_splines_poll(C);
+ }
+ }
+ return false;
+}
+
/** \} */
/* -------------------------------------------------------------------- */
diff --git a/source/blender/editors/mask/mask_intern.h b/source/blender/editors/mask/mask_intern.h
index c620d781c7f..2e99b45f215 100644
--- a/source/blender/editors/mask/mask_intern.h
+++ b/source/blender/editors/mask/mask_intern.h
@@ -86,9 +86,6 @@ void ED_mask_select_flush_all(struct Mask *mask);
/* mask_editor.c */
-bool ED_maskedit_poll(struct bContext *C);
-bool ED_maskedit_mask_poll(struct bContext *C);
-
/* Generalized solution for preserving editor viewport when making changes while lock-to-selection
* is enabled.
* Any mask operator can use this API, without worrying that some editors do not have an idea of
diff --git a/source/blender/editors/mask/mask_ops.c b/source/blender/editors/mask/mask_ops.c
index 3c0e7ee399c..14976d860f6 100644
--- a/source/blender/editors/mask/mask_ops.c
+++ b/source/blender/editors/mask/mask_ops.c
@@ -113,7 +113,7 @@ void MASK_OT_new(wmOperatorType *ot)
/* api callbacks */
ot->exec = mask_new_exec;
- ot->poll = ED_operator_mask;
+ ot->poll = ED_maskedit_poll;
/* properties */
RNA_def_string(ot->srna, "name", NULL, MAX_ID_NAME - 2, "Name", "Name of new mask");
@@ -146,7 +146,7 @@ void MASK_OT_layer_new(wmOperatorType *ot)
/* api callbacks */
ot->exec = mask_layer_new_exec;
- ot->poll = ED_maskedit_poll;
+ ot->poll = ED_maskedit_mask_poll;
/* flags */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
@@ -181,7 +181,7 @@ void MASK_OT_layer_remove(wmOperatorType *ot)
/* api callbacks */
ot->exec = mask_layer_remove_exec;
- ot->poll = ED_maskedit_poll;
+ ot->poll = ED_maskedit_mask_poll;
/* flags */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
@@ -907,7 +907,7 @@ void MASK_OT_slide_point(wmOperatorType *ot)
/* api callbacks */
ot->invoke = slide_point_invoke;
ot->modal = slide_point_modal;
- ot->poll = ED_operator_mask;
+ ot->poll = ED_maskedit_mask_visible_splines_poll;
/* flags */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
@@ -1297,7 +1297,7 @@ void MASK_OT_slide_spline_curvature(wmOperatorType *ot)
/* api callbacks */
ot->invoke = slide_spline_curvature_invoke;
ot->modal = slide_spline_curvature_modal;
- ot->poll = ED_operator_mask;
+ ot->poll = ED_maskedit_mask_visible_splines_poll;
/* flags */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
@@ -1336,7 +1336,7 @@ void MASK_OT_cyclic_toggle(wmOperatorType *ot)
/* api callbacks */
ot->exec = cyclic_toggle_exec;
- ot->poll = ED_maskedit_mask_poll;
+ ot->poll = ED_maskedit_mask_visible_splines_poll;
/* flags */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
@@ -1493,7 +1493,7 @@ void MASK_OT_delete(wmOperatorType *ot)
/* api callbacks */
ot->invoke = WM_operator_confirm;
ot->exec = delete_exec;
- ot->poll = ED_maskedit_mask_poll;
+ ot->poll = ED_maskedit_mask_visible_splines_poll;
/* flags */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
@@ -1551,7 +1551,7 @@ void MASK_OT_switch_direction(wmOperatorType *ot)
/* api callbacks */
ot->exec = mask_switch_direction_exec;
- ot->poll = ED_maskedit_mask_poll;
+ ot->poll = ED_maskedit_mask_visible_splines_poll;
/* flags */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
@@ -1613,7 +1613,7 @@ void MASK_OT_normals_make_consistent(wmOperatorType *ot)
/* api callbacks */
ot->exec = mask_normals_make_consistent_exec;
- ot->poll = ED_maskedit_mask_poll;
+ ot->poll = ED_maskedit_mask_visible_splines_poll;
/* flags */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
@@ -1693,7 +1693,7 @@ void MASK_OT_handle_type_set(wmOperatorType *ot)
/* api callbacks */
ot->invoke = WM_menu_invoke;
ot->exec = set_handle_type_exec;
- ot->poll = ED_maskedit_mask_poll;
+ ot->poll = ED_maskedit_mask_visible_splines_poll;
/* flags */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
@@ -1849,7 +1849,7 @@ void MASK_OT_feather_weight_clear(wmOperatorType *ot)
/* api callbacks */
ot->exec = mask_feather_weight_clear_exec;
- ot->poll = ED_maskedit_mask_poll;
+ ot->poll = ED_maskedit_mask_visible_splines_poll;
/* flags */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
@@ -2043,7 +2043,7 @@ void MASK_OT_duplicate(wmOperatorType *ot)
/* api callbacks */
ot->exec = mask_duplicate_exec;
- ot->poll = ED_maskedit_mask_poll;
+ ot->poll = ED_maskedit_mask_visible_splines_poll;
/* flags */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
@@ -2084,7 +2084,7 @@ void MASK_OT_copy_splines(wmOperatorType *ot)
static bool paste_splines_poll(bContext *C)
{
- if (ED_maskedit_mask_poll(C)) {
+ if (ED_maskedit_mask_visible_splines_poll(C)) {
return BKE_mask_clipboard_is_empty() == false;
}
diff --git a/source/blender/editors/mask/mask_query.c b/source/blender/editors/mask/mask_query.c
index afe457a8502..02e1524e23e 100644
--- a/source/blender/editors/mask/mask_query.c
+++ b/source/blender/editors/mask/mask_query.c
@@ -45,6 +45,8 @@ bool ED_mask_find_nearest_diff_point(const bContext *C,
float *r_u,
float *r_score)
{
+ const float threshold_sq = threshold * threshold;
+
ScrArea *area = CTX_wm_area(C);
ARegion *region = CTX_wm_region(C);
@@ -139,7 +141,7 @@ bool ED_mask_find_nearest_diff_point(const bContext *C,
}
}
- if (point && dist_best_sq < threshold) {
+ if (point && dist_best_sq < threshold_sq) {
if (r_mask_layer) {
*r_mask_layer = point_mask_layer;
}
@@ -613,7 +615,7 @@ bool ED_mask_selected_minmax(const bContext *C,
/* Use evaluated mask to take animation into account.
* The animation of splies is not "flushed" back to original, so need to explicitly
- * sue evaluated datablock here. */
+ * use evaluated datablock here. */
Mask *mask_eval = (Mask *)DEG_get_evaluated_id(depsgraph, &mask->id);
INIT_MINMAX2(min, max);
diff --git a/source/blender/editors/mask/mask_relationships.c b/source/blender/editors/mask/mask_relationships.c
index 9d8b84de66b..1f175ce51fc 100644
--- a/source/blender/editors/mask/mask_relationships.c
+++ b/source/blender/editors/mask/mask_relationships.c
@@ -21,6 +21,7 @@
#include "WM_types.h"
#include "ED_clip.h" /* frame remapping functions */
+#include "ED_mask.h"
#include "ED_screen.h"
#include "mask_intern.h" /* own include */
@@ -61,7 +62,7 @@ void MASK_OT_parent_clear(wmOperatorType *ot)
/* api callbacks */
ot->exec = mask_parent_clear_exec;
- ot->poll = ED_maskedit_mask_poll;
+ ot->poll = ED_maskedit_mask_visible_splines_poll;
/* flags */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
diff --git a/source/blender/editors/mask/mask_select.c b/source/blender/editors/mask/mask_select.c
index 0bd054e1b89..4bd80208b9e 100644
--- a/source/blender/editors/mask/mask_select.c
+++ b/source/blender/editors/mask/mask_select.c
@@ -222,7 +222,7 @@ void MASK_OT_select_all(wmOperatorType *ot)
/* api callbacks */
ot->exec = select_all_exec;
- ot->poll = ED_maskedit_mask_poll;
+ ot->poll = ED_maskedit_mask_visible_splines_poll;
/* flags */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
@@ -364,12 +364,9 @@ static int select_exec(bContext *C, wmOperator *op)
return OPERATOR_PASS_THROUGH | OPERATOR_FINISHED;
}
if (deselect_all) {
- /* For clip editor tracks, leave deselect all to clip editor. */
- if (!ED_clip_can_select(C)) {
- ED_mask_deselect_all(C);
- ED_mask_view_lock_state_restore_no_jump(C, &lock_state);
- return OPERATOR_PASS_THROUGH | OPERATOR_FINISHED;
- }
+ ED_mask_deselect_all(C);
+ ED_mask_view_lock_state_restore_no_jump(C, &lock_state);
+ return OPERATOR_PASS_THROUGH | OPERATOR_FINISHED;
}
return OPERATOR_PASS_THROUGH;
@@ -401,7 +398,8 @@ void MASK_OT_select(wmOperatorType *ot)
/* api callbacks */
ot->exec = select_exec;
ot->invoke = select_invoke;
- ot->poll = ED_maskedit_mask_poll;
+ ot->poll = ED_maskedit_mask_visible_splines_poll;
+ ot->get_name = ED_select_pick_get_name;
/* flags */
ot->flag = OPTYPE_UNDO;
@@ -506,7 +504,7 @@ void MASK_OT_select_box(wmOperatorType *ot)
ot->invoke = WM_gesture_box_invoke;
ot->exec = box_select_exec;
ot->modal = WM_gesture_box_modal;
- ot->poll = ED_maskedit_mask_poll;
+ ot->poll = ED_maskedit_mask_visible_splines_poll;
/* flags */
ot->flag = OPTYPE_UNDO;
@@ -629,7 +627,7 @@ void MASK_OT_select_lasso(wmOperatorType *ot)
ot->invoke = WM_gesture_lasso_invoke;
ot->modal = WM_gesture_lasso_modal;
ot->exec = clip_lasso_select_exec;
- ot->poll = ED_maskedit_mask_poll;
+ ot->poll = ED_maskedit_mask_visible_splines_poll;
ot->cancel = WM_gesture_lasso_cancel;
/* flags */
@@ -747,7 +745,8 @@ void MASK_OT_select_circle(wmOperatorType *ot)
ot->invoke = WM_gesture_circle_invoke;
ot->modal = WM_gesture_circle_modal;
ot->exec = circle_select_exec;
- ot->poll = ED_maskedit_mask_poll;
+ ot->poll = ED_maskedit_mask_visible_splines_poll;
+ ot->get_name = ED_select_circle_get_name;
/* flags */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
@@ -810,7 +809,7 @@ void MASK_OT_select_linked_pick(wmOperatorType *ot)
/* api callbacks */
ot->invoke = mask_select_linked_pick_invoke;
- ot->poll = ED_maskedit_mask_poll;
+ ot->poll = ED_maskedit_mask_visible_splines_poll;
/* flags */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
@@ -865,7 +864,7 @@ void MASK_OT_select_linked(wmOperatorType *ot)
/* api callbacks */
ot->exec = mask_select_linked_exec;
- ot->poll = ED_maskedit_mask_poll;
+ ot->poll = ED_maskedit_mask_visible_splines_poll;
/* flags */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
@@ -964,7 +963,7 @@ void MASK_OT_select_more(wmOperatorType *ot)
/* api callbacks */
ot->exec = mask_select_more_exec;
- ot->poll = ED_maskedit_mask_poll;
+ ot->poll = ED_maskedit_mask_visible_splines_poll;
/* flags */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
@@ -984,7 +983,7 @@ void MASK_OT_select_less(wmOperatorType *ot)
/* api callbacks */
ot->exec = mask_select_less_exec;
- ot->poll = ED_maskedit_mask_poll;
+ ot->poll = ED_maskedit_mask_visible_splines_poll;
/* flags */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
diff --git a/source/blender/editors/mask/mask_shapekey.c b/source/blender/editors/mask/mask_shapekey.c
index dd54d84a90b..55145f27012 100644
--- a/source/blender/editors/mask/mask_shapekey.c
+++ b/source/blender/editors/mask/mask_shapekey.c
@@ -67,7 +67,7 @@ void MASK_OT_shape_key_insert(wmOperatorType *ot)
/* api callbacks */
ot->exec = mask_shape_key_insert_exec;
- ot->poll = ED_maskedit_mask_poll;
+ ot->poll = ED_maskedit_mask_visible_splines_poll;
/* flags */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
@@ -113,7 +113,7 @@ void MASK_OT_shape_key_clear(wmOperatorType *ot)
/* api callbacks */
ot->exec = mask_shape_key_clear_exec;
- ot->poll = ED_maskedit_mask_poll;
+ ot->poll = ED_maskedit_mask_visible_splines_poll;
/* flags */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
@@ -197,7 +197,7 @@ void MASK_OT_shape_key_feather_reset(wmOperatorType *ot)
/* api callbacks */
ot->exec = mask_shape_key_feather_reset_exec;
- ot->poll = ED_maskedit_mask_poll;
+ ot->poll = ED_maskedit_mask_visible_splines_poll;
/* flags */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
@@ -356,7 +356,7 @@ void MASK_OT_shape_key_rekey(wmOperatorType *ot)
/* api callbacks */
ot->exec = mask_shape_key_rekey_exec;
- ot->poll = ED_maskedit_mask_poll;
+ ot->poll = ED_maskedit_mask_visible_splines_poll;
/* flags */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
diff --git a/source/blender/editors/mesh/CMakeLists.txt b/source/blender/editors/mesh/CMakeLists.txt
index ed09e5a6334..28ac913a3e3 100644
--- a/source/blender/editors/mesh/CMakeLists.txt
+++ b/source/blender/editors/mesh/CMakeLists.txt
@@ -24,7 +24,7 @@ set(INC
)
set(SRC
- editface.c
+ editface.cc
editmesh_add.c
editmesh_add_gizmo.c
editmesh_automerge.c
@@ -51,10 +51,10 @@ set(SRC
editmesh_tools.c
editmesh_undo.c
editmesh_utils.c
- mesh_data.c
+ mesh_data.cc
mesh_mirror.c
mesh_ops.c
- meshtools.c
+ meshtools.cc
mesh_intern.h
)
diff --git a/source/blender/editors/mesh/editface.c b/source/blender/editors/mesh/editface.cc
index a5c6adaa43e..69fe69fe117 100644
--- a/source/blender/editors/mesh/editface.c
+++ b/source/blender/editors/mesh/editface.cc
@@ -36,16 +36,16 @@
/* own include */
-void paintface_flush_flags(struct bContext *C, Object *ob, short flag)
+void paintface_flush_flags(bContext *C, Object *ob, short flag)
{
Mesh *me = BKE_mesh_from_object(ob);
MPoly *polys, *mp_orig;
- const int *index_array = NULL;
+ const int *index_array = nullptr;
int totpoly;
BLI_assert((flag & ~(SELECT | ME_HIDE)) == 0);
- if (me == NULL) {
+ if (me == nullptr) {
return;
}
@@ -60,7 +60,7 @@ void paintface_flush_flags(struct bContext *C, Object *ob, short flag)
Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C);
Object *ob_eval = DEG_get_evaluated_object(depsgraph, ob);
- if (ob_eval == NULL) {
+ if (ob_eval == nullptr) {
return;
}
@@ -68,7 +68,7 @@ void paintface_flush_flags(struct bContext *C, Object *ob, short flag)
Mesh *me_eval = (Mesh *)ob_eval->runtime.data_eval;
bool updated = false;
- if (me_orig != NULL && me_eval != NULL && me_orig->totpoly == me->totpoly) {
+ if (me_orig != nullptr && me_eval != nullptr && me_orig->totpoly == me->totpoly) {
/* Update the COW copy of the mesh. */
for (int i = 0; i < me->totpoly; i++) {
me_orig->mpoly[i].flag = me->mpoly[i].flag;
@@ -79,7 +79,7 @@ void paintface_flush_flags(struct bContext *C, Object *ob, short flag)
updated = true;
}
/* Mesh polys => Final derived polys */
- else if ((index_array = CustomData_get_layer(&me_eval->pdata, CD_ORIGINDEX))) {
+ else if ((index_array = (const int *)CustomData_get_layer(&me_eval->pdata, CD_ORIGINDEX))) {
polys = me_eval->mpoly;
totpoly = me_eval->totpoly;
@@ -104,10 +104,10 @@ void paintface_flush_flags(struct bContext *C, Object *ob, short flag)
BKE_mesh_batch_cache_dirty_tag(me_eval, BKE_MESH_BATCH_DIRTY_SELECT_PAINT);
}
- DEG_id_tag_update(ob->data, ID_RECALC_SELECT);
+ DEG_id_tag_update(static_cast<ID *>(ob->data), ID_RECALC_SELECT);
}
else {
- DEG_id_tag_update(ob->data, ID_RECALC_COPY_ON_WRITE | ID_RECALC_SELECT);
+ DEG_id_tag_update(static_cast<ID *>(ob->data), ID_RECALC_COPY_ON_WRITE | ID_RECALC_SELECT);
}
WM_event_add_notifier(C, NC_GEOM | ND_SELECT, ob->data);
@@ -115,18 +115,13 @@ void paintface_flush_flags(struct bContext *C, Object *ob, short flag)
void paintface_hide(bContext *C, Object *ob, const bool unselected)
{
- Mesh *me;
- MPoly *mpoly;
- int a;
-
- me = BKE_mesh_from_object(ob);
- if (me == NULL || me->totpoly == 0) {
+ Mesh *me = BKE_mesh_from_object(ob);
+ if (me == nullptr || me->totpoly == 0) {
return;
}
- mpoly = me->mpoly;
- a = me->totpoly;
- while (a--) {
+ for (int i = 0; i < me->totpoly; i++) {
+ MPoly *mpoly = &me->mpoly[i];
if ((mpoly->flag & ME_HIDE) == 0) {
if (((mpoly->flag & ME_FACE_SEL) == 0) == unselected) {
mpoly->flag |= ME_HIDE;
@@ -136,8 +131,6 @@ void paintface_hide(bContext *C, Object *ob, const bool unselected)
if (mpoly->flag & ME_HIDE) {
mpoly->flag &= ~ME_FACE_SEL;
}
-
- mpoly++;
}
BKE_mesh_flush_hidden_from_polys(me);
@@ -147,23 +140,17 @@ void paintface_hide(bContext *C, Object *ob, const bool unselected)
void paintface_reveal(bContext *C, Object *ob, const bool select)
{
- Mesh *me;
- MPoly *mpoly;
- int a;
-
- me = BKE_mesh_from_object(ob);
- if (me == NULL || me->totpoly == 0) {
+ Mesh *me = BKE_mesh_from_object(ob);
+ if (me == nullptr || me->totpoly == 0) {
return;
}
- mpoly = me->mpoly;
- a = me->totpoly;
- while (a--) {
+ for (int i = 0; i < me->totpoly; i++) {
+ MPoly *mpoly = &me->mpoly[i];
if (mpoly->flag & ME_HIDE) {
SET_FLAG_FROM_TEST(mpoly->flag, select, ME_FACE_SEL);
mpoly->flag &= ~ME_HIDE;
}
- mpoly++;
}
BKE_mesh_flush_hidden_from_polys(me);
@@ -171,13 +158,10 @@ void paintface_reveal(bContext *C, Object *ob, const bool select)
paintface_flush_flags(C, ob, SELECT | ME_HIDE);
}
-/* Set tface seams based on edge data, uses hash table to find seam edges. */
+/* Set object-mode face selection seams based on edge data, uses hash table to find seam edges. */
static void select_linked_tfaces_with_seams(Mesh *me, const uint index, const bool select)
{
- MPoly *mp;
- MLoop *ml;
- int a, b;
bool do_it = true;
bool mark = false;
@@ -186,20 +170,20 @@ static void select_linked_tfaces_with_seams(Mesh *me, const uint index, const bo
if (index != (uint)-1) {
/* only put face under cursor in array */
- mp = &me->mpoly[index];
+ MPoly *mp = &me->mpoly[index];
BKE_mesh_poly_edgebitmap_insert(edge_tag, mp, me->mloop + mp->loopstart);
BLI_BITMAP_ENABLE(poly_tag, index);
}
else {
/* fill array by selection */
- mp = me->mpoly;
- for (a = 0; a < me->totpoly; a++, mp++) {
+ for (int i = 0; i < me->totpoly; i++) {
+ MPoly *mp = &me->mpoly[i];
if (mp->flag & ME_HIDE) {
/* pass */
}
else if (mp->flag & ME_FACE_SEL) {
BKE_mesh_poly_edgebitmap_insert(edge_tag, mp, me->mloop + mp->loopstart);
- BLI_BITMAP_ENABLE(poly_tag, a);
+ BLI_BITMAP_ENABLE(poly_tag, i);
}
}
}
@@ -208,17 +192,17 @@ static void select_linked_tfaces_with_seams(Mesh *me, const uint index, const bo
do_it = false;
/* expand selection */
- mp = me->mpoly;
- for (a = 0; a < me->totpoly; a++, mp++) {
+ for (int i = 0; i < me->totpoly; i++) {
+ MPoly *mp = &me->mpoly[i];
if (mp->flag & ME_HIDE) {
continue;
}
- if (!BLI_BITMAP_TEST(poly_tag, a)) {
+ if (!BLI_BITMAP_TEST(poly_tag, i)) {
mark = false;
- ml = me->mloop + mp->loopstart;
- for (b = 0; b < mp->totloop; b++, ml++) {
+ MLoop *ml = me->mloop + mp->loopstart;
+ for (int b = 0; b < mp->totloop; b++, ml++) {
if ((me->medge[ml->e].flag & ME_SEAM) == 0) {
if (BLI_BITMAP_TEST(edge_tag, ml->e)) {
mark = true;
@@ -228,7 +212,7 @@ static void select_linked_tfaces_with_seams(Mesh *me, const uint index, const bo
}
if (mark) {
- BLI_BITMAP_ENABLE(poly_tag, a);
+ BLI_BITMAP_ENABLE(poly_tag, i);
BKE_mesh_poly_edgebitmap_insert(edge_tag, mp, me->mloop + mp->loopstart);
do_it = true;
}
@@ -238,8 +222,9 @@ static void select_linked_tfaces_with_seams(Mesh *me, const uint index, const bo
MEM_freeN(edge_tag);
- for (a = 0, mp = me->mpoly; a < me->totpoly; a++, mp++) {
- if (BLI_BITMAP_TEST(poly_tag, a)) {
+ for (int i = 0; i < me->totpoly; i++) {
+ MPoly *mp = &me->mpoly[i];
+ if (BLI_BITMAP_TEST(poly_tag, i)) {
SET_FLAG_FROM_TEST(mp->flag, select, ME_FACE_SEL);
}
}
@@ -249,11 +234,10 @@ static void select_linked_tfaces_with_seams(Mesh *me, const uint index, const bo
void paintface_select_linked(bContext *C, Object *ob, const int mval[2], const bool select)
{
- Mesh *me;
uint index = (uint)-1;
- me = BKE_mesh_from_object(ob);
- if (me == NULL || me->totpoly == 0) {
+ Mesh *me = BKE_mesh_from_object(ob);
+ if (me == nullptr || me->totpoly == 0) {
return;
}
@@ -270,34 +254,27 @@ void paintface_select_linked(bContext *C, Object *ob, const int mval[2], const b
bool paintface_deselect_all_visible(bContext *C, Object *ob, int action, bool flush_flags)
{
- Mesh *me;
- MPoly *mpoly;
- int a;
-
- me = BKE_mesh_from_object(ob);
- if (me == NULL) {
+ Mesh *me = BKE_mesh_from_object(ob);
+ if (me == nullptr) {
return false;
}
if (action == SEL_TOGGLE) {
action = SEL_SELECT;
- mpoly = me->mpoly;
- a = me->totpoly;
- while (a--) {
+ for (int i = 0; i < me->totpoly; i++) {
+ MPoly *mpoly = &me->mpoly[i];
if ((mpoly->flag & ME_HIDE) == 0 && mpoly->flag & ME_FACE_SEL) {
action = SEL_DESELECT;
break;
}
- mpoly++;
}
}
bool changed = false;
- mpoly = me->mpoly;
- a = me->totpoly;
- while (a--) {
+ for (int i = 0; i < me->totpoly; i++) {
+ MPoly *mpoly = &me->mpoly[i];
if ((mpoly->flag & ME_HIDE) == 0) {
switch (action) {
case SEL_SELECT:
@@ -318,7 +295,6 @@ bool paintface_deselect_all_visible(bContext *C, Object *ob, int action, bool fl
break;
}
}
- mpoly++;
}
if (changed) {
@@ -331,30 +307,25 @@ bool paintface_deselect_all_visible(bContext *C, Object *ob, int action, bool fl
bool paintface_minmax(Object *ob, float r_min[3], float r_max[3])
{
- const Mesh *me;
- const MPoly *mp;
- const MLoop *ml;
- const MVert *mvert;
- int a, b;
bool ok = false;
float vec[3], bmat[3][3];
- me = BKE_mesh_from_object(ob);
+ const Mesh *me = BKE_mesh_from_object(ob);
if (!me || !me->mloopuv) {
return ok;
}
+ const MVert *mvert = me->mvert;
copy_m3_m4(bmat, ob->obmat);
- mvert = me->mvert;
- mp = me->mpoly;
- for (a = me->totpoly; a > 0; a--, mp++) {
+ for (int i = 0; i < me->totpoly; i++) {
+ MPoly *mp = &me->mpoly[i];
if (mp->flag & ME_HIDE || !(mp->flag & ME_FACE_SEL)) {
continue;
}
- ml = me->mloop + mp->loopstart;
- for (b = 0; b < mp->totloop; b++, ml++) {
+ const MLoop *ml = me->mloop + mp->loopstart;
+ for (int b = 0; b < mp->totloop; b++, ml++) {
mul_v3_m3v3(vec, bmat, mvert[ml->v].co);
add_v3_v3v3(vec, vec, ob->obmat[3]);
minmax_v3v3_v3(r_min, r_max, vec);
@@ -366,19 +337,18 @@ bool paintface_minmax(Object *ob, float r_min[3], float r_max[3])
return ok;
}
-bool paintface_mouse_select(struct bContext *C,
+bool paintface_mouse_select(bContext *C,
const int mval[2],
- const struct SelectPick_Params *params,
+ const SelectPick_Params *params,
Object *ob)
{
- Mesh *me;
- MPoly *mpoly_sel = NULL;
+ MPoly *mpoly_sel = nullptr;
uint index;
bool changed = false;
bool found = false;
/* Get the face under the cursor */
- me = BKE_mesh_from_object(ob);
+ Mesh *me = BKE_mesh_from_object(ob);
if (ED_mesh_pick_face(C, ob, mval, ED_MESH_PICK_DEFAULT_FACE_DIST, &index)) {
if (index < me->totpoly) {
@@ -444,11 +414,11 @@ void paintvert_flush_flags(Object *ob)
Mesh *me = BKE_mesh_from_object(ob);
Mesh *me_eval = BKE_object_get_evaluated_mesh(ob);
MVert *mvert_eval, *mv;
- const int *index_array = NULL;
+ const int *index_array = nullptr;
int totvert;
int i;
- if (me == NULL) {
+ if (me == nullptr) {
return;
}
@@ -456,11 +426,11 @@ void paintvert_flush_flags(Object *ob)
* since this could become slow for realtime updates (circle-select for eg) */
BKE_mesh_flush_select_from_verts(me);
- if (me_eval == NULL) {
+ if (me_eval == nullptr) {
return;
}
- index_array = CustomData_get_layer(&me_eval->vdata, CD_ORIGINDEX);
+ index_array = (const int *)CustomData_get_layer(&me_eval->vdata, CD_ORIGINDEX);
mvert_eval = me_eval->mvert;
totvert = me_eval->totvert;
@@ -485,41 +455,34 @@ void paintvert_flush_flags(Object *ob)
BKE_mesh_batch_cache_dirty_tag(me, BKE_MESH_BATCH_DIRTY_ALL);
}
-void paintvert_tag_select_update(struct bContext *C, struct Object *ob)
+void paintvert_tag_select_update(bContext *C, Object *ob)
{
- DEG_id_tag_update(ob->data, ID_RECALC_COPY_ON_WRITE | ID_RECALC_SELECT);
+ DEG_id_tag_update(static_cast<ID *>(ob->data), ID_RECALC_COPY_ON_WRITE | ID_RECALC_SELECT);
WM_event_add_notifier(C, NC_GEOM | ND_SELECT, ob->data);
}
bool paintvert_deselect_all_visible(Object *ob, int action, bool flush_flags)
{
- Mesh *me;
- MVert *mvert;
- int a;
-
- me = BKE_mesh_from_object(ob);
- if (me == NULL) {
+ Mesh *me = BKE_mesh_from_object(ob);
+ if (me == nullptr) {
return false;
}
if (action == SEL_TOGGLE) {
action = SEL_SELECT;
- mvert = me->mvert;
- a = me->totvert;
- while (a--) {
+ for (int i = 0; i < me->totvert; i++) {
+ MVert *mvert = &me->mvert[i];
if ((mvert->flag & ME_HIDE) == 0 && mvert->flag & SELECT) {
action = SEL_DESELECT;
break;
}
- mvert++;
}
}
bool changed = false;
- mvert = me->mvert;
- a = me->totvert;
- while (a--) {
+ for (int i = 0; i < me->totvert; i++) {
+ MVert *mvert = &me->mvert[i];
if ((mvert->flag & ME_HIDE) == 0) {
switch (action) {
case SEL_SELECT:
@@ -540,7 +503,6 @@ bool paintvert_deselect_all_visible(Object *ob, int action, bool flush_flags)
break;
}
}
- mvert++;
}
if (changed) {
@@ -565,11 +527,8 @@ bool paintvert_deselect_all_visible(Object *ob, int action, bool flush_flags)
void paintvert_select_ungrouped(Object *ob, bool extend, bool flush_flags)
{
Mesh *me = BKE_mesh_from_object(ob);
- MVert *mv;
- MDeformVert *dv;
- int a, tot;
- if (me == NULL || me->dvert == NULL) {
+ if (me == nullptr || me->dvert == nullptr) {
return;
}
@@ -577,12 +536,11 @@ void paintvert_select_ungrouped(Object *ob, bool extend, bool flush_flags)
paintvert_deselect_all_visible(ob, SEL_DESELECT, false);
}
- dv = me->dvert;
- tot = me->totvert;
-
- for (a = 0, mv = me->mvert; a < tot; a++, mv++, dv++) {
+ for (int i = 0; i < me->totvert; i++) {
+ MVert *mv = &me->mvert[i];
+ MDeformVert *dv = &me->dvert[i];
if ((mv->flag & ME_HIDE) == 0) {
- if (dv->dw == NULL) {
+ if (dv->dw == nullptr) {
/* if null weight then not grouped */
mv->flag |= SELECT;
}
diff --git a/source/blender/editors/mesh/editmesh_add.c b/source/blender/editors/mesh/editmesh_add.c
index b2f33428b21..57e0d04727c 100644
--- a/source/blender/editors/mesh/editmesh_add.c
+++ b/source/blender/editors/mesh/editmesh_add.c
@@ -113,7 +113,7 @@ static int add_primitive_plane_exec(bContext *C, wmOperator *op)
em = BKE_editmesh_from_object(obedit);
if (calc_uvs) {
- ED_mesh_uv_texture_ensure(obedit->data, NULL);
+ ED_mesh_uv_ensure(obedit->data, NULL);
}
if (!EDBM_op_call_and_selectf(
@@ -178,7 +178,7 @@ static int add_primitive_cube_exec(bContext *C, wmOperator *op)
em = BKE_editmesh_from_object(obedit);
if (calc_uvs) {
- ED_mesh_uv_texture_ensure(obedit->data, NULL);
+ ED_mesh_uv_ensure(obedit->data, NULL);
}
if (!EDBM_op_call_and_selectf(em,
@@ -252,7 +252,7 @@ static int add_primitive_circle_exec(bContext *C, wmOperator *op)
em = BKE_editmesh_from_object(obedit);
if (calc_uvs) {
- ED_mesh_uv_texture_ensure(obedit->data, NULL);
+ ED_mesh_uv_ensure(obedit->data, NULL);
}
if (!EDBM_op_call_and_selectf(
@@ -324,7 +324,7 @@ static int add_primitive_cylinder_exec(bContext *C, wmOperator *op)
em = BKE_editmesh_from_object(obedit);
if (calc_uvs) {
- ED_mesh_uv_texture_ensure(obedit->data, NULL);
+ ED_mesh_uv_ensure(obedit->data, NULL);
}
if (!EDBM_op_call_and_selectf(em,
@@ -400,7 +400,7 @@ static int add_primitive_cone_exec(bContext *C, wmOperator *op)
em = BKE_editmesh_from_object(obedit);
if (calc_uvs) {
- ED_mesh_uv_texture_ensure(obedit->data, NULL);
+ ED_mesh_uv_ensure(obedit->data, NULL);
}
if (!EDBM_op_call_and_selectf(em,
@@ -476,7 +476,7 @@ static int add_primitive_grid_exec(bContext *C, wmOperator *op)
em = BKE_editmesh_from_object(obedit);
if (calc_uvs) {
- ED_mesh_uv_texture_ensure(obedit->data, NULL);
+ ED_mesh_uv_ensure(obedit->data, NULL);
}
if (!EDBM_op_call_and_selectf(
@@ -553,7 +553,7 @@ static int add_primitive_monkey_exec(bContext *C, wmOperator *op)
em = BKE_editmesh_from_object(obedit);
if (calc_uvs) {
- ED_mesh_uv_texture_ensure(obedit->data, NULL);
+ ED_mesh_uv_ensure(obedit->data, NULL);
}
if (!EDBM_op_call_and_selectf(em,
@@ -614,7 +614,7 @@ static int add_primitive_uvsphere_exec(bContext *C, wmOperator *op)
em = BKE_editmesh_from_object(obedit);
if (calc_uvs) {
- ED_mesh_uv_texture_ensure(obedit->data, NULL);
+ ED_mesh_uv_ensure(obedit->data, NULL);
}
if (!EDBM_op_call_and_selectf(
@@ -682,7 +682,7 @@ static int add_primitive_icosphere_exec(bContext *C, wmOperator *op)
em = BKE_editmesh_from_object(obedit);
if (calc_uvs) {
- ED_mesh_uv_texture_ensure(obedit->data, NULL);
+ ED_mesh_uv_ensure(obedit->data, NULL);
}
if (!EDBM_op_call_and_selectf(
diff --git a/source/blender/editors/mesh/editmesh_add_gizmo.c b/source/blender/editors/mesh/editmesh_add_gizmo.c
index d0f37314661..f5090c0143d 100644
--- a/source/blender/editors/mesh/editmesh_add_gizmo.c
+++ b/source/blender/editors/mesh/editmesh_add_gizmo.c
@@ -328,7 +328,7 @@ static int add_primitive_cube_gizmo_exec(bContext *C, wmOperator *op)
const bool calc_uvs = RNA_boolean_get(op->ptr, "calc_uvs");
if (calc_uvs) {
- ED_mesh_uv_texture_ensure(obedit->data, NULL);
+ ED_mesh_uv_ensure(obedit->data, NULL);
}
if (!EDBM_op_call_and_selectf(em,
diff --git a/source/blender/editors/mesh/editmesh_bevel.c b/source/blender/editors/mesh/editmesh_bevel.c
index 969d5b5912c..e7891450bd6 100644
--- a/source/blender/editors/mesh/editmesh_bevel.c
+++ b/source/blender/editors/mesh/editmesh_bevel.c
@@ -669,7 +669,7 @@ static int edbm_bevel_modal(bContext *C, wmOperator *op, const wmEvent *event)
short etype = event->type;
short eval = event->val;
- /* When activated from toolbar, need to convert leftmouse release to confirm */
+ /* When activated from toolbar, need to convert left-mouse release to confirm. */
if (ELEM(etype, LEFTMOUSE, opdata->launch_event) && (eval == KM_RELEASE) &&
RNA_boolean_get(op->ptr, "release_confirm")) {
etype = EVT_MODAL_MAP;
diff --git a/source/blender/editors/mesh/editmesh_intersect.c b/source/blender/editors/mesh/editmesh_intersect.c
index 2642a613e92..166eb40a7db 100644
--- a/source/blender/editors/mesh/editmesh_intersect.c
+++ b/source/blender/editors/mesh/editmesh_intersect.c
@@ -99,8 +99,8 @@ static void edbm_intersect_select(BMEditMesh *em, struct Mesh *me, bool do_selec
BM_edge_select_set(em->bm, e, true);
}
}
+ EDBM_selectmode_flush(em);
}
- EDBM_select_flush(em);
}
EDBM_update(me,
diff --git a/source/blender/editors/mesh/editmesh_knife.c b/source/blender/editors/mesh/editmesh_knife.c
index ee40431c101..5680865ae67 100644
--- a/source/blender/editors/mesh/editmesh_knife.c
+++ b/source/blender/editors/mesh/editmesh_knife.c
@@ -190,6 +190,22 @@ typedef struct KnifeBVH {
} KnifeBVH;
+/** Additional per-object data. */
+typedef struct KnifeObjectInfo {
+ const float (*cagecos)[3];
+
+ /**
+ * Optionally allocate triangle indices, these are needed for non-interactive knife
+ * projection as multiple cuts are made without the BVH being updated.
+ * Using these indices the it's possible to access `cagecos` even if the face has been cut
+ * and the loops in `em->looptris` no longer refer to the original triangles, see: T97153.
+ */
+ const int (*tri_indices)[3];
+
+ /** Only assigned for convenient access. */
+ BMEditMesh *em;
+} KnifeObjectInfo;
+
/* struct for properties used while drawing */
typedef struct KnifeTool_OpData {
ARegion *region; /* Region that knifetool was activated in. */
@@ -203,6 +219,9 @@ typedef struct KnifeTool_OpData {
Object **objects;
uint objects_len;
+ /** Array `objects_len` length of additional per-object data. */
+ KnifeObjectInfo *objects_info;
+
MemArena *arena;
/* Reused for edge-net filling. */
@@ -220,7 +239,6 @@ typedef struct KnifeTool_OpData {
GHash *facetrimap;
KnifeBVH bvh;
- const float (**cagecos)[3];
BLI_mempool *kverts;
BLI_mempool *kedges;
@@ -359,45 +377,45 @@ static void knifetool_raycast_planes(const KnifeTool_OpData *kcd, float r_v1[3],
kcd->vc.rv3d->persmat, planes[2], planes[0], planes[1], planes[3], NULL, NULL);
/* Ray-cast all planes. */
+ float ray_dir[3];
+ float ray_hit_best[2][3] = {{UNPACK3(kcd->prev.cage)}, {UNPACK3(kcd->curr.cage)}};
+ float lambda_best[2] = {-FLT_MAX, FLT_MAX};
+ int i;
+
{
- float ray_dir[3];
- float ray_hit_best[2][3] = {{UNPACK3(kcd->prev.cage)}, {UNPACK3(kcd->curr.cage)}};
- float lambda_best[2] = {-FLT_MAX, FLT_MAX};
- int i;
+ float curr_cage_adjust[3];
+ float co_depth[3];
- {
- float curr_cage_adjust[3];
- float co_depth[3];
+ copy_v3_v3(co_depth, kcd->prev.cage);
+ ED_view3d_win_to_3d(kcd->vc.v3d, kcd->region, co_depth, kcd->curr.mval, curr_cage_adjust);
- copy_v3_v3(co_depth, kcd->prev.cage);
- ED_view3d_win_to_3d(kcd->vc.v3d, kcd->region, co_depth, kcd->curr.mval, curr_cage_adjust);
+ sub_v3_v3v3(ray_dir, curr_cage_adjust, kcd->prev.cage);
+ }
- sub_v3_v3v3(ray_dir, curr_cage_adjust, kcd->prev.cage);
+ for (i = 0; i < 4; i++) {
+ float ray_hit[3];
+ float lambda_test;
+ if (!isect_ray_plane_v3(kcd->prev.cage, ray_dir, planes[i], &lambda_test, false)) {
+ continue;
}
- for (i = 0; i < 4; i++) {
- float ray_hit[3];
- float lambda_test;
- if (isect_ray_plane_v3(kcd->prev.cage, ray_dir, planes[i], &lambda_test, false)) {
- madd_v3_v3v3fl(ray_hit, kcd->prev.cage, ray_dir, lambda_test);
- if (lambda_test < 0.0f) {
- if (lambda_test > lambda_best[0]) {
- copy_v3_v3(ray_hit_best[0], ray_hit);
- lambda_best[0] = lambda_test;
- }
- }
- else {
- if (lambda_test < lambda_best[1]) {
- copy_v3_v3(ray_hit_best[1], ray_hit);
- lambda_best[1] = lambda_test;
- }
- }
+ madd_v3_v3v3fl(ray_hit, kcd->prev.cage, ray_dir, lambda_test);
+ if (lambda_test < 0.0f) {
+ if (lambda_test > lambda_best[0]) {
+ copy_v3_v3(ray_hit_best[0], ray_hit);
+ lambda_best[0] = lambda_test;
+ }
+ }
+ else {
+ if (lambda_test < lambda_best[1]) {
+ copy_v3_v3(ray_hit_best[1], ray_hit);
+ lambda_best[1] = lambda_test;
}
}
-
- copy_v3_v3(r_v1, ray_hit_best[0]);
- copy_v3_v3(r_v2, ray_hit_best[1]);
}
+
+ copy_v3_v3(r_v1, ray_hit_best[0]);
+ copy_v3_v3(r_v2, ray_hit_best[1]);
}
static void knifetool_draw_angle_snapping(const KnifeTool_OpData *kcd)
@@ -422,43 +440,45 @@ static void knifetool_draw_angle_snapping(const KnifeTool_OpData *kcd)
static void knifetool_draw_orientation_locking(const KnifeTool_OpData *kcd)
{
- if (!compare_v3v3(kcd->prev.cage, kcd->curr.cage, KNIFE_FLT_EPSBIG)) {
- float v1[3], v2[3];
+ if (compare_v3v3(kcd->prev.cage, kcd->curr.cage, KNIFE_FLT_EPSBIG)) {
+ return;
+ }
- /* This is causing buggy behavior when `prev.cage` and `curr.cage` are too close together. */
- knifetool_raycast_planes(kcd, v1, v2);
+ float v1[3], v2[3];
- uint pos = GPU_vertformat_attr_add(immVertexFormat(), "pos", GPU_COMP_F32, 3, GPU_FETCH_FLOAT);
- immBindBuiltinProgram(GPU_SHADER_3D_UNIFORM_COLOR);
+ /* This is causing buggy behavior when `prev.cage` and `curr.cage` are too close together. */
+ knifetool_raycast_planes(kcd, v1, v2);
- switch (kcd->constrain_axis) {
- case KNF_CONSTRAIN_AXIS_X: {
- immUniformColor3ubv(kcd->colors.xaxis);
- break;
- }
- case KNF_CONSTRAIN_AXIS_Y: {
- immUniformColor3ubv(kcd->colors.yaxis);
- break;
- }
- case KNF_CONSTRAIN_AXIS_Z: {
- immUniformColor3ubv(kcd->colors.zaxis);
- break;
- }
- default: {
- immUniformColor3ubv(kcd->colors.axis_extra);
- break;
- }
+ uint pos = GPU_vertformat_attr_add(immVertexFormat(), "pos", GPU_COMP_F32, 3, GPU_FETCH_FLOAT);
+ immBindBuiltinProgram(GPU_SHADER_3D_UNIFORM_COLOR);
+
+ switch (kcd->constrain_axis) {
+ case KNF_CONSTRAIN_AXIS_X: {
+ immUniformColor3ubv(kcd->colors.xaxis);
+ break;
}
+ case KNF_CONSTRAIN_AXIS_Y: {
+ immUniformColor3ubv(kcd->colors.yaxis);
+ break;
+ }
+ case KNF_CONSTRAIN_AXIS_Z: {
+ immUniformColor3ubv(kcd->colors.zaxis);
+ break;
+ }
+ default: {
+ immUniformColor3ubv(kcd->colors.axis_extra);
+ break;
+ }
+ }
- GPU_line_width(2.0);
+ GPU_line_width(2.0);
- immBegin(GPU_PRIM_LINES, 2);
- immVertex3fv(pos, v1);
- immVertex3fv(pos, v2);
- immEnd();
+ immBegin(GPU_PRIM_LINES, 2);
+ immVertex3fv(pos, v1);
+ immVertex3fv(pos, v2);
+ immEnd();
- immUnbindProgram();
- }
+ immUnbindProgram();
}
static void knifetool_draw_visible_distances(const KnifeTool_OpData *kcd)
@@ -1134,6 +1154,52 @@ static void knife_update_header(bContext *C, wmOperator *op, KnifeTool_OpData *k
/** \} */
/* -------------------------------------------------------------------- */
+/** \name Knife Object Info Accessors (#KnifeObjectInfo)
+ * \{ */
+
+static const int *knife_bm_tri_index_get(const KnifeTool_OpData *kcd,
+ int base_index,
+ int tri_index,
+ int tri_index_buf[3])
+{
+ const KnifeObjectInfo *obinfo = &kcd->objects_info[base_index];
+ if (obinfo->tri_indices) {
+ return obinfo->tri_indices[tri_index];
+ }
+ for (int i = 0; i < 3; i++) {
+ tri_index_buf[i] = BM_elem_index_get(obinfo->em->looptris[tri_index][i]->v);
+ }
+ return tri_index_buf;
+}
+
+static void knife_bm_tri_cagecos_get(const KnifeTool_OpData *kcd,
+ int base_index,
+ int tri_index,
+ float cos[3][3])
+{
+ const KnifeObjectInfo *obinfo = &kcd->objects_info[base_index];
+ int tri_ind_buf[3];
+ const int *tri_ind = knife_bm_tri_index_get(kcd, base_index, tri_index, tri_ind_buf);
+ for (int i = 0; i < 3; i++) {
+ copy_v3_v3(cos[i], obinfo->cagecos[tri_ind[i]]);
+ }
+}
+
+static void knife_bm_tri_cagecos_get_worldspace(const KnifeTool_OpData *kcd,
+ int base_index,
+ int tri_index,
+ float cos[3][3])
+{
+ knife_bm_tri_cagecos_get(kcd, base_index, tri_index, cos);
+ const Object *ob = kcd->objects[base_index];
+ for (int i = 0; i < 3; i++) {
+ mul_m4_v3(ob->obmat, cos[i]);
+ }
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
/** \name Knife BVH Utils
* \{ */
@@ -1162,7 +1228,6 @@ static void knife_bvh_init(KnifeTool_OpData *kcd)
}
/* Construct BVH Tree. */
- float cos[3][3];
const float epsilon = FLT_EPSILON * 2.0f;
int tottri = 0;
int ob_tottri = 0;
@@ -1220,16 +1285,9 @@ static void knife_bvh_init(KnifeTool_OpData *kcd)
continue;
}
- copy_v3_v3(cos[0], kcd->cagecos[b][BM_elem_index_get(looptris[i][0]->v)]);
- copy_v3_v3(cos[1], kcd->cagecos[b][BM_elem_index_get(looptris[i][1]->v)]);
- copy_v3_v3(cos[2], kcd->cagecos[b][BM_elem_index_get(looptris[i][2]->v)]);
-
- /* Convert to world-space. */
- mul_m4_v3(ob->obmat, cos[0]);
- mul_m4_v3(ob->obmat, cos[1]);
- mul_m4_v3(ob->obmat, cos[2]);
-
- BLI_bvhtree_insert(kcd->bvh.tree, i + tottri, (float *)cos, 3);
+ float tri_cos[3][3];
+ knife_bm_tri_cagecos_get_worldspace(kcd, b, i, tri_cos);
+ BLI_bvhtree_insert(kcd->bvh.tree, i + tottri, &tri_cos[0][0], 3);
}
tottri += em->tottri;
@@ -1252,6 +1310,10 @@ static void knife_bvh_raycast_cb(void *userdata,
const BVHTreeRay *ray,
BVHTreeRayHit *hit)
{
+ if (index == -1) {
+ return;
+ }
+
KnifeTool_OpData *kcd = userdata;
BMLoop **ltri;
Object *ob;
@@ -1260,65 +1322,55 @@ static void knife_bvh_raycast_cb(void *userdata,
float dist, uv[2];
bool isect;
int tottri;
- float tri_cos[3][3];
- if (index != -1) {
- tottri = 0;
- uint b = 0;
- for (; b < kcd->objects_len; b++) {
- index -= tottri;
- ob = kcd->objects[b];
- em = BKE_editmesh_from_object(ob);
- tottri = em->tottri;
- if (index < tottri) {
- ltri = em->looptris[index];
- break;
- }
+ tottri = 0;
+ uint b = 0;
+ for (; b < kcd->objects_len; b++) {
+ index -= tottri;
+ ob = kcd->objects[b];
+ em = BKE_editmesh_from_object(ob);
+ tottri = em->tottri;
+ if (index < tottri) {
+ ltri = em->looptris[index];
+ break;
}
+ }
- if (kcd->bvh.filter_cb) {
- if (!kcd->bvh.filter_cb(ltri[0]->f, kcd->bvh.filter_data)) {
- return;
- }
+ if (kcd->bvh.filter_cb) {
+ if (!kcd->bvh.filter_cb(ltri[0]->f, kcd->bvh.filter_data)) {
+ return;
}
+ }
- copy_v3_v3(tri_cos[0], kcd->cagecos[b][BM_elem_index_get(ltri[0]->v)]);
- copy_v3_v3(tri_cos[1], kcd->cagecos[b][BM_elem_index_get(ltri[1]->v)]);
- copy_v3_v3(tri_cos[2], kcd->cagecos[b][BM_elem_index_get(ltri[2]->v)]);
- mul_m4_v3(ob->obmat, tri_cos[0]);
- mul_m4_v3(ob->obmat, tri_cos[1]);
- mul_m4_v3(ob->obmat, tri_cos[2]);
-
- isect =
- (ray->radius > 0.0f ?
- isect_ray_tri_epsilon_v3(ray->origin,
- ray->direction,
- tri_cos[0],
- tri_cos[1],
- tri_cos[2],
- &dist,
- uv,
- ray->radius) :
+ float tri_cos[3][3];
+ knife_bm_tri_cagecos_get_worldspace(kcd, b, index, tri_cos);
+ isect = (ray->radius > 0.0f ?
+ isect_ray_tri_epsilon_v3(
+ ray->origin, ray->direction, UNPACK3(tri_cos), &dist, uv, ray->radius) :
#ifdef USE_KDOPBVH_WATERTIGHT
- isect_ray_tri_watertight_v3(
- ray->origin, ray->isect_precalc, tri_cos[0], tri_cos[1], tri_cos[2], &dist, uv));
+ isect_ray_tri_watertight_v3(
+ ray->origin, ray->isect_precalc, UNPACK3(tri_cos), &dist, uv));
#else
- isect_ray_tri_v3(
- ray->origin, ray->direction, tri_cos[0], tri_cos[1], tri_cos[2], &dist, uv));
+ isect_ray_tri_v3(ray->origin, ray->direction, UNPACK3(tri_cos), &dist, uv);
#endif
- if (isect && dist < hit->dist) {
- hit->dist = dist;
- hit->index = index;
+ if (isect && dist < hit->dist) {
+ madd_v3_v3v3fl(hit->co, ray->origin, ray->direction, dist);
- copy_v3_v3(hit->no, ltri[0]->f->no);
+ /* Discard clipped points. */
+ if (RV3D_CLIPPING_ENABLED(kcd->vc.v3d, kcd->vc.rv3d) &&
+ ED_view3d_clipping_test(kcd->vc.rv3d, hit->co, false)) {
+ return;
+ }
- madd_v3_v3v3fl(hit->co, ray->origin, ray->direction, dist);
+ hit->dist = dist;
+ hit->index = index;
- kcd->bvh.looptris = em->looptris;
- copy_v2_v2(kcd->bvh.uv, uv);
- kcd->bvh.base_index = b;
- }
+ copy_v3_v3(hit->no, ltri[0]->f->no);
+
+ kcd->bvh.looptris = em->looptris;
+ copy_v2_v2(kcd->bvh.uv, uv);
+ kcd->bvh.base_index = b;
}
}
@@ -1333,7 +1385,6 @@ static BMFace *knife_bvh_raycast(KnifeTool_OpData *kcd,
uint *r_base_index)
{
BMFace *face;
- BMLoop **ltri;
BVHTreeRayHit hit;
const float dist = r_dist ? *r_dist : FLT_MAX;
hit.dist = dist;
@@ -1347,8 +1398,9 @@ static BMFace *knife_bvh_raycast(KnifeTool_OpData *kcd,
/* Hits returned in world space. */
if (r_hitout) {
- ltri = kcd->bvh.looptris[hit.index];
- interp_v3_v3v3v3_uv(r_hitout, ltri[0]->v->co, ltri[1]->v->co, ltri[2]->v->co, kcd->bvh.uv);
+ float tri_cos[3][3];
+ knife_bm_tri_cagecos_get_worldspace(kcd, kcd->bvh.base_index, hit.index, tri_cos);
+ interp_v3_v3v3v3_uv(r_hitout, UNPACK3(tri_cos), kcd->bvh.uv);
if (r_cagehit) {
copy_v3_v3(r_cagehit, hit.co);
@@ -1384,7 +1436,6 @@ static BMFace *knife_bvh_raycast_filter(KnifeTool_OpData *kcd,
kcd->bvh.filter_data = filter_userdata;
BMFace *face;
- BMLoop **ltri;
BVHTreeRayHit hit;
const float dist = r_dist ? *r_dist : FLT_MAX;
hit.dist = dist;
@@ -1401,8 +1452,9 @@ static BMFace *knife_bvh_raycast_filter(KnifeTool_OpData *kcd,
/* Hits returned in world space. */
if (r_hitout) {
- ltri = kcd->bvh.looptris[hit.index];
- interp_v3_v3v3v3_uv(r_hitout, ltri[0]->v->co, ltri[1]->v->co, ltri[2]->v->co, kcd->bvh.uv);
+ float tri_cos[3][3];
+ knife_bm_tri_cagecos_get_worldspace(kcd, kcd->bvh.base_index, hit.index, tri_cos);
+ interp_v3_v3v3v3_uv(r_hitout, UNPACK3(tri_cos), kcd->bvh.uv);
if (r_cagehit) {
copy_v3_v3(r_cagehit, hit.co);
@@ -1684,7 +1736,7 @@ static KnifeVert *get_bm_knife_vert(KnifeTool_OpData *kcd, BMVert *v, Object *ob
BMFace *f;
if (BM_elem_index_get(v) >= 0) {
- cageco = kcd->cagecos[base_index][BM_elem_index_get(v)];
+ cageco = kcd->objects_info[base_index].cagecos[BM_elem_index_get(v)];
}
else {
cageco = v->co;
@@ -1928,29 +1980,30 @@ static void prepare_linehits_for_cut(KnifeTool_OpData *kcd)
* Also remove all but one of a series of vertex hits for the same vertex. */
for (int i = 0; i < n; i++) {
KnifeLineHit *lhi = &linehits[i];
- if (lhi->v) {
- for (int j = i - 1; j >= 0; j--) {
- KnifeLineHit *lhj = &linehits[j];
- if (!lhj->kfe || fabsf(lhi->l - lhj->l) > KNIFE_FLT_EPSBIG ||
- fabsf(lhi->m - lhj->m) > KNIFE_FLT_EPSBIG) {
- break;
- }
+ if (lhi->v == NULL) {
+ continue;
+ }
- if (lhi->kfe == lhj->kfe) {
- lhj->l = -1.0f;
- is_double = true;
- }
+ for (int j = i - 1; j >= 0; j--) {
+ KnifeLineHit *lhj = &linehits[j];
+ if (!lhj->kfe || fabsf(lhi->l - lhj->l) > KNIFE_FLT_EPSBIG ||
+ fabsf(lhi->m - lhj->m) > KNIFE_FLT_EPSBIG) {
+ break;
}
- for (int j = i + 1; j < n; j++) {
- KnifeLineHit *lhj = &linehits[j];
- if (fabsf(lhi->l - lhj->l) > KNIFE_FLT_EPSBIG ||
- fabsf(lhi->m - lhj->m) > KNIFE_FLT_EPSBIG) {
- break;
- }
- if ((lhj->kfe && (lhi->kfe == lhj->kfe)) || (lhi->v == lhj->v)) {
- lhj->l = -1.0f;
- is_double = true;
- }
+
+ if (lhi->kfe == lhj->kfe) {
+ lhj->l = -1.0f;
+ is_double = true;
+ }
+ }
+ for (int j = i + 1; j < n; j++) {
+ KnifeLineHit *lhj = &linehits[j];
+ if (fabsf(lhi->l - lhj->l) > KNIFE_FLT_EPSBIG || fabsf(lhi->m - lhj->m) > KNIFE_FLT_EPSBIG) {
+ break;
+ }
+ if ((lhj->kfe && (lhi->kfe == lhj->kfe)) || (lhi->v == lhj->v)) {
+ lhj->l = -1.0f;
+ is_double = true;
}
}
}
@@ -2222,11 +2275,12 @@ static void knife_make_face_cuts(KnifeTool_OpData *kcd, BMesh *bm, BMFace *f, Li
/* Remove dangling edges, not essential - but nice for users. */
for (i = 0; i < edge_array_len_orig; i++) {
- if (kfe_array[i]) {
- if (BM_edge_is_wire(kfe_array[i]->e)) {
- BM_edge_kill(bm, kfe_array[i]->e);
- kfe_array[i]->e = NULL;
- }
+ if (kfe_array[i] == NULL) {
+ continue;
+ }
+ if (BM_edge_is_wire(kfe_array[i]->e)) {
+ BM_edge_kill(bm, kfe_array[i]->e);
+ kfe_array[i]->e = NULL;
}
}
@@ -2538,34 +2592,30 @@ static bool knife_ray_intersect_face(KnifeTool_OpData *kcd,
BLI_assert(tri_i >= 0 && tri_i < tottri);
for (; tri_i < tottri; tri_i++) {
- float lv[3][3];
+ float tri_cos[3][3];
float ray_tri_uv[2];
tri = em->looptris[tri_i];
if (tri[0]->f != f) {
break;
}
- copy_v3_v3(lv[0], kcd->cagecos[base_index][BM_elem_index_get(tri[0]->v)]);
- copy_v3_v3(lv[1], kcd->cagecos[base_index][BM_elem_index_get(tri[1]->v)]);
- copy_v3_v3(lv[2], kcd->cagecos[base_index][BM_elem_index_get(tri[2]->v)]);
- mul_m4_v3(ob->obmat, lv[0]);
- mul_m4_v3(ob->obmat, lv[1]);
- mul_m4_v3(ob->obmat, lv[2]);
+
+ knife_bm_tri_cagecos_get_worldspace(kcd, base_index, tri_i, tri_cos);
/* Using epsilon test in case ray is directly through an internal
* tessellation edge and might not hit either tessellation tri with
* an exact test;
* We will exclude hits near real edges by a later test. */
if (isect_ray_tri_epsilon_v3(
- v1, raydir, lv[0], lv[1], lv[2], &lambda, ray_tri_uv, KNIFE_FLT_EPS)) {
+ v1, raydir, UNPACK3(tri_cos), &lambda, ray_tri_uv, KNIFE_FLT_EPS)) {
/* Check if line coplanar with tri. */
- normal_tri_v3(tri_norm, lv[0], lv[1], lv[2]);
- plane_from_point_normal_v3(tri_plane, lv[0], tri_norm);
+ normal_tri_v3(tri_norm, UNPACK3(tri_cos));
+ plane_from_point_normal_v3(tri_plane, tri_cos[0], tri_norm);
if ((dist_squared_to_plane_v3(v1, tri_plane) < KNIFE_FLT_EPS) &&
(dist_squared_to_plane_v3(v2, tri_plane) < KNIFE_FLT_EPS)) {
return false;
}
- interp_v3_v3v3v3_uv(hit_cageco, lv[0], lv[1], lv[2], ray_tri_uv);
+ interp_v3_v3v3v3_uv(hit_cageco, UNPACK3(tri_cos), ray_tri_uv);
/* Now check that far enough away from verts and edges. */
list = knife_get_face_kedges(kcd, ob, base_index, f);
for (ref = list->first; ref; ref = ref->next) {
@@ -2605,9 +2655,10 @@ static void calc_ortho_extent(KnifeTool_OpData *kcd)
ob = kcd->objects[b];
em = BKE_editmesh_from_object(ob);
- if (kcd->cagecos[b]) {
+ const float(*cagecos)[3] = kcd->objects_info[b].cagecos;
+ if (cagecos) {
for (int i = 0; i < em->bm->totvert; i++) {
- copy_v3_v3(ws, kcd->cagecos[b][i]);
+ copy_v3_v3(ws, cagecos[i]);
mul_m4_v3(ob->obmat, ws);
minmax_v3v3_v3(min, max, ws);
}
@@ -3763,7 +3814,7 @@ static void knife_reset_snap_angle_input(KnifeTool_OpData *kcd)
* If scene orientation is set to anything other than global it takes priority.
* Otherwise kcd->constrain_axis_mode is used.
*/
-static void knife_constrain_axis(bContext *C, KnifeTool_OpData *kcd)
+static void knife_constrain_axis(KnifeTool_OpData *kcd)
{
/* Obtain current mouse position in world space. */
float curr_cage_adjusted[3];
@@ -3772,7 +3823,7 @@ static void knife_constrain_axis(bContext *C, KnifeTool_OpData *kcd)
/* Constrain axes. */
Scene *scene = kcd->scene;
- ViewLayer *view_layer = CTX_data_view_layer(C);
+ ViewLayer *view_layer = kcd->vc.view_layer;
Object *obedit = (kcd->prev.ob) ? kcd->prev.ob : kcd->vc.obedit;
RegionView3D *rv3d = kcd->region->regiondata;
const short scene_orientation = BKE_scene_orientation_get_index(scene, SCE_ORIENT_DEFAULT);
@@ -3824,7 +3875,7 @@ static void knife_constrain_axis(bContext *C, KnifeTool_OpData *kcd)
* In this case the selection-buffer is used to select the face,
* then the closest `vert` or `edge` is set, and those will enable `is_co_set`.
*/
-static bool knife_snap_update_from_mval(bContext *C, KnifeTool_OpData *kcd, const float mval[2])
+static bool knife_snap_update_from_mval(KnifeTool_OpData *kcd, const float mval[2])
{
knife_pos_data_clear(&kcd->curr);
copy_v2_v2(kcd->curr.mval, mval);
@@ -3847,7 +3898,7 @@ static bool knife_snap_update_from_mval(bContext *C, KnifeTool_OpData *kcd, cons
}
if (kcd->axis_constrained) {
- knife_constrain_axis(C, kcd);
+ knife_constrain_axis(kcd);
}
}
@@ -3961,10 +4012,13 @@ static void knifetool_undo(KnifeTool_OpData *kcd)
/** \} */
/* -------------------------------------------------------------------- */
-/** \name #KnifeTool_OpData (#op->customdata) Init and Free
+/** \name #KnifeObjectInfo (#kcd->objects_info) Init and Free
* \{ */
-static void knifetool_init_cagecos(KnifeTool_OpData *kcd, Object *ob, uint base_index)
+static void knifetool_init_obinfo(KnifeTool_OpData *kcd,
+ Object *ob,
+ uint base_index,
+ bool use_tri_indices)
{
Scene *scene_eval = (Scene *)DEG_get_evaluated_id(kcd->vc.depsgraph, &kcd->scene->id);
@@ -3973,18 +4027,36 @@ static void knifetool_init_cagecos(KnifeTool_OpData *kcd, Object *ob, uint base_
BM_mesh_elem_index_ensure(em_eval->bm, BM_VERT);
- kcd->cagecos[base_index] = (const float(*)[3])BKE_editmesh_vert_coords_alloc(
+ KnifeObjectInfo *obinfo = &kcd->objects_info[base_index];
+ obinfo->em = em_eval;
+ obinfo->cagecos = (const float(*)[3])BKE_editmesh_vert_coords_alloc(
kcd->vc.depsgraph, em_eval, scene_eval, obedit_eval, NULL);
+
+ if (use_tri_indices) {
+ BMLoop *(*looptris)[3] = em_eval->looptris;
+ int(*tri_indices)[3] = MEM_mallocN(sizeof(int[3]) * em_eval->tottri, __func__);
+ for (int i = 0; i < em_eval->tottri; i++) {
+ BMLoop **tri = looptris[i];
+ tri_indices[i][0] = BM_elem_index_get(tri[0]->v);
+ tri_indices[i][1] = BM_elem_index_get(tri[1]->v);
+ tri_indices[i][2] = BM_elem_index_get(tri[2]->v);
+ }
+ obinfo->tri_indices = tri_indices;
+ }
}
-static void knifetool_free_cagecos(KnifeTool_OpData *kcd, uint base_index)
+static void knifetool_free_obinfo(KnifeTool_OpData *kcd, uint base_index)
{
- if (kcd->cagecos[base_index]) {
- MEM_freeN((void *)kcd->cagecos[base_index]);
- kcd->cagecos[base_index] = NULL;
- }
+ MEM_SAFE_FREE(kcd->objects_info[base_index].cagecos);
+ MEM_SAFE_FREE(kcd->objects_info[base_index].tri_indices);
}
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name #KnifeTool_OpData (#op->customdata) Init and Free
+ * \{ */
+
static void knife_init_colors(KnifeColors *colors)
{
/* Possible BMESH_TODO: add explicit themes or calculate these by
@@ -4007,8 +4079,7 @@ static void knife_init_colors(KnifeColors *colors)
}
/* called when modal loop selection gets set up... */
-static void knifetool_init(bContext *C,
- ViewContext *vc,
+static void knifetool_init(ViewContext *vc,
KnifeTool_OpData *kcd,
const bool only_select,
const bool cut_through,
@@ -4018,6 +4089,10 @@ static void knifetool_init(bContext *C,
const float angle_snapping_increment,
const bool is_interactive)
{
+ /* Needed so multiple non-interactive cuts (also called knife-project)
+ * doesn't access indices of loops that were created by cutting, see: T97153. */
+ bool use_tri_indices = !is_interactive;
+
kcd->vc = *vc;
Scene *scene = vc->scene;
@@ -4027,15 +4102,15 @@ static void knifetool_init(bContext *C,
kcd->region = vc->region;
kcd->objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data(
- CTX_data_view_layer(C), CTX_wm_view3d(C), &kcd->objects_len);
+ vc->view_layer, vc->v3d, &kcd->objects_len);
Object *ob;
BMEditMesh *em;
- kcd->cagecos = MEM_callocN(sizeof(*kcd->cagecos) * kcd->objects_len, "knife cagecos");
+ kcd->objects_info = MEM_callocN(sizeof(*kcd->objects_info) * kcd->objects_len, "knife cagecos");
for (uint b = 0; b < kcd->objects_len; b++) {
ob = kcd->objects[b];
em = BKE_editmesh_from_object(ob);
- knifetool_init_cagecos(kcd, ob, b);
+ knifetool_init_obinfo(kcd, ob, b, use_tri_indices);
/* Can't usefully select resulting edges in face mode. */
kcd->select_result = (em->selectmode != SCE_SELECT_FACE);
@@ -4139,9 +4214,9 @@ static void knifetool_exit_ex(KnifeTool_OpData *kcd)
/* Knife BVH cleanup. */
for (int i = 0; i < kcd->objects_len; i++) {
- knifetool_free_cagecos(kcd, i);
+ knifetool_free_obinfo(kcd, i);
}
- MEM_freeN((void *)kcd->cagecos);
+ MEM_freeN((void *)kcd->objects_info);
knife_bvh_free(kcd);
/* Line-hits cleanup. */
@@ -4169,14 +4244,14 @@ static void knifetool_exit(wmOperator *op)
/** \name Mouse-Moving Event Updates
* \{ */
-/* Update active knife edge/vert pointers. */
-static int knife_update_active(bContext *C, KnifeTool_OpData *kcd)
+/** Update active knife edge/vert pointers. */
+static int knife_update_active(KnifeTool_OpData *kcd)
{
/* If no hits are found this would normally default to (0, 0, 0) so instead
* get a point at the mouse ray closest to the previous point.
* Note that drawing lines in `free-space` isn't properly supported
* but there's no guarantee (0, 0, 0) has any geometry either - campbell */
- if (!knife_snap_update_from_mval(C, kcd, kcd->mval)) {
+ if (!knife_snap_update_from_mval(kcd, kcd->mval)) {
float origin[3];
float origin_ofs[3];
@@ -4197,20 +4272,20 @@ static int knife_update_active(bContext *C, KnifeTool_OpData *kcd)
return 1;
}
-static void knifetool_update_mval(bContext *C, KnifeTool_OpData *kcd, const float mval[2])
+static void knifetool_update_mval(KnifeTool_OpData *kcd, const float mval[2])
{
knife_recalc_ortho(kcd);
copy_v2_v2(kcd->mval, mval);
- if (knife_update_active(C, kcd)) {
+ if (knife_update_active(kcd)) {
ED_region_tag_redraw(kcd->region);
}
}
-static void knifetool_update_mval_i(bContext *C, KnifeTool_OpData *kcd, const int mval_i[2])
+static void knifetool_update_mval_i(KnifeTool_OpData *kcd, const int mval_i[2])
{
const float mval[2] = {UNPACK2(mval_i)};
- knifetool_update_mval(C, kcd, mval);
+ knifetool_update_mval(kcd, mval);
}
/** \} */
@@ -4219,33 +4294,18 @@ static void knifetool_update_mval_i(bContext *C, KnifeTool_OpData *kcd, const in
/** \name Finalization
* \{ */
-/* Called on tool confirmation. */
-static void knifetool_finish_ex(KnifeTool_OpData *kcd)
+static void knifetool_finish_single_pre(KnifeTool_OpData *kcd, Object *ob)
{
- Object *ob;
- BMEditMesh *em;
- for (uint b = 0; b < kcd->objects_len; b++) {
- ob = kcd->objects[b];
- em = BKE_editmesh_from_object(ob);
-
- knife_make_cuts(kcd, ob);
-
- EDBM_selectmode_flush(em);
- EDBM_update(ob->data,
- &(const struct EDBMUpdate_Params){
- .calc_looptri = true,
- .calc_normals = true,
- .is_destructive = true,
- });
- }
+ knife_make_cuts(kcd, ob);
}
-static void knifetool_finish_single_ex(KnifeTool_OpData *kcd, Object *ob, uint UNUSED(base_index))
+/**
+ * A post version is needed to to delay recalculating tessellation after making cuts.
+ * Without this, knife-project can't use the BVH tree to select geometry after a cut, see: T98349.
+ */
+static void knifetool_finish_single_post(KnifeTool_OpData *UNUSED(kcd), Object *ob)
{
- knife_make_cuts(kcd, ob);
-
BMEditMesh *em = BKE_editmesh_from_object(ob);
-
EDBM_selectmode_flush(em);
EDBM_update(ob->data,
&(const struct EDBMUpdate_Params){
@@ -4255,6 +4315,16 @@ static void knifetool_finish_single_ex(KnifeTool_OpData *kcd, Object *ob, uint U
});
}
+/* Called on tool confirmation. */
+static void knifetool_finish_ex(KnifeTool_OpData *kcd)
+{
+ for (uint b = 0; b < kcd->objects_len; b++) {
+ Object *ob = kcd->objects[b];
+ knifetool_finish_single_pre(kcd, ob);
+ knifetool_finish_single_post(kcd, ob);
+ }
+}
+
static void knifetool_finish(wmOperator *op)
{
KnifeTool_OpData *kcd = op->customdata;
@@ -4373,7 +4443,7 @@ static int knifetool_modal(bContext *C, wmOperator *op, const wmEvent *event)
snapping_increment_temp <= KNIFE_MAX_ANGLE_SNAPPING_INCREMENT) {
kcd->angle_snapping_increment = snapping_increment_temp;
}
- knife_update_active(C, kcd);
+ knife_update_active(kcd);
knife_update_header(C, op, kcd);
ED_region_tag_redraw(kcd->region);
return OPERATOR_RUNNING_MODAL;
@@ -4391,7 +4461,8 @@ static int knifetool_modal(bContext *C, wmOperator *op, const wmEvent *event)
ED_workspace_status_text(C, NULL);
return OPERATOR_CANCELLED;
- case KNF_MODAL_CONFIRM:
+ case KNF_MODAL_CONFIRM: {
+ const bool changed = (kcd->totkvert != 0);
/* finish */
ED_region_tag_redraw(kcd->region);
@@ -4400,11 +4471,11 @@ static int knifetool_modal(bContext *C, wmOperator *op, const wmEvent *event)
ED_workspace_status_text(C, NULL);
/* Cancel to prevent undo push for empty cuts. */
- if (kcd->totkvert == 0) {
+ if (!changed) {
return OPERATOR_CANCELLED;
}
-
return OPERATOR_FINISHED;
+ }
case KNF_MODAL_UNDO:
if (BLI_stack_is_empty(kcd->undostack)) {
ED_region_tag_redraw(kcd->region);
@@ -4413,7 +4484,7 @@ static int knifetool_modal(bContext *C, wmOperator *op, const wmEvent *event)
return OPERATOR_CANCELLED;
}
knifetool_undo(kcd);
- knife_update_active(C, kcd);
+ knife_update_active(kcd);
ED_region_tag_redraw(kcd->region);
handled = true;
break;
@@ -4421,7 +4492,7 @@ static int knifetool_modal(bContext *C, wmOperator *op, const wmEvent *event)
kcd->snap_midpoints = true;
knife_recalc_ortho(kcd);
- knife_update_active(C, kcd);
+ knife_update_active(kcd);
knife_update_header(C, op, kcd);
ED_region_tag_redraw(kcd->region);
do_refresh = true;
@@ -4431,7 +4502,7 @@ static int knifetool_modal(bContext *C, wmOperator *op, const wmEvent *event)
kcd->snap_midpoints = false;
knife_recalc_ortho(kcd);
- knife_update_active(C, kcd);
+ knife_update_active(kcd);
knife_update_header(C, op, kcd);
ED_region_tag_redraw(kcd->region);
do_refresh = true;
@@ -4465,7 +4536,7 @@ static int knifetool_modal(bContext *C, wmOperator *op, const wmEvent *event)
RNA_float_get(op->ptr, "angle_snapping_increment"));
knifetool_disable_orientation_locking(kcd);
knife_reset_snap_angle_input(kcd);
- knife_update_active(C, kcd);
+ knife_update_active(kcd);
knife_update_header(C, op, kcd);
ED_region_tag_redraw(kcd->region);
do_refresh = true;
@@ -4550,7 +4621,7 @@ static int knifetool_modal(bContext *C, wmOperator *op, const wmEvent *event)
kcd->is_drag_undo = false;
/* Needed because the last face 'hit' is ignored when dragging. */
- knifetool_update_mval(C, kcd, kcd->curr.mval);
+ knifetool_update_mval(kcd, kcd->curr.mval);
}
ED_region_tag_redraw(kcd->region);
@@ -4563,14 +4634,14 @@ static int knifetool_modal(bContext *C, wmOperator *op, const wmEvent *event)
if (kcd->is_drag_hold) {
kcd->is_drag_hold = false;
kcd->is_drag_undo = false;
- knifetool_update_mval(C, kcd, kcd->curr.mval);
+ knifetool_update_mval(kcd, kcd->curr.mval);
}
kcd->prev = kcd->curr;
kcd->curr = kcd->init;
knife_project_v2(kcd, kcd->curr.cage, kcd->curr.mval);
- knifetool_update_mval(C, kcd, kcd->curr.mval);
+ knifetool_update_mval(kcd, kcd->curr.mval);
knife_add_cut(kcd);
@@ -4606,7 +4677,8 @@ static int knifetool_modal(bContext *C, wmOperator *op, const wmEvent *event)
return OPERATOR_PASS_THROUGH;
case MOUSEMOVE: /* Mouse moved somewhere to select another loop. */
if (kcd->mode != MODE_PANNING) {
- knifetool_update_mval_i(C, kcd, event->mval);
+ knifetool_update_mval_i(kcd, event->mval);
+ knife_update_header(C, op, kcd);
if (kcd->is_drag_hold) {
if (kcd->totlinehit >= 2) {
@@ -4633,7 +4705,7 @@ static int knifetool_modal(bContext *C, wmOperator *op, const wmEvent *event)
snapping_increment_temp <= KNIFE_MAX_ANGLE_SNAPPING_INCREMENT) {
kcd->angle_snapping_increment = snapping_increment_temp;
}
- knife_update_active(C, kcd);
+ knife_update_active(kcd);
knife_update_header(C, op, kcd);
ED_region_tag_redraw(kcd->region);
return OPERATOR_RUNNING_MODAL;
@@ -4688,7 +4760,8 @@ static int knifetool_modal(bContext *C, wmOperator *op, const wmEvent *event)
if (do_refresh) {
/* We don't really need to update mval,
* but this happens to be the best way to refresh at the moment. */
- knifetool_update_mval_i(C, kcd, event->mval);
+ knifetool_update_mval_i(kcd, event->mval);
+ knife_update_header(C, op, kcd);
}
/* Keep going until the user confirms. */
@@ -4714,8 +4787,7 @@ static int knifetool_invoke(bContext *C, wmOperator *op, const wmEvent *event)
/* alloc new customdata */
kcd = op->customdata = MEM_callocN(sizeof(KnifeTool_OpData), __func__);
- knifetool_init(C,
- &vc,
+ knifetool_init(&vc,
kcd,
only_select,
cut_through,
@@ -4751,7 +4823,7 @@ static int knifetool_invoke(bContext *C, wmOperator *op, const wmEvent *event)
WM_cursor_modal_set(CTX_wm_window(C), WM_CURSOR_KNIFE);
WM_event_add_modal_handler(C, op);
- knifetool_update_mval_i(C, kcd, event->mval);
+ knifetool_update_mval_i(kcd, event->mval);
if (wait_for_input == false) {
/* Avoid copy-paste logic. */
@@ -4869,7 +4941,7 @@ static bool edbm_mesh_knife_point_isect(LinkNode *polys, const float cent_ss[2])
return false;
}
-void EDBM_mesh_knife(bContext *C, ViewContext *vc, LinkNode *polys, bool use_tag, bool cut_through)
+void EDBM_mesh_knife(ViewContext *vc, LinkNode *polys, bool use_tag, bool cut_through)
{
KnifeTool_OpData *kcd;
@@ -4884,8 +4956,7 @@ void EDBM_mesh_knife(bContext *C, ViewContext *vc, LinkNode *polys, bool use_tag
kcd = MEM_callocN(sizeof(KnifeTool_OpData), __func__);
- knifetool_init(C,
- vc,
+ knifetool_init(vc,
kcd,
only_select,
cut_through,
@@ -4911,7 +4982,7 @@ void EDBM_mesh_knife(bContext *C, ViewContext *vc, LinkNode *polys, bool use_tag
int i;
for (i = 0; i < mval_tot; i++) {
- knifetool_update_mval(C, kcd, mval_fl[i]);
+ knifetool_update_mval(kcd, mval_fl[i]);
if (i == 0) {
knife_start_cut(kcd);
kcd->mode = MODE_DRAGGING;
@@ -4939,7 +5010,7 @@ void EDBM_mesh_knife(bContext *C, ViewContext *vc, LinkNode *polys, bool use_tag
BM_mesh_elem_hflag_enable_all(em->bm, BM_EDGE, BM_ELEM_TAG, false);
}
- knifetool_finish_single_ex(kcd, ob, b);
+ knifetool_finish_single_pre(kcd, ob);
/* Tag faces inside! */
if (use_tag) {
@@ -4963,17 +5034,19 @@ void EDBM_mesh_knife(bContext *C, ViewContext *vc, LinkNode *polys, bool use_tag
/* Tag all faces linked to cut edges. */
BM_ITER_MESH (e, &iter, bm, BM_EDGES_OF_MESH) {
/* Check are we tagged?, then we are an original face. */
- if (BM_elem_flag_test(e, BM_ELEM_TAG) == false) {
- BMFace *f;
- BMIter fiter;
- BM_ITER_ELEM (f, &fiter, e, BM_FACES_OF_EDGE) {
- float cent[3], cent_ss[2];
- BM_face_calc_point_in_face(f, cent);
- mul_m4_v3(ob->obmat, cent);
- knife_project_v2(kcd, cent, cent_ss);
- if (edbm_mesh_knife_point_isect(polys, cent_ss)) {
- BM_elem_flag_enable(f, BM_ELEM_TAG);
- }
+ if (BM_elem_flag_test(e, BM_ELEM_TAG)) {
+ continue;
+ }
+
+ BMFace *f;
+ BMIter fiter;
+ BM_ITER_ELEM (f, &fiter, e, BM_FACES_OF_EDGE) {
+ float cent[3], cent_ss[2];
+ BM_face_calc_point_in_face(f, cent);
+ mul_m4_v3(ob->obmat, cent);
+ knife_project_v2(kcd, cent, cent_ss);
+ if (edbm_mesh_knife_point_isect(polys, cent_ss)) {
+ BM_elem_flag_enable(f, BM_ELEM_TAG);
}
}
}
@@ -4983,43 +5056,45 @@ void EDBM_mesh_knife(bContext *C, ViewContext *vc, LinkNode *polys, bool use_tag
BMFace *f;
keep_search = false;
BM_ITER_MESH (f, &iter, bm, BM_FACES_OF_MESH) {
- if (BM_elem_flag_test(f, BM_ELEM_TAG) == false && (F_ISECT_IS_UNKNOWN(f))) {
- /* Am I connected to a tagged face via an un-tagged edge
- * (ie, not across a cut)? */
- BMLoop *l_first = BM_FACE_FIRST_LOOP(f);
- BMLoop *l_iter = l_first;
- bool found = false;
-
- do {
- if (BM_elem_flag_test(l_iter->e, BM_ELEM_TAG) != false) {
- /* Now check if the adjacent faces is tagged. */
- BMLoop *l_radial_iter = l_iter->radial_next;
- if (l_radial_iter != l_iter) {
- do {
- if (BM_elem_flag_test(l_radial_iter->f, BM_ELEM_TAG)) {
- found = true;
- }
- } while ((l_radial_iter = l_radial_iter->radial_next) != l_iter &&
- (found == false));
- }
- }
- } while ((l_iter = l_iter->next) != l_first && (found == false));
-
- if (found) {
- float cent[3], cent_ss[2];
- BM_face_calc_point_in_face(f, cent);
- mul_m4_v3(ob->obmat, cent);
- knife_project_v2(kcd, cent, cent_ss);
- if ((kcd->cut_through || point_is_visible(kcd, cent, cent_ss, (BMElem *)f)) &&
- edbm_mesh_knife_point_isect(polys, cent_ss)) {
- BM_elem_flag_enable(f, BM_ELEM_TAG);
- keep_search = true;
- }
- else {
- /* Don't lose time on this face again, set it as outside. */
- F_ISECT_SET_OUTSIDE(f);
+ if (BM_elem_flag_test(f, BM_ELEM_TAG) || !F_ISECT_IS_UNKNOWN(f)) {
+ continue;
+ }
+
+ /* Am I connected to a tagged face via an un-tagged edge
+ * (ie, not across a cut)? */
+ BMLoop *l_first = BM_FACE_FIRST_LOOP(f);
+ BMLoop *l_iter = l_first;
+ bool found = false;
+
+ do {
+ if (BM_elem_flag_test(l_iter->e, BM_ELEM_TAG) != false) {
+ /* Now check if the adjacent faces is tagged. */
+ BMLoop *l_radial_iter = l_iter->radial_next;
+ if (l_radial_iter != l_iter) {
+ do {
+ if (BM_elem_flag_test(l_radial_iter->f, BM_ELEM_TAG)) {
+ found = true;
+ }
+ } while ((l_radial_iter = l_radial_iter->radial_next) != l_iter &&
+ (found == false));
}
}
+ } while ((l_iter = l_iter->next) != l_first && (found == false));
+
+ if (found) {
+ float cent[3], cent_ss[2];
+ BM_face_calc_point_in_face(f, cent);
+ mul_m4_v3(ob->obmat, cent);
+ knife_project_v2(kcd, cent, cent_ss);
+ if ((kcd->cut_through || point_is_visible(kcd, cent, cent_ss, (BMElem *)f)) &&
+ edbm_mesh_knife_point_isect(polys, cent_ss)) {
+ BM_elem_flag_enable(f, BM_ELEM_TAG);
+ keep_search = true;
+ }
+ else {
+ /* Don't lose time on this face again, set it as outside. */
+ F_ISECT_SET_OUTSIDE(f);
+ }
}
}
} while (keep_search);
@@ -5028,6 +5103,10 @@ void EDBM_mesh_knife(bContext *C, ViewContext *vc, LinkNode *polys, bool use_tag
#undef F_ISECT_SET_UNKNOWN
#undef F_ISECT_SET_OUTSIDE
}
+
+ /* Defer freeing data until the BVH tree is finished with, see: #point_is_visible and
+ * the doc-string for #knifetool_finish_single_post. */
+ knifetool_finish_single_post(kcd, ob);
}
knifetool_exit_ex(kcd);
diff --git a/source/blender/editors/mesh/editmesh_knife_project.c b/source/blender/editors/mesh/editmesh_knife_project.c
index bce46dd7cf7..c32b1fa99c0 100644
--- a/source/blender/editors/mesh/editmesh_knife_project.c
+++ b/source/blender/editors/mesh/editmesh_knife_project.c
@@ -142,7 +142,7 @@ static int knifeproject_exec(bContext *C, wmOperator *op)
ED_view3d_viewcontext_init_object(&vc, obedit);
BMEditMesh *em = BKE_editmesh_from_object(obedit);
- EDBM_mesh_knife(C, &vc, polys, true, cut_through);
+ EDBM_mesh_knife(&vc, polys, true, cut_through);
/* select only tagged faces */
BM_mesh_elem_hflag_disable_all(em->bm, BM_VERT | BM_EDGE | BM_FACE, BM_ELEM_SELECT, false);
diff --git a/source/blender/editors/mesh/editmesh_select_similar.c b/source/blender/editors/mesh/editmesh_select_similar.c
index 3f05c27e8fa..c931cb4948b 100644
--- a/source/blender/editors/mesh/editmesh_select_similar.c
+++ b/source/blender/editors/mesh/editmesh_select_similar.c
@@ -1370,8 +1370,14 @@ static bool edbm_select_similar_poll_property(const bContext *UNUSED(C),
const char *prop_id = RNA_property_identifier(prop);
const int type = RNA_enum_get(op->ptr, "type");
+ /* Only show compare when it is used. */
+ if (STREQ(prop_id, "compare")) {
+ if (type == SIMVERT_VGROUP) {
+ return false;
+ }
+ }
/* Only show threshold when it is used. */
- if (STREQ(prop_id, "threshold")) {
+ else if (STREQ(prop_id, "threshold")) {
if (!ELEM(type,
SIMVERT_NORMAL,
SIMEDGE_BEVEL,
diff --git a/source/blender/editors/mesh/editmesh_tools.c b/source/blender/editors/mesh/editmesh_tools.c
index cafcc4ec578..1febc429edc 100644
--- a/source/blender/editors/mesh/editmesh_tools.c
+++ b/source/blender/editors/mesh/editmesh_tools.c
@@ -3092,8 +3092,8 @@ static int edbm_rotate_colors_exec(bContext *C, wmOperator *op)
BMOperator bmop;
- Mesh *me = BKE_object_get_original_mesh(ob);
- CustomDataLayer *layer = BKE_id_attributes_active_color_get(&me->id);
+ const Mesh *me = BKE_object_get_original_mesh(ob);
+ const CustomDataLayer *layer = BKE_id_attributes_active_color_get(&me->id);
if (!layer || BKE_id_attribute_domain(&me->id, layer) != ATTR_DOMAIN_CORNER) {
continue;
@@ -3144,8 +3144,8 @@ static int edbm_reverse_colors_exec(bContext *C, wmOperator *op)
continue;
}
- Mesh *me = BKE_object_get_original_mesh(obedit);
- CustomDataLayer *layer = BKE_id_attributes_active_color_get(&me->id);
+ const Mesh *me = BKE_object_get_original_mesh(obedit);
+ const CustomDataLayer *layer = BKE_id_attributes_active_color_get(&me->id);
if (!layer || BKE_id_attribute_domain(&me->id, layer) != ATTR_DOMAIN_CORNER) {
continue;
@@ -7032,6 +7032,14 @@ static void sort_bmelem_flag(bContext *C,
}
BM_mesh_remap(em->bm, map[0], map[1], map[2]);
+
+ EDBM_update(ob->data,
+ &(const struct EDBMUpdate_Params){
+ .calc_looptri = (totelem[2] != 0),
+ .calc_normals = false,
+ .is_destructive = true,
+ });
+
DEG_id_tag_update(ob->data, ID_RECALC_GEOMETRY);
WM_event_add_notifier(C, NC_GEOM | ND_DATA, ob->data);
diff --git a/source/blender/editors/mesh/editmesh_undo.c b/source/blender/editors/mesh/editmesh_undo.c
index ecc5f8f8ef5..d75c92f963f 100644
--- a/source/blender/editors/mesh/editmesh_undo.c
+++ b/source/blender/editors/mesh/editmesh_undo.c
@@ -72,7 +72,7 @@ static CLG_LogRef LOG = {"ed.undo.mesh"};
/* Single linked list of layers stored per type */
typedef struct BArrayCustomData {
struct BArrayCustomData *next;
- CustomDataType type;
+ eCustomDataType type;
int states_len; /* number of layers for each type */
BArrayState *states[0];
} BArrayCustomData;
@@ -149,7 +149,7 @@ static void um_arraystore_cd_compact(struct CustomData *cdata,
const BArrayCustomData *bcd_reference_current = bcd_reference;
BArrayCustomData *bcd = NULL, *bcd_first = NULL, *bcd_prev = NULL;
for (int layer_start = 0, layer_end; layer_start < cdata->totlayer; layer_start = layer_end) {
- const CustomDataType type = cdata->layers[layer_start].type;
+ const eCustomDataType type = cdata->layers[layer_start].type;
/* Perform a full copy on dynamic layers.
*
diff --git a/source/blender/editors/mesh/editmesh_utils.c b/source/blender/editors/mesh/editmesh_utils.c
index c3d5f33705c..04030583f5c 100644
--- a/source/blender/editors/mesh/editmesh_utils.c
+++ b/source/blender/editors/mesh/editmesh_utils.c
@@ -9,6 +9,7 @@
#include "DNA_key_types.h"
#include "DNA_mesh_types.h"
+#include "DNA_meshdata_types.h"
#include "DNA_object_types.h"
#include "BLI_alloca.h"
@@ -19,6 +20,7 @@
#include "BKE_DerivedMesh.h"
#include "BKE_context.h"
+#include "BKE_customdata.h"
#include "BKE_editmesh.h"
#include "BKE_editmesh_bvh.h"
#include "BKE_global.h"
@@ -1639,21 +1641,22 @@ void EDBM_project_snap_verts(
float mval[2], co_proj[3];
if (ED_view3d_project_float_object(region, eve->co, mval, V3D_PROJ_TEST_NOP) ==
V3D_PROJ_RET_OK) {
- if (ED_transform_snap_object_project_view3d(snap_context,
- depsgraph,
- region,
- CTX_wm_view3d(C),
- SCE_SNAP_MODE_FACE,
- &(const struct SnapObjectParams){
- .snap_select = SNAP_NOT_ACTIVE,
- .edit_mode_type = SNAP_GEOM_FINAL,
- .use_occlusion_test = true,
- },
- mval,
- NULL,
- NULL,
- co_proj,
- NULL)) {
+ if (ED_transform_snap_object_project_view3d(
+ snap_context,
+ depsgraph,
+ region,
+ CTX_wm_view3d(C),
+ SCE_SNAP_MODE_FACE,
+ &(const struct SnapObjectParams){
+ .snap_target_select = SCE_SNAP_TARGET_NOT_ACTIVE,
+ .edit_mode_type = SNAP_GEOM_FINAL,
+ .use_occlusion_test = true,
+ },
+ mval,
+ NULL,
+ NULL,
+ co_proj,
+ NULL)) {
mul_v3_m4v3(eve->co, obedit->imat, co_proj);
}
}
diff --git a/source/blender/editors/mesh/mesh_data.c b/source/blender/editors/mesh/mesh_data.cc
index d11f0b490c1..67834bf05ce 100644
--- a/source/blender/editors/mesh/mesh_data.c
+++ b/source/blender/editors/mesh/mesh_data.cc
@@ -13,7 +13,7 @@
#include "DNA_scene_types.h"
#include "DNA_view3d_types.h"
-#include "BLI_alloca.h"
+#include "BLI_array.hh"
#include "BLI_math.h"
#include "BLI_utildefines.h"
@@ -43,10 +43,12 @@
#include "mesh_intern.h" /* own include */
+using blender::Array;
+
static CustomData *mesh_customdata_get_type(Mesh *me, const char htype, int *r_tot)
{
CustomData *data;
- BMesh *bm = (me->edit_mesh) ? me->edit_mesh->bm : NULL;
+ BMesh *bm = (me->edit_mesh) ? me->edit_mesh->bm : nullptr;
int tot;
switch (htype) {
@@ -93,7 +95,7 @@ static CustomData *mesh_customdata_get_type(Mesh *me, const char htype, int *r_t
default:
BLI_assert(0);
tot = 0;
- data = NULL;
+ data = nullptr;
break;
}
@@ -172,7 +174,7 @@ static void mesh_uv_reset_array(float **fuv, const int len)
static void mesh_uv_reset_bmface(BMFace *f, const int cd_loop_uv_offset)
{
- float **fuv = BLI_array_alloca(fuv, f->len);
+ Array<float *, BM_DEFAULT_NGON_STACK_SIZE> fuv(f->len);
BMIter liter;
BMLoop *l;
int i;
@@ -181,21 +183,21 @@ static void mesh_uv_reset_bmface(BMFace *f, const int cd_loop_uv_offset)
fuv[i] = ((MLoopUV *)BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset))->uv;
}
- mesh_uv_reset_array(fuv, f->len);
+ mesh_uv_reset_array(fuv.data(), f->len);
}
static void mesh_uv_reset_mface(MPoly *mp, MLoopUV *mloopuv)
{
- float **fuv = BLI_array_alloca(fuv, mp->totloop);
+ Array<float *, BM_DEFAULT_NGON_STACK_SIZE> fuv(mp->totloop);
for (int i = 0; i < mp->totloop; i++) {
fuv[i] = mloopuv[mp->loopstart + i].uv;
}
- mesh_uv_reset_array(fuv, mp->totloop);
+ mesh_uv_reset_array(fuv.data(), mp->totloop);
}
-void ED_mesh_uv_loop_reset_ex(struct Mesh *me, const int layernum)
+void ED_mesh_uv_loop_reset_ex(Mesh *me, const int layernum)
{
BMEditMesh *em = me->edit_mesh;
@@ -219,7 +221,7 @@ void ED_mesh_uv_loop_reset_ex(struct Mesh *me, const int layernum)
else {
/* Collect Mesh UVs */
BLI_assert(CustomData_has_layer(&me->ldata, CD_MLOOPUV));
- MLoopUV *mloopuv = CustomData_get_layer_n(&me->ldata, CD_MLOOPUV, layernum);
+ MLoopUV *mloopuv = (MLoopUV *)CustomData_get_layer_n(&me->ldata, CD_MLOOPUV, layernum);
for (int i = 0; i < me->totpoly; i++) {
mesh_uv_reset_mface(&me->mpoly[i], mloopuv);
@@ -229,7 +231,7 @@ void ED_mesh_uv_loop_reset_ex(struct Mesh *me, const int layernum)
DEG_id_tag_update(&me->id, 0);
}
-void ED_mesh_uv_loop_reset(struct bContext *C, struct Mesh *me)
+void ED_mesh_uv_loop_reset(bContext *C, Mesh *me)
{
/* could be ldata or pdata */
CustomData *ldata = GET_CD_DATA(me, ldata);
@@ -239,7 +241,7 @@ void ED_mesh_uv_loop_reset(struct bContext *C, struct Mesh *me)
WM_event_add_notifier(C, NC_GEOM | ND_DATA, me);
}
-int ED_mesh_uv_texture_add(
+int ED_mesh_uv_add(
Mesh *me, const char *name, const bool active_set, const bool do_init, ReportList *reports)
{
/* NOTE: keep in sync with #ED_mesh_color_add. */
@@ -284,7 +286,7 @@ int ED_mesh_uv_texture_add(
is_init = true;
}
else {
- CustomData_add_layer_named(&me->ldata, CD_MLOOPUV, CD_DEFAULT, NULL, me->totloop, name);
+ CustomData_add_layer_named(&me->ldata, CD_MLOOPUV, CD_DEFAULT, nullptr, me->totloop, name);
}
if (active_set || layernum_dst == 0) {
@@ -305,7 +307,7 @@ int ED_mesh_uv_texture_add(
return layernum_dst;
}
-void ED_mesh_uv_texture_ensure(struct Mesh *me, const char *name)
+void ED_mesh_uv_ensure(Mesh *me, const char *name)
{
BMEditMesh *em;
int layernum_dst;
@@ -315,25 +317,25 @@ void ED_mesh_uv_texture_ensure(struct Mesh *me, const char *name)
layernum_dst = CustomData_number_of_layers(&em->bm->ldata, CD_MLOOPUV);
if (layernum_dst == 0) {
- ED_mesh_uv_texture_add(me, name, true, true, NULL);
+ ED_mesh_uv_add(me, name, true, true, nullptr);
}
}
else {
layernum_dst = CustomData_number_of_layers(&me->ldata, CD_MLOOPUV);
if (layernum_dst == 0) {
- ED_mesh_uv_texture_add(me, name, true, true, NULL);
+ ED_mesh_uv_add(me, name, true, true, nullptr);
}
}
}
-bool ED_mesh_uv_texture_remove_index(Mesh *me, const int n)
+bool ED_mesh_uv_remove_index(Mesh *me, const int n)
{
CustomData *ldata = GET_CD_DATA(me, ldata);
CustomDataLayer *cdlu;
int index;
index = CustomData_get_layer_index_n(ldata, CD_MLOOPUV, n);
- cdlu = (index == -1) ? NULL : &ldata->layers[index];
+ cdlu = (index == -1) ? nullptr : &ldata->layers[index];
if (!cdlu) {
return false;
@@ -346,24 +348,22 @@ bool ED_mesh_uv_texture_remove_index(Mesh *me, const int n)
return true;
}
-bool ED_mesh_uv_texture_remove_active(Mesh *me)
+bool ED_mesh_uv_remove_active(Mesh *me)
{
- /* texpoly/uv are assumed to be in sync */
CustomData *ldata = GET_CD_DATA(me, ldata);
const int n = CustomData_get_active_layer(ldata, CD_MLOOPUV);
if (n != -1) {
- return ED_mesh_uv_texture_remove_index(me, n);
+ return ED_mesh_uv_remove_index(me, n);
}
return false;
}
-bool ED_mesh_uv_texture_remove_named(Mesh *me, const char *name)
+bool ED_mesh_uv_remove_named(Mesh *me, const char *name)
{
- /* texpoly/uv are assumed to be in sync */
CustomData *ldata = GET_CD_DATA(me, ldata);
const int n = CustomData_get_named_layer(ldata, CD_MLOOPUV, name);
if (n != -1) {
- return ED_mesh_uv_texture_remove_index(me, n);
+ return ED_mesh_uv_remove_index(me, n);
}
return false;
}
@@ -371,7 +371,7 @@ bool ED_mesh_uv_texture_remove_named(Mesh *me, const char *name)
int ED_mesh_color_add(
Mesh *me, const char *name, const bool active_set, const bool do_init, ReportList *reports)
{
- /* NOTE: keep in sync with #ED_mesh_uv_texture_add. */
+ /* NOTE: keep in sync with #ED_mesh_uv_add. */
BMEditMesh *em;
int layernum;
@@ -409,7 +409,7 @@ int ED_mesh_color_add(
}
else {
CustomData_add_layer_named(
- &me->ldata, CD_PROP_BYTE_COLOR, CD_DEFAULT, NULL, me->totloop, name);
+ &me->ldata, CD_PROP_BYTE_COLOR, CD_DEFAULT, nullptr, me->totloop, name);
}
if (active_set || layernum == 0) {
@@ -425,14 +425,14 @@ int ED_mesh_color_add(
return layernum;
}
-bool ED_mesh_color_ensure(struct Mesh *me, const char *name)
+bool ED_mesh_color_ensure(Mesh *me, const char *name)
{
- BLI_assert(me->edit_mesh == NULL);
+ BLI_assert(me->edit_mesh == nullptr);
CustomDataLayer *layer = BKE_id_attributes_active_color_get(&me->id);
if (!layer) {
CustomData_add_layer_named(
- &me->ldata, CD_PROP_BYTE_COLOR, CD_DEFAULT, NULL, me->totloop, name);
+ &me->ldata, CD_PROP_BYTE_COLOR, CD_DEFAULT, nullptr, me->totloop, name);
layer = me->ldata.layers + CustomData_get_layer_index(&me->ldata, CD_PROP_BYTE_COLOR);
BKE_id_attributes_active_color_set(&me->id, layer);
@@ -441,7 +441,7 @@ bool ED_mesh_color_ensure(struct Mesh *me, const char *name)
DEG_id_tag_update(&me->id, 0);
- return (layer != NULL);
+ return (layer != nullptr);
}
bool ED_mesh_color_remove_index(Mesh *me, const int n)
@@ -451,7 +451,7 @@ bool ED_mesh_color_remove_index(Mesh *me, const int n)
int index;
index = CustomData_get_layer_index_n(ldata, CD_PROP_BYTE_COLOR, n);
- cdl = (index == -1) ? NULL : &ldata->layers[index];
+ cdl = (index == -1) ? nullptr : &ldata->layers[index];
if (!cdl) {
return false;
@@ -487,7 +487,7 @@ bool ED_mesh_color_remove_named(Mesh *me, const char *name)
static bool layers_poll(bContext *C)
{
Object *ob = ED_object_context(C);
- ID *data = (ob) ? ob->data : NULL;
+ ID *data = (ob) ? static_cast<ID *>(ob->data) : nullptr;
return (ob && !ID_IS_LINKED(ob) && !ID_IS_OVERRIDE_LIBRARY(ob) && ob->type == OB_MESH && data &&
!ID_IS_LINKED(data) && !ID_IS_OVERRIDE_LIBRARY(data));
}
@@ -501,7 +501,7 @@ static bool sculpt_vertex_color_remove_poll(bContext *C)
}
Object *ob = ED_object_context(C);
- Mesh *me = ob->data;
+ Mesh *me = static_cast<Mesh *>(ob->data);
CustomData *vdata = GET_CD_DATA(me, vdata);
const int active = CustomData_get_active_layer(vdata, CD_PROP_COLOR);
if (active != -1) {
@@ -514,7 +514,7 @@ static bool sculpt_vertex_color_remove_poll(bContext *C)
int ED_mesh_sculpt_color_add(
Mesh *me, const char *name, const bool active_set, const bool do_init, ReportList *reports)
{
- /* NOTE: keep in sync with #ED_mesh_uv_texture_add. */
+ /* NOTE: keep in sync with #ED_mesh_uv_add. */
BMEditMesh *em;
int layernum;
@@ -549,12 +549,14 @@ int ED_mesh_sculpt_color_add(
}
if (CustomData_has_layer(&me->vdata, CD_PROP_COLOR) && do_init) {
- MPropCol *color_data = CustomData_get_layer(&me->vdata, CD_PROP_COLOR);
+ const MPropCol *color_data = (const MPropCol *)CustomData_get_layer(&me->vdata,
+ CD_PROP_COLOR);
CustomData_add_layer_named(
- &me->vdata, CD_PROP_COLOR, CD_DUPLICATE, color_data, me->totvert, name);
+ &me->vdata, CD_PROP_COLOR, CD_DUPLICATE, (MPropCol *)color_data, me->totvert, name);
}
else {
- CustomData_add_layer_named(&me->vdata, CD_PROP_COLOR, CD_DEFAULT, NULL, me->totvert, name);
+ CustomData_add_layer_named(
+ &me->vdata, CD_PROP_COLOR, CD_DEFAULT, nullptr, me->totvert, name);
}
if (active_set || layernum == 0) {
@@ -570,18 +572,18 @@ int ED_mesh_sculpt_color_add(
return layernum;
}
-bool ED_mesh_sculpt_color_ensure(struct Mesh *me, const char *name)
+bool ED_mesh_sculpt_color_ensure(Mesh *me, const char *name)
{
- BLI_assert(me->edit_mesh == NULL);
+ BLI_assert(me->edit_mesh == nullptr);
if (me->totvert && !CustomData_has_layer(&me->vdata, CD_PROP_COLOR)) {
- CustomData_add_layer_named(&me->vdata, CD_PROP_COLOR, CD_DEFAULT, NULL, me->totvert, name);
+ CustomData_add_layer_named(&me->vdata, CD_PROP_COLOR, CD_DEFAULT, nullptr, me->totvert, name);
BKE_mesh_update_customdata_pointers(me, true);
}
DEG_id_tag_update(&me->id, 0);
- return (me->mloopcol != NULL);
+ return (me->mloopcol != nullptr);
}
bool ED_mesh_sculpt_color_remove_index(Mesh *me, const int n)
@@ -591,7 +593,7 @@ bool ED_mesh_sculpt_color_remove_index(Mesh *me, const int n)
int index;
index = CustomData_get_layer_index_n(vdata, CD_PROP_COLOR, n);
- cdl = (index == -1) ? NULL : &vdata->layers[index];
+ cdl = (index == -1) ? nullptr : &vdata->layers[index];
if (!cdl) {
return false;
@@ -631,7 +633,7 @@ static bool uv_texture_remove_poll(bContext *C)
}
Object *ob = ED_object_context(C);
- Mesh *me = ob->data;
+ Mesh *me = static_cast<Mesh *>(ob->data);
CustomData *ldata = GET_CD_DATA(me, ldata);
const int active = CustomData_get_active_layer(ldata, CD_MLOOPUV);
if (active != -1) {
@@ -644,16 +646,16 @@ static bool uv_texture_remove_poll(bContext *C)
static int mesh_uv_texture_add_exec(bContext *C, wmOperator *op)
{
Object *ob = ED_object_context(C);
- Mesh *me = ob->data;
+ Mesh *me = static_cast<Mesh *>(ob->data);
- if (ED_mesh_uv_texture_add(me, NULL, true, true, op->reports) == -1) {
+ if (ED_mesh_uv_add(me, nullptr, true, true, op->reports) == -1) {
return OPERATOR_CANCELLED;
}
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);
}
return OPERATOR_FINISHED;
@@ -677,16 +679,16 @@ void MESH_OT_uv_texture_add(wmOperatorType *ot)
static int mesh_uv_texture_remove_exec(bContext *C, wmOperator *UNUSED(op))
{
Object *ob = ED_object_context(C);
- Mesh *me = ob->data;
+ Mesh *me = static_cast<Mesh *>(ob->data);
- if (!ED_mesh_uv_texture_remove_active(me)) {
+ if (!ED_mesh_uv_remove_active(me)) {
return OPERATOR_CANCELLED;
}
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);
}
return OPERATOR_FINISHED;
@@ -716,7 +718,7 @@ static bool vertex_color_remove_poll(bContext *C)
}
Object *ob = ED_object_context(C);
- Mesh *me = ob->data;
+ Mesh *me = static_cast<Mesh *>(ob->data);
CustomData *ldata = GET_CD_DATA(me, ldata);
const int active = CustomData_get_active_layer(ldata, CD_PROP_BYTE_COLOR);
if (active != -1) {
@@ -729,9 +731,9 @@ static bool vertex_color_remove_poll(bContext *C)
static int mesh_vertex_color_add_exec(bContext *C, wmOperator *op)
{
Object *ob = ED_object_context(C);
- Mesh *me = ob->data;
+ Mesh *me = static_cast<Mesh *>(ob->data);
- if (ED_mesh_color_add(me, NULL, true, true, op->reports) == -1) {
+ if (ED_mesh_color_add(me, nullptr, true, true, op->reports) == -1) {
return OPERATOR_CANCELLED;
}
@@ -756,7 +758,7 @@ void MESH_OT_vertex_color_add(wmOperatorType *ot)
static int mesh_vertex_color_remove_exec(bContext *C, wmOperator *UNUSED(op))
{
Object *ob = ED_object_context(C);
- Mesh *me = ob->data;
+ Mesh *me = static_cast<Mesh *>(ob->data);
if (!ED_mesh_color_remove_active(me)) {
return OPERATOR_CANCELLED;
@@ -785,9 +787,9 @@ void MESH_OT_vertex_color_remove(wmOperatorType *ot)
static int mesh_sculpt_vertex_color_add_exec(bContext *C, wmOperator *op)
{
Object *ob = ED_object_context(C);
- Mesh *me = ob->data;
+ Mesh *me = static_cast<Mesh *>(ob->data);
- if (ED_mesh_sculpt_color_add(me, NULL, true, true, op->reports) == -1) {
+ if (ED_mesh_sculpt_color_add(me, nullptr, true, true, op->reports) == -1) {
return OPERATOR_CANCELLED;
}
@@ -812,7 +814,7 @@ void MESH_OT_sculpt_vertex_color_add(wmOperatorType *ot)
static int mesh_sculpt_vertex_color_remove_exec(bContext *C, wmOperator *UNUSED(op))
{
Object *ob = ED_object_context(C);
- Mesh *me = ob->data;
+ Mesh *me = static_cast<Mesh *>(ob->data);
if (!ED_mesh_sculpt_color_remove_active(me)) {
return OPERATOR_CANCELLED;
@@ -868,7 +870,7 @@ static bool mesh_customdata_mask_clear_poll(bContext *C)
{
Object *ob = ED_object_context(C);
if (ob && ob->type == OB_MESH) {
- Mesh *me = ob->data;
+ Mesh *me = static_cast<Mesh *>(ob->data);
/* special case - can't run this if we're in sculpt mode */
if (ob->mode & OB_MODE_SCULPT) {
@@ -925,7 +927,7 @@ static int mesh_customdata_skin_state(bContext *C)
Object *ob = ED_object_context(C);
if (ob && ob->type == OB_MESH) {
- Mesh *me = ob->data;
+ Mesh *me = static_cast<Mesh *>(ob->data);
if (!ID_IS_LINKED(me) && !ID_IS_OVERRIDE_LIBRARY(me)) {
CustomData *data = GET_CD_DATA(me, vdata);
return CustomData_has_layer(data, CD_MVERT_SKIN);
@@ -942,7 +944,7 @@ static bool mesh_customdata_skin_add_poll(bContext *C)
static int mesh_customdata_skin_add_exec(bContext *C, wmOperator *UNUSED(op))
{
Object *ob = ED_object_context(C);
- Mesh *me = ob->data;
+ Mesh *me = static_cast<Mesh *>(ob->data);
BKE_mesh_ensure_skin_customdata(me);
@@ -1025,7 +1027,7 @@ static int mesh_customdata_custom_splitnormals_add_exec(bContext *C, wmOperator
me->smoothresh);
}
- CustomData_add_layer(data, CD_CUSTOMLOOPNORMAL, CD_DEFAULT, NULL, me->totloop);
+ CustomData_add_layer(data, CD_CUSTOMLOOPNORMAL, CD_DEFAULT, nullptr, me->totloop);
}
DEG_id_tag_update(&me->id, 0);
@@ -1057,7 +1059,7 @@ static int mesh_customdata_custom_splitnormals_clear_exec(bContext *C, wmOperato
if (BKE_mesh_has_custom_loop_normals(me)) {
BMEditMesh *em = me->edit_mesh;
- if (em != NULL && em->bm->lnor_spacearr != NULL) {
+ if (em != nullptr && em->bm->lnor_spacearr != nullptr) {
BKE_lnor_spacearr_clear(em->bm->lnor_spacearr);
}
return mesh_customdata_clear_exec__internal(C, BM_LOOP, CD_CUSTOMLOOPNORMAL);
@@ -1114,7 +1116,7 @@ static void mesh_add_verts(Mesh *mesh, int len)
CustomData_copy_data(&mesh->vdata, &vdata, 0, 0, mesh->totvert);
if (!CustomData_has_layer(&vdata, CD_MVERT)) {
- CustomData_add_layer(&vdata, CD_MVERT, CD_CALLOC, NULL, totvert);
+ CustomData_add_layer(&vdata, CD_MVERT, CD_CALLOC, nullptr, totvert);
}
CustomData_free(&mesh->vdata, mesh->totvert);
@@ -1152,7 +1154,7 @@ static void mesh_add_edges(Mesh *mesh, int len)
CustomData_copy_data(&mesh->edata, &edata, 0, 0, mesh->totedge);
if (!CustomData_has_layer(&edata, CD_MEDGE)) {
- CustomData_add_layer(&edata, CD_MEDGE, CD_CALLOC, NULL, totedge);
+ CustomData_add_layer(&edata, CD_MEDGE, CD_CALLOC, nullptr, totedge);
}
CustomData_free(&mesh->edata, mesh->totedge);
@@ -1186,7 +1188,7 @@ static void mesh_add_loops(Mesh *mesh, int len)
CustomData_copy_data(&mesh->ldata, &ldata, 0, 0, mesh->totloop);
if (!CustomData_has_layer(&ldata, CD_MLOOP)) {
- CustomData_add_layer(&ldata, CD_MLOOP, CD_CALLOC, NULL, totloop);
+ CustomData_add_layer(&ldata, CD_MLOOP, CD_CALLOC, nullptr, totloop);
}
BKE_mesh_runtime_clear_cache(mesh);
@@ -1215,7 +1217,7 @@ static void mesh_add_polys(Mesh *mesh, int len)
CustomData_copy_data(&mesh->pdata, &pdata, 0, 0, mesh->totpoly);
if (!CustomData_has_layer(&pdata, CD_MPOLY)) {
- CustomData_add_layer(&pdata, CD_MPOLY, CD_CALLOC, NULL, totpoly);
+ CustomData_add_layer(&pdata, CD_MPOLY, CD_CALLOC, nullptr, totpoly);
}
CustomData_free(&mesh->pdata, mesh->totpoly);
@@ -1413,21 +1415,21 @@ void ED_mesh_report_mirror(wmOperator *op, int totmirr, int totfail)
ED_mesh_report_mirror_ex(op, totmirr, totfail, SCE_SELECT_VERTEX);
}
-Mesh *ED_mesh_context(struct bContext *C)
+Mesh *ED_mesh_context(bContext *C)
{
- Mesh *mesh = CTX_data_pointer_get_type(C, "mesh", &RNA_Mesh).data;
- if (mesh != NULL) {
+ Mesh *mesh = static_cast<Mesh *>(CTX_data_pointer_get_type(C, "mesh", &RNA_Mesh).data);
+ if (mesh != nullptr) {
return mesh;
}
Object *ob = ED_object_active_context(C);
- if (ob == NULL) {
- return NULL;
+ if (ob == nullptr) {
+ return nullptr;
}
ID *data = (ID *)ob->data;
- if (data == NULL || GS(data->name) != ID_ME) {
- return NULL;
+ if (data == nullptr || GS(data->name) != ID_ME) {
+ return nullptr;
}
return (Mesh *)data;
diff --git a/source/blender/editors/mesh/mesh_intern.h b/source/blender/editors/mesh/mesh_intern.h
index b39a0b90f6d..303234df48c 100644
--- a/source/blender/editors/mesh/mesh_intern.h
+++ b/source/blender/editors/mesh/mesh_intern.h
@@ -9,6 +9,10 @@
#pragma once
+#ifdef __cplusplus
+extern "C" {
+#endif
+
struct BMEditMesh;
struct BMElem;
struct BMOperator;
@@ -170,8 +174,7 @@ void MESH_OT_knife_project(struct wmOperatorType *ot);
/**
* \param use_tag: When set, tag all faces inside the polylines.
*/
-void EDBM_mesh_knife(struct bContext *C,
- struct ViewContext *vc,
+void EDBM_mesh_knife(struct ViewContext *vc,
struct LinkNode *polys,
bool use_tag,
bool cut_through);
@@ -301,7 +304,7 @@ void MESH_OT_mark_freestyle_edge(struct wmOperatorType *ot);
void MESH_OT_mark_freestyle_face(struct wmOperatorType *ot);
#endif
-/* *** mesh_data.c *** */
+/* *** mesh_data.cc *** */
void MESH_OT_uv_texture_add(struct wmOperatorType *ot);
void MESH_OT_uv_texture_remove(struct wmOperatorType *ot);
@@ -314,3 +317,7 @@ void MESH_OT_customdata_skin_add(struct wmOperatorType *ot);
void MESH_OT_customdata_skin_clear(struct wmOperatorType *ot);
void MESH_OT_customdata_custom_splitnormals_add(struct wmOperatorType *ot);
void MESH_OT_customdata_custom_splitnormals_clear(struct wmOperatorType *ot);
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/source/blender/editors/mesh/meshtools.c b/source/blender/editors/mesh/meshtools.cc
index 9575fde68f0..9e28e1bafdd 100644
--- a/source/blender/editors/mesh/meshtools.c
+++ b/source/blender/editors/mesh/meshtools.cc
@@ -21,10 +21,8 @@
#include "DNA_view3d_types.h"
#include "DNA_workspace_types.h"
-#include "BLI_blenlib.h"
-#include "BLI_math.h"
-
#include "BKE_context.h"
+#include "BKE_customdata.h"
#include "BKE_deform.h"
#include "BKE_editmesh.h"
#include "BKE_key.h"
@@ -91,7 +89,7 @@ static void join_mesh_single(Depsgraph *depsgraph,
{
int a, b;
- Mesh *me = ob_src->data;
+ Mesh *me = static_cast<Mesh *>(ob_src->data);
MVert *mvert = *mvert_pp;
MEdge *medge = *medge_pp;
MLoop *mloop = *mloop_pp;
@@ -106,12 +104,13 @@ static void join_mesh_single(Depsgraph *depsgraph,
CustomData_copy_data_named(&me->vdata, vdata, 0, *vertofs, me->totvert);
/* vertex groups */
- MDeformVert *dvert = CustomData_get(vdata, *vertofs, CD_MDEFORMVERT);
- MDeformVert *dvert_src = CustomData_get(&me->vdata, 0, CD_MDEFORMVERT);
+ MDeformVert *dvert = (MDeformVert *)CustomData_get(vdata, *vertofs, CD_MDEFORMVERT);
+ const MDeformVert *dvert_src = (const MDeformVert *)CustomData_get(
+ &me->vdata, 0, CD_MDEFORMVERT);
/* Remap to correct new vgroup indices, if needed. */
if (dvert_src) {
- BLI_assert(dvert != NULL);
+ BLI_assert(dvert != nullptr);
/* Build src to merged mapping of vgroup indices. */
int *vgroup_index_map;
@@ -120,7 +119,7 @@ static void join_mesh_single(Depsgraph *depsgraph,
ob_src, ob_dst, &vgroup_index_map_len);
BKE_object_defgroup_index_map_apply(
dvert, me->totvert, vgroup_index_map, vgroup_index_map_len);
- if (vgroup_index_map != NULL) {
+ if (vgroup_index_map != nullptr) {
MEM_freeN(vgroup_index_map);
}
}
@@ -150,11 +149,11 @@ static void join_mesh_single(Depsgraph *depsgraph,
float(*cos)[3] = ((float(*)[3])kb->data) + *vertofs;
/* Check if this mesh has such a shape-key. */
- KeyBlock *okb = me->key ? BKE_keyblock_find_name(me->key, kb->name) : NULL;
+ KeyBlock *okb = me->key ? BKE_keyblock_find_name(me->key, kb->name) : nullptr;
if (okb) {
/* copy this mesh's shape-key to the destination shape-key
* (need to transform first) */
- float(*ocos)[3] = okb->data;
+ float(*ocos)[3] = static_cast<float(*)[3]>(okb->data);
for (a = 0; a < me->totvert; a++, cos++, ocos++) {
copy_v3_v3(*cos, *ocos);
mul_m4_v3(cmat, *cos);
@@ -180,10 +179,10 @@ static void join_mesh_single(Depsgraph *depsgraph,
float(*cos)[3] = ((float(*)[3])kb->data) + *vertofs;
/* Check if this was one of the original shape-keys. */
- KeyBlock *okb = nkey ? BKE_keyblock_find_name(nkey, kb->name) : NULL;
+ KeyBlock *okb = nkey ? BKE_keyblock_find_name(nkey, kb->name) : nullptr;
if (okb) {
/* copy this mesh's shape-key to the destination shape-key */
- float(*ocos)[3] = okb->data;
+ float(*ocos)[3] = static_cast<float(*)[3]>(okb->data);
for (a = 0; a < me->totvert; a++, cos++, ocos++) {
copy_v3_v3(*cos, *ocos);
}
@@ -254,17 +253,17 @@ static void join_mesh_single(Depsgraph *depsgraph,
}
/* Face maps. */
- int *fmap = CustomData_get(pdata, *polyofs, CD_FACEMAP);
- int *fmap_src = CustomData_get(&me->pdata, 0, CD_FACEMAP);
+ int *fmap = (int *)CustomData_get(pdata, *polyofs, CD_FACEMAP);
+ const int *fmap_src = (const int *)CustomData_get(&me->pdata, 0, CD_FACEMAP);
/* Remap to correct new face-map indices, if needed. */
if (fmap_src) {
- BLI_assert(fmap != NULL);
+ BLI_assert(fmap != nullptr);
int *fmap_index_map;
int fmap_index_map_len;
fmap_index_map = BKE_object_facemap_index_map_create(ob_src, ob_dst, &fmap_index_map_len);
BKE_object_facemap_index_map_apply(fmap, me->totpoly, fmap_index_map, fmap_index_map_len);
- if (fmap_index_map != NULL) {
+ if (fmap_index_map != nullptr) {
MEM_freeN(fmap_index_map);
}
}
@@ -290,7 +289,7 @@ static void mesh_join_offset_face_sets_ID(const Mesh *mesh, int *face_set_offset
return;
}
- int *face_sets = CustomData_get_layer(&mesh->pdata, CD_SCULPT_FACE_SETS);
+ int *face_sets = (int *)CustomData_get_layer(&mesh->pdata, CD_SCULPT_FACE_SETS);
if (!face_sets) {
return;
}
@@ -317,20 +316,18 @@ int ED_mesh_join_objects_exec(bContext *C, wmOperator *op)
Main *bmain = CTX_data_main(C);
Scene *scene = CTX_data_scene(C);
Object *ob = CTX_data_active_object(C);
- Material **matar = NULL, *ma;
+ Material **matar = nullptr, *ma;
Mesh *me;
- MVert *mvert = NULL;
- MEdge *medge = NULL;
- MPoly *mpoly = NULL;
- MLoop *mloop = NULL;
- Key *key, *nkey = NULL;
- KeyBlock *kb, *kbn;
+ MVert *mvert = nullptr;
+ MEdge *medge = nullptr;
+ MPoly *mpoly = nullptr;
+ MLoop *mloop = nullptr;
+ Key *key, *nkey = nullptr;
float imat[4][4];
int a, b, totcol, totmat = 0, totedge = 0, totvert = 0;
- int totloop = 0, totpoly = 0, vertofs, *matmap = NULL;
+ int totloop = 0, totpoly = 0, vertofs, *matmap = nullptr;
int i, haskey = 0, edgeofs, loopofs, polyofs;
bool ok = false, join_parent = false;
- bDeformGroup *dg, *odg;
CustomData vdata, edata, fdata, ldata, pdata;
if (ob->mode & OB_MODE_EDIT) {
@@ -349,7 +346,7 @@ int ED_mesh_join_objects_exec(bContext *C, wmOperator *op)
/* count & check */
CTX_DATA_BEGIN (C, Object *, ob_iter, selected_editable_objects) {
if (ob_iter->type == OB_MESH) {
- me = ob_iter->data;
+ me = static_cast<Mesh *>(ob_iter->data);
totvert += me->totvert;
totedge += me->totedge;
@@ -361,7 +358,7 @@ int ED_mesh_join_objects_exec(bContext *C, wmOperator *op)
ok = true;
}
- if ((ob->parent != NULL) && (ob_iter == ob->parent)) {
+ if ((ob->parent != nullptr) && (ob_iter == ob->parent)) {
join_parent = true;
}
@@ -376,7 +373,7 @@ int ED_mesh_join_objects_exec(bContext *C, wmOperator *op)
/* Apply parent transform if the active object's parent was joined to it.
* NOTE: This doesn't apply recursive parenting. */
if (join_parent) {
- ob->parent = NULL;
+ ob->parent = nullptr;
BKE_object_apply_mat4_ex(ob, ob->obmat, ob->parent, ob->parentinv, false);
}
@@ -416,12 +413,12 @@ int ED_mesh_join_objects_exec(bContext *C, wmOperator *op)
/* new material indices and material array */
if (totmat) {
- matar = MEM_callocN(sizeof(*matar) * totmat, "join_mesh matar");
- matmap = MEM_callocN(sizeof(*matmap) * totmat, "join_mesh matmap");
+ matar = static_cast<Material **>(MEM_callocN(sizeof(*matar) * totmat, __func__));
+ matmap = static_cast<int *>(MEM_callocN(sizeof(*matmap) * totmat, __func__));
}
totcol = ob->totcol;
- /* obact materials in new main array, is nicer start! */
+ /* Active object materials in new main array, is nicer start! */
for (a = 0; a < ob->totcol; a++) {
matar[a] = BKE_object_material_get(ob, a + 1);
id_us_plus((ID *)matar[a]);
@@ -438,7 +435,7 @@ int ED_mesh_join_objects_exec(bContext *C, wmOperator *op)
nkey = (Key *)BKE_id_copy(bmain, &key->id);
/* for all keys in old block, clear data-arrays */
- for (kb = key->block.first; kb; kb = kb->next) {
+ LISTBASE_FOREACH (KeyBlock *, kb, &key->block) {
if (kb->data) {
MEM_freeN(kb->data);
}
@@ -462,13 +459,14 @@ int ED_mesh_join_objects_exec(bContext *C, wmOperator *op)
CTX_DATA_BEGIN (C, Object *, ob_iter, selected_editable_objects) {
/* only act if a mesh, and not the one we're joining to */
if ((ob != ob_iter) && (ob_iter->type == OB_MESH)) {
- me = ob_iter->data;
+ me = static_cast<Mesh *>(ob_iter->data);
/* Join this object's vertex groups to the base one's */
- for (dg = me->vertex_group_names.first; dg; dg = dg->next) {
+ LISTBASE_FOREACH (bDeformGroup *, dg, &me->vertex_group_names) {
/* See if this group exists in the object (if it doesn't, add it to the end) */
if (!BKE_object_defgroup_find_name(ob, dg->name)) {
- odg = MEM_mallocN(sizeof(bDeformGroup), "join deformGroup");
+ bDeformGroup *odg = static_cast<bDeformGroup *>(
+ MEM_mallocN(sizeof(bDeformGroup), __func__));
memcpy(odg, dg, sizeof(bDeformGroup));
BLI_addtail(&mesh_active->vertex_group_names, odg);
}
@@ -481,8 +479,8 @@ int ED_mesh_join_objects_exec(bContext *C, wmOperator *op)
/* Join this object's face maps to the base one's. */
LISTBASE_FOREACH (bFaceMap *, fmap, &ob_iter->fmaps) {
/* See if this group exists in the object (if it doesn't, add it to the end) */
- if (BKE_object_facemap_find_name(ob, fmap->name) == NULL) {
- bFaceMap *fmap_new = MEM_mallocN(sizeof(bFaceMap), "join faceMap");
+ if (BKE_object_facemap_find_name(ob, fmap->name) == nullptr) {
+ bFaceMap *fmap_new = static_cast<bFaceMap *>(MEM_mallocN(sizeof(bFaceMap), __func__));
memcpy(fmap_new, fmap, sizeof(bFaceMap));
BLI_addtail(&ob->fmaps, fmap_new);
}
@@ -522,13 +520,15 @@ int ED_mesh_join_objects_exec(bContext *C, wmOperator *op)
* check if destination mesh already has matching entries too. */
if (me->key && key) {
/* for remapping KeyBlock.relative */
- int *index_map = MEM_mallocN(sizeof(int) * me->key->totkey, __func__);
- KeyBlock **kb_map = MEM_mallocN(sizeof(KeyBlock *) * me->key->totkey, __func__);
+ int *index_map = static_cast<int *>(
+ MEM_mallocN(sizeof(int) * me->key->totkey, __func__));
+ KeyBlock **kb_map = static_cast<KeyBlock **>(
+ MEM_mallocN(sizeof(KeyBlock *) * me->key->totkey, __func__));
- for (kb = me->key->block.first, i = 0; kb; kb = kb->next, i++) {
+ LISTBASE_FOREACH_INDEX (KeyBlock *, kb, &me->key->block, i) {
BLI_assert(i < me->key->totkey);
- kbn = BKE_keyblock_find_name(key, kb->name);
+ KeyBlock *kbn = BKE_keyblock_find_name(key, kb->name);
/* if key doesn't exist in destination mesh, add it */
if (kbn) {
index_map[i] = BLI_findindex(&key->block, kbn);
@@ -549,7 +549,7 @@ int ED_mesh_join_objects_exec(bContext *C, wmOperator *op)
}
/* remap relative index values */
- for (kb = me->key->block.first, i = 0; kb; kb = kb->next, i++) {
+ LISTBASE_FOREACH_INDEX (KeyBlock *, kb, &me->key->block, i) {
/* sanity check, should always be true */
if (LIKELY(kb->relative < me->key->totkey)) {
kb_map[i]->relative = index_map[kb->relative];
@@ -571,10 +571,10 @@ int ED_mesh_join_objects_exec(bContext *C, wmOperator *op)
CustomData_reset(&ldata);
CustomData_reset(&pdata);
- mvert = CustomData_add_layer(&vdata, CD_MVERT, CD_CALLOC, NULL, totvert);
- medge = CustomData_add_layer(&edata, CD_MEDGE, CD_CALLOC, NULL, totedge);
- mloop = CustomData_add_layer(&ldata, CD_MLOOP, CD_CALLOC, NULL, totloop);
- mpoly = CustomData_add_layer(&pdata, CD_MPOLY, CD_CALLOC, NULL, totpoly);
+ mvert = (MVert *)CustomData_add_layer(&vdata, CD_MVERT, CD_CALLOC, nullptr, totvert);
+ medge = (MEdge *)CustomData_add_layer(&edata, CD_MEDGE, CD_CALLOC, nullptr, totedge);
+ mloop = (MLoop *)CustomData_add_layer(&ldata, CD_MLOOP, CD_CALLOC, nullptr, totloop);
+ mpoly = (MPoly *)CustomData_add_layer(&pdata, CD_MPOLY, CD_CALLOC, nullptr, totpoly);
vertofs = 0;
edgeofs = 0;
@@ -661,7 +661,7 @@ int ED_mesh_join_objects_exec(bContext *C, wmOperator *op)
CTX_DATA_END;
/* return to mesh we're merging to */
- me = ob->data;
+ me = static_cast<Mesh *>(ob->data);
CustomData_free(&me->vdata, me->totvert);
CustomData_free(&me->edata, me->totedge);
@@ -703,8 +703,8 @@ int ED_mesh_join_objects_exec(bContext *C, wmOperator *op)
if (totcol) {
me->mat = matar;
- ob->mat = MEM_callocN(sizeof(*ob->mat) * totcol, "join obmatar");
- ob->matbits = MEM_callocN(sizeof(*ob->matbits) * totcol, "join obmatbits");
+ ob->mat = static_cast<Material **>(MEM_callocN(sizeof(*ob->mat) * totcol, __func__));
+ ob->matbits = static_cast<char *>(MEM_callocN(sizeof(*ob->matbits) * totcol, __func__));
MEM_freeN(matmap);
}
@@ -751,8 +751,8 @@ int ED_mesh_shapes_join_objects_exec(bContext *C, wmOperator *op)
Object *ob_active = CTX_data_active_object(C);
Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C);
Mesh *me = (Mesh *)ob_active->data;
- Mesh *selme = NULL;
- Mesh *me_deformed = NULL;
+ Mesh *selme = nullptr;
+ Mesh *me_deformed = nullptr;
Key *key = me->key;
KeyBlock *kb;
bool ok = false, nonequal_verts = false;
@@ -769,7 +769,7 @@ int ED_mesh_shapes_join_objects_exec(bContext *C, wmOperator *op)
ok = true;
}
else {
- nonequal_verts = 1;
+ nonequal_verts = true;
}
}
}
@@ -787,12 +787,12 @@ int ED_mesh_shapes_join_objects_exec(bContext *C, wmOperator *op)
return OPERATOR_CANCELLED;
}
- if (key == NULL) {
+ if (key == nullptr) {
key = me->key = BKE_key_add(bmain, (ID *)me);
key->type = KEY_RELATIVE;
/* first key added, so it was the basis. initialize it with the existing mesh */
- kb = BKE_keyblock_add(key, NULL);
+ kb = BKE_keyblock_add(key, nullptr);
BKE_keyblock_convert_from_mesh(me, key, kb);
}
@@ -835,21 +835,21 @@ int ED_mesh_shapes_join_objects_exec(bContext *C, wmOperator *op)
/** \name Mesh Topology Mirror API
* \{ */
-static MirrTopoStore_t mesh_topo_store = {NULL, -1. - 1, -1};
+static MirrTopoStore_t mesh_topo_store = {nullptr, -1, -1, false};
BLI_INLINE void mesh_mirror_topo_table_get_meshes(Object *ob,
Mesh *me_eval,
Mesh **r_me_mirror,
BMEditMesh **r_em_mirror)
{
- Mesh *me_mirror = NULL;
- BMEditMesh *em_mirror = NULL;
+ Mesh *me_mirror = nullptr;
+ BMEditMesh *em_mirror = nullptr;
- Mesh *me = ob->data;
- if (me_eval != NULL) {
+ Mesh *me = static_cast<Mesh *>(ob->data);
+ if (me_eval != nullptr) {
me_mirror = me_eval;
}
- else if (me->edit_mesh != NULL) {
+ else if (me->edit_mesh != nullptr) {
em_mirror = me->edit_mesh;
}
else {
@@ -892,7 +892,7 @@ static bool ed_mesh_mirror_topo_table_update(Object *ob, Mesh *me_eval)
static int mesh_get_x_mirror_vert_spatial(Object *ob, Mesh *me_eval, int index)
{
- Mesh *me = ob->data;
+ Mesh *me = static_cast<Mesh *>(ob->data);
MVert *mvert = me_eval ? me_eval->mvert : me->mvert;
float vec[3];
@@ -901,7 +901,7 @@ static int mesh_get_x_mirror_vert_spatial(Object *ob, Mesh *me_eval, int index)
vec[1] = mvert->co[1];
vec[2] = mvert->co[2];
- return ED_mesh_mirror_spatial_table_lookup(ob, NULL, me_eval, vec);
+ return ED_mesh_mirror_spatial_table_lookup(ob, nullptr, me_eval, vec);
}
static int mesh_get_x_mirror_vert_topo(Object *ob, Mesh *mesh, int index)
@@ -928,28 +928,25 @@ static BMVert *editbmesh_get_x_mirror_vert_spatial(Object *ob, BMEditMesh *em, c
/* ignore nan verts */
if ((isfinite(co[0]) == false) || (isfinite(co[1]) == false) || (isfinite(co[2]) == false)) {
- return NULL;
+ return nullptr;
}
vec[0] = -co[0];
vec[1] = co[1];
vec[2] = co[2];
- i = ED_mesh_mirror_spatial_table_lookup(ob, em, NULL, vec);
+ i = ED_mesh_mirror_spatial_table_lookup(ob, em, nullptr, vec);
if (i != -1) {
return BM_vert_at_index(em->bm, i);
}
- return NULL;
+ return nullptr;
}
-static BMVert *editbmesh_get_x_mirror_vert_topo(Object *ob,
- struct BMEditMesh *em,
- BMVert *eve,
- int index)
+static BMVert *editbmesh_get_x_mirror_vert_topo(Object *ob, BMEditMesh *em, BMVert *eve, int index)
{
intptr_t poinval;
- if (!ed_mesh_mirror_topo_table_update(ob, NULL)) {
- return NULL;
+ if (!ed_mesh_mirror_topo_table_update(ob, nullptr)) {
+ return nullptr;
}
if (index == -1) {
@@ -965,7 +962,7 @@ static BMVert *editbmesh_get_x_mirror_vert_topo(Object *ob,
}
if (index == em->bm->totvert) {
- return NULL;
+ return nullptr;
}
}
@@ -974,15 +971,11 @@ static BMVert *editbmesh_get_x_mirror_vert_topo(Object *ob,
if (poinval != -1) {
return (BMVert *)(poinval);
}
- return NULL;
+ return nullptr;
}
-BMVert *editbmesh_get_x_mirror_vert(Object *ob,
- struct BMEditMesh *em,
- BMVert *eve,
- const float co[3],
- int index,
- const bool use_topology)
+BMVert *editbmesh_get_x_mirror_vert(
+ Object *ob, BMEditMesh *em, BMVert *eve, const float co[3], int index, const bool use_topology)
{
if (use_topology) {
return editbmesh_get_x_mirror_vert_topo(ob, em, eve, index);
@@ -992,7 +985,7 @@ BMVert *editbmesh_get_x_mirror_vert(Object *ob,
int ED_mesh_mirror_get_vert(Object *ob, int index)
{
- Mesh *me = ob->data;
+ Mesh *me = static_cast<Mesh *>(ob->data);
BMEditMesh *em = me->edit_mesh;
bool use_topology = (me->editflag & ME_EDIT_MIRROR_TOPO) != 0;
int index_mirr;
@@ -1004,7 +997,7 @@ int ED_mesh_mirror_get_vert(Object *ob, int index)
index_mirr = eve_mirr ? BM_elem_index_get(eve_mirr) : -1;
}
else {
- index_mirr = mesh_get_x_mirror_vert(ob, NULL, index, use_topology);
+ index_mirr = mesh_get_x_mirror_vert(ob, nullptr, index, use_topology);
}
return index_mirr;
@@ -1021,7 +1014,7 @@ static float *editmesh_get_mirror_uv(
/* ignore nan verts */
if (isnan(uv[0]) || !isfinite(uv[0]) || isnan(uv[1]) || !isfinite(uv[1])) {
- return NULL;
+ return nullptr;
}
if (axis) {
@@ -1061,14 +1054,14 @@ static float *editmesh_get_mirror_uv(
}
}
- return NULL;
+ return nullptr;
}
#endif
static uint mirror_facehash(const void *ptr)
{
- const MFace *mf = ptr;
+ const MFace *mf = static_cast<const MFace *>(ptr);
uint v0, v1;
if (mf->v4) {
@@ -1121,21 +1114,21 @@ static bool mirror_facecmp(const void *a, const void *b)
int *mesh_get_x_mirror_faces(Object *ob, BMEditMesh *em, Mesh *me_eval)
{
- Mesh *me = ob->data;
+ Mesh *me = static_cast<Mesh *>(ob->data);
MVert *mv, *mvert;
MFace mirrormf, *mf, *hashmf, *mface;
GHash *fhash;
int *mirrorverts, *mirrorfaces;
- BLI_assert(em == NULL); /* Does not work otherwise, currently... */
+ BLI_assert(em == nullptr); /* Does not work otherwise, currently... */
const bool use_topology = (me->editflag & ME_EDIT_MIRROR_TOPO) != 0;
const int totvert = me_eval ? me_eval->totvert : me->totvert;
const int totface = me_eval ? me_eval->totface : me->totface;
int a;
- mirrorverts = MEM_callocN(sizeof(int) * totvert, "MirrorVerts");
- mirrorfaces = MEM_callocN(sizeof(int[2]) * totface, "MirrorFaces");
+ mirrorverts = static_cast<int *>(MEM_callocN(sizeof(int) * totvert, "MirrorVerts"));
+ mirrorfaces = static_cast<int *>(MEM_callocN(sizeof(int[2]) * totface, "MirrorFaces"));
mvert = me_eval ? me_eval->mvert : me->mvert;
mface = me_eval ? me_eval->mface : me->mface;
@@ -1165,7 +1158,7 @@ int *mesh_get_x_mirror_faces(Object *ob, BMEditMesh *em, Mesh *me_eval)
SWAP(uint, mirrormf.v2, mirrormf.v4);
}
- hashmf = BLI_ghash_lookup(fhash, &mirrormf);
+ hashmf = static_cast<MFace *>(BLI_ghash_lookup(fhash, &mirrormf));
if (hashmf) {
mirrorfaces[a * 2] = hashmf - mface;
mirrorfaces[a * 2 + 1] = mirror_facerotation(&mirrormf, hashmf);
@@ -1175,7 +1168,7 @@ int *mesh_get_x_mirror_faces(Object *ob, BMEditMesh *em, Mesh *me_eval)
}
}
- BLI_ghash_free(fhash, NULL, NULL);
+ BLI_ghash_free(fhash, nullptr, nullptr);
MEM_freeN(mirrorverts);
return mirrorfaces;
@@ -1186,7 +1179,7 @@ int *mesh_get_x_mirror_faces(Object *ob, BMEditMesh *em, Mesh *me_eval)
bool ED_mesh_pick_face(bContext *C, Object *ob, const int mval[2], uint dist_px, uint *r_index)
{
ViewContext vc;
- Mesh *me = ob->data;
+ Mesh *me = static_cast<Mesh *>(ob->data);
BLI_assert(me && GS(me->id.name) == ID_ME);
@@ -1199,8 +1192,8 @@ bool ED_mesh_pick_face(bContext *C, Object *ob, const int mval[2], uint dist_px,
ED_view3d_select_id_validate(&vc);
if (dist_px) {
- /* sample rect to increase chances of selecting, so that when clicking
- * on an edge in the backbuf, we can still select a face */
+ /* Sample rect to increase chances of selecting, so that when clicking
+ * on an edge in the back-buffer, we can still select a face. */
*r_index = DRW_select_buffer_find_nearest_to_point(
vc.depsgraph, vc.region, vc.v3d, mval, 1, me->totpoly + 1, &dist_px);
}
@@ -1220,7 +1213,7 @@ bool ED_mesh_pick_face(bContext *C, Object *ob, const int mval[2], uint dist_px,
static void ed_mesh_pick_face_vert__mpoly_find(
/* context */
- struct ARegion *region,
+ ARegion *region,
const float mval[2],
/* mesh data (evaluated) */
const MPoly *mp,
@@ -1250,14 +1243,14 @@ bool ED_mesh_pick_face_vert(
{
Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C);
uint poly_index;
- Mesh *me = ob->data;
+ Mesh *me = static_cast<Mesh *>(ob->data);
BLI_assert(me && GS(me->id.name) == ID_ME);
if (ED_mesh_pick_face(C, ob, mval, dist_px, &poly_index)) {
Scene *scene_eval = DEG_get_evaluated_scene(depsgraph);
Object *ob_eval = DEG_get_evaluated_object(depsgraph, ob);
- struct ARegion *region = CTX_wm_region(C);
+ ARegion *region = CTX_wm_region(C);
/* derived mesh to find deformed locations */
Mesh *me_eval = mesh_get_eval_final(
@@ -1266,14 +1259,13 @@ bool ED_mesh_pick_face_vert(
int v_idx_best = ORIGINDEX_NONE;
/* find the vert closest to 'mval' */
- const float mval_f[2] = {UNPACK2(mval)};
+ const float mval_f[2] = {(float)mval[0], (float)mval[1]};
float len_best = FLT_MAX;
MPoly *me_eval_mpoly;
MLoop *me_eval_mloop;
MVert *me_eval_mvert;
uint me_eval_mpoly_len;
- const int *index_mp_to_orig;
me_eval_mpoly = me_eval->mpoly;
me_eval_mloop = me_eval->mloop;
@@ -1281,7 +1273,7 @@ bool ED_mesh_pick_face_vert(
me_eval_mpoly_len = me_eval->totpoly;
- index_mp_to_orig = CustomData_get_layer(&me_eval->pdata, CD_ORIGINDEX);
+ const int *index_mp_to_orig = (const int *)CustomData_get_layer(&me_eval->pdata, CD_ORIGINDEX);
/* tag all verts using this face */
if (index_mp_to_orig) {
@@ -1313,8 +1305,8 @@ bool ED_mesh_pick_face_vert(
/* map 'dm -> me' r_index if possible */
if (v_idx_best != ORIGINDEX_NONE) {
- const int *index_mv_to_orig;
- index_mv_to_orig = CustomData_get_layer(&me_eval->vdata, CD_ORIGINDEX);
+ const int *index_mv_to_orig = (const int *)CustomData_get_layer(&me_eval->vdata,
+ CD_ORIGINDEX);
if (index_mv_to_orig) {
v_idx_best = index_mv_to_orig[v_idx_best];
}
@@ -1335,7 +1327,7 @@ bool ED_mesh_pick_face_vert(
*
* \return boolean true == Found
*/
-typedef struct VertPickData {
+struct VertPickData {
const MVert *mvert;
const float *mval_f; /* [2] */
ARegion *region;
@@ -1343,14 +1335,14 @@ typedef struct VertPickData {
/* runtime */
float len_best;
int v_idx_best;
-} VertPickData;
+};
static void ed_mesh_pick_vert__mapFunc(void *userData,
int index,
const float co[3],
const float UNUSED(no[3]))
{
- VertPickData *data = userData;
+ VertPickData *data = static_cast<VertPickData *>(userData);
if ((data->mvert[index].flag & ME_HIDE) == 0) {
float sco[2];
@@ -1368,7 +1360,7 @@ bool ED_mesh_pick_vert(
bContext *C, Object *ob, const int mval[2], uint dist_px, bool use_zbuf, uint *r_index)
{
ViewContext vc;
- Mesh *me = ob->data;
+ Mesh *me = static_cast<Mesh *>(ob->data);
BLI_assert(me && GS(me->id.name) == ID_ME);
@@ -1382,8 +1374,8 @@ bool ED_mesh_pick_vert(
if (use_zbuf) {
if (dist_px > 0) {
- /* sample rect to increase chances of selecting, so that when clicking
- * on an face in the backbuf, we can still select a vert */
+ /* Sample rectangle to increase chances of selecting, so that when clicking
+ * on an face in the back-buffer, we can still select a vert. */
*r_index = DRW_select_buffer_find_nearest_to_point(
vc.depsgraph, vc.region, vc.v3d, mval, 1, me->totvert + 1, &dist_px);
}
@@ -1405,16 +1397,16 @@ bool ED_mesh_pick_vert(
/* derived mesh to find deformed locations */
Mesh *me_eval = mesh_get_eval_final(vc.depsgraph, scene_eval, ob_eval, &CD_MASK_BAREMESH);
ARegion *region = vc.region;
- RegionView3D *rv3d = region->regiondata;
+ RegionView3D *rv3d = static_cast<RegionView3D *>(region->regiondata);
/* find the vert closest to 'mval' */
const float mval_f[2] = {(float)mval[0], (float)mval[1]};
- VertPickData data = {NULL};
+ VertPickData data = {nullptr};
ED_view3d_init_mats_rv3d(ob, rv3d);
- if (me_eval == NULL) {
+ if (me_eval == nullptr) {
return false;
}
@@ -1440,7 +1432,7 @@ bool ED_mesh_pick_vert(
MDeformVert *ED_mesh_active_dvert_get_em(Object *ob, BMVert **r_eve)
{
if (ob->mode & OB_MODE_EDIT && ob->type == OB_MESH) {
- Mesh *me = ob->data;
+ Mesh *me = static_cast<Mesh *>(ob->data);
if (!BLI_listbase_is_empty(&me->vertex_group_names)) {
BMesh *bm = me->edit_mesh->bm;
const int cd_dvert_offset = CustomData_get_offset(&bm->vdata, CD_MDEFORMVERT);
@@ -1452,27 +1444,27 @@ MDeformVert *ED_mesh_active_dvert_get_em(Object *ob, BMVert **r_eve)
if (r_eve) {
*r_eve = eve;
}
- return BM_ELEM_CD_GET_VOID_P(eve, cd_dvert_offset);
+ return static_cast<MDeformVert *>(BM_ELEM_CD_GET_VOID_P(eve, cd_dvert_offset));
}
}
}
}
if (r_eve) {
- *r_eve = NULL;
+ *r_eve = nullptr;
}
- return NULL;
+ return nullptr;
}
MDeformVert *ED_mesh_active_dvert_get_ob(Object *ob, int *r_index)
{
- Mesh *me = ob->data;
+ Mesh *me = static_cast<Mesh *>(ob->data);
int index = BKE_mesh_mselect_active_get(me, ME_VSEL);
if (r_index) {
*r_index = index;
}
- if (index == -1 || me->dvert == NULL) {
- return NULL;
+ if (index == -1 || me->dvert == nullptr) {
+ return nullptr;
}
return me->dvert + index;
}
@@ -1481,14 +1473,14 @@ MDeformVert *ED_mesh_active_dvert_get_only(Object *ob)
{
if (ob->type == OB_MESH) {
if (ob->mode & OB_MODE_EDIT) {
- return ED_mesh_active_dvert_get_em(ob, NULL);
+ return ED_mesh_active_dvert_get_em(ob, nullptr);
}
- return ED_mesh_active_dvert_get_ob(ob, NULL);
+ return ED_mesh_active_dvert_get_ob(ob, nullptr);
}
- return NULL;
+ return nullptr;
}
-void EDBM_mesh_stats_multi(struct Object **objects,
+void EDBM_mesh_stats_multi(Object **objects,
const uint objects_len,
int totelem[3],
int totelem_sel[3])
diff --git a/source/blender/editors/object/object_add.cc b/source/blender/editors/object/object_add.cc
index db8860efdd8..041a1383b28 100644
--- a/source/blender/editors/object/object_add.cc
+++ b/source/blender/editors/object/object_add.cc
@@ -621,9 +621,16 @@ Object *ED_object_add_type_with_obdata(bContext *C,
else {
ob = BKE_object_add(bmain, view_layer, type, name);
}
- BASACT(view_layer)->local_view_bits = local_view_bits;
- /* editor level activate, notifiers */
- ED_object_base_activate(C, view_layer->basact);
+
+ Base *ob_base_act = BASACT(view_layer);
+ /* While not getting a valid base is not a good thing, it can happen in convoluted corner cases,
+ * better not crash on it in releases. */
+ BLI_assert(ob_base_act != nullptr);
+ if (ob_base_act != nullptr) {
+ ob_base_act->local_view_bits = local_view_bits;
+ /* editor level activate, notifiers */
+ ED_object_base_activate(C, ob_base_act);
+ }
/* more editor stuff */
ED_object_base_init_transform_on_add(ob, loc, rot);
@@ -1265,9 +1272,9 @@ void OBJECT_OT_drop_named_image(wmOperatorType *ot)
"Relative Path",
"Select the file relative to the blend file");
RNA_def_property_flag(prop, (PropertyFlag)(PROP_HIDDEN | PROP_SKIP_SAVE));
- prop = RNA_def_string(
- ot->srna, "name", nullptr, MAX_ID_NAME - 2, "Name", "Image name to assign");
- RNA_def_property_flag(prop, (PropertyFlag)(PROP_HIDDEN | PROP_SKIP_SAVE));
+
+ WM_operator_properties_id_lookup(ot, true);
+
ED_object_add_generic_props(ot, false);
}
@@ -1651,19 +1658,12 @@ static std::optional<CollectionAddInfo> collection_add_info_get_from_op(bContext
Main *bmain = CTX_data_main(C);
PropertyRNA *prop_location = RNA_struct_find_property(op->ptr, "location");
- PropertyRNA *prop_session_uuid = RNA_struct_find_property(op->ptr, "session_uuid");
- PropertyRNA *prop_name = RNA_struct_find_property(op->ptr, "name");
+
+ add_info.collection = reinterpret_cast<Collection *>(
+ WM_operator_properties_id_lookup_from_name_or_session_uuid(bmain, op->ptr, ID_GR));
bool update_location_if_necessary = false;
- if (prop_name && RNA_property_is_set(op->ptr, prop_name)) {
- char name[MAX_ID_NAME - 2];
- RNA_property_string_get(op->ptr, prop_name, name);
- add_info.collection = (Collection *)BKE_libblock_find_name(bmain, ID_GR, name);
- update_location_if_necessary = true;
- }
- else if (RNA_property_is_set(op->ptr, prop_session_uuid)) {
- const uint32_t session_uuid = (uint32_t)RNA_property_int_get(op->ptr, prop_session_uuid);
- add_info.collection = (Collection *)BKE_libblock_find_session_uuid(bmain, ID_GR, session_uuid);
+ if (add_info.collection) {
update_location_if_necessary = true;
}
else {
@@ -1736,8 +1736,7 @@ static int object_instance_add_invoke(bContext *C, wmOperator *op, const wmEvent
RNA_int_set(op->ptr, "drop_y", event->xy[1]);
}
- if (!RNA_struct_property_is_set(op->ptr, "name") &&
- !RNA_struct_property_is_set(op->ptr, "session_uuid")) {
+ if (!WM_operator_properties_id_lookup_is_set(op->ptr)) {
return WM_enum_search_invoke(C, op, event);
}
return op->type->exec(C, op);
@@ -1769,16 +1768,7 @@ void OBJECT_OT_collection_instance_add(wmOperatorType *ot)
ot->prop = prop;
ED_object_add_generic_props(ot, false);
- 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, (PropertyFlag)(PROP_SKIP_SAVE | PROP_HIDDEN));
+ WM_operator_properties_id_lookup(ot, false);
object_add_drop_xy_props(ot);
}
@@ -1875,20 +1865,11 @@ void OBJECT_OT_collection_external_asset_drop(wmOperatorType *ot)
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_INTERNAL;
/* properties */
- 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, (PropertyFlag)(PROP_SKIP_SAVE | PROP_HIDDEN));
+ WM_operator_properties_id_lookup(ot, false);
ED_object_add_generic_props(ot, false);
- /* Important: Instancing option. Intentionally remembered across executions (no #PROP_SKIP_SAVE).
+ /* IMPORTANT: Instancing option. Intentionally remembered across executions (no #PROP_SKIP_SAVE).
*/
RNA_def_boolean(ot->srna,
"use_instance",
@@ -1920,18 +1901,12 @@ static int object_data_instance_add_exec(bContext *C, wmOperator *op)
ushort local_view_bits;
float loc[3], rot[3];
- PropertyRNA *prop_name = RNA_struct_find_property(op->ptr, "name");
PropertyRNA *prop_type = RNA_struct_find_property(op->ptr, "type");
PropertyRNA *prop_location = RNA_struct_find_property(op->ptr, "location");
- /* These shouldn't fail when created by outliner dropping as it checks the ID is valid. */
- if (!RNA_property_is_set(op->ptr, prop_name) || !RNA_property_is_set(op->ptr, prop_type)) {
- return OPERATOR_CANCELLED;
- }
const short id_type = RNA_property_enum_get(op->ptr, prop_type);
- char name[MAX_ID_NAME - 2];
- RNA_property_string_get(op->ptr, prop_name, name);
- id = BKE_libblock_find_name(bmain, id_type, name);
+ id = WM_operator_properties_id_lookup_from_name_or_session_uuid(
+ bmain, op->ptr, (ID_Type)id_type);
if (id == nullptr) {
return OPERATOR_CANCELLED;
}
@@ -1974,7 +1949,7 @@ void OBJECT_OT_data_instance_add(wmOperatorType *ot)
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
/* properties */
- RNA_def_string(ot->srna, "name", "Name", MAX_ID_NAME - 2, "Name", "ID name to add");
+ WM_operator_properties_id_lookup(ot, true);
PropertyRNA *prop = RNA_def_enum(ot->srna, "type", rna_enum_id_type_items, 0, "Type", "");
RNA_def_property_translation_context(prop, BLT_I18NCONTEXT_ID_ID);
ED_object_add_generic_props(ot, false);
@@ -2111,11 +2086,33 @@ static int object_curves_empty_hair_add_exec(bContext *C, wmOperator *op)
Curves *curves_id = static_cast<Curves *>(object->data);
curves_id->surface = surface_ob;
id_us_plus(&surface_ob->id);
+
+ Mesh *surface_mesh = static_cast<Mesh *>(surface_ob->data);
+ const char *uv_name = CustomData_get_active_layer_name(&surface_mesh->ldata, CD_MLOOPUV);
+ if (uv_name != nullptr) {
+ curves_id->surface_uv_map = BLI_strdup(uv_name);
+ }
}
return OPERATOR_FINISHED;
}
+static bool object_curves_empty_hair_add_poll(bContext *C)
+{
+ if (!U.experimental.use_new_curves_type) {
+ return false;
+ }
+ if (!ED_operator_objectmode(C)) {
+ return false;
+ }
+ Object *ob = CTX_data_active_object(C);
+ if (ob == nullptr || ob->type != OB_MESH) {
+ CTX_wm_operator_poll_msg_set(C, "No active mesh object");
+ return false;
+ }
+ return true;
+}
+
void OBJECT_OT_curves_empty_hair_add(wmOperatorType *ot)
{
ot->name = "Add Empty Curves";
@@ -2123,7 +2120,7 @@ void OBJECT_OT_curves_empty_hair_add(wmOperatorType *ot)
ot->idname = "OBJECT_OT_curves_empty_hair_add";
ot->exec = object_curves_empty_hair_add_exec;
- ot->poll = object_curves_add_poll;
+ ot->poll = object_curves_empty_hair_add_poll;
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
@@ -2762,9 +2759,32 @@ static const EnumPropertyItem convert_target_items[] = {
"Point Cloud",
"Point Cloud from Mesh objects"},
#endif
+ {OB_CURVES, "CURVES", ICON_OUTLINER_OB_CURVES, "Curves", "Curves from evaluated curve data"},
{0, nullptr, 0, nullptr, nullptr},
};
+static const EnumPropertyItem *convert_target_items_fn(bContext *UNUSED(C),
+ PointerRNA *UNUSED(ptr),
+ PropertyRNA *UNUSED(prop),
+ bool *r_free)
+{
+ EnumPropertyItem *items = nullptr;
+ int items_num = 0;
+ for (const EnumPropertyItem *item = convert_target_items; item->identifier != nullptr; item++) {
+ if (item->value == OB_CURVES) {
+ if (U.experimental.use_new_curves_type) {
+ RNA_enum_item_add(&items, &items_num, item);
+ }
+ }
+ else {
+ RNA_enum_item_add(&items, &items_num, item);
+ }
+ }
+ RNA_enum_item_end(&items, &items_num);
+ *r_free = true;
+ return items;
+}
+
static void object_data_convert_ensure_curve_cache(Depsgraph *depsgraph, Scene *scene, Object *ob)
{
if (ob->runtime.curve_cache == nullptr) {
@@ -3065,6 +3085,50 @@ static int object_convert_exec(bContext *C, wmOperator *op)
}
ob_gpencil->actcol = actcol;
}
+ else if (target == OB_CURVES) {
+ ob->flag |= OB_DONE;
+
+ Object *ob_eval = DEG_get_evaluated_object(depsgraph, ob);
+ GeometrySet geometry;
+ if (ob_eval->runtime.geometry_set_eval != nullptr) {
+ geometry = *ob_eval->runtime.geometry_set_eval;
+ }
+
+ if (geometry.has_curves()) {
+ if (keep_original) {
+ basen = duplibase_for_convert(bmain, depsgraph, scene, view_layer, base, nullptr);
+ newob = basen->object;
+
+ /* Decrement original curve's usage count. */
+ Curve *legacy_curve = static_cast<Curve *>(newob->data);
+ id_us_min(&legacy_curve->id);
+
+ /* Make a copy of the curve. */
+ newob->data = BKE_id_copy(bmain, &legacy_curve->id);
+ }
+ else {
+ newob = ob;
+ }
+
+ const CurveComponent &curve_component = *geometry.get_component_for_read<CurveComponent>();
+ const Curves *curves_eval = curve_component.get_for_read();
+ Curves *new_curves = static_cast<Curves *>(BKE_id_new(bmain, ID_CV, newob->id.name + 2));
+
+ newob->data = new_curves;
+ newob->type = OB_CURVES;
+
+ blender::bke::CurvesGeometry::wrap(
+ new_curves->geometry) = blender::bke::CurvesGeometry::wrap(curves_eval->geometry);
+ BKE_object_material_from_eval_data(bmain, newob, &curves_eval->id);
+
+ BKE_object_free_derived_caches(newob);
+ BKE_object_free_modifiers(newob, 0);
+ }
+ else {
+ BKE_reportf(
+ op->reports, RPT_WARNING, "Object '%s' has no evaluated curves data", ob->id.name + 2);
+ }
+ }
else if (ob->type == OB_MESH && target == OB_POINTCLOUD) {
ob->flag |= OB_DONE;
@@ -3480,6 +3544,7 @@ void OBJECT_OT_convert(wmOperatorType *ot)
/* properties */
ot->prop = RNA_def_enum(
ot->srna, "target", convert_target_items, OB_MESH, "Target", "Type of object to convert to");
+ RNA_def_enum_funcs(ot->prop, convert_target_items_fn);
RNA_def_boolean(ot->srna,
"keep_original",
false,
@@ -3718,15 +3783,13 @@ static int object_add_named_exec(bContext *C, wmOperator *op)
Main *bmain = CTX_data_main(C);
Scene *scene = CTX_data_scene(C);
ViewLayer *view_layer = CTX_data_view_layer(C);
- Base *basen;
- Object *ob;
const bool linked = RNA_boolean_get(op->ptr, "linked");
const eDupli_ID_Flags dupflag = (linked) ? (eDupli_ID_Flags)0 : (eDupli_ID_Flags)U.dupflag;
- char name[MAX_ID_NAME - 2];
- /* find object, create fake base */
- RNA_string_get(op->ptr, "name", name);
- ob = (Object *)BKE_libblock_find_name(bmain, ID_OB, name);
+ /* Find object, create fake base. */
+
+ Object *ob = reinterpret_cast<Object *>(
+ WM_operator_properties_id_lookup_from_name_or_session_uuid(bmain, op->ptr, ID_OB));
if (ob == nullptr) {
BKE_report(op->reports, RPT_ERROR, "Object not found");
@@ -3734,7 +3797,7 @@ static int object_add_named_exec(bContext *C, wmOperator *op)
}
/* prepare dupli */
- basen = object_add_duplicate_internal(
+ Base *basen = object_add_duplicate_internal(
bmain,
scene,
view_layer,
@@ -3814,7 +3877,7 @@ void OBJECT_OT_add_named(wmOperatorType *ot)
"Linked",
"Duplicate object but not object data, linking to the original data");
- RNA_def_string(ot->srna, "name", nullptr, MAX_ID_NAME - 2, "Name", "Object name to add");
+ WM_operator_properties_id_lookup(ot, true);
prop = RNA_def_float_matrix(
ot->srna, "matrix", 4, 4, nullptr, 0.0f, 0.0f, "Matrix", "", 0.0f, 0.0f);
@@ -3836,14 +3899,11 @@ static int object_transform_to_mouse_exec(bContext *C, wmOperator *op)
{
Main *bmain = CTX_data_main(C);
ViewLayer *view_layer = CTX_data_view_layer(C);
- Object *ob;
- if (RNA_struct_property_is_set(op->ptr, "name")) {
- char name[MAX_ID_NAME - 2];
- RNA_string_get(op->ptr, "name", name);
- ob = (Object *)BKE_libblock_find_name(bmain, ID_OB, name);
- }
- else {
+ Object *ob = reinterpret_cast<Object *>(
+ WM_operator_properties_id_lookup_from_name_or_session_uuid(bmain, op->ptr, ID_OB));
+
+ if (!ob) {
ob = OBACT(view_layer);
}
@@ -3922,12 +3982,25 @@ void OBJECT_OT_transform_to_mouse(wmOperatorType *ot)
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
PropertyRNA *prop;
- RNA_def_string(ot->srna,
- "name",
- nullptr,
- MAX_ID_NAME - 2,
- "Name",
- "Object name to place (when unset use the active object)");
+ prop = RNA_def_string(
+ ot->srna,
+ "name",
+ nullptr,
+ MAX_ID_NAME - 2,
+ "Name",
+ "Object name to place (uses the active object when this and 'session_uuid' are unset)");
+ RNA_def_property_flag(prop, (PropertyFlag)(PROP_SKIP_SAVE | PROP_HIDDEN));
+ prop = RNA_def_int(ot->srna,
+ "session_uuid",
+ 0,
+ INT32_MIN,
+ INT32_MAX,
+ "Session UUID",
+ "Session UUID of the object to place (uses the active object when this and "
+ "'name' are unset)",
+ INT32_MIN,
+ INT32_MAX);
+ RNA_def_property_flag(prop, (PropertyFlag)(PROP_SKIP_SAVE | PROP_HIDDEN));
prop = RNA_def_float_matrix(
ot->srna, "matrix", 4, 4, nullptr, 0.0f, 0.0f, "Matrix", "", 0.0f, 0.0f);
diff --git a/source/blender/editors/object/object_bake.c b/source/blender/editors/object/object_bake.c
index 1483c24ac70..effbde41c38 100644
--- a/source/blender/editors/object/object_bake.c
+++ b/source/blender/editors/object/object_bake.c
@@ -220,22 +220,22 @@ static DerivedMesh *multiresbake_create_loresdm(Scene *scene, Object *ob, int *l
MultiresModifierData *mmd = get_multires_modifier(scene, ob, 0);
Mesh *me = (Mesh *)ob->data;
MultiresModifierData tmp_mmd = *mmd;
- DerivedMesh *cddm = CDDM_from_mesh(me);
- DM_set_only_copy(cddm, &CD_MASK_BAREMESH);
+ *lvl = mmd->lvl;
if (mmd->lvl == 0) {
- dm = CDDM_copy(cddm);
- }
- else {
- tmp_mmd.lvl = mmd->lvl;
- tmp_mmd.sculptlvl = mmd->lvl;
- dm = multires_make_derived_from_derived(cddm, &tmp_mmd, scene, ob, 0);
+ DerivedMesh *cddm = CDDM_from_mesh(me);
+ DM_set_only_copy(cddm, &CD_MASK_BAREMESH);
+ return cddm;
}
- cddm->release(cddm);
+ DerivedMesh *cddm = CDDM_from_mesh(me);
+ DM_set_only_copy(cddm, &CD_MASK_BAREMESH);
+ tmp_mmd.lvl = mmd->lvl;
+ tmp_mmd.sculptlvl = mmd->lvl;
+ dm = multires_make_derived_from_derived(cddm, &tmp_mmd, scene, ob, 0);
- *lvl = mmd->lvl;
+ cddm->release(cddm);
return dm;
}
diff --git a/source/blender/editors/object/object_bake_api.c b/source/blender/editors/object/object_bake_api.c
index a7379d7e492..58daf753679 100644
--- a/source/blender/editors/object/object_bake_api.c
+++ b/source/blender/editors/object/object_bake_api.c
@@ -21,6 +21,8 @@
#include "BLI_path_util.h"
#include "BLI_string.h"
+#include "BKE_attribute.h"
+#include "BKE_callbacks.h"
#include "BKE_context.h"
#include "BKE_global.h"
#include "BKE_image.h"
@@ -446,14 +448,11 @@ static bool bake_object_check(ViewLayer *view_layer,
}
if (target == R_BAKE_TARGET_VERTEX_COLORS) {
- MPropCol *mcol = CustomData_get_layer(&me->vdata, CD_PROP_COLOR);
- const bool mcol_valid = (mcol != NULL);
- MLoopCol *mloopcol = CustomData_get_layer(&me->ldata, CD_PROP_BYTE_COLOR);
- if (mloopcol == NULL && !mcol_valid) {
+ if (BKE_id_attributes_active_color_get(&me->id) == NULL) {
BKE_reportf(reports,
RPT_ERROR,
- "No vertex colors layer found in the object \"%s\"",
- ob->id.name + 2);
+ "Mesh does not have an active color attribute \"%s\"",
+ me->id.name + 2);
return false;
}
}
@@ -937,17 +936,13 @@ static bool bake_targets_output_external(const BakeAPIRender *bkr,
static bool bake_targets_init_vertex_colors(BakeTargets *targets, Object *ob, ReportList *reports)
{
if (ob->type != OB_MESH) {
- BKE_report(
- reports, RPT_ERROR, "Vertex color baking not support with object types other than mesh");
+ BKE_report(reports, RPT_ERROR, "Color attribute baking is only supported for mesh objects");
return false;
}
Mesh *me = ob->data;
- MPropCol *mcol = CustomData_get_layer(&me->vdata, CD_PROP_COLOR);
- const bool mcol_valid = (mcol != NULL);
- MLoopCol *mloopcol = CustomData_get_layer(&me->ldata, CD_PROP_BYTE_COLOR);
- if (mloopcol == NULL && !mcol_valid) {
- BKE_report(reports, RPT_ERROR, "No vertex colors layer found to bake to");
+ if (BKE_id_attributes_active_color_get(&me->id) == NULL) {
+ BKE_report(reports, RPT_ERROR, "No active color attribute to bake to");
return false;
}
@@ -996,10 +991,10 @@ static int find_original_loop(const Mesh *me_orig,
return ORIGINDEX_NONE;
}
-static void bake_targets_populate_pixels_vertex_colors(BakeTargets *targets,
- Object *ob,
- Mesh *me_eval,
- BakePixel *pixel_array)
+static void bake_targets_populate_pixels_color_attributes(BakeTargets *targets,
+ Object *ob,
+ Mesh *me_eval,
+ BakePixel *pixel_array)
{
Mesh *me = ob->data;
const int pixels_num = targets->pixels_num;
@@ -1094,19 +1089,42 @@ static void bake_result_add_to_rgba(float rgba[4], const float *result, const in
}
}
+static void convert_float_color_to_byte_color(const MPropCol *float_colors,
+ const int num,
+ const bool is_noncolor,
+ MLoopCol *byte_colors)
+{
+ if (is_noncolor) {
+ for (int i = 0; i < num; i++) {
+ unit_float_to_uchar_clamp_v4(&byte_colors->r, float_colors[i].color);
+ }
+ }
+ else {
+ for (int i = 0; i < num; i++) {
+ linearrgb_to_srgb_uchar4(&byte_colors[i].r, float_colors[i].color);
+ }
+ }
+}
+
static bool bake_targets_output_vertex_colors(BakeTargets *targets, Object *ob)
{
Mesh *me = ob->data;
- MPropCol *mcol = CustomData_get_layer(&me->vdata, CD_PROP_COLOR);
- const bool mcol_valid = (mcol != NULL);
- MLoopCol *mloopcol = CustomData_get_layer(&me->ldata, CD_PROP_BYTE_COLOR);
+ CustomDataLayer *active_color_layer = BKE_id_attributes_active_color_get(&me->id);
+ BLI_assert(active_color_layer != NULL);
+ const eAttrDomain domain = BKE_id_attribute_domain(&me->id, active_color_layer);
+
const int channels_num = targets->channels_num;
+ const bool is_noncolor = targets->is_noncolor;
const float *result = targets->result;
- if (mcol_valid) {
+ if (domain == ATTR_DOMAIN_POINT) {
const int totvert = me->totvert;
const int totloop = me->totloop;
+ MPropCol *mcol = active_color_layer->type == CD_PROP_COLOR ?
+ active_color_layer->data :
+ MEM_malloc_arrayN(totvert, sizeof(MPropCol), __func__);
+
/* Accumulate float vertex colors in scene linear color space. */
int *num_loops_for_vertex = MEM_callocN(sizeof(int) * me->totvert, "num_loops_for_vertex");
memset(mcol, 0, sizeof(MPropCol) * me->totvert);
@@ -1125,25 +1143,35 @@ static bool bake_targets_output_vertex_colors(BakeTargets *targets, Object *ob)
}
}
+ if (mcol != active_color_layer->data) {
+ convert_float_color_to_byte_color(mcol, totvert, is_noncolor, active_color_layer->data);
+ MEM_freeN(mcol);
+ }
+
MEM_SAFE_FREE(num_loops_for_vertex);
}
- else {
- /* Byte loop colors in sRGB colors space. */
- MLoop *mloop = me->mloop;
- const int totloop = me->totloop;
- const bool is_noncolor = targets->is_noncolor;
-
- for (int i = 0; i < totloop; i++, mloop++, mloopcol++) {
- float rgba[4];
- zero_v4(rgba);
- bake_result_add_to_rgba(rgba, &result[i * channels_num], channels_num);
-
- if (is_noncolor) {
- unit_float_to_uchar_clamp_v4(&mloopcol->r, rgba);
+ else if (domain == ATTR_DOMAIN_CORNER) {
+ switch (active_color_layer->type) {
+ case CD_PROP_COLOR: {
+ MPropCol *colors = active_color_layer->data;
+ for (int i = 0; i < me->totloop; i++) {
+ zero_v4(colors[i].color);
+ bake_result_add_to_rgba(colors[i].color, &result[i * channels_num], channels_num);
+ }
+ break;
}
- else {
- linearrgb_to_srgb_uchar4(&mloopcol->r, rgba);
+ case CD_PROP_BYTE_COLOR: {
+ MLoopCol *colors = active_color_layer->data;
+ for (int i = 0; i < me->totloop; i++) {
+ MPropCol color;
+ zero_v4(color.color);
+ bake_result_add_to_rgba(color.color, &result[i * channels_num], channels_num);
+ convert_float_color_to_byte_color(&color, 1, is_noncolor, &colors[i]);
+ }
+ break;
}
+ default:
+ BLI_assert_unreachable();
}
}
@@ -1197,7 +1225,7 @@ static void bake_targets_populate_pixels(const BakeAPIRender *bkr,
BakePixel *pixel_array)
{
if (bkr->target == R_BAKE_TARGET_VERTEX_COLORS) {
- bake_targets_populate_pixels_vertex_colors(targets, ob, me_eval, pixel_array);
+ bake_targets_populate_pixels_color_attributes(targets, ob, me_eval, pixel_array);
}
else {
RE_bake_pixels_populate(me_eval, pixel_array, targets->pixels_num, targets, bkr->uv_layer);
@@ -1535,7 +1563,7 @@ static int bake(const BakeAPIRender *bkr,
ob_low_eval->obmat);
}
else {
- /* from multiresolution */
+ /* From multi-resolution. */
Mesh *me_nores = NULL;
ModifierData *md = NULL;
int mode;
@@ -1806,6 +1834,17 @@ static void bake_startjob(void *bkv, short *UNUSED(stop), short *do_update, floa
RE_SetReports(bkr->render, NULL);
}
+static void bake_job_complete(void *bkv)
+{
+ BakeAPIRender *bkr = (BakeAPIRender *)bkv;
+ BKE_callback_exec_id(bkr->main, &bkr->ob->id, BKE_CB_EVT_OBJECT_BAKE_COMPLETE);
+}
+static void bake_job_canceled(void *bkv)
+{
+ BakeAPIRender *bkr = (BakeAPIRender *)bkv;
+ BKE_callback_exec_id(bkr->main, &bkr->ob->id, BKE_CB_EVT_OBJECT_BAKE_CANCEL);
+}
+
static void bake_freejob(void *bkv)
{
BakeAPIRender *bkr = (BakeAPIRender *)bkv;
@@ -1941,6 +1980,7 @@ static int bake_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event)
/* init bake render */
bake_init_api_data(op, C, bkr);
+ BKE_callback_exec_id(CTX_data_main(C), &bkr->ob->id, BKE_CB_EVT_OBJECT_BAKE_PRE);
re = bkr->render;
/* setup new render */
@@ -1958,7 +1998,8 @@ static int bake_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event)
/* TODO: only draw bake image, can we enforce this. */
WM_jobs_timer(
wm_job, 0.5, (bkr->target == R_BAKE_TARGET_VERTEX_COLORS) ? NC_GEOM | ND_DATA : NC_IMAGE, 0);
- WM_jobs_callbacks(wm_job, bake_startjob, NULL, NULL, NULL);
+ WM_jobs_callbacks_ex(
+ wm_job, bake_startjob, NULL, NULL, NULL, bake_job_complete, bake_job_canceled);
G.is_break = false;
G.is_rendering = true;
diff --git a/source/blender/editors/object/object_collection.c b/source/blender/editors/object/object_collection.c
index 054c9e1de46..39951c2ab6e 100644
--- a/source/blender/editors/object/object_collection.c
+++ b/source/blender/editors/object/object_collection.c
@@ -526,7 +526,7 @@ void OBJECT_OT_collection_link(wmOperatorType *ot)
ot->prop = prop;
}
-static int collection_remove_exec(bContext *C, wmOperator *UNUSED(op))
+static int collection_remove_exec(bContext *C, wmOperator *op)
{
Main *bmain = CTX_data_main(C);
Object *ob = ED_object_context(C);
@@ -535,6 +535,12 @@ static int collection_remove_exec(bContext *C, wmOperator *UNUSED(op))
if (!ob || !collection) {
return OPERATOR_CANCELLED;
}
+ if (ID_IS_LINKED(collection) || ID_IS_OVERRIDE_LIBRARY(collection)) {
+ BKE_report(op->reports,
+ RPT_ERROR,
+ "Cannot remove an object from a linked or library override collection");
+ return OPERATOR_CANCELLED;
+ }
BKE_collection_object_remove(bmain, collection, ob, false);
@@ -561,7 +567,7 @@ void OBJECT_OT_collection_remove(wmOperatorType *ot)
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
}
-static int collection_unlink_exec(bContext *C, wmOperator *UNUSED(op))
+static int collection_unlink_exec(bContext *C, wmOperator *op)
{
Main *bmain = CTX_data_main(C);
Collection *collection = CTX_data_pointer_get_type(C, "collection", &RNA_Collection).data;
@@ -569,6 +575,14 @@ static int collection_unlink_exec(bContext *C, wmOperator *UNUSED(op))
if (!collection) {
return OPERATOR_CANCELLED;
}
+ if (ID_IS_OVERRIDE_LIBRARY(collection) &&
+ collection->id.override_library->hierarchy_root != &collection->id) {
+ BKE_report(op->reports,
+ RPT_ERROR,
+ "Cannot unlink a library override collection which is not the root of its override "
+ "hierarchy");
+ return OPERATOR_CANCELLED;
+ }
BKE_id_delete(bmain, collection);
diff --git a/source/blender/editors/object/object_constraint.c b/source/blender/editors/object/object_constraint.c
index d982d86fe77..bf3b71178e8 100644
--- a/source/blender/editors/object/object_constraint.c
+++ b/source/blender/editors/object/object_constraint.c
@@ -245,13 +245,11 @@ static void set_constraint_nth_target(bConstraint *con,
const char subtarget[],
int index)
{
- const bConstraintTypeInfo *cti = BKE_constraint_typeinfo_get(con);
ListBase targets = {NULL, NULL};
bConstraintTarget *ct;
int num_targets, i;
- if (cti && cti->get_constraint_targets) {
- cti->get_constraint_targets(con, &targets);
+ if (BKE_constraint_targets_get(con, &targets)) {
num_targets = BLI_listbase_count(&targets);
if (index < 0) {
@@ -274,9 +272,7 @@ static void set_constraint_nth_target(bConstraint *con,
}
}
- if (cti->flush_constraint_targets) {
- cti->flush_constraint_targets(con, &targets, 0);
- }
+ BKE_constraint_targets_flush(con, &targets, 0);
}
}
@@ -289,7 +285,6 @@ static void set_constraint_nth_target(bConstraint *con,
static void test_constraint(
Main *bmain, Object *owner, bPoseChannel *pchan, bConstraint *con, int type)
{
- const bConstraintTypeInfo *cti = BKE_constraint_typeinfo_get(con);
ListBase targets = {NULL, NULL};
bConstraintTarget *ct;
bool check_targets = true;
@@ -465,14 +460,7 @@ static void test_constraint(
}
/* Check targets for constraints */
- if (check_targets && cti && cti->get_constraint_targets) {
- cti->get_constraint_targets(con, &targets);
-
- /* constraints with empty target list that actually require targets */
- if (!targets.first && ELEM(con->type, CONSTRAINT_TYPE_ARMATURE)) {
- con->flag |= CONSTRAINT_DISABLE;
- }
-
+ if (check_targets && BKE_constraint_targets_get(con, &targets)) {
/* disable and clear constraints targets that are incorrect */
for (ct = targets.first; ct; ct = ct->next) {
/* general validity checks (for those constraints that need this) */
@@ -543,8 +531,12 @@ static void test_constraint(
}
/* free any temporary targets */
- if (cti->flush_constraint_targets) {
- cti->flush_constraint_targets(con, &targets, 0);
+ BKE_constraint_targets_flush(con, &targets, 0);
+ }
+ else if (check_targets) {
+ /* constraints with empty target list that actually require targets */
+ if (ELEM(con->type, CONSTRAINT_TYPE_ARMATURE)) {
+ con->flag |= CONSTRAINT_DISABLE;
}
}
}
diff --git a/source/blender/editors/object/object_data_transfer.c b/source/blender/editors/object/object_data_transfer.c
index dfe858e5bd9..4837b538bf6 100644
--- a/source/blender/editors/object/object_data_transfer.c
+++ b/source/blender/editors/object/object_data_transfer.c
@@ -45,7 +45,7 @@
* Note some are 'fake' ones, i.e. they are not hold by real CDLayers. */
/* Not shared with modifier, since we use a usual enum here, not a multi-choice one. */
static const EnumPropertyItem DT_layer_items[] = {
- {0, "", 0, "Vertex Data", ""},
+ RNA_ENUM_ITEM_HEADING("Vertex Data", NULL),
{DT_TYPE_MDEFORMVERT,
"VGROUP_WEIGHTS",
0,
@@ -60,7 +60,8 @@ static const EnumPropertyItem DT_layer_items[] = {
{DT_TYPE_SKIN, "SKIN", 0, "Skin Weight", "Transfer skin weights"},
#endif
{DT_TYPE_BWEIGHT_VERT, "BEVEL_WEIGHT_VERT", 0, "Bevel Weight", "Transfer bevel weights"},
- {0, "", 0, "Edge Data", ""},
+
+ RNA_ENUM_ITEM_HEADING("Edge Data", NULL),
{DT_TYPE_SHARP_EDGE, "SHARP_EDGE", 0, "Sharp", "Transfer sharp mark"},
{DT_TYPE_SEAM, "SEAM", 0, "UV Seam", "Transfer UV seam mark"},
{DT_TYPE_CREASE, "CREASE", 0, "Subdivision Crease", "Transfer crease values"},
@@ -70,11 +71,13 @@ static const EnumPropertyItem DT_layer_items[] = {
0,
"Freestyle Mark",
"Transfer Freestyle edge mark"},
- {0, "", 0, "Face Corner Data", ""},
+
+ RNA_ENUM_ITEM_HEADING("Face Corner Data", NULL),
{DT_TYPE_LNOR, "CUSTOM_NORMAL", 0, "Custom Normals", "Transfer custom normals"},
{DT_TYPE_MPROPCOL_LOOP | DT_TYPE_MLOOPCOL_LOOP, "VCOL", 0, "Colors", "Color Attributes"},
{DT_TYPE_UV, "UV", 0, "UVs", "Transfer UV layers"},
- {0, "", 0, "Face Data", ""},
+
+ RNA_ENUM_ITEM_HEADING("Face Data", NULL),
{DT_TYPE_SHARP_FACE, "SMOOTH", 0, "Smooth", "Transfer flat/smooth mark"},
{DT_TYPE_FREESTYLE_FACE,
"FREESTYLE_FACE",
@@ -85,14 +88,14 @@ static const EnumPropertyItem DT_layer_items[] = {
};
static void dt_add_vcol_layers(CustomData *cdata,
- CustomDataMask mask,
+ eCustomDataMask mask,
EnumPropertyItem **r_item,
int *r_totitem)
{
int types[2] = {CD_PROP_COLOR, CD_PROP_BYTE_COLOR};
for (int i = 0; i < 2; i++) {
- CustomDataType type = types[i];
+ eCustomDataType type = types[i];
if (!(mask & CD_TYPE_AS_MASK(type))) {
continue;
diff --git a/source/blender/editors/object/object_edit.c b/source/blender/editors/object/object_edit.c
index cb0e76c11e4..e5dd9fb2c8b 100644
--- a/source/blender/editors/object/object_edit.c
+++ b/source/blender/editors/object/object_edit.c
@@ -17,6 +17,7 @@
#include "BLI_blenlib.h"
#include "BLI_ghash.h"
+#include "BLI_math_rotation.h"
#include "BLI_utildefines.h"
#include "BLT_translation.h"
@@ -86,6 +87,7 @@
#include "RNA_access.h"
#include "RNA_define.h"
#include "RNA_enum_types.h"
+#include "RNA_types.h"
#include "UI_interface_icons.h"
@@ -1241,6 +1243,9 @@ static int object_calculate_paths_exec(bContext *C, wmOperator *op)
ED_objects_recalculate_paths_selected(C, scene, OBJECT_PATH_CALC_RANGE_FULL);
/* notifiers for updates */
+ WM_event_add_notifier(C, NC_OBJECT | ND_DRAW_ANIMVIZ, NULL);
+ /* Note: the notifier below isn't actually correct, but kept around just to be on the safe side.
+ * If further testing shows it's not necessary (for both bones and objects) removal is fine. */
WM_event_add_notifier(C, NC_OBJECT | ND_TRANSFORM | ND_POSE, NULL);
return OPERATOR_FINISHED;
@@ -1310,6 +1315,9 @@ static int object_update_paths_exec(bContext *C, wmOperator *op)
ED_objects_recalculate_paths_selected(C, scene, OBJECT_PATH_CALC_RANGE_FULL);
/* notifiers for updates */
+ WM_event_add_notifier(C, NC_OBJECT | ND_DRAW_ANIMVIZ, NULL);
+ /* Note: the notifier below isn't actually correct, but kept around just to be on the safe side.
+ * If further testing shows it's not necessary (for both bones and objects) removal is fine. */
WM_event_add_notifier(C, NC_OBJECT | ND_TRANSFORM | ND_POSE, NULL);
return OPERATOR_FINISHED;
@@ -1461,6 +1469,8 @@ void OBJECT_OT_paths_clear(wmOperatorType *ot)
static int shade_smooth_exec(bContext *C, wmOperator *op)
{
const bool use_smooth = STREQ(op->idname, "OBJECT_OT_shade_smooth");
+ const bool use_auto_smooth = RNA_boolean_get(op->ptr, "use_auto_smooth");
+ const float auto_smooth_angle = RNA_float_get(op->ptr, "auto_smooth_angle");
bool changed_multi = false;
bool has_linked_data = false;
@@ -1508,6 +1518,7 @@ static int shade_smooth_exec(bContext *C, wmOperator *op)
bool changed = false;
if (ob->type == OB_MESH) {
BKE_mesh_smooth_flag_set(ob->data, use_smooth);
+ BKE_mesh_auto_smooth_flag_set(ob->data, use_auto_smooth, auto_smooth_angle);
BKE_mesh_batch_cache_dirty_tag(ob->data, BKE_MESH_BATCH_DIRTY_ALL);
changed = true;
}
@@ -1577,6 +1588,25 @@ void OBJECT_OT_shade_smooth(wmOperatorType *ot)
/* flags */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+
+ /* properties */
+ PropertyRNA *prop;
+
+ prop = RNA_def_boolean(
+ ot->srna,
+ "use_auto_smooth",
+ false,
+ "Auto Smooth",
+ "Enable automatic smooth based on smooth/sharp faces/edges and angle between faces");
+ RNA_def_property_flag(prop, PROP_SKIP_SAVE);
+
+ prop = RNA_def_property(ot->srna, "auto_smooth_angle", PROP_FLOAT, PROP_ANGLE);
+ RNA_def_property_range(prop, 0.0f, DEG2RADF(180.0f));
+ RNA_def_property_float_default(prop, DEG2RADF(30.0f));
+ RNA_def_property_ui_text(prop,
+ "Angle",
+ "Maximum angle between face normals that will be considered as smooth"
+ "(unused if custom split normals data are available)");
}
/** \} */
@@ -1811,6 +1841,11 @@ static int move_to_collection_exec(bContext *C, wmOperator *op)
return OPERATOR_CANCELLED;
}
+ if (ID_IS_OVERRIDE_LIBRARY(collection)) {
+ BKE_report(op->reports, RPT_ERROR, "Cannot add objects to a library override collection");
+ return OPERATOR_CANCELLED;
+ }
+
ListBase objects = selected_objects_get(C);
if (is_new) {
diff --git a/source/blender/editors/object/object_modes.c b/source/blender/editors/object/object_modes.c
index fdf2cae026d..0055cdf9ea1 100644
--- a/source/blender/editors/object/object_modes.c
+++ b/source/blender/editors/object/object_modes.c
@@ -458,7 +458,7 @@ static bool object_transfer_mode_to_base(bContext *C, wmOperator *op, Base *base
return false;
}
- bool mode_transfered = false;
+ bool mode_transferred = false;
ED_undo_group_begin(C);
@@ -480,11 +480,11 @@ static bool object_transfer_mode_to_base(bContext *C, wmOperator *op, Base *base
WM_event_add_notifier(C, NC_SCENE | ND_OB_SELECT, scene);
WM_toolsystem_update_from_context_view3d(C);
- mode_transfered = true;
+ mode_transferred = true;
}
ED_undo_group_end(C);
- return mode_transfered;
+ return mode_transferred;
}
static int object_transfer_mode_invoke(bContext *C, wmOperator *op, const wmEvent *event)
@@ -493,8 +493,8 @@ static int object_transfer_mode_invoke(bContext *C, wmOperator *op, const wmEven
const eObjectMode src_mode = (eObjectMode)ob_src->mode;
Base *base_dst = ED_view3d_give_base_under_cursor(C, event->mval);
- const bool mode_transfered = object_transfer_mode_to_base(C, op, base_dst);
- if (!mode_transfered) {
+ const bool mode_transferred = object_transfer_mode_to_base(C, op, base_dst);
+ if (!mode_transferred) {
return OPERATOR_CANCELLED;
}
diff --git a/source/blender/editors/object/object_modifier.cc b/source/blender/editors/object/object_modifier.cc
index 3328fe65f2e..202c6d96a47 100644
--- a/source/blender/editors/object/object_modifier.cc
+++ b/source/blender/editors/object/object_modifier.cc
@@ -515,12 +515,12 @@ void ED_object_modifier_copy_to_object(bContext *C,
DEG_relations_tag_update(bmain);
}
-bool ED_object_modifier_convert(ReportList *UNUSED(reports),
- Main *bmain,
- Depsgraph *depsgraph,
- ViewLayer *view_layer,
- Object *ob,
- ModifierData *md)
+bool ED_object_modifier_convert_psys_to_mesh(ReportList *UNUSED(reports),
+ Main *bmain,
+ Depsgraph *depsgraph,
+ ViewLayer *view_layer,
+ Object *ob,
+ ModifierData *md)
{
int cvert = 0;
@@ -740,7 +740,13 @@ static bool modifier_apply_obdata(
}
else {
Mesh *mesh_applied = modifier_apply_create_mesh_for_modifier(
- depsgraph, ob, md_eval, true, true);
+ depsgraph,
+ ob,
+ md_eval,
+ /* It's important not to apply virtual modifiers (e.g. shape-keys) because they're kept,
+ * causing them to be applied twice, see: T97758. */
+ false,
+ true);
if (!mesh_applied) {
BKE_report(reports, RPT_ERROR, "Modifier returned error, skipping apply");
return false;
@@ -1462,7 +1468,7 @@ static int modifier_apply_exec_ex(bContext *C, wmOperator *op, int apply_as, boo
return OPERATOR_CANCELLED;
}
- if (do_merge_customdata &&
+ if (ob->type == OB_MESH && do_merge_customdata &&
(mti->type & (eModifierTypeType_Constructive | eModifierTypeType_Nonconstructive))) {
BKE_mesh_merge_customdata_for_apply_modifier((Mesh *)ob->data);
}
@@ -1525,12 +1531,12 @@ void OBJECT_OT_modifier_apply(wmOperatorType *ot)
edit_modifier_properties(ot);
edit_modifier_report_property(ot);
- RNA_def_boolean(
- ot->srna,
- "merge_customdata",
- true,
- "Merge UV's",
- "Merge UV coordinates that share a vertex to account for imprecision in some modifiers");
+ RNA_def_boolean(ot->srna,
+ "merge_customdata",
+ true,
+ "Merge UV's",
+ "For mesh objects, merge UV coordinates that share a vertex to account for "
+ "imprecision in some modifiers");
PropertyRNA *prop = RNA_def_boolean(ot->srna,
"single_user",
false,
@@ -1602,7 +1608,7 @@ void OBJECT_OT_modifier_apply_as_shapekey(wmOperatorType *ot)
/** \} */
/* ------------------------------------------------------------------- */
-/** \name Convert Modifier Operator
+/** \name Convert Particle System Modifier to Mesh Operator
* \{ */
static int modifier_convert_exec(bContext *C, wmOperator *op)
@@ -1612,18 +1618,12 @@ static int modifier_convert_exec(bContext *C, wmOperator *op)
ViewLayer *view_layer = CTX_data_view_layer(C);
Object *ob = ED_object_active_context(C);
ModifierData *md = edit_modifier_property_get(op, ob, 0);
- const ModifierTypeInfo *mti = BKE_modifier_get_info((ModifierType)md->type);
- const bool do_merge_customdata = RNA_boolean_get(op->ptr, "merge_customdata");
- if (!md || !ED_object_modifier_convert(op->reports, bmain, depsgraph, view_layer, ob, md)) {
+ if (!md || !ED_object_modifier_convert_psys_to_mesh(
+ op->reports, bmain, depsgraph, view_layer, ob, md)) {
return OPERATOR_CANCELLED;
}
- if (do_merge_customdata &&
- (mti->type & (eModifierTypeType_Constructive | eModifierTypeType_Nonconstructive))) {
- BKE_mesh_merge_customdata_for_apply_modifier((Mesh *)ob->data);
- }
-
DEG_id_tag_update(&ob->id, ID_RECALC_GEOMETRY);
WM_event_add_notifier(C, NC_OBJECT | ND_MODIFIER, ob);
@@ -1640,7 +1640,7 @@ static int modifier_convert_invoke(bContext *C, wmOperator *op, const wmEvent *U
void OBJECT_OT_modifier_convert(wmOperatorType *ot)
{
- ot->name = "Convert Modifier";
+ ot->name = "Convert Particles to Mesh";
ot->description = "Convert particles to a mesh object";
ot->idname = "OBJECT_OT_modifier_convert";
@@ -1651,13 +1651,6 @@ void OBJECT_OT_modifier_convert(wmOperatorType *ot)
/* flags */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_INTERNAL;
edit_modifier_properties(ot);
-
- RNA_def_boolean(
- ot->srna,
- "merge_customdata",
- true,
- "Merge UV's",
- "Merge UV coordinates that share a vertex to account for imprecision in some modifiers");
}
/** \} */
@@ -3393,6 +3386,7 @@ static int geometry_node_tree_copy_assign_exec(bContext *C, wmOperator *UNUSED(o
nmd->node_group = new_tree;
id_us_min(&tree->id);
+ DEG_relations_tag_update(bmain);
WM_event_add_notifier(C, NC_OBJECT | ND_MODIFIER, ob);
return OPERATOR_FINISHED;
}
diff --git a/source/blender/editors/object/object_ops.c b/source/blender/editors/object/object_ops.c
index 1067c2d6a95..8a0d380ff2f 100644
--- a/source/blender/editors/object/object_ops.c
+++ b/source/blender/editors/object/object_ops.c
@@ -281,7 +281,7 @@ void ED_operatormacros_object(void)
ot = WM_operatortype_append_macro("OBJECT_OT_duplicate_move",
"Duplicate Objects",
- "Duplicate selected objects and move them",
+ "Duplicate the selected objects and move them",
OPTYPE_UNDO | OPTYPE_REGISTER);
if (ot) {
WM_operatortype_macro_define(ot, "OBJECT_OT_duplicate");
@@ -289,11 +289,11 @@ void ED_operatormacros_object(void)
RNA_boolean_set(otmacro->ptr, "use_proportional_edit", false);
}
- /* grr, should be able to pass options on... */
- ot = WM_operatortype_append_macro("OBJECT_OT_duplicate_move_linked",
- "Duplicate Linked",
- "Duplicate selected objects and move them",
- OPTYPE_UNDO | OPTYPE_REGISTER);
+ ot = WM_operatortype_append_macro(
+ "OBJECT_OT_duplicate_move_linked",
+ "Duplicate Linked",
+ "Duplicate the selected objects, but not their object data, and move them",
+ OPTYPE_UNDO | OPTYPE_REGISTER);
if (ot) {
otmacro = WM_operatortype_macro_define(ot, "OBJECT_OT_duplicate");
RNA_boolean_set(otmacro->ptr, "linked", true);
diff --git a/source/blender/editors/object/object_relations.c b/source/blender/editors/object/object_relations.c
index 5ef8e573e27..f55ffdf0fcd 100644
--- a/source/blender/editors/object/object_relations.c
+++ b/source/blender/editors/object/object_relations.c
@@ -1653,7 +1653,7 @@ void OBJECT_OT_make_links_data(wmOperatorType *ot)
"Link Instance Collection",
"Replace assigned Collection Instance"},
{MAKE_LINKS_FONTS, "FONTS", 0, "Link Fonts to Text", "Replace Text object Fonts"},
- {0, "", 0, NULL, NULL},
+ RNA_ENUM_ITEM_SEPR,
{MAKE_LINKS_MODIFIERS, "MODIFIERS", 0, "Copy Modifiers", "Replace Modifiers"},
{MAKE_LINKS_SHADERFX,
"EFFECTS",
@@ -1964,7 +1964,7 @@ static void single_objectdata_action_users(
ID *id_act = (ID *)adt->action;
if (single_data_needs_duplication(id_act)) {
DEG_id_tag_update(&ob->id, ID_RECALC_GEOMETRY);
- BKE_animdata_duplicate_id_action(bmain, &ob->id, USER_DUP_ACT | USER_DUP_LINKED_ID);
+ BKE_animdata_duplicate_id_action(bmain, id_obdata, USER_DUP_ACT | USER_DUP_LINKED_ID);
}
}
}
@@ -2258,49 +2258,6 @@ static bool make_override_library_object_overridable_check(Main *bmain, Object *
return false;
}
-/* Set the object to override. */
-static int make_override_library_invoke(bContext *C, wmOperator *op, const wmEvent *event)
-{
- Main *bmain = CTX_data_main(C);
- Scene *scene = CTX_data_scene(C);
- Object *obact = ED_object_active_context(C);
-
- /* Sanity checks. */
- if (!scene || ID_IS_LINKED(scene) || !obact) {
- return OPERATOR_CANCELLED;
- }
-
- if ((!ID_IS_LINKED(obact) && obact->instance_collection != NULL &&
- ID_IS_OVERRIDABLE_LIBRARY(obact->instance_collection)) ||
- make_override_library_object_overridable_check(bmain, obact)) {
- uiPopupMenu *pup = UI_popup_menu_begin(C, IFACE_("OK?"), ICON_QUESTION);
- uiLayout *layout = UI_popup_menu_layout(pup);
-
- /* Create operator menu item with relevant properties filled in. */
- PointerRNA opptr_dummy;
- uiItemFullO_ptr(
- layout, op->type, op->type->name, ICON_NONE, NULL, WM_OP_EXEC_REGION_WIN, 0, &opptr_dummy);
-
- /* Present the menu and be done... */
- UI_popup_menu_end(C, pup);
-
- /* This invoke just calls another instance of this operator... */
- return OPERATOR_INTERFACE;
- }
-
- if (ID_IS_LINKED(obact)) {
- /* Show menu with list of directly linked collections containing the active object. */
- WM_enum_search_invoke(C, op, event);
- return OPERATOR_CANCELLED;
- }
-
- /* Error.. cannot continue. */
- BKE_report(op->reports,
- RPT_ERROR,
- "Can only make library override for a referenced object or collection");
- return OPERATOR_CANCELLED;
-}
-
static int make_override_library_exec(bContext *C, wmOperator *op)
{
Main *bmain = CTX_data_main(C);
@@ -2310,8 +2267,12 @@ static int make_override_library_exec(bContext *C, wmOperator *op)
ID *id_root = NULL;
bool is_override_instancing_object = false;
- GSet *user_overrides_objects_uids = BLI_gset_new(
- BLI_ghashutil_inthash_p, BLI_ghashutil_intcmp, __func__);
+ const bool do_fully_editable = RNA_boolean_get(op->ptr, "do_fully_editable");
+
+ GSet *user_overrides_objects_uids = do_fully_editable ? NULL :
+ BLI_gset_new(BLI_ghashutil_inthash_p,
+ BLI_ghashutil_intcmp,
+ __func__);
bool user_overrides_from_selected_objects = false;
if (!ID_IS_LINKED(obact) && obact->instance_collection != NULL &&
@@ -2329,27 +2290,19 @@ static int make_override_library_exec(bContext *C, wmOperator *op)
user_overrides_from_selected_objects = false;
}
else if (!make_override_library_object_overridable_check(bmain, obact)) {
- const int i = RNA_property_enum_get(op->ptr, op->type->prop);
- const uint collection_session_uuid = *((uint *)&i);
+ const int i = RNA_property_int_get(op->ptr, op->type->prop);
+ const uint collection_session_uuid = *((const uint *)&i);
if (collection_session_uuid == MAIN_ID_SESSION_UUID_UNSET) {
BKE_reportf(op->reports,
RPT_ERROR_INVALID_INPUT,
- "Active object '%s' is not overridable",
+ "Could not find an overridable root hierarchy for object '%s'",
obact->id.name + 2);
return OPERATOR_CANCELLED;
}
-
Collection *collection = BLI_listbase_bytes_find(&bmain->collections,
&collection_session_uuid,
sizeof(collection_session_uuid),
offsetof(ID, session_uuid));
- if (!ID_IS_OVERRIDABLE_LIBRARY(collection)) {
- BKE_reportf(op->reports,
- RPT_ERROR_INVALID_INPUT,
- "Could not find an overridable collection containing object '%s'",
- obact->id.name + 2);
- return OPERATOR_CANCELLED;
- }
id_root = &collection->id;
user_overrides_from_selected_objects = true;
}
@@ -2359,7 +2312,10 @@ static int make_override_library_exec(bContext *C, wmOperator *op)
user_overrides_from_selected_objects = true;
}
- if (user_overrides_from_selected_objects) {
+ if (do_fully_editable) {
+ /* Pass. */
+ }
+ else if (user_overrides_from_selected_objects) {
/* Only selected objects can be 'user overrides'. */
FOREACH_SELECTED_OBJECT_BEGIN (view_layer, CTX_wm_view3d(C), ob_iter) {
BLI_gset_add(user_overrides_objects_uids, POINTER_FROM_UINT(ob_iter->id.session_uuid));
@@ -2379,30 +2335,65 @@ static int make_override_library_exec(bContext *C, wmOperator *op)
BKE_main_id_tag_all(bmain, LIB_TAG_DOIT, false);
ID *id_root_override;
- const bool success = BKE_lib_override_library_create(
- bmain, scene, view_layer, NULL, id_root, id_root, &obact->id, &id_root_override);
-
- /* Define liboverrides from selected/validated objects as user defined. */
- ID *id_hierarchy_root_override = id_root_override->override_library->hierarchy_root;
- ID *id_iter;
- FOREACH_MAIN_ID_BEGIN (bmain, id_iter) {
- if (ID_IS_LINKED(id_iter) || !ID_IS_OVERRIDE_LIBRARY_REAL(id_iter) ||
- id_iter->override_library->hierarchy_root != id_hierarchy_root_override) {
- continue;
- }
- if (BLI_gset_haskey(user_overrides_objects_uids,
- POINTER_FROM_UINT(id_iter->override_library->reference->session_uuid))) {
- id_iter->override_library->flag &= ~IDOVERRIDE_LIBRARY_FLAG_SYSTEM_DEFINED;
+ const bool success = BKE_lib_override_library_create(bmain,
+ scene,
+ view_layer,
+ NULL,
+ id_root,
+ id_root,
+ &obact->id,
+ &id_root_override,
+ do_fully_editable);
+
+ if (!do_fully_editable) {
+ /* Define liboverrides from selected/validated objects as user defined. */
+ ID *id_hierarchy_root_override = id_root_override->override_library->hierarchy_root;
+ ID *id_iter;
+ FOREACH_MAIN_ID_BEGIN (bmain, id_iter) {
+ if (ID_IS_LINKED(id_iter) || !ID_IS_OVERRIDE_LIBRARY_REAL(id_iter) ||
+ id_iter->override_library->hierarchy_root != id_hierarchy_root_override) {
+ continue;
+ }
+ if (BLI_gset_haskey(user_overrides_objects_uids,
+ POINTER_FROM_UINT(id_iter->override_library->reference->session_uuid))) {
+ id_iter->override_library->flag &= ~IDOVERRIDE_LIBRARY_FLAG_SYSTEM_DEFINED;
+ }
}
- }
- FOREACH_MAIN_ID_END;
+ FOREACH_MAIN_ID_END;
- BLI_gset_free(user_overrides_objects_uids, NULL);
+ BLI_gset_free(user_overrides_objects_uids, NULL);
+ }
- /* Remove the instance empty from this scene, the items now have an overridden collection
- * instead. */
- if (success && is_override_instancing_object) {
- ED_object_base_free_and_unlink(bmain, scene, obact);
+ if (success) {
+ if (is_override_instancing_object) {
+ /* Remove the instance empty from this scene, the items now have an overridden collection
+ * instead. */
+ ED_object_base_free_and_unlink(bmain, scene, obact);
+ }
+ else {
+ /* Remove the found root ID from the view layer. */
+ switch (GS(id_root->name)) {
+ case ID_GR: {
+ Collection *collection_root = (Collection *)id_root;
+ LISTBASE_FOREACH_MUTABLE (
+ CollectionParent *, collection_parent, &collection_root->parents) {
+ if (ID_IS_LINKED(collection_parent->collection) ||
+ !BKE_view_layer_has_collection(view_layer, collection_parent->collection)) {
+ continue;
+ }
+ BKE_collection_child_remove(bmain, collection_parent->collection, collection_root);
+ }
+ break;
+ }
+ case ID_OB: {
+ /* TODO: Not sure how well we can handle this case, when we don't have the collections as
+ * reference containers... */
+ break;
+ }
+ default:
+ break;
+ }
+ }
}
DEG_id_tag_update(&CTX_data_scene(C)->id, ID_RECALC_BASE_FLAGS | ID_RECALC_COPY_ON_WRITE);
@@ -2411,46 +2402,68 @@ static int make_override_library_exec(bContext *C, wmOperator *op)
return success ? OPERATOR_FINISHED : OPERATOR_CANCELLED;
}
-static bool make_override_library_poll(bContext *C)
+/* Set the object to override. */
+static int make_override_library_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
{
- Object *obact = CTX_data_active_object(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_OVERRIDE_LIBRARY(obact))));
-}
+ Main *bmain = CTX_data_main(C);
+ Scene *scene = CTX_data_scene(C);
+ ViewLayer *view_layer = CTX_data_view_layer(C);
+ Object *obact = ED_object_active_context(C);
-static const EnumPropertyItem *make_override_collections_of_linked_object_itemf(
- bContext *C, PointerRNA *UNUSED(ptr), PropertyRNA *UNUSED(prop), bool *r_free)
-{
- EnumPropertyItem item_tmp = {0}, *item = NULL;
- int totitem = 0;
+ /* Sanity checks. */
+ if (!scene || ID_IS_LINKED(scene) || !obact) {
+ return OPERATOR_CANCELLED;
+ }
- Object *object = ED_object_active_context(C);
- Main *bmain = CTX_data_main(C);
+ if ((!ID_IS_LINKED(obact) && obact->instance_collection != NULL &&
+ ID_IS_OVERRIDABLE_LIBRARY(obact->instance_collection)) ||
+ make_override_library_object_overridable_check(bmain, obact)) {
+ return make_override_library_exec(C, op);
+ }
- if (!object || !ID_IS_LINKED(object)) {
- return DummyRNA_DEFAULT_items;
+ if (!ID_IS_LINKED(obact)) {
+ BKE_report(op->reports, RPT_ERROR, "Cannot make library override from a local object");
+ return OPERATOR_CANCELLED;
}
+ int potential_root_collections_num = 0;
+ uint collection_session_uuid = MAIN_ID_SESSION_UUID_UNSET;
LISTBASE_FOREACH (Collection *, collection, &bmain->collections) {
/* Only check for directly linked collections. */
- if (!ID_IS_LINKED(&collection->id) || (collection->id.tag & LIB_TAG_INDIRECT) != 0) {
+ if (!ID_IS_LINKED(&collection->id) || (collection->id.tag & LIB_TAG_INDIRECT) != 0 ||
+ !BKE_view_layer_has_collection(view_layer, collection)) {
continue;
}
- if (BKE_collection_has_object_recursive(collection, object)) {
- item_tmp.identifier = item_tmp.name = collection->id.name + 2;
- item_tmp.value = *((int *)&collection->id.session_uuid);
- RNA_enum_item_add(&item, &totitem, &item_tmp);
+ if (BKE_collection_has_object_recursive(collection, obact)) {
+ if (potential_root_collections_num == 0) {
+ collection_session_uuid = collection->id.session_uuid;
+ }
+ potential_root_collections_num++;
}
}
- RNA_enum_item_end(&item, &totitem);
- *r_free = true;
+ if (potential_root_collections_num <= 1) {
+ RNA_property_int_set(op->ptr, op->type->prop, *((int *)&collection_session_uuid));
+ return make_override_library_exec(C, op);
+ }
- return item;
+ BKE_reportf(op->reports,
+ RPT_ERROR,
+ "Too many potential root collections (%d) for the override hierarchy, "
+ "please use the Outliner instead",
+ potential_root_collections_num);
+ return OPERATOR_CANCELLED;
+}
+
+static bool make_override_library_poll(bContext *C)
+{
+ Object *obact = CTX_data_active_object(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_OVERRIDE_LIBRARY(obact))));
}
void OBJECT_OT_make_override_library(wmOperatorType *ot)
@@ -2470,16 +2483,25 @@ void OBJECT_OT_make_override_library(wmOperatorType *ot)
/* properties */
PropertyRNA *prop;
- prop = RNA_def_enum(ot->srna,
- "collection",
- DummyRNA_DEFAULT_items,
- MAIN_ID_SESSION_UUID_UNSET,
- "Override Collection",
- "Name of directly linked collection containing the selected object, to make "
- "an override from");
- RNA_def_enum_funcs(prop, make_override_collections_of_linked_object_itemf);
- RNA_def_property_flag(prop, PROP_ENUM_NO_TRANSLATE);
+ prop = RNA_def_int(ot->srna,
+ "collection",
+ MAIN_ID_SESSION_UUID_UNSET,
+ INT_MIN,
+ INT_MAX,
+ "Override Collection",
+ "Session UUID of the directly linked collection containing the selected "
+ "object, to make an override from",
+ INT_MIN,
+ INT_MAX);
+ RNA_def_property_flag(prop, PROP_HIDDEN | PROP_SKIP_SAVE);
ot->prop = prop;
+
+ prop = RNA_def_boolean(ot->srna,
+ "do_fully_editable",
+ false,
+ "Create Fully Editable",
+ "Make all created override data-blocks fully editable");
+ RNA_def_property_flag(prop, PROP_HIDDEN | PROP_SKIP_SAVE);
}
/** \} */
@@ -2594,9 +2616,7 @@ void OBJECT_OT_make_single_user(wmOperatorType *ot)
/** \name Drop Named Material on Object Operator
* \{ */
-char *ED_object_ot_drop_named_material_tooltip(bContext *C,
- PointerRNA *properties,
- const int mval[2])
+char *ED_object_ot_drop_named_material_tooltip(bContext *C, const char *name, const int mval[2])
{
int mat_slot = 0;
Object *ob = ED_view3d_give_material_slot_under_cursor(C, mval, &mat_slot);
@@ -2605,9 +2625,6 @@ char *ED_object_ot_drop_named_material_tooltip(bContext *C,
}
mat_slot = max_ii(mat_slot, 1);
- char name[MAX_ID_NAME - 2];
- RNA_string_get(properties, "name", name);
-
Material *prev_mat = BKE_object_material_get(ob, mat_slot);
char *result;
@@ -2629,11 +2646,9 @@ static int drop_named_material_invoke(bContext *C, wmOperator *op, const wmEvent
Object *ob = ED_view3d_give_material_slot_under_cursor(C, event->mval, &mat_slot);
mat_slot = max_ii(mat_slot, 1);
- Material *ma;
- char name[MAX_ID_NAME - 2];
+ Material *ma = (Material *)WM_operator_properties_id_lookup_from_name_or_session_uuid(
+ bmain, op->ptr, ID_MA);
- RNA_string_get(op->ptr, "name", name);
- ma = (Material *)BKE_libblock_find_name(bmain, ID_MA, name);
if (ob == NULL || ma == NULL) {
return OPERATOR_CANCELLED;
}
@@ -2663,7 +2678,7 @@ void OBJECT_OT_drop_named_material(wmOperatorType *ot)
ot->flag = OPTYPE_UNDO | OPTYPE_INTERNAL;
/* properties */
- RNA_def_string(ot->srna, "name", "Material", MAX_ID_NAME - 2, "Name", "Material name to assign");
+ WM_operator_properties_id_lookup(ot, true);
}
/** \} */
diff --git a/source/blender/editors/object/object_remesh.cc b/source/blender/editors/object/object_remesh.cc
index ba2efa6e517..8a7138b25ac 100644
--- a/source/blender/editors/object/object_remesh.cc
+++ b/source/blender/editors/object/object_remesh.cc
@@ -344,7 +344,7 @@ static void voxel_size_edit_draw(const bContext *C, ARegion *UNUSED(ar), void *a
BKE_unit_value_as_string(str,
VOXEL_SIZE_EDIT_MAX_STR_LEN,
(double)(cd->voxel_size * unit->scale_length),
- 4,
+ -3,
B_UNIT_LENGTH,
unit,
true);
@@ -415,15 +415,15 @@ static int voxel_size_edit_modal(bContext *C, wmOperator *op, const wmEvent *eve
}
if (event->modifier & KM_CTRL) {
- /* Linear mode, enables jumping to any voxel size. */
- d = d * 0.0005f;
- }
- else {
/* Multiply d by the initial voxel size to prevent uncontrollable speeds when using low voxel
* sizes. */
/* When the voxel size is slower, it needs more precision. */
d = d * min_ff(pow2f(cd->init_voxel_size), 0.1f) * 0.05f;
}
+ else {
+ /* Linear mode, enables jumping to any voxel size. */
+ d = d * 0.0005f;
+ }
if (cd->slow_mode) {
cd->voxel_size = cd->slow_voxel_size + d * 0.05f;
}
@@ -592,7 +592,8 @@ static int voxel_size_edit_invoke(bContext *C, wmOperator *op, const wmEvent *ev
ED_region_tag_redraw(region);
const char *status_str = TIP_(
- "Move the mouse to change the voxel size. LMB: confirm size, ESC/RMB: cancel");
+ "Move the mouse to change the voxel size. CTRL: Relative Scale, SHIFT: Precision Mode, "
+ "ENTER/LMB: Confirm Size, ESC/RMB: Cancel");
ED_workspace_status_text(C, status_str);
return OPERATOR_RUNNING_MODAL;
diff --git a/source/blender/editors/object/object_transform.cc b/source/blender/editors/object/object_transform.cc
index da3df159c33..82e67231ec1 100644
--- a/source/blender/editors/object/object_transform.cc
+++ b/source/blender/editors/object/object_transform.cc
@@ -1125,7 +1125,7 @@ static int object_transform_apply_invoke(bContext *C, wmOperator *op, const wmEv
bool can_handle_multiuser = apply_objects_internal_can_multiuser(C);
bool need_single_user = can_handle_multiuser && apply_objects_internal_need_single_user(C);
- if ((ob->data != nullptr) && need_single_user) {
+ if ((ob != nullptr) && (ob->data != nullptr) && need_single_user) {
PropertyRNA *prop = RNA_struct_find_property(op->ptr, "isolate_users");
if (!RNA_property_is_set(op->ptr, prop)) {
RNA_property_boolean_set(op->ptr, prop, true);
diff --git a/source/blender/editors/object/object_vgroup.c b/source/blender/editors/object/object_vgroup.c
index 492ece0b40e..9ad36cacc7d 100644
--- a/source/blender/editors/object/object_vgroup.c
+++ b/source/blender/editors/object/object_vgroup.c
@@ -4266,7 +4266,6 @@ static void vgroup_copy_active_to_sel_single(Object *ob, const int def_nr)
Mesh *me = ob->data;
BMEditMesh *em = me->edit_mesh;
- float weight_act;
int i;
if (em) {
@@ -4278,18 +4277,15 @@ static void vgroup_copy_active_to_sel_single(Object *ob, const int def_nr)
if (dvert_act == NULL) {
return;
}
- weight_act = BKE_defvert_find_weight(dvert_act, def_nr);
BM_ITER_MESH_INDEX (eve, &iter, em->bm, BM_VERTS_OF_MESH, i) {
if (BM_elem_flag_test(eve, BM_ELEM_SELECT) && (eve != eve_act)) {
- MDeformVert *dv = BM_ELEM_CD_GET_VOID_P(eve, cd_dvert_offset);
- MDeformWeight *dw = BKE_defvert_find_index(dv, def_nr);
- if (dw) {
- dw->weight = weight_act;
+ MDeformVert *dvert_dst = BM_ELEM_CD_GET_VOID_P(eve, cd_dvert_offset);
- if (me->symmetry & ME_SYMMETRY_X) {
- ED_mesh_defvert_mirror_update_em(ob, eve, -1, i, cd_dvert_offset);
- }
+ BKE_defvert_copy_index(dvert_dst, def_nr, dvert_act, def_nr);
+
+ if (me->symmetry & ME_SYMMETRY_X) {
+ ED_mesh_defvert_mirror_update_em(ob, eve, -1, i, cd_dvert_offset);
}
}
}
@@ -4306,17 +4302,15 @@ static void vgroup_copy_active_to_sel_single(Object *ob, const int def_nr)
if (dvert_act == NULL) {
return;
}
- weight_act = BKE_defvert_find_weight(dvert_act, def_nr);
dv = me->dvert;
for (i = 0; i < me->totvert; i++, dv++) {
if ((me->mvert[i].flag & SELECT) && (dv != dvert_act)) {
- MDeformWeight *dw = BKE_defvert_find_index(dv, def_nr);
- if (dw) {
- dw->weight = weight_act;
- if (me->symmetry & ME_SYMMETRY_X) {
- ED_mesh_defvert_mirror_update_ob(ob, -1, i);
- }
+
+ BKE_defvert_copy_index(dv, def_nr, dvert_act, def_nr);
+
+ if (me->symmetry & ME_SYMMETRY_X) {
+ ED_mesh_defvert_mirror_update_ob(ob, -1, i);
}
}
}
diff --git a/source/blender/editors/render/render_preview.cc b/source/blender/editors/render/render_preview.cc
index a56f513e98f..addcedc4481 100644
--- a/source/blender/editors/render/render_preview.cc
+++ b/source/blender/editors/render/render_preview.cc
@@ -1306,7 +1306,7 @@ static ImBuf *icon_preview_imbuf_from_brush(Brush *brush)
{
static const int flags = IB_rect | IB_multilayer | IB_metadata;
- char path[FILE_MAX];
+ char filepath[FILE_MAX];
const char *folder;
if (!(brush->icon_imbuf)) {
@@ -1315,22 +1315,22 @@ static ImBuf *icon_preview_imbuf_from_brush(Brush *brush)
if (brush->icon_filepath[0]) {
/* First use the path directly to try and load the file. */
- BLI_strncpy(path, brush->icon_filepath, sizeof(brush->icon_filepath));
- BLI_path_abs(path, ID_BLEND_PATH_FROM_GLOBAL(&brush->id));
+ BLI_strncpy(filepath, brush->icon_filepath, sizeof(brush->icon_filepath));
+ BLI_path_abs(filepath, ID_BLEND_PATH_FROM_GLOBAL(&brush->id));
/* Use default color-spaces for brushes. */
- brush->icon_imbuf = IMB_loadiffname(path, flags, nullptr);
+ brush->icon_imbuf = IMB_loadiffname(filepath, flags, nullptr);
/* otherwise lets try to find it in other directories */
if (!(brush->icon_imbuf)) {
folder = BKE_appdir_folder_id(BLENDER_DATAFILES, "brushicons");
BLI_make_file_string(
- BKE_main_blendfile_path_from_global(), path, folder, brush->icon_filepath);
+ BKE_main_blendfile_path_from_global(), filepath, folder, brush->icon_filepath);
- if (path[0]) {
+ if (filepath[0]) {
/* Use default color spaces. */
- brush->icon_imbuf = IMB_loadiffname(path, flags, nullptr);
+ brush->icon_imbuf = IMB_loadiffname(filepath, flags, nullptr);
}
}
@@ -1821,13 +1821,13 @@ void PreviewLoadJob::run_fn(void *customdata,
const char *deferred_data = static_cast<char *>(PRV_DEFERRED_DATA(preview));
const ThumbSource source = static_cast<ThumbSource>(deferred_data[0]);
- const char *path = &deferred_data[1];
+ const char *filepath = &deferred_data[1];
- // printf("loading deferred %d×%d preview for %s\n", request->sizex, request->sizey, path);
+ // printf("loading deferred %d×%d preview for %s\n", request->sizex, request->sizey, filepath);
- IMB_thumb_path_lock(path);
- ImBuf *thumb = IMB_thumb_manage(path, THB_LARGE, source);
- IMB_thumb_path_unlock(path);
+ IMB_thumb_path_lock(filepath);
+ ImBuf *thumb = IMB_thumb_manage(filepath, THB_LARGE, source);
+ IMB_thumb_path_unlock(filepath);
if (thumb) {
/* PreviewImage assumes premultiplied alpha... */
diff --git a/source/blender/editors/scene/scene_edit.c b/source/blender/editors/scene/scene_edit.c
index a13177942a8..57a9e6be917 100644
--- a/source/blender/editors/scene/scene_edit.c
+++ b/source/blender/editors/scene/scene_edit.c
@@ -67,7 +67,10 @@ static Scene *scene_add(Main *bmain, Scene *scene_old, eSceneCopyMethod method)
}
/** Add a new scene in the sequence editor. */
-static Scene *ED_scene_sequencer_add(Main *bmain, bContext *C, eSceneCopyMethod method)
+Scene *ED_scene_sequencer_add(Main *bmain,
+ bContext *C,
+ eSceneCopyMethod method,
+ const bool assign_strip)
{
Sequence *seq = NULL;
Scene *scene_active = CTX_data_scene(C);
@@ -88,6 +91,11 @@ static Scene *ED_scene_sequencer_add(Main *bmain, bContext *C, eSceneCopyMethod
Scene *scene_new = scene_add(bmain, scene_strip, method);
+ /* If don't need assign the scene to the strip, nothing else to do. */
+ if (!assign_strip) {
+ return scene_new;
+ }
+
/* As the scene is created in sequencer, do not set the new scene as active.
* This is useful for story-boarding where we want to keep actual scene active.
* The new scene is linked to the active strip and the viewport updated. */
@@ -291,7 +299,7 @@ static int scene_new_sequencer_exec(bContext *C, wmOperator *op)
Main *bmain = CTX_data_main(C);
int type = RNA_enum_get(op->ptr, "type");
- if (ED_scene_sequencer_add(bmain, C, type) == NULL) {
+ if (ED_scene_sequencer_add(bmain, C, type, true) == NULL) {
return OPERATOR_CANCELLED;
}
diff --git a/source/blender/editors/screen/area.c b/source/blender/editors/screen/area.c
index ad815f0d998..f58baa0e25c 100644
--- a/source/blender/editors/screen/area.c
+++ b/source/blender/editors/screen/area.c
@@ -145,6 +145,10 @@ void ED_region_do_listen(wmRegionListenerParams *params)
region->type->listener(params);
}
+ LISTBASE_FOREACH (uiBlock *, block, &region->uiblocks) {
+ UI_block_views_listen(block, params);
+ }
+
LISTBASE_FOREACH (uiList *, list, &region->ui_lists) {
if (list->type && list->type->listener) {
list->type->listener(list, params);
@@ -3454,9 +3458,9 @@ ScrArea *ED_area_find_under_cursor(const bContext *C, int spacetype, const int x
if (!area) {
/* Check all windows except the active one. */
int scr_pos[2];
- wmWindow *r_win = WM_window_find_under_cursor(win, xy, scr_pos);
- if (r_win && r_win != win) {
- win = r_win;
+ wmWindow *win_other = WM_window_find_under_cursor(win, xy, scr_pos);
+ if (win_other && win_other != win) {
+ win = win_other;
screen = WM_window_get_active_screen(win);
area = BKE_screen_find_area_xy(screen, spacetype, scr_pos);
}
diff --git a/source/blender/editors/screen/screen_edit.c b/source/blender/editors/screen/screen_edit.c
index d5385181055..08c8c863729 100644
--- a/source/blender/editors/screen/screen_edit.c
+++ b/source/blender/editors/screen/screen_edit.c
@@ -626,8 +626,8 @@ void ED_screen_refresh(wmWindowManager *wm, wmWindow *win)
screen_geom_vertices_scale(win, screen);
ED_screen_areas_iter (win, screen, area) {
- /* set spacetype and region callbacks, calls init() */
- /* sets subwindows for regions, adds handlers */
+ /* Set space-type and region callbacks, calls init() */
+ /* Sets sub-windows for regions, adds handlers. */
ED_area_init(wm, win, area);
}
@@ -1315,7 +1315,7 @@ void ED_screen_full_restore(bContext *C, ScrArea *area)
else {
ED_screen_state_toggle(C, win, area, state);
}
- /* warning: 'area' may be freed */
+ /* WARNING: 'area' may be freed */
}
/* otherwise just tile the area again */
else {
diff --git a/source/blender/editors/screen/screen_ops.c b/source/blender/editors/screen/screen_ops.c
index d7cf09ca89a..212fb846b43 100644
--- a/source/blender/editors/screen/screen_ops.c
+++ b/source/blender/editors/screen/screen_ops.c
@@ -659,36 +659,10 @@ bool ED_operator_editmball(bContext *C)
return false;
}
-bool ED_operator_mask(bContext *C)
-{
- ScrArea *area = CTX_wm_area(C);
- if (area && area->spacedata.first) {
- switch (area->spacetype) {
- case SPACE_CLIP: {
- SpaceClip *screen = area->spacedata.first;
- return ED_space_clip_check_show_maskedit(screen);
- }
- case SPACE_SEQ: {
- SpaceSeq *sseq = area->spacedata.first;
- Scene *scene = CTX_data_scene(C);
- return ED_space_sequencer_check_show_maskedit(sseq, scene);
- }
- case SPACE_IMAGE: {
- SpaceImage *sima = area->spacedata.first;
- ViewLayer *view_layer = CTX_data_view_layer(C);
- Object *obedit = OBEDIT_FROM_VIEW_LAYER(view_layer);
- return ED_space_image_check_show_maskedit(sima, obedit);
- }
- }
- }
-
- return false;
-}
-
-bool ED_operator_camera(bContext *C)
+bool ED_operator_camera_poll(bContext *C)
{
struct Camera *cam = CTX_data_pointer_get_type(C, "camera", &RNA_Camera).data;
- return (cam != NULL);
+ return (cam != NULL && !ID_IS_LINKED(cam));
}
/** \} */
@@ -1477,7 +1451,7 @@ static int area_close_exec(bContext *C, wmOperator *op)
bScreen *screen = CTX_wm_screen(C);
ScrArea *area = CTX_wm_area(C);
- /* This operator is scriptable, so the area passed could be invalid. */
+ /* This operator is script-able, so the area passed could be invalid. */
if (BLI_findindex(&screen->areabase, area) == -1) {
BKE_report(op->reports, RPT_ERROR, "Area not found in the active screen");
return OPERATOR_CANCELLED;
@@ -2490,6 +2464,7 @@ static int area_split_modal(bContext *C, wmOperator *op, const wmEvent *event)
return OPERATOR_CANCELLED;
case EVT_LEFTCTRLKEY:
+ case EVT_RIGHTCTRLKEY:
sd->do_snap = event->val == KM_PRESS;
update_factor = true;
break;
@@ -2722,7 +2697,7 @@ static int region_scale_invoke(bContext *C, wmOperator *op, const wmEvent *event
rmd->region->sizey = rmd->region->winy;
}
- /* now copy to regionmovedata */
+ /* Now copy to region-move-data. */
if (ELEM(rmd->edge, AE_LEFT_TO_TOPRIGHT, AE_RIGHT_TO_TOPLEFT)) {
rmd->origval = rmd->region->sizex;
}
diff --git a/source/blender/editors/sculpt_paint/CMakeLists.txt b/source/blender/editors/sculpt_paint/CMakeLists.txt
index d3bf28798c4..8879161d2af 100644
--- a/source/blender/editors/sculpt_paint/CMakeLists.txt
+++ b/source/blender/editors/sculpt_paint/CMakeLists.txt
@@ -10,6 +10,7 @@ set(INC
../../depsgraph
../../draw
../../functions
+ ../../geometry
../../gpu
../../imbuf
../../makesdna
@@ -33,6 +34,8 @@ set(SRC
curves_sculpt_delete.cc
curves_sculpt_grow_shrink.cc
curves_sculpt_ops.cc
+ curves_sculpt_selection.cc
+ curves_sculpt_selection_paint.cc
curves_sculpt_snake_hook.cc
paint_canvas.cc
paint_cursor.c
@@ -49,13 +52,13 @@ set(SRC
paint_stroke.c
paint_utils.c
paint_vertex.cc
- paint_vertex_color_ops.c
+ paint_vertex_color_ops.cc
paint_vertex_color_utils.c
paint_vertex_proj.c
paint_vertex_weight_ops.c
paint_vertex_weight_utils.c
sculpt.c
- sculpt_automasking.c
+ sculpt_automasking.cc
sculpt_boundary.c
sculpt_brush_types.c
sculpt_cloth.c
diff --git a/source/blender/editors/sculpt_paint/curves_sculpt_add.cc b/source/blender/editors/sculpt_paint/curves_sculpt_add.cc
index 1fdecf47bbd..bac03de77e7 100644
--- a/source/blender/editors/sculpt_paint/curves_sculpt_add.cc
+++ b/source/blender/editors/sculpt_paint/curves_sculpt_add.cc
@@ -18,11 +18,13 @@
#include "BKE_bvhutils.h"
#include "BKE_context.h"
#include "BKE_curves.hh"
+#include "BKE_curves_utils.hh"
+#include "BKE_geometry_set.hh"
#include "BKE_mesh.h"
#include "BKE_mesh_runtime.h"
+#include "BKE_mesh_sample.hh"
#include "BKE_paint.h"
#include "BKE_report.h"
-#include "BKE_spline.hh"
#include "DNA_brush_enums.h"
#include "DNA_brush_types.h"
@@ -36,8 +38,12 @@
#include "ED_screen.h"
#include "ED_view3d.h"
+#include "GEO_add_curves_on_mesh.hh"
+
+#include "WM_api.h"
+
/**
- * The code below uses a prefix naming convention to indicate the coordinate space:
+ * The code below uses a suffix naming convention to indicate the coordinate space:
* cu: Local space of the curves object that is being edited.
* su: Local space of the surface object.
* wo: World space.
@@ -63,80 +69,52 @@ class AddOperation : public CurvesSculptStrokeOperation {
}
}
- void on_stroke_extended(bContext *C, const StrokeExtension &stroke_extension) override;
+ void on_stroke_extended(const bContext &C, const StrokeExtension &stroke_extension) override;
};
-static void initialize_straight_curve_positions(const float3 &p1,
- const float3 &p2,
- MutableSpan<float3> r_positions)
-{
- const float step = 1.0f / (float)(r_positions.size() - 1);
- for (const int i : r_positions.index_range()) {
- r_positions[i] = math::interpolate(p1, p2, i * step);
- }
-}
-
/**
* Utility class that actually executes the update when the stroke is updated. That's useful
* because it avoids passing a very large number of parameters between functions.
*/
struct AddOperationExecutor {
AddOperation *self_ = nullptr;
- Depsgraph *depsgraph_ = nullptr;
- Scene *scene_ = nullptr;
+ CurvesSculptCommonContext ctx_;
+
Object *object_ = nullptr;
- ARegion *region_ = nullptr;
- View3D *v3d_ = nullptr;
Curves *curves_id_ = nullptr;
CurvesGeometry *curves_ = nullptr;
Object *surface_ob_ = nullptr;
Mesh *surface_ = nullptr;
Span<MLoopTri> surface_looptris_;
- Span<float3> corner_normals_su_;
- CurvesSculpt *curves_sculpt_ = nullptr;
- Brush *brush_ = nullptr;
- BrushCurvesSculptSettings *brush_settings_ = nullptr;
+ const CurvesSculpt *curves_sculpt_ = nullptr;
+ const Brush *brush_ = nullptr;
+ const BrushCurvesSculptSettings *brush_settings_ = nullptr;
+ int add_amount_;
+ bool use_front_face_;
float brush_radius_re_;
float2 brush_pos_re_;
- bool use_front_face_;
- bool interpolate_length_;
- bool interpolate_shape_;
- bool use_interpolation_;
- float new_curve_length_;
- int add_amount_;
- int points_per_curve_;
-
- /** Various matrices to convert between coordinate spaces. */
- float4x4 curves_to_world_mat_;
- float4x4 world_to_curves_mat_;
- float4x4 world_to_surface_mat_;
- float4x4 surface_to_world_mat_;
- float4x4 surface_to_curves_mat_;
- float4x4 surface_to_curves_normal_mat_;
+ CurvesSculptTransforms transforms_;
BVHTreeFromMesh surface_bvh_;
- int tot_old_curves_;
- int tot_old_points_;
-
struct AddedPoints {
Vector<float3> positions_cu;
Vector<float3> bary_coords;
Vector<int> looptri_indices;
};
- void execute(AddOperation &self, bContext *C, const StrokeExtension &stroke_extension)
+ AddOperationExecutor(const bContext &C) : ctx_(C)
+ {
+ }
+
+ void execute(AddOperation &self, const bContext &C, const StrokeExtension &stroke_extension)
{
self_ = &self;
- depsgraph_ = CTX_data_depsgraph_pointer(C);
- scene_ = CTX_data_scene(C);
- object_ = CTX_data_active_object(C);
- region_ = CTX_wm_region(C);
- v3d_ = CTX_wm_view3d(C);
+ object_ = CTX_data_active_object(&C);
curves_id_ = static_cast<Curves *>(object_->data);
curves_ = &CurvesGeometry::wrap(curves_id_->geometry);
@@ -145,41 +123,21 @@ struct AddOperationExecutor {
return;
}
- curves_to_world_mat_ = object_->obmat;
- world_to_curves_mat_ = curves_to_world_mat_.inverted();
+ transforms_ = CurvesSculptTransforms(*object_, curves_id_->surface);
surface_ob_ = curves_id_->surface;
surface_ = static_cast<Mesh *>(surface_ob_->data);
- surface_to_world_mat_ = surface_ob_->obmat;
- world_to_surface_mat_ = surface_to_world_mat_.inverted();
- surface_to_curves_mat_ = world_to_curves_mat_ * surface_to_world_mat_;
- surface_to_curves_normal_mat_ = surface_to_curves_mat_.inverted().transposed();
-
- if (!CustomData_has_layer(&surface_->ldata, CD_NORMAL)) {
- BKE_mesh_calc_normals_split(surface_);
- }
- corner_normals_su_ = {
- reinterpret_cast<const float3 *>(CustomData_get_layer(&surface_->ldata, CD_NORMAL)),
- surface_->totloop};
- curves_sculpt_ = scene_->toolsettings->curves_sculpt;
- brush_ = BKE_paint_brush(&curves_sculpt_->paint);
+ curves_sculpt_ = ctx_.scene->toolsettings->curves_sculpt;
+ brush_ = BKE_paint_brush_for_read(&curves_sculpt_->paint);
brush_settings_ = brush_->curves_sculpt_settings;
- brush_radius_re_ = BKE_brush_size_get(scene_, brush_);
+ brush_radius_re_ = brush_radius_get(*ctx_.scene, *brush_, stroke_extension);
brush_pos_re_ = stroke_extension.mouse_position;
use_front_face_ = brush_->flag & BRUSH_FRONTFACE;
const eBrushFalloffShape falloff_shape = static_cast<eBrushFalloffShape>(
brush_->falloff_shape);
add_amount_ = std::max(0, brush_settings_->add_amount);
- points_per_curve_ = std::max(2, brush_settings_->points_per_curve);
- interpolate_length_ = brush_settings_->flag & BRUSH_CURVES_SCULPT_FLAG_INTERPOLATE_LENGTH;
- interpolate_shape_ = brush_settings_->flag & BRUSH_CURVES_SCULPT_FLAG_INTERPOLATE_SHAPE;
- use_interpolation_ = interpolate_length_ || interpolate_shape_;
- new_curve_length_ = brush_settings_->curve_length;
-
- tot_old_curves_ = curves_->curves_num();
- tot_old_points_ = curves_->points_num();
if (add_amount_ == 0) {
return;
@@ -215,31 +173,56 @@ struct AddOperationExecutor {
return;
}
- if (use_interpolation_) {
- this->ensure_curve_roots_kdtree();
+ /* Find UV map. */
+ VArray_Span<float2> surface_uv_map;
+ if (curves_id_->surface_uv_map != nullptr) {
+ MeshComponent surface_component;
+ surface_component.replace(surface_, GeometryOwnershipType::ReadOnly);
+ surface_uv_map = surface_component
+ .attribute_try_get_for_read(curves_id_->surface_uv_map,
+ ATTR_DOMAIN_CORNER)
+ .typed<float2>();
}
- const int tot_added_curves = added_points.bary_coords.size();
- const int tot_added_points = tot_added_curves * points_per_curve_;
+ /* Find normals. */
+ if (!CustomData_has_layer(&surface_->ldata, CD_NORMAL)) {
+ BKE_mesh_calc_normals_split(surface_);
+ }
+ const Span<float3> corner_normals_su = {
+ reinterpret_cast<const float3 *>(CustomData_get_layer(&surface_->ldata, CD_NORMAL)),
+ surface_->totloop};
- curves_->resize(curves_->points_num() + tot_added_points,
- curves_->curves_num() + tot_added_curves);
+ geometry::AddCurvesOnMeshInputs add_inputs;
+ add_inputs.root_positions_cu = added_points.positions_cu;
+ add_inputs.bary_coords = added_points.bary_coords;
+ add_inputs.looptri_indices = added_points.looptri_indices;
+ add_inputs.interpolate_length = brush_settings_->flag &
+ BRUSH_CURVES_SCULPT_FLAG_INTERPOLATE_LENGTH;
+ add_inputs.interpolate_shape = brush_settings_->flag &
+ BRUSH_CURVES_SCULPT_FLAG_INTERPOLATE_SHAPE;
+ add_inputs.interpolate_point_count = brush_settings_->flag &
+ BRUSH_CURVES_SCULPT_FLAG_INTERPOLATE_POINT_COUNT;
+ add_inputs.fallback_curve_length = brush_settings_->curve_length;
+ add_inputs.fallback_point_count = std::max(2, brush_settings_->points_per_curve);
+ add_inputs.surface = surface_;
+ add_inputs.surface_bvh = &surface_bvh_;
+ add_inputs.surface_looptris = surface_looptris_;
+ add_inputs.surface_uv_map = surface_uv_map;
+ add_inputs.corner_normals_su = corner_normals_su;
+ add_inputs.curves_to_surface_mat = transforms_.curves_to_surface;
+ add_inputs.surface_to_curves_normal_mat = transforms_.surface_to_curves_normal;
+
+ if (add_inputs.interpolate_length || add_inputs.interpolate_shape ||
+ add_inputs.interpolate_point_count) {
+ this->ensure_curve_roots_kdtree();
+ add_inputs.old_roots_kdtree = self_->curve_roots_kdtree_;
+ }
- threading::parallel_invoke([&]() { this->initialize_curve_offsets(tot_added_curves); },
- [&]() { this->initialize_attributes(added_points); });
+ geometry::add_curves_on_mesh(*curves_, add_inputs);
DEG_id_tag_update(&curves_id_->id, ID_RECALC_GEOMETRY);
- ED_region_tag_redraw(region_);
- }
-
- float3 get_bary_coords(const Mesh &mesh, const MLoopTri &looptri, const float3 position) const
- {
- const float3 &v0 = mesh.mvert[mesh.mloop[looptri.tri[0]].v].co;
- const float3 &v1 = mesh.mvert[mesh.mloop[looptri.tri[1]].v].co;
- const float3 &v2 = mesh.mvert[mesh.mloop[looptri.tri[2]].v].co;
- float3 bary_coords;
- interp_weights_tri_v3(bary_coords, v0, v1, v2, position);
- return bary_coords;
+ WM_main_add_notifier(NC_GEOM | ND_DATA, &curves_id_->id);
+ ED_region_tag_redraw(ctx_.region);
}
/**
@@ -249,16 +232,16 @@ struct AddOperationExecutor {
{
float3 ray_start_wo, ray_end_wo;
ED_view3d_win_to_segment_clipped(
- depsgraph_, region_, v3d_, brush_pos_re_, ray_start_wo, ray_end_wo, true);
- const float3 ray_start_su = world_to_surface_mat_ * ray_start_wo;
- const float3 ray_end_su = world_to_surface_mat_ * ray_end_wo;
+ ctx_.depsgraph, ctx_.region, ctx_.v3d, brush_pos_re_, ray_start_wo, ray_end_wo, true);
+ const float3 ray_start_cu = transforms_.world_to_curves * ray_start_wo;
+ const float3 ray_end_cu = transforms_.world_to_curves * ray_end_wo;
const Vector<float4x4> symmetry_brush_transforms = get_symmetry_brush_transforms(
eCurvesSymmetryType(curves_id_->symmetry));
for (const float4x4 &brush_transform : symmetry_brush_transforms) {
- this->sample_in_center(
- r_added_points, brush_transform * ray_start_su, brush_transform * ray_end_su);
+ const float4x4 transform = transforms_.curves_to_surface * brush_transform;
+ this->sample_in_center(r_added_points, transform * ray_start_cu, transform * ray_end_cu);
}
}
@@ -285,10 +268,10 @@ struct AddOperationExecutor {
const int looptri_index = ray_hit.index;
const float3 brush_pos_su = ray_hit.co;
- const float3 bary_coords = this->get_bary_coords(
+ const float3 bary_coords = bke::mesh_surface_sample::compute_bary_coord_in_triangle(
*surface_, surface_looptris_[looptri_index], brush_pos_su);
- const float3 brush_pos_cu = surface_to_curves_mat_ * brush_pos_su;
+ const float3 brush_pos_cu = transforms_.surface_to_curves * brush_pos_su;
r_added_points.positions_cu.append(brush_pos_cu);
r_added_points.bary_coords.append(bary_coords);
@@ -312,57 +295,37 @@ struct AddOperationExecutor {
const float4x4 &brush_transform)
{
const int old_amount = r_added_points.bary_coords.size();
- const int max_iterations = std::max(100'000, add_amount_ * 10);
+ const int max_iterations = 100;
int current_iteration = 0;
while (r_added_points.bary_coords.size() < old_amount + add_amount_) {
if (current_iteration++ >= max_iterations) {
break;
}
-
- const float r = brush_radius_re_ * std::sqrt(rng.get_float());
- const float angle = rng.get_float() * 2.0f * M_PI;
- const float2 pos_re = brush_pos_re_ + r * float2(std::cos(angle), std::sin(angle));
-
- float3 ray_start_wo, ray_end_wo;
- ED_view3d_win_to_segment_clipped(
- depsgraph_, region_, v3d_, pos_re, ray_start_wo, ray_end_wo, true);
- const float3 ray_start_su = brush_transform * (world_to_surface_mat_ * ray_start_wo);
- const float3 ray_end_su = brush_transform * (world_to_surface_mat_ * ray_end_wo);
- const float3 ray_direction_su = math::normalize(ray_end_su - ray_start_su);
-
- BVHTreeRayHit ray_hit;
- ray_hit.dist = FLT_MAX;
- ray_hit.index = -1;
- BLI_bvhtree_ray_cast(surface_bvh_.tree,
- ray_start_su,
- ray_direction_su,
- 0.0f,
- &ray_hit,
- surface_bvh_.raycast_callback,
- &surface_bvh_);
-
- if (ray_hit.index == -1) {
- continue;
- }
-
- if (use_front_face_) {
- const float3 normal_su = ray_hit.no;
- if (math::dot(ray_direction_su, normal_su) >= 0.0f) {
- continue;
- }
+ const int missing_amount = add_amount_ + old_amount - r_added_points.bary_coords.size();
+ const int new_points = bke::mesh_surface_sample::sample_surface_points_projected(
+ rng,
+ *surface_,
+ surface_bvh_,
+ brush_pos_re_,
+ brush_radius_re_,
+ [&](const float2 &pos_re, float3 &r_start_su, float3 &r_end_su) {
+ float3 start_wo, end_wo;
+ ED_view3d_win_to_segment_clipped(
+ ctx_.depsgraph, ctx_.region, ctx_.v3d, pos_re, start_wo, end_wo, true);
+ const float3 start_cu = brush_transform * (transforms_.world_to_curves * start_wo);
+ const float3 end_cu = brush_transform * (transforms_.world_to_curves * end_wo);
+ r_start_su = transforms_.curves_to_surface * start_cu;
+ r_end_su = transforms_.curves_to_surface * end_cu;
+ },
+ use_front_face_,
+ add_amount_,
+ missing_amount,
+ r_added_points.bary_coords,
+ r_added_points.looptri_indices,
+ r_added_points.positions_cu);
+ for (float3 &pos : r_added_points.positions_cu.as_mutable_span().take_back(new_points)) {
+ pos = transforms_.surface_to_curves * pos;
}
-
- const int looptri_index = ray_hit.index;
- const float3 pos_su = ray_hit.co;
-
- const float3 bary_coords = this->get_bary_coords(
- *surface_, surface_looptris_[looptri_index], pos_su);
-
- const float3 pos_cu = surface_to_curves_mat_ * pos_su;
-
- r_added_points.positions_cu.append(pos_cu);
- r_added_points.bary_coords.append(bary_coords);
- r_added_points.looptri_indices.append(looptri_index);
}
}
@@ -371,66 +334,47 @@ struct AddOperationExecutor {
*/
void sample_spherical_with_symmetry(RandomNumberGenerator &rng, AddedPoints &r_added_points)
{
- /* Find ray that starts in the center of the brush. */
- float3 brush_ray_start_wo, brush_ray_end_wo;
- ED_view3d_win_to_segment_clipped(
- depsgraph_, region_, v3d_, brush_pos_re_, brush_ray_start_wo, brush_ray_end_wo, true);
- const float3 brush_ray_start_su = world_to_surface_mat_ * brush_ray_start_wo;
- const float3 brush_ray_end_su = world_to_surface_mat_ * brush_ray_end_wo;
-
- /* Find ray that starts on the boundary of the brush. That is used to compute the brush radius
- * in 3D. */
- float3 brush_radius_ray_start_wo, brush_radius_ray_end_wo;
- ED_view3d_win_to_segment_clipped(depsgraph_,
- region_,
- v3d_,
- brush_pos_re_ + float2(brush_radius_re_, 0),
- brush_radius_ray_start_wo,
- brush_radius_ray_end_wo,
+ const std::optional<CurvesBrush3D> brush_3d = sample_curves_surface_3d_brush(*ctx_.depsgraph,
+ *ctx_.region,
+ *ctx_.v3d,
+ transforms_,
+ surface_bvh_,
+ brush_pos_re_,
+ brush_radius_re_);
+ if (!brush_3d.has_value()) {
+ return;
+ }
+
+ float3 view_ray_start_wo, view_ray_end_wo;
+ ED_view3d_win_to_segment_clipped(ctx_.depsgraph,
+ ctx_.region,
+ ctx_.v3d,
+ brush_pos_re_,
+ view_ray_start_wo,
+ view_ray_end_wo,
true);
- const float3 brush_radius_ray_start_su = world_to_surface_mat_ * brush_radius_ray_start_wo;
- const float3 brush_radius_ray_end_su = world_to_surface_mat_ * brush_radius_ray_end_wo;
+ const float3 view_direction_su = math::normalize(
+ transforms_.world_to_surface * view_ray_end_wo -
+ transforms_.world_to_surface * view_ray_start_wo);
const Vector<float4x4> symmetry_brush_transforms = get_symmetry_brush_transforms(
eCurvesSymmetryType(curves_id_->symmetry));
for (const float4x4 &brush_transform : symmetry_brush_transforms) {
- this->sample_spherical(rng,
- r_added_points,
- brush_transform * brush_ray_start_su,
- brush_transform * brush_ray_end_su,
- brush_transform * brush_radius_ray_start_su,
- brush_transform * brush_radius_ray_end_su);
+ const float4x4 transform = transforms_.curves_to_surface * brush_transform;
+ const float3 brush_pos_su = transform * brush_3d->position_cu;
+ const float brush_radius_su = transform_brush_radius(
+ transform, brush_3d->position_cu, brush_3d->radius_cu);
+ this->sample_spherical(
+ rng, r_added_points, brush_pos_su, brush_radius_su, view_direction_su);
}
}
void sample_spherical(RandomNumberGenerator &rng,
AddedPoints &r_added_points,
- const float3 &brush_ray_start_su,
- const float3 &brush_ray_end_su,
- const float3 &brush_radius_ray_start_su,
- const float3 &brush_radius_ray_end_su)
+ const float3 &brush_pos_su,
+ const float brush_radius_su,
+ const float3 &view_direction_su)
{
- const float3 brush_ray_direction_su = math::normalize(brush_ray_end_su - brush_ray_start_su);
-
- BVHTreeRayHit ray_hit;
- ray_hit.dist = FLT_MAX;
- ray_hit.index = -1;
- BLI_bvhtree_ray_cast(surface_bvh_.tree,
- brush_ray_start_su,
- brush_ray_direction_su,
- 0.0f,
- &ray_hit,
- surface_bvh_.raycast_callback,
- &surface_bvh_);
-
- if (ray_hit.index == -1) {
- return;
- }
-
- /* Compute brush radius. */
- const float3 brush_pos_su = ray_hit.co;
- const float brush_radius_su = dist_to_line_v3(
- brush_pos_su, brush_radius_ray_start_su, brush_radius_ray_end_su);
const float brush_radius_sq_su = pow2f(brush_radius_su);
/* Find surface triangles within brush radius. */
@@ -447,7 +391,7 @@ struct AddOperationExecutor {
const float3 v2_su = surface_->mvert[surface_->mloop[looptri.tri[2]].v].co;
float3 normal_su;
normal_tri_v3(normal_su, v0_su, v1_su, v2_su);
- if (math::dot(normal_su, brush_ray_direction_su) >= 0.0f) {
+ if (math::dot(normal_su, view_direction_su) >= 0.0f) {
return;
}
looptri_indices.append(index);
@@ -469,9 +413,6 @@ struct AddOperationExecutor {
const float brush_plane_area_su = M_PI * brush_radius_sq_su;
const float approximate_density_su = add_amount_ / brush_plane_area_su;
- /* Used for switching between two triangle sampling strategies. */
- const float area_threshold = brush_plane_area_su;
-
/* Usually one or two iterations should be enough. */
const int max_iterations = 5;
int current_iteration = 0;
@@ -481,78 +422,18 @@ struct AddOperationExecutor {
if (current_iteration++ >= max_iterations) {
break;
}
-
- for (const int looptri_index : looptri_indices) {
- const MLoopTri &looptri = surface_looptris_[looptri_index];
-
- const float3 v0_su = surface_->mvert[surface_->mloop[looptri.tri[0]].v].co;
- const float3 v1_su = surface_->mvert[surface_->mloop[looptri.tri[1]].v].co;
- const float3 v2_su = surface_->mvert[surface_->mloop[looptri.tri[2]].v].co;
-
- const float looptri_area_su = area_tri_v3(v0_su, v1_su, v2_su);
-
- if (looptri_area_su < area_threshold) {
- /* The triangle is small compared to the brush radius. Sample by generating random
- * barycentric coordinates. */
- const int amount = rng.round_probabilistic(approximate_density_su * looptri_area_su);
- for ([[maybe_unused]] const int i : IndexRange(amount)) {
- const float3 bary_coord = rng.get_barycentric_coordinates();
- const float3 point_pos_su = attribute_math::mix3(bary_coord, v0_su, v1_su, v2_su);
- const float distance_to_brush_sq_su = math::distance_squared(point_pos_su,
- brush_pos_su);
- if (distance_to_brush_sq_su > brush_radius_sq_su) {
- continue;
- }
-
- r_added_points.bary_coords.append(bary_coord);
- r_added_points.looptri_indices.append(looptri_index);
- r_added_points.positions_cu.append(surface_to_curves_mat_ * point_pos_su);
- }
- }
- else {
- /* The triangle is large compared to the brush radius. Sample by generating random points
- * on the triangle plane within the brush radius. */
- float3 normal_su;
- normal_tri_v3(normal_su, v0_su, v1_su, v2_su);
-
- float3 brush_pos_proj_su = brush_pos_su;
- project_v3_plane(brush_pos_proj_su, normal_su, v0_su);
-
- const float proj_distance_sq_su = math::distance_squared(brush_pos_proj_su,
- brush_pos_su);
- const float brush_radius_factor_sq = 1.0f -
- std::min(1.0f,
- proj_distance_sq_su / brush_radius_sq_su);
- const float radius_proj_sq_su = brush_radius_sq_su * brush_radius_factor_sq;
- const float radius_proj_su = std::sqrt(radius_proj_sq_su);
- const float circle_area_su = M_PI * radius_proj_su;
-
- const int amount = rng.round_probabilistic(approximate_density_su * circle_area_su);
-
- const float3 axis_1_su = math::normalize(v1_su - v0_su) * radius_proj_su;
- const float3 axis_2_su = math::normalize(math::cross(
- axis_1_su, math::cross(axis_1_su, v2_su - v0_su))) *
- radius_proj_su;
-
- for ([[maybe_unused]] const int i : IndexRange(amount)) {
- const float r = std::sqrt(rng.get_float());
- const float angle = rng.get_float() * 2.0f * M_PI;
- const float x = r * std::cos(angle);
- const float y = r * std::sin(angle);
- const float3 point_pos_su = brush_pos_proj_su + axis_1_su * x + axis_2_su * y;
- if (!isect_point_tri_prism_v3(point_pos_su, v0_su, v1_su, v2_su)) {
- /* Sampled point is not in the triangle. */
- continue;
- }
-
- float3 bary_coord;
- interp_weights_tri_v3(bary_coord, v0_su, v1_su, v2_su, point_pos_su);
-
- r_added_points.bary_coords.append(bary_coord);
- r_added_points.looptri_indices.append(looptri_index);
- r_added_points.positions_cu.append(surface_to_curves_mat_ * point_pos_su);
- }
- }
+ const int new_points = bke::mesh_surface_sample::sample_surface_points_spherical(
+ rng,
+ *surface_,
+ looptri_indices,
+ brush_pos_su,
+ brush_radius_su,
+ approximate_density_su,
+ r_added_points.bary_coords,
+ r_added_points.looptri_indices,
+ r_added_points.positions_cu);
+ for (float3 &pos : r_added_points.positions_cu.as_mutable_span().take_back(new_points)) {
+ pos = transforms_.surface_to_curves * pos;
}
}
@@ -577,271 +458,20 @@ struct AddOperationExecutor {
BLI_kdtree_3d_balance(self_->curve_roots_kdtree_);
}
}
-
- void initialize_curve_offsets(const int tot_added_curves)
- {
- MutableSpan<int> offsets = curves_->offsets_for_write();
- threading::parallel_for(IndexRange(tot_added_curves), 1024, [&](const IndexRange range) {
- for (const int i : range) {
- const int curve_i = tot_old_curves_ + i;
- offsets[curve_i + 1] = tot_old_points_ + (i + 1) * points_per_curve_;
- }
- });
- }
-
- struct NeighborInfo {
- /* Curve index of the neighbor. */
- int index;
- /* The weights of all neighbors of a new curve add up to 1. */
- float weight;
- };
- static constexpr int max_neighbors = 5;
- using NeighborsVector = Vector<NeighborInfo, max_neighbors>;
-
- void initialize_attributes(const AddedPoints &added_points)
- {
- Array<NeighborsVector> neighbors_per_curve;
- if (use_interpolation_) {
- neighbors_per_curve = this->find_curve_neighbors(added_points);
- }
-
- Array<float> new_lengths_cu(added_points.bary_coords.size());
- if (interpolate_length_) {
- this->interpolate_lengths(neighbors_per_curve, new_lengths_cu);
- }
- else {
- new_lengths_cu.fill(new_curve_length_);
- }
-
- Array<float3> new_normals_su = this->compute_normals_for_added_curves_su(added_points);
- this->initialize_surface_attachment(added_points);
-
- if (interpolate_shape_) {
- this->initialize_position_with_interpolation(
- added_points, neighbors_per_curve, new_normals_su, new_lengths_cu);
- }
- else {
- this->initialize_position_without_interpolation(
- added_points, new_lengths_cu, new_normals_su);
- }
- }
-
- Array<NeighborsVector> find_curve_neighbors(const AddedPoints &added_points)
- {
- const int tot_added_curves = added_points.bary_coords.size();
- Array<NeighborsVector> neighbors_per_curve(tot_added_curves);
- threading::parallel_for(IndexRange(tot_added_curves), 128, [&](const IndexRange range) {
- for (const int i : range) {
- const float3 root_cu = added_points.positions_cu[i];
- std::array<KDTreeNearest_3d, max_neighbors> nearest_n;
- const int found_neighbors = BLI_kdtree_3d_find_nearest_n(
- self_->curve_roots_kdtree_, root_cu, nearest_n.data(), max_neighbors);
- float tot_weight = 0.0f;
- for (const int neighbor_i : IndexRange(found_neighbors)) {
- KDTreeNearest_3d &nearest = nearest_n[neighbor_i];
- const float weight = 1.0f / std::max(nearest.dist, 0.00001f);
- tot_weight += weight;
- neighbors_per_curve[i].append({nearest.index, weight});
- }
- /* Normalize weights. */
- for (NeighborInfo &neighbor : neighbors_per_curve[i]) {
- neighbor.weight /= tot_weight;
- }
- }
- });
- return neighbors_per_curve;
- }
-
- void interpolate_lengths(const Span<NeighborsVector> neighbors_per_curve,
- MutableSpan<float> r_lengths)
- {
- const Span<float3> positions_cu = curves_->positions();
-
- threading::parallel_for(r_lengths.index_range(), 128, [&](const IndexRange range) {
- for (const int added_curve_i : range) {
- const Span<NeighborInfo> neighbors = neighbors_per_curve[added_curve_i];
- float length_sum = 0.0f;
- for (const NeighborInfo &neighbor : neighbors) {
- const IndexRange neighbor_points = curves_->points_for_curve(neighbor.index);
- float neighbor_length = 0.0f;
- const int tot_segments = neighbor_points.size() - 1;
- for (const int segment_i : IndexRange(tot_segments)) {
- const float3 &p1 = positions_cu[neighbor_points[segment_i]];
- const float3 &p2 = positions_cu[neighbor_points[segment_i] + 1];
- neighbor_length += math::distance(p1, p2);
- }
- length_sum += neighbor.weight * neighbor_length;
- }
- const float length = neighbors.is_empty() ? new_curve_length_ : length_sum;
- r_lengths[added_curve_i] = length;
- }
- });
- }
-
- float3 compute_point_normal_su(const int looptri_index, const float3 &bary_coord)
- {
- const MLoopTri &looptri = surface_looptris_[looptri_index];
- const int l0 = looptri.tri[0];
- const int l1 = looptri.tri[1];
- const int l2 = looptri.tri[2];
-
- const float3 &l0_normal_su = corner_normals_su_[l0];
- const float3 &l1_normal_su = corner_normals_su_[l1];
- const float3 &l2_normal_su = corner_normals_su_[l2];
-
- const float3 normal_su = math::normalize(
- attribute_math::mix3(bary_coord, l0_normal_su, l1_normal_su, l2_normal_su));
- return normal_su;
- }
-
- Array<float3> compute_normals_for_added_curves_su(const AddedPoints &added_points)
- {
- Array<float3> normals_su(added_points.bary_coords.size());
- threading::parallel_for(normals_su.index_range(), 256, [&](const IndexRange range) {
- for (const int i : range) {
- const int looptri_index = added_points.looptri_indices[i];
- const float3 &bary_coord = added_points.bary_coords[i];
- normals_su[i] = this->compute_point_normal_su(looptri_index, bary_coord);
- }
- });
- return normals_su;
- }
-
- void initialize_surface_attachment(const AddedPoints &added_points)
- {
- MutableSpan<int> surface_triangle_indices = curves_->surface_triangle_indices_for_write();
- MutableSpan<float2> surface_triangle_coords = curves_->surface_triangle_coords_for_write();
- threading::parallel_for(
- added_points.bary_coords.index_range(), 1024, [&](const IndexRange range) {
- for (const int i : range) {
- const int curve_i = tot_old_curves_ + i;
- surface_triangle_indices[curve_i] = added_points.looptri_indices[i];
- surface_triangle_coords[curve_i] = float2(added_points.bary_coords[i]);
- }
- });
- }
-
- /**
- * Initialize new curves so that they are just a straight line in the normal direction.
- */
- void initialize_position_without_interpolation(const AddedPoints &added_points,
- const Span<float> lengths_cu,
- const MutableSpan<float3> normals_su)
- {
- MutableSpan<float3> positions_cu = curves_->positions_for_write();
-
- threading::parallel_for(
- added_points.bary_coords.index_range(), 256, [&](const IndexRange range) {
- for (const int i : range) {
- const int first_point_i = tot_old_points_ + i * points_per_curve_;
- const float3 &root_cu = added_points.positions_cu[i];
- const float length = lengths_cu[i];
- const float3 &normal_su = normals_su[i];
- const float3 normal_cu = math::normalize(surface_to_curves_normal_mat_ * normal_su);
- const float3 tip_cu = root_cu + length * normal_cu;
-
- initialize_straight_curve_positions(
- root_cu, tip_cu, positions_cu.slice(first_point_i, points_per_curve_));
- }
- });
- }
-
- /**
- * Use neighboring curves to determine the shape.
- */
- void initialize_position_with_interpolation(const AddedPoints &added_points,
- const Span<NeighborsVector> neighbors_per_curve,
- const Span<float3> new_normals_su,
- const Span<float> new_lengths_cu)
- {
- MutableSpan<float3> positions_cu = curves_->positions_for_write();
- const VArray_Span<int> surface_triangle_indices{curves_->surface_triangle_indices()};
- const Span<float2> surface_triangle_coords = curves_->surface_triangle_coords();
-
- threading::parallel_for(
- added_points.bary_coords.index_range(), 256, [&](const IndexRange range) {
- for (const int i : range) {
- const Span<NeighborInfo> neighbors = neighbors_per_curve[i];
-
- const float length_cu = new_lengths_cu[i];
- const float3 &normal_su = new_normals_su[i];
- const float3 normal_cu = math::normalize(surface_to_curves_normal_mat_ * normal_su);
-
- const float3 &root_cu = added_points.positions_cu[i];
- const int first_point_i = tot_old_points_ + i * points_per_curve_;
-
- if (neighbors.is_empty()) {
- /* If there are no neighbors, just make a straight line. */
- const float3 tip_cu = root_cu + length_cu * normal_cu;
- initialize_straight_curve_positions(
- root_cu, tip_cu, positions_cu.slice(first_point_i, points_per_curve_));
- continue;
- }
-
- positions_cu.slice(first_point_i, points_per_curve_).fill(root_cu);
-
- for (const NeighborInfo &neighbor : neighbors) {
- const int neighbor_curve_i = neighbor.index;
- const int neighbor_looptri_index = surface_triangle_indices[neighbor_curve_i];
-
- float3 neighbor_bary_coord{surface_triangle_coords[neighbor_curve_i]};
- neighbor_bary_coord.z = 1.0f - neighbor_bary_coord.x - neighbor_bary_coord.y;
-
- const float3 neighbor_normal_su = this->compute_point_normal_su(
- neighbor_looptri_index, neighbor_bary_coord);
- const float3 neighbor_normal_cu = math::normalize(surface_to_curves_normal_mat_ *
- neighbor_normal_su);
-
- /* The rotation matrix used to transform relative coordinates of the neighbor curve
- * to the new curve. */
- float normal_rotation_cu[3][3];
- rotation_between_vecs_to_mat3(normal_rotation_cu, neighbor_normal_cu, normal_cu);
-
- const IndexRange neighbor_points = curves_->points_for_curve(neighbor_curve_i);
- const float3 &neighbor_root_cu = positions_cu[neighbor_points[0]];
-
- /* Use a temporary #PolySpline, because that's the easiest way to resample an
- * existing curve right now. Resampling is necessary if the length of the new curve
- * does not match the length of the neighbors or the number of handle points is
- * different. */
- PolySpline neighbor_spline;
- neighbor_spline.resize(neighbor_points.size());
- neighbor_spline.positions().copy_from(positions_cu.slice(neighbor_points));
- neighbor_spline.mark_cache_invalid();
-
- const float neighbor_length_cu = neighbor_spline.length();
- const float length_factor = std::min(1.0f, length_cu / neighbor_length_cu);
-
- const float resample_factor = (1.0f / (points_per_curve_ - 1.0f)) * length_factor;
- for (const int j : IndexRange(points_per_curve_)) {
- const Spline::LookupResult lookup = neighbor_spline.lookup_evaluated_factor(
- j * resample_factor);
- const float index_factor = lookup.evaluated_index + lookup.factor;
- float3 p;
- neighbor_spline.sample_with_index_factors<float3>(
- neighbor_spline.positions(), {&index_factor, 1}, {&p, 1});
- const float3 relative_coord = p - neighbor_root_cu;
- float3 rotated_relative_coord = relative_coord;
- mul_m3_v3(normal_rotation_cu, rotated_relative_coord);
- positions_cu[first_point_i + j] += neighbor.weight * rotated_relative_coord;
- }
- }
- }
- });
- }
};
-void AddOperation::on_stroke_extended(bContext *C, const StrokeExtension &stroke_extension)
+void AddOperation::on_stroke_extended(const bContext &C, const StrokeExtension &stroke_extension)
{
- AddOperationExecutor executor;
+ AddOperationExecutor executor{C};
executor.execute(*this, C, stroke_extension);
}
-std::unique_ptr<CurvesSculptStrokeOperation> new_add_operation(bContext &C, ReportList *reports)
+std::unique_ptr<CurvesSculptStrokeOperation> new_add_operation(const bContext &C,
+ ReportList *reports)
{
- Object &ob_active = *CTX_data_active_object(&C);
+ const Object &ob_active = *CTX_data_active_object(&C);
BLI_assert(ob_active.type == OB_CURVES);
- Curves &curves_id = *static_cast<Curves *>(ob_active.data);
+ const Curves &curves_id = *static_cast<Curves *>(ob_active.data);
if (curves_id.surface == nullptr || curves_id.surface->type != OB_MESH) {
BKE_report(reports, RPT_WARNING, "Can not use Add brush when there is no surface mesh");
return {};
diff --git a/source/blender/editors/sculpt_paint/curves_sculpt_brush.cc b/source/blender/editors/sculpt_paint/curves_sculpt_brush.cc
index 89470772e1c..8c6ef34ef26 100644
--- a/source/blender/editors/sculpt_paint/curves_sculpt_brush.cc
+++ b/source/blender/editors/sculpt_paint/curves_sculpt_brush.cc
@@ -4,15 +4,22 @@
#include "curves_sculpt_intern.hh"
+#include "BKE_attribute_math.hh"
#include "BKE_bvhutils.h"
#include "BKE_context.h"
#include "BKE_curves.hh"
+#include "DNA_meshdata_types.h"
+
#include "ED_view3d.h"
#include "UI_interface.h"
+#include "DNA_mesh_types.h"
+#include "DNA_meshdata_types.h"
+
#include "BLI_enumerable_thread_specific.hh"
+#include "BLI_length_parameterize.hh"
#include "BLI_task.hh"
/**
@@ -41,9 +48,9 @@ static std::optional<float3> find_curves_brush_position(const CurvesGeometry &cu
const float3 &ray_start_cu,
const float3 &ray_end_cu,
const float brush_radius_re,
- ARegion &region,
- RegionView3D &rv3d,
- Object &object)
+ const ARegion &region,
+ const RegionView3D &rv3d,
+ const Object &object)
{
/* This value might have to be adjusted based on user feedback. */
const float brush_inner_radius_re = std::min<float>(brush_radius_re, (float)UI_UNIT_X / 3.0f);
@@ -94,11 +101,30 @@ static std::optional<float3> find_curves_brush_position(const CurvesGeometry &cu
for (const int curve_i : curves_range) {
const IndexRange points = curves.points_for_curve(curve_i);
- const int tot_segments = points.size() - 1;
- for (const int segment_i : IndexRange(tot_segments)) {
- const float3 &p1_cu = positions[points[segment_i]];
- const float3 &p2_cu = positions[points[segment_i] + 1];
+ if (points.size() == 1) {
+ const float3 &pos_cu = positions[points.first()];
+
+ const float depth_sq_cu = math::distance_squared(ray_start_cu, pos_cu);
+ if (depth_sq_cu > max_depth_sq_cu) {
+ continue;
+ }
+
+ float2 pos_re;
+ ED_view3d_project_float_v2_m4(&region, pos_cu, pos_re, projection.values);
+
+ BrushPositionCandidate candidate;
+ candidate.position_cu = pos_cu;
+ candidate.depth_sq_cu = depth_sq_cu;
+ candidate.distance_sq_re = math::distance_squared(brush_pos_re, pos_re);
+
+ update_if_better(best_candidate, candidate);
+ continue;
+ }
+
+ for (const int segment_i : points.drop_back(1)) {
+ const float3 &p1_cu = positions[segment_i];
+ const float3 &p2_cu = positions[segment_i + 1];
float2 p1_re, p2_re;
ED_view3d_project_float_v2_m4(&region, p1_cu, p1_re, projection.values);
@@ -141,23 +167,21 @@ static std::optional<float3> find_curves_brush_position(const CurvesGeometry &cu
return best_candidate.position_cu;
}
-std::optional<CurvesBrush3D> sample_curves_3d_brush(bContext &C,
- Object &curves_object,
+std::optional<CurvesBrush3D> sample_curves_3d_brush(const Depsgraph &depsgraph,
+ const ARegion &region,
+ const View3D &v3d,
+ const RegionView3D &rv3d,
+ const Object &curves_object,
const float2 &brush_pos_re,
const float brush_radius_re)
{
- Depsgraph *depsgraph = CTX_data_depsgraph_pointer(&C);
- ARegion *region = CTX_wm_region(&C);
- View3D *v3d = CTX_wm_view3d(&C);
- RegionView3D *rv3d = CTX_wm_region_view3d(&C);
-
- Curves &curves_id = *static_cast<Curves *>(curves_object.data);
- CurvesGeometry &curves = CurvesGeometry::wrap(curves_id.geometry);
- Object *surface_object = curves_id.surface;
+ const Curves &curves_id = *static_cast<Curves *>(curves_object.data);
+ const CurvesGeometry &curves = CurvesGeometry::wrap(curves_id.geometry);
+ const Object *surface_object = curves_id.surface;
float3 center_ray_start_wo, center_ray_end_wo;
ED_view3d_win_to_segment_clipped(
- depsgraph, region, v3d, brush_pos_re, center_ray_start_wo, center_ray_end_wo, true);
+ &depsgraph, &region, &v3d, brush_pos_re, center_ray_start_wo, center_ray_end_wo, true);
/* Shorten ray when the surface object is hit. */
if (surface_object != nullptr) {
@@ -205,8 +229,8 @@ std::optional<CurvesBrush3D> sample_curves_3d_brush(bContext &C,
center_ray_start_cu,
center_ray_end_cu,
brush_radius_re,
- *region,
- *rv3d,
+ region,
+ rv3d,
curves_object);
if (!brush_position_optional_cu.has_value()) {
/* Nothing found. */
@@ -216,9 +240,9 @@ std::optional<CurvesBrush3D> sample_curves_3d_brush(bContext &C,
/* Determine the 3D brush radius. */
float3 radius_ray_start_wo, radius_ray_end_wo;
- ED_view3d_win_to_segment_clipped(depsgraph,
- region,
- v3d,
+ ED_view3d_win_to_segment_clipped(&depsgraph,
+ &region,
+ &v3d,
brush_pos_re + float2(brush_radius_re, 0.0f),
radius_ray_start_wo,
radius_ray_end_wo,
@@ -232,6 +256,55 @@ std::optional<CurvesBrush3D> sample_curves_3d_brush(bContext &C,
return brush_3d;
}
+std::optional<CurvesBrush3D> sample_curves_surface_3d_brush(
+ const Depsgraph &depsgraph,
+ const ARegion &region,
+ const View3D &v3d,
+ const CurvesSculptTransforms &transforms,
+ const BVHTreeFromMesh &surface_bvh,
+ const float2 &brush_pos_re,
+ const float brush_radius_re)
+{
+ float3 brush_ray_start_wo, brush_ray_end_wo;
+ ED_view3d_win_to_segment_clipped(
+ &depsgraph, &region, &v3d, brush_pos_re, brush_ray_start_wo, brush_ray_end_wo, true);
+ const float3 brush_ray_start_su = transforms.world_to_surface * brush_ray_start_wo;
+ const float3 brush_ray_end_su = transforms.world_to_surface * brush_ray_end_wo;
+
+ const float3 brush_ray_direction_su = math::normalize(brush_ray_end_su - brush_ray_start_su);
+
+ BVHTreeRayHit ray_hit;
+ ray_hit.dist = FLT_MAX;
+ ray_hit.index = -1;
+ BLI_bvhtree_ray_cast(surface_bvh.tree,
+ brush_ray_start_su,
+ brush_ray_direction_su,
+ 0.0f,
+ &ray_hit,
+ surface_bvh.raycast_callback,
+ const_cast<void *>(static_cast<const void *>(&surface_bvh)));
+ if (ray_hit.index == -1) {
+ return std::nullopt;
+ }
+
+ float3 brush_radius_ray_start_wo, brush_radius_ray_end_wo;
+ ED_view3d_win_to_segment_clipped(&depsgraph,
+ &region,
+ &v3d,
+ brush_pos_re + float2(brush_radius_re, 0),
+ brush_radius_ray_start_wo,
+ brush_radius_ray_end_wo,
+ true);
+ const float3 brush_radius_ray_start_cu = transforms.world_to_curves * brush_radius_ray_start_wo;
+ const float3 brush_radius_ray_end_cu = transforms.world_to_curves * brush_radius_ray_end_wo;
+
+ const float3 brush_pos_su = ray_hit.co;
+ const float3 brush_pos_cu = transforms.surface_to_curves * brush_pos_su;
+ const float brush_radius_cu = dist_to_line_v3(
+ brush_pos_cu, brush_radius_ray_start_cu, brush_radius_ray_end_cu);
+ return CurvesBrush3D{brush_pos_cu, brush_radius_cu};
+}
+
Vector<float4x4> get_symmetry_brush_transforms(const eCurvesSymmetryType symmetry)
{
Vector<float4x4> matrices;
@@ -260,4 +333,68 @@ Vector<float4x4> get_symmetry_brush_transforms(const eCurvesSymmetryType symmetr
return matrices;
}
+float transform_brush_radius(const float4x4 &transform,
+ const float3 &brush_position,
+ const float old_radius)
+{
+ const float3 offset_position = brush_position + float3(old_radius, 0.0f, 0.0f);
+ const float3 new_position = transform * brush_position;
+ const float3 new_offset_position = transform * offset_position;
+ return math::distance(new_position, new_offset_position);
+}
+
+void move_last_point_and_resample(MutableSpan<float3> positions, const float3 &new_last_position)
+{
+ /* Find the accumulated length of each point in the original curve,
+ * treating it as a poly curve for performance reasons and simplicity. */
+ Array<float> orig_lengths(length_parameterize::lengths_num(positions.size(), false));
+ length_parameterize::accumulate_lengths<float3>(positions, false, orig_lengths);
+ const float orig_total_length = orig_lengths.last();
+
+ /* Find the factor by which the new curve is shorter or longer than the original. */
+ const float new_last_segment_length = math::distance(positions.last(1), new_last_position);
+ const float new_total_length = orig_lengths.last(1) + new_last_segment_length;
+ const float length_factor = safe_divide(new_total_length, orig_total_length);
+
+ /* Calculate the lengths to sample the original curve with by scaling the original lengths. */
+ Array<float> new_lengths(positions.size() - 1);
+ new_lengths.first() = 0.0f;
+ for (const int i : new_lengths.index_range().drop_front(1)) {
+ new_lengths[i] = orig_lengths[i - 1] * length_factor;
+ }
+
+ Array<int> indices(positions.size() - 1);
+ Array<float> factors(positions.size() - 1);
+ length_parameterize::create_samples_from_sorted_lengths(
+ orig_lengths, new_lengths, false, indices, factors);
+
+ Array<float3> new_positions(positions.size() - 1);
+ length_parameterize::linear_interpolation<float3>(positions, indices, factors, new_positions);
+ positions.drop_back(1).copy_from(new_positions);
+ positions.last() = new_last_position;
+}
+
+CurvesSculptCommonContext::CurvesSculptCommonContext(const bContext &C)
+{
+ this->depsgraph = CTX_data_depsgraph_pointer(&C);
+ this->scene = CTX_data_scene(&C);
+ this->region = CTX_wm_region(&C);
+ this->v3d = CTX_wm_view3d(&C);
+ this->rv3d = CTX_wm_region_view3d(&C);
+}
+
+CurvesSculptTransforms::CurvesSculptTransforms(const Object &curves_ob, const Object *surface_ob)
+{
+ this->curves_to_world = curves_ob.obmat;
+ this->world_to_curves = this->curves_to_world.inverted();
+
+ if (surface_ob != nullptr) {
+ this->surface_to_world = surface_ob->obmat;
+ this->world_to_surface = this->surface_to_world.inverted();
+ this->surface_to_curves = this->world_to_curves * this->surface_to_world;
+ this->curves_to_surface = this->world_to_surface * this->curves_to_world;
+ this->surface_to_curves_normal = this->surface_to_curves.inverted().transposed();
+ }
+}
+
} // namespace blender::ed::sculpt_paint
diff --git a/source/blender/editors/sculpt_paint/curves_sculpt_comb.cc b/source/blender/editors/sculpt_paint/curves_sculpt_comb.cc
index 28258a26f74..541bf9d8253 100644
--- a/source/blender/editors/sculpt_paint/curves_sculpt_comb.cc
+++ b/source/blender/editors/sculpt_paint/curves_sculpt_comb.cc
@@ -37,6 +37,8 @@
#include "UI_interface.h"
+#include "WM_api.h"
+
/**
* The code below uses a prefix naming convention to indicate the coordinate space:
* cu: Local space of the curves object that is being edited.
@@ -67,7 +69,7 @@ class CombOperation : public CurvesSculptStrokeOperation {
friend struct CombOperationExecutor;
public:
- void on_stroke_extended(bContext *C, const StrokeExtension &stroke_extension) override;
+ void on_stroke_extended(const bContext &C, const StrokeExtension &stroke_extension) override;
};
/**
@@ -76,61 +78,47 @@ class CombOperation : public CurvesSculptStrokeOperation {
*/
struct CombOperationExecutor {
CombOperation *self_ = nullptr;
- bContext *C_ = nullptr;
- Depsgraph *depsgraph_ = nullptr;
- Scene *scene_ = nullptr;
- Object *object_ = nullptr;
- ARegion *region_ = nullptr;
- View3D *v3d_ = nullptr;
- RegionView3D *rv3d_ = nullptr;
+ CurvesSculptCommonContext ctx_;
- CurvesSculpt *curves_sculpt_ = nullptr;
- Brush *brush_ = nullptr;
- float brush_radius_re_;
+ const CurvesSculpt *curves_sculpt_ = nullptr;
+ const Brush *brush_ = nullptr;
+ float brush_radius_base_re_;
+ float brush_radius_factor_;
float brush_strength_;
eBrushFalloffShape falloff_shape_;
+ Object *object_ = nullptr;
Curves *curves_id_ = nullptr;
CurvesGeometry *curves_ = nullptr;
- const Object *surface_ob_ = nullptr;
- const Mesh *surface_ = nullptr;
- Span<MLoopTri> surface_looptris_;
+ VArray<float> point_factors_;
+ Vector<int64_t> selected_curve_indices_;
+ IndexMask curve_selection_;
float2 brush_pos_prev_re_;
float2 brush_pos_re_;
float2 brush_pos_diff_re_;
- float brush_pos_diff_length_re_;
- float4x4 curves_to_world_mat_;
- float4x4 world_to_curves_mat_;
- float4x4 surface_to_world_mat_;
- float4x4 world_to_surface_mat_;
+ CurvesSculptTransforms transforms_;
- BVHTreeFromMesh surface_bvh_;
+ CombOperationExecutor(const bContext &C) : ctx_(C)
+ {
+ }
- void execute(CombOperation &self, bContext *C, const StrokeExtension &stroke_extension)
+ void execute(CombOperation &self, const bContext &C, const StrokeExtension &stroke_extension)
{
self_ = &self;
BLI_SCOPED_DEFER([&]() { self_->brush_pos_last_re_ = stroke_extension.mouse_position; });
- C_ = C;
- depsgraph_ = CTX_data_depsgraph_pointer(C);
- scene_ = CTX_data_scene(C);
- object_ = CTX_data_active_object(C);
- region_ = CTX_wm_region(C);
- v3d_ = CTX_wm_view3d(C);
- rv3d_ = CTX_wm_region_view3d(C);
-
- curves_sculpt_ = scene_->toolsettings->curves_sculpt;
- brush_ = BKE_paint_brush(&curves_sculpt_->paint);
- brush_radius_re_ = BKE_brush_size_get(scene_, brush_);
- brush_strength_ = BKE_brush_alpha_get(scene_, brush_);
+ object_ = CTX_data_active_object(&C);
- curves_to_world_mat_ = object_->obmat;
- world_to_curves_mat_ = curves_to_world_mat_.inverted();
+ curves_sculpt_ = ctx_.scene->toolsettings->curves_sculpt;
+ brush_ = BKE_paint_brush_for_read(&curves_sculpt_->paint);
+ brush_radius_base_re_ = BKE_brush_size_get(ctx_.scene, brush_);
+ brush_radius_factor_ = brush_radius_factor(*brush_, stroke_extension);
+ brush_strength_ = brush_strength_get(*ctx_.scene, *brush_, stroke_extension);
falloff_shape_ = static_cast<eBrushFalloffShape>(brush_->falloff_shape);
@@ -140,26 +128,14 @@ struct CombOperationExecutor {
return;
}
+ transforms_ = CurvesSculptTransforms(*object_, curves_id_->surface);
+
+ point_factors_ = get_point_selection(*curves_id_);
+ curve_selection_ = retrieve_selected_curves(*curves_id_, selected_curve_indices_);
+
brush_pos_prev_re_ = self_->brush_pos_last_re_;
brush_pos_re_ = stroke_extension.mouse_position;
brush_pos_diff_re_ = brush_pos_re_ - brush_pos_prev_re_;
- brush_pos_diff_length_re_ = math::length(brush_pos_diff_re_);
-
- surface_ob_ = curves_id_->surface;
- if (surface_ob_ != nullptr) {
- surface_ = static_cast<const Mesh *>(surface_ob_->data);
- surface_looptris_ = {BKE_mesh_runtime_looptri_ensure(surface_),
- BKE_mesh_runtime_looptri_len(surface_)};
- surface_to_world_mat_ = surface_ob_->obmat;
- world_to_surface_mat_ = surface_to_world_mat_.inverted();
- BKE_bvhtree_from_mesh_get(&surface_bvh_, surface_, BVHTREE_FROM_LOOPTRI, 2);
- }
-
- BLI_SCOPED_DEFER([&]() {
- if (surface_ob_ != nullptr) {
- free_bvhtree_from_mesh(&surface_bvh_);
- }
- });
if (stroke_extension.is_first) {
if (falloff_shape_ == PAINT_FALLOFF_SHAPE_SPHERE) {
@@ -186,7 +162,8 @@ struct CombOperationExecutor {
curves_->tag_positions_changed();
DEG_id_tag_update(&curves_id_->id, ID_RECALC_GEOMETRY);
- ED_region_tag_redraw(region_);
+ WM_main_add_notifier(NC_GEOM | ND_DATA, &curves_id_->id);
+ ED_region_tag_redraw(ctx_.region);
}
/**
@@ -209,13 +186,14 @@ struct CombOperationExecutor {
MutableSpan<float3> positions_cu = curves_->positions_for_write();
float4x4 projection;
- ED_view3d_ob_project_mat_get(rv3d_, object_, projection.values);
+ ED_view3d_ob_project_mat_get(ctx_.rv3d, object_, projection.values);
- const float brush_radius_sq_re = pow2f(brush_radius_re_);
+ const float brush_radius_re = brush_radius_base_re_ * brush_radius_factor_;
+ const float brush_radius_sq_re = pow2f(brush_radius_re);
- threading::parallel_for(curves_->curves_range(), 256, [&](const IndexRange curves_range) {
+ threading::parallel_for(curve_selection_.index_range(), 256, [&](const IndexRange range) {
Vector<int> &local_changed_curves = r_changed_curves.local();
- for (const int curve_i : curves_range) {
+ for (const int curve_i : curve_selection_.slice(range)) {
bool curve_changed = false;
const IndexRange points = curves_->points_for_curve(curve_i);
for (const int point_i : points.drop_front(1)) {
@@ -223,7 +201,7 @@ struct CombOperationExecutor {
/* Find the position of the point in screen space. */
float2 old_pos_re;
- ED_view3d_project_float_v2_m4(region_, old_pos_cu, old_pos_re, projection.values);
+ ED_view3d_project_float_v2_m4(ctx_.region, old_pos_cu, old_pos_re, projection.values);
const float distance_to_brush_sq_re = dist_squared_to_line_segment_v2(
old_pos_re, brush_pos_prev_re_, brush_pos_re_);
@@ -235,17 +213,21 @@ struct CombOperationExecutor {
const float distance_to_brush_re = std::sqrt(distance_to_brush_sq_re);
/* A falloff that is based on how far away the point is from the stroke. */
const float radius_falloff = BKE_brush_curve_strength(
- brush_, distance_to_brush_re, brush_radius_re_);
+ brush_, distance_to_brush_re, brush_radius_re);
/* Combine the falloff and brush strength. */
- const float weight = brush_strength_ * radius_falloff;
+ const float weight = brush_strength_ * radius_falloff * point_factors_[point_i];
- /* Offset the old point position in screen space and transform it back into 3D space. */
+ /* Offset the old point position in screen space and transform it back into 3D space.
+ */
const float2 new_position_re = old_pos_re + brush_pos_diff_re_ * weight;
float3 new_position_wo;
- ED_view3d_win_to_3d(
- v3d_, region_, curves_to_world_mat_ * old_pos_cu, new_position_re, new_position_wo);
+ ED_view3d_win_to_3d(ctx_.v3d,
+ ctx_.region,
+ transforms_.curves_to_world * old_pos_cu,
+ new_position_re,
+ new_position_wo);
const float3 new_position_cu = brush_transform *
- (world_to_curves_mat_ * new_position_wo);
+ (transforms_.world_to_curves * new_position_wo);
positions_cu[point_i] = new_position_cu;
curve_changed = true;
@@ -263,23 +245,23 @@ struct CombOperationExecutor {
void comb_spherical_with_symmetry(EnumerableThreadSpecific<Vector<int>> &r_changed_curves)
{
float4x4 projection;
- ED_view3d_ob_project_mat_get(rv3d_, object_, projection.values);
+ ED_view3d_ob_project_mat_get(ctx_.rv3d, object_, projection.values);
float3 brush_start_wo, brush_end_wo;
- ED_view3d_win_to_3d(v3d_,
- region_,
- curves_to_world_mat_ * self_->brush_3d_.position_cu,
+ ED_view3d_win_to_3d(ctx_.v3d,
+ ctx_.region,
+ transforms_.curves_to_world * self_->brush_3d_.position_cu,
brush_pos_prev_re_,
brush_start_wo);
- ED_view3d_win_to_3d(v3d_,
- region_,
- curves_to_world_mat_ * self_->brush_3d_.position_cu,
+ ED_view3d_win_to_3d(ctx_.v3d,
+ ctx_.region,
+ transforms_.curves_to_world * self_->brush_3d_.position_cu,
brush_pos_re_,
brush_end_wo);
- const float3 brush_start_cu = world_to_curves_mat_ * brush_start_wo;
- const float3 brush_end_cu = world_to_curves_mat_ * brush_end_wo;
+ const float3 brush_start_cu = transforms_.world_to_curves * brush_start_wo;
+ const float3 brush_end_cu = transforms_.world_to_curves * brush_end_wo;
- const float brush_radius_cu = self_->brush_3d_.radius_cu;
+ const float brush_radius_cu = self_->brush_3d_.radius_cu * brush_radius_factor_;
const Vector<float4x4> symmetry_brush_transforms = get_symmetry_brush_transforms(
eCurvesSymmetryType(curves_id_->symmetry));
@@ -300,9 +282,9 @@ struct CombOperationExecutor {
const float brush_radius_sq_cu = pow2f(brush_radius_cu);
const float3 brush_diff_cu = brush_end_cu - brush_start_cu;
- threading::parallel_for(curves_->curves_range(), 256, [&](const IndexRange curves_range) {
+ threading::parallel_for(curve_selection_.index_range(), 256, [&](const IndexRange range) {
Vector<int> &local_changed_curves = r_changed_curves.local();
- for (const int curve_i : curves_range) {
+ for (const int curve_i : curve_selection_.slice(range)) {
bool curve_changed = false;
const IndexRange points = curves_->points_for_curve(curve_i);
for (const int point_i : points.drop_front(1)) {
@@ -322,7 +304,7 @@ struct CombOperationExecutor {
const float radius_falloff = BKE_brush_curve_strength(
brush_, distance_to_brush_cu, brush_radius_cu);
/* Combine the falloff and brush strength. */
- const float weight = brush_strength_ * radius_falloff;
+ const float weight = brush_strength_ * radius_falloff * point_factors_[point_i];
/* Update the point position. */
positions_cu[point_i] = pos_old_cu + weight * brush_diff_cu;
@@ -340,8 +322,13 @@ struct CombOperationExecutor {
*/
void initialize_spherical_brush_reference_point()
{
- std::optional<CurvesBrush3D> brush_3d = sample_curves_3d_brush(
- *C_, *object_, brush_pos_re_, brush_radius_re_);
+ std::optional<CurvesBrush3D> brush_3d = sample_curves_3d_brush(*ctx_.depsgraph,
+ *ctx_.region,
+ *ctx_.v3d,
+ *ctx_.rv3d,
+ *object_,
+ brush_pos_re_,
+ brush_radius_base_re_);
if (brush_3d.has_value()) {
self_->brush_3d_ = *brush_3d;
}
@@ -380,11 +367,11 @@ struct CombOperationExecutor {
threading::parallel_for(changed_curves.index_range(), 256, [&](const IndexRange range) {
for (const int curve_i : changed_curves.as_span().slice(range)) {
const IndexRange points = curves_->points_for_curve(curve_i);
- for (const int segment_i : IndexRange(points.size() - 1)) {
- const float3 &p1_cu = positions_cu[points[segment_i]];
- float3 &p2_cu = positions_cu[points[segment_i] + 1];
+ for (const int segment_i : points.drop_back(1)) {
+ const float3 &p1_cu = positions_cu[segment_i];
+ float3 &p2_cu = positions_cu[segment_i + 1];
const float3 direction = math::normalize(p2_cu - p1_cu);
- const float expected_length_cu = expected_lengths_cu[points[segment_i]];
+ const float expected_length_cu = expected_lengths_cu[segment_i];
p2_cu = p1_cu + direction * expected_length_cu;
}
}
@@ -393,9 +380,9 @@ struct CombOperationExecutor {
}
};
-void CombOperation::on_stroke_extended(bContext *C, const StrokeExtension &stroke_extension)
+void CombOperation::on_stroke_extended(const bContext &C, const StrokeExtension &stroke_extension)
{
- CombOperationExecutor executor;
+ CombOperationExecutor executor{C};
executor.execute(*this, C, stroke_extension);
}
diff --git a/source/blender/editors/sculpt_paint/curves_sculpt_delete.cc b/source/blender/editors/sculpt_paint/curves_sculpt_delete.cc
index 3f3c48ecbb6..eab7dabcd22 100644
--- a/source/blender/editors/sculpt_paint/curves_sculpt_delete.cc
+++ b/source/blender/editors/sculpt_paint/curves_sculpt_delete.cc
@@ -35,6 +35,8 @@
#include "ED_screen.h"
#include "ED_view3d.h"
+#include "WM_api.h"
+
/**
* The code below uses a suffix naming convention to indicate the coordinate space:
* cu: Local space of the curves object that is being edited.
@@ -48,65 +50,57 @@ using blender::bke::CurvesGeometry;
class DeleteOperation : public CurvesSculptStrokeOperation {
private:
- float2 brush_pos_prev_re_;
-
CurvesBrush3D brush_3d_;
friend struct DeleteOperationExecutor;
public:
- void on_stroke_extended(bContext *C, const StrokeExtension &stroke_extension) override;
+ void on_stroke_extended(const bContext &C, const StrokeExtension &stroke_extension) override;
};
struct DeleteOperationExecutor {
DeleteOperation *self_ = nullptr;
- bContext *C_ = nullptr;
- Depsgraph *depsgraph_ = nullptr;
- Scene *scene_ = nullptr;
- Object *object_ = nullptr;
- ARegion *region_ = nullptr;
- View3D *v3d_ = nullptr;
- RegionView3D *rv3d_ = nullptr;
+ CurvesSculptCommonContext ctx_;
+ Object *object_ = nullptr;
Curves *curves_id_ = nullptr;
CurvesGeometry *curves_ = nullptr;
- CurvesSculpt *curves_sculpt_ = nullptr;
- Brush *brush_ = nullptr;
- float brush_radius_re_;
+ Vector<int64_t> selected_curve_indices_;
+ IndexMask curve_selection_;
+
+ const CurvesSculpt *curves_sculpt_ = nullptr;
+ const Brush *brush_ = nullptr;
+ float brush_radius_base_re_;
+ float brush_radius_factor_;
float2 brush_pos_re_;
- float2 brush_pos_prev_re_;
- float4x4 curves_to_world_mat_;
- float4x4 world_to_curves_mat_;
+ CurvesSculptTransforms transforms_;
- void execute(DeleteOperation &self, bContext *C, const StrokeExtension &stroke_extension)
+ DeleteOperationExecutor(const bContext &C) : ctx_(C)
{
- BLI_SCOPED_DEFER([&]() { self.brush_pos_prev_re_ = stroke_extension.mouse_position; });
+ }
+ void execute(DeleteOperation &self, const bContext &C, const StrokeExtension &stroke_extension)
+ {
self_ = &self;
- C_ = C;
- depsgraph_ = CTX_data_depsgraph_pointer(C);
- scene_ = CTX_data_scene(C);
- object_ = CTX_data_active_object(C);
- region_ = CTX_wm_region(C);
- v3d_ = CTX_wm_view3d(C);
- rv3d_ = CTX_wm_region_view3d(C);
+ object_ = CTX_data_active_object(&C);
curves_id_ = static_cast<Curves *>(object_->data);
curves_ = &CurvesGeometry::wrap(curves_id_->geometry);
- curves_sculpt_ = scene_->toolsettings->curves_sculpt;
- brush_ = BKE_paint_brush(&curves_sculpt_->paint);
- brush_radius_re_ = BKE_brush_size_get(scene_, brush_);
+ selected_curve_indices_.clear();
+ curve_selection_ = retrieve_selected_curves(*curves_id_, selected_curve_indices_);
+
+ curves_sculpt_ = ctx_.scene->toolsettings->curves_sculpt;
+ brush_ = BKE_paint_brush_for_read(&curves_sculpt_->paint);
+ brush_radius_base_re_ = BKE_brush_size_get(ctx_.scene, brush_);
+ brush_radius_factor_ = brush_radius_factor(*brush_, stroke_extension);
brush_pos_re_ = stroke_extension.mouse_position;
- brush_pos_prev_re_ = stroke_extension.is_first ? stroke_extension.mouse_position :
- self.brush_pos_prev_re_;
- curves_to_world_mat_ = object_->obmat;
- world_to_curves_mat_ = curves_to_world_mat_.inverted();
+ transforms_ = CurvesSculptTransforms(*object_, curves_id_->surface);
const eBrushFalloffShape falloff_shape = static_cast<eBrushFalloffShape>(
brush_->falloff_shape);
@@ -137,7 +131,8 @@ struct DeleteOperationExecutor {
curves_->remove_curves(mask);
DEG_id_tag_update(&curves_id_->id, ID_RECALC_GEOMETRY);
- ED_region_tag_redraw(region_);
+ WM_main_add_notifier(NC_GEOM | ND_DATA, &curves_id_->id);
+ ED_region_tag_redraw(ctx_.region);
}
void delete_projected_with_symmetry(MutableSpan<bool> curves_to_delete)
@@ -145,32 +140,47 @@ struct DeleteOperationExecutor {
const Vector<float4x4> symmetry_brush_transforms = get_symmetry_brush_transforms(
eCurvesSymmetryType(curves_id_->symmetry));
for (const float4x4 &brush_transform : symmetry_brush_transforms) {
- this->delete_projected(curves_to_delete, brush_transform);
+ this->delete_projected(brush_transform, curves_to_delete);
}
}
- void delete_projected(MutableSpan<bool> curves_to_delete, const float4x4 &brush_transform)
+ void delete_projected(const float4x4 &brush_transform, MutableSpan<bool> curves_to_delete)
{
const float4x4 brush_transform_inv = brush_transform.inverted();
float4x4 projection;
- ED_view3d_ob_project_mat_get(rv3d_, object_, projection.values);
+ ED_view3d_ob_project_mat_get(ctx_.rv3d, object_, projection.values);
Span<float3> positions_cu = curves_->positions();
- threading::parallel_for(curves_->curves_range(), 512, [&](IndexRange curve_range) {
- for (const int curve_i : curve_range) {
- const IndexRange point_range = curves_->points_for_curve(curve_i);
- for (const int segment_i : IndexRange(point_range.size() - 1)) {
- const float3 pos1_cu = brush_transform_inv * positions_cu[point_range[segment_i]];
- const float3 pos2_cu = brush_transform_inv * positions_cu[point_range[segment_i + 1]];
+ const float brush_radius_re = brush_radius_base_re_ * brush_radius_factor_;
+ const float brush_radius_sq_re = pow2f(brush_radius_re);
+
+ threading::parallel_for(curve_selection_.index_range(), 512, [&](const IndexRange range) {
+ for (const int curve_i : curve_selection_.slice(range)) {
+ const IndexRange points = curves_->points_for_curve(curve_i);
+ if (points.size() == 1) {
+ const float3 pos_cu = brush_transform_inv * positions_cu[points.first()];
+ float2 pos_re;
+ ED_view3d_project_float_v2_m4(ctx_.region, pos_cu, pos_re, projection.values);
+
+ if (math::distance_squared(brush_pos_re_, pos_re) <= brush_radius_sq_re) {
+ curves_to_delete[curve_i] = true;
+ }
+ continue;
+ }
+
+ for (const int segment_i : points.drop_back(1)) {
+ const float3 pos1_cu = brush_transform_inv * positions_cu[segment_i];
+ const float3 pos2_cu = brush_transform_inv * positions_cu[segment_i + 1];
float2 pos1_re, pos2_re;
- ED_view3d_project_float_v2_m4(region_, pos1_cu, pos1_re, projection.values);
- ED_view3d_project_float_v2_m4(region_, pos2_cu, pos2_re, projection.values);
+ ED_view3d_project_float_v2_m4(ctx_.region, pos1_cu, pos1_re, projection.values);
+ ED_view3d_project_float_v2_m4(ctx_.region, pos2_cu, pos2_re, projection.values);
- const float dist = dist_seg_seg_v2(pos1_re, pos2_re, brush_pos_prev_re_, brush_pos_re_);
- if (dist <= brush_radius_re_) {
+ const float dist_sq_re = dist_squared_to_line_segment_v2(
+ brush_pos_re_, pos1_re, pos2_re);
+ if (dist_sq_re <= brush_radius_sq_re) {
curves_to_delete[curve_i] = true;
break;
}
@@ -182,57 +192,50 @@ struct DeleteOperationExecutor {
void delete_spherical_with_symmetry(MutableSpan<bool> curves_to_delete)
{
float4x4 projection;
- ED_view3d_ob_project_mat_get(rv3d_, object_, projection.values);
-
- float3 brush_start_wo, brush_end_wo;
- ED_view3d_win_to_3d(v3d_,
- region_,
- curves_to_world_mat_ * self_->brush_3d_.position_cu,
- brush_pos_prev_re_,
- brush_start_wo);
- ED_view3d_win_to_3d(v3d_,
- region_,
- curves_to_world_mat_ * self_->brush_3d_.position_cu,
+ ED_view3d_ob_project_mat_get(ctx_.rv3d, object_, projection.values);
+
+ float3 brush_wo;
+ ED_view3d_win_to_3d(ctx_.v3d,
+ ctx_.region,
+ transforms_.curves_to_world * self_->brush_3d_.position_cu,
brush_pos_re_,
- brush_end_wo);
- const float3 brush_start_cu = world_to_curves_mat_ * brush_start_wo;
- const float3 brush_end_cu = world_to_curves_mat_ * brush_end_wo;
+ brush_wo);
+ const float3 brush_cu = transforms_.world_to_curves * brush_wo;
const Vector<float4x4> symmetry_brush_transforms = get_symmetry_brush_transforms(
eCurvesSymmetryType(curves_id_->symmetry));
for (const float4x4 &brush_transform : symmetry_brush_transforms) {
- this->delete_spherical(
- curves_to_delete, brush_transform * brush_start_cu, brush_transform * brush_end_cu);
+ this->delete_spherical(brush_transform * brush_cu, curves_to_delete);
}
}
- void delete_spherical(MutableSpan<bool> curves_to_delete,
- const float3 &brush_start_cu,
- const float3 &brush_end_cu)
+ void delete_spherical(const float3 &brush_cu, MutableSpan<bool> curves_to_delete)
{
Span<float3> positions_cu = curves_->positions();
- const float brush_radius_cu = self_->brush_3d_.radius_cu;
+ const float brush_radius_cu = self_->brush_3d_.radius_cu * brush_radius_factor_;
const float brush_radius_sq_cu = pow2f(brush_radius_cu);
- threading::parallel_for(curves_->curves_range(), 512, [&](IndexRange curve_range) {
- for (const int curve_i : curve_range) {
+ threading::parallel_for(curve_selection_.index_range(), 512, [&](const IndexRange range) {
+ for (const int curve_i : curve_selection_.slice(range)) {
const IndexRange points = curves_->points_for_curve(curve_i);
- for (const int segment_i : IndexRange(points.size() - 1)) {
- const float3 pos1_cu = positions_cu[points[segment_i]];
- const float3 pos2_cu = positions_cu[points[segment_i] + 1];
-
- float3 closest_segment_cu, closest_brush_cu;
- isect_seg_seg_v3(pos1_cu,
- pos2_cu,
- brush_start_cu,
- brush_end_cu,
- closest_segment_cu,
- closest_brush_cu);
- const float distance_to_brush_sq_cu = math::distance_squared(closest_segment_cu,
- closest_brush_cu);
- if (distance_to_brush_sq_cu > brush_radius_sq_cu) {
+
+ if (points.size() == 1) {
+ const float3 &pos_cu = positions_cu[points.first()];
+ const float distance_sq_cu = math::distance_squared(pos_cu, brush_cu);
+ if (distance_sq_cu < brush_radius_sq_cu) {
+ curves_to_delete[curve_i] = true;
+ }
+ continue;
+ }
+
+ for (const int segment_i : points.drop_back(1)) {
+ const float3 &pos1_cu = positions_cu[segment_i];
+ const float3 &pos2_cu = positions_cu[segment_i + 1];
+
+ const float distance_sq_cu = dist_squared_to_line_segment_v3(brush_cu, pos1_cu, pos2_cu);
+ if (distance_sq_cu > brush_radius_sq_cu) {
continue;
}
curves_to_delete[curve_i] = true;
@@ -244,17 +247,23 @@ struct DeleteOperationExecutor {
void initialize_spherical_brush_reference_point()
{
- std::optional<CurvesBrush3D> brush_3d = sample_curves_3d_brush(
- *C_, *object_, brush_pos_re_, brush_radius_re_);
+ std::optional<CurvesBrush3D> brush_3d = sample_curves_3d_brush(*ctx_.depsgraph,
+ *ctx_.region,
+ *ctx_.v3d,
+ *ctx_.rv3d,
+ *object_,
+ brush_pos_re_,
+ brush_radius_base_re_);
if (brush_3d.has_value()) {
self_->brush_3d_ = *brush_3d;
}
}
};
-void DeleteOperation::on_stroke_extended(bContext *C, const StrokeExtension &stroke_extension)
+void DeleteOperation::on_stroke_extended(const bContext &C,
+ const StrokeExtension &stroke_extension)
{
- DeleteOperationExecutor executor;
+ DeleteOperationExecutor executor{C};
executor.execute(*this, C, stroke_extension);
}
diff --git a/source/blender/editors/sculpt_paint/curves_sculpt_grow_shrink.cc b/source/blender/editors/sculpt_paint/curves_sculpt_grow_shrink.cc
index 4ac4559cbbc..cf893f09fc6 100644
--- a/source/blender/editors/sculpt_paint/curves_sculpt_grow_shrink.cc
+++ b/source/blender/editors/sculpt_paint/curves_sculpt_grow_shrink.cc
@@ -2,8 +2,6 @@
#include <algorithm>
-#include "curves_sculpt_intern.hh"
-
#include "BLI_enumerable_thread_specific.hh"
#include "BLI_float4x4.hh"
#include "BLI_kdtree.h"
@@ -36,6 +34,8 @@
#include "ED_screen.h"
#include "ED_view3d.h"
+#include "WM_api.h"
+
#include "curves_sculpt_intern.hh"
/**
@@ -68,10 +68,10 @@ class CurvesEffect {
*/
class ShrinkCurvesEffect : public CurvesEffect {
private:
- Brush &brush_;
+ const Brush &brush_;
public:
- ShrinkCurvesEffect(Brush &brush) : brush_(brush)
+ ShrinkCurvesEffect(const Brush &brush) : brush_(brush)
{
}
@@ -151,50 +151,10 @@ class ExtrapolateCurvesEffect : public CurvesEffect {
const float3 direction = math::normalize(old_last_pos_cu - direction_reference_point);
const float3 new_last_pos_cu = old_last_pos_cu + direction * move_distance_cu;
- this->move_last_point_and_resample(positions_cu, curve_points, new_last_pos_cu);
+ move_last_point_and_resample(positions_cu.slice(curve_points), new_last_pos_cu);
}
});
}
-
- void move_last_point_and_resample(MutableSpan<float3> positions,
- const IndexRange curve_points,
- const float3 &new_last_point_position) const
- {
- Vector<float> old_lengths;
- old_lengths.append(0.0f);
- /* Used to (1) normalize the segment sizes over time and (2) support making zero-length
- * segments */
- const float extra_length = 0.001f;
- for (const int segment_i : IndexRange(curve_points.size() - 1)) {
- const float3 &p1 = positions[curve_points[segment_i]];
- const float3 &p2 = positions[curve_points[segment_i] + 1];
- const float length = math::distance(p1, p2);
- old_lengths.append(old_lengths.last() + length + extra_length);
- }
- Vector<float> point_factors;
- for (float &old_length : old_lengths) {
- point_factors.append(old_length / old_lengths.last());
- }
-
- PolySpline new_spline;
- new_spline.resize(curve_points.size());
- MutableSpan<float3> new_spline_positions = new_spline.positions();
- for (const int i : IndexRange(curve_points.size() - 1)) {
- new_spline_positions[i] = positions[curve_points[i]];
- }
- new_spline_positions.last() = new_last_point_position;
- new_spline.mark_cache_invalid();
-
- for (const int i : IndexRange(curve_points.size())) {
- const float factor = point_factors[i];
- const Spline::LookupResult lookup = new_spline.lookup_evaluated_factor(factor);
- const float index_factor = lookup.evaluated_index + lookup.factor;
- float3 p;
- new_spline.sample_with_index_factors<float3>(
- new_spline_positions, {&index_factor, 1}, {&p, 1});
- positions[curve_points[i]] = p;
- }
- }
};
/**
@@ -203,10 +163,10 @@ class ExtrapolateCurvesEffect : public CurvesEffect {
class ScaleCurvesEffect : public CurvesEffect {
private:
bool scale_up_;
- Brush &brush_;
+ const Brush &brush_;
public:
- ScaleCurvesEffect(bool scale_up, Brush &brush) : scale_up_(scale_up), brush_(brush)
+ ScaleCurvesEffect(bool scale_up, const Brush &brush) : scale_up_(scale_up), brush_(brush)
{
}
@@ -261,7 +221,7 @@ class CurvesEffectOperation : public CurvesSculptStrokeOperation {
{
}
- void on_stroke_extended(bContext *C, const StrokeExtension &stroke_extension) override;
+ void on_stroke_extended(const bContext &C, const StrokeExtension &stroke_extension) override;
};
/**
@@ -270,24 +230,24 @@ class CurvesEffectOperation : public CurvesSculptStrokeOperation {
*/
struct CurvesEffectOperationExecutor {
CurvesEffectOperation *self_ = nullptr;
- Depsgraph *depsgraph_ = nullptr;
- Scene *scene_ = nullptr;
- Object *object_ = nullptr;
- ARegion *region_ = nullptr;
- View3D *v3d_ = nullptr;
- RegionView3D *rv3d_ = nullptr;
+ CurvesSculptCommonContext ctx_;
+ Object *object_ = nullptr;
Curves *curves_id_ = nullptr;
CurvesGeometry *curves_ = nullptr;
- Brush *brush_ = nullptr;
- float brush_radius_re_;
- float brush_radius_sq_re_;
+ VArray<float> curve_selection_factors_;
+ Vector<int64_t> selected_curve_indices_;
+ IndexMask curve_selection_;
+
+ const Brush *brush_ = nullptr;
+ float brush_radius_base_re_;
+ float brush_radius_factor_;
float brush_strength_;
+
eBrushFalloffShape falloff_shape_;
- float4x4 curves_to_world_mat_;
- float4x4 world_to_curves_mat_;
+ CurvesSculptTransforms transforms_;
float2 brush_pos_start_re_;
float2 brush_pos_end_re_;
@@ -297,17 +257,18 @@ struct CurvesEffectOperationExecutor {
Vector<float> move_distances_cu;
};
- void execute(CurvesEffectOperation &self, bContext *C, const StrokeExtension &stroke_extension)
+ CurvesEffectOperationExecutor(const bContext &C) : ctx_(C)
+ {
+ }
+
+ void execute(CurvesEffectOperation &self,
+ const bContext &C,
+ const StrokeExtension &stroke_extension)
{
BLI_SCOPED_DEFER([&]() { self.last_mouse_position_ = stroke_extension.mouse_position; });
self_ = &self;
- depsgraph_ = CTX_data_depsgraph_pointer(C);
- scene_ = CTX_data_scene(C);
- object_ = CTX_data_active_object(C);
- region_ = CTX_wm_region(C);
- v3d_ = CTX_wm_view3d(C);
- rv3d_ = CTX_wm_region_view3d(C);
+ object_ = CTX_data_active_object(&C);
curves_id_ = static_cast<Curves *>(object_->data);
curves_ = &CurvesGeometry::wrap(curves_id_->geometry);
@@ -315,15 +276,20 @@ struct CurvesEffectOperationExecutor {
return;
}
- CurvesSculpt &curves_sculpt = *scene_->toolsettings->curves_sculpt;
- brush_ = BKE_paint_brush(&curves_sculpt.paint);
- brush_radius_re_ = BKE_brush_size_get(scene_, brush_);
- brush_strength_ = BKE_brush_alpha_get(scene_, brush_);
- brush_radius_sq_re_ = pow2f(brush_radius_re_);
+ curve_selection_factors_ = get_curves_selection(*curves_id_);
+ curve_selection_ = retrieve_selected_curves(*curves_id_, selected_curve_indices_);
+
+ const CurvesSculpt &curves_sculpt = *ctx_.scene->toolsettings->curves_sculpt;
+ brush_ = BKE_paint_brush_for_read(&curves_sculpt.paint);
+ brush_strength_ = brush_strength_get(*ctx_.scene, *brush_, stroke_extension);
+
+ brush_radius_base_re_ = BKE_brush_size_get(ctx_.scene, brush_);
+ brush_radius_factor_ = brush_radius_factor(*brush_, stroke_extension);
+ brush_strength_ = brush_strength_get(*ctx_.scene, *brush_, stroke_extension);
+
falloff_shape_ = eBrushFalloffShape(brush_->falloff_shape);
- curves_to_world_mat_ = object_->obmat;
- world_to_curves_mat_ = curves_to_world_mat_.inverted();
+ transforms_ = CurvesSculptTransforms(*object_, curves_id_->surface);
brush_pos_start_re_ = self.last_mouse_position_;
brush_pos_end_re_ = stroke_extension.mouse_position;
@@ -331,7 +297,13 @@ struct CurvesEffectOperationExecutor {
if (stroke_extension.is_first) {
if (falloff_shape_ == PAINT_FALLOFF_SHAPE_SPHERE) {
if (std::optional<CurvesBrush3D> brush_3d = sample_curves_3d_brush(
- *C, *object_, stroke_extension.mouse_position, brush_radius_re_)) {
+ *ctx_.depsgraph,
+ *ctx_.region,
+ *ctx_.v3d,
+ *ctx_.rv3d,
+ *object_,
+ stroke_extension.mouse_position,
+ brush_radius_base_re_)) {
self.brush_3d_ = *brush_3d;
}
}
@@ -356,7 +328,8 @@ struct CurvesEffectOperationExecutor {
curves_->tag_positions_changed();
DEG_id_tag_update(&curves_id_->id, ID_RECALC_GEOMETRY);
- ED_region_tag_redraw(region_);
+ WM_main_add_notifier(NC_GEOM | ND_DATA, &curves_id_->id);
+ ED_region_tag_redraw(ctx_.region);
}
void gather_influences_projected(
@@ -365,7 +338,7 @@ struct CurvesEffectOperationExecutor {
const Span<float3> positions_cu = curves_->positions();
float4x4 projection;
- ED_view3d_ob_project_mat_get(rv3d_, object_, projection.values);
+ ED_view3d_ob_project_mat_get(ctx_.rv3d, object_, projection.values);
const Vector<float4x4> symmetry_brush_transforms = get_symmetry_brush_transforms(
eCurvesSymmetryType(curves_id_->symmetry));
@@ -374,22 +347,26 @@ struct CurvesEffectOperationExecutor {
symmetry_brush_transforms_inv.append(brush_transform.inverted());
}
+ const float brush_radius_re = brush_radius_base_re_ * brush_radius_factor_;
+ const float brush_radius_sq_re = pow2f(brush_radius_re);
+
threading::parallel_for(curves_->curves_range(), 256, [&](const IndexRange curves_range) {
Influences &local_influences = influences_for_thread.local();
for (const int curve_i : curves_range) {
const IndexRange points = curves_->points_for_curve(curve_i);
- const int tot_segments = points.size() - 1;
- float max_move_distance_cu = 0.0f;
+ const float curve_selection_factor = curve_selection_factors_[curve_i];
+
+ float max_move_distance_cu = 0.0f;
for (const float4x4 &brush_transform_inv : symmetry_brush_transforms_inv) {
- for (const int segment_i : IndexRange(tot_segments)) {
- const float3 &p1_cu = brush_transform_inv * positions_cu[points[segment_i]];
- const float3 &p2_cu = brush_transform_inv * positions_cu[points[segment_i] + 1];
+ for (const int segment_i : points.drop_back(1)) {
+ const float3 p1_cu = brush_transform_inv * positions_cu[segment_i];
+ const float3 p2_cu = brush_transform_inv * positions_cu[segment_i + 1];
float2 p1_re, p2_re;
- ED_view3d_project_float_v2_m4(region_, p1_cu, p1_re, projection.values);
- ED_view3d_project_float_v2_m4(region_, p2_cu, p2_re, projection.values);
+ ED_view3d_project_float_v2_m4(ctx_.region, p1_cu, p1_re, projection.values);
+ ED_view3d_project_float_v2_m4(ctx_.region, p2_cu, p2_re, projection.values);
float2 closest_on_brush_re;
float2 closest_on_segment_re;
@@ -404,31 +381,31 @@ struct CurvesEffectOperationExecutor {
p1_re,
p2_re);
- if (dist_to_brush_sq_re > brush_radius_sq_re_) {
+ if (dist_to_brush_sq_re > brush_radius_sq_re) {
continue;
}
const float dist_to_brush_re = std::sqrt(dist_to_brush_sq_re);
const float radius_falloff = BKE_brush_curve_strength(
- brush_, dist_to_brush_re, brush_radius_re_);
- const float weight = brush_strength_ * radius_falloff;
+ brush_, dist_to_brush_re, brush_radius_re);
+ const float weight = brush_strength_ * radius_falloff * curve_selection_factor;
const float3 closest_on_segment_cu = math::interpolate(
p1_cu, p2_cu, lambda_on_segment);
float3 brush_start_pos_wo, brush_end_pos_wo;
- ED_view3d_win_to_3d(v3d_,
- region_,
- curves_to_world_mat_ * closest_on_segment_cu,
+ ED_view3d_win_to_3d(ctx_.v3d,
+ ctx_.region,
+ transforms_.curves_to_world * closest_on_segment_cu,
brush_pos_start_re_,
brush_start_pos_wo);
- ED_view3d_win_to_3d(v3d_,
- region_,
- curves_to_world_mat_ * closest_on_segment_cu,
+ ED_view3d_win_to_3d(ctx_.v3d,
+ ctx_.region,
+ transforms_.curves_to_world * closest_on_segment_cu,
brush_pos_end_re_,
brush_end_pos_wo);
- const float3 brush_start_pos_cu = world_to_curves_mat_ * brush_start_pos_wo;
- const float3 brush_end_pos_cu = world_to_curves_mat_ * brush_end_pos_wo;
+ const float3 brush_start_pos_cu = transforms_.world_to_curves * brush_start_pos_wo;
+ const float3 brush_end_pos_cu = transforms_.world_to_curves * brush_end_pos_wo;
const float move_distance_cu = weight *
math::distance(brush_start_pos_cu, brush_end_pos_cu);
@@ -449,21 +426,21 @@ struct CurvesEffectOperationExecutor {
const Span<float3> positions_cu = curves_->positions();
float3 brush_pos_start_wo, brush_pos_end_wo;
- ED_view3d_win_to_3d(v3d_,
- region_,
- curves_to_world_mat_ * self_->brush_3d_.position_cu,
+ ED_view3d_win_to_3d(ctx_.v3d,
+ ctx_.region,
+ transforms_.curves_to_world * self_->brush_3d_.position_cu,
brush_pos_start_re_,
brush_pos_start_wo);
- ED_view3d_win_to_3d(v3d_,
- region_,
- curves_to_world_mat_ * self_->brush_3d_.position_cu,
+ ED_view3d_win_to_3d(ctx_.v3d,
+ ctx_.region,
+ transforms_.curves_to_world * self_->brush_3d_.position_cu,
brush_pos_end_re_,
brush_pos_end_wo);
- const float3 brush_pos_start_cu = world_to_curves_mat_ * brush_pos_start_wo;
- const float3 brush_pos_end_cu = world_to_curves_mat_ * brush_pos_end_wo;
+ const float3 brush_pos_start_cu = transforms_.world_to_curves * brush_pos_start_wo;
+ const float3 brush_pos_end_cu = transforms_.world_to_curves * brush_pos_end_wo;
const float3 brush_pos_diff_cu = brush_pos_end_cu - brush_pos_start_cu;
const float brush_pos_diff_length_cu = math::length(brush_pos_diff_cu);
- const float brush_radius_cu = self_->brush_3d_.radius_cu;
+ const float brush_radius_cu = self_->brush_3d_.radius_cu * brush_radius_factor_;
const float brush_radius_sq_cu = pow2f(brush_radius_cu);
const Vector<float4x4> symmetry_brush_transforms = get_symmetry_brush_transforms(
@@ -474,15 +451,18 @@ struct CurvesEffectOperationExecutor {
for (const int curve_i : curves_range) {
const IndexRange points = curves_->points_for_curve(curve_i);
- const int tot_segments = points.size() - 1;
+
float max_move_distance_cu = 0.0f;
+
+ const float curve_selection_factor = curve_selection_factors_[curve_i];
+
for (const float4x4 &brush_transform : symmetry_brush_transforms) {
const float3 brush_pos_start_transformed_cu = brush_transform * brush_pos_start_cu;
const float3 brush_pos_end_transformed_cu = brush_transform * brush_pos_end_cu;
- for (const int segment_i : IndexRange(tot_segments)) {
- const float3 &p1_cu = positions_cu[points[segment_i]];
- const float3 &p2_cu = positions_cu[points[segment_i] + 1];
+ for (const int segment_i : points.drop_back(1)) {
+ const float3 &p1_cu = positions_cu[segment_i];
+ const float3 &p2_cu = positions_cu[segment_i + 1];
float3 closest_on_segment_cu;
float3 closest_on_brush_cu;
@@ -502,7 +482,7 @@ struct CurvesEffectOperationExecutor {
const float dist_to_brush_cu = std::sqrt(dist_to_brush_sq_cu);
const float radius_falloff = BKE_brush_curve_strength(
brush_, dist_to_brush_cu, brush_radius_cu);
- const float weight = brush_strength_ * radius_falloff;
+ const float weight = brush_strength_ * radius_falloff * curve_selection_factor;
const float move_distance_cu = weight * brush_pos_diff_length_cu;
max_move_distance_cu = std::max(max_move_distance_cu, move_distance_cu);
@@ -517,18 +497,18 @@ struct CurvesEffectOperationExecutor {
}
};
-void CurvesEffectOperation::on_stroke_extended(bContext *C,
+void CurvesEffectOperation::on_stroke_extended(const bContext &C,
const StrokeExtension &stroke_extension)
{
- CurvesEffectOperationExecutor executor;
+ CurvesEffectOperationExecutor executor{C};
executor.execute(*this, C, stroke_extension);
}
std::unique_ptr<CurvesSculptStrokeOperation> new_grow_shrink_operation(
- const BrushStrokeMode brush_mode, bContext *C)
+ const BrushStrokeMode brush_mode, const bContext &C)
{
- Scene &scene = *CTX_data_scene(C);
- Brush &brush = *BKE_paint_brush(&scene.toolsettings->curves_sculpt->paint);
+ const Scene &scene = *CTX_data_scene(&C);
+ const Brush &brush = *BKE_paint_brush_for_read(&scene.toolsettings->curves_sculpt->paint);
const bool use_scale_uniform = brush.curves_sculpt_settings->flag &
BRUSH_CURVES_SCULPT_FLAG_SCALE_UNIFORM;
const bool use_grow = (brush_mode == BRUSH_STROKE_INVERT) == ((brush.flag & BRUSH_DIR_IN) != 0);
diff --git a/source/blender/editors/sculpt_paint/curves_sculpt_intern.hh b/source/blender/editors/sculpt_paint/curves_sculpt_intern.hh
index 9d000649d62..ad3871bee45 100644
--- a/source/blender/editors/sculpt_paint/curves_sculpt_intern.hh
+++ b/source/blender/editors/sculpt_paint/curves_sculpt_intern.hh
@@ -8,12 +8,20 @@
#include "paint_intern.h"
#include "BLI_math_vector.hh"
+#include "BLI_vector.hh"
+#include "BLI_virtual_array.hh"
+#include "BKE_attribute.h"
#include "BKE_curves.hh"
struct ARegion;
struct RegionView3D;
+struct Depsgraph;
+struct View3D;
struct Object;
+struct Brush;
+struct Scene;
+struct BVHTreeFromMesh;
namespace blender::ed::sculpt_paint {
@@ -22,23 +30,44 @@ using bke::CurvesGeometry;
struct StrokeExtension {
bool is_first;
float2 mouse_position;
+ float pressure;
};
+float brush_radius_factor(const Brush &brush, const StrokeExtension &stroke_extension);
+float brush_radius_get(const Scene &scene,
+ const Brush &brush,
+ const StrokeExtension &stroke_extension);
+
+float brush_strength_factor(const Brush &brush, const StrokeExtension &stroke_extension);
+float brush_strength_get(const Scene &scene,
+ const Brush &brush,
+ const StrokeExtension &stroke_extension);
+
/**
* Base class for stroke based operations in curves sculpt mode.
*/
class CurvesSculptStrokeOperation {
public:
virtual ~CurvesSculptStrokeOperation() = default;
- virtual void on_stroke_extended(bContext *C, const StrokeExtension &stroke_extension) = 0;
+ virtual void on_stroke_extended(const bContext &C, const StrokeExtension &stroke_extension) = 0;
};
-std::unique_ptr<CurvesSculptStrokeOperation> new_add_operation(bContext &C, ReportList *reports);
+std::unique_ptr<CurvesSculptStrokeOperation> new_add_operation(const bContext &C,
+ ReportList *reports);
std::unique_ptr<CurvesSculptStrokeOperation> new_comb_operation();
std::unique_ptr<CurvesSculptStrokeOperation> new_delete_operation();
std::unique_ptr<CurvesSculptStrokeOperation> new_snake_hook_operation();
std::unique_ptr<CurvesSculptStrokeOperation> new_grow_shrink_operation(
- const BrushStrokeMode brush_mode, bContext *C);
+ const BrushStrokeMode brush_mode, const bContext &C);
+std::unique_ptr<CurvesSculptStrokeOperation> new_selection_paint_operation(
+ const BrushStrokeMode brush_mode, const bContext &C);
+std::unique_ptr<CurvesSculptStrokeOperation> new_pinch_operation(const BrushStrokeMode brush_mode,
+ const bContext &C);
+std::unique_ptr<CurvesSculptStrokeOperation> new_smooth_operation();
+std::unique_ptr<CurvesSculptStrokeOperation> new_puff_operation();
+std::unique_ptr<CurvesSculptStrokeOperation> new_density_operation(
+ const BrushStrokeMode brush_mode, const bContext &C);
+std::unique_ptr<CurvesSculptStrokeOperation> new_slide_operation();
struct CurvesBrush3D {
float3 position_cu;
@@ -48,11 +77,69 @@ struct CurvesBrush3D {
/**
* Find 3d brush position based on cursor position for curves sculpting.
*/
-std::optional<CurvesBrush3D> sample_curves_3d_brush(bContext &C,
- Object &curves_object,
+std::optional<CurvesBrush3D> sample_curves_3d_brush(const Depsgraph &depsgraph,
+ const ARegion &region,
+ const View3D &v3d,
+ const RegionView3D &rv3d,
+ const Object &curves_object,
const float2 &brush_pos_re,
- float brush_radius_re);
+ const float brush_radius_re);
Vector<float4x4> get_symmetry_brush_transforms(eCurvesSymmetryType symmetry);
+/**
+ * Get the floating point selection on the curve domain, averaged from points if necessary.
+ */
+VArray<float> get_curves_selection(const Curves &curves_id);
+
+/**
+ * Get the floating point selection on the curve domain, copied from curves if necessary.
+ */
+VArray<float> get_point_selection(const Curves &curves_id);
+
+/**
+ * Find curves that have any point selected (a selection factor greater than zero),
+ * or curves that have their own selection factor greater than zero.
+ */
+IndexMask retrieve_selected_curves(const Curves &curves_id, Vector<int64_t> &r_indices);
+
+void move_last_point_and_resample(MutableSpan<float3> positions, const float3 &new_last_position);
+
+class CurvesSculptCommonContext {
+ public:
+ const Depsgraph *depsgraph = nullptr;
+ const Scene *scene = nullptr;
+ ARegion *region = nullptr;
+ const View3D *v3d = nullptr;
+ const RegionView3D *rv3d = nullptr;
+
+ CurvesSculptCommonContext(const bContext &C);
+};
+
+struct CurvesSculptTransforms {
+ float4x4 curves_to_world;
+ float4x4 curves_to_surface;
+ float4x4 world_to_curves;
+ float4x4 world_to_surface;
+ float4x4 surface_to_world;
+ float4x4 surface_to_curves;
+ float4x4 surface_to_curves_normal;
+
+ CurvesSculptTransforms() = default;
+ CurvesSculptTransforms(const Object &curves_ob, const Object *surface_ob);
+};
+
+std::optional<CurvesBrush3D> sample_curves_surface_3d_brush(
+ const Depsgraph &depsgraph,
+ const ARegion &region,
+ const View3D &v3d,
+ const CurvesSculptTransforms &transforms,
+ const BVHTreeFromMesh &surface_bvh,
+ const float2 &brush_pos_re,
+ const float brush_radius_re);
+
+float transform_brush_radius(const float4x4 &transform,
+ const float3 &brush_position,
+ const float old_radius);
+
} // namespace blender::ed::sculpt_paint
diff --git a/source/blender/editors/sculpt_paint/curves_sculpt_ops.cc b/source/blender/editors/sculpt_paint/curves_sculpt_ops.cc
index d8713c8eb1d..5d6ffa67005 100644
--- a/source/blender/editors/sculpt_paint/curves_sculpt_ops.cc
+++ b/source/blender/editors/sculpt_paint/curves_sculpt_ops.cc
@@ -18,6 +18,7 @@
#include "WM_toolsystem.h"
#include "ED_curves_sculpt.h"
+#include "ED_image.h"
#include "ED_object.h"
#include "ED_screen.h"
#include "ED_view3d.h"
@@ -49,7 +50,7 @@
bool CURVES_SCULPT_mode_poll(bContext *C)
{
- Object *ob = CTX_data_active_object(C);
+ const Object *ob = CTX_data_active_object(C);
return ob && ob->mode & OB_MODE_SCULPT_CURVES;
}
@@ -74,14 +75,44 @@ using blender::bke::CurvesGeometry;
/** \name * SCULPT_CURVES_OT_brush_stroke
* \{ */
+float brush_radius_factor(const Brush &brush, const StrokeExtension &stroke_extension)
+{
+ if (BKE_brush_use_size_pressure(&brush)) {
+ return stroke_extension.pressure;
+ }
+ return 1.0f;
+}
+
+float brush_radius_get(const Scene &scene,
+ const Brush &brush,
+ const StrokeExtension &stroke_extension)
+{
+ return BKE_brush_size_get(&scene, &brush) * brush_radius_factor(brush, stroke_extension);
+}
+
+float brush_strength_factor(const Brush &brush, const StrokeExtension &stroke_extension)
+{
+ if (BKE_brush_use_alpha_pressure(&brush)) {
+ return stroke_extension.pressure;
+ }
+ return 1.0f;
+}
+
+float brush_strength_get(const Scene &scene,
+ const Brush &brush,
+ const StrokeExtension &stroke_extension)
+{
+ return BKE_brush_alpha_get(&scene, &brush) * brush_strength_factor(brush, stroke_extension);
+}
+
static std::unique_ptr<CurvesSculptStrokeOperation> start_brush_operation(bContext &C,
wmOperator &op)
{
const BrushStrokeMode mode = static_cast<BrushStrokeMode>(RNA_enum_get(op.ptr, "mode"));
- Scene &scene = *CTX_data_scene(&C);
- CurvesSculpt &curves_sculpt = *scene.toolsettings->curves_sculpt;
- Brush &brush = *BKE_paint_brush(&curves_sculpt.paint);
+ const Scene &scene = *CTX_data_scene(&C);
+ const CurvesSculpt &curves_sculpt = *scene.toolsettings->curves_sculpt;
+ const Brush &brush = *BKE_paint_brush_for_read(&curves_sculpt.paint);
switch (brush.curves_sculpt_tool) {
case CURVES_SCULPT_TOOL_COMB:
return new_comb_operation();
@@ -92,7 +123,9 @@ static std::unique_ptr<CurvesSculptStrokeOperation> start_brush_operation(bConte
case CURVES_SCULPT_TOOL_ADD:
return new_add_operation(C, op.reports);
case CURVES_SCULPT_TOOL_GROW_SHRINK:
- return new_grow_shrink_operation(mode, &C);
+ return new_grow_shrink_operation(mode, C);
+ case CURVES_SCULPT_TOOL_SELECTION_PAINT:
+ return new_selection_paint_operation(mode, C);
}
BLI_assert_unreachable();
return {};
@@ -128,6 +161,7 @@ static void stroke_update_step(bContext *C,
StrokeExtension stroke_extension;
RNA_float_get_array(stroke_element, "mouse", stroke_extension.mouse_position);
+ stroke_extension.pressure = RNA_float_get(stroke_element, "pressure");
if (!op_data->operation) {
stroke_extension.is_first = true;
@@ -138,7 +172,7 @@ static void stroke_update_step(bContext *C,
}
if (op_data->operation) {
- op_data->operation->on_stroke_extended(C, stroke_extension);
+ op_data->operation->on_stroke_extended(*C, stroke_extension);
}
}
@@ -149,8 +183,8 @@ static void stroke_done(const bContext *C, PaintStroke *stroke)
static int sculpt_curves_stroke_invoke(bContext *C, wmOperator *op, const wmEvent *event)
{
- Paint *paint = BKE_paint_get_active_from_context(C);
- Brush *brush = BKE_paint_brush(paint);
+ const Paint *paint = BKE_paint_get_active_from_context(C);
+ const Brush *brush = BKE_paint_brush_for_read(paint);
if (brush == nullptr) {
return OPERATOR_CANCELLED;
}
@@ -219,7 +253,7 @@ static void SCULPT_CURVES_OT_brush_stroke(struct wmOperatorType *ot)
static bool curves_sculptmode_toggle_poll(bContext *C)
{
- Object *ob = CTX_data_active_object(C);
+ const Object *ob = CTX_data_active_object(C);
if (ob == nullptr) {
return false;
}
@@ -238,7 +272,7 @@ static void curves_sculptmode_enter(bContext *C)
ob->mode = OB_MODE_SCULPT_CURVES;
- paint_cursor_start(&curves_sculpt->paint, CURVES_SCULPT_mode_poll_view3d);
+ ED_paint_cursor_start(&curves_sculpt->paint, CURVES_SCULPT_mode_poll_view3d);
/* Update for mode change. */
DEG_id_tag_update(&ob->id, ID_RECALC_COPY_ON_WRITE);
diff --git a/source/blender/editors/sculpt_paint/curves_sculpt_selection.cc b/source/blender/editors/sculpt_paint/curves_sculpt_selection.cc
new file mode 100644
index 00000000000..f620fed5761
--- /dev/null
+++ b/source/blender/editors/sculpt_paint/curves_sculpt_selection.cc
@@ -0,0 +1,105 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+
+#include "BLI_index_mask_ops.hh"
+
+#include "BKE_curves.hh"
+
+#include "curves_sculpt_intern.hh"
+
+namespace blender::ed::sculpt_paint {
+
+static VArray<float> get_curves_selection(const CurvesGeometry &curves, const eAttrDomain domain)
+{
+ switch (domain) {
+ case ATTR_DOMAIN_CURVE:
+ return curves.selection_curve_float();
+ case ATTR_DOMAIN_POINT:
+ return curves.adapt_domain(
+ curves.selection_point_float(), ATTR_DOMAIN_POINT, ATTR_DOMAIN_CURVE);
+ default:
+ BLI_assert_unreachable();
+ return {};
+ }
+}
+
+VArray<float> get_curves_selection(const Curves &curves_id)
+{
+ if (!(curves_id.flag & CV_SCULPT_SELECTION_ENABLED)) {
+ return VArray<float>::ForSingle(1.0f, CurvesGeometry::wrap(curves_id.geometry).curves_num());
+ }
+ return get_curves_selection(CurvesGeometry::wrap(curves_id.geometry),
+ eAttrDomain(curves_id.selection_domain));
+}
+
+static VArray<float> get_point_selection(const CurvesGeometry &curves, const eAttrDomain domain)
+{
+ switch (domain) {
+ case ATTR_DOMAIN_CURVE:
+ return curves.adapt_domain(
+ curves.selection_curve_float(), ATTR_DOMAIN_CURVE, ATTR_DOMAIN_POINT);
+ case ATTR_DOMAIN_POINT:
+ return curves.selection_point_float();
+ default:
+ BLI_assert_unreachable();
+ return {};
+ }
+}
+
+VArray<float> get_point_selection(const Curves &curves_id)
+{
+ if (!(curves_id.flag & CV_SCULPT_SELECTION_ENABLED)) {
+ return VArray<float>::ForSingle(1.0f, CurvesGeometry::wrap(curves_id.geometry).points_num());
+ }
+ return get_point_selection(CurvesGeometry::wrap(curves_id.geometry),
+ eAttrDomain(curves_id.selection_domain));
+}
+
+static IndexMask retrieve_selected_curves(const CurvesGeometry &curves,
+ const eAttrDomain domain,
+ Vector<int64_t> &r_indices)
+{
+ switch (domain) {
+ case ATTR_DOMAIN_POINT: {
+ const VArray<float> selection = curves.selection_point_float();
+ if (selection.is_single()) {
+ return selection.get_internal_single() == 0.0f ? IndexMask(0) :
+ IndexMask(curves.curves_num());
+ }
+ return index_mask_ops::find_indices_based_on_predicate(
+ curves.curves_range(), 512, r_indices, [&](const int curve_i) {
+ for (const int i : curves.points_for_curve(curve_i)) {
+ if (selection[i] > 0.0f) {
+ return true;
+ }
+ }
+ return false;
+ });
+ }
+ case ATTR_DOMAIN_CURVE: {
+ const VArray<float> selection = curves.selection_curve_float();
+ if (selection.is_single()) {
+ return selection.get_internal_single() == 0.0f ? IndexMask(0) :
+ IndexMask(curves.curves_num());
+ }
+ return index_mask_ops::find_indices_based_on_predicate(
+ curves.curves_range(), 2048, r_indices, [&](const int i) {
+ return selection[i] > 0.0f;
+ });
+ }
+ default:
+ BLI_assert_unreachable();
+ return {};
+ }
+}
+
+IndexMask retrieve_selected_curves(const Curves &curves_id, Vector<int64_t> &r_indices)
+{
+ if (!(curves_id.flag & CV_SCULPT_SELECTION_ENABLED)) {
+ return CurvesGeometry::wrap(curves_id.geometry).curves_range();
+ }
+ return retrieve_selected_curves(CurvesGeometry::wrap(curves_id.geometry),
+ eAttrDomain(curves_id.selection_domain),
+ r_indices);
+}
+
+} // namespace blender::ed::sculpt_paint
diff --git a/source/blender/editors/sculpt_paint/curves_sculpt_selection_paint.cc b/source/blender/editors/sculpt_paint/curves_sculpt_selection_paint.cc
new file mode 100644
index 00000000000..b40aebcaaf1
--- /dev/null
+++ b/source/blender/editors/sculpt_paint/curves_sculpt_selection_paint.cc
@@ -0,0 +1,394 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+
+#include <algorithm>
+#include <numeric>
+
+#include "BLI_memory_utils.hh"
+#include "BLI_task.hh"
+
+#include "DNA_brush_types.h"
+
+#include "BKE_brush.h"
+#include "BKE_context.h"
+#include "BKE_curves.hh"
+
+#include "DEG_depsgraph.h"
+
+#include "ED_screen.h"
+#include "ED_view3d.h"
+
+#include "WM_api.h"
+
+#include "curves_sculpt_intern.hh"
+
+/**
+ * The code below uses a suffix naming convention to indicate the coordinate space:
+ * cu: Local space of the curves object that is being edited.
+ * wo: World space.
+ * re: 2D coordinates within the region.
+ */
+
+namespace blender::ed::sculpt_paint {
+
+using bke::CurvesGeometry;
+
+class SelectionPaintOperation : public CurvesSculptStrokeOperation {
+ private:
+ bool use_select_;
+ bool clear_selection_;
+
+ CurvesBrush3D brush_3d_;
+
+ friend struct SelectionPaintOperationExecutor;
+
+ public:
+ SelectionPaintOperation(const bool use_select, const bool clear_selection)
+ : use_select_(use_select), clear_selection_(clear_selection)
+ {
+ }
+ void on_stroke_extended(const bContext &C, const StrokeExtension &stroke_extension) override;
+};
+
+struct SelectionPaintOperationExecutor {
+ SelectionPaintOperation *self_ = nullptr;
+ CurvesSculptCommonContext ctx_;
+
+ Object *object_ = nullptr;
+ Curves *curves_id_ = nullptr;
+ CurvesGeometry *curves_ = nullptr;
+
+ const Brush *brush_ = nullptr;
+ float brush_radius_base_re_;
+ float brush_radius_factor_;
+ float brush_strength_;
+
+ float selection_goal_;
+
+ float2 brush_pos_re_;
+
+ CurvesSculptTransforms transforms_;
+
+ SelectionPaintOperationExecutor(const bContext &C) : ctx_(C)
+ {
+ }
+
+ void execute(SelectionPaintOperation &self,
+ const bContext &C,
+ const StrokeExtension &stroke_extension)
+ {
+ self_ = &self;
+ object_ = CTX_data_active_object(&C);
+
+ curves_id_ = static_cast<Curves *>(object_->data);
+ curves_ = &CurvesGeometry::wrap(curves_id_->geometry);
+ curves_id_->flag |= CV_SCULPT_SELECTION_ENABLED;
+ if (curves_->curves_num() == 0) {
+ return;
+ }
+
+ brush_ = BKE_paint_brush_for_read(&ctx_.scene->toolsettings->curves_sculpt->paint);
+ brush_radius_base_re_ = BKE_brush_size_get(ctx_.scene, brush_);
+ brush_radius_factor_ = brush_radius_factor(*brush_, stroke_extension);
+ brush_strength_ = BKE_brush_alpha_get(ctx_.scene, brush_);
+
+ brush_pos_re_ = stroke_extension.mouse_position;
+
+ if (self.clear_selection_) {
+ if (stroke_extension.is_first) {
+ if (curves_id_->selection_domain == ATTR_DOMAIN_POINT) {
+ curves_->selection_point_float_for_write().fill(0.0f);
+ }
+ else if (curves_id_->selection_domain == ATTR_DOMAIN_CURVE) {
+ curves_->selection_curve_float_for_write().fill(0.0f);
+ }
+ }
+ }
+
+ transforms_ = CurvesSculptTransforms(*object_, curves_id_->surface);
+
+ const eBrushFalloffShape falloff_shape = static_cast<eBrushFalloffShape>(
+ brush_->falloff_shape);
+
+ selection_goal_ = self_->use_select_ ? 1.0f : 0.0f;
+
+ if (stroke_extension.is_first) {
+ if (falloff_shape == PAINT_FALLOFF_SHAPE_SPHERE) {
+ this->initialize_spherical_brush_reference_point();
+ }
+ }
+
+ if (curves_id_->selection_domain == ATTR_DOMAIN_POINT) {
+ MutableSpan<float> selection = curves_->selection_point_float_for_write();
+ if (falloff_shape == PAINT_FALLOFF_SHAPE_TUBE) {
+ this->paint_point_selection_projected_with_symmetry(selection);
+ }
+ else if (falloff_shape == PAINT_FALLOFF_SHAPE_SPHERE) {
+ this->paint_point_selection_spherical_with_symmetry(selection);
+ }
+ }
+ else {
+ MutableSpan<float> selection = curves_->selection_curve_float_for_write();
+ if (falloff_shape == PAINT_FALLOFF_SHAPE_TUBE) {
+ this->paint_curve_selection_projected_with_symmetry(selection);
+ }
+ else if (falloff_shape == PAINT_FALLOFF_SHAPE_SPHERE) {
+ this->paint_curve_selection_spherical_with_symmetry(selection);
+ }
+ }
+
+ /* Use #ID_RECALC_GEOMETRY instead of #ID_RECALC_SELECT because
+ * selection is handled as a generic attribute for now. */
+ DEG_id_tag_update(&curves_id_->id, ID_RECALC_GEOMETRY);
+ WM_main_add_notifier(NC_GEOM | ND_DATA, &curves_id_->id);
+ ED_region_tag_redraw(ctx_.region);
+ }
+
+ void paint_point_selection_projected_with_symmetry(MutableSpan<float> selection)
+ {
+ const Vector<float4x4> symmetry_brush_transforms = get_symmetry_brush_transforms(
+ eCurvesSymmetryType(curves_id_->symmetry));
+ for (const float4x4 &brush_transform : symmetry_brush_transforms) {
+ this->paint_point_selection_projected(brush_transform, selection);
+ }
+ }
+
+ void paint_point_selection_projected(const float4x4 &brush_transform,
+ MutableSpan<float> selection)
+ {
+ const float4x4 brush_transform_inv = brush_transform.inverted();
+
+ float4x4 projection;
+ ED_view3d_ob_project_mat_get(ctx_.rv3d, object_, projection.values);
+
+ Span<float3> positions_cu = curves_->positions();
+
+ const float brush_radius_re = brush_radius_base_re_ * brush_radius_factor_;
+ const float brush_radius_sq_re = pow2f(brush_radius_re);
+
+ threading::parallel_for(curves_->points_range(), 1024, [&](const IndexRange point_range) {
+ for (const int point_i : point_range) {
+ const float3 pos_cu = brush_transform_inv * positions_cu[point_i];
+
+ /* Find the position of the point in screen space. */
+ float2 pos_re;
+ ED_view3d_project_float_v2_m4(ctx_.region, pos_cu, pos_re, projection.values);
+
+ const float distance_to_brush_sq_re = math::distance_squared(pos_re, brush_pos_re_);
+ if (distance_to_brush_sq_re > brush_radius_sq_re) {
+ /* Ignore the point because it's too far away. */
+ continue;
+ }
+
+ const float distance_to_brush_re = std::sqrt(distance_to_brush_sq_re);
+ /* A falloff that is based on how far away the point is from the stroke. */
+ const float radius_falloff = BKE_brush_curve_strength(
+ brush_, distance_to_brush_re, brush_radius_re);
+ /* Combine the falloff and brush strength. */
+ const float weight = brush_strength_ * radius_falloff;
+
+ selection[point_i] = math::interpolate(selection[point_i], selection_goal_, weight);
+ }
+ });
+ }
+
+ void paint_point_selection_spherical_with_symmetry(MutableSpan<float> selection)
+ {
+ float4x4 projection;
+ ED_view3d_ob_project_mat_get(ctx_.rv3d, object_, projection.values);
+
+ float3 brush_wo;
+ ED_view3d_win_to_3d(ctx_.v3d,
+ ctx_.region,
+ transforms_.curves_to_world * self_->brush_3d_.position_cu,
+ brush_pos_re_,
+ brush_wo);
+ const float3 brush_cu = transforms_.world_to_curves * brush_wo;
+
+ const Vector<float4x4> symmetry_brush_transforms = get_symmetry_brush_transforms(
+ eCurvesSymmetryType(curves_id_->symmetry));
+
+ for (const float4x4 &brush_transform : symmetry_brush_transforms) {
+ this->paint_point_selection_spherical(selection, brush_transform * brush_cu);
+ }
+ }
+
+ void paint_point_selection_spherical(MutableSpan<float> selection, const float3 &brush_cu)
+ {
+ Span<float3> positions_cu = curves_->positions();
+
+ const float brush_radius_cu = self_->brush_3d_.radius_cu;
+ const float brush_radius_sq_cu = pow2f(brush_radius_cu);
+
+ threading::parallel_for(curves_->points_range(), 1024, [&](const IndexRange point_range) {
+ for (const int i : point_range) {
+ const float3 pos_old_cu = positions_cu[i];
+
+ /* Compute distance to the brush. */
+ const float distance_to_brush_sq_cu = math::distance_squared(pos_old_cu, brush_cu);
+ if (distance_to_brush_sq_cu > brush_radius_sq_cu) {
+ /* Ignore the point because it's too far away. */
+ continue;
+ }
+
+ const float distance_to_brush_cu = std::sqrt(distance_to_brush_sq_cu);
+
+ /* A falloff that is based on how far away the point is from the stroke. */
+ const float radius_falloff = BKE_brush_curve_strength(
+ brush_, distance_to_brush_cu, brush_radius_cu);
+ /* Combine the falloff and brush strength. */
+ const float weight = brush_strength_ * radius_falloff;
+
+ selection[i] = math::interpolate(selection[i], selection_goal_, weight);
+ }
+ });
+ }
+
+ void paint_curve_selection_projected_with_symmetry(MutableSpan<float> selection)
+ {
+ const Vector<float4x4> symmetry_brush_transforms = get_symmetry_brush_transforms(
+ eCurvesSymmetryType(curves_id_->symmetry));
+ for (const float4x4 &brush_transform : symmetry_brush_transforms) {
+ this->paint_curve_selection_projected(brush_transform, selection);
+ }
+ }
+
+ void paint_curve_selection_projected(const float4x4 &brush_transform,
+ MutableSpan<float> selection)
+ {
+ const Span<float3> positions_cu = curves_->positions();
+ const float4x4 brush_transform_inv = brush_transform.inverted();
+
+ float4x4 projection;
+ ED_view3d_ob_project_mat_get(ctx_.rv3d, object_, projection.values);
+
+ const float brush_radius_re = brush_radius_base_re_ * brush_radius_factor_;
+ const float brush_radius_sq_re = pow2f(brush_radius_re);
+
+ threading::parallel_for(curves_->curves_range(), 1024, [&](const IndexRange curves_range) {
+ for (const int curve_i : curves_range) {
+ const float max_weight = threading::parallel_reduce(
+ curves_->points_for_curve(curve_i).drop_back(1),
+ 1024,
+ 0.0f,
+ [&](const IndexRange segment_range, const float init) {
+ float max_weight = init;
+ for (const int segment_i : segment_range) {
+ const float3 pos1_cu = brush_transform_inv * positions_cu[segment_i];
+ const float3 pos2_cu = brush_transform_inv * positions_cu[segment_i + 1];
+
+ float2 pos1_re;
+ float2 pos2_re;
+ ED_view3d_project_float_v2_m4(ctx_.region, pos1_cu, pos1_re, projection.values);
+ ED_view3d_project_float_v2_m4(ctx_.region, pos2_cu, pos2_re, projection.values);
+
+ const float distance_sq_re = dist_squared_to_line_segment_v2(
+ brush_pos_re_, pos1_re, pos2_re);
+ if (distance_sq_re > brush_radius_sq_re) {
+ continue;
+ }
+ const float radius_falloff = BKE_brush_curve_strength(
+ brush_, std::sqrt(distance_sq_re), brush_radius_re);
+ const float weight = brush_strength_ * radius_falloff;
+ max_weight = std::max(max_weight, weight);
+ }
+ return max_weight;
+ },
+ [](float a, float b) { return std::max(a, b); });
+ selection[curve_i] = math::interpolate(selection[curve_i], selection_goal_, max_weight);
+ }
+ });
+ }
+
+ void paint_curve_selection_spherical_with_symmetry(MutableSpan<float> selection)
+ {
+ float4x4 projection;
+ ED_view3d_ob_project_mat_get(ctx_.rv3d, object_, projection.values);
+
+ float3 brush_wo;
+ ED_view3d_win_to_3d(ctx_.v3d,
+ ctx_.region,
+ transforms_.curves_to_world * self_->brush_3d_.position_cu,
+ brush_pos_re_,
+ brush_wo);
+ const float3 brush_cu = transforms_.world_to_curves * brush_wo;
+
+ const Vector<float4x4> symmetry_brush_transforms = get_symmetry_brush_transforms(
+ eCurvesSymmetryType(curves_id_->symmetry));
+
+ for (const float4x4 &brush_transform : symmetry_brush_transforms) {
+ this->paint_curve_selection_spherical(selection, brush_transform * brush_cu);
+ }
+ }
+
+ void paint_curve_selection_spherical(MutableSpan<float> selection, const float3 &brush_cu)
+ {
+ const Span<float3> positions_cu = curves_->positions();
+
+ const float brush_radius_cu = self_->brush_3d_.radius_cu;
+ const float brush_radius_sq_cu = pow2f(brush_radius_cu);
+
+ threading::parallel_for(curves_->curves_range(), 1024, [&](const IndexRange curves_range) {
+ for (const int curve_i : curves_range) {
+ const float max_weight = threading::parallel_reduce(
+ curves_->points_for_curve(curve_i).drop_back(1),
+ 1024,
+ 0.0f,
+ [&](const IndexRange segment_range, const float init) {
+ float max_weight = init;
+ for (const int segment_i : segment_range) {
+ const float3 &pos1_cu = positions_cu[segment_i];
+ const float3 &pos2_cu = positions_cu[segment_i + 1];
+
+ const float distance_sq_cu = dist_squared_to_line_segment_v3(
+ brush_cu, pos1_cu, pos2_cu);
+ if (distance_sq_cu > brush_radius_sq_cu) {
+ continue;
+ }
+ const float radius_falloff = BKE_brush_curve_strength(
+ brush_, std::sqrt(distance_sq_cu), brush_radius_cu);
+ const float weight = brush_strength_ * radius_falloff;
+ max_weight = std::max(max_weight, weight);
+ }
+ return max_weight;
+ },
+ [](float a, float b) { return std::max(a, b); });
+ selection[curve_i] = math::interpolate(selection[curve_i], selection_goal_, max_weight);
+ }
+ });
+ }
+
+ void initialize_spherical_brush_reference_point()
+ {
+ std::optional<CurvesBrush3D> brush_3d = sample_curves_3d_brush(*ctx_.depsgraph,
+ *ctx_.region,
+ *ctx_.v3d,
+ *ctx_.rv3d,
+ *object_,
+ brush_pos_re_,
+ brush_radius_base_re_);
+ if (brush_3d.has_value()) {
+ self_->brush_3d_ = *brush_3d;
+ }
+ }
+};
+
+void SelectionPaintOperation::on_stroke_extended(const bContext &C,
+ const StrokeExtension &stroke_extension)
+{
+ SelectionPaintOperationExecutor executor{C};
+ executor.execute(*this, C, stroke_extension);
+}
+
+std::unique_ptr<CurvesSculptStrokeOperation> new_selection_paint_operation(
+ const BrushStrokeMode brush_mode, const bContext &C)
+{
+ Scene &scene = *CTX_data_scene(&C);
+ Brush &brush = *BKE_paint_brush(&scene.toolsettings->curves_sculpt->paint);
+ const bool use_select = ELEM(brush_mode, BRUSH_STROKE_INVERT) ==
+ ((brush.flag & BRUSH_DIR_IN) != 0);
+ const bool clear_selection = use_select && brush_mode != BRUSH_STROKE_SMOOTH;
+
+ return std::make_unique<SelectionPaintOperation>(use_select, clear_selection);
+}
+
+} // namespace blender::ed::sculpt_paint
diff --git a/source/blender/editors/sculpt_paint/curves_sculpt_snake_hook.cc b/source/blender/editors/sculpt_paint/curves_sculpt_snake_hook.cc
index d2814c17682..b63e5a7756b 100644
--- a/source/blender/editors/sculpt_paint/curves_sculpt_snake_hook.cc
+++ b/source/blender/editors/sculpt_paint/curves_sculpt_snake_hook.cc
@@ -23,7 +23,6 @@
#include "BKE_mesh.h"
#include "BKE_mesh_runtime.h"
#include "BKE_paint.h"
-#include "BKE_spline.hh"
#include "DNA_brush_enums.h"
#include "DNA_brush_types.h"
@@ -37,6 +36,8 @@
#include "ED_screen.h"
#include "ED_view3d.h"
+#include "WM_api.h"
+
/**
* The code below uses a prefix naming convention to indicate the coordinate space:
* - `cu`: Local space of the curves object that is being edited.
@@ -61,7 +62,7 @@ class SnakeHookOperation : public CurvesSculptStrokeOperation {
friend struct SnakeHookOperatorExecutor;
public:
- void on_stroke_extended(bContext *C, const StrokeExtension &stroke_extension) override;
+ void on_stroke_extended(const bContext &C, const StrokeExtension &stroke_extension) override;
};
/**
@@ -70,49 +71,51 @@ class SnakeHookOperation : public CurvesSculptStrokeOperation {
*/
struct SnakeHookOperatorExecutor {
SnakeHookOperation *self_ = nullptr;
- bContext *C_ = nullptr;
- Scene *scene_ = nullptr;
- Object *object_ = nullptr;
- ARegion *region_ = nullptr;
- View3D *v3d_ = nullptr;
- RegionView3D *rv3d_ = nullptr;
+ CurvesSculptCommonContext ctx_;
- CurvesSculpt *curves_sculpt_ = nullptr;
- Brush *brush_ = nullptr;
- float brush_radius_re_;
+ const CurvesSculpt *curves_sculpt_ = nullptr;
+ const Brush *brush_ = nullptr;
+ float brush_radius_base_re_;
+ float brush_radius_factor_;
float brush_strength_;
+
eBrushFalloffShape falloff_shape_;
+ Object *object_ = nullptr;
Curves *curves_id_ = nullptr;
CurvesGeometry *curves_ = nullptr;
- float4x4 curves_to_world_mat_;
- float4x4 world_to_curves_mat_;
+ VArray<float> curve_factors_;
+ Vector<int64_t> selected_curve_indices_;
+ IndexMask curve_selection_;
+
+ CurvesSculptTransforms transforms_;
float2 brush_pos_prev_re_;
float2 brush_pos_re_;
float2 brush_pos_diff_re_;
- void execute(SnakeHookOperation &self, bContext *C, const StrokeExtension &stroke_extension)
+ SnakeHookOperatorExecutor(const bContext &C) : ctx_(C)
+ {
+ }
+
+ void execute(SnakeHookOperation &self,
+ const bContext &C,
+ const StrokeExtension &stroke_extension)
{
BLI_SCOPED_DEFER([&]() { self.last_mouse_position_re_ = stroke_extension.mouse_position; });
self_ = &self;
- C_ = C;
- scene_ = CTX_data_scene(C);
- object_ = CTX_data_active_object(C);
- region_ = CTX_wm_region(C);
- v3d_ = CTX_wm_view3d(C);
- rv3d_ = CTX_wm_region_view3d(C);
-
- curves_sculpt_ = scene_->toolsettings->curves_sculpt;
- brush_ = BKE_paint_brush(&curves_sculpt_->paint);
- brush_radius_re_ = BKE_brush_size_get(scene_, brush_);
- brush_strength_ = BKE_brush_alpha_get(scene_, brush_);
- falloff_shape_ = static_cast<eBrushFalloffShape>(brush_->falloff_shape);
+ object_ = CTX_data_active_object(&C);
+
+ curves_sculpt_ = ctx_.scene->toolsettings->curves_sculpt;
+ brush_ = BKE_paint_brush_for_read(&curves_sculpt_->paint);
+
+ brush_radius_base_re_ = BKE_brush_size_get(ctx_.scene, brush_);
+ brush_radius_factor_ = brush_radius_factor(*brush_, stroke_extension);
+ brush_strength_ = brush_strength_get(*ctx_.scene, *brush_, stroke_extension);
- curves_to_world_mat_ = object_->obmat;
- world_to_curves_mat_ = curves_to_world_mat_.inverted();
+ falloff_shape_ = static_cast<eBrushFalloffShape>(brush_->falloff_shape);
curves_id_ = static_cast<Curves *>(object_->data);
curves_ = &CurvesGeometry::wrap(curves_id_->geometry);
@@ -120,14 +123,24 @@ struct SnakeHookOperatorExecutor {
return;
}
+ transforms_ = CurvesSculptTransforms(*object_, curves_id_->surface);
+
+ curve_factors_ = get_curves_selection(*curves_id_);
+ curve_selection_ = retrieve_selected_curves(*curves_id_, selected_curve_indices_);
+
brush_pos_prev_re_ = self.last_mouse_position_re_;
brush_pos_re_ = stroke_extension.mouse_position;
brush_pos_diff_re_ = brush_pos_re_ - brush_pos_prev_re_;
if (stroke_extension.is_first) {
if (falloff_shape_ == PAINT_FALLOFF_SHAPE_SPHERE) {
- std::optional<CurvesBrush3D> brush_3d = sample_curves_3d_brush(
- *C_, *object_, brush_pos_re_, brush_radius_re_);
+ std::optional<CurvesBrush3D> brush_3d = sample_curves_3d_brush(*ctx_.depsgraph,
+ *ctx_.region,
+ *ctx_.v3d,
+ *ctx_.rv3d,
+ *object_,
+ brush_pos_re_,
+ brush_radius_base_re_);
if (brush_3d.has_value()) {
self_->brush_3d_ = *brush_3d;
}
@@ -147,7 +160,8 @@ struct SnakeHookOperatorExecutor {
curves_->tag_positions_changed();
DEG_id_tag_update(&curves_id_->id, ID_RECALC_GEOMETRY);
- ED_region_tag_redraw(region_);
+ WM_main_add_notifier(NC_GEOM | ND_DATA, &curves_id_->id);
+ ED_region_tag_redraw(ctx_.region);
}
void projected_snake_hook_with_symmetry()
@@ -166,7 +180,10 @@ struct SnakeHookOperatorExecutor {
MutableSpan<float3> positions_cu = curves_->positions_for_write();
float4x4 projection;
- ED_view3d_ob_project_mat_get(rv3d_, object_, projection.values);
+ ED_view3d_ob_project_mat_get(ctx_.rv3d, object_, projection.values);
+
+ const float brush_radius_re = brush_radius_base_re_ * brush_radius_factor_;
+ const float brush_radius_sq_re = pow2f(brush_radius_re);
threading::parallel_for(curves_->curves_range(), 256, [&](const IndexRange curves_range) {
for (const int curve_i : curves_range) {
@@ -175,24 +192,29 @@ struct SnakeHookOperatorExecutor {
const float3 old_pos_cu = brush_transform_inv * positions_cu[last_point_i];
float2 old_pos_re;
- ED_view3d_project_float_v2_m4(region_, old_pos_cu, old_pos_re, projection.values);
+ ED_view3d_project_float_v2_m4(ctx_.region, old_pos_cu, old_pos_re, projection.values);
- const float distance_to_brush_re = math::distance(old_pos_re, brush_pos_prev_re_);
- if (distance_to_brush_re > brush_radius_re_) {
+ const float distance_to_brush_sq_re = math::distance_squared(old_pos_re,
+ brush_pos_prev_re_);
+ if (distance_to_brush_sq_re > brush_radius_sq_re) {
continue;
}
const float radius_falloff = BKE_brush_curve_strength(
- brush_, distance_to_brush_re, brush_radius_re_);
- const float weight = brush_strength_ * radius_falloff;
+ brush_, std::sqrt(distance_to_brush_sq_re), brush_radius_re);
+ const float weight = brush_strength_ * radius_falloff * curve_factors_[curve_i];
const float2 new_position_re = old_pos_re + brush_pos_diff_re_ * weight;
float3 new_position_wo;
- ED_view3d_win_to_3d(
- v3d_, region_, curves_to_world_mat_ * old_pos_cu, new_position_re, new_position_wo);
- const float3 new_position_cu = brush_transform * (world_to_curves_mat_ * new_position_wo);
-
- this->move_last_point_and_resample(positions_cu.slice(points), new_position_cu);
+ ED_view3d_win_to_3d(ctx_.v3d,
+ ctx_.region,
+ transforms_.curves_to_world * old_pos_cu,
+ new_position_re,
+ new_position_wo);
+ const float3 new_position_cu = brush_transform *
+ (transforms_.world_to_curves * new_position_wo);
+
+ move_last_point_and_resample(positions_cu.slice(points), new_position_cu);
}
});
}
@@ -200,23 +222,23 @@ struct SnakeHookOperatorExecutor {
void spherical_snake_hook_with_symmetry()
{
float4x4 projection;
- ED_view3d_ob_project_mat_get(rv3d_, object_, projection.values);
+ ED_view3d_ob_project_mat_get(ctx_.rv3d, object_, projection.values);
float3 brush_start_wo, brush_end_wo;
- ED_view3d_win_to_3d(v3d_,
- region_,
- curves_to_world_mat_ * self_->brush_3d_.position_cu,
+ ED_view3d_win_to_3d(ctx_.v3d,
+ ctx_.region,
+ transforms_.curves_to_world * self_->brush_3d_.position_cu,
brush_pos_prev_re_,
brush_start_wo);
- ED_view3d_win_to_3d(v3d_,
- region_,
- curves_to_world_mat_ * self_->brush_3d_.position_cu,
+ ED_view3d_win_to_3d(ctx_.v3d,
+ ctx_.region,
+ transforms_.curves_to_world * self_->brush_3d_.position_cu,
brush_pos_re_,
brush_end_wo);
- const float3 brush_start_cu = world_to_curves_mat_ * brush_start_wo;
- const float3 brush_end_cu = world_to_curves_mat_ * brush_end_wo;
+ const float3 brush_start_cu = transforms_.world_to_curves * brush_start_wo;
+ const float3 brush_end_cu = transforms_.world_to_curves * brush_end_wo;
- const float brush_radius_cu = self_->brush_3d_.radius_cu;
+ const float brush_radius_cu = self_->brush_3d_.radius_cu * brush_radius_factor_;
const Vector<float4x4> symmetry_brush_transforms = get_symmetry_brush_transforms(
eCurvesSymmetryType(curves_id_->symmetry));
@@ -250,51 +272,20 @@ struct SnakeHookOperatorExecutor {
const float radius_falloff = BKE_brush_curve_strength(
brush_, distance_to_brush_cu, brush_radius_cu);
- const float weight = brush_strength_ * radius_falloff;
+ const float weight = brush_strength_ * radius_falloff * curve_factors_[curve_i];
const float3 new_pos_cu = old_pos_cu + weight * brush_diff_cu;
- this->move_last_point_and_resample(positions_cu.slice(points), new_pos_cu);
+ move_last_point_and_resample(positions_cu.slice(points), new_pos_cu);
}
});
}
-
- void move_last_point_and_resample(MutableSpan<float3> positions,
- const float3 &new_last_position) const
- {
- /* Find the accumulated length of each point in the original curve,
- * treating it as a poly curve for performance reasons and simplicity. */
- Array<float> orig_lengths(length_parameterize::lengths_num(positions.size(), false));
- length_parameterize::accumulate_lengths<float3>(positions, false, orig_lengths);
- const float orig_total_length = orig_lengths.last();
-
- /* Find the factor by which the new curve is shorter or longer than the original. */
- const float new_last_segment_length = math::distance(positions.last(1), new_last_position);
- const float new_total_length = orig_lengths.last(1) + new_last_segment_length;
- const float length_factor = new_total_length / orig_total_length;
-
- /* Calculate the lengths to sample the original curve with by scaling the original lengths. */
- Array<float> new_lengths(positions.size() - 1);
- new_lengths.first() = 0.0f;
- for (const int i : new_lengths.index_range().drop_front(1)) {
- new_lengths[i] = orig_lengths[i - 1] * length_factor;
- }
-
- Array<int> indices(positions.size() - 1);
- Array<float> factors(positions.size() - 1);
- length_parameterize::create_samples_from_sorted_lengths(
- orig_lengths, new_lengths, false, indices, factors);
-
- Array<float3> new_positions(positions.size() - 1);
- length_parameterize::linear_interpolation<float3>(positions, indices, factors, new_positions);
- positions.drop_back(1).copy_from(new_positions);
- positions.last() = new_last_position;
- }
};
-void SnakeHookOperation::on_stroke_extended(bContext *C, const StrokeExtension &stroke_extension)
+void SnakeHookOperation::on_stroke_extended(const bContext &C,
+ const StrokeExtension &stroke_extension)
{
- SnakeHookOperatorExecutor executor;
+ SnakeHookOperatorExecutor executor{C};
executor.execute(*this, C, stroke_extension);
}
diff --git a/source/blender/editors/sculpt_paint/paint_cursor.c b/source/blender/editors/sculpt_paint/paint_cursor.c
index 861da185975..c5ebcf870a3 100644
--- a/source/blender/editors/sculpt_paint/paint_cursor.c
+++ b/source/blender/editors/sculpt_paint/paint_cursor.c
@@ -38,6 +38,7 @@
#include "IMB_imbuf_types.h"
+#include "ED_image.h"
#include "ED_view3d.h"
#include "DEG_depsgraph.h"
@@ -1358,7 +1359,7 @@ static void paint_cursor_sculpt_session_update_and_init(PaintCursorContext *pcon
ViewContext *vc = &pcontext->vc;
SculptCursorGeometryInfo gi;
- const float mouse[2] = {
+ const float mval_fl[2] = {
pcontext->x - pcontext->region->winrct.xmin,
pcontext->y - pcontext->region->winrct.ymin,
};
@@ -1368,7 +1369,7 @@ static void paint_cursor_sculpt_session_update_and_init(PaintCursorContext *pcon
pcontext->prev_active_vertex_index = ss->active_vertex_index;
if (!ups->stroke_active) {
pcontext->is_cursor_over_mesh = SCULPT_cursor_geometry_info_update(
- C, &gi, mouse, (pcontext->brush->falloff_shape == PAINT_FALLOFF_SHAPE_SPHERE));
+ C, &gi, mval_fl, (pcontext->brush->falloff_shape == PAINT_FALLOFF_SHAPE_SPHERE));
copy_v3_v3(pcontext->location, gi.location);
copy_v3_v3(pcontext->normal, gi.normal);
}
@@ -1932,7 +1933,7 @@ static void paint_draw_cursor(bContext *C, int x, int y, void *UNUSED(unused))
/* Public API */
-void paint_cursor_start(Paint *p, bool (*poll)(bContext *C))
+void ED_paint_cursor_start(Paint *p, bool (*poll)(bContext *C))
{
if (p && !p->paint_cursor) {
p->paint_cursor = WM_paint_cursor_activate(
diff --git a/source/blender/editors/sculpt_paint/paint_image.cc b/source/blender/editors/sculpt_paint/paint_image.cc
index 572e5b78b74..56cd4751881 100644
--- a/source/blender/editors/sculpt_paint/paint_image.cc
+++ b/source/blender/editors/sculpt_paint/paint_image.cc
@@ -287,7 +287,7 @@ static bool image_paint_poll_ex(bContext *C, bool check_tool)
return false;
}
-bool image_paint_poll(bContext *C)
+bool ED_image_tools_paint_poll(bContext *C)
{
return image_paint_poll_ex(C, true);
}
@@ -301,7 +301,7 @@ static bool image_paint_2d_clone_poll(bContext *C)
{
Brush *brush = image_paint_brush(C);
- if (!CTX_wm_region_view3d(C) && image_paint_poll(C)) {
+ if (!CTX_wm_region_view3d(C) && ED_image_tools_paint_poll(C)) {
if (brush && (brush->imagepaint_tool == PAINT_TOOL_CLONE)) {
if (brush->clone.image) {
return true;
@@ -359,9 +359,7 @@ void paint_brush_color_get(struct Scene *scene,
}
/* Gradient / Color-band colors are not considered #PROP_COLOR_GAMMA.
* Brush colors are expected to be in sRGB though. */
- IMB_colormanagement_scene_linear_to_srgb_v3(color_gr);
-
- copy_v3_v3(color, color_gr);
+ IMB_colormanagement_scene_linear_to_srgb_v3(color, color_gr);
}
else {
copy_v3_v3(color, BKE_brush_color_get(scene, br));
@@ -432,7 +430,7 @@ static void toggle_paint_cursor(Scene *scene, bool enable)
paint_cursor_delete_textures();
}
else if (enable) {
- paint_cursor_start(p, image_paint_poll);
+ ED_paint_cursor_start(p, ED_image_tools_paint_poll);
}
}
@@ -457,7 +455,7 @@ void ED_space_image_paint_update(Main *bmain, wmWindowManager *wm, Scene *scene)
if (enabled) {
BKE_paint_init(bmain, scene, PAINT_MODE_TEXTURE_2D, PAINT_CURSOR_TEXTURE_PAINT);
- paint_cursor_start(&imapaint->paint, image_paint_poll);
+ ED_paint_cursor_start(&imapaint->paint, ED_image_tools_paint_poll);
}
else {
paint_cursor_delete_textures();
@@ -738,7 +736,7 @@ void PAINT_OT_sample_color(wmOperatorType *ot)
ot->poll = sample_color_poll;
/* flags */
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+ ot->flag = OPTYPE_REGISTER;
/* properties */
PropertyRNA *prop;
@@ -927,7 +925,7 @@ static int brush_colors_flip_exec(bContext *C, wmOperator *UNUSED(op))
static bool brush_colors_flip_poll(bContext *C)
{
- if (image_paint_poll(C)) {
+ if (ED_image_tools_paint_poll(C)) {
Brush *br = image_paint_brush(C);
if (ELEM(br->imagepaint_tool, PAINT_TOOL_DRAW, PAINT_TOOL_FILL)) {
return true;
@@ -956,7 +954,7 @@ void PAINT_OT_brush_colors_flip(wmOperatorType *ot)
ot->poll = brush_colors_flip_poll;
/* flags */
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+ ot->flag = OPTYPE_REGISTER;
}
void ED_imapaint_bucket_fill(struct bContext *C,
@@ -993,7 +991,7 @@ static bool texture_paint_poll(bContext *C)
bool image_texture_paint_poll(bContext *C)
{
- return (texture_paint_poll(C) || image_paint_poll(C));
+ return (texture_paint_poll(C) || ED_image_tools_paint_poll(C));
}
bool facemask_paint_poll(bContext *C)
diff --git a/source/blender/editors/sculpt_paint/paint_image_2d.c b/source/blender/editors/sculpt_paint/paint_image_2d.c
index d30aa4dfab1..fae2e6863fa 100644
--- a/source/blender/editors/sculpt_paint/paint_image_2d.c
+++ b/source/blender/editors/sculpt_paint/paint_image_2d.c
@@ -621,39 +621,38 @@ static void brush_painter_imbuf_partial_update(BrushPainter *painter,
}
static void brush_painter_2d_tex_mapping(ImagePaintState *s,
- ImBuf *canvas,
+ ImagePaintTile *tile,
const int diameter,
- const float startpos[2],
const float pos[2],
const float mouse[2],
int mapmode,
rctf *mapping)
{
- float invw = 1.0f / (float)canvas->x;
- float invh = 1.0f / (float)canvas->y;
- int xmin, ymin, xmax, ymax;
- int ipos[2];
+ float invw = 1.0f / (float)tile->canvas->x;
+ float invh = 1.0f / (float)tile->canvas->y;
+ float start[2];
/* find start coordinate of brush in canvas */
- ipos[0] = (int)floorf((pos[0] - diameter / 2) + 1.0f);
- ipos[1] = (int)floorf((pos[1] - diameter / 2) + 1.0f);
+ start[0] = pos[0] - diameter / 2.0f;
+ start[1] = pos[1] - diameter / 2.0f;
if (mapmode == MTEX_MAP_MODE_STENCIL) {
/* map from view coordinates of brush to region coordinates */
- UI_view2d_view_to_region(s->v2d, ipos[0] * invw, ipos[1] * invh, &xmin, &ymin);
- UI_view2d_view_to_region(
- s->v2d, (ipos[0] + diameter) * invw, (ipos[1] + diameter) * invh, &xmax, &ymax);
+ float xmin, ymin, xmax, ymax;
+ UI_view2d_view_to_region_fl(s->v2d, start[0] * invw, start[1] * invh, &xmin, &ymin);
+ UI_view2d_view_to_region_fl(
+ s->v2d, (start[0] + diameter) * invw, (start[1] + diameter) * invh, &xmax, &ymax);
/* output mapping from brush ibuf x/y to region coordinates */
- mapping->xmin = xmin;
- mapping->ymin = ymin;
mapping->xmax = (xmax - xmin) / (float)diameter;
mapping->ymax = (ymax - ymin) / (float)diameter;
+ mapping->xmin = xmin + (tile->uv_origin[0] * tile->size[0] * mapping->xmax);
+ mapping->ymin = ymin + (tile->uv_origin[1] * tile->size[1] * mapping->ymax);
}
else if (mapmode == MTEX_MAP_MODE_3D) {
/* 3D mapping, just mapping to canvas 0..1. */
- mapping->xmin = 2.0f * (ipos[0] * invw - 0.5f);
- mapping->ymin = 2.0f * (ipos[1] * invh - 0.5f);
+ mapping->xmin = 2.0f * (start[0] * invw - 0.5f);
+ mapping->ymin = 2.0f * (start[1] * invh - 0.5f);
mapping->xmax = 2.0f * invw;
mapping->ymax = 2.0f * invh;
}
@@ -665,8 +664,10 @@ static void brush_painter_2d_tex_mapping(ImagePaintState *s,
mapping->ymax = 1.0f;
}
else /* if (mapmode == MTEX_MAP_MODE_TILED) */ {
- mapping->xmin = (int)(-diameter * 0.5) + (int)floorf(pos[0]) - (int)floorf(startpos[0]);
- mapping->ymin = (int)(-diameter * 0.5) + (int)floorf(pos[1]) - (int)floorf(startpos[1]);
+ mapping->xmin = (int)(-diameter * 0.5) + (int)floorf(pos[0]) -
+ (int)floorf(tile->start_paintpos[0]);
+ mapping->ymin = (int)(-diameter * 0.5) + (int)floorf(pos[1]) -
+ (int)floorf(tile->start_paintpos[1]);
mapping->xmax = 1.0f;
mapping->ymax = 1.0f;
}
@@ -711,14 +712,8 @@ static void brush_painter_2d_refresh_cache(ImagePaintState *s,
do_partial_update = true;
}
- brush_painter_2d_tex_mapping(s,
- tile->canvas,
- diameter,
- tile->start_paintpos,
- pos,
- mouse,
- brush->mtex.brush_map_mode,
- &painter->tex_mapping);
+ brush_painter_2d_tex_mapping(
+ s, tile, diameter, pos, mouse, brush->mtex.brush_map_mode, &painter->tex_mapping);
}
if (cache->is_maskbrush) {
@@ -745,14 +740,8 @@ static void brush_painter_2d_refresh_cache(ImagePaintState *s,
renew_maxmask) {
MEM_SAFE_FREE(cache->tex_mask);
- brush_painter_2d_tex_mapping(s,
- tile->canvas,
- diameter,
- tile->start_paintpos,
- pos,
- mouse,
- brush->mask_mtex.brush_map_mode,
- &painter->mask_mapping);
+ brush_painter_2d_tex_mapping(
+ s, tile, diameter, pos, mouse, brush->mask_mtex.brush_map_mode, &painter->mask_mapping);
if (do_partial_update_mask) {
brush_painter_mask_imbuf_partial_update(painter, tile, pos, diameter);
diff --git a/source/blender/editors/sculpt_paint/paint_image_ops_paint.cc b/source/blender/editors/sculpt_paint/paint_image_ops_paint.cc
index 8ddf1614e41..a671c24c514 100644
--- a/source/blender/editors/sculpt_paint/paint_image_ops_paint.cc
+++ b/source/blender/editors/sculpt_paint/paint_image_ops_paint.cc
@@ -34,6 +34,8 @@
#include "WM_toolsystem.h"
#include "WM_types.h"
+#include "ED_image.h"
+
#include "paint_intern.h"
namespace blender::ed::sculpt_paint::image::ops::paint {
@@ -316,7 +318,7 @@ static PaintOperation *texture_paint_init(bContext *C, wmOperator *op, const flo
if ((brush->imagepaint_tool == PAINT_TOOL_FILL) && (brush->flag & BRUSH_USE_GRADIENT)) {
pop->cursor = WM_paint_cursor_activate(
- SPACE_TYPE_ANY, RGN_TYPE_ANY, image_paint_poll, gradient_draw_line, pop);
+ SPACE_TYPE_ANY, RGN_TYPE_ANY, ED_image_tools_paint_poll, gradient_draw_line, pop);
}
settings->imapaint.flag |= IMAGEPAINT_DRAWING;
@@ -520,7 +522,7 @@ void PAINT_OT_image_paint(wmOperatorType *ot)
ot->invoke = paint_invoke;
ot->modal = paint_modal;
ot->exec = paint_exec;
- ot->poll = image_paint_poll;
+ ot->poll = ED_image_tools_paint_poll;
ot->cancel = paint_cancel;
/* flags */
diff --git a/source/blender/editors/sculpt_paint/paint_image_proj.c b/source/blender/editors/sculpt_paint/paint_image_proj.c
index 1303da71435..50480b8aef0 100644
--- a/source/blender/editors/sculpt_paint/paint_image_proj.c
+++ b/source/blender/editors/sculpt_paint/paint_image_proj.c
@@ -7,6 +7,7 @@
*/
#include <float.h>
+#include <limits.h>
#include <math.h>
#include <stdio.h>
#include <string.h>
@@ -35,12 +36,17 @@
#include "IMB_imbuf_types.h"
#include "DNA_brush_types.h"
+#include "DNA_customdata_types.h"
+#include "DNA_defs.h"
#include "DNA_material_types.h"
#include "DNA_mesh_types.h"
#include "DNA_meshdata_types.h"
#include "DNA_node_types.h"
+#include "DNA_object_enums.h"
#include "DNA_object_types.h"
+#include "DNA_scene_types.h"
+#include "BKE_attribute.h"
#include "BKE_brush.h"
#include "BKE_camera.h"
#include "BKE_colorband.h"
@@ -61,6 +67,8 @@
#include "BKE_report.h"
#include "BKE_scene.h"
#include "BKE_screen.h"
+#include "DNA_screen_types.h"
+#include "DNA_space_types.h"
#include "DEG_depsgraph.h"
#include "DEG_depsgraph_query.h"
@@ -76,12 +84,18 @@
#include "GPU_capabilities.h"
#include "GPU_init_exit.h"
+#include "NOD_shader.h"
+
+#include "UI_interface.h"
+#include "UI_resources.h"
+
#include "WM_api.h"
#include "WM_types.h"
#include "RNA_access.h"
#include "RNA_define.h"
#include "RNA_enum_types.h"
+#include "RNA_types.h"
#include "IMB_colormanagement.h"
@@ -3118,7 +3132,7 @@ static void project_paint_face_init(const ProjPaintState *ps,
}
}
- /* Is this UV visible from the view? - raytrace */
+ /* Is this UV visible from the view? - ray-trace */
/* project_paint_PickFace is less complex, use for testing */
// if (project_paint_PickFace(ps, pixelScreenCo, w, &side) == tri_index) {
if ((ps->do_occlude == false) ||
@@ -3208,7 +3222,7 @@ static void project_paint_face_init(const ProjPaintState *ps,
float seam_subsection[4][2];
float fac1, fac2;
- /* Pixelspace UVs. */
+ /* Pixel-space UV's. */
float lt_puv[3][2];
lt_puv[0][0] = lt_uv_pxoffset[0][0] * ibuf->x;
@@ -4068,7 +4082,7 @@ typedef struct {
static void proj_paint_layer_clone_init(ProjPaintState *ps, ProjPaintLayerClone *layer_clone)
{
- MLoopUV *mloopuv_clone_base = NULL;
+ const MLoopUV *mloopuv_clone_base = NULL;
/* use clone mtface? */
if (ps->do_layer_clone) {
@@ -4478,7 +4492,8 @@ static void project_paint_begin(const bContext *C,
}
}
- /* when using subsurf or multires, mface arrays are thrown away, we need to keep a copy */
+ /* when using sub-surface or multi-resolution,
+ * mesh-data arrays are thrown away, we need to keep a copy. */
if (ps->is_shared_user == false) {
proj_paint_state_cavity_init(ps);
}
@@ -6422,6 +6437,17 @@ static const EnumPropertyItem layer_type_items[] = {
{0, NULL, 0, NULL, NULL},
};
+static Material *get_or_create_current_material(bContext *C, Object *ob)
+{
+ Material *ma = BKE_object_material_get(ob, ob->actcol);
+ if (!ma) {
+ Main *bmain = CTX_data_main(C);
+ ma = BKE_material_add(bmain, "Material");
+ BKE_object_material_assign(bmain, ob, ma, ob->actcol, BKE_MAT_ASSIGN_USERPREF);
+ }
+ return ma;
+}
+
static Image *proj_paint_image_create(wmOperator *op, Main *bmain, bool is_data)
{
Image *ima;
@@ -6459,55 +6485,97 @@ static Image *proj_paint_image_create(wmOperator *op, Main *bmain, bool is_data)
return ima;
}
-static void proj_paint_default_color(wmOperator *op, int type, Material *ma)
+static CustomDataLayer *proj_paint_color_attribute_create(wmOperator *op, Object *ob)
{
- if (RNA_struct_property_is_set(op->ptr, "color")) {
- return;
+ char name[MAX_NAME] = "";
+ float color[4] = {0.0f, 0.0f, 0.0f, 1.0f};
+ eAttrDomain domain = ATTR_DOMAIN_POINT;
+ eCustomDataType type = CD_PROP_COLOR;
+
+ if (op) {
+ RNA_string_get(op->ptr, "name", name);
+ RNA_float_get_array(op->ptr, "color", color);
+ domain = (eAttrDomain)RNA_enum_get(op->ptr, "domain");
+ type = (eCustomDataType)RNA_enum_get(op->ptr, "data_type");
}
- bNode *in_node = ntreeFindType(ma->nodetree, SH_NODE_BSDF_PRINCIPLED);
- if (in_node == NULL) {
- return;
+ ID *id = (ID *)ob->data;
+ CustomDataLayer *layer = BKE_id_attribute_new(id, name, type, domain, op->reports);
+
+ if (!layer) {
+ return NULL;
}
- float color[4];
+ BKE_id_attributes_active_color_set(id, layer);
- if (type >= LAYER_BASE_COLOR && type < LAYER_NORMAL) {
- /* Copy color from node, so result is unchanged after assigning textures. */
- bNodeSocket *in_sock = nodeFindSocket(in_node, SOCK_IN, layer_type_items[type].name);
+ if (!BKE_id_attributes_render_color_get(id)) {
+ BKE_id_attributes_render_color_set(id, layer);
+ }
- switch (in_sock->type) {
- case SOCK_FLOAT: {
- bNodeSocketValueFloat *socket_data = in_sock->default_value;
- copy_v3_fl(color, socket_data->value);
- color[3] = 1.0f;
- break;
+ BKE_object_attributes_active_color_fill(ob, color, false);
+
+ return layer;
+}
+
+/**
+ * Get a default color for the paint slot layer from a material's Principled BSDF.
+ *
+ * \param layer_type: The layer type of the paint slot
+ * \param ma: The material to attempt using as the default color source.
+ * If this fails or \p ma is null, a default Principled BSDF is used instead.
+ */
+static void default_paint_slot_color_get(int layer_type, Material *ma, float color[4])
+{
+ switch (layer_type) {
+ case LAYER_BASE_COLOR:
+ case LAYER_SPECULAR:
+ case LAYER_ROUGHNESS:
+ case LAYER_METALLIC: {
+ bNodeTree *ntree = NULL;
+ bNode *in_node = ma ? ntreeFindType(ma->nodetree, SH_NODE_BSDF_PRINCIPLED) : NULL;
+ if (!in_node) {
+ /* An existing material or Principled BSDF node could not be found.
+ * Copy default color values from a default Principled BSDF instead. */
+ ntree = ntreeAddTree(NULL, "Temporary Shader Nodetree", ntreeType_Shader->idname);
+ in_node = nodeAddStaticNode(NULL, ntree, SH_NODE_BSDF_PRINCIPLED);
}
- case SOCK_VECTOR:
- case SOCK_RGBA: {
- bNodeSocketValueRGBA *socket_data = in_sock->default_value;
- copy_v3_v3(color, socket_data->value);
- color[3] = 1.0f;
- break;
+ bNodeSocket *in_sock = nodeFindSocket(in_node, SOCK_IN, layer_type_items[layer_type].name);
+ switch (in_sock->type) {
+ case SOCK_FLOAT: {
+ bNodeSocketValueFloat *socket_data = in_sock->default_value;
+ copy_v3_fl(color, socket_data->value);
+ color[3] = 1.0f;
+ break;
+ }
+ case SOCK_VECTOR:
+ case SOCK_RGBA: {
+ bNodeSocketValueRGBA *socket_data = in_sock->default_value;
+ copy_v3_v3(color, socket_data->value);
+ color[3] = 1.0f;
+ break;
+ }
+ default:
+ BLI_assert_unreachable();
+ rgba_float_args_set(color, 0.0f, 0.0f, 0.0f, 1.0f);
+ break;
}
- default: {
- return;
+ /* Cleanup */
+ if (ntree) {
+ ntreeFreeTree(ntree);
+ MEM_freeN(ntree);
}
+ return;
}
+ case LAYER_NORMAL:
+ /* Neutral tangent space normal map. */
+ rgba_float_args_set(color, 0.5f, 0.5f, 1.0f, 1.0f);
+ break;
+ case LAYER_BUMP:
+ case LAYER_DISPLACEMENT:
+ /* Neutral displacement and bump map. */
+ rgba_float_args_set(color, 0.5f, 0.5f, 0.5f, 1.0f);
+ break;
}
- else if (type == LAYER_NORMAL) {
- /* Neutral tangent space normal map. */
- rgba_float_args_set(color, 0.5f, 0.5f, 1.0f, 1.0f);
- }
- else if (ELEM(type, LAYER_BUMP, LAYER_DISPLACEMENT)) {
- /* Neutral displacement and bump map. */
- rgba_float_args_set(color, 0.5f, 0.5f, 0.5f, 1.0f);
- }
- else {
- return;
- }
-
- RNA_float_set_array(op->ptr, "color", color);
}
static bool proj_paint_add_slot(bContext *C, wmOperator *op)
@@ -6516,19 +6584,20 @@ static bool proj_paint_add_slot(bContext *C, wmOperator *op)
Scene *scene = CTX_data_scene(C);
Material *ma;
Image *ima = NULL;
+ CustomDataLayer *layer = NULL;
if (!ob) {
return false;
}
- ma = BKE_object_material_get(ob, ob->actcol);
+ ma = get_or_create_current_material(C, ob);
if (ma) {
Main *bmain = CTX_data_main(C);
int type = RNA_enum_get(op->ptr, "type");
bool is_data = (type > LAYER_BASE_COLOR);
- bNode *imanode;
+ bNode *new_node;
bNodeTree *ntree = ma->nodetree;
if (!ntree) {
@@ -6538,17 +6607,36 @@ static bool proj_paint_add_slot(bContext *C, wmOperator *op)
ma->use_nodes = true;
- /* try to add an image node */
- imanode = nodeAddStaticNode(C, ntree, SH_NODE_TEX_IMAGE);
-
- ima = proj_paint_image_create(op, bmain, is_data);
- imanode->id = &ima->id;
-
- nodeSetActive(ntree, imanode);
+ const ePaintCanvasSource slot_type = ob->mode == OB_MODE_SCULPT ?
+ (ePaintCanvasSource)RNA_enum_get(op->ptr,
+ "slot_type") :
+ PAINT_CANVAS_SOURCE_IMAGE;
+
+ /* Create a new node. */
+ switch (slot_type) {
+ case PAINT_CANVAS_SOURCE_IMAGE: {
+ new_node = nodeAddStaticNode(C, ntree, SH_NODE_TEX_IMAGE);
+ ima = proj_paint_image_create(op, bmain, is_data);
+ new_node->id = &ima->id;
+ break;
+ }
+ case PAINT_CANVAS_SOURCE_COLOR_ATTRIBUTE: {
+ new_node = nodeAddStaticNode(C, ntree, SH_NODE_ATTRIBUTE);
+ if ((layer = proj_paint_color_attribute_create(op, ob))) {
+ BLI_strncpy_utf8(
+ ((NodeShaderAttribute *)new_node->storage)->name, layer->name, MAX_NAME);
+ }
+ break;
+ }
+ case PAINT_CANVAS_SOURCE_MATERIAL:
+ BLI_assert_unreachable();
+ return false;
+ }
+ nodeSetActive(ntree, new_node);
/* Connect to first available principled BSDF node. */
bNode *in_node = ntreeFindType(ntree, SH_NODE_BSDF_PRINCIPLED);
- bNode *out_node = imanode;
+ bNode *out_node = new_node;
if (in_node != NULL) {
bNodeSocket *out_sock = nodeFindSocket(out_node, SOCK_OUT, "Color");
@@ -6611,6 +6699,11 @@ static bool proj_paint_add_slot(bContext *C, wmOperator *op)
BKE_image_signal(bmain, ima, NULL, IMA_SIGNAL_USER_NEW_IMAGE);
WM_event_add_notifier(C, NC_IMAGE | NA_ADDED, ima);
}
+ if (layer) {
+ BKE_texpaint_slot_refresh_cache(scene, ma, ob);
+ DEG_id_tag_update(ob->data, ID_RECALC_GEOMETRY);
+ WM_main_add_notifier(NC_GEOM | ND_DATA, ob->data);
+ }
DEG_id_tag_update(&ntree->id, 0);
DEG_id_tag_update(&ma->id, ID_RECALC_SHADING);
@@ -6632,25 +6725,8 @@ static int get_texture_layer_type(wmOperator *op, const char *prop_name)
return type;
}
-static Material *get_or_create_current_material(bContext *C, Object *ob)
-{
- Material *ma = BKE_object_material_get(ob, ob->actcol);
- if (!ma) {
- Main *bmain = CTX_data_main(C);
- ma = BKE_material_add(bmain, "Material");
- BKE_object_material_assign(bmain, ob, ma, ob->actcol, BKE_MAT_ASSIGN_USERPREF);
- }
- return ma;
-}
-
static int texture_paint_add_texture_paint_slot_exec(bContext *C, wmOperator *op)
{
- Object *ob = ED_object_active_context(C);
- Material *ma = get_or_create_current_material(C, ob);
-
- int type = get_texture_layer_type(op, "type");
- proj_paint_default_color(op, type, ma);
-
if (proj_paint_add_slot(C, op)) {
return OPERATOR_FINISHED;
}
@@ -6671,20 +6747,62 @@ static int texture_paint_add_texture_paint_slot_invoke(bContext *C,
wmOperator *op,
const wmEvent *UNUSED(event))
{
- /* Get material and default color to display in the popup. */
Object *ob = ED_object_active_context(C);
- Material *ma = get_or_create_current_material(C, ob);
+ Material *ma = BKE_object_material_get(ob, ob->actcol);
int type = get_texture_layer_type(op, "type");
- proj_paint_default_color(op, type, ma);
+ /* Set default name. */
char imagename[MAX_ID_NAME - 2];
get_default_texture_layer_name_for_object(ob, type, (char *)&imagename, sizeof(imagename));
RNA_string_set(op->ptr, "name", imagename);
+ /* Set default color. Copy the color from nodes, so it matches the existing material. */
+ float color[4];
+ default_paint_slot_color_get(type, ma, color);
+ RNA_float_set_array(op->ptr, "color", color);
+
return WM_operator_props_dialog_popup(C, op, 300);
}
+static void texture_paint_add_texture_paint_slot_ui(bContext *C, wmOperator *op)
+{
+ uiLayout *layout = op->layout;
+ uiLayoutSetPropSep(layout, true);
+ uiLayoutSetPropDecorate(layout, false);
+ Object *ob = ED_object_active_context(C);
+ ePaintCanvasSource slot_type = PAINT_CANVAS_SOURCE_IMAGE;
+
+ if (ob->mode == OB_MODE_SCULPT) {
+ slot_type = (ePaintCanvasSource)RNA_enum_get(op->ptr, "slot_type");
+ uiItemR(layout, op->ptr, "slot_type", UI_ITEM_R_EXPAND, NULL, ICON_NONE);
+ }
+
+ uiItemR(layout, op->ptr, "name", 0, NULL, ICON_NONE);
+
+ switch (slot_type) {
+ case PAINT_CANVAS_SOURCE_IMAGE: {
+ uiLayout *col = uiLayoutColumn(layout, true);
+ uiItemR(col, op->ptr, "width", 0, NULL, ICON_NONE);
+ uiItemR(col, op->ptr, "height", 0, NULL, ICON_NONE);
+
+ uiItemR(layout, op->ptr, "alpha", 0, NULL, ICON_NONE);
+ uiItemR(layout, op->ptr, "generated_type", 0, NULL, ICON_NONE);
+ uiItemR(layout, op->ptr, "float", 0, NULL, ICON_NONE);
+ break;
+ }
+ case PAINT_CANVAS_SOURCE_COLOR_ATTRIBUTE:
+ uiItemR(layout, op->ptr, "domain", UI_ITEM_R_EXPAND, NULL, ICON_NONE);
+ uiItemR(layout, op->ptr, "data_type", UI_ITEM_R_EXPAND, NULL, ICON_NONE);
+ break;
+ case PAINT_CANVAS_SOURCE_MATERIAL:
+ BLI_assert_unreachable();
+ break;
+ }
+
+ uiItemR(layout, op->ptr, "color", 0, NULL, ICON_NONE);
+}
+
#define IMA_DEF_NAME N_("Untitled")
void PAINT_OT_add_texture_paint_slot(wmOperatorType *ot)
@@ -6692,40 +6810,92 @@ void PAINT_OT_add_texture_paint_slot(wmOperatorType *ot)
PropertyRNA *prop;
static float default_color[4] = {0.0f, 0.0f, 0.0f, 1.0f};
+ static const EnumPropertyItem slot_type_items[3] = {
+ {PAINT_CANVAS_SOURCE_IMAGE, "IMAGE", 0, "Image", ""},
+ {PAINT_CANVAS_SOURCE_COLOR_ATTRIBUTE, "COLOR_ATTRIBUTE", 0, "Color Attribute", ""},
+ {0, NULL, 0, NULL, NULL},
+ };
+
+ static const EnumPropertyItem domain_items[3] = {
+ {ATTR_DOMAIN_POINT, "POINT", 0, "Vertex", ""},
+ {ATTR_DOMAIN_CORNER, "CORNER", 0, "Face Corner", ""},
+ {0, NULL, 0, NULL, NULL},
+ };
+
+ static const EnumPropertyItem attribute_type_items[3] = {
+ {CD_PROP_COLOR, "COLOR", 0, "Color", ""},
+ {CD_PROP_BYTE_COLOR, "BYTE_COLOR", 0, "Byte Color", ""},
+ {0, NULL, 0, NULL, NULL},
+ };
+
/* identifiers */
- ot->name = "Add Texture Paint Slot";
- ot->description = "Add a texture paint slot";
+ ot->name = "Add Paint Slot";
+ ot->description = "Add a paint slot";
ot->idname = "PAINT_OT_add_texture_paint_slot";
/* api callbacks */
ot->invoke = texture_paint_add_texture_paint_slot_invoke;
ot->exec = texture_paint_add_texture_paint_slot_exec;
ot->poll = ED_operator_object_active_editable_mesh;
+ ot->ui = texture_paint_add_texture_paint_slot_ui;
/* flags */
ot->flag = OPTYPE_UNDO;
- /* properties */
- prop = RNA_def_enum(ot->srna, "type", layer_type_items, 0, "Type", "Merge method to use");
+ /* Shared Properties */
+ prop = RNA_def_enum(ot->srna,
+ "type",
+ layer_type_items,
+ 0,
+ "Material Layer Type",
+ "Material layer type of new paint slot");
RNA_def_property_flag(prop, PROP_HIDDEN);
- RNA_def_string(ot->srna, "name", IMA_DEF_NAME, MAX_ID_NAME - 2, "Name", "Image data-block name");
- prop = RNA_def_int(ot->srna, "width", 1024, 1, INT_MAX, "Width", "Image width", 1, 16384);
- RNA_def_property_subtype(prop, PROP_PIXEL);
- prop = RNA_def_int(ot->srna, "height", 1024, 1, INT_MAX, "Height", "Image height", 1, 16384);
- RNA_def_property_subtype(prop, PROP_PIXEL);
+
+ prop = RNA_def_enum(
+ ot->srna, "slot_type", slot_type_items, 0, "Slot Type", "Type of new paint slot");
+
+ prop = RNA_def_string(
+ ot->srna, "name", IMA_DEF_NAME, MAX_NAME, "Name", "Name for new paint slot source");
+ RNA_def_property_flag(prop, PROP_SKIP_SAVE);
+
prop = RNA_def_float_color(
ot->srna, "color", 4, NULL, 0.0f, FLT_MAX, "Color", "Default fill color", 0.0f, 1.0f);
RNA_def_property_subtype(prop, PROP_COLOR_GAMMA);
RNA_def_property_float_array_default(prop, default_color);
+
+ /* Image Properties */
+ prop = RNA_def_int(ot->srna, "width", 1024, 1, INT_MAX, "Width", "Image width", 1, 16384);
+ RNA_def_property_subtype(prop, PROP_PIXEL);
+
+ prop = RNA_def_int(ot->srna, "height", 1024, 1, INT_MAX, "Height", "Image height", 1, 16384);
+ RNA_def_property_subtype(prop, PROP_PIXEL);
+
RNA_def_boolean(ot->srna, "alpha", true, "Alpha", "Create an image with an alpha channel");
+
RNA_def_enum(ot->srna,
"generated_type",
rna_enum_image_generated_type_items,
IMA_GENTYPE_BLANK,
"Generated Type",
"Fill the image with a grid for UV map testing");
+
RNA_def_boolean(
ot->srna, "float", 0, "32-bit Float", "Create image with 32-bit floating-point bit depth");
+
+ /* Color Attribute Properties */
+ RNA_def_enum(ot->srna,
+ "domain",
+ domain_items,
+ ATTR_DOMAIN_POINT,
+ "Domain",
+ "Type of element that attribute is stored on");
+
+ RNA_def_enum(ot->srna,
+ "data_type",
+ attribute_type_items,
+ CD_PROP_COLOR,
+ "Data Type",
+ "Type of data stored in attribute");
}
static int add_simple_uvs_exec(bContext *C, wmOperator *UNUSED(op))
diff --git a/source/blender/editors/sculpt_paint/paint_intern.h b/source/blender/editors/sculpt_paint/paint_intern.h
index 187f793eefe..3f4e660b229 100644
--- a/source/blender/editors/sculpt_paint/paint_intern.h
+++ b/source/blender/editors/sculpt_paint/paint_intern.h
@@ -98,7 +98,6 @@ void *paint_stroke_mode_data(struct PaintStroke *stroke);
float paint_stroke_distance_get(struct PaintStroke *stroke);
void paint_stroke_set_mode_data(struct PaintStroke *stroke, void *mode_data);
bool PAINT_brush_tool_poll(struct bContext *C);
-void paint_cursor_start(struct Paint *p, bool (*poll)(struct bContext *C));
/**
* Delete overlay cursor textures to preserve memory and invalidate all overlay flags.
*/
diff --git a/source/blender/editors/sculpt_paint/paint_mask.c b/source/blender/editors/sculpt_paint/paint_mask.c
index fb5e76b578f..89bbf2a3c92 100644
--- a/source/blender/editors/sculpt_paint/paint_mask.c
+++ b/source/blender/editors/sculpt_paint/paint_mask.c
@@ -1584,9 +1584,9 @@ static int sculpt_trim_gesture_box_invoke(bContext *C, wmOperator *op, const wmE
SculptSession *ss = ob->sculpt;
SculptCursorGeometryInfo sgi;
- float mouse[2] = {event->mval[0], event->mval[1]};
+ const float mval_fl[2] = {UNPACK2(event->mval)};
SCULPT_vertex_random_access_ensure(ss);
- ss->gesture_initial_hit = SCULPT_cursor_geometry_info_update(C, &sgi, mouse, false);
+ ss->gesture_initial_hit = SCULPT_cursor_geometry_info_update(C, &sgi, mval_fl, false);
if (ss->gesture_initial_hit) {
copy_v3_v3(ss->gesture_initial_location, sgi.location);
copy_v3_v3(ss->gesture_initial_normal, sgi.normal);
@@ -1625,9 +1625,9 @@ static int sculpt_trim_gesture_lasso_invoke(bContext *C, wmOperator *op, const w
SculptSession *ss = ob->sculpt;
SculptCursorGeometryInfo sgi;
- float mouse[2] = {event->mval[0], event->mval[1]};
+ const float mval_fl[2] = {UNPACK2(event->mval)};
SCULPT_vertex_random_access_ensure(ss);
- ss->gesture_initial_hit = SCULPT_cursor_geometry_info_update(C, &sgi, mouse, false);
+ ss->gesture_initial_hit = SCULPT_cursor_geometry_info_update(C, &sgi, mval_fl, false);
if (ss->gesture_initial_hit) {
copy_v3_v3(ss->gesture_initial_location, sgi.location);
copy_v3_v3(ss->gesture_initial_normal, sgi.normal);
diff --git a/source/blender/editors/sculpt_paint/paint_ops.c b/source/blender/editors/sculpt_paint/paint_ops.c
index 926a564184a..0f2b02ed3ab 100644
--- a/source/blender/editors/sculpt_paint/paint_ops.c
+++ b/source/blender/editors/sculpt_paint/paint_ops.c
@@ -82,11 +82,86 @@ static void BRUSH_OT_add(wmOperatorType *ot)
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
}
+static eGPBrush_Presets gpencil_get_brush_preset_from_tool(bToolRef *tool,
+ enum eContextObjectMode mode)
+{
+ switch (mode) {
+ case CTX_MODE_PAINT_GPENCIL: {
+ if (STREQ(tool->runtime->data_block, "DRAW")) {
+ return GP_BRUSH_PRESET_PENCIL;
+ }
+ else if (STREQ(tool->runtime->data_block, "FILL")) {
+ return GP_BRUSH_PRESET_FILL_AREA;
+ }
+ else if (STREQ(tool->runtime->data_block, "ERASE")) {
+ return GP_BRUSH_PRESET_ERASER_SOFT;
+ }
+ else if (STREQ(tool->runtime->data_block, "TINT")) {
+ return GP_BRUSH_PRESET_TINT;
+ }
+ break;
+ }
+ case CTX_MODE_SCULPT_GPENCIL: {
+ if (STREQ(tool->runtime->data_block, "SMOOTH")) {
+ return GP_BRUSH_PRESET_SMOOTH_STROKE;
+ }
+ else if (STREQ(tool->runtime->data_block, "STRENGTH")) {
+ return GP_BRUSH_PRESET_STRENGTH_STROKE;
+ }
+ else if (STREQ(tool->runtime->data_block, "THICKNESS")) {
+ return GP_BRUSH_PRESET_THICKNESS_STROKE;
+ }
+ else if (STREQ(tool->runtime->data_block, "GRAB")) {
+ return GP_BRUSH_PRESET_GRAB_STROKE;
+ }
+ else if (STREQ(tool->runtime->data_block, "PUSH")) {
+ return GP_BRUSH_PRESET_PUSH_STROKE;
+ }
+ else if (STREQ(tool->runtime->data_block, "TWIST")) {
+ return GP_BRUSH_PRESET_TWIST_STROKE;
+ }
+ else if (STREQ(tool->runtime->data_block, "PINCH")) {
+ return GP_BRUSH_PRESET_PINCH_STROKE;
+ }
+ else if (STREQ(tool->runtime->data_block, "RANDOMIZE")) {
+ return GP_BRUSH_PRESET_RANDOMIZE_STROKE;
+ }
+ else if (STREQ(tool->runtime->data_block, "CLONE")) {
+ return GP_BRUSH_PRESET_CLONE_STROKE;
+ }
+ break;
+ }
+ case CTX_MODE_WEIGHT_GPENCIL: {
+ return GP_BRUSH_PRESET_DRAW_WEIGHT;
+ }
+ case CTX_MODE_VERTEX_GPENCIL: {
+ if (STREQ(tool->runtime->data_block, "DRAW")) {
+ return GP_BRUSH_PRESET_VERTEX_DRAW;
+ }
+ else if (STREQ(tool->runtime->data_block, "BLUR")) {
+ return GP_BRUSH_PRESET_VERTEX_BLUR;
+ }
+ else if (STREQ(tool->runtime->data_block, "AVERAGE")) {
+ return GP_BRUSH_PRESET_VERTEX_AVERAGE;
+ }
+ else if (STREQ(tool->runtime->data_block, "SMEAR")) {
+ return GP_BRUSH_PRESET_VERTEX_SMEAR;
+ }
+ else if (STREQ(tool->runtime->data_block, "REPLACE")) {
+ return GP_BRUSH_PRESET_VERTEX_REPLACE;
+ }
+ break;
+ }
+ default:
+ return GP_BRUSH_PRESET_UNKNOWN;
+ break;
+ }
+ return GP_BRUSH_PRESET_UNKNOWN;
+}
+
static int brush_add_gpencil_exec(bContext *C, wmOperator *UNUSED(op))
{
- // int type = RNA_enum_get(op->ptr, "type");
- ToolSettings *ts = CTX_data_tool_settings(C);
- Paint *paint = &ts->gp_paint->paint;
+ Paint *paint = BKE_paint_get_active_from_context(C);
Brush *br = BKE_paint_brush(paint);
Main *bmain = CTX_data_main(C);
@@ -94,15 +169,70 @@ static int brush_add_gpencil_exec(bContext *C, wmOperator *UNUSED(op))
br = (Brush *)BKE_id_copy(bmain, &br->id);
}
else {
- br = BKE_brush_add(bmain, "Brush", OB_MODE_PAINT_GPENCIL);
+ /* Get the active tool to determine what type of brush is active. */
+ bScreen *screen = CTX_wm_screen(C);
+ if (screen == NULL) {
+ return OPERATOR_CANCELLED;
+ }
- /* Init grease pencil specific data. */
- BKE_brush_init_gpencil_settings(br);
- }
+ bToolRef *tool = NULL;
+ LISTBASE_FOREACH (ScrArea *, area, &screen->areabase) {
+ if (area->spacetype == SPACE_VIEW3D) {
+ /* Check the current tool is a brush. */
+ bToolRef *tref = area->runtime.tool;
+ if (tref && tref->runtime && tref->runtime->data_block[0]) {
+ tool = tref;
+ break;
+ }
+ }
+ }
- id_us_min(&br->id); /* fake user only */
+ if (tool == NULL) {
+ return OPERATOR_CANCELLED;
+ }
- BKE_paint_brush_set(paint, br);
+ /* Get Brush mode base on context mode. */
+ const enum eContextObjectMode mode = CTX_data_mode_enum(C);
+ eObjectMode obmode = OB_MODE_PAINT_GPENCIL;
+ switch (mode) {
+ case CTX_MODE_PAINT_GPENCIL:
+ obmode = OB_MODE_PAINT_GPENCIL;
+ break;
+ case CTX_MODE_SCULPT_GPENCIL:
+ obmode = OB_MODE_SCULPT_GPENCIL;
+ break;
+ case CTX_MODE_WEIGHT_GPENCIL:
+ obmode = OB_MODE_WEIGHT_GPENCIL;
+ break;
+ case CTX_MODE_VERTEX_GPENCIL:
+ obmode = OB_MODE_VERTEX_GPENCIL;
+ break;
+ default:
+ return OPERATOR_CANCELLED;
+ break;
+ }
+
+ /* Get brush preset using the actual tool. */
+ eGPBrush_Presets preset = gpencil_get_brush_preset_from_tool(tool, mode);
+
+ /* Capitalize Brush name first letter using the tool name. */
+ char name[64];
+ BLI_strncpy(name, tool->runtime->data_block, sizeof(name));
+ BLI_str_tolower_ascii(name, sizeof(name));
+ name[0] = BLI_toupper_ascii(name[0]);
+
+ /* Create the brush and assign default values. */
+ br = BKE_brush_add(bmain, name, obmode);
+ if (br) {
+ BKE_brush_init_gpencil_settings(br);
+ BKE_gpencil_brush_preset_set(bmain, br, preset);
+ }
+ }
+
+ if (br) {
+ id_us_min(&br->id); /* fake user only */
+ BKE_paint_brush_set(paint, br);
+ }
return OPERATOR_FINISHED;
}
diff --git a/source/blender/editors/sculpt_paint/paint_stroke.c b/source/blender/editors/sculpt_paint/paint_stroke.c
index d2005473512..63e6dc7e965 100644
--- a/source/blender/editors/sculpt_paint/paint_stroke.c
+++ b/source/blender/editors/sculpt_paint/paint_stroke.c
@@ -506,7 +506,7 @@ static bool paint_stroke_use_jitter(ePaintMode mode, Brush *brush, bool invert)
/* Put the location of the next stroke dot into the stroke RNA and apply it to the mesh */
static void paint_brush_stroke_add_step(
- bContext *C, wmOperator *op, PaintStroke *stroke, const float mouse_in[2], float pressure)
+ bContext *C, wmOperator *op, PaintStroke *stroke, const float mval[2], float pressure)
{
Scene *scene = CTX_data_scene(C);
Paint *paint = BKE_paint_get_active_from_context(C);
@@ -546,7 +546,7 @@ static void paint_brush_stroke_add_step(
/* copy last position -before- jittering, or space fill code
* will create too many dabs */
- copy_v2_v2(stroke->last_mouse_position, mouse_in);
+ copy_v2_v2(stroke->last_mouse_position, mval);
stroke->last_pressure = pressure;
if (paint_stroke_use_scene_spacing(brush, mode)) {
@@ -562,24 +562,24 @@ static void paint_brush_stroke_add_step(
factor *= pressure;
}
- BKE_brush_jitter_pos(scene, brush, mouse_in, mouse_out);
+ BKE_brush_jitter_pos(scene, brush, mval, mouse_out);
/* XXX: meh, this is round about because
* BKE_brush_jitter_pos isn't written in the best way to
* be reused here */
if (factor != 1.0f) {
- sub_v2_v2v2(delta, mouse_out, mouse_in);
+ sub_v2_v2v2(delta, mouse_out, mval);
mul_v2_fl(delta, factor);
- add_v2_v2v2(mouse_out, mouse_in, delta);
+ add_v2_v2v2(mouse_out, mval, delta);
}
}
else {
- copy_v2_v2(mouse_out, mouse_in);
+ copy_v2_v2(mouse_out, mval);
}
bool is_location_is_set;
ups->last_hit = paint_brush_update(
- C, brush, mode, stroke, mouse_in, mouse_out, pressure, location, &is_location_is_set);
+ C, brush, mode, stroke, mval, mouse_out, pressure, location, &is_location_is_set);
if (is_location_is_set) {
copy_v3_v3(ups->last_location, location);
}
@@ -605,7 +605,7 @@ static void paint_brush_stroke_add_step(
/* Mouse coordinates modified by the stroke type options. */
RNA_float_set_array(&itemptr, "mouse", mouse_out);
/* Original mouse coordinates. */
- RNA_float_set_array(&itemptr, "mouse_event", mouse_in);
+ RNA_float_set_array(&itemptr, "mouse_event", mval);
RNA_boolean_set(&itemptr, "pen_flip", stroke->pen_flip);
RNA_float_set(&itemptr, "pressure", pressure);
RNA_float_set(&itemptr, "x_tilt", stroke->x_tilt);
@@ -912,8 +912,13 @@ PaintStroke *paint_stroke_new(bContext *C,
rv3d->rflag |= RV3D_PAINTING;
}
- zero_v3(ups->average_stroke_accum);
- ups->average_stroke_counter = 0;
+ /* Preserve location from last stroke while applying and resetting
+ * ups->average_stroke_counter to 1.
+ */
+ if (ups->average_stroke_counter) {
+ mul_v3_fl(ups->average_stroke_accum, 1.0f / (float)ups->average_stroke_counter);
+ ups->average_stroke_counter = 1;
+ }
/* initialize here to avoid initialization conflict with threaded strokes */
BKE_curvemapping_init(br->curve);
@@ -923,6 +928,8 @@ PaintStroke *paint_stroke_new(bContext *C,
BKE_paint_set_overlay_override(br->overlay_flags);
+ ups->start_pixel_radius = BKE_brush_size_get(CTX_data_scene(C), br);
+
return stroke;
}
diff --git a/source/blender/editors/sculpt_paint/paint_vertex.cc b/source/blender/editors/sculpt_paint/paint_vertex.cc
index 16b22775b9e..67b60acc667 100644
--- a/source/blender/editors/sculpt_paint/paint_vertex.cc
+++ b/source/blender/editors/sculpt_paint/paint_vertex.cc
@@ -56,6 +56,7 @@
#include "WM_types.h"
#include "ED_armature.h"
+#include "ED_image.h"
#include "ED_mesh.h"
#include "ED_object.h"
#include "ED_screen.h"
@@ -139,8 +140,8 @@ struct NormalAnglePrecalc {
/* Returns number of elements. */
static int get_vcol_elements(Mesh *me, size_t *r_elem_size)
{
- CustomDataLayer *layer = BKE_id_attributes_active_color_get(&me->id);
- AttributeDomain domain = BKE_id_attribute_domain(&me->id, layer);
+ const CustomDataLayer *layer = BKE_id_attributes_active_color_get(&me->id);
+ const eAttrDomain domain = BKE_id_attribute_domain(&me->id, layer);
if (r_elem_size) {
*r_elem_size = layer->type == CD_PROP_COLOR ? sizeof(float) * 4ULL : 4ULL;
@@ -217,7 +218,7 @@ static MDeformVert *defweight_prev_init(MDeformVert *dvert_prev,
MDeformVert *dvert_curr,
int index)
{
- MDeformVert *dv_curr = &dvert_curr[index];
+ const MDeformVert *dv_curr = &dvert_curr[index];
MDeformVert *dv_prev = &dvert_prev[index];
if (dv_prev->flag == 1) {
dv_prev->flag = 0;
@@ -233,7 +234,7 @@ static bool vertex_paint_use_fast_update_check(Object *ob)
const Mesh *me_eval = BKE_object_get_evaluated_mesh(ob);
if (me_eval != nullptr) {
- Mesh *me = BKE_mesh_from_object(ob);
+ const Mesh *me = BKE_mesh_from_object(ob);
if (me && me->mloopcol) {
return (me->mloopcol == CustomData_get_layer(&me_eval->ldata, CD_PROP_BYTE_COLOR));
}
@@ -252,13 +253,14 @@ static void paint_last_stroke_update(Scene *scene, const float location[3])
bool vertex_paint_mode_poll(bContext *C)
{
- Object *ob = CTX_data_active_object(C);
+ const Object *ob = CTX_data_active_object(C);
- if (!(ob && ob->mode == OB_MODE_VERTEX_PAINT && ((Mesh *)ob->data)->totpoly)) {
+ if (!(ob && ob->mode == OB_MODE_VERTEX_PAINT && ((const Mesh *)ob->data)->totpoly)) {
return false;
}
- CustomDataLayer *layer = BKE_id_attributes_active_color_get((ID *)ob->data);
+ const CustomDataLayer *layer = BKE_id_attributes_active_color_get(
+ static_cast<const ID *>(ob->data));
return layer != nullptr;
}
@@ -291,15 +293,15 @@ bool vertex_paint_poll_ignore_tool(bContext *C)
bool weight_paint_mode_poll(bContext *C)
{
- Object *ob = CTX_data_active_object(C);
+ const Object *ob = CTX_data_active_object(C);
- return ob && ob->mode == OB_MODE_WEIGHT_PAINT && ((Mesh *)ob->data)->totpoly;
+ return ob && ob->mode == OB_MODE_WEIGHT_PAINT && ((const Mesh *)ob->data)->totpoly;
}
static bool weight_paint_poll_ex(bContext *C, bool check_tool)
{
- Object *ob = CTX_data_active_object(C);
- ScrArea *area;
+ const Object *ob = CTX_data_active_object(C);
+ const ScrArea *area;
if ((ob != nullptr) && (ob->mode & OB_MODE_WEIGHT_PAINT) &&
(BKE_paint_brush(&CTX_data_tool_settings(C)->wpaint->paint) != nullptr) &&
@@ -324,15 +326,14 @@ bool weight_paint_poll_ignore_tool(bContext *C)
return weight_paint_poll_ex(C, false);
}
-template<typename Color, typename Traits, AttributeDomain domain>
+template<typename Color, typename Traits, eAttrDomain domain>
static Color vpaint_get_current_col(Scene *scene, VPaint *vp, bool secondary)
{
- Brush *brush = BKE_paint_brush(&vp->paint);
+ const Brush *brush = BKE_paint_brush_for_read(&vp->paint);
float color[4];
const float *brush_color = secondary ? BKE_brush_secondary_color_get(scene, brush) :
BKE_brush_color_get(scene, brush);
- copy_v3_v3(color, brush_color);
- IMB_colormanagement_srgb_to_scene_linear_v3(color);
+ IMB_colormanagement_srgb_to_scene_linear_v3(color, brush_color);
color[3] = 1.0f; /* alpha isn't used, could even be removed to speedup paint a little */
@@ -361,7 +362,7 @@ static Color vpaint_blend(const VPaint *vp,
const Brush *brush = vp->paint.brush;
const IMB_BlendMode blend = (IMB_BlendMode)brush->blend;
- Color color_blend = BLI_mix_colors<Color, Traits>(blend, color_curr, color_paint, alpha);
+ const Color color_blend = BLI_mix_colors<Color, Traits>(blend, color_curr, color_paint, alpha);
/* If no accumulate, clip color adding with `color_orig` & `color_test`. */
if (!brush_use_accumulate(vp)) {
@@ -1322,7 +1323,7 @@ static void ed_vwpaintmode_enter_generic(
BKE_paint_ensure(scene->toolsettings, (Paint **)&scene->toolsettings->vpaint);
Paint *paint = BKE_paint_get_active_from_paintmode(scene, paint_mode);
- paint_cursor_start(paint, vertex_paint_poll);
+ ED_paint_cursor_start(paint, vertex_paint_poll);
BKE_paint_init(bmain, scene, paint_mode, PAINT_CURSOR_VERTEX_PAINT);
}
else if (mode_flag == OB_MODE_WEIGHT_PAINT) {
@@ -1330,7 +1331,7 @@ static void ed_vwpaintmode_enter_generic(
BKE_paint_ensure(scene->toolsettings, (Paint **)&scene->toolsettings->wpaint);
Paint *paint = BKE_paint_get_active_from_paintmode(scene, paint_mode);
- paint_cursor_start(paint, weight_paint_poll);
+ ED_paint_cursor_start(paint, weight_paint_poll);
BKE_paint_init(bmain, scene, paint_mode, PAINT_CURSOR_WEIGHT_PAINT);
/* weight paint specific */
@@ -1607,10 +1608,10 @@ static void smooth_brush_toggle_off(const bContext *C, Paint *paint, StrokeCache
/* Initialize the stroke cache invariants from operator properties */
static void vwpaint_update_cache_invariants(
- bContext *C, VPaint *vp, SculptSession *ss, wmOperator *op, const float mouse[2])
+ bContext *C, VPaint *vp, SculptSession *ss, wmOperator *op, const float mval[2])
{
StrokeCache *cache;
- Scene *scene = CTX_data_scene(C);
+ const Scene *scene = CTX_data_scene(C);
UnifiedPaintSettings *ups = &CTX_data_tool_settings(C)->unified_paint_settings;
ViewContext *vc = paint_stroke_view_context((PaintStroke *)op->customdata);
Object *ob = CTX_data_active_object(C);
@@ -1628,8 +1629,8 @@ static void vwpaint_update_cache_invariants(
}
/* Initial mouse location */
- if (mouse) {
- copy_v2_v2(cache->initial_mouse, mouse);
+ if (mval) {
+ copy_v2_v2(cache->initial_mouse, mval);
}
else {
zero_v2(cache->initial_mouse);
@@ -1652,7 +1653,7 @@ static void vwpaint_update_cache_invariants(
}
copy_v2_v2(cache->mouse, cache->initial_mouse);
- Brush *brush = vp->paint.brush;
+ const Brush *brush = vp->paint.brush;
/* Truly temporary data that isn't stored in properties */
cache->vc = vc;
cache->brush = brush;
@@ -2824,11 +2825,11 @@ void PAINT_OT_vertex_paint_toggle(wmOperatorType *ot)
struct VPaintDataBase {
ViewContext vc;
- AttributeDomain domain;
- CustomDataType type;
+ eAttrDomain domain;
+ eCustomDataType type;
};
-template<typename Color, typename Traits, AttributeDomain domain>
+template<typename Color, typename Traits, eAttrDomain domain>
struct VPaintData : public VPaintDataBase {
NormalAnglePrecalc normal_angle_precalc;
@@ -2856,7 +2857,7 @@ struct VPaintData : public VPaintDataBase {
} smear;
};
-template<typename Color, typename Traits, AttributeDomain domain>
+template<typename Color, typename Traits, eAttrDomain domain>
static void *vpaint_init_vpaint(bContext *C,
wmOperator *op,
Scene *scene,
@@ -2950,7 +2951,7 @@ static bool vpaint_stroke_test_start(bContext *C, wmOperator *op, const float mo
return false;
}
- AttributeDomain domain = BKE_id_attribute_domain(&me->id, layer);
+ eAttrDomain domain = BKE_id_attribute_domain(&me->id, layer);
void *vpd = nullptr;
if (domain == ATTR_DOMAIN_POINT) {
@@ -3273,7 +3274,7 @@ static void do_vpaint_brush_blur_verts(bContext *C,
});
}
-template<typename Color = ColorPaint4b, typename Traits, AttributeDomain domain>
+template<typename Color = ColorPaint4b, typename Traits, eAttrDomain domain>
static void do_vpaint_brush_smear(bContext *C,
Sculpt *UNUSED(sd),
VPaint *vp,
@@ -3452,7 +3453,7 @@ static void do_vpaint_brush_smear(bContext *C,
});
}
-template<typename Color, typename Traits, AttributeDomain domain>
+template<typename Color, typename Traits, eAttrDomain domain>
static void calculate_average_color(VPaintData<Color, Traits, domain> *vpd,
Object *ob,
Mesh *me,
@@ -3542,7 +3543,7 @@ static void calculate_average_color(VPaintData<Color, Traits, domain> *vpd,
}
}
-template<typename Color, typename Traits, AttributeDomain domain>
+template<typename Color, typename Traits, eAttrDomain domain>
static float paint_and_tex_color_alpha(VPaint *vp,
VPaintData<Color, Traits, domain> *vpd,
const float v_co[3],
@@ -3560,7 +3561,7 @@ static float paint_and_tex_color_alpha(VPaint *vp,
return rgba[3];
}
-template<typename Color, typename Traits, AttributeDomain domain>
+template<typename Color, typename Traits, eAttrDomain domain>
static void vpaint_do_draw(bContext *C,
Sculpt *UNUSED(sd),
VPaint *vp,
@@ -3700,7 +3701,7 @@ static void vpaint_do_draw(bContext *C,
});
}
-template<typename Color, typename Traits, AttributeDomain domain>
+template<typename Color, typename Traits, eAttrDomain domain>
static void vpaint_do_blur(bContext *C,
Sculpt *sd,
VPaint *vp,
@@ -3719,7 +3720,7 @@ static void vpaint_do_blur(bContext *C,
}
}
-template<typename Color, typename Traits, AttributeDomain domain>
+template<typename Color, typename Traits, eAttrDomain domain>
static void vpaint_paint_leaves(bContext *C,
Sculpt *sd,
VPaint *vp,
@@ -3755,7 +3756,7 @@ static void vpaint_paint_leaves(bContext *C,
}
}
-template<typename Color, typename Traits, AttributeDomain domain>
+template<typename Color, typename Traits, eAttrDomain domain>
static void vpaint_do_paint(bContext *C,
Sculpt *sd,
VPaint *vp,
@@ -3786,7 +3787,7 @@ static void vpaint_do_paint(bContext *C,
}
}
-template<typename Color, typename Traits, AttributeDomain domain>
+template<typename Color, typename Traits, eAttrDomain domain>
static void vpaint_do_radial_symmetry(bContext *C,
Sculpt *sd,
VPaint *vp,
@@ -3805,7 +3806,7 @@ static void vpaint_do_radial_symmetry(bContext *C,
/* near duplicate of: sculpt.c's,
* 'do_symmetrical_brush_actions' and 'wpaint_do_symmetrical_brush_actions'. */
-template<typename Color, typename Traits, AttributeDomain domain>
+template<typename Color, typename Traits, eAttrDomain domain>
static void vpaint_do_symmetrical_brush_actions(
bContext *C, Sculpt *sd, VPaint *vp, VPaintData<Color, Traits, domain> *vpd, Object *ob)
{
@@ -3852,7 +3853,7 @@ static void vpaint_do_symmetrical_brush_actions(
cache->is_last_valid = true;
}
-template<typename Color, typename Traits, AttributeDomain domain>
+template<typename Color, typename Traits, eAttrDomain domain>
static void vpaint_stroke_update_step_intern(bContext *C, PaintStroke *stroke, PointerRNA *itemptr)
{
Scene *scene = CTX_data_scene(C);
@@ -3940,7 +3941,7 @@ static void vpaint_stroke_update_step(bContext *C,
}
}
-template<typename Color, typename Traits, AttributeDomain domain>
+template<typename Color, typename Traits, eAttrDomain domain>
static void vpaint_free_vpaintdata(Object *UNUSED(ob), void *_vpd)
{
VPaintData<Color, Traits, domain> *vpd = static_cast<VPaintData<Color, Traits, domain> *>(_vpd);
@@ -4097,7 +4098,7 @@ void PAINT_OT_vertex_paint(wmOperatorType *ot)
/** \name Set Vertex Colors Operator
* \{ */
-template<typename Color, typename Traits, AttributeDomain domain>
+template<typename Color, typename Traits, eAttrDomain domain>
static bool vertex_color_set(Object *ob, ColorPaint4f paintcol_in, Color *color_layer)
{
Mesh *me;
@@ -4165,7 +4166,7 @@ static bool paint_object_attributes_active_color_fill_ex(Object *ob,
me->editflag &= ~ME_EDIT_PAINT_FACE_SEL;
me->editflag &= ~ME_EDIT_PAINT_VERT_SEL;
}
- AttributeDomain domain = BKE_id_attribute_domain(&me->id, layer);
+ eAttrDomain domain = BKE_id_attribute_domain(&me->id, layer);
bool ok = false;
if (domain == ATTR_DOMAIN_POINT) {
if (layer->type == CD_PROP_COLOR) {
diff --git a/source/blender/editors/sculpt_paint/paint_vertex_color_ops.c b/source/blender/editors/sculpt_paint/paint_vertex_color_ops.cc
index a2e1adff50a..6a47aceb2b0 100644
--- a/source/blender/editors/sculpt_paint/paint_vertex_color_ops.c
+++ b/source/blender/editors/sculpt_paint/paint_vertex_color_ops.cc
@@ -11,6 +11,7 @@
#include "DNA_object_types.h"
#include "DNA_scene_types.h"
+#include "BLI_array.hh"
#include "BLI_math_base.h"
#include "BLI_math_color.h"
@@ -30,6 +31,8 @@
#include "paint_intern.h" /* own include */
+using blender::Array;
+
/* -------------------------------------------------------------------- */
/** \name Internal Utility Functions
* \{ */
@@ -45,7 +48,7 @@ static bool vertex_weight_paint_mode_poll(bContext *C)
static void tag_object_after_update(Object *object)
{
BLI_assert(object->type == OB_MESH);
- Mesh *mesh = object->data;
+ Mesh *mesh = static_cast<Mesh *>(object->data);
DEG_id_tag_update(&mesh->id, ID_RECALC_COPY_ON_WRITE);
/* NOTE: Original mesh is used for display, so tag it directly here. */
BKE_mesh_batch_cache_dirty_tag(mesh, BKE_MESH_BATCH_DIRTY_ALL);
@@ -63,7 +66,8 @@ static bool vertex_paint_from_weight(Object *ob)
const MPoly *mp;
int vgroup_active;
- if (((me = BKE_mesh_from_object(ob)) == NULL || (ED_mesh_color_ensure(me, NULL)) == false)) {
+ if (((me = BKE_mesh_from_object(ob)) == nullptr ||
+ (ED_mesh_color_ensure(me, nullptr)) == false)) {
return false;
}
@@ -128,14 +132,13 @@ static void vertex_color_smooth_looptag(Mesh *me, const bool *mlooptag)
{
const bool use_face_sel = (me->editflag & ME_EDIT_PAINT_FACE_SEL) != 0;
const MPoly *mp;
- int(*scol)[4];
bool has_shared = false;
- if (me->mloopcol == NULL || me->totvert == 0 || me->totpoly == 0) {
+ if (me->mloopcol == nullptr || me->totvert == 0 || me->totpoly == 0) {
return;
}
- scol = MEM_callocN(sizeof(int) * me->totvert * 5, "scol");
+ int(*scol)[4] = static_cast<int(*)[4]>(MEM_callocN(sizeof(int) * me->totvert * 5, "scol"));
int i;
for (i = 0, mp = me->mpoly; i < me->totpoly; i++, mp++) {
@@ -185,16 +188,15 @@ static bool vertex_color_smooth(Object *ob)
const MPoly *mp;
int i, j;
- bool *mlooptag;
-
- if (((me = BKE_mesh_from_object(ob)) == NULL) || (ED_mesh_color_ensure(me, NULL) == false)) {
+ if (((me = BKE_mesh_from_object(ob)) == nullptr) ||
+ (ED_mesh_color_ensure(me, nullptr) == false)) {
return false;
}
const bool use_face_sel = (me->editflag & ME_EDIT_PAINT_FACE_SEL) != 0;
const bool use_vert_sel = (me->editflag & ME_EDIT_PAINT_VERT_SEL) != 0;
- mlooptag = MEM_callocN(sizeof(bool) * me->totloop, "VPaintData mlooptag");
+ Array<bool> loop_tag(me->totloop, false);
/* simply tag loops of selected faces */
mp = me->mpoly;
@@ -208,7 +210,7 @@ static bool vertex_color_smooth(Object *ob)
j = 0;
do {
if (!(use_vert_sel && !(me->mvert[ml->v].flag & SELECT))) {
- mlooptag[mp->loopstart + j] = true;
+ loop_tag[mp->loopstart + j] = true;
}
ml++;
j++;
@@ -218,9 +220,7 @@ static bool vertex_color_smooth(Object *ob)
/* remove stale me->mcol, will be added later */
BKE_mesh_tessface_clear(me);
- vertex_color_smooth_looptag(me, mlooptag);
-
- MEM_freeN(mlooptag);
+ vertex_color_smooth_looptag(me, loop_tag.data());
tag_object_after_update(ob);
@@ -268,7 +268,8 @@ static void vpaint_tx_brightness_contrast(const float col[3],
const void *user_data,
float r_col[3])
{
- const struct VPaintTx_BrightContrastData *data = user_data;
+ const VPaintTx_BrightContrastData *data = static_cast<const VPaintTx_BrightContrastData *>(
+ user_data);
for (int i = 0; i < 3; i++) {
r_col[i] = data->gain * col[i] + data->offset;
@@ -302,10 +303,9 @@ static int vertex_color_brightness_contrast_exec(bContext *C, wmOperator *op)
}
}
- const struct VPaintTx_BrightContrastData user_data = {
- .gain = gain,
- .offset = offset,
- };
+ VPaintTx_BrightContrastData user_data{};
+ user_data.gain = gain;
+ user_data.offset = offset;
if (ED_vpaint_color_transform(obact, vpaint_tx_brightness_contrast, &user_data)) {
WM_event_add_notifier(C, NC_OBJECT | ND_DRAW, obact);
@@ -345,7 +345,7 @@ struct VPaintTx_HueSatData {
static void vpaint_tx_hsv(const float col[3], const void *user_data, float r_col[3])
{
- const struct VPaintTx_HueSatData *data = user_data;
+ const VPaintTx_HueSatData *data = static_cast<const VPaintTx_HueSatData *>(user_data);
float hsv[3];
rgb_to_hsv_v(col, hsv);
@@ -366,11 +366,10 @@ static int vertex_color_hsv_exec(bContext *C, wmOperator *op)
{
Object *obact = CTX_data_active_object(C);
- const struct VPaintTx_HueSatData user_data = {
- .hue = RNA_float_get(op->ptr, "h"),
- .sat = RNA_float_get(op->ptr, "s"),
- .val = RNA_float_get(op->ptr, "v"),
- };
+ VPaintTx_HueSatData user_data{};
+ user_data.hue = RNA_float_get(op->ptr, "h");
+ user_data.sat = RNA_float_get(op->ptr, "s");
+ user_data.val = RNA_float_get(op->ptr, "v");
if (ED_vpaint_color_transform(obact, vpaint_tx_hsv, &user_data)) {
WM_event_add_notifier(C, NC_OBJECT | ND_DRAW, obact);
@@ -410,7 +409,7 @@ static int vertex_color_invert_exec(bContext *C, wmOperator *UNUSED(op))
{
Object *obact = CTX_data_active_object(C);
- if (ED_vpaint_color_transform(obact, vpaint_tx_invert, NULL)) {
+ if (ED_vpaint_color_transform(obact, vpaint_tx_invert, nullptr)) {
WM_event_add_notifier(C, NC_OBJECT | ND_DRAW, obact);
return OPERATOR_FINISHED;
}
@@ -439,7 +438,7 @@ struct VPaintTx_LevelsData {
static void vpaint_tx_levels(const float col[3], const void *user_data, float r_col[3])
{
- const struct VPaintTx_LevelsData *data = user_data;
+ const VPaintTx_LevelsData *data = static_cast<const VPaintTx_LevelsData *>(user_data);
for (int i = 0; i < 3; i++) {
r_col[i] = data->gain * (col[i] + data->offset);
}
@@ -449,10 +448,9 @@ static int vertex_color_levels_exec(bContext *C, wmOperator *op)
{
Object *obact = CTX_data_active_object(C);
- const struct VPaintTx_LevelsData user_data = {
- .gain = RNA_float_get(op->ptr, "gain"),
- .offset = RNA_float_get(op->ptr, "offset"),
- };
+ VPaintTx_LevelsData user_data{};
+ user_data.gain = RNA_float_get(op->ptr, "gain");
+ user_data.offset = RNA_float_get(op->ptr, "offset");
if (ED_vpaint_color_transform(obact, vpaint_tx_levels, &user_data)) {
WM_event_add_notifier(C, NC_OBJECT | ND_DRAW, obact);
diff --git a/source/blender/editors/sculpt_paint/sculpt.c b/source/blender/editors/sculpt_paint/sculpt.c
index 32b7047c2b0..9ce80e4a433 100644
--- a/source/blender/editors/sculpt_paint/sculpt.c
+++ b/source/blender/editors/sculpt_paint/sculpt.c
@@ -148,7 +148,7 @@ const float *SCULPT_vertex_co_get(SculptSession *ss, int index)
bool SCULPT_has_loop_colors(const Object *ob)
{
Mesh *me = BKE_object_get_original_mesh(ob);
- CustomDataLayer *layer = BKE_id_attributes_active_color_get(&me->id);
+ const CustomDataLayer *layer = BKE_id_attributes_active_color_get(&me->id);
return layer && BKE_id_attribute_domain(&me->id, layer) == ATTR_DOMAIN_CORNER;
}
@@ -1354,8 +1354,23 @@ static void paint_mesh_restore_co_task_cb(void *__restrict userdata,
SculptSession *ss = data->ob->sculpt;
SculptUndoNode *unode;
- SculptUndoType type = (data->brush->sculpt_tool == SCULPT_TOOL_MASK ? SCULPT_UNDO_MASK :
- SCULPT_UNDO_COORDS);
+ SculptUndoType type;
+
+ switch (data->brush->sculpt_tool) {
+ case SCULPT_TOOL_MASK:
+ type = SCULPT_UNDO_MASK;
+ BKE_pbvh_node_mark_update_mask(data->nodes[n]);
+ break;
+ case SCULPT_TOOL_PAINT:
+ case SCULPT_TOOL_SMEAR:
+ type = SCULPT_UNDO_COLOR;
+ BKE_pbvh_node_mark_update_color(data->nodes[n]);
+ break;
+ default:
+ type = SCULPT_UNDO_COORDS;
+ BKE_pbvh_node_mark_update(data->nodes[n]);
+ break;
+ }
if (ss->bm) {
unode = SCULPT_undo_push_node(data->ob, data->nodes[n], type);
@@ -1397,8 +1412,6 @@ static void paint_mesh_restore_co_task_cb(void *__restrict userdata,
}
}
BKE_pbvh_vertex_iter_end;
-
- BKE_pbvh_node_mark_update(data->nodes[n]);
}
static void paint_mesh_restore_co(Sculpt *sd, Object *ob)
@@ -3248,8 +3261,8 @@ static void do_brush_action(Sculpt *sd,
}
nodes = sculpt_pbvh_gather_generic(ob, sd, brush, use_original, radius_scale, &totnode);
}
-
- if (sculpt_needs_pbvh_pixels(paint_mode_settings, brush, ob)) {
+ const bool use_pixels = sculpt_needs_pbvh_pixels(paint_mode_settings, brush, ob);
+ if (use_pixels) {
sculpt_pbvh_update_pixels(paint_mode_settings, ss, ob);
}
@@ -3302,16 +3315,18 @@ static void do_brush_action(Sculpt *sd,
}
float location[3];
- SculptThreadedTaskData task_data = {
- .sd = sd,
- .ob = ob,
- .brush = brush,
- .nodes = nodes,
- };
+ if (!use_pixels) {
+ SculptThreadedTaskData task_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, &task_data, do_brush_action_task_cb, &settings);
+ TaskParallelSettings settings;
+ BKE_pbvh_parallel_range_settings(&settings, true, totnode);
+ BLI_task_parallel_range(0, totnode, &task_data, do_brush_action_task_cb, &settings);
+ }
if (sculpt_brush_needs_normal(ss, brush)) {
update_sculpt_normal(sd, ob, nodes, totnode);
@@ -3520,15 +3535,7 @@ static void sculpt_combine_proxies_task_cb(void *__restrict userdata,
SculptSession *ss = data->ob->sculpt;
Sculpt *sd = data->sd;
Object *ob = data->ob;
-
- /* These brushes start from original coordinates. */
- const bool use_orco = ELEM(data->brush->sculpt_tool,
- SCULPT_TOOL_GRAB,
- SCULPT_TOOL_ROTATE,
- SCULPT_TOOL_THUMB,
- SCULPT_TOOL_ELASTIC_DEFORM,
- SCULPT_TOOL_BOUNDARY,
- SCULPT_TOOL_POSE);
+ const bool use_orco = data->use_proxies_orco;
PBVHVertexIter vd;
PBVHProxyNode *proxies;
@@ -3583,12 +3590,23 @@ static void sculpt_combine_proxies(Sculpt *sd, Object *ob)
return;
}
+ /* First line is tools that don't support proxies. */
+ const bool use_orco = ELEM(brush->sculpt_tool,
+ SCULPT_TOOL_GRAB,
+ SCULPT_TOOL_ROTATE,
+ SCULPT_TOOL_THUMB,
+ SCULPT_TOOL_ELASTIC_DEFORM,
+ SCULPT_TOOL_BOUNDARY,
+ SCULPT_TOOL_POSE);
+
BKE_pbvh_gather_proxies(ss->pbvh, &nodes, &totnode);
+
SculptThreadedTaskData data = {
.sd = sd,
.ob = ob,
.brush = brush,
.nodes = nodes,
+ .use_proxies_orco = use_orco,
};
TaskParallelSettings settings;
@@ -3597,6 +3615,27 @@ static void sculpt_combine_proxies(Sculpt *sd, Object *ob)
MEM_SAFE_FREE(nodes);
}
+void SCULPT_combine_transform_proxies(Sculpt *sd, Object *ob)
+{
+ SculptSession *ss = ob->sculpt;
+ PBVHNode **nodes;
+ int totnode;
+
+ BKE_pbvh_gather_proxies(ss->pbvh, &nodes, &totnode);
+ SculptThreadedTaskData data = {
+ .sd = sd,
+ .ob = ob,
+ .nodes = nodes,
+ .use_proxies_orco = false,
+ };
+
+ TaskParallelSettings settings;
+ BKE_pbvh_parallel_range_settings(&settings, true, totnode);
+ BLI_task_parallel_range(0, totnode, &data, sculpt_combine_proxies_task_cb, &settings);
+
+ MEM_SAFE_FREE(nodes);
+}
+
/**
* Copy the modified vertices from the #PBVH to the active key.
*/
@@ -4135,7 +4174,7 @@ static void smooth_brush_toggle_off(const bContext *C, Paint *paint, StrokeCache
/* Initialize the stroke cache invariants from operator properties. */
static void sculpt_update_cache_invariants(
- bContext *C, Sculpt *sd, SculptSession *ss, wmOperator *op, const float mouse[2])
+ bContext *C, Sculpt *sd, SculptSession *ss, wmOperator *op, const float mval[2])
{
StrokeCache *cache = MEM_callocN(sizeof(StrokeCache), "stroke cache");
UnifiedPaintSettings *ups = &CTX_data_tool_settings(C)->unified_paint_settings;
@@ -4165,8 +4204,8 @@ static void sculpt_update_cache_invariants(
sculpt_init_mirror_clipping(ob, ss);
/* Initial mouse location. */
- if (mouse) {
- copy_v2_v2(cache->initial_mouse, mouse);
+ if (mval) {
+ copy_v2_v2(cache->initial_mouse, mval);
}
else {
zero_v2(cache->initial_mouse);
@@ -4304,7 +4343,8 @@ static bool sculpt_needs_delta_from_anchored_origin(Brush *brush)
SCULPT_TOOL_POSE,
SCULPT_TOOL_BOUNDARY,
SCULPT_TOOL_THUMB,
- SCULPT_TOOL_ELASTIC_DEFORM)) {
+ SCULPT_TOOL_ELASTIC_DEFORM,
+ SCULPT_TOOL_SMEAR)) {
return true;
}
if (brush->sculpt_tool == SCULPT_TOOL_CLOTH &&
@@ -4334,7 +4374,7 @@ static void sculpt_update_brush_delta(UnifiedPaintSettings *ups, Object *ob, Bru
{
SculptSession *ss = ob->sculpt;
StrokeCache *cache = ss->cache;
- const float mouse[2] = {
+ const float mval[2] = {
cache->mouse_event[0],
cache->mouse_event[1],
};
@@ -4353,6 +4393,7 @@ static void sculpt_update_brush_delta(UnifiedPaintSettings *ups, Object *ob, Bru
SCULPT_TOOL_SNAKE_HOOK,
SCULPT_TOOL_POSE,
SCULPT_TOOL_BOUNDARY,
+ SCULPT_TOOL_SMEAR,
SCULPT_TOOL_THUMB) &&
!sculpt_brush_use_topology_rake(ss, brush)) {
return;
@@ -4374,9 +4415,9 @@ static void sculpt_update_brush_delta(UnifiedPaintSettings *ups, Object *ob, Bru
add_v3_v3(cache->true_location, cache->grab_delta);
}
- /* Compute 3d coordinate at same z from original location + mouse. */
+ /* Compute 3d coordinate at same z from original location + mval. */
mul_v3_m4v3(loc, ob->obmat, cache->orig_grab_location);
- ED_view3d_win_to_3d(cache->vc->v3d, cache->vc->region, loc, mouse, grab_location);
+ ED_view3d_win_to_3d(cache->vc->v3d, cache->vc->region, loc, mval, grab_location);
/* Compute delta to move verts by. */
if (!SCULPT_stroke_is_first_brush_step_of_symmetry_pass(ss->cache)) {
@@ -4744,7 +4785,7 @@ static void sculpt_find_nearest_to_ray_cb(PBVHNode *node, void *data_v, float *t
}
float SCULPT_raycast_init(ViewContext *vc,
- const float mouse[2],
+ const float mval[2],
float ray_start[3],
float ray_end[3],
float ray_normal[3],
@@ -4758,7 +4799,7 @@ float SCULPT_raycast_init(ViewContext *vc,
/* TODO: what if the segment is totally clipped? (return == 0). */
ED_view3d_win_to_segment_clipped(
- vc->depsgraph, vc->region, vc->v3d, mouse, ray_start, ray_end, true);
+ vc->depsgraph, vc->region, vc->v3d, mval, ray_start, ray_end, true);
invert_m4_m4(obimat, ob->obmat);
mul_m4_v3(obimat, ray_start);
@@ -4782,7 +4823,7 @@ float SCULPT_raycast_init(ViewContext *vc,
bool SCULPT_cursor_geometry_info_update(bContext *C,
SculptCursorGeometryInfo *out,
- const float mouse[2],
+ const float mval[2],
bool use_sampled_normal)
{
Depsgraph *depsgraph = CTX_data_depsgraph_pointer(C);
@@ -4811,7 +4852,7 @@ bool SCULPT_cursor_geometry_info_update(bContext *C,
}
/* PBVH raycast to get active vertex and face normal. */
- depth = SCULPT_raycast_init(&vc, mouse, ray_start, ray_end, ray_normal, original);
+ depth = SCULPT_raycast_init(&vc, mval, ray_start, ray_end, ray_normal, original);
SCULPT_stroke_modifiers_check(C, ob, brush);
SculptRaycastData srd = {
@@ -4909,7 +4950,7 @@ bool SCULPT_cursor_geometry_info_update(bContext *C,
return true;
}
-bool SCULPT_stroke_get_location(bContext *C, float out[3], const float mouse[2])
+bool SCULPT_stroke_get_location(bContext *C, float out[3], const float mval[2])
{
Depsgraph *depsgraph = CTX_data_depsgraph_pointer(C);
Object *ob;
@@ -4931,7 +4972,7 @@ bool SCULPT_stroke_get_location(bContext *C, float out[3], const float mouse[2])
SCULPT_stroke_modifiers_check(C, ob, brush);
- depth = SCULPT_raycast_init(&vc, mouse, ray_start, ray_end, ray_normal, original);
+ depth = SCULPT_raycast_init(&vc, mval, ray_start, ray_end, ray_normal, original);
if (BKE_pbvh_type(ss->pbvh) == PBVH_BMESH) {
BM_mesh_elem_table_ensure(ss->bm, BM_VERT);
@@ -5236,14 +5277,10 @@ void SCULPT_flush_update_done(const bContext *C, Object *ob, SculptUpdateType up
/* Returns whether the mouse/stylus is over the mesh (1)
* or over the background (0). */
-static bool over_mesh(bContext *C, struct wmOperator *UNUSED(op), float x, float y)
+static bool over_mesh(bContext *C, struct wmOperator *UNUSED(op), const float mval[2])
{
- float mouse[2], co[3];
-
- mouse[0] = x;
- mouse[1] = y;
-
- return SCULPT_stroke_get_location(C, co, mouse);
+ float co_dummy[3];
+ return SCULPT_stroke_get_location(C, co_dummy, mval);
}
bool SCULPT_handles_colors_report(SculptSession *ss, ReportList *reports)
@@ -5264,36 +5301,44 @@ bool SCULPT_handles_colors_report(SculptSession *ss, ReportList *reports)
return false;
}
-static bool sculpt_stroke_test_start(bContext *C, struct wmOperator *op, const float mouse[2])
+static bool sculpt_stroke_test_start(bContext *C, struct wmOperator *op, const float mval[2])
{
- /* Don't start the stroke until mouse goes over the mesh.
- * NOTE: mouse will only be null when re-executing the saved stroke.
- * We have exception for 'exec' strokes since they may not set 'mouse',
+ /* Don't start the stroke until `mval` goes over the mesh.
+ * NOTE: `mval` will only be null when re-executing the saved stroke.
+ * We have exception for 'exec' strokes since they may not set `mval`,
* only 'location', see: T52195. */
- if (((op->flag & OP_IS_INVOKE) == 0) || (mouse == NULL) ||
- over_mesh(C, op, mouse[0], mouse[1])) {
+ if (((op->flag & OP_IS_INVOKE) == 0) || (mval == NULL) || over_mesh(C, op, mval)) {
Object *ob = CTX_data_active_object(C);
SculptSession *ss = ob->sculpt;
Sculpt *sd = CTX_data_tool_settings(C)->sculpt;
Brush *brush = BKE_paint_brush(&sd->paint);
+ ToolSettings *tool_settings = CTX_data_tool_settings(C);
/* NOTE: This should be removed when paint mode is available. Paint mode can force based on the
* canvas it is painting on. (ref. use_sculpt_texture_paint). */
if (brush && SCULPT_TOOL_NEEDS_COLOR(brush->sculpt_tool)) {
View3D *v3d = CTX_wm_view3d(C);
- if (v3d) {
+ if (v3d->shading.type == OB_SOLID) {
v3d->shading.color_type = V3D_SHADING_VERTEX_COLOR;
}
}
ED_view3d_init_mats_rv3d(ob, CTX_wm_region_view3d(C));
- sculpt_update_cache_invariants(C, sd, ss, op, mouse);
+ sculpt_update_cache_invariants(C, sd, ss, op, mval);
SculptCursorGeometryInfo sgi;
- SCULPT_cursor_geometry_info_update(C, &sgi, mouse, false);
+ SCULPT_cursor_geometry_info_update(C, &sgi, mval, false);
- SCULPT_undo_push_begin(ob, sculpt_tool_name(sd));
+ /* Setup the correct undo system. Image painting and sculpting are mutual exclusive.
+ * Color attributes are part of the sculpting undo system. */
+ if (brush && brush->sculpt_tool == SCULPT_TOOL_PAINT &&
+ SCULPT_use_image_paint_brush(&tool_settings->paint_mode, ob)) {
+ ED_image_undo_push_begin(op->type->name, PAINT_MODE_SCULPT);
+ }
+ else {
+ SCULPT_undo_push_begin(ob, sculpt_tool_name(sd));
+ }
return true;
}
@@ -5420,7 +5465,13 @@ static void sculpt_stroke_done(const bContext *C, struct PaintStroke *UNUSED(str
SCULPT_cache_free(ss->cache);
ss->cache = NULL;
- SCULPT_undo_push_end(ob);
+ if (brush && brush->sculpt_tool == SCULPT_TOOL_PAINT &&
+ SCULPT_use_image_paint_brush(&tool_settings->paint_mode, ob)) {
+ ED_image_undo_push_end();
+ }
+ else {
+ SCULPT_undo_push_end(ob);
+ }
if (brush->sculpt_tool == SCULPT_TOOL_MASK) {
SCULPT_flush_update_done(C, ob, SCULPT_UPDATE_MASK);
@@ -5469,7 +5520,7 @@ static int sculpt_brush_stroke_invoke(bContext *C, wmOperator *op, const wmEvent
/* For tablet rotation. */
ignore_background_click = RNA_boolean_get(op->ptr, "ignore_background_click");
- if (ignore_background_click && !over_mesh(C, op, event->xy[0], event->xy[1])) {
+ if (ignore_background_click && !over_mesh(C, op, (const float[2]){UNPACK2(event->mval)})) {
paint_stroke_free(C, op, op->customdata);
return OPERATOR_PASS_THROUGH;
}
@@ -5729,7 +5780,8 @@ void SCULPT_connected_components_ensure(Object *ob)
{
SculptSession *ss = ob->sculpt;
- /* Topology IDs already initialized. They only need to be recalculated when the PBVH is rebuild.
+ /* Topology IDs already initialized. They only need to be recalculated when the PBVH is
+ * rebuild.
*/
if (ss->vertex_info.connected_component) {
return;
@@ -5793,7 +5845,8 @@ void SCULPT_fake_neighbors_ensure(Sculpt *sd, Object *ob, const float max_dist)
SculptSession *ss = ob->sculpt;
const int totvert = SCULPT_vertex_count_get(ss);
- /* Fake neighbors were already initialized with the same distance, so no need to be recalculated.
+ /* Fake neighbors were already initialized with the same distance, so no need to be
+ * recalculated.
*/
if (ss->fake_neighbors.fake_neighbor_index &&
ss->fake_neighbors.current_max_distance == max_dist) {
diff --git a/source/blender/editors/sculpt_paint/sculpt_automasking.c b/source/blender/editors/sculpt_paint/sculpt_automasking.cc
index d7a2a18504c..bb101717c9b 100644
--- a/source/blender/editors/sculpt_paint/sculpt_automasking.c
+++ b/source/blender/editors/sculpt_paint/sculpt_automasking.cc
@@ -9,6 +9,7 @@
#include "BLI_blenlib.h"
#include "BLI_hash.h"
+#include "BLI_index_range.hh"
#include "BLI_math.h"
#include "BLI_task.h"
@@ -43,8 +44,10 @@
#include "bmesh.h"
-#include <math.h>
-#include <stdlib.h>
+#include <cmath>
+#include <cstdlib>
+
+using blender::IndexRange;
AutomaskingCache *SCULPT_automasking_active_cache_get(SculptSession *ss)
{
@@ -54,7 +57,7 @@ AutomaskingCache *SCULPT_automasking_active_cache_get(SculptSession *ss)
if (ss->filter_cache) {
return ss->filter_cache->automasking;
}
- return NULL;
+ return nullptr;
}
bool SCULPT_is_automasking_mode_enabled(const Sculpt *sd,
@@ -167,18 +170,18 @@ static bool sculpt_automasking_is_constrained_by_radius(Brush *br)
return false;
}
-typedef struct AutomaskFloodFillData {
+struct AutomaskFloodFillData {
float *automask_factor;
float radius;
bool use_radius;
float location[3];
char symm;
-} AutomaskFloodFillData;
+};
static bool automask_floodfill_cb(
SculptSession *ss, int from_v, int to_v, bool UNUSED(is_duplicate), void *userdata)
{
- AutomaskFloodFillData *data = userdata;
+ AutomaskFloodFillData *data = (AutomaskFloodFillData *)userdata;
data->automask_factor[to_v] = 1.0f;
data->automask_factor[from_v] = 1.0f;
@@ -194,11 +197,11 @@ static float *SCULPT_topology_automasking_init(Sculpt *sd, Object *ob, float *au
if (BKE_pbvh_type(ss->pbvh) == PBVH_FACES && !ss->pmap) {
BLI_assert_msg(0, "Topology masking: pmap missing");
- return NULL;
+ return nullptr;
}
const int totvert = SCULPT_vertex_count_get(ss);
- for (int i = 0; i < totvert; i++) {
+ for (int i : IndexRange(totvert)) {
automask_factor[i] = 0.0f;
}
@@ -209,12 +212,13 @@ static float *SCULPT_topology_automasking_init(Sculpt *sd, Object *ob, float *au
const float radius = ss->cache ? ss->cache->radius : FLT_MAX;
SCULPT_floodfill_add_active(sd, ob, ss, &flood, radius);
- AutomaskFloodFillData fdata = {
- .automask_factor = automask_factor,
- .radius = radius,
- .use_radius = ss->cache && sculpt_automasking_is_constrained_by_radius(brush),
- .symm = SCULPT_mesh_symmetry_xyz_get(ob),
- };
+ AutomaskFloodFillData fdata = {nullptr};
+
+ fdata.automask_factor = automask_factor;
+ fdata.radius = radius;
+ fdata.use_radius = ss->cache && sculpt_automasking_is_constrained_by_radius(brush);
+ fdata.symm = SCULPT_mesh_symmetry_xyz_get(ob);
+
copy_v3_v3(fdata.location, SCULPT_active_vertex_co_get(ss));
SCULPT_floodfill_execute(ss, &flood, automask_floodfill_cb, &fdata);
SCULPT_floodfill_free(&flood);
@@ -228,17 +232,17 @@ static float *sculpt_face_sets_automasking_init(Sculpt *sd, Object *ob, float *a
Brush *brush = BKE_paint_brush(&sd->paint);
if (!SCULPT_is_automasking_enabled(sd, ss, brush)) {
- return NULL;
+ return nullptr;
}
if (BKE_pbvh_type(ss->pbvh) == PBVH_FACES && !ss->pmap) {
BLI_assert_msg(0, "Face Sets automasking: pmap missing");
- return NULL;
+ return nullptr;
}
int tot_vert = SCULPT_vertex_count_get(ss);
int active_face_set = SCULPT_active_face_set_get(ss);
- for (int i = 0; i < tot_vert; i++) {
+ for (int i : IndexRange(tot_vert)) {
if (!SCULPT_vertex_has_face_set(ss, i, active_face_set)) {
automask_factor[i] *= 0.0f;
}
@@ -258,13 +262,13 @@ float *SCULPT_boundary_automasking_init(Object *ob,
if (!ss->pmap) {
BLI_assert_msg(0, "Boundary Edges masking: pmap missing");
- return NULL;
+ return nullptr;
}
const int totvert = SCULPT_vertex_count_get(ss);
- int *edge_distance = MEM_callocN(sizeof(int) * totvert, "automask_factor");
+ int *edge_distance = (int *)MEM_callocN(sizeof(int) * totvert, "automask_factor");
- for (int i = 0; i < totvert; i++) {
+ for (int i : IndexRange(totvert)) {
edge_distance[i] = EDGE_DISTANCE_INF;
switch (mode) {
case AUTOMASK_INIT_BOUNDARY_EDGES:
@@ -280,8 +284,8 @@ float *SCULPT_boundary_automasking_init(Object *ob,
}
}
- for (int propagation_it = 0; propagation_it < propagation_steps; propagation_it++) {
- for (int i = 0; i < totvert; i++) {
+ for (int propagation_it : IndexRange(propagation_steps)) {
+ for (int i : IndexRange(totvert)) {
if (edge_distance[i] != EDGE_DISTANCE_INF) {
continue;
}
@@ -295,7 +299,7 @@ float *SCULPT_boundary_automasking_init(Object *ob,
}
}
- for (int i = 0; i < totvert; i++) {
+ for (int i : IndexRange(totvert)) {
if (edge_distance[i] == EDGE_DISTANCE_INF) {
continue;
}
@@ -323,10 +327,11 @@ AutomaskingCache *SCULPT_automasking_cache_init(Sculpt *sd, Brush *brush, Object
const int totvert = SCULPT_vertex_count_get(ss);
if (!SCULPT_is_automasking_enabled(sd, ss, brush)) {
- return NULL;
+ return nullptr;
}
- AutomaskingCache *automasking = MEM_callocN(sizeof(AutomaskingCache), "automasking cache");
+ AutomaskingCache *automasking = (AutomaskingCache *)MEM_callocN(sizeof(AutomaskingCache),
+ "automasking cache");
SCULPT_automasking_cache_settings_update(automasking, ss, sd, brush);
SCULPT_boundary_info_ensure(ob);
@@ -334,8 +339,8 @@ AutomaskingCache *SCULPT_automasking_cache_init(Sculpt *sd, Brush *brush, Object
return automasking;
}
- automasking->factor = MEM_malloc_arrayN(totvert, sizeof(float), "automask_factor");
- for (int i = 0; i < totvert; i++) {
+ automasking->factor = (float *)MEM_malloc_arrayN(totvert, sizeof(float), "automask_factor");
+ for (int i : IndexRange(totvert)) {
automasking->factor[i] = 1.0f;
}
diff --git a/source/blender/editors/sculpt_paint/sculpt_cloth.c b/source/blender/editors/sculpt_paint/sculpt_cloth.c
index dcf90f9e819..9d231f2ccd2 100644
--- a/source/blender/editors/sculpt_paint/sculpt_cloth.c
+++ b/source/blender/editors/sculpt_paint/sculpt_cloth.c
@@ -1553,11 +1553,9 @@ static int sculpt_cloth_filter_invoke(bContext *C, wmOperator *op, const wmEvent
const eSculptClothFilterType filter_type = RNA_enum_get(op->ptr, "type");
/* Update the active vertex */
- float mouse[2];
+ float mval_fl[2] = {UNPACK2(event->mval)};
SculptCursorGeometryInfo sgi;
- mouse[0] = event->mval[0];
- mouse[1] = event->mval[1];
- SCULPT_cursor_geometry_info_update(C, &sgi, mouse, false);
+ SCULPT_cursor_geometry_info_update(C, &sgi, mval_fl, false);
SCULPT_vertex_random_access_ensure(ss);
diff --git a/source/blender/editors/sculpt_paint/sculpt_detail.c b/source/blender/editors/sculpt_paint/sculpt_detail.c
index fe69cf6b84f..00503087e39 100644
--- a/source/blender/editors/sculpt_paint/sculpt_detail.c
+++ b/source/blender/editors/sculpt_paint/sculpt_detail.c
@@ -158,7 +158,7 @@ static EnumPropertyItem prop_sculpt_sample_detail_mode_types[] = {
{0, NULL, 0, NULL, NULL},
};
-static void sample_detail_voxel(bContext *C, ViewContext *vc, int mx, int my)
+static void sample_detail_voxel(bContext *C, ViewContext *vc, const int mval[2])
{
Depsgraph *depsgraph = CTX_data_depsgraph_pointer(C);
Object *ob = vc->obact;
@@ -169,8 +169,8 @@ static void sample_detail_voxel(bContext *C, ViewContext *vc, int mx, int my)
SCULPT_vertex_random_access_ensure(ss);
/* Update the active vertex. */
- const float mouse[2] = {mx, my};
- SCULPT_cursor_geometry_info_update(C, &sgi, mouse, false);
+ const float mval_fl[2] = {UNPACK2(mval)};
+ SCULPT_cursor_geometry_info_update(C, &sgi, mval_fl, false);
BKE_sculpt_update_object_for_edit(depsgraph, ob, true, false, false);
/* Average the edge length of the connected edges to the active vertex. */
@@ -201,7 +201,7 @@ static void sculpt_raycast_detail_cb(PBVHNode *node, void *data_v, float *tmin)
}
}
-static void sample_detail_dyntopo(bContext *C, ViewContext *vc, ARegion *region, int mx, int my)
+static void sample_detail_dyntopo(bContext *C, ViewContext *vc, const int mval[2])
{
Sculpt *sd = CTX_data_tool_settings(C)->sculpt;
Object *ob = vc->obact;
@@ -209,9 +209,9 @@ static void sample_detail_dyntopo(bContext *C, ViewContext *vc, ARegion *region,
SCULPT_stroke_modifiers_check(C, ob, brush);
- const float mouse[2] = {mx - region->winrct.xmin, my - region->winrct.ymin};
+ const float mval_fl[2] = {UNPACK2(mval)};
float ray_start[3], ray_end[3], ray_normal[3];
- float depth = SCULPT_raycast_init(vc, mouse, ray_start, ray_end, ray_normal, false);
+ float depth = SCULPT_raycast_init(vc, mval_fl, ray_start, ray_end, ray_normal, false);
SculptDetailRaycastData srd;
srd.hit = 0;
@@ -228,14 +228,12 @@ static void sample_detail_dyntopo(bContext *C, ViewContext *vc, ARegion *region,
}
}
-static int sample_detail(bContext *C, int mx, int my, int mode)
+static int sample_detail(bContext *C, const int event_xy[2], int mode)
{
/* Find 3D view to pick from. */
bScreen *screen = CTX_wm_screen(C);
- 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;
+ ScrArea *area = BKE_screen_find_area_xy(screen, SPACE_VIEW3D, event_xy);
+ ARegion *region = (area) ? BKE_area_find_region_xy(area, RGN_TYPE_WINDOW, event_xy) : NULL;
if (region == NULL) {
return OPERATOR_CANCELLED;
}
@@ -260,6 +258,11 @@ static int sample_detail(bContext *C, int mx, int my, int mode)
return OPERATOR_CANCELLED;
}
+ const int mval[2] = {
+ event_xy[0] - region->winrct.xmin,
+ event_xy[1] - region->winrct.ymin,
+ };
+
/* Pick sample detail. */
switch (mode) {
case SAMPLE_DETAIL_DYNTOPO:
@@ -268,7 +271,7 @@ static int sample_detail(bContext *C, int mx, int my, int mode)
CTX_wm_region_set(C, prev_region);
return OPERATOR_CANCELLED;
}
- sample_detail_dyntopo(C, &vc, region, mx, my);
+ sample_detail_dyntopo(C, &vc, mval);
break;
case SAMPLE_DETAIL_VOXEL:
if (BKE_pbvh_type(ss->pbvh) != PBVH_FACES) {
@@ -276,7 +279,7 @@ static int sample_detail(bContext *C, int mx, int my, int mode)
CTX_wm_region_set(C, prev_region);
return OPERATOR_CANCELLED;
}
- sample_detail_voxel(C, &vc, mx, my);
+ sample_detail_voxel(C, &vc, mval);
break;
}
@@ -292,7 +295,7 @@ static int sculpt_sample_detail_size_exec(bContext *C, wmOperator *op)
int ss_co[2];
RNA_int_get_array(op->ptr, "location", ss_co);
int mode = RNA_enum_get(op->ptr, "mode");
- return sample_detail(C, ss_co[0], ss_co[1], mode);
+ return sample_detail(C, ss_co, mode);
}
static int sculpt_sample_detail_size_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(e))
@@ -308,12 +311,10 @@ static int sculpt_sample_detail_size_modal(bContext *C, wmOperator *op, const wm
switch (event->type) {
case LEFTMOUSE:
if (event->val == KM_PRESS) {
- const int ss_co[2] = {event->xy[0], event->xy[1]};
-
int mode = RNA_enum_get(op->ptr, "mode");
- sample_detail(C, ss_co[0], ss_co[1], mode);
+ sample_detail(C, event->xy, mode);
- RNA_int_set_array(op->ptr, "location", ss_co);
+ RNA_int_set_array(op->ptr, "location", event->xy);
WM_cursor_modal_restore(CTX_wm_window(C));
ED_workspace_status_text(C, NULL);
WM_main_add_notifier(NC_SCENE | ND_TOOLSETTINGS, NULL);
@@ -657,11 +658,13 @@ static int dyntopo_detail_size_edit_modal(bContext *C, wmOperator *op, const wmE
ED_region_tag_redraw(region);
- if (event->type == EVT_LEFTCTRLKEY && event->val == KM_PRESS) {
- cd->sample_mode = true;
- }
- if (event->type == EVT_LEFTCTRLKEY && event->val == KM_RELEASE) {
- cd->sample_mode = false;
+ if (ELEM(event->type, EVT_LEFTCTRLKEY, EVT_RIGHTCTRLKEY)) {
+ if (event->val == KM_PRESS) {
+ cd->sample_mode = true;
+ }
+ else if (event->val == KM_RELEASE) {
+ cd->sample_mode = false;
+ }
}
/* Sample mode sets the detail size sampling the average edge length under the surface. */
diff --git a/source/blender/editors/sculpt_paint/sculpt_expand.c b/source/blender/editors/sculpt_paint/sculpt_expand.c
index 46940b619e6..fbf988d63e8 100644
--- a/source/blender/editors/sculpt_paint/sculpt_expand.c
+++ b/source/blender/editors/sculpt_paint/sculpt_expand.c
@@ -1450,13 +1450,11 @@ static void sculpt_expand_update_for_vertex(bContext *C, Object *ob, const int v
* Updates the #SculptSession cursor data and gets the active vertex
* if the cursor is over the mesh.
*/
-static int sculpt_expand_target_vertex_update_and_get(bContext *C,
- Object *ob,
- const float mouse[2])
+static int sculpt_expand_target_vertex_update_and_get(bContext *C, Object *ob, const float mval[2])
{
SculptSession *ss = ob->sculpt;
SculptCursorGeometryInfo sgi;
- if (SCULPT_cursor_geometry_info_update(C, &sgi, mouse, false)) {
+ if (SCULPT_cursor_geometry_info_update(C, &sgi, mval, false)) {
return SCULPT_active_vertex_get(ss);
}
return SCULPT_EXPAND_VERTEX_NONE;
@@ -1588,16 +1586,16 @@ static void sculpt_expand_find_active_connected_components_from_vert(Object *ob,
static void sculpt_expand_set_initial_components_for_mouse(bContext *C,
Object *ob,
ExpandCache *expand_cache,
- const float mouse[2])
+ const float mval[2])
{
SculptSession *ss = ob->sculpt;
- int initial_vertex = sculpt_expand_target_vertex_update_and_get(C, ob, mouse);
+ int initial_vertex = sculpt_expand_target_vertex_update_and_get(C, ob, mval);
if (initial_vertex == SCULPT_EXPAND_VERTEX_NONE) {
/* Cursor not over the mesh, for creating valid initial falloffs, fallback to the last active
* vertex in the sculpt session. */
initial_vertex = SCULPT_active_vertex_get(ss);
}
- copy_v2_v2(ss->expand_cache->initial_mouse, mouse);
+ copy_v2_v2(ss->expand_cache->initial_mouse, mval);
expand_cache->initial_active_vertex = initial_vertex;
expand_cache->initial_active_face_set = SCULPT_active_face_set_get(ss);
@@ -1629,14 +1627,14 @@ static void sculpt_expand_move_propagation_origin(bContext *C,
{
Sculpt *sd = CTX_data_tool_settings(C)->sculpt;
- const float mouse[2] = {event->mval[0], event->mval[1]};
+ const float mval_fl[2] = {UNPACK2(event->mval)};
float move_disp[2];
- sub_v2_v2v2(move_disp, mouse, expand_cache->initial_mouse_move);
+ sub_v2_v2v2(move_disp, mval_fl, expand_cache->initial_mouse_move);
- float new_mouse[2];
- add_v2_v2v2(new_mouse, move_disp, expand_cache->original_mouse_move);
+ float new_mval[2];
+ add_v2_v2v2(new_mval, move_disp, expand_cache->original_mouse_move);
- sculpt_expand_set_initial_components_for_mouse(C, ob, expand_cache, new_mouse);
+ sculpt_expand_set_initial_components_for_mouse(C, ob, expand_cache, new_mval);
sculpt_expand_falloff_factors_from_vertex_and_symm_create(
expand_cache,
sd,
@@ -1697,8 +1695,8 @@ static int sculpt_expand_modal(bContext *C, wmOperator *op, const wmEvent *event
sculpt_expand_ensure_sculptsession_data(ob);
/* Update and get the active vertex (and face) from the cursor. */
- const float mouse[2] = {event->mval[0], event->mval[1]};
- const int target_expand_vertex = sculpt_expand_target_vertex_update_and_get(C, ob, mouse);
+ const float mval_fl[2] = {UNPACK2(event->mval)};
+ const int target_expand_vertex = sculpt_expand_target_vertex_update_and_get(C, ob, mval_fl);
/* Handle the modal keymap state changes. */
ExpandCache *expand_cache = ss->expand_cache;
@@ -1756,7 +1754,7 @@ static int sculpt_expand_modal(bContext *C, wmOperator *op, const wmEvent *event
}
expand_cache->move = true;
expand_cache->move_original_falloff_type = expand_cache->falloff_type;
- copy_v2_v2(expand_cache->initial_mouse_move, mouse);
+ copy_v2_v2(expand_cache->initial_mouse_move, mval_fl);
copy_v2_v2(expand_cache->original_mouse_move, expand_cache->initial_mouse);
if (expand_cache->falloff_type == SCULPT_EXPAND_FALLOFF_GEODESIC &&
SCULPT_vertex_count_get(ss) > expand_cache->max_geodesic_move_preview) {
@@ -2001,7 +1999,7 @@ static void sculpt_expand_cache_initial_config_set(bContext *C,
BKE_curvemapping_init(expand_cache->brush->curve);
copy_v4_fl(expand_cache->fill_color, 1.0f);
copy_v3_v3(expand_cache->fill_color, BKE_brush_color_get(ss->scene, expand_cache->brush));
- IMB_colormanagement_srgb_to_scene_linear_v3(expand_cache->fill_color);
+ IMB_colormanagement_srgb_to_scene_linear_v3(expand_cache->fill_color, expand_cache->fill_color);
expand_cache->scene = CTX_data_scene(C);
expand_cache->mtex = &expand_cache->brush->mtex;
diff --git a/source/blender/editors/sculpt_paint/sculpt_face_set.c b/source/blender/editors/sculpt_paint/sculpt_face_set.c
index 7171c241534..ce704e619ea 100644
--- a/source/blender/editors/sculpt_paint/sculpt_face_set.c
+++ b/source/blender/editors/sculpt_paint/sculpt_face_set.c
@@ -60,7 +60,7 @@
int ED_sculpt_face_sets_find_next_available_id(struct Mesh *mesh)
{
- int *face_sets = CustomData_get_layer(&mesh->pdata, CD_SCULPT_FACE_SETS);
+ const int *face_sets = CustomData_get_layer(&mesh->pdata, CD_SCULPT_FACE_SETS);
if (!face_sets) {
return SCULPT_FACE_SET_NONE;
}
@@ -150,25 +150,22 @@ static void do_draw_face_sets_brush_task_cb_ex(void *__restrict userdata,
}
}
}
-
else if (BKE_pbvh_type(ss->pbvh) == PBVH_GRIDS) {
- {
- 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);
-
- if (fade > 0.05f) {
- SCULPT_vertex_face_set_set(ss, vd.index, ss->cache->paint_face_set);
- }
+ 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);
+
+ if (fade > 0.05f) {
+ SCULPT_vertex_face_set_set(ss, vd.index, ss->cache->paint_face_set);
}
}
}
@@ -952,11 +949,9 @@ static int sculpt_face_sets_change_visibility_invoke(bContext *C,
/* Update the active vertex and Face Set using the cursor position to avoid relying on the paint
* cursor updates. */
SculptCursorGeometryInfo sgi;
- float mouse[2];
- mouse[0] = event->mval[0];
- mouse[1] = event->mval[1];
+ const float mval_fl[2] = {UNPACK2(event->mval)};
SCULPT_vertex_random_access_ensure(ss);
- SCULPT_cursor_geometry_info_update(C, &sgi, mouse, false);
+ SCULPT_cursor_geometry_info_update(C, &sgi, mval_fl, false);
return sculpt_face_sets_change_visibility_exec(C, op);
}
@@ -1404,8 +1399,8 @@ static int sculpt_face_set_edit_invoke(bContext *C, wmOperator *op, const wmEven
/* Update the current active Face Set and Vertex as the operator can be used directly from the
* tool without brush cursor. */
SculptCursorGeometryInfo sgi;
- const float mouse[2] = {event->mval[0], event->mval[1]};
- if (!SCULPT_cursor_geometry_info_update(C, &sgi, mouse, false)) {
+ const float mval_fl[2] = {UNPACK2(event->mval)};
+ if (!SCULPT_cursor_geometry_info_update(C, &sgi, mval_fl, false)) {
/* The cursor is not over the mesh. Cancel to avoid editing the last updated Face Set ID. */
return OPERATOR_CANCELLED;
}
diff --git a/source/blender/editors/sculpt_paint/sculpt_filter_color.c b/source/blender/editors/sculpt_paint/sculpt_filter_color.c
index 09f13ff110d..95c01d24c6d 100644
--- a/source/blender/editors/sculpt_paint/sculpt_filter_color.c
+++ b/source/blender/editors/sculpt_paint/sculpt_filter_color.c
@@ -124,8 +124,8 @@ static void color_filter_task_cb(void *__restrict userdata,
}
case COLOR_FILTER_HUE:
rgb_to_hsv_v(orig_color, hsv_color);
- hue = hsv_color[0] + fade;
- hsv_color[0] = fabs((hsv_color[0] + fade) - hue);
+ hue = hsv_color[0];
+ hsv_color[0] = fmod((hsv_color[0] + fabs(fade)) - hue, 1);
hsv_to_rgb_v(hsv_color, final_color);
break;
case COLOR_FILTER_SATURATION:
@@ -298,7 +298,7 @@ static int sculpt_color_filter_modal(bContext *C, wmOperator *op, const wmEvent
float fill_color[3];
RNA_float_get_array(op->ptr, "fill_color", fill_color);
- IMB_colormanagement_srgb_to_scene_linear_v3(fill_color);
+ IMB_colormanagement_srgb_to_scene_linear_v3(fill_color, fill_color);
if (filter_strength < 0.0 && !ss->filter_cache->pre_smoothed_color) {
sculpt_color_presmooth_init(ss);
@@ -328,18 +328,20 @@ static int sculpt_color_filter_invoke(bContext *C, wmOperator *op, const wmEvent
{
Object *ob = CTX_data_active_object(C);
Sculpt *sd = CTX_data_tool_settings(C)->sculpt;
+ View3D *v3d = CTX_wm_view3d(C);
SculptSession *ss = ob->sculpt;
PBVH *pbvh = ob->sculpt->pbvh;
+ if (v3d->shading.type == OB_SOLID) {
+ v3d->shading.color_type = V3D_SHADING_VERTEX_COLOR;
+ }
const bool use_automasking = SCULPT_is_automasking_enabled(sd, ss, NULL);
if (use_automasking) {
/* Update the active face set manually as the paint cursor is not enabled when using the Mesh
* Filter Tool. */
- float mouse[2];
+ float mval_fl[2] = {UNPACK2(event->mval)};
SculptCursorGeometryInfo sgi;
- mouse[0] = event->mval[0];
- mouse[1] = event->mval[1];
- SCULPT_cursor_geometry_info_update(C, &sgi, mouse, false);
+ SCULPT_cursor_geometry_info_update(C, &sgi, mval_fl, false);
}
/* Disable for multires and dyntopo for now */
@@ -374,7 +376,7 @@ void SCULPT_OT_color_filter(struct wmOperatorType *ot)
/* identifiers */
ot->name = "Filter Color";
ot->idname = "SCULPT_OT_color_filter";
- ot->description = "Applies a filter to modify the current sculpt vertex colors";
+ ot->description = "Applies a filter to modify the active color attribute";
/* api callbacks */
ot->invoke = sculpt_color_filter_invoke;
diff --git a/source/blender/editors/sculpt_paint/sculpt_filter_mesh.c b/source/blender/editors/sculpt_paint/sculpt_filter_mesh.c
index a32b1c3015b..dbed5624adf 100644
--- a/source/blender/editors/sculpt_paint/sculpt_filter_mesh.c
+++ b/source/blender/editors/sculpt_paint/sculpt_filter_mesh.c
@@ -675,11 +675,9 @@ static int sculpt_mesh_filter_invoke(bContext *C, wmOperator *op, const wmEvent
if (use_automasking) {
/* Update the active face set manually as the paint cursor is not enabled when using the Mesh
* Filter Tool. */
- float mouse[2];
+ float mval_fl[2] = {UNPACK2(event->mval)};
SculptCursorGeometryInfo sgi;
- mouse[0] = event->mval[0];
- mouse[1] = event->mval[1];
- SCULPT_cursor_geometry_info_update(C, &sgi, mouse, false);
+ SCULPT_cursor_geometry_info_update(C, &sgi, mval_fl, false);
}
SCULPT_vertex_random_access_ensure(ss);
diff --git a/source/blender/editors/sculpt_paint/sculpt_intern.h b/source/blender/editors/sculpt_paint/sculpt_intern.h
index f9633c91087..0693b445fe5 100644
--- a/source/blender/editors/sculpt_paint/sculpt_intern.h
+++ b/source/blender/editors/sculpt_paint/sculpt_intern.h
@@ -247,6 +247,10 @@ typedef struct SculptThreadedTaskData {
float (*mat)[4];
float (*vertCos)[3];
+ /* When true, the displacement stored in the proxies will be aplied to the original coordinates
+ * instead of to the current coordinates. */
+ bool use_proxies_orco;
+
/* X and Z vectors aligned to the stroke direction for operations where perpendicular vectors to
* the stroke direction are needed. */
float (*stroke_xz)[3];
@@ -290,6 +294,10 @@ typedef struct SculptThreadedTaskData {
bool mask_expand_create_face_set;
float transform_mats[8][4][4];
+ float elastic_transform_mat[4][4];
+ float elastic_transform_pivot[3];
+ float elastic_transform_pivot_init[3];
+ float elastic_transform_radius;
/* Boundary brush */
float boundary_deform_strength;
@@ -372,6 +380,14 @@ typedef enum SculptFilterOrientation {
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;
+
#define SCULPT_CLAY_STABILIZER_LEN 10
typedef struct AutomaskingSettings {
@@ -440,6 +456,8 @@ typedef struct FilterCache {
int active_face_set;
+ SculptTransformDisplacementMode transform_displacement_mode;
+
/* Auto-masking. */
AutomaskingCache *automasking;
@@ -1137,12 +1155,15 @@ bool SCULPT_search_sphere_cb(PBVHNode *node, void *data_v);
*/
bool SCULPT_search_circle_cb(PBVHNode *node, void *data_v);
+void SCULPT_combine_transform_proxies(Sculpt *sd, Object *ob);
+
/**
* 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);
@@ -1652,11 +1673,11 @@ void SCULPT_do_paint_brush(struct PaintModeSettings *paint_mode_settings,
int totnode) ATTR_NONNULL();
/**
- * @brief Get the image canvas for painting on the given object.
+ * \brief Get the image canvas for painting on the given object.
*
- * @return #true if an image is found. The #r_image and #r_image_user fields are filled with the
+ * \return #true if an image is found. The #r_image and #r_image_user fields are filled with the
* image and image user. Returns false when the image isn't found. In the later case the r_image
- * and r_image_user are set to nullptr/NULL.
+ * and r_image_user are set to NULL.
*/
bool SCULPT_paint_image_canvas_get(struct PaintModeSettings *paint_mode_settings,
struct Object *ob,
diff --git a/source/blender/editors/sculpt_paint/sculpt_mask_expand.c b/source/blender/editors/sculpt_paint/sculpt_mask_expand.c
index 201e02b8235..4593c6a8b60 100644
--- a/source/blender/editors/sculpt_paint/sculpt_mask_expand.c
+++ b/source/blender/editors/sculpt_paint/sculpt_mask_expand.c
@@ -167,10 +167,8 @@ static int sculpt_mask_expand_modal(bContext *C, wmOperator *op, const wmEvent *
if (RNA_boolean_get(op->ptr, "use_cursor")) {
SculptCursorGeometryInfo sgi;
- float mouse[2];
- mouse[0] = event->mval[0];
- mouse[1] = event->mval[1];
- if (SCULPT_cursor_geometry_info_update(C, &sgi, mouse, false)) {
+ const float mval_fl[2] = {UNPACK2(event->mval)};
+ if (SCULPT_cursor_geometry_info_update(C, &sgi, mval_fl, false)) {
/* The cursor is over the mesh, get the update iteration from the updated active vertex. */
mask_expand_update_it = ss->filter_cache->mask_update_it[(int)SCULPT_active_vertex_get(ss)];
}
@@ -340,16 +338,14 @@ static int sculpt_mask_expand_invoke(bContext *C, wmOperator *op, const wmEvent
const bool create_face_set = RNA_boolean_get(op->ptr, "create_face_set");
SculptCursorGeometryInfo sgi;
- float mouse[2];
- mouse[0] = event->mval[0];
- mouse[1] = event->mval[1];
+ const float mval_fl[2] = {UNPACK2(event->mval)};
SCULPT_vertex_random_access_ensure(ss);
op->customdata = MEM_mallocN(sizeof(float[2]), "initial mouse position");
- copy_v2_v2(op->customdata, mouse);
+ copy_v2_v2(op->customdata, mval_fl);
- SCULPT_cursor_geometry_info_update(C, &sgi, mouse, false);
+ SCULPT_cursor_geometry_info_update(C, &sgi, mval_fl, false);
BKE_sculpt_update_object_for_edit(depsgraph, ob, true, true, false);
diff --git a/source/blender/editors/sculpt_paint/sculpt_ops.c b/source/blender/editors/sculpt_paint/sculpt_ops.c
index 2b5a20205bd..f16763be735 100644
--- a/source/blender/editors/sculpt_paint/sculpt_ops.c
+++ b/source/blender/editors/sculpt_paint/sculpt_ops.c
@@ -84,6 +84,7 @@
#include "WM_toolsystem.h"
#include "WM_types.h"
+#include "ED_image.h"
#include "ED_object.h"
#include "ED_screen.h"
#include "ED_sculpt.h"
@@ -349,7 +350,7 @@ void ED_object_sculptmode_enter_ex(Main *bmain,
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);
+ ED_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. */
@@ -637,16 +638,16 @@ static int vertex_to_loop_colors_exec(bContext *C, wmOperator *UNUSED(op))
if (MPropCol_layer_n == -1) {
return OPERATOR_CANCELLED;
}
- MPropCol *vertcols = CustomData_get_layer_n(&mesh->vdata, CD_PROP_COLOR, MPropCol_layer_n);
+ const 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);
+ const MLoop *loops = CustomData_get_layer(&mesh->ldata, CD_MLOOP);
+ const MPoly *polys = CustomData_get_layer(&mesh->pdata, CD_MPOLY);
for (int i = 0; i < mesh->totpoly; i++) {
- MPoly *c_poly = &polys[i];
+ const 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];
+ const 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);
@@ -711,7 +712,8 @@ static int loop_to_vertex_colors_exec(bContext *C, wmOperator *UNUSED(op))
if (mloopcol_layer_n == -1) {
return OPERATOR_CANCELLED;
}
- MLoopCol *loopcols = CustomData_get_layer_n(&mesh->ldata, CD_PROP_BYTE_COLOR, mloopcol_layer_n);
+ const MLoopCol *loopcols = CustomData_get_layer_n(
+ &mesh->ldata, CD_PROP_BYTE_COLOR, mloopcol_layer_n);
const int MPropCol_layer_n = CustomData_get_active_layer(&mesh->vdata, CD_PROP_COLOR);
if (MPropCol_layer_n == -1) {
@@ -719,14 +721,14 @@ static int loop_to_vertex_colors_exec(bContext *C, wmOperator *UNUSED(op))
}
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);
+ const MLoop *loops = CustomData_get_layer(&mesh->ldata, CD_MLOOP);
+ const MPoly *polys = CustomData_get_layer(&mesh->pdata, CD_MPOLY);
for (int i = 0; i < mesh->totpoly; i++) {
- MPoly *c_poly = &polys[i];
+ const 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];
+ const 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);
@@ -780,8 +782,7 @@ static int sculpt_sample_color_invoke(bContext *C, wmOperator *op, const wmEvent
}
float color_srgb[3];
- copy_v3_v3(color_srgb, active_vertex_color);
- IMB_colormanagement_scene_linear_to_srgb_v3(color_srgb);
+ IMB_colormanagement_scene_linear_to_srgb_v3(color_srgb, active_vertex_color);
BKE_brush_color_set(scene, brush, color_srgb);
WM_event_add_notifier(C, NC_BRUSH | NA_EDITED, brush);
@@ -1043,6 +1044,10 @@ static int sculpt_mask_by_color_invoke(bContext *C, wmOperator *op, const wmEven
Depsgraph *depsgraph = CTX_data_depsgraph_pointer(C);
Object *ob = CTX_data_active_object(C);
SculptSession *ss = ob->sculpt;
+ View3D *v3d = CTX_wm_view3d(C);
+ if (v3d->shading.type == OB_SOLID) {
+ v3d->shading.color_type = V3D_SHADING_VERTEX_COLOR;
+ }
BKE_sculpt_update_object_for_edit(depsgraph, ob, true, true, false);
@@ -1056,10 +1061,8 @@ static int sculpt_mask_by_color_invoke(bContext *C, wmOperator *op, const wmEven
/* 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);
+ const float mval_fl[2] = {UNPACK2(event->mval)};
+ SCULPT_cursor_geometry_info_update(C, &sgi, mval_fl, false);
SCULPT_undo_push_begin(ob, "Mask by color");
BKE_sculpt_color_layer_create_if_needed(ob);
@@ -1094,7 +1097,7 @@ 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";
+ ot->description = "Creates a mask based on the active color attribute";
/* api callbacks */
ot->invoke = sculpt_mask_by_color_invoke;
diff --git a/source/blender/editors/sculpt_paint/sculpt_paint_color.c b/source/blender/editors/sculpt_paint/sculpt_paint_color.c
index 7a8a6e8e484..fa9f24377da 100644
--- a/source/blender/editors/sculpt_paint/sculpt_paint_color.c
+++ b/source/blender/editors/sculpt_paint/sculpt_paint_color.c
@@ -124,7 +124,7 @@ static void do_paint_brush_task_cb_ex(void *__restrict userdata,
copy_v3_v3(brush_color,
ss->cache->invert ? BKE_brush_secondary_color_get(ss->scene, brush) :
BKE_brush_color_get(ss->scene, brush));
- IMB_colormanagement_srgb_to_scene_linear_v3(brush_color);
+ IMB_colormanagement_srgb_to_scene_linear_v3(brush_color, brush_color);
BKE_pbvh_vertex_iter_begin (ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) {
SCULPT_orig_vert_data_update(&orig_data, &vd);
@@ -380,6 +380,15 @@ static void do_smear_brush_task_cb_exec(void *__restrict userdata,
ss, &test, data->brush->falloff_shape);
const int thread_id = BLI_task_parallel_thread_id(tls);
+ float brush_delta[3];
+
+ if (brush->flag & BRUSH_ANCHORED) {
+ copy_v3_v3(brush_delta, ss->cache->grab_delta_symmetry);
+ }
+ else {
+ sub_v3_v3v3(brush_delta, ss->cache->location, ss->cache->last_location);
+ }
+
BKE_pbvh_vertex_iter_begin (ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) {
if (!sculpt_brush_test_sq_fn(&test, vd.co)) {
continue;
@@ -404,7 +413,7 @@ static void do_smear_brush_task_cb_exec(void *__restrict userdata,
switch (brush->smear_deform_type) {
case BRUSH_SMEAR_DEFORM_DRAG:
- sub_v3_v3v3(current_disp, ss->cache->location, ss->cache->last_location);
+ copy_v3_v3(current_disp, brush_delta);
break;
case BRUSH_SMEAR_DEFORM_PINCH:
sub_v3_v3v3(current_disp, ss->cache->location, vd.co);
@@ -529,12 +538,10 @@ void SCULPT_do_smear_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode
const int totvert = SCULPT_vertex_count_get(ss);
- if (SCULPT_stroke_is_first_brush_step(ss->cache)) {
- if (!ss->cache->prev_colors) {
- ss->cache->prev_colors = MEM_callocN(sizeof(float[4]) * totvert, "prev colors");
- for (int i = 0; i < totvert; i++) {
- SCULPT_vertex_color_get(ss, i, ss->cache->prev_colors[i]);
- }
+ if (!ss->cache->prev_colors) {
+ ss->cache->prev_colors = MEM_callocN(sizeof(float[4]) * totvert, "prev colors");
+ for (int i = 0; i < totvert; i++) {
+ SCULPT_vertex_color_get(ss, i, ss->cache->prev_colors[i]);
}
}
diff --git a/source/blender/editors/sculpt_paint/sculpt_paint_image.cc b/source/blender/editors/sculpt_paint/sculpt_paint_image.cc
index df1ccc0fbe9..975a8f21aaf 100644
--- a/source/blender/editors/sculpt_paint/sculpt_paint_image.cc
+++ b/source/blender/editors/sculpt_paint/sculpt_paint_image.cc
@@ -360,6 +360,86 @@ static void do_paint_pixels(void *__restrict userdata,
node_data.flags.dirty |= pixels_updated;
}
+static void undo_region_tiles(
+ ImBuf *ibuf, int x, int y, int w, int h, int *tx, int *ty, int *tw, int *th)
+{
+ int srcx = 0, srcy = 0;
+ IMB_rectclip(ibuf, nullptr, &x, &y, &srcx, &srcy, &w, &h);
+ *tw = ((x + w - 1) >> ED_IMAGE_UNDO_TILE_BITS);
+ *th = ((y + h - 1) >> ED_IMAGE_UNDO_TILE_BITS);
+ *tx = (x >> ED_IMAGE_UNDO_TILE_BITS);
+ *ty = (y >> ED_IMAGE_UNDO_TILE_BITS);
+}
+
+static void push_undo(const NodeData &node_data,
+ Image &image,
+ ImageUser &image_user,
+ const image::ImageTileWrapper &image_tile,
+ ImBuf &image_buffer,
+ ImBuf **tmpibuf)
+{
+ for (const UDIMTileUndo &tile_undo : node_data.undo_regions) {
+ if (tile_undo.tile_number != image_tile.get_tile_number()) {
+ continue;
+ }
+ int tilex, tiley, tilew, tileh;
+ ListBase *undo_tiles = ED_image_paint_tile_list_get();
+ undo_region_tiles(&image_buffer,
+ tile_undo.region.xmin,
+ tile_undo.region.ymin,
+ BLI_rcti_size_x(&tile_undo.region),
+ BLI_rcti_size_y(&tile_undo.region),
+ &tilex,
+ &tiley,
+ &tilew,
+ &tileh);
+ for (int ty = tiley; ty <= tileh; ty++) {
+ for (int tx = tilex; tx <= tilew; tx++) {
+ ED_image_paint_tile_push(undo_tiles,
+ &image,
+ &image_buffer,
+ tmpibuf,
+ &image_user,
+ tx,
+ ty,
+ nullptr,
+ nullptr,
+ true,
+ true);
+ }
+ }
+ }
+}
+
+static void do_push_undo_tile(void *__restrict userdata,
+ const int n,
+ const TaskParallelTLS *__restrict UNUSED(tls))
+{
+ TexturePaintingUserData *data = static_cast<TexturePaintingUserData *>(userdata);
+ PBVHNode *node = data->nodes[n];
+
+ NodeData &node_data = BKE_pbvh_pixels_node_data_get(*node);
+ Image *image = data->image_data.image;
+ ImageUser *image_user = data->image_data.image_user;
+
+ ImBuf *tmpibuf = nullptr;
+ ImageUser local_image_user = *image_user;
+ LISTBASE_FOREACH (ImageTile *, tile, &image->tiles) {
+ image::ImageTileWrapper image_tile(tile);
+ local_image_user.tile = image_tile.get_tile_number();
+ ImBuf *image_buffer = BKE_image_acquire_ibuf(image, &local_image_user, nullptr);
+ if (image_buffer == nullptr) {
+ continue;
+ }
+
+ push_undo(node_data, *image, *image_user, image_tile, *image_buffer, &tmpibuf);
+ BKE_image_release_ibuf(image, image_buffer, nullptr);
+ }
+ if (tmpibuf) {
+ IMB_freeImBuf(tmpibuf);
+ }
+}
+
static void do_mark_dirty_regions(void *__restrict userdata,
const int n,
const TaskParallelTLS *__restrict UNUSED(tls))
@@ -380,8 +460,9 @@ bool SCULPT_paint_image_canvas_get(PaintModeSettings *paint_mode_settings,
Image **r_image,
ImageUser **r_image_user)
{
- BLI_assert(r_image);
- BLI_assert(r_image_user);
+ *r_image = nullptr;
+ *r_image_user = nullptr;
+
ImageData image_data;
if (!ImageData::init_active_image(ob, &image_data, paint_mode_settings)) {
return false;
@@ -421,6 +502,7 @@ void SCULPT_do_paint_brush_image(
TaskParallelSettings settings;
BKE_pbvh_parallel_range_settings(&settings, true, totnode);
+ BLI_task_parallel_range(0, totnode, &data, do_push_undo_tile, &settings);
BLI_task_parallel_range(0, totnode, &data, do_paint_pixels, &settings);
TaskParallelSettings settings_flush;
diff --git a/source/blender/editors/sculpt_paint/sculpt_transform.c b/source/blender/editors/sculpt_paint/sculpt_transform.c
index b3616254b26..48033f3407e 100644
--- a/source/blender/editors/sculpt_paint/sculpt_transform.c
+++ b/source/blender/editors/sculpt_paint/sculpt_transform.c
@@ -16,6 +16,7 @@
#include "BKE_brush.h"
#include "BKE_context.h"
+#include "BKE_kelvinlet.h"
#include "BKE_mesh.h"
#include "BKE_mesh_mapping.h"
#include "BKE_object.h"
@@ -33,6 +34,7 @@
#include "ED_object.h"
#include "ED_screen.h"
#include "ED_sculpt.h"
+#include "ED_view3d.h"
#include "paint_intern.h"
#include "sculpt_intern.h"
@@ -54,6 +56,10 @@ 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);
@@ -61,10 +67,18 @@ 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);
+
+ if (sd->transform_mode == SCULPT_TRANSFORM_MODE_RADIUS_ELASTIC) {
+ ss->filter_cache->transform_displacement_mode = SCULPT_TRANSFORM_DISPLACEMENT_INCREMENTAL;
+ }
+ else {
+ 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])
{
@@ -73,9 +87,18 @@ 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];
- 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);
+ 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;
+ }
for (int i = 0; i < PAINT_SYMM_AREAS; i++) {
ePaintSymmetryAreas v_symm = i;
@@ -134,16 +157,26 @@ static void sculpt_transform_task_cb(void *__restrict userdata,
SCULPT_undo_push_node(data->ob, node, SCULPT_UNDO_COORDS);
BKE_pbvh_vertex_iter_begin (ss->pbvh, node, vd, PBVH_ITER_UNIQUE) {
SCULPT_orig_vert_data_update(&orig_data, &vd);
+ float *start_co;
float transformed_co[3], orig_co[3], disp[3];
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);
- copy_v3_v3(transformed_co, 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);
mul_m4_v3(data->transform_mats[(int)symm_area], transformed_co);
- sub_v3_v3v3(disp, transformed_co, orig_co);
+ sub_v3_v3v3(disp, transformed_co, start_co);
mul_v3_fl(disp, 1.0f - fade);
- add_v3_v3v3(vd.co, orig_co, disp);
+ add_v3_v3v3(vd.co, start_co, disp);
if (vd.mvert) {
BKE_pbvh_vert_mark_update(ss->pbvh, vd.index);
@@ -165,7 +198,8 @@ static void sculpt_transform_all_vertices(Sculpt *sd, Object *ob)
.nodes = ss->filter_cache->nodes,
};
- sculpt_transform_matrices_init(ss, symm, data.transform_mats);
+ sculpt_transform_matrices_init(
+ ss, symm, ss->filter_cache->transform_displacement_mode, 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). */
@@ -175,6 +209,98 @@ static void sculpt_transform_all_vertices(Sculpt *sd, Object *ob)
0, ss->filter_cache->totnode, &data, sculpt_transform_task_cb, &settings);
}
+static void sculpt_elastic_transform_task_cb(void *__restrict userdata,
+ const int i,
+ const TaskParallelTLS *__restrict UNUSED(tls))
+{
+
+ SculptThreadedTaskData *data = userdata;
+ SculptSession *ss = data->ob->sculpt;
+ PBVHNode *node = data->nodes[i];
+
+ float(*proxy)[3] = BKE_pbvh_node_add_proxy(ss->pbvh, data->nodes[i])->co;
+
+ SculptOrigVertData orig_data;
+ SCULPT_orig_vert_data_init(&orig_data, data->ob, data->nodes[i]);
+
+ KelvinletParams params;
+ /* TODO(pablodp606): These parameters can be exposed if needed as transform strength and volume
+ * preservation like in the elastic deform brushes. Setting them to the same default as elastic
+ * deform triscale grab because they work well in most cases. */
+ const float force = 1.0f;
+ const float shear_modulus = 1.0f;
+ const float poisson_ratio = 0.4f;
+ BKE_kelvinlet_init_params(
+ &params, data->elastic_transform_radius, force, shear_modulus, poisson_ratio);
+
+ SCULPT_undo_push_node(data->ob, node, SCULPT_UNDO_COORDS);
+
+ PBVHVertexIter vd;
+ 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];
+ const float fade = vd.mask ? *vd.mask : 0.0f;
+ copy_v3_v3(orig_co, orig_data.co);
+
+ copy_v3_v3(transformed_co, vd.co);
+ mul_m4_v3(data->elastic_transform_mat, transformed_co);
+ sub_v3_v3v3(disp, transformed_co, vd.co);
+
+ float final_disp[3];
+ BKE_kelvinlet_grab_triscale(final_disp, &params, vd.co, data->elastic_transform_pivot, disp);
+ mul_v3_fl(final_disp, 20.0f * (1.0f - fade));
+
+ copy_v3_v3(proxy[vd.i], final_disp);
+
+ if (vd.mvert) {
+ BKE_pbvh_vert_mark_update(ss->pbvh, vd.index);
+ }
+ }
+ BKE_pbvh_vertex_iter_end;
+
+ BKE_pbvh_node_mark_update(node);
+}
+
+static void sculpt_transform_radius_elastic(Sculpt *sd, Object *ob, const float transform_radius)
+{
+ SculptSession *ss = ob->sculpt;
+ BLI_assert(ss->filter_cache->transform_displacement_mode ==
+ SCULPT_TRANSFORM_DISPLACEMENT_INCREMENTAL);
+
+ const char symm = SCULPT_mesh_symmetry_xyz_get(ob);
+
+ SculptThreadedTaskData data = {
+ .sd = sd,
+ .ob = ob,
+ .nodes = ss->filter_cache->nodes,
+ .elastic_transform_radius = transform_radius,
+ };
+
+ sculpt_transform_matrices_init(
+ ss, symm, ss->filter_cache->transform_displacement_mode, data.transform_mats);
+
+ TaskParallelSettings settings;
+ BKE_pbvh_parallel_range_settings(&settings, true, ss->filter_cache->totnode);
+
+ /* Elastic transform needs to apply all transform matrices to all vertices and then combine the
+ * displacement proxies as all vertices are modified by all symmetry passes. */
+ for (ePaintSymmetryFlags symmpass = 0; symmpass <= symm; symmpass++) {
+ if (SCULPT_is_symmetry_iteration_valid(symmpass, symm)) {
+ flip_v3_v3(data.elastic_transform_pivot, ss->pivot_pos, symmpass);
+ flip_v3_v3(data.elastic_transform_pivot_init, ss->init_pivot_pos, symmpass);
+
+ printf(
+ "%.2f %.2f %.2f\n", ss->init_pivot_pos[0], ss->init_pivot_pos[1], ss->init_pivot_pos[2]);
+
+ const int symm_area = SCULPT_get_vertex_symm_area(data.elastic_transform_pivot);
+ copy_m4_m4(data.elastic_transform_mat, data.transform_mats[symm_area]);
+ BLI_task_parallel_range(
+ 0, ss->filter_cache->totnode, &data, sculpt_elastic_transform_task_cb, &settings);
+ }
+ }
+ SCULPT_combine_transform_proxies(sd, ob);
+}
+
void ED_sculpt_update_modal_transform(struct bContext *C, Object *ob)
{
Sculpt *sd = CTX_data_tool_settings(C)->sculpt;
@@ -184,7 +310,36 @@ void ED_sculpt_update_modal_transform(struct bContext *C, Object *ob)
SCULPT_vertex_random_access_ensure(ss);
BKE_sculpt_update_object_for_edit(depsgraph, ob, false, false, false);
- sculpt_transform_all_vertices(sd, ob);
+ switch (sd->transform_mode) {
+ case SCULPT_TRANSFORM_MODE_ALL_VERTICES: {
+ sculpt_transform_all_vertices(sd, ob);
+ break;
+ }
+ case SCULPT_TRANSFORM_MODE_RADIUS_ELASTIC: {
+ Brush *brush = BKE_paint_brush(&sd->paint);
+ Scene *scene = CTX_data_scene(C);
+ float transform_radius;
+
+ if (BKE_brush_use_locked_size(scene, brush)) {
+ transform_radius = BKE_brush_unprojected_radius_get(scene, brush);
+ }
+ else {
+ ViewContext vc;
+
+ ED_view3d_viewcontext_init(C, &vc, depsgraph);
+
+ transform_radius = paint_calc_object_space_radius(
+ &vc, ss->init_pivot_pos, BKE_brush_size_get(scene, brush));
+ }
+
+ sculpt_transform_radius_elastic(sd, ob, transform_radius);
+ break;
+ }
+ }
+
+ 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);
@@ -267,10 +422,11 @@ static int sculpt_set_pivot_position_exec(bContext *C, wmOperator *op)
/* Pivot to ray-cast surface. */
else if (mode == SCULPT_PIVOT_POSITION_CURSOR_SURFACE) {
float stroke_location[3];
- float mouse[2];
- mouse[0] = RNA_float_get(op->ptr, "mouse_x");
- mouse[1] = RNA_float_get(op->ptr, "mouse_y");
- if (SCULPT_stroke_get_location(C, stroke_location, mouse)) {
+ const float mval[2] = {
+ RNA_float_get(op->ptr, "mouse_x"),
+ RNA_float_get(op->ptr, "mouse_y"),
+ };
+ if (SCULPT_stroke_get_location(C, stroke_location, mval)) {
copy_v3_v3(ss->pivot_pos, stroke_location);
}
}
diff --git a/source/blender/editors/sculpt_paint/sculpt_undo.c b/source/blender/editors/sculpt_paint/sculpt_undo.c
index 5867dc558de..e82f14b1ca7 100644
--- a/source/blender/editors/sculpt_paint/sculpt_undo.c
+++ b/source/blender/editors/sculpt_paint/sculpt_undo.c
@@ -50,6 +50,7 @@
#include "WM_api.h"
#include "WM_types.h"
+#include "ED_geometry.h"
#include "ED_object.h"
#include "ED_sculpt.h"
#include "ED_undo.h"
@@ -105,7 +106,7 @@ typedef struct UndoSculpt {
} UndoSculpt;
typedef struct SculptAttrRef {
- AttributeDomain domain;
+ eAttrDomain domain;
int type;
char name[MAX_CUSTOMDATA_LAYER_NAME];
bool was_set;
@@ -1265,7 +1266,7 @@ static SculptUndoNode *sculpt_undo_face_sets_push(Object *ob, SculptUndoType typ
unode->face_sets = MEM_callocN(me->totpoly * sizeof(int), "sculpt face sets");
- int *face_sets = CustomData_get_layer(&me->pdata, CD_SCULPT_FACE_SETS);
+ const int *face_sets = CustomData_get_layer(&me->pdata, CD_SCULPT_FACE_SETS);
for (int i = 0; i < me->totpoly; i++) {
unode->face_sets[i] = face_sets[i];
}
@@ -1464,7 +1465,7 @@ static bool sculpt_attribute_ref_equals(SculptAttrRef *a, SculptAttrRef *b)
static void sculpt_save_active_attribute(Object *ob, SculptAttrRef *attr)
{
Mesh *me = BKE_object_get_original_mesh(ob);
- CustomDataLayer *layer;
+ const CustomDataLayer *layer;
if (ob && me && (layer = BKE_id_attributes_active_color_get((ID *)me))) {
attr->domain = BKE_id_attribute_domain((ID *)me, layer);
@@ -1565,6 +1566,24 @@ static void sculpt_undo_set_active_layer(struct bContext *C, SculptAttrRef *attr
CustomDataLayer *layer;
layer = BKE_id_attribute_find(&me->id, attr->name, attr->type, attr->domain);
+ /* Temporary fix for T97408. This is a fundamental
+ * bug in the undo stack; the operator code needs to push
+ * an extra undo step before running an operator if a
+ * non-memfile undo system is active.
+ *
+ * For now, detect if the layer does exist but with a different
+ * domain and just unconvert it.
+ */
+ if (!layer) {
+ layer = BKE_id_attribute_search(&me->id, attr->name, CD_MASK_PROP_ALL, ATTR_DOMAIN_MASK_ALL);
+ eAttrDomain domain = layer ? BKE_id_attribute_domain(&me->id, layer) : ATTR_DOMAIN_NUM;
+
+ if (layer && ED_geometry_attribute_convert(
+ me, attr->name, layer->type, domain, attr->type, attr->domain)) {
+ layer = BKE_id_attribute_find(&me->id, attr->name, attr->type, attr->domain);
+ }
+ }
+
if (!layer) {
/* Memfile undo killed the layer; re-create it. */
CustomData *cdata = attr->domain == ATTR_DOMAIN_POINT ? &me->vdata : &me->ldata;
diff --git a/source/blender/editors/sound/sound_ops.c b/source/blender/editors/sound/sound_ops.c
index a63ed142ed8..2a8a2be8b65 100644
--- a/source/blender/editors/sound/sound_ops.c
+++ b/source/blender/editors/sound/sound_ops.c
@@ -761,7 +761,8 @@ static int sound_pack_exec(bContext *C, wmOperator *op)
sound->packedfile = BKE_packedfile_new(
op->reports, sound->filepath, ID_BLEND_PATH(bmain, &sound->id));
- BKE_sound_load(bmain, sound);
+
+ DEG_id_tag_update_ex(bmain, &sound->id, ID_RECALC_AUDIO);
return OPERATOR_FINISHED;
}
diff --git a/source/blender/editors/space_action/action_select.c b/source/blender/editors/space_action/action_select.c
index b972ccbaf89..aff888818e0 100644
--- a/source/blender/editors/space_action/action_select.c
+++ b/source/blender/editors/space_action/action_select.c
@@ -887,6 +887,7 @@ void ACTION_OT_select_circle(wmOperatorType *ot)
ot->exec = action_circle_select_exec;
ot->poll = ED_operator_action_active;
ot->cancel = WM_gesture_circle_cancel;
+ ot->get_name = ED_select_circle_get_name;
/* flags */
ot->flag = OPTYPE_UNDO;
diff --git a/source/blender/editors/space_buttons/space_buttons.c b/source/blender/editors/space_buttons/space_buttons.c
index 1d0061ab7d8..052af39319c 100644
--- a/source/blender/editors/space_buttons/space_buttons.c
+++ b/source/blender/editors/space_buttons/space_buttons.c
@@ -724,6 +724,9 @@ static void buttons_area_listener(const wmSpaceTypeListenerParams *params)
/* Needed to refresh context path when changing active particle system index. */
buttons_area_redraw(area, BCONTEXT_PARTICLE);
break;
+ case ND_DRAW_ANIMVIZ:
+ buttons_area_redraw(area, BCONTEXT_OBJECT);
+ break;
default:
/* Not all object RNA props have a ND_ notifier (yet) */
ED_area_tag_redraw(area);
diff --git a/source/blender/editors/space_clip/clip_buttons.c b/source/blender/editors/space_clip/clip_buttons.c
index e24d461019b..72df2b74b11 100644
--- a/source/blender/editors/space_clip/clip_buttons.c
+++ b/source/blender/editors/space_clip/clip_buttons.c
@@ -303,7 +303,7 @@ static void marker_block_handler(bContext *C, void *arg_cb, int event)
cb->marker->pattern_corners[a][1] *= scale_y;
}
- BKE_tracking_marker_clamp(cb->marker, CLAMP_PAT_DIM);
+ BKE_tracking_marker_clamp_search_size(cb->marker);
ok = true;
}
@@ -319,7 +319,7 @@ static void marker_block_handler(bContext *C, void *arg_cb, int event)
sub_v2_v2v2(cb->marker->search_min, delta, side);
add_v2_v2v2(cb->marker->search_max, delta, side);
- BKE_tracking_marker_clamp(cb->marker, CLAMP_SEARCH_POS);
+ BKE_tracking_marker_clamp_search_position(cb->marker);
ok = true;
}
@@ -340,7 +340,7 @@ static void marker_block_handler(bContext *C, void *arg_cb, int event)
cb->marker->search_max[0] += dim[0];
cb->marker->search_max[1] += dim[1];
- BKE_tracking_marker_clamp(cb->marker, CLAMP_SEARCH_DIM);
+ BKE_tracking_marker_clamp_search_size(cb->marker);
ok = true;
}
diff --git a/source/blender/editors/space_clip/clip_draw.c b/source/blender/editors/space_clip/clip_draw.c
index 99524184323..7800ce797aa 100644
--- a/source/blender/editors/space_clip/clip_draw.c
+++ b/source/blender/editors/space_clip/clip_draw.c
@@ -676,6 +676,40 @@ static void track_colors(MovieTrackingTrack *track, int act, float col[3], float
}
}
+static void set_draw_marker_area_color(const MovieTrackingTrack *track,
+ const MovieTrackingMarker *marker,
+ const bool is_track_active,
+ const bool is_area_selected,
+ const float color[3],
+ const float selected_color[3])
+{
+ if (track->flag & TRACK_LOCKED) {
+ if (is_track_active) {
+ immUniformThemeColor(TH_ACT_MARKER);
+ }
+ else if (is_area_selected) {
+ immUniformThemeColorShade(TH_LOCK_MARKER, 64);
+ }
+ else {
+ immUniformThemeColor(TH_LOCK_MARKER);
+ }
+ }
+ else if (marker->flag & MARKER_DISABLED) {
+ if (is_track_active) {
+ immUniformThemeColor(TH_ACT_MARKER);
+ }
+ else if (is_area_selected) {
+ immUniformThemeColorShade(TH_DIS_MARKER, 128);
+ }
+ else {
+ immUniformThemeColor(TH_DIS_MARKER);
+ }
+ }
+ else {
+ immUniformColor3fv(is_area_selected ? selected_color : color);
+ }
+}
+
static void draw_marker_areas(SpaceClip *sc,
MovieTrackingTrack *track,
MovieTrackingMarker *marker,
@@ -785,31 +819,7 @@ static void draw_marker_areas(SpaceClip *sc,
GPU_matrix_push();
GPU_matrix_translate_2fv(marker_pos);
- if (track->flag & TRACK_LOCKED) {
- if (act) {
- immUniformThemeColor(TH_ACT_MARKER);
- }
- else if (track->pat_flag & SELECT) {
- immUniformThemeColorShade(TH_LOCK_MARKER, 64);
- }
- else {
- immUniformThemeColor(TH_LOCK_MARKER);
- }
- }
- else if (marker->flag & MARKER_DISABLED) {
- if (act) {
- immUniformThemeColor(TH_ACT_MARKER);
- }
- else if (track->pat_flag & SELECT) {
- immUniformThemeColorShade(TH_DIS_MARKER, 128);
- }
- else {
- immUniformThemeColor(TH_DIS_MARKER);
- }
- }
- else {
- immUniformColor3fv((track->pat_flag & SELECT) ? scol : col);
- }
+ set_draw_marker_area_color(track, marker, act, track->pat_flag & SELECT, col, scol);
if (tiny) {
immUniform1f("dash_width", 6.0f);
@@ -834,6 +844,8 @@ static void draw_marker_areas(SpaceClip *sc,
0;
if ((track->search_flag & SELECT) == sel && (sc->flag & SC_SHOW_MARKER_SEARCH) && show_search) {
+ set_draw_marker_area_color(track, marker, act, track->search_flag & SELECT, col, scol);
+
imm_draw_box_wire_2d(shdr_pos,
marker->search_min[0],
marker->search_min[1],
diff --git a/source/blender/editors/space_clip/clip_editor.c b/source/blender/editors/space_clip/clip_editor.c
index 87e88d094d7..cf7c3b51ae3 100644
--- a/source/blender/editors/space_clip/clip_editor.c
+++ b/source/blender/editors/space_clip/clip_editor.c
@@ -102,6 +102,16 @@ bool ED_space_clip_maskedit_poll(bContext *C)
return false;
}
+bool ED_space_clip_maskedit_visible_splines_poll(bContext *C)
+{
+ if (!ED_space_clip_maskedit_poll(C)) {
+ return false;
+ }
+
+ const SpaceClip *space_clip = CTX_wm_space_clip(C);
+ return space_clip->mask_info.draw_flag & MASK_DRAWFLAG_SPLINE;
+}
+
bool ED_space_clip_maskedit_mask_poll(bContext *C)
{
if (ED_space_clip_maskedit_poll(C)) {
@@ -117,6 +127,16 @@ bool ED_space_clip_maskedit_mask_poll(bContext *C)
return false;
}
+bool ED_space_clip_maskedit_mask_visible_splines_poll(bContext *C)
+{
+ if (!ED_space_clip_maskedit_mask_poll(C)) {
+ return false;
+ }
+
+ const SpaceClip *space_clip = CTX_wm_space_clip(C);
+ return space_clip->mask_info.draw_flag & MASK_DRAWFLAG_SPLINE;
+}
+
/** \} */
/* -------------------------------------------------------------------- */
@@ -272,7 +292,7 @@ bool ED_space_clip_get_position(struct SpaceClip *sc,
return true;
}
-bool ED_space_clip_color_sample(SpaceClip *sc, ARegion *region, int mval[2], float r_col[3])
+bool ED_space_clip_color_sample(SpaceClip *sc, ARegion *region, const int mval[2], float r_col[3])
{
ImBuf *ibuf;
float fx, fy, co[2];
diff --git a/source/blender/editors/space_clip/clip_intern.h b/source/blender/editors/space_clip/clip_intern.h
index dd01c095479..7f9cf61b748 100644
--- a/source/blender/editors/space_clip/clip_intern.h
+++ b/source/blender/editors/space_clip/clip_intern.h
@@ -187,8 +187,10 @@ void clip_draw_sfra_efra(struct View2D *v2d, struct Scene *scene);
/* tracking_ops.c */
-struct MovieTrackingTrack *tracking_marker_check_slide(
- struct bContext *C, const struct wmEvent *event, int *r_area, int *r_action, int *r_corner);
+/* Find track which can be slid in a proximity of the given event.
+ * Uses the same distance tolerance rule as the "Slide Marker" operator. */
+struct MovieTrackingTrack *tracking_find_slidable_track_in_proximity(struct bContext *C,
+ const float co[2]);
void CLIP_OT_add_marker(struct wmOperatorType *ot);
void CLIP_OT_add_marker_at_click(struct wmOperatorType *ot);
diff --git a/source/blender/editors/space_clip/clip_ops.c b/source/blender/editors/space_clip/clip_ops.c
index e61c264ca06..f5bf850791a 100644
--- a/source/blender/editors/space_clip/clip_ops.c
+++ b/source/blender/editors/space_clip/clip_ops.c
@@ -777,7 +777,7 @@ void CLIP_OT_view_zoom_in(wmOperatorType *ot)
ot->poll = ED_space_clip_view_clip_poll;
/* flags */
- ot->flag |= OPTYPE_LOCK_BYPASS;
+ ot->flag = OPTYPE_LOCK_BYPASS;
/* properties */
prop = RNA_def_float_vector(ot->srna,
@@ -834,7 +834,7 @@ void CLIP_OT_view_zoom_out(wmOperatorType *ot)
ot->poll = ED_space_clip_view_clip_poll;
/* flags */
- ot->flag |= OPTYPE_LOCK_BYPASS;
+ ot->flag = OPTYPE_LOCK_BYPASS;
/* properties */
prop = RNA_def_float_vector(ot->srna,
@@ -883,7 +883,7 @@ void CLIP_OT_view_zoom_ratio(wmOperatorType *ot)
ot->poll = ED_space_clip_view_clip_poll;
/* flags */
- ot->flag |= OPTYPE_LOCK_BYPASS;
+ ot->flag = OPTYPE_LOCK_BYPASS;
/* properties */
RNA_def_float(ot->srna,
diff --git a/source/blender/editors/space_clip/space_clip.c b/source/blender/editors/space_clip/space_clip.c
index 91fef23019c..a73883e7624 100644
--- a/source/blender/editors/space_clip/space_clip.c
+++ b/source/blender/editors/space_clip/space_clip.c
@@ -619,6 +619,44 @@ static void clip_dropboxes(void)
WM_dropbox_add(lb, "CLIP_OT_open", clip_drop_poll, clip_drop_copy, NULL, NULL);
}
+static bool clip_set_region_visible(const bContext *C,
+ ARegion *region,
+ const bool is_visible,
+ const short alignment,
+ const bool view_all_on_show)
+{
+ bool view_changed = false;
+
+ if (is_visible) {
+ if (region && (region->flag & RGN_FLAG_HIDDEN)) {
+ region->flag &= ~RGN_FLAG_HIDDEN;
+ region->v2d.flag &= ~V2D_IS_INIT;
+ if (view_all_on_show) {
+ region->v2d.cur = region->v2d.tot;
+ }
+ view_changed = true;
+ }
+ if (region && region->alignment != alignment) {
+ region->alignment = alignment;
+ view_changed = true;
+ }
+ }
+ else {
+ if (region && !(region->flag & RGN_FLAG_HIDDEN)) {
+ region->flag |= RGN_FLAG_HIDDEN;
+ region->v2d.flag &= ~V2D_IS_INIT;
+ WM_event_remove_handlers((bContext *)C, &region->handlers);
+ view_changed = true;
+ }
+ if (region && region->alignment != RGN_ALIGN_NONE) {
+ region->alignment = RGN_ALIGN_NONE;
+ view_changed = true;
+ }
+ }
+
+ return view_changed;
+}
+
static void clip_refresh(const bContext *C, ScrArea *area)
{
wmWindowManager *wm = CTX_wm_manager(C);
@@ -662,127 +700,14 @@ static void clip_refresh(const bContext *C, ScrArea *area)
break;
}
- if (main_visible) {
- if (region_main && (region_main->flag & RGN_FLAG_HIDDEN)) {
- region_main->flag &= ~RGN_FLAG_HIDDEN;
- region_main->v2d.flag &= ~V2D_IS_INIT;
- view_changed = true;
- }
-
- if (region_main && region_main->alignment != RGN_ALIGN_NONE) {
- region_main->alignment = RGN_ALIGN_NONE;
- view_changed = true;
- }
- }
- else {
- if (region_main && !(region_main->flag & RGN_FLAG_HIDDEN)) {
- region_main->flag |= RGN_FLAG_HIDDEN;
- region_main->v2d.flag &= ~V2D_IS_INIT;
- WM_event_remove_handlers((bContext *)C, &region_main->handlers);
- view_changed = true;
- }
- if (region_main && region_main->alignment != RGN_ALIGN_NONE) {
- region_main->alignment = RGN_ALIGN_NONE;
- view_changed = true;
- }
- }
-
- if (properties_visible) {
- if (region_properties && (region_properties->flag & RGN_FLAG_HIDDEN)) {
- region_properties->flag &= ~RGN_FLAG_HIDDEN;
- region_properties->v2d.flag &= ~V2D_IS_INIT;
- view_changed = true;
- }
- if (region_properties && region_properties->alignment != RGN_ALIGN_RIGHT) {
- region_properties->alignment = RGN_ALIGN_RIGHT;
- view_changed = true;
- }
- }
- else {
- if (region_properties && !(region_properties->flag & RGN_FLAG_HIDDEN)) {
- region_properties->flag |= RGN_FLAG_HIDDEN;
- region_properties->v2d.flag &= ~V2D_IS_INIT;
- WM_event_remove_handlers((bContext *)C, &region_properties->handlers);
- view_changed = true;
- }
- if (region_properties && region_properties->alignment != RGN_ALIGN_NONE) {
- region_properties->alignment = RGN_ALIGN_NONE;
- view_changed = true;
- }
- }
-
- if (tools_visible) {
- if (region_tools && (region_tools->flag & RGN_FLAG_HIDDEN)) {
- region_tools->flag &= ~RGN_FLAG_HIDDEN;
- region_tools->v2d.flag &= ~V2D_IS_INIT;
- view_changed = true;
- }
- if (region_tools && region_tools->alignment != RGN_ALIGN_LEFT) {
- region_tools->alignment = RGN_ALIGN_LEFT;
- view_changed = true;
- }
- }
- else {
- if (region_tools && !(region_tools->flag & RGN_FLAG_HIDDEN)) {
- region_tools->flag |= RGN_FLAG_HIDDEN;
- region_tools->v2d.flag &= ~V2D_IS_INIT;
- WM_event_remove_handlers((bContext *)C, &region_tools->handlers);
- view_changed = true;
- }
- if (region_tools && region_tools->alignment != RGN_ALIGN_NONE) {
- region_tools->alignment = RGN_ALIGN_NONE;
- view_changed = true;
- }
- }
-
- if (preview_visible) {
- if (region_preview && (region_preview->flag & RGN_FLAG_HIDDEN)) {
- region_preview->flag &= ~RGN_FLAG_HIDDEN;
- region_preview->v2d.flag &= ~V2D_IS_INIT;
- region_preview->v2d.cur = region_preview->v2d.tot;
- view_changed = true;
- }
- if (region_preview && region_preview->alignment != RGN_ALIGN_NONE) {
- region_preview->alignment = RGN_ALIGN_NONE;
- view_changed = true;
- }
- }
- else {
- if (region_preview && !(region_preview->flag & RGN_FLAG_HIDDEN)) {
- region_preview->flag |= RGN_FLAG_HIDDEN;
- region_preview->v2d.flag &= ~V2D_IS_INIT;
- WM_event_remove_handlers((bContext *)C, &region_preview->handlers);
- view_changed = true;
- }
- if (region_preview && region_preview->alignment != RGN_ALIGN_NONE) {
- region_preview->alignment = RGN_ALIGN_NONE;
- view_changed = true;
- }
- }
-
- if (channels_visible) {
- if (region_channels && (region_channels->flag & RGN_FLAG_HIDDEN)) {
- region_channels->flag &= ~RGN_FLAG_HIDDEN;
- region_channels->v2d.flag &= ~V2D_IS_INIT;
- view_changed = true;
- }
- if (region_channels && region_channels->alignment != RGN_ALIGN_LEFT) {
- region_channels->alignment = RGN_ALIGN_LEFT;
- view_changed = true;
- }
- }
- else {
- if (region_channels && !(region_channels->flag & RGN_FLAG_HIDDEN)) {
- region_channels->flag |= RGN_FLAG_HIDDEN;
- region_channels->v2d.flag &= ~V2D_IS_INIT;
- WM_event_remove_handlers((bContext *)C, &region_channels->handlers);
- view_changed = true;
- }
- if (region_channels && region_channels->alignment != RGN_ALIGN_NONE) {
- region_channels->alignment = RGN_ALIGN_NONE;
- view_changed = true;
- }
- }
+ view_changed |= clip_set_region_visible(C, region_main, main_visible, RGN_ALIGN_NONE, false);
+ view_changed |= clip_set_region_visible(
+ C, region_properties, properties_visible, RGN_ALIGN_RIGHT, false);
+ view_changed |= clip_set_region_visible(C, region_tools, tools_visible, RGN_ALIGN_LEFT, false);
+ view_changed |= clip_set_region_visible(
+ C, region_preview, preview_visible, RGN_ALIGN_NONE, true);
+ view_changed |= clip_set_region_visible(
+ C, region_channels, channels_visible, RGN_ALIGN_LEFT, false);
if (view_changed) {
ED_area_init(wm, window, area);
@@ -935,6 +860,7 @@ static void clip_main_region_draw(const bContext *C, ARegion *region)
sc->mask_info.draw_flag,
sc->mask_info.draw_type,
sc->mask_info.overlay_mode,
+ sc->mask_info.blend_factor,
mask_width,
mask_height,
aspx,
diff --git a/source/blender/editors/space_clip/tracking_ops.c b/source/blender/editors/space_clip/tracking_ops.c
index e7bdbfe7c68..ca224b04da5 100644
--- a/source/blender/editors/space_clip/tracking_ops.c
+++ b/source/blender/editors/space_clip/tracking_ops.c
@@ -336,35 +336,44 @@ void CLIP_OT_delete_marker(wmOperatorType *ot)
/** \name Slide Marker Operator
* \{ */
-enum {
- SLIDE_ACTION_POS = 0,
+typedef enum eSlideAction {
+ SLIDE_ACTION_NONE,
+
+ SLIDE_ACTION_POS,
SLIDE_ACTION_SIZE,
SLIDE_ACTION_OFFSET,
SLIDE_ACTION_TILT_SIZE,
-};
+} eSlideAction;
typedef struct {
- short area, action;
+ short area;
+ eSlideAction action;
MovieTrackingTrack *track;
MovieTrackingMarker *marker;
int mval[2];
int width, height;
- float *min, *max, *pos, *offset, (*corners)[2];
- float spos[2];
+ float *min, *max, *pos, (*corners)[2];
bool lock, accurate;
/* Data to restore on cancel. */
- float old_search_min[2], old_search_max[2], old_pos[2], old_offset[2];
+ float old_search_min[2], old_search_max[2], old_pos[2];
float old_corners[4][2];
float (*old_markers)[2];
} SlideMarkerData;
-static void slide_marker_tilt_slider(const MovieTrackingMarker *marker, float r_slider[2])
+static void slide_marker_tilt_slider_relative(const float pattern_corners[4][2], float r_slider[2])
+{
+ add_v2_v2v2(r_slider, pattern_corners[1], pattern_corners[2]);
+}
+
+static void slide_marker_tilt_slider(const float marker_pos[2],
+ const float pattern_corners[4][2],
+ float r_slider[2])
{
- add_v2_v2v2(r_slider, marker->pattern_corners[1], marker->pattern_corners[2]);
- add_v2_v2(r_slider, marker->pos);
+ slide_marker_tilt_slider_relative(pattern_corners, r_slider);
+ add_v2_v2(r_slider, marker_pos);
}
static SlideMarkerData *create_slide_marker_data(SpaceClip *sc,
@@ -373,7 +382,7 @@ static SlideMarkerData *create_slide_marker_data(SpaceClip *sc,
const wmEvent *event,
int area,
int corner,
- int action,
+ eSlideAction action,
int width,
int height)
{
@@ -389,29 +398,14 @@ static SlideMarkerData *create_slide_marker_data(SpaceClip *sc,
if (area == TRACK_AREA_POINT) {
data->pos = marker->pos;
- data->offset = track->offset;
}
else if (area == TRACK_AREA_PAT) {
- if (action == SLIDE_ACTION_SIZE) {
- data->corners = marker->pattern_corners;
- }
- else if (action == SLIDE_ACTION_OFFSET) {
- data->pos = marker->pos;
- data->offset = track->offset;
- data->old_markers = MEM_callocN(sizeof(*data->old_markers) * track->markersnr,
- "slide markers");
- for (int a = 0; a < track->markersnr; a++) {
- copy_v2_v2(data->old_markers[a], track->markers[a].pos);
- }
- }
- else if (action == SLIDE_ACTION_POS) {
+ if (action == SLIDE_ACTION_POS) {
data->corners = marker->pattern_corners;
data->pos = marker->pattern_corners[corner];
- copy_v2_v2(data->spos, data->pos);
}
else if (action == SLIDE_ACTION_TILT_SIZE) {
data->corners = marker->pattern_corners;
- slide_marker_tilt_slider(marker, data->spos);
}
}
else if (area == TRACK_AREA_SEARCH) {
@@ -434,7 +428,6 @@ static SlideMarkerData *create_slide_marker_data(SpaceClip *sc,
copy_v2_v2(data->old_search_min, marker->search_min);
copy_v2_v2(data->old_search_max, marker->search_max);
copy_v2_v2(data->old_pos, marker->pos);
- copy_v2_v2(data->old_offset, track->offset);
return data;
}
@@ -497,7 +490,7 @@ static int mouse_to_tilt_distance_squared(const MovieTrackingMarker *marker,
int height)
{
float slider[2];
- slide_marker_tilt_slider(marker, slider);
+ slide_marker_tilt_slider(marker->pos, marker->pattern_corners, slider);
return mouse_to_slide_zone_distance_squared(co, slider, width, height);
}
@@ -534,117 +527,96 @@ static bool slide_check_corners(float (*corners)[2])
return true;
}
-MovieTrackingTrack *tracking_marker_check_slide(
- bContext *C, const wmEvent *event, int *r_area, int *r_action, int *r_corner)
+static MovieTrackingTrack *tracking_marker_check_slide(
+ bContext *C, const float co[2], int *r_area, eSlideAction *r_action, int *r_corner)
{
const float distance_clip_squared = 12.0f * 12.0f;
SpaceClip *sc = CTX_wm_space_clip(C);
- ARegion *region = CTX_wm_region(C);
-
MovieClip *clip = ED_space_clip_get_clip(sc);
- MovieTrackingTrack *track;
- int width, height;
- float co[2];
ListBase *tracksbase = BKE_tracking_get_active_tracks(&clip->tracking);
- int framenr = ED_space_clip_get_clip_frame_number(sc);
+ const int framenr = ED_space_clip_get_clip_frame_number(sc);
float global_min_distance_squared = FLT_MAX;
- /* Sliding zone designator which is the closest to the mouse
- * across all the tracks.
- */
- int min_action = -1, min_area = 0, min_corner = -1;
+ /* Sliding zone designator which is the closest to the mouse across all the tracks. */
+ eSlideAction min_action;
+ int min_area = 0, min_corner = -1;
MovieTrackingTrack *min_track = NULL;
+ int width, height;
ED_space_clip_get_size(sc, &width, &height);
-
if (width == 0 || height == 0) {
return NULL;
}
- ED_clip_mouse_pos(sc, region, event->mval, co);
+ LISTBASE_FOREACH (MovieTrackingTrack *, track, tracksbase) {
+ if (!TRACK_VIEW_SELECTED(sc, track) || (track->flag & TRACK_LOCKED)) {
+ continue;
+ }
- track = tracksbase->first;
- while (track) {
- if (TRACK_VIEW_SELECTED(sc, track) && (track->flag & TRACK_LOCKED) == 0) {
- const MovieTrackingMarker *marker = BKE_tracking_marker_get(track, framenr);
- /* Sliding zone designator which is the closest to the mouse for
- * the current tracks.
- */
- float min_distance_squared = FLT_MAX;
- int action = -1, area = 0, corner = -1;
-
- if ((marker->flag & MARKER_DISABLED) == 0) {
- float distance_squared;
-
- /* We start checking with whether the mouse is close enough
- * to the pattern offset area.
- */
- distance_squared = mouse_to_offset_distance_squared(track, marker, co, width, height);
- area = TRACK_AREA_POINT;
- action = SLIDE_ACTION_POS;
+ const MovieTrackingMarker *marker = BKE_tracking_marker_get(track, framenr);
+ if (marker->flag & MARKER_DISABLED) {
+ continue;
+ }
- /* NOTE: All checks here are assuming there's no maximum distance
- * limit, so checks are quite simple here.
- * Actual distance clipping happens later once all the sliding
- * zones are checked.
- */
+ /* We start checking with whether the mouse is close enough to the pattern offset area. */
+ float distance_squared = mouse_to_offset_distance_squared(track, marker, co, width, height);
+
+ /* Sliding zone designator which is the closest to the mouse for the current tracks.
+ *
+ * NOTE: All checks here are assuming there's no maximum distance limit, so checks are quite
+ * simple here. Actual distance clipping happens later once all the sliding zones are checked.
+ */
+ float min_distance_squared = distance_squared;
+ int area = TRACK_AREA_POINT;
+ int action = SLIDE_ACTION_POS;
+ int corner = -1;
+
+ /* If search area is visible, check how close to its sliding zones mouse is. */
+ if (sc->flag & SC_SHOW_MARKER_SEARCH) {
+ distance_squared = mouse_to_search_corner_distance_squared(marker, co, 1, width, height);
+ if (distance_squared < min_distance_squared) {
+ area = TRACK_AREA_SEARCH;
+ action = SLIDE_ACTION_OFFSET;
min_distance_squared = distance_squared;
+ }
- /* If search area is visible, check how close to its sliding
- * zones mouse is.
- */
- if (sc->flag & SC_SHOW_MARKER_SEARCH) {
- distance_squared = mouse_to_search_corner_distance_squared(marker, co, 1, width, height);
- if (distance_squared < min_distance_squared) {
- area = TRACK_AREA_SEARCH;
- action = SLIDE_ACTION_OFFSET;
- min_distance_squared = distance_squared;
- }
-
- distance_squared = mouse_to_search_corner_distance_squared(marker, co, 0, width, height);
- if (distance_squared < min_distance_squared) {
- area = TRACK_AREA_SEARCH;
- action = SLIDE_ACTION_SIZE;
- min_distance_squared = distance_squared;
- }
- }
-
- /* If pattern area is visible, check which corner is closest to
- * the mouse.
- */
- if (sc->flag & SC_SHOW_MARKER_PATTERN) {
- int current_corner = -1;
- distance_squared = mouse_to_closest_pattern_corner_distance_squared(
- marker, co, width, height, &current_corner);
- if (distance_squared < min_distance_squared) {
- area = TRACK_AREA_PAT;
- action = SLIDE_ACTION_POS;
- corner = current_corner;
- min_distance_squared = distance_squared;
- }
+ distance_squared = mouse_to_search_corner_distance_squared(marker, co, 0, width, height);
+ if (distance_squared < min_distance_squared) {
+ area = TRACK_AREA_SEARCH;
+ action = SLIDE_ACTION_SIZE;
+ min_distance_squared = distance_squared;
+ }
+ }
- /* Here we also check whether the mouse is actually closer to
- * the widget which controls scale and tilt.
- */
- distance_squared = mouse_to_tilt_distance_squared(marker, co, width, height);
- if (distance_squared < min_distance_squared) {
- area = TRACK_AREA_PAT;
- action = SLIDE_ACTION_TILT_SIZE;
- min_distance_squared = distance_squared;
- }
- }
+ /* If pattern area is visible, check which corner is closest to the mouse. */
+ if (sc->flag & SC_SHOW_MARKER_PATTERN) {
+ int current_corner = -1;
+ distance_squared = mouse_to_closest_pattern_corner_distance_squared(
+ marker, co, width, height, &current_corner);
+ if (distance_squared < min_distance_squared) {
+ area = TRACK_AREA_PAT;
+ action = SLIDE_ACTION_POS;
+ corner = current_corner;
+ min_distance_squared = distance_squared;
+ }
- if (min_distance_squared < global_min_distance_squared) {
- min_area = area;
- min_action = action;
- min_corner = corner;
- min_track = track;
- global_min_distance_squared = min_distance_squared;
- }
+ /* Here we also check whether the mouse is actually closer to the widget which controls scale
+ * and tilt. */
+ distance_squared = mouse_to_tilt_distance_squared(marker, co, width, height);
+ if (distance_squared < min_distance_squared) {
+ area = TRACK_AREA_PAT;
+ action = SLIDE_ACTION_TILT_SIZE;
+ min_distance_squared = distance_squared;
}
}
- track = track->next;
+ if (min_distance_squared < global_min_distance_squared) {
+ min_area = area;
+ min_action = action;
+ min_corner = corner;
+ min_track = track;
+ global_min_distance_squared = min_distance_squared;
+ }
}
if (global_min_distance_squared < distance_clip_squared / sc->zoom) {
@@ -659,9 +631,16 @@ MovieTrackingTrack *tracking_marker_check_slide(
}
return min_track;
}
+
return NULL;
}
+struct MovieTrackingTrack *tracking_find_slidable_track_in_proximity(struct bContext *C,
+ const float co[2])
+{
+ return tracking_marker_check_slide(C, co, NULL, NULL, NULL);
+}
+
static void *slide_marker_customdata(bContext *C, const wmEvent *event)
{
SpaceClip *sc = CTX_wm_space_clip(C);
@@ -672,7 +651,8 @@ static void *slide_marker_customdata(bContext *C, const wmEvent *event)
float co[2];
void *customdata = NULL;
int framenr = ED_space_clip_get_clip_frame_number(sc);
- int area, action, corner;
+ eSlideAction action;
+ int area, corner;
ED_space_clip_get_size(sc, &width, &height);
@@ -682,7 +662,7 @@ static void *slide_marker_customdata(bContext *C, const wmEvent *event)
ED_clip_mouse_pos(sc, region, event->mval, co);
- track = tracking_marker_check_slide(C, event, &area, &action, &corner);
+ track = tracking_marker_check_slide(C, co, &area, &action, &corner);
if (track != NULL) {
MovieTrackingMarker *marker = BKE_tracking_marker_get(track, framenr);
customdata = create_slide_marker_data(
@@ -718,14 +698,12 @@ static int slide_marker_invoke(bContext *C, wmOperator *op, const wmEvent *event
static void cancel_mouse_slide(SlideMarkerData *data)
{
- MovieTrackingTrack *track = data->track;
MovieTrackingMarker *marker = data->marker;
memcpy(marker->pattern_corners, data->old_corners, sizeof(marker->pattern_corners));
copy_v2_v2(marker->search_min, data->old_search_min);
copy_v2_v2(marker->search_max, data->old_search_max);
copy_v2_v2(marker->pos, data->old_pos);
- copy_v2_v2(track->offset, data->old_offset);
if (data->old_markers != NULL) {
for (int a = 0; a < data->track->markersnr; a++) {
@@ -765,7 +743,6 @@ static void free_slide_data(SlideMarkerData *data)
static int slide_marker_modal(bContext *C, wmOperator *op, const wmEvent *event)
{
SpaceClip *sc = CTX_wm_space_clip(C);
- ARegion *region = CTX_wm_region(C);
SlideMarkerData *data = (SlideMarkerData *)op->customdata;
float dx, dy, mdelta[2];
@@ -804,110 +781,66 @@ static int slide_marker_modal(bContext *C, wmOperator *op, const wmEvent *event)
}
if (data->area == TRACK_AREA_POINT) {
- if (data->action == SLIDE_ACTION_OFFSET) {
- data->offset[0] = data->old_offset[0] + dx;
- data->offset[1] = data->old_offset[1] + dy;
- }
- else {
- data->pos[0] = data->old_pos[0] + dx;
- data->pos[1] = data->old_pos[1] + dy;
- }
+ data->pos[0] += dx;
+ data->pos[1] += dy;
WM_event_add_notifier(C, NC_OBJECT | ND_TRANSFORM, NULL);
DEG_id_tag_update(&sc->clip->id, 0);
}
else if (data->area == TRACK_AREA_PAT) {
- if (data->action == SLIDE_ACTION_SIZE) {
- float start[2], end[2];
- float scale;
-
- ED_clip_point_stable_pos(sc, region, data->mval[0], data->mval[1], &start[0], &start[1]);
-
- sub_v2_v2(start, data->old_pos);
-
- if (len_squared_v2(start) != 0.0f) {
- float mval[2];
-
- if (data->accurate) {
- mval[0] = data->mval[0] + (event->mval[0] - data->mval[0]) / 5.0f;
- mval[1] = data->mval[1] + (event->mval[1] - data->mval[1]) / 5.0f;
- }
- else {
- mval[0] = event->mval[0];
- mval[1] = event->mval[1];
- }
+ if (data->action == SLIDE_ACTION_POS) {
+ float prev_pos[2];
+ copy_v2_v2(prev_pos, data->pos);
- ED_clip_point_stable_pos(sc, region, mval[0], mval[1], &end[0], &end[1]);
-
- sub_v2_v2(end, data->old_pos);
- scale = len_v2(end) / len_v2(start);
-
- if (scale > 0.0f) {
- for (int a = 0; a < 4; a++) {
- mul_v2_v2fl(data->corners[a], data->old_corners[a], scale);
- }
- }
- }
-
- BKE_tracking_marker_clamp(data->marker, CLAMP_PAT_DIM);
- }
- else if (data->action == SLIDE_ACTION_OFFSET) {
- const float d[2] = {dx, dy};
- for (int a = 0; a < data->track->markersnr; a++) {
- add_v2_v2v2(data->track->markers[a].pos, data->old_markers[a], d);
- }
- sub_v2_v2v2(data->offset, data->old_offset, d);
- }
- else if (data->action == SLIDE_ACTION_POS) {
- float spos[2];
-
- copy_v2_v2(spos, data->pos);
-
- data->pos[0] = data->spos[0] + dx;
- data->pos[1] = data->spos[1] + dy;
+ data->pos[0] += dx;
+ data->pos[1] += dy;
if (!slide_check_corners(data->corners)) {
- copy_v2_v2(data->pos, spos);
+ copy_v2_v2(data->pos, prev_pos);
}
- /* Currently only patterns are allowed to have such
- * combination of event and data.
- */
- BKE_tracking_marker_clamp(data->marker, CLAMP_PAT_DIM);
+ /* Allow pattern to be arbitrary size and resize search area if needed. */
+ BKE_tracking_marker_clamp_search_size(data->marker);
}
else if (data->action == SLIDE_ACTION_TILT_SIZE) {
- const float mouse_delta[2] = {dx, dy};
-
- /* Vector which connects marker position with tilt/scale sliding area before sliding
- * began. */
- float start[2];
- sub_v2_v2v2(start, data->spos, data->old_pos);
- start[0] *= data->width;
- start[1] *= data->height;
-
- /* Vector which connects marker position with tilt/scale sliding area with the sliding
- * delta applied. */
- float end[2];
- add_v2_v2v2(end, data->spos, mouse_delta);
- sub_v2_v2(end, data->old_pos);
- end[0] *= data->width;
- end[1] *= data->height;
+ const float delta[2] = {dx, dy};
+
+ /* Slider position relative to the marker position using current state of pattern
+ * corners. */
+ float slider[2];
+ slide_marker_tilt_slider_relative(data->corners, slider);
+
+ /* Vector which connects marker position with the slider state at the current corners
+ * state.
+ * The coordinate is in the pixel space. */
+ float start_px[2];
+ copy_v2_v2(start_px, slider);
+ start_px[0] *= data->width;
+ start_px[1] *= data->height;
+
+ /* Vector which connects marker position with the slider state with the new mouse delta
+ * taken into account.
+ * The coordinate is in the pixel space. */
+ float end_px[2];
+ add_v2_v2v2(end_px, slider, delta);
+ end_px[0] *= data->width;
+ end_px[1] *= data->height;
float scale = 1.0f;
- if (len_squared_v2(start) != 0.0f) {
- scale = len_v2(end) / len_v2(start);
+ if (len_squared_v2(start_px) != 0.0f) {
+ scale = len_v2(end_px) / len_v2(start_px);
if (scale < 0.0f) {
scale = 0.0;
}
}
- const float angle = -angle_signed_v2v2(start, end);
+ const float angle = -angle_signed_v2v2(start_px, end_px);
for (int a = 0; a < 4; a++) {
float vec[2];
- mul_v2_v2fl(data->corners[a], data->old_corners[a], scale);
+ mul_v2_fl(data->corners[a], scale);
copy_v2_v2(vec, data->corners[a]);
vec[0] *= data->width;
@@ -917,30 +850,32 @@ static int slide_marker_modal(bContext *C, wmOperator *op, const wmEvent *event)
data->corners[a][1] = (vec[1] * cosf(angle) + vec[0] * sinf(angle)) / data->height;
}
- BKE_tracking_marker_clamp(data->marker, CLAMP_PAT_DIM);
+ BKE_tracking_marker_clamp_search_size(data->marker);
}
}
else if (data->area == TRACK_AREA_SEARCH) {
if (data->action == SLIDE_ACTION_SIZE) {
- data->min[0] = data->old_search_min[0] - dx;
- data->max[0] = data->old_search_max[0] + dx;
+ data->min[0] -= dx;
+ data->min[1] += dy;
- data->min[1] = data->old_search_min[1] + dy;
- data->max[1] = data->old_search_max[1] - dy;
+ data->max[0] += dx;
+ data->max[1] -= dy;
- BKE_tracking_marker_clamp(data->marker, CLAMP_SEARCH_DIM);
- }
- else if (data->area == TRACK_AREA_SEARCH) {
- const float d[2] = {dx, dy};
- add_v2_v2v2(data->min, data->old_search_min, d);
- add_v2_v2v2(data->max, data->old_search_max, d);
+ BKE_tracking_marker_clamp_search_size(data->marker);
}
+ else if (data->action == SLIDE_ACTION_OFFSET) {
+ const float delta[2] = {dx, dy};
+ add_v2_v2(data->min, delta);
+ add_v2_v2(data->max, delta);
- BKE_tracking_marker_clamp(data->marker, CLAMP_SEARCH_POS);
+ BKE_tracking_marker_clamp_search_position(data->marker);
+ }
}
data->marker->flag &= ~MARKER_TRACKED;
+ copy_v2_v2_int(data->mval, event->mval);
+
WM_event_add_notifier(C, NC_MOVIECLIP | NA_EDITED, NULL);
break;
@@ -1012,9 +947,9 @@ static int clear_track_path_exec(bContext *C, wmOperator *op)
MovieClip *clip = ED_space_clip_get_clip(sc);
MovieTracking *tracking = &clip->tracking;
ListBase *tracksbase = BKE_tracking_get_active_tracks(tracking);
- int action = RNA_enum_get(op->ptr, "action");
+ const eTrackClearAction action = RNA_enum_get(op->ptr, "action");
const bool clear_active = RNA_boolean_get(op->ptr, "clear_active");
- int framenr = ED_space_clip_get_clip_frame_number(sc);
+ const int framenr = ED_space_clip_get_clip_frame_number(sc);
if (clear_active) {
MovieTrackingTrack *track = BKE_tracking_track_get_active(tracking);
diff --git a/source/blender/editors/space_clip/tracking_select.c b/source/blender/editors/space_clip/tracking_select.c
index 5f940b817a9..28e304bfa74 100644
--- a/source/blender/editors/space_clip/tracking_select.c
+++ b/source/blender/editors/space_clip/tracking_select.c
@@ -273,7 +273,18 @@ void ed_tracking_deselect_all_plane_tracks(ListBase *plane_tracks_base)
}
}
-static int mouse_select(bContext *C, const float co[2], const bool extend, const bool deselect_all)
+static bool select_poll(bContext *C)
+{
+ SpaceClip *sc = CTX_wm_space_clip(C);
+
+ if (sc) {
+ return sc->clip && sc->view == SC_VIEW_CLIP;
+ }
+
+ return false;
+}
+
+static int select_exec(bContext *C, wmOperator *op)
{
SpaceClip *sc = CTX_wm_space_clip(C);
MovieClip *clip = ED_space_clip_get_clip(sc);
@@ -281,12 +292,35 @@ static int mouse_select(bContext *C, const float co[2], const bool extend, const
ListBase *tracksbase = BKE_tracking_get_active_tracks(tracking);
ListBase *plane_tracks_base = BKE_tracking_get_active_plane_tracks(tracking);
MovieTrackingTrack *act_track = BKE_tracking_track_get_active(tracking);
- MovieTrackingTrack *track;
- MovieTrackingPlaneTrack *plane_track;
+ const bool extend = RNA_boolean_get(op->ptr, "extend");
+ const bool deselect_all = RNA_boolean_get(op->ptr, "deselect_all");
+
+ float co[2];
+ RNA_float_get_array(op->ptr, "location", co);
+
+ /* Special code which allows to slide a marker which belongs to currently selected but not yet
+ * active track. If such track is found activate it and return pass-though so that marker slide
+ * operator can be used immediately after.
+ * This logic makes it convenient to slide markers when left mouse selection is used. */
+ if (!extend) {
+ MovieTrackingTrack *track = tracking_find_slidable_track_in_proximity(C, co);
+ if (track != NULL) {
+ MovieClip *clip_iter = ED_space_clip_get_clip(sc);
+
+ clip_iter->tracking.act_track = track;
+
+ WM_event_add_notifier(C, NC_GEOM | ND_SELECT, NULL);
+ DEG_id_tag_update(&clip_iter->id, ID_RECALC_SELECT);
+
+ return OPERATOR_PASS_THROUGH;
+ }
+ }
+
float distance_to_track, distance_to_plane_track;
- track = find_nearest_track(sc, tracksbase, co, &distance_to_track);
- plane_track = find_nearest_plane_track(sc, plane_tracks_base, co, &distance_to_plane_track);
+ MovieTrackingTrack *track = find_nearest_track(sc, tracksbase, co, &distance_to_track);
+ MovieTrackingPlaneTrack *plane_track = find_nearest_plane_track(
+ sc, plane_tracks_base, co, &distance_to_plane_track);
ClipViewLockState lock_state;
ED_clip_view_lock_state_store(C, &lock_state);
@@ -360,8 +394,6 @@ static int mouse_select(bContext *C, const float co[2], const bool extend, const
else if (deselect_all) {
ed_tracking_deselect_all_tracks(tracksbase);
ed_tracking_deselect_all_plane_tracks(plane_tracks_base);
- /* Mask as well if we are in combined mask / track view. */
- ED_mask_deselect_all(C);
}
ED_clip_view_lock_state_restore_no_jump(C, &lock_state);
@@ -375,51 +407,12 @@ static int mouse_select(bContext *C, const float co[2], const bool extend, const
return OPERATOR_FINISHED | OPERATOR_PASS_THROUGH;
}
-static bool select_poll(bContext *C)
-{
- SpaceClip *sc = CTX_wm_space_clip(C);
-
- if (sc) {
- return sc->clip && sc->view == SC_VIEW_CLIP;
- }
-
- return false;
-}
-
-static int select_exec(bContext *C, wmOperator *op)
-{
- float co[2];
-
- RNA_float_get_array(op->ptr, "location", co);
- const bool extend = RNA_boolean_get(op->ptr, "extend");
- const bool deselect_all = RNA_boolean_get(op->ptr, "deselect_all");
-
- return mouse_select(C, co, extend, deselect_all);
-}
-
static int select_invoke(bContext *C, wmOperator *op, const wmEvent *event)
{
SpaceClip *sc = CTX_wm_space_clip(C);
ARegion *region = CTX_wm_region(C);
float co[2];
- const bool extend = RNA_boolean_get(op->ptr, "extend");
-
- if (!extend) {
- MovieTrackingTrack *track = tracking_marker_check_slide(C, event, NULL, NULL, NULL);
-
- if (track) {
- MovieClip *clip = ED_space_clip_get_clip(sc);
-
- clip->tracking.act_track = track;
-
- WM_event_add_notifier(C, NC_GEOM | ND_SELECT, NULL);
- DEG_id_tag_update(&clip->id, ID_RECALC_SELECT);
-
- return OPERATOR_PASS_THROUGH;
- }
- }
-
ED_clip_mouse_pos(sc, region, event->mval, co);
RNA_float_set_array(op->ptr, "location", co);
@@ -835,6 +828,7 @@ void CLIP_OT_select_circle(wmOperatorType *ot)
ot->modal = WM_gesture_circle_modal;
ot->exec = circle_select_exec;
ot->poll = ED_space_clip_tracking_poll;
+ ot->get_name = ED_select_circle_get_name;
/* flags */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
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 e5a4919f548..87595ecdb88 100644
--- a/source/blender/editors/space_file/asset_catalog_tree_view.cc
+++ b/source/blender/editors/space_file/asset_catalog_tree_view.cc
@@ -407,8 +407,15 @@ std::string AssetCatalogDropController::drop_tooltip_asset_list(const wmDrag &dr
std::string basic_tip = is_multiple_assets ? TIP_("Move assets to catalog") :
TIP_("Move asset to catalog");
- return basic_tip + ": " + catalog_item_.get_name() + " (" + catalog_item_.catalog_path().str() +
- ")";
+ basic_tip += ": " + catalog_item_.get_name();
+
+ /* Display the full catalog path, but only if it's not exactly the same as the already shown name
+ * (i.e. not a root level catalog with no parent). */
+ if (catalog_item_.get_name() != catalog_item_.catalog_path().str()) {
+ basic_tip += " (" + catalog_item_.catalog_path().str() + ")";
+ }
+
+ return basic_tip;
}
bool AssetCatalogDropController::on_drop(struct bContext *C, const wmDrag &drag)
diff --git a/source/blender/editors/space_file/file_intern.h b/source/blender/editors/space_file/file_intern.h
index 1ee6445f4ba..655a7983e2b 100644
--- a/source/blender/editors/space_file/file_intern.h
+++ b/source/blender/editors/space_file/file_intern.h
@@ -83,6 +83,7 @@ void FILE_OT_rename(struct wmOperatorType *ot);
void FILE_OT_smoothscroll(struct wmOperatorType *ot);
void FILE_OT_filepath_drop(struct wmOperatorType *ot);
void FILE_OT_start_filter(struct wmOperatorType *ot);
+void FILE_OT_edit_directory_path(struct wmOperatorType *ot);
void FILE_OT_view_selected(struct wmOperatorType *ot);
void file_directory_enter_handle(bContext *C, void *arg_unused, void *arg_but);
diff --git a/source/blender/editors/space_file/file_ops.c b/source/blender/editors/space_file/file_ops.c
index 578288ca289..62bdd583bc1 100644
--- a/source/blender/editors/space_file/file_ops.c
+++ b/source/blender/editors/space_file/file_ops.c
@@ -2914,9 +2914,9 @@ void FILE_OT_delete(struct wmOperatorType *ot)
static int file_start_filter_exec(bContext *C, wmOperator *UNUSED(op))
{
- ScrArea *area = CTX_wm_area(C);
- SpaceFile *sfile = CTX_wm_space_file(C);
- FileSelectParams *params = ED_fileselect_get_active_params(sfile);
+ const ScrArea *area = CTX_wm_area(C);
+ const SpaceFile *sfile = CTX_wm_space_file(C);
+ const FileSelectParams *params = ED_fileselect_get_active_params(sfile);
ARegion *region_ctx = CTX_wm_region(C);
@@ -2950,6 +2950,46 @@ void FILE_OT_start_filter(struct wmOperatorType *ot)
/** \} */
/* -------------------------------------------------------------------- */
+/** \name Edit Directory Path Operator
+ * \{ */
+
+static int file_edit_directory_path_exec(bContext *C, wmOperator *UNUSED(op))
+{
+ const ScrArea *area = CTX_wm_area(C);
+ const SpaceFile *sfile = CTX_wm_space_file(C);
+ const FileSelectParams *params = ED_fileselect_get_active_params(sfile);
+
+ ARegion *region_ctx = CTX_wm_region(C);
+
+ if (area) {
+ LISTBASE_FOREACH (ARegion *, region, &area->regionbase) {
+ CTX_wm_region_set(C, region);
+ if (UI_textbutton_activate_rna(C, region, params, "directory")) {
+ break;
+ }
+ }
+ }
+
+ CTX_wm_region_set(C, region_ctx);
+
+ return OPERATOR_FINISHED;
+}
+
+void FILE_OT_edit_directory_path(struct wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Edit Directory Path";
+ ot->description = "Start editing directory field";
+ ot->idname = "FILE_OT_edit_directory_path";
+
+ /* api callbacks */
+ ot->exec = file_edit_directory_path_exec;
+ ot->poll = ED_operator_file_active;
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
/** \name Macro Operators
* \{ */
diff --git a/source/blender/editors/space_file/filelist.c b/source/blender/editors/space_file/filelist.c
index 9f71d6f77c7..183af0c14f5 100644
--- a/source/blender/editors/space_file/filelist.c
+++ b/source/blender/editors/space_file/filelist.c
@@ -336,7 +336,7 @@ enum {
};
typedef struct FileListEntryPreview {
- char path[FILE_MAX];
+ char filepath[FILE_MAX];
uint flags;
int index;
int attributes; /* from FileDirEntry. */
@@ -1636,13 +1636,13 @@ static void filelist_cache_preview_runf(TaskPool *__restrict pool, void *taskdat
source = THB_SOURCE_FONT;
}
- IMB_thumb_path_lock(preview->path);
+ IMB_thumb_path_lock(preview->filepath);
/* Always generate biggest preview size for now, it's simpler and avoids having to re-generate
* in case user switch to a bigger preview size. Do not create preview when file is offline. */
ImBuf *imbuf = (preview->attributes & FILE_ATTR_OFFLINE) ?
- IMB_thumb_read(preview->path, THB_LARGE) :
- IMB_thumb_manage(preview->path, THB_LARGE, source);
- IMB_thumb_path_unlock(preview->path);
+ IMB_thumb_read(preview->filepath, THB_LARGE) :
+ IMB_thumb_manage(preview->filepath, THB_LARGE, source);
+ IMB_thumb_path_unlock(preview->filepath);
if (imbuf) {
preview->icon_id = BKE_icon_imbuf_create(imbuf);
}
@@ -1753,7 +1753,7 @@ static void filelist_cache_previews_push(FileList *filelist, FileDirEntry *entry
if (preview_in_memory) {
/* TODO(mano-wii): No need to use the thread API here. */
BLI_assert(BKE_previewimg_is_finished(preview_in_memory, ICON_SIZE_PREVIEW));
- preview->path[0] = '\0';
+ preview->filepath[0] = '\0';
ImBuf *imbuf = BKE_previewimg_to_imbuf(preview_in_memory, ICON_SIZE_PREVIEW);
if (imbuf) {
preview->icon_id = BKE_icon_imbuf_create(imbuf);
@@ -1762,13 +1762,13 @@ static void filelist_cache_previews_push(FileList *filelist, FileDirEntry *entry
}
else {
if (entry->redirection_path) {
- BLI_strncpy(preview->path, entry->redirection_path, FILE_MAXDIR);
+ BLI_strncpy(preview->filepath, entry->redirection_path, FILE_MAXDIR);
}
else {
BLI_join_dirfile(
- preview->path, sizeof(preview->path), filelist->filelist.root, entry->relpath);
+ preview->filepath, sizeof(preview->filepath), filelist->filelist.root, entry->relpath);
}
- // printf("%s: %d - %s\n", __func__, preview->index, preview->path);
+ // printf("%s: %d - %s\n", __func__, preview->index, preview->filepath);
FileListEntryPreviewTaskData *preview_taskdata = MEM_mallocN(sizeof(*preview_taskdata),
__func__);
@@ -2667,7 +2667,7 @@ bool filelist_cache_previews_update(FileList *filelist)
* we do not want to cache it again here. */
entry = filelist_file_ex(filelist, preview->index, false);
- // printf("%s: %d - %s - %p\n", __func__, preview->index, preview->path, preview->img);
+ // printf("%s: %d - %s - %p\n", __func__, preview->index, preview->filepath, preview->img);
if (entry) {
if (preview->icon_id) {
@@ -2802,7 +2802,8 @@ int ED_path_extension_type(const char *path)
if (BLI_path_extension_check(path, ".zip")) {
return FILE_TYPE_ARCHIVE;
}
- if (BLI_path_extension_check_n(path, ".obj", ".3ds", ".fbx", ".glb", ".gltf", ".svg", NULL)) {
+ if (BLI_path_extension_check_n(
+ path, ".obj", ".mtl", ".3ds", ".fbx", ".glb", ".gltf", ".svg", ".stl", NULL)) {
return FILE_TYPE_OBJECT_IO;
}
if (BLI_path_extension_check_array(path, imb_ext_image)) {
@@ -3074,7 +3075,7 @@ static int filelist_readjob_list_dir(const char *root,
}
target = entry->redirection_path;
#ifdef WIN32
- /* On Windows don't show ".lnk" extension for valid shortcuts. */
+ /* On Windows don't show `.lnk` extension for valid shortcuts. */
BLI_path_extension_replace(entry->relpath, FILE_MAXDIR, "");
#endif
}
diff --git a/source/blender/editors/space_file/filesel.c b/source/blender/editors/space_file/filesel.c
index 011506368ee..e42e1e98660 100644
--- a/source/blender/editors/space_file/filesel.c
+++ b/source/blender/editors/space_file/filesel.c
@@ -983,6 +983,7 @@ void ED_fileselect_init_layout(struct SpaceFile *sfile, ARegion *region)
if (params->display == FILE_IMGDISPLAY) {
const float pad_fac = compact ? 0.15f : 0.3f;
+ /* Matches UI_preview_tile_size_x()/_y() by default. */
layout->prv_w = ((float)params->thumbnail_size / 20.0f) * UI_UNIT_X;
layout->prv_h = ((float)params->thumbnail_size / 20.0f) * UI_UNIT_Y;
layout->tile_border_x = pad_fac * UI_UNIT_X;
@@ -1009,6 +1010,7 @@ void ED_fileselect_init_layout(struct SpaceFile *sfile, ARegion *region)
else if (params->display == FILE_VERTICALDISPLAY) {
int rowcount;
+ /* Matches UI_preview_tile_size_x()/_y() by default. */
layout->prv_w = ((float)params->thumbnail_size / 20.0f) * UI_UNIT_X;
layout->prv_h = ((float)params->thumbnail_size / 20.0f) * UI_UNIT_Y;
layout->tile_border_x = 0.4f * UI_UNIT_X;
@@ -1030,6 +1032,7 @@ void ED_fileselect_init_layout(struct SpaceFile *sfile, ARegion *region)
layout->flag = FILE_LAYOUT_VER;
}
else if (params->display == FILE_HORIZONTALDISPLAY) {
+ /* Matches UI_preview_tile_size_x()/_y() by default. */
layout->prv_w = ((float)params->thumbnail_size / 20.0f) * UI_UNIT_X;
layout->prv_h = ((float)params->thumbnail_size / 20.0f) * UI_UNIT_Y;
layout->tile_border_x = 0.4f * UI_UNIT_X;
@@ -1364,3 +1367,21 @@ ScrArea *ED_fileselect_handler_area_find(const wmWindow *win, const wmOperator *
return NULL;
}
+
+ScrArea *ED_fileselect_handler_area_find_any_with_op(const wmWindow *win)
+{
+ const bScreen *screen = WM_window_get_active_screen(win);
+
+ ED_screen_areas_iter (win, screen, area) {
+ if (area->spacetype != SPACE_FILE) {
+ continue;
+ }
+
+ const SpaceFile *sfile = area->spacedata.first;
+ if (sfile->op) {
+ return area;
+ }
+ }
+
+ return NULL;
+}
diff --git a/source/blender/editors/space_file/fsmenu.c b/source/blender/editors/space_file/fsmenu.c
index 65354591034..310c688383b 100644
--- a/source/blender/editors/space_file/fsmenu.c
+++ b/source/blender/editors/space_file/fsmenu.c
@@ -519,13 +519,13 @@ void fsmenu_remove_entry(struct FSMenu *fsmenu, FSMenuCategory category, int idx
}
}
-void fsmenu_write_file(struct FSMenu *fsmenu, const char *filename)
+void fsmenu_write_file(struct FSMenu *fsmenu, const char *filepath)
{
FSMenuEntry *fsm_iter = NULL;
char fsm_name[FILE_MAX];
int nwritten = 0;
- FILE *fp = BLI_fopen(filename, "w");
+ FILE *fp = BLI_fopen(filepath, "w");
if (!fp) {
return;
}
@@ -556,14 +556,14 @@ void fsmenu_write_file(struct FSMenu *fsmenu, const char *filename)
fclose(fp);
}
-void fsmenu_read_bookmarks(struct FSMenu *fsmenu, const char *filename)
+void fsmenu_read_bookmarks(struct FSMenu *fsmenu, const char *filepath)
{
char line[FILE_MAXDIR];
char name[FILE_MAXFILE];
FSMenuCategory category = FS_CATEGORY_BOOKMARKS;
FILE *fp;
- fp = BLI_fopen(filename, "r");
+ fp = BLI_fopen(filepath, "r");
if (!fp) {
return;
}
@@ -890,7 +890,7 @@ void fsmenu_read_system(struct FSMenu *fsmenu, int read_bookmarks)
continue;
}
- /* Exclude "all my files" as it makes no sense in blender fileselector */
+ /* Exclude "all my files" as it makes no sense in blender file-selector. */
/* Exclude "airdrop" if wlan not active as it would show "" ) */
if (!strstr(line, "myDocuments.cannedSearch") && (*line != '\0')) {
fsmenu_insert_entry(
diff --git a/source/blender/editors/space_file/fsmenu.h b/source/blender/editors/space_file/fsmenu.h
index 861c37ecaa1..6e980a326fc 100644
--- a/source/blender/editors/space_file/fsmenu.h
+++ b/source/blender/editors/space_file/fsmenu.h
@@ -38,10 +38,10 @@ short fsmenu_can_save(struct FSMenu *fsmenu, enum FSMenuCategory category, int i
void fsmenu_remove_entry(struct FSMenu *fsmenu, enum FSMenuCategory category, int idx);
/** saves the 'bookmarks' to the specified file */
-void fsmenu_write_file(struct FSMenu *fsmenu, const char *filename);
+void fsmenu_write_file(struct FSMenu *fsmenu, const char *filepath);
/** reads the 'bookmarks' from the specified file */
-void fsmenu_read_bookmarks(struct FSMenu *fsmenu, const char *filename);
+void fsmenu_read_bookmarks(struct FSMenu *fsmenu, const char *filepath);
/** adds system specific directories */
void fsmenu_read_system(struct FSMenu *fsmenu, int read_bookmarks);
diff --git a/source/blender/editors/space_file/space_file.c b/source/blender/editors/space_file/space_file.c
index 0170361f244..a462476aae0 100644
--- a/source/blender/editors/space_file/space_file.c
+++ b/source/blender/editors/space_file/space_file.c
@@ -695,6 +695,7 @@ static void file_operatortypes(void)
WM_operatortype_append(FILE_OT_smoothscroll);
WM_operatortype_append(FILE_OT_filepath_drop);
WM_operatortype_append(FILE_OT_start_filter);
+ WM_operatortype_append(FILE_OT_edit_directory_path);
WM_operatortype_append(FILE_OT_view_selected);
}
diff --git a/source/blender/editors/space_graph/graph_select.c b/source/blender/editors/space_graph/graph_select.c
index 39b980ac4c3..e71c5114b0a 100644
--- a/source/blender/editors/space_graph/graph_select.c
+++ b/source/blender/editors/space_graph/graph_select.c
@@ -1080,6 +1080,7 @@ void GRAPH_OT_select_circle(wmOperatorType *ot)
ot->exec = graph_circle_select_exec;
ot->poll = graphop_visible_keyframes_poll;
ot->cancel = WM_gesture_circle_cancel;
+ ot->get_name = ED_select_circle_get_name;
/* flags */
ot->flag = OPTYPE_UNDO;
diff --git a/source/blender/editors/space_image/CMakeLists.txt b/source/blender/editors/space_image/CMakeLists.txt
index c385420b18e..39fb41245bf 100644
--- a/source/blender/editors/space_image/CMakeLists.txt
+++ b/source/blender/editors/space_image/CMakeLists.txt
@@ -61,7 +61,7 @@ if(WITH_IMAGE_CINEON)
endif()
if(WITH_IMAGE_WEBP)
- add_definitions(-DWITH_WEBP)
+ add_definitions(-DWITH_WEBP)
endif()
blender_add_lib(bf_editor_space_image "${SRC}" "${INC}" "${INC_SYS}" "${LIB}")
diff --git a/source/blender/editors/space_image/image_buttons.c b/source/blender/editors/space_image/image_buttons.c
index 208928afc1f..d0c21f85472 100644
--- a/source/blender/editors/space_image/image_buttons.c
+++ b/source/blender/editors/space_image/image_buttons.c
@@ -845,7 +845,10 @@ void uiTemplateImage(uiLayout *layout,
row = uiLayoutRow(row, true);
uiLayoutSetEnabled(row, is_packed == false);
- uiItemR(row, &imaptr, "filepath", 0, "", ICON_NONE);
+
+ prop = RNA_struct_find_property(&imaptr, "filepath");
+ uiDefAutoButR(block, &imaptr, prop, -1, "", ICON_NONE, 0, 0, 200, UI_UNIT_Y);
+ uiItemO(row, "", ICON_FILEBROWSER, "image.file_browse");
uiItemO(row, "", ICON_FILE_REFRESH, "image.reload");
}
diff --git a/source/blender/editors/space_image/image_edit.c b/source/blender/editors/space_image/image_edit.c
index e851b99d3ba..950acd77f6a 100644
--- a/source/blender/editors/space_image/image_edit.c
+++ b/source/blender/editors/space_image/image_edit.c
@@ -483,6 +483,16 @@ bool ED_space_image_maskedit_poll(bContext *C)
return false;
}
+bool ED_space_image_maskedit_visible_splines_poll(bContext *C)
+{
+ if (!ED_space_image_maskedit_poll(C)) {
+ return false;
+ }
+
+ const SpaceImage *space_image = CTX_wm_space_image(C);
+ return space_image->mask_info.draw_flag & MASK_DRAWFLAG_SPLINE;
+}
+
bool ED_space_image_paint_curve(const bContext *C)
{
SpaceImage *sima = CTX_wm_space_image(C);
@@ -508,6 +518,16 @@ bool ED_space_image_maskedit_mask_poll(bContext *C)
return false;
}
+bool ED_space_image_maskedit_mask_visible_splines_poll(bContext *C)
+{
+ if (!ED_space_image_maskedit_mask_poll(C)) {
+ return false;
+ }
+
+ const SpaceImage *space_image = CTX_wm_space_image(C);
+ return space_image->mask_info.draw_flag & MASK_DRAWFLAG_SPLINE;
+}
+
bool ED_space_image_cursor_poll(bContext *C)
{
return ED_operator_uvedit_space_image(C) || ED_space_image_maskedit_poll(C) ||
diff --git a/source/blender/editors/space_image/image_intern.h b/source/blender/editors/space_image/image_intern.h
index 2322420069e..364bec1377d 100644
--- a/source/blender/editors/space_image/image_intern.h
+++ b/source/blender/editors/space_image/image_intern.h
@@ -49,6 +49,7 @@ void IMAGE_OT_new(struct wmOperatorType *ot);
* Called by other space types too.
*/
void IMAGE_OT_open(struct wmOperatorType *ot);
+void IMAGE_OT_file_browse(struct wmOperatorType *ot);
/**
* Called by other space types too.
*/
diff --git a/source/blender/editors/space_image/image_ops.c b/source/blender/editors/space_image/image_ops.c
index aa77aab2283..537132ac428 100644
--- a/source/blender/editors/space_image/image_ops.c
+++ b/source/blender/editors/space_image/image_ops.c
@@ -197,6 +197,20 @@ static ImageUser *image_user_from_context(const bContext *C)
return (sima) ? &sima->iuser : NULL;
}
+static ImageUser image_user_from_active_tile(Image *ima)
+{
+ ImageUser iuser;
+ BKE_imageuser_default(&iuser);
+
+ /* Use the file associated with the active tile. Otherwise use the first tile. */
+ if (ima && ima->source == IMA_SRC_TILED) {
+ const ImageTile *active = (ImageTile *)BLI_findlink(&ima->tiles, ima->active_tile_index);
+ iuser.tile = active ? active->tile_number : ((ImageTile *)ima->tiles.first)->tile_number;
+ }
+
+ return iuser;
+}
+
static bool image_from_context_has_data_poll(bContext *C)
{
Image *ima = image_from_context(C);
@@ -214,13 +228,14 @@ static bool image_from_context_has_data_poll(bContext *C)
}
/**
- * Use this when the image buffer is accessed without the image user.
+ * Use this when the image buffer is accessing the active tile without the image user.
*/
-static bool image_from_context_has_data_poll_no_image_user(bContext *C)
+static bool image_from_context_has_data_poll_active_tile(bContext *C)
{
Image *ima = image_from_context(C);
+ ImageUser iuser = image_user_from_active_tile(ima);
- return BKE_image_has_ibuf(ima, NULL);
+ return BKE_image_has_ibuf(ima, &iuser);
}
static bool image_not_packed_poll(bContext *C)
@@ -949,7 +964,7 @@ static int image_view_selected_exec(bContext *C, wmOperator *UNUSED(op))
static bool image_view_selected_poll(bContext *C)
{
- return (space_image_main_region_poll(C) && (ED_operator_uvedit(C) || ED_operator_mask(C)));
+ return (space_image_main_region_poll(C) && (ED_operator_uvedit(C) || ED_maskedit_poll(C)));
}
void IMAGE_OT_view_selected(wmOperatorType *ot)
@@ -1274,8 +1289,8 @@ static Image *image_open_single(Main *bmain,
BKE_image_free_views(ima);
}
- if ((range->length > 1) && (ima->source == IMA_SRC_FILE)) {
- if (range->udim_tiles.first) {
+ if (ima->source == IMA_SRC_FILE) {
+ if (range->udims_detected && range->udim_tiles.first) {
ima->source = IMA_SRC_TILED;
ImageTile *first_tile = ima->tiles.first;
first_tile->tile_number = range->offset;
@@ -1283,7 +1298,7 @@ static Image *image_open_single(Main *bmain,
BKE_image_add_tile(ima, POINTER_AS_INT(node->data), NULL);
}
}
- else {
+ else if (range->length > 1) {
ima->source = IMA_SRC_SEQUENCE;
}
}
@@ -1446,7 +1461,7 @@ static int image_open_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(
image_open_init(C, op);
- /* show multiview save options only if scene has multiviews */
+ /* Show multi-view save options only if scene has multi-views. */
PropertyRNA *prop;
prop = RNA_struct_find_property(op->ptr, "show_multiview");
RNA_property_boolean_set(op->ptr, prop, (scene->r.scemode & R_MULTIVIEW) != 0);
@@ -1535,6 +1550,115 @@ void IMAGE_OT_open(wmOperatorType *ot)
/** \} */
/* -------------------------------------------------------------------- */
+/** \name Browse Image Operator
+ * \{ */
+
+static int image_file_browse_exec(bContext *C, wmOperator *op)
+{
+ Image *ima = op->customdata;
+ if (ima == NULL) {
+ return OPERATOR_CANCELLED;
+ }
+
+ char filepath[FILE_MAX];
+ RNA_string_get(op->ptr, "filepath", filepath);
+
+ /* If loading into a tiled texture, ensure that the filename is tokenized. */
+ if (ima->source == IMA_SRC_TILED) {
+ char *filename = (char *)BLI_path_basename(filepath);
+ BKE_image_ensure_tile_token(filename);
+ }
+
+ PointerRNA imaptr;
+ PropertyRNA *imaprop;
+ RNA_id_pointer_create(&ima->id, &imaptr);
+ imaprop = RNA_struct_find_property(&imaptr, "filepath");
+
+ RNA_property_string_set(&imaptr, imaprop, filepath);
+ RNA_property_update(C, &imaptr, imaprop);
+
+ return OPERATOR_FINISHED;
+}
+
+static int image_file_browse_invoke(bContext *C, wmOperator *op, const wmEvent *event)
+{
+ Image *ima = image_from_context(C);
+ if (!ima) {
+ return OPERATOR_CANCELLED;
+ }
+
+ char filepath[FILE_MAX];
+ BLI_strncpy(filepath, ima->filepath, sizeof(filepath));
+
+ /* Shift+Click to open the file, Alt+Click to browse a folder in the OS's browser. */
+ if (event->modifier & (KM_SHIFT | KM_ALT)) {
+ wmOperatorType *ot = WM_operatortype_find("WM_OT_path_open", true);
+ PointerRNA props_ptr;
+
+ if (event->modifier & KM_ALT) {
+ char *lslash = (char *)BLI_path_slash_rfind(filepath);
+ if (lslash) {
+ *lslash = '\0';
+ }
+ }
+ else if (ima->source == IMA_SRC_TILED) {
+ ImageUser iuser = image_user_from_active_tile(ima);
+ BKE_image_user_file_path(&iuser, ima, filepath);
+ }
+
+ WM_operator_properties_create_ptr(&props_ptr, ot);
+ RNA_string_set(&props_ptr, "filepath", filepath);
+ WM_operator_name_call_ptr(C, ot, WM_OP_EXEC_DEFAULT, &props_ptr, NULL);
+ WM_operator_properties_free(&props_ptr);
+
+ return OPERATOR_CANCELLED;
+ }
+
+ /* The image is typically passed to the operator via layout/button context (e.g.
+ * #uiLayoutSetContextPointer()). The File Browser doesn't support restoring this context
+ * when calling `exec()` though, so we have to pass it the image via custom data. */
+ op->customdata = ima;
+
+ image_filesel(C, op, filepath);
+
+ return OPERATOR_RUNNING_MODAL;
+}
+
+static bool image_file_browse_poll(bContext *C)
+{
+ return image_from_context(C) != NULL;
+}
+
+void IMAGE_OT_file_browse(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Browse Image";
+ ot->description =
+ "Open an image file browser, hold Shift to open the file, Alt to browse containing "
+ "directory";
+ ot->idname = "IMAGE_OT_file_browse";
+
+ /* api callbacks */
+ ot->exec = image_file_browse_exec;
+ ot->invoke = image_file_browse_invoke;
+ ot->poll = image_file_browse_poll;
+
+ /* flags */
+ ot->flag = OPTYPE_UNDO;
+
+ /* properties */
+ WM_operator_properties_filesel(ot,
+ FILE_TYPE_FOLDER | FILE_TYPE_IMAGE | FILE_TYPE_MOVIE,
+ FILE_SPECIAL,
+ FILE_OPENFILE,
+ WM_FILESEL_FILEPATH | WM_FILESEL_RELPATH,
+ FILE_DEFAULTDISPLAY,
+ FILE_SORT_DEFAULT);
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
/** \name Match Movie Length Operator
* \{ */
@@ -1680,184 +1804,27 @@ void IMAGE_OT_replace(wmOperatorType *ot)
typedef struct ImageSaveData {
ImageUser *iuser;
Image *image;
- ImageFormatData im_format;
+ ImageSaveOptions opts;
} ImageSaveData;
-static char imtype_best_depth(ImBuf *ibuf, const char imtype)
-{
- const char depth_ok = BKE_imtype_valid_depths(imtype);
-
- if (ibuf->rect_float) {
- if (depth_ok & R_IMF_CHAN_DEPTH_32) {
- return R_IMF_CHAN_DEPTH_32;
- }
- if (depth_ok & R_IMF_CHAN_DEPTH_24) {
- return R_IMF_CHAN_DEPTH_24;
- }
- if (depth_ok & R_IMF_CHAN_DEPTH_16) {
- return R_IMF_CHAN_DEPTH_16;
- }
- if (depth_ok & R_IMF_CHAN_DEPTH_12) {
- return R_IMF_CHAN_DEPTH_12;
- }
- return R_IMF_CHAN_DEPTH_8;
- }
-
- if (depth_ok & R_IMF_CHAN_DEPTH_8) {
- return R_IMF_CHAN_DEPTH_8;
- }
- if (depth_ok & R_IMF_CHAN_DEPTH_12) {
- return R_IMF_CHAN_DEPTH_12;
- }
- if (depth_ok & R_IMF_CHAN_DEPTH_16) {
- return R_IMF_CHAN_DEPTH_16;
- }
- if (depth_ok & R_IMF_CHAN_DEPTH_24) {
- return R_IMF_CHAN_DEPTH_24;
- }
- if (depth_ok & R_IMF_CHAN_DEPTH_32) {
- return R_IMF_CHAN_DEPTH_32;
- }
- return R_IMF_CHAN_DEPTH_8; /* fallback, should not get here */
-}
-
-static int image_save_options_init(Main *bmain,
- ImageSaveOptions *opts,
- Image *ima,
- ImageUser *iuser,
- const bool guess_path,
- const bool save_as_render)
+static void image_save_options_from_op(Main *bmain, ImageSaveOptions *opts, wmOperator *op)
{
- void *lock;
- ImBuf *ibuf = BKE_image_acquire_ibuf(ima, iuser, &lock);
-
- if (ibuf) {
- Scene *scene = opts->scene;
- bool is_depth_set = false;
-
- if (ELEM(ima->type, IMA_TYPE_R_RESULT, IMA_TYPE_COMPOSITE)) {
- /* imtype */
- BKE_image_format_init_for_write(&opts->im_format, scene, NULL);
- is_depth_set = true;
- if (!BKE_image_is_multiview(ima)) {
- /* In case multiview is disabled,
- * render settings would be invalid for render result in this area. */
- opts->im_format.stereo3d_format = *ima->stereo3d_format;
- opts->im_format.views_format = ima->views_format;
- }
- }
- else {
- if (ima->source == IMA_SRC_GENERATED) {
- opts->im_format.imtype = R_IMF_IMTYPE_PNG;
- opts->im_format.compress = ibuf->foptions.quality;
- opts->im_format.planes = ibuf->planes;
- }
- else {
- BKE_image_format_from_imbuf(&opts->im_format, ibuf);
- }
-
- /* use the multiview image settings as the default */
- opts->im_format.stereo3d_format = *ima->stereo3d_format;
- opts->im_format.views_format = ima->views_format;
-
- BKE_image_format_color_management_copy_from_scene(&opts->im_format, scene);
- }
-
- opts->im_format.color_management = R_IMF_COLOR_MANAGEMENT_FOLLOW_SCENE;
-
- if (ima->source == IMA_SRC_TILED) {
- BLI_strncpy(opts->filepath, ima->filepath, sizeof(opts->filepath));
- BLI_path_abs(opts->filepath, ID_BLEND_PATH_FROM_GLOBAL(&ima->id));
- }
- else {
- BLI_strncpy(opts->filepath, ibuf->name, sizeof(opts->filepath));
- }
-
- /* sanitize all settings */
-
- /* unlikely but just in case */
- if (ELEM(opts->im_format.planes, R_IMF_PLANES_BW, R_IMF_PLANES_RGB, R_IMF_PLANES_RGBA) == 0) {
- opts->im_format.planes = R_IMF_PLANES_RGBA;
- }
-
- /* depth, account for float buffer and format support */
- if (is_depth_set == false) {
- opts->im_format.depth = imtype_best_depth(ibuf, opts->im_format.imtype);
- }
-
- /* some formats don't use quality so fallback to scenes quality */
- if (opts->im_format.quality == 0) {
- opts->im_format.quality = scene->r.im_format.quality;
- }
-
- /* check for empty path */
- if (guess_path && opts->filepath[0] == 0) {
- const bool is_prev_save = !STREQ(G.ima, "//");
- if (save_as_render) {
- if (is_prev_save) {
- BLI_strncpy(opts->filepath, G.ima, sizeof(opts->filepath));
- }
- else {
- BLI_strncpy(opts->filepath, "//untitled", sizeof(opts->filepath));
- BLI_path_abs(opts->filepath, BKE_main_blendfile_path(bmain));
- }
- }
- else {
- BLI_snprintf(opts->filepath, sizeof(opts->filepath), "//%s", ima->id.name + 2);
- BLI_path_make_safe(opts->filepath);
- BLI_path_abs(opts->filepath, is_prev_save ? G.ima : BKE_main_blendfile_path(bmain));
- }
-
- /* 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>");
- }
- }
- }
-
- BKE_image_release_ibuf(ima, ibuf, lock);
-
- return (ibuf != NULL);
-}
-
-static void image_save_options_from_op(Main *bmain,
- ImageSaveOptions *opts,
- wmOperator *op,
- ImageFormatData *imf)
-{
- if (imf) {
- BKE_image_format_free(&opts->im_format);
- BKE_image_format_copy(&opts->im_format, imf);
- }
-
if (RNA_struct_property_is_set(op->ptr, "filepath")) {
RNA_string_get(op->ptr, "filepath", opts->filepath);
BLI_path_abs(opts->filepath, BKE_main_blendfile_path(bmain));
}
-}
-
-static void image_save_options_to_op(ImageSaveOptions *opts, wmOperator *op)
-{
- if (op->customdata) {
- ImageSaveData *isd = op->customdata;
- BKE_image_format_free(&isd->im_format);
- BKE_image_format_copy(&isd->im_format, &opts->im_format);
- }
- RNA_string_set(op->ptr, "filepath", opts->filepath);
-}
-
-static bool save_image_op(
- Main *bmain, Image *ima, ImageUser *iuser, wmOperator *op, ImageSaveOptions *opts)
-{
opts->relative = (RNA_struct_find_property(op->ptr, "relative_path") &&
RNA_boolean_get(op->ptr, "relative_path"));
opts->save_copy = (RNA_struct_find_property(op->ptr, "copy") &&
RNA_boolean_get(op->ptr, "copy"));
opts->save_as_render = (RNA_struct_find_property(op->ptr, "save_as_render") &&
RNA_boolean_get(op->ptr, "save_as_render"));
+}
+static bool save_image_op(
+ Main *bmain, Image *ima, ImageUser *iuser, wmOperator *op, ImageSaveOptions *opts)
+{
WM_cursor_wait(true);
bool ok = BKE_image_save(op->reports, bmain, ima, iuser, opts);
@@ -1872,11 +1839,56 @@ static bool save_image_op(
return ok;
}
+static ImageSaveData *image_save_as_init(bContext *C, wmOperator *op)
+{
+ Main *bmain = CTX_data_main(C);
+ Image *image = image_from_context(C);
+ ImageUser *iuser = image_user_from_context(C);
+ Scene *scene = CTX_data_scene(C);
+
+ ImageSaveData *isd = MEM_callocN(sizeof(*isd), __func__);
+ isd->image = image;
+ isd->iuser = iuser;
+
+ if (!BKE_image_save_options_init(&isd->opts, bmain, scene, image, iuser, true, false)) {
+ BKE_image_save_options_free(&isd->opts);
+ MEM_freeN(isd);
+ return NULL;
+ }
+
+ isd->opts.do_newpath = true;
+
+ if (!RNA_struct_property_is_set(op->ptr, "filepath")) {
+ RNA_string_set(op->ptr, "filepath", isd->opts.filepath);
+ }
+
+ /* Enable save_copy by default for render results. */
+ if (ELEM(image->type, IMA_TYPE_R_RESULT, IMA_TYPE_COMPOSITE) &&
+ !RNA_struct_property_is_set(op->ptr, "copy")) {
+ RNA_boolean_set(op->ptr, "copy", true);
+ }
+
+ if (!RNA_struct_property_is_set(op->ptr, "save_as_render")) {
+ RNA_boolean_set(op->ptr, "save_as_render", isd->opts.save_as_render);
+ }
+
+ /* Show multiview save options only if image has multiviews. */
+ PropertyRNA *prop;
+ prop = RNA_struct_find_property(op->ptr, "show_multiview");
+ RNA_property_boolean_set(op->ptr, prop, BKE_image_is_multiview(image));
+ prop = RNA_struct_find_property(op->ptr, "use_multiview");
+ RNA_property_boolean_set(op->ptr, prop, BKE_image_is_multiview(image));
+
+ op->customdata = isd;
+
+ return isd;
+}
+
static void image_save_as_free(wmOperator *op)
{
if (op->customdata) {
ImageSaveData *isd = op->customdata;
- BKE_image_format_free(&isd->im_format);
+ BKE_image_save_options_free(&isd->opts);
MEM_freeN(op->customdata);
op->customdata = NULL;
@@ -1886,96 +1898,55 @@ static void image_save_as_free(wmOperator *op)
static int image_save_as_exec(bContext *C, wmOperator *op)
{
Main *bmain = CTX_data_main(C);
- Scene *scene = CTX_data_scene(C);
- ImageSaveOptions opts;
+ ImageSaveData *isd;
- Image *image = NULL;
- ImageUser *iuser = NULL;
- ImageFormatData *imf = NULL;
if (op->customdata) {
- ImageSaveData *isd = op->customdata;
- image = isd->image;
- iuser = isd->iuser;
- imf = &isd->im_format;
+ isd = op->customdata;
}
else {
- image = image_from_context(C);
- iuser = image_user_from_context(C);
+ isd = image_save_as_init(C, op);
+ if (isd == NULL) {
+ return OPERATOR_CANCELLED;
+ }
}
- BKE_image_save_options_init(&opts, bmain, scene);
-
- /* just in case to initialize values,
- * these should be set on invoke or by the caller. */
- image_save_options_init(bmain, &opts, image, iuser, false, false);
-
- image_save_options_from_op(bmain, &opts, op, imf);
- opts.do_newpath = true;
+ image_save_options_from_op(bmain, &isd->opts, op);
+ BKE_image_save_options_update(&isd->opts, isd->image);
- save_image_op(bmain, image, iuser, op, &opts);
+ save_image_op(bmain, isd->image, isd->iuser, op, &isd->opts);
- if (opts.save_copy == false) {
- BKE_image_free_packedfiles(image);
+ if (isd->opts.save_copy == false) {
+ BKE_image_free_packedfiles(isd->image);
}
- BKE_image_save_options_free(&opts);
-
image_save_as_free(op);
return OPERATOR_FINISHED;
}
-static bool image_save_as_check(bContext *UNUSED(C), wmOperator *op)
+static bool image_save_as_check(bContext *C, wmOperator *op)
{
+ Main *bmain = CTX_data_main(C);
ImageSaveData *isd = op->customdata;
- return WM_operator_filesel_ensure_ext_imtype(op, &isd->im_format);
+
+ image_save_options_from_op(bmain, &isd->opts, op);
+ BKE_image_save_options_update(&isd->opts, isd->image);
+
+ return WM_operator_filesel_ensure_ext_imtype(op, &isd->opts.im_format);
}
static int image_save_as_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
{
- Main *bmain = CTX_data_main(C);
- Image *ima = image_from_context(C);
- ImageUser *iuser = image_user_from_context(C);
- Scene *scene = CTX_data_scene(C);
- ImageSaveOptions opts;
- PropertyRNA *prop;
- const bool save_as_render = (ima->source == IMA_SRC_VIEWER);
-
if (RNA_struct_property_is_set(op->ptr, "filepath")) {
return image_save_as_exec(C, op);
}
- BKE_image_save_options_init(&opts, bmain, scene);
-
- if (image_save_options_init(bmain, &opts, ima, iuser, true, save_as_render) == 0) {
- BKE_image_save_options_free(&opts);
+ ImageSaveData *isd = image_save_as_init(C, op);
+ if (isd == NULL) {
return OPERATOR_CANCELLED;
}
- image_save_options_to_op(&opts, op);
- /* enable save_copy by default for render results */
- if (ELEM(ima->type, IMA_TYPE_R_RESULT, IMA_TYPE_COMPOSITE) &&
- !RNA_struct_property_is_set(op->ptr, "copy")) {
- RNA_boolean_set(op->ptr, "copy", true);
- }
-
- RNA_boolean_set(op->ptr, "save_as_render", save_as_render);
-
- ImageSaveData *isd = MEM_callocN(sizeof(*isd), __func__);
- isd->image = ima;
- isd->iuser = iuser;
-
- BKE_image_format_copy(&isd->im_format, &opts.im_format);
- op->customdata = isd;
-
- /* show multiview save options only if image has multiviews */
- prop = RNA_struct_find_property(op->ptr, "show_multiview");
- RNA_property_boolean_set(op->ptr, prop, BKE_image_is_multiview(ima));
- prop = RNA_struct_find_property(op->ptr, "use_multiview");
- RNA_property_boolean_set(op->ptr, prop, BKE_image_is_multiview(ima));
-
- image_filesel(C, op, opts.filepath);
- BKE_image_save_options_free(&opts);
+ image_filesel(C, op, isd->opts.filepath);
return OPERATOR_RUNNING_MODAL;
}
@@ -2003,7 +1974,7 @@ static void image_save_as_draw(bContext *UNUSED(C), wmOperator *op)
ImageSaveData *isd = op->customdata;
PointerRNA imf_ptr;
const bool is_multiview = RNA_boolean_get(op->ptr, "show_multiview");
- const bool use_color_management = RNA_boolean_get(op->ptr, "save_as_render");
+ const bool save_as_render = RNA_boolean_get(op->ptr, "save_as_render");
uiLayoutSetPropSep(layout, true);
uiLayoutSetPropDecorate(layout, false);
@@ -2015,8 +1986,15 @@ static void image_save_as_draw(bContext *UNUSED(C), wmOperator *op)
uiItemS(layout);
/* image template */
- RNA_pointer_create(NULL, &RNA_ImageFormatSettings, &isd->im_format, &imf_ptr);
- uiTemplateImageSettings(layout, &imf_ptr, use_color_management);
+ RNA_pointer_create(NULL, &RNA_ImageFormatSettings, &isd->opts.im_format, &imf_ptr);
+ uiTemplateImageSettings(layout, &imf_ptr, save_as_render);
+
+ if (!save_as_render) {
+ PointerRNA linear_settings_ptr = RNA_pointer_get(&imf_ptr, "linear_colorspace_settings");
+ uiLayout *col = uiLayoutColumn(layout, true);
+ uiItemS(col);
+ uiItemR(col, &linear_settings_ptr, "name", 0, IFACE_("Color Space"), ICON_NONE);
+ }
/* multiview template */
if (is_multiview) {
@@ -2062,16 +2040,19 @@ void IMAGE_OT_save_as(wmOperatorType *ot)
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
/* properties */
- RNA_def_boolean(ot->srna,
- "save_as_render",
- 0,
- "Save As Render",
- "Apply render part of display transform when saving byte image");
- RNA_def_boolean(ot->srna,
- "copy",
- 0,
- "Copy",
- "Create a new image file without modifying the current image in blender");
+ PropertyRNA *prop;
+ prop = RNA_def_boolean(ot->srna,
+ "save_as_render",
+ 0,
+ "Save As Render",
+ "Apply render part of display transform when saving byte image");
+ RNA_def_property_flag(prop, PROP_SKIP_SAVE);
+ prop = RNA_def_boolean(ot->srna,
+ "copy",
+ 0,
+ "Copy",
+ "Create a new image file without modifying the current image in blender");
+ RNA_def_property_flag(prop, PROP_SKIP_SAVE);
image_operator_prop_allow_tokens(ot);
WM_operator_properties_filesel(ot,
@@ -2138,12 +2119,11 @@ static int image_save_exec(bContext *C, wmOperator *op)
return OPERATOR_FINISHED;
}
- BKE_image_save_options_init(&opts, bmain, scene);
- if (image_save_options_init(bmain, &opts, image, iuser, false, false) == 0) {
+ if (!BKE_image_save_options_init(&opts, bmain, scene, image, iuser, false, false)) {
BKE_image_save_options_free(&opts);
return OPERATOR_CANCELLED;
}
- image_save_options_from_op(bmain, &opts, op, NULL);
+ image_save_options_from_op(bmain, &opts, op);
/* Check if file write permission is ok. */
if (BLI_exists(opts.filepath) && !BLI_file_is_writable(opts.filepath)) {
@@ -2316,6 +2296,14 @@ static bool image_has_valid_path(Image *ima)
return strchr(ima->filepath, '\\') || strchr(ima->filepath, '/');
}
+static bool image_should_pack_during_save_all(const Image *ima)
+{
+ /* Images without a filepath (implied with IMA_SRC_GENERATED) should
+ * be packed during a save_all operation. */
+ return (ima->source == IMA_SRC_GENERATED) ||
+ (ima->source == IMA_SRC_TILED && !BKE_image_has_filepath(ima));
+}
+
bool ED_image_should_save_modified(const Main *bmain)
{
ReportList reports;
@@ -2339,7 +2327,7 @@ int ED_image_save_all_modified_info(const Main *bmain, ReportList *reports)
bool is_format_writable;
if (image_should_be_saved(ima, &is_format_writable)) {
- if (BKE_image_has_packedfile(ima) || (ima->source == IMA_SRC_GENERATED)) {
+ if (BKE_image_has_packedfile(ima) || image_should_pack_during_save_all(ima)) {
if (!ID_IS_LINKED(ima)) {
num_saveable_images++;
}
@@ -2396,15 +2384,14 @@ bool ED_image_save_all_modified(const bContext *C, ReportList *reports)
bool is_format_writable;
if (image_should_be_saved(ima, &is_format_writable)) {
- if (BKE_image_has_packedfile(ima) || (ima->source == IMA_SRC_GENERATED)) {
+ if (BKE_image_has_packedfile(ima) || image_should_pack_during_save_all(ima)) {
BKE_image_memorypack(ima);
}
else if (is_format_writable) {
if (image_has_valid_path(ima)) {
ImageSaveOptions opts;
Scene *scene = CTX_data_scene(C);
- BKE_image_save_options_init(&opts, bmain, scene);
- if (image_save_options_init(bmain, &opts, ima, NULL, false, false)) {
+ if (!BKE_image_save_options_init(&opts, bmain, scene, ima, NULL, false, false)) {
bool saved_successfully = BKE_image_save(reports, bmain, ima, NULL, &opts);
ok = ok && saved_successfully;
}
@@ -2711,7 +2698,8 @@ void IMAGE_OT_new(wmOperatorType *ot)
static int image_flip_exec(bContext *C, wmOperator *op)
{
Image *ima = image_from_context(C);
- ImBuf *ibuf = BKE_image_acquire_ibuf(ima, NULL, NULL);
+ ImageUser iuser = image_user_from_active_tile(ima);
+ ImBuf *ibuf = BKE_image_acquire_ibuf(ima, &iuser, NULL);
SpaceImage *sima = CTX_wm_space_image(C);
const bool is_paint = ((sima != NULL) && (sima->mode == SI_MODE_PAINT));
@@ -2808,7 +2796,7 @@ void IMAGE_OT_flip(wmOperatorType *ot)
/* api callbacks */
ot->exec = image_flip_exec;
- ot->poll = image_from_context_has_data_poll_no_image_user;
+ ot->poll = image_from_context_has_data_poll_active_tile;
/* properties */
PropertyRNA *prop;
@@ -2831,7 +2819,8 @@ void IMAGE_OT_flip(wmOperatorType *ot)
static int image_invert_exec(bContext *C, wmOperator *op)
{
Image *ima = image_from_context(C);
- ImBuf *ibuf = BKE_image_acquire_ibuf(ima, NULL, NULL);
+ ImageUser iuser = image_user_from_active_tile(ima);
+ ImBuf *ibuf = BKE_image_acquire_ibuf(ima, &iuser, NULL);
SpaceImage *sima = CTX_wm_space_image(C);
const bool is_paint = ((sima != NULL) && (sima->mode == SI_MODE_PAINT));
@@ -2929,7 +2918,7 @@ void IMAGE_OT_invert(wmOperatorType *ot)
/* api callbacks */
ot->exec = image_invert_exec;
- ot->poll = image_from_context_has_data_poll_no_image_user;
+ ot->poll = image_from_context_has_data_poll_active_tile;
/* properties */
prop = RNA_def_boolean(ot->srna, "invert_r", 0, "Red", "Invert red channel");
@@ -2954,9 +2943,10 @@ void IMAGE_OT_invert(wmOperatorType *ot)
static int image_scale_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
{
Image *ima = image_from_context(C);
+ ImageUser iuser = image_user_from_active_tile(ima);
PropertyRNA *prop = RNA_struct_find_property(op->ptr, "size");
if (!RNA_property_is_set(op->ptr, prop)) {
- ImBuf *ibuf = BKE_image_acquire_ibuf(ima, NULL, NULL);
+ ImBuf *ibuf = BKE_image_acquire_ibuf(ima, &iuser, NULL);
const int size[2] = {ibuf->x, ibuf->y};
RNA_property_int_set_array(op->ptr, prop, size);
BKE_image_release_ibuf(ima, ibuf, NULL);
@@ -2967,7 +2957,8 @@ static int image_scale_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED
static int image_scale_exec(bContext *C, wmOperator *op)
{
Image *ima = image_from_context(C);
- ImBuf *ibuf = BKE_image_acquire_ibuf(ima, NULL, NULL);
+ ImageUser iuser = image_user_from_active_tile(ima);
+ ImBuf *ibuf = BKE_image_acquire_ibuf(ima, &iuser, NULL);
SpaceImage *sima = CTX_wm_space_image(C);
const bool is_paint = ((sima != NULL) && (sima->mode == SI_MODE_PAINT));
@@ -3017,7 +3008,7 @@ void IMAGE_OT_resize(wmOperatorType *ot)
/* api callbacks */
ot->invoke = image_scale_invoke;
ot->exec = image_scale_exec;
- ot->poll = image_from_context_has_data_poll_no_image_user;
+ ot->poll = image_from_context_has_data_poll_active_tile;
/* properties */
RNA_def_int_vector(ot->srna, "size", 2, NULL, 1, INT_MAX, "Size", "", 1, SHRT_MAX);
@@ -3040,9 +3031,8 @@ static bool image_pack_test(bContext *C, wmOperator *op)
return false;
}
- if (ELEM(ima->source, IMA_SRC_SEQUENCE, IMA_SRC_MOVIE, IMA_SRC_TILED)) {
- BKE_report(
- op->reports, RPT_ERROR, "Packing movies, image sequences or tiled images not supported");
+ if (ELEM(ima->source, IMA_SRC_SEQUENCE, IMA_SRC_MOVIE)) {
+ BKE_report(op->reports, RPT_ERROR, "Packing movies or image sequences not supported");
return false;
}
@@ -3110,9 +3100,8 @@ static int image_unpack_exec(bContext *C, wmOperator *op)
return OPERATOR_CANCELLED;
}
- if (ELEM(ima->source, IMA_SRC_SEQUENCE, IMA_SRC_MOVIE, IMA_SRC_TILED)) {
- BKE_report(
- op->reports, RPT_ERROR, "Unpacking movies, image sequences or tiled images not supported");
+ if (ELEM(ima->source, IMA_SRC_SEQUENCE, IMA_SRC_MOVIE)) {
+ BKE_report(op->reports, RPT_ERROR, "Unpacking movies or image sequences not supported");
return OPERATOR_CANCELLED;
}
@@ -3144,9 +3133,8 @@ static int image_unpack_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSE
return OPERATOR_CANCELLED;
}
- if (ELEM(ima->source, IMA_SRC_SEQUENCE, IMA_SRC_MOVIE, IMA_SRC_TILED)) {
- BKE_report(
- op->reports, RPT_ERROR, "Unpacking movies, image sequences or tiled images not supported");
+ if (ELEM(ima->source, IMA_SRC_SEQUENCE, IMA_SRC_MOVIE)) {
+ BKE_report(op->reports, RPT_ERROR, "Unpacking movies or image sequences not supported");
return OPERATOR_CANCELLED;
}
@@ -3216,7 +3204,7 @@ bool ED_space_image_get_position(SpaceImage *sima,
}
bool ED_space_image_color_sample(
- SpaceImage *sima, ARegion *region, int mval[2], float r_col[3], bool *r_is_data)
+ SpaceImage *sima, ARegion *region, const int mval[2], float r_col[3], bool *r_is_data)
{
if (r_is_data) {
*r_is_data = false;
diff --git a/source/blender/editors/space_image/image_sequence.c b/source/blender/editors/space_image/image_sequence.c
index 365cf2542b2..fbeef47e278 100644
--- a/source/blender/editors/space_image/image_sequence.c
+++ b/source/blender/editors/space_image/image_sequence.c
@@ -107,10 +107,10 @@ static void image_detect_frame_range(ImageFrameRange *range, const bool detect_u
/* UDIM */
if (detect_udim) {
int udim_start, udim_range;
- bool result = BKE_image_get_tile_info(
+ range->udims_detected = BKE_image_get_tile_info(
range->filepath, &range->udim_tiles, &udim_start, &udim_range);
- if (result) {
+ if (range->udims_detected) {
range->offset = udim_start;
range->length = udim_range;
return;
diff --git a/source/blender/editors/space_image/image_undo.c b/source/blender/editors/space_image/image_undo.c
index c3a48abcae1..a7a8bde1115 100644
--- a/source/blender/editors/space_image/image_undo.c
+++ b/source/blender/editors/space_image/image_undo.c
@@ -287,7 +287,7 @@ static void ptile_restore_runtime_list(ListBase *paint_tiles)
ibuf->userflags |= IB_RECT_INVALID; /* force recreate of char rect */
}
if (ibuf->mipmap[0]) {
- ibuf->userflags |= IB_MIPMAP_INVALID; /* force mip-map recreation. */
+ ibuf->userflags |= IB_MIPMAP_INVALID; /* Force MIP-MAP recreation. */
}
ibuf->userflags |= IB_DISPLAY_BUFFER_INVALID;
@@ -1040,7 +1040,7 @@ static ImageUndoStep *image_undo_push_begin(const char *name, int paint_mode)
bContext *C = NULL; /* special case, we never read from this. */
UndoStep *us_p = BKE_undosys_step_push_init_with_type(ustack, C, name, BKE_UNDOSYS_TYPE_IMAGE);
ImageUndoStep *us = (ImageUndoStep *)us_p;
- BLI_assert(ELEM(paint_mode, PAINT_MODE_TEXTURE_2D, PAINT_MODE_TEXTURE_3D));
+ BLI_assert(ELEM(paint_mode, PAINT_MODE_TEXTURE_2D, PAINT_MODE_TEXTURE_3D, PAINT_MODE_SCULPT));
us->paint_mode = paint_mode;
return us;
}
diff --git a/source/blender/editors/space_image/space_image.c b/source/blender/editors/space_image/space_image.c
index 568bd064e3e..785a5419e04 100644
--- a/source/blender/editors/space_image/space_image.c
+++ b/source/blender/editors/space_image/space_image.c
@@ -103,7 +103,7 @@ static SpaceLink *image_create(const ScrArea *UNUSED(area), const Scene *UNUSED(
simage->overlay.flag = SI_OVERLAY_SHOW_OVERLAYS | SI_OVERLAY_SHOW_GRID_BACKGROUND;
BKE_imageuser_default(&simage->iuser);
- simage->iuser.flag = IMA_SHOW_STEREO | IMA_ANIM_ALWAYS | IMA_SHOW_MAX_RESOLUTION;
+ simage->iuser.flag = IMA_SHOW_STEREO | IMA_ANIM_ALWAYS;
BKE_scopes_new(&simage->scopes);
simage->sample_line_hist.height = 100;
@@ -199,6 +199,7 @@ static void image_operatortypes(void)
WM_operatortype_append(IMAGE_OT_new);
WM_operatortype_append(IMAGE_OT_open);
+ WM_operatortype_append(IMAGE_OT_file_browse);
WM_operatortype_append(IMAGE_OT_match_movie_length);
WM_operatortype_append(IMAGE_OT_replace);
WM_operatortype_append(IMAGE_OT_reload);
@@ -315,6 +316,9 @@ static void image_listener(const wmSpaceTypeListenerParams *params)
ED_area_tag_redraw(area);
break;
case ND_MODE:
+ ED_paint_cursor_start(&params->scene->toolsettings->imapaint.paint,
+ ED_image_tools_paint_poll);
+
if (wmn->subtype == NS_EDITMODE_MESH) {
ED_area_tag_refresh(area);
}
@@ -690,6 +694,7 @@ static void image_main_region_draw(const bContext *C, ARegion *region)
sima->mask_info.draw_flag & ~MASK_DRAWFLAG_OVERLAY,
sima->mask_info.draw_type,
sima->mask_info.overlay_mode,
+ sima->mask_info.blend_factor,
width,
height,
aspx,
diff --git a/source/blender/editors/space_info/info_stats.cc b/source/blender/editors/space_info/info_stats.cc
index b817ff887ce..29a7eb150a1 100644
--- a/source/blender/editors/space_info/info_stats.cc
+++ b/source/blender/editors/space_info/info_stats.cc
@@ -46,6 +46,7 @@
#include "BKE_pbvh.h"
#include "BKE_scene.h"
#include "BKE_subdiv_ccg.h"
+#include "BKE_subdiv_modifier.h"
#include "DEG_depsgraph_query.h"
@@ -92,15 +93,18 @@ static bool stats_mesheval(const Mesh *me_eval, bool is_selected, SceneStats *st
}
int totvert, totedge, totface, totloop;
- if (me_eval->runtime.subdiv_ccg != nullptr) {
- const SubdivCCG *subdiv_ccg = me_eval->runtime.subdiv_ccg;
+
+ const SubdivCCG *subdiv_ccg = me_eval->runtime.subdiv_ccg;
+ const SubsurfRuntimeData *subsurf_runtime_data = me_eval->runtime.subsurf_runtime_data;
+
+ if (subdiv_ccg != nullptr) {
BKE_subdiv_ccg_topology_counters(subdiv_ccg, &totvert, &totedge, &totface, &totloop);
}
- else if (me_eval->runtime.subsurf_resolution != 0) {
- totvert = me_eval->runtime.subsurf_totvert;
- totedge = me_eval->runtime.subsurf_totedge;
- totface = me_eval->runtime.subsurf_totpoly;
- totloop = me_eval->runtime.subsurf_totloop;
+ else if (subsurf_runtime_data && subsurf_runtime_data->resolution != 0) {
+ totvert = subsurf_runtime_data->stats_totvert;
+ totedge = subsurf_runtime_data->stats_totedge;
+ totface = subsurf_runtime_data->stats_totpoly;
+ totloop = subsurf_runtime_data->stats_totloop;
}
else {
totvert = me_eval->totvert;
diff --git a/source/blender/editors/space_nla/nla_channels.c b/source/blender/editors/space_nla/nla_channels.c
index 8b059b33a9a..40082b08806 100644
--- a/source/blender/editors/space_nla/nla_channels.c
+++ b/source/blender/editors/space_nla/nla_channels.c
@@ -58,14 +58,12 @@
* --> Most channels are now selection only.
*/
-static int mouse_nla_channels(
- bContext *C, bAnimContext *ac, float x, int channel_index, short selectmode)
+static int mouse_nla_channels(bContext *C, bAnimContext *ac, int channel_index, short selectmode)
{
ListBase anim_data = {NULL, NULL};
bAnimListElem *ale;
int filter;
- View2D *v2d = &ac->region->v2d;
int notifierFlags = 0;
/* get the channel that was clicked on */
@@ -203,47 +201,8 @@ static int mouse_nla_channels(
}
case ANIMTYPE_NLATRACK: {
NlaTrack *nlt = (NlaTrack *)ale->data;
- AnimData *adt = ale->adt;
- short offset;
-
- /* offset for start of channel (on LHS of channel-list) */
- if (ale->id) {
- /* special exception for materials and particles */
- if (ELEM(GS(ale->id->name), ID_MA, ID_PA)) {
- offset = 21 + NLACHANNEL_BUTTON_WIDTH;
- }
- else {
- offset = 14;
- }
- }
- else {
- offset = 0;
- }
- if (x >= (v2d->cur.xmax - NLACHANNEL_BUTTON_WIDTH)) {
- /* toggle protection (only if there's a toggle there) */
- nlt->flag ^= NLATRACK_PROTECTED;
-
- /* notifier flags - channel was edited */
- notifierFlags |= (ND_ANIMCHAN | NA_EDITED);
- }
- else if (x >= (v2d->cur.xmax - 2 * NLACHANNEL_BUTTON_WIDTH)) {
- /* toggle mute */
- nlt->flag ^= NLATRACK_MUTED;
-
- /* notifier flags - channel was edited */
- notifierFlags |= (ND_ANIMCHAN | NA_EDITED);
- ale->update |= ANIM_UPDATE_DEPS;
- }
- else if (x <= ((NLACHANNEL_BUTTON_WIDTH * 2) + offset)) {
- /* toggle 'solo' */
- BKE_nlatrack_solo_toggle(adt, nlt);
-
- /* notifier flags - channel was edited */
- notifierFlags |= (ND_ANIMCHAN | NA_EDITED);
- ale->update |= ANIM_UPDATE_DEPS;
- }
- else if (nlaedit_is_tweakmode_on(ac) == 0) {
+ if (nlaedit_is_tweakmode_on(ac) == 0) {
/* set selection */
if (selectmode == SELECT_INVERT) {
/* inverse selection status of this F-Curve only */
@@ -269,61 +228,40 @@ static int mouse_nla_channels(
case ANIMTYPE_NLAACTION: {
AnimData *adt = BKE_animdata_from_id(ale->id);
- /* button region... */
- if (x >= (v2d->cur.xmax - NLACHANNEL_BUTTON_WIDTH)) {
- if (nlaedit_is_tweakmode_on(ac) == 0) {
- /* 'push-down' action - only usable when not in tweak-mode */
- /* TODO: make this use the operator instead of calling the function directly
- * however, calling the operator requires that we supply the args,
- * and that works with proper buttons only */
- BKE_nla_action_pushdown(adt, ID_IS_OVERRIDE_LIBRARY(ale->id));
- }
- else {
- /* When in tweak-mode, this button becomes the toggle for mapped editing. */
- adt->flag ^= ADT_NLA_EDIT_NOMAP;
- }
+ /* NOTE: rest of NLA-Action name doubles for operating on the AnimData block
+ * - this is useful when there's no clear divider, and makes more sense in
+ * the case of users trying to use this to change actions
+ * - in tweak-mode, clicking here gets us out of tweak-mode, as changing selection
+ * while in tweak-mode is really evil!
+ * - we disable "solo" flags too, to make it easier to work with stashed actions
+ * with less trouble
+ */
+ if (nlaedit_is_tweakmode_on(ac)) {
+ /* Exit tweak-mode immediately. */
+ nlaedit_disable_tweakmode(ac, true);
/* changes to NLA-Action occurred */
notifierFlags |= ND_NLA_ACTCHANGE;
ale->update |= ANIM_UPDATE_DEPS;
}
- /* OR rest of name... */
else {
- /* NOTE: rest of NLA-Action name doubles for operating on the AnimData block
- * - this is useful when there's no clear divider, and makes more sense in
- * the case of users trying to use this to change actions
- * - in tweak-mode, clicking here gets us out of tweak-mode, as changing selection
- * while in tweak-mode is really evil!
- * - we disable "solo" flags too, to make it easier to work with stashed actions
- * with less trouble
- */
- if (nlaedit_is_tweakmode_on(ac)) {
- /* Exit tweak-mode immediately. */
- nlaedit_disable_tweakmode(ac, true);
-
- /* changes to NLA-Action occurred */
- notifierFlags |= ND_NLA_ACTCHANGE;
- ale->update |= ANIM_UPDATE_DEPS;
+ /* select/deselect */
+ if (selectmode == SELECT_INVERT) {
+ /* inverse selection status of this AnimData block only */
+ adt->flag ^= ADT_UI_SELECTED;
}
else {
- /* select/deselect */
- if (selectmode == SELECT_INVERT) {
- /* inverse selection status of this AnimData block only */
- adt->flag ^= ADT_UI_SELECTED;
- }
- else {
- /* select AnimData block by itself */
- ANIM_anim_channels_select_set(ac, ACHANNEL_SETFLAG_CLEAR);
- adt->flag |= ADT_UI_SELECTED;
- }
-
- /* set active? */
- if (adt->flag & ADT_UI_SELECTED) {
- adt->flag |= ADT_UI_ACTIVE;
- }
+ /* select AnimData block by itself */
+ ANIM_anim_channels_select_set(ac, ACHANNEL_SETFLAG_CLEAR);
+ adt->flag |= ADT_UI_SELECTED;
+ }
- notifierFlags |= (ND_ANIMCHAN | NA_SELECTED);
+ /* set active? */
+ if (adt->flag & ADT_UI_SELECTED) {
+ adt->flag |= ADT_UI_ACTIVE;
}
+
+ notifierFlags |= (ND_ANIMCHAN | NA_SELECTED);
}
break;
}
@@ -386,7 +324,7 @@ static int nlachannels_mouseclick_invoke(bContext *C, wmOperator *op, const wmEv
&channel_index);
/* handle mouse-click in the relevant channel then */
- notifierFlags = mouse_nla_channels(C, &ac, x, channel_index, selectmode);
+ notifierFlags = mouse_nla_channels(C, &ac, channel_index, selectmode);
/* set notifier that things have changed */
WM_event_add_notifier(C, NC_ANIMATION | notifierFlags, NULL);
diff --git a/source/blender/editors/space_nla/nla_draw.c b/source/blender/editors/space_nla/nla_draw.c
index 6c631f46069..bb9e201d94a 100644
--- a/source/blender/editors/space_nla/nla_draw.c
+++ b/source/blender/editors/space_nla/nla_draw.c
@@ -621,7 +621,6 @@ static void nla_draw_strip(SpaceNla *snla,
static void nla_draw_strip_text(AnimData *adt,
NlaTrack *nlt,
NlaStrip *strip,
- int index,
View2D *v2d,
float xminc,
float xmaxc,
@@ -636,7 +635,7 @@ static void nla_draw_strip_text(AnimData *adt,
/* just print the name and the range */
if (strip->flag & NLASTRIP_FLAG_TEMP_META) {
- str_len = BLI_snprintf_rlen(str, sizeof(str), "%d) Temp-Meta", index);
+ str_len = BLI_snprintf_rlen(str, sizeof(str), "Temp-Meta");
}
else {
str_len = BLI_strncpy_rlen(str, strip->name, sizeof(str));
@@ -702,6 +701,89 @@ static void nla_draw_strip_frames_text(
/* ---------------------- */
+/**
+ * Gets the first and last visible NLA strips on a track.
+ * Note that this also includes tracks that might only be
+ * visible because of their extendmode.
+ */
+static ListBase get_visible_nla_strips(NlaTrack *nlt, View2D *v2d)
+{
+ if (BLI_listbase_is_empty(&nlt->strips)) {
+ ListBase empty = {NULL, NULL};
+ return empty;
+ }
+
+ NlaStrip *first = NULL;
+ NlaStrip *last = NULL;
+
+ /* Find the first strip that is within the bounds of the view. */
+ LISTBASE_FOREACH (NlaStrip *, strip, &nlt->strips) {
+ if (BKE_nlastrip_within_bounds(strip, v2d->cur.xmin, v2d->cur.xmax)) {
+ first = last = strip;
+ break;
+ }
+ }
+
+ const bool has_strips_within_bounds = first != NULL;
+
+ if (has_strips_within_bounds) {
+ /* Find the last visible strip. */
+ for (NlaStrip *strip = first->next; strip; strip = strip->next) {
+ if (!BKE_nlastrip_within_bounds(strip, v2d->cur.xmin, v2d->cur.xmax)) {
+ break;
+ }
+ last = strip;
+ }
+ /* Check if the first strip is adjacent to a strip outside the view to the left
+ * that has an extendmode region that should be drawn.
+ * If so, adjust the first strip to include drawing that strip as well.
+ */
+ NlaStrip *prev = first->prev;
+ if (prev && prev->extendmode != NLASTRIP_EXTEND_NOTHING) {
+ first = prev;
+ }
+ }
+ else {
+ /* No immediately visible strips.
+ * Figure out where our view is relative to the strips, then determine
+ * if the view is adjacent to a strip that should have its extendmode
+ * rendered.
+ */
+ NlaStrip *first_strip = nlt->strips.first;
+ NlaStrip *last_strip = nlt->strips.last;
+ if (first_strip && v2d->cur.xmax < first_strip->start &&
+ first_strip->extendmode == NLASTRIP_EXTEND_HOLD) {
+ /* The view is to the left of all strips and the first strip has an
+ * extendmode that should be drawn.
+ */
+ first = last = first_strip;
+ }
+ else if (last_strip && v2d->cur.xmin > last_strip->end &&
+ last_strip->extendmode != NLASTRIP_EXTEND_NOTHING) {
+ /* The view is to the right of all strips and the last strip has an
+ * extendmode that should be drawn.
+ */
+ first = last = last_strip;
+ }
+ else {
+ /* The view is in the middle of two strips. */
+ LISTBASE_FOREACH (NlaStrip *, strip, &nlt->strips) {
+ /* Find the strip to the left by finding the strip to the right and getting its prev. */
+ if (v2d->cur.xmax < strip->start) {
+ /* If the strip to the left has an extendmode, set that as the only visible strip. */
+ if (strip->prev && strip->prev->extendmode != NLASTRIP_EXTEND_NOTHING) {
+ first = last = strip->prev;
+ }
+ break;
+ }
+ }
+ }
+ }
+
+ ListBase visible_strips = {first, last};
+ return visible_strips;
+}
+
void draw_nla_main_data(bAnimContext *ac, SpaceNla *snla, ARegion *region)
{
View2D *v2d = &region->v2d;
@@ -737,29 +819,26 @@ void draw_nla_main_data(bAnimContext *ac, SpaceNla *snla, ARegion *region)
case ANIMTYPE_NLATRACK: {
AnimData *adt = ale->adt;
NlaTrack *nlt = (NlaTrack *)ale->data;
- NlaStrip *strip;
- int index;
-
- /* draw each strip in the track (if visible) */
- for (strip = nlt->strips.first, index = 1; strip; strip = strip->next, index++) {
- if (BKE_nlastrip_within_bounds(strip, v2d->cur.xmin, v2d->cur.xmax)) {
- const float xminc = strip->start + text_margin_x;
- const float xmaxc = strip->end - text_margin_x;
-
- /* draw the visualization of the strip */
- nla_draw_strip(snla, adt, nlt, strip, v2d, ymin, ymax);
-
- /* add the text for this strip to the cache */
- if (xminc < xmaxc) {
- nla_draw_strip_text(adt, nlt, strip, index, v2d, xminc, xmaxc, ymin, ymax);
- }
-
- /* if transforming strips (only real reason for temp-metas currently),
- * add to the cache the frame numbers of the strip's extents
- */
- if (strip->flag & NLASTRIP_FLAG_TEMP_META) {
- nla_draw_strip_frames_text(nlt, strip, v2d, ymin, ymax);
- }
+ ListBase visible_nla_strips = get_visible_nla_strips(nlt, v2d);
+
+ /* Draw each visible strip in the track. */
+ LISTBASE_FOREACH (NlaStrip *, strip, &visible_nla_strips) {
+ const float xminc = strip->start + text_margin_x;
+ const float xmaxc = strip->end - text_margin_x;
+
+ /* draw the visualization of the strip */
+ nla_draw_strip(snla, adt, nlt, strip, v2d, ymin, ymax);
+
+ /* add the text for this strip to the cache */
+ if (xminc < xmaxc) {
+ nla_draw_strip_text(adt, nlt, strip, v2d, xminc, xmaxc, ymin, ymax);
+ }
+
+ /* if transforming strips (only real reason for temp-metas currently),
+ * add to the cache the frame numbers of the strip's extents
+ */
+ if (strip->flag & NLASTRIP_FLAG_TEMP_META) {
+ nla_draw_strip_frames_text(nlt, strip, v2d, ymin, ymax);
}
}
break;
diff --git a/source/blender/editors/space_nla/nla_edit.c b/source/blender/editors/space_nla/nla_edit.c
index 2aa9b347ed7..81520445000 100644
--- a/source/blender/editors/space_nla/nla_edit.c
+++ b/source/blender/editors/space_nla/nla_edit.c
@@ -1004,7 +1004,7 @@ static int nlaedit_add_meta_exec(bContext *C, wmOperator *UNUSED(op))
NlaStrip *strip;
if (BKE_nlatrack_is_nonlocal_in_liboverride(ale->id, nlt)) {
- /* No making metastrips in non-local tracks of override data. */
+ /* No making meta-strips in non-local tracks of override data. */
continue;
}
@@ -1078,7 +1078,7 @@ static int nlaedit_remove_meta_exec(bContext *C, wmOperator *UNUSED(op))
NlaTrack *nlt = (NlaTrack *)ale->data;
if (BKE_nlatrack_is_nonlocal_in_liboverride(ale->id, nlt)) {
- /* No removing metastrips from non-local tracks of override data. */
+ /* No removing meta-strips from non-local tracks of override data. */
continue;
}
@@ -1714,7 +1714,7 @@ static int nlaedit_swap_exec(bContext *C, wmOperator *op)
BKE_nlatrack_add_strip(nlt, sb, is_liboverride);
}
- /* clear (temp) metastrips */
+ /* Clear (temp) meta-strips. */
BKE_nlastrips_clear_metas(&nlt->strips, 0, 1);
}
diff --git a/source/blender/editors/space_node/drawnode.cc b/source/blender/editors/space_node/drawnode.cc
index d5507619e0d..6806d715004 100644
--- a/source/blender/editors/space_node/drawnode.cc
+++ b/source/blender/editors/space_node/drawnode.cc
@@ -20,6 +20,7 @@
#include "BKE_image.h"
#include "BKE_main.h"
#include "BKE_node.h"
+#include "BKE_node_runtime.hh"
#include "BKE_node_tree_update.h"
#include "BKE_scene.h"
#include "BKE_tracking.h"
@@ -1271,14 +1272,14 @@ static void node_file_output_socket_draw(bContext *C,
static bool socket_needs_attribute_search(bNode &node, bNodeSocket &socket)
{
- if (node.declaration == nullptr) {
+ if (node.runtime->declaration == nullptr) {
return false;
}
if (socket.in_out == SOCK_OUT) {
return false;
}
const int socket_index = BLI_findindex(&node.inputs, &socket);
- return node.declaration->inputs()[socket_index]->is_attribute_name();
+ return node.runtime->declaration->inputs()[socket_index]->is_attribute_name();
}
static void std_node_socket_draw(
diff --git a/source/blender/editors/space_node/node_add.cc b/source/blender/editors/space_node/node_add.cc
index 7fb15d69ab5..975d4eda7e3 100644
--- a/source/blender/editors/space_node/node_add.cc
+++ b/source/blender/editors/space_node/node_add.cc
@@ -303,10 +303,8 @@ static bNodeTree *node_add_group_get_and_poll_group_node_tree(Main *bmain,
wmOperator *op,
bNodeTree *ntree)
{
- char name[MAX_ID_NAME - 2];
- RNA_string_get(op->ptr, "name", name);
-
- bNodeTree *node_group = (bNodeTree *)BKE_libblock_find_name(bmain, ID_NT, name);
+ bNodeTree *node_group = reinterpret_cast<bNodeTree *>(
+ WM_operator_properties_id_lookup_from_name_or_session_uuid(bmain, op->ptr, ID_NT));
if (!node_group) {
return nullptr;
}
@@ -348,8 +346,14 @@ static int node_add_group_exec(bContext *C, wmOperator *op)
ED_preview_kill_jobs(CTX_wm_manager(C), CTX_data_main(C));
+ const char *node_idname = node_group_idname(C);
+ if (node_idname[0] == '\0') {
+ BKE_report(op->reports, RPT_WARNING, "Could not determine type of group node");
+ return OPERATOR_CANCELLED;
+ }
+
bNode *group_node = node_add_node(*C,
- node_group_idname(C),
+ node_idname,
(node_group->type == NTREE_CUSTOM) ? NODE_CUSTOM_GROUP :
NODE_GROUP,
snode->runtime->cursor[0],
@@ -365,9 +369,25 @@ static int node_add_group_exec(bContext *C, wmOperator *op)
nodeSetActive(ntree, group_node);
ED_node_tree_propagate_change(C, bmain, nullptr);
+ DEG_relations_tag_update(bmain);
return OPERATOR_FINISHED;
}
+static bool node_add_group_poll(bContext *C)
+{
+ if (!ED_operator_node_editable(C)) {
+ return false;
+ }
+ const SpaceNode *snode = CTX_wm_space_node(C);
+ if (snode->edittree->type == NTREE_CUSTOM) {
+ CTX_wm_operator_poll_msg_set(C,
+ "This node editor displays a custom (Python defined) node tree. "
+ "Dropping node groups isn't supported for this.");
+ return false;
+ }
+ return true;
+}
+
static int node_add_group_invoke(bContext *C, wmOperator *op, const wmEvent *event)
{
ARegion *region = CTX_wm_region(C);
@@ -396,12 +416,12 @@ void NODE_OT_add_group(wmOperatorType *ot)
/* callbacks */
ot->exec = node_add_group_exec;
ot->invoke = node_add_group_invoke;
- ot->poll = ED_operator_node_editable;
+ ot->poll = node_add_group_poll;
/* flags */
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");
+ WM_operator_properties_id_lookup(ot, true);
}
/** \} */
@@ -410,26 +430,16 @@ void NODE_OT_add_group(wmOperatorType *ot)
/** \name Add Node Object Operator
* \{ */
-static Object *node_add_object_get_and_poll_object_node_tree(Main *bmain, wmOperator *op)
-{
- if (RNA_struct_property_is_set(op->ptr, "session_uuid")) {
- const uint32_t session_uuid = (uint32_t)RNA_int_get(op->ptr, "session_uuid");
- return (Object *)BKE_libblock_find_session_uuid(bmain, ID_OB, session_uuid);
- }
-
- char name[MAX_ID_NAME - 2];
- RNA_string_get(op->ptr, "name", name);
- return (Object *)BKE_libblock_find_name(bmain, ID_OB, name);
-}
-
static int node_add_object_exec(bContext *C, wmOperator *op)
{
Main *bmain = CTX_data_main(C);
SpaceNode *snode = CTX_wm_space_node(C);
bNodeTree *ntree = snode->edittree;
- Object *object;
- if (!(object = node_add_object_get_and_poll_object_node_tree(bmain, op))) {
+ Object *object = reinterpret_cast<Object *>(
+ WM_operator_properties_id_lookup_from_name_or_session_uuid(bmain, op->ptr, ID_OB));
+
+ if (!object) {
return OPERATOR_CANCELLED;
}
@@ -486,8 +496,6 @@ 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";
@@ -501,17 +509,7 @@ void NODE_OT_add_object(wmOperatorType *ot)
/* flags */
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");
- 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));
+ WM_operator_properties_id_lookup(ot, true);
}
/** \} */
@@ -520,27 +518,16 @@ void NODE_OT_add_object(wmOperatorType *ot)
/** \name Add Node Collection Operator
* \{ */
-static Collection *node_add_collection_get_and_poll_collection_node_tree(Main *bmain,
- wmOperator *op)
-{
- if (RNA_struct_property_is_set(op->ptr, "session_uuid")) {
- const uint32_t session_uuid = (uint32_t)RNA_int_get(op->ptr, "session_uuid");
- return (Collection *)BKE_libblock_find_session_uuid(bmain, ID_GR, session_uuid);
- }
-
- char name[MAX_ID_NAME - 2];
- RNA_string_get(op->ptr, "name", name);
- return (Collection *)BKE_libblock_find_name(bmain, ID_GR, name);
-}
-
static int node_add_collection_exec(bContext *C, wmOperator *op)
{
Main *bmain = CTX_data_main(C);
SpaceNode &snode = *CTX_wm_space_node(C);
bNodeTree *ntree = snode.edittree;
- Collection *collection;
- if (!(collection = node_add_collection_get_and_poll_collection_node_tree(bmain, op))) {
+ Collection *collection = reinterpret_cast<Collection *>(
+ WM_operator_properties_id_lookup_from_name_or_session_uuid(bmain, op->ptr, ID_GR));
+
+ if (!collection) {
return OPERATOR_CANCELLED;
}
@@ -597,8 +584,6 @@ 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";
@@ -612,18 +597,7 @@ void NODE_OT_add_collection(wmOperatorType *ot)
/* flags */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_INTERNAL;
- RNA_def_string(
- ot->srna, "name", "Collection", MAX_ID_NAME - 2, "Name", "Data-block name to assign");
- prop = RNA_def_int(ot->srna,
- "session_uuid",
- 0,
- INT32_MIN,
- INT32_MAX,
- "Session UUID",
- "Session UUID of the data-block to assign",
- INT32_MIN,
- INT32_MAX);
- RNA_def_property_flag(prop, (PropertyFlag)(PROP_HIDDEN | PROP_SKIP_SAVE));
+ WM_operator_properties_id_lookup(ot, true);
}
/** \} */
@@ -745,7 +719,7 @@ void NODE_OT_add_file(wmOperatorType *ot)
WM_FILESEL_FILEPATH | WM_FILESEL_RELPATH,
FILE_DEFAULTDISPLAY,
FILE_SORT_DEFAULT);
- RNA_def_string(ot->srna, "name", "Image", MAX_ID_NAME - 2, "Name", "Data-block name to assign");
+ WM_operator_properties_id_lookup(ot, true);
}
/** \} */
@@ -754,18 +728,6 @@ void NODE_OT_add_file(wmOperatorType *ot)
/** \name Add Mask Node Operator
* \{ */
-static ID *node_add_mask_get_and_poll_mask(Main *bmain, wmOperator *op)
-{
- if (RNA_struct_property_is_set(op->ptr, "session_uuid")) {
- const uint32_t session_uuid = (uint32_t)RNA_int_get(op->ptr, "session_uuid");
- return BKE_libblock_find_session_uuid(bmain, ID_MSK, session_uuid);
- }
-
- char name[MAX_ID_NAME - 2];
- RNA_string_get(op->ptr, "name", name);
- return BKE_libblock_find_name(bmain, ID_MSK, name);
-}
-
static bool node_add_mask_poll(bContext *C)
{
SpaceNode *snode = CTX_wm_space_node(C);
@@ -779,7 +741,7 @@ static int node_add_mask_exec(bContext *C, wmOperator *op)
SpaceNode &snode = *CTX_wm_space_node(C);
bNode *node;
- ID *mask = node_add_mask_get_and_poll_mask(bmain, op);
+ ID *mask = WM_operator_properties_id_lookup_from_name_or_session_uuid(bmain, op->ptr, ID_MSK);
if (!mask) {
return OPERATOR_CANCELLED;
}
@@ -805,8 +767,6 @@ 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";
@@ -819,17 +779,7 @@ void NODE_OT_add_mask(wmOperatorType *ot)
/* flags */
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");
- 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));
+ WM_operator_properties_id_lookup(ot, true);
}
/** \} */
diff --git a/source/blender/editors/space_node/node_context_path.cc b/source/blender/editors/space_node/node_context_path.cc
index 4247d5a1fbc..b9bee3ed15e 100644
--- a/source/blender/editors/space_node/node_context_path.cc
+++ b/source/blender/editors/space_node/node_context_path.cc
@@ -26,8 +26,6 @@
#include "UI_interface.hh"
#include "UI_resources.h"
-#include "UI_interface.hh"
-
#include "node_intern.hh"
struct Curve;
@@ -139,7 +137,7 @@ static void get_context_path_node_geometry(const bContext &C,
Object *object = CTX_data_active_object(&C);
ui::context_path_add_generic(path, RNA_Object, object);
ModifierData *modifier = BKE_object_active_modifier(object);
- ui::context_path_add_generic(path, RNA_Modifier, modifier, ICON_MODIFIER);
+ ui::context_path_add_generic(path, RNA_Modifier, modifier, ICON_GEOMETRY_NODES);
context_path_add_node_tree_and_node_groups(snode, path);
}
}
diff --git a/source/blender/editors/space_node/node_draw.cc b/source/blender/editors/space_node/node_draw.cc
index 9076b17a926..7003d51b2b6 100644
--- a/source/blender/editors/space_node/node_draw.cc
+++ b/source/blender/editors/space_node/node_draw.cc
@@ -66,6 +66,7 @@
#include "NOD_geometry_nodes_eval_log.hh"
#include "NOD_node_declaration.hh"
+#include "NOD_socket_declarations_geometry.hh"
#include "FN_field.hh"
#include "FN_field_cpp_type.hh"
@@ -75,7 +76,7 @@
using blender::GPointer;
using blender::fn::GField;
namespace geo_log = blender::nodes::geometry_nodes_eval_log;
-using geo_log::NamedAttributeUsage;
+using geo_log::eNamedAttrUsage;
extern "C" {
/* XXX interface.h */
@@ -871,7 +872,8 @@ static void create_inspection_string_for_gfield(const geo_log::GFieldValueLog &v
}
static void create_inspection_string_for_geometry(const geo_log::GeometryValueLog &value_log,
- std::stringstream &ss)
+ std::stringstream &ss,
+ const nodes::decl::Geometry *geometry)
{
Span<GeometryComponentType> component_types = value_log.component_types();
if (component_types.is_empty()) {
@@ -895,9 +897,9 @@ static void create_inspection_string_for_geometry(const geo_log::GeometryValueLo
BLI_snprintf(line,
sizeof(line),
TIP_("\u2022 Mesh: %s vertices, %s edges, %s faces"),
- to_string(mesh_info.tot_verts).c_str(),
- to_string(mesh_info.tot_edges).c_str(),
- to_string(mesh_info.tot_faces).c_str());
+ to_string(mesh_info.verts_num).c_str(),
+ to_string(mesh_info.edges_num).c_str(),
+ to_string(mesh_info.faces_num).c_str());
ss << line << line_end;
break;
}
@@ -908,7 +910,7 @@ static void create_inspection_string_for_geometry(const geo_log::GeometryValueLo
BLI_snprintf(line,
sizeof(line),
TIP_("\u2022 Point Cloud: %s points"),
- to_string(pointcloud_info.tot_points).c_str());
+ to_string(pointcloud_info.points_num).c_str());
ss << line << line_end;
break;
}
@@ -918,7 +920,7 @@ static void create_inspection_string_for_geometry(const geo_log::GeometryValueLo
BLI_snprintf(line,
sizeof(line),
TIP_("\u2022 Curve: %s splines"),
- to_string(curve_info.tot_splines).c_str());
+ to_string(curve_info.splines_num).c_str());
ss << line << line_end;
break;
}
@@ -928,7 +930,7 @@ static void create_inspection_string_for_geometry(const geo_log::GeometryValueLo
BLI_snprintf(line,
sizeof(line),
TIP_("\u2022 Instances: %s"),
- to_string(instances_info.tot_instances).c_str());
+ to_string(instances_info.instances_num).c_str());
ss << line << line_end;
break;
}
@@ -938,6 +940,45 @@ static void create_inspection_string_for_geometry(const geo_log::GeometryValueLo
}
}
}
+
+ /* If the geometry declaration is null, as is the case for input to group output,
+ * or it is an output socket don't show supported types. */
+ if (geometry == nullptr || geometry->in_out() == SOCK_OUT) {
+ return;
+ }
+
+ Span<GeometryComponentType> supported_types = geometry->supported_types();
+ if (supported_types.is_empty()) {
+ ss << ".\n\n" << TIP_("Supported: All Types");
+ return;
+ }
+
+ ss << ".\n\n" << TIP_("Supported: ");
+ for (GeometryComponentType type : supported_types) {
+ switch (type) {
+ case GEO_COMPONENT_TYPE_MESH: {
+ ss << TIP_("Mesh");
+ break;
+ }
+ case GEO_COMPONENT_TYPE_POINT_CLOUD: {
+ ss << TIP_("Point Cloud");
+ break;
+ }
+ case GEO_COMPONENT_TYPE_CURVE: {
+ ss << TIP_("Curve");
+ break;
+ }
+ case GEO_COMPONENT_TYPE_INSTANCES: {
+ ss << TIP_("Instances");
+ break;
+ }
+ case GEO_COMPONENT_TYPE_VOLUME: {
+ ss << TIP_("Volume");
+ break;
+ }
+ }
+ ss << ((type == supported_types.last()) ? "" : ", ");
+ }
}
static std::optional<std::string> create_socket_inspection_string(bContext *C,
@@ -970,7 +1011,10 @@ static std::optional<std::string> create_socket_inspection_string(bContext *C,
}
else if (const geo_log::GeometryValueLog *geo_value_log =
dynamic_cast<const geo_log::GeometryValueLog *>(value_log)) {
- create_inspection_string_for_geometry(*geo_value_log, ss);
+ create_inspection_string_for_geometry(
+ *geo_value_log,
+ ss,
+ dynamic_cast<const nodes::decl::Geometry *>(socket.runtime->declaration));
}
return ss.str();
@@ -982,8 +1026,8 @@ static bool node_socket_has_tooltip(bNodeTree *ntree, bNodeSocket *socket)
return true;
}
- if (socket->declaration != nullptr) {
- const blender::nodes::SocketDeclaration &socket_decl = *socket->declaration;
+ if (socket->runtime->declaration != nullptr) {
+ const blender::nodes::SocketDeclaration &socket_decl = *socket->runtime->declaration;
return !socket_decl.description().is_empty();
}
@@ -996,8 +1040,8 @@ static char *node_socket_get_tooltip(bContext *C,
bNodeSocket *socket)
{
std::stringstream output;
- if (socket->declaration != nullptr) {
- const blender::nodes::SocketDeclaration &socket_decl = *socket->declaration;
+ if (socket->runtime->declaration != nullptr) {
+ const blender::nodes::SocketDeclaration &socket_decl = *socket->runtime->declaration;
blender::StringRef description = socket_decl.description();
if (!description.is_empty()) {
output << TIP_(description.data());
@@ -1695,7 +1739,7 @@ struct NodeExtraInfoRow {
};
struct NamedAttributeTooltipArg {
- Map<std::string, NamedAttributeUsage> usage_by_attribute;
+ Map<std::string, eNamedAttrUsage> usage_by_attribute;
};
static char *named_attribute_tooltip(bContext *UNUSED(C), void *argN, const char *UNUSED(tip))
@@ -1707,7 +1751,7 @@ static char *named_attribute_tooltip(bContext *UNUSED(C), void *argN, const char
struct NameWithUsage {
StringRefNull name;
- NamedAttributeUsage usage;
+ eNamedAttrUsage usage;
};
Vector<NameWithUsage> sorted_used_attribute;
@@ -1722,16 +1766,16 @@ static char *named_attribute_tooltip(bContext *UNUSED(C), void *argN, const char
for (const NameWithUsage &attribute : sorted_used_attribute) {
const StringRefNull name = attribute.name;
- const NamedAttributeUsage usage = attribute.usage;
+ const eNamedAttrUsage usage = attribute.usage;
ss << " \u2022 \"" << name << "\": ";
Vector<std::string> usages;
- if ((usage & NamedAttributeUsage::Read) != NamedAttributeUsage::None) {
+ if ((usage & eNamedAttrUsage::Read) != eNamedAttrUsage::None) {
usages.append(TIP_("read"));
}
- if ((usage & NamedAttributeUsage::Write) != NamedAttributeUsage::None) {
+ if ((usage & eNamedAttrUsage::Write) != eNamedAttrUsage::None) {
usages.append(TIP_("write"));
}
- if ((usage & NamedAttributeUsage::Remove) != NamedAttributeUsage::None) {
+ if ((usage & eNamedAttrUsage::Remove) != eNamedAttrUsage::None) {
usages.append(TIP_("remove"));
}
for (const int i : usages.index_range()) {
@@ -1749,7 +1793,7 @@ static char *named_attribute_tooltip(bContext *UNUSED(C), void *argN, const char
}
static NodeExtraInfoRow row_from_used_named_attribute(
- const Map<std::string, NamedAttributeUsage> &usage_by_attribute_name)
+ const Map<std::string, eNamedAttrUsage> &usage_by_attribute_name)
{
const int attributes_num = usage_by_attribute_name.size();
@@ -1777,7 +1821,7 @@ static std::optional<NodeExtraInfoRow> node_get_accessed_attributes_row(const Sp
return std::nullopt;
}
- Map<std::string, NamedAttributeUsage> usage_by_attribute;
+ Map<std::string, eNamedAttrUsage> usage_by_attribute;
tree_log->foreach_node_log([&](const geo_log::NodeLog &node_log) {
for (const geo_log::UsedNamedAttribute &used_attribute : node_log.used_named_attributes()) {
usage_by_attribute.lookup_or_add_as(used_attribute.name,
@@ -1807,7 +1851,7 @@ static std::optional<NodeExtraInfoRow> node_get_accessed_attributes_row(const Sp
if (node_log == nullptr) {
return std::nullopt;
}
- Map<std::string, NamedAttributeUsage> usage_by_attribute;
+ Map<std::string, eNamedAttrUsage> usage_by_attribute;
for (const geo_log::UsedNamedAttribute &used_attribute : node_log->used_named_attributes()) {
usage_by_attribute.lookup_or_add_as(used_attribute.name,
used_attribute.usage) |= used_attribute.usage;
@@ -2654,7 +2698,7 @@ static void frame_node_draw_label(const bNodeTree &ntree,
BLF_enable(fontid, BLF_ASPECT);
BLF_aspect(fontid, aspect, aspect, 1.0f);
/* clamp otherwise it can suck up a LOT of memory */
- BLF_size(fontid, MIN2(24.0f, font_size), U.dpi);
+ BLF_size(fontid, MIN2(24.0f, font_size) * U.pixelsize, U.dpi);
/* title color */
int color_id = node_get_colorid(node);
diff --git a/source/blender/editors/space_node/node_edit.cc b/source/blender/editors/space_node/node_edit.cc
index 2d7972e2291..ffc9befc81c 100644
--- a/source/blender/editors/space_node/node_edit.cc
+++ b/source/blender/editors/space_node/node_edit.cc
@@ -15,6 +15,7 @@
#include "DNA_text_types.h"
#include "DNA_world_types.h"
+#include "BKE_callbacks.h"
#include "BKE_context.h"
#include "BKE_global.h"
#include "BKE_image.h"
@@ -66,7 +67,9 @@ namespace blender::ed::space_node {
#define USE_ESC_COMPO
-/* ***************** composite job manager ********************** */
+/* -------------------------------------------------------------------- */
+/** \name Composite Job Manager
+ * \{ */
enum {
COM_RECALC_COMPOSITE = 1,
@@ -273,6 +276,7 @@ static void compo_startjob(void *cjv,
// XXX BIF_store_spare();
/* 1 is do_previews */
+ BKE_callback_exec_id(cj->bmain, &scene->id, BKE_CB_EVT_COMPOSITE_PRE);
if ((cj->scene->r.scemode & R_MULTIVIEW) == 0) {
ntreeCompositExecTree(cj->scene, ntree, &cj->scene->r, false, true, "");
@@ -291,8 +295,30 @@ static void compo_startjob(void *cjv,
ntree->progress = nullptr;
}
+static void compo_canceljob(void *cjv)
+{
+ CompoJob *cj = (CompoJob *)cjv;
+ Main *bmain = cj->bmain;
+ Scene *scene = cj->scene;
+ BKE_callback_exec_id(bmain, &scene->id, BKE_CB_EVT_COMPOSITE_CANCEL);
+}
+
+static void compo_completejob(void *cjv)
+{
+ CompoJob *cj = (CompoJob *)cjv;
+ Main *bmain = cj->bmain;
+ Scene *scene = cj->scene;
+ BKE_callback_exec_id(bmain, &scene->id, BKE_CB_EVT_COMPOSITE_POST);
+}
+
+/** \} */
+
} // namespace blender::ed::space_node
+/* -------------------------------------------------------------------- */
+/** \name Composite Job C API
+ * \{ */
+
void ED_node_composite_job(const bContext *C, struct bNodeTree *nodetree, Scene *scene_owner)
{
using namespace blender::ed::space_node;
@@ -331,14 +357,24 @@ void ED_node_composite_job(const bContext *C, struct bNodeTree *nodetree, Scene
/* setup job */
WM_jobs_customdata_set(wm_job, cj, compo_freejob);
WM_jobs_timer(wm_job, 0.1, NC_SCENE | ND_COMPO_RESULT, NC_SCENE | ND_COMPO_RESULT);
- WM_jobs_callbacks(wm_job, compo_startjob, compo_initjob, compo_updatejob, nullptr);
+ WM_jobs_callbacks_ex(wm_job,
+ compo_startjob,
+ compo_initjob,
+ compo_updatejob,
+ nullptr,
+ compo_completejob,
+ compo_canceljob);
WM_jobs_start(CTX_wm_manager(C), wm_job);
}
+/** \} */
+
namespace blender::ed::space_node {
-/* ***************************************** */
+/* -------------------------------------------------------------------- */
+/** \name Composite Poll & Utility Functions
+ * \{ */
bool composite_node_active(bContext *C)
{
@@ -388,8 +424,14 @@ static void send_notifiers_after_tree_change(ID *id, bNodeTree *ntree)
}
}
+/** \} */
+
} // namespace blender::ed::space_node
+/* -------------------------------------------------------------------- */
+/** \name Node Editor Public API Functions
+ * \{ */
+
void ED_node_tree_propagate_change(const bContext *C, Main *bmain, bNodeTree *root_ntree)
{
if (C != nullptr) {
@@ -783,9 +825,13 @@ 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 ***************** */
+/* -------------------------------------------------------------------- */
+/** \name Generic Operator Functions for Nodes
+ * \{ */
#if 0 /* UNUSED */
@@ -861,7 +907,11 @@ static void edit_node_properties_get(
}
#endif
-/* ************************** Node generic ************** */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Node Generic
+ * \{ */
/* is rct in visible part of node? */
static bNode *visible_node(SpaceNode &snode, const rctf &rct)
@@ -874,7 +924,11 @@ static bNode *visible_node(SpaceNode &snode, const rctf &rct)
return nullptr;
}
-/* ********************** size widget operator ******************** */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Node Size Widget Operator
+ * \{ */
struct NodeSizeWidget {
float mxstart, mystart;
@@ -1077,7 +1131,11 @@ void NODE_OT_resize(wmOperatorType *ot)
ot->flag = OPTYPE_BLOCKING;
}
-/* ********************** hidden sockets ******************** */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Node Hidden Sockets
+ * \{ */
bool node_has_hidden_sockets(bNode *node)
{
@@ -1211,7 +1269,11 @@ bool node_find_indicated_socket(SpaceNode &snode,
return false;
}
-/* ****************** Link Dimming *********************** */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Node Link Dimming
+ * \{ */
float node_link_dim_factor(const View2D &v2d, const bNodeLink &link)
{
@@ -1237,7 +1299,11 @@ bool node_link_is_hidden_or_dimmed(const View2D &v2d, const bNodeLink &link)
return nodeLinkIsHidden(&link) || node_link_dim_factor(v2d, link) < 0.5f;
}
-/* ****************** Duplicate *********************** */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Node Duplicate Operator
+ * \{ */
static void node_duplicate_reparent_recursive(const Map<const bNode *, bNode *> &node_map,
bNode *node)
@@ -1422,8 +1488,7 @@ void node_select_all(ListBase *lb, int action)
}
}
-/* ******************************** */
-/* XXX some code needing updating to operators. */
+/* XXX: some code needing updating to operators. */
/* goes over all scenes, reads render layers */
static int node_read_viewlayers_exec(bContext *C, wmOperator *UNUSED(op))
@@ -1526,7 +1591,11 @@ void NODE_OT_render_changed(wmOperatorType *ot)
ot->flag = 0;
}
-/* ****************** Hide operator *********************** */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Node Hide Operator
+ * \{ */
static void node_flag_toggle_exec(SpaceNode *snode, int toggle_flag)
{
@@ -1722,7 +1791,11 @@ void NODE_OT_hide_socket_toggle(wmOperatorType *ot)
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
}
-/* ****************** Mute operator *********************** */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Node Mute Operator
+ * \{ */
static int node_mute_exec(bContext *C, wmOperator *UNUSED(op))
{
@@ -1758,7 +1831,11 @@ void NODE_OT_mute_toggle(wmOperatorType *ot)
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
}
-/* ****************** Delete operator ******************* */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Node Delete Operator
+ * \{ */
static int node_delete_exec(bContext *C, wmOperator *UNUSED(op))
{
@@ -1793,7 +1870,11 @@ void NODE_OT_delete(wmOperatorType *ot)
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
}
-/* ****************** Switch View ******************* */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Node Switch View
+ * \{ */
static bool node_switch_view_poll(bContext *C)
{
@@ -1837,7 +1918,12 @@ void NODE_OT_switch_view_update(wmOperatorType *ot)
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
}
-/* ****************** Delete with reconnect ******************* */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Node Delete with Reconnect Operator
+ * \{ */
+
static int node_delete_reconnect_exec(bContext *C, wmOperator *UNUSED(op))
{
Main *bmain = CTX_data_main(C);
@@ -1872,7 +1958,11 @@ void NODE_OT_delete_reconnect(wmOperatorType *ot)
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
}
-/* ****************** File Output Add Socket ******************* */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Node File Output Add Socket Operator
+ * \{ */
static int node_output_file_add_socket_exec(bContext *C, wmOperator *op)
{
@@ -1922,7 +2012,11 @@ void NODE_OT_output_file_add_socket(wmOperatorType *ot)
ot->srna, "file_path", "Image", MAX_NAME, "File Path", "Subpath of the output file");
}
-/* ****************** Multi File Output Remove Socket ******************* */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Node Multi File Output Remove Socket Operator
+ * \{ */
static int node_output_file_remove_active_socket_exec(bContext *C, wmOperator *UNUSED(op))
{
@@ -1968,7 +2062,11 @@ void NODE_OT_output_file_remove_active_socket(wmOperatorType *ot)
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
}
-/* ****************** Multi File Output Move Socket ******************* */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Node Multi File Output Move Socket Node
+ * \{ */
static int node_output_file_move_active_socket_exec(bContext *C, wmOperator *op)
{
@@ -2040,7 +2138,11 @@ void NODE_OT_output_file_move_active_socket(wmOperatorType *ot)
RNA_def_enum(ot->srna, "direction", direction_items, 2, "Direction", "");
}
-/* ****************** Copy Node Color ******************* */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Node Copy Node Color Operator
+ * \{ */
static int node_copy_color_exec(bContext *C, wmOperator *UNUSED(op))
{
@@ -2085,7 +2187,11 @@ void NODE_OT_node_copy_color(wmOperatorType *ot)
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
}
-/* ****************** Copy to clipboard ******************* */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Node Copy to Clipboard Operator
+ * \{ */
static int node_clipboard_copy_exec(bContext *C, wmOperator *UNUSED(op))
{
@@ -2163,7 +2269,11 @@ void NODE_OT_clipboard_copy(wmOperatorType *ot)
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
}
-/* ****************** Paste from clipboard ******************* */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Node Paste from Clipboard
+ * \{ */
static int node_clipboard_paste_exec(bContext *C, wmOperator *op)
{
@@ -2287,7 +2397,11 @@ void NODE_OT_clipboard_paste(wmOperatorType *ot)
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
}
-/********************** Add interface socket operator *********************/
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Node-Tree Add Interface Socket Operator
+ * \{ */
static bNodeSocket *ntree_get_active_interface_socket(ListBase *lb)
{
@@ -2357,7 +2471,11 @@ void NODE_OT_tree_socket_add(wmOperatorType *ot)
RNA_def_enum(ot->srna, "in_out", rna_enum_node_socket_in_out_items, SOCK_IN, "Socket Type", "");
}
-/********************** Remove interface socket operator *********************/
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Node-Tree Remove Interface Socket Operator
+ * \{ */
static int ntree_socket_remove_exec(bContext *C, wmOperator *op)
{
@@ -2403,7 +2521,11 @@ void NODE_OT_tree_socket_remove(wmOperatorType *ot)
RNA_def_enum(ot->srna, "in_out", rna_enum_node_socket_in_out_items, SOCK_IN, "Socket Type", "");
}
-/********************** Change interface socket type operator *********************/
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Node-Tree Change Interface Socket Type Operator
+ * \{ */
static int ntree_socket_change_type_exec(bContext *C, wmOperator *op)
{
@@ -2503,7 +2625,11 @@ void NODE_OT_tree_socket_change_type(wmOperatorType *ot)
ot->prop = prop;
}
-/********************** Move interface socket operator *********************/
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Node-Tree Move Interface Socket Operator
+ * \{ */
static const EnumPropertyItem move_direction_items[] = {
{1, "UP", 0, "Up", ""},
@@ -2577,7 +2703,11 @@ void NODE_OT_tree_socket_move(wmOperatorType *ot)
RNA_def_enum(ot->srna, "in_out", rna_enum_node_socket_in_out_items, SOCK_IN, "Socket Type", "");
}
-/* ********************** Shader Script Update ******************/
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Node Shader Script Update
+ * \{ */
static bool node_shader_script_update_poll(bContext *C)
{
@@ -2722,7 +2852,11 @@ void NODE_OT_shader_script_update(wmOperatorType *ot)
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
}
-/* ********************** Viewer border ******************/
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Node Viewer Border
+ * \{ */
static void viewer_border_corner_to_backdrop(SpaceNode *snode,
ARegion *region,
@@ -2844,7 +2978,11 @@ void NODE_OT_clear_viewer_border(wmOperatorType *ot)
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
}
-/* ****************** Cryptomatte Add Socket ******************* */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Cryptomatte Add Socket
+ * \{ */
static int node_cryptomatte_add_socket_exec(bContext *C, wmOperator *UNUSED(op))
{
@@ -2888,7 +3026,11 @@ void NODE_OT_cryptomatte_layer_add(wmOperatorType *ot)
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
}
-/* ****************** Cryptomatte Remove Socket ******************* */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Cryptomatte Remove Socket
+ * \{ */
static int node_cryptomatte_remove_socket_exec(bContext *C, wmOperator *UNUSED(op))
{
@@ -2933,4 +3075,7 @@ 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 fee64da0459..f08e23c8371 100644
--- a/source/blender/editors/space_node/node_geometry_attribute_search.cc
+++ b/source/blender/editors/space_node/node_geometry_attribute_search.cc
@@ -82,8 +82,10 @@ static Vector<const GeometryAttributeInfo *> get_attribute_info_from_context(
if (const geo_log::GeometryValueLog *geo_value_log =
dynamic_cast<const geo_log::GeometryValueLog *>(value_log)) {
for (const GeometryAttributeInfo &attribute : geo_value_log->attributes()) {
- if (names.add(attribute.name)) {
- attributes.append(&attribute);
+ if (bke::allow_procedural_attribute_access(attribute.name)) {
+ if (names.add(attribute.name)) {
+ attributes.append(&attribute);
+ }
}
}
}
@@ -126,7 +128,7 @@ static void attribute_search_update_fn(
* Some custom data types don't correspond to node types and therefore can't be
* used by the named attribute input node. Find the best option or fallback to float.
*/
-static CustomDataType data_type_in_attribute_input_node(const CustomDataType type)
+static eCustomDataType data_type_in_attribute_input_node(const eCustomDataType type)
{
switch (type) {
case CD_PROP_FLOAT:
@@ -183,9 +185,9 @@ static void attribute_search_exec_fn(bContext *C, void *data_v, void *item_v)
BLI_assert(socket->type == SOCK_STRING);
/* For the attribute input node, also adjust the type and links connected to the output. */
- if (node->type == GEO_NODE_INPUT_NAMED_ATTRIBUTE) {
+ if (node->type == GEO_NODE_INPUT_NAMED_ATTRIBUTE && item->data_type.has_value()) {
NodeGeometryInputNamedAttribute &storage = *(NodeGeometryInputNamedAttribute *)node->storage;
- const CustomDataType new_type = data_type_in_attribute_input_node(item->data_type);
+ const eCustomDataType new_type = data_type_in_attribute_input_node(*item->data_type);
if (new_type != storage.data_type) {
storage.data_type = new_type;
/* Make the output socket with the new type on the attribute input node active. */
diff --git a/source/blender/editors/space_node/node_intern.hh b/source/blender/editors/space_node/node_intern.hh
index 10d4ad36d95..924537d0e8a 100644
--- a/source/blender/editors/space_node/node_intern.hh
+++ b/source/blender/editors/space_node/node_intern.hh
@@ -31,7 +31,9 @@ struct wmKeyConfig;
struct wmWindow;
/* Outside of blender namespace to avoid Python documentation build error with `ctypes`. */
+extern "C" {
extern const char *node_context_dir[];
+};
namespace blender::ed::space_node {
@@ -74,8 +76,18 @@ struct SpaceNode_Runtime {
/** Mouse position for drawing socket-less links and adding nodes. */
float2 cursor;
- /** For auto compositing. */
- bool recalc;
+ /**
+ * Indicates that the compositing tree in the space needs to be re-evaluated using the
+ * auto-compositing pipeline.
+ * Takes priority over the regular compositing.
+ */
+ bool recalc_auto_compositing;
+
+ /**
+ * Indicates that the compositing int the space tree needs to be re-evaluated using
+ * regular compositing pipeline.
+ */
+ bool recalc_regular_compositing;
/** Temporary data for modal linking operator. */
std::unique_ptr<bNodeLinkDrag> linkdrag;
@@ -94,7 +106,7 @@ enum NodeResizeDirection {
};
ENUM_OPERATORS(NodeResizeDirection, NODE_RESIZE_LEFT);
-/* Nodes draw without dpi - the view zoom is flexible. */
+/* Nodes draw without DPI - the view zoom is flexible. */
#define HIDDEN_RAD (0.75f * U.widget_unit)
#define BASIS_RAD (0.2f * U.widget_unit)
#define NODE_DYS (U.widget_unit / 2)
@@ -117,8 +129,6 @@ ENUM_OPERATORS(NodeResizeDirection, NODE_RESIZE_LEFT);
*/
float2 space_node_group_offset(const SpaceNode &snode);
-rctf node_frame_rect_inside(const bNode &node);
-
int node_get_resize_cursor(NodeResizeDirection directions);
/**
* Usual convention here would be #node_socket_get_color(),
@@ -155,6 +165,9 @@ void node_keymap(wmKeyConfig *keyconf);
/* node_select.cc */
+rctf node_frame_rect_inside(const bNode &node);
+bool node_or_socket_isect_event(bContext *C, const wmEvent *event);
+
void node_deselect_all(SpaceNode &snode);
void node_socket_select(bNode *node, bNodeSocket &sock);
void node_socket_deselect(bNode *node, bNodeSocket &sock, bool deselect_node);
diff --git a/source/blender/editors/space_node/node_relationships.cc b/source/blender/editors/space_node/node_relationships.cc
index c757fb46407..e10bedb18f4 100644
--- a/source/blender/editors/space_node/node_relationships.cc
+++ b/source/blender/editors/space_node/node_relationships.cc
@@ -454,7 +454,7 @@ static bool socket_can_be_viewed(const OutputSocketRef &socket)
SOCK_RGBA);
}
-static CustomDataType socket_type_to_custom_data_type(const eNodeSocketDatatype socket_type)
+static eCustomDataType socket_type_to_custom_data_type(const eNodeSocketDatatype socket_type)
{
switch (socket_type) {
case SOCK_FLOAT:
@@ -491,7 +491,7 @@ static bNodeSocket *node_link_viewer_get_socket(bNodeTree &ntree,
return viewer_socket;
}
NodeGeometryViewer *storage = (NodeGeometryViewer *)viewer_node.storage;
- const CustomDataType data_type = socket_type_to_custom_data_type(
+ const eCustomDataType data_type = socket_type_to_custom_data_type(
(eNodeSocketDatatype)src_socket.type);
BLI_assert(data_type != CD_AUTO_FROM_NAME);
storage->data_type = data_type;
@@ -2048,7 +2048,7 @@ static bNodeSocket *get_main_socket(bNodeTree &ntree, bNode &node, eNodeSocketIn
/* Try to get the main socket based on the socket declaration. */
nodeDeclarationEnsure(&ntree, &node);
- const nodes::NodeDeclaration *node_decl = node.declaration;
+ const nodes::NodeDeclaration *node_decl = node.runtime->declaration;
if (node_decl != nullptr) {
Span<nodes::SocketDeclarationPtr> socket_decls = (in_out == SOCK_IN) ? node_decl->inputs() :
node_decl->outputs();
diff --git a/source/blender/editors/space_node/node_select.cc b/source/blender/editors/space_node/node_select.cc
index 1d0097068f1..9d73156edab 100644
--- a/source/blender/editors/space_node/node_select.cc
+++ b/source/blender/editors/space_node/node_select.cc
@@ -48,6 +48,8 @@
namespace blender::ed::space_node {
+static bool is_event_over_node_or_socket(bContext *C, const wmEvent *event);
+
/**
* Function to detect if there is a visible view3d that uses workbench in texture mode.
* This function is for fixing T76970 for Blender 2.83. The actual fix should add a mechanism in
@@ -98,6 +100,11 @@ rctf node_frame_rect_inside(const bNode &node)
return frame_inside;
}
+bool node_or_socket_isect_event(bContext *C, const wmEvent *event)
+{
+ return is_event_over_node_or_socket(C, event);
+}
+
static bool node_frame_select_isect_mouse(bNode *node, const float2 &mouse)
{
/* Frame nodes are selectable by their borders (including their whole rect - as for other nodes -
@@ -193,11 +200,6 @@ static bool is_event_over_node_or_socket(bContext *C, const wmEvent *event)
return is_position_over_node_or_socket(*snode, mouse);
}
-static void node_toggle(bNode *node)
-{
- nodeSetSelected(node, !(node->flag & SELECT));
-}
-
void node_socket_select(bNode *node, bNodeSocket &sock)
{
sock.flag |= SELECT;
@@ -510,10 +512,10 @@ void node_select_single(bContext &C, bNode &node)
WM_event_add_notifier(&C, NC_NODE | NA_SELECTED, nullptr);
}
-static int node_mouse_select(bContext *C,
- wmOperator *op,
- const int mval[2],
- bool wait_to_deselect_others)
+static bool node_mouse_select(bContext *C,
+ wmOperator *op,
+ const int mval[2],
+ struct SelectPick_Params *params)
{
Main &bmain = *CTX_data_main(C);
SpaceNode &snode = *CTX_wm_space_node(C);
@@ -525,36 +527,38 @@ static int node_mouse_select(bContext *C,
bNodeSocket *sock = nullptr;
bNodeSocket *tsock;
float cursor[2];
- int ret_value = OPERATOR_CANCELLED;
- const bool extend = RNA_boolean_get(op->ptr, "extend");
/* always do socket_select when extending selection. */
- const bool socket_select = extend || RNA_boolean_get(op->ptr, "socket_select");
- const bool deselect_all = RNA_boolean_get(op->ptr, "deselect_all");
-
- /* These cases are never modal. */
- if (extend || socket_select) {
- wait_to_deselect_others = false;
- }
+ const bool socket_select = (params->sel_op == SEL_OP_XOR) ||
+ RNA_boolean_get(op->ptr, "socket_select");
+ bool changed = false;
+ bool found = false;
+ bool node_was_selected = false;
/* get mouse coordinates in view2d space */
UI_view2d_region_to_view(&region.v2d, mval[0], mval[1], &cursor[0], &cursor[1]);
/* first do socket selection, these generally overlap with nodes. */
if (socket_select) {
+ /* NOTE: unlike nodes #SelectPick_Params isn't fully supported. */
+ const bool extend = (params->sel_op == SEL_OP_XOR);
if (node_find_indicated_socket(snode, &node, &sock, cursor, SOCK_IN)) {
+ found = true;
+ node_was_selected = node->flag & SELECT;
+
/* NOTE: SOCK_IN does not take into account the extend case...
* This feature is not really used anyway currently? */
node_socket_toggle(node, *sock, true);
- ret_value = OPERATOR_FINISHED;
+ changed = true;
}
else if (node_find_indicated_socket(snode, &node, &sock, cursor, SOCK_OUT)) {
+ found = true;
+ node_was_selected = node->flag & SELECT;
+
if (sock->flag & SELECT) {
if (extend) {
node_socket_deselect(node, *sock, true);
- }
- else {
- ret_value = OPERATOR_FINISHED;
+ changed = true;
}
}
else {
@@ -566,6 +570,7 @@ static int node_mouse_select(bContext *C,
continue;
}
node_socket_deselect(node, *tsock, true);
+ changed = true;
}
}
if (!extend) {
@@ -575,69 +580,71 @@ static int node_mouse_select(bContext *C,
}
for (tsock = (bNodeSocket *)tnode->outputs.first; tsock; tsock = tsock->next) {
node_socket_deselect(tnode, *tsock, true);
+ changed = true;
}
}
}
node_socket_select(node, *sock);
- ret_value = OPERATOR_FINISHED;
+ changed = true;
}
}
}
if (!sock) {
+
/* find the closest visible node */
node = node_under_mouse_select(*snode.edittree, (int)cursor[0], (int)cursor[1]);
+ found = (node != nullptr);
+ node_was_selected = node && (node->flag & SELECT);
- if (extend) {
- if (node != nullptr) {
- /* If node is selected but not active, we want to make it active,
- * but not toggle (deselect) it. */
- if (!((node->flag & SELECT) && (node->flag & NODE_ACTIVE) == 0)) {
- node_toggle(node);
- }
- ret_value = OPERATOR_FINISHED;
- }
- }
- else if (deselect_all && node == nullptr) {
- /* Rather than deselecting others, users may want to drag to box-select (drag from empty
- * space) or tweak-translate an already selected item. If these cases may apply, delay
- * deselection. */
- if (wait_to_deselect_others) {
- ret_value = OPERATOR_RUNNING_MODAL;
+ if (params->sel_op == SEL_OP_SET) {
+ if ((found && params->select_passthrough) && (node->flag & SELECT)) {
+ found = false;
}
- else {
- /* Deselect in empty space. */
+ else if (found || params->deselect_all) {
+ /* Deselect everything. */
for (tnode = (bNode *)snode.edittree->nodes.first; tnode; tnode = tnode->next) {
nodeSetSelected(tnode, false);
}
- ret_value = OPERATOR_FINISHED;
+ changed = true;
}
}
- else if (node != nullptr) {
- /* When clicking on an already selected node, we want to wait to deselect
- * others and allow the user to start moving the node without that. */
- if (wait_to_deselect_others && (node->flag & SELECT)) {
- ret_value = OPERATOR_RUNNING_MODAL;
- }
- else {
- nodeSetSelected(node, true);
- for (tnode = (bNode *)snode.edittree->nodes.first; tnode; tnode = tnode->next) {
- if (tnode != node) {
- nodeSetSelected(tnode, false);
- }
+ if (found) {
+ switch (params->sel_op) {
+ case SEL_OP_ADD: {
+ nodeSetSelected(node, true);
+ break;
+ }
+ case SEL_OP_SUB: {
+ nodeSetSelected(node, false);
+ break;
+ }
+ case SEL_OP_XOR: {
+ /* Check active so clicking on an inactive node activates it. */
+ bool is_selected = (node->flag & NODE_SELECT) && (node->flag & NODE_ACTIVE);
+ nodeSetSelected(node, !is_selected);
+ break;
+ }
+ case SEL_OP_SET: {
+ nodeSetSelected(node, true);
+ break;
+ }
+ case SEL_OP_AND: {
+ BLI_assert_unreachable(); /* Doesn't make sense for picking. */
+ break;
}
-
- ret_value = OPERATOR_FINISHED;
}
+
+ changed = true;
}
}
/* update node order */
- if (ret_value != OPERATOR_CANCELLED) {
+ if (changed || found) {
bool active_texture_changed = false;
bool viewer_node_changed = false;
- if (node != nullptr && ret_value != OPERATOR_RUNNING_MODAL) {
+ if ((node != nullptr) && (node_was_selected == false || params->select_passthrough == false)) {
viewer_node_changed = (node->flag & NODE_DO_OUTPUT) == 0 && node->type == GEO_NODE_VIEWER;
ED_node_set_active(&bmain, &snode, snode.edittree, node, &active_texture_changed);
}
@@ -654,23 +661,35 @@ static int node_mouse_select(bContext *C,
WM_event_add_notifier(C, NC_NODE | NA_SELECTED, nullptr);
}
- return ret_value;
+ return changed || found;
}
static int node_select_exec(bContext *C, wmOperator *op)
{
- const bool wait_to_deselect_others = RNA_boolean_get(op->ptr, "wait_to_deselect_others");
-
/* get settings from RNA properties for operator */
int mval[2];
- mval[0] = RNA_int_get(op->ptr, "mouse_x");
- mval[1] = RNA_int_get(op->ptr, "mouse_y");
+ RNA_int_get_array(op->ptr, "location", mval);
+
+ struct SelectPick_Params params = {};
+ ED_select_pick_params_from_operator(op->ptr, &params);
/* perform the select */
- const int ret_value = node_mouse_select(C, op, mval, wait_to_deselect_others);
+ const bool changed = node_mouse_select(C, op, mval, &params);
+
+ if (changed) {
+ return OPERATOR_PASS_THROUGH | OPERATOR_FINISHED;
+ }
+ /* Nothing selected, just passthrough. */
+ return OPERATOR_PASS_THROUGH | OPERATOR_CANCELLED;
+}
+
+static int node_select_invoke(bContext *C, wmOperator *op, const wmEvent *event)
+{
+ RNA_int_set_array(op->ptr, "location", event->mval);
- /* allow tweak event to work too */
- return ret_value | OPERATOR_PASS_THROUGH;
+ const int retval = node_select_exec(C, op);
+
+ return WM_operator_flag_only_pass_through_on_press(retval, event);
}
void NODE_OT_select(wmOperatorType *ot)
@@ -684,24 +703,29 @@ void NODE_OT_select(wmOperatorType *ot)
/* api callbacks */
ot->exec = node_select_exec;
- ot->invoke = WM_generic_select_invoke;
- ot->modal = WM_generic_select_modal;
+ ot->invoke = node_select_invoke;
ot->poll = ED_operator_node_active;
+ ot->get_name = ED_select_pick_get_name;
/* flags */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
/* properties */
- WM_operator_properties_generic_select(ot);
- prop = RNA_def_boolean(ot->srna, "extend", false, "Extend", "");
- RNA_def_property_flag(prop, PROP_SKIP_SAVE);
+ WM_operator_properties_mouse_select(ot);
+
+ prop = RNA_def_int_vector(ot->srna,
+ "location",
+ 2,
+ nullptr,
+ INT_MIN,
+ INT_MAX,
+ "Location",
+ "Mouse location",
+ INT_MIN,
+ INT_MAX);
+ RNA_def_property_flag(prop, PROP_HIDDEN);
+
RNA_def_boolean(ot->srna, "socket_select", false, "Socket Select", "");
- prop = RNA_def_boolean(ot->srna,
- "deselect_all",
- false,
- "Deselect On Nothing",
- "Deselect all when nothing under the cursor");
- RNA_def_property_flag(prop, PROP_SKIP_SAVE);
}
/** \} */
@@ -871,8 +895,8 @@ void NODE_OT_select_circle(wmOperatorType *ot)
ot->invoke = WM_gesture_circle_invoke;
ot->exec = node_circleselect_exec;
ot->modal = WM_gesture_circle_modal;
-
ot->poll = ED_operator_node_active;
+ ot->get_name = ED_select_circle_get_name;
/* flags */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
diff --git a/source/blender/editors/space_node/node_view.cc b/source/blender/editors/space_node/node_view.cc
index 91a21527ac9..6f30632244b 100644
--- a/source/blender/editors/space_node/node_view.cc
+++ b/source/blender/editors/space_node/node_view.cc
@@ -643,6 +643,12 @@ static int sample_invoke(bContext *C, wmOperator *op, const wmEvent *event)
ARegion *region = CTX_wm_region(C);
ImageSampleInfo *info;
+ /* Don't handle events intended for nodes (which rely on click/drag distinction).
+ * which this operator would use since sampling is normally activated on press, see: T98191. */
+ if (node_or_socket_isect_event(C, event)) {
+ return OPERATOR_PASS_THROUGH;
+ }
+
if (!ED_node_is_compositor(snode) || !(snode->flag & SNODE_BACKDRAW)) {
return OPERATOR_CANCELLED;
}
diff --git a/source/blender/editors/space_node/space_node.cc b/source/blender/editors/space_node/space_node.cc
index 34f357ae5c3..15afd024766 100644
--- a/source/blender/editors/space_node/space_node.cc
+++ b/source/blender/editors/space_node/space_node.cc
@@ -324,6 +324,41 @@ static bool any_node_uses_id(const bNodeTree *ntree, const ID *id)
return false;
}
+/**
+ * Tag the space to recalculate the compositing tree using auto-compositing pipeline.
+ *
+ * Will check the space to be using a compositing tree, and check whether auto-compositing
+ * is enabled. If the checks do not pass then the function has no affect.
+ */
+static void node_area_tag_recalc_auto_compositing(SpaceNode *snode, ScrArea *area)
+{
+ if (!ED_node_is_compositor(snode)) {
+ return;
+ }
+
+ if (snode->flag & SNODE_AUTO_RENDER) {
+ snode->runtime->recalc_auto_compositing = true;
+ ED_area_tag_refresh(area);
+ }
+}
+
+/**
+ * Tag the space to recalculate the current tree.
+ *
+ * For all node trees this will do `snode_set_context()` which takes care of setting an active
+ * tree. This will be done in the area refresh callback.
+ *
+ * For compositor tree this will additionally start of the compositor job.
+ */
+static void node_area_tag_tree_recalc(SpaceNode *snode, ScrArea *area)
+{
+ if (ED_node_is_compositor(snode)) {
+ snode->runtime->recalc_regular_compositing = true;
+ }
+
+ ED_area_tag_refresh(area);
+}
+
static void node_area_listener(const wmSpaceTypeListenerParams *params)
{
ScrArea *area = params->area;
@@ -346,25 +381,20 @@ static void node_area_listener(const wmSpaceTypeListenerParams *params)
UI_view2d_center_set(&region->v2d, path->view_center[0], path->view_center[1]);
}
- ED_area_tag_refresh(area);
+ node_area_tag_tree_recalc(snode, area);
break;
}
case ND_FRAME:
- ED_area_tag_refresh(area);
+ node_area_tag_tree_recalc(snode, area);
break;
case ND_COMPO_RESULT:
ED_area_tag_redraw(area);
break;
case ND_TRANSFORM_DONE:
- if (ED_node_is_compositor(snode)) {
- if (snode->flag & SNODE_AUTO_RENDER) {
- snode->runtime->recalc = true;
- ED_area_tag_refresh(area);
- }
- }
+ node_area_tag_recalc_auto_compositing(snode, area);
break;
case ND_LAYER_CONTENT:
- ED_area_tag_refresh(area);
+ node_area_tag_tree_recalc(snode, area);
break;
}
break;
@@ -373,46 +403,46 @@ static void node_area_listener(const wmSpaceTypeListenerParams *params)
case NC_MATERIAL:
if (ED_node_is_shader(snode)) {
if (wmn->data == ND_SHADING) {
- ED_area_tag_refresh(area);
+ node_area_tag_tree_recalc(snode, area);
}
else if (wmn->data == ND_SHADING_DRAW) {
- ED_area_tag_refresh(area);
+ node_area_tag_tree_recalc(snode, area);
}
else if (wmn->data == ND_SHADING_LINKS) {
- ED_area_tag_refresh(area);
+ node_area_tag_tree_recalc(snode, area);
}
}
break;
case NC_TEXTURE:
if (ED_node_is_shader(snode) || ED_node_is_texture(snode)) {
if (wmn->data == ND_NODES) {
- ED_area_tag_refresh(area);
+ node_area_tag_tree_recalc(snode, area);
}
}
break;
case NC_WORLD:
if (ED_node_is_shader(snode) && shader_type == SNODE_SHADER_WORLD) {
- ED_area_tag_refresh(area);
+ node_area_tag_tree_recalc(snode, area);
}
break;
case NC_OBJECT:
if (ED_node_is_shader(snode)) {
if (wmn->data == ND_OB_SHADING) {
- ED_area_tag_refresh(area);
+ node_area_tag_tree_recalc(snode, area);
}
}
else if (ED_node_is_geometry(snode)) {
/* Rather strict check: only redraw when the reference matches the current editor's ID. */
if (wmn->data == ND_MODIFIER) {
if (wmn->reference == snode->id || snode->id == nullptr) {
- ED_area_tag_refresh(area);
+ node_area_tag_tree_recalc(snode, area);
}
}
}
break;
case NC_SPACE:
if (wmn->data == ND_SPACE_NODE) {
- ED_area_tag_refresh(area);
+ node_area_tag_tree_recalc(snode, area);
}
else if (wmn->data == ND_SPACE_NODE_VIEW) {
ED_area_tag_redraw(area);
@@ -420,7 +450,7 @@ static void node_area_listener(const wmSpaceTypeListenerParams *params)
break;
case NC_NODE:
if (wmn->action == NA_EDITED) {
- ED_area_tag_refresh(area);
+ node_area_tag_tree_recalc(snode, area);
}
else if (wmn->action == NA_SELECTED) {
ED_area_tag_redraw(area);
@@ -429,14 +459,14 @@ static void node_area_listener(const wmSpaceTypeListenerParams *params)
case NC_SCREEN:
switch (wmn->data) {
case ND_ANIMPLAY:
- ED_area_tag_refresh(area);
+ node_area_tag_tree_recalc(snode, area);
break;
}
break;
case NC_MASK:
if (wmn->action == NA_EDITED) {
if (snode->nodetree && snode->nodetree->type == NTREE_COMPOSIT) {
- ED_area_tag_refresh(area);
+ node_area_tag_tree_recalc(snode, area);
}
}
break;
@@ -447,7 +477,7 @@ static void node_area_listener(const wmSpaceTypeListenerParams *params)
/* 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);
+ node_area_tag_tree_recalc(snode, area);
}
}
}
@@ -457,7 +487,7 @@ static void node_area_listener(const wmSpaceTypeListenerParams *params)
if (wmn->action == NA_EDITED) {
if (ED_node_is_compositor(snode)) {
if (any_node_uses_id(snode->nodetree, (ID *)wmn->reference)) {
- ED_area_tag_refresh(area);
+ node_area_tag_tree_recalc(snode, area);
}
}
}
@@ -465,12 +495,12 @@ static void node_area_listener(const wmSpaceTypeListenerParams *params)
case NC_LINESTYLE:
if (ED_node_is_shader(snode) && shader_type == SNODE_SHADER_LINESTYLE) {
- ED_area_tag_refresh(area);
+ node_area_tag_tree_recalc(snode, area);
}
break;
case NC_WM:
if (wmn->data == ND_UNDO) {
- ED_area_tag_refresh(area);
+ node_area_tag_tree_recalc(snode, area);
}
break;
case NC_GPENCIL:
@@ -493,11 +523,13 @@ static void node_area_refresh(const struct bContext *C, ScrArea *area)
Scene *scene = (Scene *)snode->id;
if (scene->use_nodes) {
/* recalc is set on 3d view changes for auto compo */
- if (snode->runtime->recalc) {
- snode->runtime->recalc = false;
+ if (snode->runtime->recalc_auto_compositing) {
+ snode->runtime->recalc_auto_compositing = false;
+ snode->runtime->recalc_regular_compositing = false;
node_render_changed_exec((struct bContext *)C, nullptr);
}
- else {
+ else if (snode->runtime->recalc_regular_compositing) {
+ snode->runtime->recalc_regular_compositing = false;
ED_node_composite_job(C, snode->nodetree, scene);
}
}
@@ -640,7 +672,7 @@ static void node_group_drop_copy(bContext *UNUSED(C), wmDrag *drag, wmDropBox *d
{
ID *id = WM_drag_get_local_ID_or_import_from_asset(drag, 0);
- RNA_string_set(drop->ptr, "name", id->name + 2);
+ RNA_int_set(drop->ptr, "session_uuid", (int)id->session_uuid);
}
static void node_id_drop_copy(bContext *UNUSED(C), wmDrag *drag, wmDropBox *drop)
@@ -655,7 +687,7 @@ static void node_id_path_drop_copy(bContext *UNUSED(C), wmDrag *drag, wmDropBox
ID *id = WM_drag_get_local_ID_or_import_from_asset(drag, 0);
if (id) {
- RNA_string_set(drop->ptr, "name", id->name + 2);
+ RNA_int_set(drop->ptr, "session_uuid", (int)id->session_uuid);
RNA_struct_property_unset(drop->ptr, "filepath");
}
else if (drag->path[0]) {
@@ -794,8 +826,10 @@ 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`. */
+extern "C" {
const char *node_context_dir[] = {
"selected_nodes", "active_node", "light", "material", "world", nullptr};
+};
namespace blender::ed::space_node {
diff --git a/source/blender/editors/space_outliner/CMakeLists.txt b/source/blender/editors/space_outliner/CMakeLists.txt
index 59f6bd85d59..97d2957eed2 100644
--- a/source/blender/editors/space_outliner/CMakeLists.txt
+++ b/source/blender/editors/space_outliner/CMakeLists.txt
@@ -27,6 +27,7 @@ set(SRC
outliner_draw.cc
outliner_edit.cc
outliner_ops.cc
+ outliner_query.cc
outliner_select.cc
outliner_sync.cc
outliner_tools.cc
@@ -57,6 +58,7 @@ set(SRC
tree/tree_element_scene_objects.cc
tree/tree_element_seq.cc
tree/tree_element_view_layer.cc
+ tree/tree_iterator.cc
outliner_intern.hh
tree/common.hh
@@ -75,6 +77,7 @@ set(SRC
tree/tree_element_scene_objects.hh
tree/tree_element_seq.hh
tree/tree_element_view_layer.hh
+ tree/tree_iterator.hh
)
set(LIB
diff --git a/source/blender/editors/space_outliner/outliner_context.cc b/source/blender/editors/space_outliner/outliner_context.cc
index d07b6641836..1a804cb58b8 100644
--- a/source/blender/editors/space_outliner/outliner_context.cc
+++ b/source/blender/editors/space_outliner/outliner_context.cc
@@ -12,23 +12,25 @@
#include "DNA_space_types.h"
#include "outliner_intern.hh"
+#include "tree/tree_iterator.hh"
-static void outliner_context_selected_ids_recursive(const ListBase *subtree,
+using namespace blender::ed::outliner;
+
+static void outliner_context_selected_ids_recursive(const SpaceOutliner &space_outliner,
bContextDataResult *result)
{
- LISTBASE_FOREACH (const TreeElement *, te, subtree) {
+ tree_iterator::all(space_outliner, [&](const TreeElement *te) {
const TreeStoreElem *tse = TREESTORE(te);
if ((tse->flag & TSE_SELECTED) && (ELEM(tse->type, TSE_SOME_ID, TSE_LAYER_COLLECTION))) {
CTX_data_id_list_add(result, tse->id);
}
- outliner_context_selected_ids_recursive(&te->subtree, result);
- }
+ });
}
static void outliner_context_selected_ids(const SpaceOutliner *space_outliner,
bContextDataResult *result)
{
- outliner_context_selected_ids_recursive(&space_outliner->tree, result);
+ outliner_context_selected_ids_recursive(*space_outliner, result);
CTX_data_type_set(result, CTX_DATA_TYPE_COLLECTION);
}
diff --git a/source/blender/editors/space_outliner/outliner_dragdrop.cc b/source/blender/editors/space_outliner/outliner_dragdrop.cc
index 88640210ea3..e20958c1b1e 100644
--- a/source/blender/editors/space_outliner/outliner_dragdrop.cc
+++ b/source/blender/editors/space_outliner/outliner_dragdrop.cc
@@ -170,7 +170,8 @@ static TreeElement *outliner_drop_insert_find(bContext *C,
*r_insert_type = TE_INSERT_BEFORE;
return first;
}
- BLI_assert(0);
+
+ BLI_assert_unreachable();
return nullptr;
}
@@ -315,7 +316,7 @@ static bool parent_drop_poll(bContext *C, wmDrag *drag, const wmEvent *event)
{
SpaceOutliner *space_outliner = CTX_wm_space_outliner(C);
- bool changed = outliner_flag_set(&space_outliner->tree, TSE_DRAG_ANY, false);
+ bool changed = outliner_flag_set(*space_outliner, TSE_DRAG_ANY, false);
if (changed) {
ED_region_tag_redraw_no_rebuild(CTX_wm_region(C));
}
@@ -846,8 +847,7 @@ static bool datastack_drop_poll(bContext *C, wmDrag *drag, const wmEvent *event)
SpaceOutliner *space_outliner = CTX_wm_space_outliner(C);
ARegion *region = CTX_wm_region(C);
- bool changed = outliner_flag_set(
- &space_outliner->tree, TSE_HIGHLIGHTED_ANY | TSE_DRAG_ANY, false);
+ bool changed = outliner_flag_set(*space_outliner, TSE_HIGHLIGHTED_ANY | TSE_DRAG_ANY, false);
StackDropData *drop_data = reinterpret_cast<StackDropData *>(drag->poin);
if (!drop_data) {
@@ -1194,8 +1194,7 @@ static bool collection_drop_poll(bContext *C, wmDrag *drag, const wmEvent *event
{
SpaceOutliner *space_outliner = CTX_wm_space_outliner(C);
ARegion *region = CTX_wm_region(C);
- bool changed = outliner_flag_set(
- &space_outliner->tree, TSE_HIGHLIGHTED_ANY | TSE_DRAG_ANY, false);
+ bool changed = outliner_flag_set(*space_outliner, TSE_HIGHLIGHTED_ANY | TSE_DRAG_ANY, false);
CollectionDrop data;
if (((event->modifier & KM_SHIFT) == 0) &&
@@ -1460,7 +1459,7 @@ static int outliner_item_drag_drop_invoke(bContext *C,
/* Only drag element under mouse if it was not selected before. */
if ((tselem->flag & TSE_SELECTED) == 0) {
- outliner_flag_set(&space_outliner->tree, TSE_SELECTED, 0);
+ outliner_flag_set(*space_outliner, TSE_SELECTED, 0);
tselem->flag |= TSE_SELECTED;
}
diff --git a/source/blender/editors/space_outliner/outliner_draw.cc b/source/blender/editors/space_outliner/outliner_draw.cc
index d898be4eb2c..753de83a10d 100644
--- a/source/blender/editors/space_outliner/outliner_draw.cc
+++ b/source/blender/editors/space_outliner/outliner_draw.cc
@@ -38,6 +38,7 @@
#include "BKE_library.h"
#include "BKE_main.h"
#include "BKE_modifier.h"
+#include "BKE_node.h"
#include "BKE_object.h"
#include "BKE_particle.h"
#include "BKE_report.h"
@@ -70,7 +71,9 @@
#include "tree/tree_element_id.hh"
#include "tree/tree_element_overrides.hh"
#include "tree/tree_element_rna.hh"
+#include "tree/tree_iterator.hh"
+using namespace blender;
using namespace blender::ed::outliner;
/* -------------------------------------------------------------------- */
@@ -1713,72 +1716,70 @@ static void outliner_draw_restrictbuts(uiBlock *block,
}
static void outliner_draw_userbuts(uiBlock *block,
- ARegion *region,
- SpaceOutliner *space_outliner,
- ListBase *lb)
+ const ARegion *region,
+ const SpaceOutliner *space_outliner)
{
+ tree_iterator::all_open(*space_outliner, [&](const TreeElement *te) {
+ if (!outliner_is_element_in_view(te, &region->v2d)) {
+ return;
+ }
- LISTBASE_FOREACH (TreeElement *, te, lb) {
- TreeStoreElem *tselem = TREESTORE(te);
- if (outliner_is_element_in_view(te, &region->v2d)) {
- if (tselem->type == TSE_SOME_ID) {
- uiBut *bt;
- ID *id = tselem->id;
- const char *tip = nullptr;
- char buf[16] = "";
- int but_flag = UI_BUT_DRAG_LOCK;
+ const TreeStoreElem *tselem = TREESTORE(te);
+ if (tselem->type != TSE_SOME_ID) {
+ return;
+ }
- if (ID_IS_LINKED(id)) {
- but_flag |= UI_BUT_DISABLED;
- }
+ uiBut *bt;
+ ID *id = tselem->id;
+ const char *tip = nullptr;
+ char buf[16] = "";
+ int but_flag = UI_BUT_DRAG_LOCK;
- BLI_str_format_int_grouped(buf, id->us);
- bt = uiDefBut(block,
- UI_BTYPE_BUT,
- 1,
- buf,
- (int)(region->v2d.cur.xmax - OL_TOG_USER_BUTS_USERS),
- te->ys,
- UI_UNIT_X,
- UI_UNIT_Y,
- nullptr,
- 0.0,
- 0.0,
- 0,
- 0,
- TIP_("Number of users of this data-block"));
- UI_but_flag_enable(bt, but_flag);
-
- if (id->flag & LIB_FAKEUSER) {
- tip = TIP_("Data-block will be retained using a fake user");
- }
- else {
- tip = TIP_("Data-block has no users and will be deleted");
- }
- bt = uiDefIconButBitS(block,
- UI_BTYPE_ICON_TOGGLE,
- LIB_FAKEUSER,
- 1,
- ICON_FAKE_USER_OFF,
- (int)(region->v2d.cur.xmax - OL_TOG_USER_BUTS_STATUS),
- te->ys,
- UI_UNIT_X,
- UI_UNIT_Y,
- &id->flag,
- 0,
- 0,
- 0,
- 0,
- tip);
- UI_but_func_set(bt, restrictbutton_id_user_toggle, id, nullptr);
- UI_but_flag_enable(bt, but_flag);
- }
+ if (ID_IS_LINKED(id)) {
+ but_flag |= UI_BUT_DISABLED;
}
- if (TSELEM_OPEN(tselem, space_outliner)) {
- outliner_draw_userbuts(block, region, space_outliner, &te->subtree);
+ BLI_str_format_int_grouped(buf, id->us);
+ bt = uiDefBut(block,
+ UI_BTYPE_BUT,
+ 1,
+ buf,
+ (int)(region->v2d.cur.xmax - OL_TOG_USER_BUTS_USERS),
+ te->ys,
+ UI_UNIT_X,
+ UI_UNIT_Y,
+ nullptr,
+ 0.0,
+ 0.0,
+ 0,
+ 0,
+ TIP_("Number of users of this data-block"));
+ UI_but_flag_enable(bt, but_flag);
+
+ if (id->flag & LIB_FAKEUSER) {
+ tip = TIP_("Data-block will be retained using a fake user");
}
- }
+ else {
+ tip = TIP_("Data-block has no users and will be deleted");
+ }
+ bt = uiDefIconButBitS(block,
+ UI_BTYPE_ICON_TOGGLE,
+ LIB_FAKEUSER,
+ 1,
+ ICON_FAKE_USER_OFF,
+ (int)(region->v2d.cur.xmax - OL_TOG_USER_BUTS_STATUS),
+ te->ys,
+ UI_UNIT_X,
+ UI_UNIT_Y,
+ &id->flag,
+ 0,
+ 0,
+ 0,
+ 0,
+ tip);
+ UI_but_func_set(bt, restrictbutton_id_user_toggle, id, nullptr);
+ UI_but_flag_enable(bt, but_flag);
+ });
}
static void outliner_draw_overrides_rna_buts(uiBlock *block,
@@ -1808,6 +1809,25 @@ static void outliner_draw_overrides_rna_buts(uiBlock *block,
TreeElementOverridesProperty &override_elem = *tree_element_cast<TreeElementOverridesProperty>(
te);
+ if (!override_elem.is_rna_path_valid) {
+ uiBut *but = uiDefBut(block,
+ UI_BTYPE_LABEL,
+ 0,
+ override_elem.rna_path.c_str(),
+ x + pad_x,
+ te->ys + pad_y,
+ item_max_width,
+ item_height,
+ nullptr,
+ 0.0f,
+ 0.0f,
+ 0.0f,
+ 0.0f,
+ "");
+ UI_but_flag_enable(but, UI_BUT_REDALERT);
+ continue;
+ }
+
PointerRNA *ptr = &override_elem.override_rna_ptr;
PropertyRNA *prop = &override_elem.override_rna_prop;
const PropertyType prop_type = RNA_property_type(prop);
@@ -1900,90 +1920,6 @@ static void outliner_draw_overrides_restrictbuts(Main *bmain,
}
}
-static bool outliner_draw_overrides_warning_buts(uiBlock *block,
- ARegion *region,
- SpaceOutliner *space_outliner,
- ListBase *lb,
- const bool is_open)
-{
- bool any_item_has_warnings = false;
-
- LISTBASE_FOREACH (TreeElement *, te, lb) {
- bool item_has_warnings = false;
- const bool do_draw = outliner_is_element_in_view(te, &region->v2d);
- int but_flag = UI_BUT_DRAG_LOCK;
- const char *tip = nullptr;
-
- TreeStoreElem *tselem = TREESTORE(te);
- switch (tselem->type) {
- case TSE_LIBRARY_OVERRIDE_BASE: {
- ID *id = tselem->id;
-
- if (id->flag & LIB_LIB_OVERRIDE_RESYNC_LEFTOVER) {
- item_has_warnings = true;
- if (do_draw) {
- tip = TIP_(
- "This override data-block is not needed anymore, but was detected as user-edited");
- }
- }
- else if (ID_IS_OVERRIDE_LIBRARY_REAL(id) && ID_REAL_USERS(id) == 0) {
- item_has_warnings = true;
- if (do_draw) {
- tip = TIP_("This override data-block is unused");
- }
- }
- break;
- }
- case TSE_LIBRARY_OVERRIDE: {
- const bool is_rna_path_valid = (bool)(POINTER_AS_UINT(te->directdata));
- if (!is_rna_path_valid) {
- item_has_warnings = true;
- if (do_draw) {
- tip = TIP_(
- "This override property does not exist in current data, it will be removed on "
- "next .blend file save");
- }
- }
- break;
- }
- default:
- break;
- }
-
- const bool any_child_has_warnings = outliner_draw_overrides_warning_buts(
- block,
- region,
- space_outliner,
- &te->subtree,
- is_open && TSELEM_OPEN(tselem, space_outliner));
-
- if (do_draw &&
- (item_has_warnings || (any_child_has_warnings && !TSELEM_OPEN(tselem, space_outliner)))) {
- if (tip == nullptr) {
- tip = TIP_("Some sub-items require attention");
- }
- uiBut *bt = uiDefIconBut(block,
- UI_BTYPE_BUT,
- 1,
- ICON_ERROR,
- (int)(region->v2d.cur.xmax - OL_TOG_USER_BUTS_STATUS),
- te->ys,
- UI_UNIT_X,
- UI_UNIT_Y,
- nullptr,
- 0.0,
- 0.0,
- 0.0,
- 0.0,
- tip);
- UI_but_flag_enable(bt, but_flag);
- }
- any_item_has_warnings = any_item_has_warnings || item_has_warnings || any_child_has_warnings;
- }
-
- return any_item_has_warnings;
-}
-
static void outliner_draw_separator(ARegion *region, const int x)
{
View2D *v2d = &region->v2d;
@@ -2004,81 +1940,82 @@ static void outliner_draw_separator(ARegion *region, const int x)
immUnbindProgram();
}
-static void outliner_draw_rnabuts(
- uiBlock *block, ARegion *region, SpaceOutliner *space_outliner, int sizex, ListBase *lb)
+static void outliner_draw_rnabuts(uiBlock *block,
+ ARegion *region,
+ SpaceOutliner *space_outliner,
+ int sizex)
{
PointerRNA ptr;
PropertyRNA *prop;
- LISTBASE_FOREACH (TreeElement *, te, lb) {
+ tree_iterator::all_open(*space_outliner, [&](TreeElement *te) {
TreeStoreElem *tselem = TREESTORE(te);
- if (outliner_is_element_in_view(te, &region->v2d)) {
- 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,
- prop,
- -1,
- "",
- ICON_NONE,
- sizex,
- te->ys,
- OL_RNA_COL_SIZEX,
- UI_UNIT_Y - 1);
- UI_but_flag_enable(but, UI_BUT_DISABLED);
- }
- else if (RNA_property_type(prop) == PROP_ENUM) {
- uiDefAutoButR(block,
- &ptr,
- prop,
- -1,
- nullptr,
- ICON_NONE,
- sizex,
- te->ys,
- OL_RNA_COL_SIZEX,
- UI_UNIT_Y - 1);
- }
- else {
- uiDefAutoButR(block,
- &ptr,
- prop,
- -1,
- "",
- ICON_NONE,
- sizex,
- te->ys,
- OL_RNA_COL_SIZEX,
- UI_UNIT_Y - 1);
- }
- }
- }
- 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,
- prop,
- te->index,
- "",
- ICON_NONE,
- sizex,
- te->ys,
- OL_RNA_COL_SIZEX,
- UI_UNIT_Y - 1);
- }
- }
- if (TSELEM_OPEN(tselem, space_outliner)) {
- outliner_draw_rnabuts(block, region, space_outliner, sizex, &te->subtree);
- }
- }
+ if (!outliner_is_element_in_view(te, &region->v2d)) {
+ return;
+ }
+
+ 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,
+ prop,
+ -1,
+ "",
+ ICON_NONE,
+ sizex,
+ te->ys,
+ OL_RNA_COL_SIZEX,
+ UI_UNIT_Y - 1);
+ UI_but_flag_enable(but, UI_BUT_DISABLED);
+ }
+ else if (RNA_property_type(prop) == PROP_ENUM) {
+ uiDefAutoButR(block,
+ &ptr,
+ prop,
+ -1,
+ nullptr,
+ ICON_NONE,
+ sizex,
+ te->ys,
+ OL_RNA_COL_SIZEX,
+ UI_UNIT_Y - 1);
+ }
+ else {
+ uiDefAutoButR(block,
+ &ptr,
+ prop,
+ -1,
+ "",
+ ICON_NONE,
+ sizex,
+ te->ys,
+ OL_RNA_COL_SIZEX,
+ UI_UNIT_Y - 1);
+ }
+ }
+ }
+ 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,
+ prop,
+ te->index,
+ "",
+ ICON_NONE,
+ sizex,
+ te->ys,
+ OL_RNA_COL_SIZEX,
+ UI_UNIT_Y - 1);
+ }
+ });
}
static void outliner_buttons(const bContext *C,
@@ -2164,9 +2101,9 @@ static void outliner_mode_toggle_fn(bContext *C, void *tselem_poin, void *UNUSED
static void outliner_draw_mode_column_toggle(uiBlock *block,
TreeViewContext *tvc,
TreeElement *te,
- TreeStoreElem *tselem,
const bool lock_object_modes)
{
+ TreeStoreElem *tselem = TREESTORE(te);
if ((tselem->type != TSE_SOME_ID) || (te->idcode != ID_OB)) {
return;
}
@@ -2237,59 +2174,63 @@ static void outliner_draw_mode_column_toggle(uiBlock *block,
}
}
-static void outliner_draw_mode_column(const bContext *C,
- uiBlock *block,
+static void outliner_draw_mode_column(uiBlock *block,
TreeViewContext *tvc,
- SpaceOutliner *space_outliner,
- ListBase *tree)
+ SpaceOutliner *space_outliner)
{
- TreeStoreElem *tselem;
const bool lock_object_modes = tvc->scene->toolsettings->object_flag & SCE_OBJECT_MODE_LOCK;
- LISTBASE_FOREACH (TreeElement *, te, tree) {
- tselem = TREESTORE(te);
-
+ tree_iterator::all_open(*space_outliner, [&](TreeElement *te) {
if (tvc->obact && tvc->obact->mode != OB_MODE_OBJECT) {
- outliner_draw_mode_column_toggle(block, tvc, te, tselem, lock_object_modes);
+ outliner_draw_mode_column_toggle(block, tvc, te, lock_object_modes);
}
+ });
+}
- if (TSELEM_OPEN(tselem, space_outliner)) {
- outliner_draw_mode_column(C, block, tvc, space_outliner, &te->subtree);
+static StringRefNull outliner_draw_get_warning_tree_element_subtree(const TreeElement *parent_te)
+{
+ LISTBASE_FOREACH (const TreeElement *, sub_te, &parent_te->subtree) {
+ const AbstractTreeElement *abstract_te = tree_element_cast<AbstractTreeElement>(sub_te);
+ StringRefNull warning_msg = abstract_te ? abstract_te->getWarning() : "";
+
+ if (!warning_msg.is_empty()) {
+ return warning_msg;
+ }
+
+ warning_msg = outliner_draw_get_warning_tree_element_subtree(sub_te);
+ if (!warning_msg.is_empty()) {
+ return warning_msg;
}
}
+
+ return "";
}
-/* 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)
+static StringRefNull outliner_draw_get_warning_tree_element(const SpaceOutliner &space_outliner,
+ const TreeElement *te)
{
- 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);
+ const AbstractTreeElement *abstract_te = tree_element_cast<AbstractTreeElement>(te);
+ const StringRefNull warning_msg = abstract_te ? abstract_te->getWarning() : "";
- if (outliner_draw_warning_tree_element(
- block, space_outliner, sub_te, sub_tselem, use_mode_column, te_ys)) {
- return true;
- }
- }
- }
- return false;
+ if (!warning_msg.is_empty()) {
+ return warning_msg;
}
- 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);
+ /* If given element has no warning, recursively try to display the first sub-element's warning.
+ */
+ if (!TSELEM_OPEN(te->store_elem, &space_outliner)) {
+ return outliner_draw_get_warning_tree_element_subtree(te);
+ }
+ return "";
+}
+
+static void outliner_draw_warning_tree_element(uiBlock *block,
+ const SpaceOutliner *space_outliner,
+ StringRefNull warning_msg,
+ const bool use_mode_column,
+ const int te_ys)
+{
/* 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 :
@@ -2299,7 +2240,7 @@ static bool outliner_draw_warning_tree_element(uiBlock *block,
uiBut *but = uiDefIconBut(block,
UI_BTYPE_ICON_TOGGLE,
0,
- icon,
+ ICON_ERROR,
mode_column_offset,
te_ys,
UI_UNIT_X,
@@ -2309,28 +2250,25 @@ static bool outliner_draw_warning_tree_element(uiBlock *block,
0.0,
0.0,
0.0,
- tip);
+ warning_msg.c_str());
/* 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)
+static void outliner_draw_warning_column(uiBlock *block,
+ const SpaceOutliner *space_outliner,
+ const bool use_mode_column)
{
- LISTBASE_FOREACH (TreeElement *, te, tree) {
- TreeStoreElem *tselem = TREESTORE(te);
+ tree_iterator::all_open(*space_outliner, [&](const TreeElement *te) {
+ /* Get warning for this element, or if there is none and the element is collapsed, the first
+ * warning in the collapsed sub-tree. */
+ StringRefNull warning_msg = outliner_draw_get_warning_tree_element(*space_outliner, 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);
+ if (!warning_msg.is_empty()) {
+ outliner_draw_warning_tree_element(
+ block, space_outliner, warning_msg, use_mode_column, te->ys);
}
- }
+ });
}
/** \} */
@@ -2504,6 +2442,11 @@ static BIFIconID tree_element_get_icon_from_id(const ID *id)
return ICON_WORKSPACE;
case ID_MSK:
return ICON_MOD_MASK;
+ case ID_NT: {
+ const bNodeTree *ntree = (bNodeTree *)id;
+ const bNodeTreeType *ntreetype = ntree->typeinfo;
+ return (BIFIconID)ntreetype->ui_icon;
+ }
case ID_MC:
return ICON_SEQUENCE;
case ID_PC:
@@ -3206,18 +3149,16 @@ static void outliner_draw_iconrow(bContext *C,
}
/* closed tree element */
-static void outliner_set_coord_tree_element(TreeElement *te, int startx, int starty)
+static void outliner_set_subtree_coords(const TreeElement *te)
{
- /* closed items may be displayed in row of parent, don't change their coordinate! */
- if ((te->flag & TE_ICONROW) == 0 && (te->flag & TE_ICONROW_MERGED) == 0) {
- te->xs = 0;
- te->ys = 0;
- te->xend = 0;
- }
-
- LISTBASE_FOREACH (TreeElement *, ten, &te->subtree) {
- outliner_set_coord_tree_element(ten, startx + UI_UNIT_X, starty);
- }
+ tree_iterator::all(te->subtree, [&](TreeElement *te) {
+ /* closed items may be displayed in row of parent, don't change their coordinate! */
+ if ((te->flag & TE_ICONROW) == 0 && (te->flag & TE_ICONROW_MERGED) == 0) {
+ te->xs = 0;
+ te->ys = 0;
+ te->xend = 0;
+ }
+ });
}
static bool element_should_draw_faded(const TreeViewContext *tvc,
@@ -3469,10 +3410,7 @@ static void outliner_draw_tree_element(bContext *C,
}
}
else {
- LISTBASE_FOREACH (TreeElement *, ten, &te->subtree) {
- outliner_set_coord_tree_element(ten, startx, *starty);
- }
-
+ outliner_set_subtree_coords(te);
*starty -= UI_UNIT_Y;
}
}
@@ -3628,22 +3566,21 @@ static void outliner_draw_struct_marks(ARegion *region,
}
}
-static void outliner_draw_highlights_recursive(uint pos,
- const ARegion *region,
- const SpaceOutliner *space_outliner,
- const ListBase *lb,
- const float col_selection[4],
- const float col_active[4],
- const float col_highlight[4],
- const float col_searchmatch[4],
- int start_x,
- int *io_start_y)
+static void outliner_draw_highlights(uint pos,
+ const ARegion *region,
+ const SpaceOutliner *space_outliner,
+ const float col_selection[4],
+ const float col_active[4],
+ const float col_highlight[4],
+ const float col_searchmatch[4],
+ int start_x,
+ int *io_start_y)
{
const bool is_searching = (SEARCHING_OUTLINER(space_outliner) ||
(space_outliner->outlinevis == SO_DATA_API &&
space_outliner->search_string[0] != 0));
- LISTBASE_FOREACH (TreeElement *, te, lb) {
+ tree_iterator::all_open(*space_outliner, [&](const TreeElement *te) {
const TreeStoreElem *tselem = TREESTORE(te);
const int start_y = *io_start_y;
@@ -3699,19 +3636,7 @@ static void outliner_draw_highlights_recursive(uint pos,
}
*io_start_y -= UI_UNIT_Y;
- if (TSELEM_OPEN(tselem, space_outliner)) {
- outliner_draw_highlights_recursive(pos,
- region,
- space_outliner,
- &te->subtree,
- col_selection,
- col_active,
- col_highlight,
- col_searchmatch,
- start_x + UI_UNIT_X,
- io_start_y);
- }
- }
+ });
}
static void outliner_draw_highlights(ARegion *region,
@@ -3733,16 +3658,15 @@ static void outliner_draw_highlights(ARegion *region,
GPUVertFormat *format = immVertexFormat();
uint pos = GPU_vertformat_attr_add(format, "pos", GPU_COMP_I32, 2, GPU_FETCH_INT_TO_FLOAT);
immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
- outliner_draw_highlights_recursive(pos,
- region,
- space_outliner,
- &space_outliner->tree,
- col_selection,
- col_active,
- col_highlight,
- col_searchmatch,
- startx,
- starty);
+ outliner_draw_highlights(pos,
+ region,
+ space_outliner,
+ col_selection,
+ col_active,
+ col_highlight,
+ col_searchmatch,
+ startx,
+ starty);
immUnbindProgram();
GPU_blend(GPU_BLEND_NONE);
}
@@ -3935,13 +3859,8 @@ void draw_outliner(const bContext *C)
UI_view2d_view_ortho(v2d);
/* Only show mode column in View Layers and Scenes view. */
- 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();
+ const bool use_mode_column = outliner_shows_mode_column(*space_outliner);
+ const bool use_warning_column = outliner_has_element_warnings(*space_outliner);
/* Draw outliner stuff (background, hierarchy lines and names). */
const float right_column_width = outliner_right_columns_width(space_outliner);
@@ -3971,18 +3890,14 @@ void draw_outliner(const bContext *C)
outliner_draw_separator(region, buttons_start_x + OL_RNA_COL_SIZEX);
UI_block_emboss_set(block, UI_EMBOSS);
- outliner_draw_rnabuts(block, region, space_outliner, buttons_start_x, &space_outliner->tree);
+ outliner_draw_rnabuts(block, region, space_outliner, buttons_start_x);
UI_block_emboss_set(block, UI_EMBOSS_NONE_OR_STATUS);
}
else if (space_outliner->outlinevis == SO_ID_ORPHANS) {
/* draw user toggle columns */
- outliner_draw_userbuts(block, region, space_outliner, &space_outliner->tree);
+ outliner_draw_userbuts(block, region, space_outliner);
}
else if (space_outliner->outlinevis == SO_OVERRIDES_LIBRARY) {
- /* Draw overrides status columns. */
- outliner_draw_overrides_warning_buts(
- block, region, space_outliner, &space_outliner->tree, true);
-
const int x = region->v2d.cur.xmax - right_column_width;
outliner_draw_separator(region, x);
if (space_outliner->lib_override_view_mode == SO_LIB_OVERRIDE_VIEW_PROPERTIES) {
@@ -4011,12 +3926,12 @@ void draw_outliner(const bContext *C)
/* Draw mode icons */
if (use_mode_column) {
- outliner_draw_mode_column(C, block, &tvc, space_outliner, &space_outliner->tree);
+ outliner_draw_mode_column(block, &tvc, space_outliner);
}
/* Draw warning icons */
if (use_warning_column) {
- outliner_draw_warning_column(C, block, space_outliner, use_mode_column, &space_outliner->tree);
+ outliner_draw_warning_column(block, space_outliner, use_mode_column);
}
UI_block_emboss_set(block, UI_EMBOSS);
diff --git a/source/blender/editors/space_outliner/outliner_edit.cc b/source/blender/editors/space_outliner/outliner_edit.cc
index d6c5901b546..c4a9398a5f7 100644
--- a/source/blender/editors/space_outliner/outliner_edit.cc
+++ b/source/blender/editors/space_outliner/outliner_edit.cc
@@ -60,6 +60,7 @@
#include "outliner_intern.hh"
#include "tree/tree_element_rna.hh"
+#include "tree/tree_iterator.hh"
using namespace blender::ed::outliner;
@@ -107,7 +108,7 @@ static int outliner_highlight_update(bContext *C, wmOperator *UNUSED(op), const
if (!hovered_te || !is_over_icon || !(hovered_te->store_elem->flag & TSE_HIGHLIGHTED) ||
!(icon_te->store_elem->flag & TSE_HIGHLIGHTED_ICON)) {
/* Clear highlights when nothing is hovered or when a new item is hovered. */
- changed = outliner_flag_set(&space_outliner->tree, TSE_HIGHLIGHTED_ANY | TSE_DRAG_ANY, false);
+ changed = outliner_flag_set(*space_outliner, TSE_HIGHLIGHTED_ANY | TSE_DRAG_ANY, false);
if (hovered_te) {
hovered_te->store_elem->flag |= TSE_HIGHLIGHTED;
changed = true;
@@ -167,7 +168,7 @@ void outliner_item_openclose(SpaceOutliner *space_outliner,
}
if (toggle_all) {
- outliner_flag_set(&te->subtree, TSE_CLOSED, !open);
+ outliner_flag_set(te->subtree, TSE_CLOSED, !open);
}
}
@@ -334,8 +335,16 @@ static void do_item_rename(ARegion *region,
add_textbut = true;
}
}
- else if (te->idcode == ID_LI && ((Library *)tselem->id)->parent) {
- BKE_report(reports, RPT_WARNING, "Cannot edit the path of an indirectly linked library");
+ else if (te->idcode == ID_LI) {
+ if (reinterpret_cast<Library *>(tselem->id)->parent) {
+ BKE_report(reports, RPT_WARNING, "Cannot edit the path of an indirectly linked library");
+ }
+ else {
+ BKE_report(
+ reports,
+ RPT_WARNING,
+ "Library path is not editable from here anymore, please use Relocate operation instead");
+ }
}
else {
add_textbut = true;
@@ -1069,11 +1078,16 @@ int outliner_flag_is_any_test(ListBase *lb, short flag, const int curlevel)
return 0;
}
-bool outliner_flag_set(ListBase *lb, short flag, short set)
+bool outliner_flag_set(const SpaceOutliner &space_outliner, const short flag, const short set)
+{
+ return outliner_flag_set(space_outliner.tree, flag, set);
+}
+
+bool outliner_flag_set(const ListBase &lb, const short flag, const short set)
{
bool changed = false;
- LISTBASE_FOREACH (TreeElement *, te, lb) {
+ tree_iterator::all(lb, [&](TreeElement *te) {
TreeStoreElem *tselem = TREESTORE(te);
bool has_flag = (tselem->flag & flag);
if (set == 0) {
@@ -1086,21 +1100,24 @@ bool outliner_flag_set(ListBase *lb, short flag, short set)
tselem->flag |= flag;
changed = true;
}
- changed |= outliner_flag_set(&te->subtree, flag, set);
- }
+ });
return changed;
}
-bool outliner_flag_flip(ListBase *lb, short flag)
+bool outliner_flag_flip(const SpaceOutliner &space_outliner, const short flag)
+{
+ return outliner_flag_flip(space_outliner.tree, flag);
+}
+
+bool outliner_flag_flip(const ListBase &lb, const short flag)
{
bool changed = false;
- LISTBASE_FOREACH (TreeElement *, te, lb) {
+ tree_iterator::all(lb, [&](TreeElement *te) {
TreeStoreElem *tselem = TREESTORE(te);
tselem->flag ^= flag;
- changed |= outliner_flag_flip(&te->subtree, flag);
- }
+ });
return changed;
}
@@ -1117,10 +1134,10 @@ static int outliner_toggle_expanded_exec(bContext *C, wmOperator *UNUSED(op))
ARegion *region = CTX_wm_region(C);
if (outliner_flag_is_any_test(&space_outliner->tree, TSE_CLOSED, 1)) {
- outliner_flag_set(&space_outliner->tree, TSE_CLOSED, 0);
+ outliner_flag_set(*space_outliner, TSE_CLOSED, 0);
}
else {
- outliner_flag_set(&space_outliner->tree, TSE_CLOSED, 1);
+ outliner_flag_set(*space_outliner, TSE_CLOSED, 1);
}
ED_region_tag_redraw(region);
@@ -1161,13 +1178,13 @@ static int outliner_select_all_exec(bContext *C, wmOperator *op)
switch (action) {
case SEL_SELECT:
- outliner_flag_set(&space_outliner->tree, TSE_SELECTED, 1);
+ outliner_flag_set(*space_outliner, TSE_SELECTED, 1);
break;
case SEL_DESELECT:
- outliner_flag_set(&space_outliner->tree, TSE_SELECTED, 0);
+ outliner_flag_set(*space_outliner, TSE_SELECTED, 0);
break;
case SEL_INVERT:
- outliner_flag_flip(&space_outliner->tree, TSE_SELECTED);
+ outliner_flag_flip(*space_outliner, TSE_SELECTED);
break;
}
@@ -1203,32 +1220,16 @@ void OUTLINER_OT_select_all(wmOperatorType *ot)
/** \name View Show Active (Outliner) Operator
* \{ */
-static void outliner_set_coordinates_element_recursive(SpaceOutliner *space_outliner,
- TreeElement *te,
- int startx,
- int *starty)
-{
- TreeStoreElem *tselem = TREESTORE(te);
-
- /* store coord and continue, we need coordinates for elements outside view too */
- te->xs = (float)startx;
- te->ys = (float)(*starty);
- *starty -= UI_UNIT_Y;
-
- if (TSELEM_OPEN(tselem, space_outliner)) {
- LISTBASE_FOREACH (TreeElement *, ten, &te->subtree) {
- outliner_set_coordinates_element_recursive(space_outliner, ten, startx + UI_UNIT_X, starty);
- }
- }
-}
-
-void outliner_set_coordinates(ARegion *region, SpaceOutliner *space_outliner)
+void outliner_set_coordinates(const ARegion *region, const SpaceOutliner *space_outliner)
{
int starty = (int)(region->v2d.tot.ymax) - UI_UNIT_Y;
- LISTBASE_FOREACH (TreeElement *, te, &space_outliner->tree) {
- outliner_set_coordinates_element_recursive(space_outliner, te, 0, &starty);
- }
+ tree_iterator::all_open(*space_outliner, [&](TreeElement *te) {
+ /* store coord and continue, we need coordinates for elements outside view too */
+ te->xs = 0;
+ te->ys = (float)starty;
+ starty -= UI_UNIT_Y;
+ });
}
/* return 1 when levels were opened */
@@ -1616,11 +1617,11 @@ static int subtree_has_objects(ListBase *lb)
return 0;
}
-/* recursive helper function for Show Hierarchy operator */
-static void tree_element_show_hierarchy(Scene *scene, SpaceOutliner *space_outliner, ListBase *lb)
+/* Helper function for Show Hierarchy operator */
+static void tree_element_show_hierarchy(Scene *scene, SpaceOutliner *space_outliner)
{
/* open all object elems, close others */
- LISTBASE_FOREACH (TreeElement *, te, lb) {
+ tree_iterator::all_open(*space_outliner, [&](TreeElement *te) {
TreeStoreElem *tselem = TREESTORE(te);
if (ELEM(tselem->type,
@@ -1648,11 +1649,7 @@ static void tree_element_show_hierarchy(Scene *scene, SpaceOutliner *space_outli
else {
tselem->flag |= TSE_CLOSED;
}
-
- if (TSELEM_OPEN(tselem, space_outliner)) {
- tree_element_show_hierarchy(scene, space_outliner, &te->subtree);
- }
- }
+ });
}
/* show entire object level hierarchy */
@@ -1663,7 +1660,7 @@ static int outliner_show_hierarchy_exec(bContext *C, wmOperator *UNUSED(op))
Scene *scene = CTX_data_scene(C);
/* recursively open/close levels */
- tree_element_show_hierarchy(scene, space_outliner, &space_outliner->tree);
+ tree_element_show_hierarchy(scene, space_outliner);
ED_region_tag_redraw(region);
@@ -1865,79 +1862,75 @@ enum {
DRIVERS_EDITMODE_REMOVE,
} /*eDrivers_EditModes*/;
-/* Recursively iterate over tree, finding and working on selected items */
+/* Iterate over tree, finding and working on selected items */
static void do_outliner_drivers_editop(SpaceOutliner *space_outliner,
- ListBase *tree,
ReportList *reports,
short mode)
{
- LISTBASE_FOREACH (TreeElement *, te, tree) {
+ tree_iterator::all_open(*space_outliner, [&](TreeElement *te) {
TreeStoreElem *tselem = TREESTORE(te);
/* if item is selected, perform operation */
- if (tselem->flag & TSE_SELECTED) {
- 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 (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);
- }
+ if (!(tselem->flag & TSE_SELECTED)) {
+ return;
+ }
- /* only if ID and path were set, should we perform any actions */
- if (id && path) {
- short dflags = CREATEDRIVER_WITH_DEFAULT_DVAR;
- int arraylen = 1;
+ ID *id = nullptr;
+ char *path = nullptr;
+ int array_index = 0;
+ short flag = 0;
+ short groupmode = KSP_GROUP_KSNAME;
- /* array checks */
- if (flag & KSP_FLAG_WHOLE_ARRAY) {
- /* entire array was selected, so add drivers for all */
- arraylen = RNA_property_array_length(&ptr, prop);
- }
- else {
- arraylen = array_index;
- }
+ 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;
- /* we should do at least one step */
- if (arraylen == array_index) {
- arraylen++;
- }
+ /* check if RNA-property described by this selected element is an animatable prop */
+ 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);
+ }
- /* for each array element we should affect, add driver */
- for (; array_index < arraylen; array_index++) {
- /* action depends on mode */
- switch (mode) {
- case DRIVERS_EDITMODE_ADD: {
- /* add a new driver with the information obtained (only if valid) */
- ANIM_add_driver(reports, id, path, array_index, dflags, DRIVER_TYPE_PYTHON);
- break;
- }
- case DRIVERS_EDITMODE_REMOVE: {
- /* remove driver matching the information obtained (only if valid) */
- ANIM_remove_driver(reports, id, path, array_index, dflags);
- break;
- }
+ /* only if ID and path were set, should we perform any actions */
+ if (id && path) {
+ short dflags = CREATEDRIVER_WITH_DEFAULT_DVAR;
+ int arraylen = 1;
+
+ /* array checks */
+ if (flag & KSP_FLAG_WHOLE_ARRAY) {
+ /* entire array was selected, so add drivers for all */
+ arraylen = RNA_property_array_length(&ptr, prop);
+ }
+ else {
+ arraylen = array_index;
+ }
+
+ /* we should do at least one step */
+ if (arraylen == array_index) {
+ arraylen++;
+ }
+
+ /* for each array element we should affect, add driver */
+ for (; array_index < arraylen; array_index++) {
+ /* action depends on mode */
+ switch (mode) {
+ case DRIVERS_EDITMODE_ADD: {
+ /* add a new driver with the information obtained (only if valid) */
+ ANIM_add_driver(reports, id, path, array_index, dflags, DRIVER_TYPE_PYTHON);
+ break;
+ }
+ case DRIVERS_EDITMODE_REMOVE: {
+ /* remove driver matching the information obtained (only if valid) */
+ ANIM_remove_driver(reports, id, path, array_index, dflags);
+ break;
}
}
-
- /* free path, since it had to be generated */
- MEM_freeN(path);
}
- }
- /* go over sub-tree */
- if (TSELEM_OPEN(tselem, space_outliner)) {
- do_outliner_drivers_editop(space_outliner, &te->subtree, reports, mode);
+ /* free path, since it had to be generated */
+ MEM_freeN(path);
}
- }
+ });
}
/** \} */
@@ -1956,8 +1949,7 @@ static int outliner_drivers_addsel_exec(bContext *C, wmOperator *op)
}
/* recursively go into tree, adding selected items */
- do_outliner_drivers_editop(
- space_outliner, &space_outliner->tree, op->reports, DRIVERS_EDITMODE_ADD);
+ do_outliner_drivers_editop(space_outliner, op->reports, DRIVERS_EDITMODE_ADD);
/* send notifiers */
WM_event_add_notifier(C, NC_ANIMATION | ND_FCURVES_ORDER, nullptr); /* XXX */
@@ -1996,8 +1988,7 @@ static int outliner_drivers_deletesel_exec(bContext *C, wmOperator *op)
}
/* recursively go into tree, adding selected items */
- do_outliner_drivers_editop(
- space_outliner, &space_outliner->tree, op->reports, DRIVERS_EDITMODE_REMOVE);
+ do_outliner_drivers_editop(space_outliner, op->reports, DRIVERS_EDITMODE_REMOVE);
/* send notifiers */
WM_event_add_notifier(C, ND_KEYS, nullptr); /* XXX */
@@ -2064,68 +2055,64 @@ static KeyingSet *verify_active_keyingset(Scene *scene, short add)
return ks;
}
-/* Recursively iterate over tree, finding and working on selected items */
+/* Iterate over tree, finding and working on selected items */
static void do_outliner_keyingset_editop(SpaceOutliner *space_outliner,
KeyingSet *ks,
- ListBase *tree,
- short mode)
+ const short mode)
{
- LISTBASE_FOREACH (TreeElement *, te, tree) {
+ tree_iterator::all_open(*space_outliner, [&](TreeElement *te) {
TreeStoreElem *tselem = TREESTORE(te);
/* if item is selected, perform operation */
- if (tselem->flag & TSE_SELECTED) {
- 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 */
- 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);
- }
+ if (!(tselem->flag & TSE_SELECTED)) {
+ return;
+ }
- /* only if ID and path were set, should we perform any actions */
- if (id && path) {
- /* action depends on mode */
- switch (mode) {
- case KEYINGSET_EDITMODE_ADD: {
- /* 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, 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, nullptr, path, array_index, groupmode);
+ 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 */
+ 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);
+ }
- if (ksp) {
- /* free path's data */
- BKE_keyingset_free_path(ks, ksp);
+ /* only if ID and path were set, should we perform any actions */
+ if (id && path) {
+ /* action depends on mode */
+ switch (mode) {
+ case KEYINGSET_EDITMODE_ADD: {
+ /* 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, 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, nullptr, path, array_index, groupmode);
- ks->active_path = 0;
- }
- break;
+ if (ksp) {
+ /* free path's data */
+ BKE_keyingset_free_path(ks, ksp);
+
+ ks->active_path = 0;
}
+ break;
}
-
- /* free path, since it had to be generated */
- MEM_freeN(path);
}
- }
- /* go over sub-tree */
- if (TSELEM_OPEN(tselem, space_outliner)) {
- do_outliner_keyingset_editop(space_outliner, ks, &te->subtree, mode);
+ /* free path, since it had to be generated */
+ MEM_freeN(path);
}
- }
+ });
}
/** \} */
@@ -2150,7 +2137,7 @@ static int outliner_keyingset_additems_exec(bContext *C, wmOperator *op)
}
/* recursively go into tree, adding selected items */
- do_outliner_keyingset_editop(space_outliner, ks, &space_outliner->tree, KEYINGSET_EDITMODE_ADD);
+ do_outliner_keyingset_editop(space_outliner, ks, KEYINGSET_EDITMODE_ADD);
/* send notifiers */
WM_event_add_notifier(C, NC_SCENE | ND_KEYINGSET, nullptr);
@@ -2191,8 +2178,7 @@ static int outliner_keyingset_removeitems_exec(bContext *C, wmOperator *UNUSED(o
}
/* recursively go into tree, adding selected items */
- do_outliner_keyingset_editop(
- space_outliner, ks, &space_outliner->tree, KEYINGSET_EDITMODE_REMOVE);
+ do_outliner_keyingset_editop(space_outliner, ks, KEYINGSET_EDITMODE_REMOVE);
/* send notifiers */
WM_event_add_notifier(C, NC_SCENE | ND_KEYINGSET, nullptr);
diff --git a/source/blender/editors/space_outliner/outliner_intern.hh b/source/blender/editors/space_outliner/outliner_intern.hh
index f3bcb7b0f1e..a0dcb49aa43 100644
--- a/source/blender/editors/space_outliner/outliner_intern.hh
+++ b/source/blender/editors/space_outliner/outliner_intern.hh
@@ -160,8 +160,6 @@ 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 */
@@ -410,8 +408,12 @@ 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.
*/
-bool outliner_flag_set(ListBase *lb, short flag, short set);
-bool outliner_flag_flip(ListBase *lb, short flag);
+extern "C++" {
+bool outliner_flag_set(const SpaceOutliner &space_outliner, short flag, short set);
+bool outliner_flag_set(const ListBase &lb, short flag, short set);
+bool outliner_flag_flip(const SpaceOutliner &space_outliner, short flag);
+bool outliner_flag_flip(const ListBase &lb, short flag);
+}
void item_rename_fn(struct bContext *C,
struct ReportList *reports,
@@ -453,7 +455,8 @@ void id_remap_fn(struct bContext *C,
/**
* To retrieve coordinates with redrawing the entire tree.
*/
-void outliner_set_coordinates(struct ARegion *region, struct SpaceOutliner *space_outliner);
+void outliner_set_coordinates(const struct ARegion *region,
+ const struct SpaceOutliner *space_outliner);
/**
* Open or close a tree element, optionally toggling all children recursively.
@@ -510,6 +513,11 @@ void OUTLINER_OT_drivers_delete_selected(struct wmOperatorType *ot);
void OUTLINER_OT_orphans_purge(struct wmOperatorType *ot);
+/* outliner_query.cc ---------------------------------------------- */
+
+bool outliner_shows_mode_column(const SpaceOutliner &space_outliner);
+bool outliner_has_element_warnings(const SpaceOutliner &space_outliner);
+
/* outliner_tools.c ---------------------------------------------- */
void merged_element_search_menu_invoke(struct bContext *C,
diff --git a/source/blender/editors/space_outliner/outliner_query.cc b/source/blender/editors/space_outliner/outliner_query.cc
new file mode 100644
index 00000000000..d6483c44fce
--- /dev/null
+++ b/source/blender/editors/space_outliner/outliner_query.cc
@@ -0,0 +1,48 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+
+/** \file
+ * \ingroup spoutliner
+ */
+
+#include <functional>
+
+#include "BLI_listbase.h"
+
+#include "DNA_space_types.h"
+
+#include "outliner_intern.hh"
+#include "tree/tree_display.hh"
+
+using namespace blender::ed::outliner;
+
+bool outliner_shows_mode_column(const SpaceOutliner &space_outliner)
+{
+ const AbstractTreeDisplay &tree_display = *space_outliner.runtime->tree_display;
+
+ return tree_display.supportsModeColumn() && (space_outliner.flag & SO_MODE_COLUMN);
+}
+
+/**
+ * Iterate over the entire tree (including collapsed sub-elements), probing if any of the elements
+ * has a warning to be displayed.
+ */
+bool outliner_has_element_warnings(const SpaceOutliner &space_outliner)
+{
+ std::function<bool(const ListBase &)> recursive_fn;
+
+ recursive_fn = [&](const ListBase &lb) {
+ LISTBASE_FOREACH (const TreeElement *, te, &lb) {
+ if (te->abstract_element && !te->abstract_element->getWarning().is_empty()) {
+ return true;
+ }
+
+ if (recursive_fn(te->subtree)) {
+ return true;
+ }
+ }
+
+ return false;
+ };
+
+ return recursive_fn(space_outliner.tree);
+}
diff --git a/source/blender/editors/space_outliner/outliner_select.cc b/source/blender/editors/space_outliner/outliner_select.cc
index fd0ee422df0..877e0fc325c 100644
--- a/source/blender/editors/space_outliner/outliner_select.cc
+++ b/source/blender/editors/space_outliner/outliner_select.cc
@@ -66,7 +66,9 @@
#include "RNA_prototypes.h"
#include "outliner_intern.hh"
+#include "tree/tree_display.hh"
#include "tree/tree_element_seq.hh"
+#include "tree/tree_iterator.hh"
using namespace blender::ed::outliner;
@@ -1456,7 +1458,7 @@ void outliner_item_select(bContext *C,
/* Clear previous active when activating and clear selection when not extending selection */
const short clear_flag = (activate ? TSE_ACTIVE : 0) | (extend ? 0 : TSE_SELECTED);
if (clear_flag) {
- outliner_flag_set(&space_outliner->tree, clear_flag, false);
+ outliner_flag_set(*space_outliner, clear_flag, false);
}
if (select_flag & OL_ITEM_SELECT) {
@@ -1530,7 +1532,7 @@ static void do_outliner_range_select(bContext *C,
const bool active_selected = (tselem->flag & TSE_SELECTED);
if (!extend) {
- outliner_flag_set(&space_outliner->tree, TSE_SELECTED, false);
+ outliner_flag_set(*space_outliner, TSE_SELECTED, false);
}
/* Select active if under cursor */
@@ -1557,12 +1559,11 @@ static bool outliner_is_co_within_restrict_columns(const SpaceOutliner *space_ou
bool outliner_is_co_within_mode_column(SpaceOutliner *space_outliner, const float view_mval[2])
{
- /* Mode toggles only show in View Layer and Scenes modes. */
- if (!ELEM(space_outliner->outlinevis, SO_VIEW_LAYER, SO_SCENES)) {
+ if (!outliner_shows_mode_column(*space_outliner)) {
return false;
}
- return space_outliner->flag & SO_MODE_COLUMN && view_mval[0] < UI_UNIT_X;
+ return view_mval[0] < UI_UNIT_X;
}
static bool outliner_is_co_within_active_mode_column(bContext *C,
@@ -1604,7 +1605,7 @@ static int outliner_item_do_activate_from_cursor(bContext *C,
if (!(te = outliner_find_item_at_y(space_outliner, &space_outliner->tree, view_mval[1]))) {
if (deselect_all) {
- changed |= outliner_flag_set(&space_outliner->tree, TSE_SELECTED, false);
+ changed |= outliner_flag_set(*space_outliner, TSE_SELECTED, false);
}
}
/* Don't allow toggle on scene collection */
@@ -1692,7 +1693,7 @@ void OUTLINER_OT_item_activate(wmOperatorType *ot)
ot->poll = ED_operator_outliner_active;
- ot->flag |= OPTYPE_REGISTER | OPTYPE_UNDO;
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
PropertyRNA *prop;
prop = RNA_def_boolean(ot->srna, "extend", false, "Extend", "Extend selection for activation");
@@ -1715,26 +1716,17 @@ void OUTLINER_OT_item_activate(wmOperatorType *ot)
/** \name Box Select Operator
* \{ */
-static void outliner_item_box_select(bContext *C,
- SpaceOutliner *space_outliner,
- Scene *scene,
- rctf *rectf,
- TreeElement *te,
- bool select)
+static void outliner_box_select(bContext *C,
+ SpaceOutliner *space_outliner,
+ const rctf *rectf,
+ const bool select)
{
- TreeStoreElem *tselem = TREESTORE(te);
-
- if (te->ys <= rectf->ymax && te->ys + UI_UNIT_Y >= rectf->ymin) {
- outliner_item_select(
- C, space_outliner, te, (select ? OL_ITEM_SELECT : OL_ITEM_DESELECT) | OL_ITEM_EXTEND);
- }
-
- /* Look at its children. */
- if (TSELEM_OPEN(tselem, space_outliner)) {
- LISTBASE_FOREACH (TreeElement *, te_sub, &te->subtree) {
- outliner_item_box_select(C, space_outliner, scene, rectf, te_sub, select);
+ tree_iterator::all_open(*space_outliner, [&](TreeElement *te) {
+ if (te->ys <= rectf->ymax && te->ys + UI_UNIT_Y >= rectf->ymin) {
+ outliner_item_select(
+ C, space_outliner, te, (select ? OL_ITEM_SELECT : OL_ITEM_DESELECT) | OL_ITEM_EXTEND);
}
- }
+ });
}
static int outliner_box_select_exec(bContext *C, wmOperator *op)
@@ -1747,15 +1739,13 @@ static int outliner_box_select_exec(bContext *C, wmOperator *op)
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);
+ outliner_flag_set(*space_outliner, TSE_SELECTED, 0);
}
WM_operator_properties_border_to_rctf(op, &rectf);
UI_view2d_region_to_view_rctf(&region->v2d, &rectf, &rectf);
- LISTBASE_FOREACH (TreeElement *, te, &space_outliner->tree) {
- outliner_item_box_select(C, space_outliner, scene, &rectf, te, select);
- }
+ outliner_box_select(C, space_outliner, &rectf, select);
DEG_id_tag_update(&scene->id, ID_RECALC_SELECT);
WM_event_add_notifier(C, NC_SCENE | ND_OB_SELECT, scene);
@@ -2038,7 +2028,7 @@ void OUTLINER_OT_select_walk(wmOperatorType *ot)
ot->invoke = outliner_walk_select_invoke;
ot->poll = ED_operator_outliner_active;
- ot->flag |= OPTYPE_REGISTER | OPTYPE_UNDO;
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
/* properties */
PropertyRNA *prop;
diff --git a/source/blender/editors/space_outliner/outliner_tools.cc b/source/blender/editors/space_outliner/outliner_tools.cc
index 5da64177e51..ec19e8d5e5b 100644
--- a/source/blender/editors/space_outliner/outliner_tools.cc
+++ b/source/blender/editors/space_outliner/outliner_tools.cc
@@ -84,6 +84,7 @@
#include "outliner_intern.hh"
#include "tree/tree_element_rna.hh"
#include "tree/tree_element_seq.hh"
+#include "tree/tree_iterator.hh"
static CLG_LogRef LOG = {"ed.outliner.tools"};
@@ -221,53 +222,81 @@ static void unlink_action_fn(bContext *C,
}
static void unlink_material_fn(bContext *UNUSED(C),
- ReportList *UNUSED(reports),
+ ReportList *reports,
Scene *UNUSED(scene),
TreeElement *te,
TreeStoreElem *tsep,
- TreeStoreElem *UNUSED(tselem),
+ TreeStoreElem *tselem,
void *UNUSED(user_data))
{
+ const bool te_is_material = TSE_IS_REAL_ID(tselem) && (GS(tselem->id->name) == ID_MA);
+
+ if (!te_is_material) {
+ /* Just fail silently. Another element may be selected that is a material, we don't want to
+ * confuse users with an error in that case. */
+ return;
+ }
+
+ if (!tsep || !TSE_IS_REAL_ID(tsep)) {
+ /* Valid case, no parent element of the material or it is not an ID (could be a #TSE_ID_BASE
+ * for example) so there's no data to unlink from. */
+ BKE_reportf(reports,
+ RPT_WARNING,
+ "Cannot unlink material '%s'. It's not clear which object or object-data it "
+ "should be unlinked from, there's no object or object-data as parent in the "
+ "Outliner tree",
+ tselem->id->name + 2);
+ return;
+ }
+
Material **matar = nullptr;
int a, totcol = 0;
- if (GS(tsep->id->name) == ID_OB) {
- Object *ob = (Object *)tsep->id;
- totcol = ob->totcol;
- matar = ob->mat;
- }
- else if (GS(tsep->id->name) == ID_ME) {
- Mesh *me = (Mesh *)tsep->id;
- totcol = me->totcol;
- matar = me->mat;
- }
- else if (GS(tsep->id->name) == ID_CU_LEGACY) {
- Curve *cu = (Curve *)tsep->id;
- totcol = cu->totcol;
- matar = cu->mat;
- }
- else if (GS(tsep->id->name) == ID_MB) {
- MetaBall *mb = (MetaBall *)tsep->id;
- totcol = mb->totcol;
- matar = mb->mat;
- }
- else if (GS(tsep->id->name) == ID_CV) {
- Curves *curves = (Curves *)tsep->id;
- totcol = curves->totcol;
- matar = curves->mat;
- }
- else if (GS(tsep->id->name) == ID_PT) {
- PointCloud *pointcloud = (PointCloud *)tsep->id;
- totcol = pointcloud->totcol;
- matar = pointcloud->mat;
- }
- else if (GS(tsep->id->name) == ID_VO) {
- Volume *volume = (Volume *)tsep->id;
- totcol = volume->totcol;
- matar = volume->mat;
- }
- else {
- BLI_assert(0);
+ switch (GS(tsep->id->name)) {
+ case ID_OB: {
+ Object *ob = (Object *)tsep->id;
+ totcol = ob->totcol;
+ matar = ob->mat;
+ break;
+ }
+ case ID_ME: {
+ Mesh *me = (Mesh *)tsep->id;
+ totcol = me->totcol;
+ matar = me->mat;
+ break;
+ }
+ case ID_CU_LEGACY: {
+ Curve *cu = (Curve *)tsep->id;
+ totcol = cu->totcol;
+ matar = cu->mat;
+ break;
+ }
+ case ID_MB: {
+ MetaBall *mb = (MetaBall *)tsep->id;
+ totcol = mb->totcol;
+ matar = mb->mat;
+ break;
+ }
+ case ID_CV: {
+ Curves *curves = (Curves *)tsep->id;
+ totcol = curves->totcol;
+ matar = curves->mat;
+ break;
+ }
+ case ID_PT: {
+ PointCloud *pointcloud = (PointCloud *)tsep->id;
+ totcol = pointcloud->totcol;
+ matar = pointcloud->mat;
+ break;
+ }
+ case ID_VO: {
+ Volume *volume = (Volume *)tsep->id;
+ totcol = volume->totcol;
+ matar = volume->mat;
+ break;
+ }
+ default:
+ BLI_assert_unreachable();
}
if (LIKELY(matar != nullptr)) {
@@ -404,11 +433,10 @@ static void outliner_do_libdata_operation(bContext *C,
ReportList *reports,
Scene *scene,
SpaceOutliner *space_outliner,
- ListBase *lb,
outliner_operation_fn operation_fn,
void *user_data)
{
- LISTBASE_FOREACH (TreeElement *, te, lb) {
+ tree_iterator::all_open(*space_outliner, [&](TreeElement *te) {
TreeStoreElem *tselem = TREESTORE(te);
if (tselem->flag & TSE_SELECTED) {
if (((tselem->type == TSE_SOME_ID) && (te->idcode != 0)) ||
@@ -417,11 +445,7 @@ static void outliner_do_libdata_operation(bContext *C,
operation_fn(C, reports, scene, te, tsep, tselem, user_data);
}
}
- if (TSELEM_OPEN(tselem, space_outliner)) {
- outliner_do_libdata_operation(
- C, reports, scene, space_outliner, &te->subtree, operation_fn, user_data);
- }
- }
+ });
}
/** \} */
@@ -492,7 +516,7 @@ static int outliner_scene_operation_exec(bContext *C, wmOperator *op)
ED_undo_push(C, "Delete Scene(s)");
}
else {
- BLI_assert(0);
+ BLI_assert_unreachable();
return OPERATOR_CANCELLED;
}
@@ -755,6 +779,10 @@ static void id_local_fn(bContext *C,
struct OutlinerLibOverrideData {
bool do_hierarchy;
+
+ /** When creating new overrides, make them all user-editable. */
+ bool do_fully_editable;
+
/**
* 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
@@ -949,7 +977,8 @@ static void id_override_library_create_fn(bContext *C,
id_root_reference,
id_hierarchy_root_reference,
id_instance_hint,
- &id_root_override);
+ &id_root_override,
+ data->do_fully_editable);
BLI_assert(id_root_override != nullptr);
BLI_assert(!ID_IS_LINKED(id_root_override));
@@ -1589,21 +1618,17 @@ static void outliner_do_data_operation(
SpaceOutliner *space_outliner,
int type,
int event,
- ListBase *lb,
void (*operation_fn)(int, TreeElement *, TreeStoreElem *, void *),
void *arg)
{
- LISTBASE_FOREACH (TreeElement *, te, lb) {
+ tree_iterator::all_open(*space_outliner, [&](TreeElement *te) {
TreeStoreElem *tselem = TREESTORE(te);
if (tselem->flag & TSE_SELECTED) {
if (tselem->type == type) {
operation_fn(event, te, tselem, arg);
}
}
- if (TSELEM_OPEN(tselem, space_outliner)) {
- outliner_do_data_operation(space_outliner, type, event, &te->subtree, operation_fn, arg);
- }
- }
+ });
}
static Base *outliner_batch_delete_hierarchy(
@@ -1726,53 +1751,59 @@ static int outliner_object_operation_exec(bContext *C, wmOperator *op)
event = RNA_enum_get(op->ptr, "type");
- if (event == OL_OP_SELECT) {
- Scene *sce = scene; /* To be able to delete, scenes are set... */
- outliner_do_object_operation(
- C, op->reports, scene, space_outliner, &space_outliner->tree, object_select_fn);
- if (scene != sce) {
- WM_window_set_active_scene(bmain, C, win, sce);
- }
+ switch (event) {
+ case OL_OP_SELECT: {
+ Scene *sce = scene; /* To be able to delete, scenes are set... */
+ outliner_do_object_operation(
+ C, op->reports, scene, space_outliner, &space_outliner->tree, object_select_fn);
+ /* FIXME: This is most certainly broken, maybe check should rather be
+ * `if (CTX_data_scene(C) != scene)` ? */
+ if (scene != sce) {
+ WM_window_set_active_scene(bmain, C, win, sce);
+ }
- str = "Select Objects";
- selection_changed = true;
- }
- else if (event == OL_OP_SELECT_HIERARCHY) {
- Scene *sce = scene; /* To be able to delete, scenes are set... */
- outliner_do_object_operation_ex(C,
- op->reports,
- scene,
- space_outliner,
- &space_outliner->tree,
- object_select_hierarchy_fn,
- nullptr,
- false);
- if (scene != sce) {
- WM_window_set_active_scene(bmain, C, win, sce);
- }
- str = "Select Object Hierarchy";
- selection_changed = true;
- }
- else if (event == OL_OP_DESELECT) {
- outliner_do_object_operation(
- C, op->reports, scene, space_outliner, &space_outliner->tree, object_deselect_fn);
- str = "Deselect Objects";
- selection_changed = true;
- }
- else if (event == OL_OP_REMAP) {
- outliner_do_libdata_operation(
- 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). */
- }
- else if (event == OL_OP_RENAME) {
- outliner_do_object_operation(
- C, op->reports, scene, space_outliner, &space_outliner->tree, item_rename_fn);
- str = "Rename Object";
- }
- else {
- BLI_assert(0);
- return OPERATOR_CANCELLED;
+ str = "Select Objects";
+ selection_changed = true;
+ break;
+ }
+ case OL_OP_SELECT_HIERARCHY: {
+ Scene *sce = scene; /* To be able to delete, scenes are set... */
+ outliner_do_object_operation_ex(C,
+ op->reports,
+ scene,
+ space_outliner,
+ &space_outliner->tree,
+ object_select_hierarchy_fn,
+ nullptr,
+ false);
+ /* FIXME: This is most certainly broken, maybe check should rather be
+ * `if (CTX_data_scene(C) != scene)` ? */
+ if (scene != sce) {
+ WM_window_set_active_scene(bmain, C, win, sce);
+ }
+ str = "Select Object Hierarchy";
+ selection_changed = true;
+ break;
+ }
+ case OL_OP_DESELECT:
+ outliner_do_object_operation(
+ C, op->reports, scene, space_outliner, &space_outliner->tree, object_deselect_fn);
+ str = "Deselect Objects";
+ selection_changed = true;
+ break;
+ case OL_OP_REMAP:
+ outliner_do_libdata_operation(C, op->reports, scene, space_outliner, 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). */
+ break;
+ case OL_OP_RENAME:
+ outliner_do_object_operation(
+ C, op->reports, scene, space_outliner, &space_outliner->tree, item_rename_fn);
+ str = "Rename Object";
+ break;
+ default:
+ BLI_assert_unreachable();
+ return OPERATOR_CANCELLED;
}
if (selection_changed) {
@@ -1943,7 +1974,7 @@ void OUTLINER_OT_delete(wmOperatorType *ot)
ot->poll = ED_operator_outliner_active;
/* flags */
- ot->flag |= OPTYPE_REGISTER | OPTYPE_UNDO;
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
/* properties */
PropertyRNA *prop = RNA_def_boolean(
@@ -1964,6 +1995,7 @@ enum eOutlinerIdOpTypes {
OUTLINER_IDOP_LOCAL,
OUTLINER_IDOP_OVERRIDE_LIBRARY_CREATE,
OUTLINER_IDOP_OVERRIDE_LIBRARY_CREATE_HIERARCHY,
+ OUTLINER_IDOP_OVERRIDE_LIBRARY_CREATE_HIERARCHY_FULLY_EDITABLE,
OUTLINER_IDOP_OVERRIDE_LIBRARY_MAKE_EDITABLE,
OUTLINER_IDOP_OVERRIDE_LIBRARY_RESET,
OUTLINER_IDOP_OVERRIDE_LIBRARY_RESET_HIERARCHY,
@@ -1996,7 +2028,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, nullptr, nullptr},
+ RNA_ENUM_ITEM_SEPR,
{OUTLINER_IDOP_OVERRIDE_LIBRARY_CREATE,
"OVERRIDE_LIBRARY_CREATE",
0,
@@ -2009,6 +2041,12 @@ static const EnumPropertyItem prop_id_op_types[] = {
"Make Library Override Hierarchy",
"Make a local override of this linked data-block, and its hierarchy of dependencies - only "
"applies to active Outliner item"},
+ {OUTLINER_IDOP_OVERRIDE_LIBRARY_CREATE_HIERARCHY_FULLY_EDITABLE,
+ "OVERRIDE_LIBRARY_CREATE_HIERARCHY_FULLY_EDITABLE",
+ 0,
+ "Make Library Override Hierarchy Fully Editable",
+ "Make a local override of this linked data-block, and its hierarchy of dependencies, making "
+ "them all fully user-editable - only applies to active Outliner item"},
{OUTLINER_IDOP_OVERRIDE_LIBRARY_MAKE_EDITABLE,
"OVERRIDE_LIBRARY_MAKE_EDITABLE",
0,
@@ -2049,10 +2087,10 @@ static const EnumPropertyItem prop_id_op_types[] = {
"Clear Library Override Hierarchy",
"Delete this local override (including its hierarchy of override dependencies) and relink "
"its usages to the linked data-blocks"},
- {0, "", 0, nullptr, nullptr},
+ RNA_ENUM_ITEM_SEPR,
{OUTLINER_IDOP_COPY, "COPY", ICON_COPYDOWN, "Copy", ""},
{OUTLINER_IDOP_PASTE, "PASTE", ICON_PASTEDOWN, "Paste", ""},
- {0, "", 0, nullptr, nullptr},
+ RNA_ENUM_ITEM_SEPR,
{OUTLINER_IDOP_FAKE_ADD,
"ADD_FAKE",
0,
@@ -2088,6 +2126,7 @@ static bool outliner_id_operation_item_poll(bContext *C,
}
return false;
case OUTLINER_IDOP_OVERRIDE_LIBRARY_CREATE_HIERARCHY:
+ case OUTLINER_IDOP_OVERRIDE_LIBRARY_CREATE_HIERARCHY_FULLY_EDITABLE:
if (ID_IS_OVERRIDABLE_LIBRARY(tselem->id) || (ID_IS_LINKED(tselem->id))) {
return true;
}
@@ -2164,13 +2203,8 @@ static int outliner_id_operation_exec(bContext *C, wmOperator *op)
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,
- nullptr);
+ outliner_do_libdata_operation(
+ C, op->reports, scene, space_outliner, unlink_object_fn, nullptr);
WM_event_add_notifier(C, NC_SCENE | ND_LAYER, nullptr);
ED_undo_push(C, "Unlink Object");
@@ -2179,61 +2213,36 @@ static int outliner_id_operation_exec(bContext *C, wmOperator *op)
switch (idlevel) {
case ID_AC:
- outliner_do_libdata_operation(C,
- op->reports,
- scene,
- space_outliner,
- &space_outliner->tree,
- unlink_action_fn,
- nullptr);
+ outliner_do_libdata_operation(
+ C, op->reports, scene, space_outliner, unlink_action_fn, nullptr);
WM_event_add_notifier(C, NC_ANIMATION | ND_NLA_ACTCHANGE, nullptr);
ED_undo_push(C, "Unlink action");
break;
case ID_MA:
- outliner_do_libdata_operation(C,
- op->reports,
- scene,
- space_outliner,
- &space_outliner->tree,
- unlink_material_fn,
- nullptr);
+ outliner_do_libdata_operation(
+ C, op->reports, scene, space_outliner, unlink_material_fn, nullptr);
WM_event_add_notifier(C, NC_OBJECT | ND_OB_SHADING, nullptr);
ED_undo_push(C, "Unlink material");
break;
case ID_TE:
- outliner_do_libdata_operation(C,
- op->reports,
- scene,
- space_outliner,
- &space_outliner->tree,
- unlink_texture_fn,
- nullptr);
+ outliner_do_libdata_operation(
+ C, op->reports, scene, space_outliner, unlink_texture_fn, nullptr);
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,
- nullptr);
+ outliner_do_libdata_operation(
+ C, op->reports, scene, space_outliner, unlink_world_fn, nullptr);
WM_event_add_notifier(C, NC_SCENE | ND_WORLD, nullptr);
ED_undo_push(C, "Unlink world");
break;
case ID_GR:
- outliner_do_libdata_operation(C,
- op->reports,
- scene,
- space_outliner,
- &space_outliner->tree,
- unlink_collection_fn,
- nullptr);
+ outliner_do_libdata_operation(
+ C, op->reports, scene, space_outliner, unlink_collection_fn, nullptr);
WM_event_add_notifier(C, NC_SCENE | ND_LAYER, nullptr);
ED_undo_push(C, "Unlink Collection");
@@ -2246,20 +2255,14 @@ 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, nullptr);
+ outliner_do_libdata_operation(C, op->reports, scene, space_outliner, 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,
- &override_data);
+ outliner_do_libdata_operation(
+ C, op->reports, scene, space_outliner, id_override_library_create_fn, &override_data);
ED_undo_push(C, "Overridden Data");
break;
}
@@ -2270,19 +2273,30 @@ static int outliner_id_operation_exec(bContext *C, wmOperator *op)
op->reports,
scene,
space_outliner,
- &space_outliner->tree,
id_override_library_create_hierarchy_pre_process_fn,
&override_data);
+ outliner_do_libdata_operation(
+ C, op->reports, scene, space_outliner, id_override_library_create_fn, &override_data);
+ id_override_library_create_hierarchy_post_process(C, &override_data);
+
+ ED_undo_push(C, "Overridden Data Hierarchy");
+ break;
+ }
+ case OUTLINER_IDOP_OVERRIDE_LIBRARY_CREATE_HIERARCHY_FULLY_EDITABLE: {
+ OutlinerLibOverrideData override_data{};
+ override_data.do_hierarchy = true;
+ override_data.do_fully_editable = true;
outliner_do_libdata_operation(C,
op->reports,
scene,
space_outliner,
- &space_outliner->tree,
- id_override_library_create_fn,
+ id_override_library_create_hierarchy_pre_process_fn,
&override_data);
+ outliner_do_libdata_operation(
+ C, op->reports, scene, space_outliner, id_override_library_create_fn, &override_data);
id_override_library_create_hierarchy_post_process(C, &override_data);
- ED_undo_push(C, "Overridden Data Hierarchy");
+ ED_undo_push(C, "Overridden Data Hierarchy Fully Editable");
break;
}
case OUTLINER_IDOP_OVERRIDE_LIBRARY_MAKE_EDITABLE: {
@@ -2290,7 +2304,6 @@ static int outliner_id_operation_exec(bContext *C, wmOperator *op)
op->reports,
scene,
space_outliner,
- &space_outliner->tree,
id_override_library_toggle_flag_fn,
POINTER_FROM_UINT(IDOVERRIDE_LIBRARY_FLAG_SYSTEM_DEFINED));
@@ -2299,39 +2312,24 @@ static int outliner_id_operation_exec(bContext *C, wmOperator *op)
}
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,
- &override_data);
+ outliner_do_libdata_operation(
+ C, op->reports, scene, space_outliner, id_override_library_reset_fn, &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,
- &override_data);
+ outliner_do_libdata_operation(
+ C, op->reports, scene, space_outliner, id_override_library_reset_fn, &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,
- &override_data);
+ outliner_do_libdata_operation(
+ C, op->reports, scene, space_outliner, id_override_library_resync_fn, &override_data);
ED_undo_push(C, "Resync Overridden Data Hierarchy");
break;
}
@@ -2339,35 +2337,20 @@ static int outliner_id_operation_exec(bContext *C, wmOperator *op)
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);
+ outliner_do_libdata_operation(
+ C, op->reports, scene, space_outliner, id_override_library_resync_fn, &override_data);
ED_undo_push(C, "Resync Overridden Data Hierarchy");
break;
}
case OUTLINER_IDOP_OVERRIDE_LIBRARY_CLEAR_HIERARCHY: {
- outliner_do_libdata_operation(C,
- op->reports,
- scene,
- space_outliner,
- &space_outliner->tree,
- id_override_library_clear_hierarchy_fn,
- nullptr);
+ outliner_do_libdata_operation(
+ C, op->reports, scene, space_outliner, id_override_library_clear_hierarchy_fn, nullptr);
ED_undo_push(C, "Clear Overridden Data Hierarchy");
break;
}
case OUTLINER_IDOP_OVERRIDE_LIBRARY_CLEAR_SINGLE: {
- outliner_do_libdata_operation(C,
- op->reports,
- scene,
- space_outliner,
- &space_outliner->tree,
- id_override_library_clear_single_fn,
- nullptr);
+ outliner_do_libdata_operation(
+ C, op->reports, scene, space_outliner, id_override_library_clear_single_fn, nullptr);
ED_undo_push(C, "Clear Overridden Data Hierarchy");
break;
}
@@ -2375,26 +2358,16 @@ static int outliner_id_operation_exec(bContext *C, wmOperator *op)
/* make single user */
switch (idlevel) {
case ID_AC:
- outliner_do_libdata_operation(C,
- op->reports,
- scene,
- space_outliner,
- &space_outliner->tree,
- singleuser_action_fn,
- nullptr);
+ outliner_do_libdata_operation(
+ C, op->reports, scene, space_outliner, singleuser_action_fn, nullptr);
WM_event_add_notifier(C, NC_ANIMATION | ND_NLA_ACTCHANGE, nullptr);
ED_undo_push(C, "Single-User Action");
break;
case ID_WO:
- outliner_do_libdata_operation(C,
- op->reports,
- scene,
- space_outliner,
- &space_outliner->tree,
- singleuser_world_fn,
- nullptr);
+ outliner_do_libdata_operation(
+ C, op->reports, scene, space_outliner, singleuser_world_fn, nullptr);
WM_event_add_notifier(C, NC_SCENE | ND_WORLD, nullptr);
ED_undo_push(C, "Single-User World");
@@ -2409,15 +2382,14 @@ 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, nullptr);
+ C, op->reports, scene, space_outliner, id_delete_fn, nullptr);
ED_undo_push(C, "Delete");
}
break;
}
case OUTLINER_IDOP_REMAP: {
if (idlevel > 0) {
- outliner_do_libdata_operation(
- C, op->reports, scene, space_outliner, &space_outliner->tree, id_remap_fn, nullptr);
+ outliner_do_libdata_operation(C, op->reports, scene, space_outliner, 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). */
}
@@ -2440,13 +2412,8 @@ 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,
- nullptr);
+ outliner_do_libdata_operation(
+ C, op->reports, scene, space_outliner, id_fake_user_set_fn, nullptr);
WM_event_add_notifier(C, NC_ID | NA_EDITED, nullptr);
ED_undo_push(C, "Add Fake User");
@@ -2454,13 +2421,8 @@ static int outliner_id_operation_exec(bContext *C, wmOperator *op)
}
case OUTLINER_IDOP_FAKE_CLEAR: {
/* clear fake user */
- outliner_do_libdata_operation(C,
- op->reports,
- scene,
- space_outliner,
- &space_outliner->tree,
- id_fake_user_clear_fn,
- nullptr);
+ outliner_do_libdata_operation(
+ C, op->reports, scene, space_outliner, id_fake_user_clear_fn, nullptr);
WM_event_add_notifier(C, NC_ID | NA_EDITED, nullptr);
ED_undo_push(C, "Clear Fake User");
@@ -2469,20 +2431,15 @@ static int outliner_id_operation_exec(bContext *C, wmOperator *op)
case OUTLINER_IDOP_RENAME: {
/* rename */
outliner_do_libdata_operation(
- C, op->reports, scene, space_outliner, &space_outliner->tree, item_rename_fn, nullptr);
+ C, op->reports, scene, space_outliner, item_rename_fn, nullptr);
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,
- nullptr);
+ outliner_do_libdata_operation(
+ C, op->reports, scene, space_outliner, id_select_linked_fn, nullptr);
ED_outliner_select_sync_from_all_tag(C);
ED_undo_push(C, "Select");
break;
@@ -2527,14 +2484,12 @@ void OUTLINER_OT_id_operation(wmOperatorType *ot)
enum eOutlinerLibOpTypes {
OL_LIB_INVALID = 0,
- OL_LIB_RENAME,
OL_LIB_DELETE,
OL_LIB_RELOCATE,
OL_LIB_RELOAD,
};
static const EnumPropertyItem outliner_lib_op_type_items[] = {
- {OL_LIB_RENAME, "RENAME", 0, "Rename", ""},
{OL_LIB_DELETE,
"DELETE",
ICON_X,
@@ -2566,30 +2521,20 @@ static int outliner_lib_operation_exec(bContext *C, wmOperator *op)
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, nullptr);
-
- 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, nullptr);
+ outliner_do_libdata_operation(C, op->reports, scene, space_outliner, 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, nullptr);
+ C, op->reports, scene, space_outliner, 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, nullptr);
+ outliner_do_libdata_operation(C, op->reports, scene, space_outliner, 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;
@@ -2632,11 +2577,10 @@ void OUTLINER_OT_lib_operation(wmOperatorType *ot)
static void outliner_do_id_set_operation(
SpaceOutliner *space_outliner,
int type,
- ListBase *lb,
ID *newid,
void (*operation_fn)(TreeElement *, TreeStoreElem *, TreeStoreElem *, ID *))
{
- LISTBASE_FOREACH (TreeElement *, te, lb) {
+ tree_iterator::all_open(*space_outliner, [&](TreeElement *te) {
TreeStoreElem *tselem = TREESTORE(te);
if (tselem->flag & TSE_SELECTED) {
if (tselem->type == type) {
@@ -2644,10 +2588,7 @@ static void outliner_do_id_set_operation(
operation_fn(te, tselem, tsep, newid);
}
}
- if (TSELEM_OPEN(tselem, space_outliner)) {
- outliner_do_id_set_operation(space_outliner, type, &te->subtree, newid, operation_fn);
- }
- }
+ });
}
static void actionset_id_fn(TreeElement *UNUSED(te),
@@ -2702,12 +2643,10 @@ static int outliner_action_set_exec(bContext *C, wmOperator *op)
/* perform action if valid channel */
if (datalevel == TSE_ANIM_DATA) {
- outliner_do_id_set_operation(
- space_outliner, datalevel, &space_outliner->tree, (ID *)act, actionset_id_fn);
+ outliner_do_id_set_operation(space_outliner, datalevel, (ID *)act, actionset_id_fn);
}
else if (idlevel == ID_AC) {
- outliner_do_id_set_operation(
- space_outliner, idlevel, &space_outliner->tree, (ID *)act, actionset_id_fn);
+ outliner_do_id_set_operation(space_outliner, idlevel, (ID *)act, actionset_id_fn);
}
else {
return OPERATOR_CANCELLED;
@@ -2794,8 +2733,7 @@ static int outliner_animdata_operation_exec(bContext *C, wmOperator *op)
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, nullptr);
+ outliner_do_data_operation(space_outliner, datalevel, event, clear_animdata_fn, nullptr);
WM_event_add_notifier(C, NC_ANIMATION | ND_NLA_ACTCHANGE, nullptr);
ED_undo_push(C, "Clear Animation Data");
@@ -2812,32 +2750,23 @@ 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, nullptr);
+ outliner_do_data_operation(space_outliner, datalevel, event, unlinkact_animdata_fn, nullptr);
WM_event_add_notifier(C, NC_ANIMATION | ND_NLA_ACTCHANGE, nullptr);
ED_undo_push(C, "Unlink action");
break;
case OUTLINER_ANIMOP_REFRESH_DRV:
- outliner_do_data_operation(space_outliner,
- datalevel,
- event,
- &space_outliner->tree,
- refreshdrivers_animdata_fn,
- nullptr);
+ outliner_do_data_operation(
+ space_outliner, datalevel, event, refreshdrivers_animdata_fn, nullptr);
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,
- nullptr);
+ outliner_do_data_operation(
+ space_outliner, datalevel, event, cleardrivers_animdata_fn, nullptr);
WM_event_add_notifier(C, NC_ANIMATION | ND_ANIMCHAN, nullptr);
ED_undo_push(C, "Clear Drivers");
@@ -2887,8 +2816,7 @@ static int outliner_constraint_operation_exec(bContext *C, wmOperator *op)
SpaceOutliner *space_outliner = CTX_wm_space_outliner(C);
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);
+ outliner_do_data_operation(space_outliner, TSE_CONSTRAINT, event, constraint_fn, C);
if (event == OL_CONSTRAINTOP_DELETE) {
outliner_cleanup_tree(space_outliner);
@@ -2934,8 +2862,7 @@ static int outliner_modifier_operation_exec(bContext *C, wmOperator *op)
SpaceOutliner *space_outliner = CTX_wm_space_outliner(C);
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);
+ outliner_do_data_operation(space_outliner, TSE_MODIFIER, event, modifier_fn, C);
if (event == OL_MODIFIER_OP_DELETE) {
outliner_cleanup_tree(space_outliner);
@@ -2978,24 +2905,21 @@ static int outliner_data_operation_exec(bContext *C, wmOperator *op)
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, nullptr);
+ outliner_do_data_operation(space_outliner, datalevel, event, 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, nullptr);
+ outliner_do_data_operation(space_outliner, datalevel, event, 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, nullptr);
+ outliner_do_data_operation(space_outliner, datalevel, event, ebone_fn, nullptr);
WM_event_add_notifier(C, NC_OBJECT | ND_POSE, nullptr);
ED_undo_push(C, "EditBone operation");
@@ -3003,16 +2927,14 @@ static int outliner_data_operation_exec(bContext *C, wmOperator *op)
}
case TSE_SEQUENCE: {
Scene *scene = CTX_data_scene(C);
- outliner_do_data_operation(
- space_outliner, datalevel, event, &space_outliner->tree, sequence_fn, scene);
+ outliner_do_data_operation(space_outliner, datalevel, event, sequence_fn, scene);
WM_event_add_notifier(C, NC_SCENE | ND_SEQUENCER | NA_SELECTED, scene);
ED_undo_push(C, "Sequencer operation");
break;
}
case TSE_GP_LAYER: {
- outliner_do_data_operation(
- space_outliner, datalevel, event, &space_outliner->tree, gpencil_layer_fn, nullptr);
+ outliner_do_data_operation(space_outliner, datalevel, event, gpencil_layer_fn, nullptr);
WM_event_add_notifier(C, NC_GPENCIL | ND_DATA, nullptr);
ED_undo_push(C, "Grease Pencil Layer operation");
@@ -3020,8 +2942,7 @@ static int outliner_data_operation_exec(bContext *C, wmOperator *op)
}
case TSE_RNA_STRUCT:
if (event == OL_DOP_SELECT_LINKED) {
- outliner_do_data_operation(
- space_outliner, datalevel, event, &space_outliner->tree, data_select_linked_fn, C);
+ outliner_do_data_operation(space_outliner, datalevel, event, data_select_linked_fn, C);
}
break;
diff --git a/source/blender/editors/space_outliner/outliner_tree.cc b/source/blender/editors/space_outliner/outliner_tree.cc
index bbd9b48c260..aa739758ecb 100644
--- a/source/blender/editors/space_outliner/outliner_tree.cc
+++ b/source/blender/editors/space_outliner/outliner_tree.cc
@@ -802,7 +802,8 @@ TreeElement *outliner_add_element(SpaceOutliner *space_outliner,
void *idv,
TreeElement *parent,
short type,
- short index)
+ short index,
+ const bool expand)
{
ID *id = reinterpret_cast<ID *>(idv);
@@ -894,10 +895,10 @@ TreeElement *outliner_add_element(SpaceOutliner *space_outliner,
te->idcode = GS(id->name);
}
- if (te->abstract_element && te->abstract_element->isExpandValid()) {
+ if (expand && te->abstract_element && te->abstract_element->isExpandValid()) {
tree_element_expand(*te->abstract_element, *space_outliner);
}
- else if (type == TSE_SOME_ID) {
+ else if (expand && (type == TSE_SOME_ID)) {
/* ID types not (fully) ported to new design yet. */
if (te->abstract_element->expandPoll(*space_outliner)) {
outliner_add_id_contents(space_outliner, te, tselem, id);
@@ -919,10 +920,6 @@ TreeElement *outliner_add_element(SpaceOutliner *space_outliner,
BLI_assert_msg(false, "Element type should already use new AbstractTreeElement design");
}
- if (tree_element_warnings_get(te, nullptr, nullptr)) {
- te->flag |= TE_HAS_WARNING;
- }
-
return te;
}
@@ -1686,6 +1683,9 @@ void outliner_build_tree(Main *mainvar,
space_outliner->storeflag &= ~SO_TREESTORE_REBUILD;
if (region->do_draw & RGN_DRAW_NO_REBUILD) {
+ BLI_assert_msg(space_outliner->runtime->tree_display != nullptr,
+ "Skipping rebuild before tree was built properly, a full redraw should be "
+ "triggered instead");
return;
}
diff --git a/source/blender/editors/space_outliner/outliner_utils.cc b/source/blender/editors/space_outliner/outliner_utils.cc
index 4b947154864..0db612ce6db 100644
--- a/source/blender/editors/space_outliner/outliner_utils.cc
+++ b/source/blender/editors/space_outliner/outliner_utils.cc
@@ -27,6 +27,9 @@
#include "UI_view2d.h"
#include "outliner_intern.hh"
+#include "tree/tree_iterator.hh"
+
+using namespace blender::ed::outliner;
/* -------------------------------------------------------------------- */
/** \name Tree View Context
diff --git a/source/blender/editors/space_outliner/space_outliner.cc b/source/blender/editors/space_outliner/space_outliner.cc
index 97dc659155f..5bcd1edebc0 100644
--- a/source/blender/editors/space_outliner/space_outliner.cc
+++ b/source/blender/editors/space_outliner/space_outliner.cc
@@ -438,7 +438,7 @@ static void outliner_deactivate(struct ScrArea *area)
{
/* Remove hover highlights */
SpaceOutliner *space_outliner = reinterpret_cast<SpaceOutliner *>(area->spacedata.first);
- outliner_flag_set(&space_outliner->tree, TSE_HIGHLIGHTED_ANY, false);
+ outliner_flag_set(*space_outliner, TSE_HIGHLIGHTED_ANY, false);
ED_region_tag_redraw_no_rebuild(BKE_area_find_region_type(area, RGN_TYPE_WINDOW));
}
diff --git a/source/blender/editors/space_outliner/tree/tree_display.cc b/source/blender/editors/space_outliner/tree/tree_display.cc
index 141c68594e8..6ab497b3fbb 100644
--- a/source/blender/editors/space_outliner/tree/tree_display.cc
+++ b/source/blender/editors/space_outliner/tree/tree_display.cc
@@ -45,9 +45,9 @@ std::unique_ptr<AbstractTreeDisplay> AbstractTreeDisplay::createFromDisplayMode(
return nullptr;
}
-bool AbstractTreeDisplay::hasWarnings() const
+bool AbstractTreeDisplay::supportsModeColumn() const
{
- return has_warnings;
+ return false;
}
} // namespace blender::ed::outliner
diff --git a/source/blender/editors/space_outliner/tree/tree_display.hh b/source/blender/editors/space_outliner/tree/tree_display.hh
index 327f29aa15e..190e35c81d6 100644
--- a/source/blender/editors/space_outliner/tree/tree_display.hh
+++ b/source/blender/editors/space_outliner/tree/tree_display.hh
@@ -75,12 +75,16 @@ class AbstractTreeDisplay {
*/
virtual ListBase buildTree(const TreeSourceData &source_data) = 0;
- /** Accessor to whether given tree has some warnings to display. */
- bool hasWarnings() const;
+ /**
+ * Define if the display mode should be allowed to show a mode column on the left. This column
+ * adds an icon to indicate which objects are in the current mode (edit mode, pose mode, etc.)
+ * and allows adding other objects to the mode by clicking the icon.
+ *
+ * Returns false by default.
+ */
+ virtual bool supportsModeColumn() 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_;
};
@@ -100,6 +104,8 @@ class TreeDisplayViewLayer final : public AbstractTreeDisplay {
ListBase buildTree(const TreeSourceData &source_data) override;
+ bool supportsModeColumn() const override;
+
private:
void add_view_layer(Scene &, ListBase &, TreeElement *);
void add_layer_collections_recursive(ListBase &, ListBase &, TreeElement &);
@@ -212,6 +218,8 @@ class TreeDisplayScenes final : public AbstractTreeDisplay {
TreeDisplayScenes(SpaceOutliner &space_outliner);
ListBase buildTree(const TreeSourceData &source_data) override;
+
+ bool supportsModeColumn() const override;
};
/* -------------------------------------------------------------------- */
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 476bbdb63ae..405f1dd73f4 100644
--- a/source/blender/editors/space_outliner/tree/tree_display_libraries.cc
+++ b/source/blender/editors/space_outliner/tree/tree_display_libraries.cc
@@ -116,6 +116,11 @@ TreeElement *TreeDisplayLibraries::add_library_contents(Main &mainvar, ListBase
ID *id = static_cast<ID *>(lbarray[a]->first);
const bool is_library = (GS(id->name) == ID_LI) && (lib != nullptr);
+ /* Don't show deprecated types. */
+ if (ID_TYPE_IS_DEPRECATED(GS(id->name))) {
+ continue;
+ }
+
/* check if there's data in current lib */
for (ID *id_iter : List<ID>(lbarray[a])) {
if (id_iter->lib == lib) {
@@ -136,9 +141,6 @@ TreeElement *TreeDisplayLibraries::add_library_contents(Main &mainvar, ListBase
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_override_library_hierarchies.cc b/source/blender/editors/space_outliner/tree/tree_display_override_library_hierarchies.cc
index 38025b58fd2..67798e978ab 100644
--- a/source/blender/editors/space_outliner/tree/tree_display_override_library_hierarchies.cc
+++ b/source/blender/editors/space_outliner/tree/tree_display_override_library_hierarchies.cc
@@ -34,13 +34,6 @@ TreeDisplayOverrideLibraryHierarchies::TreeDisplayOverrideLibraryHierarchies(
{
}
-/* XXX Remove expanded subtree, we add our own items here. Expanding should probably be
- * optional. */
-static void remove_expanded_children(TreeElement &te)
-{
- outliner_free_tree(&te.subtree);
-}
-
ListBase TreeDisplayOverrideLibraryHierarchies::buildTree(const TreeSourceData &source_data)
{
ListBase tree = {nullptr};
@@ -114,8 +107,7 @@ ListBase TreeDisplayOverrideLibraryHierarchies::build_hierarchy_for_lib_or_main(
});
TreeElement *new_id_te = outliner_add_element(
- &space_outliner_, &new_base_te->subtree, iter_id, new_base_te, TSE_SOME_ID, 0);
- remove_expanded_children(*new_id_te);
+ &space_outliner_, &new_base_te->subtree, iter_id, new_base_te, TSE_SOME_ID, 0, false);
build_hierarchy_for_ID(bmain, *iter_id, *tree_element_cast<TreeElementID>(new_id_te));
}
@@ -193,8 +185,8 @@ static int build_hierarchy_foreach_ID_cb(LibraryIDLinkCallbackData *cb_data)
&id,
&build_data.parent_te->getLegacyElement(),
TSE_SOME_ID,
- 0);
- remove_expanded_children(*new_te);
+ 0,
+ false);
build_data.sibling_ids.add(&id);
BuildHierarchyForeachIDCbData child_build_data{build_data.bmain,
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 9e00a425a5a..6b1de7f8b95 100644
--- a/source/blender/editors/space_outliner/tree/tree_display_scenes.cc
+++ b/source/blender/editors/space_outliner/tree/tree_display_scenes.cc
@@ -26,6 +26,11 @@ TreeDisplayScenes::TreeDisplayScenes(SpaceOutliner &space_outliner)
{
}
+bool TreeDisplayScenes::supportsModeColumn() const
+{
+ return true;
+}
+
ListBase TreeDisplayScenes::buildTree(const TreeSourceData &source_data)
{
/* On first view we open scenes. */
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 19811e45b90..c8869d90eca 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
@@ -55,6 +55,11 @@ TreeDisplayViewLayer::TreeDisplayViewLayer(SpaceOutliner &space_outliner)
{
}
+bool TreeDisplayViewLayer::supportsModeColumn() const
+{
+ return true;
+}
+
ListBase TreeDisplayViewLayer::buildTree(const TreeSourceData &source_data)
{
ListBase tree = {nullptr};
@@ -266,14 +271,14 @@ void ObjectsChildrenBuilder::make_object_parent_hierarchy_collections()
if (!found) {
/* We add the child in the tree even if it is not in the collection.
- * We deliberately clear its sub-tree though, to make it less prominent. */
+ * We don't expand its sub-tree though, to make it less prominent. */
TreeElement *child_ob_tree_element = outliner_add_element(&outliner_,
&parent_ob_tree_element->subtree,
child,
parent_ob_tree_element,
TSE_SOME_ID,
- 0);
- outliner_free_tree(&child_ob_tree_element->subtree);
+ 0,
+ false);
child_ob_tree_element->flag |= TE_CHILD_NOT_IN_COLLECTION;
child_ob_tree_elements.append(child_ob_tree_element);
}
diff --git a/source/blender/editors/space_outliner/tree/tree_element.cc b/source/blender/editors/space_outliner/tree/tree_element.cc
index 1e3fd2df7c2..94d55b70e3c 100644
--- a/source/blender/editors/space_outliner/tree/tree_element.cc
+++ b/source/blender/editors/space_outliner/tree/tree_element.cc
@@ -100,6 +100,11 @@ std::unique_ptr<AbstractTreeElement> AbstractTreeElement::createFromType(const i
return nullptr;
}
+StringRefNull AbstractTreeElement::getWarning() const
+{
+ return "";
+}
+
void AbstractTreeElement::uncollapse_by_default(TreeElement *legacy_te)
{
if (!TREESTORE(legacy_te)->used) {
@@ -118,39 +123,4 @@ void tree_element_expand(const AbstractTreeElement &tree_element, SpaceOutliner
tree_element.expand(space_outliner);
}
-bool tree_element_warnings_get(TreeElement *te, int *r_icon, const char **r_message)
-{
- TreeStoreElem *tselem = te->store_elem;
-
- if (tselem->type != TSE_SOME_ID) {
- return false;
- }
- if (te->idcode != ID_LI) {
- return false;
- }
-
- 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;
-}
-
} // namespace blender::ed::outliner
diff --git a/source/blender/editors/space_outliner/tree/tree_element.hh b/source/blender/editors/space_outliner/tree/tree_element.hh
index c6593a517dd..1098068d628 100644
--- a/source/blender/editors/space_outliner/tree/tree_element.hh
+++ b/source/blender/editors/space_outliner/tree/tree_element.hh
@@ -8,6 +8,8 @@
#include <memory>
+#include "BLI_string_ref.hh"
+
struct ListBase;
struct SpaceOutliner;
struct TreeElement;
@@ -56,6 +58,12 @@ class AbstractTreeElement {
}
/**
+ * By letting this return a warning message, the tree element will display a warning icon with
+ * the message in the tooltip.
+ */
+ virtual StringRefNull getWarning() const;
+
+ /**
* Expand this tree element if it is displayed for the first time (as identified by its
* tree-store element).
*
@@ -86,23 +94,20 @@ class AbstractTreeElement {
* \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().
+ *
+ * \param expand: If true, the element may add its own sub-tree. E.g. objects will list their
+ * animation data, object data, constraints, modifiers, ... This often adds visual
+ * noise, and can be expensive to add in big scenes. So prefer setting this to
+ * false.
*/
struct TreeElement *outliner_add_element(SpaceOutliner *space_outliner,
ListBase *lb,
void *idv,
struct TreeElement *parent,
short type,
- short index);
+ short index,
+ const bool expand = true);
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_id.cc b/source/blender/editors/space_outliner/tree/tree_element_id.cc
index ef5e056f229..86f5fd4eff5 100644
--- a/source/blender/editors/space_outliner/tree/tree_element_id.cc
+++ b/source/blender/editors/space_outliner/tree/tree_element_id.cc
@@ -27,6 +27,11 @@ namespace blender::ed::outliner {
std::unique_ptr<TreeElementID> TreeElementID::createFromID(TreeElement &legacy_te, ID &id)
{
+ if (ID_TYPE_IS_DEPRECATED(GS(id.name))) {
+ BLI_assert_msg(0, "Outliner trying to build tree-element for deprecated ID type");
+ return nullptr;
+ }
+
switch (ID_Type type = GS(id.name); type) {
case ID_LI:
return std::make_unique<TreeElementIDLibrary>(legacy_te, (Library &)id);
@@ -70,10 +75,9 @@ std::unique_ptr<TreeElementID> TreeElementID::createFromID(TreeElement &legacy_t
case ID_PC:
case ID_CF:
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");
- return nullptr;
+ BLI_assert_unreachable();
+ break;
}
return nullptr;
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 0dcaec0385a..4f1b951ccaf 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
@@ -4,6 +4,8 @@
* \ingroup spoutliner
*/
+#include "BLT_translation.h"
+
#include "DNA_ID.h"
#include "DNA_listBase.h"
@@ -24,4 +26,21 @@ bool TreeElementIDLibrary::isExpandValid() const
return true;
}
+StringRefNull TreeElementIDLibrary::getWarning() const
+{
+ Library &library = reinterpret_cast<Library &>(id_);
+
+ if (library.tag & LIBRARY_TAG_RESYNC_REQUIRED) {
+ return TIP_(
+ "Contains linked library overrides that need to be resynced, updating the library is "
+ "recommended");
+ }
+
+ if (library.id.tag & LIB_TAG_MISSING) {
+ return TIP_("Missing library");
+ }
+
+ return {};
+}
+
} // namespace blender::ed::outliner
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 ed599cf04da..2d89b55813f 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
@@ -17,6 +17,8 @@ class TreeElementIDLibrary final : public TreeElementID {
TreeElementIDLibrary(TreeElement &legacy_te, Library &library);
bool isExpandValid() const override;
+
+ blender::StringRefNull getWarning() const override;
};
} // namespace blender::ed::outliner
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 857f5577e59..871de39b1dd 100644
--- a/source/blender/editors/space_outliner/tree/tree_element_overrides.cc
+++ b/source/blender/editors/space_outliner/tree/tree_element_overrides.cc
@@ -38,6 +38,19 @@ TreeElementOverridesBase::TreeElementOverridesBase(TreeElement &legacy_te, ID &i
}
}
+StringRefNull TreeElementOverridesBase::getWarning() const
+{
+ if (id.flag & LIB_LIB_OVERRIDE_RESYNC_LEFTOVER) {
+ return TIP_("This override data-block is not needed anymore, but was detected as user-edited");
+ }
+
+ if (ID_IS_OVERRIDE_LIBRARY_REAL(&id) && ID_REAL_USERS(&id) == 0) {
+ return TIP_("This override data-block is unused");
+ }
+
+ return {};
+}
+
void TreeElementOverridesBase::expand(SpaceOutliner &space_outliner) const
{
BLI_assert(id.override_library != nullptr);
@@ -54,21 +67,38 @@ void TreeElementOverridesBase::expand(SpaceOutliner &space_outliner) const
for (auto *override_prop :
ListBaseWrapper<IDOverrideLibraryProperty>(id.override_library->properties)) {
+ int rnaprop_index = 0;
const bool is_rna_path_valid = BKE_lib_override_rna_property_find(
- &idpoin, override_prop, &override_rna_ptr, &override_rna_prop);
- if (is_rna_path_valid && !show_system_overrides &&
- ELEM(override_prop->rna_prop_type, PROP_POINTER, PROP_COLLECTION) &&
- RNA_struct_is_ID(RNA_property_pointer_type(&override_rna_ptr, override_rna_prop))) {
- bool do_continue = true;
- for (auto *override_prop_op :
- ListBaseWrapper<IDOverrideLibraryPropertyOperation>(override_prop->operations)) {
- if ((override_prop_op->flag & IDOVERRIDE_LIBRARY_FLAG_IDPOINTER_MATCH_REFERENCE) == 0) {
- do_continue = false;
- break;
+ &idpoin, override_prop, &override_rna_ptr, &override_rna_prop, &rnaprop_index);
+
+ /* Check for conditions where the liboverride property should be considered as a system
+ * override, if needed. */
+ if (is_rna_path_valid && !show_system_overrides) {
+ bool do_skip = true;
+ bool is_system_override = false;
+
+ /* Matching ID pointers are considered as system overrides. */
+ if (ELEM(override_prop->rna_prop_type, PROP_POINTER, PROP_COLLECTION) &&
+ RNA_struct_is_ID(RNA_property_pointer_type(&override_rna_ptr, override_rna_prop))) {
+ for (auto *override_prop_op :
+ ListBaseWrapper<IDOverrideLibraryPropertyOperation>(override_prop->operations)) {
+ if ((override_prop_op->flag & IDOVERRIDE_LIBRARY_FLAG_IDPOINTER_MATCH_REFERENCE) == 0) {
+ do_skip = false;
+ break;
+ }
+ else {
+ is_system_override = true;
+ }
}
}
- if (do_continue) {
+ /* Animated/driven properties are considered as system overrides. */
+ if (!is_system_override && !BKE_lib_override_library_property_is_animated(
+ &id, override_prop, override_rna_prop, rnaprop_index)) {
+ do_skip = false;
+ }
+
+ if (do_skip) {
continue;
}
}
@@ -84,14 +114,24 @@ TreeElementOverridesProperty::TreeElementOverridesProperty(TreeElement &legacy_t
TreeElementOverridesData &override_data)
: AbstractTreeElement(legacy_te),
override_rna_ptr(override_data.override_rna_ptr),
- override_rna_prop(override_data.override_rna_prop)
+ override_rna_prop(override_data.override_rna_prop),
+ rna_path(override_data.override_property.rna_path),
+ is_rna_path_valid(override_data.is_rna_path_valid)
{
BLI_assert(legacy_te.store_elem->type == TSE_LIBRARY_OVERRIDE);
legacy_te.name = override_data.override_property.rna_path;
- /* Abusing this for now, better way to do it is also pending current refactor of the whole tree
- * code to use C++. */
- legacy_te.directdata = POINTER_FROM_UINT(override_data.is_rna_path_valid);
+}
+
+StringRefNull TreeElementOverridesProperty::getWarning() const
+{
+ if (!is_rna_path_valid) {
+ return TIP_(
+ "This override property does not exist in current data, it will be removed on "
+ "next .blend file save");
+ }
+
+ return {};
}
} // namespace blender::ed::outliner
diff --git a/source/blender/editors/space_outliner/tree/tree_element_overrides.hh b/source/blender/editors/space_outliner/tree/tree_element_overrides.hh
index a2d1409f193..1db46d9af1d 100644
--- a/source/blender/editors/space_outliner/tree/tree_element_overrides.hh
+++ b/source/blender/editors/space_outliner/tree/tree_element_overrides.hh
@@ -8,6 +8,8 @@
#include "RNA_types.h"
+#include "BLI_string_ref.hh"
+
#include "tree_element.hh"
struct ID;
@@ -32,6 +34,8 @@ class TreeElementOverridesBase final : public AbstractTreeElement {
TreeElementOverridesBase(TreeElement &legacy_te, ID &id);
void expand(SpaceOutliner &) const override;
+
+ StringRefNull getWarning() const override;
};
class TreeElementOverridesProperty final : public AbstractTreeElement {
@@ -39,8 +43,13 @@ class TreeElementOverridesProperty final : public AbstractTreeElement {
PointerRNA override_rna_ptr;
PropertyRNA &override_rna_prop;
+ StringRefNull rna_path;
+ bool is_rna_path_valid;
+
public:
TreeElementOverridesProperty(TreeElement &legacy_te, TreeElementOverridesData &override_data);
+
+ StringRefNull getWarning() const override;
};
} // namespace blender::ed::outliner
diff --git a/source/blender/editors/space_outliner/tree/tree_iterator.cc b/source/blender/editors/space_outliner/tree/tree_iterator.cc
new file mode 100644
index 00000000000..8d2b0b21433
--- /dev/null
+++ b/source/blender/editors/space_outliner/tree/tree_iterator.cc
@@ -0,0 +1,59 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+
+/** \file
+ * \ingroup spoutliner
+ */
+
+#include "DNA_space_types.h"
+
+#include "BLI_listbase.h"
+
+#include "../outliner_intern.hh"
+
+#include "tree_iterator.hh"
+
+namespace blender::ed::outliner::tree_iterator {
+
+void all(const SpaceOutliner &space_outliner, const VisitorFn visitor)
+{
+ all_open(space_outliner, space_outliner.tree, visitor);
+}
+
+void all(const ListBase &subtree, const VisitorFn visitor)
+{
+ LISTBASE_FOREACH_MUTABLE (TreeElement *, element, &subtree) {
+ /* Get needed data out in case element gets freed. */
+ const ListBase subtree = element->subtree;
+
+ visitor(element);
+ /* Don't access element from now on, it may be freed. */
+
+ all(subtree, visitor);
+ }
+}
+
+void all_open(const SpaceOutliner &space_outliner, const VisitorFn visitor)
+{
+ all_open(space_outliner, space_outliner.tree, visitor);
+}
+
+void all_open(const SpaceOutliner &space_outliner,
+ const ListBase &subtree,
+ const VisitorFn visitor)
+{
+ LISTBASE_FOREACH_MUTABLE (TreeElement *, element, &subtree) {
+ /* Get needed data out in case element gets freed. */
+ const TreeStoreElem *tselem = TREESTORE(element);
+ const ListBase subtree = element->subtree;
+
+ visitor(element);
+ /* Don't access element from now on, it may be freed. Note that the open/collapsed state may
+ * also have been changed in the visitor callback. */
+
+ if (TSELEM_OPEN(tselem, &space_outliner)) {
+ all_open(space_outliner, subtree, visitor);
+ }
+ }
+}
+
+} // namespace blender::ed::outliner::tree_iterator
diff --git a/source/blender/editors/space_outliner/tree/tree_iterator.hh b/source/blender/editors/space_outliner/tree/tree_iterator.hh
new file mode 100644
index 00000000000..de5bcd2c462
--- /dev/null
+++ b/source/blender/editors/space_outliner/tree/tree_iterator.hh
@@ -0,0 +1,35 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+
+/** \file
+ * \ingroup spoutliner
+ */
+
+#pragma once
+
+#include "BLI_function_ref.hh"
+
+struct ListBase;
+struct SpaceOutliner;
+struct TreeElement;
+
+namespace blender::ed::outliner {
+namespace tree_iterator {
+
+using VisitorFn = FunctionRef<void(TreeElement *)>;
+
+/**
+ * Preorder (meaning depth-first) traversal of all elements (regardless of collapsed state).
+ * Freeing the currently visited element in \a visitor is fine.
+ */
+void all(const SpaceOutliner &space_outliner, VisitorFn visitor);
+void all(const ListBase &subtree, VisitorFn visitor);
+
+/**
+ * Preorder (meaning depth-first) traversal of all elements not part of a collapsed sub-tree.
+ * Freeing the currently visited element in \a visitor is fine (but not its tree-store element).
+ */
+void all_open(const SpaceOutliner &, VisitorFn visitor);
+void all_open(const SpaceOutliner &, const ListBase &subtree, VisitorFn visitor);
+
+} // namespace tree_iterator
+} // namespace blender::ed::outliner
diff --git a/source/blender/editors/space_sequencer/sequencer_add.c b/source/blender/editors/space_sequencer/sequencer_add.c
index 9298eb83b46..647d13a4d56 100644
--- a/source/blender/editors/space_sequencer/sequencer_add.c
+++ b/source/blender/editors/space_sequencer/sequencer_add.c
@@ -31,6 +31,7 @@
#include "BKE_mask.h"
#include "BKE_movieclip.h"
#include "BKE_report.h"
+#include "BKE_scene.h"
#include "BKE_sound.h"
#include "IMB_imbuf.h"
@@ -54,6 +55,7 @@
#include "SEQ_transform.h"
#include "SEQ_utils.h"
+#include "ED_scene.h"
/* For menu, popup, icons, etc. */
#include "ED_screen.h"
#include "ED_sequencer.h"
@@ -136,7 +138,7 @@ static void sequencer_generic_props__internal(wmOperatorType *ot, int flag)
ot->srna,
"overlap_shuffle_override",
false,
- "Override Overlap Shuffle Behaviour",
+ "Override Overlap Shuffle Behavior",
"Use the overlap_mode tool settings to determine how to shuffle overlapping strips");
RNA_def_property_flag(prop, PROP_HIDDEN | PROP_SKIP_SAVE);
@@ -189,10 +191,11 @@ static int sequencer_generic_invoke_xy_guess_channel(bContext *C, int type)
}
for (seq = ed->seqbasep->first; seq; seq = seq->next) {
- if ((ELEM(type, -1, seq->type)) && (seq->enddisp < timeline_frame) &&
- (timeline_frame - seq->enddisp < proximity)) {
+ const int strip_end = SEQ_time_right_handle_frame_get(seq);
+ if ((ELEM(type, -1, seq->type)) && (strip_end < timeline_frame) &&
+ (timeline_frame - strip_end < proximity)) {
tgt = seq;
- proximity = timeline_frame - seq->enddisp;
+ proximity = timeline_frame - strip_end;
}
}
@@ -337,7 +340,7 @@ static void seq_load_apply_generic_options(bContext *C, wmOperator *op, Sequence
ScrArea *area = CTX_wm_area(C);
const bool use_sync_markers = (((SpaceSeq *)area->spacedata.first)->flag & SEQ_MARKER_TRANS) !=
0;
- SEQ_transform_handle_overlap(scene, ed->seqbasep, strip_col, use_sync_markers);
+ SEQ_transform_handle_overlap(scene, ed->seqbasep, strip_col, NULL, use_sync_markers);
SEQ_collection_free(strip_col);
}
@@ -469,6 +472,125 @@ void SEQUENCER_OT_scene_strip_add(struct wmOperatorType *ot)
ot->prop = prop;
}
+static EnumPropertyItem strip_new_scene_items[] = {
+ {SCE_COPY_NEW, "NEW", 0, "New", "Add new Strip with a new empty Scene with default settings"},
+ {SCE_COPY_EMPTY,
+ "EMPTY",
+ 0,
+ "Copy Settings",
+ "Add a new Strip, with an empty scene, and copy settings from the current scene"},
+ {SCE_COPY_LINK_COLLECTION,
+ "LINK_COPY",
+ 0,
+ "Linked Copy",
+ "Add a Strip and link in the collections from the current scene (shallow copy)"},
+ {SCE_COPY_FULL,
+ "FULL_COPY",
+ 0,
+ "Full Copy",
+ "Add a Strip and make a full copy of the current scene"},
+ {0, NULL, 0, NULL, NULL},
+};
+
+static int sequencer_add_scene_strip_new_exec(bContext *C, wmOperator *op)
+{
+ Main *bmain = CTX_data_main(C);
+ Scene *scene = CTX_data_scene(C);
+ const Editing *ed = SEQ_editing_ensure(scene);
+
+ if (RNA_boolean_get(op->ptr, "replace_sel")) {
+ ED_sequencer_deselect_all(scene);
+ }
+
+ SeqLoadData load_data;
+ load_data_init_from_operator(&load_data, C, op);
+
+ int type = RNA_enum_get(op->ptr, "type");
+ Scene *scene_new = ED_scene_sequencer_add(bmain, C, type, false);
+ if (scene_new == NULL) {
+ return OPERATOR_CANCELLED;
+ }
+ load_data.scene = scene_new;
+
+ Sequence *seq = SEQ_add_scene_strip(scene, ed->seqbasep, &load_data);
+ seq_load_apply_generic_options(C, op, seq);
+
+ 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);
+
+ return OPERATOR_FINISHED;
+}
+
+static int sequencer_add_scene_strip_new_invoke(bContext *C,
+ wmOperator *op,
+ const wmEvent *UNUSED(event))
+{
+ sequencer_disable_one_time_properties(C, op);
+ sequencer_generic_invoke_xy__internal(C, op, 0, SEQ_TYPE_SCENE);
+ return sequencer_add_scene_strip_new_exec(C, op);
+}
+
+static const EnumPropertyItem *strip_new_sequencer_enum_itemf(bContext *C,
+ PointerRNA *UNUSED(ptr),
+ PropertyRNA *UNUSED(prop),
+ bool *r_free)
+{
+ EnumPropertyItem *item = NULL;
+ int totitem = 0;
+ uint item_index;
+
+ item_index = RNA_enum_from_value(strip_new_scene_items, SCE_COPY_NEW);
+ RNA_enum_item_add(&item, &totitem, &strip_new_scene_items[item_index]);
+
+ bool has_scene_or_no_context = false;
+ if (C == NULL) {
+ /* For documentation generation. */
+ has_scene_or_no_context = true;
+ }
+ else {
+ Scene *scene = CTX_data_scene(C);
+ Sequence *seq = SEQ_select_active_get(scene);
+ if ((seq && (seq->type == SEQ_TYPE_SCENE) && (seq->scene != NULL))) {
+ has_scene_or_no_context = true;
+ }
+ }
+
+ if (has_scene_or_no_context) {
+ int values[] = {SCE_COPY_EMPTY, SCE_COPY_LINK_COLLECTION, SCE_COPY_FULL};
+ for (int i = 0; i < ARRAY_SIZE(values); i++) {
+ item_index = RNA_enum_from_value(strip_new_scene_items, values[i]);
+ RNA_enum_item_add(&item, &totitem, &strip_new_scene_items[item_index]);
+ }
+ }
+
+ RNA_enum_item_end(&item, &totitem);
+ *r_free = true;
+ return item;
+}
+
+void SEQUENCER_OT_scene_strip_add_new(struct wmOperatorType *ot)
+{
+ /* Identifiers. */
+ ot->name = "Add Strip with a new Scene";
+ ot->idname = "SEQUENCER_OT_scene_strip_add_new";
+ ot->description = "Create a new Strip and add a assign a new Scene as source";
+
+ /* Api callbacks. */
+ ot->invoke = sequencer_add_scene_strip_new_invoke;
+ ot->exec = sequencer_add_scene_strip_new_exec;
+ ot->poll = ED_operator_sequencer_active_editable;
+
+ /* Flags. */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+
+ sequencer_generic_props__internal(ot, SEQPROP_STARTFRAME);
+
+ ot->prop = RNA_def_enum(ot->srna, "type", strip_new_scene_items, SCE_COPY_NEW, "Type", "");
+ RNA_def_enum_funcs(ot->prop, strip_new_sequencer_enum_itemf);
+ RNA_def_property_flag(ot->prop, PROP_ENUM_NO_TRANSLATE);
+}
+
static int sequencer_add_movieclip_strip_exec(bContext *C, wmOperator *op)
{
Main *bmain = CTX_data_main(C);
@@ -664,7 +786,6 @@ static void seq_build_proxy(bContext *C, SeqCollection *movie_strips)
}
static void sequencer_add_movie_clamp_sound_strip_length(Scene *scene,
- ListBase *seqbase,
Sequence *seq_movie,
Sequence *seq_sound)
{
@@ -672,9 +793,8 @@ static void sequencer_add_movie_clamp_sound_strip_length(Scene *scene,
return;
}
- SEQ_transform_set_right_handle_frame(seq_sound, SEQ_transform_get_right_handle_frame(seq_movie));
- SEQ_transform_set_left_handle_frame(seq_sound, SEQ_transform_get_left_handle_frame(seq_movie));
- SEQ_time_update_sequence(scene, seqbase, seq_sound);
+ SEQ_time_right_handle_frame_set(scene, seq_sound, SEQ_time_right_handle_frame_get(seq_movie));
+ SEQ_time_left_handle_frame_set(scene, seq_sound, SEQ_time_left_handle_frame_get(seq_movie));
}
static void sequencer_add_movie_multiple_strips(bContext *C,
@@ -712,7 +832,7 @@ static void sequencer_add_movie_multiple_strips(bContext *C,
else {
if (RNA_boolean_get(op->ptr, "sound")) {
seq_sound = SEQ_add_sound_strip(bmain, scene, ed->seqbasep, load_data);
- sequencer_add_movie_clamp_sound_strip_length(scene, ed->seqbasep, seq_movie, seq_sound);
+ sequencer_add_movie_clamp_sound_strip_length(scene, seq_movie, seq_sound);
if (seq_sound) {
/* The video has sound, shift the video strip up a channel to make room for the sound
@@ -721,7 +841,8 @@ static void sequencer_add_movie_multiple_strips(bContext *C,
}
}
- load_data->start_frame += seq_movie->enddisp - seq_movie->startdisp;
+ load_data->start_frame += SEQ_time_right_handle_frame_get(seq_movie) -
+ SEQ_time_left_handle_frame_get(seq_movie);
if (overlap_shuffle_override) {
has_seq_overlap |= seq_load_apply_generic_options_only_test_overlap(
C, op, seq_sound, strip_col);
@@ -742,7 +863,7 @@ static void sequencer_add_movie_multiple_strips(bContext *C,
ScrArea *area = CTX_wm_area(C);
const bool use_sync_markers = (((SpaceSeq *)area->spacedata.first)->flag &
SEQ_MARKER_TRANS) != 0;
- SEQ_transform_handle_overlap(scene, ed->seqbasep, strip_col, use_sync_markers);
+ SEQ_transform_handle_overlap(scene, ed->seqbasep, strip_col, NULL, use_sync_markers);
}
SEQ_collection_free(strip_col);
@@ -769,7 +890,7 @@ static bool sequencer_add_movie_single_strip(bContext *C,
}
if (RNA_boolean_get(op->ptr, "sound")) {
seq_sound = SEQ_add_sound_strip(bmain, scene, ed->seqbasep, load_data);
- sequencer_add_movie_clamp_sound_strip_length(scene, ed->seqbasep, seq_movie, seq_sound);
+ sequencer_add_movie_clamp_sound_strip_length(scene, seq_movie, seq_sound);
if (seq_sound) {
/* The video has sound, shift the video strip up a channel to make room for the sound
* strip. */
@@ -792,7 +913,7 @@ static bool sequencer_add_movie_single_strip(bContext *C,
ScrArea *area = CTX_wm_area(C);
const bool use_sync_markers = (((SpaceSeq *)area->spacedata.first)->flag &
SEQ_MARKER_TRANS) != 0;
- SEQ_transform_handle_overlap(scene, ed->seqbasep, strip_col, use_sync_markers);
+ SEQ_transform_handle_overlap(scene, ed->seqbasep, strip_col, NULL, use_sync_markers);
}
SEQ_collection_free(strip_col);
@@ -952,7 +1073,8 @@ static void sequencer_add_sound_multiple_strips(bContext *C,
}
else {
seq_load_apply_generic_options(C, op, seq);
- load_data->start_frame += seq->enddisp - seq->startdisp;
+ load_data->start_frame += SEQ_time_right_handle_frame_get(seq) -
+ SEQ_time_left_handle_frame_get(seq);
}
}
RNA_END;
@@ -1179,8 +1301,7 @@ static int sequencer_add_image_strip_exec(bContext *C, wmOperator *op)
/* Adjust length. */
if (load_data.image.len == 1) {
- SEQ_transform_set_right_handle_frame(seq, load_data.image.end_frame);
- SEQ_time_update_sequence(scene, SEQ_active_seqbase_get(ed), seq);
+ SEQ_time_right_handle_frame_set(scene, seq, load_data.image.end_frame);
}
seq_load_apply_generic_options(C, op, seq);
diff --git a/source/blender/editors/space_sequencer/sequencer_channels_draw.c b/source/blender/editors/space_sequencer/sequencer_channels_draw.c
index a777132e9fc..c11388e8555 100644
--- a/source/blender/editors/space_sequencer/sequencer_channels_draw.c
+++ b/source/blender/editors/space_sequencer/sequencer_channels_draw.c
@@ -200,7 +200,7 @@ static float text_size_get(const SeqChannelDrawContext *context)
return UI_fontstyle_height_max(&style->widget) * 1.5f * context->scale;
}
-/* Todo: decide what gets priority - label or buttons */
+/* TODO: decide what gets priority - label or buttons. */
static rctf label_rect_init(const SeqChannelDrawContext *context,
const int channel_index,
const float used_width)
@@ -286,7 +286,7 @@ static void draw_channel_labels(const SeqChannelDrawContext *context,
}
}
-/* Todo: different text/buttons alignment */
+/* TODO: different text/buttons alignment. */
static void draw_channel_header(const SeqChannelDrawContext *context,
uiBlock *block,
const int channel_index)
diff --git a/source/blender/editors/space_sequencer/sequencer_drag_drop.c b/source/blender/editors/space_sequencer/sequencer_drag_drop.c
index 645c0dc9a1d..8dadb9360e3 100644
--- a/source/blender/editors/space_sequencer/sequencer_drag_drop.c
+++ b/source/blender/editors/space_sequencer/sequencer_drag_drop.c
@@ -231,9 +231,8 @@ static void update_overlay_strip_poistion_data(bContext *C, const int mval[2])
else {
/* Check if there is a strip that would intersect with the new strip(s). */
coords->is_intersecting = false;
- Sequence dummy_seq = {.machine = coords->channel,
- .startdisp = coords->start_frame,
- .enddisp = coords->start_frame + coords->strip_len};
+ Sequence dummy_seq = {
+ .machine = coords->channel, .start = coords->start_frame, .len = coords->strip_len};
Editing *ed = SEQ_editing_get(scene);
for (int i = 0; i < coords->channel_len && !coords->is_intersecting; i++) {
diff --git a/source/blender/editors/space_sequencer/sequencer_draw.c b/source/blender/editors/space_sequencer/sequencer_draw.c
index 4cb41c702da..25701c323b9 100644
--- a/source/blender/editors/space_sequencer/sequencer_draw.c
+++ b/source/blender/editors/space_sequencer/sequencer_draw.c
@@ -572,8 +572,6 @@ static void drawmeta_contents(Scene *scene,
float y2,
const bool show_strip_color_tag)
{
- Editing *ed = SEQ_editing_get(scene);
- ListBase *channels = SEQ_channels_displayed_get(ed);
Sequence *seq;
uchar col[4];
@@ -582,11 +580,16 @@ static void drawmeta_contents(Scene *scene,
int chan_range = 0;
float draw_range = y2 - y1;
float draw_height;
- ListBase *seqbase;
+
+ Editing *ed = SEQ_editing_get(scene);
+ ListBase *channels = SEQ_channels_displayed_get(ed);
+ ListBase *meta_seqbase;
+ ListBase *meta_channels;
int offset;
- seqbase = SEQ_get_seqbase_from_sequence(seqm, &offset);
- if (!seqbase || BLI_listbase_is_empty(seqbase)) {
+ meta_seqbase = SEQ_get_seqbase_from_sequence(seqm, &meta_channels, &offset);
+
+ if (!meta_seqbase || BLI_listbase_is_empty(meta_seqbase)) {
return;
}
@@ -599,7 +602,7 @@ static void drawmeta_contents(Scene *scene,
GPU_blend(GPU_BLEND_ALPHA);
- for (seq = seqbase->first; seq; seq = seq->next) {
+ for (seq = meta_seqbase->first; seq; seq = seq->next) {
chan_min = min_ii(chan_min, seq->machine);
chan_max = max_ii(chan_max, seq->machine);
}
@@ -613,9 +616,9 @@ static void drawmeta_contents(Scene *scene,
immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
/* Draw only immediate children (1 level depth). */
- for (seq = seqbase->first; seq; seq = seq->next) {
- const int startdisp = seq->startdisp + offset;
- const int enddisp = seq->enddisp + offset;
+ for (seq = meta_seqbase->first; seq; seq = seq->next) {
+ const int startdisp = SEQ_time_left_handle_frame_get(seq) + offset;
+ const int enddisp = SEQ_time_right_handle_frame_get(seq) + offset;
if ((startdisp > x2 || enddisp < x1) == 0) {
float y_chan = (seq->machine - chan_min) / (float)(chan_range)*draw_range;
@@ -631,7 +634,7 @@ static void drawmeta_contents(Scene *scene,
color3ubv_from_seq(scene, seq, show_strip_color_tag, col);
}
- if (SEQ_render_is_muted(channels, seqm) || SEQ_render_is_muted(&seqm->channels, seq)) {
+ if (SEQ_render_is_muted(channels, seqm) || SEQ_render_is_muted(meta_channels, seq)) {
col[3] = 64;
}
else {
@@ -665,7 +668,10 @@ float sequence_handle_size_get_clamped(Sequence *seq, const float pixelx)
const float maxhandle = (pixelx * SEQ_HANDLE_SIZE) * U.pixelsize;
/* Ensure that handle is not wider, than quarter of strip. */
- return min_ff(maxhandle, ((float)(seq->enddisp - seq->startdisp) / 4.0f));
+ return min_ff(
+ maxhandle,
+ ((float)(SEQ_time_right_handle_frame_get(seq) - SEQ_time_left_handle_frame_get(seq)) /
+ 4.0f));
}
/* Draw a handle, on left or right side of strip. */
@@ -683,8 +689,8 @@ static void draw_seq_handle(View2D *v2d,
uint whichsel = 0;
uchar col[4];
- x1 = seq->startdisp;
- x2 = seq->enddisp;
+ x1 = SEQ_time_left_handle_frame_get(seq);
+ x2 = SEQ_time_right_handle_frame_get(seq);
y1 = seq->machine + SEQ_STRIP_OFSBOTTOM;
y2 = seq->machine + SEQ_STRIP_OFSTOP;
@@ -736,7 +742,11 @@ static void draw_seq_handle(View2D *v2d,
BLF_set_default();
/* Calculate if strip is wide enough for showing the labels. */
- numstr_len = BLI_snprintf_rlen(numstr, sizeof(numstr), "%d%d", seq->startdisp, seq->enddisp);
+ numstr_len = BLI_snprintf_rlen(numstr,
+ sizeof(numstr),
+ "%d%d",
+ SEQ_time_left_handle_frame_get(seq),
+ SEQ_time_right_handle_frame_get(seq));
float tot_width = BLF_width(fontid, numstr, numstr_len);
if ((x2 - x1) / pixelx > 20 + tot_width) {
@@ -744,12 +754,14 @@ static void draw_seq_handle(View2D *v2d,
float text_margin = 1.2f * handsize_clamped;
if (direction == SEQ_LEFTHANDLE) {
- numstr_len = BLI_snprintf_rlen(numstr, sizeof(numstr), "%d", seq->startdisp);
+ numstr_len = BLI_snprintf_rlen(
+ numstr, sizeof(numstr), "%d", SEQ_time_left_handle_frame_get(seq));
x1 += text_margin;
y1 += 0.09f;
}
else {
- numstr_len = BLI_snprintf_rlen(numstr, sizeof(numstr), "%d", seq->enddisp - 1);
+ numstr_len = BLI_snprintf_rlen(
+ numstr, sizeof(numstr), "%d", SEQ_time_right_handle_frame_get(seq) - 1);
x1 = x2 - (text_margin + pixelx * BLF_width(fontid, numstr, numstr_len));
y1 += 0.09f;
}
@@ -910,7 +922,8 @@ static size_t draw_seq_text_get_overlay_string(SpaceSeq *sseq,
char strip_duration_text[16];
if (sseq->timeline_overlay.flag & SEQ_TIMELINE_SHOW_STRIP_DURATION) {
- const int strip_duration = seq->enddisp - seq->startdisp;
+ const int strip_duration = SEQ_time_right_handle_frame_get(seq) -
+ SEQ_time_left_handle_frame_get(seq);
SNPRINTF(strip_duration_text, "%d", strip_duration);
if (i != 0) {
text_array[i++] = text_sep;
@@ -977,8 +990,8 @@ static void draw_sequence_extensions_overlay(
float x1, x2, y1, y2;
uchar col[4], blend_col[3];
- x1 = seq->startdisp;
- x2 = seq->enddisp;
+ x1 = SEQ_time_left_handle_frame_get(seq);
+ x2 = SEQ_time_right_handle_frame_get(seq);
y1 = seq->machine + SEQ_STRIP_OFSBOTTOM;
y2 = seq->machine + SEQ_STRIP_OFSTOP;
@@ -1035,15 +1048,19 @@ static void draw_color_strip_band(
immUniformColor4ubv(col);
- immRectf(pos, seq->startdisp, y1, seq->enddisp, text_margin_y);
+ immRectf(pos,
+ SEQ_time_left_handle_frame_get(seq),
+ y1,
+ SEQ_time_right_handle_frame_get(seq),
+ text_margin_y);
/* 1px line to better separate the color band. */
UI_GetColorPtrShade3ubv(col, col, -20);
immUniformColor4ubv(col);
immBegin(GPU_PRIM_LINES, 2);
- immVertex2f(pos, seq->startdisp, text_margin_y);
- immVertex2f(pos, seq->enddisp, text_margin_y);
+ immVertex2f(pos, SEQ_time_left_handle_frame_get(seq), text_margin_y);
+ immVertex2f(pos, SEQ_time_right_handle_frame_get(seq), text_margin_y);
immEnd();
GPU_blend(GPU_BLEND_NONE);
@@ -1095,28 +1112,25 @@ static void draw_seq_background(Scene *scene,
/* Draw the main strip body. */
if (is_single_image) {
- immRectf(pos,
- SEQ_transform_get_left_handle_frame(seq),
- y1,
- SEQ_transform_get_right_handle_frame(seq),
- y2);
+ immRectf(
+ pos, SEQ_time_left_handle_frame_get(seq), y1, SEQ_time_right_handle_frame_get(seq), y2);
}
else {
immRectf(pos, x1, y1, x2, y2);
}
/* Draw background for hold still regions. */
- if (!is_single_image && (seq->startstill || seq->endstill)) {
+ if (!is_single_image && SEQ_time_has_still_frames(seq)) {
UI_GetColorPtrShade3ubv(col, col, -35);
immUniformColor4ubv(col);
- if (seq->startstill) {
- const float content_start = min_ff(seq->enddisp, seq->start);
- immRectf(pos, seq->startdisp, y1, content_start, y2);
+ if (SEQ_time_has_left_still_frames(seq)) {
+ const float content_start = min_ff(SEQ_time_right_handle_frame_get(seq), seq->start);
+ immRectf(pos, SEQ_time_left_handle_frame_get(seq), y1, content_start, y2);
}
- if (seq->endstill) {
- const float content_end = max_ff(seq->startdisp, seq->start + seq->len);
- immRectf(pos, content_end, y1, seq->enddisp, y2);
+ if (SEQ_time_has_right_still_frames(seq)) {
+ const float content_end = max_ff(SEQ_time_left_handle_frame_get(seq), seq->start + seq->len);
+ immRectf(pos, content_end, y1, SEQ_time_right_handle_frame_get(seq), y2);
}
}
@@ -1333,14 +1347,15 @@ static void draw_seq_strip(const bContext *C,
SEQ_TIMELINE_SHOW_STRIP_COLOR_TAG);
/* Draw strip body. */
- x1 = (seq->startstill) ? seq->start : seq->startdisp;
+ x1 = SEQ_time_has_left_still_frames(seq) ? seq->start : SEQ_time_left_handle_frame_get(seq);
y1 = seq->machine + SEQ_STRIP_OFSBOTTOM;
- x2 = (seq->endstill) ? (seq->start + seq->len) : seq->enddisp;
+ x2 = SEQ_time_has_right_still_frames(seq) ? (seq->start + seq->len) :
+ SEQ_time_right_handle_frame_get(seq);
y2 = seq->machine + SEQ_STRIP_OFSTOP;
/* Limit body to strip bounds. Meta strip can end up with content outside of strip range. */
- x1 = min_ff(x1, seq->enddisp);
- x2 = max_ff(x2, seq->startdisp);
+ x1 = min_ff(x1, SEQ_time_right_handle_frame_get(seq));
+ x2 = max_ff(x2, SEQ_time_left_handle_frame_get(seq));
float text_margin_y;
bool y_threshold;
@@ -1380,8 +1395,8 @@ static void draw_seq_strip(const bContext *C,
}
immUnbindProgram();
- x1 = seq->startdisp;
- x2 = seq->enddisp;
+ x1 = SEQ_time_left_handle_frame_get(seq);
+ x2 = SEQ_time_right_handle_frame_get(seq);
if ((seq->type == SEQ_TYPE_META) ||
((seq->type == SEQ_TYPE_SCENE) && (seq->flag & SEQ_SCENE_STRIPS))) {
@@ -1471,23 +1486,23 @@ static void draw_effect_inputs_highlight(Sequence *seq)
immUniformColor4ub(255, 255, 255, 48);
immRectf(pos,
- seq1->startdisp,
+ SEQ_time_left_handle_frame_get(seq1),
seq1->machine + SEQ_STRIP_OFSBOTTOM,
- seq1->enddisp,
+ SEQ_time_right_handle_frame_get(seq1),
seq1->machine + SEQ_STRIP_OFSTOP);
if (seq2 && seq2 != seq1) {
immRectf(pos,
- seq2->startdisp,
+ SEQ_time_left_handle_frame_get(seq2),
seq2->machine + SEQ_STRIP_OFSBOTTOM,
- seq2->enddisp,
+ SEQ_time_right_handle_frame_get(seq2),
seq2->machine + SEQ_STRIP_OFSTOP);
}
if (seq3 && !ELEM(seq3, seq1, seq2)) {
immRectf(pos,
- seq3->startdisp,
+ SEQ_time_left_handle_frame_get(seq3),
seq3->machine + SEQ_STRIP_OFSBOTTOM,
- seq3->enddisp,
+ SEQ_time_right_handle_frame_get(seq3),
seq3->machine + SEQ_STRIP_OFSTOP);
}
immUnbindProgram();
@@ -2081,10 +2096,10 @@ static int sequencer_draw_get_transform_preview_frame(Scene *scene)
int preview_frame;
if (last_seq->flag & SEQ_RIGHTSEL) {
- preview_frame = last_seq->enddisp - 1;
+ preview_frame = SEQ_time_right_handle_frame_get(last_seq) - 1;
}
else {
- preview_frame = last_seq->startdisp;
+ preview_frame = SEQ_time_left_handle_frame_get(last_seq);
}
return preview_frame;
@@ -2310,10 +2325,10 @@ static void draw_seq_strips(const bContext *C, Editing *ed, ARegion *region)
if (seq == last_seq && (last_seq->flag & SELECT)) {
continue;
}
- if (min_ii(seq->startdisp, seq->start) > v2d->cur.xmax) {
+ if (min_ii(SEQ_time_left_handle_frame_get(seq), seq->start) > v2d->cur.xmax) {
continue;
}
- if (max_ii(seq->enddisp, seq->start + seq->len) < v2d->cur.xmin) {
+ if (max_ii(SEQ_time_right_handle_frame_get(seq), seq->start + seq->len) < v2d->cur.xmin) {
continue;
}
if (seq->machine + 1.0f < v2d->cur.ymin) {
@@ -2368,9 +2383,9 @@ static void draw_seq_strips(const bContext *C, Editing *ed, ARegion *region)
immUniformColor4ub(255, 255, 255, 48);
immRectf(pos,
- seq->startdisp,
+ SEQ_time_left_handle_frame_get(seq),
seq->machine + SEQ_STRIP_OFSBOTTOM,
- seq->enddisp,
+ SEQ_time_right_handle_frame_get(seq),
seq->machine + SEQ_STRIP_OFSTOP);
immUnbindProgram();
@@ -2597,7 +2612,8 @@ static void draw_cache_view(const bContext *C)
continue;
}
- if (seq->startdisp > v2d->cur.xmax || seq->enddisp < v2d->cur.xmin) {
+ if (SEQ_time_left_handle_frame_get(seq) > v2d->cur.xmax ||
+ SEQ_time_right_handle_frame_get(seq) < v2d->cur.xmin) {
continue;
}
@@ -2607,7 +2623,11 @@ static void draw_cache_view(const bContext *C)
if (scene->ed->cache_flag & SEQ_CACHE_VIEW_RAW) {
const float bg_color[4] = {1.0f, 0.1f, 0.02f, 0.1f};
immUniformColor4f(bg_color[0], bg_color[1], bg_color[2], bg_color[3]);
- immRectf(pos, seq->startdisp, stripe_bot, seq->enddisp, stripe_top);
+ immRectf(pos,
+ SEQ_time_left_handle_frame_get(seq),
+ stripe_bot,
+ SEQ_time_right_handle_frame_get(seq),
+ stripe_top);
}
stripe_bot += stripe_ht + stripe_ofs_y;
@@ -2616,7 +2636,11 @@ static void draw_cache_view(const bContext *C)
if (scene->ed->cache_flag & SEQ_CACHE_VIEW_PREPROCESSED) {
const float bg_color[4] = {0.1f, 0.1f, 0.75f, 0.1f};
immUniformColor4f(bg_color[0], bg_color[1], bg_color[2], bg_color[3]);
- immRectf(pos, seq->startdisp, stripe_bot, seq->enddisp, stripe_top);
+ immRectf(pos,
+ SEQ_time_left_handle_frame_get(seq),
+ stripe_bot,
+ SEQ_time_right_handle_frame_get(seq),
+ stripe_top);
}
stripe_top = seq->machine + SEQ_STRIP_OFSTOP - stripe_ofs_y;
@@ -2625,7 +2649,11 @@ static void draw_cache_view(const bContext *C)
if (scene->ed->cache_flag & SEQ_CACHE_VIEW_COMPOSITE) {
const float bg_color[4] = {1.0f, 0.6f, 0.0f, 0.1f};
immUniformColor4f(bg_color[0], bg_color[1], bg_color[2], bg_color[3]);
- immRectf(pos, seq->startdisp, stripe_bot, seq->enddisp, stripe_top);
+ immRectf(pos,
+ SEQ_time_left_handle_frame_get(seq),
+ stripe_bot,
+ SEQ_time_right_handle_frame_get(seq),
+ stripe_top);
}
}
diff --git a/source/blender/editors/space_sequencer/sequencer_edit.c b/source/blender/editors/space_sequencer/sequencer_edit.c
index 0305ad279a0..86c438c616e 100644
--- a/source/blender/editors/space_sequencer/sequencer_edit.c
+++ b/source/blender/editors/space_sequencer/sequencer_edit.c
@@ -57,6 +57,7 @@
#include "ED_keyframing.h"
#include "ED_numinput.h"
#include "ED_outliner.h"
+#include "ED_scene.h"
#include "ED_screen.h"
#include "ED_sequencer.h"
@@ -76,8 +77,6 @@
typedef struct TransSeq {
int start, machine;
- int startstill, endstill;
- int startdisp, enddisp;
int startofs, endofs;
int anim_startofs, anim_endofs;
/* int final_left, final_right; */ /* UNUSED */
@@ -345,7 +344,6 @@ static int sequencer_snap_exec(bContext *C, wmOperator *op)
Scene *scene = CTX_data_scene(C);
Editing *ed = SEQ_editing_get(scene);
- ListBase *seqbase = SEQ_active_seqbase_get(ed);
ListBase *channels = SEQ_channels_displayed_get(ed);
Sequence *seq;
int snap_frame;
@@ -357,20 +355,19 @@ static int sequencer_snap_exec(bContext *C, wmOperator *op)
if (seq->flag & SELECT && !SEQ_transform_is_locked(channels, seq) &&
SEQ_transform_sequence_can_be_translated(seq)) {
if ((seq->flag & (SEQ_LEFTSEL + SEQ_RIGHTSEL)) == 0) {
- SEQ_transform_translate_sequence(
- scene, seq, (snap_frame - seq->startofs + seq->startstill) - seq->start);
+ SEQ_transform_translate_sequence(scene, seq, (snap_frame - seq->startofs) - seq->start);
}
else {
if (seq->flag & SEQ_LEFTSEL) {
- SEQ_transform_set_left_handle_frame(seq, snap_frame);
+ SEQ_time_left_handle_frame_set(scene, seq, snap_frame);
}
else { /* SEQ_RIGHTSEL */
- SEQ_transform_set_right_handle_frame(seq, snap_frame);
+ SEQ_time_right_handle_frame_set(scene, seq, snap_frame);
}
- SEQ_transform_handle_xlimits(seq, seq->flag & SEQ_LEFTSEL, seq->flag & SEQ_RIGHTSEL);
- SEQ_transform_fix_single_image_seq_offsets(seq);
+ SEQ_transform_handle_xlimits(
+ scene, seq, seq->flag & SEQ_LEFTSEL, seq->flag & SEQ_RIGHTSEL);
+ SEQ_transform_fix_single_image_seq_offsets(scene, seq);
}
- SEQ_time_update_sequence(scene, seqbase, seq);
}
}
@@ -391,27 +388,22 @@ static int sequencer_snap_exec(bContext *C, wmOperator *op)
if (seq->seq1 && (seq->seq1->flag & SELECT)) {
if (!either_handle_selected) {
- SEQ_offset_animdata(scene, seq, (snap_frame - seq->startdisp));
+ SEQ_offset_animdata(scene, seq, (snap_frame - SEQ_time_left_handle_frame_get(seq)));
}
- SEQ_time_update_sequence(scene, seqbase, seq);
}
else if (seq->seq2 && (seq->seq2->flag & SELECT)) {
if (!either_handle_selected) {
- SEQ_offset_animdata(scene, seq, (snap_frame - seq->startdisp));
+ SEQ_offset_animdata(scene, seq, (snap_frame - SEQ_time_left_handle_frame_get(seq)));
}
- SEQ_time_update_sequence(scene, seqbase, seq);
}
else if (seq->seq3 && (seq->seq3->flag & SELECT)) {
if (!either_handle_selected) {
- SEQ_offset_animdata(scene, seq, (snap_frame - seq->startdisp));
+ SEQ_offset_animdata(scene, seq, (snap_frame - SEQ_time_left_handle_frame_get(seq)));
}
- SEQ_time_update_sequence(scene, seqbase, seq);
}
}
}
- SEQ_sort(SEQ_active_seqbase_get(ed));
-
DEG_id_tag_update(&scene->id, ID_RECALC_SEQUENCER_STRIPS);
WM_event_add_notifier(C, NC_SCENE | ND_SEQUENCER, scene);
@@ -478,10 +470,6 @@ static void transseq_backup(TransSeq *ts, Sequence *seq)
{
ts->start = seq->start;
ts->machine = seq->machine;
- ts->startstill = seq->startstill;
- ts->endstill = seq->endstill;
- ts->startdisp = seq->startdisp;
- ts->enddisp = seq->enddisp;
ts->startofs = seq->startofs;
ts->endofs = seq->endofs;
ts->anim_startofs = seq->anim_startofs;
@@ -493,10 +481,6 @@ static void transseq_restore(TransSeq *ts, Sequence *seq)
{
seq->start = ts->start;
seq->machine = ts->machine;
- seq->startstill = ts->startstill;
- seq->endstill = ts->endstill;
- seq->startdisp = ts->startdisp;
- seq->enddisp = ts->enddisp;
seq->startofs = ts->startofs;
seq->endofs = ts->endofs;
seq->anim_startofs = ts->anim_startofs;
@@ -595,69 +579,22 @@ static int sequencer_slip_invoke(bContext *C, wmOperator *op, const wmEvent *eve
return OPERATOR_RUNNING_MODAL;
}
-static bool sequencer_slip_recursively(Scene *scene, SlipData *data, int offset)
+static void sequencer_slip_recursively(Scene *scene, SlipData *data, int offset)
{
- /* Only data types supported for now. */
- bool changed = false;
-
- /* Iterate in reverse so meta-strips are iterated after their children. */
for (int i = data->num_seq - 1; i >= 0; i--) {
Sequence *seq = data->seq_array[i];
- int endframe;
- /* Offset seq start. */
seq->start = data->ts[i].start + offset;
-
if (data->trim[i]) {
- /* Find the end-frame. */
- endframe = seq->start + seq->len;
-
- /* Compute the sequence offsets. */
- if (endframe > seq->enddisp) {
- seq->endstill = 0;
- seq->endofs = endframe - seq->enddisp;
- changed = true;
- }
- else {
- seq->endstill = seq->enddisp - endframe;
- seq->endofs = 0;
- changed = true;
- }
-
- if (seq->start > seq->startdisp) {
- seq->startstill = seq->start - seq->startdisp;
- seq->startofs = 0;
- changed = true;
- }
- else {
- seq->startstill = 0;
- seq->startofs = seq->startdisp - seq->start;
- changed = true;
- }
- }
- else {
- /* No transform data (likely effect strip). Only move start and end. */
- seq->startdisp = data->ts[i].startdisp + offset;
- seq->enddisp = data->ts[i].enddisp + offset;
- changed = true;
- }
-
- /* Effects are only added if we they are in a meta-strip.
- * In this case, dependent strips will just be transformed and
- * we can skip calculating for effects.
- * This way we can avoid an extra loop just for effects. */
- if (!(seq->type & SEQ_TYPE_EFFECT)) {
- ListBase *seqbase = SEQ_active_seqbase_get(SEQ_editing_get(scene));
- SEQ_time_update_sequence(scene, seqbase, seq);
+ seq->startofs = data->ts[i].startofs - offset;
+ seq->endofs = data->ts[i].endofs + offset;
}
}
- if (changed) {
- for (int i = data->num_seq - 1; i >= 0; i--) {
- Sequence *seq = data->seq_array[i];
- SEQ_relations_invalidate_cache_preprocessed(scene, seq);
- }
+
+ for (int i = data->num_seq - 1; i >= 0; i--) {
+ Sequence *seq = data->seq_array[i];
+ SEQ_relations_invalidate_cache_preprocessed(scene, seq);
}
- return changed;
}
/* Make sure, that each strip contains at least 1 frame of content. */
@@ -670,12 +607,12 @@ static void sequencer_slip_apply_limits(SlipData *data, int *offset)
int seq_content_end = seq_content_start + seq->len + seq->anim_startofs + seq->anim_endofs;
int diff = 0;
- if (seq_content_start >= seq->enddisp) {
- diff = seq->enddisp - seq_content_start - 1;
+ if (seq_content_start >= SEQ_time_right_handle_frame_get(seq)) {
+ diff = SEQ_time_right_handle_frame_get(seq) - seq_content_start - 1;
}
- if (seq_content_end <= seq->startdisp) {
- diff = seq->startdisp - seq_content_end + 1;
+ if (seq_content_end <= SEQ_time_left_handle_frame_get(seq)) {
+ diff = SEQ_time_left_handle_frame_get(seq) - seq_content_end + 1;
}
*offset += diff;
}
@@ -687,7 +624,6 @@ static int sequencer_slip_exec(bContext *C, wmOperator *op)
Scene *scene = CTX_data_scene(C);
Editing *ed = SEQ_editing_get(scene);
int offset = RNA_int_get(op->ptr, "offset");
- bool success = false;
/* Recursively count the trimmed elements. */
int num_seq = slip_count_sequences_recursive(ed->seqbasep, true);
@@ -709,19 +645,16 @@ static int sequencer_slip_exec(bContext *C, wmOperator *op)
}
sequencer_slip_apply_limits(data, &offset);
- success = sequencer_slip_recursively(scene, data, offset);
+ sequencer_slip_recursively(scene, data, offset);
MEM_freeN(data->seq_array);
MEM_freeN(data->trim);
MEM_freeN(data->ts);
MEM_freeN(data);
- if (success) {
- WM_event_add_notifier(C, NC_SCENE | ND_SEQUENCER, scene);
- DEG_id_tag_update(&scene->id, ID_RECALC_SEQUENCER_STRIPS);
- return OPERATOR_FINISHED;
- }
- return OPERATOR_CANCELLED;
+ WM_event_add_notifier(C, NC_SCENE | ND_SEQUENCER, scene);
+ DEG_id_tag_update(&scene->id, ID_RECALC_SEQUENCER_STRIPS);
+ return OPERATOR_FINISHED;
}
static void sequencer_slip_update_header(Scene *scene, ScrArea *area, SlipData *data, int offset)
@@ -762,9 +695,8 @@ static int sequencer_slip_modal(bContext *C, wmOperator *op, const wmEvent *even
RNA_int_set(op->ptr, "offset", offset);
- if (sequencer_slip_recursively(scene, data, offset)) {
- WM_event_add_notifier(C, NC_SCENE | ND_SEQUENCER, scene);
- }
+ sequencer_slip_recursively(scene, data, offset);
+ WM_event_add_notifier(C, NC_SCENE | ND_SEQUENCER, scene);
return OPERATOR_RUNNING_MODAL;
}
@@ -795,9 +727,8 @@ static int sequencer_slip_modal(bContext *C, wmOperator *op, const wmEvent *even
RNA_int_set(op->ptr, "offset", offset);
- if (sequencer_slip_recursively(scene, data, offset)) {
- WM_event_add_notifier(C, NC_SCENE | ND_SEQUENCER, scene);
- }
+ sequencer_slip_recursively(scene, data, offset);
+ WM_event_add_notifier(C, NC_SCENE | ND_SEQUENCER, scene);
}
break;
}
@@ -827,8 +758,6 @@ static int sequencer_slip_modal(bContext *C, wmOperator *op, const wmEvent *even
for (int i = 0; i < data->num_seq; i++) {
Sequence *seq = data->seq_array[i];
SEQ_add_reload_new_file(bmain, scene, seq, false);
- ListBase *seqbase = SEQ_active_seqbase_get(SEQ_editing_get(scene));
- SEQ_time_update_sequence(scene, seqbase, seq);
}
MEM_freeN(data->seq_array);
@@ -875,9 +804,8 @@ static int sequencer_slip_modal(bContext *C, wmOperator *op, const wmEvent *even
RNA_int_set(op->ptr, "offset", offset);
- if (sequencer_slip_recursively(scene, data, offset)) {
- WM_event_add_notifier(C, NC_SCENE | ND_SEQUENCER, scene);
- }
+ sequencer_slip_recursively(scene, data, offset);
+ WM_event_add_notifier(C, NC_SCENE | ND_SEQUENCER, scene);
}
return OPERATOR_RUNNING_MODAL;
@@ -1325,7 +1253,6 @@ static int sequencer_reassign_inputs_exec(bContext *C, wmOperator *op)
last_seq->seq3 = seq3;
int old_start = last_seq->start;
- SEQ_time_update_recursive(scene, last_seq);
SEQ_relations_invalidate_cache_preprocessed(scene, last_seq);
SEQ_offset_animdata(scene, last_seq, (last_seq->start - old_start));
@@ -1483,13 +1410,15 @@ static int sequencer_split_exec(bContext *C, wmOperator *op)
if (ignore_selection) {
if (use_cursor_position) {
LISTBASE_FOREACH (Sequence *, seq, SEQ_active_seqbase_get(ed)) {
- if (seq->enddisp == split_frame && seq->machine == split_channel) {
+ if (SEQ_time_right_handle_frame_get(seq) == split_frame &&
+ seq->machine == split_channel) {
seq_selected = seq->flag & SEQ_ALLSEL;
}
}
if (!seq_selected) {
LISTBASE_FOREACH (Sequence *, seq, SEQ_active_seqbase_get(ed)) {
- if (seq->startdisp == split_frame && seq->machine == split_channel) {
+ if (SEQ_time_left_handle_frame_get(seq) == split_frame &&
+ seq->machine == split_channel) {
seq->flag &= ~SEQ_ALLSEL;
}
}
@@ -1500,20 +1429,18 @@ static int sequencer_split_exec(bContext *C, wmOperator *op)
if (split_side != SEQ_SIDE_BOTH) {
LISTBASE_FOREACH (Sequence *, seq, SEQ_active_seqbase_get(ed)) {
if (split_side == SEQ_SIDE_LEFT) {
- if (seq->startdisp >= split_frame) {
+ if (SEQ_time_left_handle_frame_get(seq) >= split_frame) {
seq->flag &= ~SEQ_ALLSEL;
}
}
else {
- if (seq->enddisp <= split_frame) {
+ if (SEQ_time_right_handle_frame_get(seq) <= split_frame) {
seq->flag &= ~SEQ_ALLSEL;
}
}
}
}
}
-
- SEQ_sort(SEQ_active_seqbase_get(ed));
}
if (changed) {
WM_event_add_notifier(C, NC_SCENE | ND_SEQUENCER, scene);
@@ -1719,11 +1646,26 @@ void SEQUENCER_OT_duplicate(wmOperatorType *ot)
/** \name Erase Strips Operator
* \{ */
-static int sequencer_delete_exec(bContext *C, wmOperator *UNUSED(op))
+static void sequencer_delete_strip_data(bContext *C, Sequence *seq)
+{
+ if (seq->type != SEQ_TYPE_SCENE) {
+ return;
+ }
+
+ Main *bmain = CTX_data_main(C);
+ if (seq->scene) {
+ if (ED_scene_delete(C, bmain, seq->scene)) {
+ WM_event_add_notifier(C, NC_SCENE | NA_REMOVED, seq->scene);
+ }
+ }
+}
+
+static int sequencer_delete_exec(bContext *C, wmOperator *op)
{
Main *bmain = CTX_data_main(C);
Scene *scene = CTX_data_scene(C);
ListBase *seqbasep = SEQ_active_seqbase_get(SEQ_editing_get(scene));
+ const bool delete_data = RNA_boolean_get(op->ptr, "delete_data");
if (sequencer_view_has_preview_poll(C) && !sequencer_view_preview_only_poll(C)) {
return OPERATOR_CANCELLED;
@@ -1736,6 +1678,9 @@ static int sequencer_delete_exec(bContext *C, wmOperator *UNUSED(op))
SEQ_ITERATOR_FOREACH (seq, selected_strips) {
SEQ_edit_flag_for_removal(scene, seqbasep, seq);
+ if (delete_data) {
+ sequencer_delete_strip_data(C, seq);
+ }
}
SEQ_edit_remove_flagged_sequences(scene, seqbasep);
@@ -1778,6 +1723,14 @@ void SEQUENCER_OT_delete(wmOperatorType *ot)
/* Flags. */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+
+ /* Properties. */
+ ot->prop = RNA_def_boolean(ot->srna,
+ "delete_data",
+ false,
+ "Delete Data",
+ "After removing the Strip, delete the associated data also");
+ RNA_def_property_flag(ot->prop, PROP_SKIP_SAVE);
}
/** \} */
@@ -1795,15 +1748,13 @@ static int sequencer_offset_clear_exec(bContext *C, wmOperator *UNUSED(op))
/* For effects, try to find a replacement input. */
for (seq = ed->seqbasep->first; seq; seq = seq->next) {
if ((seq->type & SEQ_TYPE_EFFECT) == 0 && (seq->flag & SELECT)) {
- seq->startofs = seq->endofs = seq->startstill = seq->endstill = 0;
+ seq->startofs = seq->endofs = 0;
}
}
/* Update lengths, etc. */
seq = ed->seqbasep->first;
while (seq) {
- ListBase *seqbase = SEQ_active_seqbase_get(ed);
- SEQ_time_update_sequence(scene, seqbase, seq);
SEQ_relations_invalidate_cache_preprocessed(scene, seq);
seq = seq->next;
}
@@ -1869,8 +1820,8 @@ static int sequencer_separate_images_exec(bContext *C, wmOperator *op)
/* TODO: remove f-curve and assign to split image strips.
* The old animation system would remove the user of `seq->ipo`. */
- start_ofs = timeline_frame = SEQ_transform_get_left_handle_frame(seq);
- frame_end = SEQ_transform_get_right_handle_frame(seq);
+ start_ofs = timeline_frame = SEQ_time_left_handle_frame_get(seq);
+ frame_end = SEQ_time_right_handle_frame_get(seq);
while (timeline_frame < frame_end) {
/* New seq. */
@@ -1881,7 +1832,7 @@ static int sequencer_separate_images_exec(bContext *C, wmOperator *op)
seq_new->start = start_ofs;
seq_new->type = SEQ_TYPE_IMAGE;
seq_new->len = 1;
- seq_new->endstill = step - 1;
+ seq_new->endofs = 1 - step;
/* New strip. */
strip_new = seq_new->strip;
@@ -1894,8 +1845,6 @@ static int sequencer_separate_images_exec(bContext *C, wmOperator *op)
BLI_strncpy(se_new->name, se->name, sizeof(se_new->name));
strip_new->stripdata = se_new;
- SEQ_time_update_sequence(scene, seqbase, seq_new);
-
if (step > 1) {
seq_new->flag &= ~SEQ_OVERLAP;
if (SEQ_transform_test_overlap(seqbase, seq_new)) {
@@ -1919,9 +1868,6 @@ 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);
return OPERATOR_FINISHED;
@@ -2031,8 +1977,8 @@ static int sequencer_meta_make_exec(bContext *C, wmOperator *op)
BLI_addtail(&seqm->seqbase, seq);
SEQ_relations_invalidate_cache_preprocessed(scene, seq);
channel_max = max_ii(seq->machine, channel_max);
- meta_start_frame = min_ii(seq->startdisp, meta_start_frame);
- meta_end_frame = max_ii(seq->enddisp, meta_end_frame);
+ meta_start_frame = min_ii(SEQ_time_left_handle_frame_get(seq), meta_start_frame);
+ meta_end_frame = max_ii(SEQ_time_right_handle_frame_get(seq), meta_end_frame);
}
}
@@ -2041,7 +1987,6 @@ static int sequencer_meta_make_exec(bContext *C, wmOperator *op)
SEQ_sequence_base_unique_name_recursive(scene, &ed->seqbase, seqm);
seqm->start = meta_start_frame;
seqm->len = meta_end_frame - meta_start_frame;
- SEQ_time_update_sequence(scene, active_seqbase, seqm);
SEQ_select_active_set(scene, seqm);
if (SEQ_transform_test_overlap(active_seqbase, seqm)) {
SEQ_transform_seqbase_shuffle(active_seqbase, seqm, scene);
@@ -2109,7 +2054,6 @@ static int sequencer_meta_separate_exec(bContext *C, wmOperator *UNUSED(op))
}
}
- SEQ_sort(active_seqbase);
DEG_id_tag_update(&scene->id, ID_RECALC_SEQUENCER_STRIPS);
WM_event_add_notifier(C, NC_SCENE | ND_SEQUENCER, scene);
@@ -2215,19 +2159,18 @@ static const EnumPropertyItem prop_side_lr_types[] = {
static void swap_sequence(Scene *scene, Sequence *seqa, Sequence *seqb)
{
- ListBase *seqbase = SEQ_active_seqbase_get(SEQ_editing_get(scene));
- int gap = seqb->startdisp - seqa->enddisp;
+ int gap = SEQ_time_left_handle_frame_get(seqb) - SEQ_time_right_handle_frame_get(seqa);
int seq_a_start;
int seq_b_start;
- seq_b_start = (seqb->start - seqb->startdisp) + seqa->startdisp;
+ seq_b_start = (seqb->start - SEQ_time_left_handle_frame_get(seqb)) +
+ SEQ_time_left_handle_frame_get(seqa);
SEQ_transform_translate_sequence(scene, seqb, seq_b_start - seqb->start);
- SEQ_time_update_sequence(scene, seqbase, seqb);
SEQ_relations_invalidate_cache_preprocessed(scene, seqb);
- seq_a_start = (seqa->start - seqa->startdisp) + seqb->enddisp + gap;
+ seq_a_start = (seqa->start - SEQ_time_left_handle_frame_get(seqa)) +
+ SEQ_time_right_handle_frame_get(seqb) + gap;
SEQ_transform_translate_sequence(scene, seqa, seq_a_start - seqa->start);
- SEQ_time_update_sequence(scene, seqbase, seqa);
SEQ_relations_invalidate_cache_preprocessed(scene, seqa);
}
@@ -2252,13 +2195,13 @@ static Sequence *find_next_prev_sequence(Scene *scene, Sequence *test, int lr, i
switch (lr) {
case SEQ_SIDE_LEFT:
- if (seq->enddisp <= test->startdisp) {
- dist = test->enddisp - seq->startdisp;
+ if (SEQ_time_right_handle_frame_get(seq) <= SEQ_time_left_handle_frame_get(test)) {
+ dist = SEQ_time_right_handle_frame_get(test) - SEQ_time_left_handle_frame_get(seq);
}
break;
case SEQ_SIDE_RIGHT:
- if (seq->startdisp >= test->enddisp) {
- dist = seq->startdisp - test->enddisp;
+ if (SEQ_time_left_handle_frame_get(seq) >= SEQ_time_right_handle_frame_get(test)) {
+ dist = SEQ_time_left_handle_frame_get(seq) - SEQ_time_right_handle_frame_get(test);
}
break;
}
@@ -2318,14 +2261,6 @@ static int sequencer_swap_exec(bContext *C, wmOperator *op)
break;
}
- /* XXX: Should be a generic function. */
- for (iseq = seqbase->first; iseq; iseq = iseq->next) {
- if ((iseq->type & SEQ_TYPE_EFFECT) &&
- (seq_is_parent(iseq, active_seq) || seq_is_parent(iseq, seq))) {
- SEQ_time_update_sequence(scene, seqbase, iseq);
- }
- }
-
/* Do this in a new loop since both effects need to be calculated first. */
for (iseq = seqbase->first; iseq; iseq = iseq->next) {
if ((iseq->type & SEQ_TYPE_EFFECT) &&
@@ -2337,10 +2272,7 @@ static int sequencer_swap_exec(bContext *C, wmOperator *op)
}
}
- SEQ_sort(SEQ_active_seqbase_get(ed));
-
WM_event_add_notifier(C, NC_SCENE | ND_SEQUENCER, scene);
-
return OPERATOR_FINISHED;
}
@@ -2457,6 +2389,13 @@ static void sequencer_copy_animation(Scene *scene, Sequence *seq)
return;
}
+ /* Add curves for strips inside meta strip. */
+ if (seq->type == SEQ_TYPE_META) {
+ LISTBASE_FOREACH (Sequence *, meta_child, &seq->seqbase) {
+ sequencer_copy_animation(scene, meta_child);
+ }
+ }
+
GSet *fcurves = SEQ_fcurves_by_strip_get(seq, &scene->adt->action->curves);
if (fcurves == NULL) {
return;
@@ -2466,6 +2405,7 @@ static void sequencer_copy_animation(Scene *scene, Sequence *seq)
BLI_addtail(&fcurves_clipboard, BKE_fcurve_copy(fcu));
}
GSET_FOREACH_END();
+
BLI_gset_free(fcurves, NULL);
}
@@ -2587,8 +2527,8 @@ static int sequencer_paste_exec(bContext *C, wmOperator *op)
else {
int min_seq_startdisp = INT_MAX;
LISTBASE_FOREACH (Sequence *, seq, &seqbase_clipboard) {
- if (seq->startdisp < min_seq_startdisp) {
- min_seq_startdisp = seq->startdisp;
+ if (SEQ_time_left_handle_frame_get(seq) < min_seq_startdisp) {
+ min_seq_startdisp = SEQ_time_left_handle_frame_get(seq);
}
}
/* Paste strips relative to the current-frame. */
@@ -2596,7 +2536,7 @@ static int sequencer_paste_exec(bContext *C, wmOperator *op)
}
/* Paste animation.
- * Note: Only fcurves are copied. Drivers and NLA action strips are not copied.
+ * 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.
@@ -2619,13 +2559,17 @@ static int sequencer_paste_exec(bContext *C, wmOperator *op)
* in the new list. */
BLI_movelisttolist(ed->seqbasep, &nseqbase);
+ /* Make sure, that pasted strips have unique names. This has to be done immediately after adding
+ * strips to seqbase, for lookup cache to work correctly. */
+ for (iseq = iseq_first; iseq; iseq = iseq->next) {
+ SEQ_ensure_unique_name(iseq, scene);
+ }
+
for (iseq = iseq_first; iseq; iseq = iseq->next) {
if (SEQ_clipboard_pasted_seq_was_active(iseq)) {
SEQ_select_active_set(scene, iseq);
}
- /* Make sure, that pasted strips have unique names. */
- SEQ_ensure_unique_name(iseq, scene);
/* Translate after name has been changed, otherwise this will affect animdata of original
* strip. */
SEQ_transform_translate_sequence(scene, iseq, ofs);
@@ -2703,10 +2647,6 @@ static int sequencer_swap_data_exec(bContext *C, wmOperator *op)
seq_act->scene_sound = NULL;
seq_other->scene_sound = NULL;
- ListBase *seqbase = SEQ_active_seqbase_get(SEQ_editing_get(scene));
- SEQ_time_update_sequence(scene, seqbase, seq_act);
- SEQ_time_update_sequence(scene, seqbase, seq_other);
-
if (seq_act->sound) {
BKE_sound_add_scene_sound_defaults(scene, seq_act);
}
@@ -2949,9 +2889,6 @@ static int sequencer_change_path_exec(bContext *C, wmOperator *op)
/* Correct start/end frames so we don't move.
* Important not to set seq->len = len; allow the function to handle it. */
SEQ_add_reload_new_file(bmain, scene, seq, true);
-
- ListBase *seqbase = SEQ_active_seqbase_get(SEQ_editing_get(scene));
- SEQ_time_update_sequence(scene, seqbase, seq);
}
else if (ELEM(seq->type, SEQ_TYPE_SOUND_RAM, SEQ_TYPE_SOUND_HD)) {
bSound *sound = seq->sound;
@@ -3040,6 +2977,81 @@ void SEQUENCER_OT_change_path(struct wmOperatorType *ot)
/** \} */
/* -------------------------------------------------------------------- */
+/** \name Change Strip Scene Operator
+ * \{ */
+
+static bool sequencer_strip_change_scene_poll(bContext *C)
+{
+ Editing *ed = SEQ_editing_get(CTX_data_scene(C));
+ if (ed == NULL) {
+ return false;
+ }
+ Sequence *seq = ed->act_seq;
+ return ((seq != NULL) && (seq->type == SEQ_TYPE_SCENE));
+}
+static int sequencer_change_scene_exec(bContext *C, wmOperator *op)
+{
+ Main *bmain = CTX_data_main(C);
+ Scene *scene = CTX_data_scene(C);
+ Scene *scene_seq = BLI_findlink(&bmain->scenes, RNA_enum_get(op->ptr, "scene"));
+
+ if (scene_seq == NULL) {
+ BKE_report(op->reports, RPT_ERROR, "Scene not found");
+ return OPERATOR_CANCELLED;
+ }
+
+ /* Assign new scene. */
+ Sequence *seq = SEQ_select_active_get(scene);
+ if (seq) {
+ seq->scene = scene_seq;
+ /* Do a refresh of the sequencer data. */
+ SEQ_relations_invalidate_cache_raw(scene, seq);
+ DEG_id_tag_update(&scene->id, ID_RECALC_AUDIO | ID_RECALC_SEQUENCER_STRIPS);
+ DEG_relations_tag_update(bmain);
+ }
+
+ WM_event_add_notifier(C, NC_SCENE | ND_SCENEBROWSE, scene);
+ WM_event_add_notifier(C, NC_SCENE | ND_SEQUENCER, scene);
+
+ return OPERATOR_FINISHED;
+}
+
+static int sequencer_change_scene_invoke(bContext *C, wmOperator *op, const wmEvent *event)
+{
+ if (!RNA_struct_property_is_set(op->ptr, "scene")) {
+ return WM_enum_search_invoke(C, op, event);
+ }
+
+ return sequencer_change_scene_exec(C, op);
+}
+
+void SEQUENCER_OT_change_scene(struct wmOperatorType *ot)
+{
+ PropertyRNA *prop;
+
+ /* Identifiers. */
+ ot->name = "Change Scene";
+ ot->idname = "SEQUENCER_OT_change_scene";
+ ot->description = "Change Scene assigned to Strip";
+
+ /* Api callbacks. */
+ ot->exec = sequencer_change_scene_exec;
+ ot->invoke = sequencer_change_scene_invoke;
+ ot->poll = sequencer_strip_change_scene_poll;
+
+ /* Flags. */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+
+ /* Properties. */
+ prop = RNA_def_enum(ot->srna, "scene", DummyRNA_NULL_items, 0, "Scene", "");
+ RNA_def_enum_funcs(prop, RNA_scene_without_active_itemf);
+ RNA_def_property_flag(prop, PROP_ENUM_NO_TRANSLATE);
+ ot->prop = prop;
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
/** \name Export Subtitles Operator
* \{ */
@@ -3049,8 +3061,8 @@ static int seq_cmp_time_startdisp_channel(const void *a, const void *b)
Sequence *seq_a = (Sequence *)a;
Sequence *seq_b = (Sequence *)b;
- int seq_a_start = SEQ_transform_get_left_handle_frame(seq_a);
- int seq_b_start = SEQ_transform_get_left_handle_frame(seq_b);
+ int seq_a_start = SEQ_time_left_handle_frame_get(seq_a);
+ int seq_b_start = SEQ_time_left_handle_frame_get(seq_b);
/* If strips have the same start frame favor the one with a higher channel. */
if (seq_a_start == seq_b_start) {
@@ -3096,7 +3108,7 @@ static bool seq_get_text_strip_cb(Sequence *seq, void *user_data)
ListBase *channels = SEQ_channels_displayed_get(ed);
/* Only text strips that are not muted and don't end with negative frame. */
if ((seq->type == SEQ_TYPE_TEXT) && !SEQ_render_is_muted(channels, seq) &&
- (seq->enddisp > cd->scene->r.sfra)) {
+ (SEQ_time_right_handle_frame_get(seq) > cd->scene->r.sfra)) {
BLI_addtail(cd->text_seq, MEM_dupallocN(seq));
}
return true;
@@ -3154,16 +3166,17 @@ static int sequencer_export_subtitles_exec(bContext *C, wmOperator *op)
char timecode_str_end[32];
/* Write time-code relative to start frame of scene. Don't allow negative time-codes. */
- BLI_timecode_string_from_time(timecode_str_start,
- sizeof(timecode_str_start),
- -2,
- FRA2TIME(max_ii(seq->startdisp - scene->r.sfra, 0)),
- FPS,
- USER_TIMECODE_SUBRIP);
+ BLI_timecode_string_from_time(
+ timecode_str_start,
+ sizeof(timecode_str_start),
+ -2,
+ FRA2TIME(max_ii(SEQ_time_left_handle_frame_get(seq) - scene->r.sfra, 0)),
+ FPS,
+ USER_TIMECODE_SUBRIP);
BLI_timecode_string_from_time(timecode_str_end,
sizeof(timecode_str_end),
-2,
- FRA2TIME(seq->enddisp - scene->r.sfra),
+ FRA2TIME(SEQ_time_right_handle_frame_get(seq) - scene->r.sfra),
FPS,
USER_TIMECODE_SUBRIP);
@@ -3231,8 +3244,8 @@ static int sequencer_set_range_to_strips_exec(bContext *C, wmOperator *op)
for (seq = ed->seqbasep->first; seq; seq = seq->next) {
if (seq->flag & SELECT) {
selected = true;
- sfra = min_ii(sfra, seq->startdisp);
- efra = max_ii(efra, seq->enddisp - 1);
+ sfra = min_ii(sfra, SEQ_time_left_handle_frame_get(seq));
+ efra = max_ii(efra, SEQ_time_right_handle_frame_get(seq) - 1);
}
}
diff --git a/source/blender/editors/space_sequencer/sequencer_intern.h b/source/blender/editors/space_sequencer/sequencer_intern.h
index 67df065ef35..3307c3fde2f 100644
--- a/source/blender/editors/space_sequencer/sequencer_intern.h
+++ b/source/blender/editors/space_sequencer/sequencer_intern.h
@@ -197,6 +197,7 @@ void SEQUENCER_OT_rendersize(struct wmOperatorType *ot);
void SEQUENCER_OT_change_effect_input(struct wmOperatorType *ot);
void SEQUENCER_OT_change_effect_type(struct wmOperatorType *ot);
void SEQUENCER_OT_change_path(struct wmOperatorType *ot);
+void SEQUENCER_OT_change_scene(struct wmOperatorType *ot);
void SEQUENCER_OT_copy(struct wmOperatorType *ot);
void SEQUENCER_OT_paste(struct wmOperatorType *ot);
@@ -231,6 +232,7 @@ void SEQUENCER_OT_select_grouped(struct wmOperatorType *ot);
/* sequencer_add.c */
void SEQUENCER_OT_scene_strip_add(struct wmOperatorType *ot);
+void SEQUENCER_OT_scene_strip_add_new(struct wmOperatorType *ot);
void SEQUENCER_OT_movie_strip_add(struct wmOperatorType *ot);
void SEQUENCER_OT_movieclip_strip_add(struct wmOperatorType *ot);
void SEQUENCER_OT_mask_strip_add(struct wmOperatorType *ot);
diff --git a/source/blender/editors/space_sequencer/sequencer_ops.c b/source/blender/editors/space_sequencer/sequencer_ops.c
index 1aa2991f07a..f7a9bcf41e6 100644
--- a/source/blender/editors/space_sequencer/sequencer_ops.c
+++ b/source/blender/editors/space_sequencer/sequencer_ops.c
@@ -58,6 +58,7 @@ void sequencer_operatortypes(void)
WM_operatortype_append(SEQUENCER_OT_change_effect_input);
WM_operatortype_append(SEQUENCER_OT_change_effect_type);
WM_operatortype_append(SEQUENCER_OT_change_path);
+ WM_operatortype_append(SEQUENCER_OT_change_scene);
WM_operatortype_append(SEQUENCER_OT_set_range_to_strips);
WM_operatortype_append(SEQUENCER_OT_strip_transform_clear);
@@ -81,6 +82,7 @@ void sequencer_operatortypes(void)
/* sequencer_add.c */
WM_operatortype_append(SEQUENCER_OT_scene_strip_add);
+ WM_operatortype_append(SEQUENCER_OT_scene_strip_add_new);
WM_operatortype_append(SEQUENCER_OT_movieclip_strip_add);
WM_operatortype_append(SEQUENCER_OT_mask_strip_add);
WM_operatortype_append(SEQUENCER_OT_movie_strip_add);
diff --git a/source/blender/editors/space_sequencer/sequencer_select.c b/source/blender/editors/space_sequencer/sequencer_select.c
index 95707f83d85..f237fbc0a12 100644
--- a/source/blender/editors/space_sequencer/sequencer_select.c
+++ b/source/blender/editors/space_sequencer/sequencer_select.c
@@ -116,13 +116,13 @@ static void select_active_side(ListBase *seqbase, int sel_side, int channel, int
if (channel == seq->machine) {
switch (sel_side) {
case SEQ_SIDE_LEFT:
- if (frame > (seq->startdisp)) {
+ if (frame > (SEQ_time_left_handle_frame_get(seq))) {
seq->flag &= ~(SEQ_RIGHTSEL | SEQ_LEFTSEL);
seq->flag |= SELECT;
}
break;
case SEQ_SIDE_RIGHT:
- if (frame < (seq->startdisp)) {
+ if (frame < (SEQ_time_left_handle_frame_get(seq))) {
seq->flag &= ~(SEQ_RIGHTSEL | SEQ_LEFTSEL);
seq->flag |= SELECT;
}
@@ -152,13 +152,13 @@ static void select_active_side_range(ListBase *seqbase,
}
switch (sel_side) {
case SEQ_SIDE_LEFT:
- if (frame > (seq->startdisp)) {
+ if (frame > (SEQ_time_left_handle_frame_get(seq))) {
seq->flag &= ~(SEQ_RIGHTSEL | SEQ_LEFTSEL);
seq->flag |= SELECT;
}
break;
case SEQ_SIDE_RIGHT:
- if (frame < (seq->startdisp)) {
+ if (frame < (SEQ_time_left_handle_frame_get(seq))) {
seq->flag &= ~(SEQ_RIGHTSEL | SEQ_LEFTSEL);
seq->flag |= SELECT;
}
@@ -179,8 +179,8 @@ static void select_linked_time(ListBase *seqbase, Sequence *seq_link)
for (seq = seqbase->first; seq; seq = seq->next) {
if (seq_link->machine != seq->machine) {
- int left_match = (seq->startdisp == seq_link->startdisp) ? 1 : 0;
- int right_match = (seq->enddisp == seq_link->enddisp) ? 1 : 0;
+ int left_match = (SEQ_time_left_handle_frame_get(seq) == seq_link->startdisp) ? 1 : 0;
+ int right_match = (SEQ_time_right_handle_frame_get(seq) == seq_link->enddisp) ? 1 : 0;
if (left_match && right_match) {
/* Direct match, copy the selection settings. */
@@ -247,8 +247,8 @@ void ED_sequencer_select_sequence_single(Scene *scene, Sequence *seq, bool desel
void seq_rectf(Sequence *seq, rctf *rect)
{
- rect->xmin = seq->startdisp;
- rect->xmax = seq->enddisp;
+ rect->xmin = SEQ_time_left_handle_frame_get(seq);
+ rect->xmax = SEQ_time_right_handle_frame_get(seq);
rect->ymin = seq->machine + SEQ_STRIP_OFSBOTTOM;
rect->ymax = seq->machine + SEQ_STRIP_OFSTOP;
}
@@ -273,12 +273,12 @@ Sequence *find_neighboring_sequence(Scene *scene, Sequence *test, int lr, int se
(sel == 0 && (seq->flag & SELECT) == 0))) {
switch (lr) {
case SEQ_SIDE_LEFT:
- if (test->startdisp == (seq->enddisp)) {
+ if (SEQ_time_left_handle_frame_get(test) == (SEQ_time_right_handle_frame_get(seq))) {
return seq;
}
break;
case SEQ_SIDE_RIGHT:
- if (test->enddisp == (seq->startdisp)) {
+ if (SEQ_time_right_handle_frame_get(test) == (SEQ_time_left_handle_frame_get(seq))) {
return seq;
}
break;
@@ -311,13 +311,18 @@ Sequence *find_nearest_seq(Scene *scene, View2D *v2d, int *hand, const int mval[
while (seq) {
if (seq->machine == (int)y) {
/* Check for both normal strips, and strips that have been flipped horizontally. */
- if (((seq->startdisp < seq->enddisp) && (seq->startdisp <= x && seq->enddisp >= x)) ||
- ((seq->startdisp > seq->enddisp) && (seq->startdisp >= x && seq->enddisp <= x))) {
+ if (((SEQ_time_left_handle_frame_get(seq) < SEQ_time_right_handle_frame_get(seq)) &&
+ (SEQ_time_left_handle_frame_get(seq) <= x &&
+ SEQ_time_right_handle_frame_get(seq) >= x)) ||
+ ((SEQ_time_left_handle_frame_get(seq) > SEQ_time_right_handle_frame_get(seq)) &&
+ (SEQ_time_left_handle_frame_get(seq) >= x &&
+ SEQ_time_right_handle_frame_get(seq) <= x))) {
if (SEQ_transform_sequence_can_be_translated(seq)) {
/* Clamp handles to defined size in pixel space. */
handsize = 2.0f * sequence_handle_size_get_clamped(seq, pixelx);
- displen = (float)abs(seq->startdisp - seq->enddisp);
+ displen = (float)abs(SEQ_time_left_handle_frame_get(seq) -
+ SEQ_time_right_handle_frame_get(seq));
/* Don't even try to grab the handles of small strips. */
if (displen / pixelx > 16) {
@@ -332,10 +337,10 @@ Sequence *find_nearest_seq(Scene *scene, View2D *v2d, int *hand, const int mval[
CLAMP(handsize, 7 * pixelx, 30 * pixelx);
}
- if (handsize + seq->startdisp >= x) {
+ if (handsize + SEQ_time_left_handle_frame_get(seq) >= x) {
*hand = SEQ_SIDE_LEFT;
}
- else if (-handsize + seq->enddisp <= x) {
+ else if (-handsize + SEQ_time_right_handle_frame_get(seq) <= x) {
*hand = SEQ_SIDE_RIGHT;
}
}
@@ -578,8 +583,8 @@ static void sequencer_select_side_of_frame(const bContext *C,
const float x = UI_view2d_region_to_view_x(v2d, mval[0]);
LISTBASE_FOREACH (Sequence *, seq_iter, SEQ_active_seqbase_get(ed)) {
- if (((x < CFRA) && (seq_iter->enddisp <= CFRA)) ||
- ((x >= CFRA) && (seq_iter->startdisp >= CFRA))) {
+ if (((x < CFRA) && (SEQ_time_right_handle_frame_get(seq_iter) <= CFRA)) ||
+ ((x >= CFRA) && (SEQ_time_left_handle_frame_get(seq_iter) >= CFRA))) {
/* Select left or right. */
seq_iter->flag |= SELECT;
recurs_sel_seq(seq_iter);
@@ -634,7 +639,8 @@ static void sequencer_select_linked_handle(const bContext *C,
case SEQ_SIDE_LEFT:
if ((seq->flag & SEQ_LEFTSEL) && (neighbor->flag & SEQ_RIGHTSEL)) {
seq->flag |= SELECT;
- select_active_side(ed->seqbasep, SEQ_SIDE_LEFT, seq->machine, seq->startdisp);
+ select_active_side(
+ ed->seqbasep, SEQ_SIDE_LEFT, seq->machine, SEQ_time_left_handle_frame_get(seq));
}
else {
seq->flag |= SELECT;
@@ -647,7 +653,8 @@ static void sequencer_select_linked_handle(const bContext *C,
case SEQ_SIDE_RIGHT:
if ((seq->flag & SEQ_RIGHTSEL) && (neighbor->flag & SEQ_LEFTSEL)) {
seq->flag |= SELECT;
- select_active_side(ed->seqbasep, SEQ_SIDE_RIGHT, seq->machine, seq->startdisp);
+ select_active_side(
+ ed->seqbasep, SEQ_SIDE_RIGHT, seq->machine, SEQ_time_left_handle_frame_get(seq));
}
else {
seq->flag |= SELECT;
@@ -661,7 +668,8 @@ static void sequencer_select_linked_handle(const bContext *C,
}
else {
- select_active_side(ed->seqbasep, sel_side, seq->machine, seq->startdisp);
+ select_active_side(
+ ed->seqbasep, sel_side, seq->machine, SEQ_time_left_handle_frame_get(seq));
}
}
}
@@ -996,6 +1004,7 @@ void SEQUENCER_OT_select(wmOperatorType *ot)
ot->invoke = sequencer_select_invoke;
ot->modal = WM_generic_select_modal;
ot->poll = ED_operator_sequencer_active;
+ ot->get_name = ED_select_pick_get_name;
/* Flags. */
ot->flag = OPTYPE_UNDO;
@@ -1427,10 +1436,10 @@ static int sequencer_select_side_of_frame_exec(bContext *C, wmOperator *op)
bool test = false;
switch (side) {
case -1:
- test = (timeline_frame >= seq->enddisp);
+ test = (timeline_frame >= SEQ_time_right_handle_frame_get(seq));
break;
case 1:
- test = (timeline_frame <= seq->startdisp);
+ test = (timeline_frame <= SEQ_time_left_handle_frame_get(seq));
break;
case 2:
test = SEQ_time_strip_intersects_frame(seq, timeline_frame);
@@ -1504,10 +1513,10 @@ static int sequencer_select_side_exec(bContext *C, wmOperator *op)
if (seq->flag & SELECT) {
selected = true;
if (sel_side == SEQ_SIDE_LEFT) {
- *frame_limit_p = max_ii(*frame_limit_p, seq->startdisp);
+ *frame_limit_p = max_ii(*frame_limit_p, SEQ_time_left_handle_frame_get(seq));
}
else {
- *frame_limit_p = min_ii(*frame_limit_p, seq->startdisp);
+ *frame_limit_p = min_ii(*frame_limit_p, SEQ_time_left_handle_frame_get(seq));
}
}
}
@@ -1647,7 +1656,7 @@ static int sequencer_box_select_exec(bContext *C, wmOperator *op)
float handsize = sequence_handle_size_get_clamped(seq, pixelx);
/* Right handle. */
- if (rectf.xmax > (seq->enddisp - handsize)) {
+ if (rectf.xmax > (SEQ_time_right_handle_frame_get(seq) - handsize)) {
if (select) {
seq->flag |= SELECT | SEQ_RIGHTSEL;
}
@@ -1660,7 +1669,7 @@ static int sequencer_box_select_exec(bContext *C, wmOperator *op)
}
}
/* Left handle. */
- if (rectf.xmin < (seq->startdisp + handsize)) {
+ if (rectf.xmin < (SEQ_time_left_handle_frame_get(seq) + handsize)) {
if (select) {
seq->flag |= SELECT | SEQ_LEFTSEL;
}
@@ -1952,7 +1961,8 @@ static bool select_grouped_time_overlap(SeqCollection *strips,
Sequence *seq;
SEQ_ITERATOR_FOREACH (seq, strips) {
- if (seq->startdisp < actseq->enddisp && seq->enddisp > actseq->startdisp) {
+ if (SEQ_time_left_handle_frame_get(seq) < SEQ_time_right_handle_frame_get(actseq) &&
+ SEQ_time_right_handle_frame_get(seq) > SEQ_time_left_handle_frame_get(actseq)) {
seq->flag |= SELECT;
changed = true;
}
@@ -1970,8 +1980,10 @@ static void query_lower_channel_strips(Sequence *seq_reference,
if (seq_test->machine > seq_reference->machine) {
continue; /* Not lower channel. */
}
- if (seq_test->enddisp <= seq_reference->startdisp ||
- seq_test->startdisp >= seq_reference->enddisp) {
+ if (SEQ_time_right_handle_frame_get(seq_test) <=
+ SEQ_time_left_handle_frame_get(seq_reference) ||
+ SEQ_time_left_handle_frame_get(seq_test) >=
+ SEQ_time_right_handle_frame_get(seq_reference)) {
continue; /* Not intersecting in time. */
}
SEQ_collection_append_strip(seq_test, collection);
diff --git a/source/blender/editors/space_sequencer/sequencer_thumbnails.c b/source/blender/editors/space_sequencer/sequencer_thumbnails.c
index 43c5e004040..984d3b1f374 100644
--- a/source/blender/editors/space_sequencer/sequencer_thumbnails.c
+++ b/source/blender/editors/space_sequencer/sequencer_thumbnails.c
@@ -23,6 +23,7 @@
#include "SEQ_relations.h"
#include "SEQ_render.h"
#include "SEQ_sequencer.h"
+#include "SEQ_time.h"
#include "WM_api.h"
#include "WM_types.h"
@@ -73,10 +74,10 @@ static bool check_seq_need_thumbnails(Sequence *seq, rctf *view_area)
if (!ELEM(seq->type, SEQ_TYPE_MOVIE, SEQ_TYPE_IMAGE)) {
return false;
}
- if (min_ii(seq->startdisp, seq->start) > view_area->xmax) {
+ if (min_ii(SEQ_time_left_handle_frame_get(seq), seq->start) > view_area->xmax) {
return false;
}
- if (max_ii(seq->enddisp, seq->start + seq->len) < view_area->xmin) {
+ if (max_ii(SEQ_time_right_handle_frame_get(seq), seq->start + seq->len) < view_area->xmin) {
return false;
}
if (seq->machine + 1.0f < view_area->ymin) {
@@ -205,7 +206,7 @@ static GHash *sequencer_thumbnail_ghash_init(const bContext *C, View2D *v2d, Edi
else {
if (val_need_update != NULL) {
val_need_update->seq_dupli->start = seq->start;
- val_need_update->seq_dupli->startdisp = seq->startdisp;
+ val_need_update->seq_dupli->startdisp = SEQ_time_left_handle_frame_get(seq);
}
}
}
@@ -362,15 +363,16 @@ static int sequencer_thumbnail_closest_previous_frame_get(int timeline_frame,
static int sequencer_thumbnail_closest_guaranteed_frame_get(Sequence *seq, int timeline_frame)
{
- if (timeline_frame <= seq->startdisp) {
- return seq->startdisp;
+ if (timeline_frame <= SEQ_time_left_handle_frame_get(seq)) {
+ return SEQ_time_left_handle_frame_get(seq);
}
/* Set of "guaranteed" thumbnails. */
- const int frame_index = timeline_frame - seq->startdisp;
+ const int frame_index = timeline_frame - SEQ_time_left_handle_frame_get(seq);
const int frame_step = SEQ_render_thumbnails_guaranteed_set_frame_step_get(seq);
const int relative_base_frame = round_fl_to_int((frame_index / (float)frame_step)) * frame_step;
- const int nearest_guaranted_absolute_frame = relative_base_frame + seq->startdisp;
+ const int nearest_guaranted_absolute_frame = relative_base_frame +
+ SEQ_time_left_handle_frame_get(seq);
return nearest_guaranted_absolute_frame;
}
@@ -443,9 +445,11 @@ void draw_seq_strip_thumbnail(View2D *v2d,
float thumb_y_end = y1 + thumb_height;
float cut_off = 0;
- float upper_thumb_bound = (seq->endstill) ? (seq->start + seq->len) : seq->enddisp;
+ float upper_thumb_bound = SEQ_time_has_right_still_frames(seq) ?
+ (seq->start + seq->len) :
+ SEQ_time_right_handle_frame_get(seq);
if (seq->type == SEQ_TYPE_IMAGE) {
- upper_thumb_bound = seq->enddisp;
+ upper_thumb_bound = SEQ_time_right_handle_frame_get(seq);
}
float timeline_frame = SEQ_render_thumbnail_first_frame_get(seq, thumb_width, &v2d->cur);
@@ -471,8 +475,8 @@ void draw_seq_strip_thumbnail(View2D *v2d,
}
/* Set the clipping bound to show the left handle moving over thumbs and not shift thumbs. */
- if (IN_RANGE_INCL(seq->startdisp, timeline_frame, thumb_x_end)) {
- cut_off = seq->startdisp - timeline_frame;
+ if (IN_RANGE_INCL(SEQ_time_left_handle_frame_get(seq), timeline_frame, thumb_x_end)) {
+ cut_off = SEQ_time_left_handle_frame_get(seq) - timeline_frame;
clipped = true;
}
diff --git a/source/blender/editors/space_sequencer/sequencer_view.c b/source/blender/editors/space_sequencer/sequencer_view.c
index b3dbc3c72d1..857ca6d989b 100644
--- a/source/blender/editors/space_sequencer/sequencer_view.c
+++ b/source/blender/editors/space_sequencer/sequencer_view.c
@@ -20,8 +20,6 @@
#include "UI_view2d.h"
-#include "RNA_define.h"
-
#include "SEQ_iterator.h"
#include "SEQ_select.h"
#include "SEQ_sequencer.h"
@@ -308,8 +306,8 @@ static void seq_view_collection_rect_timeline(Scene *scene, SeqCollection *strip
int xmargin = FPS;
SEQ_ITERATOR_FOREACH (seq, strips) {
- xmin = min_ii(xmin, seq->startdisp);
- xmax = max_ii(xmax, seq->enddisp);
+ xmin = min_ii(xmin, SEQ_time_left_handle_frame_get(seq));
+ xmax = max_ii(xmax, SEQ_time_right_handle_frame_get(seq));
ymin = min_ii(ymin, seq->machine);
ymax = max_ii(ymax, seq->machine);
diff --git a/source/blender/editors/space_spreadsheet/space_spreadsheet.cc b/source/blender/editors/space_spreadsheet/space_spreadsheet.cc
index b3d6c395e89..dd3aac1eae9 100644
--- a/source/blender/editors/space_spreadsheet/space_spreadsheet.cc
+++ b/source/blender/editors/space_spreadsheet/space_spreadsheet.cc
@@ -32,8 +32,6 @@
#include "BLF_api.h"
-#include "spreadsheet_intern.hh"
-
#include "spreadsheet_context.hh"
#include "spreadsheet_data_source_geometry.hh"
#include "spreadsheet_dataset_draw.hh"
@@ -304,6 +302,7 @@ static float get_default_column_width(const ColumnValues &values)
switch (values.type()) {
case SPREADSHEET_VALUE_TYPE_BOOL:
return 2.0f;
+ case SPREADSHEET_VALUE_TYPE_INT8:
case SPREADSHEET_VALUE_TYPE_INT32:
return float_width;
case SPREADSHEET_VALUE_TYPE_FLOAT:
diff --git a/source/blender/editors/space_spreadsheet/spreadsheet_column.cc b/source/blender/editors/space_spreadsheet/spreadsheet_column.cc
index a29aa1fd026..46e98acb8e8 100644
--- a/source/blender/editors/space_spreadsheet/spreadsheet_column.cc
+++ b/source/blender/editors/space_spreadsheet/spreadsheet_column.cc
@@ -23,6 +23,9 @@ eSpreadsheetColumnValueType cpp_type_to_column_type(const CPPType &type)
if (type.is<bool>()) {
return SPREADSHEET_VALUE_TYPE_BOOL;
}
+ if (type.is<int8_t>()) {
+ return SPREADSHEET_VALUE_TYPE_INT8;
+ }
if (type.is<int>()) {
return SPREADSHEET_VALUE_TYPE_INT32;
}
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 4afa70d9ef6..f5315b616d0 100644
--- a/source/blender/editors/space_spreadsheet/spreadsheet_data_source_geometry.cc
+++ b/source/blender/editors/space_spreadsheet/spreadsheet_data_source_geometry.cc
@@ -64,7 +64,7 @@ std::unique_ptr<ColumnValues> ExtraColumns::get_column_values(
void GeometryDataSource::foreach_default_column_ids(
FunctionRef<void(const SpreadsheetColumnID &, bool is_extra)> fn) const
{
- if (component_->attribute_domain_size(domain_) == 0) {
+ if (component_->attribute_domain_num(domain_) == 0) {
return;
}
@@ -81,6 +81,9 @@ void GeometryDataSource::foreach_default_column_ids(
if (attribute_id.is_anonymous()) {
return true;
}
+ if (!bke::allow_procedural_attribute_access(attribute_id.name())) {
+ return true;
+ }
SpreadsheetColumnID column_id;
column_id.name = (char *)attribute_id.name().data();
fn(column_id, false);
@@ -110,8 +113,8 @@ void GeometryDataSource::foreach_default_column_ids(
std::unique_ptr<ColumnValues> GeometryDataSource::get_column_values(
const SpreadsheetColumnID &column_id) const
{
- const int domain_size = component_->attribute_domain_size(domain_);
- if (domain_size == 0) {
+ const int domain_num = component_->attribute_domain_num(domain_);
+ if (domain_num == 0) {
return {};
}
@@ -129,7 +132,7 @@ std::unique_ptr<ColumnValues> GeometryDataSource::get_column_values(
Span<InstanceReference> references = instances.references();
return std::make_unique<ColumnValues>(
column_id.name,
- VArray<InstanceReference>::ForFunc(domain_size,
+ VArray<InstanceReference>::ForFunc(domain_num,
[reference_handles, references](int64_t index) {
return references[reference_handles[index]];
}));
@@ -137,13 +140,13 @@ std::unique_ptr<ColumnValues> GeometryDataSource::get_column_values(
Span<float4x4> transforms = instances.instance_transforms();
if (STREQ(column_id.name, "Rotation")) {
return std::make_unique<ColumnValues>(
- column_id.name, VArray<float3>::ForFunc(domain_size, [transforms](int64_t index) {
+ column_id.name, VArray<float3>::ForFunc(domain_num, [transforms](int64_t index) {
return transforms[index].to_euler();
}));
}
if (STREQ(column_id.name, "Scale")) {
return std::make_unique<ColumnValues>(
- column_id.name, VArray<float3>::ForFunc(domain_size, [transforms](int64_t index) {
+ column_id.name, VArray<float3>::ForFunc(domain_num, [transforms](int64_t index) {
return transforms[index].scale();
}));
}
@@ -210,7 +213,7 @@ std::unique_ptr<ColumnValues> GeometryDataSource::get_column_values(
int GeometryDataSource::tot_rows() const
{
- return component_->attribute_domain_size(domain_);
+ return component_->attribute_domain_num(domain_);
}
/**
@@ -256,7 +259,7 @@ IndexMask GeometryDataSource::apply_selection_filter(Vector<int64_t> &indices) c
BMesh *bm = mesh_orig->edit_mesh->bm;
BM_mesh_elem_table_ensure(bm, BM_VERT);
- int *orig_indices = (int *)CustomData_get_layer(&mesh_eval->vdata, CD_ORIGINDEX);
+ const int *orig_indices = (int *)CustomData_get_layer(&mesh_eval->vdata, CD_ORIGINDEX);
if (orig_indices != nullptr) {
/* Use CD_ORIGINDEX layer if it exists. */
VArray<bool> selection = mesh_component->attribute_try_adapt_domain<bool>(
@@ -509,7 +512,7 @@ class GeometryComponentCacheValue : public SpreadsheetCache::Value {
public:
/* Stores the result of fields evaluated on a geometry component. Without this, fields would have
* to be reevaluated on every redraw. */
- Map<std::pair<AttributeDomain, GField>, GArray<>> arrays;
+ Map<std::pair<eAttrDomain, GField>, GArray<>> arrays;
};
static void add_fields_as_extra_columns(SpaceSpreadsheet *sspreadsheet,
@@ -523,18 +526,18 @@ static void add_fields_as_extra_columns(SpaceSpreadsheet *sspreadsheet,
sspreadsheet->runtime->cache.lookup_or_add<GeometryComponentCacheValue>(
std::make_unique<GeometryComponentCacheKey>(component));
- const AttributeDomain domain = (AttributeDomain)sspreadsheet->attribute_domain;
- const int domain_size = component.attribute_domain_size(domain);
+ const eAttrDomain domain = (eAttrDomain)sspreadsheet->attribute_domain;
+ const int domain_num = component.attribute_domain_num(domain);
for (const auto item : fields_to_show.items()) {
StringRef name = item.key;
const GField &field = item.value;
/* Use the cached evaluated array if it exists, otherwise evaluate the field now. */
GArray<> &evaluated_array = cache.arrays.lookup_or_add_cb({domain, field}, [&]() {
- GArray<> evaluated_array(field.cpp_type(), domain_size);
+ GArray<> evaluated_array(field.cpp_type(), domain_num);
bke::GeometryComponentFieldContext field_context{component, domain};
- fn::FieldEvaluator field_evaluator{field_context, domain_size};
+ fn::FieldEvaluator field_evaluator{field_context, domain_num};
field_evaluator.add_with_destination(field, evaluated_array);
field_evaluator.evaluate();
return evaluated_array;
@@ -547,7 +550,7 @@ static void add_fields_as_extra_columns(SpaceSpreadsheet *sspreadsheet,
std::unique_ptr<DataSource> data_source_from_geometry(const bContext *C, Object *object_eval)
{
SpaceSpreadsheet *sspreadsheet = CTX_wm_space_spreadsheet(C);
- const AttributeDomain domain = (AttributeDomain)sspreadsheet->attribute_domain;
+ const eAttrDomain domain = (eAttrDomain)sspreadsheet->attribute_domain;
const GeometryComponentType component_type = get_display_component_type(C, object_eval);
GeometrySet geometry_set = spreadsheet_get_display_geometry_set(sspreadsheet, object_eval);
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 8b281e5a558..04b4f6d8d06 100644
--- a/source/blender/editors/space_spreadsheet/spreadsheet_data_source_geometry.hh
+++ b/source/blender/editors/space_spreadsheet/spreadsheet_data_source_geometry.hh
@@ -40,7 +40,7 @@ class GeometryDataSource : public DataSource {
Object *object_eval_;
const GeometrySet geometry_set_;
const GeometryComponent *component_;
- AttributeDomain domain_;
+ eAttrDomain domain_;
ExtraColumns extra_columns_;
/* Some data is computed on the fly only when it is requested. Computing it does not change the
@@ -53,7 +53,7 @@ class GeometryDataSource : public DataSource {
GeometryDataSource(Object *object_eval,
GeometrySet geometry_set,
const GeometryComponentType component_type,
- const AttributeDomain domain,
+ const eAttrDomain domain,
ExtraColumns extra_columns)
: object_eval_(object_eval),
geometry_set_(std::move(geometry_set)),
diff --git a/source/blender/editors/space_spreadsheet/spreadsheet_dataset_draw.cc b/source/blender/editors/space_spreadsheet/spreadsheet_dataset_draw.cc
index c4b5228758c..ee22f4173ab 100644
--- a/source/blender/editors/space_spreadsheet/spreadsheet_dataset_draw.cc
+++ b/source/blender/editors/space_spreadsheet/spreadsheet_dataset_draw.cc
@@ -27,7 +27,7 @@ class GeometryDataSetTreeView;
class GeometryDataSetTreeViewItem : public ui::AbstractTreeViewItem {
GeometryComponentType component_type_;
- std::optional<AttributeDomain> domain_;
+ std::optional<eAttrDomain> domain_;
BIFIconID icon_;
public:
@@ -35,7 +35,7 @@ class GeometryDataSetTreeViewItem : public ui::AbstractTreeViewItem {
StringRef label,
BIFIconID icon);
GeometryDataSetTreeViewItem(GeometryComponentType component_type,
- AttributeDomain domain,
+ eAttrDomain domain,
StringRef label,
BIFIconID icon);
@@ -113,7 +113,7 @@ GeometryDataSetTreeViewItem::GeometryDataSetTreeViewItem(GeometryComponentType c
this->set_collapsed(false);
}
GeometryDataSetTreeViewItem::GeometryDataSetTreeViewItem(GeometryComponentType component_type,
- AttributeDomain domain,
+ eAttrDomain domain,
StringRef label,
BIFIconID icon)
: component_type_(component_type), domain_(domain), icon_(icon)
@@ -144,7 +144,7 @@ void GeometryDataSetTreeViewItem::build_row(uiLayout &row)
/* Using the tree row button instead of a separate right aligned button gives padding
* to the right side of the number, which it didn't have with the button. */
char element_count[7];
- BLI_str_format_attribute_domain_size(element_count, *count);
+ BLI_str_format_decimal_unit(element_count, *count);
UI_but_hint_drawstr_set((uiBut *)this->tree_row_button(), element_count);
}
}
@@ -194,7 +194,7 @@ std::optional<int> GeometryDataSetTreeViewItem::count() const
}
if (const GeometryComponent *component = geometry.get_component_for_read(component_type_)) {
- return component->attribute_domain_size(*domain_);
+ return component->attribute_domain_num(*domain_);
}
return 0;
diff --git a/source/blender/editors/space_spreadsheet/spreadsheet_ops.cc b/source/blender/editors/space_spreadsheet/spreadsheet_ops.cc
index 4d6dc3b4166..166c5de9fc3 100644
--- a/source/blender/editors/space_spreadsheet/spreadsheet_ops.cc
+++ b/source/blender/editors/space_spreadsheet/spreadsheet_ops.cc
@@ -5,12 +5,6 @@
#include "ED_screen.h"
-#include "RNA_access.h"
-#include "RNA_define.h"
-
-#include "WM_api.h"
-#include "WM_types.h"
-
#include "BLI_listbase.h"
#include "MEM_guardedalloc.h"
@@ -20,8 +14,6 @@
#include "RNA_access.h"
#include "RNA_define.h"
-#include "ED_screen.h"
-
#include "WM_api.h"
#include "WM_types.h"
@@ -92,7 +84,7 @@ static int select_component_domain_invoke(bContext *C,
{
GeometryComponentType component_type = static_cast<GeometryComponentType>(
RNA_int_get(op->ptr, "component_type"));
- AttributeDomain attribute_domain = static_cast<AttributeDomain>(
+ eAttrDomain attribute_domain = static_cast<eAttrDomain>(
RNA_int_get(op->ptr, "attribute_domain_type"));
SpaceSpreadsheet *sspreadsheet = CTX_wm_space_spreadsheet(C);
diff --git a/source/blender/editors/space_spreadsheet/spreadsheet_row_filter.cc b/source/blender/editors/space_spreadsheet/spreadsheet_row_filter.cc
index eb8f111baa0..e1ff4b59b14 100644
--- a/source/blender/editors/space_spreadsheet/spreadsheet_row_filter.cc
+++ b/source/blender/editors/space_spreadsheet/spreadsheet_row_filter.cc
@@ -14,8 +14,6 @@
#include "RNA_access.h"
-#include "spreadsheet_intern.hh"
-
#include "spreadsheet_data_source_geometry.hh"
#include "spreadsheet_intern.hh"
#include "spreadsheet_layout.hh"
@@ -73,6 +71,35 @@ static void apply_row_filter(const SpreadsheetRowFilter &row_filter,
}
}
}
+ else if (column_data.type().is<int8_t>()) {
+ const int value = row_filter.value_int;
+ switch (row_filter.operation) {
+ case SPREADSHEET_ROW_FILTER_EQUAL: {
+ apply_filter_operation(
+ column_data.typed<int8_t>(),
+ [&](const int cell) { return cell == value; },
+ prev_mask,
+ new_indices);
+ break;
+ }
+ case SPREADSHEET_ROW_FILTER_GREATER: {
+ apply_filter_operation(
+ column_data.typed<int8_t>(),
+ [value](const int cell) { return cell > value; },
+ prev_mask,
+ new_indices);
+ break;
+ }
+ case SPREADSHEET_ROW_FILTER_LESS: {
+ apply_filter_operation(
+ column_data.typed<int8_t>(),
+ [&](const int cell) { return cell < value; },
+ prev_mask,
+ new_indices);
+ break;
+ }
+ }
+ }
else if (column_data.type().is<int>()) {
const int value = row_filter.value_int;
switch (row_filter.operation) {
@@ -190,33 +217,29 @@ static void apply_row_filter(const SpreadsheetRowFilter &row_filter,
}
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();
+
+ 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;
- },
- prev_mask,
- new_indices);
- break;
- }
- }
+ }
+ case InstanceReference::Type::None: {
+ return false;
+ }
+ }
+ BLI_assert_unreachable();
+ return false;
+ },
+ prev_mask,
+ new_indices);
}
}
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 7c1ac024c12..d42a371c666 100644
--- a/source/blender/editors/space_spreadsheet/spreadsheet_row_filter_ui.cc
+++ b/source/blender/editors/space_spreadsheet/spreadsheet_row_filter_ui.cc
@@ -63,6 +63,7 @@ static std::string value_string(const SpreadsheetRowFilter &row_filter,
const eSpreadsheetColumnValueType data_type)
{
switch (data_type) {
+ case SPREADSHEET_VALUE_TYPE_INT8:
case SPREADSHEET_VALUE_TYPE_INT32:
return std::to_string(row_filter.value_int);
case SPREADSHEET_VALUE_TYPE_FLOAT: {
@@ -200,6 +201,10 @@ static void spreadsheet_filter_panel_draw(const bContext *C, Panel *panel)
}
switch (static_cast<eSpreadsheetColumnValueType>(column->data_type)) {
+ case SPREADSHEET_VALUE_TYPE_INT8:
+ uiItemR(layout, filter_ptr, "operation", 0, nullptr, ICON_NONE);
+ uiItemR(layout, filter_ptr, "value_int8", 0, IFACE_("Value"), ICON_NONE);
+ break;
case SPREADSHEET_VALUE_TYPE_INT32:
uiItemR(layout, filter_ptr, "operation", 0, nullptr, ICON_NONE);
uiItemR(layout, filter_ptr, "value_int", 0, IFACE_("Value"), ICON_NONE);
diff --git a/source/blender/editors/space_text/text_draw.c b/source/blender/editors/space_text/text_draw.c
index 36eafedbc80..c93ffccd477 100644
--- a/source/blender/editors/space_text/text_draw.c
+++ b/source/blender/editors/space_text/text_draw.c
@@ -1603,7 +1603,7 @@ void draw_text_main(SpaceText *st, ARegion *region)
return;
}
- /* dpi controlled line height and font size */
+ /* DPI controlled line height and font size. */
st->runtime.lheight_px = (U.widget_unit * st->lheight) / 20;
/* don't draw lines below this */
diff --git a/source/blender/editors/space_view3d/drawobject.c b/source/blender/editors/space_view3d/drawobject.c
index 7776119a594..8add6886584 100644
--- a/source/blender/editors/space_view3d/drawobject.c
+++ b/source/blender/editors/space_view3d/drawobject.c
@@ -6,12 +6,14 @@
*/
#include "DNA_mesh_types.h"
+#include "DNA_meshdata_types.h"
#include "DNA_object_types.h"
#include "DNA_scene_types.h"
-#include "BLI_math.h"
+#include "BLI_math_vector.h"
#include "BKE_DerivedMesh.h"
+#include "BKE_customdata.h"
#include "BKE_editmesh.h"
#include "BKE_global.h"
#include "BKE_object.h"
diff --git a/source/blender/editors/space_view3d/space_view3d.c b/source/blender/editors/space_view3d/space_view3d.c
index a02058fde6b..9ed2fec96db 100644
--- a/source/blender/editors/space_view3d/space_view3d.c
+++ b/source/blender/editors/space_view3d/space_view3d.c
@@ -590,16 +590,15 @@ static bool view3d_mat_drop_poll(bContext *C, wmDrag *drag, const wmEvent *event
static char *view3d_mat_drop_tooltip(bContext *C,
wmDrag *drag,
const int xy[2],
- struct wmDropBox *drop)
+ wmDropBox *UNUSED(drop))
{
const char *name = WM_drag_get_item_name(drag);
ARegion *region = CTX_wm_region(C);
- RNA_string_set(drop->ptr, "name", name);
- int mval[2] = {
+ const int mval[2] = {
xy[0] - region->winrct.xmin,
xy[1] - region->winrct.ymin,
};
- return ED_object_ot_drop_named_material_tooltip(C, drop->ptr, mval);
+ return ED_object_ot_drop_named_material_tooltip(C, name, mval);
}
static bool view3d_world_drop_poll(bContext *C, wmDrag *drag, const wmEvent *event)
@@ -716,7 +715,7 @@ static void view3d_ob_drop_copy_local_id(bContext *UNUSED(C), wmDrag *drag, wmDr
{
ID *id = WM_drag_get_local_ID(drag, ID_OB);
- RNA_string_set(drop->ptr, "name", id->name + 2);
+ RNA_int_set(drop->ptr, "session_uuid", id->session_uuid);
/* Don't duplicate ID's which were just imported. Only do that for existing, local IDs. */
BLI_assert(drag->type != WM_DRAG_ASSET);
@@ -751,7 +750,7 @@ static void view3d_ob_drop_copy_external_asset(bContext *UNUSED(C), wmDrag *drag
DEG_relations_tag_update(CTX_data_main(C));
WM_event_add_notifier(C, NC_SCENE | ND_LAYER_CONTENT, scene);
- RNA_string_set(drop->ptr, "name", id->name + 2);
+ RNA_int_set(drop->ptr, "session_uuid", id->session_uuid);
Base *base = BKE_view_layer_base_find(view_layer, (Object *)id);
if (base != NULL) {
@@ -823,15 +822,15 @@ static void view3d_id_drop_copy(bContext *UNUSED(C), wmDrag *drag, wmDropBox *dr
{
ID *id = WM_drag_get_local_ID_or_import_from_asset(drag, 0);
- RNA_string_set(drop->ptr, "name", id->name + 2);
+ WM_operator_properties_id_lookup_set_from_id(drop->ptr, id);
}
static void view3d_id_drop_copy_with_type(bContext *UNUSED(C), wmDrag *drag, wmDropBox *drop)
{
ID *id = WM_drag_get_local_ID_or_import_from_asset(drag, 0);
- RNA_string_set(drop->ptr, "name", id->name + 2);
RNA_enum_set(drop->ptr, "type", GS(id->name));
+ WM_operator_properties_id_lookup_set_from_id(drop->ptr, id);
}
static void view3d_id_path_drop_copy(bContext *UNUSED(C), wmDrag *drag, wmDropBox *drop)
@@ -839,7 +838,7 @@ static void view3d_id_path_drop_copy(bContext *UNUSED(C), wmDrag *drag, wmDropBo
ID *id = WM_drag_get_local_ID_or_import_from_asset(drag, 0);
if (id) {
- RNA_string_set(drop->ptr, "name", id->name + 2);
+ WM_operator_properties_id_lookup_set_from_id(drop->ptr, id);
RNA_struct_property_unset(drop->ptr, "filepath");
}
else if (drag->path[0]) {
diff --git a/source/blender/editors/space_view3d/view3d_cursor_snap.c b/source/blender/editors/space_view3d/view3d_cursor_snap.c
index 96a193cc10d..395df42b2cb 100644
--- a/source/blender/editors/space_view3d/view3d_cursor_snap.c
+++ b/source/blender/editors/space_view3d/view3d_cursor_snap.c
@@ -8,11 +8,9 @@
*/
#include "DNA_object_types.h"
-#include "DNA_scene_types.h"
#include "BLI_listbase.h"
#include "BLI_rect.h"
-#include "DNA_scene_types.h"
#include "MEM_guardedalloc.h"
@@ -54,7 +52,7 @@ typedef struct SnapCursorDataIntern {
struct SnapObjectContext *snap_context_v3d;
const Scene *scene;
- short snap_elem_hidden;
+ eSnapMode snap_elem_hidden;
float prevpoint_stack[3];
@@ -374,7 +372,7 @@ void ED_view3d_cursor_snap_draw_util(RegionView3D *rv3d,
const float normal[3],
const uchar color_line[4],
const uchar color_point[4],
- const short snap_elem_type)
+ const eSnapMode snap_elem_type)
{
if (!loc_prev && !loc_curr) {
return;
@@ -539,9 +537,9 @@ static bool v3d_cursor_is_snap_invert(SnapCursorDataIntern *data_intern, const w
/** \name Update
* \{ */
-static short v3d_cursor_snap_elements(V3DSnapCursorState *snap_state, Scene *scene)
+static eSnapMode v3d_cursor_snap_elements(V3DSnapCursorState *snap_state, Scene *scene)
{
- short snap_elements = snap_state->snap_elem_force;
+ eSnapMode snap_elements = snap_state->snap_elem_force;
if (!snap_elements) {
return scene->toolsettings->snap_mode;
}
@@ -587,7 +585,7 @@ static void v3d_cursor_snap_update(V3DSnapCursorState *state,
v3d_cursor_snap_context_ensure(scene);
float co[3], no[3], face_nor[3], obmat[4][4], omat[3][3];
- short snap_elem = 0;
+ eSnapMode snap_elem = SCE_SNAP_MODE_NONE;
int snap_elem_index[3] = {-1, -1, -1};
int index = -1;
@@ -596,8 +594,8 @@ static void v3d_cursor_snap_update(V3DSnapCursorState *state,
zero_v3(face_nor);
unit_m3(omat);
- ushort snap_elements = v3d_cursor_snap_elements(state, scene);
- data_intern->snap_elem_hidden = 0;
+ eSnapMode snap_elements = v3d_cursor_snap_elements(state, scene);
+ data_intern->snap_elem_hidden = SCE_SNAP_MODE_NONE;
const bool calc_plane_omat = v3d_cursor_snap_calc_plane();
if (calc_plane_omat && !(snap_elements & SCE_SNAP_MODE_FACE)) {
data_intern->snap_elem_hidden = SCE_SNAP_MODE_FACE;
@@ -613,7 +611,7 @@ static void v3d_cursor_snap_update(V3DSnapCursorState *state,
if (snap_data->is_snap_invert != !(ts->snap_flag & SCE_SNAP)) {
snap_data->is_enabled = false;
if (!calc_plane_omat) {
- snap_data->snap_elem = 0;
+ snap_data->snap_elem = SCE_SNAP_MODE_NONE;
return;
}
snap_elements = data_intern->snap_elem_hidden = SCE_SNAP_MODE_FACE;
@@ -621,8 +619,7 @@ static void v3d_cursor_snap_update(V3DSnapCursorState *state,
}
#endif
- if (snap_elements & (SCE_SNAP_MODE_VERTEX | SCE_SNAP_MODE_EDGE | SCE_SNAP_MODE_FACE |
- SCE_SNAP_MODE_EDGE_MIDPOINT | SCE_SNAP_MODE_EDGE_PERPENDICULAR)) {
+ if (snap_elements & SCE_SNAP_MODE_GEOM) {
float prev_co[3] = {0.0f};
if (state->prevpoint) {
copy_v3_v3(prev_co, state->prevpoint);
@@ -648,7 +645,7 @@ static void v3d_cursor_snap_update(V3DSnapCursorState *state,
v3d,
snap_elements,
&(const struct SnapObjectParams){
- .snap_select = SNAP_ALL,
+ .snap_target_select = SCE_SNAP_TARGET_ALL,
.edit_mode_type = edit_mode_type,
.use_occlusion_test = use_occlusion_test,
},
@@ -669,7 +666,8 @@ static void v3d_cursor_snap_update(V3DSnapCursorState *state,
if (calc_plane_omat) {
RegionView3D *rv3d = region->regiondata;
- bool orient_surface = snap_elem && (state->plane_orient == V3D_PLACE_ORIENT_SURFACE);
+ bool orient_surface = (snap_elem != SCE_SNAP_MODE_NONE) &&
+ (state->plane_orient == V3D_PLACE_ORIENT_SURFACE);
if (orient_surface) {
copy_m3_m4(omat, obmat);
}
@@ -700,7 +698,7 @@ static void v3d_cursor_snap_update(V3DSnapCursorState *state,
}
}
- float *co_depth = snap_elem ? co : scene->cursor.location;
+ float *co_depth = (snap_elem != SCE_SNAP_MODE_NONE) ? co : scene->cursor.location;
snap_elem &= ~data_intern->snap_elem_hidden;
if (snap_elem == 0) {
RegionView3D *rv3d = region->regiondata;
@@ -816,7 +814,7 @@ static void v3d_cursor_snap_draw_fn(bContext *C, int x, int y, void *UNUSED(cust
}
const bool draw_plane = state->draw_plane || state->draw_box;
- if (!snap_data->snap_elem && !draw_plane) {
+ if (snap_data->snap_elem == SCE_SNAP_MODE_NONE && !draw_plane) {
return;
}
@@ -834,7 +832,7 @@ static void v3d_cursor_snap_draw_fn(bContext *C, int x, int y, void *UNUSED(cust
v3d_cursor_plane_draw(rv3d, state->plane_axis, matrix);
}
- if (snap_data->snap_elem && (state->draw_point || state->draw_box)) {
+ if (snap_data->snap_elem != SCE_SNAP_MODE_NONE && (state->draw_point || state->draw_box)) {
const float *prev_point = (snap_data->snap_elem & SCE_SNAP_MODE_EDGE_PERPENDICULAR) ?
state->prevpoint :
NULL;
diff --git a/source/blender/editors/space_view3d/view3d_draw.c b/source/blender/editors/space_view3d/view3d_draw.c
index 5b068750d76..b9e4c19295d 100644
--- a/source/blender/editors/space_view3d/view3d_draw.c
+++ b/source/blender/editors/space_view3d/view3d_draw.c
@@ -1786,11 +1786,13 @@ void ED_view3d_draw_offscreen_simple(Depsgraph *depsgraph,
}
/* Disable other overlays (set all available _HIDE_ flags). */
v3d.overlay.flag |= V3D_OVERLAY_HIDE_CURSOR | V3D_OVERLAY_HIDE_TEXT |
- V3D_OVERLAY_HIDE_MOTION_PATHS | V3D_OVERLAY_HIDE_BONES |
- V3D_OVERLAY_HIDE_OBJECT_ORIGINS;
+ V3D_OVERLAY_HIDE_MOTION_PATHS | V3D_OVERLAY_HIDE_OBJECT_ORIGINS;
if ((draw_flags & V3D_OFSDRAW_SHOW_OBJECT_EXTRAS) == 0) {
v3d.overlay.flag |= V3D_OVERLAY_HIDE_OBJECT_XTRAS;
}
+ if ((object_type_exclude_viewport_override & (1 << OB_ARMATURE)) != 0) {
+ v3d.overlay.flag |= V3D_OVERLAY_HIDE_BONES;
+ }
v3d.flag |= V3D_HIDE_HELPLINES;
}
diff --git a/source/blender/editors/space_view3d/view3d_edit.c b/source/blender/editors/space_view3d/view3d_edit.c
index e52ff062302..5fbdbef676c 100644
--- a/source/blender/editors/space_view3d/view3d_edit.c
+++ b/source/blender/editors/space_view3d/view3d_edit.c
@@ -608,7 +608,7 @@ void VIEW3D_OT_background_image_add(wmOperatorType *ot)
ot->flag = OPTYPE_UNDO;
/* properties */
- RNA_def_string(ot->srna, "name", "Image", MAX_ID_NAME - 2, "Name", "Image name to assign");
+ WM_operator_properties_id_lookup(ot, true);
WM_operator_properties_filesel(ot,
FILE_TYPE_FOLDER | FILE_TYPE_IMAGE | FILE_TYPE_MOVIE,
FILE_SPECIAL,
@@ -631,13 +631,20 @@ static int background_image_remove_exec(bContext *C, wmOperator *op)
CameraBGImage *bgpic_rem = BLI_findlink(&cam->bg_images, index);
if (bgpic_rem) {
- if (bgpic_rem->source == CAM_BGIMG_SOURCE_IMAGE) {
- id_us_min((ID *)bgpic_rem->ima);
- }
- else if (bgpic_rem->source == CAM_BGIMG_SOURCE_MOVIE) {
- id_us_min((ID *)bgpic_rem->clip);
+ if (ID_IS_OVERRIDE_LIBRARY(cam) &&
+ (bgpic_rem->flag & CAM_BGIMG_FLAG_OVERRIDE_LIBRARY_LOCAL) == 0) {
+ BKE_reportf(op->reports,
+ RPT_WARNING,
+ "Cannot remove background image %d from camera '%s', as it is from the linked "
+ "reference data",
+ index,
+ cam->id.name + 2);
+ return OPERATOR_CANCELLED;
}
+ id_us_min((ID *)bgpic_rem->ima);
+ id_us_min((ID *)bgpic_rem->clip);
+
BKE_camera_background_image_remove(cam, bgpic_rem);
WM_event_add_notifier(C, NC_CAMERA | ND_DRAW_RENDER_VIEWPORT, cam);
@@ -657,7 +664,7 @@ void VIEW3D_OT_background_image_remove(wmOperatorType *ot)
/* api callbacks */
ot->exec = background_image_remove_exec;
- ot->poll = ED_operator_camera;
+ ot->poll = ED_operator_camera_poll;
/* flags */
ot->flag = 0;
@@ -678,10 +685,8 @@ static int drop_world_exec(bContext *C, wmOperator *op)
Main *bmain = CTX_data_main(C);
Scene *scene = CTX_data_scene(C);
- char name[MAX_ID_NAME - 2];
-
- RNA_string_get(op->ptr, "name", name);
- World *world = (World *)BKE_libblock_find_name(bmain, ID_WO, name);
+ World *world = (World *)WM_operator_properties_id_lookup_from_name_or_session_uuid(
+ bmain, op->ptr, ID_WO);
if (world == NULL) {
return OPERATOR_CANCELLED;
}
@@ -718,7 +723,7 @@ void VIEW3D_OT_drop_world(wmOperatorType *ot)
ot->flag = OPTYPE_UNDO | OPTYPE_INTERNAL;
/* properties */
- RNA_def_string(ot->srna, "name", "World", MAX_ID_NAME - 2, "Name", "World to assign");
+ WM_operator_properties_id_lookup(ot, true);
}
/** \} */
@@ -905,7 +910,7 @@ void ED_view3d_cursor3d_position_rotation(bContext *C,
v3d,
SCE_SNAP_MODE_FACE,
&(const struct SnapObjectParams){
- .snap_select = SNAP_ALL,
+ .snap_target_select = SCE_SNAP_TARGET_ALL,
.edit_mode_type = SNAP_GEOM_FINAL,
.use_occlusion_test = true,
},
diff --git a/source/blender/editors/space_view3d/view3d_gizmo_ruler.c b/source/blender/editors/space_view3d/view3d_gizmo_ruler.c
index 567022cc9d1..9aae30c4a7e 100644
--- a/source/blender/editors/space_view3d/view3d_gizmo_ruler.c
+++ b/source/blender/editors/space_view3d/view3d_gizmo_ruler.c
@@ -359,7 +359,7 @@ static bool view3d_ruler_item_mousemove(const bContext *C,
v3d,
SCE_SNAP_MODE_FACE,
&(const struct SnapObjectParams){
- .snap_select = SNAP_ALL,
+ .snap_target_select = SCE_SNAP_TARGET_ALL,
.edit_mode_type = SNAP_GEOM_CAGE,
},
mval_fl,
@@ -374,7 +374,7 @@ static bool view3d_ruler_item_mousemove(const bContext *C,
depsgraph,
v3d,
&(const struct SnapObjectParams){
- .snap_select = SNAP_ALL,
+ .snap_target_select = SCE_SNAP_TARGET_ALL,
.edit_mode_type = SNAP_GEOM_CAGE,
},
ray_start,
@@ -1228,11 +1228,7 @@ static void WIDGETGROUP_ruler_setup(const bContext *C, wmGizmoGroup *gzgroup)
gzt_snap = WM_gizmotype_find("GIZMO_GT_snap_3d", true);
gizmo = WM_gizmo_new_ptr(gzt_snap, gzgroup, NULL);
- RNA_enum_set(gizmo->ptr,
- "snap_elements_force",
- (SCE_SNAP_MODE_VERTEX | SCE_SNAP_MODE_EDGE | SCE_SNAP_MODE_FACE |
- /* SCE_SNAP_MODE_VOLUME | SCE_SNAP_MODE_GRID | SCE_SNAP_MODE_INCREMENT | */
- SCE_SNAP_MODE_EDGE_PERPENDICULAR | SCE_SNAP_MODE_EDGE_MIDPOINT));
+ RNA_enum_set(gizmo->ptr, "snap_elements_force", SCE_SNAP_MODE_GEOM);
ED_gizmotypes_snap_3d_flag_set(gizmo, V3D_SNAPCURSOR_SNAP_EDIT_GEOM_CAGE);
WM_gizmo_set_color(gizmo, (float[4]){1.0f, 1.0f, 1.0f, 1.0f});
diff --git a/source/blender/editors/space_view3d/view3d_gizmo_tool_generic.c b/source/blender/editors/space_view3d/view3d_gizmo_tool_generic.c
index f0557205e8f..aa287403e23 100644
--- a/source/blender/editors/space_view3d/view3d_gizmo_tool_generic.c
+++ b/source/blender/editors/space_view3d/view3d_gizmo_tool_generic.c
@@ -19,8 +19,6 @@
#include "MEM_guardedalloc.h"
-#include "WM_toolsystem.h"
-
#include "RNA_access.h"
#include "RNA_define.h"
diff --git a/source/blender/editors/space_view3d/view3d_navigate_roll.c b/source/blender/editors/space_view3d/view3d_navigate_roll.c
index ea21eed6445..087ca72211e 100644
--- a/source/blender/editors/space_view3d/view3d_navigate_roll.c
+++ b/source/blender/editors/space_view3d/view3d_navigate_roll.c
@@ -48,11 +48,7 @@ static void view_roll_angle(ARegion *region,
normalize_qt(quat);
if (use_axis_view && RV3D_VIEW_IS_AXIS(rv3d->view) && (fabsf(angle) == (float)M_PI_2)) {
- if (ED_view3d_quat_to_axis_view(quat, 0.01f, &rv3d->view, &rv3d->view_axis_roll)) {
- if (rv3d->view != RV3D_VIEW_USER) {
- ED_view3d_quat_from_axis_view(rv3d->view, rv3d->view_axis_roll, quat_mul);
- }
- }
+ ED_view3d_quat_to_axis_view_and_reset_quat(quat, 0.01f, &rv3d->view, &rv3d->view_axis_roll);
}
else {
rv3d->view = RV3D_VIEW_USER;
diff --git a/source/blender/editors/space_view3d/view3d_navigate_rotate.c b/source/blender/editors/space_view3d/view3d_navigate_rotate.c
index c9ef6422982..989fa152acc 100644
--- a/source/blender/editors/space_view3d/view3d_navigate_rotate.c
+++ b/source/blender/editors/space_view3d/view3d_navigate_rotate.c
@@ -162,10 +162,8 @@ static void viewrotate_apply_snap(ViewOpsData *vod)
if (found) {
/* lock 'quat_best' to an axis view if we can */
- ED_view3d_quat_to_axis_view(quat_best, 0.01f, &rv3d->view, &rv3d->view_axis_roll);
- if (rv3d->view != RV3D_VIEW_USER) {
- ED_view3d_quat_from_axis_view(rv3d->view, rv3d->view_axis_roll, quat_best);
- }
+ ED_view3d_quat_to_axis_view_and_reset_quat(
+ quat_best, 0.01f, &rv3d->view, &rv3d->view_axis_roll);
}
else {
copy_qt_qt(quat_best, viewquat_align);
diff --git a/source/blender/editors/space_view3d/view3d_navigate_walk.c b/source/blender/editors/space_view3d/view3d_navigate_walk.c
index 19e064438fc..c4eff01375b 100644
--- a/source/blender/editors/space_view3d/view3d_navigate_walk.c
+++ b/source/blender/editors/space_view3d/view3d_navigate_walk.c
@@ -412,7 +412,7 @@ static bool walk_floor_distance_get(RegionView3D *rv3d,
walk->depsgraph,
walk->v3d,
&(const struct SnapObjectParams){
- .snap_select = SNAP_ALL,
+ .snap_target_select = SCE_SNAP_TARGET_ALL,
/* Avoid having to convert the edit-mesh to a regular mesh. */
.edit_mode_type = SNAP_GEOM_EDIT,
},
@@ -454,7 +454,7 @@ static bool walk_ray_cast(RegionView3D *rv3d,
walk->depsgraph,
walk->v3d,
&(const struct SnapObjectParams){
- .snap_select = SNAP_ALL,
+ .snap_target_select = SCE_SNAP_TARGET_ALL,
},
ray_start,
ray_normal,
diff --git a/source/blender/editors/space_view3d/view3d_placement.c b/source/blender/editors/space_view3d/view3d_placement.c
index eefc085bdf8..d3b82476d09 100644
--- a/source/blender/editors/space_view3d/view3d_placement.c
+++ b/source/blender/editors/space_view3d/view3d_placement.c
@@ -695,7 +695,7 @@ static bool view3d_interactive_add_calc_snap(bContext *UNUSED(C),
if (r_is_snap_invert) {
*r_is_snap_invert = snap_data->is_snap_invert;
}
- return snap_data->snap_elem != 0;
+ return snap_data->snap_elem != SCE_SNAP_MODE_NONE;
}
/** \} */
@@ -1303,7 +1303,7 @@ static int idp_rna_snap_target_get_fn(struct PointerRNA *UNUSED(ptr),
struct PropertyRNA *UNUSED(prop))
{
V3DSnapCursorState *snap_state = ED_view3d_cursor_snap_state_get();
- if (!snap_state->snap_elem_force) {
+ if (snap_state->snap_elem_force == SCE_SNAP_MODE_NONE) {
return PLACE_SNAP_TO_DEFAULT;
}
@@ -1316,7 +1316,7 @@ static void idp_rna_snap_target_set_fn(struct PointerRNA *UNUSED(ptr),
struct PropertyRNA *UNUSED(prop),
int value)
{
- short snap_mode = 0; /* #toolsettings->snap_mode. */
+ eSnapMode snap_mode = SCE_SNAP_MODE_NONE; /* #toolsettings->snap_mode. */
const enum ePlace_SnapTo snap_to = value;
if (snap_to == PLACE_SNAP_TO_GEOMETRY) {
snap_mode = SCE_SNAP_MODE_GEOM;
diff --git a/source/blender/editors/space_view3d/view3d_project.c b/source/blender/editors/space_view3d/view3d_project.c
index 85d239507ce..1230515a180 100644
--- a/source/blender/editors/space_view3d/view3d_project.c
+++ b/source/blender/editors/space_view3d/view3d_project.c
@@ -30,7 +30,7 @@
void ED_view3d_project_float_v2_m4(const ARegion *region,
const float co[3],
float r_co[2],
- float mat[4][4])
+ const float mat[4][4])
{
float vec4[4];
@@ -52,7 +52,7 @@ void ED_view3d_project_float_v2_m4(const ARegion *region,
void ED_view3d_project_float_v3_m4(const ARegion *region,
const float co[3],
float r_co[3],
- float mat[4][4])
+ const float mat[4][4])
{
float vec4[4];
@@ -312,7 +312,7 @@ float ED_view3d_calc_depth_for_comparison(const RegionView3D *rv3d, const float
return -dot_v3v3(rv3d->viewinv[2], co);
}
-static void view3d_win_to_ray_segment(struct Depsgraph *depsgraph,
+static void view3d_win_to_ray_segment(const struct Depsgraph *depsgraph,
const ARegion *region,
const View3D *v3d,
const float mval[2],
@@ -642,9 +642,9 @@ void ED_view3d_win_to_vector(const ARegion *region, const float mval[2], float r
normalize_v3(r_out);
}
-bool ED_view3d_win_to_segment_clipped(struct Depsgraph *depsgraph,
+bool ED_view3d_win_to_segment_clipped(const struct Depsgraph *depsgraph,
const ARegion *region,
- View3D *v3d,
+ const View3D *v3d,
const float mval[2],
float r_ray_start[3],
float r_ray_end[3],
diff --git a/source/blender/editors/space_view3d/view3d_select.c b/source/blender/editors/space_view3d/view3d_select.c
index 7a022441876..8eff9ee472f 100644
--- a/source/blender/editors/space_view3d/view3d_select.c
+++ b/source/blender/editors/space_view3d/view3d_select.c
@@ -57,8 +57,6 @@
#include "BKE_tracking.h"
#include "BKE_workspace.h"
-#include "DEG_depsgraph.h"
-
#include "WM_api.h"
#include "WM_toolsystem.h"
#include "WM_types.h"
@@ -1647,7 +1645,7 @@ static int bone_select_menu_exec(bContext *C, wmOperator *op)
const int name_index = RNA_enum_get(op->ptr, "name");
const struct SelectPick_Params params = {
- .sel_op = ED_select_op_from_operator(op),
+ .sel_op = ED_select_op_from_operator(op->ptr),
};
View3D *v3d = CTX_wm_view3d(C);
@@ -2876,8 +2874,9 @@ static int view3d_select_exec(bContext *C, wmOperator *op)
Object *obact = CTX_data_active_object(C);
struct SelectPick_Params params = {0};
- ED_select_pick_params_from_operator(op, &params);
+ ED_select_pick_params_from_operator(op->ptr, &params);
+ const bool vert_without_handles = RNA_boolean_get(op->ptr, "vert_without_handles");
bool center = RNA_boolean_get(op->ptr, "center");
bool enumerate = RNA_boolean_get(op->ptr, "enumerate");
/* Only force object select for edit-mode to support vertex parenting,
@@ -2932,7 +2931,8 @@ static int view3d_select_exec(bContext *C, wmOperator *op)
changed = ED_lattice_select_pick(C, mval, &params);
}
else if (ELEM(obedit->type, OB_CURVES_LEGACY, OB_SURF)) {
- changed = ED_curve_editnurb_select_pick(C, mval, ED_view3d_select_dist_px(), &params);
+ changed = ED_curve_editnurb_select_pick(
+ C, mval, ED_view3d_select_dist_px(), vert_without_handles, &params);
}
else if (obedit->type == OB_MBALL) {
changed = ED_mball_select_pick(C, mval, &params);
@@ -2988,6 +2988,7 @@ void VIEW3D_OT_select(wmOperatorType *ot)
ot->invoke = view3d_select_invoke;
ot->exec = view3d_select_exec;
ot->poll = ED_operator_view3d_active;
+ ot->get_name = ED_select_pick_get_name;
/* flags */
ot->flag = OPTYPE_UNDO;
@@ -3008,6 +3009,15 @@ void VIEW3D_OT_select(wmOperatorType *ot)
prop = RNA_def_boolean(ot->srna, "object", 0, "Object", "Use object selection (edit mode only)");
RNA_def_property_flag(prop, PROP_SKIP_SAVE);
+ /* Needed for select-through to usefully drag handles, see: T98254.
+ * NOTE: this option may be removed and become default behavior, see design task: T98552. */
+ prop = RNA_def_boolean(ot->srna,
+ "vert_without_handles",
+ 0,
+ "Control Point Without Handles",
+ "Only select the curve control point, not it's handles");
+ RNA_def_property_flag(prop, PROP_SKIP_SAVE);
+
prop = RNA_def_int_vector(ot->srna,
"location",
2,
@@ -4740,6 +4750,7 @@ void VIEW3D_OT_select_circle(wmOperatorType *ot)
ot->exec = view3d_circle_select_exec;
ot->poll = view3d_selectable_data;
ot->cancel = view3d_circle_select_cancel;
+ ot->get_name = ED_select_circle_get_name;
/* flags */
ot->flag = OPTYPE_UNDO;
diff --git a/source/blender/editors/space_view3d/view3d_utils.c b/source/blender/editors/space_view3d/view3d_utils.c
index e6895c0f4a3..306394ce53d 100644
--- a/source/blender/editors/space_view3d/view3d_utils.c
+++ b/source/blender/editors/space_view3d/view3d_utils.c
@@ -106,7 +106,7 @@ void ED_view3d_dist_range_get(const View3D *v3d, float r_dist_range[2])
r_dist_range[1] = v3d->clip_end * 10.0f;
}
-bool ED_view3d_clip_range_get(Depsgraph *depsgraph,
+bool ED_view3d_clip_range_get(const Depsgraph *depsgraph,
const View3D *v3d,
const RegionView3D *rv3d,
float *r_clipsta,
@@ -1317,22 +1317,59 @@ bool ED_view3d_quat_to_axis_view(const float quat[4],
*r_view = RV3D_VIEW_USER;
*r_view_axis_roll = RV3D_VIEW_AXIS_ROLL_0;
- /* quat values are all unit length */
- for (int view = RV3D_VIEW_FRONT; view <= RV3D_VIEW_BOTTOM; view++) {
- for (int view_axis_roll = RV3D_VIEW_AXIS_ROLL_0; view_axis_roll <= RV3D_VIEW_AXIS_ROLL_270;
- view_axis_roll++) {
- if (fabsf(angle_signed_qtqt(
- quat, view3d_quat_axis[view - RV3D_VIEW_FRONT][view_axis_roll])) < epsilon) {
- *r_view = view;
- *r_view_axis_roll = view_axis_roll;
- return true;
+ /* Quaternion values are all unit length. */
+
+ if (epsilon < M_PI_4) {
+ /* Under 45 degrees, just pick the closest value. */
+ for (int view = RV3D_VIEW_FRONT; view <= RV3D_VIEW_BOTTOM; view++) {
+ for (int view_axis_roll = RV3D_VIEW_AXIS_ROLL_0; view_axis_roll <= RV3D_VIEW_AXIS_ROLL_270;
+ view_axis_roll++) {
+ if (fabsf(angle_signed_qtqt(
+ quat, view3d_quat_axis[view - RV3D_VIEW_FRONT][view_axis_roll])) < epsilon) {
+ *r_view = view;
+ *r_view_axis_roll = view_axis_roll;
+ return true;
+ }
+ }
+ }
+ }
+ else {
+ /* Epsilon over 45 degrees, check all & find use the closest. */
+ float delta_best = FLT_MAX;
+ for (int view = RV3D_VIEW_FRONT; view <= RV3D_VIEW_BOTTOM; view++) {
+ for (int view_axis_roll = RV3D_VIEW_AXIS_ROLL_0; view_axis_roll <= RV3D_VIEW_AXIS_ROLL_270;
+ view_axis_roll++) {
+ const float delta_test = fabsf(
+ angle_signed_qtqt(quat, view3d_quat_axis[view - RV3D_VIEW_FRONT][view_axis_roll]));
+ if (delta_best > delta_test) {
+ delta_best = delta_test;
+ *r_view = view;
+ *r_view_axis_roll = view_axis_roll;
+ }
}
}
+ if (*r_view != RV3D_VIEW_USER) {
+ return true;
+ }
}
return false;
}
+bool ED_view3d_quat_to_axis_view_and_reset_quat(float quat[4],
+ const float epsilon,
+ char *r_view,
+ char *r_view_axis_roll)
+{
+ const bool is_axis_view = ED_view3d_quat_to_axis_view(quat, epsilon, r_view, r_view_axis_roll);
+ if (is_axis_view) {
+ /* Reset `quat` to it's view axis, so axis-aligned views are always *exactly* aligned. */
+ BLI_assert(*r_view != RV3D_VIEW_USER);
+ ED_view3d_quat_from_axis_view(*r_view, *r_view_axis_roll, quat);
+ }
+ return is_axis_view;
+}
+
char ED_view3d_lock_view_from_index(int index)
{
switch (index) {
diff --git a/source/blender/editors/transform/transform.c b/source/blender/editors/transform/transform.c
index 7a2a2a8a5e8..960d9a25ca7 100644
--- a/source/blender/editors/transform/transform.c
+++ b/source/blender/editors/transform/transform.c
@@ -1172,12 +1172,20 @@ int transformEvent(TransInfo *t, const wmEvent *event)
MOD_CONSTRAINT_SELECT_PLANE;
if (t->con.mode & CON_APPLY) {
stopConstraint(t);
+ initSelectConstraint(t);
+
+ /* In this case we might just want to remove the constraint,
+ * so set #TREDRAW_SOFT to only select the constraint on the next mouse move event.
+ * This way we can kind of "cancel" due to confirmation without constraint. */
+ t->redraw = TREDRAW_SOFT;
}
+ else {
+ initSelectConstraint(t);
- initSelectConstraint(t);
- /* Use #TREDRAW_SOFT so that #selectConstraint is only called on the next event.
- * This allows us to "deselect" the constraint. */
- t->redraw = TREDRAW_SOFT;
+ /* When first called, set #TREDRAW_HARD to select constraint immediately in
+ * #selectConstraint. */
+ BLI_assert(t->redraw == TREDRAW_HARD);
+ }
}
}
handled = true;
@@ -1417,9 +1425,6 @@ static void drawTransformView(const struct bContext *C, ARegion *region, void *a
/* edge slide, vert slide */
drawEdgeSlide(t);
drawVertSlide(t);
-
- /* Rotation */
- drawDial3d(t);
}
}
@@ -1571,6 +1576,7 @@ void saveTransform(bContext *C, TransInfo *t, wmOperator *op)
/* do we check for parameter? */
if (transformModeUseSnap(t)) {
if (!(t->modifiers & MOD_SNAP) != !(t->tsnap.flag & SCE_SNAP)) {
+ /* Type is #eSnapFlag, but type must match various snap attributes in #ToolSettings. */
char *snap_flag_ptr;
wmMsgParams_RNA msg_key_params = {{0}};
@@ -1778,13 +1784,6 @@ bool initTransform(bContext *C, TransInfo *t, wmOperator *op, const wmEvent *eve
t->launch_event = event ? WM_userdef_event_type_from_keymap_type(event->type) : -1;
t->is_launch_event_drag = event ? (event->val == KM_CLICK_DRAG) : false;
- /* XXX Remove this when wm_operator_call_internal doesn't use window->eventstate
- * (which can have type = 0) */
- /* For gizmo only, so assume LEFTMOUSE. */
- if (t->launch_event == 0) {
- t->launch_event = LEFTMOUSE;
- }
-
unit_m3(t->spacemtx);
initTransInfo(C, t, op, event);
@@ -2053,3 +2052,17 @@ bool checkUseAxisMatrix(TransInfo *t)
return false;
}
+
+bool transform_apply_matrix(TransInfo *t, float mat[4][4])
+{
+ if (t->transform_matrix != NULL) {
+ t->transform_matrix(t, mat);
+ return true;
+ }
+ return false;
+}
+
+void transform_final_value_get(const TransInfo *t, float *value, const int value_num)
+{
+ memcpy(value, t->values_final, sizeof(float) * value_num);
+}
diff --git a/source/blender/editors/transform/transform.h b/source/blender/editors/transform/transform.h
index a3df6a44682..a35942aedec 100644
--- a/source/blender/editors/transform/transform.h
+++ b/source/blender/editors/transform/transform.h
@@ -13,6 +13,7 @@
#include "DNA_listBase.h"
#include "DNA_object_enums.h"
+#include "DNA_scene_types.h"
#include "DEG_depsgraph.h"
@@ -153,7 +154,8 @@ typedef enum {
} eTModifier;
/** #TransSnap.status */
-typedef enum {
+typedef enum eTSnap {
+ SNAP_RESETTED = 0,
SNAP_FORCED = 1 << 0,
TARGET_INIT = 1 << 1,
/* Special flag for snap to grid. */
@@ -294,11 +296,14 @@ typedef struct TransSnapPoint {
} TransSnapPoint;
typedef struct TransSnap {
- char flag;
- char mode;
- short target;
- short modePoint;
- short modeSelect;
+ /* Snapping options stored as flags */
+ eSnapFlag flag;
+ /* Method(s) used for snapping source to target */
+ eSnapMode mode;
+ /* Part of source to snap to target */
+ eSnapSourceSelect source_select;
+ /* Determines which objects are possible target */
+ eSnapTargetSelect target_select;
bool align;
bool project;
bool snap_self;
@@ -306,7 +311,7 @@ typedef struct TransSnap {
bool use_backface_culling;
eTSnap status;
/* Snapped Element Type (currently for objects only). */
- char snapElem;
+ eSnapMode snapElem;
/** snapping from this point (in global-space). */
float snapTarget[3];
/** to this point (in global-space). */
@@ -533,6 +538,13 @@ typedef struct TransInfo {
/* Event handler function that determines whether the viewport needs to be redrawn. */
eRedrawFlag (*handleEvent)(struct TransInfo *, const struct wmEvent *);
+ /**
+ * Optional callback to transform a single matrix.
+ *
+ * \note used by the gizmo to transform the matrix used to position it.
+ */
+ void (*transform_matrix)(struct TransInfo *t, float mat_xform[4][4]);
+
/** Constraint Data. */
TransCon con;
@@ -713,6 +725,12 @@ void removeAspectRatio(TransInfo *t, float vec[2]);
*/
struct wmKeyMap *transform_modal_keymap(struct wmKeyConfig *keyconf);
+/**
+ * Transform a single matrix using the current `t->final_values`.
+ */
+bool transform_apply_matrix(TransInfo *t, float mat[4][4]);
+void transform_final_value_get(const TransInfo *t, float *value, int value_num);
+
/** \} */
/* -------------------------------------------------------------------- */
@@ -725,7 +743,6 @@ struct wmKeyMap *transform_modal_keymap(struct wmKeyConfig *keyconf);
bool gimbal_axis_pose(struct Object *ob, const struct bPoseChannel *pchan, float gmat[3][3]);
bool gimbal_axis_object(struct Object *ob, float gmat[3][3]);
-void drawDial3d(const TransInfo *t);
/** \} */
diff --git a/source/blender/editors/transform/transform_convert.c b/source/blender/editors/transform/transform_convert.c
index dbe67bd0d66..d9b971c5478 100644
--- a/source/blender/editors/transform/transform_convert.c
+++ b/source/blender/editors/transform/transform_convert.c
@@ -479,6 +479,45 @@ TransDataCurveHandleFlags *initTransDataCurveHandles(TransData *td, struct BezTr
/** \name UV Coordinates
* \{ */
+/**
+ * Find the correction for the scaling factor when "Constrain to Bounds" is active.
+ * \param numerator: How far the UV boundary (unit square) is from the origin of the scale.
+ * \param denominator: How far the AABB is from the origin of the scale.
+ * \param scale: Scale parameter to update.
+ */
+static void constrain_scale_to_boundary(const float numerator,
+ const float denominator,
+ float *scale)
+{
+ if (denominator == 0.0f) {
+ /* The origin of the scale is on the edge of the boundary. */
+ if (numerator < 0.0f) {
+ /* Negative scale will wrap around and put us outside the boundary. */
+ *scale = 0.0f; /* Hold at the boundary instead. */
+ }
+ return; /* Nothing else we can do without more info. */
+ }
+
+ const float correction = numerator / denominator;
+ if (correction < 0.0f || !isfinite(correction)) {
+ /* TODO: Correction is negative or invalid, but we lack context to fix `*scale`. */
+ return;
+ }
+
+ if (denominator < 0.0f) {
+ /* Scale origin is outside boundary, only make scale bigger. */
+ if (*scale < correction) {
+ *scale = correction;
+ }
+ return;
+ }
+
+ /* Scale origin is inside boundary, the "regular" case, limit maximum scale. */
+ if (*scale > correction) {
+ *scale = correction;
+ }
+}
+
bool clipUVTransform(TransInfo *t, float vec[2], const bool resize)
{
bool clipx = true, clipy = true;
@@ -517,31 +556,29 @@ bool clipUVTransform(TransInfo *t, float vec[2], const bool resize)
}
if (resize) {
- if (min[0] < base_offset[0] && t->center_global[0] > base_offset[0] &&
- t->center_global[0] < base_offset[0] + (t->aspect[0] * 0.5f)) {
- vec[0] *= (t->center_global[0] - base_offset[0]) / (t->center_global[0] - min[0]);
- }
- else if (max[0] > (base_offset[0] + t->aspect[0]) &&
- t->center_global[0] < (base_offset[0] + t->aspect[0])) {
- vec[0] *= (t->center_global[0] - (base_offset[0] + t->aspect[0])) /
- (t->center_global[0] - max[0]);
- }
- else {
- clipx = 0;
- }
-
- if (min[1] < base_offset[1] && t->center_global[1] > base_offset[1] &&
- t->center_global[1] < base_offset[1] + (t->aspect[1] * 0.5f)) {
- vec[1] *= (t->center_global[1] - base_offset[1]) / (t->center_global[1] - min[1]);
- }
- else if (max[1] > (base_offset[1] + t->aspect[1]) &&
- t->center_global[1] < (base_offset[1] + t->aspect[1])) {
- vec[1] *= (t->center_global[1] - (base_offset[1] + t->aspect[1])) /
- (t->center_global[1] - max[1]);
- }
- else {
- clipy = 0;
- }
+ /* Assume no change is required. */
+ float scalex = 1.0f;
+ float scaley = 1.0f;
+
+ /* Update U against the left border. */
+ constrain_scale_to_boundary(
+ t->center_global[0] - base_offset[0], t->center_global[0] - min[0], &scalex);
+ /* Now the right border, negated, because `-1.0 / -1.0 = 1.0` */
+ constrain_scale_to_boundary(base_offset[0] + t->aspect[0] - t->center_global[0],
+ max[0] - t->center_global[0],
+ &scalex);
+
+ /* Do the same for the V co-ordinate, which is called `y`. */
+ constrain_scale_to_boundary(
+ t->center_global[1] - base_offset[1], t->center_global[1] - min[1], &scaley);
+ constrain_scale_to_boundary(base_offset[1] + t->aspect[1] - t->center_global[1],
+ max[1] - t->center_global[1],
+ &scaley);
+
+ clipx = (scalex != 1.0f);
+ clipy = (scaley != 1.0f);
+ vec[0] *= scalex;
+ vec[1] *= scaley;
}
else {
if (min[0] < base_offset[0]) {
@@ -1570,10 +1607,9 @@ void transform_convert_clip_mirror_modifier_apply(TransDataContainer *tc)
}
}
-void animrecord_check_state(TransInfo *t, struct Object *ob)
+void animrecord_check_state(TransInfo *t, struct ID *id)
{
Scene *scene = t->scene;
- ID *id = &ob->id;
wmTimer *animtimer = t->animtimer;
ScreenAnimData *sad = (animtimer) ? animtimer->customdata : NULL;
diff --git a/source/blender/editors/transform/transform_convert.h b/source/blender/editors/transform/transform_convert.h
index 7080deaec66..037fbe26c77 100644
--- a/source/blender/editors/transform/transform_convert.h
+++ b/source/blender/editors/transform/transform_convert.h
@@ -95,7 +95,7 @@ void transform_convert_clip_mirror_modifier_apply(TransDataContainer *tc);
/**
* For the realtime animation recording feature, handle overlapping data.
*/
-void animrecord_check_state(TransInfo *t, struct Object *ob);
+void animrecord_check_state(TransInfo *t, struct ID *id);
/* transform_convert_action.c */
diff --git a/source/blender/editors/transform/transform_convert_armature.c b/source/blender/editors/transform/transform_convert_armature.c
index 3c1101d48a5..e1b25acb21e 100644
--- a/source/blender/editors/transform/transform_convert_armature.c
+++ b/source/blender/editors/transform/transform_convert_armature.c
@@ -1471,7 +1471,7 @@ void recalcData_pose(TransInfo *t)
/* XXX: this currently doesn't work, since flags aren't set yet! */
int targetless_ik = (t->flag & T_AUTOIK);
- animrecord_check_state(t, ob);
+ animrecord_check_state(t, &ob->id);
autokeyframe_pose(t->context, t->scene, ob, t->mode, targetless_ik);
}
diff --git a/source/blender/editors/transform/transform_convert_graph.c b/source/blender/editors/transform/transform_convert_graph.c
index 54222fbb117..2039daee386 100644
--- a/source/blender/editors/transform/transform_convert_graph.c
+++ b/source/blender/editors/transform/transform_convert_graph.c
@@ -24,12 +24,9 @@
#include "UI_view2d.h"
#include "transform.h"
-#include "transform_snap.h"
-
#include "transform_convert.h"
-#include "transform_snap.h"
-
#include "transform_mode.h"
+#include "transform_snap.h"
typedef struct TransDataGraph {
float unit_scale;
diff --git a/source/blender/editors/transform/transform_convert_mask.c b/source/blender/editors/transform/transform_convert_mask.c
index 5255cc4412e..b07d2bda0c5 100644
--- a/source/blender/editors/transform/transform_convert_mask.c
+++ b/source/blender/editors/transform/transform_convert_mask.c
@@ -261,18 +261,10 @@ void createTransMaskingData(bContext *C, TransInfo *t)
tc->data_len = 0;
- if (!mask) {
+ if (!ED_maskedit_mask_visible_splines_poll(C)) {
return;
}
- if (t->spacetype == SPACE_CLIP) {
- SpaceClip *sc = t->area->spacedata.first;
- MovieClip *clip = ED_space_clip_get_clip(sc);
- if (!clip) {
- return;
- }
- }
-
/* count */
for (masklay = mask->masklayers.first; masklay; masklay = masklay->next) {
MaskSpline *spline;
diff --git a/source/blender/editors/transform/transform_convert_nla.c b/source/blender/editors/transform/transform_convert_nla.c
index 685c35489de..2fa8fcf65ba 100644
--- a/source/blender/editors/transform/transform_convert_nla.c
+++ b/source/blender/editors/transform/transform_convert_nla.c
@@ -26,12 +26,9 @@
#include "RNA_prototypes.h"
#include "transform.h"
-#include "transform_snap.h"
-
#include "transform_convert.h"
-#include "transform_snap.h"
-
#include "transform_mode.h"
+#include "transform_snap.h"
/** Used for NLA transform (stored in #TransData.extra pointer). */
typedef struct TransDataNla {
diff --git a/source/blender/editors/transform/transform_convert_node.c b/source/blender/editors/transform/transform_convert_node.c
index d5d79bedbf4..8281052c314 100644
--- a/source/blender/editors/transform/transform_convert_node.c
+++ b/source/blender/editors/transform/transform_convert_node.c
@@ -46,7 +46,7 @@ static void NodeToTransData(TransData *td, TransData2D *td2d, bNode *node, const
}
/* use top-left corner as the transform origin for nodes */
- /* weirdo - but the node system is a mix of free 2d elements and dpi sensitive UI */
+ /* Weirdo - but the node system is a mix of free 2d elements and DPI sensitive UI. */
#ifdef USE_NODE_CENTER
td2d->loc[0] = (locx * dpi_fac) + (BLI_rctf_size_x(&node->totr) * +0.5f);
td2d->loc[1] = (locy * dpi_fac) + (BLI_rctf_size_y(&node->totr) * -0.5f);
@@ -194,7 +194,7 @@ void flushTransNodes(TransInfo *t)
loc[1] += 0.5f * BLI_rctf_size_y(&node->totr);
#endif
- /* weirdo - but the node system is a mix of free 2d elements and dpi sensitive UI */
+ /* Weirdo - but the node system is a mix of free 2d elements and DPI sensitive UI. */
loc[0] /= dpi_fac;
loc[1] /= dpi_fac;
diff --git a/source/blender/editors/transform/transform_convert_object.c b/source/blender/editors/transform/transform_convert_object.c
index d2585493679..5879a65eb4b 100644
--- a/source/blender/editors/transform/transform_convert_object.c
+++ b/source/blender/editors/transform/transform_convert_object.c
@@ -884,7 +884,7 @@ void recalcData_objects(TransInfo *t)
/* TODO: autokeyframe calls need some setting to specify to add samples
* (FPoints) instead of keyframes? */
if ((t->animtimer) && IS_AUTOKEY_ON(t->scene)) {
- animrecord_check_state(t, ob);
+ animrecord_check_state(t, &ob->id);
autokeyframe_object(t->context, t->scene, t->view_layer, ob, t->mode);
}
diff --git a/source/blender/editors/transform/transform_convert_sequencer.c b/source/blender/editors/transform/transform_convert_sequencer.c
index 5964af7ed4b..226b0f84f14 100644
--- a/source/blender/editors/transform/transform_convert_sequencer.c
+++ b/source/blender/editors/transform/transform_convert_sequencer.c
@@ -91,8 +91,8 @@ static void SeqTransInfo(TransInfo *t, Sequence *seq, int *r_count, int *r_flag)
/* *** Extend Transform *** */
int cfra = CFRA;
- int left = SEQ_transform_get_left_handle_frame(seq);
- int right = SEQ_transform_get_right_handle_frame(seq);
+ int left = SEQ_time_left_handle_frame_get(seq);
+ int right = SEQ_time_right_handle_frame_get(seq);
if (((seq->flag & SELECT) == 0 || SEQ_transform_is_locked(channels, seq))) {
*r_count = 0;
@@ -173,16 +173,16 @@ static TransData *SeqToTransData(
/* Use seq_tx_get_final_left() and an offset here
* so transform has the left hand location of the strip.
* tdsq->start_offset is used when flushing the tx data back */
- start_left = SEQ_transform_get_left_handle_frame(seq);
+ start_left = SEQ_time_left_handle_frame_get(seq);
td2d->loc[0] = start_left;
tdsq->start_offset = start_left - seq->start; /* use to apply the original location */
break;
case SEQ_LEFTSEL:
- start_left = SEQ_transform_get_left_handle_frame(seq);
+ start_left = SEQ_time_left_handle_frame_get(seq);
td2d->loc[0] = start_left;
break;
case SEQ_RIGHTSEL:
- td2d->loc[0] = SEQ_transform_get_right_handle_frame(seq);
+ td2d->loc[0] = SEQ_time_right_handle_frame_get(seq);
break;
}
@@ -278,76 +278,7 @@ static void seq_transform_cancel(TransInfo *t, SeqCollection *transformed_strips
if (SEQ_transform_test_overlap(seqbase, seq)) {
SEQ_transform_seqbase_shuffle(seqbase, seq, t->scene);
}
-
- SEQ_time_update_sequence(t->scene, seqbase, seq);
- }
-}
-
-static bool seq_transform_check_overlap(SeqCollection *transformed_strips)
-{
- Sequence *seq;
- SEQ_ITERATOR_FOREACH (seq, transformed_strips) {
- if (seq->flag & SEQ_OVERLAP) {
- return true;
- }
- }
- return false;
-}
-
-static SeqCollection *extract_standalone_strips(SeqCollection *transformed_strips)
-{
- SeqCollection *collection = SEQ_collection_create(__func__);
- Sequence *seq;
- SEQ_ITERATOR_FOREACH (seq, transformed_strips) {
- if ((seq->type & SEQ_TYPE_EFFECT) == 0 || seq->seq1 == NULL) {
- SEQ_collection_append_strip(seq, collection);
- }
- }
- return collection;
-}
-
-/* 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;
- {
- Sequence *seq;
- SEQ_ITERATOR_FOREACH (seq, transformed_strips) {
- minframe = min_ii(minframe, seq->startdisp);
- }
}
-
- SeqCollection *collection = SEQ_collection_create(__func__);
- LISTBASE_FOREACH (Sequence *, seq, seqbase) {
- if ((seq->flag & SELECT) == 0 && seq->startdisp >= minframe) {
- SEQ_collection_append_strip(seq, collection);
- }
- }
- return collection;
-}
-
-static void seq_transform_update_effects(Scene *scene,
- ListBase *seqbasep,
- SeqCollection *collection)
-{
- Sequence *seq;
- SEQ_ITERATOR_FOREACH (seq, collection) {
- if ((seq->type & SEQ_TYPE_EFFECT) && (seq->seq1 || seq->seq2 || seq->seq3)) {
- SEQ_time_update_sequence(scene, seqbasep, seq);
- }
- }
-}
-
-/* Check if effect strips with input are transformed. */
-static bool seq_transform_check_strip_effects(SeqCollection *transformed_strips)
-{
- Sequence *seq;
- SEQ_ITERATOR_FOREACH (seq, transformed_strips) {
- if ((seq->type & SEQ_TYPE_EFFECT) && (seq->seq1 || seq->seq2 || seq->seq3)) {
- return true;
- }
- }
- return false;
}
static ListBase *seqbase_active_get(const TransInfo *t)
@@ -356,241 +287,15 @@ static ListBase *seqbase_active_get(const TransInfo *t)
return SEQ_active_seqbase_get(ed);
}
-/* 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(Scene *scene,
- ListBase *seqbasep,
- SeqCollection *transformed_strips,
- bool use_sync_markers)
-{
- ListBase *markers = &scene->markers;
-
- SeqCollection *right_side_strips = query_right_side_strips(seqbasep, transformed_strips);
-
- /* Temporarily move right side strips beyond timeline boundary. */
- Sequence *seq;
- SEQ_ITERATOR_FOREACH (seq, right_side_strips) {
- seq->machine += MAXSEQ * 2;
- }
-
- /* Shuffle transformed standalone strips. This is because transformed strips can overlap with
- * strips on left side. */
- SeqCollection *standalone_strips = extract_standalone_strips(transformed_strips);
- SEQ_transform_seqbase_shuffle_time(
- standalone_strips, seqbasep, scene, markers, use_sync_markers);
- SEQ_collection_free(standalone_strips);
-
- /* Move temporarily moved strips back to their original place and tag for shuffling. */
- SEQ_ITERATOR_FOREACH (seq, right_side_strips) {
- seq->machine -= MAXSEQ * 2;
- }
- /* Shuffle again to displace strips on right side. Final effect shuffling is done in
- * SEQ_transform_handle_overlap. */
- SEQ_transform_seqbase_shuffle_time(
- right_side_strips, seqbasep, scene, markers, use_sync_markers);
- seq_transform_update_effects(scene, seqbasep, right_side_strips);
- SEQ_collection_free(right_side_strips);
-}
-
-static SeqCollection *query_overwrite_targets(ListBase *seqbasep,
- SeqCollection *transformed_strips)
-{
- SeqCollection *collection = SEQ_query_unselected_strips(seqbasep);
-
- Sequence *seq, *seq_transformed;
- SEQ_ITERATOR_FOREACH (seq, collection) {
- bool does_overlap = false;
-
- SEQ_ITERATOR_FOREACH (seq_transformed, transformed_strips) {
- /* Effects of transformed strips can be unselected. These must not be included. */
- if (seq == seq_transformed) {
- SEQ_collection_remove_strip(seq, collection);
- }
- if (SEQ_transform_test_overlap_seq_seq(seq, seq_transformed)) {
- does_overlap = true;
- }
- }
-
- if (!does_overlap) {
- SEQ_collection_remove_strip(seq, collection);
- }
- }
-
- return collection;
-}
-
-typedef enum eOvelapDescrition {
- /* No overlap. */
- STRIP_OVERLAP_NONE,
- /* Overlapping strip covers overlapped completely. */
- STRIP_OVERLAP_IS_FULL,
- /* Overlapping strip is inside overlapped. */
- STRIP_OVERLAP_IS_INSIDE,
- /* Partial overlap between 2 strips. */
- STRIP_OVERLAP_LEFT_SIDE,
- STRIP_OVERLAP_RIGHT_SIDE,
-} eOvelapDescrition;
-
-static eOvelapDescrition overlap_description_get(const Sequence *transformed,
- const Sequence *target)
-{
- if (transformed->startdisp <= target->startdisp && transformed->enddisp >= target->enddisp) {
- return STRIP_OVERLAP_IS_FULL;
- }
- if (transformed->startdisp > target->startdisp && transformed->enddisp < target->enddisp) {
- return STRIP_OVERLAP_IS_INSIDE;
- }
- if (transformed->startdisp <= target->startdisp && target->startdisp <= transformed->enddisp) {
- return STRIP_OVERLAP_LEFT_SIDE;
- }
- if (transformed->startdisp <= target->enddisp && target->enddisp <= transformed->enddisp) {
- return STRIP_OVERLAP_RIGHT_SIDE;
- }
- return STRIP_OVERLAP_NONE;
-}
-
-/* Split strip in 3 parts, remove middle part and fit transformed inside. */
-static void seq_transform_handle_overwrite_split(Scene *scene,
- ListBase *seqbasep,
- const Sequence *transformed,
- Sequence *target)
-{
- /* Because we are doing a soft split, bmain is not used in SEQ_edit_strip_split, so we can pass
- * NULL here. */
- Main *bmain = NULL;
-
- Sequence *split_strip = SEQ_edit_strip_split(
- bmain, scene, seqbasep, target, transformed->startdisp, SEQ_SPLIT_SOFT, NULL);
- SEQ_edit_strip_split(
- bmain, scene, seqbasep, split_strip, transformed->enddisp, SEQ_SPLIT_SOFT, NULL);
- SEQ_edit_flag_for_removal(scene, seqbasep, split_strip);
- SEQ_edit_remove_flagged_sequences(scene, seqbasep);
-}
-
-/* Trim strips by adjusting handle position.
- * This is bit more complicated in case overlap happens on effect. */
-static void seq_transform_handle_overwrite_trim(Scene *scene,
- ListBase *seqbasep,
- const Sequence *transformed,
- Sequence *target,
- const eOvelapDescrition overlap)
-{
- SeqCollection *targets = SEQ_query_by_reference(target, seqbasep, SEQ_query_strip_effect_chain);
-
- /* Expand collection by adding all target's children, effects and their children. */
- if ((target->type & SEQ_TYPE_EFFECT) != 0) {
- SEQ_collection_expand(seqbasep, targets, SEQ_query_strip_effect_chain);
- }
-
- /* Trim all non effects, that have influence on effect length which is overlapping. */
- Sequence *seq;
- SEQ_ITERATOR_FOREACH (seq, targets) {
- if ((seq->type & SEQ_TYPE_EFFECT) != 0 && SEQ_effect_get_num_inputs(seq->type) > 0) {
- continue;
- }
- if (overlap == STRIP_OVERLAP_LEFT_SIDE) {
- SEQ_transform_set_left_handle_frame(seq, transformed->enddisp);
- }
- else {
- BLI_assert(overlap == STRIP_OVERLAP_RIGHT_SIDE);
- SEQ_transform_set_right_handle_frame(seq, transformed->startdisp);
- }
-
- SEQ_time_update_sequence(scene, seqbasep, seq);
- }
- SEQ_collection_free(targets);
-}
-
-static void seq_transform_handle_overwrite(Scene *scene,
- ListBase *seqbasep,
- SeqCollection *transformed_strips)
-{
- SeqCollection *targets = query_overwrite_targets(seqbasep, transformed_strips);
- SeqCollection *strips_to_delete = SEQ_collection_create(__func__);
-
- Sequence *target;
- Sequence *transformed;
- SEQ_ITERATOR_FOREACH (target, targets) {
- SEQ_ITERATOR_FOREACH (transformed, transformed_strips) {
- if (transformed->machine != target->machine) {
- continue;
- }
-
- const eOvelapDescrition overlap = overlap_description_get(transformed, target);
-
- if (overlap == STRIP_OVERLAP_IS_FULL) {
- SEQ_collection_append_strip(target, strips_to_delete);
- }
- else if (overlap == STRIP_OVERLAP_IS_INSIDE) {
- seq_transform_handle_overwrite_split(scene, seqbasep, transformed, target);
- }
- else if (ELEM(overlap, STRIP_OVERLAP_LEFT_SIDE, STRIP_OVERLAP_RIGHT_SIDE)) {
- seq_transform_handle_overwrite_trim(scene, seqbasep, transformed, target, overlap);
- }
- }
- }
-
- SEQ_collection_free(targets);
-
- /* Remove covered strips. This must be done in separate loop, because `SEQ_edit_strip_split()`
- * also uses `SEQ_edit_remove_flagged_sequences()`. See T91096. */
- if (SEQ_collection_len(strips_to_delete) > 0) {
- Sequence *seq;
- SEQ_ITERATOR_FOREACH (seq, strips_to_delete) {
- SEQ_edit_flag_for_removal(scene, seqbasep, seq);
- }
- SEQ_edit_remove_flagged_sequences(scene, seqbasep);
- }
- SEQ_collection_free(strips_to_delete);
-}
-
-static void seq_transform_handle_overlap_shuffle(Scene *scene,
- ListBase *seqbasep,
- SeqCollection *transformed_strips,
- bool use_sync_markers)
-{
- ListBase *markers = &scene->markers;
-
- /* Shuffle non strips with no effects attached. */
- SeqCollection *standalone_strips = extract_standalone_strips(transformed_strips);
- SEQ_transform_seqbase_shuffle_time(
- standalone_strips, seqbasep, scene, markers, use_sync_markers);
- SEQ_collection_free(standalone_strips);
-}
-
-void SEQ_transform_handle_overlap(Scene *scene,
- ListBase *seqbasep,
- SeqCollection *transformed_strips,
- bool use_sync_markers)
+static bool seq_transform_check_overlap(SeqCollection *transformed_strips)
{
- const eSeqOverlapMode overlap_mode = SEQ_tool_settings_overlap_mode_get(scene);
-
- switch (overlap_mode) {
- case SEQ_OVERLAP_EXPAND:
- seq_transform_handle_expand_to_fit(scene, seqbasep, transformed_strips, use_sync_markers);
- break;
- case SEQ_OVERLAP_OVERWRITE:
- seq_transform_handle_overwrite(scene, seqbasep, transformed_strips);
- break;
- case SEQ_OVERLAP_SHUFFLE:
- seq_transform_handle_overlap_shuffle(scene, seqbasep, transformed_strips, use_sync_markers);
- break;
- }
-
- if (seq_transform_check_strip_effects(transformed_strips)) {
- /* Update effect strips based on strips just moved in time. */
- seq_transform_update_effects(scene, seqbasep, transformed_strips);
- }
-
- /* If any effects still overlap, we need to move them up.
- * In some cases other strips can be overlapping still, see T90646. */
Sequence *seq;
SEQ_ITERATOR_FOREACH (seq, transformed_strips) {
- if (SEQ_transform_test_overlap(seqbasep, seq)) {
- SEQ_transform_seqbase_shuffle(seqbasep, seq, scene);
+ if (seq->flag & SEQ_OVERLAP) {
+ return true;
}
- seq->flag &= ~SEQ_OVERLAP;
}
+ return false;
}
static SeqCollection *seq_transform_collection_from_transdata(TransDataContainer *tc)
@@ -627,18 +332,17 @@ static void freeSeqData(TransInfo *t, TransDataContainer *tc, TransCustomData *c
return;
}
+ TransSeq *ts = tc->custom.type.data;
ListBase *seqbasep = seqbase_active_get(t);
Scene *scene = t->scene;
const bool use_sync_markers = (((SpaceSeq *)t->area->spacedata.first)->flag &
SEQ_MARKER_TRANS) != 0;
if (seq_transform_check_overlap(transformed_strips)) {
- SEQ_transform_handle_overlap(scene, seqbasep, transformed_strips, use_sync_markers);
+ SEQ_transform_handle_overlap(
+ scene, seqbasep, transformed_strips, ts->time_dependent_strips, use_sync_markers);
}
- seq_transform_update_effects(scene, seqbasep, transformed_strips);
SEQ_collection_free(transformed_strips);
-
- SEQ_sort(ed->seqbasep);
DEG_id_tag_update(&t->scene->id, ID_RECALC_SEQUENCER_STRIPS);
free_transform_custom_data(custom_data);
}
@@ -662,7 +366,10 @@ typedef enum SeqInputSide {
static Sequence *effect_input_get(Sequence *effect, SeqInputSide side)
{
Sequence *input = effect->seq1;
- if (effect->seq2 && (effect->seq2->startdisp - effect->seq1->startdisp) * side > 0) {
+ if (effect->seq2 && (SEQ_time_left_handle_frame_get(effect->seq2) -
+ SEQ_time_left_handle_frame_get(effect->seq1)) *
+ side >
+ 0) {
input = effect->seq2;
}
return input;
@@ -825,23 +532,6 @@ void createTransSeqData(TransInfo *t)
/** \name UVs Transform Flush
* \{ */
-/* commented _only_ because the meta may have animation data which
- * needs moving too T28158. */
-
-BLI_INLINE void trans_update_seq(Scene *sce, Sequence *seq, int old_start, int sel_flag)
-{
- /* Calculate this strip and all nested strips.
- * Children are ALWAYS transformed first so we don't need to do this in another loop.
- */
-
- ListBase *seqbase = SEQ_active_seqbase_get(SEQ_editing_get(sce));
- SEQ_time_update_sequence(sce, seqbase, seq);
-
- if (sel_flag == SELECT) {
- SEQ_offset_animdata(sce, seq, seq->start - old_start);
- }
-}
-
static void view2d_edge_pan_loc_compensate(TransInfo *t, float loc_in[2], float r_loc[2])
{
TransSeq *ts = (TransSeq *)TRANS_DATA_CONTAINER_FIRST_SINGLE(t)->custom.type.data;
@@ -914,24 +604,24 @@ static void flushTransSeq(TransInfo *t)
break;
}
case SEQ_LEFTSEL: { /* No vertical transform. */
- int old_startdisp = seq->startdisp;
- SEQ_transform_set_left_handle_frame(seq, new_frame);
- SEQ_transform_handle_xlimits(seq, tdsq->flag & SEQ_LEFTSEL, tdsq->flag & SEQ_RIGHTSEL);
- SEQ_transform_fix_single_image_seq_offsets(seq);
- SEQ_time_update_sequence(t->scene, seqbasep, seq);
- if (abs(seq->startdisp - old_startdisp) > abs(max_offset)) {
- max_offset = seq->startdisp - old_startdisp;
+ int old_startdisp = SEQ_time_left_handle_frame_get(seq);
+ SEQ_time_left_handle_frame_set(t->scene, seq, new_frame);
+ SEQ_transform_handle_xlimits(
+ t->scene, seq, tdsq->flag & SEQ_LEFTSEL, tdsq->flag & SEQ_RIGHTSEL);
+ SEQ_transform_fix_single_image_seq_offsets(t->scene, seq);
+ if (abs(SEQ_time_left_handle_frame_get(seq) - old_startdisp) > abs(max_offset)) {
+ max_offset = SEQ_time_left_handle_frame_get(seq) - old_startdisp;
}
break;
}
case SEQ_RIGHTSEL: { /* No vertical transform. */
- int old_enddisp = seq->enddisp;
- SEQ_transform_set_right_handle_frame(seq, new_frame);
- SEQ_transform_handle_xlimits(seq, tdsq->flag & SEQ_LEFTSEL, tdsq->flag & SEQ_RIGHTSEL);
- SEQ_transform_fix_single_image_seq_offsets(seq);
- SEQ_time_update_sequence(t->scene, seqbasep, seq);
- if (abs(seq->enddisp - old_enddisp) > abs(max_offset)) {
- max_offset = seq->enddisp - old_enddisp;
+ int old_enddisp = SEQ_time_right_handle_frame_get(seq);
+ SEQ_time_right_handle_frame_set(t->scene, seq, new_frame);
+ SEQ_transform_handle_xlimits(
+ t->scene, seq, tdsq->flag & SEQ_LEFTSEL, tdsq->flag & SEQ_RIGHTSEL);
+ SEQ_transform_fix_single_image_seq_offsets(t->scene, seq);
+ if (abs(SEQ_time_right_handle_frame_get(seq) - old_enddisp) > abs(max_offset)) {
+ max_offset = SEQ_time_right_handle_frame_get(seq) - old_enddisp;
}
break;
}
@@ -945,15 +635,6 @@ static void flushTransSeq(TransInfo *t)
SEQ_offset_animdata(t->scene, seq, max_offset);
}
- /* Update effect length and position. */
- if (ELEM(t->mode, TFM_SEQ_SLIDE, TFM_TIME_TRANSLATE)) {
- for (seq = seqbasep->first; seq; seq = seq->next) {
- if (seq->seq1 || seq->seq2 || seq->seq3) {
- SEQ_time_update_sequence(t->scene, seqbasep, seq);
- }
- }
- }
-
/* need to do the overlap check in a new loop otherwise adjacent strips
* will not be updated and we'll get false positives */
SeqCollection *transformed_strips = seq_transform_collection_from_transdata(tc);
diff --git a/source/blender/editors/transform/transform_convert_sequencer_image.c b/source/blender/editors/transform/transform_convert_sequencer_image.c
index cbc2cab0a7a..76c6632039a 100644
--- a/source/blender/editors/transform/transform_convert_sequencer_image.c
+++ b/source/blender/editors/transform/transform_convert_sequencer_image.c
@@ -154,6 +154,42 @@ void createTransSeqImageData(TransInfo *t)
SEQ_collection_free(strips);
}
+static bool autokeyframe_sequencer_image(bContext *C,
+ Scene *scene,
+ StripTransform *transform,
+ const int tmode)
+{
+ PointerRNA ptr;
+ PropertyRNA *prop;
+ RNA_pointer_create(&scene->id, &RNA_SequenceTransform, transform, &ptr);
+
+ const bool around_cursor = scene->toolsettings->sequencer_tool_settings->pivot_point ==
+ V3D_AROUND_CURSOR;
+ const bool do_loc = tmode == TFM_TRANSLATION || around_cursor;
+ const bool do_rot = tmode == TFM_ROTATION;
+ const bool do_scale = tmode == TFM_RESIZE;
+
+ bool changed = false;
+ if (do_rot) {
+ prop = RNA_struct_find_property(&ptr, "rotation");
+ changed |= ED_autokeyframe_property(C, scene, &ptr, prop, -1, CFRA, false);
+ }
+ if (do_loc) {
+ prop = RNA_struct_find_property(&ptr, "offset_x");
+ changed |= ED_autokeyframe_property(C, scene, &ptr, prop, -1, CFRA, false);
+ prop = RNA_struct_find_property(&ptr, "offset_y");
+ changed |= ED_autokeyframe_property(C, scene, &ptr, prop, -1, CFRA, false);
+ }
+ if (do_scale) {
+ prop = RNA_struct_find_property(&ptr, "scale_x");
+ changed |= ED_autokeyframe_property(C, scene, &ptr, prop, -1, CFRA, false);
+ prop = RNA_struct_find_property(&ptr, "scale_y");
+ changed |= ED_autokeyframe_property(C, scene, &ptr, prop, -1, CFRA, false);
+ }
+
+ return changed;
+}
+
void recalcData_sequencer_image(TransInfo *t)
{
TransDataContainer *tc = TRANS_DATA_CONTAINER_FIRST_SINGLE(t);
@@ -187,6 +223,7 @@ void recalcData_sequencer_image(TransInfo *t)
copy_v2_v2(translation, tdseq->orig_origin_position);
sub_v2_v2(translation, origin);
mul_v2_v2(translation, mirror);
+ translation[0] *= t->scene->r.yasp / t->scene->r.xasp;
transform->xofs = tdseq->orig_translation[0] - translation[0];
transform->yofs = tdseq->orig_translation[1] - translation[1];
@@ -197,53 +234,39 @@ void recalcData_sequencer_image(TransInfo *t)
/* Rotation. Scaling can cause negative rotation. */
if (t->mode == TFM_ROTATION) {
- const float orig_dir[2] = {cosf(tdseq->orig_rotation), sinf(tdseq->orig_rotation)};
- float rotation = angle_signed_v2v2(handle_x, orig_dir) * mirror[0] * mirror[1];
- transform->rotation = tdseq->orig_rotation + rotation;
- transform->rotation += DEG2RAD(360.0);
- transform->rotation = fmod(transform->rotation, DEG2RAD(360.0));
+ transform->rotation = tdseq->orig_rotation - t->values_final[0];
+ }
+
+ if ((t->animtimer) && IS_AUTOKEY_ON(t->scene)) {
+ animrecord_check_state(t, &t->scene->id);
+ autokeyframe_sequencer_image(t->context, t->scene, transform, t->mode);
}
+
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->state == TRANS_CANCEL) {
+ if (t->mode == TFM_ROTATION) {
+ transform->rotation = tdseq->orig_rotation;
+ }
+ continue;
}
- 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);
+
+ if (IS_AUTOKEY_ON(t->scene)) {
+ autokeyframe_sequencer_image(t->context, t->scene, transform, t->mode);
}
}
}
diff --git a/source/blender/editors/transform/transform_convert_tracking.c b/source/blender/editors/transform/transform_convert_tracking.c
index 45f17512c09..d447cd71a40 100644
--- a/source/blender/editors/transform/transform_convert_tracking.c
+++ b/source/blender/editors/transform/transform_convert_tracking.c
@@ -621,7 +621,7 @@ static void flushTransTracking(TransInfo *t)
TransData *td;
TransData2D *td2d;
TransDataTracking *tdt;
- int a;
+ int td_index;
if (t->state == TRANS_CANCEL) {
cancelTransTracking(t);
@@ -630,8 +630,9 @@ static void flushTransTracking(TransInfo *t)
TransDataContainer *tc = TRANS_DATA_CONTAINER_FIRST_SINGLE(t);
/* flush to 2d vector from internally used 3d vector */
- for (a = 0, td = tc->data, td2d = tc->data_2d, tdt = tc->custom.type.data; a < tc->data_len;
- a++, td2d++, td++, tdt++) {
+ for (td_index = 0, td = tc->data, td2d = tc->data_2d, tdt = tc->custom.type.data;
+ td_index < tc->data_len;
+ td_index++, td2d++, td++, tdt++) {
if (tdt->mode == transDataTracking_ModeTracks) {
float loc2d[2];
@@ -655,7 +656,7 @@ static void flushTransTracking(TransInfo *t)
if (!tdt->smarkers) {
tdt->smarkers = MEM_callocN(sizeof(*tdt->smarkers) * tdt->markersnr,
"flushTransTracking markers");
- for (a = 0; a < tdt->markersnr; a++) {
+ for (int a = 0; a < tdt->markersnr; a++) {
copy_v2_v2(tdt->smarkers[a], tdt->markers[a].pos);
}
}
@@ -665,7 +666,7 @@ static void flushTransTracking(TransInfo *t)
sub_v2_v2v2(d2, loc2d, tdt->srelative);
- for (a = 0; a < tdt->markersnr; a++) {
+ for (int a = 0; a < tdt->markersnr; a++) {
add_v2_v2v2(tdt->markers[a].pos, tdt->smarkers[a], d2);
}
@@ -712,23 +713,23 @@ void recalcData_tracking(TransInfo *t)
if (t->mode == TFM_TRANSLATION) {
if (TRACK_AREA_SELECTED(track, TRACK_AREA_PAT)) {
- BKE_tracking_marker_clamp(marker, CLAMP_PAT_POS);
+ BKE_tracking_marker_clamp_pattern_position(marker);
}
if (TRACK_AREA_SELECTED(track, TRACK_AREA_SEARCH)) {
- BKE_tracking_marker_clamp(marker, CLAMP_SEARCH_POS);
+ BKE_tracking_marker_clamp_search_position(marker);
}
}
else if (t->mode == TFM_RESIZE) {
if (TRACK_AREA_SELECTED(track, TRACK_AREA_PAT)) {
- BKE_tracking_marker_clamp(marker, CLAMP_PAT_DIM);
+ BKE_tracking_marker_clamp_search_size(marker);
}
if (TRACK_AREA_SELECTED(track, TRACK_AREA_SEARCH)) {
- BKE_tracking_marker_clamp(marker, CLAMP_SEARCH_DIM);
+ BKE_tracking_marker_clamp_search_size(marker);
}
}
else if (t->mode == TFM_ROTATION) {
if (TRACK_AREA_SELECTED(track, TRACK_AREA_PAT)) {
- BKE_tracking_marker_clamp(marker, CLAMP_PAT_POS);
+ BKE_tracking_marker_clamp_pattern_position(marker);
}
}
}
diff --git a/source/blender/editors/transform/transform_generics.c b/source/blender/editors/transform/transform_generics.c
index 975dbc2e986..e45cac36736 100644
--- a/source/blender/editors/transform/transform_generics.c
+++ b/source/blender/editors/transform/transform_generics.c
@@ -358,6 +358,10 @@ void initTransInfo(bContext *C, TransInfo *t, wmOperator *op, const wmEvent *eve
}
else if (t->spacetype == SPACE_SEQ && region->regiontype == RGN_TYPE_PREVIEW) {
t->options |= CTX_SEQUENCER_IMAGE;
+
+ /* Needed for autokeying transforms in preview during playback. */
+ bScreen *animscreen = ED_screen_animation_playing(CTX_wm_manager(C));
+ t->animtimer = (animscreen) ? animscreen->animtimer : NULL;
}
setTransformViewAspect(t, t->aspect);
diff --git a/source/blender/editors/transform/transform_gizmo_3d.c b/source/blender/editors/transform/transform_gizmo_3d.c
index aa8dad2b95f..5b749e05052 100644
--- a/source/blender/editors/transform/transform_gizmo_3d.c
+++ b/source/blender/editors/transform/transform_gizmo_3d.c
@@ -45,7 +45,6 @@
#include "WM_api.h"
#include "WM_message.h"
#include "WM_types.h"
-#include "wm.h"
#include "ED_armature.h"
#include "ED_gizmo_library.h"
@@ -71,6 +70,10 @@
#include "GPU_state.h"
+static void gizmo_refresh_from_matrix(wmGizmoGroup *gzgroup,
+ const float twmat[4][4],
+ const float scale[3]);
+
/* return codes for select, and drawing flags */
#define MAN_TRANS_X (1 << 0)
@@ -155,6 +158,9 @@ typedef struct GizmoGroup {
float viewinv_m3[3][3];
} prev;
+ /* Only for Rotate operator. */
+ float rotation;
+
struct wmGizmo *gizmos[MAN_AXIS_LAST];
} GizmoGroup;
@@ -1269,103 +1275,31 @@ static void gizmo_xform_message_subscribe(wmGizmoGroup *gzgroup,
WM_msg_subscribe_rna_anon_prop(mbus, EditBone, lock, &msg_sub_value_gz_tag_refresh);
}
-void drawDial3d(const TransInfo *t)
+static void gizmo_3d_dial_matrixbasis_calc(const ARegion *region,
+ float axis[3],
+ float center_global[3],
+ float mval_init[2],
+ float r_mat_basis[4][4])
{
- if (t->mode == TFM_ROTATION && t->spacetype == SPACE_VIEW3D) {
- if (t->options & CTX_PAINT_CURVE) {
- /* Matrices are in the screen space. Not supported. */
- return;
- }
-
- wmGizmo *gz = wm_gizmomap_modal_get(t->region->gizmo_map);
- if (gz == NULL) {
- /* We only draw Dial3d if the operator has been called by a gizmo. */
- return;
- }
-
- float mat_basis[4][4];
- float mat_final[4][4];
- float color[4];
- float increment = 0.0f;
- float line_with = GIZMO_AXIS_LINE_WIDTH + 1.0f;
- float scale = UI_DPI_FAC * U.gizmo_size;
-
- int axis_idx;
-
- const TransCon *tc = &(t->con);
- if (tc->mode & CON_APPLY) {
- if (tc->mode & CON_AXIS0) {
- axis_idx = MAN_AXIS_ROT_X;
- negate_v3_v3(mat_basis[2], t->spacemtx[0]);
- }
- else if (tc->mode & CON_AXIS1) {
- axis_idx = MAN_AXIS_ROT_Y;
- negate_v3_v3(mat_basis[2], t->spacemtx[1]);
- }
- else {
- BLI_assert((tc->mode & CON_AXIS2) != 0);
- axis_idx = MAN_AXIS_ROT_Z;
- negate_v3_v3(mat_basis[2], t->spacemtx[2]);
- }
- }
- else {
- axis_idx = MAN_AXIS_ROT_C;
- copy_v3_v3(mat_basis[2], t->spacemtx[t->orient_axis]);
- scale *= 1.2f;
- line_with -= 1.0f;
- }
-
- copy_v3_v3(mat_basis[3], t->center_global);
- mat_basis[2][3] = -dot_v3v3(mat_basis[2], mat_basis[3]);
-
- if (ED_view3d_win_to_3d_on_plane(
- t->region, mat_basis[2], (float[2]){UNPACK2(t->mouse.imval)}, false, mat_basis[1])) {
- sub_v3_v3(mat_basis[1], mat_basis[3]);
- normalize_v3(mat_basis[1]);
- cross_v3_v3v3(mat_basis[0], mat_basis[1], mat_basis[2]);
- }
- else {
- /* The plane and the mouse direction are parallel.
- * Calculate a matrix orthogonal to the axis. */
- ortho_basis_v3v3_v3(mat_basis[0], mat_basis[1], mat_basis[2]);
- }
-
- mat_basis[0][3] = 0.0f;
- mat_basis[1][3] = 0.0f;
- mat_basis[2][3] = 0.0f;
- mat_basis[3][3] = 1.0f;
-
- copy_m4_m4(mat_final, mat_basis);
- scale *= ED_view3d_pixel_size_no_ui_scale(t->region->regiondata, mat_final[3]);
- mul_mat3_m4_fl(mat_final, scale);
+ copy_v3_v3(r_mat_basis[2], axis);
+ copy_v3_v3(r_mat_basis[3], center_global);
+ r_mat_basis[2][3] = -dot_v3v3(axis, center_global);
- if (activeSnap(t) && (!transformModeUseSnap(t) ||
- (t->tsnap.mode & (SCE_SNAP_MODE_INCREMENT | SCE_SNAP_MODE_GRID)))) {
- increment = (t->modifiers & MOD_PRECISION) ? t->snap[1] : t->snap[0];
- }
-
- BLI_assert(axis_idx >= MAN_AXIS_RANGE_ROT_START && axis_idx < MAN_AXIS_RANGE_ROT_END);
- gizmo_get_axis_color(axis_idx, NULL, color, color);
-
- GPU_depth_test(GPU_DEPTH_NONE);
- GPU_blend(GPU_BLEND_ALPHA);
- GPU_line_smooth(true);
-
- ED_gizmotypes_dial_3d_draw_util(mat_basis,
- mat_final,
- line_with,
- color,
- false,
- &(struct Dial3dParams){
- .draw_options = ED_GIZMO_DIAL_DRAW_FLAG_ANGLE_VALUE,
- .angle_delta = t->values_final[0],
- .angle_increment = increment,
- });
-
- GPU_line_smooth(false);
- GPU_depth_test(GPU_DEPTH_LESS_EQUAL);
- GPU_blend(GPU_BLEND_NONE);
+ if (ED_view3d_win_to_3d_on_plane(region, axis, mval_init, false, r_mat_basis[1])) {
+ sub_v3_v3(r_mat_basis[1], center_global);
+ normalize_v3(r_mat_basis[1]);
+ cross_v3_v3v3(r_mat_basis[0], r_mat_basis[1], r_mat_basis[2]);
+ }
+ else {
+ /* The plane and the mouse direction are parallel.
+ * Calculate a matrix orthogonal to the axis. */
+ ortho_basis_v3v3_v3(r_mat_basis[0], r_mat_basis[1], r_mat_basis[2]);
}
+
+ r_mat_basis[0][3] = 0.0f;
+ r_mat_basis[1][3] = 0.0f;
+ r_mat_basis[2][3] = 0.0f;
+ r_mat_basis[3][3] = 1.0f;
}
/** \} */
@@ -1374,6 +1308,23 @@ void drawDial3d(const TransInfo *t)
/** \name Transform Gizmo
* \{ */
+/** Scale of the two-axis planes. */
+#define MAN_AXIS_SCALE_PLANE_SCALE 0.07f
+/** Offset of the two-axis planes, depends on the gizmos scale. Define to avoid repeating. */
+#define MAN_AXIS_SCALE_PLANE_OFFSET 7.0f
+
+static void rotation_get_fn(const wmGizmo *UNUSED(gz), wmGizmoProperty *gz_prop, void *value)
+{
+ const GizmoGroup *ggd = (const GizmoGroup *)gz_prop->custom_func.user_data;
+ *(float *)value = ggd->rotation;
+}
+
+static void rotation_set_fn(const wmGizmo *UNUSED(gz), wmGizmoProperty *gz_prop, const void *value)
+{
+ GizmoGroup *ggd = (GizmoGroup *)gz_prop->custom_func.user_data;
+ ggd->rotation = *(const float *)value;
+}
+
static GizmoGroup *gizmogroup_init(wmGizmoGroup *gzgroup)
{
GizmoGroup *ggd;
@@ -1384,6 +1335,9 @@ static GizmoGroup *gizmogroup_init(wmGizmoGroup *gzgroup)
const wmGizmoType *gzt_dial = WM_gizmotype_find("GIZMO_GT_dial_3d", true);
const wmGizmoType *gzt_prim = WM_gizmotype_find("GIZMO_GT_primitive_3d", true);
+ wmGizmoPropertyFnParams params = {
+ .value_get_fn = rotation_get_fn, .value_set_fn = rotation_set_fn, .user_data = ggd};
+
#define GIZMO_NEW_ARROW(v, draw_style) \
{ \
ggd->gizmos[v] = WM_gizmo_new_ptr(gzt_arrow, gzgroup, NULL); \
@@ -1394,6 +1348,7 @@ static GizmoGroup *gizmogroup_init(wmGizmoGroup *gzgroup)
{ \
ggd->gizmos[v] = WM_gizmo_new_ptr(gzt_dial, gzgroup, NULL); \
RNA_enum_set(ggd->gizmos[v]->ptr, "draw_options", draw_options); \
+ WM_gizmo_target_property_def_func(ggd->gizmos[v], "offset", &params); \
} \
((void)0)
#define GIZMO_NEW_PRIM(v, draw_style) \
@@ -1461,18 +1416,104 @@ static int gizmo_modal(bContext *C,
ARegion *region = CTX_wm_region(C);
RegionView3D *rv3d = region->regiondata;
- struct TransformBounds tbounds;
-
- if (ED_transform_calc_gizmo_stats(C,
- &(struct TransformCalcParams){
- .use_only_center = true,
- },
- &tbounds)) {
- gizmo_prepare_mat(C, rv3d, &tbounds);
- WM_gizmo_set_matrix_location(widget, rv3d->twmat[3]);
+ wmGizmoGroup *gzgroup = widget->parent_gzgroup;
+
+ /* Recalculating the orientation has two problems.
+ * - The matrix calculated based on the transformed selection may not match the matrix
+ * that was set when transform started.
+ * - Inspecting the selection for every update is expensive (for *every* redraw).
+ *
+ * Instead, use #transform_apply_matrix to transform `rv3d->twmat` or the final scale value
+ * when scaling.
+ */
+ if (false) {
+ struct TransformBounds tbounds;
+
+ if (ED_transform_calc_gizmo_stats(C,
+ &(struct TransformCalcParams){
+ .use_only_center = true,
+ },
+ &tbounds)) {
+ gizmo_prepare_mat(C, rv3d, &tbounds);
+ for (wmGizmo *gz = gzgroup->gizmos.first; gz; gz = gz->next) {
+ WM_gizmo_set_matrix_location(gz, rv3d->twmat[3]);
+ }
+ }
}
+ else {
+ GizmoGroup *ggd = gzgroup->customdata;
+
+ short axis_type = 0;
+ MAN_ITER_AXES_BEGIN (axis, axis_idx) {
+ if (axis == widget) {
+ axis_type = gizmo_get_axis_type(axis_idx);
+ break;
+ }
+ }
+ MAN_ITER_AXES_END;
+
+ /* Showing axes which aren't being manipulated doesn't always work so well.
+ *
+ * For rotate: global axis will reset after finish.
+ * Also, gimbal axis isn't properly recalculated while transforming.
+ */
+ if (axis_type == MAN_AXES_ROTATE) {
+ MAN_ITER_AXES_BEGIN (axis, axis_idx) {
+ if (axis == widget) {
+ continue;
+ }
+
+ bool is_plane_dummy;
+ const uint aidx_norm = gizmo_orientation_axis(axis_idx, &is_plane_dummy);
+ /* Always show the axis-aligned handle as it's distracting when it's disabled. */
+ if (aidx_norm == 3) {
+ continue;
+ }
+ WM_gizmo_set_flag(axis, WM_GIZMO_HIDDEN, true);
+ }
+ MAN_ITER_AXES_END;
+ }
- ED_region_tag_redraw_editor_overlays(region);
+ wmWindow *win = CTX_wm_window(C);
+ wmOperator *op = NULL;
+ for (int i = 0; i < widget->op_data_len; i++) {
+ wmGizmoOpElem *gzop = WM_gizmo_operator_get(widget, i);
+ op = WM_operator_find_modal_by_type(win, gzop->type);
+ if (op != NULL) {
+ break;
+ }
+ }
+
+ if (op != NULL) {
+ float twmat[4][4];
+ float scale_buf[3];
+ float *scale = NULL;
+ bool update = false;
+ copy_m4_m4(twmat, rv3d->twmat);
+
+ if (axis_type == MAN_AXES_SCALE) {
+ scale = scale_buf;
+ transform_final_value_get(op->customdata, scale, 3);
+ update = true;
+ }
+ else if (axis_type == MAN_AXES_ROTATE) {
+ transform_final_value_get(op->customdata, &ggd->rotation, 1);
+ if (widget != ggd->gizmos[MAN_AXIS_ROT_C]) {
+ ggd->rotation *= -1;
+ }
+ RNA_float_set(
+ widget->ptr, "incremental_angle", transform_snap_increment_get(op->customdata));
+ }
+ else if (transform_apply_matrix(op->customdata, twmat)) {
+ update = true;
+ }
+
+ if (update) {
+ gizmo_refresh_from_matrix(gzgroup, twmat, scale);
+ ED_region_tag_redraw_editor_overlays(region);
+ }
+ }
+ }
return OPERATOR_RUNNING_MODAL;
}
@@ -1524,9 +1565,8 @@ static void gizmogroup_init_properties_from_twtype(wmGizmoGroup *gzgroup)
case MAN_AXIS_SCALE_XY:
case MAN_AXIS_SCALE_YZ:
case MAN_AXIS_SCALE_ZX: {
- const float ofs_ax = 7.0f;
- const float ofs[3] = {ofs_ax, ofs_ax, 0.0f};
- WM_gizmo_set_scale(axis, 0.07f);
+ const float ofs[3] = {MAN_AXIS_SCALE_PLANE_OFFSET, MAN_AXIS_SCALE_PLANE_OFFSET, 0.0f};
+ WM_gizmo_set_scale(axis, MAN_AXIS_SCALE_PLANE_SCALE);
WM_gizmo_set_matrix_offset_location(axis, ofs);
WM_gizmo_set_flag(axis, WM_GIZMO_DRAW_OFFSET_SCALE, true);
break;
@@ -1638,46 +1678,23 @@ static void WIDGETGROUP_gizmo_setup(const bContext *C, wmGizmoGroup *gzgroup)
gizmogroup_init_properties_from_twtype(gzgroup);
}
-static void WIDGETGROUP_gizmo_refresh(const bContext *C, wmGizmoGroup *gzgroup)
+/**
+ * Set properties for axes.
+ *
+ * \param twmat: The transform matrix (typically #RegionView3D.twmat).
+ * \param scale: Optional scale, to show scale while modally dragging the scale handles.
+ */
+static void gizmo_refresh_from_matrix(wmGizmoGroup *gzgroup,
+ const float twmat[4][4],
+ const float scale[3])
{
GizmoGroup *ggd = gzgroup->customdata;
- Scene *scene = CTX_data_scene(C);
- ScrArea *area = CTX_wm_area(C);
- View3D *v3d = area->spacedata.first;
- ARegion *region = CTX_wm_region(C);
- RegionView3D *rv3d = region->regiondata;
- struct TransformBounds tbounds;
-
- if (ggd->use_twtype_refresh) {
- ggd->twtype = v3d->gizmo_show_object & ggd->twtype_init;
- if (ggd->twtype != ggd->twtype_prev) {
- ggd->twtype_prev = ggd->twtype;
- gizmogroup_init_properties_from_twtype(gzgroup);
- }
- }
-
- const int orient_index = BKE_scene_orientation_get_index_from_flag(scene, ggd->twtype_init);
-
- /* skip, we don't draw anything anyway */
- if ((ggd->all_hidden = (ED_transform_calc_gizmo_stats(C,
- &(struct TransformCalcParams){
- .use_only_center = true,
- .orientation_index = orient_index + 1,
- },
- &tbounds) == 0))) {
- return;
- }
-
- gizmo_prepare_mat(C, rv3d, &tbounds);
-
- /* *** set properties for axes *** */
MAN_ITER_AXES_BEGIN (axis, axis_idx) {
const short axis_type = gizmo_get_axis_type(axis_idx);
const int aidx_norm = gizmo_orientation_axis(axis_idx, NULL);
- WM_gizmo_set_matrix_location(axis, rv3d->twmat[3]);
-
+ WM_gizmo_set_matrix_location(axis, twmat[3]);
switch (axis_idx) {
case MAN_AXIS_TRANS_X:
case MAN_AXIS_TRANS_Y:
@@ -1690,8 +1707,17 @@ static void WIDGETGROUP_gizmo_refresh(const bContext *C, wmGizmoGroup *gzgroup)
gizmo_line_range(ggd->twtype, axis_type, &start_co[2], &len);
- WM_gizmo_set_matrix_rotation_from_z_axis(axis, rv3d->twmat[aidx_norm]);
- RNA_float_set(axis->ptr, "length", len);
+ const float *z_axis = twmat[aidx_norm];
+ if (axis_type == MAN_AXES_SCALE) {
+ /* Scale handles are cubes that don't look right when not aligned with other axes.
+ * This is noticeable when the axis is rotated to something besides the global-axis. */
+ const int aidx_norm_y = (aidx_norm + 2) % 3;
+ const float *y_axis = twmat[aidx_norm_y];
+ WM_gizmo_set_matrix_rotation_from_yz_axis(axis, y_axis, z_axis);
+ }
+ else {
+ WM_gizmo_set_matrix_rotation_from_z_axis(axis, z_axis);
+ }
if (axis_idx >= MAN_AXIS_RANGE_TRANS_START && axis_idx < MAN_AXIS_RANGE_TRANS_END) {
if (ggd->twtype & V3D_GIZMO_SHOW_OBJECT_ROTATE) {
@@ -1699,24 +1725,56 @@ static void WIDGETGROUP_gizmo_refresh(const bContext *C, wmGizmoGroup *gzgroup)
start_co[2] += 0.215f;
}
}
+
+ if (scale) {
+ if (axis_type == MAN_AXES_SCALE) {
+ len = ((start_co[2] + len) * scale[aidx_norm]) - start_co[2];
+ }
+ }
+
+ RNA_float_set(axis->ptr, "length", len);
+
WM_gizmo_set_matrix_offset_location(axis, start_co);
+
WM_gizmo_set_flag(axis, WM_GIZMO_DRAW_OFFSET_SCALE, true);
+
break;
}
case MAN_AXIS_ROT_X:
case MAN_AXIS_ROT_Y:
case MAN_AXIS_ROT_Z:
- WM_gizmo_set_matrix_rotation_from_z_axis(axis, rv3d->twmat[aidx_norm]);
- break;
+ case MAN_AXIS_ROT_C: {
+ if (axis_idx != MAN_AXIS_ROT_C) {
+ WM_gizmo_set_matrix_rotation_from_z_axis(axis, twmat[aidx_norm]);
+ }
+
+ /* Remove #ED_GIZMO_DIAL_DRAW_FLAG_ANGLE_VALUE. It is used only for modal drawing. */
+ PropertyRNA *prop = RNA_struct_find_property(axis->ptr, "draw_options");
+ RNA_property_enum_set(axis->ptr,
+ prop,
+ RNA_property_enum_get(axis->ptr, prop) &
+ ~ED_GIZMO_DIAL_DRAW_FLAG_ANGLE_VALUE);
+ } break;
case MAN_AXIS_TRANS_XY:
case MAN_AXIS_TRANS_YZ:
case MAN_AXIS_TRANS_ZX:
case MAN_AXIS_SCALE_XY:
case MAN_AXIS_SCALE_YZ:
case MAN_AXIS_SCALE_ZX: {
- const float *y_axis = rv3d->twmat[aidx_norm - 1 < 0 ? 2 : aidx_norm - 1];
- const float *z_axis = rv3d->twmat[aidx_norm];
+ const int aidx_norm_x = (aidx_norm + 1) % 3;
+ const int aidx_norm_y = (aidx_norm + 2) % 3;
+ const float *y_axis = twmat[aidx_norm_y];
+ const float *z_axis = twmat[aidx_norm];
WM_gizmo_set_matrix_rotation_from_yz_axis(axis, y_axis, z_axis);
+
+ if (axis_type == MAN_AXES_SCALE) {
+ float ofs[3] = {MAN_AXIS_SCALE_PLANE_OFFSET, MAN_AXIS_SCALE_PLANE_OFFSET, 0.0f};
+ if (scale) {
+ ofs[0] *= scale[aidx_norm_x];
+ ofs[1] *= scale[aidx_norm_y];
+ }
+ WM_gizmo_set_matrix_offset_location(axis, ofs);
+ }
break;
}
}
@@ -1733,6 +1791,49 @@ static void WIDGETGROUP_gizmo_refresh(const bContext *C, wmGizmoGroup *gzgroup)
}
}
+static void WIDGETGROUP_gizmo_refresh(const bContext *C, wmGizmoGroup *gzgroup)
+{
+ ARegion *region = CTX_wm_region(C);
+
+ {
+ wmGizmo *gz = WM_gizmomap_get_modal(region->gizmo_map);
+ if (gz && gz->parent_gzgroup == gzgroup) {
+ return;
+ }
+ }
+
+ GizmoGroup *ggd = gzgroup->customdata;
+ Scene *scene = CTX_data_scene(C);
+ ScrArea *area = CTX_wm_area(C);
+ View3D *v3d = area->spacedata.first;
+ RegionView3D *rv3d = region->regiondata;
+ struct TransformBounds tbounds;
+
+ if (ggd->use_twtype_refresh) {
+ ggd->twtype = v3d->gizmo_show_object & ggd->twtype_init;
+ if (ggd->twtype != ggd->twtype_prev) {
+ ggd->twtype_prev = ggd->twtype;
+ gizmogroup_init_properties_from_twtype(gzgroup);
+ }
+ }
+
+ const int orient_index = BKE_scene_orientation_get_index_from_flag(scene, ggd->twtype_init);
+
+ /* skip, we don't draw anything anyway */
+ if ((ggd->all_hidden = (ED_transform_calc_gizmo_stats(C,
+ &(struct TransformCalcParams){
+ .use_only_center = true,
+ .orientation_index = orient_index + 1,
+ },
+ &tbounds) == 0))) {
+ return;
+ }
+
+ gizmo_prepare_mat(C, rv3d, &tbounds);
+
+ gizmo_refresh_from_matrix(gzgroup, rv3d->twmat, NULL);
+}
+
static void WIDGETGROUP_gizmo_message_subscribe(const bContext *C,
wmGizmoGroup *gzgroup,
struct wmMsgBus *mbus)
@@ -1756,11 +1857,22 @@ static void WIDGETGROUP_gizmo_draw_prepare(const bContext *C, wmGizmoGroup *gzgr
copy_m3_m4(viewinv_m3, rv3d->viewinv);
float idot[3];
+ /* Re-calculate hidden unless modal. */
+ bool is_modal = false;
+ {
+ wmGizmo *gz = WM_gizmomap_get_modal(region->gizmo_map);
+ if (gz && gz->parent_gzgroup == gzgroup) {
+ is_modal = true;
+ }
+ }
+
/* when looking through a selected camera, the gizmo can be at the
* exact same position as the view, skip so we don't break selection */
if (ggd->all_hidden || fabsf(ED_view3d_pixel_size(rv3d, rv3d->twmat[3])) < 5e-7f) {
MAN_ITER_AXES_BEGIN (axis, axis_idx) {
- WM_gizmo_set_flag(axis, WM_GIZMO_HIDDEN, true);
+ if (!is_modal) {
+ WM_gizmo_set_flag(axis, WM_GIZMO_HIDDEN, true);
+ }
}
MAN_ITER_AXES_END;
return;
@@ -1771,12 +1883,15 @@ static void WIDGETGROUP_gizmo_draw_prepare(const bContext *C, wmGizmoGroup *gzgr
MAN_ITER_AXES_BEGIN (axis, axis_idx) {
const short axis_type = gizmo_get_axis_type(axis_idx);
/* XXX maybe unset _HIDDEN flag on redraw? */
-
if (gizmo_is_axis_visible(rv3d, ggd->twtype, idot, axis_type, axis_idx)) {
- WM_gizmo_set_flag(axis, WM_GIZMO_HIDDEN, false);
+ if (!is_modal) {
+ WM_gizmo_set_flag(axis, WM_GIZMO_HIDDEN, false);
+ }
}
else {
- WM_gizmo_set_flag(axis, WM_GIZMO_HIDDEN, true);
+ if (!is_modal) {
+ WM_gizmo_set_flag(axis, WM_GIZMO_HIDDEN, true);
+ }
continue;
}
@@ -1785,13 +1900,15 @@ static void WIDGETGROUP_gizmo_draw_prepare(const bContext *C, wmGizmoGroup *gzgr
WM_gizmo_set_color(axis, color);
WM_gizmo_set_color_highlight(axis, color_hi);
- switch (axis_idx) {
- case MAN_AXIS_TRANS_C:
- case MAN_AXIS_ROT_C:
- case MAN_AXIS_SCALE_C:
- case MAN_AXIS_ROT_T:
- WM_gizmo_set_matrix_rotation_from_z_axis(axis, rv3d->viewinv[2]);
- break;
+ if (!is_modal) {
+ switch (axis_idx) {
+ case MAN_AXIS_TRANS_C:
+ case MAN_AXIS_ROT_C:
+ case MAN_AXIS_SCALE_C:
+ case MAN_AXIS_ROT_T:
+ WM_gizmo_set_matrix_rotation_from_z_axis(axis, rv3d->viewinv[2]);
+ break;
+ }
}
}
MAN_ITER_AXES_END;
@@ -1879,6 +1996,17 @@ static void WIDGETGROUP_gizmo_invoke_prepare(const bContext *C,
}
}
}
+ else if (ELEM(axis_idx, MAN_AXIS_ROT_X, MAN_AXIS_ROT_Y, MAN_AXIS_ROT_Z, MAN_AXIS_ROT_C)) {
+ gizmo_3d_dial_matrixbasis_calc(CTX_wm_region(C),
+ gz->matrix_basis[2],
+ gz->matrix_basis[3],
+ (float[2]){UNPACK2(event->mval)},
+ gz->matrix_basis);
+ PropertyRNA *prop = RNA_struct_find_property(gz->ptr, "draw_options");
+ RNA_property_enum_set(
+ gz->ptr, prop, RNA_property_enum_get(gz->ptr, prop) | ED_GIZMO_DIAL_DRAW_FLAG_ANGLE_VALUE);
+ RNA_float_set(gz->ptr, "incremental_angle", 0.0f);
+ }
}
static bool WIDGETGROUP_gizmo_poll_generic(View3D *v3d)
@@ -1944,8 +2072,8 @@ void VIEW3D_GGT_xform_gizmo(wmGizmoGroupType *gzgt)
gzgt->name = "3D View: Transform Gizmo";
gzgt->idname = "VIEW3D_GGT_xform_gizmo";
- gzgt->flag = WM_GIZMOGROUPTYPE_3D | WM_GIZMOGROUPTYPE_DRAW_MODAL_EXCLUDE |
- WM_GIZMOGROUPTYPE_TOOL_FALLBACK_KEYMAP | WM_GIZMOGROUPTYPE_DELAY_REFRESH_FOR_TWEAK;
+ gzgt->flag = WM_GIZMOGROUPTYPE_3D | WM_GIZMOGROUPTYPE_TOOL_FALLBACK_KEYMAP |
+ WM_GIZMOGROUPTYPE_DELAY_REFRESH_FOR_TWEAK;
gzgt->gzmap_params.spaceid = SPACE_VIEW3D;
gzgt->gzmap_params.regionid = RGN_TYPE_WINDOW;
diff --git a/source/blender/editors/transform/transform_mode.c b/source/blender/editors/transform/transform_mode.c
index 2fd81486bb6..83f1bd35f81 100644
--- a/source/blender/editors/transform/transform_mode.c
+++ b/source/blender/editors/transform/transform_mode.c
@@ -35,7 +35,7 @@
/* Own include. */
#include "transform_mode.h"
-int transform_mode_really_used(bContext *C, int mode)
+eTfmMode transform_mode_really_used(bContext *C, eTfmMode mode)
{
if (mode == TFM_BONESIZE) {
Object *ob = CTX_data_active_object(C);
diff --git a/source/blender/editors/transform/transform_mode.h b/source/blender/editors/transform/transform_mode.h
index 6930b87090c..eac6734ed88 100644
--- a/source/blender/editors/transform/transform_mode.h
+++ b/source/blender/editors/transform/transform_mode.h
@@ -25,7 +25,7 @@ typedef struct TransDataGenericSlideVert {
/* transform_mode.c */
-int transform_mode_really_used(struct bContext *C, int mode);
+eTfmMode transform_mode_really_used(struct bContext *C, eTfmMode mode);
bool transdata_check_local_center(const TransInfo *t, short around);
/**
* Informs if the mode can be switched during modal.
diff --git a/source/blender/editors/transform/transform_mode_rotate.c b/source/blender/editors/transform/transform_mode_rotate.c
index 4b86adc4f46..94caaa288e5 100644
--- a/source/blender/editors/transform/transform_mode_rotate.c
+++ b/source/blender/editors/transform/transform_mode_rotate.c
@@ -322,10 +322,30 @@ static void applyRotation(TransInfo *t, const int UNUSED(mval[2]))
ED_area_status_text(t->area, str);
}
+static void applyRotationMatrix(TransInfo *t, float mat_xform[4][4])
+{
+ float axis_final[3];
+ const float angle_final = t->values_final[0];
+ if ((t->con.mode & CON_APPLY) && t->con.applyRot) {
+ t->con.applyRot(t, NULL, NULL, axis_final, NULL);
+ }
+ else {
+ negate_v3_v3(axis_final, t->spacemtx[t->orient_axis]);
+ }
+
+ float mat3[3][3];
+ float mat4[4][4];
+ axis_angle_normalized_to_mat3(mat3, axis_final, angle_final);
+ copy_m4_m3(mat4, mat3);
+ transform_pivot_set_m4(mat4, t->center_global);
+ mul_m4_m4m4(mat_xform, mat4, mat_xform);
+}
+
void initRotation(TransInfo *t)
{
t->mode = TFM_ROTATION;
t->transform = applyRotation;
+ t->transform_matrix = applyRotationMatrix;
t->tsnap.applySnap = ApplySnapRotation;
t->tsnap.distance = RotationBetween;
diff --git a/source/blender/editors/transform/transform_mode_trackball.c b/source/blender/editors/transform/transform_mode_trackball.c
index 2e405449bc3..3716826800b 100644
--- a/source/blender/editors/transform/transform_mode_trackball.c
+++ b/source/blender/editors/transform/transform_mode_trackball.c
@@ -75,19 +75,25 @@ static void transdata_elem_trackball_fn(void *__restrict iter_data_v,
/** \name Transform (Rotation - Trackball)
* \{ */
-static void applyTrackballValue(TransInfo *t,
- const float axis1[3],
- const float axis2[3],
- const float angles[2])
+static void applyTrackballValue_calc_axis_angle(const TransInfo *t,
+ const float phi[2],
+ float r_axis[3],
+ float *r_angle)
+{
+ float axis1[3], axis2[3];
+ normalize_v3_v3(axis1, t->persinv[0]);
+ normalize_v3_v3(axis2, t->persinv[1]);
+
+ mul_v3_v3fl(r_axis, axis1, phi[0]);
+ madd_v3_v3fl(r_axis, axis2, phi[1]);
+ *r_angle = normalize_v3(r_axis);
+}
+
+static void applyTrackballValue(TransInfo *t, const float axis[3], const float angle)
{
float mat_final[3][3];
- float axis[3];
- float angle;
int i;
- mul_v3_v3fl(axis, axis1, angles[0]);
- madd_v3_v3fl(axis, axis2, angles[1]);
- angle = normalize_v3(axis);
axis_angle_normalized_to_mat3(mat_final, axis, angle);
FOREACH_TRANS_DATA_CONTAINER (t, tc) {
@@ -120,17 +126,8 @@ static void applyTrackball(TransInfo *t, const int UNUSED(mval[2]))
{
char str[UI_MAX_DRAW_STR];
size_t ofs = 0;
- float axis1[3], axis2[3];
-#if 0 /* UNUSED */
- float mat[3][3], totmat[3][3], smat[3][3];
-#endif
float phi[2];
- copy_v3_v3(axis1, t->persinv[0]);
- copy_v3_v3(axis2, t->persinv[1]);
- normalize_v3(axis1);
- normalize_v3(axis2);
-
copy_v2_v2(phi, t->values);
transform_snap_increment(t, phi);
@@ -165,27 +162,35 @@ static void applyTrackball(TransInfo *t, const int UNUSED(mval[2]))
str + ofs, sizeof(str) - ofs, TIP_(" Proportional size: %.2f"), t->prop_size);
}
-#if 0 /* UNUSED */
- axis_angle_normalized_to_mat3(smat, axis1, phi[0]);
- axis_angle_normalized_to_mat3(totmat, axis2, phi[1]);
+ float axis_final[3], angle_final;
+ applyTrackballValue_calc_axis_angle(t, phi, axis_final, &angle_final);
+ applyTrackballValue(t, axis_final, angle_final);
- mul_m3_m3m3(mat, smat, totmat);
+ recalcData(t);
- /* TRANSFORM_FIX_ME */
- // copy_m3_m3(t->mat, mat); /* used in gizmo. */
-#endif
+ ED_area_status_text(t->area, str);
+}
- applyTrackballValue(t, axis1, axis2, phi);
+static void applyTrackballMatrix(TransInfo *t, float mat_xform[4][4])
+{
+ const float phi[2] = {UNPACK2(t->values_final)};
- recalcData(t);
+ float axis_final[3], angle_final;
+ applyTrackballValue_calc_axis_angle(t, phi, axis_final, &angle_final);
- ED_area_status_text(t->area, str);
+ float mat3[3][3], mat4[4][4];
+ axis_angle_normalized_to_mat3(mat3, axis_final, angle_final);
+
+ copy_m4_m3(mat4, mat3);
+ transform_pivot_set_m4(mat4, t->center_global);
+ mul_m4_m4m4(mat_xform, mat4, mat_xform);
}
void initTrackball(TransInfo *t)
{
t->mode = TFM_TRACKBALL;
t->transform = applyTrackball;
+ t->transform_matrix = applyTrackballMatrix;
initMouseInputMode(t, &t->mouse, INPUT_TRACKBALL);
diff --git a/source/blender/editors/transform/transform_mode_translate.c b/source/blender/editors/transform/transform_mode_translate.c
index c881cde351e..3c6b6ea4117 100644
--- a/source/blender/editors/transform/transform_mode_translate.c
+++ b/source/blender/editors/transform/transform_mode_translate.c
@@ -469,7 +469,7 @@ static void applyTranslation(TransInfo *t, const int UNUSED(mval[2]))
add_v3_v3(global_dir, values_ofs);
}
- t->tsnap.snapElem = 0;
+ t->tsnap.snapElem = SCE_SNAP_MODE_NONE;
applySnapping(t, global_dir);
transform_snap_grid(t, global_dir);
@@ -486,7 +486,7 @@ static void applyTranslation(TransInfo *t, const int UNUSED(mval[2]))
/* Test for mixed snap with grid. */
float snap_dist_sq = FLT_MAX;
- if (t->tsnap.snapElem != 0) {
+ if (t->tsnap.snapElem != SCE_SNAP_MODE_NONE) {
snap_dist_sq = len_squared_v3v3(t->values, global_dir);
}
if ((snap_dist_sq == FLT_MAX) || (len_squared_v3v3(global_dir, incr_dir) < snap_dist_sq)) {
@@ -518,6 +518,13 @@ static void applyTranslation(TransInfo *t, const int UNUSED(mval[2]))
ED_area_status_text(t->area, str);
}
+static void applyTranslationMatrix(TransInfo *t, float mat_xform[4][4])
+{
+ float delta[3];
+ mul_v3_m3v3(delta, t->spacemtx, t->values_final);
+ add_v3_v3(mat_xform[3], delta);
+}
+
void initTranslation(TransInfo *t)
{
if (t->spacetype == SPACE_ACTION) {
@@ -530,6 +537,7 @@ void initTranslation(TransInfo *t)
}
t->transform = applyTranslation;
+ t->transform_matrix = applyTranslationMatrix;
t->tsnap.applySnap = ApplySnapTranslation;
t->tsnap.distance = transform_snap_distance_len_squared_fn;
diff --git a/source/blender/editors/transform/transform_ops.c b/source/blender/editors/transform/transform_ops.c
index 600f525b428..cd8a2f17554 100644
--- a/source/blender/editors/transform/transform_ops.c
+++ b/source/blender/editors/transform/transform_ops.c
@@ -419,7 +419,7 @@ static int transform_modal(bContext *C, wmOperator *op, const wmEvent *event)
/* XXX, workaround: active needs to be calculated before transforming,
* since we're not reading from 'td->center' in this case. see: T40241 */
- if (t->tsnap.target == SCE_SNAP_TARGET_ACTIVE) {
+ if (t->tsnap.source_select == SCE_SNAP_SOURCE_ACTIVE) {
/* In camera view, tsnap callback is not set
* (see #initSnappingMode() in transform_snap.c, and T40348). */
if (t->tsnap.targetSnap && ((t->tsnap.status & TARGET_INIT) == 0)) {
@@ -648,7 +648,11 @@ void Transform_Properties(struct wmOperatorType *ot, int flags)
RNA_def_property_flag(prop, PROP_HIDDEN);
if (flags & P_GEO_SNAP) {
- prop = RNA_def_enum(ot->srna, "snap_target", rna_enum_snap_target_items, 0, "Target", "");
+ /* TODO(@gfxcoder): Rename `snap_target` to `snap_source` to avoid
+ * previous ambiguity of "target" (now, "source" is geometry to be moved and "target" is
+ * geometry to which moved geometry is snapped). Use "Source snap point" and "Point on
+ * source that will snap to target" for name and description, respectively. */
+ prop = RNA_def_enum(ot->srna, "snap_target", rna_enum_snap_source_items, 0, "Target", "");
RNA_def_property_flag(prop, PROP_HIDDEN);
prop = RNA_def_float_vector(
ot->srna, "snap_point", 3, NULL, -FLT_MAX, FLT_MAX, "Point", "", -FLT_MAX, FLT_MAX);
diff --git a/source/blender/editors/transform/transform_snap.c b/source/blender/editors/transform/transform_snap.c
index e119b264ae7..649217092aa 100644
--- a/source/blender/editors/transform/transform_snap.c
+++ b/source/blender/editors/transform/transform_snap.c
@@ -79,8 +79,8 @@ static void TargetSnapActive(TransInfo *t);
/** \name Implementations
* \{ */
-static bool snapNodeTest(View2D *v2d, bNode *node, eSnapSelect snap_select);
-static NodeBorder snapNodeBorder(int snap_node_mode);
+static bool snapNodeTest(View2D *v2d, bNode *node, eSnapTargetSelect snap_target_select);
+static NodeBorder snapNodeBorder(eSnapMode snap_node_mode);
#if 0
int BIF_snappingSupported(Object *obedit)
@@ -377,56 +377,59 @@ void applyProject(TransInfo *t)
if (ED_view3d_project_float_global(t->region, iloc, mval_fl, V3D_PROJ_TEST_NOP) ==
V3D_PROJ_RET_OK) {
- if (ED_transform_snap_object_project_view3d(
- t->tsnap.object_context,
- t->depsgraph,
- t->region,
- t->view,
- SCE_SNAP_MODE_FACE,
- &(const struct SnapObjectParams){
- .snap_select = t->tsnap.modeSelect,
- .edit_mode_type = (t->flag & T_EDIT) != 0 ? SNAP_GEOM_EDIT : SNAP_GEOM_FINAL,
- .use_occlusion_test = false,
- .use_backface_culling = t->tsnap.use_backface_culling,
- },
- mval_fl,
- NULL,
- 0,
- loc,
- no)) {
+ eSnapMode hit = ED_transform_snap_object_project_view3d(
+ t->tsnap.object_context,
+ t->depsgraph,
+ t->region,
+ t->view,
+ SCE_SNAP_MODE_FACE,
+ &(const struct SnapObjectParams){
+ .snap_target_select = t->tsnap.target_select,
+ .edit_mode_type = (t->flag & T_EDIT) != 0 ? SNAP_GEOM_EDIT : SNAP_GEOM_FINAL,
+ .use_occlusion_test = false,
+ .use_backface_culling = t->tsnap.use_backface_culling,
+ },
+ mval_fl,
+ NULL,
+ 0,
+ loc,
+ no);
+ if (hit != SCE_SNAP_MODE_FACE) {
+ return;
+ }
+
#if 0
- if (tc->use_local_mat) {
- mul_m4_v3(tc->imat, loc);
- }
+ if (tc->use_local_mat) {
+ mul_m4_v3(tc->imat, loc);
+ }
#endif
- sub_v3_v3v3(tvec, loc, iloc);
+ sub_v3_v3v3(tvec, loc, iloc);
- mul_m3_v3(td->smtx, tvec);
+ mul_m3_v3(td->smtx, tvec);
- add_v3_v3(td->loc, tvec);
+ add_v3_v3(td->loc, tvec);
- if (t->tsnap.align && (t->options & CTX_OBJECT)) {
- /* handle alignment as well */
- const float *original_normal;
- float mat[3][3];
+ if (t->tsnap.align && (t->options & CTX_OBJECT)) {
+ /* handle alignment as well */
+ const float *original_normal;
+ float mat[3][3];
- /* In pose mode, we want to align normals with Y axis of bones... */
- original_normal = td->axismtx[2];
+ /* In pose mode, we want to align normals with Y axis of bones... */
+ original_normal = td->axismtx[2];
- rotation_between_vecs_to_mat3(mat, original_normal, no);
+ rotation_between_vecs_to_mat3(mat, original_normal, no);
- transform_data_ext_rotate(td, mat, true);
+ transform_data_ext_rotate(td, mat, true);
- /* TODO: support constraints for rotation too? see #ElementRotation. */
- }
+ /* TODO: support constraints for rotation too? see #ElementRotation. */
}
}
+ }
#if 0 /* TODO: support this? */
- constraintTransLim(t, td);
+ constraintTransLim(t, td);
#endif
- }
}
}
@@ -522,13 +525,13 @@ void applySnapping(TransInfo *t, float *vec)
void resetSnapping(TransInfo *t)
{
- t->tsnap.status = 0;
- t->tsnap.snapElem = 0;
+ t->tsnap.status = SNAP_RESETTED;
+ t->tsnap.snapElem = SCE_SNAP_MODE_NONE;
t->tsnap.align = false;
- t->tsnap.project = 0;
- t->tsnap.mode = 0;
- t->tsnap.modeSelect = 0;
- t->tsnap.target = 0;
+ t->tsnap.project = false;
+ t->tsnap.mode = SCE_SNAP_MODE_NONE;
+ t->tsnap.target_select = SCE_SNAP_TARGET_ALL;
+ t->tsnap.source_select = SCE_SNAP_SOURCE_CLOSEST;
t->tsnap.last = 0;
t->tsnap.snapNormal[0] = 0;
@@ -581,7 +584,7 @@ static bool bm_face_is_snap_target(BMFace *f, void *UNUSED(user_data))
return true;
}
-static char snap_flag_from_spacetype(TransInfo *t)
+static eSnapFlag snap_flag_from_spacetype(TransInfo *t)
{
ToolSettings *ts = t->settings;
if (t->spacetype == SPACE_NODE) {
@@ -596,7 +599,7 @@ static char snap_flag_from_spacetype(TransInfo *t)
return ts->snap_flag;
}
-static short snap_mode_from_spacetype(TransInfo *t)
+static eSnapMode snap_mode_from_spacetype(TransInfo *t)
{
ToolSettings *ts = t->settings;
@@ -605,7 +608,7 @@ static short snap_mode_from_spacetype(TransInfo *t)
}
if (t->spacetype == SPACE_IMAGE) {
- short snap_mode = ts->snap_uv_mode;
+ eSnapMode snap_mode = ts->snap_uv_mode;
if ((snap_mode & SCE_SNAP_MODE_INCREMENT) && (ts->snap_uv_flag & SCE_SNAP_ABS_GRID) &&
(t->mode == TFM_TRANSLATION)) {
snap_mode &= ~SCE_SNAP_MODE_INCREMENT;
@@ -623,7 +626,7 @@ static short snap_mode_from_spacetype(TransInfo *t)
return SCE_SNAP_MODE_INCREMENT;
}
- short snap_mode = ts->snap_mode;
+ eSnapMode snap_mode = ts->snap_mode;
if ((snap_mode & SCE_SNAP_MODE_INCREMENT) && (ts->snap_flag & SCE_SNAP_ABS_GRID) &&
(t->mode == TFM_TRANSLATION)) {
/* Special case in which snap to increments is transformed to snap to grid. */
@@ -641,7 +644,7 @@ static short snap_mode_from_spacetype(TransInfo *t)
return SCE_SNAP_MODE_INCREMENT;
}
-static short snap_select_type_get(TransInfo *t)
+static eSnapTargetSelect snap_select_type_get(TransInfo *t)
{
ViewLayer *view_layer = t->view_layer;
Base *base_act = view_layer->basact;
@@ -652,7 +655,7 @@ static short snap_select_type_get(TransInfo *t)
* TODO: perform self snap in gpencil_strokes.
*
* When we're moving the origins, allow snapping onto our own geometry (see T69132). */
- return SNAP_ALL;
+ return SCE_SNAP_TARGET_ALL;
}
const int obedit_type = t->obedit_type;
@@ -669,44 +672,44 @@ static short snap_select_type_get(TransInfo *t)
if ((obedit_type == OB_MESH) && (t->flag & T_PROP_EDIT)) {
/* Exclude editmesh if using proportional edit */
- return SNAP_NOT_EDITED;
+ return SCE_SNAP_TARGET_NOT_EDITED;
}
if (!t->tsnap.snap_self) {
- return SNAP_NOT_ACTIVE;
+ return SCE_SNAP_TARGET_NOT_ACTIVE;
}
- return SNAP_NOT_SELECTED;
+ return SCE_SNAP_TARGET_NOT_SELECTED;
}
- return SNAP_ALL;
+ return SCE_SNAP_TARGET_ALL;
}
if (base_act && (base_act->object->mode & OB_MODE_PARTICLE_EDIT)) {
/* Particles edit mode. */
- return SNAP_ALL;
+ return SCE_SNAP_TARGET_ALL;
}
/* Object or pose mode. */
- return SNAP_NOT_SELECTED;
+ return SCE_SNAP_TARGET_NOT_SELECTED;
}
if (ELEM(t->spacetype, SPACE_NODE, SPACE_SEQ)) {
- return SNAP_NOT_SELECTED;
+ return SCE_SNAP_TARGET_NOT_SELECTED;
}
- return SNAP_ALL;
+ return SCE_SNAP_TARGET_ALL;
}
static void initSnappingMode(TransInfo *t)
{
ToolSettings *ts = t->settings;
t->tsnap.mode = snap_mode_from_spacetype(t);
- t->tsnap.modeSelect = snap_select_type_get(t);
+ t->tsnap.target_select = snap_select_type_get(t);
if ((t->spacetype != SPACE_VIEW3D) || !(ts->snap_mode & SCE_SNAP_MODE_FACE)) {
/* Force project off when not supported. */
- t->tsnap.project = 0;
+ t->tsnap.project = false;
}
if (ELEM(t->spacetype, SPACE_VIEW3D, SPACE_IMAGE, SPACE_NODE, SPACE_SEQ)) {
@@ -752,7 +755,7 @@ void initSnapping(TransInfo *t, wmOperator *op)
{
resetSnapping(t);
t->tsnap.flag = snap_flag_from_spacetype(t);
- short snap_target = t->settings->snap_target;
+ eSnapSourceSelect snap_source = t->settings->snap_target;
/* if snap property exists */
PropertyRNA *prop;
@@ -763,7 +766,10 @@ void initSnapping(TransInfo *t, wmOperator *op)
if ((prop = RNA_struct_find_property(op->ptr, "snap_target")) &&
RNA_property_is_set(op->ptr, prop)) {
- snap_target = RNA_property_enum_get(op->ptr, prop);
+ /* TODO(@gfxcoder): Rename `snap_target` to `snap_source` to avoid
+ * previous ambiguity of "target" (now, "source" is geometry to be moved and "target" is
+ * geometry to which moved geometry is snapped). */
+ snap_source = RNA_property_enum_get(op->ptr, prop);
}
if ((prop = RNA_struct_find_property(op->ptr, "snap_point")) &&
@@ -803,7 +809,7 @@ void initSnapping(TransInfo *t, wmOperator *op)
t->tsnap.peel = ((t->tsnap.flag & SCE_SNAP_PROJECT) != 0);
}
- t->tsnap.target = snap_target;
+ t->tsnap.source_select = snap_source;
initSnappingMode(t);
}
@@ -844,11 +850,11 @@ static void setSnappingCallback(TransInfo *t)
return;
}
- switch (t->tsnap.target) {
- case SCE_SNAP_TARGET_CLOSEST:
+ switch (t->tsnap.source_select) {
+ case SCE_SNAP_SOURCE_CLOSEST:
t->tsnap.targetSnap = TargetSnapClosest;
break;
- case SCE_SNAP_TARGET_CENTER:
+ case SCE_SNAP_SOURCE_CENTER:
if (!ELEM(t->mode, TFM_ROTATION, TFM_RESIZE)) {
t->tsnap.targetSnap = TargetSnapCenter;
break;
@@ -856,10 +862,10 @@ static void setSnappingCallback(TransInfo *t)
/* Can't do TARGET_CENTER with these modes,
* use TARGET_MEDIAN instead. */
ATTR_FALLTHROUGH;
- case SCE_SNAP_TARGET_MEDIAN:
+ case SCE_SNAP_SOURCE_MEDIAN:
t->tsnap.targetSnap = TargetSnapMedian;
break;
- case SCE_SNAP_TARGET_ACTIVE:
+ case SCE_SNAP_SOURCE_ACTIVE:
t->tsnap.targetSnap = TargetSnapActive;
break;
}
@@ -973,7 +979,7 @@ static void snap_calc_view3d_fn(TransInfo *t, float *UNUSED(vec))
float no[3];
float mval[2];
bool found = false;
- short snap_elem = 0;
+ eSnapMode snap_elem = SCE_SNAP_MODE_NONE;
float dist_px = SNAP_MIN_DISTANCE; /* Use a user defined value here. */
mval[0] = t->mval[0];
@@ -982,7 +988,7 @@ static void snap_calc_view3d_fn(TransInfo *t, float *UNUSED(vec))
if (t->tsnap.mode & SCE_SNAP_MODE_GEOM) {
zero_v3(no); /* objects won't set this */
snap_elem = snapObjectsTransform(t, mval, &dist_px, loc, no);
- found = snap_elem != 0;
+ found = (snap_elem != SCE_SNAP_MODE_NONE);
}
if ((found == false) && (t->tsnap.mode & SCE_SNAP_MODE_VOLUME)) {
found = peelObjectsTransform(
@@ -1003,7 +1009,7 @@ static void snap_calc_view3d_fn(TransInfo *t, float *UNUSED(vec))
t->tsnap.status &= ~POINT_INIT;
}
- t->tsnap.snapElem = (char)snap_elem;
+ t->tsnap.snapElem = snap_elem;
}
static void snap_calc_uv_fn(TransInfo *t, float *UNUSED(vec))
@@ -1020,7 +1026,7 @@ static void snap_calc_uv_fn(TransInfo *t, float *UNUSED(vec))
objects,
objects_len,
t->mval,
- true,
+ t->tsnap.target_select == SCE_SNAP_TARGET_NOT_SELECTED,
&dist_sq,
t->tsnap.snapPoint)) {
t->tsnap.snapPoint[0] *= t->aspect[0];
@@ -1190,7 +1196,7 @@ static void TargetSnapActive(TransInfo *t)
}
/* No active, default to median */
else {
- t->tsnap.target = SCE_SNAP_TARGET_MEDIAN;
+ t->tsnap.source_select = SCE_SNAP_SOURCE_MEDIAN;
t->tsnap.targetSnap = TargetSnapMedian;
TargetSnapMedian(t);
}
@@ -1302,7 +1308,7 @@ static void TargetSnapClosest(TransInfo *t)
/** \name Snap Objects
* \{ */
-short snapObjectsTransform(
+eSnapMode snapObjectsTransform(
TransInfo *t, const float mval[2], float *dist_px, float r_loc[3], float r_no[3])
{
float *target = (t->tsnap.status & TARGET_INIT) ? t->tsnap.snapTarget : t->center_global;
@@ -1313,7 +1319,7 @@ short snapObjectsTransform(
t->view,
t->tsnap.mode,
&(const struct SnapObjectParams){
- .snap_select = t->tsnap.modeSelect,
+ .snap_target_select = t->tsnap.target_select,
.edit_mode_type = (t->flag & T_EDIT) != 0 ? SNAP_GEOM_EDIT : SNAP_GEOM_FINAL,
.use_occlusion_test = t->settings->snap_mode != SCE_SNAP_MODE_FACE,
.use_backface_culling = t->tsnap.use_backface_culling,
@@ -1346,7 +1352,7 @@ bool peelObjectsTransform(TransInfo *t,
t->region,
t->view,
&(const struct SnapObjectParams){
- .snap_select = t->tsnap.modeSelect,
+ .snap_target_select = t->tsnap.target_select,
.edit_mode_type = (t->flag & T_EDIT) != 0 ? SNAP_GEOM_EDIT : SNAP_GEOM_FINAL,
},
mval,
@@ -1414,16 +1420,16 @@ bool peelObjectsTransform(TransInfo *t,
/** \name snap Nodes
* \{ */
-static bool snapNodeTest(View2D *v2d, bNode *node, eSnapSelect snap_select)
+static bool snapNodeTest(View2D *v2d, bNode *node, eSnapTargetSelect snap_target_select)
{
/* node is use for snapping only if a) snap mode matches and b) node is inside the view */
- return ((snap_select == SNAP_NOT_SELECTED && !(node->flag & NODE_SELECT)) ||
- (snap_select == SNAP_ALL && !(node->flag & NODE_ACTIVE))) &&
+ return ((snap_target_select == SCE_SNAP_TARGET_NOT_SELECTED && !(node->flag & NODE_SELECT)) ||
+ (snap_target_select == SCE_SNAP_TARGET_ALL && !(node->flag & NODE_ACTIVE))) &&
(node->totr.xmin < v2d->cur.xmax && node->totr.xmax > v2d->cur.xmin &&
node->totr.ymin < v2d->cur.ymax && node->totr.ymax > v2d->cur.ymin);
}
-static NodeBorder snapNodeBorder(int snap_node_mode)
+static NodeBorder snapNodeBorder(eSnapMode snap_node_mode)
{
NodeBorder flag = 0;
if (snap_node_mode & SCE_SNAP_MODE_NODE_X) {
@@ -1499,7 +1505,7 @@ static bool snapNodes(ToolSettings *ts,
SpaceNode *snode,
ARegion *region,
const int mval[2],
- eSnapSelect snap_select,
+ eSnapTargetSelect snap_target_select,
float r_loc[2],
float *r_dist_px,
char *r_node_border)
@@ -1511,7 +1517,7 @@ static bool snapNodes(ToolSettings *ts,
*r_node_border = 0;
for (node = ntree->nodes.first; node; node = node->next) {
- if (snapNodeTest(&region->v2d, node, snap_select)) {
+ if (snapNodeTest(&region->v2d, node, snap_target_select)) {
retval |= snapNode(ts, snode, region, node, mval, r_loc, r_dist_px, r_node_border);
}
}
@@ -1526,7 +1532,7 @@ bool snapNodesTransform(
t->area->spacedata.first,
t->region,
mval,
- t->tsnap.modeSelect,
+ t->tsnap.target_select,
r_loc,
r_dist_px,
r_node_border);
@@ -1548,7 +1554,7 @@ static void snap_grid_apply(
float in[3];
if (t->con.mode & CON_APPLY) {
- BLI_assert(t->tsnap.snapElem == 0);
+ BLI_assert(t->tsnap.snapElem == SCE_SNAP_MODE_NONE);
t->con.applyVec(t, NULL, NULL, loc, in);
}
else {
@@ -1676,6 +1682,16 @@ bool transform_snap_increment(const TransInfo *t, float *r_val)
return transform_snap_increment_ex(t, false, r_val);
}
+float transform_snap_increment_get(const TransInfo *t)
+{
+ if (activeSnap(t) && (!transformModeUseSnap(t) ||
+ (t->tsnap.mode & (SCE_SNAP_MODE_INCREMENT | SCE_SNAP_MODE_GRID)))) {
+ return (t->modifiers & MOD_PRECISION) ? t->snap[1] : t->snap[0];
+ }
+
+ return 0.0f;
+}
+
/** \} */
/* -------------------------------------------------------------------- */
diff --git a/source/blender/editors/transform/transform_snap.h b/source/blender/editors/transform/transform_snap.h
index cde97d14be4..6db027df067 100644
--- a/source/blender/editors/transform/transform_snap.h
+++ b/source/blender/editors/transform/transform_snap.h
@@ -19,12 +19,12 @@ bool peelObjectsTransform(struct TransInfo *t,
float r_no[3],
float *r_thickness);
-short snapObjectsTransform(struct TransInfo *t,
- const float mval[2],
- float *dist_px,
- /* return args */
- float r_loc[3],
- float r_no[3]);
+eSnapMode snapObjectsTransform(struct TransInfo *t,
+ const float mval[2],
+ float *dist_px,
+ /* return args */
+ float r_loc[3],
+ float r_no[3]);
bool snapNodesTransform(struct TransInfo *t,
const int mval[2],
/* return args */
@@ -36,6 +36,7 @@ bool transformModeUseSnap(const TransInfo *t);
bool transform_snap_increment_ex(const TransInfo *t, bool use_local_space, float *r_val);
bool transform_snap_increment(const TransInfo *t, float *val);
+float transform_snap_increment_get(const TransInfo *t);
bool transform_snap_grid(TransInfo *t, float *val);
bool activeSnap(const TransInfo *t);
diff --git a/source/blender/editors/transform/transform_snap_object.cc b/source/blender/editors/transform/transform_snap_object.cc
index fade7f47d9c..cf99d4b2ef3 100644
--- a/source/blender/editors/transform/transform_snap_object.cc
+++ b/source/blender/editors/transform/transform_snap_object.cc
@@ -157,7 +157,7 @@ struct SnapObjectContext {
enum eViewProj view_proj;
float clip_plane[MAX_CLIPPLANE_LEN][4];
short clip_plane_len;
- short snap_to_flag;
+ eSnapMode snap_to_flag;
bool has_occlusion_plane; /* Ignore plane of occlusion in curves. */
} runtime;
};
@@ -168,8 +168,13 @@ struct SnapObjectContext {
/** \name Utilities
* \{ */
-/* Mesh used for snapping.
- * If nullptr the BMesh should be used. */
+/**
+ * Mesh used for snapping.
+ *
+ * - When the return value is null the `BKE_editmesh_from_object(ob_eval)` should be used.
+ * - In rare cases there is no evaluated mesh available and a null result doesn't imply an
+ * edit-mesh, so callers need to account for a null edit-mesh too, see: T96536.
+ */
static const Mesh *mesh_for_snap(Object *ob_eval, eSnapEditType edit_mode_type, bool *r_use_hide)
{
const Mesh *me_eval = BKE_object_get_evaluated_mesh(ob_eval);
@@ -278,8 +283,10 @@ static SnapData_Mesh *snap_object_data_mesh_get(SnapObjectContext *sctx,
}
}
else {
- /* Any existing #SnapData_EditMesh is now invalid. */
- sctx->editmesh_caches.remove(BKE_editmesh_from_object(ob_eval));
+ if (ob_eval->type == OB_MESH) {
+ /* Any existing #SnapData_EditMesh is now invalid. */
+ sctx->editmesh_caches.remove(BKE_editmesh_from_object(ob_eval));
+ }
std::unique_ptr<SnapData_Mesh> sod_ptr = std::make_unique<SnapData_Mesh>();
sod = sod_ptr.get();
@@ -412,7 +419,7 @@ using IterSnapObjsCallback = void (*)(SnapObjectContext *sctx,
void *data);
static bool snap_object_is_snappable(const SnapObjectContext *sctx,
- const eSnapSelect snap_select,
+ const eSnapTargetSelect snap_select,
const Base *base_act,
const Base *base,
const bool is_in_object_mode)
@@ -421,7 +428,7 @@ static bool snap_object_is_snappable(const SnapObjectContext *sctx,
return false;
}
- if ((snap_select == SNAP_ALL) || (base->flag_legacy & BA_TRANSFORM_LOCKED_IN_PLACE)) {
+ if ((snap_select == SCE_SNAP_TARGET_ALL) || (base->flag_legacy & BA_TRANSFORM_LOCKED_IN_PLACE)) {
return true;
}
@@ -429,15 +436,15 @@ static bool snap_object_is_snappable(const SnapObjectContext *sctx,
return false;
}
- if (snap_select == SNAP_NOT_ACTIVE) {
+ if (snap_select == SCE_SNAP_TARGET_NOT_ACTIVE) {
return base_act != base;
}
- if (snap_select == SNAP_NOT_EDITED) {
+ if (snap_select == SCE_SNAP_TARGET_NOT_EDITED) {
return base->object->mode != OB_MODE_EDIT;
}
- if (snap_select == SNAP_NOT_SELECTED) {
+ if (snap_select == SCE_SNAP_TARGET_NOT_SELECTED) {
if (is_in_object_mode) {
return !((base->flag & BASE_SELECTED) || (base->flag_legacy & BA_WAS_SEL));
}
@@ -446,7 +453,7 @@ static bool snap_object_is_snappable(const SnapObjectContext *sctx,
return true;
}
- if (snap_select == SNAP_SELECTABLE) {
+ if (snap_select == SCE_SNAP_TARGET_ONLY_SELECTABLE) {
return (base->flag & BASE_SELECTABLE) != 0;
}
@@ -462,12 +469,12 @@ static void iter_snap_objects(SnapObjectContext *sctx,
void *data)
{
ViewLayer *view_layer = DEG_get_input_view_layer(sctx->runtime.depsgraph);
- const eSnapSelect snap_select = params->snap_select;
+ const eSnapTargetSelect snap_target_select = params->snap_target_select;
Base *base_act = view_layer->basact;
const bool is_in_object_mode = !base_act || base_act->object->mode == OB_MODE_OBJECT;
LISTBASE_FOREACH (Base *, base, &view_layer->object_bases) {
- if (!snap_object_is_snappable(sctx, snap_select, base_act, base, is_in_object_mode)) {
+ if (!snap_object_is_snappable(sctx, snap_target_select, base_act, base, is_in_object_mode)) {
continue;
}
@@ -998,6 +1005,9 @@ static void raycast_obj_fn(SnapObjectContext *sctx,
const Mesh *me_eval = mesh_for_snap(ob_eval, edit_mode_type, &use_hide);
if (me_eval == nullptr) {
BMEditMesh *em = BKE_editmesh_from_object(ob_eval);
+ if (UNLIKELY(!em)) { /* See #mesh_for_snap doc-string. */
+ return;
+ }
BLI_assert_msg(em == BKE_editmesh_from_object(DEG_get_original_object(ob_eval)),
"Make sure there is only one pointer for looptris");
retval = raycastEditMesh(sctx,
@@ -1525,18 +1535,18 @@ static void nearest2d_data_init_editmesh(SnapData_EditMesh *sod,
/** \name Internal Object Snapping API
* \{ */
-static short snap_mesh_polygon(SnapObjectContext *sctx,
- const SnapObjectParams *params,
- Object *ob_eval,
- const float obmat[4][4],
- /* read/write args */
- float *dist_px,
- /* return args */
- float r_loc[3],
- float r_no[3],
- int *r_index)
+static eSnapMode snap_mesh_polygon(SnapObjectContext *sctx,
+ const SnapObjectParams *params,
+ Object *ob_eval,
+ const float obmat[4][4],
+ /* read/write args */
+ float *dist_px,
+ /* return args */
+ float r_loc[3],
+ float r_no[3],
+ int *r_index)
{
- short elem = 0;
+ eSnapMode elem = SCE_SNAP_MODE_NONE;
float lpmat[4][4];
mul_m4_m4m4(lpmat, sctx->runtime.pmat, obmat);
@@ -1655,23 +1665,23 @@ static short snap_mesh_polygon(SnapObjectContext *sctx,
return elem;
}
- return 0;
+ return SCE_SNAP_MODE_NONE;
}
-static short snap_mesh_edge_verts_mixed(SnapObjectContext *sctx,
- const SnapObjectParams *params,
- Object *ob_eval,
- const float obmat[4][4],
- float original_dist_px,
- const float prev_co[3],
- /* read/write args */
- float *dist_px,
- /* return args */
- float r_loc[3],
- float r_no[3],
- int *r_index)
+static eSnapMode snap_mesh_edge_verts_mixed(SnapObjectContext *sctx,
+ const SnapObjectParams *params,
+ Object *ob_eval,
+ const float obmat[4][4],
+ float original_dist_px,
+ const float prev_co[3],
+ /* read/write args */
+ float *dist_px,
+ /* return args */
+ float r_loc[3],
+ float r_no[3],
+ int *r_index)
{
- short elem = SCE_SNAP_MODE_EDGE;
+ eSnapMode elem = SCE_SNAP_MODE_EDGE;
if (ob_eval->type != OB_MESH) {
return elem;
@@ -1818,19 +1828,19 @@ static short snap_mesh_edge_verts_mixed(SnapObjectContext *sctx,
return elem;
}
-static short snapArmature(SnapObjectContext *sctx,
- const SnapObjectParams *params,
- Object *ob_eval,
- const float obmat[4][4],
- bool is_object_active,
- /* read/write args */
- float *dist_px,
- /* return args */
- float r_loc[3],
- float *UNUSED(r_no),
- int *r_index)
+static eSnapMode snapArmature(SnapObjectContext *sctx,
+ const SnapObjectParams *params,
+ Object *ob_eval,
+ const float obmat[4][4],
+ bool is_object_active,
+ /* read/write args */
+ float *dist_px,
+ /* return args */
+ float r_loc[3],
+ float *UNUSED(r_no),
+ int *r_index)
{
- short retval = 0;
+ eSnapMode retval = SCE_SNAP_MODE_NONE;
if (sctx->runtime.snap_to_flag == SCE_SNAP_MODE_FACE) { /* Currently only edge and vert */
return retval;
@@ -1867,7 +1877,7 @@ static short snapArmature(SnapObjectContext *sctx,
const bool is_posemode = is_object_active && (ob_eval->mode & OB_MODE_POSE);
const bool skip_selected = (is_editmode || is_posemode) &&
- (params->snap_select == SNAP_NOT_SELECTED);
+ (params->snap_target_select & SCE_SNAP_TARGET_NOT_SELECTED);
const bool is_persp = sctx->runtime.view_proj == VIEW_PROJ_PERSP;
if (arm->edbo) {
@@ -1982,25 +1992,25 @@ static short snapArmature(SnapObjectContext *sctx,
return retval;
}
- return 0;
+ return SCE_SNAP_MODE_NONE;
}
-static short snapCurve(SnapObjectContext *sctx,
- const SnapObjectParams *params,
- Object *ob_eval,
- const float obmat[4][4],
- /* read/write args */
- float *dist_px,
- /* return args */
- float r_loc[3],
- float *UNUSED(r_no),
- int *r_index)
+static eSnapMode snapCurve(SnapObjectContext *sctx,
+ const SnapObjectParams *params,
+ Object *ob_eval,
+ const float obmat[4][4],
+ /* read/write args */
+ float *dist_px,
+ /* return args */
+ float r_loc[3],
+ float *UNUSED(r_no),
+ int *r_index)
{
bool has_snap = false;
/* only vertex snapping mode (eg control points and handles) supported for now) */
if ((sctx->runtime.snap_to_flag & SCE_SNAP_MODE_VERTEX) == 0) {
- return 0;
+ return SCE_SNAP_MODE_NONE;
}
Curve *cu = static_cast<Curve *>(ob_eval->data);
@@ -2024,7 +2034,7 @@ static short snapCurve(SnapObjectContext *sctx,
sctx->runtime.win_size,
sctx->runtime.mval,
dist_px_sq)) {
- return 0;
+ return SCE_SNAP_MODE_NONE;
}
}
@@ -2046,7 +2056,7 @@ static short snapCurve(SnapObjectContext *sctx,
}
bool is_persp = sctx->runtime.view_proj == VIEW_PROJ_PERSP;
- bool skip_selected = params->snap_select == SNAP_NOT_SELECTED;
+ bool skip_selected = params->snap_target_select & SCE_SNAP_TARGET_NOT_SELECTED;
LISTBASE_FOREACH (Nurb *, nu, (use_obedit ? &cu->editnurb->nurbs : &cu->nurb)) {
for (int u = 0; u < nu->pntsu; u++) {
@@ -2069,11 +2079,14 @@ static short snapCurve(SnapObjectContext *sctx,
nu->bezt[u].vec[1],
&dist_px_sq,
r_loc);
+
/* Don't snap if handle is selected (moving),
* or if it is aligning to a moving handle. */
- is_selected = (!(nu->bezt[u].f1 & SELECT) &&
- !(nu->bezt[u].h1 & HD_ALIGN && nu->bezt[u].f3 & SELECT)) != 0;
- if (!(is_selected && skip_selected)) {
+ bool is_selected_h1 = (nu->bezt[u].f1 & SELECT) != 0;
+ bool is_selected_h2 = (nu->bezt[u].f3 & SELECT) != 0;
+ bool is_autoalign_h1 = (nu->bezt[u].h1 & HD_ALIGN) != 0;
+ bool is_autoalign_h2 = (nu->bezt[u].h2 & HD_ALIGN) != 0;
+ if (!skip_selected || !(is_selected_h1 || (is_autoalign_h1 && is_selected_h2))) {
has_snap |= test_projected_vert_dist(&neasrest_precalc,
clip_planes_local,
clip_plane_len,
@@ -2083,9 +2096,7 @@ static short snapCurve(SnapObjectContext *sctx,
r_loc);
}
- is_selected = (!(nu->bezt[u].f3 & SELECT) &&
- !(nu->bezt[u].h2 & HD_ALIGN && nu->bezt[u].f1 & SELECT)) != 0;
- if (!(is_selected && skip_selected)) {
+ if (!skip_selected || !(is_selected_h2 || (is_autoalign_h2 && is_selected_h1))) {
has_snap |= test_projected_vert_dist(&neasrest_precalc,
clip_planes_local,
clip_plane_len,
@@ -2151,21 +2162,21 @@ static short snapCurve(SnapObjectContext *sctx,
return SCE_SNAP_MODE_VERTEX;
}
- return 0;
+ return SCE_SNAP_MODE_NONE;
}
/* may extend later (for now just snaps to empty center) */
-static short snap_object_center(const SnapObjectContext *sctx,
- Object *ob_eval,
- const float obmat[4][4],
- /* read/write args */
- float *dist_px,
- /* return args */
- float r_loc[3],
- float *UNUSED(r_no),
- int *r_index)
+static eSnapMode snap_object_center(const SnapObjectContext *sctx,
+ Object *ob_eval,
+ const float obmat[4][4],
+ /* read/write args */
+ float *dist_px,
+ /* return args */
+ float r_loc[3],
+ float *UNUSED(r_no),
+ int *r_index)
{
- short retval = 0;
+ eSnapMode retval = SCE_SNAP_MODE_NONE;
if (ob_eval->transflag & OB_DUPLI) {
return retval;
@@ -2207,20 +2218,20 @@ static short snap_object_center(const SnapObjectContext *sctx,
return retval;
}
- return 0;
+ return SCE_SNAP_MODE_NONE;
}
-static short snapCamera(const SnapObjectContext *sctx,
- Object *object,
- const float obmat[4][4],
- /* read/write args */
- float *dist_px,
- /* return args */
- float r_loc[3],
- float *r_no,
- int *r_index)
+static eSnapMode snapCamera(const SnapObjectContext *sctx,
+ Object *object,
+ const float obmat[4][4],
+ /* read/write args */
+ float *dist_px,
+ /* return args */
+ float r_loc[3],
+ float *r_no,
+ int *r_index)
{
- short retval = 0;
+ eSnapMode retval = SCE_SNAP_MODE_NONE;
Scene *scene = sctx->scene;
@@ -2301,28 +2312,28 @@ static short snapCamera(const SnapObjectContext *sctx,
return retval;
}
- return 0;
+ return SCE_SNAP_MODE_NONE;
}
-static short snapMesh(SnapObjectContext *sctx,
- const SnapObjectParams *params,
- Object *ob_eval,
- const Mesh *me_eval,
- const float obmat[4][4],
- bool use_hide,
- /* read/write args */
- float *dist_px,
- /* return args */
- float r_loc[3],
- float r_no[3],
- int *r_index)
+static eSnapMode snapMesh(SnapObjectContext *sctx,
+ const SnapObjectParams *params,
+ Object *ob_eval,
+ const Mesh *me_eval,
+ const float obmat[4][4],
+ bool use_hide,
+ /* read/write args */
+ float *dist_px,
+ /* return args */
+ float r_loc[3],
+ float r_no[3],
+ int *r_index)
{
BLI_assert(sctx->runtime.snap_to_flag != SCE_SNAP_MODE_FACE);
if (me_eval->totvert == 0) {
- return 0;
+ return SCE_SNAP_MODE_NONE;
}
if (me_eval->totedge == 0 && !(sctx->runtime.snap_to_flag & SCE_SNAP_MODE_VERTEX)) {
- return 0;
+ return SCE_SNAP_MODE_NONE;
}
float lpmat[4][4];
@@ -2335,7 +2346,7 @@ static short snapMesh(SnapObjectContext *sctx,
if (bb &&
!snap_bound_box_check_dist(
bb->vec[0], bb->vec[6], lpmat, sctx->runtime.win_size, sctx->runtime.mval, dist_px_sq)) {
- return 0;
+ return SCE_SNAP_MODE_NONE;
}
SnapData_Mesh *sod = snap_object_data_mesh_get(sctx, ob_eval, me_eval, use_hide);
@@ -2376,7 +2387,7 @@ static short snapMesh(SnapObjectContext *sctx,
nearest.dist_sq = dist_px_sq;
int last_index = nearest.index;
- short elem = SCE_SNAP_MODE_VERTEX;
+ eSnapMode elem = SCE_SNAP_MODE_VERTEX;
float tobmat[4][4], clip_planes_local[MAX_CLIPPLANE_LEN][4];
transpose_m4_m4(tobmat, obmat);
@@ -2480,31 +2491,31 @@ static short snapMesh(SnapObjectContext *sctx,
return elem;
}
- return 0;
+ return SCE_SNAP_MODE_NONE;
}
-static short snapEditMesh(SnapObjectContext *sctx,
- const SnapObjectParams *params,
- Object *ob_eval,
- BMEditMesh *em,
- const float obmat[4][4],
- /* read/write args */
- float *dist_px,
- /* return args */
- float r_loc[3],
- float r_no[3],
- int *r_index)
+static eSnapMode snapEditMesh(SnapObjectContext *sctx,
+ const SnapObjectParams *params,
+ Object *ob_eval,
+ BMEditMesh *em,
+ const float obmat[4][4],
+ /* read/write args */
+ float *dist_px,
+ /* return args */
+ float r_loc[3],
+ float r_no[3],
+ int *r_index)
{
BLI_assert(sctx->runtime.snap_to_flag != SCE_SNAP_MODE_FACE);
if ((sctx->runtime.snap_to_flag & ~SCE_SNAP_MODE_FACE) == SCE_SNAP_MODE_VERTEX) {
if (em->bm->totvert == 0) {
- return 0;
+ return SCE_SNAP_MODE_NONE;
}
}
else {
if (em->bm->totedge == 0) {
- return 0;
+ return SCE_SNAP_MODE_NONE;
}
}
@@ -2520,7 +2531,7 @@ static short snapEditMesh(SnapObjectContext *sctx,
/* was BKE_boundbox_ray_hit_check, see: cf6ca226fa58 */
if (!snap_bound_box_check_dist(
sod->min, sod->max, lpmat, sctx->runtime.win_size, sctx->runtime.mval, dist_px_sq)) {
- return 0;
+ return SCE_SNAP_MODE_NONE;
}
if (sctx->runtime.snap_to_flag & SCE_SNAP_MODE_VERTEX) {
@@ -2595,7 +2606,7 @@ static short snapEditMesh(SnapObjectContext *sctx,
nearest.index = -1;
nearest.dist_sq = dist_px_sq;
- short elem = SCE_SNAP_MODE_VERTEX;
+ eSnapMode elem = SCE_SNAP_MODE_VERTEX;
float tobmat[4][4], clip_planes_local[MAX_CLIPPLANE_LEN][4];
transpose_m4_m4(tobmat, obmat);
@@ -2661,7 +2672,7 @@ static short snapEditMesh(SnapObjectContext *sctx,
return elem;
}
- return 0;
+ return SCE_SNAP_MODE_NONE;
}
struct SnapObjUserData {
@@ -2673,7 +2684,7 @@ struct SnapObjUserData {
int *r_index;
Object **r_ob;
float (*r_obmat)[4];
- short ret;
+ eSnapMode ret;
};
/**
@@ -2687,7 +2698,7 @@ static void snap_obj_fn(SnapObjectContext *sctx,
void *data)
{
SnapObjUserData *dt = static_cast<SnapObjUserData *>(data);
- short retval = 0;
+ eSnapMode retval = SCE_SNAP_MODE_NONE;
switch (ob_eval->type) {
case OB_MESH: {
@@ -2696,6 +2707,9 @@ static void snap_obj_fn(SnapObjectContext *sctx,
const Mesh *me_eval = mesh_for_snap(ob_eval, edit_mode_type, &use_hide);
if (me_eval == nullptr) {
BMEditMesh *em = BKE_editmesh_from_object(ob_eval);
+ if (UNLIKELY(!em)) { /* See #mesh_for_snap doc-string. */
+ return;
+ }
BLI_assert_msg(em == BKE_editmesh_from_object(DEG_get_original_object(ob_eval)),
"Make sure there is only one pointer for looptris");
retval = snapEditMesh(
@@ -2731,11 +2745,8 @@ static void snap_obj_fn(SnapObjectContext *sctx,
dt->r_index);
break;
case OB_CURVES_LEGACY:
- retval = snapCurve(
- sctx, params, ob_eval, obmat, dt->dist_px, dt->r_loc, dt->r_no, dt->r_index);
- break; /* Use ATTR_FALLTHROUGH if we want to snap to the generated mesh. */
case OB_SURF:
- if (BKE_object_is_in_editmode(ob_eval)) {
+ if (ob_eval->type == OB_CURVES_LEGACY || BKE_object_is_in_editmode(ob_eval)) {
retval = snapCurve(
sctx, params, ob_eval, obmat, dt->dist_px, dt->r_loc, dt->r_no, dt->r_index);
if (params->edit_mode_type != SNAP_GEOM_FINAL) {
@@ -2804,18 +2815,18 @@ static void snap_obj_fn(SnapObjectContext *sctx,
* \param r_ob: Hit object.
* \param r_obmat: Object matrix (may not be #Object.obmat with dupli-instances).
*/
-static short snapObjectsRay(SnapObjectContext *sctx,
- const SnapObjectParams *params,
- /* read/write args */
- /* Parameters below cannot be const, because they are assigned to a
- * non-const variable (readability-non-const-parameter). */
- float *dist_px /* NOLINT */,
- /* return args */
- float r_loc[3] /* NOLINT */,
- float r_no[3] /* NOLINT */,
- int *r_index /* NOLINT */,
- Object **r_ob,
- float r_obmat[4][4])
+static eSnapMode snapObjectsRay(SnapObjectContext *sctx,
+ const SnapObjectParams *params,
+ /* read/write args */
+ /* Parameters below cannot be const, because they are assigned to a
+ * non-const variable (readability-non-const-parameter). */
+ float *dist_px /* NOLINT */,
+ /* return args */
+ float r_loc[3] /* NOLINT */,
+ float r_no[3] /* NOLINT */,
+ int *r_index /* NOLINT */,
+ Object **r_ob,
+ float r_obmat[4][4])
{
SnapObjUserData data = {};
data.dist_px = dist_px;
@@ -2824,7 +2835,7 @@ static short snapObjectsRay(SnapObjectContext *sctx,
data.r_ob = r_ob;
data.r_index = r_index;
data.r_obmat = r_obmat;
- data.ret = 0;
+ data.ret = SCE_SNAP_MODE_NONE;
iter_snap_objects(sctx, params, snap_obj_fn, &data);
@@ -2997,31 +3008,29 @@ bool ED_transform_snap_object_project_ray(SnapObjectContext *sctx,
sctx, depsgraph, v3d, params, ray_origin, ray_direction, ray_depth, r_co, r_no);
}
-static short transform_snap_context_project_view3d_mixed_impl(SnapObjectContext *sctx,
- Depsgraph *depsgraph,
- const ARegion *region,
- const View3D *v3d,
- const ushort snap_to_flag,
- const SnapObjectParams *params,
- const float mval[2],
- const float prev_co[3],
- float *dist_px,
- float r_loc[3],
- float r_no[3],
- int *r_index,
- Object **r_ob,
- float r_obmat[4][4],
- float r_face_nor[3])
+static eSnapMode transform_snap_context_project_view3d_mixed_impl(SnapObjectContext *sctx,
+ Depsgraph *depsgraph,
+ const ARegion *region,
+ const View3D *v3d,
+ const eSnapMode snap_to_flag,
+ const SnapObjectParams *params,
+ const float mval[2],
+ const float prev_co[3],
+ float *dist_px,
+ float r_loc[3],
+ float r_no[3],
+ int *r_index,
+ Object **r_ob,
+ float r_obmat[4][4],
+ float r_face_nor[3])
{
sctx->runtime.depsgraph = depsgraph;
sctx->runtime.region = region;
sctx->runtime.v3d = v3d;
- BLI_assert((snap_to_flag & (SCE_SNAP_MODE_VERTEX | SCE_SNAP_MODE_EDGE | SCE_SNAP_MODE_FACE |
- SCE_SNAP_MODE_EDGE_MIDPOINT | SCE_SNAP_MODE_EDGE_PERPENDICULAR)) !=
- 0);
+ BLI_assert((snap_to_flag & SCE_SNAP_MODE_GEOM) != 0);
- short retval = 0;
+ eSnapMode retval = SCE_SNAP_MODE_NONE;
bool has_hit = false;
Object *ob_eval = nullptr;
@@ -3040,7 +3049,7 @@ static short transform_snap_context_project_view3d_mixed_impl(SnapObjectContext
float ray_start[3], ray_normal[3];
if (!ED_view3d_win_to_ray_clipped_ex(
depsgraph, region, v3d, mval, nullptr, ray_normal, ray_start, true)) {
- return 0;
+ return SCE_SNAP_MODE_NONE;
}
float dummy_ray_depth = BVH_RAYCAST_DIST_MAX;
@@ -3084,7 +3093,7 @@ static short transform_snap_context_project_view3d_mixed_impl(SnapObjectContext
if (snap_to_flag & (SCE_SNAP_MODE_VERTEX | SCE_SNAP_MODE_EDGE | SCE_SNAP_MODE_EDGE_MIDPOINT |
SCE_SNAP_MODE_EDGE_PERPENDICULAR)) {
- short elem_test, elem = 0;
+ eSnapMode elem_test, elem = SCE_SNAP_MODE_NONE;
float dist_px_tmp = *dist_px;
copy_m4_m4(sctx->runtime.pmat, rv3d->persmat);
@@ -3094,9 +3103,11 @@ static short transform_snap_context_project_view3d_mixed_impl(SnapObjectContext
sctx->runtime.view_proj = rv3d->is_persp ? VIEW_PROJ_PERSP : VIEW_PROJ_ORTHO;
/* First snap to edge instead of middle or perpendicular. */
- sctx->runtime.snap_to_flag = snap_to_flag & (SCE_SNAP_MODE_VERTEX | SCE_SNAP_MODE_EDGE);
+ sctx->runtime.snap_to_flag = static_cast<eSnapMode>(
+ snap_to_flag & (SCE_SNAP_MODE_VERTEX | SCE_SNAP_MODE_EDGE));
if (snap_to_flag & (SCE_SNAP_MODE_EDGE_MIDPOINT | SCE_SNAP_MODE_EDGE_PERPENDICULAR)) {
- sctx->runtime.snap_to_flag |= SCE_SNAP_MODE_EDGE;
+ sctx->runtime.snap_to_flag = static_cast<eSnapMode>(sctx->runtime.snap_to_flag |
+ SCE_SNAP_MODE_EDGE);
}
planes_from_projmat(sctx->runtime.pmat,
@@ -3180,21 +3191,21 @@ static short transform_snap_context_project_view3d_mixed_impl(SnapObjectContext
return retval;
}
-short ED_transform_snap_object_project_view3d_ex(SnapObjectContext *sctx,
- Depsgraph *depsgraph,
- const ARegion *region,
- const View3D *v3d,
- const ushort snap_to,
- const SnapObjectParams *params,
- const float mval[2],
- const float prev_co[3],
- float *dist_px,
- float r_loc[3],
- float r_no[3],
- int *r_index,
- Object **r_ob,
- float r_obmat[4][4],
- float r_face_nor[3])
+eSnapMode ED_transform_snap_object_project_view3d_ex(SnapObjectContext *sctx,
+ Depsgraph *depsgraph,
+ const ARegion *region,
+ const View3D *v3d,
+ const eSnapMode snap_to,
+ const SnapObjectParams *params,
+ const float mval[2],
+ const float prev_co[3],
+ float *dist_px,
+ float r_loc[3],
+ float r_no[3],
+ int *r_index,
+ Object **r_ob,
+ float r_obmat[4][4],
+ float r_face_nor[3])
{
return transform_snap_context_project_view3d_mixed_impl(sctx,
depsgraph,
@@ -3213,17 +3224,17 @@ short ED_transform_snap_object_project_view3d_ex(SnapObjectContext *sctx,
r_face_nor);
}
-short ED_transform_snap_object_project_view3d(SnapObjectContext *sctx,
- Depsgraph *depsgraph,
- const ARegion *region,
- const View3D *v3d,
- const ushort snap_to,
- const SnapObjectParams *params,
- const float mval[2],
- const float prev_co[3],
- float *dist_px,
- float r_loc[3],
- float r_no[3])
+eSnapMode ED_transform_snap_object_project_view3d(SnapObjectContext *sctx,
+ Depsgraph *depsgraph,
+ const ARegion *region,
+ const View3D *v3d,
+ const eSnapMode snap_to,
+ const SnapObjectParams *params,
+ const float mval[2],
+ const float prev_co[3],
+ float *dist_px,
+ float r_loc[3],
+ float r_no[3])
{
return ED_transform_snap_object_project_view3d_ex(sctx,
depsgraph,
diff --git a/source/blender/editors/transform/transform_snap_sequencer.c b/source/blender/editors/transform/transform_snap_sequencer.c
index 7dc361ff5bb..dbcae2b6320 100644
--- a/source/blender/editors/transform/transform_snap_sequencer.c
+++ b/source/blender/editors/transform/transform_snap_sequencer.c
@@ -25,6 +25,7 @@
#include "SEQ_relations.h"
#include "SEQ_render.h"
#include "SEQ_sequencer.h"
+#include "SEQ_time.h"
#include "transform.h"
#include "transform_snap.h"
@@ -65,14 +66,14 @@ static void seq_snap_source_points_build(TransSeqSnapData *snap_data, SeqCollect
SEQ_ITERATOR_FOREACH (seq, snap_sources) {
int left = 0, right = 0;
if (seq->flag & SEQ_LEFTSEL) {
- left = right = seq->startdisp;
+ left = right = SEQ_time_left_handle_frame_get(seq);
}
else if (seq->flag & SEQ_RIGHTSEL) {
- left = right = seq->enddisp;
+ left = right = SEQ_time_right_handle_frame_get(seq);
}
else {
- left = seq->startdisp;
- right = seq->enddisp;
+ left = SEQ_time_left_handle_frame_get(seq);
+ right = SEQ_time_right_handle_frame_get(seq);
}
snap_data->source_snap_points[i] = left;
@@ -193,21 +194,24 @@ static void seq_snap_target_points_build(Scene *scene,
Sequence *seq;
SEQ_ITERATOR_FOREACH (seq, snap_targets) {
- snap_data->target_snap_points[i] = seq->startdisp;
- snap_data->target_snap_points[i + 1] = seq->enddisp;
+ snap_data->target_snap_points[i] = SEQ_time_left_handle_frame_get(seq);
+ snap_data->target_snap_points[i + 1] = SEQ_time_right_handle_frame_get(seq);
i += 2;
if (snap_mode & SEQ_SNAP_TO_STRIP_HOLD) {
- int content_start = min_ii(seq->enddisp, seq->start);
- int content_end = max_ii(seq->startdisp, seq->start + seq->len);
+ int content_start = min_ii(SEQ_time_right_handle_frame_get(seq), seq->start);
+ int content_end = max_ii(SEQ_time_left_handle_frame_get(seq), seq->start + seq->len);
/* Effects and single image strips produce incorrect content length. Skip these strips. */
if ((seq->type & SEQ_TYPE_EFFECT) != 0 || seq->len == 1) {
- content_start = seq->startdisp;
- content_end = seq->enddisp;
+ content_start = SEQ_time_left_handle_frame_get(seq);
+ content_end = SEQ_time_right_handle_frame_get(seq);
}
- CLAMP(content_start, seq->startdisp, seq->enddisp);
- CLAMP(content_end, seq->startdisp, seq->enddisp);
+ CLAMP(content_start,
+ SEQ_time_left_handle_frame_get(seq),
+ SEQ_time_right_handle_frame_get(seq));
+ CLAMP(
+ content_end, SEQ_time_left_handle_frame_get(seq), SEQ_time_right_handle_frame_get(seq));
snap_data->target_snap_points[i] = content_start;
snap_data->target_snap_points[i + 1] = content_end;
diff --git a/source/blender/editors/util/CMakeLists.txt b/source/blender/editors/util/CMakeLists.txt
index 89d80d582f8..5c2a3374aa1 100644
--- a/source/blender/editors/util/CMakeLists.txt
+++ b/source/blender/editors/util/CMakeLists.txt
@@ -91,6 +91,7 @@ set(SRC
../include/ED_uvedit.h
../include/ED_view3d.h
../include/ED_view3d_offscreen.h
+ ../include/UI_grid_view.hh
../include/UI_icons.h
../include/UI_interface.h
../include/UI_interface.hh
diff --git a/source/blender/editors/util/ed_util.c b/source/blender/editors/util/ed_util.c
index f07364cd4d3..3cfe6bd61a4 100644
--- a/source/blender/editors/util/ed_util.c
+++ b/source/blender/editors/util/ed_util.c
@@ -19,6 +19,7 @@
#include "BKE_collection.h"
#include "BKE_global.h"
+#include "BKE_layer.h"
#include "BKE_lib_id.h"
#include "BKE_lib_remap.h"
#include "BKE_main.h"
@@ -40,6 +41,7 @@
#include "ED_mesh.h"
#include "ED_object.h"
#include "ED_paint.h"
+#include "ED_screen.h"
#include "ED_space_api.h"
#include "ED_util.h"
@@ -137,8 +139,12 @@ void ED_editors_init(bContext *C)
ED_object_posemode_enter_ex(bmain, ob);
}
- /* Other edit/paint/etc. modes are only settable for objects in active scene currently. */
- if (!BKE_collection_has_object_recursive(scene->master_collection, ob)) {
+ /* Other edit/paint/etc. modes are only settable for objects visible in active scene currently.
+ * Otherwise, they (and their obdata) may not be (fully) evaluated, which is mandatory for some
+ * modes like Sculpt.
+ * Ref. T98225. */
+ if (!BKE_collection_has_object_recursive(scene->master_collection, ob) ||
+ !BKE_scene_has_object(scene, ob) || (ob->visibility_flag & OB_HIDE_VIEWPORT) != 0) {
continue;
}
@@ -182,6 +188,18 @@ void ED_editors_init(bContext *C)
ED_space_image_paint_update(bmain, wm, scene);
}
+ /* Enforce a full redraw for the first time areas/regions get drawn. Further region init/refresh
+ * just triggers non-rebuild redraws (#RGN_DRAW_NO_REBUILD). Usually a full redraw would be
+ * triggered by a `NC_WM | ND_FILEREAD` notifier, but if a startup script calls an operator that
+ * redraws the window, notifiers are not handled before the operator runs. See T98461. */
+ LISTBASE_FOREACH (wmWindow *, win, &wm->windows) {
+ const bScreen *screen = WM_window_get_active_screen(win);
+
+ ED_screen_areas_iter (win, screen, area) {
+ ED_area_tag_redraw(area);
+ }
+ }
+
ED_assetlist_storage_tag_main_data_dirty();
SWAP(int, reports->flag, reports_flag_prev);
diff --git a/source/blender/editors/util/ed_util_ops.cc b/source/blender/editors/util/ed_util_ops.cc
index 803e65590a0..af3589e50f0 100644
--- a/source/blender/editors/util/ed_util_ops.cc
+++ b/source/blender/editors/util/ed_util_ops.cc
@@ -67,19 +67,19 @@ static bool lib_id_preview_editing_poll(bContext *C)
static int lib_id_load_custom_preview_exec(bContext *C, wmOperator *op)
{
- char path[FILE_MAX];
+ char filepath[FILE_MAX];
- RNA_string_get(op->ptr, "filepath", path);
+ RNA_string_get(op->ptr, "filepath", filepath);
- if (!BLI_is_file(path)) {
- BKE_reportf(op->reports, RPT_ERROR, "File not found '%s'", path);
+ if (!BLI_is_file(filepath)) {
+ BKE_reportf(op->reports, RPT_ERROR, "File not found '%s'", filepath);
return OPERATOR_CANCELLED;
}
PointerRNA idptr = CTX_data_pointer_get(C, "id");
ID *id = (ID *)idptr.data;
- BKE_previewimg_id_custom_set(id, path);
+ BKE_previewimg_id_custom_set(id, filepath);
WM_event_add_notifier(C, NC_ASSET | NA_EDITED, nullptr);
diff --git a/source/blender/editors/util/select_utils.c b/source/blender/editors/util/select_utils.c
index 53f9aca8e8d..660afa4c3d7 100644
--- a/source/blender/editors/util/select_utils.c
+++ b/source/blender/editors/util/select_utils.c
@@ -66,15 +66,18 @@ eSelectOp ED_select_op_modal(const eSelectOp sel_op, const bool is_first)
return sel_op;
}
-int ED_select_similar_compare_float(const float delta, const float thresh, const int compare)
+bool ED_select_similar_compare_float(const float delta,
+ const float thresh,
+ const eSimilarCmp compare)
{
+ BLI_assert(thresh >= 0.0f);
switch (compare) {
case SIM_CMP_EQ:
return (fabsf(delta) <= thresh);
case SIM_CMP_GT:
- return ((delta + thresh) >= 0.0);
+ return ((delta + thresh) >= 0.0f);
case SIM_CMP_LT:
- return ((delta - thresh) <= 0.0);
+ return ((delta - thresh) <= 0.0f);
default:
BLI_assert_unreachable();
return 0;
@@ -84,8 +87,10 @@ int ED_select_similar_compare_float(const float delta, const float thresh, const
bool ED_select_similar_compare_float_tree(const KDTree_1d *tree,
const float length,
const float thresh,
- const int compare)
+ const eSimilarCmp compare)
{
+ BLI_assert(compare == SIM_CMP_EQ || length >= 0.0f); /* See precision note below. */
+
/* Length of the edge we want to compare against. */
float nearest_edge_length;
@@ -112,6 +117,7 @@ bool ED_select_similar_compare_float_tree(const KDTree_1d *tree,
KDTreeNearest_1d nearest;
if (BLI_kdtree_1d_find_nearest(tree, &nearest_edge_length, &nearest) != -1) {
+ BLI_assert(compare == SIM_CMP_EQ || nearest.co[0] >= 0.0f); /* See precision note above. */
float delta = length - nearest.co[0];
return ED_select_similar_compare_float(delta, thresh, compare);
}
@@ -119,11 +125,11 @@ bool ED_select_similar_compare_float_tree(const KDTree_1d *tree,
return false;
}
-eSelectOp ED_select_op_from_operator(wmOperator *op)
+eSelectOp ED_select_op_from_operator(PointerRNA *ptr)
{
- const bool extend = RNA_boolean_get(op->ptr, "extend");
- const bool deselect = RNA_boolean_get(op->ptr, "deselect");
- const bool toggle = RNA_boolean_get(op->ptr, "toggle");
+ const bool extend = RNA_boolean_get(ptr, "extend");
+ const bool deselect = RNA_boolean_get(ptr, "deselect");
+ const bool toggle = RNA_boolean_get(ptr, "toggle");
if (extend) {
return SEL_OP_ADD;
@@ -137,10 +143,56 @@ eSelectOp ED_select_op_from_operator(wmOperator *op)
return SEL_OP_SET;
}
-void ED_select_pick_params_from_operator(wmOperator *op, struct SelectPick_Params *params)
+void ED_select_pick_params_from_operator(PointerRNA *ptr, struct SelectPick_Params *params)
{
memset(params, 0x0, sizeof(*params));
- params->sel_op = ED_select_op_from_operator(op);
- params->deselect_all = RNA_boolean_get(op->ptr, "deselect_all");
- params->select_passthrough = RNA_boolean_get(op->ptr, "select_passthrough");
+ params->sel_op = ED_select_op_from_operator(ptr);
+ params->deselect_all = RNA_boolean_get(ptr, "deselect_all");
+ params->select_passthrough = RNA_boolean_get(ptr, "select_passthrough");
+}
+
+/* -------------------------------------------------------------------- */
+/** \name Operator Naming Callbacks
+ * \{ */
+
+const char *ED_select_pick_get_name(wmOperatorType *UNUSED(ot), PointerRNA *ptr)
+{
+ struct SelectPick_Params params = {0};
+ ED_select_pick_params_from_operator(ptr, &params);
+ switch (params.sel_op) {
+ case SEL_OP_ADD:
+ return "Select (Extend)";
+ case SEL_OP_SUB:
+ return "Select (Deselect)";
+ case SEL_OP_XOR:
+ return "Select (Toggle)";
+ case SEL_OP_AND:
+ BLI_assert_unreachable();
+ ATTR_FALLTHROUGH;
+ case SEL_OP_SET:
+ break;
+ }
+ return "Select";
}
+
+const char *ED_select_circle_get_name(wmOperatorType *UNUSED(ot), PointerRNA *ptr)
+{
+ /* Matches options in #WM_operator_properties_select_operation_simple */
+ const eSelectOp sel_op = RNA_enum_get(ptr, "mode");
+ switch (sel_op) {
+ case SEL_OP_ADD:
+ return "Circle Select (Extend)";
+ case SEL_OP_SUB:
+ return "Circle Select (Deselect)";
+ case SEL_OP_XOR:
+ ATTR_FALLTHROUGH;
+ case SEL_OP_AND:
+ BLI_assert_unreachable();
+ ATTR_FALLTHROUGH;
+ case SEL_OP_SET:
+ break;
+ }
+ return "Circle Select";
+}
+
+/** \} */
diff --git a/source/blender/editors/uvedit/uvedit_intern.h b/source/blender/editors/uvedit/uvedit_intern.h
index 181982f0b2c..04128cf378c 100644
--- a/source/blender/editors/uvedit/uvedit_intern.h
+++ b/source/blender/editors/uvedit/uvedit_intern.h
@@ -182,5 +182,6 @@ void UV_OT_select_circle(struct wmOperatorType *ot);
void UV_OT_select_more(struct wmOperatorType *ot);
void UV_OT_select_less(struct wmOperatorType *ot);
void UV_OT_select_overlap(struct wmOperatorType *ot);
+void UV_OT_select_similar(struct wmOperatorType *ot);
/* Used only when UV sync select is disabled. */
void UV_OT_select_mode(struct wmOperatorType *ot);
diff --git a/source/blender/editors/uvedit/uvedit_ops.c b/source/blender/editors/uvedit/uvedit_ops.c
index fe6f9f0d513..0b5d6592426 100644
--- a/source/blender/editors/uvedit/uvedit_ops.c
+++ b/source/blender/editors/uvedit/uvedit_ops.c
@@ -2044,6 +2044,7 @@ void ED_operatortypes_uvedit(void)
WM_operatortype_append(UV_OT_select_pinned);
WM_operatortype_append(UV_OT_select_box);
WM_operatortype_append(UV_OT_select_lasso);
+ WM_operatortype_append(UV_OT_select_similar);
WM_operatortype_append(UV_OT_select_circle);
WM_operatortype_append(UV_OT_select_more);
WM_operatortype_append(UV_OT_select_less);
diff --git a/source/blender/editors/uvedit/uvedit_select.c b/source/blender/editors/uvedit/uvedit_select.c
index 13dac431b57..8dcf2ceb679 100644
--- a/source/blender/editors/uvedit/uvedit_select.c
+++ b/source/blender/editors/uvedit/uvedit_select.c
@@ -12,6 +12,7 @@
#include "MEM_guardedalloc.h"
#include "DNA_image_types.h"
+#include "DNA_material_types.h"
#include "DNA_meshdata_types.h"
#include "DNA_node_types.h"
#include "DNA_object_types.h"
@@ -22,6 +23,7 @@
#include "BLI_blenlib.h"
#include "BLI_hash.h"
#include "BLI_kdopbvh.h"
+#include "BLI_kdtree.h"
#include "BLI_lasso_2d.h"
#include "BLI_math.h"
#include "BLI_polyfill_2d.h"
@@ -31,6 +33,7 @@
#include "BKE_customdata.h"
#include "BKE_editmesh.h"
#include "BKE_layer.h"
+#include "BKE_material.h"
#include "BKE_mesh.h"
#include "BKE_mesh_mapping.h"
#include "BKE_report.h"
@@ -75,6 +78,16 @@ static void uv_select_tag_update_for_object(Depsgraph *depsgraph,
const ToolSettings *ts,
Object *obedit);
+typedef enum {
+ UV_SSIM_AREA_UV = 1000,
+ UV_SSIM_AREA_3D,
+ UV_SSIM_LENGTH_UV,
+ UV_SSIM_LENGTH_3D,
+ UV_SSIM_SIDES,
+ UV_SSIM_PIN,
+ UV_SSIM_MATERIAL,
+} eUVSelectSimilar;
+
/* -------------------------------------------------------------------- */
/** \name Active Selection Tracking
*
@@ -586,12 +599,25 @@ bool uvedit_uv_select_test_ex(const ToolSettings *ts, BMLoop *l, const int cd_lo
if (ts->selectmode & SCE_SELECT_FACE) {
return BM_elem_flag_test_bool(l->f, BM_ELEM_SELECT);
}
+ if (ts->selectmode & SCE_SELECT_EDGE) {
+ /* Are you looking for `uvedit_edge_select_test(...)` instead? */
+ }
return BM_elem_flag_test_bool(l->v, BM_ELEM_SELECT);
}
MLoopUV *luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
+
+ if (ts->selectmode & SCE_SELECT_FACE) {
+ /* Are you looking for `uvedit_face_select_test(...)` instead? */
+ }
+
+ if (ts->selectmode & SCE_SELECT_EDGE) {
+ /* Are you looking for `uvedit_edge_select_test(...)` instead? */
+ }
+
return (luv->flag & MLOOPUV_VERTSEL) != 0;
}
+
bool uvedit_uv_select_test(const Scene *scene, BMLoop *l, const int cd_loop_uv_offset)
{
return uvedit_uv_select_test_ex(scene->toolsettings, l, cd_loop_uv_offset);
@@ -653,6 +679,9 @@ void uvedit_uv_select_shared_vert(const Scene *scene,
e_first = e_iter = l->e;
do {
BMLoop *l_radial_iter = e_iter->l;
+ if (!l_radial_iter) {
+ continue; /* Skip wire edges with no loops. */
+ }
do {
if (l_radial_iter->v == l->v) {
if (uvedit_face_visible_test(scene, l_radial_iter->f)) {
@@ -696,6 +725,10 @@ void uvedit_uv_select_enable(const Scene *scene,
{
const ToolSettings *ts = scene->toolsettings;
+ if (ts->selectmode & SCE_SELECT_EDGE) {
+ /* Are you looking for `uvedit_edge_select_set(...)` instead? */
+ }
+
if (ts->uv_flag & UV_SYNC_SELECTION) {
if (ts->selectmode & SCE_SELECT_FACE) {
BM_face_select_set(em->bm, l->f, true);
@@ -2422,7 +2455,7 @@ static bool uv_mouse_select_multi(bContext *C,
UvNearestHit hit = UV_NEAREST_HIT_INIT_DIST_PX(&region->v2d, 75.0f);
int selectmode, sticky;
bool found_item = false;
- /* 0 == don't flush, 1 == sel, -1 == desel; only use when selection sync is enabled */
+ /* 0 == don't flush, 1 == sel, -1 == deselect; only use when selection sync is enabled. */
int flush = 0;
/* Penalty (in pixels) applied to elements that are already selected
@@ -2511,8 +2544,15 @@ static bool uv_mouse_select_multi(bContext *C,
else if (selectmode == UV_SELECT_EDGE) {
is_selected = uvedit_edge_select_test(scene, hit.l, cd_loop_uv_offset);
}
- else { /* Vertex or island. */
- is_selected = uvedit_uv_select_test(scene, hit.l, cd_loop_uv_offset);
+ else {
+ /* Vertex or island. For island (if we were using #uv_find_nearest_face_multi_ex, see above),
+ * `hit.l` is NULL, use `hit.efa` instead. */
+ if (hit.l != NULL) {
+ is_selected = uvedit_uv_select_test(scene, hit.l, cd_loop_uv_offset);
+ }
+ else {
+ is_selected = uvedit_face_select_test(scene, hit.efa, cd_loop_uv_offset);
+ }
}
}
@@ -2645,7 +2685,7 @@ static int uv_select_exec(bContext *C, wmOperator *op)
RNA_float_get_array(op->ptr, "location", co);
struct SelectPick_Params params = {0};
- ED_select_pick_params_from_operator(op, &params);
+ ED_select_pick_params_from_operator(op->ptr, &params);
const bool changed = uv_mouse_select(C, co, &params);
@@ -2680,6 +2720,7 @@ void UV_OT_select(wmOperatorType *ot)
ot->exec = uv_select_exec;
ot->invoke = uv_select_invoke;
ot->poll = ED_operator_uvedit; /* requires space image */
+ ot->get_name = ED_select_pick_get_name;
/* properties */
PropertyRNA *prop;
@@ -2724,7 +2765,7 @@ static int uv_mouse_select_loop_generic_multi(bContext *C,
const ToolSettings *ts = scene->toolsettings;
UvNearestHit hit = UV_NEAREST_HIT_INIT_MAX(&region->v2d);
bool found_item = false;
- /* 0 == don't flush, 1 == sel, -1 == desel; only use when selection sync is enabled */
+ /* 0 == don't flush, 1 == sel, -1 == deselect; only use when selection sync is enabled. */
int flush = 0;
/* Find edge. */
@@ -3278,8 +3319,6 @@ static void uv_select_flush_from_tag_face(const Scene *scene, Object *obedit, co
BM_ITER_MESH_INDEX (efa, &iter, em->bm, BM_FACES_OF_MESH, efa_index) {
if (BM_elem_flag_test(efa, BM_ELEM_TAG)) {
- /* tf = BM_ELEM_CD_GET_VOID_P(efa, cd_poly_tex_offset); */ /* UNUSED */
-
BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
MLoopUV *luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
if (select) {
@@ -3349,8 +3388,6 @@ static void uv_select_flush_from_tag_loop(const Scene *scene, Object *obedit, co
/* now select tagged verts */
BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
- /* tf = BM_ELEM_CD_GET_VOID_P(efa, cd_poly_tex_offset); */ /* UNUSED */
-
BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
if (BM_elem_flag_test(l->v, BM_ELEM_TAG)) {
uvedit_uv_select_set(scene, em, l, select, false, cd_loop_uv_offset);
@@ -3369,8 +3406,6 @@ static void uv_select_flush_from_tag_loop(const Scene *scene, Object *obedit, co
}
BM_ITER_MESH_INDEX (efa, &iter, em->bm, BM_FACES_OF_MESH, efa_index) {
- /* tf = BM_ELEM_CD_GET_VOID_P(efa, cd_poly_tex_offset); */ /* UNUSED */
-
BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
if (BM_elem_flag_test(l, BM_ELEM_TAG)) {
uv_select_flush_from_tag_sticky_loc_internal(
@@ -3849,6 +3884,7 @@ void UV_OT_select_circle(wmOperatorType *ot)
ot->exec = uv_circle_select_exec;
ot->poll = ED_operator_uvedit_space_image; /* requires space image */
ot->cancel = WM_gesture_circle_cancel;
+ ot->get_name = ED_select_circle_get_name;
/* flags */
ot->flag = OPTYPE_UNDO;
@@ -4406,6 +4442,550 @@ void UV_OT_select_overlap(wmOperatorType *ot)
}
/** \} */
+/** \name Select Similar Operator
+ * \{ */
+
+static float get_uv_vert_needle(const eUVSelectSimilar type,
+ BMVert *vert,
+ const float ob_m3[3][3],
+ MLoopUV *luv,
+ const int cd_loop_uv_offset)
+{
+ float result = 0.0f;
+ switch (type) {
+ case UV_SSIM_AREA_UV: {
+ BMFace *f;
+ BMIter iter;
+ BM_ITER_ELEM (f, &iter, vert, BM_FACES_OF_VERT) {
+ result += BM_face_calc_area_uv(f, cd_loop_uv_offset);
+ }
+ } break;
+ case UV_SSIM_AREA_3D: {
+ BMFace *f;
+ BMIter iter;
+ BM_ITER_ELEM (f, &iter, vert, BM_FACES_OF_VERT) {
+ result += BM_face_calc_area_with_mat3(f, ob_m3);
+ }
+ } break;
+ case UV_SSIM_SIDES: {
+ BMEdge *e;
+ BMIter iter;
+ BM_ITER_ELEM (e, &iter, vert, BM_EDGES_OF_VERT) {
+ result += 1.0f;
+ }
+ } break;
+ case UV_SSIM_PIN:
+ return (luv->flag & MLOOPUV_PINNED) ? 1.0f : 0.0f;
+ default:
+ BLI_assert_unreachable();
+ return false;
+ }
+
+ return result;
+}
+
+static float get_uv_edge_needle(const eUVSelectSimilar type,
+ BMEdge *edge,
+ const float ob_m3[3][3],
+ MLoopUV *luv_a,
+ MLoopUV *luv_b,
+ const int cd_loop_uv_offset)
+{
+ float result = 0.0f;
+ switch (type) {
+ case UV_SSIM_AREA_UV: {
+ BMFace *f;
+ BMIter iter;
+ BM_ITER_ELEM (f, &iter, edge, BM_FACES_OF_EDGE) {
+ result += BM_face_calc_area_uv(f, cd_loop_uv_offset);
+ }
+ } break;
+ case UV_SSIM_AREA_3D: {
+ BMFace *f;
+ BMIter iter;
+ BM_ITER_ELEM (f, &iter, edge, BM_FACES_OF_EDGE) {
+ result += BM_face_calc_area_with_mat3(f, ob_m3);
+ }
+ } break;
+ case UV_SSIM_LENGTH_UV:
+ return len_v2v2(luv_a->uv, luv_b->uv);
+ case UV_SSIM_LENGTH_3D:
+ return len_v3v3(edge->v1->co, edge->v2->co);
+ case UV_SSIM_SIDES: {
+ BMEdge *e;
+ BMIter iter;
+ BM_ITER_ELEM (e, &iter, edge, BM_FACES_OF_EDGE) {
+ result += 1.0f;
+ }
+ } break;
+ case UV_SSIM_PIN:
+ if (luv_a->flag & MLOOPUV_PINNED) {
+ result += 1.0f;
+ }
+ if (luv_b->flag & MLOOPUV_PINNED) {
+ result += 1.0f;
+ }
+ break;
+ default:
+ BLI_assert_unreachable();
+ return false;
+ }
+
+ return result;
+}
+
+static float get_uv_face_needle(const eUVSelectSimilar type,
+ BMFace *face,
+ const float ob_m3[3][3],
+ const int cd_loop_uv_offset)
+{
+ float result = 0.0f;
+ switch (type) {
+ case UV_SSIM_AREA_UV:
+ return BM_face_calc_area_uv(face, cd_loop_uv_offset);
+ case UV_SSIM_AREA_3D:
+ return BM_face_calc_area_with_mat3(face, ob_m3);
+ case UV_SSIM_SIDES:
+ return face->len;
+ case UV_SSIM_PIN: {
+ BMLoop *l;
+ BMIter liter;
+ BM_ITER_ELEM (l, &liter, face, BM_LOOPS_OF_FACE) {
+ MLoopUV *luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
+ if (luv->flag & MLOOPUV_PINNED) {
+ result += 1.0f;
+ }
+ }
+ } break;
+ case UV_SSIM_MATERIAL:
+ return face->mat_nr;
+ default:
+ BLI_assert_unreachable();
+ return false;
+ }
+ return result;
+}
+
+static int uv_select_similar_vert_exec(bContext *C, wmOperator *op)
+{
+ Scene *scene = CTX_data_scene(C);
+ ViewLayer *view_layer = CTX_data_view_layer(C);
+ Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C);
+ ToolSettings *ts = CTX_data_tool_settings(C);
+
+ const eUVSelectSimilar type = RNA_enum_get(op->ptr, "type");
+ const float threshold = RNA_float_get(op->ptr, "threshold");
+ const eSimilarCmp compare = RNA_enum_get(op->ptr, "compare");
+
+ uint objects_len = 0;
+ Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data_with_uvs(
+ view_layer, ((View3D *)NULL), &objects_len);
+
+ int max_verts_selected_all = 0;
+ for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
+ Object *ob = objects[ob_index];
+ BMEditMesh *em = BKE_editmesh_from_object(ob);
+ BMFace *face;
+ BMIter iter;
+ BM_ITER_MESH (face, &iter, em->bm, BM_FACES_OF_MESH) {
+ if (!uvedit_face_visible_test(scene, face)) {
+ continue;
+ }
+ max_verts_selected_all += face->len;
+ }
+ /* TODO: Get a tighter bounds */
+ }
+
+ int tree_index = 0;
+ KDTree_1d *tree_1d = BLI_kdtree_1d_new(max_verts_selected_all);
+
+ for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
+ Object *ob = objects[ob_index];
+ BMEditMesh *em = BKE_editmesh_from_object(ob);
+ BMesh *bm = em->bm;
+ if (bm->totvertsel == 0) {
+ continue;
+ }
+
+ const int cd_loop_uv_offset = CustomData_get_offset(&bm->ldata, CD_MLOOPUV);
+ float ob_m3[3][3];
+ copy_m3_m4(ob_m3, ob->obmat);
+
+ BMFace *face;
+ BMIter iter;
+ BM_ITER_MESH (face, &iter, em->bm, BM_FACES_OF_MESH) {
+ if (!uvedit_face_visible_test(scene, face)) {
+ continue;
+ }
+ BMLoop *l;
+ BMIter liter;
+ BM_ITER_ELEM (l, &liter, face, BM_LOOPS_OF_FACE) {
+ if (!uvedit_uv_select_test(scene, l, cd_loop_uv_offset)) {
+ continue;
+ }
+ MLoopUV *luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
+ float needle = get_uv_vert_needle(type, l->v, ob_m3, luv, cd_loop_uv_offset);
+ BLI_kdtree_1d_insert(tree_1d, tree_index++, &needle);
+ }
+ }
+ }
+
+ if (tree_1d != NULL) {
+ BLI_kdtree_1d_deduplicate(tree_1d);
+ BLI_kdtree_1d_balance(tree_1d);
+ }
+
+ for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
+ Object *ob = objects[ob_index];
+ BMEditMesh *em = BKE_editmesh_from_object(ob);
+ BMesh *bm = em->bm;
+ if (bm->totvertsel == 0) {
+ continue;
+ }
+
+ bool changed = false;
+ const int cd_loop_uv_offset = CustomData_get_offset(&bm->ldata, CD_MLOOPUV);
+ float ob_m3[3][3];
+ copy_m3_m4(ob_m3, ob->obmat);
+
+ BMFace *face;
+ BMIter iter;
+ BM_ITER_MESH (face, &iter, em->bm, BM_FACES_OF_MESH) {
+ if (!uvedit_face_visible_test(scene, face)) {
+ continue;
+ }
+ BMLoop *l;
+ BMIter liter;
+ BM_ITER_ELEM (l, &liter, face, BM_LOOPS_OF_FACE) {
+ if (uvedit_uv_select_test(scene, l, cd_loop_uv_offset)) {
+ continue; /* Already selected. */
+ }
+ MLoopUV *luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
+ const float needle = get_uv_vert_needle(type, l->v, ob_m3, luv, cd_loop_uv_offset);
+ bool select = ED_select_similar_compare_float_tree(tree_1d, needle, threshold, compare);
+ if (select) {
+ uvedit_uv_select_set(scene, em, l, select, false, cd_loop_uv_offset);
+ changed = true;
+ }
+ }
+ if (changed) {
+ uv_select_tag_update_for_object(depsgraph, ts, ob);
+ }
+ }
+ }
+
+ MEM_SAFE_FREE(objects);
+ BLI_kdtree_1d_free(tree_1d);
+ return OPERATOR_FINISHED;
+}
+
+static int uv_select_similar_edge_exec(bContext *C, wmOperator *op)
+{
+ Scene *scene = CTX_data_scene(C);
+ ViewLayer *view_layer = CTX_data_view_layer(C);
+ Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C);
+ ToolSettings *ts = CTX_data_tool_settings(C);
+
+ const eUVSelectSimilar type = RNA_enum_get(op->ptr, "type");
+ const float threshold = RNA_float_get(op->ptr, "threshold");
+ const eSimilarCmp compare = RNA_enum_get(op->ptr, "compare");
+
+ uint objects_len = 0;
+ Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data_with_uvs(
+ view_layer, ((View3D *)NULL), &objects_len);
+
+ int max_edges_selected_all = 0;
+ for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
+ Object *ob = objects[ob_index];
+ BMEditMesh *em = BKE_editmesh_from_object(ob);
+ BMFace *face;
+ BMIter iter;
+ BM_ITER_MESH (face, &iter, em->bm, BM_FACES_OF_MESH) {
+ if (!uvedit_face_visible_test(scene, face)) {
+ continue;
+ }
+ max_edges_selected_all += face->len;
+ }
+ /* TODO: Get a tighter bounds. */
+ }
+
+ int tree_index = 0;
+ KDTree_1d *tree_1d = BLI_kdtree_1d_new(max_edges_selected_all);
+
+ for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
+ Object *ob = objects[ob_index];
+ BMEditMesh *em = BKE_editmesh_from_object(ob);
+ BMesh *bm = em->bm;
+ if (bm->totvertsel == 0) {
+ continue;
+ }
+
+ const int cd_loop_uv_offset = CustomData_get_offset(&bm->ldata, CD_MLOOPUV);
+ float ob_m3[3][3];
+ copy_m3_m4(ob_m3, ob->obmat);
+
+ BMFace *face;
+ BMIter iter;
+ BM_ITER_MESH (face, &iter, em->bm, BM_FACES_OF_MESH) {
+ if (!uvedit_face_visible_test(scene, face)) {
+ continue;
+ }
+ BMLoop *l;
+ BMIter liter;
+ BM_ITER_ELEM (l, &liter, face, BM_LOOPS_OF_FACE) {
+ if (!uvedit_edge_select_test(scene, l, cd_loop_uv_offset)) {
+ continue;
+ }
+
+ MLoopUV *luv_a = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
+ MLoopUV *luv_b = BM_ELEM_CD_GET_VOID_P(l->next, cd_loop_uv_offset);
+ float needle = get_uv_edge_needle(type, l->e, ob_m3, luv_a, luv_b, cd_loop_uv_offset);
+ if (tree_1d) {
+ BLI_kdtree_1d_insert(tree_1d, tree_index++, &needle);
+ }
+ }
+ }
+ }
+
+ if (tree_1d != NULL) {
+ BLI_kdtree_1d_deduplicate(tree_1d);
+ BLI_kdtree_1d_balance(tree_1d);
+ }
+
+ for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
+ Object *ob = objects[ob_index];
+ BMEditMesh *em = BKE_editmesh_from_object(ob);
+ BMesh *bm = em->bm;
+ if (bm->totvertsel == 0) {
+ continue;
+ }
+
+ bool changed = false;
+ const int cd_loop_uv_offset = CustomData_get_offset(&bm->ldata, CD_MLOOPUV);
+ float ob_m3[3][3];
+ copy_m3_m4(ob_m3, ob->obmat);
+
+ BMFace *face;
+ BMIter iter;
+ BM_ITER_MESH (face, &iter, em->bm, BM_FACES_OF_MESH) {
+ if (!uvedit_face_visible_test(scene, face)) {
+ continue;
+ }
+ BMLoop *l;
+ BMIter liter;
+ BM_ITER_ELEM (l, &liter, face, BM_LOOPS_OF_FACE) {
+ if (uvedit_edge_select_test(scene, l, cd_loop_uv_offset)) {
+ continue; /* Already selected. */
+ }
+
+ MLoopUV *luv_a = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
+ MLoopUV *luv_b = BM_ELEM_CD_GET_VOID_P(l->next, cd_loop_uv_offset);
+ float needle = get_uv_edge_needle(type, l->e, ob_m3, luv_a, luv_b, cd_loop_uv_offset);
+ bool select = ED_select_similar_compare_float_tree(tree_1d, needle, threshold, compare);
+ if (select) {
+ uvedit_edge_select_set(scene, em, l, select, false, cd_loop_uv_offset);
+ changed = true;
+ }
+ }
+ if (changed) {
+ uv_select_tag_update_for_object(depsgraph, ts, ob);
+ }
+ }
+ }
+
+ MEM_SAFE_FREE(objects);
+ BLI_kdtree_1d_free(tree_1d);
+ return OPERATOR_FINISHED;
+}
+
+static int uv_select_similar_face_exec(bContext *C, wmOperator *op)
+{
+ Scene *scene = CTX_data_scene(C);
+ ViewLayer *view_layer = CTX_data_view_layer(C);
+ Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C);
+ ToolSettings *ts = CTX_data_tool_settings(C);
+
+ const eUVSelectSimilar type = RNA_enum_get(op->ptr, "type");
+ const float threshold = RNA_float_get(op->ptr, "threshold");
+ const eSimilarCmp compare = RNA_enum_get(op->ptr, "compare");
+
+ uint objects_len = 0;
+ Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data_with_uvs(
+ view_layer, ((View3D *)NULL), &objects_len);
+
+ int max_faces_selected_all = 0;
+ for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
+ Object *ob = objects[ob_index];
+ BMEditMesh *em = BKE_editmesh_from_object(ob);
+ max_faces_selected_all += em->bm->totfacesel;
+ /* TODO: Get a tighter bounds */
+ }
+
+ int tree_index = 0;
+ KDTree_1d *tree_1d = BLI_kdtree_1d_new(max_faces_selected_all);
+
+ for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
+ Object *ob = objects[ob_index];
+
+ BMEditMesh *em = BKE_editmesh_from_object(ob);
+ BMesh *bm = em->bm;
+
+ float ob_m3[3][3];
+ copy_m3_m4(ob_m3, ob->obmat);
+
+ const int cd_loop_uv_offset = CustomData_get_offset(&bm->ldata, CD_MLOOPUV);
+
+ BMFace *face;
+ BMIter iter;
+ BM_ITER_MESH (face, &iter, bm, BM_FACES_OF_MESH) {
+ if (!uvedit_face_visible_test(scene, face)) {
+ continue;
+ }
+ if (!uvedit_face_select_test(scene, face, cd_loop_uv_offset)) {
+ continue;
+ }
+
+ float needle = get_uv_face_needle(type, face, ob_m3, cd_loop_uv_offset);
+ if (tree_1d) {
+ BLI_kdtree_1d_insert(tree_1d, tree_index++, &needle);
+ }
+ }
+ }
+
+ if (tree_1d != NULL) {
+ BLI_kdtree_1d_deduplicate(tree_1d);
+ BLI_kdtree_1d_balance(tree_1d);
+ }
+
+ for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
+ Object *ob = objects[ob_index];
+
+ BMEditMesh *em = BKE_editmesh_from_object(ob);
+ BMesh *bm = em->bm;
+ bool changed = false;
+ bool do_history = false;
+ const int cd_loop_uv_offset = CustomData_get_offset(&bm->ldata, CD_MLOOPUV);
+
+ float ob_m3[3][3];
+ copy_m3_m4(ob_m3, ob->obmat);
+
+ BMFace *face;
+ BMIter iter;
+ BM_ITER_MESH (face, &iter, bm, BM_FACES_OF_MESH) {
+ if (!uvedit_face_visible_test(scene, face)) {
+ continue;
+ }
+ if (uvedit_face_select_test(scene, face, cd_loop_uv_offset)) {
+ continue;
+ }
+
+ float needle = get_uv_face_needle(type, face, ob_m3, cd_loop_uv_offset);
+
+ bool select = ED_select_similar_compare_float_tree(tree_1d, needle, threshold, compare);
+ if (select) {
+ uvedit_face_select_set(scene, em, face, select, do_history, cd_loop_uv_offset);
+ changed = true;
+ }
+ }
+ if (changed) {
+ uv_select_tag_update_for_object(depsgraph, ts, ob);
+ }
+ }
+
+ MEM_SAFE_FREE(objects);
+ BLI_kdtree_1d_free(tree_1d);
+ return OPERATOR_FINISHED;
+}
+
+/* Select similar UV faces/edges/verts based on current selection. */
+static int uv_select_similar_exec(bContext *C, wmOperator *op)
+{
+ ToolSettings *ts = CTX_data_tool_settings(C);
+ PropertyRNA *prop = RNA_struct_find_property(op->ptr, "threshold");
+
+ if (!RNA_property_is_set(op->ptr, prop)) {
+ RNA_property_float_set(op->ptr, prop, ts->select_thresh);
+ }
+ else {
+ ts->select_thresh = RNA_property_float_get(op->ptr, prop);
+ }
+
+ int selectmode = (ts->uv_flag & UV_SYNC_SELECTION) ? ts->selectmode : ts->uv_selectmode;
+ if (selectmode & UV_SELECT_EDGE) {
+ return uv_select_similar_edge_exec(C, op);
+ }
+ else if (selectmode & UV_SELECT_FACE) {
+ return uv_select_similar_face_exec(C, op);
+ }
+ if (selectmode & UV_SELECT_ISLAND) {
+ // return uv_select_similar_island_exec(C, op);
+ }
+
+ return uv_select_similar_vert_exec(C, op);
+}
+
+static EnumPropertyItem prop_vert_similar_types[] = {{UV_SSIM_PIN, "PIN", 0, "Pinned", ""}, {0}};
+
+static EnumPropertyItem prop_edge_similar_types[] = {
+ {UV_SSIM_LENGTH_UV, "LENGTH", 0, "Length", ""},
+ {UV_SSIM_LENGTH_3D, "LENGTH_3D", 0, "Length 3D", ""},
+ {UV_SSIM_PIN, "PIN", 0, "Pinned", ""},
+ {0}};
+
+static EnumPropertyItem prop_face_similar_types[] = {
+ {UV_SSIM_AREA_UV, "AREA", 0, "Area", ""},
+ {UV_SSIM_AREA_3D, "AREA_3D", 0, "Area 3D", ""},
+ {UV_SSIM_SIDES, "SIDES", 0, "Polygon Sides", ""},
+ {UV_SSIM_MATERIAL, "MATERIAL", 0, "Material", ""},
+ {0}};
+
+static EnumPropertyItem prop_similar_compare_types[] = {{SIM_CMP_EQ, "EQUAL", 0, "Equal", ""},
+ {SIM_CMP_GT, "GREATER", 0, "Greater", ""},
+ {SIM_CMP_LT, "LESS", 0, "Less", ""},
+ {0}};
+
+static const EnumPropertyItem *uv_select_similar_type_itemf(bContext *C,
+ PointerRNA *UNUSED(ptr),
+ PropertyRNA *UNUSED(prop),
+ bool *UNUSED(r_free))
+{
+ const ToolSettings *ts = CTX_data_tool_settings(C);
+ if (ts) {
+ int selectmode = (ts->uv_flag & UV_SYNC_SELECTION) ? ts->selectmode : ts->uv_selectmode;
+ if (selectmode & UV_SELECT_EDGE) {
+ return prop_edge_similar_types;
+ }
+ if (selectmode & UV_SELECT_FACE) {
+ return prop_face_similar_types;
+ }
+ }
+
+ return prop_vert_similar_types;
+}
+void UV_OT_select_similar(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Select Similar";
+ ot->description = "Select similar UVs by property types";
+ ot->idname = "UV_OT_select_similar";
+
+ /* api callbacks */
+ ot->invoke = WM_menu_invoke;
+ ot->exec = uv_select_similar_exec;
+ ot->poll = ED_operator_uvedit_space_image;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+
+ /* properties */
+ PropertyRNA *prop = ot->prop = RNA_def_enum(
+ ot->srna, "type", prop_vert_similar_types, SIMVERT_NORMAL, "Type", "");
+ RNA_def_enum_funcs(prop, uv_select_similar_type_itemf);
+ RNA_def_enum(ot->srna, "compare", prop_similar_compare_types, SIM_CMP_EQ, "Compare", "");
+ RNA_def_float(ot->srna, "threshold", 0.0f, 0.0f, 1.0f, "Threshold", "", 0.0f, 1.0f);
+}
+
+/** \} */
/* -------------------------------------------------------------------- */
/** \name Selected Elements as Arrays (Vertex, Edge & Faces)
diff --git a/source/blender/editors/uvedit/uvedit_smart_stitch.c b/source/blender/editors/uvedit/uvedit_smart_stitch.c
index bacf321fce1..55e44607f6f 100644
--- a/source/blender/editors/uvedit/uvedit_smart_stitch.c
+++ b/source/blender/editors/uvedit/uvedit_smart_stitch.c
@@ -1716,7 +1716,7 @@ static void stitch_draw_vbo(GPUVertBuf *vbo, GPUPrimType prim_type, const float
GPU_batch_discard(batch);
}
-/* TODO: make things pretier : store batches inside StitchPreviewer instead of the bare verts pos
+/* TODO: make things prettier : store batches inside StitchPreviewer instead of the bare verts pos
*/
static void stitch_draw(const bContext *UNUSED(C), ARegion *UNUSED(region), void *arg)
{
diff --git a/source/blender/editors/uvedit/uvedit_unwrap_ops.c b/source/blender/editors/uvedit/uvedit_unwrap_ops.c
index 34fae2ffb2a..3618286ec01 100644
--- a/source/blender/editors/uvedit/uvedit_unwrap_ops.c
+++ b/source/blender/editors/uvedit/uvedit_unwrap_ops.c
@@ -103,7 +103,7 @@ static bool ED_uvedit_ensure_uvs(Object *obedit)
int cd_loop_uv_offset;
if (em && em->bm->totface && !CustomData_has_layer(&em->bm->ldata, CD_MLOOPUV)) {
- ED_mesh_uv_texture_add(obedit->data, NULL, true, true, NULL);
+ ED_mesh_uv_add(obedit->data, NULL, true, true, NULL);
}
/* Happens when there are no faces. */
@@ -267,60 +267,104 @@ static bool uvedit_have_selection_multi(const Scene *scene,
return have_select;
}
+void ED_uvedit_get_aspect_from_material(Object *ob,
+ const int material_index,
+ float *r_aspx,
+ float *r_aspy)
+{
+ if (UNLIKELY(material_index < 0 || material_index >= ob->totcol)) {
+ *r_aspx = 1.0f;
+ *r_aspy = 1.0f;
+ return;
+ }
+ Image *ima;
+ ED_object_get_active_image(ob, material_index + 1, &ima, NULL, NULL, NULL);
+ ED_image_get_uv_aspect(ima, NULL, r_aspx, r_aspy);
+}
+
void ED_uvedit_get_aspect(Object *ob, float *r_aspx, float *r_aspy)
{
BMEditMesh *em = BKE_editmesh_from_object(ob);
BLI_assert(em != NULL);
bool sloppy = true;
bool selected = false;
- BMFace *efa;
- Image *ima;
+ BMFace *efa = BM_mesh_active_face_get(em->bm, sloppy, selected);
+ if (!efa) {
+ *r_aspx = 1.0f;
+ *r_aspy = 1.0f;
+ return;
+ }
- efa = BM_mesh_active_face_get(em->bm, sloppy, selected);
+ ED_uvedit_get_aspect_from_material(ob, efa->mat_nr, r_aspx, r_aspy);
+}
- if (efa) {
- ED_object_get_active_image(ob, efa->mat_nr + 1, &ima, NULL, NULL, NULL);
+static bool uvedit_is_face_affected(const Scene *scene,
+ BMFace *efa,
+ const UnwrapOptions *options,
+ const int cd_loop_uv_offset)
+{
+ if (BM_elem_flag_test(efa, BM_ELEM_HIDDEN)) {
+ return false;
+ }
- ED_image_get_uv_aspect(ima, NULL, r_aspx, r_aspy);
+ if (options->only_selected_faces && !BM_elem_flag_test(efa, BM_ELEM_SELECT)) {
+ return false;
}
- else {
- *r_aspx = 1.0f;
- *r_aspy = 1.0f;
+
+ if (options->topology_from_uvs && options->only_selected_uvs &&
+ !uvedit_face_select_test(scene, efa, cd_loop_uv_offset)) {
+ return false;
+ }
+
+ return true;
+}
+
+/* Prepare unique indices for each unique pinned UV, even if it shares a BMVert.
+ */
+static void uvedit_prepare_pinned_indices(ParamHandle *handle,
+ BMFace *efa,
+ const int cd_loop_uv_offset)
+{
+ BMIter liter;
+ BMLoop *l;
+ BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
+ MLoopUV *luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
+ if (luv->flag & MLOOPUV_PINNED) {
+ int bmvertindex = BM_elem_index_get(l->v);
+ GEO_uv_prepare_pin_index(handle, bmvertindex, luv->uv);
+ }
}
}
static void construct_param_handle_face_add(ParamHandle *handle,
const Scene *scene,
BMFace *efa,
- int face_index,
+ ParamKey face_index,
const int cd_loop_uv_offset)
{
- ParamKey key;
ParamKey *vkeys = BLI_array_alloca(vkeys, efa->len);
- ParamBool *pin = BLI_array_alloca(pin, efa->len);
- ParamBool *select = BLI_array_alloca(select, efa->len);
- float **co = BLI_array_alloca(co, efa->len);
+ bool *pin = BLI_array_alloca(pin, efa->len);
+ bool *select = BLI_array_alloca(select, efa->len);
+ const float **co = BLI_array_alloca(co, efa->len);
float **uv = BLI_array_alloca(uv, efa->len);
int i;
BMIter liter;
BMLoop *l;
- key = (ParamKey)face_index;
-
/* let parametrizer split the ngon, it can make better decisions
* about which split is best for unwrapping than poly-fill. */
BM_ITER_ELEM_INDEX (l, &liter, efa, BM_LOOPS_OF_FACE, i) {
MLoopUV *luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
- vkeys[i] = (ParamKey)BM_elem_index_get(l->v);
+ vkeys[i] = GEO_uv_find_pin_index(handle, BM_elem_index_get(l->v), luv->uv);
co[i] = l->v->co;
uv[i] = luv->uv;
pin[i] = (luv->flag & MLOOPUV_PINNED) != 0;
select[i] = uvedit_uv_select_test(scene, l, cd_loop_uv_offset);
}
- GEO_uv_parametrizer_face_add(handle, key, i, vkeys, co, uv, pin, select);
+ GEO_uv_parametrizer_face_add(handle, face_index, i, vkeys, co, uv, pin, select);
}
/* See: construct_param_handle_multi to handle multiple objects at once. */
@@ -330,16 +374,12 @@ static ParamHandle *construct_param_handle(const Scene *scene,
const UnwrapOptions *options,
UnwrapResultInfo *result_info)
{
- ParamHandle *handle;
BMFace *efa;
- BMLoop *l;
BMEdge *eed;
- BMIter iter, liter;
+ BMIter iter;
int i;
- const int cd_loop_uv_offset = CustomData_get_offset(&bm->ldata, CD_MLOOPUV);
-
- handle = GEO_uv_parametrizer_construct_begin();
+ ParamHandle *handle = GEO_uv_parametrizer_construct_begin();
if (options->correct_aspect) {
float aspx, aspy;
@@ -354,30 +394,17 @@ static ParamHandle *construct_param_handle(const Scene *scene,
/* we need the vert indices */
BM_mesh_elem_index_ensure(bm, BM_VERT);
+ const int cd_loop_uv_offset = CustomData_get_offset(&bm->ldata, CD_MLOOPUV);
BM_ITER_MESH_INDEX (efa, &iter, bm, BM_FACES_OF_MESH, i) {
-
- if (BM_elem_flag_test(efa, BM_ELEM_HIDDEN) ||
- (options->only_selected_faces && BM_elem_flag_test(efa, BM_ELEM_SELECT) == 0)) {
- continue;
+ if (uvedit_is_face_affected(scene, efa, options, cd_loop_uv_offset)) {
+ uvedit_prepare_pinned_indices(handle, efa, cd_loop_uv_offset);
}
+ }
- if (options->topology_from_uvs) {
- bool is_loopsel = false;
-
- BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
- if (options->only_selected_uvs &&
- (uvedit_uv_select_test(scene, l, cd_loop_uv_offset) == false)) {
- continue;
- }
- is_loopsel = true;
- break;
- }
- if (is_loopsel == false) {
- continue;
- }
+ BM_ITER_MESH_INDEX (efa, &iter, bm, BM_FACES_OF_MESH, i) {
+ if (uvedit_is_face_affected(scene, efa, options, cd_loop_uv_offset)) {
+ construct_param_handle_face_add(handle, scene, efa, i, cd_loop_uv_offset);
}
-
- construct_param_handle_face_add(handle, scene, efa, i, cd_loop_uv_offset);
}
if (!options->topology_from_uvs || options->topology_from_uvs_use_seams) {
@@ -408,14 +435,12 @@ static ParamHandle *construct_param_handle_multi(const Scene *scene,
const UnwrapOptions *options,
int *count_fail)
{
- ParamHandle *handle;
BMFace *efa;
- BMLoop *l;
BMEdge *eed;
- BMIter iter, liter;
+ BMIter iter;
int i;
- handle = GEO_uv_parametrizer_construct_begin();
+ ParamHandle *handle = GEO_uv_parametrizer_construct_begin();
if (options->correct_aspect) {
Object *ob = objects[0];
@@ -444,29 +469,15 @@ static ParamHandle *construct_param_handle_multi(const Scene *scene,
}
BM_ITER_MESH_INDEX (efa, &iter, bm, BM_FACES_OF_MESH, i) {
-
- if (BM_elem_flag_test(efa, BM_ELEM_HIDDEN) ||
- (options->only_selected_faces && BM_elem_flag_test(efa, BM_ELEM_SELECT) == 0)) {
- continue;
+ if (uvedit_is_face_affected(scene, efa, options, cd_loop_uv_offset)) {
+ uvedit_prepare_pinned_indices(handle, efa, cd_loop_uv_offset);
}
+ }
- if (options->topology_from_uvs) {
- bool is_loopsel = false;
-
- BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
- if (options->only_selected_uvs &&
- (uvedit_uv_select_test(scene, l, cd_loop_uv_offset) == false)) {
- continue;
- }
- is_loopsel = true;
- break;
- }
- if (is_loopsel == false) {
- continue;
- }
+ BM_ITER_MESH_INDEX (efa, &iter, bm, BM_FACES_OF_MESH, i) {
+ if (uvedit_is_face_affected(scene, efa, options, cd_loop_uv_offset)) {
+ construct_param_handle_face_add(handle, scene, efa, i + offset, cd_loop_uv_offset);
}
-
- construct_param_handle_face_add(handle, scene, efa, i + offset, cd_loop_uv_offset);
}
if (!options->topology_from_uvs || options->topology_from_uvs_use_seams) {
@@ -493,8 +504,8 @@ static void texface_from_original_index(const Scene *scene,
BMFace *efa,
int index,
float **r_uv,
- ParamBool *r_pin,
- ParamBool *r_select)
+ bool *r_pin,
+ bool *r_select)
{
BMLoop *l;
BMIter liter;
@@ -530,7 +541,6 @@ static ParamHandle *construct_param_handle_subsurfed(const Scene *scene,
const UnwrapOptions *options,
UnwrapResultInfo *result_info)
{
- ParamHandle *handle;
/* index pointers */
MPoly *mpoly;
MLoop *mloop;
@@ -562,7 +572,7 @@ static ParamHandle *construct_param_handle_subsurfed(const Scene *scene,
const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV);
- handle = GEO_uv_parametrizer_construct_begin();
+ ParamHandle *handle = GEO_uv_parametrizer_construct_begin();
if (options->correct_aspect) {
float aspx, aspy;
@@ -627,8 +637,8 @@ static ParamHandle *construct_param_handle_subsurfed(const Scene *scene,
/* Prepare and feed faces to the solver */
for (i = 0, mpoly = subsurfedPolys; i < numOfFaces; i++, mpoly++) {
ParamKey key, vkeys[4];
- ParamBool pin[4], select[4];
- float *co[4];
+ bool pin[4], select[4];
+ const float *co[4];
float *uv[4];
BMFace *origFace = faceMap[i];
@@ -646,7 +656,7 @@ static ParamHandle *construct_param_handle_subsurfed(const Scene *scene,
mloop = &subsurfedLoops[mpoly->loopstart];
- /* We will not check for v4 here. Subsurfed mfaces always have 4 vertices. */
+ /* We will not check for v4 here. Sub-surface faces always have 4 vertices. */
BLI_assert(mpoly->totloop == 4);
key = (ParamKey)i;
vkeys[0] = (ParamKey)mloop[0].v;
@@ -1014,8 +1024,7 @@ static void uvedit_pack_islands(const Scene *scene, Object *ob, BMesh *bm)
bool rotate = true;
bool ignore_pinned = false;
- ParamHandle *handle;
- handle = construct_param_handle(scene, ob, bm, &options, NULL);
+ ParamHandle *handle = construct_param_handle(scene, ob, bm, &options, NULL);
GEO_uv_parametrizer_pack(handle, scene->toolsettings->uvcalc_margin, rotate, ignore_pinned);
GEO_uv_parametrizer_flush(handle);
GEO_uv_parametrizer_delete(handle);
@@ -1034,8 +1043,7 @@ static void uvedit_pack_islands_multi(const Scene *scene,
bool rotate,
bool ignore_pinned)
{
- ParamHandle *handle;
- handle = construct_param_handle_multi(scene, objects, objects_len, options, NULL);
+ ParamHandle *handle = construct_param_handle_multi(scene, objects, objects_len, options, NULL);
GEO_uv_parametrizer_pack(handle, scene->toolsettings->uvcalc_margin, rotate, ignore_pinned);
GEO_uv_parametrizer_flush(handle);
GEO_uv_parametrizer_delete(handle);
@@ -1241,7 +1249,7 @@ void ED_uvedit_live_unwrap_begin(Scene *scene, Object *obedit)
handle = construct_param_handle(scene, obedit, em->bm, &options, NULL);
}
- GEO_uv_parametrizer_lscm_begin(handle, PARAM_TRUE, abf);
+ GEO_uv_parametrizer_lscm_begin(handle, true, abf);
/* Create or increase size of g_live_unwrap.handles array */
if (g_live_unwrap.handles == NULL) {
@@ -1527,49 +1535,88 @@ static void uv_transform_properties(wmOperatorType *ot, int radius)
}
}
-static void correct_uv_aspect(Object *ob, BMEditMesh *em)
+static void shrink_loop_uv_by_aspect_ratio(BMFace *efa,
+ const int cd_loop_uv_offset,
+ const float aspect_y)
{
+ BLI_assert(aspect_y != 1.0f); /* Nothing to do, should be handled by caller. */
+ BLI_assert(aspect_y > 0.0f); /* Negative aspect ratios are not supported. */
+
BMLoop *l;
- BMIter iter, liter;
- MLoopUV *luv;
- BMFace *efa;
- float scale, aspx, aspy;
+ BMIter iter;
+ BM_ITER_ELEM (l, &iter, efa, BM_LOOPS_OF_FACE) {
+ MLoopUV *luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
+ if (aspect_y > 1.0f) {
+ /* Reduce round-off error, i.e. `u = (u - 0.5) / aspect_y + 0.5`. */
+ luv->uv[0] = luv->uv[0] / aspect_y + (0.5f - 0.5f / aspect_y);
+ }
+ else {
+ /* Reduce round-off error, i.e. `v = (v - 0.5) * aspect_y + 0.5`. */
+ luv->uv[1] = luv->uv[1] * aspect_y + (0.5f - 0.5f * aspect_y);
+ }
+ }
+}
+static void correct_uv_aspect(Object *ob, BMEditMesh *em)
+{
const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV);
-
+ float aspx, aspy;
ED_uvedit_get_aspect(ob, &aspx, &aspy);
+ const float aspect_y = aspx / aspy;
+ if (aspect_y == 1.0f) {
+ /* Scaling by 1.0 has no effect. */
+ return;
+ }
+ BMFace *efa;
+ BMIter iter;
+ BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
+ if (BM_elem_flag_test(efa, BM_ELEM_SELECT)) {
+ shrink_loop_uv_by_aspect_ratio(efa, cd_loop_uv_offset, aspect_y);
+ }
+ }
+}
- if (aspx == aspy) {
+static void correct_uv_aspect_per_face(Object *ob, BMEditMesh *em)
+{
+ const int materials_num = ob->totcol;
+ if (materials_num == 0) {
+ /* Without any materials, there is no aspect_y information and nothing to do. */
return;
}
- if (aspx > aspy) {
- scale = aspy / aspx;
+ float *material_aspect_y = BLI_array_alloca(material_aspect_y, materials_num);
+ /* Lazily initialize aspect ratio for materials. */
+ copy_vn_fl(material_aspect_y, materials_num, -1.0f);
- BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
- if (!BM_elem_flag_test(efa, BM_ELEM_SELECT)) {
- continue;
- }
+ const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV);
- BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
- luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
- luv->uv[0] = ((luv->uv[0] - 0.5f) * scale) + 0.5f;
- }
+ BMFace *efa;
+ BMIter iter;
+ BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
+ if (!BM_elem_flag_test(efa, BM_ELEM_SELECT)) {
+ continue;
}
- }
- else {
- scale = aspx / aspy;
- BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
- if (!BM_elem_flag_test(efa, BM_ELEM_SELECT)) {
- continue;
- }
+ const int material_index = efa->mat_nr;
+ if (UNLIKELY(material_index < 0 || material_index >= materials_num)) {
+ /* The index might be for a material slot which is not currently setup. */
+ continue;
+ }
- BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
- luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
- luv->uv[1] = ((luv->uv[1] - 0.5f) * scale) + 0.5f;
- }
+ float aspect_y = material_aspect_y[material_index];
+ if (aspect_y == -1.0f) {
+ /* Lazily initialize aspect ratio for materials. */
+ float aspx, aspy;
+ ED_uvedit_get_aspect_from_material(ob, material_index, &aspx, &aspy);
+ aspect_y = aspx / aspy;
+ material_aspect_y[material_index] = aspect_y;
+ }
+
+ if (aspect_y == 1.0f) {
+ /* Scaling by 1.0 has no effect. */
+ continue;
}
+ shrink_loop_uv_by_aspect_ratio(efa, cd_loop_uv_offset, aspect_y);
}
}
@@ -1613,7 +1660,17 @@ static void uv_map_clip_correct_properties(wmOperatorType *ot)
uv_map_clip_correct_properties_ex(ot, true);
}
-static void uv_map_clip_correct_multi(Object **objects, uint objects_len, wmOperator *op)
+/**
+ * \param per_face_aspect: Calculate the aspect ratio per-face,
+ * otherwise use a single aspect for all UV's based on the material of the active face.
+ * TODO: using per-face aspect may split UV islands so more advanced UV projection methods
+ * such as "Unwrap" & "Smart UV Projections" will need to handle aspect correction themselves.
+ * For now keep using a single aspect for all faces in this case.
+ */
+static void uv_map_clip_correct_multi(Object **objects,
+ uint objects_len,
+ wmOperator *op,
+ bool per_face_aspect)
{
BMFace *efa;
BMLoop *l;
@@ -1633,9 +1690,14 @@ static void uv_map_clip_correct_multi(Object **objects, uint objects_len, wmOper
BMEditMesh *em = BKE_editmesh_from_object(ob);
const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV);
- /* correct for image aspect ratio */
+ /* Correct for image aspect ratio. */
if (correct_aspect) {
- correct_uv_aspect(ob, em);
+ if (per_face_aspect) {
+ correct_uv_aspect_per_face(ob, em);
+ }
+ else {
+ correct_uv_aspect(ob, em);
+ }
}
if (scale_to_bounds) {
@@ -1678,6 +1740,11 @@ static void uv_map_clip_correct_multi(Object **objects, uint objects_len, wmOper
dy = 1.0f / dy;
}
+ if (dx == 1.0f && dy == 1.0f) {
+ /* Scaling by 1.0 has no effect. */
+ return;
+ }
+
for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
Object *ob = objects[ob_index];
@@ -1702,7 +1769,7 @@ static void uv_map_clip_correct_multi(Object **objects, uint objects_len, wmOper
static void uv_map_clip_correct(Object *ob, wmOperator *op)
{
- uv_map_clip_correct_multi(&ob, 1, op);
+ uv_map_clip_correct_multi(&ob, 1, op, true);
}
/** \} */
@@ -1733,7 +1800,7 @@ static void uvedit_unwrap(const Scene *scene,
handle = construct_param_handle(scene, obedit, em->bm, options, result_info);
}
- GEO_uv_parametrizer_lscm_begin(handle, PARAM_FALSE, scene->toolsettings->unwrapper == 0);
+ GEO_uv_parametrizer_lscm_begin(handle, false, scene->toolsettings->unwrapper == 0);
GEO_uv_parametrizer_lscm_solve(handle,
result_info ? &result_info->count_changed : NULL,
result_info ? &result_info->count_failed : NULL);
@@ -2283,7 +2350,9 @@ static int smart_project_exec(bContext *C, wmOperator *op)
.use_seams = true,
});
- uv_map_clip_correct_multi(objects_changed, object_changed_len, op);
+ /* #ED_uvedit_pack_islands_multi only supports `per_face_aspect = false`. */
+ const bool per_face_aspect = false;
+ uv_map_clip_correct_multi(objects_changed, object_changed_len, op, per_face_aspect);
}
MEM_freeN(objects_changed);
@@ -2485,7 +2554,7 @@ static int uv_from_view_exec(bContext *C, wmOperator *op)
}
if (changed_multi) {
- uv_map_clip_correct_multi(objects, objects_len, op);
+ uv_map_clip_correct_multi(objects, objects_len, op, true);
}
MEM_freeN(objects);
@@ -2968,7 +3037,7 @@ void ED_uvedit_add_simple_uvs(Main *bmain, const Scene *scene, Object *ob)
* since we are not in edit mode we need to ensure only the uv flags are tested */
scene->toolsettings->uv_flag &= ~UV_SYNC_SELECTION;
- ED_mesh_uv_texture_ensure(me, NULL);
+ ED_mesh_uv_ensure(me, NULL);
BM_mesh_bm_from_me(bm,
me,
diff --git a/source/blender/freestyle/intern/blender_interface/BlenderFileLoader.cpp b/source/blender/freestyle/intern/blender_interface/BlenderFileLoader.cpp
index 9304e6aa3fb..e76e74b89e4 100644
--- a/source/blender/freestyle/intern/blender_interface/BlenderFileLoader.cpp
+++ b/source/blender/freestyle/intern/blender_interface/BlenderFileLoader.cpp
@@ -370,7 +370,7 @@ int BlenderFileLoader::testDegenerateTriangle(float v1[3], float v2[3], float v3
return 0;
}
-static bool testEdgeMark(Mesh *me, FreestyleEdge *fed, const MLoopTri *lt, int i)
+static bool testEdgeMark(Mesh *me, const FreestyleEdge *fed, const MLoopTri *lt, int i)
{
MLoop *mloop = &me->mloop[lt->tri[i]];
MLoop *mloop_next = &me->mloop[lt->tri[(i + 1) % 3]];
@@ -395,7 +395,7 @@ void BlenderFileLoader::insertShapeNode(Object *ob, Mesh *me, int id)
// Compute loop normals
BKE_mesh_calc_normals_split(me);
- float(*lnors)[3] = nullptr;
+ const float(*lnors)[3] = nullptr;
if (CustomData_has_layer(&me->ldata, CD_NORMAL)) {
lnors = (float(*)[3])CustomData_get_layer(&me->ldata, CD_NORMAL);
@@ -405,8 +405,8 @@ void BlenderFileLoader::insertShapeNode(Object *ob, Mesh *me, int id)
MVert *mvert = me->mvert;
MLoop *mloop = me->mloop;
MPoly *mpoly = me->mpoly;
- FreestyleEdge *fed = (FreestyleEdge *)CustomData_get_layer(&me->edata, CD_FREESTYLE_EDGE);
- FreestyleFace *ffa = (FreestyleFace *)CustomData_get_layer(&me->pdata, CD_FREESTYLE_FACE);
+ const FreestyleEdge *fed = (FreestyleEdge *)CustomData_get_layer(&me->edata, CD_FREESTYLE_EDGE);
+ const FreestyleFace *ffa = (FreestyleFace *)CustomData_get_layer(&me->pdata, CD_FREESTYLE_FACE);
// Compute view matrix
Object *ob_camera_eval = DEG_get_evaluated_object(_depsgraph, RE_GetCamera(_re));
diff --git a/source/blender/freestyle/intern/blender_interface/BlenderStrokeRenderer.cpp b/source/blender/freestyle/intern/blender_interface/BlenderStrokeRenderer.cpp
index 03e9134c6c2..979673fd736 100644
--- a/source/blender/freestyle/intern/blender_interface/BlenderStrokeRenderer.cpp
+++ b/source/blender/freestyle/intern/blender_interface/BlenderStrokeRenderer.cpp
@@ -499,9 +499,9 @@ void BlenderStrokeRenderer::test_strip_visibility(Strip::vertex_container &strip
StrokeVertexRep *svRep[3];
bool visible;
- // iterate over all vertices and count visible faces and strip segments
- // (note: a strip segment is a series of visible faces, while two strip
- // segments are separated by one or more invisible faces)
+ /* Iterate over all vertices and count visible faces and strip segments
+ * (NOTE: a strip segment is a series of visible faces, while two strip
+ * segments are separated by one or more invisible faces). */
v[0] = strip_vertices.begin();
v[1] = v[0] + 1;
v[2] = v[0] + 2;
diff --git a/source/blender/freestyle/intern/geometry/SweepLine.h b/source/blender/freestyle/intern/geometry/SweepLine.h
index 1165e1bf064..c170ee4d122 100644
--- a/source/blender/freestyle/intern/geometry/SweepLine.h
+++ b/source/blender/freestyle/intern/geometry/SweepLine.h
@@ -183,7 +183,7 @@ template<class T1, class T2> struct binary_rule {
binary_rule()
{
}
- template<class T3, class T4> binary_rule(const binary_rule<T3, T4> &brother)
+ template<class T3, class T4> binary_rule(const binary_rule<T3, T4> & /*brother*/)
{
}
virtual ~binary_rule()
diff --git a/source/blender/functions/FN_field.hh b/source/blender/functions/FN_field.hh
index 0005d788a3b..a8136d06c5f 100644
--- a/source/blender/functions/FN_field.hh
+++ b/source/blender/functions/FN_field.hh
@@ -372,7 +372,7 @@ class FieldEvaluator : NonMovable, NonCopyable {
/**
* \param field: Field to add to the evaluator.
* \param dst: Mutable span that the evaluated result for this field is be written into.
- * \note: When the output may only be used as a single value, the version of this function with
+ * \note When the output may only be used as a single value, the version of this function with
* a virtual array result array should be used.
*/
int add_with_destination(GField field, GMutableSpan dst);
@@ -380,7 +380,7 @@ class FieldEvaluator : NonMovable, NonCopyable {
/**
* \param field: Field to add to the evaluator.
* \param dst: Mutable span that the evaluated result for this field is be written into.
- * \note: When the output may only be used as a single value, the version of this function with
+ * \note When the output may only be used as a single value, the version of this function with
* a virtual array result array should be used.
*/
template<typename T> int add_with_destination(Field<T> field, MutableSpan<T> dst)
@@ -476,6 +476,8 @@ template<typename T> T evaluate_constant_field(const Field<T> &field)
return value;
}
+Field<bool> invert_boolean_field(const Field<bool> &field);
+
GField make_constant_field(const CPPType &type, const void *value);
template<typename T> Field<T> make_constant_field(T value)
diff --git a/source/blender/functions/FN_multi_function_builder.hh b/source/blender/functions/FN_multi_function_builder.hh
index a35339b2495..e6dc01eb539 100644
--- a/source/blender/functions/FN_multi_function_builder.hh
+++ b/source/blender/functions/FN_multi_function_builder.hh
@@ -207,9 +207,9 @@ void execute_materialized(TypeSequence<ParamTags...> /* param_tags */,
(
/* Setup information for all parameters. */
[&] {
- using ParamTag = ParamTags;
- using T = typename ParamTag::base_type;
- ArgInfo<ParamTags> &arg_info = std::get<I>(args_info);
+ typedef ParamTags ParamTag;
+ typedef typename ParamTag::base_type T;
+ [[maybe_unused]] ArgInfo<ParamTags> &arg_info = std::get<I>(args_info);
if constexpr (ParamTag::category == MFParamCategory::SingleInput) {
VArray<T> &varray = *args;
if (varray.is_single()) {
@@ -246,7 +246,7 @@ void execute_materialized(TypeSequence<ParamTags...> /* param_tags */,
[&] {
using ParamTag = ParamTags;
using T = typename ParamTag::base_type;
- ArgInfo<ParamTags> &arg_info = std::get<I>(args_info);
+ [[maybe_unused]] ArgInfo<ParamTags> &arg_info = std::get<I>(args_info);
if constexpr (ParamTag::category == MFParamCategory::SingleInput) {
if (arg_info.mode == ArgMode::Single) {
/* The single value has been filled into a buffer already reused for every chunk. */
@@ -282,9 +282,9 @@ void execute_materialized(TypeSequence<ParamTags...> /* param_tags */,
(
/* Destruct values that have been materialized before. */
[&] {
- using ParamTag = ParamTags;
- using T = typename ParamTag::base_type;
- ArgInfo<ParamTags> &arg_info = std::get<I>(args_info);
+ typedef ParamTags ParamTag;
+ typedef typename ParamTag::base_type T;
+ [[maybe_unused]] ArgInfo<ParamTags> &arg_info = std::get<I>(args_info);
if constexpr (ParamTag::category == MFParamCategory::SingleInput) {
if (arg_info.mode == ArgMode::Materialized) {
T *in_chunk = std::get<I>(buffers_owner).ptr();
@@ -298,9 +298,9 @@ void execute_materialized(TypeSequence<ParamTags...> /* param_tags */,
(
/* Destruct buffers for single value inputs. */
[&] {
- using ParamTag = ParamTags;
- using T = typename ParamTag::base_type;
- ArgInfo<ParamTags> &arg_info = std::get<I>(args_info);
+ typedef ParamTags ParamTag;
+ typedef typename ParamTag::base_type T;
+ [[maybe_unused]] ArgInfo<ParamTags> &arg_info = std::get<I>(args_info);
if constexpr (ParamTag::category == MFParamCategory::SingleInput) {
if (arg_info.mode == ArgMode::Single) {
MutableSpan<T> in_chunk = std::get<I>(buffers);
@@ -347,8 +347,8 @@ template<typename... ParamTags> class CustomMF : public MultiFunction {
(
/* Get all parameters from #params and store them in #retrieved_params. */
[&]() {
- using ParamTag = typename TagsSequence::template at_index<I>;
- using T = typename ParamTag::base_type;
+ typedef typename TagsSequence::template at_index<I> ParamTag;
+ typedef typename ParamTag::base_type T;
if constexpr (ParamTag::category == MFParamCategory::SingleInput) {
std::get<I>(retrieved_params) = params.readonly_single_input<T>(I);
@@ -402,7 +402,7 @@ template<typename... ParamTags> class CustomMF : public MultiFunction {
(
/* Loop over all parameter types and add an entry for each in the signature. */
[&] {
- using ParamTag = typename TagsSequence::template at_index<I>;
+ typedef typename TagsSequence::template at_index<I> ParamTag;
signature.add(ParamTag(), "");
}(),
...);
diff --git a/source/blender/functions/FN_multi_function_params.hh b/source/blender/functions/FN_multi_function_params.hh
index 9d09378ab63..16a33c9cda7 100644
--- a/source/blender/functions/FN_multi_function_params.hh
+++ b/source/blender/functions/FN_multi_function_params.hh
@@ -41,6 +41,10 @@ class MFParamsBuilder {
MFParamsBuilder(const MFSignature &signature, const IndexMask mask)
: signature_(&signature), mask_(mask), min_array_size_(mask.min_array_size())
{
+ virtual_arrays_.reserve(signature.virtual_array_num);
+ mutable_spans_.reserve(signature.span_num);
+ virtual_vector_arrays_.reserve(signature.virtual_vector_array_num);
+ vector_arrays_.reserve(signature.vector_array_num);
}
public:
@@ -53,28 +57,33 @@ class MFParamsBuilder {
template<typename T> void add_readonly_single_input_value(T value, StringRef expected_name = "")
{
- this->add_readonly_single_input(VArray<T>::ForSingle(std::move(value), min_array_size_),
- expected_name);
+ this->assert_current_param_type(MFParamType::ForSingleInput(CPPType::get<T>()), expected_name);
+ virtual_arrays_.append_unchecked_as(
+ varray_tag::single{}, CPPType::get<T>(), min_array_size_, &value);
}
template<typename T> void add_readonly_single_input(const T *value, StringRef expected_name = "")
{
- this->add_readonly_single_input(
- GVArray::ForSingleRef(CPPType::get<T>(), min_array_size_, value), expected_name);
+ this->assert_current_param_type(MFParamType::ForSingleInput(CPPType::get<T>()), expected_name);
+ virtual_arrays_.append_unchecked_as(
+ varray_tag::single_ref{}, CPPType::get<T>(), min_array_size_, value);
}
void add_readonly_single_input(const GSpan span, StringRef expected_name = "")
{
- this->add_readonly_single_input(GVArray::ForSpan(span), expected_name);
+ this->assert_current_param_type(MFParamType::ForSingleInput(span.type()), expected_name);
+ BLI_assert(span.size() >= min_array_size_);
+ virtual_arrays_.append_unchecked_as(varray_tag::span{}, span);
}
void add_readonly_single_input(GPointer value, StringRef expected_name = "")
{
- this->add_readonly_single_input(
- GVArray::ForSingleRef(*value.type(), min_array_size_, value.get()), expected_name);
+ this->assert_current_param_type(MFParamType::ForSingleInput(*value.type()), expected_name);
+ virtual_arrays_.append_unchecked_as(
+ varray_tag::single_ref{}, *value.type(), min_array_size_, value.get());
}
void add_readonly_single_input(GVArray varray, StringRef expected_name = "")
{
this->assert_current_param_type(MFParamType::ForSingleInput(varray.type()), expected_name);
BLI_assert(varray.size() >= min_array_size_);
- virtual_arrays_.append(varray);
+ virtual_arrays_.append_unchecked_as(std::move(varray));
}
void add_readonly_vector_input(const GVectorArray &vector_array, StringRef expected_name = "")
@@ -92,7 +101,7 @@ class MFParamsBuilder {
{
this->assert_current_param_type(MFParamType::ForVectorInput(ref.type()), expected_name);
BLI_assert(ref.size() >= min_array_size_);
- virtual_vector_arrays_.append(&ref);
+ virtual_vector_arrays_.append_unchecked(&ref);
}
template<typename T> void add_uninitialized_single_output(T *value, StringRef expected_name = "")
@@ -104,7 +113,7 @@ class MFParamsBuilder {
{
this->assert_current_param_type(MFParamType::ForSingleOutput(ref.type()), expected_name);
BLI_assert(ref.size() >= min_array_size_);
- mutable_spans_.append(ref);
+ mutable_spans_.append_unchecked(ref);
}
void add_ignored_single_output(StringRef expected_name = "")
{
@@ -115,7 +124,7 @@ class MFParamsBuilder {
const CPPType &type = param_type.data_type().single_type();
/* An empty span indicates that this is ignored. */
const GMutableSpan dummy_span{type};
- mutable_spans_.append(dummy_span);
+ mutable_spans_.append_unchecked(dummy_span);
}
void add_vector_output(GVectorArray &vector_array, StringRef expected_name = "")
@@ -123,14 +132,14 @@ class MFParamsBuilder {
this->assert_current_param_type(MFParamType::ForVectorOutput(vector_array.type()),
expected_name);
BLI_assert(vector_array.size() >= min_array_size_);
- vector_arrays_.append(&vector_array);
+ vector_arrays_.append_unchecked(&vector_array);
}
void add_single_mutable(GMutableSpan ref, StringRef expected_name = "")
{
this->assert_current_param_type(MFParamType::ForMutableSingle(ref.type()), expected_name);
BLI_assert(ref.size() >= min_array_size_);
- mutable_spans_.append(ref);
+ mutable_spans_.append_unchecked(ref);
}
void add_vector_mutable(GVectorArray &vector_array, StringRef expected_name = "")
@@ -138,7 +147,7 @@ class MFParamsBuilder {
this->assert_current_param_type(MFParamType::ForMutableVector(vector_array.type()),
expected_name);
BLI_assert(vector_array.size() >= min_array_size_);
- vector_arrays_.append(&vector_array);
+ vector_arrays_.append_unchecked(&vector_array);
}
GMutableSpan computed_array(int param_index)
diff --git a/source/blender/functions/FN_multi_function_procedure.hh b/source/blender/functions/FN_multi_function_procedure.hh
index 75a54992a48..da269b08155 100644
--- a/source/blender/functions/FN_multi_function_procedure.hh
+++ b/source/blender/functions/FN_multi_function_procedure.hh
@@ -87,7 +87,7 @@ class MFVariable : NonCopyable, NonMovable {
MFDataType data_type_;
Vector<MFInstruction *> users_;
std::string name_;
- int id_;
+ int index_in_graph_;
friend MFProcedure;
friend MFCallInstruction;
@@ -101,7 +101,7 @@ class MFVariable : NonCopyable, NonMovable {
StringRefNull name() const;
void set_name(std::string name);
- int id() const;
+ int index_in_procedure() const;
};
/** Base class for all instruction types. */
@@ -376,9 +376,9 @@ inline StringRefNull MFVariable::name() const
return name_;
}
-inline int MFVariable::id() const
+inline int MFVariable::index_in_procedure() const
{
- return id_;
+ return index_in_graph_;
}
/** \} */
diff --git a/source/blender/functions/FN_multi_function_signature.hh b/source/blender/functions/FN_multi_function_signature.hh
index 62c491609a4..6181555dbd1 100644
--- a/source/blender/functions/FN_multi_function_signature.hh
+++ b/source/blender/functions/FN_multi_function_signature.hh
@@ -29,6 +29,15 @@ struct MFSignature {
Vector<int> param_data_indices;
bool depends_on_context = false;
+ /**
+ * Number of elements of each of these types that has to be passed into the multi-function as an
+ * input or output.
+ */
+ int span_num = 0;
+ int virtual_array_num = 0;
+ int virtual_vector_array_num = 0;
+ int vector_array_num = 0;
+
int data_index(int param_index) const
{
return param_data_indices[param_index];
@@ -38,10 +47,6 @@ struct MFSignature {
class MFSignatureBuilder {
private:
MFSignature signature_;
- int span_count_ = 0;
- int virtual_array_count_ = 0;
- int virtual_vector_array_count_ = 0;
- int vector_array_count_ = 0;
public:
MFSignatureBuilder(const char *function_name)
@@ -79,10 +84,10 @@ class MFSignatureBuilder {
switch (data_type.category()) {
case MFDataType::Single:
- signature_.param_data_indices.append(virtual_array_count_++);
+ signature_.param_data_indices.append(signature_.virtual_array_num++);
break;
case MFDataType::Vector:
- signature_.param_data_indices.append(virtual_vector_array_count_++);
+ signature_.param_data_indices.append(signature_.virtual_vector_array_num++);
break;
}
}
@@ -112,10 +117,10 @@ class MFSignatureBuilder {
switch (data_type.category()) {
case MFDataType::Single:
- signature_.param_data_indices.append(span_count_++);
+ signature_.param_data_indices.append(signature_.span_num++);
break;
case MFDataType::Vector:
- signature_.param_data_indices.append(vector_array_count_++);
+ signature_.param_data_indices.append(signature_.vector_array_num++);
break;
}
}
@@ -145,10 +150,10 @@ class MFSignatureBuilder {
switch (data_type.category()) {
case MFDataType::Single:
- signature_.param_data_indices.append(span_count_++);
+ signature_.param_data_indices.append(signature_.span_num++);
break;
case MFDataType::Vector:
- signature_.param_data_indices.append(vector_array_count_++);
+ signature_.param_data_indices.append(signature_.vector_array_num++);
break;
}
}
diff --git a/source/blender/functions/intern/field.cc b/source/blender/functions/intern/field.cc
index a53da717606..47f6a0f19ca 100644
--- a/source/blender/functions/intern/field.cc
+++ b/source/blender/functions/intern/field.cc
@@ -518,6 +518,14 @@ GField make_field_constant_if_possible(GField field)
return new_field;
}
+Field<bool> invert_boolean_field(const Field<bool> &field)
+{
+ static CustomMF_SI_SO<bool, bool> not_fn{
+ "Not", [](bool a) { return !a; }, CustomMF_presets::AllSpanOrSingle()};
+ auto not_op = std::make_shared<FieldOperation>(FieldOperation(not_fn, {field}));
+ return Field<bool>(not_op);
+}
+
GField make_constant_field(const CPPType &type, const void *value)
{
auto constant_node = std::make_shared<FieldConstant>(type, value);
diff --git a/source/blender/functions/intern/multi_function_procedure.cc b/source/blender/functions/intern/multi_function_procedure.cc
index bc045bfd44b..7ad324a9574 100644
--- a/source/blender/functions/intern/multi_function_procedure.cc
+++ b/source/blender/functions/intern/multi_function_procedure.cc
@@ -173,7 +173,7 @@ MFVariable &MFProcedure::new_variable(MFDataType data_type, std::string name)
MFVariable &variable = *allocator_.construct<MFVariable>().release();
variable.name_ = std::move(name);
variable.data_type_ = data_type;
- variable.id_ = variables_.size();
+ variable.index_in_graph_ = variables_.size();
variables_.append(&variable);
return variable;
}
@@ -753,7 +753,7 @@ class MFProcedureDotExport {
ss << "null";
}
else {
- ss << "$" << variable->id();
+ ss << "$" << variable->index_in_procedure();
if (!variable->name().is_empty()) {
ss << "(" << variable->name() << ")";
}
diff --git a/source/blender/functions/intern/multi_function_procedure_executor.cc b/source/blender/functions/intern/multi_function_procedure_executor.cc
index d852fe19924..a45240dad55 100644
--- a/source/blender/functions/intern/multi_function_procedure_executor.cc
+++ b/source/blender/functions/intern/multi_function_procedure_executor.cc
@@ -157,10 +157,6 @@ class ValueAllocator : NonCopyable, NonMovable {
{
}
- template<typename... Args> VariableState *obtain_variable_state(Args &&...args);
-
- void release_variable_state(VariableState *state);
-
VariableValue_GVArray *obtain_GVArray(const GVArray &varray)
{
return this->obtain<VariableValue_GVArray>(varray);
@@ -294,32 +290,27 @@ class ValueAllocator : NonCopyable, NonMovable {
* This class keeps track of a single variable during evaluation.
*/
class VariableState : NonCopyable, NonMovable {
- private:
+ public:
/** The current value of the variable. The storage format may change over time. */
- VariableValue *value_;
+ VariableValue *value_ = nullptr;
/** Number of indices that are currently initialized in this variable. */
- int tot_initialized_;
+ int tot_initialized_ = 0;
/* This a non-owning pointer to either span buffer or #GVectorArray or null. */
void *caller_provided_storage_ = nullptr;
- public:
- VariableState(VariableValue &value, int tot_initialized, void *caller_provided_storage = nullptr)
- : value_(&value),
- tot_initialized_(tot_initialized),
- caller_provided_storage_(caller_provided_storage)
- {
- }
-
- void destruct_self(ValueAllocator &value_allocator, const MFDataType &data_type)
+ void destruct_value(ValueAllocator &value_allocator, const MFDataType &data_type)
{
value_allocator.release_value(value_, data_type);
- value_allocator.release_variable_state(this);
+ value_ = nullptr;
}
/* True if this contains only one value for all indices, i.e. the value for all indices is
* the same. */
bool is_one() const
{
+ if (value_ == nullptr) {
+ return true;
+ }
switch (value_->type) {
case ValueType::GVArray:
return this->value_as<VariableValue_GVArray>()->data.is_single();
@@ -353,6 +344,7 @@ class VariableState : NonCopyable, NonMovable {
{
/* Sanity check to make sure that enough values are initialized. */
BLI_assert(mask.size() <= tot_initialized_);
+ BLI_assert(value_ != nullptr);
switch (value_->type) {
case ValueType::GVArray: {
@@ -391,7 +383,7 @@ class VariableState : NonCopyable, NonMovable {
const MFDataType &data_type,
ValueAllocator &value_allocator)
{
- if (ELEM(value_->type, ValueType::Span, ValueType::GVectorArray)) {
+ if (value_ != nullptr && ELEM(value_->type, ValueType::Span, ValueType::GVectorArray)) {
return;
}
@@ -408,22 +400,24 @@ class VariableState : NonCopyable, NonMovable {
/* Reuse the storage provided caller when possible. */
new_value = value_allocator.obtain_Span_not_owned(caller_provided_storage_);
}
- if (value_->type == ValueType::GVArray) {
- /* Fill new buffer with data from virtual array. */
- this->value_as<VariableValue_GVArray>()->data.materialize_to_uninitialized(
- full_mask, new_value->data);
- }
- else if (value_->type == ValueType::OneSingle) {
- auto *old_value_typed_ = this->value_as<VariableValue_OneSingle>();
- if (old_value_typed_->is_initialized) {
- /* Fill the buffer with a single value. */
- type.fill_construct_indices(old_value_typed_->data, new_value->data, full_mask);
+ if (value_ != nullptr) {
+ if (value_->type == ValueType::GVArray) {
+ /* Fill new buffer with data from virtual array. */
+ this->value_as<VariableValue_GVArray>()->data.materialize_to_uninitialized(
+ full_mask, new_value->data);
}
+ else if (value_->type == ValueType::OneSingle) {
+ auto *old_value_typed_ = this->value_as<VariableValue_OneSingle>();
+ if (old_value_typed_->is_initialized) {
+ /* Fill the buffer with a single value. */
+ type.fill_construct_indices(old_value_typed_->data, new_value->data, full_mask);
+ }
+ }
+ else {
+ BLI_assert_unreachable();
+ }
+ value_allocator.release_value(value_, data_type);
}
- else {
- BLI_assert_unreachable();
- }
- value_allocator.release_value(value_, data_type);
value_ = new_value;
break;
}
@@ -437,19 +431,21 @@ class VariableState : NonCopyable, NonMovable {
new_value = value_allocator.obtain_GVectorArray_not_owned(
*(GVectorArray *)caller_provided_storage_);
}
- if (value_->type == ValueType::GVVectorArray) {
- /* Fill new vector array with data from virtual vector array. */
- new_value->data.extend(full_mask, this->value_as<VariableValue_GVVectorArray>()->data);
- }
- else if (value_->type == ValueType::OneVector) {
- /* Fill all indices with the same value. */
- const GSpan vector = this->value_as<VariableValue_OneVector>()->data[0];
- new_value->data.extend(full_mask, GVVectorArray_For_SingleGSpan{vector, array_size});
- }
- else {
- BLI_assert_unreachable();
+ if (value_ != nullptr) {
+ if (value_->type == ValueType::GVVectorArray) {
+ /* Fill new vector array with data from virtual vector array. */
+ new_value->data.extend(full_mask, this->value_as<VariableValue_GVVectorArray>()->data);
+ }
+ else if (value_->type == ValueType::OneVector) {
+ /* Fill all indices with the same value. */
+ const GSpan vector = this->value_as<VariableValue_OneVector>()->data[0];
+ new_value->data.extend(full_mask, GVVectorArray_For_SingleGSpan{vector, array_size});
+ }
+ else {
+ BLI_assert_unreachable();
+ }
+ value_allocator.release_value(value_, data_type);
}
- value_allocator.release_value(value_, data_type);
value_ = new_value;
break;
}
@@ -466,6 +462,7 @@ class VariableState : NonCopyable, NonMovable {
BLI_assert(mask.size() <= tot_initialized_);
this->ensure_is_mutable(full_mask, data_type, value_allocator);
+ BLI_assert(value_ != nullptr);
switch (value_->type) {
case ValueType::Span: {
@@ -497,6 +494,7 @@ class VariableState : NonCopyable, NonMovable {
/* Sanity check to make sure that enough values are not initialized. */
BLI_assert(mask.size() <= full_mask.size() - tot_initialized_);
this->ensure_is_mutable(full_mask, data_type, value_allocator);
+ BLI_assert(value_ != nullptr);
switch (value_->type) {
case ValueType::Span: {
@@ -524,6 +522,7 @@ class VariableState : NonCopyable, NonMovable {
void add_as_input__one(MFParamsBuilder &params, const MFDataType &data_type) const
{
BLI_assert(this->is_one());
+ BLI_assert(value_ != nullptr);
switch (value_->type) {
case ValueType::GVArray: {
@@ -556,7 +555,7 @@ class VariableState : NonCopyable, NonMovable {
void ensure_is_mutable__one(const MFDataType &data_type, ValueAllocator &value_allocator)
{
BLI_assert(this->is_one());
- if (ELEM(value_->type, ValueType::OneSingle, ValueType::OneVector)) {
+ if (value_ != nullptr && ELEM(value_->type, ValueType::OneSingle, ValueType::OneVector)) {
return;
}
@@ -564,38 +563,42 @@ class VariableState : NonCopyable, NonMovable {
case MFDataType::Single: {
const CPPType &type = data_type.single_type();
VariableValue_OneSingle *new_value = value_allocator.obtain_OneSingle(type);
- if (value_->type == ValueType::GVArray) {
- this->value_as<VariableValue_GVArray>()->data.get_internal_single_to_uninitialized(
- new_value->data);
- new_value->is_initialized = true;
- }
- else if (value_->type == ValueType::Span) {
- BLI_assert(tot_initialized_ == 0);
- /* Nothing to do, the single value is uninitialized already. */
- }
- else {
- BLI_assert_unreachable();
+ if (value_ != nullptr) {
+ if (value_->type == ValueType::GVArray) {
+ this->value_as<VariableValue_GVArray>()->data.get_internal_single_to_uninitialized(
+ new_value->data);
+ new_value->is_initialized = true;
+ }
+ else if (value_->type == ValueType::Span) {
+ BLI_assert(tot_initialized_ == 0);
+ /* Nothing to do, the single value is uninitialized already. */
+ }
+ else {
+ BLI_assert_unreachable();
+ }
+ value_allocator.release_value(value_, data_type);
}
- value_allocator.release_value(value_, data_type);
value_ = new_value;
break;
}
case MFDataType::Vector: {
const CPPType &type = data_type.vector_base_type();
VariableValue_OneVector *new_value = value_allocator.obtain_OneVector(type);
- if (value_->type == ValueType::GVVectorArray) {
- const GVVectorArray &old_vector_array =
- this->value_as<VariableValue_GVVectorArray>()->data;
- new_value->data.extend(IndexRange(1), old_vector_array);
- }
- else if (value_->type == ValueType::GVectorArray) {
- BLI_assert(tot_initialized_ == 0);
- /* Nothing to do. */
- }
- else {
- BLI_assert_unreachable();
+ if (value_ != nullptr) {
+ if (value_->type == ValueType::GVVectorArray) {
+ const GVVectorArray &old_vector_array =
+ this->value_as<VariableValue_GVVectorArray>()->data;
+ new_value->data.extend(IndexRange(1), old_vector_array);
+ }
+ else if (value_->type == ValueType::GVectorArray) {
+ BLI_assert(tot_initialized_ == 0);
+ /* Nothing to do. */
+ }
+ else {
+ BLI_assert_unreachable();
+ }
+ value_allocator.release_value(value_, data_type);
}
- value_allocator.release_value(value_, data_type);
value_ = new_value;
break;
}
@@ -608,6 +611,7 @@ class VariableState : NonCopyable, NonMovable {
{
BLI_assert(this->is_one());
this->ensure_is_mutable__one(data_type, value_allocator);
+ BLI_assert(value_ != nullptr);
switch (value_->type) {
case ValueType::OneSingle: {
@@ -637,6 +641,7 @@ class VariableState : NonCopyable, NonMovable {
{
BLI_assert(this->is_one());
this->ensure_is_mutable__one(data_type, value_allocator);
+ BLI_assert(value_ != nullptr);
switch (value_->type) {
case ValueType::OneSingle: {
@@ -676,6 +681,7 @@ class VariableState : NonCopyable, NonMovable {
const MFDataType &data_type,
ValueAllocator &value_allocator)
{
+ BLI_assert(value_ != nullptr);
int new_tot_initialized = tot_initialized_ - mask.size();
/* Sanity check to make sure that enough indices can be destructed. */
@@ -743,6 +749,7 @@ class VariableState : NonCopyable, NonMovable {
void indices_split(IndexMask mask, IndicesSplitVectors &r_indices)
{
BLI_assert(mask.size() <= tot_initialized_);
+ BLI_assert(value_ != nullptr);
switch (value_->type) {
case ValueType::GVArray: {
@@ -778,51 +785,47 @@ class VariableState : NonCopyable, NonMovable {
template<typename T> T *value_as()
{
+ BLI_assert(value_ != nullptr);
BLI_assert(value_->type == T::static_type);
return static_cast<T *>(value_);
}
template<typename T> const T *value_as() const
{
+ BLI_assert(value_ != nullptr);
BLI_assert(value_->type == T::static_type);
return static_cast<T *>(value_);
}
};
-template<typename... Args> VariableState *ValueAllocator::obtain_variable_state(Args &&...args)
-{
- if (variable_state_free_list_.is_empty()) {
- void *buffer = linear_allocator_.allocate(sizeof(VariableState), alignof(VariableState));
- return new (buffer) VariableState(std::forward<Args>(args)...);
- }
- return new (variable_state_free_list_.pop()) VariableState(std::forward<Args>(args)...);
-}
-
-void ValueAllocator::release_variable_state(VariableState *state)
-{
- state->~VariableState();
- variable_state_free_list_.push(state);
-}
-
/** Keeps track of the states of all variables during evaluation. */
class VariableStates {
private:
ValueAllocator value_allocator_;
- Map<const MFVariable *, VariableState *> variable_states_;
+ const MFProcedure &procedure_;
+ /** The state of every variable, indexed by #MFVariable::index_in_procedure(). */
+ Array<VariableState> variable_states_;
IndexMask full_mask_;
public:
- VariableStates(LinearAllocator<> &linear_allocator, IndexMask full_mask)
- : value_allocator_(linear_allocator), full_mask_(full_mask)
+ VariableStates(LinearAllocator<> &linear_allocator,
+ const MFProcedure &procedure,
+ IndexMask full_mask)
+ : value_allocator_(linear_allocator),
+ procedure_(procedure),
+ variable_states_(procedure.variables().size()),
+ full_mask_(full_mask)
{
}
~VariableStates()
{
- for (auto &&item : variable_states_.items()) {
- const MFVariable *variable = item.key;
- VariableState *state = item.value;
- state->destruct_self(value_allocator_, variable->data_type());
+ for (const int variable_i : procedure_.variables().index_range()) {
+ VariableState &state = variable_states_[variable_i];
+ if (state.value_ != nullptr) {
+ const MFVariable *variable = procedure_.variables()[variable_i];
+ state.destruct_value(value_allocator_, variable->data_type());
+ }
}
}
@@ -848,9 +851,12 @@ class VariableStates {
bool input_is_initialized,
void *caller_provided_storage = nullptr) {
const int tot_initialized = input_is_initialized ? full_mask_.size() : 0;
- variable_states_.add_new(variable,
- value_allocator_.obtain_variable_state(
- *value, tot_initialized, caller_provided_storage));
+ const int variable_i = variable->index_in_procedure();
+ VariableState &variable_state = variable_states_[variable_i];
+ BLI_assert(variable_state.value_ == nullptr);
+ variable_state.value_ = value;
+ variable_state.tot_initialized_ = tot_initialized;
+ variable_state.caller_provided_storage_ = caller_provided_storage;
};
switch (param_type.category()) {
@@ -936,32 +942,15 @@ class VariableStates {
{
VariableState &variable_state = this->get_variable_state(variable);
if (variable_state.destruct(mask, full_mask_, variable.data_type(), value_allocator_)) {
- variable_state.destruct_self(value_allocator_, variable.data_type());
- variable_states_.remove_contained(&variable);
+ variable_state.destruct_value(value_allocator_, variable.data_type());
}
}
VariableState &get_variable_state(const MFVariable &variable)
{
- return *variable_states_.lookup_or_add_cb(
- &variable, [&]() { return this->create_new_state_for_variable(variable); });
- }
-
- VariableState *create_new_state_for_variable(const MFVariable &variable)
- {
- MFDataType data_type = variable.data_type();
- switch (data_type.category()) {
- case MFDataType::Single: {
- const CPPType &type = data_type.single_type();
- return value_allocator_.obtain_variable_state(*value_allocator_.obtain_OneSingle(type), 0);
- }
- case MFDataType::Vector: {
- const CPPType &type = data_type.vector_base_type();
- return value_allocator_.obtain_variable_state(*value_allocator_.obtain_OneVector(type), 0);
- }
- }
- BLI_assert_unreachable();
- return nullptr;
+ const int variable_i = variable.index_in_procedure();
+ VariableState &variable_state = variable_states_[variable_i];
+ return variable_state;
}
};
@@ -977,49 +966,82 @@ static bool evaluate_as_one(const MultiFunction &fn,
return false;
}
for (VariableState *state : param_variable_states) {
- if (state != nullptr && !state->is_one()) {
+ if (state != nullptr && state->value_ != nullptr && !state->is_one()) {
return false;
}
}
return true;
}
-static void execute_call_instruction(const MFCallInstruction &instruction,
- IndexMask mask,
- VariableStates &variable_states,
- const MFContext &context)
+static void gather_parameter_variable_states(const MultiFunction &fn,
+ const MFCallInstruction &instruction,
+ VariableStates &variable_states,
+ MutableSpan<VariableState *> r_param_variable_states)
{
- const MultiFunction &fn = instruction.fn();
-
- Vector<VariableState *> param_variable_states;
- param_variable_states.resize(fn.param_amount());
-
for (const int param_index : fn.param_indices()) {
const MFVariable *variable = instruction.params()[param_index];
if (variable == nullptr) {
- param_variable_states[param_index] = nullptr;
+ r_param_variable_states[param_index] = nullptr;
}
else {
VariableState &variable_state = variable_states.get_variable_state(*variable);
- param_variable_states[param_index] = &variable_state;
+ r_param_variable_states[param_index] = &variable_state;
+ }
+ }
+}
+
+static void fill_params__one(const MultiFunction &fn,
+ const IndexMask mask,
+ MFParamsBuilder &params,
+ VariableStates &variable_states,
+ const Span<VariableState *> param_variable_states)
+{
+ for (const int param_index : fn.param_indices()) {
+ const MFParamType param_type = fn.param_type(param_index);
+ VariableState *variable_state = param_variable_states[param_index];
+ if (variable_state == nullptr) {
+ params.add_ignored_single_output();
+ }
+ else {
+ variable_states.add_as_param__one(*variable_state, params, param_type, mask);
}
}
+}
+
+static void fill_params(const MultiFunction &fn,
+ const IndexMask mask,
+ MFParamsBuilder &params,
+ VariableStates &variable_states,
+ const Span<VariableState *> param_variable_states)
+{
+ for (const int param_index : fn.param_indices()) {
+ const MFParamType param_type = fn.param_type(param_index);
+ VariableState *variable_state = param_variable_states[param_index];
+ if (variable_state == nullptr) {
+ params.add_ignored_single_output();
+ }
+ else {
+ variable_states.add_as_param(*variable_state, params, param_type, mask);
+ }
+ }
+}
+
+static void execute_call_instruction(const MFCallInstruction &instruction,
+ const IndexMask mask,
+ VariableStates &variable_states,
+ const MFContext &context)
+{
+ const MultiFunction &fn = instruction.fn();
+
+ Vector<VariableState *> param_variable_states;
+ param_variable_states.resize(fn.param_amount());
+ gather_parameter_variable_states(fn, instruction, variable_states, param_variable_states);
/* If all inputs to the function are constant, it's enough to call the function only once instead
* of for every index. */
if (evaluate_as_one(fn, param_variable_states, mask, variable_states.full_mask())) {
MFParamsBuilder params(fn, 1);
-
- for (const int param_index : fn.param_indices()) {
- const MFParamType param_type = fn.param_type(param_index);
- VariableState *variable_state = param_variable_states[param_index];
- if (variable_state == nullptr) {
- params.add_ignored_single_output();
- }
- else {
- variable_states.add_as_param__one(*variable_state, params, param_type, mask);
- }
- }
+ fill_params__one(fn, mask, params, variable_states, param_variable_states);
try {
fn.call(IndexRange(1), params, context);
@@ -1031,17 +1053,7 @@ static void execute_call_instruction(const MFCallInstruction &instruction,
}
else {
MFParamsBuilder params(fn, &mask);
-
- for (const int param_index : fn.param_indices()) {
- const MFParamType param_type = fn.param_type(param_index);
- VariableState *variable_state = param_variable_states[param_index];
- if (variable_state == nullptr) {
- params.add_ignored_single_output();
- }
- else {
- variable_states.add_as_param(*variable_state, params, param_type, mask);
- }
- }
+ fill_params(fn, mask, params, variable_states, param_variable_states);
try {
fn.call_auto(mask, params, context);
@@ -1090,7 +1102,7 @@ struct NextInstructionInfo {
*/
class InstructionScheduler {
private:
- Map<const MFInstruction *, Vector<InstructionIndices>> indices_by_instruction_;
+ Stack<NextInstructionInfo> next_instructions_;
public:
InstructionScheduler() = default;
@@ -1103,7 +1115,7 @@ class InstructionScheduler {
InstructionIndices new_indices;
new_indices.is_owned = false;
new_indices.referenced_indices = mask;
- indices_by_instruction_.lookup_or_add_default(&instruction).append(std::move(new_indices));
+ next_instructions_.push({&instruction, std::move(new_indices)});
}
void add_owned_indices(const MFInstruction &instruction, Vector<int64_t> indices)
@@ -1116,43 +1128,28 @@ class InstructionScheduler {
InstructionIndices new_indices;
new_indices.is_owned = true;
new_indices.owned_indices = std::move(indices);
- indices_by_instruction_.lookup_or_add_default(&instruction).append(std::move(new_indices));
+ next_instructions_.push({&instruction, std::move(new_indices)});
}
- void add_previous_instruction_indices(const MFInstruction &instruction,
- NextInstructionInfo &instr_info)
+ bool is_done() const
{
- indices_by_instruction_.lookup_or_add_default(&instruction)
- .append(std::move(instr_info.indices));
+ return next_instructions_.is_empty();
}
- NextInstructionInfo pop_next()
+ const NextInstructionInfo &peek() const
{
- if (indices_by_instruction_.is_empty()) {
- return {};
- }
- /* TODO: Implement better mechanism to determine next instruction. */
- const MFInstruction *instruction = *indices_by_instruction_.keys().begin();
+ BLI_assert(!this->is_done());
+ return next_instructions_.peek();
+ }
- NextInstructionInfo next_instruction_info;
- next_instruction_info.instruction = instruction;
- next_instruction_info.indices = this->pop_indices_array(instruction);
- return next_instruction_info;
+ void update_instruction_pointer(const MFInstruction &instruction)
+ {
+ next_instructions_.peek().instruction = &instruction;
}
- private:
- InstructionIndices pop_indices_array(const MFInstruction *instruction)
+ NextInstructionInfo pop()
{
- Vector<InstructionIndices> *indices = indices_by_instruction_.lookup_ptr(instruction);
- if (indices == nullptr) {
- return {};
- }
- InstructionIndices r_indices = (*indices).pop_last();
- BLI_assert(!r_indices.mask().is_empty());
- if (indices->is_empty()) {
- indices_by_instruction_.remove_contained(instruction);
- }
- return r_indices;
+ return next_instructions_.pop();
}
};
@@ -1160,23 +1157,26 @@ void MFProcedureExecutor::call(IndexMask full_mask, MFParams params, MFContext c
{
BLI_assert(procedure_.validate());
+ AlignedBuffer<512, 64> local_buffer;
LinearAllocator<> linear_allocator;
+ linear_allocator.provide_buffer(local_buffer);
- VariableStates variable_states{linear_allocator, full_mask};
+ VariableStates variable_states{linear_allocator, procedure_, full_mask};
variable_states.add_initial_variable_states(*this, procedure_, params);
InstructionScheduler scheduler;
scheduler.add_referenced_indices(*procedure_.entry(), full_mask);
/* Loop until all indices got to a return instruction. */
- while (NextInstructionInfo instr_info = scheduler.pop_next()) {
+ while (!scheduler.is_done()) {
+ const NextInstructionInfo &instr_info = scheduler.peek();
const MFInstruction &instruction = *instr_info.instruction;
switch (instruction.type()) {
case MFInstructionType::Call: {
const MFCallInstruction &call_instruction = static_cast<const MFCallInstruction &>(
instruction);
execute_call_instruction(call_instruction, instr_info.mask(), variable_states, context);
- scheduler.add_previous_instruction_indices(*call_instruction.next(), instr_info);
+ scheduler.update_instruction_pointer(*call_instruction.next());
break;
}
case MFInstructionType::Branch: {
@@ -1187,6 +1187,7 @@ void MFProcedureExecutor::call(IndexMask full_mask, MFParams params, MFContext c
IndicesSplitVectors new_indices;
variable_state.indices_split(instr_info.mask(), new_indices);
+ scheduler.pop();
scheduler.add_owned_indices(*branch_instruction.branch_false(), new_indices[false]);
scheduler.add_owned_indices(*branch_instruction.branch_true(), new_indices[true]);
break;
@@ -1196,17 +1197,18 @@ void MFProcedureExecutor::call(IndexMask full_mask, MFParams params, MFContext c
static_cast<const MFDestructInstruction &>(instruction);
const MFVariable *variable = destruct_instruction.variable();
variable_states.destruct(*variable, instr_info.mask());
- scheduler.add_previous_instruction_indices(*destruct_instruction.next(), instr_info);
+ scheduler.update_instruction_pointer(*destruct_instruction.next());
break;
}
case MFInstructionType::Dummy: {
const MFDummyInstruction &dummy_instruction = static_cast<const MFDummyInstruction &>(
instruction);
- scheduler.add_previous_instruction_indices(*dummy_instruction.next(), instr_info);
+ scheduler.update_instruction_pointer(*dummy_instruction.next());
break;
}
case MFInstructionType::Return: {
/* Don't insert the indices back into the scheduler. */
+ scheduler.pop();
break;
}
}
diff --git a/source/blender/geometry/CMakeLists.txt b/source/blender/geometry/CMakeLists.txt
index 8716d6c8f67..531487a45e2 100644
--- a/source/blender/geometry/CMakeLists.txt
+++ b/source/blender/geometry/CMakeLists.txt
@@ -15,16 +15,24 @@ set(INC
)
set(SRC
+ intern/add_curves_on_mesh.cc
intern/mesh_merge_by_distance.cc
+ intern/mesh_primitive_cuboid.cc
intern/mesh_to_curve_convert.cc
intern/point_merge_by_distance.cc
intern/realize_instances.cc
+ intern/resample_curves.cc
+ intern/reverse_uv_sampler.cc
intern/uv_parametrizer.c
+ GEO_add_curves_on_mesh.hh
GEO_mesh_merge_by_distance.hh
+ GEO_mesh_primitive_cuboid.hh
GEO_mesh_to_curve.hh
GEO_point_merge_by_distance.hh
GEO_realize_instances.hh
+ GEO_resample_curves.hh
+ GEO_reverse_uv_sampler.hh
GEO_uv_parametrizer.h
)
diff --git a/source/blender/geometry/GEO_add_curves_on_mesh.hh b/source/blender/geometry/GEO_add_curves_on_mesh.hh
new file mode 100644
index 00000000000..cf60a8e8ace
--- /dev/null
+++ b/source/blender/geometry/GEO_add_curves_on_mesh.hh
@@ -0,0 +1,54 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+
+#pragma once
+
+#include "BLI_float4x4.hh"
+#include "BLI_kdtree.h"
+#include "BLI_math_vector.hh"
+#include "BLI_span.hh"
+
+#include "BKE_bvhutils.h"
+#include "BKE_curves.hh"
+
+#include "DNA_mesh_types.h"
+#include "DNA_meshdata_types.h"
+
+namespace blender::geometry {
+
+struct AddCurvesOnMeshInputs {
+ /** Information about the root points where new curves should be generated. */
+ Span<float3> root_positions_cu;
+ Span<float3> bary_coords;
+ Span<int> looptri_indices;
+
+ /** Determines shape of new curves. */
+ bool interpolate_length = false;
+ bool interpolate_shape = false;
+ bool interpolate_point_count = false;
+ float fallback_curve_length = 0.0f;
+ int fallback_point_count = 0;
+
+ /** Information about the surface that the new curves are attached to. */
+ const Mesh *surface = nullptr;
+ BVHTreeFromMesh *surface_bvh = nullptr;
+ Span<MLoopTri> surface_looptris;
+ Span<float2> surface_uv_map;
+ Span<float3> corner_normals_su;
+
+ /** Transformation matrices. */
+ float4x4 curves_to_surface_mat;
+ float4x4 surface_to_curves_normal_mat;
+
+ /**
+ * KD-Tree that contains the root points of existing curves. This is only necessary when
+ * interpolation is used.
+ */
+ KDTree_3d *old_roots_kdtree = nullptr;
+};
+
+/**
+ * Generate new curves on a mesh surface with the given inputs. Existing curves stay intact.
+ */
+void add_curves_on_mesh(bke::CurvesGeometry &curves, const AddCurvesOnMeshInputs &inputs);
+
+} // namespace blender::geometry
diff --git a/source/blender/geometry/GEO_mesh_primitive_cuboid.hh b/source/blender/geometry/GEO_mesh_primitive_cuboid.hh
new file mode 100644
index 00000000000..6107b15b62d
--- /dev/null
+++ b/source/blender/geometry/GEO_mesh_primitive_cuboid.hh
@@ -0,0 +1,21 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+
+#pragma once
+
+#include "BLI_math_vec_types.hh"
+
+struct Mesh;
+namespace blender {
+namespace bke {
+class AttributeIDRef;
+}
+} // namespace blender
+
+namespace blender::geometry {
+
+Mesh *create_cuboid_mesh(
+ const float3 &size, int verts_x, int verts_y, int verts_z, const bke::AttributeIDRef &uv_id);
+
+Mesh *create_cuboid_mesh(const float3 &size, int verts_x, int verts_y, int verts_z);
+
+} // namespace blender::geometry
diff --git a/source/blender/geometry/GEO_resample_curves.hh b/source/blender/geometry/GEO_resample_curves.hh
new file mode 100644
index 00000000000..97399ccb0a5
--- /dev/null
+++ b/source/blender/geometry/GEO_resample_curves.hh
@@ -0,0 +1,39 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+
+#pragma once
+
+#include "FN_field.hh"
+
+#include "BKE_geometry_set.hh"
+
+struct Curves;
+
+namespace blender::geometry {
+
+/**
+ * Create new curves where the selected curves have been resampled with a number of uniform-length
+ * samples defined by the count field. Interpolate attributes to the result, with an accuracy that
+ * depends on the curve's resolution parameter.
+ *
+ * \note The values provided by the #count_field are clamped to 1 or greater.
+ */
+Curves *resample_to_count(const CurveComponent &src_component,
+ const fn::Field<bool> &selection_field,
+ const fn::Field<int> &count_field);
+
+/**
+ * Create new curves resampled to make each segment have the length specified by the
+ * #segment_length field input, rounded to make the length of each segment the same.
+ * The accuracy will depend on the curve's resolution parameter.
+ */
+Curves *resample_to_length(const CurveComponent &src_component,
+ const fn::Field<bool> &selection_field,
+ const fn::Field<float> &segment_length_field);
+
+/**
+ * Evaluate each selected curve to its implicit evaluated points.
+ */
+Curves *resample_to_evaluated(const CurveComponent &src_component,
+ const fn::Field<bool> &selection_field);
+
+} // namespace blender::geometry
diff --git a/source/blender/geometry/GEO_reverse_uv_sampler.hh b/source/blender/geometry/GEO_reverse_uv_sampler.hh
new file mode 100644
index 00000000000..d392b65eaf4
--- /dev/null
+++ b/source/blender/geometry/GEO_reverse_uv_sampler.hh
@@ -0,0 +1,42 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+
+#pragma once
+
+#include <optional>
+
+#include "BLI_math_vector.hh"
+#include "BLI_span.hh"
+
+#include "DNA_meshdata_types.h"
+
+namespace blender::geometry {
+
+/**
+ * Can find the polygon/triangle that maps to a specific uv coordinate.
+ *
+ * \note this uses a trivial implementation currently that has to be replaced.
+ */
+class ReverseUVSampler {
+ private:
+ const Span<float2> uv_map_;
+ const Span<MLoopTri> looptris_;
+
+ public:
+ ReverseUVSampler(const Span<float2> uv_map, const Span<MLoopTri> looptris);
+
+ enum class ResultType {
+ None,
+ Ok,
+ Multiple,
+ };
+
+ struct Result {
+ ResultType type = ResultType::None;
+ const MLoopTri *looptri = nullptr;
+ float3 bary_weights;
+ };
+
+ Result sample(const float2 &query_uv) const;
+};
+
+} // namespace blender::geometry
diff --git a/source/blender/geometry/GEO_uv_parametrizer.h b/source/blender/geometry/GEO_uv_parametrizer.h
index a5194883cf2..2181f95945e 100644
--- a/source/blender/geometry/GEO_uv_parametrizer.h
+++ b/source/blender/geometry/GEO_uv_parametrizer.h
@@ -12,12 +12,9 @@
extern "C" {
#endif
-typedef void ParamHandle; /* handle to a set of charts */
-typedef intptr_t ParamKey; /* (hash) key for identifying verts and faces */
-typedef enum ParamBool {
- PARAM_TRUE = 1,
- PARAM_FALSE = 0,
-} ParamBool;
+typedef struct ParamHandle ParamHandle; /* Handle to an array of charts. */
+typedef intptr_t ParamKey; /* Key (hash) for identifying verts and faces. */
+#define PARAM_KEY_MAX INTPTR_MAX
/* -------------------------------------------------------------------- */
/** \name Chart Construction:
@@ -38,20 +35,24 @@ ParamHandle *GEO_uv_parametrizer_construct_begin(void);
void GEO_uv_parametrizer_aspect_ratio(ParamHandle *handle, float aspx, float aspy);
+void GEO_uv_prepare_pin_index(ParamHandle *handle, const int bmvertindex, const float uv[2]);
+
+ParamKey GEO_uv_find_pin_index(ParamHandle *handle, const int bmvertindex, const float uv[2]);
+
void GEO_uv_parametrizer_face_add(ParamHandle *handle,
- ParamKey key,
- int nverts,
- ParamKey *vkeys,
- float *co[4],
- float *uv[4],
- ParamBool *pin,
- ParamBool *select);
+ const ParamKey key,
+ const int nverts,
+ const ParamKey *vkeys,
+ const float **co,
+ float **uv, /* Output will eventually be written to `uv`. */
+ const bool *pin,
+ const bool *select);
void GEO_uv_parametrizer_edge_set_seam(ParamHandle *handle, ParamKey *vkeys);
void GEO_uv_parametrizer_construct_end(ParamHandle *handle,
- ParamBool fill,
- ParamBool topology_from_uvs,
+ bool fill,
+ bool topology_from_uvs,
int *count_fail);
void GEO_uv_parametrizer_delete(ParamHandle *handle);
@@ -70,7 +71,7 @@ void GEO_uv_parametrizer_delete(ParamHandle *handle);
*
* \{ */
-void GEO_uv_parametrizer_lscm_begin(ParamHandle *handle, ParamBool live, ParamBool abf);
+void GEO_uv_parametrizer_lscm_begin(ParamHandle *handle, bool live, bool abf);
void GEO_uv_parametrizer_lscm_solve(ParamHandle *handle, int *count_changed, int *count_failed);
void GEO_uv_parametrizer_lscm_end(ParamHandle *handle);
@@ -88,14 +89,6 @@ void GEO_uv_parametrizer_stretch_end(ParamHandle *handle);
/** \} */
/* -------------------------------------------------------------------- */
-/** \name Area Smooth
- * \{ */
-
-void GEO_uv_parametrizer_smooth_area(ParamHandle *handle);
-
-/** \} */
-
-/* -------------------------------------------------------------------- */
/** \name Packing
* \{ */
diff --git a/source/blender/geometry/intern/add_curves_on_mesh.cc b/source/blender/geometry/intern/add_curves_on_mesh.cc
new file mode 100644
index 00000000000..34551bd474f
--- /dev/null
+++ b/source/blender/geometry/intern/add_curves_on_mesh.cc
@@ -0,0 +1,354 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+
+#include "BKE_mesh_sample.hh"
+#include "BKE_spline.hh"
+
+#include "GEO_add_curves_on_mesh.hh"
+
+/**
+ * The code below uses a suffix naming convention to indicate the coordinate space:
+ * cu: Local space of the curves object that is being edited.
+ * su: Local space of the surface object.
+ */
+
+namespace blender::geometry {
+
+using bke::CurvesGeometry;
+
+struct NeighborCurve {
+ /* Curve index of the neighbor. */
+ int index;
+ /* The weights of all neighbors of a new curve add up to 1. */
+ float weight;
+};
+
+static constexpr int max_neighbors = 5;
+using NeighborCurves = Vector<NeighborCurve, max_neighbors>;
+
+static float3 compute_surface_point_normal(const MLoopTri &looptri,
+ const float3 &bary_coord,
+ const Span<float3> corner_normals)
+{
+ const int l0 = looptri.tri[0];
+ const int l1 = looptri.tri[1];
+ const int l2 = looptri.tri[2];
+
+ const float3 &l0_normal = corner_normals[l0];
+ const float3 &l1_normal = corner_normals[l1];
+ const float3 &l2_normal = corner_normals[l2];
+
+ const float3 normal = math::normalize(
+ attribute_math::mix3(bary_coord, l0_normal, l1_normal, l2_normal));
+ return normal;
+}
+
+static void initialize_straight_curve_positions(const float3 &p1,
+ const float3 &p2,
+ MutableSpan<float3> r_positions)
+{
+ const float step = 1.0f / (float)(r_positions.size() - 1);
+ for (const int i : r_positions.index_range()) {
+ r_positions[i] = math::interpolate(p1, p2, i * step);
+ }
+}
+
+static Array<NeighborCurves> find_curve_neighbors(const Span<float3> root_positions,
+ const KDTree_3d &old_roots_kdtree)
+{
+ const int tot_added_curves = root_positions.size();
+ Array<NeighborCurves> neighbors_per_curve(tot_added_curves);
+ threading::parallel_for(IndexRange(tot_added_curves), 128, [&](const IndexRange range) {
+ for (const int i : range) {
+ const float3 root = root_positions[i];
+ std::array<KDTreeNearest_3d, max_neighbors> nearest_n;
+ const int found_neighbors = BLI_kdtree_3d_find_nearest_n(
+ &old_roots_kdtree, root, nearest_n.data(), max_neighbors);
+ float tot_weight = 0.0f;
+ for (const int neighbor_i : IndexRange(found_neighbors)) {
+ KDTreeNearest_3d &nearest = nearest_n[neighbor_i];
+ const float weight = 1.0f / std::max(nearest.dist, 0.00001f);
+ tot_weight += weight;
+ neighbors_per_curve[i].append({nearest.index, weight});
+ }
+ /* Normalize weights. */
+ for (NeighborCurve &neighbor : neighbors_per_curve[i]) {
+ neighbor.weight /= tot_weight;
+ }
+ }
+ });
+ return neighbors_per_curve;
+}
+
+template<typename T, typename GetValueF>
+void interpolate_from_neighbors(const Span<NeighborCurves> neighbors_per_curve,
+ const T &fallback,
+ const GetValueF &get_value_from_neighbor,
+ MutableSpan<T> r_interpolated_values)
+{
+ attribute_math::DefaultMixer<T> mixer{r_interpolated_values};
+ threading::parallel_for(r_interpolated_values.index_range(), 512, [&](const IndexRange range) {
+ for (const int i : range) {
+ const NeighborCurves &neighbors = neighbors_per_curve[i];
+ if (neighbors.is_empty()) {
+ mixer.mix_in(i, fallback, 1.0f);
+ }
+ else {
+ for (const NeighborCurve &neighbor : neighbors) {
+ const T neighbor_value = get_value_from_neighbor(neighbor.index);
+ mixer.mix_in(i, neighbor_value, neighbor.weight);
+ }
+ }
+ }
+ });
+ mixer.finalize();
+}
+
+static void interpolate_position_without_interpolation(
+ CurvesGeometry &curves,
+ const int old_curves_num,
+ const Span<float3> root_positions_cu,
+ const Span<float> new_lengths_cu,
+ const Span<float3> new_normals_su,
+ const float4x4 &surface_to_curves_normal_mat)
+{
+ const int added_curves_num = root_positions_cu.size();
+ MutableSpan<float3> positions_cu = curves.positions_for_write();
+ threading::parallel_for(IndexRange(added_curves_num), 256, [&](const IndexRange range) {
+ for (const int i : range) {
+ const int curve_i = old_curves_num + i;
+ const IndexRange points = curves.points_for_curve(curve_i);
+ const float3 &root_cu = root_positions_cu[i];
+ const float length = new_lengths_cu[i];
+ const float3 &normal_su = new_normals_su[i];
+ const float3 normal_cu = math::normalize(surface_to_curves_normal_mat * normal_su);
+ const float3 tip_cu = root_cu + length * normal_cu;
+
+ initialize_straight_curve_positions(root_cu, tip_cu, positions_cu.slice(points));
+ }
+ });
+}
+
+static void interpolate_position_with_interpolation(CurvesGeometry &curves,
+ const Span<float3> root_positions_cu,
+ const Span<NeighborCurves> neighbors_per_curve,
+ const int old_curves_num,
+ const Span<float> new_lengths_cu,
+ const Span<float3> new_normals_su,
+ const float4x4 &surface_to_curves_normal_mat,
+ const float4x4 &curves_to_surface_mat,
+ const BVHTreeFromMesh &surface_bvh,
+ const Span<MLoopTri> surface_looptris,
+ const Mesh &surface,
+ const Span<float3> corner_normals_su)
+{
+ MutableSpan<float3> positions_cu = curves.positions_for_write();
+ const int added_curves_num = root_positions_cu.size();
+
+ threading::parallel_for(IndexRange(added_curves_num), 256, [&](const IndexRange range) {
+ for (const int i : range) {
+ const NeighborCurves &neighbors = neighbors_per_curve[i];
+ const int curve_i = old_curves_num + i;
+ const IndexRange points = curves.points_for_curve(curve_i);
+
+ const float length_cu = new_lengths_cu[i];
+ const float3 &normal_su = new_normals_su[i];
+ const float3 normal_cu = math::normalize(surface_to_curves_normal_mat * normal_su);
+
+ const float3 &root_cu = root_positions_cu[i];
+
+ if (neighbors.is_empty()) {
+ /* If there are no neighbors, just make a straight line. */
+ const float3 tip_cu = root_cu + length_cu * normal_cu;
+ initialize_straight_curve_positions(root_cu, tip_cu, positions_cu.slice(points));
+ continue;
+ }
+
+ positions_cu.slice(points).fill(root_cu);
+
+ for (const NeighborCurve &neighbor : neighbors) {
+ const int neighbor_curve_i = neighbor.index;
+ const float3 &neighbor_first_pos_cu = positions_cu[curves.offsets()[neighbor_curve_i]];
+ const float3 neighbor_first_pos_su = curves_to_surface_mat * neighbor_first_pos_cu;
+
+ BVHTreeNearest nearest;
+ nearest.dist_sq = FLT_MAX;
+ BLI_bvhtree_find_nearest(surface_bvh.tree,
+ neighbor_first_pos_su,
+ &nearest,
+ surface_bvh.nearest_callback,
+ const_cast<BVHTreeFromMesh *>(&surface_bvh));
+ const int neighbor_looptri_index = nearest.index;
+ const MLoopTri &neighbor_looptri = surface_looptris[neighbor_looptri_index];
+
+ const float3 neighbor_bary_coord =
+ bke::mesh_surface_sample::compute_bary_coord_in_triangle(
+ surface, neighbor_looptri, nearest.co);
+
+ const float3 neighbor_normal_su = compute_surface_point_normal(
+ surface_looptris[neighbor_looptri_index], neighbor_bary_coord, corner_normals_su);
+ const float3 neighbor_normal_cu = math::normalize(surface_to_curves_normal_mat *
+ neighbor_normal_su);
+
+ /* The rotation matrix used to transform relative coordinates of the neighbor curve
+ * to the new curve. */
+ float normal_rotation_cu[3][3];
+ rotation_between_vecs_to_mat3(normal_rotation_cu, neighbor_normal_cu, normal_cu);
+
+ const IndexRange neighbor_points = curves.points_for_curve(neighbor_curve_i);
+ const float3 &neighbor_root_cu = positions_cu[neighbor_points[0]];
+
+ /* Use a temporary #PolySpline, because that's the easiest way to resample an
+ * existing curve right now. Resampling is necessary if the length of the new curve
+ * does not match the length of the neighbors or the number of handle points is
+ * different. */
+ PolySpline neighbor_spline;
+ neighbor_spline.resize(neighbor_points.size());
+ neighbor_spline.positions().copy_from(positions_cu.slice(neighbor_points));
+ neighbor_spline.mark_cache_invalid();
+
+ const float neighbor_length_cu = neighbor_spline.length();
+ const float length_factor = std::min(1.0f, length_cu / neighbor_length_cu);
+
+ const float resample_factor = (1.0f / (points.size() - 1.0f)) * length_factor;
+ for (const int j : IndexRange(points.size())) {
+ const Spline::LookupResult lookup = neighbor_spline.lookup_evaluated_factor(
+ j * resample_factor);
+ const float index_factor = lookup.evaluated_index + lookup.factor;
+ float3 p;
+ neighbor_spline.sample_with_index_factors<float3>(
+ neighbor_spline.positions(), {&index_factor, 1}, {&p, 1});
+ const float3 relative_coord = p - neighbor_root_cu;
+ float3 rotated_relative_coord = relative_coord;
+ mul_m3_v3(normal_rotation_cu, rotated_relative_coord);
+ positions_cu[points[j]] += neighbor.weight * rotated_relative_coord;
+ }
+ }
+ }
+ });
+}
+
+void add_curves_on_mesh(CurvesGeometry &curves, const AddCurvesOnMeshInputs &inputs)
+{
+ const bool use_interpolation = inputs.interpolate_length || inputs.interpolate_point_count ||
+ inputs.interpolate_shape;
+
+ Array<NeighborCurves> neighbors_per_curve;
+ if (use_interpolation) {
+ BLI_assert(inputs.old_roots_kdtree != nullptr);
+ neighbors_per_curve = find_curve_neighbors(inputs.root_positions_cu, *inputs.old_roots_kdtree);
+ }
+
+ const int added_curves_num = inputs.root_positions_cu.size();
+ const int old_points_num = curves.points_num();
+ const int old_curves_num = curves.curves_num();
+ const int new_curves_num = old_curves_num + added_curves_num;
+
+ /* Grow number of curves first, so that the offsets array can be filled. */
+ curves.resize(old_points_num, new_curves_num);
+
+ /* Compute new curve offsets. */
+ MutableSpan<int> curve_offsets = curves.offsets_for_write();
+ MutableSpan<int> new_point_counts_per_curve = curve_offsets.take_back(added_curves_num);
+ if (inputs.interpolate_point_count) {
+ interpolate_from_neighbors<int>(
+ neighbors_per_curve,
+ inputs.fallback_point_count,
+ [&](const int curve_i) { return curves.points_for_curve(curve_i).size(); },
+ new_point_counts_per_curve);
+ }
+ else {
+ new_point_counts_per_curve.fill(inputs.fallback_point_count);
+ }
+ for (const int i : IndexRange(added_curves_num)) {
+ curve_offsets[old_curves_num + i + 1] += curve_offsets[old_curves_num + i];
+ }
+
+ const int new_points_num = curves.offsets().last();
+ curves.resize(new_points_num, new_curves_num);
+ MutableSpan<float3> positions_cu = curves.positions_for_write();
+
+ /* Determine length of new curves. */
+ Array<float> new_lengths_cu(added_curves_num);
+ if (inputs.interpolate_length) {
+ interpolate_from_neighbors<float>(
+ neighbors_per_curve,
+ inputs.fallback_curve_length,
+ [&](const int curve_i) {
+ const IndexRange points = curves.points_for_curve(curve_i);
+ float length = 0.0f;
+ for (const int segment_i : points.drop_back(1)) {
+ const float3 &p1 = positions_cu[segment_i];
+ const float3 &p2 = positions_cu[segment_i + 1];
+ length += math::distance(p1, p2);
+ }
+ return length;
+ },
+ new_lengths_cu);
+ }
+ else {
+ new_lengths_cu.fill(inputs.fallback_curve_length);
+ }
+
+ /* Find surface normal at root points. */
+ Array<float3> new_normals_su(added_curves_num);
+ threading::parallel_for(IndexRange(added_curves_num), 256, [&](const IndexRange range) {
+ for (const int i : range) {
+ const int looptri_index = inputs.looptri_indices[i];
+ const float3 &bary_coord = inputs.bary_coords[i];
+ new_normals_su[i] = compute_surface_point_normal(
+ inputs.surface_looptris[looptri_index], bary_coord, inputs.corner_normals_su);
+ }
+ });
+
+ /* Propagate attachment information. */
+ if (!inputs.surface_uv_map.is_empty()) {
+ MutableSpan<float2> surface_uv_coords = curves.surface_uv_coords_for_write();
+ bke::mesh_surface_sample::sample_corner_attribute(
+ *inputs.surface,
+ inputs.looptri_indices,
+ inputs.bary_coords,
+ GVArray::ForSpan(inputs.surface_uv_map),
+ IndexRange(added_curves_num),
+ surface_uv_coords.take_back(added_curves_num));
+ }
+
+ /* Update selection arrays when available. */
+ const VArray<float> points_selection = curves.selection_point_float();
+ if (points_selection.is_span()) {
+ MutableSpan<float> points_selection_span = curves.selection_point_float_for_write();
+ points_selection_span.drop_front(old_points_num).fill(1.0f);
+ }
+ const VArray<float> curves_selection = curves.selection_curve_float();
+ if (curves_selection.is_span()) {
+ MutableSpan<float> curves_selection_span = curves.selection_curve_float_for_write();
+ curves_selection_span.drop_front(old_curves_num).fill(1.0f);
+ }
+
+ /* Initialize position attribute. */
+ if (inputs.interpolate_shape) {
+ interpolate_position_with_interpolation(curves,
+ inputs.root_positions_cu,
+ neighbors_per_curve,
+ old_curves_num,
+ new_lengths_cu,
+ new_normals_su,
+ inputs.surface_to_curves_normal_mat,
+ inputs.curves_to_surface_mat,
+ *inputs.surface_bvh,
+ inputs.surface_looptris,
+ *inputs.surface,
+ inputs.corner_normals_su);
+ }
+ else {
+ interpolate_position_without_interpolation(curves,
+ old_curves_num,
+ inputs.root_positions_cu,
+ new_lengths_cu,
+ new_normals_su,
+ inputs.surface_to_curves_normal_mat);
+ }
+
+ curves.update_curve_types();
+}
+
+} // 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
index e45b84632ab..d3a5a194555 100644
--- a/source/blender/geometry/intern/mesh_merge_by_distance.cc
+++ b/source/blender/geometry/intern/mesh_merge_by_distance.cc
@@ -82,7 +82,7 @@ struct WeldPoly {
int loop_start;
int loop_end;
/* Final Polygon Size. */
- int len;
+ int loop_len;
/* Group of loops that will be affected. */
struct WeldGroup loops;
};
@@ -104,9 +104,6 @@ struct WeldMesh {
/* References all polygons and loops that will be affected. */
Vector<WeldLoop> wloop;
Vector<WeldPoly> wpoly;
- MutableSpan<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
@@ -147,14 +144,14 @@ struct WeldLoopOfPolyIter {
* \{ */
#ifdef USE_WELD_DEBUG
-static bool weld_iter_loop_of_poly_begin(WeldLoopOfPolyIter *iter,
+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 bool weld_iter_loop_of_poly_next(WeldLoopOfPolyIter &iter);
static void weld_assert_edge_kill_len(Span<WeldEdge> wedge, const int supposed_kill_len)
{
@@ -170,12 +167,8 @@ static void weld_assert_edge_kill_len(Span<WeldEdge> wedge, const int supposed_k
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,
+static void weld_assert_poly_and_loop_kill_len(WeldMesh *weld_mesh,
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)
@@ -184,11 +177,12 @@ static void weld_assert_poly_and_loop_kill_len(Span<WeldPoly> wpoly,
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];
+ int poly_ctx = weld_mesh->poly_map[i];
if (poly_ctx != OUT_OF_CONTEXT) {
- const WeldPoly *wp = &wpoly[poly_ctx];
+ const WeldPoly *wp = &weld_mesh->wpoly[poly_ctx];
WeldLoopOfPolyIter iter;
- if (!weld_iter_loop_of_poly_begin(&iter, *wp, wloop, mloop, loop_map, nullptr)) {
+ if (!weld_iter_loop_of_poly_begin(
+ iter, *wp, weld_mesh->wloop, mloop, weld_mesh->loop_map, nullptr)) {
poly_kills++;
continue;
}
@@ -197,13 +191,13 @@ static void weld_assert_poly_and_loop_kill_len(Span<WeldPoly> wpoly,
poly_kills++;
continue;
}
- int remain = wp->len;
+ int remain = wp->loop_len;
int l = wp->loop_start;
while (remain) {
int l_next = l + 1;
- int loop_ctx = loop_map[l];
+ int loop_ctx = weld_mesh->loop_map[l];
if (loop_ctx != OUT_OF_CONTEXT) {
- const WeldLoop *wl = &wloop[loop_ctx];
+ const WeldLoop *wl = &weld_mesh->wloop[loop_ctx];
if (wl->loop_skip_to != OUT_OF_CONTEXT) {
l_next = wl->loop_skip_to;
}
@@ -225,19 +219,19 @@ static void weld_assert_poly_and_loop_kill_len(Span<WeldPoly> wpoly,
}
}
- const WeldPoly *wp = wpoly_new.data();
- for (int i = wpoly_new.size(); i--; wp++) {
- if (wp->poly_dst != OUT_OF_CONTEXT) {
+ for (const int i : weld_mesh->wpoly.index_range().take_back(weld_mesh->wpoly_new_len)) {
+ const WeldPoly &wp = weld_mesh->wpoly[i];
+ if (wp.poly_dst != OUT_OF_CONTEXT) {
poly_kills++;
continue;
}
- int remain = wp->len;
- int l = wp->loop_start;
+ int remain = wp.loop_len;
+ int l = wp.loop_start;
while (remain) {
int l_next = l + 1;
- int loop_ctx = loop_map[l];
+ int loop_ctx = weld_mesh->loop_map[l];
if (loop_ctx != OUT_OF_CONTEXT) {
- const WeldLoop *wl = &wloop[loop_ctx];
+ const WeldLoop *wl = &weld_mesh->wloop[loop_ctx];
if (wl->loop_skip_to != OUT_OF_CONTEXT) {
l_next = wl->loop_skip_to;
}
@@ -263,10 +257,10 @@ static void weld_assert_poly_no_vert_repetition(const WeldPoly &wp,
Span<MLoop> mloop,
Span<int> loop_map)
{
- const int len = wp.len;
- Array<int, 64> verts(len);
+ const int loop_len = wp.loop_len;
+ Array<int, 64> verts(loop_len);
WeldLoopOfPolyIter iter;
- if (!weld_iter_loop_of_poly_begin(&iter, wp, wloop, mloop, loop_map, nullptr)) {
+ if (!weld_iter_loop_of_poly_begin(iter, wp, wloop, mloop, loop_map, nullptr)) {
return;
}
else {
@@ -275,9 +269,9 @@ static void weld_assert_poly_no_vert_repetition(const WeldPoly &wp,
verts[i++] = iter.v;
}
}
- for (int i = 0; i < len; i++) {
+ for (int i = 0; i < loop_len; i++) {
int va = verts[i];
- for (int j = i + 1; j < len; j++) {
+ for (int j = i + 1; j < loop_len; j++) {
int vb = verts[j];
BLI_assert(va != vb);
}
@@ -290,7 +284,7 @@ static void weld_assert_poly_len(const WeldPoly *wp, const Span<WeldLoop> wloop)
return;
}
- int len = wp->len;
+ int loop_len = wp->loop_len;
const WeldLoop *wl = &wloop[wp->loops.ofs];
BLI_assert(wp->loop_start <= wl->loop_orig);
@@ -304,10 +298,10 @@ static void weld_assert_poly_len(const WeldPoly *wp, const Span<WeldLoop> wloop)
min_len++;
}
}
- BLI_assert(len >= min_len);
+ BLI_assert(loop_len >= min_len);
int max_len = wp->loop_end - wp->loop_start + 1;
- BLI_assert(len <= max_len);
+ BLI_assert(loop_len <= max_len);
}
#endif /* USE_WELD_DEBUG */
@@ -786,7 +780,7 @@ static void weld_poly_loop_ctx_alloc(Span<MPoly> mpoly,
wp.loops.ofs = prev_wloop_len;
wp.loop_start = loopstart;
wp.loop_end = loopstart + totloop - 1;
- wp.len = totloop;
+ wp.loop_len = totloop;
wpoly.append(wp);
poly_map[i] = wpoly_len++;
@@ -802,15 +796,10 @@ static void weld_poly_loop_ctx_alloc(Span<MPoly> mpoly,
}
}
- if (mpoly.size() < (wpoly_len + maybe_new_poly)) {
- wpoly.resize(wpoly_len + maybe_new_poly);
- }
+ wpoly.reserve(wpoly.size() + maybe_new_poly);
r_weld_mesh->wloop = std::move(wloop);
r_weld_mesh->wpoly = std::move(wpoly);
- r_weld_mesh->wpoly_new = r_weld_mesh->wpoly.as_mutable_span().drop_front(wpoly_len);
- 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);
@@ -827,8 +816,8 @@ static void weld_poly_split_recursive(Span<int> vert_dest_map,
int *r_poly_kill,
int *r_loop_kill)
{
- int poly_len = r_wp->len;
- if (poly_len < 3 || ctx_verts_len < 1) {
+ int poly_loop_len = r_wp->loop_len;
+ if (poly_loop_len < 3 || ctx_verts_len < 1) {
return;
}
@@ -870,7 +859,7 @@ static void weld_poly_split_recursive(Span<int> vert_dest_map,
}
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;
+ const int dist_b = poly_loop_len - dist_a;
BLI_assert(dist_a != 0 && dist_b != 0);
if (dist_a == 1 || dist_b == 1) {
@@ -886,7 +875,7 @@ static void weld_poly_split_recursive(Span<int> vert_dest_map,
wla->flag = ELEM_COLLAPSED;
wl_tmp->flag = ELEM_COLLAPSED;
loop_kill += 2;
- poly_len -= 2;
+ poly_loop_len -= 2;
}
if (dist_b == 2) {
if (wl_tmp != nullptr) {
@@ -901,20 +890,22 @@ static void weld_poly_split_recursive(Span<int> vert_dest_map,
wl_tmp->flag = ELEM_COLLAPSED;
}
loop_kill += 2;
- poly_len -= 2;
+ poly_loop_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 = &r_weld_mesh->wpoly_new[r_weld_mesh->wpoly_new_len++];
+ r_weld_mesh->wpoly.increase_size_by_unchecked(1);
+ WeldPoly *new_wp = &r_weld_mesh->wpoly.last();
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;
+ new_wp->loop_len = dist_a;
+ r_weld_mesh->wpoly_new_len++;
weld_poly_split_recursive(vert_dest_map,
#ifdef USE_WELD_DEBUG
mloop,
@@ -924,8 +915,8 @@ static void weld_poly_split_recursive(Span<int> vert_dest_map,
r_weld_mesh,
r_poly_kill,
r_loop_kill);
- BLI_assert(dist_b == poly_len - dist_a);
- poly_len = dist_b;
+ BLI_assert(dist_b == poly_loop_len - dist_a);
+ poly_loop_len = dist_b;
if (wla_prev->loop_orig > wla->loop_orig) {
/* New start. */
r_wp->loop_start = wlb->loop_orig;
@@ -950,7 +941,7 @@ static void weld_poly_split_recursive(Span<int> vert_dest_map,
wla_prev = wla;
}
}
- r_wp->len = poly_len;
+ r_wp->loop_len = poly_loop_len;
*r_loop_kill += loop_kill;
#ifdef USE_WELD_DEBUG
@@ -968,10 +959,8 @@ static void weld_poly_loop_ctx_setup(Span<MLoop> mloop,
MutableSpan<WeldGroup> r_vlinks,
WeldMesh *r_weld_mesh)
{
- MutableSpan<WeldPoly> wpoly = r_weld_mesh->wpoly;
+ WeldPoly *wpoly = r_weld_mesh->wpoly.data();
MutableSpan<WeldLoop> wloop = r_weld_mesh->wloop;
- int wpoly_len = r_weld_mesh->wpoly_len;
- int wpoly_new_len = 0;
int poly_kill_len = 0;
int loop_kill_len = 0;
@@ -979,28 +968,31 @@ static void weld_poly_loop_ctx_setup(Span<MLoop> mloop,
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)) {
+ /* Setup Poly/Loop. */
+ /* `wpoly.size()` may change during the loop,
+ * so make it clear that we are only working with the original wpolys. */
+ IndexRange wpoly_original_range = r_weld_mesh->wpoly.index_range();
+ for (const int i : wpoly_original_range) {
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 poly_loop_len = wp.loop_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) {
+ if (poly_loop_len == 3) {
wp.flag = ELEM_COLLAPSED;
poly_kill_len++;
loop_kill_len += 3;
- poly_len = 0;
+ poly_loop_len = 0;
break;
}
loop_kill_len++;
- poly_len--;
+ poly_loop_len--;
}
else {
const int vert_dst = wl->vert;
@@ -1010,10 +1002,10 @@ static void weld_poly_loop_ctx_setup(Span<MLoop> mloop,
}
}
- if (poly_len) {
- wp.len = poly_len;
+ if (poly_loop_len) {
+ wp.loop_len = poly_loop_len;
#ifdef USE_WELD_DEBUG
- weld_assert_poly_len(wp, wloop);
+ weld_assert_poly_len(&wp, wloop);
#endif
weld_poly_split_recursive(vert_dest_map,
@@ -1025,32 +1017,19 @@ static void weld_poly_loop_ctx_setup(Span<MLoop> mloop,
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,
- r_weld_mesh->wpoly_new,
- wloop,
- mloop,
- loop_map,
- r_weld_mesh->poly_map,
- mpoly,
- poly_kill_len,
- loop_kill_len);
+ weld_assert_poly_and_loop_kill_len(r_weld_mesh, mloop, 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];
+ for (const WeldPoly &wp : r_weld_mesh->wpoly) {
WeldLoopOfPolyIter iter;
if (weld_iter_loop_of_poly_begin(iter, wp, wloop, mloop, loop_map, nullptr)) {
while (weld_iter_loop_of_poly_next(iter)) {
@@ -1068,7 +1047,7 @@ static void weld_poly_loop_ctx_setup(Span<MLoop> mloop,
if (link_len) {
Array<int> link_poly_buffer(link_len);
- for (const int i : IndexRange(wpoly_and_new_len)) {
+ for (const int i : IndexRange(r_weld_mesh->wpoly.size())) {
const WeldPoly &wp = wpoly[i];
WeldLoopOfPolyIter iter;
if (weld_iter_loop_of_poly_begin(iter, wp, wloop, mloop, loop_map, nullptr)) {
@@ -1086,7 +1065,7 @@ static void weld_poly_loop_ctx_setup(Span<MLoop> mloop,
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)) {
+ for (const int i : IndexRange(r_weld_mesh->wpoly.size())) {
const WeldPoly &wp = wpoly[i];
if (wp.poly_dst != OUT_OF_CONTEXT) {
/* No need to retest poly.
@@ -1103,7 +1082,7 @@ static void weld_poly_loop_ctx_setup(Span<MLoop> mloop,
BLI_assert(link_poly_buffer[link_a->ofs] == i);
continue;
}
- int wp_len = wp.len;
+ int wp_loop_len = wp.loop_len;
polys_ctx_a = &link_poly_buffer[link_a->ofs];
for (; polys_len_a--; polys_ctx_a++) {
p_ctx_a = *polys_ctx_a;
@@ -1112,7 +1091,7 @@ static void weld_poly_loop_ctx_setup(Span<MLoop> mloop,
}
WeldPoly *wp_tmp = &wpoly[p_ctx_a];
- if (wp_tmp->len != wp_len) {
+ if (wp_tmp->loop_len != wp_loop_len) {
continue;
}
@@ -1151,31 +1130,23 @@ static void weld_poly_loop_ctx_setup(Span<MLoop> mloop,
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;
+ loop_kill_len += wp_tmp->loop_len;
poly_kill_len++;
}
}
}
}
else {
- poly_kill_len = r_weld_mesh->wpoly_len;
- loop_kill_len = r_weld_mesh->wloop_len;
+ poly_kill_len = r_weld_mesh->wpoly.size();
+ loop_kill_len = r_weld_mesh->wloop.size();
- for (WeldPoly &wp : wpoly) {
+ for (WeldPoly &wp : r_weld_mesh->wpoly) {
wp.flag = ELEM_COLLAPSED;
}
}
#ifdef USE_WELD_DEBUG
- weld_assert_poly_and_loop_kill_len(wpoly,
- r_weld_mesh->wpoly_new,
- wloop,
- mloop,
- loop_map,
- r_weld_mesh->poly_map,
- mpoly,
- poly_kill_len,
- loop_kill_len);
+ weld_assert_poly_and_loop_kill_len(r_weld_mesh, mloop, mpoly, poly_kill_len, loop_kill_len);
#endif
r_weld_mesh->poly_kill_len = poly_kill_len;
@@ -1545,8 +1516,9 @@ static Mesh *create_merged_mesh(const Mesh &mesh,
r_i++;
}
- for (const int i : IndexRange(weld_mesh.wpoly_new_len)) {
- const WeldPoly &wp = weld_mesh.wpoly_new[i];
+ /* New Polygons. */
+ for (const int i : weld_mesh.wpoly.index_range().take_back(weld_mesh.wpoly_new_len)) {
+ const WeldPoly &wp = weld_mesh.wpoly[i];
const int loop_start = loop_cur;
WeldLoopOfPolyIter iter;
if (!weld_iter_loop_of_poly_begin(
diff --git a/source/blender/geometry/intern/mesh_primitive_cuboid.cc b/source/blender/geometry/intern/mesh_primitive_cuboid.cc
new file mode 100644
index 00000000000..07ac2419ad9
--- /dev/null
+++ b/source/blender/geometry/intern/mesh_primitive_cuboid.cc
@@ -0,0 +1,431 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+
+#include "BLI_index_range.hh"
+#include "BLI_math_vector.h"
+#include "BLI_math_vector.hh"
+
+#include "DNA_mesh_types.h"
+#include "DNA_meshdata_types.h"
+
+#include "BKE_attribute_access.hh"
+#include "BKE_geometry_set.hh"
+#include "BKE_mesh.h"
+
+#include "GEO_mesh_primitive_cuboid.hh"
+
+namespace blender::geometry {
+
+struct CuboidConfig {
+ float3 size;
+ int verts_x;
+ int verts_y;
+ int verts_z;
+ int edges_x;
+ int edges_y;
+ int edges_z;
+ int vertex_count;
+ int poly_count;
+ int loop_count;
+
+ CuboidConfig(float3 size, int verts_x, int verts_y, int verts_z)
+ : size(size),
+ verts_x(verts_x),
+ verts_y(verts_y),
+ verts_z(verts_z),
+ edges_x(verts_x - 1),
+ edges_y(verts_y - 1),
+ edges_z(verts_z - 1)
+ {
+ BLI_assert(edges_x > 0 && edges_y > 0 && edges_z > 0);
+ this->vertex_count = this->get_vertex_count();
+ this->poly_count = this->get_poly_count();
+ this->loop_count = this->poly_count * 4;
+ }
+
+ private:
+ int get_vertex_count()
+ {
+ const int inner_position_count = (verts_x - 2) * (verts_y - 2) * (verts_z - 2);
+ return verts_x * verts_y * verts_z - inner_position_count;
+ }
+
+ int get_poly_count()
+ {
+ return 2 * (edges_x * edges_y + edges_y * edges_z + edges_z * edges_x);
+ }
+};
+
+static void calculate_vertices(const CuboidConfig &config, MutableSpan<MVert> verts)
+{
+ const float z_bottom = -config.size.z / 2.0f;
+ const float z_delta = config.size.z / config.edges_z;
+
+ const float x_left = -config.size.x / 2.0f;
+ const float x_delta = config.size.x / config.edges_x;
+
+ const float y_front = -config.size.y / 2.0f;
+ const float y_delta = config.size.y / config.edges_y;
+
+ int vert_index = 0;
+
+ for (const int z : IndexRange(config.verts_z)) {
+ if (ELEM(z, 0, config.edges_z)) {
+ /* Fill bottom and top. */
+ const float z_pos = z_bottom + z_delta * z;
+ for (const int y : IndexRange(config.verts_y)) {
+ const float y_pos = y_front + y_delta * y;
+ for (const int x : IndexRange(config.verts_x)) {
+ const float x_pos = x_left + x_delta * x;
+ copy_v3_v3(verts[vert_index++].co, float3(x_pos, y_pos, z_pos));
+ }
+ }
+ }
+ else {
+ for (const int y : IndexRange(config.verts_y)) {
+ if (ELEM(y, 0, config.edges_y)) {
+ /* Fill y-sides. */
+ const float y_pos = y_front + y_delta * y;
+ const float z_pos = z_bottom + z_delta * z;
+ for (const int x : IndexRange(config.verts_x)) {
+ const float x_pos = x_left + x_delta * x;
+ copy_v3_v3(verts[vert_index++].co, float3(x_pos, y_pos, z_pos));
+ }
+ }
+ else {
+ /* Fill x-sides. */
+ const float x_pos = x_left;
+ const float y_pos = y_front + y_delta * y;
+ const float z_pos = z_bottom + z_delta * z;
+ copy_v3_v3(verts[vert_index++].co, float3(x_pos, y_pos, z_pos));
+ const float x_pos2 = x_left + x_delta * config.edges_x;
+ copy_v3_v3(verts[vert_index++].co, float3(x_pos2, y_pos, z_pos));
+ }
+ }
+ }
+ }
+}
+
+/* vert_1 = bottom left, vert_2 = bottom right, vert_3 = top right, vert_4 = top left.
+ * Hence they are passed as 1,4,3,2 when calculating polys clockwise, and 1,2,3,4 for
+ * anti-clockwise.
+ */
+static void define_quad(MutableSpan<MPoly> polys,
+ MutableSpan<MLoop> loops,
+ const int poly_index,
+ const int loop_index,
+ const int vert_1,
+ const int vert_2,
+ const int vert_3,
+ const int vert_4)
+{
+ MPoly &poly = polys[poly_index];
+ poly.loopstart = loop_index;
+ poly.totloop = 4;
+
+ MLoop &loop_1 = loops[loop_index];
+ loop_1.v = vert_1;
+ MLoop &loop_2 = loops[loop_index + 1];
+ loop_2.v = vert_2;
+ MLoop &loop_3 = loops[loop_index + 2];
+ loop_3.v = vert_3;
+ MLoop &loop_4 = loops[loop_index + 3];
+ loop_4.v = vert_4;
+}
+
+static void calculate_polys(const CuboidConfig &config,
+ MutableSpan<MPoly> polys,
+ MutableSpan<MLoop> loops)
+{
+ int loop_index = 0;
+ int poly_index = 0;
+
+ /* Number of vertices in an XY cross-section of the cube (barring top and bottom faces). */
+ const int xy_cross_section_vert_count = config.verts_x * config.verts_y -
+ (config.verts_x - 2) * (config.verts_y - 2);
+
+ /* Calculate polys for Bottom faces. */
+ int vert_1_start = 0;
+
+ 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;
+ const int vert_3 = vert_2 + 1;
+ const int vert_4 = vert_1 + 1;
+
+ define_quad(polys, loops, poly_index, loop_index, vert_1, vert_2, vert_3, vert_4);
+ loop_index += 4;
+ poly_index++;
+ }
+ vert_1_start += config.verts_x;
+ }
+
+ /* Calculate polys for Front faces. */
+ vert_1_start = 0;
+ int vert_2_start = config.verts_x * config.verts_y;
+
+ for ([[maybe_unused]] const int z : IndexRange(config.edges_z)) {
+ for (const int x : IndexRange(config.edges_x)) {
+ define_quad(polys,
+ loops,
+ poly_index,
+ loop_index,
+ vert_1_start + x,
+ vert_1_start + x + 1,
+ vert_2_start + x + 1,
+ vert_2_start + x);
+ loop_index += 4;
+ poly_index++;
+ }
+ vert_1_start = vert_2_start;
+ vert_2_start += config.verts_x * config.verts_y - (config.verts_x - 2) * (config.verts_y - 2);
+ }
+
+ /* Calculate polys for Top faces. */
+ vert_1_start = config.verts_x * config.verts_y +
+ (config.verts_z - 2) * (config.verts_x * config.verts_y -
+ (config.verts_x - 2) * (config.verts_y - 2));
+ vert_2_start = vert_1_start + config.verts_x;
+
+ for ([[maybe_unused]] const int y : IndexRange(config.edges_y)) {
+ for (const int x : IndexRange(config.edges_x)) {
+ define_quad(polys,
+ loops,
+ poly_index,
+ loop_index,
+ vert_1_start + x,
+ vert_1_start + x + 1,
+ vert_2_start + x + 1,
+ vert_2_start + x);
+ loop_index += 4;
+ poly_index++;
+ }
+ vert_2_start += config.verts_x;
+ vert_1_start += config.verts_x;
+ }
+
+ /* Calculate polys for Back faces. */
+ vert_1_start = config.verts_x * config.edges_y;
+ vert_2_start = vert_1_start + xy_cross_section_vert_count;
+
+ for (const int z : IndexRange(config.edges_z)) {
+ if (z == (config.edges_z - 1)) {
+ vert_2_start += (config.verts_x - 2) * (config.verts_y - 2);
+ }
+ for (const int x : IndexRange(config.edges_x)) {
+ define_quad(polys,
+ loops,
+ poly_index,
+ loop_index,
+ vert_1_start + x,
+ vert_2_start + x,
+ vert_2_start + x + 1,
+ vert_1_start + x + 1);
+ loop_index += 4;
+ poly_index++;
+ }
+ vert_2_start += xy_cross_section_vert_count;
+ vert_1_start += xy_cross_section_vert_count;
+ }
+
+ /* Calculate polys for Left faces. */
+ vert_1_start = 0;
+ vert_2_start = config.verts_x * config.verts_y;
+
+ for (const int z : IndexRange(config.edges_z)) {
+ for (const int y : IndexRange(config.edges_y)) {
+ int vert_1;
+ int vert_2;
+ int vert_3;
+ int vert_4;
+
+ if (z == 0 || y == 0) {
+ vert_1 = vert_1_start + config.verts_x * y;
+ vert_4 = vert_1 + config.verts_x;
+ }
+ else {
+ vert_1 = vert_1_start + 2 * y;
+ vert_1 += config.verts_x - 2;
+ vert_4 = vert_1 + 2;
+ }
+
+ if (y == 0 || z == (config.edges_z - 1)) {
+ vert_2 = vert_2_start + config.verts_x * y;
+ vert_3 = vert_2 + config.verts_x;
+ }
+ else {
+ vert_2 = vert_2_start + 2 * y;
+ vert_2 += config.verts_x - 2;
+ vert_3 = vert_2 + 2;
+ }
+
+ define_quad(polys, loops, poly_index, loop_index, vert_1, vert_2, vert_3, vert_4);
+ loop_index += 4;
+ poly_index++;
+ }
+ if (z == 0) {
+ vert_1_start += config.verts_x * config.verts_y;
+ }
+ else {
+ vert_1_start += xy_cross_section_vert_count;
+ }
+ vert_2_start += xy_cross_section_vert_count;
+ }
+
+ /* Calculate polys for Right faces. */
+ vert_1_start = config.edges_x;
+ vert_2_start = vert_1_start + config.verts_x * config.verts_y;
+
+ for (const int z : IndexRange(config.edges_z)) {
+ for (const int y : IndexRange(config.edges_y)) {
+ int vert_1 = vert_1_start;
+ int vert_2 = vert_2_start;
+ int vert_3 = vert_2_start + 2;
+ int vert_4 = vert_1 + config.verts_x;
+
+ if (z == 0) {
+ vert_1 = vert_1_start + config.verts_x * y;
+ vert_4 = vert_1 + config.verts_x;
+ }
+ else {
+ vert_1 = vert_1_start + 2 * y;
+ vert_4 = vert_1 + 2;
+ }
+
+ if (z == (config.edges_z - 1)) {
+ vert_2 = vert_2_start + config.verts_x * y;
+ vert_3 = vert_2 + config.verts_x;
+ }
+ else {
+ vert_2 = vert_2_start + 2 * y;
+ vert_3 = vert_2 + 2;
+ }
+
+ if (y == (config.edges_y - 1)) {
+ vert_3 = vert_2 + config.verts_x;
+ vert_4 = vert_1 + config.verts_x;
+ }
+
+ define_quad(polys, loops, poly_index, loop_index, vert_1, vert_4, vert_3, vert_2);
+ loop_index += 4;
+ poly_index++;
+ }
+ if (z == 0) {
+ vert_1_start += config.verts_x * config.verts_y;
+ }
+ else {
+ vert_1_start += xy_cross_section_vert_count;
+ }
+ vert_2_start += xy_cross_section_vert_count;
+ }
+}
+
+static void calculate_uvs(const CuboidConfig &config, Mesh *mesh, const bke::AttributeIDRef &uv_id)
+{
+ MeshComponent mesh_component;
+ mesh_component.replace(mesh, GeometryOwnershipType::Editable);
+ bke::OutputAttribute_Typed<float2> uv_attribute =
+ mesh_component.attribute_try_get_for_output_only<float2>(uv_id, ATTR_DOMAIN_CORNER);
+ MutableSpan<float2> uvs = uv_attribute.as_span();
+
+ int loop_index = 0;
+
+ const float x_delta = 0.25f / static_cast<float>(config.edges_x);
+ const float y_delta = 0.25f / static_cast<float>(config.edges_y);
+ const float z_delta = 0.25f / static_cast<float>(config.edges_z);
+
+ /* Calculate bottom face UVs. */
+ for (const int y : IndexRange(config.edges_y)) {
+ for (const int x : IndexRange(config.edges_x)) {
+ uvs[loop_index++] = float2(0.25f + x * x_delta, 0.375f - y * y_delta);
+ uvs[loop_index++] = float2(0.25f + x * x_delta, 0.375f - (y + 1) * y_delta);
+ uvs[loop_index++] = float2(0.25f + (x + 1) * x_delta, 0.375f - (y + 1) * y_delta);
+ uvs[loop_index++] = float2(0.25f + (x + 1) * x_delta, 0.375f - y * y_delta);
+ }
+ }
+
+ /* Calculate front face UVs. */
+ for (const int z : IndexRange(config.edges_z)) {
+ for (const int x : IndexRange(config.edges_x)) {
+ uvs[loop_index++] = float2(0.25f + x * x_delta, 0.375f + z * z_delta);
+ uvs[loop_index++] = float2(0.25f + (x + 1) * x_delta, 0.375f + z * z_delta);
+ uvs[loop_index++] = float2(0.25f + (x + 1) * x_delta, 0.375f + (z + 1) * z_delta);
+ uvs[loop_index++] = float2(0.25f + x * x_delta, 0.375f + (z + 1) * z_delta);
+ }
+ }
+
+ /* Calculate top face UVs. */
+ for (const int y : IndexRange(config.edges_y)) {
+ for (const int x : IndexRange(config.edges_x)) {
+ uvs[loop_index++] = float2(0.25f + x * x_delta, 0.625f + y * y_delta);
+ uvs[loop_index++] = float2(0.25f + (x + 1) * x_delta, 0.625f + y * y_delta);
+ uvs[loop_index++] = float2(0.25f + (x + 1) * x_delta, 0.625f + (y + 1) * y_delta);
+ uvs[loop_index++] = float2(0.25f + x * x_delta, 0.625f + (y + 1) * y_delta);
+ }
+ }
+
+ /* Calculate back face UVs. */
+ for (const int z : IndexRange(config.edges_z)) {
+ for (const int x : IndexRange(config.edges_x)) {
+ uvs[loop_index++] = float2(1.0f - x * x_delta, 0.375f + z * z_delta);
+ uvs[loop_index++] = float2(1.0f - x * x_delta, 0.375f + (z + 1) * z_delta);
+ uvs[loop_index++] = float2(1.0f - (x + 1) * x_delta, 0.375f + (z + 1) * z_delta);
+ uvs[loop_index++] = float2(1.0f - (x + 1) * x_delta, 0.375f + z * z_delta);
+ }
+ }
+
+ /* Calculate left face UVs. */
+ for (const int z : IndexRange(config.edges_z)) {
+ for (const int y : IndexRange(config.edges_y)) {
+ uvs[loop_index++] = float2(0.25f - y * y_delta, 0.375f + z * z_delta);
+ uvs[loop_index++] = float2(0.25f - y * y_delta, 0.375f + (z + 1) * z_delta);
+ uvs[loop_index++] = float2(0.25f - (y + 1) * y_delta, 0.375f + (z + 1) * z_delta);
+ uvs[loop_index++] = float2(0.25f - (y + 1) * y_delta, 0.375f + z * z_delta);
+ }
+ }
+
+ /* Calculate right face UVs. */
+ for (const int z : IndexRange(config.edges_z)) {
+ for (const int y : IndexRange(config.edges_y)) {
+ uvs[loop_index++] = float2(0.50f + y * y_delta, 0.375f + z * z_delta);
+ uvs[loop_index++] = float2(0.50f + (y + 1) * y_delta, 0.375f + z * z_delta);
+ uvs[loop_index++] = float2(0.50f + (y + 1) * y_delta, 0.375f + (z + 1) * z_delta);
+ uvs[loop_index++] = float2(0.50f + y * y_delta, 0.375f + (z + 1) * z_delta);
+ }
+ }
+
+ uv_attribute.save();
+}
+
+Mesh *create_cuboid_mesh(const float3 &size,
+ const int verts_x,
+ const int verts_y,
+ const int verts_z,
+ const bke::AttributeIDRef &uv_id)
+{
+ const CuboidConfig config(size, verts_x, verts_y, verts_z);
+
+ Mesh *mesh = BKE_mesh_new_nomain(
+ config.vertex_count, 0, 0, config.loop_count, config.poly_count);
+
+ calculate_vertices(config, {mesh->mvert, mesh->totvert});
+
+ calculate_polys(config, {mesh->mpoly, mesh->totpoly}, {mesh->mloop, mesh->totloop});
+ BKE_mesh_calc_edges(mesh, false, false);
+
+ if (uv_id) {
+ calculate_uvs(config, mesh, uv_id);
+ }
+
+ return mesh;
+}
+
+Mesh *create_cuboid_mesh(const float3 &size,
+ const int verts_x,
+ const int verts_y,
+ const int verts_z)
+{
+ return create_cuboid_mesh(size, verts_x, verts_y, verts_z, {});
+}
+
+} // 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
index 09ca83ef976..6639ff650d3 100644
--- a/source/blender/geometry/intern/point_merge_by_distance.cc
+++ b/source/blender/geometry/intern/point_merge_by_distance.cc
@@ -97,9 +97,9 @@ PointCloud *point_merge_by_distance(const PointCloudComponent &src_points,
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);
+ const IndexRange points(map_offsets[dst_index],
+ map_offsets[dst_index + 1] - map_offsets[dst_index]);
+ MutableSpan<int> point_merge_indices = merge_map.as_mutable_span().slice(points);
point_merge_indices[point_merge_counts[dst_index]] = i;
point_merge_counts[dst_index]++;
}
@@ -116,9 +116,8 @@ PointCloud *point_merge_by_distance(const PointCloudComponent &src_points,
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()];
+ const IndexRange points(map_offsets[i_dst], map_offsets[i_dst + 1] - map_offsets[i_dst]);
+ dst_ids[i_dst] = src_ids[points.first()];
}
});
@@ -147,9 +146,9 @@ PointCloud *point_merge_by_distance(const PointCloudComponent &src_points,
* 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);
+ const IndexRange points(map_offsets[i_dst],
+ map_offsets[i_dst + 1] - map_offsets[i_dst]);
+ Span<int> src_merge_indices = merge_map.as_span().slice(points);
for (const int i_src : src_merge_indices) {
mixer.mix_in(0, src[i_src]);
}
diff --git a/source/blender/geometry/intern/realize_instances.cc b/source/blender/geometry/intern/realize_instances.cc
index f3f0e5b1fce..bd4099d37f9 100644
--- a/source/blender/geometry/intern/realize_instances.cc
+++ b/source/blender/geometry/intern/realize_instances.cc
@@ -134,6 +134,12 @@ struct RealizeCurveInfo {
* doesn't exist on some (but not all) of the input curves data-blocks.
*/
Span<float> radius;
+
+ /**
+ * The resolution attribute must be filled with the default value if it does not exist on some
+ * curves.
+ */
+ VArray<int> resolution;
};
/** Start indices in the final output curves data-block. */
@@ -185,6 +191,7 @@ struct AllCurvesInfo {
bool create_id_attribute = false;
bool create_handle_postion_attributes = false;
bool create_radius_attribute = false;
+ bool create_resolution_attribute = false;
};
/** Collects all tasks that need to be executed to realize all instances. */
@@ -279,12 +286,12 @@ static void copy_generic_attributes_to_result(
const Span<std::optional<GVArray_GSpan>> src_attributes,
const AttributeFallbacksArray &attribute_fallbacks,
const OrderedAttributes &ordered_attributes,
- const FunctionRef<IndexRange(AttributeDomain)> &range_fn,
+ const FunctionRef<IndexRange(eAttrDomain)> &range_fn,
MutableSpan<GMutableSpan> dst_attributes)
{
threading::parallel_for(dst_attributes.index_range(), 10, [&](const IndexRange attribute_range) {
for (const int attribute_index : attribute_range) {
- const AttributeDomain domain = ordered_attributes.kinds[attribute_index].domain;
+ const eAttrDomain domain = ordered_attributes.kinds[attribute_index].domain;
const IndexRange element_slice = range_fn(domain);
GMutableSpan dst_span = dst_attributes[attribute_index].slice(element_slice);
@@ -363,7 +370,7 @@ static Vector<std::pair<int, GSpan>> prepare_attribute_fallbacks(
return true;
}
GSpan span = *attributes.get_for_read(attribute_id);
- const CustomDataType expected_type = ordered_attributes.kinds[attribute_index].data_type;
+ const eCustomDataType expected_type = ordered_attributes.kinds[attribute_index].data_type;
if (meta_data.data_type != expected_type) {
const CPPType &from_type = span.type();
const CPPType &to_type = *custom_data_type_to_cpp_type(expected_type);
@@ -374,7 +381,7 @@ static Vector<std::pair<int, GSpan>> prepare_attribute_fallbacks(
}
/* Convert the attribute on the instances component to the expected attribute type. */
std::unique_ptr<GArray<>> temporary_array = std::make_unique<GArray<>>(
- to_type, instances_component.instances_amount());
+ to_type, instances_component.instances_num());
conversions.convert_to_initialized_n(span, temporary_array->as_mutable_span());
span = temporary_array->as_span();
gather_info.r_temporary_arrays.append(std::move(temporary_array));
@@ -548,7 +555,7 @@ static void gather_realize_tasks_recursive(GatherTasksInfo &gather_info,
case GEO_COMPONENT_TYPE_CURVE: {
const CurveComponent &curve_component = *static_cast<const CurveComponent *>(component);
const Curves *curves = curve_component.get_for_read();
- if (curves != nullptr && curves->geometry.curve_size > 0) {
+ if (curves != nullptr && curves->geometry.curve_num > 0) {
const int curve_index = gather_info.curves.order.index_of(curves);
const RealizeCurveInfo &curve_info = gather_info.curves.realize_info[curve_index];
gather_info.r_tasks.curve_tasks.append({gather_info.r_offsets.curves_offsets,
@@ -556,8 +563,8 @@ static void gather_realize_tasks_recursive(GatherTasksInfo &gather_info,
base_transform,
base_instance_context.curves,
base_instance_context.id});
- gather_info.r_offsets.curves_offsets.point += curves->geometry.point_size;
- gather_info.r_offsets.curves_offsets.curve += curves->geometry.curve_size;
+ gather_info.r_offsets.curves_offsets.point += curves->geometry.point_num;
+ gather_info.r_offsets.curves_offsets.curve += curves->geometry.curve_num;
}
break;
}
@@ -644,8 +651,8 @@ static AllPointCloudsInfo preprocess_pointclouds(const GeometrySet &geometry_set
pointcloud_info.attributes.reinitialize(info.attributes.size());
for (const int attribute_index : info.attributes.index_range()) {
const AttributeIDRef &attribute_id = info.attributes.ids[attribute_index];
- const CustomDataType data_type = info.attributes.kinds[attribute_index].data_type;
- const AttributeDomain domain = info.attributes.kinds[attribute_index].domain;
+ const eCustomDataType data_type = info.attributes.kinds[attribute_index].data_type;
+ const eAttrDomain domain = info.attributes.kinds[attribute_index].domain;
if (component.attribute_exists(attribute_id)) {
GVArray attribute = component.attribute_get_for_read(attribute_id, domain, data_type);
pointcloud_info.attributes[attribute_index].emplace(std::move(attribute));
@@ -687,7 +694,7 @@ static void execute_realize_pointcloud_task(const RealizeInstancesOptions &optio
pointcloud_info.attributes,
task.attribute_fallbacks,
ordered_attributes,
- [&](const AttributeDomain domain) {
+ [&](const eAttrDomain domain) {
BLI_assert(domain == ATTR_DOMAIN_POINT);
UNUSED_VARS_NDEBUG(domain);
return point_slice;
@@ -728,7 +735,7 @@ static void execute_realize_pointcloud_tasks(const RealizeInstancesOptions &opti
Vector<GMutableSpan> dst_attribute_spans;
for (const int attribute_index : ordered_attributes.index_range()) {
const AttributeIDRef &attribute_id = ordered_attributes.ids[attribute_index];
- const CustomDataType data_type = ordered_attributes.kinds[attribute_index].data_type;
+ const eCustomDataType data_type = ordered_attributes.kinds[attribute_index].data_type;
OutputAttribute dst_attribute = dst_component.attribute_try_get_for_output_only(
attribute_id, ATTR_DOMAIN_POINT, data_type);
dst_attribute_spans.append(dst_attribute.as_span());
@@ -835,8 +842,8 @@ static AllMeshesInfo preprocess_meshes(const GeometrySet &geometry_set,
mesh_info.attributes.reinitialize(info.attributes.size());
for (const int attribute_index : info.attributes.index_range()) {
const AttributeIDRef &attribute_id = info.attributes.ids[attribute_index];
- const CustomDataType data_type = info.attributes.kinds[attribute_index].data_type;
- const AttributeDomain domain = info.attributes.kinds[attribute_index].domain;
+ const eCustomDataType data_type = info.attributes.kinds[attribute_index].data_type;
+ const eAttrDomain domain = info.attributes.kinds[attribute_index].domain;
if (component.attribute_exists(attribute_id)) {
GVArray attribute = component.attribute_get_for_read(attribute_id, domain, data_type);
mesh_info.attributes[attribute_index].emplace(std::move(attribute));
@@ -927,7 +934,7 @@ static void execute_realize_mesh_task(const RealizeInstancesOptions &options,
mesh_info.attributes,
task.attribute_fallbacks,
ordered_attributes,
- [&](const AttributeDomain domain) {
+ [&](const eAttrDomain domain) {
switch (domain) {
case ATTR_DOMAIN_POINT:
return IndexRange(task.start_indices.vertex, mesh.totvert);
@@ -991,8 +998,8 @@ static void execute_realize_mesh_tasks(const RealizeInstancesOptions &options,
Vector<GMutableSpan> dst_attribute_spans;
for (const int attribute_index : ordered_attributes.index_range()) {
const AttributeIDRef &attribute_id = ordered_attributes.ids[attribute_index];
- const AttributeDomain domain = ordered_attributes.kinds[attribute_index].domain;
- const CustomDataType data_type = ordered_attributes.kinds[attribute_index].data_type;
+ const eAttrDomain domain = ordered_attributes.kinds[attribute_index].domain;
+ const eCustomDataType data_type = ordered_attributes.kinds[attribute_index].data_type;
OutputAttribute dst_attribute = dst_component.attribute_try_get_for_output_only(
attribute_id, domain, data_type);
dst_attribute_spans.append(dst_attribute.as_span());
@@ -1037,6 +1044,7 @@ static OrderedAttributes gather_generic_curve_attributes_to_propagate(
src_component_types, GEO_COMPONENT_TYPE_CURVE, true, attributes_to_propagate);
attributes_to_propagate.remove("position");
attributes_to_propagate.remove("radius");
+ attributes_to_propagate.remove("resolution");
attributes_to_propagate.remove("handle_right");
attributes_to_propagate.remove("handle_left");
r_create_id = attributes_to_propagate.pop_try("id").has_value();
@@ -1052,7 +1060,7 @@ static void gather_curves_to_realize(const GeometrySet &geometry_set,
VectorSet<const Curves *> &r_curves)
{
if (const Curves *curves = geometry_set.get_curves_for_read()) {
- if (curves->geometry.curve_size != 0) {
+ if (curves->geometry.curve_num != 0) {
r_curves.add(curves);
}
}
@@ -1075,17 +1083,18 @@ static AllCurvesInfo preprocess_curves(const GeometrySet &geometry_set,
info.realize_info.reinitialize(info.order.size());
for (const int curve_index : info.realize_info.index_range()) {
RealizeCurveInfo &curve_info = info.realize_info[curve_index];
- const Curves *curves = info.order[curve_index];
- curve_info.curves = curves;
+ const Curves *curves_id = info.order[curve_index];
+ const bke::CurvesGeometry &curves = bke::CurvesGeometry::wrap(curves_id->geometry);
+ curve_info.curves = curves_id;
/* Access attributes. */
CurveComponent component;
- component.replace(const_cast<Curves *>(curves), GeometryOwnershipType::ReadOnly);
+ component.replace(const_cast<Curves *>(curves_id), GeometryOwnershipType::ReadOnly);
curve_info.attributes.reinitialize(info.attributes.size());
for (const int attribute_index : info.attributes.index_range()) {
- const AttributeDomain domain = info.attributes.kinds[attribute_index].domain;
+ const eAttrDomain domain = info.attributes.kinds[attribute_index].domain;
const AttributeIDRef &attribute_id = info.attributes.ids[attribute_index];
- const CustomDataType data_type = info.attributes.kinds[attribute_index].data_type;
+ const eCustomDataType data_type = info.attributes.kinds[attribute_index].data_type;
if (component.attribute_exists(attribute_id)) {
GVArray attribute = component.attribute_get_for_read(attribute_id, domain, data_type);
curve_info.attributes[attribute_index].emplace(std::move(attribute));
@@ -1106,6 +1115,12 @@ static AllCurvesInfo preprocess_curves(const GeometrySet &geometry_set,
info.create_radius_attribute = true;
}
+ /* Retrieve the resolution attribute, if it exists. */
+ curve_info.resolution = curves.resolution();
+ if (component.attribute_exists("resolution")) {
+ info.create_resolution_attribute = true;
+ }
+
/* Retrieve handle position attributes, if they exist. */
if (component.attribute_exists("handle_right")) {
curve_info.handle_left = component
@@ -1131,7 +1146,8 @@ static void execute_realize_curve_task(const RealizeInstancesOptions &options,
MutableSpan<int> all_dst_ids,
MutableSpan<float3> all_handle_left,
MutableSpan<float3> all_handle_right,
- MutableSpan<float> all_radii)
+ MutableSpan<float> all_radii,
+ MutableSpan<int> all_resolutions)
{
const RealizeCurveInfo &curves_info = *task.curve_info;
const Curves &curves_id = *curves_info.curves;
@@ -1171,6 +1187,10 @@ static void execute_realize_curve_task(const RealizeInstancesOptions &options,
}
}
+ if (all_curves_info.create_resolution_attribute) {
+ curves_info.resolution.materialize(all_resolutions.slice(dst_curve_range));
+ }
+
/* Copy curve offsets. */
const Span<int> src_offsets = curves.offsets();
const MutableSpan<int> dst_offsets = dst_curves.offsets_for_write().slice(dst_curve_range);
@@ -1189,7 +1209,7 @@ static void execute_realize_curve_task(const RealizeInstancesOptions &options,
curves_info.attributes,
task.attribute_fallbacks,
ordered_attributes,
- [&](const AttributeDomain domain) {
+ [&](const eAttrDomain domain) {
switch (domain) {
case ATTR_DOMAIN_POINT:
return IndexRange(task.start_indices.point, curves.points_num());
@@ -1215,13 +1235,13 @@ static void execute_realize_curve_tasks(const RealizeInstancesOptions &options,
const RealizeCurveTask &last_task = tasks.last();
const Curves &last_curves = *last_task.curve_info->curves;
- const int points_size = last_task.start_indices.point + last_curves.geometry.point_size;
- const int curves_size = last_task.start_indices.curve + last_curves.geometry.curve_size;
+ const int points_num = last_task.start_indices.point + last_curves.geometry.point_num;
+ const int curves_num = last_task.start_indices.curve + last_curves.geometry.curve_num;
/* Allocate new curves data-block. */
- Curves *dst_curves_id = bke::curves_new_nomain(points_size, curves_size);
+ Curves *dst_curves_id = bke::curves_new_nomain(points_num, curves_num);
bke::CurvesGeometry &dst_curves = bke::CurvesGeometry::wrap(dst_curves_id->geometry);
- dst_curves.offsets_for_write().last() = points_size;
+ dst_curves.offsets_for_write().last() = points_num;
CurveComponent &dst_component = r_realized_geometry.get_component_for_write<CurveComponent>();
dst_component.replace(dst_curves_id);
@@ -1238,8 +1258,8 @@ static void execute_realize_curve_tasks(const RealizeInstancesOptions &options,
Vector<GMutableSpan> dst_attribute_spans;
for (const int attribute_index : ordered_attributes.index_range()) {
const AttributeIDRef &attribute_id = ordered_attributes.ids[attribute_index];
- const AttributeDomain domain = ordered_attributes.kinds[attribute_index].domain;
- const CustomDataType data_type = ordered_attributes.kinds[attribute_index].data_type;
+ const eAttrDomain domain = ordered_attributes.kinds[attribute_index].domain;
+ const eCustomDataType data_type = ordered_attributes.kinds[attribute_index].data_type;
OutputAttribute dst_attribute = dst_component.attribute_try_get_for_output_only(
attribute_id, domain, data_type);
dst_attribute_spans.append(dst_attribute.as_span());
@@ -1268,6 +1288,15 @@ static void execute_realize_curve_tasks(const RealizeInstancesOptions &options,
radius_span = radius.as_span();
}
+ /* Prepare resolution attribute if necessary. */
+ OutputAttribute_Typed<int> resolution;
+ MutableSpan<int> resolution_span;
+ if (all_curves_info.create_resolution_attribute) {
+ resolution = dst_component.attribute_try_get_for_output_only<int>("resolution",
+ ATTR_DOMAIN_CURVE);
+ resolution_span = resolution.as_span();
+ }
+
/* Actually execute all tasks. */
threading::parallel_for(tasks.index_range(), 100, [&](const IndexRange task_range) {
for (const int task_index : task_range) {
@@ -1281,7 +1310,8 @@ static void execute_realize_curve_tasks(const RealizeInstancesOptions &options,
point_ids_span,
handle_left_span,
handle_right_span,
- radius_span);
+ radius_span,
+ resolution_span);
}
});
@@ -1295,6 +1325,9 @@ static void execute_realize_curve_tasks(const RealizeInstancesOptions &options,
if (radius) {
radius.save();
}
+ if (resolution) {
+ resolution.save();
+ }
if (all_curves_info.create_handle_postion_attributes) {
handle_left.save();
handle_right.save();
diff --git a/source/blender/geometry/intern/resample_curves.cc b/source/blender/geometry/intern/resample_curves.cc
new file mode 100644
index 00000000000..36525e1bdf0
--- /dev/null
+++ b/source/blender/geometry/intern/resample_curves.cc
@@ -0,0 +1,444 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+
+#include "BLI_length_parameterize.hh"
+#include "BLI_task.hh"
+
+#include "FN_field.hh"
+#include "FN_multi_function_builder.hh"
+
+#include "BKE_attribute_math.hh"
+#include "BKE_curves.hh"
+#include "BKE_curves_utils.hh"
+#include "BKE_geometry_fields.hh"
+
+#include "GEO_resample_curves.hh"
+
+namespace blender::geometry {
+
+static fn::Field<int> get_count_input_max_one(const fn::Field<int> &count_field)
+{
+ static fn::CustomMF_SI_SO<int, int> max_one_fn(
+ "Clamp Above One",
+ [](int value) { return std::max(1, value); },
+ fn::CustomMF_presets::AllSpanOrSingle());
+ auto clamp_op = std::make_shared<fn::FieldOperation>(
+ fn::FieldOperation(max_one_fn, {count_field}));
+
+ return fn::Field<int>(std::move(clamp_op));
+}
+
+static fn::Field<int> get_count_input_from_length(const fn::Field<float> &length_field)
+{
+ static fn::CustomMF_SI_SI_SO<float, float, int> get_count_fn(
+ "Length Input to Count",
+ [](const float curve_length, const float sample_length) {
+ /* Find the number of sampled segments by dividing the total length by
+ * the sample length. Then there is one more sampled point than segment. */
+ const int count = int(curve_length / sample_length) + 1;
+ return std::max(1, count);
+ },
+ fn::CustomMF_presets::AllSpanOrSingle());
+
+ auto get_count_op = std::make_shared<fn::FieldOperation>(fn::FieldOperation(
+ get_count_fn,
+ {fn::Field<float>(std::make_shared<bke::CurveLengthFieldInput>()), length_field}));
+
+ return fn::Field<int>(std::move(get_count_op));
+}
+
+/**
+ * Return true if the attribute should be copied/interpolated to the result curves.
+ * Don't output attributes that correspond to curve types that have no curves in the result.
+ */
+static bool interpolate_attribute_to_curves(const bke::AttributeIDRef &attribute_id,
+ const std::array<int, CURVE_TYPES_NUM> &type_counts)
+{
+ if (!attribute_id.is_named()) {
+ return true;
+ }
+ if (ELEM(attribute_id.name(),
+ "handle_type_left",
+ "handle_type_right",
+ "handle_left",
+ "handle_right")) {
+ return type_counts[CURVE_TYPE_BEZIER] != 0;
+ }
+ if (ELEM(attribute_id.name(), "nurbs_weight")) {
+ return type_counts[CURVE_TYPE_NURBS] != 0;
+ }
+ return true;
+}
+
+/**
+ * Return true if the attribute should be copied to poly curves.
+ */
+static bool interpolate_attribute_to_poly_curve(const bke::AttributeIDRef &attribute_id)
+{
+ static const Set<StringRef> no_interpolation{{
+ "handle_type_left",
+ "handle_type_right",
+ "handle_position_right",
+ "handle_position_left",
+ "nurbs_weight",
+ }};
+ return !(attribute_id.is_named() && no_interpolation.contains(attribute_id.name()));
+}
+
+/**
+ * Retrieve spans from source and result attributes.
+ */
+static void retrieve_attribute_spans(const Span<bke::AttributeIDRef> ids,
+ const CurveComponent &src_component,
+ CurveComponent &dst_component,
+ Vector<GSpan> &src,
+ Vector<GMutableSpan> &dst,
+ Vector<bke::OutputAttribute> &dst_attributes)
+{
+ for (const int i : ids.index_range()) {
+ GVArray src_attribute = src_component.attribute_try_get_for_read(ids[i], ATTR_DOMAIN_POINT);
+ BLI_assert(src_attribute);
+ src.append(src_attribute.get_internal_span());
+
+ const eCustomDataType data_type = bke::cpp_type_to_custom_data_type(src_attribute.type());
+ bke::OutputAttribute dst_attribute = dst_component.attribute_try_get_for_output_only(
+ ids[i], ATTR_DOMAIN_POINT, data_type);
+ dst.append(dst_attribute.as_span());
+ dst_attributes.append(std::move(dst_attribute));
+ }
+}
+
+struct AttributesForInterpolation : NonCopyable, NonMovable {
+ Vector<GSpan> src;
+ Vector<GMutableSpan> dst;
+
+ Vector<bke::OutputAttribute> dst_attributes;
+
+ Vector<GSpan> src_no_interpolation;
+ Vector<GMutableSpan> dst_no_interpolation;
+};
+
+/**
+ * Gather a set of all generic attribute IDs to copy to the result curves.
+ */
+static void gather_point_attributes_to_interpolate(const CurveComponent &src_component,
+ CurveComponent &dst_component,
+ AttributesForInterpolation &result)
+{
+ bke::CurvesGeometry &dst_curves = bke::CurvesGeometry::wrap(
+ dst_component.get_for_write()->geometry);
+
+ VectorSet<bke::AttributeIDRef> ids;
+ VectorSet<bke::AttributeIDRef> ids_no_interpolation;
+ src_component.attribute_foreach(
+ [&](const bke::AttributeIDRef &id, const AttributeMetaData meta_data) {
+ if (meta_data.domain != ATTR_DOMAIN_POINT) {
+ return true;
+ }
+ if (!interpolate_attribute_to_curves(id, dst_curves.curve_type_counts())) {
+ return true;
+ }
+ if (interpolate_attribute_to_poly_curve(id)) {
+ ids.add_new(id);
+ }
+ else {
+ ids_no_interpolation.add_new(id);
+ }
+ return true;
+ });
+
+ /* Position is handled differently since it has non-generic interpolation for Bezier
+ * curves and because the evaluated positions are cached for each evaluated point. */
+ ids.remove_contained("position");
+
+ retrieve_attribute_spans(
+ ids, src_component, dst_component, result.src, result.dst, result.dst_attributes);
+
+ /* Attributes that aren't interpolated like Bezier handles still have to be be copied
+ * to the result when there are any unselected curves of the corresponding type. */
+ retrieve_attribute_spans(ids_no_interpolation,
+ src_component,
+ dst_component,
+ result.src_no_interpolation,
+ result.dst_no_interpolation,
+ result.dst_attributes);
+
+ dst_curves.update_customdata_pointers();
+}
+
+static Curves *resample_to_uniform(const CurveComponent &src_component,
+ const fn::Field<bool> &selection_field,
+ const fn::Field<int> &count_field)
+{
+ const bke::CurvesGeometry &src_curves = bke::CurvesGeometry::wrap(
+ src_component.get_for_read()->geometry);
+
+ /* Create the new curves without any points and evaluate the final count directly
+ * into the offsets array, in order to be accumulated into offsets later. */
+ Curves *dst_curves_id = bke::curves_new_nomain(0, src_curves.curves_num());
+ bke::CurvesGeometry &dst_curves = bke::CurvesGeometry::wrap(dst_curves_id->geometry);
+
+ /* Directly copy curve attributes, since they stay the same (except for curve types). */
+ CustomData_copy(&src_curves.curve_data,
+ &dst_curves.curve_data,
+ CD_MASK_ALL,
+ CD_DUPLICATE,
+ src_curves.curves_num());
+ MutableSpan<int> dst_offsets = dst_curves.offsets_for_write();
+
+ bke::GeometryComponentFieldContext field_context{src_component, ATTR_DOMAIN_CURVE};
+ fn::FieldEvaluator evaluator{field_context, src_curves.curves_num()};
+ evaluator.set_selection(selection_field);
+ evaluator.add_with_destination(count_field, dst_offsets);
+ evaluator.evaluate();
+ const IndexMask selection = evaluator.get_evaluated_selection_as_mask();
+ const Vector<IndexRange> unselected_ranges = selection.extract_ranges_invert(
+ src_curves.curves_range(), nullptr);
+
+ /* Fill the counts for the curves that aren't selected and accumulate the counts into offsets. */
+ bke::curves::fill_curve_counts(src_curves, unselected_ranges, dst_offsets);
+ bke::curves::accumulate_counts_to_offsets(dst_offsets);
+ dst_curves.resize(dst_offsets.last(), dst_curves.curves_num());
+
+ /* All resampled curves are poly curves. */
+ dst_curves.fill_curve_types(selection, CURVE_TYPE_POLY);
+
+ VArray<bool> curves_cyclic = src_curves.cyclic();
+ VArray<int8_t> curve_types = src_curves.curve_types();
+ Span<float3> evaluated_positions = src_curves.evaluated_positions();
+ MutableSpan<float3> dst_positions = dst_curves.positions_for_write();
+
+ AttributesForInterpolation attributes;
+ CurveComponent dst_component;
+ dst_component.replace(dst_curves_id, GeometryOwnershipType::Editable);
+ gather_point_attributes_to_interpolate(src_component, dst_component, attributes);
+
+ src_curves.ensure_evaluated_lengths();
+
+ /* Sampling arbitrary attributes works by first interpolating them to the curve's standard
+ * "evaluated points" and then interpolating that result with the uniform samples. This is
+ * potentially wasteful when down-sampling a curve to many fewer points. There are two possible
+ * solutions: only sample the necessary points for interpolation, or first sample curve
+ * parameter/segment indices and evaluate the curve directly. */
+ Array<int> sample_indices(dst_curves.points_num());
+ Array<float> sample_factors(dst_curves.points_num());
+
+ /* Use a "for each group of curves: for each attribute: for each curve" pattern to work on
+ * smaller sections of data that ideally fit into CPU cache better than simply one attribute at a
+ * time or one curve at a time. */
+ threading::parallel_for(selection.index_range(), 512, [&](IndexRange selection_range) {
+ const IndexMask sliced_selection = selection.slice(selection_range);
+
+ Vector<std::byte> evaluated_buffer;
+
+ /* Gather uniform samples based on the accumulated lengths of the original curve. */
+ for (const int i_curve : sliced_selection) {
+ const bool cyclic = curves_cyclic[i_curve];
+ const IndexRange dst_points = dst_curves.points_for_curve(i_curve);
+ length_parameterize::create_uniform_samples(
+ src_curves.evaluated_lengths_for_curve(i_curve, cyclic),
+ curves_cyclic[i_curve],
+ sample_indices.as_mutable_span().slice(dst_points),
+ sample_factors.as_mutable_span().slice(dst_points));
+ }
+
+ /* For every attribute, evaluate attributes from every curve in the range in the original
+ * curve's "evaluated points", then use linear interpolation to sample to the result. */
+ for (const int i_attribute : attributes.dst.index_range()) {
+ attribute_math::convert_to_static_type(attributes.src[i_attribute].type(), [&](auto dummy) {
+ using T = decltype(dummy);
+ Span<T> src = attributes.src[i_attribute].typed<T>();
+ MutableSpan<T> dst = attributes.dst[i_attribute].typed<T>();
+
+ for (const int i_curve : sliced_selection) {
+ const IndexRange src_points = src_curves.points_for_curve(i_curve);
+ const IndexRange dst_points = dst_curves.points_for_curve(i_curve);
+
+ if (curve_types[i_curve] == CURVE_TYPE_POLY) {
+ length_parameterize::linear_interpolation(src.slice(src_points),
+ sample_indices.as_span().slice(dst_points),
+ sample_factors.as_span().slice(dst_points),
+ dst.slice(dst_points));
+ }
+ else {
+ const int evaluated_size = src_curves.evaluated_points_for_curve(i_curve).size();
+ evaluated_buffer.clear();
+ evaluated_buffer.resize(sizeof(T) * evaluated_size);
+ MutableSpan<T> evaluated = evaluated_buffer.as_mutable_span().cast<T>();
+ src_curves.interpolate_to_evaluated(i_curve, src.slice(src_points), evaluated);
+
+ length_parameterize::linear_interpolation(evaluated.as_span(),
+ sample_indices.as_span().slice(dst_points),
+ sample_factors.as_span().slice(dst_points),
+ dst.slice(dst_points));
+ }
+ }
+ });
+ }
+
+ /* Interpolate the evaluated positions to the resampled curves. */
+ for (const int i_curve : sliced_selection) {
+ const IndexRange src_points = src_curves.evaluated_points_for_curve(i_curve);
+ const IndexRange dst_points = dst_curves.points_for_curve(i_curve);
+ length_parameterize::linear_interpolation(evaluated_positions.slice(src_points),
+ sample_indices.as_span().slice(dst_points),
+ sample_factors.as_span().slice(dst_points),
+ dst_positions.slice(dst_points));
+ }
+
+ /* Fill the default value for non-interpolating attributes that still must be copied. */
+ for (GMutableSpan dst : attributes.dst_no_interpolation) {
+ for (const int i_curve : sliced_selection) {
+ const IndexRange dst_points = dst_curves.points_for_curve(i_curve);
+ dst.type().value_initialize_n(dst.slice(dst_points).data(), dst_points.size());
+ }
+ }
+ });
+
+ /* Any attribute data from unselected curve points can be directly copied. */
+ for (const int i : attributes.src.index_range()) {
+ bke::curves::copy_point_data(
+ src_curves, dst_curves, unselected_ranges, attributes.src[i], attributes.dst[i]);
+ }
+ for (const int i : attributes.src_no_interpolation.index_range()) {
+ bke::curves::copy_point_data(src_curves,
+ dst_curves,
+ unselected_ranges,
+ attributes.src_no_interpolation[i],
+ attributes.dst_no_interpolation[i]);
+ }
+
+ /* Copy positions for unselected curves. */
+ Span<float3> src_positions = src_curves.positions();
+ bke::curves::copy_point_data(
+ src_curves, dst_curves, unselected_ranges, src_positions, dst_positions);
+
+ for (bke::OutputAttribute &attribute : attributes.dst_attributes) {
+ attribute.save();
+ }
+
+ return dst_curves_id;
+}
+
+Curves *resample_to_count(const CurveComponent &src_component,
+ const fn::Field<bool> &selection_field,
+ const fn::Field<int> &count_field)
+{
+ return resample_to_uniform(src_component, selection_field, get_count_input_max_one(count_field));
+}
+
+Curves *resample_to_length(const CurveComponent &src_component,
+ const fn::Field<bool> &selection_field,
+ const fn::Field<float> &segment_length_field)
+{
+ return resample_to_uniform(
+ src_component, selection_field, get_count_input_from_length(segment_length_field));
+}
+
+Curves *resample_to_evaluated(const CurveComponent &src_component,
+ const fn::Field<bool> &selection_field)
+{
+ const bke::CurvesGeometry &src_curves = bke::CurvesGeometry::wrap(
+ src_component.get_for_read()->geometry);
+
+ bke::GeometryComponentFieldContext field_context{src_component, ATTR_DOMAIN_CURVE};
+ fn::FieldEvaluator evaluator{field_context, src_curves.curves_num()};
+ evaluator.set_selection(selection_field);
+ evaluator.evaluate();
+ const IndexMask selection = evaluator.get_evaluated_selection_as_mask();
+ const Vector<IndexRange> unselected_ranges = selection.extract_ranges_invert(
+ src_curves.curves_range(), nullptr);
+
+ Curves *dst_curves_id = bke::curves_new_nomain(0, src_curves.curves_num());
+ bke::CurvesGeometry &dst_curves = bke::CurvesGeometry::wrap(dst_curves_id->geometry);
+
+ /* Directly copy curve attributes, since they stay the same (except for curve types). */
+ CustomData_copy(&src_curves.curve_data,
+ &dst_curves.curve_data,
+ CD_MASK_ALL,
+ CD_DUPLICATE,
+ src_curves.curves_num());
+ /* All resampled curves are poly curves. */
+ dst_curves.fill_curve_types(selection, CURVE_TYPE_POLY);
+ MutableSpan<int> dst_offsets = dst_curves.offsets_for_write();
+
+ src_curves.ensure_evaluated_offsets();
+ threading::parallel_for(selection.index_range(), 4096, [&](IndexRange range) {
+ for (const int i : selection.slice(range)) {
+ dst_offsets[i] = src_curves.evaluated_points_for_curve(i).size();
+ }
+ });
+ bke::curves::fill_curve_counts(src_curves, unselected_ranges, dst_offsets);
+ bke::curves::accumulate_counts_to_offsets(dst_offsets);
+
+ dst_curves.resize(dst_offsets.last(), dst_curves.curves_num());
+
+ /* Create the correct number of uniform-length samples for every selected curve. */
+ Span<float3> evaluated_positions = src_curves.evaluated_positions();
+ MutableSpan<float3> dst_positions = dst_curves.positions_for_write();
+
+ AttributesForInterpolation attributes;
+ CurveComponent dst_component;
+ dst_component.replace(dst_curves_id, GeometryOwnershipType::Editable);
+ gather_point_attributes_to_interpolate(src_component, dst_component, attributes);
+
+ threading::parallel_for(selection.index_range(), 512, [&](IndexRange selection_range) {
+ const IndexMask sliced_selection = selection.slice(selection_range);
+
+ /* Evaluate generic point attributes directly to the result attributes. */
+ for (const int i_attribute : attributes.dst.index_range()) {
+ attribute_math::convert_to_static_type(attributes.src[i_attribute].type(), [&](auto dummy) {
+ using T = decltype(dummy);
+ Span<T> src = attributes.src[i_attribute].typed<T>();
+ MutableSpan<T> dst = attributes.dst[i_attribute].typed<T>();
+
+ for (const int i_curve : sliced_selection) {
+ const IndexRange src_points = src_curves.points_for_curve(i_curve);
+ const IndexRange dst_points = dst_curves.points_for_curve(i_curve);
+ src_curves.interpolate_to_evaluated(
+ i_curve, src.slice(src_points), dst.slice(dst_points));
+ }
+ });
+ }
+
+ /* Copy the evaluated positions to the selected curves. */
+ for (const int i_curve : sliced_selection) {
+ const IndexRange src_points = src_curves.evaluated_points_for_curve(i_curve);
+ const IndexRange dst_points = dst_curves.points_for_curve(i_curve);
+ dst_positions.slice(dst_points).copy_from(evaluated_positions.slice(src_points));
+ }
+
+ /* Fill the default value for non-interpolating attributes that still must be copied. */
+ for (GMutableSpan dst : attributes.dst_no_interpolation) {
+ for (const int i_curve : sliced_selection) {
+ const IndexRange dst_points = dst_curves.points_for_curve(i_curve);
+ dst.type().value_initialize_n(dst.slice(dst_points).data(), dst_points.size());
+ }
+ }
+ });
+
+ /* Any attribute data from unselected curve points can be directly copied. */
+ for (const int i : attributes.src.index_range()) {
+ bke::curves::copy_point_data(
+ src_curves, dst_curves, unselected_ranges, attributes.src[i], attributes.dst[i]);
+ }
+ for (const int i : attributes.src_no_interpolation.index_range()) {
+ bke::curves::copy_point_data(src_curves,
+ dst_curves,
+ unselected_ranges,
+ attributes.src_no_interpolation[i],
+ attributes.dst_no_interpolation[i]);
+ }
+
+ /* Copy positions for unselected curves. */
+ Span<float3> src_positions = src_curves.positions();
+ bke::curves::copy_point_data(
+ src_curves, dst_curves, unselected_ranges, src_positions, dst_positions);
+
+ for (bke::OutputAttribute &attribute : attributes.dst_attributes) {
+ attribute.save();
+ }
+
+ return dst_curves_id;
+}
+
+} // namespace blender::geometry
diff --git a/source/blender/geometry/intern/reverse_uv_sampler.cc b/source/blender/geometry/intern/reverse_uv_sampler.cc
new file mode 100644
index 00000000000..9aa98895a86
--- /dev/null
+++ b/source/blender/geometry/intern/reverse_uv_sampler.cc
@@ -0,0 +1,32 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+
+#include "GEO_reverse_uv_sampler.hh"
+
+#include "BLI_math_geom.h"
+
+namespace blender::geometry {
+
+ReverseUVSampler::ReverseUVSampler(const Span<float2> uv_map, const Span<MLoopTri> looptris)
+ : uv_map_(uv_map), looptris_(looptris)
+{
+}
+
+ReverseUVSampler::Result ReverseUVSampler::sample(const float2 &query_uv) const
+{
+ for (const MLoopTri &looptri : looptris_) {
+ const float2 &uv0 = uv_map_[looptri.tri[0]];
+ const float2 &uv1 = uv_map_[looptri.tri[1]];
+ const float2 &uv2 = uv_map_[looptri.tri[2]];
+ float3 bary_weights;
+ if (!barycentric_coords_v2(uv0, uv1, uv2, query_uv, bary_weights)) {
+ continue;
+ }
+ if (IN_RANGE_INCL(bary_weights.x, 0.0f, 1.0f) && IN_RANGE_INCL(bary_weights.y, 0.0f, 1.0f) &&
+ IN_RANGE_INCL(bary_weights.z, 0.0f, 1.0f)) {
+ return Result{ResultType::Ok, &looptri, bary_weights};
+ }
+ }
+ return Result{};
+}
+
+} // namespace blender::geometry
diff --git a/source/blender/geometry/intern/uv_parametrizer.c b/source/blender/geometry/intern/uv_parametrizer.c
index e25fff0d6b8..8863b9192ca 100644
--- a/source/blender/geometry/intern/uv_parametrizer.c
+++ b/source/blender/geometry/intern/uv_parametrizer.c
@@ -4,26 +4,18 @@
* \ingroup eduv
*/
+#include "GEO_uv_parametrizer.h"
+
#include "MEM_guardedalloc.h"
#include "BLI_boxpack_2d.h"
#include "BLI_convexhull_2d.h"
+#include "BLI_ghash.h"
#include "BLI_heap.h"
-#include "BLI_math.h"
#include "BLI_memarena.h"
#include "BLI_polyfill_2d.h"
#include "BLI_polyfill_2d_beautify.h"
#include "BLI_rand.h"
-#include "BLI_utildefines.h"
-
-#include "GEO_uv_parametrizer.h"
-
-#include <math.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-
-#include "BLI_sys_types.h" /* for intptr_t support */
#include "eigen_capi.h"
@@ -36,11 +28,6 @@
#define param_warning(message) \
{/*printf("Warning %s:%d: %s\n", __FILE__, __LINE__, message);*/}(void)0
-typedef enum PBool {
- P_TRUE = 1,
- P_FALSE = 0,
-} PBool;
-
/* Special Purpose Hash */
typedef intptr_t PHashKey;
@@ -56,12 +43,6 @@ typedef struct PHash {
int size, cursize, cursize_id;
} PHash;
-struct PChart;
-struct PEdge;
-struct PFace;
-struct PHandle;
-struct PVert;
-
/* Simplices */
typedef struct PVert {
@@ -171,7 +152,7 @@ typedef struct PChart {
} u;
uchar flag;
- struct PHandle *handle;
+ ParamHandle *handle;
} PChart;
enum PChartFlag {
@@ -185,7 +166,7 @@ enum PHandleState {
PHANDLE_STATE_STRETCH,
};
-typedef struct PHandle {
+typedef struct ParamHandle {
enum PHandleState state;
MemArena *arena;
MemArena *polyfill_arena;
@@ -196,6 +177,9 @@ typedef struct PHandle {
PHash *hash_edges;
PHash *hash_faces;
+ struct GHash *pin_hash;
+ int unique_pin_count;
+
PChart **charts;
int ncharts;
@@ -204,7 +188,7 @@ typedef struct PHandle {
RNG *rng;
float blend;
bool do_aspect;
-} PHandle;
+} ParamHandle;
/* PHash
* - special purpose hash that keeps all its elements in a single linked list.
@@ -320,54 +304,14 @@ static PHashLink *phash_next(PHash *ph, PHashKey key, PHashLink *link)
/* Geometry */
-static float p_vec_angle_cos(const float v1[3], const float v2[3], const float v3[3])
-{
- float d1[3], d2[3];
-
- d1[0] = v1[0] - v2[0];
- d1[1] = v1[1] - v2[1];
- d1[2] = v1[2] - v2[2];
-
- d2[0] = v3[0] - v2[0];
- d2[1] = v3[1] - v2[1];
- d2[2] = v3[2] - v2[2];
-
- normalize_v3(d1);
- normalize_v3(d2);
-
- return d1[0] * d2[0] + d1[1] * d2[1] + d1[2] * d2[2];
-}
-
static float p_vec_angle(const float v1[3], const float v2[3], const float v3[3])
{
- float dot = p_vec_angle_cos(v1, v2, v3);
-
- if (dot <= -1.0f) {
- return (float)M_PI;
- }
- if (dot >= 1.0f) {
- return 0.0f;
- }
- return acosf(dot);
+ return angle_v3v3v3(v1, v2, v3);
}
-
static float p_vec2_angle(const float v1[2], const float v2[2], const float v3[2])
{
- float u1[3], u2[3], u3[3];
-
- u1[0] = v1[0];
- u1[1] = v1[1];
- u1[2] = 0.0f;
- u2[0] = v2[0];
- u2[1] = v2[1];
- u2[2] = 0.0f;
- u3[0] = v3[0];
- u3[1] = v3[1];
- u3[2] = 0.0f;
-
- return p_vec_angle(u1, u2, u3);
+ return angle_v2v2v2(v1, v2, v3);
}
-
static void p_triangle_angles(
const float v1[3], const float v2[3], const float v3[3], float *r_a1, float *r_a2, float *r_a3)
{
@@ -408,25 +352,12 @@ static float p_face_uv_area_signed(PFace *f)
static float p_edge_length(PEdge *e)
{
- PVert *v1 = e->vert, *v2 = e->next->vert;
- float d[3];
-
- d[0] = v2->co[0] - v1->co[0];
- d[1] = v2->co[1] - v1->co[1];
- d[2] = v2->co[2] - v1->co[2];
-
- return sqrtf(d[0] * d[0] + d[1] * d[1] + d[2] * d[2]);
+ return len_v3v3(e->vert->co, e->next->vert->co);
}
static float p_edge_uv_length(PEdge *e)
{
- PVert *v1 = e->vert, *v2 = e->next->vert;
- float d[3];
-
- d[0] = v2->uv[0] - v1->uv[0];
- d[1] = v2->uv[1] - v1->uv[1];
-
- return sqrtf(d[0] * d[0] + d[1] * d[1]);
+ return len_v2v2(e->vert->uv, e->next->vert->uv);
}
static void p_chart_uv_bbox(PChart *chart, float minv[2], float maxv[2])
@@ -500,63 +431,26 @@ static void p_chart_uv_to_array(PChart *chart, float (*points)[2])
}
}
-static void UNUSED_FUNCTION(p_chart_uv_from_array)(PChart *chart, float (*points)[2])
-{
- PVert *v;
- uint i = 0;
-
- for (v = chart->verts; v; v = v->nextlink) {
- copy_v2_v2(v->uv, points[i++]);
- }
-}
-
-static PBool p_intersect_line_2d_dir(const float v1[2],
- const float dir1[2],
- const float v2[2],
- const float dir2[2],
- float r_isect[2])
+static bool p_intersect_line_2d_dir(const float v1[2],
+ const float dir1[2],
+ const float v2[2],
+ const float dir2[2],
+ float r_isect[2])
{
float lmbda, div;
div = dir2[0] * dir1[1] - dir2[1] * dir1[0];
if (div == 0.0f) {
- return P_FALSE;
+ return false;
}
lmbda = ((v1[1] - v2[1]) * dir1[0] - (v1[0] - v2[0]) * dir1[1]) / div;
r_isect[0] = v1[0] + lmbda * dir2[0];
r_isect[1] = v1[1] + lmbda * dir2[1];
- return P_TRUE;
-}
-
-#if 0
-static PBool p_intersect_line_2d(const float v1[2],
- const float v2[2],
- const float v3[2],
- const float v4[2],
- const float r_isect[2])
-{
- float dir1[2], dir2[2];
-
- dir1[0] = v4[0] - v3[0];
- dir1[1] = v4[1] - v3[1];
-
- dir2[0] = v2[0] - v1[0];
- dir2[1] = v2[1] - v1[1];
-
- if (!p_intersect_line_2d_dir(v1, dir1, v2, dir2, isect)) {
- /* parallel - should never happen in theory for polygon kernel, but
- * let's give a point nearby in case things go wrong */
- isect[0] = (v1[0] + v2[0]) * 0.5f;
- isect[1] = (v1[1] + v2[1]) * 0.5f;
- return P_FALSE;
- }
-
- return P_TRUE;
+ return true;
}
-#endif
/* Topological Utilities */
@@ -587,9 +481,9 @@ static PEdge *p_boundary_edge_prev(PEdge *e)
return last->next->next;
}
-static PBool p_vert_interior(PVert *v)
+static bool p_vert_interior(PVert *v)
{
- return (v->edge->pair != NULL);
+ return v->edge->pair;
}
static void p_face_flip(PFace *f)
@@ -637,7 +531,7 @@ static void p_chart_topological_sanity_check(PChart *chart)
/* Loading / Flushing */
-static void p_vert_load_pin_select_uvs(PHandle *handle, PVert *v)
+static void p_vert_load_pin_select_uvs(ParamHandle *handle, PVert *v)
{
PEdge *e;
int nedges = 0, npins = 0;
@@ -679,7 +573,7 @@ static void p_vert_load_pin_select_uvs(PHandle *handle, PVert *v)
}
}
-static void p_flush_uvs(PHandle *handle, PChart *chart)
+static void p_flush_uvs(ParamHandle *handle, PChart *chart)
{
PEdge *e;
@@ -691,7 +585,7 @@ static void p_flush_uvs(PHandle *handle, PChart *chart)
}
}
-static void p_flush_uvs_blend(PHandle *handle, PChart *chart, float blend)
+static void p_flush_uvs_blend(ParamHandle *handle, PChart *chart, float blend)
{
PEdge *e;
float invblend = 1.0f - blend;
@@ -742,7 +636,7 @@ static void p_face_restore_uvs(PFace *f)
/* Construction (use only during construction, relies on u.key being set */
-static PVert *p_vert_add(PHandle *handle, PHashKey key, const float co[3], PEdge *e)
+static PVert *p_vert_add(ParamHandle *handle, PHashKey key, const float co[3], PEdge *e)
{
PVert *v = (PVert *)BLI_memarena_alloc(handle->arena, sizeof(*v));
copy_v3_v3(v->co, co);
@@ -765,7 +659,7 @@ static PVert *p_vert_add(PHandle *handle, PHashKey key, const float co[3], PEdge
return v;
}
-static PVert *p_vert_lookup(PHandle *handle, PHashKey key, const float co[3], PEdge *e)
+static PVert *p_vert_lookup(ParamHandle *handle, PHashKey key, const float co[3], PEdge *e)
{
PVert *v = (PVert *)phash_lookup(handle->hash_verts, key);
@@ -789,7 +683,7 @@ static PVert *p_vert_copy(PChart *chart, PVert *v)
return nv;
}
-static PEdge *p_edge_lookup(PHandle *handle, const PHashKey *vkeys)
+static PEdge *p_edge_lookup(ParamHandle *handle, const PHashKey *vkeys)
{
PHashKey key = PHASH_edge(vkeys[0], vkeys[1]);
PEdge *e = (PEdge *)phash_lookup(handle->hash_edges, key);
@@ -808,9 +702,8 @@ static PEdge *p_edge_lookup(PHandle *handle, const PHashKey *vkeys)
return NULL;
}
-static int p_face_exists(ParamHandle *phandle, ParamKey *pvkeys, int i1, int i2, int i3)
+static int p_face_exists(ParamHandle *handle, const ParamKey *pvkeys, int i1, int i2, int i3)
{
- PHandle *handle = (PHandle *)phandle;
PHashKey *vkeys = (PHashKey *)pvkeys;
PHashKey key = PHASH_edge(vkeys[i1], vkeys[i2]);
PEdge *e = (PEdge *)phash_lookup(handle->hash_edges, key);
@@ -818,22 +711,22 @@ static int p_face_exists(ParamHandle *phandle, ParamKey *pvkeys, int i1, int i2,
while (e) {
if ((e->vert->u.key == vkeys[i1]) && (e->next->vert->u.key == vkeys[i2])) {
if (e->next->next->vert->u.key == vkeys[i3]) {
- return P_TRUE;
+ return true;
}
}
else if ((e->vert->u.key == vkeys[i2]) && (e->next->vert->u.key == vkeys[i1])) {
if (e->next->next->vert->u.key == vkeys[i3]) {
- return P_TRUE;
+ return true;
}
}
e = (PEdge *)phash_next(handle->hash_edges, key, (PHashLink *)e);
}
- return P_FALSE;
+ return false;
}
-static PChart *p_chart_new(PHandle *handle)
+static PChart *p_chart_new(ParamHandle *handle)
{
PChart *chart = (PChart *)MEM_callocN(sizeof(*chart), "PChart");
chart->handle = handle;
@@ -847,7 +740,7 @@ static void p_chart_delete(PChart *chart)
MEM_freeN(chart);
}
-static PBool p_edge_implicit_seam(PEdge *e, PEdge *ep)
+static bool p_edge_implicit_seam(PEdge *e, PEdge *ep)
{
float *uv1, *uv2, *uvp1, *uvp2;
float limit[2];
@@ -870,18 +763,18 @@ static PBool p_edge_implicit_seam(PEdge *e, PEdge *ep)
if ((fabsf(uv1[0] - uvp1[0]) > limit[0]) || (fabsf(uv1[1] - uvp1[1]) > limit[1])) {
e->flag |= PEDGE_SEAM;
ep->flag |= PEDGE_SEAM;
- return P_TRUE;
+ return true;
}
if ((fabsf(uv2[0] - uvp2[0]) > limit[0]) || (fabsf(uv2[1] - uvp2[1]) > limit[1])) {
e->flag |= PEDGE_SEAM;
ep->flag |= PEDGE_SEAM;
- return P_TRUE;
+ return true;
}
- return P_FALSE;
+ return false;
}
-static PBool p_edge_has_pair(PHandle *handle, PEdge *e, PBool topology_from_uvs, PEdge **r_pair)
+static bool p_edge_has_pair(ParamHandle *handle, PEdge *e, bool topology_from_uvs, PEdge **r_pair)
{
PHashKey key;
PEdge *pe;
@@ -890,7 +783,7 @@ static PBool p_edge_has_pair(PHandle *handle, PEdge *e, PBool topology_from_uvs,
PHashKey key2 = e->next->vert->u.key;
if (e->flag & PEDGE_SEAM) {
- return P_FALSE;
+ return false;
}
key = PHASH_edge(key1, key2);
@@ -909,7 +802,7 @@ static PBool p_edge_has_pair(PHandle *handle, PEdge *e, PBool topology_from_uvs,
if ((pe->flag & PEDGE_SEAM) || *r_pair ||
(topology_from_uvs && p_edge_implicit_seam(e, pe))) {
*r_pair = NULL;
- return P_FALSE;
+ return false;
}
*r_pair = pe;
@@ -923,17 +816,17 @@ static PBool p_edge_has_pair(PHandle *handle, PEdge *e, PBool topology_from_uvs,
if ((*r_pair)->next->pair || (*r_pair)->next->next->pair) {
/* non unfoldable, maybe mobius ring or klein bottle */
*r_pair = NULL;
- return P_FALSE;
+ return false;
}
}
return (*r_pair != NULL);
}
-static PBool p_edge_connect_pair(PHandle *handle,
- PEdge *e,
- PBool topology_from_uvs,
- PEdge ***stack)
+static bool p_edge_connect_pair(ParamHandle *handle,
+ PEdge *e,
+ bool topology_from_uvs,
+ PEdge ***stack)
{
PEdge *pair = NULL;
@@ -954,7 +847,7 @@ static PBool p_edge_connect_pair(PHandle *handle,
return (e->pair != NULL);
}
-static int p_connect_pairs(PHandle *handle, PBool topology_from_uvs)
+static int p_connect_pairs(ParamHandle *handle, bool topology_from_uvs)
{
PEdge **stackbase = MEM_mallocN(sizeof(*stackbase) * phash_size(handle->hash_faces),
"Pstackbase");
@@ -1008,7 +901,7 @@ static void p_split_vert(PChart *chart, PEdge *e)
{
PEdge *we, *lastwe = NULL;
PVert *v = e->vert;
- PBool copy = P_TRUE;
+ bool copy = true;
if (e->flag & PEDGE_PIN) {
chart->flag |= PCHART_HAS_PINS;
@@ -1034,7 +927,7 @@ static void p_split_vert(PChart *chart, PEdge *e)
if (we == v->edge) {
/* found it, no need to copy */
- copy = P_FALSE;
+ copy = false;
v->nextlink = chart->verts;
chart->verts = v;
chart->nverts++;
@@ -1061,7 +954,7 @@ static void p_split_vert(PChart *chart, PEdge *e)
}
}
-static PChart **p_split_charts(PHandle *handle, PChart *chart, int ncharts)
+static PChart **p_split_charts(ParamHandle *handle, PChart *chart, int ncharts)
{
PChart **charts = MEM_mallocN(sizeof(*charts) * ncharts, "PCharts"), *nchart;
PFace *f, *nextf;
@@ -1100,7 +993,7 @@ static PChart **p_split_charts(PHandle *handle, PChart *chart, int ncharts)
return charts;
}
-static PFace *p_face_add(PHandle *handle)
+static PFace *p_face_add(ParamHandle *handle)
{
PFace *f;
PEdge *e1, *e2, *e3;
@@ -1132,16 +1025,16 @@ static PFace *p_face_add(PHandle *handle)
return f;
}
-static PFace *p_face_add_construct(PHandle *handle,
+static PFace *p_face_add_construct(ParamHandle *handle,
ParamKey key,
const ParamKey *vkeys,
- float *co[4],
- float *uv[4],
+ const float **co,
+ float **uv,
int i1,
int i2,
int i3,
- const ParamBool *pin,
- const ParamBool *select)
+ const bool *pin,
+ const bool *select)
{
PFace *f = p_face_add(handle);
PEdge *e1 = f->edge, *e2 = e1->next, *e3 = e2->next;
@@ -1178,7 +1071,6 @@ static PFace *p_face_add_construct(PHandle *handle,
}
}
- /* insert into hash */
f->u.key = key;
phash_insert(handle->hash_faces, (PHashLink *)f);
@@ -1219,14 +1111,14 @@ static PFace *p_face_add_fill(PChart *chart, PVert *v1, PVert *v2, PVert *v3)
return f;
}
-static PBool p_quad_split_direction(PHandle *handle, float **co, PHashKey *vkeys)
+static bool p_quad_split_direction(ParamHandle *handle, const float **co, const ParamKey *vkeys)
{
/* Slight bias to prefer one edge over the other in case they are equal, so
* that in symmetric models we choose the same split direction instead of
* depending on floating point errors to decide. */
float bias = 1.0f + 1e-6f;
float fac = len_v3v3(co[0], co[2]) * bias - len_v3v3(co[1], co[3]);
- PBool dir = (fac <= 0.0f);
+ bool dir = (fac <= 0.0f);
/* The face exists check is there because of a special case:
* when two quads share three vertices, they can each be split into two triangles,
@@ -1565,22 +1457,22 @@ static float p_vert_cotan(const float v1[3], const float v2[3], const float v3[3
return dot_v3v3(a, b) / clen;
}
-static PBool p_vert_flipped_wheel_triangle(PVert *v)
+static bool p_vert_flipped_wheel_triangle(PVert *v)
{
PEdge *e = v->edge;
do {
if (p_face_uv_area_signed(e->face) < 0.0f) {
- return P_TRUE;
+ return true;
}
e = p_wheel_edge_next(e);
} while (e && (e != v->edge));
- return P_FALSE;
+ return false;
}
-static PBool p_vert_map_harmonic_weights(PVert *v)
+static bool p_vert_map_harmonic_weights(PVert *v)
{
float weightsum, positionsum[2], olduv[2];
@@ -1646,10 +1538,10 @@ static PBool p_vert_map_harmonic_weights(PVert *v)
v->uv[0] = olduv[0];
v->uv[1] = olduv[1];
- return P_FALSE;
+ return false;
}
- return P_TRUE;
+ return true;
}
static void p_vert_harmonic_insert(PVert *v)
@@ -1882,7 +1774,7 @@ static void p_split_vertex(PEdge *edge, PEdge *pair)
} while (e && (e != newv->edge));
}
-static PBool p_collapse_allowed_topologic(PEdge *edge, PEdge *pair)
+static bool p_collapse_allowed_topologic(PEdge *edge, PEdge *pair)
{
PVert *oldv, *keepv;
@@ -1892,22 +1784,22 @@ static PBool p_collapse_allowed_topologic(PEdge *edge, PEdge *pair)
if (!edge || !pair) {
/* avoid collapsing chart into an edge */
if (edge && !edge->next->pair && !edge->next->next->pair) {
- return P_FALSE;
+ return false;
}
else if (pair && !pair->next->pair && !pair->next->next->pair) {
- return P_FALSE;
+ return false;
}
}
/* avoid merging two boundaries (oldv and keepv are on the 'other side' of
* the chart) */
else if (!p_vert_interior(oldv) && !p_vert_interior(keepv)) {
- return P_FALSE;
+ return false;
}
- return P_TRUE;
+ return true;
}
-static PBool p_collapse_normal_flipped(float *v1, float *v2, float *vold, float *vnew)
+static bool p_collapse_normal_flipped(float *v1, float *v2, float *vold, float *vnew)
{
float nold[3], nnew[3], sub1[3], sub2[3];
@@ -1922,7 +1814,7 @@ static PBool p_collapse_normal_flipped(float *v1, float *v2, float *vold, float
return (dot_v3v3(nold, nnew) <= 0.0f);
}
-static PBool p_collapse_allowed_geometric(PEdge *edge, PEdge *pair)
+static bool p_collapse_allowed_geometric(PEdge *edge, PEdge *pair)
{
PVert *oldv, *keepv;
PEdge *e;
@@ -1949,7 +1841,7 @@ static PBool p_collapse_allowed_geometric(PEdge *edge, PEdge *pair)
}
if (p_collapse_normal_flipped(v1->co, v2->co, oldv->co, keepv->co)) {
- return P_FALSE;
+ return false;
}
a[0] = angle;
@@ -1966,10 +1858,10 @@ static PBool p_collapse_allowed_geometric(PEdge *edge, PEdge *pair)
for (i = 0; i < 3; i++) {
if ((b[i] < a[i]) && (b[i] < minangle)) {
- return P_FALSE;
+ return false;
}
else if ((b[i] > a[i]) && (b[i] > maxangle)) {
- return P_FALSE;
+ return false;
}
}
@@ -1979,7 +1871,7 @@ static PBool p_collapse_allowed_geometric(PEdge *edge, PEdge *pair)
if (p_vert_interior(oldv)) {
/* HLSCM criterion: angular defect smaller than threshold. */
if (fabsf(angulardefect) > (float)(M_PI * 30.0 / 180.0)) {
- return P_FALSE;
+ return false;
}
}
else {
@@ -1988,27 +1880,27 @@ static PBool p_collapse_allowed_geometric(PEdge *edge, PEdge *pair)
/* ABF++ criterion 2: avoid collapsing verts inwards. */
if (p_vert_interior(keepv)) {
- return P_FALSE;
+ return false;
}
/* Don't collapse significant boundary changes. */
angle = p_vec_angle(v1->co, oldv->co, v2->co);
if (angle < (M_PI * 160.0 / 180.0)) {
- return P_FALSE;
+ return false;
}
}
- return P_TRUE;
+ return true;
}
-static PBool p_collapse_allowed(PEdge *edge, PEdge *pair)
+static bool p_collapse_allowed(PEdge *edge, PEdge *pair)
{
PVert *oldv, *keepv;
p_collapsing_verts(edge, pair, &oldv, &keepv);
if (oldv->flag & PVERT_PIN) {
- return P_FALSE;
+ return false;
}
return (p_collapse_allowed_topologic(edge, pair) && p_collapse_allowed_geometric(edge, pair));
@@ -2571,21 +2463,17 @@ static float p_abf_compute_gradient(PAbfSystem *sys, PChart *chart)
return norm;
}
-static PBool p_abf_matrix_invert(PAbfSystem *sys, PChart *chart)
+static bool p_abf_matrix_invert(PAbfSystem *sys, PChart *chart)
{
- PFace *f;
- PEdge *e;
- int i, j, ninterior = sys->ninterior, nvar = 2 * sys->ninterior;
- PBool success;
- LinearSolver *context;
-
- context = EIG_linear_solver_new(0, nvar, 1);
+ int ninterior = sys->ninterior;
+ int nvar = 2 * ninterior;
+ LinearSolver *context = EIG_linear_solver_new(0, nvar, 1);
- for (i = 0; i < nvar; i++) {
+ for (int i = 0; i < nvar; i++) {
EIG_linear_solver_right_hand_side_add(context, 0, i, sys->bInterior[i]);
}
- for (f = chart->faces; f; f = f->nextlink) {
+ for (PFace *f = chart->faces; f; f = f->nextlink) {
float wi1, wi2, wi3, b, si, beta[3], j2[3][3], W[3][3];
float row1[6], row2[6], row3[6];
int vid[6];
@@ -2690,14 +2578,14 @@ static PBool p_abf_matrix_invert(PAbfSystem *sys, PChart *chart)
row3[5] = j2[0][2] * W[2][0] + j2[1][2] * W[2][1];
}
- for (i = 0; i < 3; i++) {
+ for (int i = 0; i < 3; i++) {
int r = vid[i];
if (r == -1) {
continue;
}
- for (j = 0; j < 6; j++) {
+ for (int j = 0; j < 6; j++) {
int c = vid[j];
if (c == -1) {
@@ -2728,10 +2616,10 @@ static PBool p_abf_matrix_invert(PAbfSystem *sys, PChart *chart)
}
}
- success = EIG_linear_solver_solve(context);
+ bool success = EIG_linear_solver_solve(context);
if (success) {
- for (f = chart->faces; f; f = f->nextlink) {
+ for (PFace *f = chart->faces; f; f = f->nextlink) {
float dlambda1, pre[3], dalpha;
PEdge *e1 = f->edge, *e2 = e1->next, *e3 = e2->next;
PVert *v1 = e1->vert, *v2 = e2->vert, *v3 = e3->vert;
@@ -2777,7 +2665,7 @@ static PBool p_abf_matrix_invert(PAbfSystem *sys, PChart *chart)
sys->alpha[e3->u.id] += dalpha / sys->weight[e3->u.id] - pre[2];
/* clamp */
- e = f->edge;
+ PEdge *e = f->edge;
do {
if (sys->alpha[e->u.id] > (float)M_PI) {
sys->alpha[e->u.id] = (float)M_PI;
@@ -2788,7 +2676,7 @@ static PBool p_abf_matrix_invert(PAbfSystem *sys, PChart *chart)
} while (e != f->edge);
}
- for (i = 0; i < ninterior; i++) {
+ for (int i = 0; i < ninterior; i++) {
sys->lambdaPlanar[i] += (float)EIG_linear_solver_variable_get(context, 0, i);
sys->lambdaLength[i] += (float)EIG_linear_solver_variable_get(context, 0, ninterior + i);
}
@@ -2799,7 +2687,7 @@ static PBool p_abf_matrix_invert(PAbfSystem *sys, PChart *chart)
return success;
}
-static PBool p_chart_abf_solve(PChart *chart)
+static bool p_chart_abf_solve(PChart *chart)
{
PVert *v;
PFace *f;
@@ -2910,7 +2798,7 @@ static PBool p_chart_abf_solve(PChart *chart)
if (!p_abf_matrix_invert(&sys, chart)) {
param_warning("ABF failed to invert matrix");
p_abf_free_system(&sys);
- return P_FALSE;
+ return false;
}
p_abf_compute_sines(&sys);
@@ -2919,14 +2807,14 @@ static PBool p_chart_abf_solve(PChart *chart)
if (i == ABF_MAX_ITER) {
param_warning("ABF maximum iterations reached");
p_abf_free_system(&sys);
- return P_FALSE;
+ return false;
}
}
chart->u.lscm.abf_alpha = MEM_dupallocN(sys.alpha);
p_abf_free_system(&sys);
- return P_TRUE;
+ return true;
}
/* Least Squares Conformal Maps */
@@ -2982,7 +2870,7 @@ static void p_chart_pin_positions(PChart *chart, PVert **pin1, PVert **pin2)
}
}
-static PBool p_chart_symmetry_pins(PChart *chart, PEdge *outer, PVert **pin1, PVert **pin2)
+static bool p_chart_symmetry_pins(PChart *chart, PEdge *outer, PVert **pin1, PVert **pin2)
{
PEdge *be, *lastbe = NULL, *maxe1 = NULL, *maxe2 = NULL, *be1, *be2;
PEdge *cure = NULL, *firste1 = NULL, *firste2 = NULL, *nextbe;
@@ -3043,7 +2931,7 @@ static PBool p_chart_symmetry_pins(PChart *chart, PEdge *outer, PVert **pin1, PV
}
if (!maxe1 || !maxe2 || (maxlen < 0.5f * totlen)) {
- return P_FALSE;
+ return false;
}
/* find pin1 in the split vertices */
@@ -3143,10 +3031,10 @@ static void p_chart_lscm_load_solution(PChart *chart)
}
}
-static void p_chart_lscm_begin(PChart *chart, PBool live, PBool abf)
+static void p_chart_lscm_begin(PChart *chart, bool live, bool abf)
{
PVert *v, *pin1, *pin2;
- PBool select = P_FALSE, deselect = P_FALSE;
+ bool select = false, deselect = false;
int npins = 0, id = 0;
/* give vertices matrix indices and count pins */
@@ -3154,12 +3042,12 @@ static void p_chart_lscm_begin(PChart *chart, PBool live, PBool abf)
if (v->flag & PVERT_PIN) {
npins++;
if (v->flag & PVERT_SELECT) {
- select = P_TRUE;
+ select = true;
}
}
if (!(v->flag & PVERT_SELECT)) {
- deselect = P_TRUE;
+ deselect = true;
}
}
@@ -3212,7 +3100,7 @@ static void p_chart_lscm_begin(PChart *chart, PBool live, PBool abf)
}
}
-static PBool p_chart_lscm_solve(PHandle *handle, PChart *chart)
+static bool p_chart_lscm_solve(ParamHandle *handle, PChart *chart)
{
LinearSolver *context = chart->u.lscm.context;
PVert *v, *pin1 = chart->u.lscm.pin1, *pin2 = chart->u.lscm.pin2;
@@ -3349,7 +3237,7 @@ static PBool p_chart_lscm_solve(PHandle *handle, PChart *chart)
if (EIG_linear_solver_solve(context)) {
p_chart_lscm_load_solution(chart);
- return P_TRUE;
+ return true;
}
for (v = chart->verts; v; v = v->nextlink) {
@@ -3357,7 +3245,7 @@ static PBool p_chart_lscm_solve(PHandle *handle, PChart *chart)
v->uv[1] = 0.0f;
}
- return P_FALSE;
+ return false;
}
static void p_chart_lscm_transform_single_pin(PChart *chart)
@@ -3569,7 +3457,7 @@ static int p_compare_geometric_uv(const void *a, const void *b)
return 1;
}
-static PBool p_chart_convex_hull(PChart *chart, PVert ***r_verts, int *r_nverts, int *r_right)
+static bool p_chart_convex_hull(PChart *chart, PVert ***r_verts, int *r_nverts, int *r_right)
{
/* Graham algorithm, taken from:
* http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/117225 */
@@ -3581,7 +3469,7 @@ static PBool p_chart_convex_hull(PChart *chart, PVert ***r_verts, int *r_nverts,
p_chart_boundaries(chart, NULL, &be);
if (!be) {
- return P_FALSE;
+ return false;
}
e = be;
@@ -3635,7 +3523,7 @@ static PBool p_chart_convex_hull(PChart *chart, PVert ***r_verts, int *r_nverts,
MEM_freeN(U);
MEM_freeN(L);
- return P_TRUE;
+ return true;
}
static float p_rectangle_area(float *p1, float *dir, float *p2, float *p3, float *p4)
@@ -3818,550 +3706,11 @@ static void p_chart_rotate_fit_aabb(PChart *chart)
}
}
-/* Area Smoothing */
-
-/* 2d BSP tree for inverse mapping - that's a bit silly. */
-
-typedef struct SmoothTriangle {
- float co1[2], co2[2], co3[2];
- float oco1[2], oco2[2], oco3[2];
-} SmoothTriangle;
-
-typedef struct SmoothNode {
- struct SmoothNode *c1, *c2;
- SmoothTriangle **tri;
- float split;
- int axis, ntri;
-} SmoothNode;
-
-static void p_barycentric_2d(
- const float v1[2], const float v2[2], const float v3[2], const float p[2], float b[3])
-{
- float a[2], c[2], h[2], div;
-
- a[0] = v2[0] - v1[0];
- a[1] = v2[1] - v1[1];
- c[0] = v3[0] - v1[0];
- c[1] = v3[1] - v1[1];
-
- div = a[0] * c[1] - a[1] * c[0];
-
- if (div == 0.0f) {
- b[0] = 1.0f / 3.0f;
- b[1] = 1.0f / 3.0f;
- b[2] = 1.0f / 3.0f;
- }
- else {
- h[0] = p[0] - v1[0];
- h[1] = p[1] - v1[1];
-
- div = 1.0f / div;
-
- b[1] = (h[0] * c[1] - h[1] * c[0]) * div;
- b[2] = (a[0] * h[1] - a[1] * h[0]) * div;
- b[0] = 1.0f - b[1] - b[2];
- }
-}
-
-static PBool p_triangle_inside(SmoothTriangle *t, float co[2])
-{
- float b[3];
-
- p_barycentric_2d(t->co1, t->co2, t->co3, co, b);
-
- if ((b[0] >= 0.0f) && (b[1] >= 0.0f) && (b[2] >= 0.0f)) {
- co[0] = t->oco1[0] * b[0] + t->oco2[0] * b[1] + t->oco3[0] * b[2];
- co[1] = t->oco1[1] * b[0] + t->oco2[1] * b[1] + t->oco3[1] * b[2];
- return P_TRUE;
- }
-
- return P_FALSE;
-}
-
-static SmoothNode *p_node_new(
- MemArena *arena, SmoothTriangle **tri, int ntri, float *bmin, float *bmax, int depth)
-{
- SmoothNode *node = BLI_memarena_alloc(arena, sizeof(*node));
- int axis, i, t1size = 0, t2size = 0;
- float split, /* mi, */ /* UNUSED */ mx;
- SmoothTriangle **t1, **t2, *t;
-
- node->tri = tri;
- node->ntri = ntri;
-
- if (ntri <= 10 || depth >= 15) {
- return node;
- }
-
- t1 = MEM_mallocN(sizeof(*t1) * ntri, "PNodeTri1");
- t2 = MEM_mallocN(sizeof(*t2) * ntri, "PNodeTri1");
-
- axis = (bmax[0] - bmin[0] > bmax[1] - bmin[1]) ? 0 : 1;
- split = 0.5f * (bmin[axis] + bmax[axis]);
-
- for (i = 0; i < ntri; i++) {
- t = tri[i];
-
- if ((t->co1[axis] <= split) || (t->co2[axis] <= split) || (t->co3[axis] <= split)) {
- t1[t1size] = t;
- t1size++;
- }
- if ((t->co1[axis] >= split) || (t->co2[axis] >= split) || (t->co3[axis] >= split)) {
- t2[t2size] = t;
- t2size++;
- }
- }
-
- if ((t1size == t2size) && (t1size == ntri)) {
- MEM_freeN(t1);
- MEM_freeN(t2);
- return node;
- }
-
- node->tri = NULL;
- node->ntri = 0;
- MEM_freeN(tri);
-
- node->axis = axis;
- node->split = split;
-
- /* mi = bmin[axis]; */ /* UNUSED */
- mx = bmax[axis];
- bmax[axis] = split;
- node->c1 = p_node_new(arena, t1, t1size, bmin, bmax, depth + 1);
-
- bmin[axis] = bmax[axis];
- bmax[axis] = mx;
- node->c2 = p_node_new(arena, t2, t2size, bmin, bmax, depth + 1);
-
- return node;
-}
-
-static void p_node_delete(SmoothNode *node)
-{
- if (node->c1) {
- p_node_delete(node->c1);
- }
- if (node->c2) {
- p_node_delete(node->c2);
- }
- if (node->tri) {
- MEM_freeN(node->tri);
- }
-}
-
-static PBool p_node_intersect(SmoothNode *node, float co[2])
-{
- int i;
-
- if (node->tri) {
- for (i = 0; i < node->ntri; i++) {
- if (p_triangle_inside(node->tri[i], co)) {
- return P_TRUE;
- }
- }
-
- return P_FALSE;
- }
-
- if (co[node->axis] < node->split) {
- return p_node_intersect(node->c1, co);
- }
- return p_node_intersect(node->c2, co);
-}
-
-/* smoothing */
-
-static int p_compare_float(const void *a_, const void *b_)
-{
- const float a = *(const float *)a_;
- const float b = *(const float *)b_;
-
- if (a < b) {
- return -1;
- }
- if (a == b) {
- return 0;
- }
- return 1;
-}
-
-static float p_smooth_median_edge_length(PChart *chart)
-{
- PEdge *e;
- float *lengths = MEM_mallocN(sizeof(chart->edges) * chart->nedges, "PMedianLength");
- float median;
- int i;
-
- /* ok, so I'm lazy */
- for (i = 0, e = chart->edges; e; e = e->nextlink, i++) {
- lengths[i] = p_edge_length(e);
- }
-
- qsort(lengths, i, sizeof(float), p_compare_float);
-
- median = lengths[i / 2];
- MEM_freeN(lengths);
-
- return median;
-}
-
-static float p_smooth_distortion(PEdge *e, float avg2d, float avg3d)
-{
- float len2d = p_edge_uv_length(e) * avg3d;
- float len3d = p_edge_length(e) * avg2d;
-
- return (len3d == 0.0f) ? 0.0f : len2d / len3d;
-}
-
-static void p_smooth(PChart *chart)
-{
- PEdge *e;
- PVert *v;
- PFace *f;
- int j, it2, maxiter2, it;
- int nedges = chart->nedges, nwheel, gridx, gridy;
- int edgesx, edgesy, nsize, esize, i, x, y, maxiter;
- float minv[2], maxv[2], median, invmedian, avglen2d, avglen3d;
- float center[2], dx, dy, *nodes, dlimit, d, *oldnodesx, *oldnodesy;
- float *nodesx, *nodesy, *hedges, *vedges, climit, moved, padding;
- SmoothTriangle *triangles, *t, *t2, **tri, **trip;
- SmoothNode *root;
- MemArena *arena;
-
- if (nedges == 0) {
- return;
- }
-
- p_chart_uv_bbox(chart, minv, maxv);
- median = p_smooth_median_edge_length(chart) * 0.10f;
-
- if (median == 0.0f) {
- return;
- }
-
- invmedian = 1.0f / median;
-
- /* compute edge distortion */
- avglen2d = avglen3d = 0.0;
-
- for (e = chart->edges; e; e = e->nextlink) {
- avglen2d += p_edge_uv_length(e);
- avglen3d += p_edge_length(e);
- }
-
- avglen2d /= nedges;
- avglen3d /= nedges;
-
- for (v = chart->verts; v; v = v->nextlink) {
- v->u.distortion = 0.0;
- nwheel = 0;
-
- e = v->edge;
- do {
- v->u.distortion += p_smooth_distortion(e, avglen2d, avglen3d);
- nwheel++;
-
- e = e->next->next->pair;
- } while (e && (e != v->edge));
-
- v->u.distortion /= nwheel;
- }
-
- /* need to do excessive grid size checking still */
- center[0] = 0.5f * (minv[0] + maxv[0]);
- center[1] = 0.5f * (minv[1] + maxv[1]);
-
- dx = 0.5f * (maxv[0] - minv[0]);
- dy = 0.5f * (maxv[1] - minv[1]);
-
- padding = 0.15f;
- dx += padding * dx + 2.0f * median;
- dy += padding * dy + 2.0f * median;
-
- gridx = (int)(dx * invmedian);
- gridy = (int)(dy * invmedian);
-
- minv[0] = center[0] - median * gridx;
- minv[1] = center[1] - median * gridy;
- maxv[0] = center[0] + median * gridx;
- maxv[1] = center[1] + median * gridy;
-
- /* create grid */
- gridx = gridx * 2 + 1;
- gridy = gridy * 2 + 1;
-
- if ((gridx <= 2) || (gridy <= 2)) {
- return;
- }
-
- edgesx = gridx - 1;
- edgesy = gridy - 1;
- nsize = gridx * gridy;
- esize = edgesx * edgesy;
-
- nodes = MEM_mallocN(sizeof(float) * nsize, "PSmoothNodes");
- nodesx = MEM_mallocN(sizeof(float) * nsize, "PSmoothNodesX");
- nodesy = MEM_mallocN(sizeof(float) * nsize, "PSmoothNodesY");
- oldnodesx = MEM_mallocN(sizeof(float) * nsize, "PSmoothOldNodesX");
- oldnodesy = MEM_mallocN(sizeof(float) * nsize, "PSmoothOldNodesY");
- hedges = MEM_mallocN(sizeof(float) * esize, "PSmoothHEdges");
- vedges = MEM_mallocN(sizeof(float) * esize, "PSmoothVEdges");
-
- if (!nodes || !nodesx || !nodesy || !oldnodesx || !oldnodesy || !hedges || !vedges) {
- if (nodes) {
- MEM_freeN(nodes);
- }
- if (nodesx) {
- MEM_freeN(nodesx);
- }
- if (nodesy) {
- MEM_freeN(nodesy);
- }
- if (oldnodesx) {
- MEM_freeN(oldnodesx);
- }
- if (oldnodesy) {
- MEM_freeN(oldnodesy);
- }
- if (hedges) {
- MEM_freeN(hedges);
- }
- if (vedges) {
- MEM_freeN(vedges);
- }
-
- // printf("Not enough memory for area smoothing grid");
- return;
- }
-
- for (x = 0; x < gridx; x++) {
- for (y = 0; y < gridy; y++) {
- i = x + y * gridx;
-
- nodesx[i] = minv[0] + median * x;
- nodesy[i] = minv[1] + median * y;
-
- nodes[i] = 1.0f;
- }
- }
-
- /* embed in grid */
- for (f = chart->faces; f; f = f->nextlink) {
- PEdge *e1 = f->edge, *e2 = e1->next, *e3 = e2->next;
- float fmin[2], fmax[2];
- int bx1, by1, bx2, by2;
-
- INIT_MINMAX2(fmin, fmax);
-
- minmax_v2v2_v2(fmin, fmax, e1->vert->uv);
- minmax_v2v2_v2(fmin, fmax, e2->vert->uv);
- minmax_v2v2_v2(fmin, fmax, e3->vert->uv);
-
- bx1 = (int)((fmin[0] - minv[0]) * invmedian);
- by1 = (int)((fmin[1] - minv[1]) * invmedian);
- bx2 = (int)((fmax[0] - minv[0]) * invmedian + 2);
- by2 = (int)((fmax[1] - minv[1]) * invmedian + 2);
-
- for (x = bx1; x < bx2; x++) {
- for (y = by1; y < by2; y++) {
- float p[2], b[3];
-
- i = x + y * gridx;
-
- p[0] = nodesx[i];
- p[1] = nodesy[i];
-
- p_barycentric_2d(e1->vert->uv, e2->vert->uv, e3->vert->uv, p, b);
-
- if ((b[0] > 0.0f) && (b[1] > 0.0f) && (b[2] > 0.0f)) {
- nodes[i] = e1->vert->u.distortion * b[0];
- nodes[i] += e2->vert->u.distortion * b[1];
- nodes[i] += e3->vert->u.distortion * b[2];
- }
- }
- }
- }
-
- /* smooth the grid */
- maxiter = 10;
- climit = 0.00001f * nsize;
-
- for (it = 0; it < maxiter; it++) {
- moved = 0.0f;
-
- for (x = 0; x < edgesx; x++) {
- for (y = 0; y < edgesy; y++) {
- i = x + y * gridx;
- j = x + y * edgesx;
-
- hedges[j] = (nodes[i] + nodes[i + 1]) * 0.5f;
- vedges[j] = (nodes[i] + nodes[i + gridx]) * 0.5f;
-
- /* we do *inverse* mapping */
- hedges[j] = 1.0f / hedges[j];
- vedges[j] = 1.0f / vedges[j];
- }
- }
-
- maxiter2 = 50;
- dlimit = 0.0001f;
-
- for (it2 = 0; it2 < maxiter2; it2++) {
- d = 0.0f;
-
- memcpy(oldnodesx, nodesx, sizeof(float) * nsize);
- memcpy(oldnodesy, nodesy, sizeof(float) * nsize);
-
- for (x = 1; x < gridx - 1; x++) {
- for (y = 1; y < gridy - 1; y++) {
- float p[2], oldp[2], sum1, sum2, diff[2], length;
-
- i = x + gridx * y;
- j = x + edgesx * y;
-
- oldp[0] = oldnodesx[i];
- oldp[1] = oldnodesy[i];
-
- sum1 = hedges[j - 1] * oldnodesx[i - 1];
- sum1 += hedges[j] * oldnodesx[i + 1];
- sum1 += vedges[j - edgesx] * oldnodesx[i - gridx];
- sum1 += vedges[j] * oldnodesx[i + gridx];
-
- sum2 = hedges[j - 1];
- sum2 += hedges[j];
- sum2 += vedges[j - edgesx];
- sum2 += vedges[j];
-
- nodesx[i] = sum1 / sum2;
-
- sum1 = hedges[j - 1] * oldnodesy[i - 1];
- sum1 += hedges[j] * oldnodesy[i + 1];
- sum1 += vedges[j - edgesx] * oldnodesy[i - gridx];
- sum1 += vedges[j] * oldnodesy[i + gridx];
-
- nodesy[i] = sum1 / sum2;
-
- p[0] = nodesx[i];
- p[1] = nodesy[i];
-
- diff[0] = p[0] - oldp[0];
- diff[1] = p[1] - oldp[1];
-
- length = len_v2(diff);
- d = max_ff(d, length);
- moved += length;
- }
- }
-
- if (d < dlimit) {
- break;
- }
- }
-
- if (moved < climit) {
- break;
- }
- }
-
- MEM_freeN(oldnodesx);
- MEM_freeN(oldnodesy);
- MEM_freeN(hedges);
- MEM_freeN(vedges);
-
- /* Create BSP. */
- t = triangles = MEM_mallocN(sizeof(SmoothTriangle) * esize * 2, "PSmoothTris");
- trip = tri = MEM_mallocN(sizeof(SmoothTriangle *) * esize * 2, "PSmoothTriP");
-
- if (!triangles || !tri) {
- MEM_freeN(nodes);
- MEM_freeN(nodesx);
- MEM_freeN(nodesy);
-
- if (triangles) {
- MEM_freeN(triangles);
- }
- if (tri) {
- MEM_freeN(tri);
- }
-
- // printf("Not enough memory for area smoothing grid");
- return;
- }
-
- for (x = 0; x < edgesx; x++) {
- for (y = 0; y < edgesy; y++) {
- i = x + y * gridx;
-
- t->co1[0] = nodesx[i];
- t->co1[1] = nodesy[i];
-
- t->co2[0] = nodesx[i + 1];
- t->co2[1] = nodesy[i + 1];
-
- t->co3[0] = nodesx[i + gridx];
- t->co3[1] = nodesy[i + gridx];
-
- t->oco1[0] = minv[0] + x * median;
- t->oco1[1] = minv[1] + y * median;
-
- t->oco2[0] = minv[0] + (x + 1) * median;
- t->oco2[1] = minv[1] + y * median;
-
- t->oco3[0] = minv[0] + x * median;
- t->oco3[1] = minv[1] + (y + 1) * median;
-
- t2 = t + 1;
-
- t2->co1[0] = nodesx[i + gridx + 1];
- t2->co1[1] = nodesy[i + gridx + 1];
-
- t2->oco1[0] = minv[0] + (x + 1) * median;
- t2->oco1[1] = minv[1] + (y + 1) * median;
-
- t2->co2[0] = t->co2[0];
- t2->co2[1] = t->co2[1];
- t2->oco2[0] = t->oco2[0];
- t2->oco2[1] = t->oco2[1];
-
- t2->co3[0] = t->co3[0];
- t2->co3[1] = t->co3[1];
- t2->oco3[0] = t->oco3[0];
- t2->oco3[1] = t->oco3[1];
-
- *trip = t;
- trip++;
- t++;
- *trip = t;
- trip++;
- t++;
- }
- }
-
- MEM_freeN(nodes);
- MEM_freeN(nodesx);
- MEM_freeN(nodesy);
-
- arena = BLI_memarena_new(MEM_SIZE_OPTIMAL(1 << 16), "param smooth arena");
- root = p_node_new(arena, tri, esize * 2, minv, maxv, 0);
-
- for (v = chart->verts; v; v = v->nextlink) {
- if (!p_node_intersect(root, v->uv)) {
- param_warning("area smoothing error: couldn't find mapping triangle\n");
- }
- }
-
- p_node_delete(root);
- BLI_memarena_free(arena);
-
- MEM_freeN(triangles);
-}
-
/* Exported */
ParamHandle *GEO_uv_parametrizer_construct_begin(void)
{
- PHandle *handle = MEM_callocN(sizeof(*handle), "PHandle");
+ ParamHandle *handle = MEM_callocN(sizeof(*handle), "ParamHandle");
handle->construction_chart = p_chart_new(handle);
handle->state = PHANDLE_STATE_ALLOCATED;
handle->arena = BLI_memarena_new(MEM_SIZE_OPTIMAL(1 << 16), "param construct arena");
@@ -4375,21 +3724,18 @@ ParamHandle *GEO_uv_parametrizer_construct_begin(void)
handle->hash_edges = phash_new((PHashLink **)&handle->construction_chart->edges, 1);
handle->hash_faces = phash_new((PHashLink **)&handle->construction_chart->faces, 1);
- return (ParamHandle *)handle;
+ return handle;
}
-void GEO_uv_parametrizer_aspect_ratio(ParamHandle *handle, float aspx, float aspy)
+void GEO_uv_parametrizer_aspect_ratio(ParamHandle *phandle, float aspx, float aspy)
{
- PHandle *phandle = (PHandle *)handle;
-
phandle->aspx = aspx;
phandle->aspy = aspy;
phandle->do_aspect = true;
}
-void GEO_uv_parametrizer_delete(ParamHandle *handle)
+void GEO_uv_parametrizer_delete(ParamHandle *phandle)
{
- PHandle *phandle = (PHandle *)handle;
int i;
param_assert(ELEM(phandle->state, PHANDLE_STATE_ALLOCATED, PHANDLE_STATE_CONSTRUCTED));
@@ -4398,8 +3744,11 @@ void GEO_uv_parametrizer_delete(ParamHandle *handle)
p_chart_delete(phandle->charts[i]);
}
- if (phandle->charts) {
- MEM_freeN(phandle->charts);
+ MEM_SAFE_FREE(phandle->charts);
+
+ if (phandle->pin_hash) {
+ BLI_ghash_free(phandle->pin_hash, NULL, NULL);
+ phandle->pin_hash = NULL;
}
if (phandle->construction_chart) {
@@ -4416,19 +3765,92 @@ void GEO_uv_parametrizer_delete(ParamHandle *handle)
MEM_freeN(phandle);
}
+typedef struct GeoUVPinIndex {
+ struct GeoUVPinIndex *next;
+ float uv[2];
+ ParamKey reindex;
+} GeoUVPinIndex;
+
+/* Find a (mostly) unique ParamKey given a BMVert index and UV co-ordinates.
+ * For each unique pinned UVs, return a unique ParamKey, starting with
+ * a very large number, and decreasing steadily from there.
+ * For non-pinned UVs which share a BMVert with a pinned UV,
+ * return the index corresponding to the closest pinned UV.
+ * For everything else, just return the BMVert index.
+ * Note that ParamKeys will eventually be hashed, so they don't need to be contiguous.
+ */
+ParamKey GEO_uv_find_pin_index(ParamHandle *handle, const int bmvertindex, const float uv[2])
+{
+ if (!handle->pin_hash) {
+ return bmvertindex; /* No verts pinned. */
+ }
+
+ GeoUVPinIndex *pinuvlist = BLI_ghash_lookup(handle->pin_hash, POINTER_FROM_INT(bmvertindex));
+ if (!pinuvlist) {
+ return bmvertindex; /* Vert not pinned. */
+ }
+
+ /* At least one of the UVs associated with bmvertindex is pinned. Find the best one. */
+ float bestdistsquared = len_squared_v2v2(pinuvlist->uv, uv);
+ ParamKey bestkey = pinuvlist->reindex;
+ pinuvlist = pinuvlist->next;
+ while (pinuvlist) {
+ const float distsquared = len_squared_v2v2(pinuvlist->uv, uv);
+ if (bestdistsquared > distsquared) {
+ bestdistsquared = distsquared;
+ bestkey = pinuvlist->reindex;
+ }
+ pinuvlist = pinuvlist->next;
+ }
+ return bestkey;
+}
+
+static GeoUVPinIndex *new_geo_uv_pinindex(ParamHandle *handle, const float uv[2])
+{
+ GeoUVPinIndex *pinuv = BLI_memarena_alloc(handle->arena, sizeof(*pinuv));
+ pinuv->next = NULL;
+ copy_v2_v2(pinuv->uv, uv);
+ pinuv->reindex = PARAM_KEY_MAX - (handle->unique_pin_count++);
+ return pinuv;
+}
+
+void GEO_uv_prepare_pin_index(ParamHandle *handle, const int bmvertindex, const float uv[2])
+{
+ if (!handle->pin_hash) {
+ handle->pin_hash = BLI_ghash_int_new("uv pin reindex");
+ }
+
+ GeoUVPinIndex *pinuvlist = BLI_ghash_lookup(handle->pin_hash, POINTER_FROM_INT(bmvertindex));
+ if (!pinuvlist) {
+ BLI_ghash_insert(
+ handle->pin_hash, POINTER_FROM_INT(bmvertindex), new_geo_uv_pinindex(handle, uv));
+ return;
+ }
+
+ while (true) {
+ if (equals_v2v2(pinuvlist->uv, uv)) {
+ return;
+ }
+ if (!pinuvlist->next) {
+ pinuvlist->next = new_geo_uv_pinindex(handle, uv);
+ return;
+ }
+ pinuvlist = pinuvlist->next;
+ }
+}
+
static void p_add_ngon(ParamHandle *handle,
- ParamKey key,
- int nverts,
- ParamKey *vkeys,
- float **co,
- float **uv,
- ParamBool *pin,
- ParamBool *select)
+ const ParamKey key,
+ const int nverts,
+ const ParamKey *vkeys,
+ const float **co,
+ float **uv, /* Output will eventually be written to `uv`. */
+ const bool *pin,
+ const bool *select)
{
/* Allocate memory for polyfill. */
- PHandle *phandle = (PHandle *)handle;
- MemArena *arena = phandle->polyfill_arena;
- Heap *heap = phandle->polyfill_heap;
+ MemArena *arena = handle->polyfill_arena;
+ Heap *heap = handle->polyfill_heap;
uint nfilltri = nverts - 2;
uint(*tris)[3] = BLI_memarena_alloc(arena, sizeof(*tris) * (size_t)nfilltri);
float(*projverts)[2] = BLI_memarena_alloc(arena, sizeof(*projverts) * (size_t)nverts);
@@ -4466,11 +3888,11 @@ static void p_add_ngon(ParamHandle *handle,
uint v1 = tri[1];
uint v2 = tri[2];
- ParamKey tri_vkeys[3] = {vkeys[v0], vkeys[v1], vkeys[v2]};
- float *tri_co[3] = {co[v0], co[v1], co[v2]};
+ const ParamKey tri_vkeys[3] = {vkeys[v0], vkeys[v1], vkeys[v2]};
+ const float *tri_co[3] = {co[v0], co[v1], co[v2]};
float *tri_uv[3] = {uv[v0], uv[v1], uv[v2]};
- ParamBool tri_pin[3] = {pin[v0], pin[v1], pin[v2]};
- ParamBool tri_select[3] = {select[v0], select[v1], select[v2]};
+ bool tri_pin[3] = {pin[v0], pin[v1], pin[v2]};
+ bool tri_select[3] = {select[v0], select[v1], select[v2]};
GEO_uv_parametrizer_face_add(handle, key, 3, tri_vkeys, tri_co, tri_uv, tri_pin, tri_select);
}
@@ -4478,24 +3900,22 @@ static void p_add_ngon(ParamHandle *handle,
BLI_memarena_clear(arena);
}
-void GEO_uv_parametrizer_face_add(ParamHandle *handle,
- ParamKey key,
- int nverts,
- ParamKey *vkeys,
- float *co[4],
- float *uv[4],
- ParamBool *pin,
- ParamBool *select)
+void GEO_uv_parametrizer_face_add(ParamHandle *phandle,
+ const ParamKey key,
+ const int nverts,
+ const ParamKey *vkeys,
+ const float **co,
+ float **uv,
+ const bool *pin,
+ const bool *select)
{
- PHandle *phandle = (PHandle *)handle;
-
param_assert(phash_lookup(phandle->hash_faces, key) == NULL);
param_assert(phandle->state == PHANDLE_STATE_ALLOCATED);
param_assert(ELEM(nverts, 3, 4));
if (nverts > 4) {
/* ngon */
- p_add_ngon(handle, key, nverts, vkeys, co, uv, pin, select);
+ p_add_ngon(phandle, key, nverts, vkeys, co, uv, pin, select);
}
else if (nverts == 4) {
/* quad */
@@ -4514,9 +3934,8 @@ void GEO_uv_parametrizer_face_add(ParamHandle *handle,
}
}
-void GEO_uv_parametrizer_edge_set_seam(ParamHandle *handle, ParamKey *vkeys)
+void GEO_uv_parametrizer_edge_set_seam(ParamHandle *phandle, ParamKey *vkeys)
{
- PHandle *phandle = (PHandle *)handle;
PEdge *e;
param_assert(phandle->state == PHANDLE_STATE_ALLOCATED);
@@ -4527,19 +3946,18 @@ void GEO_uv_parametrizer_edge_set_seam(ParamHandle *handle, ParamKey *vkeys)
}
}
-void GEO_uv_parametrizer_construct_end(ParamHandle *handle,
- ParamBool fill,
- ParamBool topology_from_uvs,
+void GEO_uv_parametrizer_construct_end(ParamHandle *phandle,
+ bool fill,
+ bool topology_from_uvs,
int *count_fail)
{
- PHandle *phandle = (PHandle *)handle;
PChart *chart = phandle->construction_chart;
int i, j, nboundaries = 0;
PEdge *outer;
param_assert(phandle->state == PHANDLE_STATE_ALLOCATED);
- phandle->ncharts = p_connect_pairs(phandle, (PBool)topology_from_uvs);
+ phandle->ncharts = p_connect_pairs(phandle, topology_from_uvs);
phandle->charts = p_split_charts(phandle, chart, phandle->ncharts);
p_chart_delete(phandle->construction_chart);
@@ -4572,7 +3990,7 @@ void GEO_uv_parametrizer_construct_end(ParamHandle *handle,
}
for (v = chart->verts; v; v = v->nextlink) {
- p_vert_load_pin_select_uvs(handle, v);
+ p_vert_load_pin_select_uvs(phandle, v);
}
}
@@ -4581,9 +3999,8 @@ void GEO_uv_parametrizer_construct_end(ParamHandle *handle,
phandle->state = PHANDLE_STATE_CONSTRUCTED;
}
-void GEO_uv_parametrizer_lscm_begin(ParamHandle *handle, ParamBool live, ParamBool abf)
+void GEO_uv_parametrizer_lscm_begin(ParamHandle *phandle, bool live, bool abf)
{
- PHandle *phandle = (PHandle *)handle;
PFace *f;
int i;
@@ -4594,13 +4011,12 @@ void GEO_uv_parametrizer_lscm_begin(ParamHandle *handle, ParamBool live, ParamBo
for (f = phandle->charts[i]->faces; f; f = f->nextlink) {
p_face_backup_uvs(f);
}
- p_chart_lscm_begin(phandle->charts[i], (PBool)live, (PBool)abf);
+ p_chart_lscm_begin(phandle->charts[i], live, abf);
}
}
-void GEO_uv_parametrizer_lscm_solve(ParamHandle *handle, int *count_changed, int *count_failed)
+void GEO_uv_parametrizer_lscm_solve(ParamHandle *phandle, int *count_changed, int *count_failed)
{
- PHandle *phandle = (PHandle *)handle;
PChart *chart;
int i;
@@ -4610,7 +4026,7 @@ void GEO_uv_parametrizer_lscm_solve(ParamHandle *handle, int *count_changed, int
chart = phandle->charts[i];
if (chart->u.lscm.context) {
- const PBool result = p_chart_lscm_solve(phandle, chart);
+ const bool result = p_chart_lscm_solve(phandle, chart);
if (result && !(chart->flag & PCHART_HAS_PINS)) {
p_chart_rotate_minimum_area(chart);
@@ -4638,9 +4054,8 @@ void GEO_uv_parametrizer_lscm_solve(ParamHandle *handle, int *count_changed, int
}
}
-void GEO_uv_parametrizer_lscm_end(ParamHandle *handle)
+void GEO_uv_parametrizer_lscm_end(ParamHandle *phandle)
{
- PHandle *phandle = (PHandle *)handle;
int i;
param_assert(phandle->state == PHANDLE_STATE_LSCM);
@@ -4655,9 +4070,8 @@ void GEO_uv_parametrizer_lscm_end(ParamHandle *handle)
phandle->state = PHANDLE_STATE_CONSTRUCTED;
}
-void GEO_uv_parametrizer_stretch_begin(ParamHandle *handle)
+void GEO_uv_parametrizer_stretch_begin(ParamHandle *phandle)
{
- PHandle *phandle = (PHandle *)handle;
PChart *chart;
PVert *v;
PFace *f;
@@ -4685,17 +4099,14 @@ void GEO_uv_parametrizer_stretch_begin(ParamHandle *handle)
}
}
-void GEO_uv_parametrizer_stretch_blend(ParamHandle *handle, float blend)
+void GEO_uv_parametrizer_stretch_blend(ParamHandle *phandle, float blend)
{
- PHandle *phandle = (PHandle *)handle;
-
param_assert(phandle->state == PHANDLE_STATE_STRETCH);
phandle->blend = blend;
}
-void GEO_uv_parametrizer_stretch_iter(ParamHandle *handle)
+void GEO_uv_parametrizer_stretch_iter(ParamHandle *phandle)
{
- PHandle *phandle = (PHandle *)handle;
PChart *chart;
int i;
@@ -4707,10 +4118,8 @@ void GEO_uv_parametrizer_stretch_iter(ParamHandle *handle)
}
}
-void GEO_uv_parametrizer_stretch_end(ParamHandle *handle)
+void GEO_uv_parametrizer_stretch_end(ParamHandle *phandle)
{
- PHandle *phandle = (PHandle *)handle;
-
param_assert(phandle->state == PHANDLE_STATE_STRETCH);
phandle->state = PHANDLE_STATE_CONSTRUCTED;
@@ -4718,33 +4127,12 @@ void GEO_uv_parametrizer_stretch_end(ParamHandle *handle)
phandle->rng = NULL;
}
-void GEO_uv_parametrizer_smooth_area(ParamHandle *handle)
-{
- PHandle *phandle = (PHandle *)handle;
- int i;
-
- param_assert(phandle->state == PHANDLE_STATE_CONSTRUCTED);
-
- for (i = 0; i < phandle->ncharts; i++) {
- PChart *chart = phandle->charts[i];
- PVert *v;
-
- for (v = chart->verts; v; v = v->nextlink) {
- v->flag &= ~PVERT_PIN;
- }
-
- p_smooth(chart);
- }
-}
-
/* don't pack, just rotate (used for better packing) */
-static void GEO_uv_parametrizer_pack_rotate(ParamHandle *handle, bool ignore_pinned)
+static void GEO_uv_parametrizer_pack_rotate(ParamHandle *phandle, bool ignore_pinned)
{
PChart *chart;
int i;
- PHandle *phandle = (PHandle *)handle;
-
for (i = 0; i < phandle->ncharts; i++) {
chart = phandle->charts[i];
@@ -4770,9 +4158,7 @@ void GEO_uv_parametrizer_pack(ParamHandle *handle,
float trans[2];
double area = 0.0;
- PHandle *phandle = (PHandle *)handle;
-
- if (phandle->ncharts == 0) {
+ if (handle->ncharts == 0) {
return;
}
@@ -4781,15 +4167,15 @@ void GEO_uv_parametrizer_pack(ParamHandle *handle,
GEO_uv_parametrizer_pack_rotate(handle, ignore_pinned);
}
- if (phandle->aspx != phandle->aspy) {
- GEO_uv_parametrizer_scale(handle, 1.0f / phandle->aspx, 1.0f / phandle->aspy);
+ if (handle->aspx != handle->aspy) {
+ GEO_uv_parametrizer_scale(handle, 1.0f / handle->aspx, 1.0f / handle->aspy);
}
/* we may not use all these boxes */
- boxarray = MEM_mallocN(phandle->ncharts * sizeof(BoxPack), "BoxPack box");
+ boxarray = MEM_mallocN(handle->ncharts * sizeof(BoxPack), "BoxPack box");
- for (i = 0; i < phandle->ncharts; i++) {
- chart = phandle->charts[i];
+ for (i = 0; i < handle->ncharts; i++) {
+ chart = handle->charts[i];
if (ignore_pinned && (chart->flag & PCHART_HAS_PINS)) {
unpacked++;
@@ -4821,8 +4207,8 @@ void GEO_uv_parametrizer_pack(ParamHandle *handle,
* 0.0 to 1.0 but not give a massive margin */
margin = (margin * (float)area) * 0.1f;
unpacked = 0;
- for (i = 0; i < phandle->ncharts; i++) {
- chart = phandle->charts[i];
+ for (i = 0; i < handle->ncharts; i++) {
+ chart = handle->charts[i];
if (ignore_pinned && (chart->flag & PCHART_HAS_PINS)) {
unpacked++;
@@ -4838,7 +4224,7 @@ void GEO_uv_parametrizer_pack(ParamHandle *handle,
}
}
- BLI_box_pack_2d(boxarray, phandle->ncharts - unpacked, &tot_width, &tot_height);
+ BLI_box_pack_2d(boxarray, handle->ncharts - unpacked, &tot_width, &tot_height);
if (tot_height > tot_width) {
scale = tot_height != 0.0f ? (1.0f / tot_height) : 1.0f;
@@ -4847,30 +4233,29 @@ void GEO_uv_parametrizer_pack(ParamHandle *handle,
scale = tot_width != 0.0f ? (1.0f / tot_width) : 1.0f;
}
- for (i = 0; i < phandle->ncharts - unpacked; i++) {
+ for (i = 0; i < handle->ncharts - unpacked; i++) {
box = boxarray + i;
trans[0] = box->x;
trans[1] = box->y;
- chart = phandle->charts[box->index];
+ chart = handle->charts[box->index];
p_chart_uv_translate(chart, trans);
p_chart_uv_scale(chart, scale);
}
MEM_freeN(boxarray);
- if (phandle->aspx != phandle->aspy) {
- GEO_uv_parametrizer_scale(handle, phandle->aspx, phandle->aspy);
+ if (handle->aspx != handle->aspy) {
+ GEO_uv_parametrizer_scale(handle, handle->aspx, handle->aspy);
}
}
-void GEO_uv_parametrizer_average(ParamHandle *handle, bool ignore_pinned)
+void GEO_uv_parametrizer_average(ParamHandle *phandle, bool ignore_pinned)
{
PChart *chart;
int i;
float tot_uvarea = 0.0f, tot_facearea = 0.0f;
float tot_fac, fac;
float minv[2], maxv[2], trans[2];
- PHandle *phandle = (PHandle *)handle;
if (phandle->ncharts == 0) {
return;
@@ -4930,9 +4315,8 @@ void GEO_uv_parametrizer_average(ParamHandle *handle, bool ignore_pinned)
}
}
-void GEO_uv_parametrizer_scale(ParamHandle *handle, float x, float y)
+void GEO_uv_parametrizer_scale(ParamHandle *phandle, float x, float y)
{
- PHandle *phandle = (PHandle *)handle;
PChart *chart;
int i;
@@ -4942,9 +4326,8 @@ void GEO_uv_parametrizer_scale(ParamHandle *handle, float x, float y)
}
}
-void GEO_uv_parametrizer_flush(ParamHandle *handle)
+void GEO_uv_parametrizer_flush(ParamHandle *phandle)
{
- PHandle *phandle = (PHandle *)handle;
PChart *chart;
int i;
@@ -4964,9 +4347,8 @@ void GEO_uv_parametrizer_flush(ParamHandle *handle)
}
}
-void GEO_uv_parametrizer_flush_restore(ParamHandle *handle)
+void GEO_uv_parametrizer_flush_restore(ParamHandle *phandle)
{
- PHandle *phandle = (PHandle *)handle;
PChart *chart;
PFace *f;
int i;
diff --git a/source/blender/gpencil_modifiers/CMakeLists.txt b/source/blender/gpencil_modifiers/CMakeLists.txt
index f87c85f808f..69fc26c99e9 100644
--- a/source/blender/gpencil_modifiers/CMakeLists.txt
+++ b/source/blender/gpencil_modifiers/CMakeLists.txt
@@ -72,7 +72,6 @@ set(SRC
intern/lineart/MOD_lineart.h
intern/lineart/lineart_intern.h
-
)
if(WITH_TBB)
diff --git a/source/blender/gpencil_modifiers/intern/MOD_gpencil_util.c b/source/blender/gpencil_modifiers/intern/MOD_gpencil_util.c
index 6cf7f6f11e5..d59d2cb52fc 100644
--- a/source/blender/gpencil_modifiers/intern/MOD_gpencil_util.c
+++ b/source/blender/gpencil_modifiers/intern/MOD_gpencil_util.c
@@ -7,7 +7,7 @@
#include <stdio.h>
-#include "BLI_blenlib.h"
+#include "BLI_listbase.h"
#include "BLI_math_vector.h"
#include "BLI_utildefines.h"
diff --git a/source/blender/gpencil_modifiers/intern/MOD_gpencil_util.h b/source/blender/gpencil_modifiers/intern/MOD_gpencil_util.h
index e7301b4d910..73423d9a8ee 100644
--- a/source/blender/gpencil_modifiers/intern/MOD_gpencil_util.h
+++ b/source/blender/gpencil_modifiers/intern/MOD_gpencil_util.h
@@ -49,5 +49,5 @@ typedef void (*gpBakeCb)(struct GpencilModifierData *md_,
void generic_bake_deform_stroke(struct Depsgraph *depsgraph,
struct GpencilModifierData *md,
struct Object *ob,
- const bool retime,
+ bool retime,
gpBakeCb bake_cb);
diff --git a/source/blender/gpencil_modifiers/intern/MOD_gpencilarmature.c b/source/blender/gpencil_modifiers/intern/MOD_gpencilarmature.c
index f5ecce69129..092253dde79 100644
--- a/source/blender/gpencil_modifiers/intern/MOD_gpencilarmature.c
+++ b/source/blender/gpencil_modifiers/intern/MOD_gpencilarmature.c
@@ -8,10 +8,9 @@
#include <stdio.h>
#include "BLI_listbase.h"
+#include "BLI_math_vector.h"
#include "BLI_utildefines.h"
-#include "BLI_math.h"
-
#include "BLT_translation.h"
#include "DNA_defaults.h"
diff --git a/source/blender/gpencil_modifiers/intern/MOD_gpencilarray.c b/source/blender/gpencil_modifiers/intern/MOD_gpencilarray.c
index 38866bcd32a..407055c6165 100644
--- a/source/blender/gpencil_modifiers/intern/MOD_gpencilarray.c
+++ b/source/blender/gpencil_modifiers/intern/MOD_gpencilarray.c
@@ -9,14 +9,11 @@
#include "MEM_guardedalloc.h"
-#include "BLI_utildefines.h"
-
#include "BLI_hash.h"
+#include "BLI_listbase.h"
+#include "BLI_math_vector.h"
#include "BLI_rand.h"
-
-#include "BLI_blenlib.h"
-#include "BLI_math.h"
-#include "BLI_rand.h"
+#include "BLI_utildefines.h"
#include "BLT_translation.h"
diff --git a/source/blender/gpencil_modifiers/intern/MOD_gpencilbuild.c b/source/blender/gpencil_modifiers/intern/MOD_gpencilbuild.c
index 930ebb78b46..cf390e8d3a0 100644
--- a/source/blender/gpencil_modifiers/intern/MOD_gpencilbuild.c
+++ b/source/blender/gpencil_modifiers/intern/MOD_gpencilbuild.c
@@ -7,14 +7,15 @@
#include <stdio.h>
#include <stdlib.h>
+#include <string.h>
#include "MEM_guardedalloc.h"
-#include "BLI_utildefines.h"
-
-#include "BLI_blenlib.h"
-#include "BLI_math.h"
+#include "BLI_listbase.h"
+#include "BLI_math_base.h"
+#include "BLI_math_vector.h"
#include "BLI_sort.h"
+#include "BLI_utildefines.h"
#include "BLT_translation.h"
@@ -109,7 +110,7 @@ static void reduce_stroke_points(bGPdata *gpd,
const int points_num,
const eBuildGpencil_Transition transition)
{
- if (points_num == 0) {
+ if ((points_num == 0) || (gps->points == NULL)) {
clear_stroke(gpf, gps);
return;
}
diff --git a/source/blender/gpencil_modifiers/intern/MOD_gpencilcolor.c b/source/blender/gpencil_modifiers/intern/MOD_gpencilcolor.c
index 792def30812..8ada66cfd55 100644
--- a/source/blender/gpencil_modifiers/intern/MOD_gpencilcolor.c
+++ b/source/blender/gpencil_modifiers/intern/MOD_gpencilcolor.c
@@ -9,7 +9,6 @@
#include "BLI_utildefines.h"
-#include "BLI_blenlib.h"
#include "BLI_math_color.h"
#include "BLI_math_vector.h"
diff --git a/source/blender/gpencil_modifiers/intern/MOD_gpencildash.c b/source/blender/gpencil_modifiers/intern/MOD_gpencildash.c
index e57b9df03f5..41015c429fe 100644
--- a/source/blender/gpencil_modifiers/intern/MOD_gpencildash.c
+++ b/source/blender/gpencil_modifiers/intern/MOD_gpencildash.c
@@ -9,11 +9,9 @@
#include <string.h>
#include "BLI_listbase.h"
-#include "BLI_math.h"
+#include "BLI_math_vector.h"
#include "BLI_string.h"
-#include "BLT_translation.h"
-
#include "DNA_defaults.h"
#include "DNA_gpencil_modifier_types.h"
#include "DNA_gpencil_types.h"
diff --git a/source/blender/gpencil_modifiers/intern/MOD_gpencilenvelope.c b/source/blender/gpencil_modifiers/intern/MOD_gpencilenvelope.c
index e5604005240..0f1652a5620 100644
--- a/source/blender/gpencil_modifiers/intern/MOD_gpencilenvelope.c
+++ b/source/blender/gpencil_modifiers/intern/MOD_gpencilenvelope.c
@@ -8,8 +8,8 @@
#include <stdio.h>
#include "BLI_listbase.h"
-#include "BLI_math.h"
#include "BLI_math_geom.h"
+#include "BLI_math_vector.h"
#include "BLI_utildefines.h"
#include "BLT_translation.h"
@@ -22,7 +22,6 @@
#include "DNA_scene_types.h"
#include "DNA_screen_types.h"
-#include "BKE_colortools.h"
#include "BKE_context.h"
#include "BKE_deform.h"
#include "BKE_gpencil.h"
diff --git a/source/blender/gpencil_modifiers/intern/MOD_gpencilhook.c b/source/blender/gpencil_modifiers/intern/MOD_gpencilhook.c
index bc0464cb4f9..652894af017 100644
--- a/source/blender/gpencil_modifiers/intern/MOD_gpencilhook.c
+++ b/source/blender/gpencil_modifiers/intern/MOD_gpencilhook.c
@@ -6,12 +6,14 @@
*/
#include <stdio.h>
+#include <string.h>
#include "BLI_listbase.h"
+#include "BLI_math_base.h"
+#include "BLI_math_matrix.h"
+#include "BLI_math_vector.h"
#include "BLI_utildefines.h"
-#include "BLI_math.h"
-
#include "BLT_translation.h"
#include "DNA_defaults.h"
diff --git a/source/blender/gpencil_modifiers/intern/MOD_gpencillength.c b/source/blender/gpencil_modifiers/intern/MOD_gpencillength.c
index c92c062348c..5a358f5b3a1 100644
--- a/source/blender/gpencil_modifiers/intern/MOD_gpencillength.c
+++ b/source/blender/gpencil_modifiers/intern/MOD_gpencillength.c
@@ -6,10 +6,11 @@
*/
#include <stdio.h>
+#include <string.h>
#include "BLI_hash.h"
#include "BLI_listbase.h"
-#include "BLI_math.h"
+#include "BLI_math_base.h"
#include "BLI_rand.h"
#include "BLI_utildefines.h"
diff --git a/source/blender/gpencil_modifiers/intern/MOD_gpencillineart.c b/source/blender/gpencil_modifiers/intern/MOD_gpencillineart.c
index 0e7df2a136d..8d77fb50c71 100644
--- a/source/blender/gpencil_modifiers/intern/MOD_gpencillineart.c
+++ b/source/blender/gpencil_modifiers/intern/MOD_gpencillineart.c
@@ -7,9 +7,8 @@
#include <stdio.h>
-#include "BLI_utildefines.h"
-
#include "BLI_math_vector.h"
+#include "BLI_utildefines.h"
#include "BLT_translation.h"
@@ -22,9 +21,6 @@
#include "DNA_scene_types.h"
#include "DNA_screen_types.h"
-#include "MOD_gpencil_lineart.h"
-#include "lineart/MOD_lineart.h"
-
#include "BKE_collection.h"
#include "BKE_context.h"
#include "BKE_global.h"
@@ -43,8 +39,10 @@
#include "DEG_depsgraph.h"
#include "DEG_depsgraph_query.h"
+#include "MOD_gpencil_lineart.h"
#include "MOD_gpencil_modifiertypes.h"
#include "MOD_gpencil_ui_common.h"
+#include "lineart/MOD_lineart.h"
#include "WM_api.h"
#include "WM_types.h"
@@ -218,9 +216,18 @@ static void add_this_collection(Collection *c,
if (!c) {
return;
}
+ bool default_add = true;
+ /* Do not do nested collection usage check, this is consistent with lineart calculation, because
+ * collection usage doesn't have a INHERIT mode. This might initially be derived from the fact
+ * that an object can be inside multiple collections, but might be irrelevant now with the way
+ * objects are iterated. Keep this logic for now. */
+ if (c->lineart_usage & COLLECTION_LRT_EXCLUDE) {
+ default_add = false;
+ }
FOREACH_COLLECTION_VISIBLE_OBJECT_RECURSIVE_BEGIN (c, ob, mode) {
if (ELEM(ob->type, OB_MESH, OB_MBALL, OB_CURVES_LEGACY, OB_SURF, OB_FONT)) {
- if (ob->lineart.usage != OBJECT_LRT_EXCLUDE) {
+ if ((ob->lineart.usage == OBJECT_LRT_INHERIT && default_add) ||
+ ob->lineart.usage != OBJECT_LRT_EXCLUDE) {
DEG_add_object_relation(ctx->node, ob, DEG_OB_COMP_GEOMETRY, "Line Art Modifier");
DEG_add_object_relation(ctx->node, ob, DEG_OB_COMP_TRANSFORM, "Line Art Modifier");
}
@@ -239,15 +246,11 @@ static void updateDepsgraph(GpencilModifierData *md,
DEG_add_object_relation(ctx->node, ctx->object, DEG_OB_COMP_TRANSFORM, "Line Art Modifier");
LineartGpencilModifierData *lmd = (LineartGpencilModifierData *)md;
- if (lmd->source_type == LRT_SOURCE_OBJECT && lmd->source_object) {
- DEG_add_object_relation(
- ctx->node, lmd->source_object, DEG_OB_COMP_GEOMETRY, "Line Art Modifier");
- DEG_add_object_relation(
- ctx->node, lmd->source_object, DEG_OB_COMP_TRANSFORM, "Line Art Modifier");
- }
- else {
- add_this_collection(ctx->scene->master_collection, ctx, mode);
- }
+
+ /* Always add whole master collection because line art will need the whole scene for
+ * visibility computation. Line art exclusion is handled inside #add_this_collection. */
+ add_this_collection(ctx->scene->master_collection, ctx, mode);
+
if (lmd->calculation_flags & LRT_USE_CUSTOM_CAMERA && lmd->source_camera) {
DEG_add_object_relation(
ctx->node, lmd->source_camera, DEG_OB_COMP_TRANSFORM, "Line Art Modifier");
@@ -321,6 +324,10 @@ static void panel_draw(const bContext *UNUSED(C), Panel *panel)
uiItemPointerR(
row, ptr, "target_material", &obj_data_ptr, "materials", NULL, ICON_SHADING_TEXTURE);
+ uiLayout *col = uiLayoutColumn(layout, false);
+ uiItemR(col, ptr, "thickness", UI_ITEM_R_SLIDER, IFACE_("Line Thickness"), ICON_NONE);
+ uiItemR(col, ptr, "opacity", UI_ITEM_R_SLIDER, NULL, ICON_NONE);
+
gpencil_modifier_panel_end(layout, ptr);
}
@@ -349,7 +356,7 @@ static void edge_types_panel_draw(const bContext *UNUSED(C), Panel *panel)
uiLayout *sub = uiLayoutRowWithHeading(col, false, IFACE_("Crease"));
uiItemR(sub, ptr, "use_crease", 0, "", ICON_NONE);
uiLayout *entry = uiLayoutRow(sub, false);
- uiLayoutSetEnabled(entry, RNA_boolean_get(ptr, "use_crease") || is_first);
+ uiLayoutSetActive(entry, RNA_boolean_get(ptr, "use_crease") || is_first);
if (use_cache && !is_first) {
uiItemL(entry, IFACE_("Angle Cached"), ICON_INFO);
}
@@ -395,21 +402,6 @@ static void options_panel_draw(const bContext *UNUSED(C), Panel *panel)
uiItemR(col, ptr, "use_back_face_culling", 0, IFACE_("Force Backface Culling"), ICON_NONE);
}
-static void style_panel_draw(const bContext *UNUSED(C), Panel *panel)
-{
- uiLayout *layout = panel->layout;
- PointerRNA *ptr = gpencil_modifier_panel_get_property_pointers(panel, NULL);
-
- const bool is_baked = RNA_boolean_get(ptr, "is_baked");
-
- uiLayoutSetPropSep(layout, true);
- uiLayoutSetEnabled(layout, !is_baked);
-
- uiItemR(layout, ptr, "thickness", UI_ITEM_R_SLIDER, NULL, ICON_NONE);
-
- uiItemR(layout, ptr, "opacity", UI_ITEM_R_SLIDER, NULL, ICON_NONE);
-}
-
static void occlusion_panel_draw(const bContext *UNUSED(C), Panel *panel)
{
uiLayout *layout = panel->layout;
@@ -521,6 +513,7 @@ static void intersection_panel_draw(const bContext *UNUSED(C), Panel *panel)
uiItemR(layout, ptr, "use_intersection_match", 0, IFACE_("Exact Match"), ICON_NONE);
}
+
static void face_mark_panel_draw_header(const bContext *UNUSED(C), Panel *panel)
{
uiLayout *layout = panel->layout;
@@ -704,8 +697,6 @@ static void panelRegister(ARegionType *region_type)
region_type, "edge_types", "Edge Types", NULL, edge_types_panel_draw, panel_type);
gpencil_modifier_subpanel_register(
region_type, "geometry", "Geometry Processing", NULL, options_panel_draw, panel_type);
- gpencil_modifier_subpanel_register(
- region_type, "style", "Style", NULL, style_panel_draw, panel_type);
PanelType *occlusion_panel = gpencil_modifier_subpanel_register(
region_type, "occlusion", "Occlusion", NULL, occlusion_panel_draw, panel_type);
gpencil_modifier_subpanel_register(region_type,
diff --git a/source/blender/gpencil_modifiers/intern/MOD_gpencilmirror.c b/source/blender/gpencil_modifiers/intern/MOD_gpencilmirror.c
index 6460a69a6cc..df66251159c 100644
--- a/source/blender/gpencil_modifiers/intern/MOD_gpencilmirror.c
+++ b/source/blender/gpencil_modifiers/intern/MOD_gpencilmirror.c
@@ -10,7 +10,7 @@
#include "BLI_utildefines.h"
#include "BLI_listbase.h"
-#include "BLI_math.h"
+#include "BLI_math_vector.h"
#include "BLT_translation.h"
diff --git a/source/blender/gpencil_modifiers/intern/MOD_gpencilmultiply.c b/source/blender/gpencil_modifiers/intern/MOD_gpencilmultiply.c
index d80e32feb2e..fd4eb5da835 100644
--- a/source/blender/gpencil_modifiers/intern/MOD_gpencilmultiply.c
+++ b/source/blender/gpencil_modifiers/intern/MOD_gpencilmultiply.c
@@ -16,8 +16,8 @@
#include "DNA_scene_types.h"
#include "DNA_screen_types.h"
-#include "BLI_blenlib.h"
-#include "BLI_math.h"
+#include "BLI_listbase.h"
+#include "BLI_math_vector.h"
#include "BLI_utildefines.h"
#include "BKE_context.h"
diff --git a/source/blender/gpencil_modifiers/intern/MOD_gpencilnoise.c b/source/blender/gpencil_modifiers/intern/MOD_gpencilnoise.c
index 259e62a249c..253603aea67 100644
--- a/source/blender/gpencil_modifiers/intern/MOD_gpencilnoise.c
+++ b/source/blender/gpencil_modifiers/intern/MOD_gpencilnoise.c
@@ -7,11 +7,10 @@
#include <stdio.h>
-#include "BLI_listbase.h"
-#include "BLI_utildefines.h"
-
#include "BLI_hash.h"
+#include "BLI_listbase.h"
#include "BLI_math_vector.h"
+#include "BLI_utildefines.h"
#include "BLT_translation.h"
diff --git a/source/blender/gpencil_modifiers/intern/MOD_gpenciloffset.c b/source/blender/gpencil_modifiers/intern/MOD_gpenciloffset.c
index f201a147082..ba88c83161f 100644
--- a/source/blender/gpencil_modifiers/intern/MOD_gpenciloffset.c
+++ b/source/blender/gpencil_modifiers/intern/MOD_gpenciloffset.c
@@ -7,15 +7,14 @@
#include <stdio.h>
+#include "BLI_hash.h"
#include "BLI_listbase.h"
+#include "BLI_math.h"
+#include "BLI_rand.h"
#include "BLI_utildefines.h"
#include "BLT_translation.h"
-#include "BLI_hash.h"
-#include "BLI_math.h"
-#include "BLI_rand.h"
-
#include "DNA_defaults.h"
#include "DNA_gpencil_modifier_types.h"
#include "DNA_gpencil_types.h"
diff --git a/source/blender/gpencil_modifiers/intern/MOD_gpencilopacity.c b/source/blender/gpencil_modifiers/intern/MOD_gpencilopacity.c
index b964b143a0f..0bcbd71f029 100644
--- a/source/blender/gpencil_modifiers/intern/MOD_gpencilopacity.c
+++ b/source/blender/gpencil_modifiers/intern/MOD_gpencilopacity.c
@@ -6,12 +6,10 @@
*/
#include <stdio.h>
+#include <string.h>
#include "BLI_utildefines.h"
-#include "BLI_blenlib.h"
-#include "BLI_math_vector.h"
-
#include "BLT_translation.h"
#include "DNA_defaults.h"
diff --git a/source/blender/gpencil_modifiers/intern/MOD_gpencilshrinkwrap.c b/source/blender/gpencil_modifiers/intern/MOD_gpencilshrinkwrap.c
index 7de1cc89a45..cd2373dcb26 100644
--- a/source/blender/gpencil_modifiers/intern/MOD_gpencilshrinkwrap.c
+++ b/source/blender/gpencil_modifiers/intern/MOD_gpencilshrinkwrap.c
@@ -9,7 +9,7 @@
#include <string.h> /* For #MEMCPY_STRUCT_AFTER. */
#include "BLI_listbase.h"
-#include "BLI_math.h"
+#include "BLI_math_vector.h"
#include "BLI_utildefines.h"
#include "BLT_translation.h"
@@ -18,7 +18,6 @@
#include "DNA_gpencil_modifier_types.h"
#include "DNA_gpencil_types.h"
#include "DNA_mesh_types.h"
-#include "DNA_meshdata_types.h"
#include "DNA_object_types.h"
#include "DNA_scene_types.h"
#include "DNA_screen_types.h"
diff --git a/source/blender/gpencil_modifiers/intern/MOD_gpencilsimplify.c b/source/blender/gpencil_modifiers/intern/MOD_gpencilsimplify.c
index e7dfdfee8d2..07350b73ce3 100644
--- a/source/blender/gpencil_modifiers/intern/MOD_gpencilsimplify.c
+++ b/source/blender/gpencil_modifiers/intern/MOD_gpencilsimplify.c
@@ -16,7 +16,6 @@
#include "DNA_gpencil_types.h"
#include "DNA_object_types.h"
#include "DNA_screen_types.h"
-#include "DNA_vec_types.h"
#include "BKE_context.h"
#include "BKE_gpencil_geom.h"
diff --git a/source/blender/gpencil_modifiers/intern/MOD_gpenciltexture.c b/source/blender/gpencil_modifiers/intern/MOD_gpenciltexture.c
index 5c8c65b9f97..6ba7a934bff 100644
--- a/source/blender/gpencil_modifiers/intern/MOD_gpenciltexture.c
+++ b/source/blender/gpencil_modifiers/intern/MOD_gpenciltexture.c
@@ -8,7 +8,7 @@
#include <stdio.h>
#include "BLI_listbase.h"
-#include "BLI_math.h"
+#include "BLI_math_vector.h"
#include "BLI_utildefines.h"
#include "BLT_translation.h"
diff --git a/source/blender/gpencil_modifiers/intern/MOD_gpencilthick.c b/source/blender/gpencil_modifiers/intern/MOD_gpencilthick.c
index 3ddb508d58a..68fe15df898 100644
--- a/source/blender/gpencil_modifiers/intern/MOD_gpencilthick.c
+++ b/source/blender/gpencil_modifiers/intern/MOD_gpencilthick.c
@@ -8,7 +8,7 @@
#include <stdio.h>
#include "BLI_listbase.h"
-#include "BLI_math.h"
+#include "BLI_math_vector.h"
#include "BLI_utildefines.h"
#include "DNA_defaults.h"
diff --git a/source/blender/gpencil_modifiers/intern/MOD_gpenciltime.c b/source/blender/gpencil_modifiers/intern/MOD_gpenciltime.c
index bf2e9a86817..414231fcae5 100644
--- a/source/blender/gpencil_modifiers/intern/MOD_gpenciltime.c
+++ b/source/blender/gpencil_modifiers/intern/MOD_gpenciltime.c
@@ -58,18 +58,19 @@ static int remapTime(struct GpencilModifierData *md,
const bool invpass = mmd->flag & GP_TIME_INVERT_LAYERPASS;
int sfra = custom ? mmd->sfra : scene->r.sfra;
int efra = custom ? mmd->efra : scene->r.efra;
+ int offset = mmd->offset;
+ int nfra = 0;
CLAMP_MIN(sfra, 0);
CLAMP_MIN(efra, 0);
+ if (offset < 0) {
+ offset = abs(efra - sfra + offset + 1);
+ }
/* Avoid inverse ranges. */
- if (efra < sfra) {
+ if (efra <= sfra) {
return cfra;
}
- const int time_range = efra - sfra + 1;
- int offset = mmd->offset;
- int segments = 0;
-
/* omit if filter by layer */
if (mmd->layername[0] != '\0') {
if (invgpl == false) {
@@ -97,60 +98,55 @@ static int remapTime(struct GpencilModifierData *md,
}
}
- /* if fix mode, return predefined frame number */
- if (mmd->mode == GP_TIME_MODE_FIX) {
- return offset;
- }
-
- /* invert current frame number */
- if (mmd->mode == GP_TIME_MODE_REVERSE) {
- cfra = efra - cfra + sfra;
- }
-
/* apply frame scale */
cfra *= mmd->frame_scale;
- /* verify offset never is greater than frame range */
- if (abs(offset) > time_range) {
- offset = offset - ((offset / time_range) * time_range);
+ /* if fix mode, return predefined frame number */
+ if (mmd->mode == GP_TIME_MODE_FIX) {
+ return offset;
}
- /* verify not outside range if loop is disabled */
- if ((mmd->flag & GP_TIME_KEEP_LOOP) == 0) {
- if (cfra + offset < sfra) {
- return sfra;
+ if (mmd->mode == GP_TIME_MODE_NORMAL) {
+ if ((mmd->flag & GP_TIME_KEEP_LOOP) == 0) {
+ nfra = cfra + sfra + offset - 1 < efra ? cfra + sfra + offset - 1 : efra;
}
- if (cfra + offset > efra) {
- return efra;
+ else {
+ nfra = (offset + cfra - 1) % (efra - sfra + 1) + sfra;
}
}
-
- /* check frames before start */
- if (cfra < sfra) {
- segments = ((cfra + sfra) / time_range);
- cfra = cfra + (segments * time_range);
- }
-
- /* check frames after end */
- if (cfra > efra) {
- segments = ((cfra - sfra) / time_range);
- cfra = cfra - (segments * time_range);
+ if (mmd->mode == GP_TIME_MODE_REVERSE) {
+ if ((mmd->flag & GP_TIME_KEEP_LOOP) == 0) {
+ nfra = efra - cfra - offset > sfra ? efra - cfra - offset + 1 : sfra;
+ }
+ else {
+ nfra = (efra + 1 - (cfra + offset - 1) % (efra - sfra + 1)) - 1;
+ }
}
- if (mmd->flag & GP_TIME_KEEP_LOOP) {
- const int nfra = cfra + offset;
-
- /* if the sum of the cfra is out scene frame range, recalc */
- if (cfra + offset < sfra) {
- const int delta = abs(sfra - nfra);
- return efra - delta + 1;
+ if (mmd->mode == GP_TIME_MODE_PINGPONG) {
+ if ((mmd->flag & GP_TIME_KEEP_LOOP) == 0) {
+ if (((int)(cfra + offset - 1) / (efra - sfra)) % (2)) {
+ nfra = efra - (cfra + offset - 1) % (efra - sfra);
+ }
+ else {
+ nfra = sfra + (cfra + offset - 1) % (efra - sfra);
+ }
+ if (cfra > (efra - sfra) * 2) {
+ nfra = sfra + offset;
+ }
}
- if (cfra + offset > efra) {
- return nfra - efra + sfra - 1;
+ else {
+
+ if (((int)(cfra + offset - 1) / (efra - sfra)) % (2)) {
+ nfra = efra - (cfra + offset - 1) % (efra - sfra);
+ }
+ else {
+ nfra = sfra + (cfra + offset - 1) % (efra - sfra);
+ }
}
}
- return cfra + offset;
+ return nfra;
}
static void panel_draw(const bContext *UNUSED(C), Panel *panel)
diff --git a/source/blender/gpencil_modifiers/intern/MOD_gpenciltint.c b/source/blender/gpencil_modifiers/intern/MOD_gpenciltint.c
index 8fa14496616..ad8804782e8 100644
--- a/source/blender/gpencil_modifiers/intern/MOD_gpenciltint.c
+++ b/source/blender/gpencil_modifiers/intern/MOD_gpenciltint.c
@@ -10,7 +10,7 @@
#include "BLI_utildefines.h"
#include "BLI_listbase.h"
-#include "BLI_math.h"
+#include "BLI_math_vector.h"
#include "DNA_defaults.h"
#include "DNA_gpencil_modifier_types.h"
@@ -47,7 +47,6 @@
#include "DEG_depsgraph.h"
#include "DEG_depsgraph_build.h"
-#include "DEG_depsgraph_query.h"
static void initData(GpencilModifierData *md)
{
diff --git a/source/blender/gpencil_modifiers/intern/MOD_gpencilweight_angle.c b/source/blender/gpencil_modifiers/intern/MOD_gpencilweight_angle.c
index e90408b1a94..f40e6ba0728 100644
--- a/source/blender/gpencil_modifiers/intern/MOD_gpencilweight_angle.c
+++ b/source/blender/gpencil_modifiers/intern/MOD_gpencilweight_angle.c
@@ -8,7 +8,7 @@
#include <stdio.h>
#include "BLI_listbase.h"
-#include "BLI_math.h"
+#include "BLI_math_vector.h"
#include "BLI_utildefines.h"
#include "DNA_defaults.h"
@@ -18,7 +18,6 @@
#include "DNA_object_types.h"
#include "DNA_screen_types.h"
-#include "BKE_colortools.h"
#include "BKE_context.h"
#include "BKE_deform.h"
#include "BKE_gpencil.h"
@@ -29,7 +28,6 @@
#include "DEG_depsgraph.h"
#include "DEG_depsgraph_build.h"
-#include "DEG_depsgraph_query.h"
#include "UI_interface.h"
#include "UI_resources.h"
diff --git a/source/blender/gpencil_modifiers/intern/MOD_gpencilweight_proximity.c b/source/blender/gpencil_modifiers/intern/MOD_gpencilweight_proximity.c
index d2c31591a98..1a6cadabf51 100644
--- a/source/blender/gpencil_modifiers/intern/MOD_gpencilweight_proximity.c
+++ b/source/blender/gpencil_modifiers/intern/MOD_gpencilweight_proximity.c
@@ -8,7 +8,7 @@
#include <stdio.h>
#include "BLI_listbase.h"
-#include "BLI_math.h"
+#include "BLI_math_vector.h"
#include "BLI_utildefines.h"
#include "DNA_defaults.h"
@@ -29,7 +29,6 @@
#include "DEG_depsgraph.h"
#include "DEG_depsgraph_build.h"
-#include "DEG_depsgraph_query.h"
#include "UI_interface.h"
#include "UI_resources.h"
diff --git a/source/blender/gpencil_modifiers/intern/lineart/MOD_lineart.h b/source/blender/gpencil_modifiers/intern/lineart/MOD_lineart.h
index 99107a96cfe..a72ce76d591 100644
--- a/source/blender/gpencil_modifiers/intern/lineart/MOD_lineart.h
+++ b/source/blender/gpencil_modifiers/intern/lineart/MOD_lineart.h
@@ -36,10 +36,10 @@ typedef struct LineartTriangle {
/* first culled in line list to use adjacent triangle info, then go through triangle list. */
double gn[3];
- unsigned char material_mask_bits;
- unsigned char intersection_mask;
- unsigned char mat_occlusion;
- unsigned char flags; /* #eLineartTriangleFlags */
+ uint8_t material_mask_bits;
+ uint8_t intersection_mask;
+ uint8_t mat_occlusion;
+ uint8_t flags; /* #eLineartTriangleFlags */
/**
* Only use single link list, because we don't need to go back in order.
@@ -84,10 +84,10 @@ typedef struct LineartEdgeSegment {
/** at==0: left at==1: right (this is in 2D projected space) */
double at;
/** Occlusion level after "at" point */
- unsigned char occlusion;
+ uint8_t occlusion;
/* Used to filter line art occlusion edges */
- unsigned char material_mask_bits;
+ uint8_t material_mask_bits;
} LineartEdgeSegment;
typedef struct LineartVert {
@@ -102,7 +102,7 @@ typedef struct LineartVert {
* size of the struct is extended to include intersection data.
* See #eLineArtVertFlags.
*/
- char flag;
+ uint8_t flag;
} LineartVert;
@@ -119,21 +119,14 @@ typedef enum eLineArtVertFlags {
} eLineArtVertFlags;
typedef struct LineartEdge {
- /** We only need link node kind of list here. */
- struct LineartEdge *next;
struct LineartVert *v1, *v2;
- /**
- * Local vertex index for two ends, not pouting in #RenderVert because all verts are loaded, so
- * as long as fewer than half of the mesh edges are becoming a feature line, we save more memory.
- */
- int v1_obindex, v2_obindex;
struct LineartTriangle *t1, *t2;
ListBase segments;
- char min_occ;
+ int8_t min_occ;
/** Also for line type determination on chaining. */
uint16_t flags;
- unsigned char intersection_mask;
+ uint8_t intersection_mask;
/**
* Still need this entry because culled lines will not add to object
@@ -153,13 +146,15 @@ typedef struct LineartEdgeChain {
float length;
/** Used when re-connecting and grease-pencil stroke generation. */
- char picked;
- char level;
+ int8_t picked;
+ int8_t level;
/** Chain now only contains one type of segments */
int type;
- unsigned char material_mask_bits;
- unsigned char intersection_mask;
+ /** Will only connect chains that has the same loop id. */
+ int loop_id;
+ uint8_t material_mask_bits;
+ uint8_t intersection_mask;
struct Object *object_ref;
} LineartEdgeChain;
@@ -172,9 +167,9 @@ typedef struct LineartEdgeChainItem {
float gpos[3];
float normal[3];
uint16_t line_type;
- char occlusion;
- unsigned char material_mask_bits;
- unsigned char intersection_mask;
+ int8_t occlusion;
+ uint8_t material_mask_bits;
+ uint8_t intersection_mask;
size_t index;
} LineartEdgeChainItem;
@@ -182,17 +177,17 @@ typedef struct LineartChainRegisterEntry {
struct LineartChainRegisterEntry *next, *prev;
LineartEdgeChain *ec;
LineartEdgeChainItem *eci;
- char picked;
+ int8_t picked;
/* left/right mark.
* Because we revert list in chaining so we need the flag. */
- char is_left;
+ int8_t is_left;
} LineartChainRegisterEntry;
typedef struct LineartAdjacentEdge {
- unsigned int v1;
- unsigned int v2;
- unsigned int e;
+ uint32_t v1;
+ uint32_t v2;
+ uint32_t e;
} LineartAdjacentEdge;
enum eLineArtTileRecursiveLimit {
@@ -206,135 +201,136 @@ enum eLineArtTileRecursiveLimit {
#define LRT_TILE_SPLITTING_TRIANGLE_LIMIT 100
#define LRT_TILE_EDGE_COUNT_INITIAL 32
-typedef struct LineartRenderBuffer {
- struct LineartRenderBuffer *prev, *next;
+typedef struct LineartPendingEdges {
+ LineartEdge **array;
+ int max;
+ int next;
+} LineartPendingEdges;
- int thread_count;
+typedef struct LineartData {
int w, h;
- int tile_size_w, tile_size_h;
- int tile_count_x, tile_count_y;
- double width_per_tile, height_per_tile;
- double view_projection[4][4];
- double view[4][4];
+ int thread_count;
+ int sizeof_triangle;
- float overscan;
+ LineartStaticMemPool render_data_pool;
+ /* A pointer to LineartCache::chain_data_pool, which acts as a cache for edge chains. */
+ LineartStaticMemPool *chain_data_pool;
- struct LineartBoundingArea *initial_bounding_areas;
- unsigned int bounding_area_count;
+ struct _qtree {
- /* When splitting bounding areas, if there's an ortho camera placed at a straight angle, there
- * will be a lot of triangles aligned in line which can not be separated by continue subdividing
- * the tile. So we set a strict limit when using ortho camera. See eLineArtTileRecursiveLimit. */
- int tile_recursive_level;
+ int count_x, count_y;
+ double tile_width, tile_height;
- ListBase vertex_buffer_pointers;
- ListBase line_buffer_pointers;
- ListBase triangle_buffer_pointers;
+ /* When splitting bounding areas, if there's an ortho camera placed at a straight angle, there
+ * will be a lot of triangles aligned in line which can not be separated by continue
+ * subdividing the tile. So we set a strict limit when using ortho camera. See
+ * eLineArtTileRecursiveLimit. */
+ int recursive_level;
- /** This one's memory is not from main pool and is free()ed after culling stage. */
- ListBase triangle_adjacent_pointers;
+ struct LineartBoundingArea *initials;
- ListBase intersecting_vertex_buffer;
- /** Use the one comes with Line Art. */
- LineartStaticMemPool render_data_pool;
- ListBase wasted_cuts;
- SpinLock lock_cuts;
+ uint32_t tile_count;
- /* This is just a pointer to LineartCache::chain_data_pool, which acts as a cache for line
- * chains. */
- LineartStaticMemPool *chain_data_pool;
+ } qtree;
- /* Render status */
- double view_vector[3];
+ struct _geom {
- int triangle_size;
+ ListBase vertex_buffer_pointers;
+ ListBase line_buffer_pointers;
+ ListBase triangle_buffer_pointers;
- /* Although using ListBase here, LineartEdge is single linked list.
- * list.last is used to store worker progress along the list.
- * See lineart_main_occlusion_begin() for more info. */
- ListBase contour;
- ListBase intersection;
- ListBase crease;
- ListBase material;
- ListBase edge_mark;
- ListBase floating;
+ /** This one's memory is not from main pool and is free()ed after culling stage. */
+ ListBase triangle_adjacent_pointers;
- ListBase chains;
+ ListBase intersecting_vertex_buffer;
- /* For managing calculation tasks for multiple threads. */
- SpinLock lock_task;
+ } geom;
- /* settings */
-
- int max_occlusion_level;
- double crease_angle;
- double crease_cos;
-
- int draw_material_preview;
- double material_transparency;
-
- bool use_contour;
- bool use_crease;
- bool use_material;
- bool use_edge_marks;
- bool use_intersections;
- bool use_loose;
- bool fuzzy_intersections;
- bool fuzzy_everything;
- bool allow_boundaries;
- bool allow_overlapping_edges;
- bool allow_duplicated_types;
- bool remove_doubles;
- bool use_loose_as_contour;
- 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];
- double camera_pos[3];
- double active_camera_pos[3]; /* Stroke offset calculation may use active or selected camera. */
- double near_clip, far_clip;
- float shift_x, shift_y;
- float crease_threshold;
- float chaining_image_threshold;
- float angle_splitting_threshold;
+ struct _conf {
+
+ double view_projection[4][4];
+ double view[4][4];
+
+ float overscan;
+
+ int max_occlusion_level;
+ double crease_angle;
+ double crease_cos;
+
+ int draw_material_preview;
+ double material_transparency;
+
+ bool use_contour;
+ bool use_crease;
+ bool use_material;
+ bool use_edge_marks;
+ bool use_intersections;
+ bool use_loose;
+ bool fuzzy_intersections;
+ bool fuzzy_everything;
+ bool allow_boundaries;
+ bool allow_overlapping_edges;
+ bool allow_duplicated_types;
+ bool remove_doubles;
+ bool use_loose_as_contour;
+ bool use_loose_edge_chain;
+ bool use_geometry_space_chain;
+ bool use_image_boundary_trimming;
+ bool use_back_face_culling;
- float chain_smooth_tolerance;
+ bool filter_face_mark;
+ bool filter_face_mark_invert;
+ bool filter_face_mark_boundaries;
+ bool filter_face_mark_keep_contour;
- /* FIXME(Yiming): Temporary solution for speeding up calculation by not including lines that
- * are not in the selected source. This will not be needed after we have a proper scene-wise
- * cache running because multiple modifiers can then select results from that without further
- * calculation. */
- int _source_type;
- struct Collection *_source_collection;
- struct Object *_source_object;
+ bool force_crease;
+ bool sharp_as_crease;
-} LineartRenderBuffer;
+ 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];
+ double camera_pos[3];
+ double active_camera_pos[3]; /* Stroke offset calculation may use active or selected camera. */
+ double near_clip, far_clip;
+ float shift_x, shift_y;
+ float crease_threshold;
+ float chaining_image_threshold;
+ float angle_splitting_threshold;
+
+ float chain_smooth_tolerance;
+
+ double view_vector[3];
+
+ } conf;
+
+ LineartElementLinkNode *isect_scheduled_up_to;
+ int isect_scheduled_up_to_index;
+
+ /* Note: Data inside #pending_edges are allocated with MEM_xxx call instead of in pool. */
+ struct LineartPendingEdges pending_edges;
+ int scheduled_count;
+
+ ListBase chains;
+
+ ListBase wasted_cuts;
+ SpinLock lock_cuts;
+ SpinLock lock_task;
+
+} LineartData;
typedef struct LineartCache {
/** Separate memory pool for chain data, this goes to the cache, so when we free the main pool,
* chains will still be available. */
LineartStaticMemPool chain_data_pool;
- /** A copy of rb->chains so we have that data available after rb has been destroyed. */
+ /** A copy of ld->chains so we have that data available after ld has been destroyed. */
ListBase chains;
/** Cache only contains edge types specified in this variable. */
- char rb_edge_types;
+ int8_t rb_edge_types;
} LineartCache;
#define DBL_TRIANGLE_LIM 1e-8
@@ -360,18 +356,15 @@ typedef enum eLineartTriangleFlags {
#define LRT_THREAD_EDGE_COUNT 1000
typedef struct LineartRenderTaskInfo {
- struct LineartRenderBuffer *rb;
+ struct LineartData *ld;
int thread_id;
- /* These lists only denote the part of the main edge list that the thread should iterate over.
- * Be careful to not iterate outside of these bounds as it is not thread safe to do so. */
- ListBase contour;
- ListBase intersection;
- ListBase crease;
- ListBase material;
- ListBase edge_mark;
- ListBase floating;
+ /**
+ * #pending_edges here only stores a reference to a portion in
+ * LineartData::pending_edges, assigned by the occlusion scheduler.
+ */
+ struct LineartPendingEdges pending_edges;
} LineartRenderTaskInfo;
@@ -389,24 +382,18 @@ typedef struct LineartObjectInfo {
bool free_use_mesh;
- /* Threads will add lines inside here, when all threads are done, we combine those into the
- * ones in LineartRenderBuffer. */
- ListBase contour;
- ListBase intersection;
- ListBase crease;
- ListBase material;
- ListBase edge_mark;
- ListBase floating;
+ /* Note: Data inside #pending_edges are allocated with MEM_xxx call instead of in pool. */
+ struct LineartPendingEdges pending_edges;
} LineartObjectInfo;
typedef struct LineartObjectLoadTaskInfo {
- struct LineartRenderBuffer *rb;
+ struct LineartData *ld;
int thread_id;
/* LinkNode styled list */
LineartObjectInfo *pending;
/* Used to spread the load across several threads. This can not overflow. */
- long unsigned int total_faces;
+ uint64_t total_faces;
} LineartObjectLoadTaskInfo;
/**
@@ -440,15 +427,18 @@ typedef struct LineartBoundingArea {
/** 1,2,3,4 quadrant */
struct LineartBoundingArea *child;
+ SpinLock lock;
+
ListBase lp;
ListBase rp;
ListBase up;
ListBase bp;
- uint16_t triangle_count;
- uint16_t max_triangle_count;
- uint16_t line_count;
- uint16_t max_line_count;
+ uint32_t triangle_count;
+ uint32_t max_triangle_count;
+ uint32_t line_count;
+ uint32_t max_line_count;
+ uint32_t user_count;
/* Use array for speeding up multiple accesses. */
struct LineartTriangle **linked_triangles;
@@ -470,9 +460,6 @@ typedef struct LineartBoundingArea {
#define LRT_MIN3_INDEX_ABC(x, y, z) (x < y ? (x < z ? a : (y < z ? b : c)) : (y < z ? b : c))
-#define LRT_ABC(index) (index == 0 ? a : (index == 1 ? b : c))
-#define LRT_PABC(index) (index == 0 ? pa : (index == 1 ? pb : pc))
-
#define DBL_LOOSER 1e-5
#define LRT_DOUBLE_CLOSE_LOOSER(a, b) (((a) + DBL_LOOSER) >= (b) && ((a)-DBL_LOOSER) <= (b))
#define LRT_DOUBLE_CLOSE_ENOUGH(a, b) (((a) + DBL_EDGE_LIM) >= (b) && ((a)-DBL_EDGE_LIM) <= (b))
@@ -487,7 +474,7 @@ typedef struct LineartBoundingArea {
* r_aligned: True when 1) a and b is exactly on the same straight line and 2) a and b share a
* common end-point.
*
- * Important: if r_aligned is true, r_ratio will be either 0 or 1 depending on which point from
+ * IMPORTANT: if r_aligned is true, r_ratio will be either 0 or 1 depending on which point from
* segment a is shared with segment b. If it's a1 then r_ratio is 0, else then r_ratio is 1. This
* extra information is needed for line art occlusion stage to work correctly in such cases.
*/
@@ -637,30 +624,28 @@ BLI_INLINE int lineart_intersect_seg_seg(const double *a1,
struct Depsgraph;
struct LineartGpencilModifierData;
-struct LineartRenderBuffer;
+struct LineartData;
struct Scene;
void MOD_lineart_destroy_render_data(struct LineartGpencilModifierData *lmd);
-void MOD_lineart_chain_feature_lines(LineartRenderBuffer *rb);
-void MOD_lineart_chain_split_for_fixed_occlusion(LineartRenderBuffer *rb);
+void MOD_lineart_chain_feature_lines(LineartData *ld);
+void MOD_lineart_chain_split_for_fixed_occlusion(LineartData *ld);
/**
* This function only connects two different chains. It will not do any clean up or smart chaining.
* So no: removing overlapping chains, removal of short isolated segments, and no loop reduction is
* implemented yet.
*/
-void MOD_lineart_chain_connect(LineartRenderBuffer *rb);
-void MOD_lineart_chain_discard_short(LineartRenderBuffer *rb, float threshold);
-void MOD_lineart_chain_clip_at_border(LineartRenderBuffer *rb);
+void MOD_lineart_chain_connect(LineartData *ld);
+void MOD_lineart_chain_discard_short(LineartData *ld, float threshold);
+void MOD_lineart_chain_clip_at_border(LineartData *ld);
/**
* This should always be the last stage!, see the end of
* #MOD_lineart_chain_split_for_fixed_occlusion().
*/
-void MOD_lineart_chain_split_angle(LineartRenderBuffer *rb, float angle_threshold_rad);
-void MOD_lineart_smooth_chains(LineartRenderBuffer *rb, float tolerance);
-void MOD_lineart_chain_offset_towards_camera(LineartRenderBuffer *rb,
- float dist,
- bool use_custom_camera);
+void MOD_lineart_chain_split_angle(LineartData *ld, float angle_threshold_rad);
+void MOD_lineart_smooth_chains(LineartData *ld, float tolerance);
+void MOD_lineart_chain_offset_towards_camera(LineartData *ld, float dist, bool use_custom_camera);
int MOD_lineart_chain_count(const LineartEdgeChain *ec);
void MOD_lineart_chain_clear_picked_flag(LineartCache *lc);
@@ -680,14 +665,12 @@ struct Scene;
/**
* This only gets initial "biggest" tile.
*/
-LineartBoundingArea *MOD_lineart_get_parent_bounding_area(LineartRenderBuffer *rb,
- double x,
- double y);
+LineartBoundingArea *MOD_lineart_get_parent_bounding_area(LineartData *ld, double x, double y);
/**
* Wrapper for more convenience.
*/
-LineartBoundingArea *MOD_lineart_get_bounding_area(LineartRenderBuffer *rb, double x, double y);
+LineartBoundingArea *MOD_lineart_get_bounding_area(LineartData *ld, double x, double y);
struct bGPDframe;
struct bGPDlayer;
@@ -700,16 +683,16 @@ void MOD_lineart_gpencil_generate(LineartCache *cache,
struct Object *ob,
struct bGPDlayer *gpl,
struct bGPDframe *gpf,
- char source_type,
+ int8_t source_type,
void *source_reference,
int level_start,
int level_end,
int mat_nr,
- short edge_types,
- unsigned char mask_switches,
- unsigned char material_mask_bits,
- unsigned char intersection_mask,
- short thickness,
+ int16_t edge_types,
+ uint8_t mask_switches,
+ uint8_t material_mask_bits,
+ uint8_t intersection_mask,
+ int16_t thickness,
float opacity,
const char *source_vgname,
const char *vgname,
diff --git a/source/blender/gpencil_modifiers/intern/lineart/lineart_chain.c b/source/blender/gpencil_modifiers/intern/lineart/lineart_chain.c
index b666eb677eb..1d84bb8e232 100644
--- a/source/blender/gpencil_modifiers/intern/lineart/lineart_chain.c
+++ b/source/blender/gpencil_modifiers/intern/lineart/lineart_chain.c
@@ -23,7 +23,7 @@ static LineartEdge *lineart_line_get_connected(LineartBoundingArea *ba,
LineartVert *vt,
LineartVert **new_vt,
int match_flag,
- unsigned char match_isec_mask)
+ uint8_t match_isec_mask)
{
for (int i = 0; i < ba->line_count; i++) {
LineartEdge *n_e = ba->linked_lines[i];
@@ -60,12 +60,12 @@ static LineartEdge *lineart_line_get_connected(LineartBoundingArea *ba,
return NULL;
}
-static LineartEdgeChain *lineart_chain_create(LineartRenderBuffer *rb)
+static LineartEdgeChain *lineart_chain_create(LineartData *ld)
{
LineartEdgeChain *ec;
- ec = lineart_mem_acquire(rb->chain_data_pool, sizeof(LineartEdgeChain));
+ ec = lineart_mem_acquire(ld->chain_data_pool, sizeof(LineartEdgeChain));
- BLI_addtail(&rb->chains, ec);
+ BLI_addtail(&ld->chains, ec);
return ec;
}
@@ -85,14 +85,14 @@ static bool lineart_point_overlapping(LineartEdgeChainItem *eci,
return false;
}
-static LineartEdgeChainItem *lineart_chain_append_point(LineartRenderBuffer *rb,
+static LineartEdgeChainItem *lineart_chain_append_point(LineartData *ld,
LineartEdgeChain *ec,
float *fbcoord,
float *gpos,
float *normal,
- char type,
+ uint8_t type,
int level,
- unsigned char material_mask_bits,
+ uint8_t material_mask_bits,
size_t index)
{
LineartEdgeChainItem *eci;
@@ -108,7 +108,7 @@ static LineartEdgeChainItem *lineart_chain_append_point(LineartRenderBuffer *rb,
return old_eci;
}
- eci = lineart_mem_acquire(rb->chain_data_pool, sizeof(LineartEdgeChainItem));
+ eci = lineart_mem_acquire(ld->chain_data_pool, sizeof(LineartEdgeChainItem));
copy_v4_v4(eci->pos, fbcoord);
copy_v3_v3(eci->gpos, gpos);
@@ -122,14 +122,14 @@ static LineartEdgeChainItem *lineart_chain_append_point(LineartRenderBuffer *rb,
return eci;
}
-static LineartEdgeChainItem *lineart_chain_prepend_point(LineartRenderBuffer *rb,
+static LineartEdgeChainItem *lineart_chain_prepend_point(LineartData *ld,
LineartEdgeChain *ec,
float *fbcoord,
float *gpos,
float *normal,
- char type,
+ uint8_t type,
int level,
- unsigned char material_mask_bits,
+ uint8_t material_mask_bits,
size_t index)
{
LineartEdgeChainItem *eci;
@@ -138,7 +138,7 @@ static LineartEdgeChainItem *lineart_chain_prepend_point(LineartRenderBuffer *rb
return ec->chain.first;
}
- eci = lineart_mem_acquire(rb->chain_data_pool, sizeof(LineartEdgeChainItem));
+ eci = lineart_mem_acquire(ld->chain_data_pool, sizeof(LineartEdgeChainItem));
copy_v4_v4(eci->pos, fbcoord);
copy_v3_v3(eci->gpos, gpos);
@@ -152,14 +152,14 @@ static LineartEdgeChainItem *lineart_chain_prepend_point(LineartRenderBuffer *rb
return eci;
}
-void MOD_lineart_chain_feature_lines(LineartRenderBuffer *rb)
+void MOD_lineart_chain_feature_lines(LineartData *ld)
{
LineartEdgeChain *ec;
LineartEdgeChainItem *eci;
LineartBoundingArea *ba;
LineartEdgeSegment *es;
int last_occlusion;
- unsigned char last_transparency;
+ uint8_t last_transparency;
/* Used when converting from double. */
float use_fbcoord[4];
float use_gpos[3];
@@ -181,7 +181,7 @@ void MOD_lineart_chain_feature_lines(LineartRenderBuffer *rb)
e->flags |= LRT_EDGE_FLAG_CHAIN_PICKED;
- ec = lineart_chain_create(rb);
+ ec = lineart_chain_create(ld);
/* One chain can only have one object_ref and intersection_mask,
* so we assign them based on the first segment we found. */
@@ -207,11 +207,11 @@ void MOD_lineart_chain_feature_lines(LineartRenderBuffer *rb)
}
/* Step 1: grow left. */
- ba = MOD_lineart_get_bounding_area(rb, e->v1->fbcoord[0], e->v1->fbcoord[1]);
+ ba = MOD_lineart_get_bounding_area(ld, e->v1->fbcoord[0], e->v1->fbcoord[1]);
new_vt = e->v1;
es = e->segments.first;
VERT_COORD_TO_FLOAT(new_vt);
- lineart_chain_prepend_point(rb,
+ lineart_chain_prepend_point(ld,
ec,
use_fbcoord,
use_gpos,
@@ -219,7 +219,7 @@ void MOD_lineart_chain_feature_lines(LineartRenderBuffer *rb)
e->flags,
es->occlusion,
es->material_mask_bits,
- e->v1_obindex);
+ e->v1->index);
while (ba && (new_e = lineart_line_get_connected(
ba, new_vt, &new_vt, e->flags, e->intersection_mask))) {
new_e->flags |= LRT_EDGE_FLAG_CHAIN_PICKED;
@@ -248,7 +248,7 @@ void MOD_lineart_chain_feature_lines(LineartRenderBuffer *rb)
interp_v3_v3v3_db(gpos, new_e->v1->gloc, new_e->v2->gloc, global_at);
use_fbcoord[3] = interpf(new_e->v2->fbcoord[3], new_e->v1->fbcoord[3], global_at);
POS_TO_FLOAT(lpos, gpos)
- lineart_chain_prepend_point(rb,
+ lineart_chain_prepend_point(ld,
ec,
use_fbcoord,
use_gpos,
@@ -256,7 +256,7 @@ void MOD_lineart_chain_feature_lines(LineartRenderBuffer *rb)
new_e->flags,
es->occlusion,
es->material_mask_bits,
- new_e->v1_obindex);
+ new_e->v1->index);
last_occlusion = es->occlusion;
last_transparency = es->material_mask_bits;
}
@@ -274,7 +274,7 @@ void MOD_lineart_chain_feature_lines(LineartRenderBuffer *rb)
interp_v3_v3v3_db(gpos, new_e->v1->gloc, new_e->v2->gloc, global_at);
use_fbcoord[3] = interpf(new_e->v2->fbcoord[3], new_e->v1->fbcoord[3], global_at);
POS_TO_FLOAT(lpos, gpos)
- lineart_chain_prepend_point(rb,
+ lineart_chain_prepend_point(ld,
ec,
use_fbcoord,
use_gpos,
@@ -282,12 +282,12 @@ void MOD_lineart_chain_feature_lines(LineartRenderBuffer *rb)
new_e->flags,
last_occlusion,
last_transparency,
- new_e->v2_obindex);
+ new_e->v2->index);
last_occlusion = es->occlusion;
last_transparency = es->material_mask_bits;
}
VERT_COORD_TO_FLOAT(new_e->v2);
- lineart_chain_prepend_point(rb,
+ lineart_chain_prepend_point(ld,
ec,
use_fbcoord,
use_gpos,
@@ -295,9 +295,9 @@ void MOD_lineart_chain_feature_lines(LineartRenderBuffer *rb)
new_e->flags,
last_occlusion,
last_transparency,
- new_e->v2_obindex);
+ new_e->v2->index);
}
- ba = MOD_lineart_get_bounding_area(rb, new_vt->fbcoord[0], new_vt->fbcoord[1]);
+ ba = MOD_lineart_get_bounding_area(ld, new_vt->fbcoord[0], new_vt->fbcoord[1]);
}
/* Restore normal value. */
@@ -328,7 +328,7 @@ void MOD_lineart_chain_feature_lines(LineartRenderBuffer *rb)
interp_v3_v3v3_db(gpos, e->v1->gloc, e->v2->gloc, global_at);
use_fbcoord[3] = interpf(e->v2->fbcoord[3], e->v1->fbcoord[3], global_at);
POS_TO_FLOAT(lpos, gpos)
- lineart_chain_append_point(rb,
+ lineart_chain_append_point(ld,
ec,
use_fbcoord,
use_gpos,
@@ -336,12 +336,12 @@ void MOD_lineart_chain_feature_lines(LineartRenderBuffer *rb)
e->flags,
es->occlusion,
es->material_mask_bits,
- e->v1_obindex);
+ e->v1->index);
last_occlusion = es->occlusion;
last_transparency = es->material_mask_bits;
}
VERT_COORD_TO_FLOAT(e->v2)
- lineart_chain_append_point(rb,
+ lineart_chain_append_point(ld,
ec,
use_fbcoord,
use_gpos,
@@ -349,10 +349,10 @@ void MOD_lineart_chain_feature_lines(LineartRenderBuffer *rb)
e->flags,
last_occlusion,
last_transparency,
- e->v2_obindex);
+ e->v2->index);
/* Step 3: grow right. */
- ba = MOD_lineart_get_bounding_area(rb, e->v2->fbcoord[0], e->v2->fbcoord[1]);
+ ba = MOD_lineart_get_bounding_area(ld, e->v2->fbcoord[0], e->v2->fbcoord[1]);
new_vt = e->v2;
while (ba && (new_e = lineart_line_get_connected(
ba, new_vt, &new_vt, e->flags, e->intersection_mask))) {
@@ -394,7 +394,7 @@ void MOD_lineart_chain_feature_lines(LineartRenderBuffer *rb)
last_occlusion = es->prev ? es->prev->occlusion : last_occlusion;
last_transparency = es->prev ? es->prev->material_mask_bits : last_transparency;
POS_TO_FLOAT(lpos, gpos)
- lineart_chain_append_point(rb,
+ lineart_chain_append_point(ld,
ec,
use_fbcoord,
use_gpos,
@@ -402,7 +402,7 @@ void MOD_lineart_chain_feature_lines(LineartRenderBuffer *rb)
new_e->flags,
last_occlusion,
last_transparency,
- new_e->v1_obindex);
+ new_e->v1->index);
}
}
else if (new_vt == new_e->v2) {
@@ -420,7 +420,7 @@ void MOD_lineart_chain_feature_lines(LineartRenderBuffer *rb)
interp_v3_v3v3_db(gpos, new_e->v1->gloc, new_e->v2->gloc, global_at);
use_fbcoord[3] = interpf(new_e->v2->fbcoord[3], new_e->v1->fbcoord[3], global_at);
POS_TO_FLOAT(lpos, gpos)
- lineart_chain_append_point(rb,
+ lineart_chain_append_point(ld,
ec,
use_fbcoord,
use_gpos,
@@ -428,12 +428,12 @@ void MOD_lineart_chain_feature_lines(LineartRenderBuffer *rb)
new_e->flags,
es->occlusion,
es->material_mask_bits,
- new_e->v2_obindex);
+ new_e->v2->index);
last_occlusion = es->occlusion;
last_transparency = es->material_mask_bits;
}
VERT_COORD_TO_FLOAT(new_e->v2)
- lineart_chain_append_point(rb,
+ lineart_chain_append_point(ld,
ec,
use_fbcoord,
use_gpos,
@@ -441,11 +441,11 @@ void MOD_lineart_chain_feature_lines(LineartRenderBuffer *rb)
new_e->flags,
last_occlusion,
last_transparency,
- new_e->v2_obindex);
+ new_e->v2->index);
}
- ba = MOD_lineart_get_bounding_area(rb, new_vt->fbcoord[0], new_vt->fbcoord[1]);
+ ba = MOD_lineart_get_bounding_area(ld, new_vt->fbcoord[0], new_vt->fbcoord[1]);
}
- if (rb->fuzzy_everything) {
+ if (ld->conf.fuzzy_everything) {
ec->type = LRT_EDGE_FLAG_CONTOUR;
}
else {
@@ -455,7 +455,7 @@ void MOD_lineart_chain_feature_lines(LineartRenderBuffer *rb)
LRT_ITER_ALL_LINES_END
}
-static LineartBoundingArea *lineart_bounding_area_get_eci_recursive(LineartRenderBuffer *rb,
+static LineartBoundingArea *lineart_bounding_area_get_eci_recursive(LineartData *ld,
LineartBoundingArea *root,
LineartEdgeChainItem *eci)
{
@@ -468,32 +468,32 @@ static LineartBoundingArea *lineart_bounding_area_get_eci_recursive(LineartRende
ba.l <= eci->pos[0] && ba.r >= eci->pos[0] && ba.b <= eci->pos[1] && ba.u >= eci->pos[1]
if (IN_BOUND(ch[0], eci)) {
- return lineart_bounding_area_get_eci_recursive(rb, &ch[0], eci);
+ return lineart_bounding_area_get_eci_recursive(ld, &ch[0], eci);
}
if (IN_BOUND(ch[1], eci)) {
- return lineart_bounding_area_get_eci_recursive(rb, &ch[1], eci);
+ return lineart_bounding_area_get_eci_recursive(ld, &ch[1], eci);
}
if (IN_BOUND(ch[2], eci)) {
- return lineart_bounding_area_get_eci_recursive(rb, &ch[2], eci);
+ return lineart_bounding_area_get_eci_recursive(ld, &ch[2], eci);
}
if (IN_BOUND(ch[3], eci)) {
- return lineart_bounding_area_get_eci_recursive(rb, &ch[3], eci);
+ return lineart_bounding_area_get_eci_recursive(ld, &ch[3], eci);
}
#undef IN_BOUND
return NULL;
}
-static LineartBoundingArea *lineart_bounding_area_get_end_point(LineartRenderBuffer *rb,
+static LineartBoundingArea *lineart_bounding_area_get_end_point(LineartData *ld,
LineartEdgeChainItem *eci)
{
if (!eci) {
return NULL;
}
- LineartBoundingArea *root = MOD_lineart_get_parent_bounding_area(rb, eci->pos[0], eci->pos[1]);
+ LineartBoundingArea *root = MOD_lineart_get_parent_bounding_area(ld, eci->pos[0], eci->pos[1]);
if (root == NULL) {
return NULL;
}
- return lineart_bounding_area_get_eci_recursive(rb, root, eci);
+ return lineart_bounding_area_get_eci_recursive(ld, root, eci);
}
/**
@@ -502,14 +502,14 @@ static LineartBoundingArea *lineart_bounding_area_get_end_point(LineartRenderBuf
* areas, this happens either when 1) the geometry is way too dense, or 2) the chaining threshold
* is too big that it covers multiple small bounding areas.
*/
-static void lineart_bounding_area_link_point_recursive(LineartRenderBuffer *rb,
+static void lineart_bounding_area_link_point_recursive(LineartData *ld,
LineartBoundingArea *root,
LineartEdgeChain *ec,
LineartEdgeChainItem *eci)
{
if (root->child == NULL) {
LineartChainRegisterEntry *cre = lineart_list_append_pointer_pool_sized(
- &root->linked_chains, &rb->render_data_pool, ec, sizeof(LineartChainRegisterEntry));
+ &root->linked_chains, &ld->render_data_pool, ec, sizeof(LineartChainRegisterEntry));
cre->eci = eci;
@@ -524,34 +524,34 @@ static void lineart_bounding_area_link_point_recursive(LineartRenderBuffer *rb,
ba.l <= eci->pos[0] && ba.r >= eci->pos[0] && ba.b <= eci->pos[1] && ba.u >= eci->pos[1]
if (IN_BOUND(ch[0], eci)) {
- lineart_bounding_area_link_point_recursive(rb, &ch[0], ec, eci);
+ lineart_bounding_area_link_point_recursive(ld, &ch[0], ec, eci);
}
else if (IN_BOUND(ch[1], eci)) {
- lineart_bounding_area_link_point_recursive(rb, &ch[1], ec, eci);
+ lineart_bounding_area_link_point_recursive(ld, &ch[1], ec, eci);
}
else if (IN_BOUND(ch[2], eci)) {
- lineart_bounding_area_link_point_recursive(rb, &ch[2], ec, eci);
+ lineart_bounding_area_link_point_recursive(ld, &ch[2], ec, eci);
}
else if (IN_BOUND(ch[3], eci)) {
- lineart_bounding_area_link_point_recursive(rb, &ch[3], ec, eci);
+ lineart_bounding_area_link_point_recursive(ld, &ch[3], ec, eci);
}
#undef IN_BOUND
}
}
-static void lineart_bounding_area_link_chain(LineartRenderBuffer *rb, LineartEdgeChain *ec)
+static void lineart_bounding_area_link_chain(LineartData *ld, LineartEdgeChain *ec)
{
LineartEdgeChainItem *pl = ec->chain.first;
LineartEdgeChainItem *pr = ec->chain.last;
- LineartBoundingArea *ba1 = MOD_lineart_get_parent_bounding_area(rb, pl->pos[0], pl->pos[1]);
- LineartBoundingArea *ba2 = MOD_lineart_get_parent_bounding_area(rb, pr->pos[0], pr->pos[1]);
+ LineartBoundingArea *ba1 = MOD_lineart_get_parent_bounding_area(ld, pl->pos[0], pl->pos[1]);
+ LineartBoundingArea *ba2 = MOD_lineart_get_parent_bounding_area(ld, pr->pos[0], pr->pos[1]);
if (ba1) {
- lineart_bounding_area_link_point_recursive(rb, ba1, ec, pl);
+ lineart_bounding_area_link_point_recursive(ld, ba1, ec, pl);
}
if (ba2) {
- lineart_bounding_area_link_point_recursive(rb, ba2, ec, pr);
+ lineart_bounding_area_link_point_recursive(ld, ba2, ec, pr);
}
}
@@ -564,7 +564,7 @@ static bool lineart_chain_fix_ambiguous_segments(LineartEdgeChain *ec,
float dist_accum = 0;
int fixed_occ = last_matching_eci->occlusion;
- unsigned char fixed_mask = last_matching_eci->material_mask_bits;
+ uint8_t fixed_mask = last_matching_eci->material_mask_bits;
LineartEdgeChainItem *can_skip_to = NULL;
LineartEdgeChainItem *last_eci = last_matching_eci;
@@ -606,23 +606,28 @@ static bool lineart_chain_fix_ambiguous_segments(LineartEdgeChain *ec,
return false;
}
-void MOD_lineart_chain_split_for_fixed_occlusion(LineartRenderBuffer *rb)
+void MOD_lineart_chain_split_for_fixed_occlusion(LineartData *ld)
{
LineartEdgeChain *ec, *new_ec;
LineartEdgeChainItem *eci, *next_eci;
ListBase swap = {0};
- swap.first = rb->chains.first;
- swap.last = rb->chains.last;
+ swap.first = ld->chains.first;
+ swap.last = ld->chains.last;
- rb->chains.last = rb->chains.first = NULL;
+ ld->chains.last = ld->chains.first = NULL;
+ int loop_id = 0;
while ((ec = BLI_pophead(&swap)) != NULL) {
ec->next = ec->prev = NULL;
- BLI_addtail(&rb->chains, ec);
+ BLI_addtail(&ld->chains, ec);
+
+ ec->loop_id = loop_id;
+ loop_id++;
+
LineartEdgeChainItem *first_eci = (LineartEdgeChainItem *)ec->chain.first;
int fixed_occ = first_eci->occlusion;
- unsigned char fixed_mask = first_eci->material_mask_bits;
+ uint8_t fixed_mask = first_eci->material_mask_bits;
ec->level = fixed_occ;
ec->material_mask_bits = fixed_mask;
for (eci = first_eci->next; eci; eci = next_eci) {
@@ -634,8 +639,8 @@ void MOD_lineart_chain_split_for_fixed_occlusion(LineartRenderBuffer *rb)
}
if (lineart_chain_fix_ambiguous_segments(ec,
eci->prev,
- rb->chaining_image_threshold,
- rb->chain_preserve_details,
+ ld->conf.chaining_image_threshold,
+ ld->conf.chain_preserve_details,
&next_eci)) {
continue;
}
@@ -648,15 +653,16 @@ void MOD_lineart_chain_split_for_fixed_occlusion(LineartRenderBuffer *rb)
/* No need to split at the last point anyway. */
break;
}
- new_ec = lineart_chain_create(rb);
+ new_ec = lineart_chain_create(ld);
new_ec->chain.first = eci;
new_ec->chain.last = ec->chain.last;
+ new_ec->loop_id = loop_id;
ec->chain.last = eci->prev;
((LineartEdgeChainItem *)ec->chain.last)->next = 0;
eci->prev = 0;
/* End the previous one. */
- lineart_chain_append_point(rb,
+ lineart_chain_append_point(ld,
ec,
eci->pos,
eci->gpos,
@@ -677,16 +683,16 @@ void MOD_lineart_chain_split_for_fixed_occlusion(LineartRenderBuffer *rb)
}
}
/* Get rid of those very short "zig-zag" lines that jumps around visibility. */
- MOD_lineart_chain_discard_short(rb, DBL_EDGE_LIM);
- LISTBASE_FOREACH (LineartEdgeChain *, iec, &rb->chains) {
- lineart_bounding_area_link_chain(rb, iec);
+ MOD_lineart_chain_discard_short(ld, DBL_EDGE_LIM);
+ LISTBASE_FOREACH (LineartEdgeChain *, iec, &ld->chains) {
+ lineart_bounding_area_link_chain(ld, iec);
}
}
/**
* NOTE: segment type (crease/material/contour...) is ambiguous after this.
*/
-static void lineart_chain_connect(LineartRenderBuffer *UNUSED(rb),
+static void lineart_chain_connect(LineartData *UNUSED(ld),
LineartEdgeChain *onto,
LineartEdgeChain *sub,
int reverse_1,
@@ -736,13 +742,14 @@ static void lineart_chain_connect(LineartRenderBuffer *UNUSED(rb),
}
}
-static LineartChainRegisterEntry *lineart_chain_get_closest_cre(LineartRenderBuffer *rb,
+static LineartChainRegisterEntry *lineart_chain_get_closest_cre(LineartData *ld,
LineartBoundingArea *ba,
LineartEdgeChain *ec,
LineartEdgeChainItem *eci,
int occlusion,
- unsigned char material_mask_bits,
- unsigned char isec_mask,
+ uint8_t material_mask_bits,
+ uint8_t isec_mask,
+ int loop_id,
float dist,
float *result_new_len,
LineartBoundingArea *caller_ba)
@@ -754,8 +761,8 @@ static LineartChainRegisterEntry *lineart_chain_get_closest_cre(LineartRenderBuf
* next one. */
LISTBASE_FOREACH_MUTABLE (LineartChainRegisterEntry *, cre, &ba->linked_chains) {
if (cre->ec->object_ref != ec->object_ref) {
- if (!rb->fuzzy_everything) {
- if (rb->fuzzy_intersections) {
+ if (!ld->conf.fuzzy_everything) {
+ if (ld->conf.fuzzy_intersections) {
/* If none of those are intersection lines... */
if ((!(cre->ec->type & LRT_EDGE_FLAG_INTERSECTION)) &&
(!(ec->type & LRT_EDGE_FLAG_INTERSECTION))) {
@@ -775,9 +782,9 @@ static LineartChainRegisterEntry *lineart_chain_get_closest_cre(LineartRenderBuf
(cre->ec->intersection_mask != isec_mask)) {
continue;
}
- if (!rb->fuzzy_everything) {
+ if (!ld->conf.fuzzy_everything) {
if (cre->ec->type != ec->type) {
- if (rb->fuzzy_intersections) {
+ if (ld->conf.fuzzy_intersections) {
if (!(cre->ec->type == LRT_EDGE_FLAG_INTERSECTION ||
ec->type == LRT_EDGE_FLAG_INTERSECTION)) {
continue; /* Fuzzy intersections but no intersection line found. */
@@ -789,9 +796,13 @@ static LineartChainRegisterEntry *lineart_chain_get_closest_cre(LineartRenderBuf
}
}
- float new_len = rb->use_geometry_space_chain ? len_v3v3(cre->eci->gpos, eci->gpos) :
- len_v2v2(cre->eci->pos, eci->pos);
- if (new_len < dist) {
+ float new_len = ld->conf.use_geometry_space_chain ? len_v3v3(cre->eci->gpos, eci->gpos) :
+ len_v2v2(cre->eci->pos, eci->pos);
+ /* Even if the vertex is not from the same contour loop, we try to chain it still if the
+ * distance is small enough. This way we can better chain smaller loops and smooth them out
+ * later. */
+ if (((cre->ec->loop_id == loop_id) && (new_len < dist)) ||
+ ((cre->ec->loop_id != loop_id) && (new_len < dist / 10))) {
closest_cre = cre;
dist = new_len;
if (result_new_len) {
@@ -806,15 +817,16 @@ static LineartChainRegisterEntry *lineart_chain_get_closest_cre(LineartRenderBuf
#define LRT_TEST_ADJACENT_AREAS(dist_to, list) \
if (dist_to < dist && dist_to > 0) { \
- LISTBASE_FOREACH (LinkData *, ld, list) { \
- LineartBoundingArea *sba = (LineartBoundingArea *)ld->data; \
- adjacent_closest = lineart_chain_get_closest_cre(rb, \
+ LISTBASE_FOREACH (LinkData *, link, list) { \
+ LineartBoundingArea *sba = (LineartBoundingArea *)link->data; \
+ adjacent_closest = lineart_chain_get_closest_cre(ld, \
sba, \
ec, \
eci, \
occlusion, \
material_mask_bits, \
isec_mask, \
+ loop_id, \
dist, \
&adjacent_new_len, \
ba); \
@@ -836,35 +848,36 @@ static LineartChainRegisterEntry *lineart_chain_get_closest_cre(LineartRenderBuf
return closest_cre;
}
-void MOD_lineart_chain_connect(LineartRenderBuffer *rb)
+void MOD_lineart_chain_connect(LineartData *ld)
{
LineartEdgeChain *ec;
LineartEdgeChainItem *eci_l, *eci_r;
LineartBoundingArea *ba_l, *ba_r;
LineartChainRegisterEntry *closest_cre_l, *closest_cre_r, *closest_cre;
- float dist = rb->chaining_image_threshold;
+ float dist = ld->conf.chaining_image_threshold;
float dist_l, dist_r;
- int occlusion, reverse_main;
- unsigned char material_mask_bits, isec_mask;
+ int occlusion, reverse_main, loop_id;
+ uint8_t material_mask_bits, isec_mask;
ListBase swap = {0};
- if (rb->chaining_image_threshold < 0.0001) {
+ if (ld->conf.chaining_image_threshold < 0.0001) {
return;
}
- swap.first = rb->chains.first;
- swap.last = rb->chains.last;
+ swap.first = ld->chains.first;
+ swap.last = ld->chains.last;
- rb->chains.last = rb->chains.first = NULL;
+ ld->chains.last = ld->chains.first = NULL;
while ((ec = BLI_pophead(&swap)) != NULL) {
ec->next = ec->prev = NULL;
if (ec->picked) {
continue;
}
- BLI_addtail(&rb->chains, ec);
+ BLI_addtail(&ld->chains, ec);
+ loop_id = ec->loop_id;
- if (ec->type == LRT_EDGE_FLAG_LOOSE && (!rb->use_loose_edge_chain)) {
+ if (ec->type == LRT_EDGE_FLAG_LOOSE && (!ld->conf.use_loose_edge_chain)) {
continue;
}
@@ -874,12 +887,30 @@ void MOD_lineart_chain_connect(LineartRenderBuffer *rb)
eci_l = ec->chain.first;
eci_r = ec->chain.last;
- while ((ba_l = lineart_bounding_area_get_end_point(rb, eci_l)) &&
- (ba_r = lineart_bounding_area_get_end_point(rb, eci_r))) {
- closest_cre_l = lineart_chain_get_closest_cre(
- rb, ba_l, ec, eci_l, occlusion, material_mask_bits, isec_mask, dist, &dist_l, NULL);
- closest_cre_r = lineart_chain_get_closest_cre(
- rb, ba_r, ec, eci_r, occlusion, material_mask_bits, isec_mask, dist, &dist_r, NULL);
+ while ((ba_l = lineart_bounding_area_get_end_point(ld, eci_l)) &&
+ (ba_r = lineart_bounding_area_get_end_point(ld, eci_r))) {
+ closest_cre_l = lineart_chain_get_closest_cre(ld,
+ ba_l,
+ ec,
+ eci_l,
+ occlusion,
+ material_mask_bits,
+ isec_mask,
+ loop_id,
+ dist,
+ &dist_l,
+ NULL);
+ closest_cre_r = lineart_chain_get_closest_cre(ld,
+ ba_r,
+ ec,
+ eci_r,
+ occlusion,
+ material_mask_bits,
+ isec_mask,
+ loop_id,
+ dist,
+ &dist_r,
+ NULL);
if (closest_cre_l && closest_cre_r) {
if (dist_l < dist_r) {
closest_cre = closest_cre_l;
@@ -905,10 +936,10 @@ void MOD_lineart_chain_connect(LineartRenderBuffer *rb)
closest_cre->picked = 1;
closest_cre->ec->picked = 1;
if (closest_cre->is_left) {
- lineart_chain_connect(rb, ec, closest_cre->ec, reverse_main, 0);
+ lineart_chain_connect(ld, ec, closest_cre->ec, reverse_main, 0);
}
else {
- lineart_chain_connect(rb, ec, closest_cre->ec, reverse_main, 1);
+ lineart_chain_connect(ld, ec, closest_cre->ec, reverse_main, 1);
}
BLI_remlink(&swap, closest_cre->ec);
eci_l = ec->chain.first;
@@ -938,13 +969,13 @@ float MOD_lineart_chain_compute_length(LineartEdgeChain *ec)
return offset_accum;
}
-void MOD_lineart_chain_discard_short(LineartRenderBuffer *rb, const float threshold)
+void MOD_lineart_chain_discard_short(LineartData *ld, const float threshold)
{
LineartEdgeChain *ec, *next_ec;
- for (ec = rb->chains.first; ec; ec = next_ec) {
+ for (ec = ld->chains.first; ec; ec = next_ec) {
next_ec = ec->next;
if (MOD_lineart_chain_compute_length(ec) < threshold) {
- BLI_remlink(&rb->chains, ec);
+ BLI_remlink(&ld->chains, ec);
}
}
}
@@ -968,35 +999,75 @@ void MOD_lineart_chain_clear_picked_flag(LineartCache *lc)
}
}
-void MOD_lineart_smooth_chains(LineartRenderBuffer *rb, float tolerance)
+void MOD_lineart_smooth_chains(LineartData *ld, float tolerance)
{
- LISTBASE_FOREACH (LineartEdgeChain *, ec, &rb->chains) {
- LineartEdgeChainItem *next_eci;
- for (LineartEdgeChainItem *eci = ec->chain.first; eci; eci = next_eci) {
- next_eci = eci->next;
- LineartEdgeChainItem *eci2, *eci3, *eci4;
-
- /* Not enough point to do simplify. */
- if ((!(eci2 = eci->next)) || (!(eci3 = eci2->next))) {
- continue;
- }
-
- /* No need to care for different line types/occlusion and so on, because at this stage they
- * are all the same within a chain. */
-
- /* If p3 is within the p1-p2 segment of a width of "tolerance". */
- if (dist_to_line_segment_v2(eci3->pos, eci->pos, eci2->pos) < tolerance) {
- /* And if p4 is on the extension of p1-p2 , we remove p3. */
- if ((eci4 = eci3->next) && (dist_to_line_v2(eci4->pos, eci->pos, eci2->pos) < tolerance)) {
- BLI_remlink(&ec->chain, eci3);
- next_eci = eci;
+ LISTBASE_FOREACH (LineartEdgeChain *, ec, &ld->chains) {
+ /* Go through the chain two times, once from each direction. */
+ for (int times = 0; times < 2; times++) {
+ for (LineartEdgeChainItem *eci = ec->chain.first, *next_eci = eci->next; eci;
+ eci = next_eci) {
+ LineartEdgeChainItem *eci2, *eci3, *eci4;
+
+ if ((!(eci2 = eci->next)) || (!(eci3 = eci2->next))) {
+ /* Not enough points to simplify. */
+ next_eci = eci->next;
+ continue;
}
+ /* No need to care for different line types/occlusion and so on, because at this stage they
+ * are all the same within a chain.
+ *
+ * We need to simplify a chain from this:
+ * 1-----------2
+ * 3-----------4
+ * to this:
+ * 1-----------2--_
+ * `--4 */
+
+ /* If p3 is within the p1-p2 segment of a width of "tolerance", in other words, p3 is
+ * approximately on the segment of p1-p2. */
+ if (dist_to_line_segment_v2(eci3->pos, eci->pos, eci2->pos) < tolerance) {
+ float vec2[2], vec3[2], v2n[2], ratio, len2;
+ sub_v2_v2v2(vec2, eci2->pos, eci->pos);
+ sub_v2_v2v2(vec3, eci3->pos, eci->pos);
+ normalize_v2_v2(v2n, vec2);
+ ratio = dot_v2v2(v2n, vec3);
+ len2 = len_v2(vec2);
+ /* Because this smoothing applies on geometries of different scales in the same scene,
+ * some small scale features (e.g. the "tails" on the inner ring of a torus geometry)
+ * could be completely erased if the tolerance value is set for accommodating the entire
+ * scene. Those situations typically result in (ratio << 0), looks like this:
+ * 1---2
+ * 3-------------------------------4
+ * (this sort of long zigzag obviously are "features" that can't be erased)
+ * setting a ratio of -10 turned out to be a reasonable threshold in tests. */
+ if (ratio < len2 && ratio > -len2 * 10) {
+ /* We only remove p3 if p4 is on the extension of p1->p2. */
+ if ((eci4 = eci3->next) &&
+ (dist_to_line_v2(eci4->pos, eci->pos, eci2->pos) < tolerance)) {
+ BLI_remlink(&ec->chain, eci3);
+ next_eci = eci;
+ continue;
+ }
+ if (!eci4) {
+ /* See if the last segment's direction is reversed, if so remove that.
+ * Basically we don't need to preserve p3 if the entire chain looked like this:
+ * ...----1----3===2 */
+ if (len_v2(vec2) > len_v2(vec3)) {
+ BLI_remlink(&ec->chain, eci3);
+ }
+ next_eci = NULL;
+ continue;
+ }
+ }
+ }
+ next_eci = eci->next;
}
+ BLI_listbase_reverse(&ec->chain);
}
}
}
-static LineartEdgeChainItem *lineart_chain_create_crossing_point(LineartRenderBuffer *rb,
+static LineartEdgeChainItem *lineart_chain_create_crossing_point(LineartData *ld,
LineartEdgeChainItem *eci_inside,
LineartEdgeChainItem *eci_outside)
{
@@ -1026,7 +1097,7 @@ static LineartEdgeChainItem *lineart_chain_create_crossing_point(LineartRenderBu
ratiof(eci1->pos[1], eci2->pos[1], isec[1]);
float gratio = eci1->pos[3] * ratio / (ratio * eci1->pos[3] + (1 - ratio) * eci2->pos[3]);
- LineartEdgeChainItem *eci = lineart_mem_acquire(rb->chain_data_pool,
+ LineartEdgeChainItem *eci = lineart_mem_acquire(ld->chain_data_pool,
sizeof(LineartEdgeChainItem));
memcpy(eci, eci1, sizeof(LineartEdgeChainItem));
interp_v3_v3v3(eci->gpos, eci1->gpos, eci2->gpos, gratio);
@@ -1040,16 +1111,16 @@ static LineartEdgeChainItem *lineart_chain_create_crossing_point(LineartRenderBu
((eci)->pos[0] >= -1.0f && (eci)->pos[0] <= 1.0f && (eci)->pos[1] >= -1.0f && \
(eci)->pos[1] <= 1.0f)
-void MOD_lineart_chain_clip_at_border(LineartRenderBuffer *rb)
+void MOD_lineart_chain_clip_at_border(LineartData *ld)
{
LineartEdgeChain *ec;
LineartEdgeChainItem *eci, *next_eci, *prev_eci, *new_eci;
bool is_inside, new_inside;
ListBase swap = {0};
- swap.first = rb->chains.first;
- swap.last = rb->chains.last;
+ swap.first = ld->chains.first;
+ swap.last = ld->chains.last;
- rb->chains.last = rb->chains.first = NULL;
+ ld->chains.last = ld->chains.first = NULL;
while ((ec = BLI_pophead(&swap)) != NULL) {
bool ec_added = false;
LineartEdgeChainItem *first_eci = (LineartEdgeChainItem *)ec->chain.first;
@@ -1066,9 +1137,9 @@ void MOD_lineart_chain_clip_at_border(LineartRenderBuffer *rb)
if ((new_inside = LRT_ECI_INSIDE(eci)) != is_inside) {
if (new_inside == false) {
/* Stroke goes out. */
- new_eci = lineart_chain_create_crossing_point(rb, prev_eci, eci);
+ new_eci = lineart_chain_create_crossing_point(ld, prev_eci, eci);
- LineartEdgeChain *new_ec = lineart_mem_acquire(rb->chain_data_pool,
+ LineartEdgeChain *new_ec = lineart_mem_acquire(ld->chain_data_pool,
sizeof(LineartEdgeChain));
memcpy(new_ec, ec, sizeof(LineartEdgeChain));
new_ec->chain.first = next_eci;
@@ -1076,7 +1147,7 @@ void MOD_lineart_chain_clip_at_border(LineartRenderBuffer *rb)
prev_eci->next = NULL;
ec->chain.last = prev_eci;
BLI_addtail(&ec->chain, new_eci);
- BLI_addtail(&rb->chains, ec);
+ BLI_addtail(&ld->chains, ec);
ec_added = true;
ec = new_ec;
@@ -1085,7 +1156,7 @@ void MOD_lineart_chain_clip_at_border(LineartRenderBuffer *rb)
continue;
}
/* Stroke comes in. */
- new_eci = lineart_chain_create_crossing_point(rb, eci, prev_eci);
+ new_eci = lineart_chain_create_crossing_point(ld, eci, prev_eci);
ec->chain.first = eci;
eci->prev = NULL;
@@ -1101,25 +1172,25 @@ void MOD_lineart_chain_clip_at_border(LineartRenderBuffer *rb)
}
if ((!ec_added) && is_inside) {
- BLI_addtail(&rb->chains, ec);
+ BLI_addtail(&ld->chains, ec);
}
}
}
-void MOD_lineart_chain_split_angle(LineartRenderBuffer *rb, float angle_threshold_rad)
+void MOD_lineart_chain_split_angle(LineartData *ld, float angle_threshold_rad)
{
LineartEdgeChain *ec, *new_ec;
LineartEdgeChainItem *eci, *next_eci, *prev_eci;
ListBase swap = {0};
- swap.first = rb->chains.first;
- swap.last = rb->chains.last;
+ swap.first = ld->chains.first;
+ swap.last = ld->chains.last;
- rb->chains.last = rb->chains.first = NULL;
+ ld->chains.last = ld->chains.first = NULL;
while ((ec = BLI_pophead(&swap)) != NULL) {
ec->next = ec->prev = NULL;
- BLI_addtail(&rb->chains, ec);
+ BLI_addtail(&ld->chains, ec);
LineartEdgeChainItem *first_eci = (LineartEdgeChainItem *)ec->chain.first;
for (eci = first_eci->next; eci; eci = next_eci) {
next_eci = eci->next;
@@ -1132,7 +1203,7 @@ void MOD_lineart_chain_split_angle(LineartRenderBuffer *rb, float angle_threshol
break; /* No need to split at the last point anyway. */
}
if (angle < angle_threshold_rad) {
- new_ec = lineart_chain_create(rb);
+ new_ec = lineart_chain_create(ld);
new_ec->chain.first = eci;
new_ec->chain.last = ec->chain.last;
ec->chain.last = eci->prev;
@@ -1140,7 +1211,7 @@ void MOD_lineart_chain_split_angle(LineartRenderBuffer *rb, float angle_threshol
eci->prev = 0;
/* End the previous one. */
- lineart_chain_append_point(rb,
+ lineart_chain_append_point(ld,
ec,
eci->pos,
eci->gpos,
@@ -1152,6 +1223,8 @@ void MOD_lineart_chain_split_angle(LineartRenderBuffer *rb, float angle_threshol
new_ec->object_ref = ec->object_ref;
new_ec->type = ec->type;
new_ec->level = ec->level;
+ new_ec->loop_id = ec->loop_id;
+ new_ec->intersection_mask = ec->intersection_mask;
new_ec->material_mask_bits = ec->material_mask_bits;
ec = new_ec;
}
@@ -1159,40 +1232,37 @@ void MOD_lineart_chain_split_angle(LineartRenderBuffer *rb, float angle_threshol
}
}
-void MOD_lineart_chain_offset_towards_camera(LineartRenderBuffer *rb,
- float dist,
- bool use_custom_camera)
+void MOD_lineart_chain_offset_towards_camera(LineartData *ld, float dist, bool use_custom_camera)
{
float dir[3];
float cam[3];
float view[3];
float view_clamp[3];
- copy_v3fl_v3db(cam, rb->camera_pos);
- copy_v3fl_v3db(view, rb->view_vector);
if (use_custom_camera) {
- copy_v3fl_v3db(cam, rb->camera_pos);
+ copy_v3fl_v3db(cam, ld->conf.camera_pos);
}
else {
- copy_v3fl_v3db(cam, rb->active_camera_pos);
+ copy_v3fl_v3db(cam, ld->conf.active_camera_pos);
}
- if (rb->cam_is_persp) {
- LISTBASE_FOREACH (LineartEdgeChain *, ec, &rb->chains) {
+ if (ld->conf.cam_is_persp) {
+ LISTBASE_FOREACH (LineartEdgeChain *, ec, &ld->chains) {
LISTBASE_FOREACH (LineartEdgeChainItem *, eci, &ec->chain) {
sub_v3_v3v3(dir, cam, eci->gpos);
float orig_len = len_v3(dir);
normalize_v3(dir);
- mul_v3_fl(dir, MIN2(dist, orig_len - rb->near_clip));
+ mul_v3_fl(dir, MIN2(dist, orig_len - ld->conf.near_clip));
add_v3_v3(eci->gpos, dir);
}
}
}
else {
- LISTBASE_FOREACH (LineartEdgeChain *, ec, &rb->chains) {
+ copy_v3fl_v3db(view, ld->conf.view_vector);
+ LISTBASE_FOREACH (LineartEdgeChain *, ec, &ld->chains) {
LISTBASE_FOREACH (LineartEdgeChainItem *, eci, &ec->chain) {
sub_v3_v3v3(dir, cam, eci->gpos);
- float len_lim = dot_v3v3(view, dir) - rb->near_clip;
+ float len_lim = dot_v3v3(view, dir) - ld->conf.near_clip;
normalize_v3_v3(view_clamp, view);
mul_v3_fl(view_clamp, MIN2(dist, len_lim));
add_v3_v3(eci->gpos, view_clamp);
diff --git a/source/blender/gpencil_modifiers/intern/lineart/lineart_cpp_bridge.cc b/source/blender/gpencil_modifiers/intern/lineart/lineart_cpp_bridge.cc
index 174399618a5..5e741ccbd55 100644
--- a/source/blender/gpencil_modifiers/intern/lineart/lineart_cpp_bridge.cc
+++ b/source/blender/gpencil_modifiers/intern/lineart/lineart_cpp_bridge.cc
@@ -21,5 +21,5 @@ static bool cmp_adjacent_items(const LineartAdjacentEdge &p1, const LineartAdjac
void lineart_sort_adjacent_items(LineartAdjacentEdge *ai, int length)
{
- blender::parallel_sort(ai, ai + length - 1, cmp_adjacent_items);
+ blender::parallel_sort(ai, ai + length, cmp_adjacent_items);
}
diff --git a/source/blender/gpencil_modifiers/intern/lineart/lineart_cpu.c b/source/blender/gpencil_modifiers/intern/lineart/lineart_cpu.c
index dbe2ae0b890..c08bf3e0fe9 100644
--- a/source/blender/gpencil_modifiers/intern/lineart/lineart_cpu.c
+++ b/source/blender/gpencil_modifiers/intern/lineart/lineart_cpu.c
@@ -21,6 +21,7 @@
#include "BKE_collection.h"
#include "BKE_customdata.h"
#include "BKE_deform.h"
+#include "BKE_duplilist.h"
#include "BKE_editmesh.h"
#include "BKE_global.h"
#include "BKE_gpencil.h"
@@ -45,16 +46,41 @@
#include "DNA_scene_types.h"
#include "MEM_guardedalloc.h"
-#include "bmesh.h"
-#include "bmesh_class.h"
-#include "bmesh_tools.h"
-
#include "lineart_intern.h"
-static LineartBoundingArea *lineart_edge_first_bounding_area(LineartRenderBuffer *rb,
- LineartEdge *e);
+typedef struct LineartIsecSingle {
+ float v1[3], v2[3];
+ LineartTriangle *tri1, *tri2;
+} LineartIsecSingle;
+
+typedef struct LineartIsecThread {
+ int thread_id;
+
+ /* Scheduled work range. */
+ LineartElementLinkNode *pending_from;
+ LineartElementLinkNode *pending_to;
+ int index_from;
+ int index_to;
+
+ /* Thread intersection result data. */
+ LineartIsecSingle *array;
+ int current;
+ int max;
+ int count_test;
+
+ /* For individual thread reference.*/
+ LineartData *ld;
+} LineartIsecThread;
-static void lineart_bounding_area_link_edge(LineartRenderBuffer *rb,
+typedef struct LineartIsecData {
+ LineartData *ld;
+ LineartIsecThread *threads;
+ int thread_count;
+} LineartIsecData;
+
+static LineartBoundingArea *lineart_edge_first_bounding_area(LineartData *ld, LineartEdge *e);
+
+static void lineart_bounding_area_link_edge(LineartData *ld,
LineartBoundingArea *root_ba,
LineartEdge *e);
@@ -68,20 +94,8 @@ static LineartBoundingArea *lineart_bounding_area_next(LineartBoundingArea *this
double *next_x,
double *next_y);
-static bool lineart_get_edge_bounding_areas(LineartRenderBuffer *rb,
- LineartEdge *e,
- int *rowbegin,
- int *rowend,
- int *colbegin,
- int *colend);
-
-static void lineart_bounding_area_link_triangle(LineartRenderBuffer *rb,
- LineartBoundingArea *root_ba,
- LineartTriangle *tri,
- double *LRUB,
- int recursive,
- int recursive_level,
- bool do_intersection);
+static bool lineart_get_edge_bounding_areas(
+ LineartData *ld, LineartEdge *e, int *rowbegin, int *rowend, int *colbegin, int *colend);
static bool lineart_triangle_edge_image_space_occlusion(SpinLock *spl,
const LineartTriangle *tri,
@@ -96,54 +110,67 @@ static bool lineart_triangle_edge_image_space_occlusion(SpinLock *spl,
double *from,
double *to);
-static void lineart_add_edge_to_list(LineartRenderBuffer *rb, LineartEdge *e);
+static void lineart_add_edge_to_array(LineartPendingEdges *pe, LineartEdge *e);
+
+static void lineart_bounding_area_link_triangle(LineartData *ld,
+ LineartBoundingArea *root_ba,
+ LineartTriangle *tri,
+ double *LRUB,
+ int recursive,
+ int recursive_level,
+ bool do_intersection,
+ struct LineartIsecThread *th);
+
+static void lineart_free_bounding_area_memory(LineartBoundingArea *ba, bool recursive);
+
+static void lineart_free_bounding_area_memories(LineartData *ld);
static LineartCache *lineart_init_cache(void);
-static void lineart_discard_segment(LineartRenderBuffer *rb, LineartEdgeSegment *es)
+static void lineart_discard_segment(LineartData *ld, LineartEdgeSegment *es)
{
- BLI_spin_lock(&rb->lock_cuts);
+ BLI_spin_lock(&ld->lock_cuts);
memset(es, 0, sizeof(LineartEdgeSegment));
/* Storing the node for potentially reuse the memory for new segment data.
* Line Art data is not freed after all calculations are done. */
- BLI_addtail(&rb->wasted_cuts, es);
+ BLI_addtail(&ld->wasted_cuts, es);
- BLI_spin_unlock(&rb->lock_cuts);
+ BLI_spin_unlock(&ld->lock_cuts);
}
-static LineartEdgeSegment *lineart_give_segment(LineartRenderBuffer *rb)
+static LineartEdgeSegment *lineart_give_segment(LineartData *ld)
{
- BLI_spin_lock(&rb->lock_cuts);
+ BLI_spin_lock(&ld->lock_cuts);
/* See if there is any already allocated memory we can reuse. */
- if (rb->wasted_cuts.first) {
- LineartEdgeSegment *es = (LineartEdgeSegment *)BLI_pophead(&rb->wasted_cuts);
- BLI_spin_unlock(&rb->lock_cuts);
+ if (ld->wasted_cuts.first) {
+ LineartEdgeSegment *es = (LineartEdgeSegment *)BLI_pophead(&ld->wasted_cuts);
+ BLI_spin_unlock(&ld->lock_cuts);
memset(es, 0, sizeof(LineartEdgeSegment));
return es;
}
- BLI_spin_unlock(&rb->lock_cuts);
+ BLI_spin_unlock(&ld->lock_cuts);
/* Otherwise allocate some new memory. */
- return (LineartEdgeSegment *)lineart_mem_acquire_thread(&rb->render_data_pool,
+ return (LineartEdgeSegment *)lineart_mem_acquire_thread(&ld->render_data_pool,
sizeof(LineartEdgeSegment));
}
/**
* Cuts the edge in image space and mark occlusion level for each segment.
*/
-static void lineart_edge_cut(LineartRenderBuffer *rb,
+static void lineart_edge_cut(LineartData *ld,
LineartEdge *e,
double start,
double end,
uchar material_mask_bits,
uchar mat_occlusion)
{
- LineartEdgeSegment *es, *ies, *next_es, *prev_es;
+ LineartEdgeSegment *seg, *i_seg, *next_seg, *prev_seg;
LineartEdgeSegment *cut_start_before = 0, *cut_end_before = 0;
- LineartEdgeSegment *ns = 0, *ns2 = 0;
+ LineartEdgeSegment *new_seg1 = 0, *new_seg2 = 0;
int untouched = 0;
/* If for some reason the occlusion function may give a result that has zero length, or reversed
@@ -170,132 +197,136 @@ static void lineart_edge_cut(LineartRenderBuffer *rb,
/* Begin looking for starting position of the segment. */
/* Not using a list iteration macro because of it more clear when using for loops to iterate
* through the segments. */
- for (es = e->segments.first; es; es = es->next) {
- if (LRT_DOUBLE_CLOSE_ENOUGH(es->at, start)) {
- cut_start_before = es;
- ns = cut_start_before;
+ for (seg = e->segments.first; seg; seg = seg->next) {
+ if (LRT_DOUBLE_CLOSE_ENOUGH(seg->at, start)) {
+ cut_start_before = seg;
+ new_seg1 = cut_start_before;
break;
}
- if (es->next == NULL) {
+ if (seg->next == NULL) {
break;
}
- ies = es->next;
- if (ies->at > start + 1e-09 && start > es->at) {
- cut_start_before = ies;
- ns = lineart_give_segment(rb);
+ i_seg = seg->next;
+ if (i_seg->at > start + 1e-09 && start > seg->at) {
+ cut_start_before = i_seg;
+ new_seg1 = lineart_give_segment(ld);
break;
}
}
if (!cut_start_before && LRT_DOUBLE_CLOSE_ENOUGH(1, end)) {
untouched = 1;
}
- for (es = cut_start_before; es; es = es->next) {
+ for (seg = cut_start_before; seg; seg = seg->next) {
/* We tried to cut at existing cutting point (e.g. where the line's occluded by a triangle
* strip). */
- if (LRT_DOUBLE_CLOSE_ENOUGH(es->at, end)) {
- cut_end_before = es;
- ns2 = cut_end_before;
+ if (LRT_DOUBLE_CLOSE_ENOUGH(seg->at, end)) {
+ cut_end_before = seg;
+ new_seg2 = cut_end_before;
break;
}
/* This check is to prevent `es->at == 1.0` (where we don't need to cut because we are at the
* end point). */
- if (!es->next && LRT_DOUBLE_CLOSE_ENOUGH(1, end)) {
- cut_end_before = es;
- ns2 = cut_end_before;
+ if (!seg->next && LRT_DOUBLE_CLOSE_ENOUGH(1, end)) {
+ cut_end_before = seg;
+ new_seg2 = cut_end_before;
untouched = 1;
break;
}
/* When an actual cut is needed in the line. */
- if (es->at > end) {
- cut_end_before = es;
- ns2 = lineart_give_segment(rb);
+ if (seg->at > end) {
+ cut_end_before = seg;
+ new_seg2 = lineart_give_segment(ld);
break;
}
}
/* When we still can't find any existing cut in the line, we allocate new ones. */
- if (ns == NULL) {
- ns = lineart_give_segment(rb);
+ if (new_seg1 == NULL) {
+ new_seg1 = lineart_give_segment(ld);
}
- if (ns2 == NULL) {
+ if (new_seg2 == NULL) {
if (untouched) {
- ns2 = ns;
- cut_end_before = ns2;
+ new_seg2 = new_seg1;
+ cut_end_before = new_seg2;
}
else {
- ns2 = lineart_give_segment(rb);
+ new_seg2 = lineart_give_segment(ld);
}
}
if (cut_start_before) {
- if (cut_start_before != ns) {
+ if (cut_start_before != new_seg1) {
/* Insert cutting points for when a new cut is needed. */
- ies = cut_start_before->prev ? cut_start_before->prev : NULL;
- ns->occlusion = ies ? ies->occlusion : 0;
- ns->material_mask_bits = ies->material_mask_bits;
- BLI_insertlinkbefore(&e->segments, cut_start_before, ns);
+ i_seg = cut_start_before->prev ? cut_start_before->prev : NULL;
+ if (i_seg) {
+ new_seg1->occlusion = i_seg->occlusion;
+ new_seg1->material_mask_bits = i_seg->material_mask_bits;
+ }
+ BLI_insertlinkbefore(&e->segments, cut_start_before, new_seg1);
}
/* Otherwise we already found a existing cutting point, no need to insert a new one. */
}
else {
/* We have yet to reach a existing cutting point even after we searched the whole line, so we
* append the new cut to the end. */
- ies = e->segments.last;
- ns->occlusion = ies->occlusion;
- ns->material_mask_bits = ies->material_mask_bits;
- BLI_addtail(&e->segments, ns);
+ i_seg = e->segments.last;
+ new_seg1->occlusion = i_seg->occlusion;
+ new_seg1->material_mask_bits = i_seg->material_mask_bits;
+ BLI_addtail(&e->segments, new_seg1);
}
if (cut_end_before) {
/* The same manipulation as on "cut_start_before". */
- if (cut_end_before != ns2) {
- ies = cut_end_before->prev ? cut_end_before->prev : NULL;
- ns2->occlusion = ies ? ies->occlusion : 0;
- ns2->material_mask_bits = ies ? ies->material_mask_bits : 0;
- BLI_insertlinkbefore(&e->segments, cut_end_before, ns2);
+ if (cut_end_before != new_seg2) {
+ i_seg = cut_end_before->prev ? cut_end_before->prev : NULL;
+ if (i_seg) {
+ new_seg2->occlusion = i_seg->occlusion;
+ new_seg2->material_mask_bits = i_seg->material_mask_bits;
+ }
+ BLI_insertlinkbefore(&e->segments, cut_end_before, new_seg2);
}
}
else {
- ies = e->segments.last;
- ns2->occlusion = ies->occlusion;
- ns2->material_mask_bits = ies->material_mask_bits;
- BLI_addtail(&e->segments, ns2);
+ i_seg = e->segments.last;
+ new_seg2->occlusion = i_seg->occlusion;
+ new_seg2->material_mask_bits = i_seg->material_mask_bits;
+ BLI_addtail(&e->segments, new_seg2);
}
/* If we touched the cut list, we assign the new cut position based on new cut position,
* this way we accommodate precision lost due to multiple cut inserts. */
- ns->at = start;
+ new_seg1->at = start;
if (!untouched) {
- ns2->at = end;
+ new_seg2->at = end;
}
else {
/* For the convenience of the loop below. */
- ns2 = ns2->next;
+ new_seg2 = new_seg2->next;
}
/* Register 1 level of occlusion for all touched segments. */
- for (es = ns; es && es != ns2; es = es->next) {
- es->occlusion += mat_occlusion;
- es->material_mask_bits |= material_mask_bits;
+ for (seg = new_seg1; seg && seg != new_seg2; seg = seg->next) {
+ seg->occlusion += mat_occlusion;
+ seg->material_mask_bits |= material_mask_bits;
}
/* Reduce adjacent cutting points of the same level, which saves memory. */
- char min_occ = 127;
- prev_es = NULL;
- for (es = e->segments.first; es; es = next_es) {
- next_es = es->next;
-
- if (prev_es && prev_es->occlusion == es->occlusion &&
- prev_es->material_mask_bits == es->material_mask_bits) {
- BLI_remlink(&e->segments, es);
+ int8_t min_occ = 127;
+ prev_seg = NULL;
+ for (seg = e->segments.first; seg; seg = next_seg) {
+ next_seg = seg->next;
+
+ if (prev_seg && prev_seg->occlusion == seg->occlusion &&
+ prev_seg->material_mask_bits == seg->material_mask_bits) {
+ BLI_remlink(&e->segments, seg);
/* This puts the node back to the render buffer, if more cut happens, these unused nodes get
* picked first. */
- lineart_discard_segment(rb, es);
+ lineart_discard_segment(ld, seg);
continue;
}
- min_occ = MIN2(min_occ, es->occlusion);
+ min_occ = MIN2(min_occ, seg->occlusion);
- prev_es = es;
+ prev_seg = seg;
}
e->min_occ = min_occ;
}
@@ -311,29 +342,14 @@ BLI_INLINE bool lineart_occlusion_is_adjacent_intersection(LineartEdge *e, Linea
(v2->base.flag && v2->intersecting_with == tri));
}
-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);
- memcpy(new_array, ba->linked_triangles, sizeof(LineartTriangle *) * ba->max_triangle_count);
- ba->max_triangle_count *= 2;
- ba->linked_triangles = new_array;
- }
- ba->linked_triangles[ba->triangle_count] = tri;
- ba->triangle_count++;
+static void lineart_bounding_area_triangle_reallocate(LineartBoundingArea *ba)
+{
+ ba->max_triangle_count *= 2;
+ ba->linked_triangles = MEM_recallocN(ba->linked_triangles,
+ sizeof(LineartTriangle *) * ba->max_triangle_count);
}
-static void lineart_bounding_area_line_add(LineartRenderBuffer *rb,
- LineartBoundingArea *ba,
- LineartEdge *e)
+static void lineart_bounding_area_line_add(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
@@ -342,20 +358,21 @@ static void lineart_bounding_area_line_add(LineartRenderBuffer *rb,
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);
+ LineartEdge **new_array = MEM_mallocN(sizeof(LineartEdge *) * ba->max_line_count * 2,
+ "new ba_line_array");
memcpy(new_array, ba->linked_lines, sizeof(LineartEdge *) * ba->max_line_count);
ba->max_line_count *= 2;
+ MEM_freeN(ba->linked_lines);
ba->linked_lines = new_array;
}
ba->linked_lines[ba->line_count] = e;
ba->line_count++;
}
-static void lineart_occlusion_single_line(LineartRenderBuffer *rb, LineartEdge *e, int thread_id)
+static void lineart_occlusion_single_line(LineartData *ld, LineartEdge *e, int thread_id)
{
double x = e->v1->fbcoord[0], y = e->v1->fbcoord[1];
- LineartBoundingArea *ba = lineart_edge_first_bounding_area(rb, e);
+ LineartBoundingArea *ba = lineart_edge_first_bounding_area(ld, e);
LineartBoundingArea *nba = ba;
LineartTriangleThread *tri;
@@ -384,20 +401,20 @@ static void lineart_occlusion_single_line(LineartRenderBuffer *rb, LineartEdge *
continue;
}
tri->testing_e[thread_id] = e;
- if (lineart_triangle_edge_image_space_occlusion(&rb->lock_task,
+ if (lineart_triangle_edge_image_space_occlusion(&ld->lock_task,
(const LineartTriangle *)tri,
e,
- rb->camera_pos,
- rb->cam_is_persp,
- rb->allow_overlapping_edges,
- rb->view_projection,
- rb->view_vector,
- rb->shift_x,
- rb->shift_y,
+ ld->conf.camera_pos,
+ ld->conf.cam_is_persp,
+ ld->conf.allow_overlapping_edges,
+ ld->conf.view_projection,
+ ld->conf.view_vector,
+ ld->conf.shift_x,
+ ld->conf.shift_y,
&l,
&r)) {
- lineart_edge_cut(rb, e, l, r, tri->base.material_mask_bits, tri->base.mat_occlusion);
- if (e->min_occ > rb->max_occlusion_level) {
+ lineart_edge_cut(ld, e, l, r, tri->base.material_mask_bits, tri->base.mat_occlusion);
+ if (e->min_occ > ld->conf.max_occlusion_level) {
/* No need to calculate any longer on this line because no level more than set value is
* going to show up in the rendered result. */
return;
@@ -409,72 +426,40 @@ static void lineart_occlusion_single_line(LineartRenderBuffer *rb, LineartEdge *
}
}
-static int lineart_occlusion_make_task_info(LineartRenderBuffer *rb, LineartRenderTaskInfo *rti)
+static int lineart_occlusion_make_task_info(LineartData *ld, LineartRenderTaskInfo *rti)
{
- LineartEdge *data;
- int i;
int res = 0;
+ int starting_index;
- BLI_spin_lock(&rb->lock_task);
+ BLI_spin_lock(&ld->lock_task);
-#define LRT_ASSIGN_OCCLUSION_TASK(name) \
- if (rb->name.last) { \
- data = rb->name.last; \
- rti->name.first = (void *)data; \
- for (i = 0; i < LRT_THREAD_EDGE_COUNT && data; i++) { \
- data = data->next; \
- } \
- rti->name.last = data; \
- rb->name.last = data; \
- res = 1; \
- } \
- else { \
- rti->name.first = rti->name.last = NULL; \
- }
-
- LRT_ASSIGN_OCCLUSION_TASK(contour);
- LRT_ASSIGN_OCCLUSION_TASK(intersection);
- LRT_ASSIGN_OCCLUSION_TASK(crease);
- LRT_ASSIGN_OCCLUSION_TASK(material);
- LRT_ASSIGN_OCCLUSION_TASK(edge_mark);
- LRT_ASSIGN_OCCLUSION_TASK(floating);
+ starting_index = ld->scheduled_count;
+ ld->scheduled_count += LRT_THREAD_EDGE_COUNT;
-#undef LRT_ASSIGN_OCCLUSION_TASK
+ BLI_spin_unlock(&ld->lock_task);
- BLI_spin_unlock(&rb->lock_task);
+ if (starting_index >= ld->pending_edges.next) {
+ res = 0;
+ }
+ else {
+ rti->pending_edges.array = &ld->pending_edges.array[starting_index];
+ int remaining = ld->pending_edges.next - starting_index;
+ rti->pending_edges.max = MIN2(remaining, LRT_THREAD_EDGE_COUNT);
+ res = 1;
+ }
return res;
}
static void lineart_occlusion_worker(TaskPool *__restrict UNUSED(pool), LineartRenderTaskInfo *rti)
{
- LineartRenderBuffer *rb = rti->rb;
+ LineartData *ld = rti->ld;
LineartEdge *eip;
- while (lineart_occlusion_make_task_info(rb, rti)) {
-
- for (eip = rti->contour.first; eip && eip != rti->contour.last; eip = eip->next) {
- lineart_occlusion_single_line(rb, eip, rti->thread_id);
- }
-
- for (eip = rti->crease.first; eip && eip != rti->crease.last; eip = eip->next) {
- lineart_occlusion_single_line(rb, eip, rti->thread_id);
- }
-
- for (eip = rti->intersection.first; eip && eip != rti->intersection.last; eip = eip->next) {
- lineart_occlusion_single_line(rb, eip, rti->thread_id);
- }
-
- for (eip = rti->material.first; eip && eip != rti->material.last; eip = eip->next) {
- lineart_occlusion_single_line(rb, eip, rti->thread_id);
- }
-
- for (eip = rti->edge_mark.first; eip && eip != rti->edge_mark.last; eip = eip->next) {
- lineart_occlusion_single_line(rb, eip, rti->thread_id);
- }
-
- for (eip = rti->floating.first; eip && eip != rti->floating.last; eip = eip->next) {
- lineart_occlusion_single_line(rb, eip, rti->thread_id);
+ while (lineart_occlusion_make_task_info(ld, rti)) {
+ for (int i = 0; i < rti->pending_edges.max; i++) {
+ eip = rti->pending_edges.array[i];
+ lineart_occlusion_single_line(ld, eip, rti->thread_id);
}
}
}
@@ -484,27 +469,18 @@ static void lineart_occlusion_worker(TaskPool *__restrict UNUSED(pool), LineartR
* #MOD_lineart_compute_feature_lines function.
* This function handles all occlusion calculation.
*/
-static void lineart_main_occlusion_begin(LineartRenderBuffer *rb)
+static void lineart_main_occlusion_begin(LineartData *ld)
{
- int thread_count = rb->thread_count;
+ int thread_count = ld->thread_count;
LineartRenderTaskInfo *rti = MEM_callocN(sizeof(LineartRenderTaskInfo) * thread_count,
"Task Pool");
int i;
- /* The "last" entry is used to store worker progress in the whole list.
- * These list themselves are single-direction linked, with list.first being the head. */
- rb->contour.last = rb->contour.first;
- rb->crease.last = rb->crease.first;
- rb->intersection.last = rb->intersection.first;
- rb->material.last = rb->material.first;
- rb->edge_mark.last = rb->edge_mark.first;
- rb->floating.last = rb->floating.first;
-
TaskPool *tp = BLI_task_pool_create(NULL, TASK_PRIORITY_HIGH);
for (i = 0; i < thread_count; i++) {
rti[i].thread_id = i;
- rti[i].rb = rb;
+ rti[i].ld = ld;
BLI_task_pool_push(tp, (TaskRunFunction)lineart_occlusion_worker, &rti[i], 0, NULL);
}
BLI_task_pool_work_and_wait(tp);
@@ -594,6 +570,12 @@ static int lineart_point_on_line_segment(double v[2], double v0[2], double v1[2]
return 0;
}
+enum LineartPointTri {
+ LRT_OUTSIDE_TRIANGLE = 0,
+ LRT_ON_TRIANGLE = 1,
+ LRT_INSIDE_TRIANGLE = 2,
+};
+
/**
* Same algorithm as lineart_point_inside_triangle(), but returns differently:
* 0-outside 1-on the edge 2-inside.
@@ -604,7 +586,7 @@ static int lineart_point_triangle_relation(double v[2], double v0[2], double v1[
double r;
if (lineart_point_on_line_segment(v, v0, v1) || lineart_point_on_line_segment(v, v1, v2) ||
lineart_point_on_line_segment(v, v2, v0)) {
- return 1;
+ return LRT_ON_TRIANGLE;
}
cl = (v0[0] - v[0]) * (v1[1] - v[1]) - (v0[1] - v[1]) * (v1[0] - v[0]);
@@ -612,28 +594,28 @@ static int lineart_point_triangle_relation(double v[2], double v0[2], double v1[
cl = (v1[0] - v[0]) * (v2[1] - v[1]) - (v1[1] - v[1]) * (v2[0] - v[0]);
if ((r = c * cl) < 0) {
- return 0;
+ return LRT_OUTSIDE_TRIANGLE;
}
c = cl;
cl = (v2[0] - v[0]) * (v0[1] - v[1]) - (v2[1] - v[1]) * (v0[0] - v[0]);
if ((r = c * cl) < 0) {
- return 0;
+ return LRT_OUTSIDE_TRIANGLE;
}
c = cl;
cl = (v0[0] - v[0]) * (v1[1] - v[1]) - (v0[1] - v[1]) * (v1[0] - v[0]);
if ((r = c * cl) < 0) {
- return 0;
+ return LRT_OUTSIDE_TRIANGLE;
}
if (r == 0) {
- return 1;
+ return LRT_ON_TRIANGLE;
}
- return 2;
+ return LRT_INSIDE_TRIANGLE;
}
/**
@@ -681,17 +663,17 @@ static bool lineart_point_inside_triangle3d(double v[3], double v0[3], double v1
* The following `lineart_memory_get_XXX_space` functions are for allocating new memory for some
* modified geometries in the culling stage.
*/
-static LineartElementLinkNode *lineart_memory_get_triangle_space(LineartRenderBuffer *rb)
+static LineartElementLinkNode *lineart_memory_get_triangle_space(LineartData *ld)
{
LineartElementLinkNode *eln;
/* We don't need to allocate a whole bunch of triangles because the amount of clipped triangles
* are relatively small. */
- LineartTriangle *render_triangles = lineart_mem_acquire(&rb->render_data_pool,
- 64 * rb->triangle_size);
+ LineartTriangle *render_triangles = lineart_mem_acquire(&ld->render_data_pool,
+ 64 * ld->sizeof_triangle);
- eln = lineart_list_append_pointer_pool_sized(&rb->triangle_buffer_pointers,
- &rb->render_data_pool,
+ eln = lineart_list_append_pointer_pool_sized(&ld->geom.triangle_buffer_pointers,
+ &ld->render_data_pool,
render_triangles,
sizeof(LineartElementLinkNode));
eln->element_count = 64;
@@ -700,15 +682,15 @@ static LineartElementLinkNode *lineart_memory_get_triangle_space(LineartRenderBu
return eln;
}
-static LineartElementLinkNode *lineart_memory_get_vert_space(LineartRenderBuffer *rb)
+static LineartElementLinkNode *lineart_memory_get_vert_space(LineartData *ld)
{
LineartElementLinkNode *eln;
- LineartVert *render_vertices = lineart_mem_acquire(&rb->render_data_pool,
+ LineartVert *render_vertices = lineart_mem_acquire(&ld->render_data_pool,
sizeof(LineartVert) * 64);
- eln = lineart_list_append_pointer_pool_sized(&rb->vertex_buffer_pointers,
- &rb->render_data_pool,
+ eln = lineart_list_append_pointer_pool_sized(&ld->geom.vertex_buffer_pointers,
+ &ld->render_data_pool,
render_vertices,
sizeof(LineartElementLinkNode));
eln->element_count = 64;
@@ -717,18 +699,18 @@ static LineartElementLinkNode *lineart_memory_get_vert_space(LineartRenderBuffer
return eln;
}
-static LineartElementLinkNode *lineart_memory_get_edge_space(LineartRenderBuffer *rb)
+static LineartElementLinkNode *lineart_memory_get_edge_space(LineartData *ld)
{
LineartElementLinkNode *eln;
- LineartEdge *render_edges = lineart_mem_acquire(&rb->render_data_pool, sizeof(LineartEdge) * 64);
+ LineartEdge *render_edges = lineart_mem_acquire(&ld->render_data_pool, sizeof(LineartEdge) * 64);
- eln = lineart_list_append_pointer_pool_sized(&rb->line_buffer_pointers,
- &rb->render_data_pool,
+ eln = lineart_list_append_pointer_pool_sized(&ld->geom.line_buffer_pointers,
+ &ld->render_data_pool,
render_edges,
sizeof(LineartElementLinkNode));
eln->element_count = 64;
- eln->crease_threshold = rb->crease_threshold;
+ eln->crease_threshold = ld->conf.crease_threshold;
eln->flags |= LRT_ELEMENT_IS_ADDITIONAL;
return eln;
@@ -739,6 +721,7 @@ static void lineart_triangle_post(LineartTriangle *tri, LineartTriangle *orig)
/* Just re-assign normal and set cull flag. */
copy_v3_v3_db(tri->gn, orig->gn);
tri->flags = LRT_CULL_GENERATED;
+ tri->intersection_mask = orig->intersection_mask;
tri->material_mask_bits = orig->material_mask_bits;
tri->mat_occlusion = orig->mat_occlusion;
}
@@ -756,13 +739,12 @@ static bool lineart_edge_match(LineartTriangle *tri, LineartEdge *e, int v1, int
(tri->v[v2] == e->v1 && tri->v[v1] == e->v2));
}
-static void lineart_discard_duplicated_edges(LineartEdge *old_e, int v1id, int v2id)
+static void lineart_discard_duplicated_edges(LineartEdge *old_e)
{
LineartEdge *e = old_e;
- e++;
- while (e->v1_obindex == v1id && e->v2_obindex == v2id) {
- e->flags |= LRT_EDGE_FLAG_CHAIN_PICKED;
+ while (e->flags & LRT_EDGE_FLAG_NEXT_IS_DUPLICATION) {
e++;
+ e->flags |= LRT_EDGE_FLAG_CHAIN_PICKED;
}
}
@@ -770,7 +752,7 @@ static void lineart_discard_duplicated_edges(LineartEdge *old_e, int v1id, int v
* Does near-plane cut on 1 triangle only. When cutting with far-plane, the camera vectors gets
* reversed by the caller so don't need to implement one in a different direction.
*/
-static void lineart_triangle_cull_single(LineartRenderBuffer *rb,
+static void lineart_triangle_cull_single(LineartData *ld,
LineartTriangle *tri,
int in0,
int in1,
@@ -787,17 +769,16 @@ static void lineart_triangle_cull_single(LineartRenderBuffer *rb,
LineartElementLinkNode *e_eln,
LineartElementLinkNode *t_eln)
{
- double vv1[3], vv2[3], dot1, dot2;
+ double span_v1[3], span_v2[3], dot_v1, dot_v2;
double a;
int v_count = *r_v_count;
int e_count = *r_e_count;
int t_count = *r_t_count;
- int v1_obi, v2_obi;
- char new_flag = 0;
+ uint16_t new_flag = 0;
LineartEdge *new_e, *e, *old_e;
LineartEdgeSegment *es;
- LineartTriangleAdjacent *ta;
+ LineartTriangleAdjacent *tri_adj;
if (tri->flags & (LRT_CULL_USED | LRT_CULL_GENERATED | LRT_CULL_DISCARD)) {
return;
@@ -805,62 +786,61 @@ static void lineart_triangle_cull_single(LineartRenderBuffer *rb,
/* See definition of tri->intersecting_verts and the usage in
* lineart_geometry_object_load() for details. */
- ta = (void *)tri->intersecting_verts;
+ tri_adj = (void *)tri->intersecting_verts;
LineartVert *vt = &((LineartVert *)v_eln->pointer)[v_count];
- LineartTriangle *tri1 = (void *)(((uchar *)t_eln->pointer) + rb->triangle_size * t_count);
- LineartTriangle *tri2 = (void *)(((uchar *)t_eln->pointer) + rb->triangle_size * (t_count + 1));
+ LineartTriangle *tri1 = (void *)(((uchar *)t_eln->pointer) + ld->sizeof_triangle * t_count);
+ LineartTriangle *tri2 = (void *)(((uchar *)t_eln->pointer) +
+ ld->sizeof_triangle * (t_count + 1));
new_e = &((LineartEdge *)e_eln->pointer)[e_count];
/* Init `edge` to the last `edge` entry. */
e = new_e;
#define INCREASE_EDGE \
- v1_obi = e->v1_obindex; \
- v2_obi = e->v2_obindex; \
new_e = &((LineartEdge *)e_eln->pointer)[e_count]; \
e_count++; \
e = new_e; \
- e->v1_obindex = v1_obi; \
- e->v2_obindex = v2_obi; \
- es = lineart_mem_acquire(&rb->render_data_pool, sizeof(LineartEdgeSegment)); \
+ es = lineart_mem_acquire(&ld->render_data_pool, sizeof(LineartEdgeSegment)); \
BLI_addtail(&e->segments, es);
#define SELECT_EDGE(e_num, v1_link, v2_link, new_tri) \
- if (ta->e[e_num]) { \
- old_e = ta->e[e_num]; \
+ if (tri_adj->e[e_num]) { \
+ old_e = tri_adj->e[e_num]; \
new_flag = old_e->flags; \
old_e->flags = LRT_EDGE_FLAG_CHAIN_PICKED; \
- lineart_discard_duplicated_edges(old_e, old_e->v1_obindex, old_e->v2_obindex); \
+ lineart_discard_duplicated_edges(old_e); \
INCREASE_EDGE \
e->v1 = (v1_link); \
e->v2 = (v2_link); \
+ e->v1->index = (v1_link)->index; \
+ e->v2->index = (v1_link)->index; \
e->flags = new_flag; \
e->object_ref = ob; \
e->t1 = ((old_e->t1 == tri) ? (new_tri) : (old_e->t1)); \
e->t2 = ((old_e->t2 == tri) ? (new_tri) : (old_e->t2)); \
- lineart_add_edge_to_list(rb, e); \
+ lineart_add_edge_to_array(&ld->pending_edges, e); \
}
#define RELINK_EDGE(e_num, new_tri) \
- if (ta->e[e_num]) { \
- old_e = ta->e[e_num]; \
+ if (tri_adj->e[e_num]) { \
+ old_e = tri_adj->e[e_num]; \
old_e->t1 = ((old_e->t1 == tri) ? (new_tri) : (old_e->t1)); \
old_e->t2 = ((old_e->t2 == tri) ? (new_tri) : (old_e->t2)); \
}
#define REMOVE_TRIANGLE_EDGE \
- if (ta->e[0]) { \
- ta->e[0]->flags = LRT_EDGE_FLAG_CHAIN_PICKED; \
- lineart_discard_duplicated_edges(ta->e[0], ta->e[0]->v1_obindex, ta->e[0]->v2_obindex); \
+ if (tri_adj->e[0]) { \
+ tri_adj->e[0]->flags = LRT_EDGE_FLAG_CHAIN_PICKED; \
+ lineart_discard_duplicated_edges(tri_adj->e[0]); \
} \
- if (ta->e[1]) { \
- ta->e[1]->flags = LRT_EDGE_FLAG_CHAIN_PICKED; \
- lineart_discard_duplicated_edges(ta->e[1], ta->e[1]->v1_obindex, ta->e[1]->v2_obindex); \
+ if (tri_adj->e[1]) { \
+ tri_adj->e[1]->flags = LRT_EDGE_FLAG_CHAIN_PICKED; \
+ lineart_discard_duplicated_edges(tri_adj->e[1]); \
} \
- if (ta->e[2]) { \
- ta->e[2]->flags = LRT_EDGE_FLAG_CHAIN_PICKED; \
- lineart_discard_duplicated_edges(ta->e[2], ta->e[2]->v1_obindex, ta->e[2]->v2_obindex); \
+ if (tri_adj->e[2]) { \
+ tri_adj->e[2]->flags = LRT_EDGE_FLAG_CHAIN_PICKED; \
+ lineart_discard_duplicated_edges(tri_adj->e[2]); \
}
switch (in0 + in1 + in2) {
@@ -900,22 +880,22 @@ static void lineart_triangle_cull_single(LineartRenderBuffer *rb,
if (!in0) {
/* Cut point for line 2---|-----0. */
- sub_v3_v3v3_db(vv1, tri->v[0]->gloc, cam_pos);
- sub_v3_v3v3_db(vv2, cam_pos, tri->v[2]->gloc);
- dot1 = dot_v3v3_db(vv1, view_dir);
- dot2 = dot_v3v3_db(vv2, view_dir);
- a = dot1 / (dot1 + dot2);
+ sub_v3_v3v3_db(span_v1, tri->v[0]->gloc, cam_pos);
+ sub_v3_v3v3_db(span_v2, cam_pos, tri->v[2]->gloc);
+ dot_v1 = dot_v3v3_db(span_v1, view_dir);
+ dot_v2 = dot_v3v3_db(span_v2, view_dir);
+ a = dot_v1 / (dot_v1 + dot_v2);
/* Assign it to a new point. */
interp_v3_v3v3_db(vt[0].gloc, tri->v[0]->gloc, tri->v[2]->gloc, a);
mul_v4_m4v3_db(vt[0].fbcoord, vp, vt[0].gloc);
vt[0].index = tri->v[2]->index;
/* Cut point for line 1---|-----0. */
- sub_v3_v3v3_db(vv1, tri->v[0]->gloc, cam_pos);
- sub_v3_v3v3_db(vv2, cam_pos, tri->v[1]->gloc);
- dot1 = dot_v3v3_db(vv1, view_dir);
- dot2 = dot_v3v3_db(vv2, view_dir);
- a = dot1 / (dot1 + dot2);
+ sub_v3_v3v3_db(span_v1, tri->v[0]->gloc, cam_pos);
+ sub_v3_v3v3_db(span_v2, cam_pos, tri->v[1]->gloc);
+ dot_v1 = dot_v3v3_db(span_v1, view_dir);
+ dot_v2 = dot_v3v3_db(span_v2, view_dir);
+ a = dot_v1 / (dot_v1 + dot_v2);
/* Assign it to another new point. */
interp_v3_v3v3_db(vt[1].gloc, tri->v[0]->gloc, tri->v[1]->gloc, a);
mul_v4_m4v3_db(vt[1].fbcoord, vp, vt[1].gloc);
@@ -925,7 +905,7 @@ static void lineart_triangle_cull_single(LineartRenderBuffer *rb,
INCREASE_EDGE
if (allow_boundaries) {
e->flags = LRT_EDGE_FLAG_CONTOUR;
- lineart_prepend_edge_direct(&rb->contour.first, e);
+ lineart_add_edge_to_array(&ld->pending_edges, e);
}
/* NOTE: inverting `e->v1/v2` (left/right point) doesn't matter as long as
* `tri->edge` and `tri->v` has the same sequence. and the winding direction
@@ -953,20 +933,20 @@ static void lineart_triangle_cull_single(LineartRenderBuffer *rb,
t_count += 1;
}
else if (!in2) {
- sub_v3_v3v3_db(vv1, tri->v[2]->gloc, cam_pos);
- sub_v3_v3v3_db(vv2, cam_pos, tri->v[0]->gloc);
- dot1 = dot_v3v3_db(vv1, view_dir);
- dot2 = dot_v3v3_db(vv2, view_dir);
- a = dot1 / (dot1 + dot2);
+ sub_v3_v3v3_db(span_v1, tri->v[2]->gloc, cam_pos);
+ sub_v3_v3v3_db(span_v2, cam_pos, tri->v[0]->gloc);
+ dot_v1 = dot_v3v3_db(span_v1, view_dir);
+ dot_v2 = dot_v3v3_db(span_v2, view_dir);
+ a = dot_v1 / (dot_v1 + dot_v2);
interp_v3_v3v3_db(vt[0].gloc, tri->v[2]->gloc, tri->v[0]->gloc, a);
mul_v4_m4v3_db(vt[0].fbcoord, vp, vt[0].gloc);
vt[0].index = tri->v[0]->index;
- sub_v3_v3v3_db(vv1, tri->v[2]->gloc, cam_pos);
- sub_v3_v3v3_db(vv2, cam_pos, tri->v[1]->gloc);
- dot1 = dot_v3v3_db(vv1, view_dir);
- dot2 = dot_v3v3_db(vv2, view_dir);
- a = dot1 / (dot1 + dot2);
+ sub_v3_v3v3_db(span_v1, tri->v[2]->gloc, cam_pos);
+ sub_v3_v3v3_db(span_v2, cam_pos, tri->v[1]->gloc);
+ dot_v1 = dot_v3v3_db(span_v1, view_dir);
+ dot_v2 = dot_v3v3_db(span_v2, view_dir);
+ a = dot_v1 / (dot_v1 + dot_v2);
interp_v3_v3v3_db(vt[1].gloc, tri->v[2]->gloc, tri->v[1]->gloc, a);
mul_v4_m4v3_db(vt[1].fbcoord, vp, vt[1].gloc);
vt[1].index = tri->v[1]->index;
@@ -974,7 +954,7 @@ static void lineart_triangle_cull_single(LineartRenderBuffer *rb,
INCREASE_EDGE
if (allow_boundaries) {
e->flags = LRT_EDGE_FLAG_CONTOUR;
- lineart_prepend_edge_direct(&rb->contour.first, e);
+ lineart_add_edge_to_array(&ld->pending_edges, e);
}
e->v1 = &vt[0];
e->v2 = &vt[1];
@@ -994,20 +974,20 @@ static void lineart_triangle_cull_single(LineartRenderBuffer *rb,
t_count += 1;
}
else if (!in1) {
- sub_v3_v3v3_db(vv1, tri->v[1]->gloc, cam_pos);
- sub_v3_v3v3_db(vv2, cam_pos, tri->v[2]->gloc);
- dot1 = dot_v3v3_db(vv1, view_dir);
- dot2 = dot_v3v3_db(vv2, view_dir);
- a = dot1 / (dot1 + dot2);
+ sub_v3_v3v3_db(span_v1, tri->v[1]->gloc, cam_pos);
+ sub_v3_v3v3_db(span_v2, cam_pos, tri->v[2]->gloc);
+ dot_v1 = dot_v3v3_db(span_v1, view_dir);
+ dot_v2 = dot_v3v3_db(span_v2, view_dir);
+ a = dot_v1 / (dot_v1 + dot_v2);
interp_v3_v3v3_db(vt[0].gloc, tri->v[1]->gloc, tri->v[2]->gloc, a);
mul_v4_m4v3_db(vt[0].fbcoord, vp, vt[0].gloc);
vt[0].index = tri->v[2]->index;
- sub_v3_v3v3_db(vv1, tri->v[1]->gloc, cam_pos);
- sub_v3_v3v3_db(vv2, cam_pos, tri->v[0]->gloc);
- dot1 = dot_v3v3_db(vv1, view_dir);
- dot2 = dot_v3v3_db(vv2, view_dir);
- a = dot1 / (dot1 + dot2);
+ sub_v3_v3v3_db(span_v1, tri->v[1]->gloc, cam_pos);
+ sub_v3_v3v3_db(span_v2, cam_pos, tri->v[0]->gloc);
+ dot_v1 = dot_v3v3_db(span_v1, view_dir);
+ dot_v2 = dot_v3v3_db(span_v2, view_dir);
+ a = dot_v1 / (dot_v1 + dot_v2);
interp_v3_v3v3_db(vt[1].gloc, tri->v[1]->gloc, tri->v[0]->gloc, a);
mul_v4_m4v3_db(vt[1].fbcoord, vp, vt[1].gloc);
vt[1].index = tri->v[0]->index;
@@ -1015,7 +995,7 @@ static void lineart_triangle_cull_single(LineartRenderBuffer *rb,
INCREASE_EDGE
if (allow_boundaries) {
e->flags = LRT_EDGE_FLAG_CONTOUR;
- lineart_prepend_edge_direct(&rb->contour.first, e);
+ lineart_add_edge_to_array(&ld->pending_edges, e);
}
e->v1 = &vt[1];
e->v2 = &vt[0];
@@ -1065,22 +1045,22 @@ static void lineart_triangle_cull_single(LineartRenderBuffer *rb,
*/
if (in0) {
/* Cut point for line 0---|------1. */
- sub_v3_v3v3_db(vv1, tri->v[1]->gloc, cam_pos);
- sub_v3_v3v3_db(vv2, cam_pos, tri->v[0]->gloc);
- dot1 = dot_v3v3_db(vv1, view_dir);
- dot2 = dot_v3v3_db(vv2, view_dir);
- a = dot2 / (dot1 + dot2);
+ sub_v3_v3v3_db(span_v1, tri->v[1]->gloc, cam_pos);
+ sub_v3_v3v3_db(span_v2, cam_pos, tri->v[0]->gloc);
+ dot_v1 = dot_v3v3_db(span_v1, view_dir);
+ dot_v2 = dot_v3v3_db(span_v2, view_dir);
+ a = dot_v2 / (dot_v1 + dot_v2);
/* Assign to a new point. */
interp_v3_v3v3_db(vt[0].gloc, tri->v[0]->gloc, tri->v[1]->gloc, a);
mul_v4_m4v3_db(vt[0].fbcoord, vp, vt[0].gloc);
vt[0].index = tri->v[0]->index;
/* Cut point for line 0---|------2. */
- sub_v3_v3v3_db(vv1, tri->v[2]->gloc, cam_pos);
- sub_v3_v3v3_db(vv2, cam_pos, tri->v[0]->gloc);
- dot1 = dot_v3v3_db(vv1, view_dir);
- dot2 = dot_v3v3_db(vv2, view_dir);
- a = dot2 / (dot1 + dot2);
+ sub_v3_v3v3_db(span_v1, tri->v[2]->gloc, cam_pos);
+ sub_v3_v3v3_db(span_v2, cam_pos, tri->v[0]->gloc);
+ dot_v1 = dot_v3v3_db(span_v1, view_dir);
+ dot_v2 = dot_v3v3_db(span_v2, view_dir);
+ a = dot_v2 / (dot_v1 + dot_v2);
/* Assign to other new point. */
interp_v3_v3v3_db(vt[1].gloc, tri->v[0]->gloc, tri->v[2]->gloc, a);
mul_v4_m4v3_db(vt[1].fbcoord, vp, vt[1].gloc);
@@ -1090,7 +1070,7 @@ static void lineart_triangle_cull_single(LineartRenderBuffer *rb,
INCREASE_EDGE
if (allow_boundaries) {
e->flags = LRT_EDGE_FLAG_CONTOUR;
- lineart_prepend_edge_direct(&rb->contour.first, e);
+ lineart_add_edge_to_array(&ld->pending_edges, e);
}
e->v1 = &vt[1];
e->v2 = &vt[0];
@@ -1121,20 +1101,20 @@ static void lineart_triangle_cull_single(LineartRenderBuffer *rb,
}
else if (in1) {
- sub_v3_v3v3_db(vv1, tri->v[1]->gloc, cam_pos);
- sub_v3_v3v3_db(vv2, cam_pos, tri->v[2]->gloc);
- dot1 = dot_v3v3_db(vv1, view_dir);
- dot2 = dot_v3v3_db(vv2, view_dir);
- a = dot1 / (dot1 + dot2);
+ sub_v3_v3v3_db(span_v1, tri->v[1]->gloc, cam_pos);
+ sub_v3_v3v3_db(span_v2, cam_pos, tri->v[2]->gloc);
+ dot_v1 = dot_v3v3_db(span_v1, view_dir);
+ dot_v2 = dot_v3v3_db(span_v2, view_dir);
+ a = dot_v1 / (dot_v1 + dot_v2);
interp_v3_v3v3_db(vt[0].gloc, tri->v[1]->gloc, tri->v[2]->gloc, a);
mul_v4_m4v3_db(vt[0].fbcoord, vp, vt[0].gloc);
vt[0].index = tri->v[1]->index;
- sub_v3_v3v3_db(vv1, tri->v[1]->gloc, cam_pos);
- sub_v3_v3v3_db(vv2, cam_pos, tri->v[0]->gloc);
- dot1 = dot_v3v3_db(vv1, view_dir);
- dot2 = dot_v3v3_db(vv2, view_dir);
- a = dot1 / (dot1 + dot2);
+ sub_v3_v3v3_db(span_v1, tri->v[1]->gloc, cam_pos);
+ sub_v3_v3v3_db(span_v2, cam_pos, tri->v[0]->gloc);
+ dot_v1 = dot_v3v3_db(span_v1, view_dir);
+ dot_v2 = dot_v3v3_db(span_v2, view_dir);
+ a = dot_v1 / (dot_v1 + dot_v2);
interp_v3_v3v3_db(vt[1].gloc, tri->v[1]->gloc, tri->v[0]->gloc, a);
mul_v4_m4v3_db(vt[1].fbcoord, vp, vt[1].gloc);
vt[1].index = tri->v[1]->index;
@@ -1142,10 +1122,11 @@ static void lineart_triangle_cull_single(LineartRenderBuffer *rb,
INCREASE_EDGE
if (allow_boundaries) {
e->flags = LRT_EDGE_FLAG_CONTOUR;
- lineart_prepend_edge_direct(&rb->contour.first, e);
+ lineart_add_edge_to_array(&ld->pending_edges, e);
}
e->v1 = &vt[1];
e->v2 = &vt[0];
+
e->t1 = tri1;
e->object_ref = ob;
@@ -1169,20 +1150,20 @@ static void lineart_triangle_cull_single(LineartRenderBuffer *rb,
}
else if (in2) {
- sub_v3_v3v3_db(vv1, tri->v[2]->gloc, cam_pos);
- sub_v3_v3v3_db(vv2, cam_pos, tri->v[0]->gloc);
- dot1 = dot_v3v3_db(vv1, view_dir);
- dot2 = dot_v3v3_db(vv2, view_dir);
- a = dot1 / (dot1 + dot2);
+ sub_v3_v3v3_db(span_v1, tri->v[2]->gloc, cam_pos);
+ sub_v3_v3v3_db(span_v2, cam_pos, tri->v[0]->gloc);
+ dot_v1 = dot_v3v3_db(span_v1, view_dir);
+ dot_v2 = dot_v3v3_db(span_v2, view_dir);
+ a = dot_v1 / (dot_v1 + dot_v2);
interp_v3_v3v3_db(vt[0].gloc, tri->v[2]->gloc, tri->v[0]->gloc, a);
mul_v4_m4v3_db(vt[0].fbcoord, vp, vt[0].gloc);
vt[0].index = tri->v[2]->index;
- sub_v3_v3v3_db(vv1, tri->v[2]->gloc, cam_pos);
- sub_v3_v3v3_db(vv2, cam_pos, tri->v[1]->gloc);
- dot1 = dot_v3v3_db(vv1, view_dir);
- dot2 = dot_v3v3_db(vv2, view_dir);
- a = dot1 / (dot1 + dot2);
+ sub_v3_v3v3_db(span_v1, tri->v[2]->gloc, cam_pos);
+ sub_v3_v3v3_db(span_v2, cam_pos, tri->v[1]->gloc);
+ dot_v1 = dot_v3v3_db(span_v1, view_dir);
+ dot_v2 = dot_v3v3_db(span_v2, view_dir);
+ a = dot_v1 / (dot_v1 + dot_v2);
interp_v3_v3v3_db(vt[1].gloc, tri->v[2]->gloc, tri->v[1]->gloc, a);
mul_v4_m4v3_db(vt[1].fbcoord, vp, vt[1].gloc);
vt[1].index = tri->v[2]->index;
@@ -1190,10 +1171,11 @@ static void lineart_triangle_cull_single(LineartRenderBuffer *rb,
INCREASE_EDGE
if (allow_boundaries) {
e->flags = LRT_EDGE_FLAG_CONTOUR;
- lineart_prepend_edge_direct(&rb->contour.first, e);
+ lineart_add_edge_to_array(&ld->pending_edges, e);
}
e->v1 = &vt[1];
e->v2 = &vt[0];
+
e->t1 = tri1;
e->object_ref = ob;
@@ -1233,22 +1215,22 @@ static void lineart_triangle_cull_single(LineartRenderBuffer *rb,
* new topology that represents the trimmed triangle. (which then became a triangle or a square
* formed by two triangles)
*/
-static void lineart_main_cull_triangles(LineartRenderBuffer *rb, bool clip_far)
+static void lineart_main_cull_triangles(LineartData *ld, bool clip_far)
{
LineartTriangle *tri;
LineartElementLinkNode *v_eln, *t_eln, *e_eln;
- double(*vp)[4] = rb->view_projection;
+ double(*vp)[4] = ld->conf.view_projection;
int i;
int v_count = 0, t_count = 0, e_count = 0;
Object *ob;
- bool allow_boundaries = rb->allow_boundaries;
+ bool allow_boundaries = ld->conf.allow_boundaries;
double cam_pos[3];
- double clip_start = rb->near_clip, clip_end = rb->far_clip;
+ double clip_start = ld->conf.near_clip, clip_end = ld->conf.far_clip;
double view_dir[3], clip_advance[3];
- copy_v3_v3_db(view_dir, rb->view_vector);
- copy_v3_v3_db(clip_advance, rb->view_vector);
- copy_v3_v3_db(cam_pos, rb->camera_pos);
+ copy_v3_v3_db(view_dir, ld->conf.view_vector);
+ copy_v3_v3_db(clip_advance, ld->conf.view_vector);
+ copy_v3_v3_db(cam_pos, ld->conf.camera_pos);
if (clip_far) {
/* Move starting point to end plane. */
@@ -1264,25 +1246,25 @@ static void lineart_main_cull_triangles(LineartRenderBuffer *rb, bool clip_far)
add_v3_v3_db(cam_pos, clip_advance);
}
- v_eln = lineart_memory_get_vert_space(rb);
- t_eln = lineart_memory_get_triangle_space(rb);
- e_eln = lineart_memory_get_edge_space(rb);
+ v_eln = lineart_memory_get_vert_space(ld);
+ t_eln = lineart_memory_get_triangle_space(ld);
+ e_eln = lineart_memory_get_edge_space(ld);
/* Additional memory space for storing generated points and triangles. */
#define LRT_CULL_ENSURE_MEMORY \
if (v_count > 60) { \
v_eln->element_count = v_count; \
- v_eln = lineart_memory_get_vert_space(rb); \
+ v_eln = lineart_memory_get_vert_space(ld); \
v_count = 0; \
} \
if (t_count > 60) { \
t_eln->element_count = t_count; \
- t_eln = lineart_memory_get_triangle_space(rb); \
+ t_eln = lineart_memory_get_triangle_space(ld); \
t_count = 0; \
} \
if (e_count > 60) { \
e_eln->element_count = e_count; \
- e_eln = lineart_memory_get_edge_space(rb); \
+ e_eln = lineart_memory_get_edge_space(ld); \
e_count = 0; \
}
@@ -1317,21 +1299,21 @@ static void lineart_main_cull_triangles(LineartRenderBuffer *rb, bool clip_far)
int use_w = 3;
int in0 = 0, in1 = 0, in2 = 0;
- if (!rb->cam_is_persp) {
+ if (!ld->conf.cam_is_persp) {
clip_start = -1;
clip_end = 1;
use_w = 2;
}
/* Then go through all the other triangles. */
- LISTBASE_FOREACH (LineartElementLinkNode *, eln, &rb->triangle_buffer_pointers) {
+ LISTBASE_FOREACH (LineartElementLinkNode *, eln, &ld->geom.triangle_buffer_pointers) {
if (eln->flags & LRT_ELEMENT_IS_ADDITIONAL) {
continue;
}
ob = eln->object_ref;
for (i = 0; i < eln->element_count; i++) {
/* Select the triangle in the array. */
- tri = (void *)(((uchar *)eln->pointer) + rb->triangle_size * i);
+ tri = (void *)(((uchar *)eln->pointer) + ld->sizeof_triangle * i);
if (tri->flags & LRT_CULL_DISCARD) {
continue;
@@ -1339,7 +1321,7 @@ static void lineart_main_cull_triangles(LineartRenderBuffer *rb, bool clip_far)
LRT_CULL_DECIDE_INSIDE
LRT_CULL_ENSURE_MEMORY
- lineart_triangle_cull_single(rb,
+ lineart_triangle_cull_single(ld,
tri,
in0,
in1,
@@ -1368,33 +1350,33 @@ static void lineart_main_cull_triangles(LineartRenderBuffer *rb, bool clip_far)
* Adjacent data is only used during the initial stages of computing.
* So we can free it using this function when it is not needed anymore.
*/
-static void lineart_main_free_adjacent_data(LineartRenderBuffer *rb)
+static void lineart_main_free_adjacent_data(LineartData *ld)
{
- LinkData *ld;
- while ((ld = BLI_pophead(&rb->triangle_adjacent_pointers)) != NULL) {
- MEM_freeN(ld->data);
+ LinkData *link;
+ while ((link = BLI_pophead(&ld->geom.triangle_adjacent_pointers)) != NULL) {
+ MEM_freeN(link->data);
}
- LISTBASE_FOREACH (LineartElementLinkNode *, eln, &rb->triangle_buffer_pointers) {
+ LISTBASE_FOREACH (LineartElementLinkNode *, eln, &ld->geom.triangle_buffer_pointers) {
LineartTriangle *tri = eln->pointer;
int i;
for (i = 0; i < eln->element_count; i++) {
/* See definition of tri->intersecting_verts and the usage in
* lineart_geometry_object_load() for detailed. */
tri->intersecting_verts = NULL;
- tri = (LineartTriangle *)(((uchar *)tri) + rb->triangle_size);
+ tri = (LineartTriangle *)(((uchar *)tri) + ld->sizeof_triangle);
}
}
}
-static void lineart_main_perspective_division(LineartRenderBuffer *rb)
+static void lineart_main_perspective_division(LineartData *ld)
{
LineartVert *vt;
int i;
- LISTBASE_FOREACH (LineartElementLinkNode *, eln, &rb->vertex_buffer_pointers) {
+ LISTBASE_FOREACH (LineartElementLinkNode *, eln, &ld->geom.vertex_buffer_pointers) {
vt = eln->pointer;
for (i = 0; i < eln->element_count; i++) {
- if (rb->cam_is_persp) {
+ if (ld->conf.cam_is_persp) {
/* Do not divide Z, we use Z to back transform cut points in later chaining process. */
vt[i].fbcoord[0] /= vt[i].fbcoord[3];
vt[i].fbcoord[1] /= vt[i].fbcoord[3];
@@ -1405,13 +1387,13 @@ static void lineart_main_perspective_division(LineartRenderBuffer *rb)
// `vt[i].fbcoord[2] = -2 * vt[i].fbcoord[2] / (far - near) - (far + near) / (far - near);
}
/* Shifting is always needed. */
- vt[i].fbcoord[0] -= rb->shift_x * 2;
- vt[i].fbcoord[1] -= rb->shift_y * 2;
+ vt[i].fbcoord[0] -= ld->conf.shift_x * 2;
+ vt[i].fbcoord[1] -= ld->conf.shift_y * 2;
}
}
}
-static void lineart_main_discard_out_of_frame_edges(LineartRenderBuffer *rb)
+static void lineart_main_discard_out_of_frame_edges(LineartData *ld)
{
LineartEdge *e;
int i;
@@ -1419,7 +1401,7 @@ static void lineart_main_discard_out_of_frame_edges(LineartRenderBuffer *rb)
#define LRT_VERT_OUT_OF_BOUND(v) \
(v && (v->fbcoord[0] < -1 || v->fbcoord[0] > 1 || v->fbcoord[1] < -1 || v->fbcoord[1] > 1))
- LISTBASE_FOREACH (LineartElementLinkNode *, eln, &rb->line_buffer_pointers) {
+ LISTBASE_FOREACH (LineartElementLinkNode *, eln, &ld->geom.line_buffer_pointers) {
e = (LineartEdge *)eln->pointer;
for (i = 0; i < eln->element_count; i++) {
if ((LRT_VERT_OUT_OF_BOUND(e[i].v1) && LRT_VERT_OUT_OF_BOUND(e[i].v2))) {
@@ -1456,14 +1438,22 @@ static void lineart_mvert_transform_task(void *__restrict userdata,
v->index = i;
}
-#define LRT_EDGE_FLAG_TYPE_MAX_BITS 6
+static const int LRT_MESH_EDGE_TYPES[] = {
+ LRT_EDGE_FLAG_EDGE_MARK,
+ LRT_EDGE_FLAG_CONTOUR,
+ LRT_EDGE_FLAG_CREASE,
+ LRT_EDGE_FLAG_MATERIAL,
+ LRT_EDGE_FLAG_LOOSE,
+};
+
+#define LRT_MESH_EDGE_TYPES_COUNT 5
-static int lineart_edge_type_duplication_count(char eflag)
+static int lineart_edge_type_duplication_count(int eflag)
{
int count = 0;
/* See eLineartEdgeFlag for details. */
- for (int i = 0; i < LRT_EDGE_FLAG_TYPE_MAX_BITS; i++) {
- if (eflag & (1 << i)) {
+ for (int i = 0; i < LRT_MESH_EDGE_TYPES_COUNT; i++) {
+ if (eflag & LRT_MESH_EDGE_TYPES[i]) {
count++;
}
}
@@ -1474,17 +1464,17 @@ static int lineart_edge_type_duplication_count(char eflag)
* Because we have a variable size for #LineartTriangle, we need an access helper.
* See #LineartTriangleThread for more info.
*/
-static LineartTriangle *lineart_triangle_from_index(LineartRenderBuffer *rb,
+static LineartTriangle *lineart_triangle_from_index(LineartData *ld,
LineartTriangle *rt_array,
int index)
{
- char *b = (char *)rt_array;
- b += (index * rb->triangle_size);
+ int8_t *b = (int8_t *)rt_array;
+ b += (index * ld->sizeof_triangle);
return (LineartTriangle *)b;
}
typedef struct EdgeFeatData {
- LineartRenderBuffer *rb;
+ LineartData *ld;
Mesh *me;
const MLoopTri *mlooptri;
LineartTriangle *tri_array;
@@ -1530,7 +1520,8 @@ static void lineart_identify_mlooptri_feature_edges(void *__restrict userdata,
}
bool face_mark_filtered = false;
- bool enable_face_mark = (e_feat_data->use_freestyle_face && e_feat_data->rb->filter_face_mark);
+ bool enable_face_mark = (e_feat_data->use_freestyle_face &&
+ e_feat_data->ld->conf.filter_face_mark);
bool only_contour = false;
if (enable_face_mark) {
FreestyleFace *ff1, *ff2;
@@ -1547,7 +1538,8 @@ static void lineart_identify_mlooptri_feature_edges(void *__restrict userdata,
* path is simper when it's assuming both ff1 and ff2 not NULL. */
ff2 = ff1;
}
- if (e_feat_data->rb->filter_face_mark_boundaries ^ e_feat_data->rb->filter_face_mark_invert) {
+ if (e_feat_data->ld->conf.filter_face_mark_boundaries ^
+ e_feat_data->ld->conf.filter_face_mark_invert) {
if ((ff1->flag & FREESTYLE_FACE_MARK) || (ff2->flag & FREESTYLE_FACE_MARK)) {
face_mark_filtered = true;
}
@@ -1557,12 +1549,12 @@ static void lineart_identify_mlooptri_feature_edges(void *__restrict userdata,
face_mark_filtered = true;
}
}
- if (e_feat_data->rb->filter_face_mark_invert) {
+ if (e_feat_data->ld->conf.filter_face_mark_invert) {
face_mark_filtered = !face_mark_filtered;
}
if (!face_mark_filtered) {
edge_nabr[i].flags = LRT_EDGE_FLAG_INHIBIT;
- if (e_feat_data->rb->filter_face_mark_keep_contour) {
+ if (e_feat_data->ld->conf.filter_face_mark_keep_contour) {
only_contour = true;
}
}
@@ -1581,50 +1573,50 @@ static void lineart_identify_mlooptri_feature_edges(void *__restrict userdata,
LineartTriangle *tri1, *tri2;
LineartVert *vert;
- LineartRenderBuffer *rb = e_feat_data->rb;
+ LineartData *ld = e_feat_data->ld;
int f1 = i / 3, f2 = edge_nabr[i].e / 3;
/* The mesh should already be triangulated now, so we can assume each face is a triangle. */
- tri1 = lineart_triangle_from_index(rb, e_feat_data->tri_array, f1);
- tri2 = lineart_triangle_from_index(rb, e_feat_data->tri_array, f2);
+ tri1 = lineart_triangle_from_index(ld, e_feat_data->tri_array, f1);
+ tri2 = lineart_triangle_from_index(ld, e_feat_data->tri_array, f2);
vert = &e_feat_data->v_array[edge_nabr[i].v1];
double view_vector_persp[3];
double *view_vector = view_vector_persp;
- double dot_1 = 0, dot_2 = 0;
+ double dot_v1 = 0, dot_v2 = 0;
double result;
bool material_back_face = ((tri1->flags | tri2->flags) & LRT_TRIANGLE_MAT_BACK_FACE_CULLING);
- if (rb->use_contour || rb->use_back_face_culling || material_back_face) {
- if (rb->cam_is_persp) {
- sub_v3_v3v3_db(view_vector, rb->camera_pos, vert->gloc);
+ if (ld->conf.use_contour || ld->conf.use_back_face_culling || material_back_face) {
+ if (ld->conf.cam_is_persp) {
+ sub_v3_v3v3_db(view_vector, ld->conf.camera_pos, vert->gloc);
}
else {
- view_vector = rb->view_vector;
+ view_vector = ld->conf.view_vector;
}
- dot_1 = dot_v3v3_db(view_vector, tri1->gn);
- dot_2 = dot_v3v3_db(view_vector, tri2->gn);
+ dot_v1 = dot_v3v3_db(view_vector, tri1->gn);
+ dot_v2 = dot_v3v3_db(view_vector, tri2->gn);
- if ((result = dot_1 * dot_2) <= 0 && (dot_1 + dot_2)) {
+ if ((result = dot_v1 * dot_v2) <= 0 && (dot_v1 + dot_v2)) {
edge_flag_result |= LRT_EDGE_FLAG_CONTOUR;
}
- if (rb->use_back_face_culling) {
- if (dot_1 < 0) {
+ if (ld->conf.use_back_face_culling) {
+ if (dot_v1 < 0) {
tri1->flags |= LRT_CULL_DISCARD;
}
- if (dot_2 < 0) {
+ if (dot_v2 < 0) {
tri2->flags |= LRT_CULL_DISCARD;
}
}
if (material_back_face) {
- if (tri1->flags & LRT_TRIANGLE_MAT_BACK_FACE_CULLING && dot_1 < 0) {
+ if (tri1->flags & LRT_TRIANGLE_MAT_BACK_FACE_CULLING && dot_v1 < 0) {
tri1->flags |= LRT_CULL_DISCARD;
}
- if (tri2->flags & LRT_TRIANGLE_MAT_BACK_FACE_CULLING && dot_2 < 0) {
+ if (tri2->flags & LRT_TRIANGLE_MAT_BACK_FACE_CULLING && dot_v2 < 0) {
tri2->flags |= LRT_CULL_DISCARD;
}
}
@@ -1632,9 +1624,9 @@ static void lineart_identify_mlooptri_feature_edges(void *__restrict userdata,
if (!only_contour) {
- if (rb->use_crease) {
+ if (ld->conf.use_crease) {
bool do_crease = true;
- if (!rb->force_crease && !e_feat_data->use_auto_smooth &&
+ if (!ld->conf.force_crease && !e_feat_data->use_auto_smooth &&
(me->mpoly[mlooptri[f1].poly].flag & ME_SMOOTH) &&
(me->mpoly[mlooptri[f2].poly].flag & ME_SMOOTH)) {
do_crease = false;
@@ -1647,7 +1639,7 @@ static void lineart_identify_mlooptri_feature_edges(void *__restrict userdata,
int mat1 = me->mpoly[mlooptri[f1].poly].mat_nr;
int mat2 = me->mpoly[mlooptri[f2].poly].mat_nr;
- if (rb->use_material && mat1 != mat2) {
+ if (ld->conf.use_material && mat1 != mat2) {
edge_flag_result |= LRT_EDGE_FLAG_MATERIAL;
}
}
@@ -1663,11 +1655,11 @@ static void lineart_identify_mlooptri_feature_edges(void *__restrict userdata,
if (real_edges[i % 3] >= 0) {
MEdge *medge = &me->medge[real_edges[i % 3]];
- if (rb->use_crease && rb->sharp_as_crease && (medge->flag & ME_SHARP)) {
+ if (ld->conf.use_crease && ld->conf.sharp_as_crease && (medge->flag & ME_SHARP)) {
edge_flag_result |= LRT_EDGE_FLAG_CREASE;
}
- if (rb->use_edge_marks && e_feat_data->use_freestyle_edge) {
+ if (ld->conf.use_edge_marks && e_feat_data->use_freestyle_edge) {
FreestyleEdge *fe;
int index = e_feat_data->freestyle_edge_index;
fe = &((FreestyleEdge *)me->edata.layers[index].data)[real_edges[i % 3]];
@@ -1683,7 +1675,7 @@ static void lineart_identify_mlooptri_feature_edges(void *__restrict userdata,
/* Only allocate for feature edge (instead of all edges) to save memory.
* If allow duplicated edges, one edge gets added multiple times if it has multiple types.
*/
- reduce_data->feat_edges += e_feat_data->rb->allow_duplicated_types ?
+ reduce_data->feat_edges += e_feat_data->ld->conf.allow_duplicated_types ?
lineart_edge_type_duplication_count(edge_flag_result) :
1;
}
@@ -1721,6 +1713,7 @@ static void lineart_join_loose_edge_arr(LooseEdgeData *loose_data, LooseEdgeData
sizeof(MEdge *) * to_be_joined->loose_count);
loose_data->loose_count += to_be_joined->loose_count;
MEM_freeN(to_be_joined->loose_array);
+ to_be_joined->loose_array = NULL;
}
static void lineart_add_loose_edge(LooseEdgeData *loose_data, MEdge *e)
@@ -1754,89 +1747,71 @@ static void loose_data_sum_reduce(const void *__restrict UNUSED(userdata),
lineart_join_loose_edge_arr(final, loose_chunk);
}
-static void lineart_add_edge_to_list(LineartRenderBuffer *rb, LineartEdge *e)
+static void lineart_add_edge_to_array(LineartPendingEdges *pe, LineartEdge *e)
{
- switch (e->flags) {
- case LRT_EDGE_FLAG_CONTOUR:
- lineart_prepend_edge_direct(&rb->contour.first, e);
- break;
- case LRT_EDGE_FLAG_CREASE:
- lineart_prepend_edge_direct(&rb->crease.first, e);
- break;
- case LRT_EDGE_FLAG_MATERIAL:
- lineart_prepend_edge_direct(&rb->material.first, e);
- break;
- case LRT_EDGE_FLAG_EDGE_MARK:
- lineart_prepend_edge_direct(&rb->edge_mark.first, e);
- break;
- case LRT_EDGE_FLAG_INTERSECTION:
- lineart_prepend_edge_direct(&rb->intersection.first, e);
- break;
- case LRT_EDGE_FLAG_LOOSE:
- lineart_prepend_edge_direct(&rb->floating.first, e);
- break;
+ if (pe->next >= pe->max || !pe->max) {
+ if (!pe->max) {
+ pe->max = 1000;
+ }
+
+ LineartEdge **new_array = MEM_mallocN(sizeof(LineartEdge *) * pe->max * 2,
+ "LineartPendingEdges array");
+ if (LIKELY(pe->array)) {
+ memcpy(new_array, pe->array, sizeof(LineartEdge *) * pe->max);
+ MEM_freeN(pe->array);
+ }
+ pe->max *= 2;
+ pe->array = new_array;
}
+ pe->array[pe->next] = e;
+ pe->next++;
}
-static void lineart_add_edge_to_list_thread(LineartObjectInfo *obi, LineartEdge *e)
+static void lineart_add_edge_to_array_thread(LineartObjectInfo *obi, LineartEdge *e)
{
+ lineart_add_edge_to_array(&obi->pending_edges, e);
+}
-#define LRT_ASSIGN_EDGE(name) \
- lineart_prepend_edge_direct(&obi->name.first, e); \
- if (!obi->name.last) { \
- obi->name.last = e; \
- }
- switch (e->flags) {
- case LRT_EDGE_FLAG_CONTOUR:
- LRT_ASSIGN_EDGE(contour);
- break;
- case LRT_EDGE_FLAG_CREASE:
- LRT_ASSIGN_EDGE(crease);
- break;
- case LRT_EDGE_FLAG_MATERIAL:
- LRT_ASSIGN_EDGE(material);
- break;
- case LRT_EDGE_FLAG_EDGE_MARK:
- LRT_ASSIGN_EDGE(edge_mark);
- break;
- case LRT_EDGE_FLAG_INTERSECTION:
- LRT_ASSIGN_EDGE(intersection);
- break;
- case LRT_EDGE_FLAG_LOOSE:
- LRT_ASSIGN_EDGE(floating);
- break;
+/* Note: For simplicity, this function doesn't actually do anything if you already have data in
+ * #pe. */
+static void lineart_finalize_object_edge_array_reserve(LineartPendingEdges *pe, int count)
+{
+ if (pe->max || pe->array) {
+ return;
}
-#undef LRT_ASSIGN_EDGE
+
+ pe->max = count;
+ LineartEdge **new_array = MEM_mallocN(sizeof(LineartEdge *) * pe->max,
+ "LineartPendingEdges array final");
+ pe->array = new_array;
}
-static void lineart_finalize_object_edge_list(LineartRenderBuffer *rb, LineartObjectInfo *obi)
+static void lineart_finalize_object_edge_array(LineartPendingEdges *pe, LineartObjectInfo *obi)
{
-#define LRT_OBI_TO_RB(name) \
- if (obi->name.last) { \
- ((LineartEdge *)obi->name.last)->next = rb->name.first; \
- rb->name.first = obi->name.first; \
- }
- LRT_OBI_TO_RB(contour);
- LRT_OBI_TO_RB(crease);
- LRT_OBI_TO_RB(material);
- LRT_OBI_TO_RB(edge_mark);
- LRT_OBI_TO_RB(intersection);
- LRT_OBI_TO_RB(floating);
-#undef LRT_OBI_TO_RB
+ /* In case of line art "occlusion only" or contour not enabled, it's possible for an object to
+ * not produce any feature lines. */
+ if (!obi->pending_edges.array) {
+ return;
+ }
+ memcpy(&pe->array[pe->next],
+ obi->pending_edges.array,
+ sizeof(LineartEdge *) * obi->pending_edges.next);
+ MEM_freeN(obi->pending_edges.array);
+ pe->next += obi->pending_edges.next;
}
static void lineart_triangle_adjacent_assign(LineartTriangle *tri,
- LineartTriangleAdjacent *ta,
+ LineartTriangleAdjacent *tri_adj,
LineartEdge *e)
{
if (lineart_edge_match(tri, e, 0, 1)) {
- ta->e[0] = e;
+ tri_adj->e[0] = e;
}
else if (lineart_edge_match(tri, e, 1, 2)) {
- ta->e[1] = e;
+ tri_adj->e[1] = e;
}
else if (lineart_edge_match(tri, e, 2, 0)) {
- ta->e[2] = e;
+ tri_adj->e[2] = e;
}
}
@@ -1922,7 +1897,7 @@ static void lineart_edge_neighbor_init_task(void *__restrict userdata,
adj_e->v1 = mloop[looptri->tri[i % 3]].v;
adj_e->v2 = mloop[looptri->tri[(i + 1) % 3]].v;
if (adj_e->v1 > adj_e->v2) {
- SWAP(unsigned int, adj_e->v1, adj_e->v2);
+ SWAP(uint32_t, adj_e->v1, adj_e->v2);
}
edge_nabr->e = -1;
@@ -1968,7 +1943,7 @@ static LineartEdgeNeighbor *lineart_build_edge_neighbor(Mesh *me, int total_edge
return edge_nabr;
}
-static void lineart_geometry_object_load(LineartObjectInfo *ob_info, LineartRenderBuffer *re_buf)
+static void lineart_geometry_object_load(LineartObjectInfo *ob_info, LineartData *la_data)
{
LineartElementLinkNode *elem_link_node;
LineartVert *la_v_arr;
@@ -2002,19 +1977,20 @@ static void lineart_geometry_object_load(LineartObjectInfo *ob_info, LineartRend
/* If we allow duplicated edges, one edge should get added multiple times if is has been
* classified as more than one edge type. This is so we can create multiple different line type
* chains containing the same edge. */
- la_v_arr = lineart_mem_acquire_thread(&re_buf->render_data_pool,
+ la_v_arr = lineart_mem_acquire_thread(&la_data->render_data_pool,
sizeof(LineartVert) * me->totvert);
- la_tri_arr = lineart_mem_acquire_thread(&re_buf->render_data_pool,
- tot_tri * re_buf->triangle_size);
+ la_tri_arr = lineart_mem_acquire_thread(&la_data->render_data_pool,
+ tot_tri * la_data->sizeof_triangle);
Object *orig_ob = ob_info->original_ob;
- BLI_spin_lock(&re_buf->lock_task);
- elem_link_node = lineart_list_append_pointer_pool_sized_thread(&re_buf->vertex_buffer_pointers,
- &re_buf->render_data_pool,
- la_v_arr,
- sizeof(LineartElementLinkNode));
- BLI_spin_unlock(&re_buf->lock_task);
+ BLI_spin_lock(&la_data->lock_task);
+ elem_link_node = lineart_list_append_pointer_pool_sized_thread(
+ &la_data->geom.vertex_buffer_pointers,
+ &la_data->render_data_pool,
+ la_v_arr,
+ sizeof(LineartElementLinkNode));
+ BLI_spin_unlock(&la_data->lock_task);
elem_link_node->element_count = me->totvert;
elem_link_node->object_ref = orig_ob;
@@ -2030,7 +2006,7 @@ static void lineart_geometry_object_load(LineartObjectInfo *ob_info, LineartRend
use_auto_smooth = true;
}
else {
- crease_angle = re_buf->crease_threshold;
+ crease_angle = la_data->conf.crease_threshold;
}
/* FIXME(Yiming): Hack for getting clean 3D text, the seam that extruded text object creates
@@ -2039,12 +2015,13 @@ static void lineart_geometry_object_load(LineartObjectInfo *ob_info, LineartRend
elem_link_node->flags |= LRT_ELEMENT_BORDER_ONLY;
}
- BLI_spin_lock(&re_buf->lock_task);
- elem_link_node = lineart_list_append_pointer_pool_sized_thread(&re_buf->triangle_buffer_pointers,
- &re_buf->render_data_pool,
- la_tri_arr,
- sizeof(LineartElementLinkNode));
- BLI_spin_unlock(&re_buf->lock_task);
+ BLI_spin_lock(&la_data->lock_task);
+ elem_link_node = lineart_list_append_pointer_pool_sized_thread(
+ &la_data->geom.triangle_buffer_pointers,
+ &la_data->render_data_pool,
+ la_tri_arr,
+ sizeof(LineartElementLinkNode));
+ BLI_spin_unlock(&la_data->lock_task);
int usage = ob_info->usage;
@@ -2056,10 +2033,10 @@ static void lineart_geometry_object_load(LineartObjectInfo *ob_info, LineartRend
LineartTriangleAdjacent *tri_adj = MEM_callocN(sizeof(LineartTriangleAdjacent) * tot_tri,
"LineartTriangleAdjacent");
/* Link is minimal so we use pool anyway. */
- BLI_spin_lock(&re_buf->lock_task);
+ BLI_spin_lock(&la_data->lock_task);
lineart_list_append_pointer_pool_thread(
- &re_buf->triangle_adjacent_pointers, &re_buf->render_data_pool, tri_adj);
- BLI_spin_unlock(&re_buf->lock_task);
+ &la_data->geom.triangle_adjacent_pointers, &la_data->render_data_pool, tri_adj);
+ BLI_spin_unlock(&la_data->lock_task);
/* Convert all vertices to lineart verts. */
TaskParallelSettings vert_settings;
@@ -2075,11 +2052,6 @@ static void lineart_geometry_object_load(LineartObjectInfo *ob_info, LineartRend
BLI_task_parallel_range(
0, me->totvert, &vert_data, lineart_mvert_transform_task, &vert_settings);
- /* Register a global index increment. See #lineart_triangle_share_edge() and
- * #lineart_main_load_geometries() for detailed. It's okay that global_vindex might eventually
- * overflow, in such large scene it's virtually impossible for two vertex of the same numeric
- * index to come close together. */
- ob_info->global_i_offset = me->totvert;
/* Convert all mesh triangles into lineart triangles.
* Also create an edge map to get connectivity between edges and triangles. */
@@ -2093,10 +2065,10 @@ static void lineart_geometry_object_load(LineartObjectInfo *ob_info, LineartRend
tri_data.mlooptri = mlooptri;
tri_data.vert_arr = la_v_arr;
tri_data.tri_arr = la_tri_arr;
- tri_data.lineart_triangle_size = re_buf->triangle_size;
+ tri_data.lineart_triangle_size = la_data->sizeof_triangle;
tri_data.tri_adj = tri_adj;
- unsigned int total_edges = tot_tri * 3;
+ uint32_t total_edges = tot_tri * 3;
BLI_task_parallel_range(0, tot_tri, &tri_data, lineart_load_tri_task, &tri_settings);
@@ -2114,7 +2086,7 @@ static void lineart_geometry_object_load(LineartObjectInfo *ob_info, LineartRend
edge_feat_settings.func_reduce = feat_data_sum_reduce;
EdgeFeatData edge_feat_data = {0};
- edge_feat_data.rb = re_buf;
+ edge_feat_data.ld = la_data;
edge_feat_data.me = me;
edge_feat_data.mlooptri = mlooptri;
edge_feat_data.edge_nabr = lineart_build_edge_neighbor(me, total_edges);
@@ -2140,7 +2112,7 @@ static void lineart_geometry_object_load(LineartObjectInfo *ob_info, LineartRend
&edge_feat_settings);
LooseEdgeData loose_data = {0};
- if (re_buf->use_loose) {
+ if (la_data->conf.use_loose) {
/* Only identifying floating edges at this point because other edges has been taken care of
* inside #lineart_identify_mlooptri_feature_edges function. */
TaskParallelSettings edge_loose_settings;
@@ -2156,20 +2128,21 @@ static void lineart_geometry_object_load(LineartObjectInfo *ob_info, LineartRend
int allocate_la_e = edge_reduce.feat_edges + loose_data.loose_count;
- la_edge_arr = lineart_mem_acquire_thread(&re_buf->render_data_pool,
+ la_edge_arr = lineart_mem_acquire_thread(&la_data->render_data_pool,
sizeof(LineartEdge) * allocate_la_e);
- la_seg_arr = lineart_mem_acquire_thread(&re_buf->render_data_pool,
+ la_seg_arr = lineart_mem_acquire_thread(&la_data->render_data_pool,
sizeof(LineartEdgeSegment) * allocate_la_e);
- BLI_spin_lock(&re_buf->lock_task);
- elem_link_node = lineart_list_append_pointer_pool_sized_thread(&re_buf->line_buffer_pointers,
- &re_buf->render_data_pool,
- la_edge_arr,
- sizeof(LineartElementLinkNode));
- BLI_spin_unlock(&re_buf->lock_task);
+ BLI_spin_lock(&la_data->lock_task);
+ elem_link_node = lineart_list_append_pointer_pool_sized_thread(
+ &la_data->geom.line_buffer_pointers,
+ &la_data->render_data_pool,
+ la_edge_arr,
+ sizeof(LineartElementLinkNode));
+ BLI_spin_unlock(&la_data->lock_task);
elem_link_node->element_count = allocate_la_e;
elem_link_node->object_ref = orig_ob;
- // Start of the edge/seg arr
+ /* Start of the edge/seg arr */
LineartEdge *la_edge;
LineartEdgeSegment *la_seg;
la_edge = la_edge_arr;
@@ -2187,27 +2160,25 @@ static void lineart_geometry_object_load(LineartObjectInfo *ob_info, LineartRend
continue;
}
- bool edge_added = false;
+ LineartEdge *edge_added = NULL;
/* See eLineartEdgeFlag for details. */
- for (int flag_bit = 0; flag_bit < LRT_EDGE_FLAG_TYPE_MAX_BITS; flag_bit++) {
- char use_type = 1 << flag_bit;
+ for (int flag_bit = 0; flag_bit < LRT_MESH_EDGE_TYPES_COUNT; flag_bit++) {
+ int use_type = LRT_MESH_EDGE_TYPES[flag_bit];
if (!(use_type & edge_nabr->flags)) {
continue;
}
la_edge->v1 = &la_v_arr[edge_nabr->v1];
la_edge->v2 = &la_v_arr[edge_nabr->v2];
- la_edge->v1_obindex = la_edge->v1->index;
- la_edge->v2_obindex = la_edge->v2->index;
int findex = i / 3;
- la_edge->t1 = lineart_triangle_from_index(re_buf, la_tri_arr, findex);
+ la_edge->t1 = lineart_triangle_from_index(la_data, la_tri_arr, findex);
if (!edge_added) {
lineart_triangle_adjacent_assign(la_edge->t1, &tri_adj[findex], la_edge);
}
if (edge_nabr->e != -1) {
findex = edge_nabr->e / 3;
- la_edge->t2 = lineart_triangle_from_index(re_buf, la_tri_arr, findex);
+ la_edge->t2 = lineart_triangle_from_index(la_data, la_tri_arr, findex);
if (!edge_added) {
lineart_triangle_adjacent_assign(la_edge->t2, &tri_adj[findex], la_edge);
}
@@ -2217,15 +2188,19 @@ static void lineart_geometry_object_load(LineartObjectInfo *ob_info, LineartRend
BLI_addtail(&la_edge->segments, la_seg);
if (usage == OBJECT_LRT_INHERIT || usage == OBJECT_LRT_INCLUDE ||
usage == OBJECT_LRT_NO_INTERSECTION) {
- lineart_add_edge_to_list_thread(ob_info, la_edge);
+ lineart_add_edge_to_array_thread(ob_info, la_edge);
+ }
+
+ if (edge_added) {
+ edge_added->flags |= LRT_EDGE_FLAG_NEXT_IS_DUPLICATION;
}
- edge_added = true;
+ edge_added = la_edge;
la_edge++;
la_seg++;
- if (!re_buf->allow_duplicated_types) {
+ if (!la_data->conf.allow_duplicated_types) {
break;
}
}
@@ -2235,14 +2210,12 @@ static void lineart_geometry_object_load(LineartObjectInfo *ob_info, LineartRend
for (int i = 0; i < loose_data.loose_count; i++) {
la_edge->v1 = &la_v_arr[loose_data.loose_array[i]->v1];
la_edge->v2 = &la_v_arr[loose_data.loose_array[i]->v2];
- la_edge->v1_obindex = la_edge->v1->index;
- la_edge->v2_obindex = la_edge->v2->index;
la_edge->flags = LRT_EDGE_FLAG_LOOSE;
la_edge->object_ref = orig_ob;
BLI_addtail(&la_edge->segments, la_seg);
if (usage == OBJECT_LRT_INHERIT || usage == OBJECT_LRT_INCLUDE ||
usage == OBJECT_LRT_NO_INTERSECTION) {
- lineart_add_edge_to_list_thread(ob_info, la_edge);
+ lineart_add_edge_to_array_thread(ob_info, la_edge);
}
la_edge++;
la_seg++;
@@ -2261,10 +2234,7 @@ static void lineart_object_load_worker(TaskPool *__restrict UNUSED(pool),
LineartObjectLoadTaskInfo *olti)
{
for (LineartObjectInfo *obi = olti->pending; obi; obi = obi->next) {
- lineart_geometry_object_load(obi, olti->rb);
- if (G.debug_value == 4000) {
- printf("thread id: %d processed: %d\n", olti->thread_id, obi->original_me->totpoly);
- }
+ lineart_geometry_object_load(obi, olti->ld);
}
}
@@ -2342,7 +2312,7 @@ static void lineart_geometry_load_assign_thread(LineartObjectLoadTaskInfo *olti_
int this_face_count)
{
LineartObjectLoadTaskInfo *use_olti = olti_list;
- long unsigned int min_face = use_olti->total_faces;
+ uint64_t min_face = use_olti->total_faces;
for (int i = 0; i < thread_count; i++) {
if (olti_list[i].total_faces < min_face) {
min_face = olti_list[i].total_faces;
@@ -2358,18 +2328,21 @@ static void lineart_geometry_load_assign_thread(LineartObjectLoadTaskInfo *olti_
static bool lineart_geometry_check_visible(double (*model_view_proj)[4],
double shift_x,
double shift_y,
- Object *use_ob)
+ Mesh *use_mesh)
{
- const BoundBox *bb = BKE_object_boundbox_get(use_ob);
- if (!bb) {
- /* For lights and empty stuff there will be no bbox. */
+ if (!use_mesh) {
return false;
}
+ float mesh_min[3], mesh_max[3];
+ INIT_MINMAX(mesh_min, mesh_max);
+ BKE_mesh_minmax(use_mesh, mesh_min, mesh_max);
+ BoundBox bb = {0};
+ BKE_boundbox_init_from_minmax(&bb, mesh_min, mesh_max);
double co[8][4];
double tmp[3];
for (int i = 0; i < 8; i++) {
- copy_v3db_v3fl(co[i], bb->vec[i]);
+ copy_v3db_v3fl(co[i], bb.vec[i]);
copy_v3_v3_db(tmp, co[i]);
mul_v4_m4v3_db(co[i], model_view_proj, tmp);
co[i][0] -= shift_x * 2 * co[i][3];
@@ -2395,19 +2368,83 @@ static bool lineart_geometry_check_visible(double (*model_view_proj)[4],
return true;
}
+static void lineart_object_load_single_instance(LineartData *ld,
+ Depsgraph *depsgraph,
+ Scene *scene,
+ Object *ob,
+ Object *ref_ob,
+ float use_mat[4][4],
+ bool is_render,
+ LineartObjectLoadTaskInfo *olti,
+ int thread_count)
+{
+ LineartObjectInfo *obi = lineart_mem_acquire(&ld->render_data_pool, sizeof(LineartObjectInfo));
+ obi->usage = lineart_usage_check(scene->master_collection, ob, is_render);
+ obi->override_intersection_mask = lineart_intersection_mask_check(scene->master_collection, ob);
+ Mesh *use_mesh;
+
+ if (obi->usage == OBJECT_LRT_EXCLUDE) {
+ return;
+ }
+
+ /* Prepare the matrix used for transforming this specific object (instance). This has to be
+ * done before mesh boundbox check because the function needs that. */
+ mul_m4db_m4db_m4fl_uniq(obi->model_view_proj, ld->conf.view_projection, use_mat);
+ mul_m4db_m4db_m4fl_uniq(obi->model_view, ld->conf.view, use_mat);
+
+ if (!ELEM(ob->type, OB_MESH, OB_MBALL, OB_CURVES_LEGACY, OB_SURF, OB_FONT)) {
+ return;
+ }
+ if (ob->type == OB_MESH) {
+ use_mesh = BKE_object_get_evaluated_mesh(ob);
+ if (use_mesh->edit_mesh) {
+ /* If the object is being edited, then the mesh is not evaluated fully into the final
+ * result, do not load them. */
+ return;
+ }
+ }
+ else {
+ use_mesh = BKE_mesh_new_from_object(depsgraph, ob, true, true);
+ }
+
+ /* In case we still can not get any mesh geometry data from the object */
+ if (!use_mesh) {
+ return;
+ }
+
+ if (!lineart_geometry_check_visible(
+ obi->model_view_proj, ld->conf.shift_x, ld->conf.shift_y, use_mesh)) {
+ return;
+ }
+
+ if (ob->type != OB_MESH) {
+ obi->free_use_mesh = true;
+ }
+
+ /* Make normal matrix. */
+ float imat[4][4];
+ invert_m4_m4(imat, use_mat);
+ transpose_m4(imat);
+ copy_m4d_m4(obi->normal, imat);
+
+ obi->original_me = use_mesh;
+ obi->original_ob = (ref_ob->id.orig_id ? (Object *)ref_ob->id.orig_id : (Object *)ref_ob);
+ lineart_geometry_load_assign_thread(olti, obi, thread_count, use_mesh->totpoly);
+}
+
static void lineart_main_load_geometries(
Depsgraph *depsgraph,
Scene *scene,
Object *camera /* Still use camera arg for convenience. */,
- LineartRenderBuffer *rb,
+ LineartData *ld,
bool allow_duplicates)
{
double proj[4][4], view[4][4], result[4][4];
float inv[4][4];
Camera *cam = camera->data;
float sensor = BKE_camera_sensor_size(cam->sensor_fit, cam->sensor_x, cam->sensor_y);
- int fit = BKE_camera_sensor_fit(cam->sensor_fit, rb->w, rb->h);
- double asp = ((double)rb->w / (double)rb->h);
+ int fit = BKE_camera_sensor_fit(cam->sensor_fit, ld->w, ld->h);
+ double asp = ((double)ld->w / (double)ld->h);
int bound_box_discard_count = 0;
@@ -2418,7 +2455,7 @@ static void lineart_main_load_geometries(
if (fit == CAMERA_SENSOR_FIT_HOR && asp < 1) {
sensor /= asp;
}
- const double fov = focallength_to_fov(cam->lens / (1 + rb->overscan), sensor);
+ const double fov = focallength_to_fov(cam->lens / (1 + ld->conf.overscan), sensor);
lineart_matrix_perspective_44d(proj, fov, asp, cam->clip_start, cam->clip_end);
}
else if (cam->type == CAM_ORTHO) {
@@ -2426,22 +2463,30 @@ static void lineart_main_load_geometries(
lineart_matrix_ortho_44d(proj, -w, w, -w / asp, w / asp, cam->clip_start, cam->clip_end);
}
- double t_start;
+ invert_m4_m4(inv, ld->conf.cam_obmat);
+ mul_m4db_m4db_m4fl_uniq(result, proj, inv);
+ copy_m4_m4_db(proj, result);
+ copy_m4_m4_db(ld->conf.view_projection, proj);
+ unit_m4_db(view);
+ copy_m4_m4_db(ld->conf.view, view);
+
+ BLI_listbase_clear(&ld->geom.triangle_buffer_pointers);
+ BLI_listbase_clear(&ld->geom.vertex_buffer_pointers);
+
+ double t_start;
if (G.debug_value == 4000) {
t_start = PIL_check_seconds_timer();
}
- invert_m4_m4(inv, rb->cam_obmat);
- mul_m4db_m4db_m4fl_uniq(result, proj, inv);
- copy_m4_m4_db(proj, result);
- copy_m4_m4_db(rb->view_projection, proj);
+ int thread_count = ld->thread_count;
- unit_m4_db(view);
- copy_m4_m4_db(rb->view, view);
+ /* This memory is in render buffer memory pool. So we don't need to free those after loading. */
+ LineartObjectLoadTaskInfo *olti = lineart_mem_acquire(
+ &ld->render_data_pool, sizeof(LineartObjectLoadTaskInfo) * thread_count);
- BLI_listbase_clear(&rb->triangle_buffer_pointers);
- BLI_listbase_clear(&rb->vertex_buffer_pointers);
+ eEvaluationMode eval_mode = DEG_get_mode(depsgraph);
+ bool is_render = eval_mode == DAG_EVAL_RENDER;
int flags = DEG_ITER_OBJECT_FLAG_LINKED_DIRECTLY | DEG_ITER_OBJECT_FLAG_LINKED_VIA_SET |
DEG_ITER_OBJECT_FLAG_VISIBLE;
@@ -2451,74 +2496,25 @@ static void lineart_main_load_geometries(
flags |= DEG_ITER_OBJECT_FLAG_DUPLI;
}
- int thread_count = rb->thread_count;
-
- /* 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);
-
- bool is_render = DEG_get_mode(depsgraph) == DAG_EVAL_RENDER;
-
+ /* XXX(@Yiming): Temporary solution, this iterator is technically unsafe to use *during*
+ * depsgraph evaluation, see D14997 for detailed explanations. */
DEG_OBJECT_ITER_BEGIN (depsgraph, ob, flags) {
- LineartObjectInfo *obi = lineart_mem_acquire(&rb->render_data_pool, sizeof(LineartObjectInfo));
- obi->usage = lineart_usage_check(scene->master_collection, ob, is_render);
- obi->override_intersection_mask = lineart_intersection_mask_check(scene->master_collection,
- ob);
- Mesh *use_mesh;
-
- if (obi->usage == OBJECT_LRT_EXCLUDE) {
- continue;
- }
-
- Object *use_ob = DEG_get_evaluated_object(depsgraph, ob);
- /* Prepare the matrix used for transforming this specific object (instance). This has to be
- * done before mesh boundbox check because the function needs that. */
- mul_m4db_m4db_m4fl_uniq(obi->model_view_proj, rb->view_projection, ob->obmat);
- mul_m4db_m4db_m4fl_uniq(obi->model_view, rb->view, ob->obmat);
+ Object *eval_ob = DEG_get_evaluated_object(depsgraph, ob);
- if (!ELEM(use_ob->type, OB_MESH, OB_MBALL, OB_CURVES_LEGACY, OB_SURF, OB_FONT)) {
+ if (!eval_ob) {
continue;
}
- if (!lineart_geometry_check_visible(obi->model_view_proj, rb->shift_x, rb->shift_y, use_ob)) {
- if (G.debug_value == 4000) {
- bound_box_discard_count++;
- }
- continue;
- }
-
- if (use_ob->type == OB_MESH) {
- use_mesh = BKE_object_get_evaluated_mesh(use_ob);
- }
- else {
- /* If DEG_ITER_OBJECT_FLAG_DUPLI is set, some curve objects may also have an evaluated mesh
- * object in the list. To avoid adding duplicate geometry, ignore evaluated curve objects
- * in those cases. */
- if (allow_duplicates && BKE_object_get_evaluated_mesh(ob) != NULL) {
- continue;
- }
- use_mesh = BKE_mesh_new_from_object(depsgraph, use_ob, true, true);
- }
-
- /* In case we still can not get any mesh geometry data from the object */
- if (!use_mesh) {
+ /* DEG_OBJECT_ITER_BEGIN will include the instanced mesh of these curve object types, so don't
+ * load them twice. */
+ if (allow_duplicates && ELEM(ob->type, OB_CURVES_LEGACY, OB_FONT, OB_SURF)) {
continue;
}
- if (ob->type != OB_MESH) {
- obi->free_use_mesh = true;
+ if (BKE_object_visibility(eval_ob, eval_mode) & OB_VISIBLE_SELF) {
+ lineart_object_load_single_instance(
+ ld, depsgraph, scene, eval_ob, eval_ob, eval_ob->obmat, is_render, olti, thread_count);
}
-
- /* Make normal matrix. */
- float imat[4][4];
- invert_m4_m4(imat, ob->obmat);
- transpose_m4(imat);
- copy_m4d_m4(obi->normal, imat);
-
- obi->original_me = use_mesh;
- obi->original_ob = (ob->id.orig_id ? (Object *)ob->id.orig_id : (Object *)ob);
- lineart_geometry_load_assign_thread(olti, obi, thread_count, use_mesh->totpoly);
}
DEG_OBJECT_ITER_END;
@@ -2528,7 +2524,7 @@ static void lineart_main_load_geometries(
printf("thread count: %d\n", thread_count);
}
for (int i = 0; i < thread_count; i++) {
- olti[i].rb = rb;
+ olti[i].ld = ld;
olti[i].thread_id = i;
BLI_task_pool_push(tp, (TaskRunFunction)lineart_object_load_worker, &olti[i], 0, NULL);
}
@@ -2539,6 +2535,17 @@ static void lineart_main_load_geometries(
* lineart_triangle_share_edge() can work properly from the lack of triangle adjacent info. */
int global_i = 0;
+ int edge_count = 0;
+ for (int i = 0; i < thread_count; i++) {
+ for (LineartObjectInfo *obi = olti[i].pending; obi; obi = obi->next) {
+ if (!obi->v_eln) {
+ continue;
+ }
+ edge_count += obi->pending_edges.next;
+ }
+ }
+ lineart_finalize_object_edge_array_reserve(&ld->pending_edges, edge_count);
+
for (int i = 0; i < thread_count; i++) {
for (LineartObjectInfo *obi = olti[i].pending; obi; obi = obi->next) {
if (!obi->v_eln) {
@@ -2549,8 +2556,13 @@ static void lineart_main_load_geometries(
for (int vi = 0; vi < v_count; vi++) {
v[vi].index += global_i;
}
+ /* Register a global index increment. See #lineart_triangle_share_edge() and
+ * #lineart_main_load_geometries() for detailed. It's okay that global_vindex might
+ * eventually overflow, in such large scene it's virtually impossible for two vertex of the
+ * same numeric index to come close together. */
+ obi->global_i_offset = global_i;
global_i += v_count;
- lineart_finalize_object_edge_list(rb, obi);
+ lineart_finalize_object_edge_array(&ld->pending_edges, obi);
}
}
@@ -2644,6 +2656,9 @@ static bool lineart_edge_from_triangle(const LineartTriangle *tri,
(num > is[order[1]] ? order[1] : (num > is[order[0]] ? order[0] : -1))); \
}
+#define LRT_ISEC(index) (index == 0 ? isec_e1 : (index == 1 ? isec_e2 : isec_e3))
+#define LRT_PARALLEL(index) (index == 0 ? para_e1 : (index == 1 ? para_e2 : para_e3))
+
/**
* This is the main function to calculate
* the occlusion status between 1(one) triangle and 1(one) line.
@@ -2657,7 +2672,7 @@ static bool lineart_edge_from_triangle(const LineartTriangle *tri,
* extruding from one of the triangle's point. To get the information using one math process can
* solve this problem.
*
- * 2) Currently using discrete a/b/c/pa/pb/pc/is[3] values for storing
+ * 2) Currently using discrete a/b/c/para_e1/para_e2/para_e3/is[3] values for storing
* intersection/edge_aligned/intersection_order info, which isn't optimal, needs a better
* representation (likely a struct) for readability and clarity of code path.
*
@@ -2679,18 +2694,20 @@ static bool lineart_triangle_edge_image_space_occlusion(SpinLock *UNUSED(spl),
double *from,
double *to)
{
- double is[3] = {0};
- int order[3];
- int LCross = -1, RCross = -1;
- int a, b, c; /* Crossing info. */
- bool pa, pb, pc; /* Parallel info. */
- int st_l = 0, st_r = 0;
-
- double Lv[3];
- double Rv[3];
- double vd4[4];
- double Cv[3];
- double dot_l, dot_r, dot_la, dot_ra;
+ double cross_ratios[3] = {0};
+ int cross_order[3];
+ int cross_v1 = -1, cross_v2 = -1;
+ /* If the edge intersects with the triangle edges (including extensions). */
+ int isec_e1, isec_e2, isec_e3;
+ /* If edge is parallel to one of the edges in the triangle. */
+ bool para_e1, para_e2, para_e3;
+ enum LineartPointTri state_v1 = 0, state_v2 = 0;
+
+ double dir_v1[3];
+ double dir_v2[3];
+ double view_vector[4];
+ double dir_cam[3];
+ double dot_v1, dot_v2, dot_v1a, dot_v2a;
double dot_f;
double gloc[4], trans[4];
double cut = -1;
@@ -2713,31 +2730,25 @@ static bool lineart_triangle_edge_image_space_occlusion(SpinLock *UNUSED(spl),
}
/* Check if the line visually crosses one of the edge in the triangle. */
- a = lineart_intersect_seg_seg(LFBC, RFBC, FBC0, FBC1, &is[0], &pa);
- b = lineart_intersect_seg_seg(LFBC, RFBC, FBC1, FBC2, &is[1], &pb);
- c = lineart_intersect_seg_seg(LFBC, RFBC, FBC2, FBC0, &is[2], &pc);
+ isec_e1 = lineart_intersect_seg_seg(LFBC, RFBC, FBC0, FBC1, &cross_ratios[0], &para_e1);
+ isec_e2 = lineart_intersect_seg_seg(LFBC, RFBC, FBC1, FBC2, &cross_ratios[1], &para_e2);
+ isec_e3 = lineart_intersect_seg_seg(LFBC, RFBC, FBC2, FBC0, &cross_ratios[2], &para_e3);
/* Sort the intersection distance. */
- INTERSECT_SORT_MIN_TO_MAX_3(is[0], is[1], is[2], order);
+ INTERSECT_SORT_MIN_TO_MAX_3(cross_ratios[0], cross_ratios[1], cross_ratios[2], cross_order);
- sub_v3_v3v3_db(Lv, e->v1->gloc, tri->v[0]->gloc);
- sub_v3_v3v3_db(Rv, e->v2->gloc, tri->v[0]->gloc);
-
- copy_v3_v3_db(Cv, camera_dir);
+ sub_v3_v3v3_db(dir_v1, e->v1->gloc, tri->v[0]->gloc);
+ sub_v3_v3v3_db(dir_v2, e->v2->gloc, tri->v[0]->gloc);
+ copy_v3_v3_db(dir_cam, camera_dir);
+ copy_v3_v3_db(view_vector, override_camera_loc);
if (override_cam_is_persp) {
- copy_v3_v3_db(vd4, override_camera_loc);
- }
- else {
- copy_v4_v4_db(vd4, override_camera_loc);
- }
- if (override_cam_is_persp) {
- sub_v3_v3v3_db(Cv, vd4, tri->v[0]->gloc);
+ sub_v3_v3v3_db(dir_cam, view_vector, tri->v[0]->gloc);
}
- dot_l = dot_v3v3_db(Lv, tri->gn);
- dot_r = dot_v3v3_db(Rv, tri->gn);
- dot_f = dot_v3v3_db(Cv, tri->gn);
+ dot_v1 = dot_v3v3_db(dir_v1, tri->gn);
+ dot_v2 = dot_v3v3_db(dir_v2, tri->gn);
+ dot_f = dot_v3v3_db(dir_cam, 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
@@ -2748,40 +2759,39 @@ static bool lineart_triangle_edge_image_space_occlusion(SpinLock *UNUSED(spl),
return false;
}
+ /* Whether two end points are inside/on_the_edge/outside of the triangle. */
+ state_v1 = lineart_point_triangle_relation(LFBC, FBC0, FBC1, FBC2);
+ state_v2 = lineart_point_triangle_relation(RFBC, FBC0, FBC1, FBC2);
+
/* If the edge doesn't visually cross any edge of the triangle... */
- if (!a && !b && !c) {
+ if (!isec_e1 && !isec_e2 && !isec_e3) {
/* And if both end point from the edge is outside of the triangle... */
- if (!(st_l = lineart_point_triangle_relation(LFBC, FBC0, FBC1, FBC2)) &&
- !(st_r = lineart_point_triangle_relation(RFBC, FBC0, FBC1, FBC2))) {
+ if ((!state_v1) && (!state_v2)) {
return 0; /* We don't have any occlusion. */
}
}
- /* Whether two end points are inside/on_the_edge/outside of the triangle. */
- st_l = lineart_point_triangle_relation(LFBC, FBC0, FBC1, FBC2);
- st_r = lineart_point_triangle_relation(RFBC, FBC0, FBC1, FBC2);
-
/* Determine the cut position. */
- dot_la = fabs(dot_l);
- if (dot_la < DBL_EPSILON) {
- dot_la = 0;
- dot_l = 0;
+ dot_v1a = fabs(dot_v1);
+ if (dot_v1a < DBL_EPSILON) {
+ dot_v1a = 0;
+ dot_v1 = 0;
}
- dot_ra = fabs(dot_r);
- if (dot_ra < DBL_EPSILON) {
- dot_ra = 0;
- dot_r = 0;
+ dot_v2a = fabs(dot_v2);
+ if (dot_v2a < DBL_EPSILON) {
+ dot_v2a = 0;
+ dot_v2 = 0;
}
- if (dot_l - dot_r == 0) {
+ if (dot_v1 - dot_v2 == 0) {
cut = 100000;
}
- else if (dot_l * dot_r <= 0) {
- cut = dot_la / fabs(dot_l - dot_r);
+ else if (dot_v1 * dot_v2 <= 0) {
+ cut = dot_v1a / fabs(dot_v1 - dot_v2);
}
else {
- cut = fabs(dot_r + dot_l) / fabs(dot_l - dot_r);
- cut = dot_ra > dot_la ? 1 - cut : cut;
+ cut = fabs(dot_v2 + dot_v1) / fabs(dot_v1 - dot_v2);
+ cut = dot_v2a > dot_v1a ? 1 - cut : cut;
}
/* Transform the cut from geometry space to image space. */
@@ -2802,7 +2812,7 @@ static bool lineart_triangle_edge_image_space_occlusion(SpinLock *UNUSED(spl),
}
#define LRT_GUARD_NOT_FOUND \
- if (LCross < 0 || RCross < 0) { \
+ if (cross_v1 < 0 || cross_v2 < 0) { \
return false; \
}
@@ -2810,95 +2820,97 @@ static bool lineart_triangle_edge_image_space_occlusion(SpinLock *UNUSED(spl),
* indicates triangle boundary. DBL_TRIANGLE_LIM is needed to for floating point precision
* tolerance. */
- if (st_l == 2) {
+ if (state_v1 == LRT_INSIDE_TRIANGLE) {
/* Left side is in the triangle. */
- if (st_r == 2) {
+ if (state_v2 == LRT_INSIDE_TRIANGLE) {
/* | l---r | */
- INTERSECT_JUST_SMALLER(is, order, DBL_TRIANGLE_LIM, LCross);
- INTERSECT_JUST_GREATER(is, order, 1 - DBL_TRIANGLE_LIM, RCross);
+ INTERSECT_JUST_SMALLER(cross_ratios, cross_order, DBL_TRIANGLE_LIM, cross_v1);
+ INTERSECT_JUST_GREATER(cross_ratios, cross_order, 1 - DBL_TRIANGLE_LIM, cross_v2);
}
- else if (st_r == 1) {
+ else if (state_v2 == LRT_ON_TRIANGLE) {
/* | l------r| */
- INTERSECT_JUST_SMALLER(is, order, DBL_TRIANGLE_LIM, LCross);
- INTERSECT_JUST_GREATER(is, order, 1 - DBL_TRIANGLE_LIM, RCross);
+ INTERSECT_JUST_SMALLER(cross_ratios, cross_order, DBL_TRIANGLE_LIM, cross_v1);
+ INTERSECT_JUST_GREATER(cross_ratios, cross_order, 1 - DBL_TRIANGLE_LIM, cross_v2);
}
- else if (st_r == 0) {
+ else if (state_v2 == LRT_OUTSIDE_TRIANGLE) {
/* | l-------|------r */
- INTERSECT_JUST_SMALLER(is, order, DBL_TRIANGLE_LIM, LCross);
- INTERSECT_JUST_GREATER(is, order, 0, RCross);
+ INTERSECT_JUST_SMALLER(cross_ratios, cross_order, DBL_TRIANGLE_LIM, cross_v1);
+ INTERSECT_JUST_GREATER(cross_ratios, cross_order, 0, cross_v2);
}
}
- else if (st_l == 1) {
+ else if (state_v1 == LRT_ON_TRIANGLE) {
/* Left side is on some edge of the triangle. */
- if (st_r == 2) {
+ if (state_v2 == LRT_INSIDE_TRIANGLE) {
/* |l------r | */
- INTERSECT_JUST_SMALLER(is, order, DBL_TRIANGLE_LIM, LCross);
- INTERSECT_JUST_GREATER(is, order, 1 - DBL_TRIANGLE_LIM, RCross);
+ INTERSECT_JUST_SMALLER(cross_ratios, cross_order, DBL_TRIANGLE_LIM, cross_v1);
+ INTERSECT_JUST_GREATER(cross_ratios, cross_order, 1 - DBL_TRIANGLE_LIM, cross_v2);
}
- else if (st_r == 1) {
+ else if (state_v2 == LRT_ON_TRIANGLE) {
/* |l---------r| */
- INTERSECT_JUST_SMALLER(is, order, DBL_TRIANGLE_LIM, LCross);
- INTERSECT_JUST_GREATER(is, order, 1 - DBL_TRIANGLE_LIM, RCross);
+ INTERSECT_JUST_SMALLER(cross_ratios, cross_order, DBL_TRIANGLE_LIM, cross_v1);
+ INTERSECT_JUST_GREATER(cross_ratios, cross_order, 1 - DBL_TRIANGLE_LIM, cross_v2);
}
- else if (st_r == 0) {
+ else if (state_v2 == LRT_OUTSIDE_TRIANGLE) {
/* |l----------|-------r (crossing the triangle) [OR]
* r---------|l | (not crossing the triangle) */
- INTERSECT_JUST_GREATER(is, order, DBL_TRIANGLE_LIM, RCross);
- if (RCross >= 0 && LRT_ABC(RCross) && is[RCross] > (DBL_TRIANGLE_LIM)) {
- INTERSECT_JUST_SMALLER(is, order, DBL_TRIANGLE_LIM, LCross);
+ INTERSECT_JUST_GREATER(cross_ratios, cross_order, DBL_TRIANGLE_LIM, cross_v2);
+ if (cross_v2 >= 0 && LRT_ISEC(cross_v2) && cross_ratios[cross_v2] > (DBL_TRIANGLE_LIM)) {
+ INTERSECT_JUST_SMALLER(cross_ratios, cross_order, DBL_TRIANGLE_LIM, cross_v1);
}
else {
- INTERSECT_JUST_SMALLER(is, order, DBL_TRIANGLE_LIM, RCross);
- if (RCross > 0) {
- INTERSECT_JUST_SMALLER(is, order, is[RCross], LCross);
+ INTERSECT_JUST_SMALLER(cross_ratios, cross_order, DBL_TRIANGLE_LIM, cross_v2);
+ if (cross_v2 > 0) {
+ INTERSECT_JUST_SMALLER(cross_ratios, cross_order, cross_ratios[cross_v2], cross_v1);
}
}
LRT_GUARD_NOT_FOUND
/* We could have the edge being completely parallel to the triangle where there isn't a
* viable occlusion result. */
- if ((LRT_PABC(LCross) && !LRT_ABC(LCross)) || (LRT_PABC(RCross) && !LRT_ABC(RCross))) {
+ if ((LRT_PARALLEL(cross_v1) && !LRT_ISEC(cross_v1)) ||
+ (LRT_PARALLEL(cross_v2) && !LRT_ISEC(cross_v2))) {
return false;
}
}
}
- else if (st_l == 0) {
+ else if (state_v1 == LRT_OUTSIDE_TRIANGLE) {
/* Left side is outside of the triangle. */
- if (st_r == 2) {
+ if (state_v2 == LRT_INSIDE_TRIANGLE) {
/* l---|---r | */
- INTERSECT_JUST_SMALLER(is, order, 1 - DBL_TRIANGLE_LIM, LCross);
- INTERSECT_JUST_GREATER(is, order, 1 - DBL_TRIANGLE_LIM, RCross);
+ INTERSECT_JUST_SMALLER(cross_ratios, cross_order, 1 - DBL_TRIANGLE_LIM, cross_v1);
+ INTERSECT_JUST_GREATER(cross_ratios, cross_order, 1 - DBL_TRIANGLE_LIM, cross_v2);
}
- else if (st_r == 1) {
+ else if (state_v2 == LRT_ON_TRIANGLE) {
/* |r----------|-------l (crossing the triangle) [OR]
* l---------|r | (not crossing the triangle) */
- INTERSECT_JUST_SMALLER(is, order, 1 - DBL_TRIANGLE_LIM, LCross);
- if (LCross >= 0 && LRT_ABC(LCross) && is[LCross] < (1 - DBL_TRIANGLE_LIM)) {
- INTERSECT_JUST_GREATER(is, order, 1 - DBL_TRIANGLE_LIM, RCross);
+ INTERSECT_JUST_SMALLER(cross_ratios, cross_order, 1 - DBL_TRIANGLE_LIM, cross_v1);
+ if (cross_v1 >= 0 && LRT_ISEC(cross_v1) && cross_ratios[cross_v1] < (1 - DBL_TRIANGLE_LIM)) {
+ INTERSECT_JUST_GREATER(cross_ratios, cross_order, 1 - DBL_TRIANGLE_LIM, cross_v2);
}
else {
- INTERSECT_JUST_GREATER(is, order, 1 - DBL_TRIANGLE_LIM, LCross);
- if (LCross > 0) {
- INTERSECT_JUST_GREATER(is, order, is[LCross], RCross);
+ INTERSECT_JUST_GREATER(cross_ratios, cross_order, 1 - DBL_TRIANGLE_LIM, cross_v1);
+ if (cross_v1 > 0) {
+ INTERSECT_JUST_GREATER(cross_ratios, cross_order, cross_ratios[cross_v1], cross_v2);
}
}
LRT_GUARD_NOT_FOUND
/* The same logic applies as above case. */
- if ((LRT_PABC(LCross) && !LRT_ABC(LCross)) || (LRT_PABC(RCross) && !LRT_ABC(RCross))) {
+ if ((LRT_PARALLEL(cross_v1) && !LRT_ISEC(cross_v1)) ||
+ (LRT_PARALLEL(cross_v2) && !LRT_ISEC(cross_v2))) {
return false;
}
}
- else if (st_r == 0) {
+ else if (state_v2 == LRT_OUTSIDE_TRIANGLE) {
/* l---|----|----r (crossing the triangle) [OR]
* l----r | | (not crossing the triangle) */
- INTERSECT_JUST_GREATER(is, order, -DBL_TRIANGLE_LIM, LCross);
- if (LCross >= 0 && LRT_ABC(LCross)) {
- INTERSECT_JUST_GREATER(is, order, is[LCross], RCross);
+ INTERSECT_JUST_GREATER(cross_ratios, cross_order, -DBL_TRIANGLE_LIM, cross_v1);
+ if (cross_v1 >= 0 && LRT_ISEC(cross_v1)) {
+ INTERSECT_JUST_GREATER(cross_ratios, cross_order, cross_ratios[cross_v1], cross_v2);
}
else {
- if (LCross >= 0) {
- INTERSECT_JUST_GREATER(is, order, is[LCross], LCross);
- if (LCross >= 0) {
- INTERSECT_JUST_GREATER(is, order, is[LCross], RCross);
+ if (cross_v1 >= 0) {
+ INTERSECT_JUST_GREATER(cross_ratios, cross_order, cross_ratios[cross_v1], cross_v1);
+ if (cross_v1 >= 0) {
+ INTERSECT_JUST_GREATER(cross_ratios, cross_order, cross_ratios[cross_v1], cross_v2);
}
}
}
@@ -2907,28 +2919,28 @@ static bool lineart_triangle_edge_image_space_occlusion(SpinLock *UNUSED(spl),
LRT_GUARD_NOT_FOUND
- double LF = dot_l * dot_f, RF = dot_r * dot_f;
+ double dot_1f = dot_v1 * dot_f, dot_2f = dot_v2 * dot_f;
/* Determine the start and end point of image space cut on a line. */
- if (LF <= 0 && RF <= 0 && (dot_l || dot_r)) {
- *from = MAX2(0, is[LCross]);
- *to = MIN2(1, is[RCross]);
+ if (dot_1f <= 0 && dot_2f <= 0 && (dot_v1 || dot_v2)) {
+ *from = MAX2(0, cross_ratios[cross_v1]);
+ *to = MIN2(1, cross_ratios[cross_v2]);
if (*from >= *to) {
return false;
}
return true;
}
- if (LF >= 0 && RF <= 0 && (dot_l || dot_r)) {
- *from = MAX2(cut, is[LCross]);
- *to = MIN2(1, is[RCross]);
+ if (dot_1f >= 0 && dot_2f <= 0 && (dot_v1 || dot_v2)) {
+ *from = MAX2(cut, cross_ratios[cross_v1]);
+ *to = MIN2(1, cross_ratios[cross_v2]);
if (*from >= *to) {
return false;
}
return true;
}
- if (LF <= 0 && RF >= 0 && (dot_l || dot_r)) {
- *from = MAX2(0, is[LCross]);
- *to = MIN2(cut, is[RCross]);
+ if (dot_1f <= 0 && dot_2f >= 0 && (dot_v1 || dot_v2)) {
+ *from = MAX2(0, cross_ratios[cross_v1]);
+ *to = MIN2(cut, cross_ratios[cross_v2]);
if (*from >= *to) {
return false;
}
@@ -2942,6 +2954,8 @@ static bool lineart_triangle_edge_image_space_occlusion(SpinLock *UNUSED(spl),
#undef INTERSECT_SORT_MIN_TO_MAX_3
#undef INTERSECT_JUST_GREATER
#undef INTERSECT_JUST_SMALLER
+#undef LRT_ISEC
+#undef LRT_PARALLEL
/**
* At this stage of the computation we don't have triangle adjacent info anymore,
@@ -3023,272 +3037,239 @@ static LineartVert *lineart_triangle_share_point(const LineartTriangle *l,
return NULL;
}
-/**
- * To save time and prevent overlapping lines when computing intersection lines.
- */
-static bool lineart_vert_already_intersected_2v(LineartVertIntersection *vt,
- LineartVertIntersection *v1,
- LineartVertIntersection *v2)
-{
- return ((vt->isec1 == v1->base.index && vt->isec2 == v2->base.index) ||
- (vt->isec2 == v2->base.index && vt->isec1 == v1->base.index));
-}
-
-static void lineart_vert_set_intersection_2v(LineartVert *vt, LineartVert *v1, LineartVert *v2)
+static bool lineart_triangle_2v_intersection_math(
+ LineartVert *v1, LineartVert *v2, LineartTriangle *tri, double *last, double *rv)
{
- LineartVertIntersection *irv = (LineartVertIntersection *)vt;
- irv->isec1 = v1->index;
- irv->isec2 = v2->index;
-}
-
-/**
- * This tests a triangle against a virtual line represented by `v1---v2`.
- * The vertices returned after repeated calls to this function
- * is then used to create a triangle/triangle intersection line.
- */
-static LineartVert *lineart_triangle_2v_intersection_test(LineartRenderBuffer *rb,
- LineartVert *v1,
- LineartVert *v2,
- LineartTriangle *tri,
- LineartTriangle *testing,
- LineartVert *last)
-{
- double Lv[3];
- double Rv[3];
- double dot_l, dot_r;
- LineartVert *result;
+ /* Direction vectors for the edge verts. We will check if the verts are on the same side of the
+ * triangle or not. */
+ double dir_v1[3], dir_v2[3];
+ double dot_v1, dot_v2;
double gloc[3];
- LineartVert *l = v1, *r = v2;
- for (LinkNode *ln = (void *)testing->intersecting_verts; ln; ln = ln->next) {
- LineartVertIntersection *vt = ln->link;
- if (vt->intersecting_with == tri &&
- lineart_vert_already_intersected_2v(
- vt, (LineartVertIntersection *)l, (LineartVertIntersection *)r)) {
- return (LineartVert *)vt;
- }
- }
-
- sub_v3_v3v3_db(Lv, l->gloc, testing->v[0]->gloc);
- sub_v3_v3v3_db(Rv, r->gloc, testing->v[0]->gloc);
+ sub_v3_v3v3_db(dir_v1, v1->gloc, tri->v[0]->gloc);
+ sub_v3_v3v3_db(dir_v2, v2->gloc, tri->v[0]->gloc);
- dot_l = dot_v3v3_db(Lv, testing->gn);
- dot_r = dot_v3v3_db(Rv, testing->gn);
+ dot_v1 = dot_v3v3_db(dir_v1, tri->gn);
+ dot_v2 = dot_v3v3_db(dir_v2, tri->gn);
- if (dot_l * dot_r > 0 || (!dot_l && !dot_r)) {
- return 0;
+ if (dot_v1 * dot_v2 > 0 || (!dot_v1 && !dot_v2)) {
+ return false;
}
- dot_l = fabs(dot_l);
- dot_r = fabs(dot_r);
+ dot_v1 = fabs(dot_v1);
+ dot_v2 = fabs(dot_v2);
- interp_v3_v3v3_db(gloc, l->gloc, r->gloc, dot_l / (dot_l + dot_r));
+ interp_v3_v3v3_db(gloc, v1->gloc, v2->gloc, dot_v1 / (dot_v1 + dot_v2));
- /* Due to precision issue, we might end up with the same point as the one we already detected.
- */
- if (last && LRT_DOUBLE_CLOSE_ENOUGH(last->gloc[0], gloc[0]) &&
- LRT_DOUBLE_CLOSE_ENOUGH(last->gloc[1], gloc[1]) &&
- LRT_DOUBLE_CLOSE_ENOUGH(last->gloc[2], gloc[2])) {
- return NULL;
+ /* Due to precision issue, we might end up with the same point as the one we already detected. */
+ if (last && LRT_DOUBLE_CLOSE_ENOUGH(last[0], gloc[0]) &&
+ LRT_DOUBLE_CLOSE_ENOUGH(last[1], gloc[1]) && LRT_DOUBLE_CLOSE_ENOUGH(last[2], gloc[2])) {
+ return false;
}
if (!(lineart_point_inside_triangle3d(
- gloc, testing->v[0]->gloc, testing->v[1]->gloc, testing->v[2]->gloc))) {
- return NULL;
+ gloc, tri->v[0]->gloc, tri->v[1]->gloc, tri->v[2]->gloc))) {
+ return false;
}
- /* This is an intersection vert, the size is bigger than LineartVert,
- * allocated separately. */
- result = lineart_mem_acquire(&rb->render_data_pool, sizeof(LineartVertIntersection));
-
- /* Indicate the data structure difference. */
- result->flag = LRT_VERT_HAS_INTERSECTION_DATA;
-
- copy_v3_v3_db(result->gloc, gloc);
+ copy_v3_v3_db(rv, gloc);
- lineart_prepend_pool(&testing->intersecting_verts, &rb->render_data_pool, result);
-
- return result;
+ return true;
}
-/**
- * Test if two triangles intersect. Generates one intersection line if the check succeeds.
- */
-static LineartEdge *lineart_triangle_intersect(LineartRenderBuffer *rb,
- LineartTriangle *tri,
- LineartTriangle *testing)
+static bool lineart_triangle_intersect_math(LineartTriangle *tri,
+ LineartTriangle *t2,
+ double *v1,
+ double *v2)
{
- LineartVert *v1 = 0, *v2 = 0;
- LineartVert **next = &v1;
- LineartEdge *result;
- LineartVert *E0T = 0;
- LineartVert *E1T = 0;
- LineartVert *E2T = 0;
- LineartVert *TE0 = 0;
- LineartVert *TE1 = 0;
- LineartVert *TE2 = 0;
+ double *next = v1, *last = NULL;
LineartVert *sv1, *sv2;
- double cl[3];
- double ZMin, ZMax;
- ZMax = rb->far_clip;
- ZMin = rb->near_clip;
- copy_v3_v3_db(cl, rb->camera_pos);
- LineartVert *share = lineart_triangle_share_point(testing, tri);
+ LineartVert *share = lineart_triangle_share_point(t2, tri);
if (share) {
/* If triangles have sharing points like `abc` and `acd`, then we only need to detect `bc`
* against `acd` or `cd` against `abc`. */
- LineartVert *new_share;
lineart_triangle_get_other_verts(tri, share, &sv1, &sv2);
- v1 = new_share = lineart_mem_acquire(&rb->render_data_pool, (sizeof(LineartVertIntersection)));
-
- new_share->flag = LRT_VERT_HAS_INTERSECTION_DATA;
-
- copy_v3_v3_db(new_share->gloc, share->gloc);
+ copy_v3_v3_db(v1, share->gloc);
- v2 = lineart_triangle_2v_intersection_test(rb, sv1, sv2, tri, testing, 0);
-
- if (v2 == NULL) {
- lineart_triangle_get_other_verts(testing, share, &sv1, &sv2);
- v2 = lineart_triangle_2v_intersection_test(rb, sv1, sv2, testing, tri, 0);
- if (v2 == NULL) {
- return 0;
+ if (!lineart_triangle_2v_intersection_math(sv1, sv2, t2, 0, v2)) {
+ lineart_triangle_get_other_verts(t2, share, &sv1, &sv2);
+ if (lineart_triangle_2v_intersection_math(sv1, sv2, tri, 0, v2)) {
+ return true;
}
- lineart_prepend_pool(&testing->intersecting_verts, &rb->render_data_pool, new_share);
- }
- else {
- lineart_prepend_pool(&tri->intersecting_verts, &rb->render_data_pool, new_share);
}
}
else {
/* If not sharing any points, then we need to try all the possibilities. */
- E0T = lineart_triangle_2v_intersection_test(rb, tri->v[0], tri->v[1], tri, testing, 0);
- if (E0T && (!(*next))) {
- (*next) = E0T;
- lineart_vert_set_intersection_2v((*next), tri->v[0], tri->v[1]);
- next = &v2;
- }
- E1T = lineart_triangle_2v_intersection_test(rb, tri->v[1], tri->v[2], tri, testing, v1);
- if (E1T && (!(*next))) {
- (*next) = E1T;
- lineart_vert_set_intersection_2v((*next), tri->v[1], tri->v[2]);
- next = &v2;
- }
- if (!(*next)) {
- E2T = lineart_triangle_2v_intersection_test(rb, tri->v[2], tri->v[0], tri, testing, v1);
- }
- if (E2T && (!(*next))) {
- (*next) = E2T;
- lineart_vert_set_intersection_2v((*next), tri->v[2], tri->v[0]);
- next = &v2;
+ if (lineart_triangle_2v_intersection_math(tri->v[0], tri->v[1], t2, 0, v1)) {
+ next = v2;
+ last = v1;
}
- if (!(*next)) {
- TE0 = lineart_triangle_2v_intersection_test(
- rb, testing->v[0], testing->v[1], testing, tri, v1);
- }
- if (TE0 && (!(*next))) {
- (*next) = TE0;
- lineart_vert_set_intersection_2v((*next), testing->v[0], testing->v[1]);
- next = &v2;
+ if (lineart_triangle_2v_intersection_math(tri->v[1], tri->v[2], t2, last, next)) {
+ if (last) {
+ return true;
+ }
+ next = v2;
+ last = v1;
}
- if (!(*next)) {
- TE1 = lineart_triangle_2v_intersection_test(
- rb, testing->v[1], testing->v[2], testing, tri, v1);
+ if (lineart_triangle_2v_intersection_math(tri->v[2], tri->v[0], t2, last, next)) {
+ if (last) {
+ return true;
+ }
+ next = v2;
+ last = v1;
}
- if (TE1 && (!(*next))) {
- (*next) = TE1;
- lineart_vert_set_intersection_2v((*next), testing->v[1], testing->v[2]);
- next = &v2;
+
+ if (lineart_triangle_2v_intersection_math(t2->v[0], t2->v[1], tri, last, next)) {
+ if (last) {
+ return true;
+ }
+ next = v2;
+ last = v1;
}
- if (!(*next)) {
- TE2 = lineart_triangle_2v_intersection_test(
- rb, testing->v[2], testing->v[0], testing, tri, v1);
+ if (lineart_triangle_2v_intersection_math(t2->v[1], t2->v[2], tri, last, next)) {
+ if (last) {
+ return true;
+ }
+ next = v2;
+ last = v1;
}
- if (TE2 && (!(*next))) {
- (*next) = TE2;
- lineart_vert_set_intersection_2v((*next), testing->v[2], testing->v[0]);
- next = &v2;
+ if (lineart_triangle_2v_intersection_math(t2->v[2], t2->v[0], tri, last, next)) {
+ if (last) {
+ return true;
+ }
+ next = v2;
+ last = v1;
}
+ }
+ return false;
+}
- if (!(*next)) {
- return 0;
- }
+static void lineart_add_isec_thread(LineartIsecThread *th,
+ const double *v1,
+ const double *v2,
+ LineartTriangle *tri1,
+ LineartTriangle *tri2)
+{
+ if (th->current == th->max) {
+
+ LineartIsecSingle *new_array = MEM_mallocN(sizeof(LineartIsecSingle) * th->max * 2,
+ "LineartIsecSingle");
+ memcpy(new_array, th->array, sizeof(LineartIsecSingle) * th->max);
+ th->max *= 2;
+ MEM_freeN(th->array);
+ th->array = new_array;
+ }
+ LineartIsecSingle *isec_single = &th->array[th->current];
+ copy_v3fl_v3db(isec_single->v1, v1);
+ copy_v3fl_v3db(isec_single->v2, v2);
+ isec_single->tri1 = tri1;
+ isec_single->tri2 = tri2;
+ th->current++;
+}
+
+#define LRT_ISECT_TRIANGLE_PER_THREAD 4096
+
+static bool lineart_schedule_new_triangle_task(LineartIsecThread *th)
+{
+ LineartData *ld = th->ld;
+ int remaining = LRT_ISECT_TRIANGLE_PER_THREAD;
+
+ BLI_spin_lock(&ld->lock_task);
+ LineartElementLinkNode *eln = ld->isect_scheduled_up_to;
+
+ if (!eln) {
+ BLI_spin_unlock(&ld->lock_task);
+ return false;
}
- /* The intersection line has been generated only in geometry space, so we need to transform
- * them as well. */
- mul_v4_m4v3_db(v1->fbcoord, rb->view_projection, v1->gloc);
- mul_v4_m4v3_db(v2->fbcoord, rb->view_projection, v2->gloc);
- if (rb->cam_is_persp) {
- mul_v3db_db(v1->fbcoord, (1 / v1->fbcoord[3]));
- mul_v3db_db(v2->fbcoord, (1 / v2->fbcoord[3]));
+ th->pending_from = eln;
+ th->index_from = ld->isect_scheduled_up_to_index;
+
+ while (remaining > 0 && eln) {
+ int remaining_this_eln = eln->element_count - ld->isect_scheduled_up_to_index;
+ int added_count = MIN2(remaining, remaining_this_eln);
+ remaining -= added_count;
+ if (remaining || added_count == remaining_this_eln) {
+ eln = eln->next;
+ ld->isect_scheduled_up_to = eln;
+ ld->isect_scheduled_up_to_index = 0;
+ }
+ else {
+ ld->isect_scheduled_up_to_index += added_count;
+ }
}
- v1->fbcoord[0] -= rb->shift_x * 2;
- v1->fbcoord[1] -= rb->shift_y * 2;
- v2->fbcoord[0] -= rb->shift_x * 2;
- v2->fbcoord[1] -= rb->shift_y * 2;
- /* This z transformation is not the same as the rest of the part, because the data don't go
- * through normal perspective division calls in the pipeline, but this way the 3D result and
- * occlusion on the generated line is correct, and we don't really use 2D for viewport stroke
- * generation anyway. */
- v1->fbcoord[2] = ZMin * ZMax / (ZMax - fabs(v1->fbcoord[2]) * (ZMax - ZMin));
- v2->fbcoord[2] = ZMin * ZMax / (ZMax - fabs(v2->fbcoord[2]) * (ZMax - ZMin));
+ th->pending_to = eln ? eln : ld->geom.triangle_buffer_pointers.last;
+ th->index_to = ld->isect_scheduled_up_to_index;
- ((LineartVertIntersection *)v1)->intersecting_with = tri;
- ((LineartVertIntersection *)v2)->intersecting_with = testing;
+ BLI_spin_unlock(&ld->lock_task);
- result = lineart_mem_acquire(&rb->render_data_pool, sizeof(LineartEdge));
- result->v1 = v1;
- result->v2 = v2;
- result->t1 = tri;
- result->t2 = testing;
+ return true;
+}
- LineartEdgeSegment *es = lineart_mem_acquire(&rb->render_data_pool, sizeof(LineartEdgeSegment));
- BLI_addtail(&result->segments, es);
- /* Don't need to OR flags right now, just a type mark. */
- result->flags = LRT_EDGE_FLAG_INTERSECTION;
- result->intersection_mask = (tri->intersection_mask | testing->intersection_mask);
+/* This function initializes two things:
+ * 1) Triangle array scheduling info, for each worker thread to get its chunk from the scheduler.
+ * 2) Per-thread intersection result array. Does not store actual #LineartEdge, these results will
+ * be finalized by #lineart_create_edges_from_isec_data
+ */
+static void lineart_init_isec_thread(LineartIsecData *d, LineartData *ld, int thread_count)
+{
+ d->threads = MEM_callocN(sizeof(LineartIsecThread) * thread_count, "LineartIsecThread arr");
+ d->ld = ld;
+ d->thread_count = thread_count;
- lineart_prepend_edge_direct(&rb->intersection.first, result);
+ ld->isect_scheduled_up_to = ld->geom.triangle_buffer_pointers.first;
+ ld->isect_scheduled_up_to_index = 0;
- return result;
+ for (int i = 0; i < thread_count; i++) {
+ LineartIsecThread *it = &d->threads[i];
+ it->array = MEM_mallocN(sizeof(LineartIsecSingle) * 100, "LineartIsecSingle arr");
+ it->max = 100;
+ it->current = 0;
+ it->thread_id = i;
+ it->ld = ld;
+ }
}
-static void lineart_triangle_intersect_in_bounding_area(LineartRenderBuffer *rb,
- LineartTriangle *tri,
- LineartBoundingArea *ba)
+static void lineart_destroy_isec_thread(LineartIsecData *d)
{
- /* Testing_triangle->testing[0] is used to store pairing triangle reference.
- * See definition of LineartTriangleThread for more info. */
- LineartTriangle *testing_triangle;
- LineartTriangleThread *tt;
+ for (int i = 0; i < d->thread_count; i++) {
+ LineartIsecThread *it = &d->threads[i];
+ MEM_freeN(it->array);
+ }
+ MEM_freeN(d->threads);
+}
- double *G0 = tri->v[0]->gloc, *G1 = tri->v[1]->gloc, *G2 = tri->v[2]->gloc;
+static void lineart_triangle_intersect_in_bounding_area(LineartTriangle *tri,
+ LineartBoundingArea *ba,
+ LineartIsecThread *th,
+ int up_to)
+{
+ BLI_assert(th != NULL);
- /* If this is not the smallest subdiv bounding area. */
- if (ba->child) {
- lineart_triangle_intersect_in_bounding_area(rb, tri, &ba->child[0]);
- lineart_triangle_intersect_in_bounding_area(rb, tri, &ba->child[1]);
- lineart_triangle_intersect_in_bounding_area(rb, tri, &ba->child[2]);
- lineart_triangle_intersect_in_bounding_area(rb, tri, &ba->child[3]);
+ if (!th) {
return;
}
- /* If this _is_ the smallest subdiv bounding area, then do the intersections there. */
- for (int i = 0; i < ba->triangle_count; i++) {
- testing_triangle = ba->linked_triangles[i];
- tt = (LineartTriangleThread *)testing_triangle;
+ double *G0 = tri->v[0]->gloc, *G1 = tri->v[1]->gloc, *G2 = tri->v[2]->gloc;
+
+ /* If this _is_ the smallest subdivision bounding area, then do the intersections there. */
+ for (int i = 0; i < up_to; i++) {
+ /* Testing_triangle->testing[0] is used to store pairing triangle reference.
+ * See definition of LineartTriangleThread for more info. */
+ LineartTriangle *testing_triangle = ba->linked_triangles[i];
+ LineartTriangleThread *tt = (LineartTriangleThread *)testing_triangle;
- if (testing_triangle == tri || tt->testing_e[0] == (LineartEdge *)tri) {
+ if (testing_triangle == tri || tt->testing_e[th->thread_id] == (LineartEdge *)tri) {
continue;
}
- tt->testing_e[0] = (LineartEdge *)tri;
+ tt->testing_e[th->thread_id] = (LineartEdge *)tri;
if ((testing_triangle->flags & LRT_TRIANGLE_NO_INTERSECTION) ||
((testing_triangle->flags & LRT_TRIANGLE_INTERSECTION_ONLY) &&
@@ -3311,21 +3292,25 @@ static void lineart_triangle_intersect_in_bounding_area(LineartRenderBuffer *rb,
}
/* If we do need to compute intersection, then finally do it. */
- lineart_triangle_intersect(rb, tri, testing_triangle);
+
+ double iv1[3], iv2[3];
+ if (lineart_triangle_intersect_math(tri, testing_triangle, iv1, iv2)) {
+ lineart_add_isec_thread(th, iv1, iv2, tri, testing_triangle);
+ }
}
}
/**
* The calculated view vector will point towards the far-plane from the camera position.
*/
-static void lineart_main_get_view_vector(LineartRenderBuffer *rb)
+static void lineart_main_get_view_vector(LineartData *ld)
{
float direction[3] = {0, 0, 1};
float trans[3];
float inv[4][4];
float obmat_no_scale[4][4];
- copy_m4_m4(obmat_no_scale, rb->cam_obmat);
+ copy_m4_m4(obmat_no_scale, ld->conf.cam_obmat);
normalize_v3(obmat_no_scale[0]);
normalize_v3(obmat_no_scale[1]);
@@ -3333,46 +3318,45 @@ static void lineart_main_get_view_vector(LineartRenderBuffer *rb)
invert_m4_m4(inv, obmat_no_scale);
transpose_m4(inv);
mul_v3_mat3_m4v3(trans, inv, direction);
- copy_m4_m4(rb->cam_obmat, obmat_no_scale);
- copy_v3db_v3fl(rb->view_vector, trans);
+ copy_m4_m4(ld->conf.cam_obmat, obmat_no_scale);
+ copy_v3db_v3fl(ld->conf.view_vector, trans);
}
-static void lineart_destroy_render_data(LineartRenderBuffer *rb)
+static void lineart_destroy_render_data(LineartData *ld)
{
- if (rb == NULL) {
+ if (ld == NULL) {
return;
}
- memset(&rb->contour, 0, sizeof(ListBase));
- memset(&rb->crease, 0, sizeof(ListBase));
- memset(&rb->intersection, 0, sizeof(ListBase));
- memset(&rb->edge_mark, 0, sizeof(ListBase));
- memset(&rb->material, 0, sizeof(ListBase));
- memset(&rb->floating, 0, sizeof(ListBase));
+ BLI_listbase_clear(&ld->chains);
+ BLI_listbase_clear(&ld->wasted_cuts);
+
+ BLI_listbase_clear(&ld->geom.vertex_buffer_pointers);
+ BLI_listbase_clear(&ld->geom.line_buffer_pointers);
+ BLI_listbase_clear(&ld->geom.triangle_buffer_pointers);
- BLI_listbase_clear(&rb->chains);
- BLI_listbase_clear(&rb->wasted_cuts);
+ BLI_spin_end(&ld->lock_task);
+ BLI_spin_end(&ld->lock_cuts);
+ BLI_spin_end(&ld->render_data_pool.lock_mem);
- BLI_listbase_clear(&rb->vertex_buffer_pointers);
- BLI_listbase_clear(&rb->line_buffer_pointers);
- BLI_listbase_clear(&rb->triangle_buffer_pointers);
+ if (ld->pending_edges.array) {
+ MEM_freeN(ld->pending_edges.array);
+ }
- BLI_spin_end(&rb->lock_task);
- BLI_spin_end(&rb->lock_cuts);
- BLI_spin_end(&rb->render_data_pool.lock_mem);
+ lineart_free_bounding_area_memories(ld);
- lineart_mem_destroy(&rb->render_data_pool);
+ lineart_mem_destroy(&ld->render_data_pool);
}
void MOD_lineart_destroy_render_data(LineartGpencilModifierData *lmd)
{
- LineartRenderBuffer *rb = lmd->render_buffer_ptr;
+ LineartData *ld = lmd->la_data_ptr;
- lineart_destroy_render_data(rb);
+ lineart_destroy_render_data(ld);
- if (rb) {
- MEM_freeN(rb);
- lmd->render_buffer_ptr = NULL;
+ if (ld) {
+ MEM_freeN(ld);
+ lmd->la_data_ptr = NULL;
}
if (G.debug_value == 4000) {
@@ -3396,16 +3380,16 @@ void MOD_lineart_clear_cache(struct LineartCache **lc)
(*lc) = NULL;
}
-static LineartRenderBuffer *lineart_create_render_buffer(Scene *scene,
- LineartGpencilModifierData *lmd,
- Object *camera,
- Object *active_camera,
- LineartCache *lc)
+static LineartData *lineart_create_render_buffer(Scene *scene,
+ LineartGpencilModifierData *lmd,
+ Object *camera,
+ Object *active_camera,
+ LineartCache *lc)
{
- LineartRenderBuffer *rb = MEM_callocN(sizeof(LineartRenderBuffer), "Line Art render buffer");
+ LineartData *ld = MEM_callocN(sizeof(LineartData), "Line Art render buffer");
lmd->cache = lc;
- lmd->render_buffer_ptr = rb;
+ lmd->la_data_ptr = ld;
lc->rb_edge_types = lmd->edge_types_override;
if (!scene || !camera || !lc) {
@@ -3419,98 +3403,98 @@ static LineartRenderBuffer *lineart_create_render_buffer(Scene *scene,
clipping_offset = 0.0001;
}
- copy_v3db_v3fl(rb->camera_pos, camera->obmat[3]);
+ copy_v3db_v3fl(ld->conf.camera_pos, camera->obmat[3]);
if (active_camera) {
- copy_v3db_v3fl(rb->active_camera_pos, active_camera->obmat[3]);
+ copy_v3db_v3fl(ld->conf.active_camera_pos, active_camera->obmat[3]);
}
- copy_m4_m4(rb->cam_obmat, camera->obmat);
- rb->cam_is_persp = (c->type == CAM_PERSP);
- rb->near_clip = c->clip_start + clipping_offset;
- rb->far_clip = c->clip_end - clipping_offset;
- rb->w = scene->r.xsch;
- rb->h = scene->r.ysch;
+ copy_m4_m4(ld->conf.cam_obmat, camera->obmat);
+
+ ld->conf.cam_is_persp = (c->type == CAM_PERSP);
+ ld->conf.near_clip = c->clip_start + clipping_offset;
+ ld->conf.far_clip = c->clip_end - clipping_offset;
+ ld->w = scene->r.xsch;
+ ld->h = scene->r.ysch;
- if (rb->cam_is_persp) {
- rb->tile_recursive_level = LRT_TILE_RECURSIVE_PERSPECTIVE;
+ if (ld->conf.cam_is_persp) {
+ ld->qtree.recursive_level = LRT_TILE_RECURSIVE_PERSPECTIVE;
}
else {
- rb->tile_recursive_level = LRT_TILE_RECURSIVE_ORTHO;
+ ld->qtree.recursive_level = LRT_TILE_RECURSIVE_ORTHO;
}
- double asp = ((double)rb->w / (double)rb->h);
- int fit = BKE_camera_sensor_fit(c->sensor_fit, rb->w, rb->h);
- rb->shift_x = fit == CAMERA_SENSOR_FIT_HOR ? c->shiftx : c->shiftx / asp;
- rb->shift_y = fit == CAMERA_SENSOR_FIT_VERT ? c->shifty : c->shifty * asp;
+ double asp = ((double)ld->w / (double)ld->h);
+ int fit = BKE_camera_sensor_fit(c->sensor_fit, ld->w, ld->h);
+ ld->conf.shift_x = fit == CAMERA_SENSOR_FIT_HOR ? c->shiftx : c->shiftx / asp;
+ ld->conf.shift_y = fit == CAMERA_SENSOR_FIT_VERT ? c->shifty : c->shifty * asp;
- rb->overscan = lmd->overscan;
+ ld->conf.overscan = lmd->overscan;
- rb->shift_x /= (1 + rb->overscan);
- rb->shift_y /= (1 + rb->overscan);
+ ld->conf.shift_x /= (1 + ld->conf.overscan);
+ ld->conf.shift_y /= (1 + ld->conf.overscan);
- rb->crease_threshold = cos(M_PI - lmd->crease_threshold);
- rb->chaining_image_threshold = lmd->chaining_image_threshold;
- rb->angle_splitting_threshold = lmd->angle_splitting_threshold;
- rb->chain_smooth_tolerance = lmd->chain_smooth_tolerance;
+ ld->conf.crease_threshold = cos(M_PI - lmd->crease_threshold);
+ ld->conf.chaining_image_threshold = lmd->chaining_image_threshold;
+ ld->conf.angle_splitting_threshold = lmd->angle_splitting_threshold;
+ ld->conf.chain_smooth_tolerance = lmd->chain_smooth_tolerance;
- rb->fuzzy_intersections = (lmd->calculation_flags & LRT_INTERSECTION_AS_CONTOUR) != 0;
- rb->fuzzy_everything = (lmd->calculation_flags & LRT_EVERYTHING_AS_CONTOUR) != 0;
- rb->allow_boundaries = (lmd->calculation_flags & LRT_ALLOW_CLIPPING_BOUNDARIES) != 0;
- rb->use_loose_as_contour = (lmd->calculation_flags & LRT_LOOSE_AS_CONTOUR) != 0;
- rb->use_loose_edge_chain = (lmd->calculation_flags & LRT_CHAIN_LOOSE_EDGES) != 0;
- rb->use_geometry_space_chain = (lmd->calculation_flags & LRT_CHAIN_GEOMETRY_SPACE) != 0;
- rb->use_image_boundary_trimming = (lmd->calculation_flags & LRT_USE_IMAGE_BOUNDARY_TRIMMING) !=
- 0;
+ ld->conf.fuzzy_intersections = (lmd->calculation_flags & LRT_INTERSECTION_AS_CONTOUR) != 0;
+ ld->conf.fuzzy_everything = (lmd->calculation_flags & LRT_EVERYTHING_AS_CONTOUR) != 0;
+ ld->conf.allow_boundaries = (lmd->calculation_flags & LRT_ALLOW_CLIPPING_BOUNDARIES) != 0;
+ ld->conf.use_loose_as_contour = (lmd->calculation_flags & LRT_LOOSE_AS_CONTOUR) != 0;
+ ld->conf.use_loose_edge_chain = (lmd->calculation_flags & LRT_CHAIN_LOOSE_EDGES) != 0;
+ ld->conf.use_geometry_space_chain = (lmd->calculation_flags & LRT_CHAIN_GEOMETRY_SPACE) != 0;
+ ld->conf.use_image_boundary_trimming = (lmd->calculation_flags &
+ LRT_USE_IMAGE_BOUNDARY_TRIMMING) != 0;
/* See lineart_edge_from_triangle() for how this option may impact performance. */
- rb->allow_overlapping_edges = (lmd->calculation_flags & LRT_ALLOW_OVERLAPPING_EDGES) != 0;
+ ld->conf.allow_overlapping_edges = (lmd->calculation_flags & LRT_ALLOW_OVERLAPPING_EDGES) != 0;
- rb->allow_duplicated_types = (lmd->calculation_flags & LRT_ALLOW_OVERLAP_EDGE_TYPES) != 0;
+ ld->conf.allow_duplicated_types = (lmd->calculation_flags & LRT_ALLOW_OVERLAP_EDGE_TYPES) != 0;
- 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;
+ ld->conf.force_crease = (lmd->calculation_flags & LRT_USE_CREASE_ON_SMOOTH_SURFACES) != 0;
+ ld->conf.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;
+ ld->conf.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;
+ ld->conf.max_occlusion_level = lmd->level_end_override;
- rb->use_back_face_culling = (lmd->calculation_flags & LRT_USE_BACK_FACE_CULLING) != 0;
+ ld->conf.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;
- rb->use_crease = (edge_types & LRT_EDGE_FLAG_CREASE) != 0;
- rb->use_material = (edge_types & LRT_EDGE_FLAG_MATERIAL) != 0;
- rb->use_edge_marks = (edge_types & LRT_EDGE_FLAG_EDGE_MARK) != 0;
- rb->use_intersections = (edge_types & LRT_EDGE_FLAG_INTERSECTION) != 0;
- rb->use_loose = (edge_types & LRT_EDGE_FLAG_LOOSE) != 0;
+ ld->conf.use_contour = (edge_types & LRT_EDGE_FLAG_CONTOUR) != 0;
+ ld->conf.use_crease = (edge_types & LRT_EDGE_FLAG_CREASE) != 0;
+ ld->conf.use_material = (edge_types & LRT_EDGE_FLAG_MATERIAL) != 0;
+ ld->conf.use_edge_marks = (edge_types & LRT_EDGE_FLAG_EDGE_MARK) != 0;
+ ld->conf.use_intersections = (edge_types & LRT_EDGE_FLAG_INTERSECTION) != 0;
+ ld->conf.use_loose = (edge_types & LRT_EDGE_FLAG_LOOSE) != 0;
+
+ ld->conf.filter_face_mark_invert = (lmd->calculation_flags & LRT_FILTER_FACE_MARK_INVERT) != 0;
+ ld->conf.filter_face_mark = (lmd->calculation_flags & LRT_FILTER_FACE_MARK) != 0;
+ ld->conf.filter_face_mark_boundaries = (lmd->calculation_flags &
+ LRT_FILTER_FACE_MARK_BOUNDARIES) != 0;
+ ld->conf.filter_face_mark_keep_contour = (lmd->calculation_flags &
+ LRT_FILTER_FACE_MARK_KEEP_CONTOUR) != 0;
- rb->filter_face_mark_invert = (lmd->calculation_flags & LRT_FILTER_FACE_MARK_INVERT) != 0;
- 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;
+ ld->chain_data_pool = &lc->chain_data_pool;
- rb->chain_data_pool = &lc->chain_data_pool;
+ BLI_spin_init(&ld->lock_task);
+ BLI_spin_init(&ld->lock_cuts);
+ BLI_spin_init(&ld->render_data_pool.lock_mem);
- BLI_spin_init(&rb->lock_task);
- BLI_spin_init(&rb->lock_cuts);
- BLI_spin_init(&rb->render_data_pool.lock_mem);
+ ld->thread_count = BKE_render_num_threads(&scene->r);
- return rb;
+ return ld;
}
-static int lineart_triangle_size_get(const Scene *scene, LineartRenderBuffer *rb)
+static int lineart_triangle_size_get(LineartData *ld)
{
- if (rb->thread_count == 0) {
- rb->thread_count = BKE_render_num_threads(&scene->r);
- }
- return sizeof(LineartTriangle) + (sizeof(LineartEdge *) * (rb->thread_count));
+ return sizeof(LineartTriangle) + (sizeof(LineartEdge *) * (ld->thread_count));
}
-static void lineart_main_bounding_area_make_initial(LineartRenderBuffer *rb)
+static void lineart_main_bounding_area_make_initial(LineartData *ld)
{
/* Initial tile split is defined as 4 (subdivided as 4*4), increasing the value allows the
* algorithm to build the acceleration structure for bigger scenes a little faster but not as
@@ -3520,24 +3504,32 @@ static void lineart_main_bounding_area_make_initial(LineartRenderBuffer *rb)
int row, col;
LineartBoundingArea *ba;
+ /* Always make sure the shortest side has at least LRT_BA_ROWS tiles. */
+ if (ld->w > ld->h) {
+ sp_w = sp_h * ld->w / ld->h;
+ }
+ else {
+ sp_h = sp_w * ld->h / ld->w;
+ }
+
/* Because NDC (Normalized Device Coordinates) range is (-1,1),
* so the span for each initial tile is double of that in the (0,1) range. */
double span_w = (double)1 / sp_w * 2.0;
double span_h = (double)1 / sp_h * 2.0;
- rb->tile_count_x = sp_w;
- rb->tile_count_y = sp_h;
- rb->width_per_tile = span_w;
- rb->height_per_tile = span_h;
+ ld->qtree.count_x = sp_w;
+ ld->qtree.count_y = sp_h;
+ ld->qtree.tile_width = span_w;
+ ld->qtree.tile_height = span_h;
- rb->bounding_area_count = sp_w * sp_h;
- rb->initial_bounding_areas = lineart_mem_acquire(
- &rb->render_data_pool, sizeof(LineartBoundingArea) * rb->bounding_area_count);
+ ld->qtree.tile_count = sp_w * sp_h;
+ ld->qtree.initials = lineart_mem_acquire(&ld->render_data_pool,
+ sizeof(LineartBoundingArea) * ld->qtree.tile_count);
/* Initialize tiles. */
for (row = 0; row < sp_h; row++) {
for (col = 0; col < sp_w; col++) {
- ba = &rb->initial_bounding_areas[row * LRT_BA_ROWS + col];
+ ba = &ld->qtree.initials[row * ld->qtree.count_x + col];
/* Set the four direction limits. */
ba->l = span_w * col - 1.0;
@@ -3551,34 +3543,12 @@ static void lineart_main_bounding_area_make_initial(LineartRenderBuffer *rb)
/* Init linked_triangles array. */
ba->max_triangle_count = LRT_TILE_SPLITTING_TRIANGLE_LIMIT;
ba->max_line_count = LRT_TILE_EDGE_COUNT_INITIAL;
- ba->linked_triangles = lineart_mem_acquire(
- &rb->render_data_pool, sizeof(LineartTriangle *) * ba->max_triangle_count);
- ba->linked_lines = lineart_mem_acquire(&rb->render_data_pool,
- sizeof(LineartEdge *) * ba->max_line_count);
+ ba->linked_triangles = MEM_callocN(sizeof(LineartTriangle *) * ba->max_triangle_count,
+ "ba_linked_triangles");
+ ba->linked_lines = MEM_callocN(sizeof(LineartEdge *) * ba->max_line_count,
+ "ba_linked_lines");
- /* Link adjacent ones. */
- if (row) {
- lineart_list_append_pointer_pool(
- &ba->up,
- &rb->render_data_pool,
- &rb->initial_bounding_areas[(row - 1) * LRT_BA_ROWS + col]);
- }
- if (col) {
- lineart_list_append_pointer_pool(&ba->lp,
- &rb->render_data_pool,
- &rb->initial_bounding_areas[row * LRT_BA_ROWS + col - 1]);
- }
- if (row != sp_h - 1) {
- lineart_list_append_pointer_pool(
- &ba->bp,
- &rb->render_data_pool,
- &rb->initial_bounding_areas[(row + 1) * LRT_BA_ROWS + col]);
- }
- if (col != sp_w - 1) {
- lineart_list_append_pointer_pool(&ba->rp,
- &rb->render_data_pool,
- &rb->initial_bounding_areas[row * LRT_BA_ROWS + col + 1]);
- }
+ BLI_spin_init(&ba->lock);
}
}
}
@@ -3586,11 +3556,11 @@ static void lineart_main_bounding_area_make_initial(LineartRenderBuffer *rb)
/**
* Re-link adjacent tiles after one gets subdivided.
*/
-static void lineart_bounding_areas_connect_new(LineartRenderBuffer *rb, LineartBoundingArea *root)
+static void lineart_bounding_areas_connect_new(LineartData *ld, LineartBoundingArea *root)
{
LineartBoundingArea *ba = root->child, *tba;
LinkData *lip2, *next_lip;
- LineartStaticMemPool *mph = &rb->render_data_pool;
+ LineartStaticMemPool *mph = &ld->render_data_pool;
/* Inter-connection with newly created 4 child bounding areas. */
lineart_list_append_pointer_pool(&ba[1].rp, mph, &ba[0]);
@@ -3726,17 +3696,59 @@ static void lineart_bounding_areas_connect_new(LineartRenderBuffer *rb, LineartB
BLI_listbase_clear(&root->bp);
}
+static void lineart_bounding_areas_connect_recursive(LineartData *ld, LineartBoundingArea *root)
+{
+ if (root->child) {
+ lineart_bounding_areas_connect_new(ld, root);
+ for (int i = 0; i < 4; i++) {
+ lineart_bounding_areas_connect_recursive(ld, &root->child[i]);
+ }
+ }
+}
+
+static void lineart_main_bounding_areas_connect_post(LineartData *ld)
+{
+ int total_tile_initial = ld->qtree.count_x * ld->qtree.count_y;
+ int tiles_per_row = ld->qtree.count_x;
+
+ for (int row = 0; row < ld->qtree.count_y; row++) {
+ for (int col = 0; col < ld->qtree.count_x; col++) {
+ LineartBoundingArea *ba = &ld->qtree.initials[row * tiles_per_row + col];
+ /* Link adjacent ones. */
+ if (row) {
+ lineart_list_append_pointer_pool(
+ &ba->up, &ld->render_data_pool, &ld->qtree.initials[(row - 1) * tiles_per_row + col]);
+ }
+ if (col) {
+ lineart_list_append_pointer_pool(
+ &ba->lp, &ld->render_data_pool, &ld->qtree.initials[row * tiles_per_row + col - 1]);
+ }
+ if (row != ld->qtree.count_y - 1) {
+ lineart_list_append_pointer_pool(
+ &ba->bp, &ld->render_data_pool, &ld->qtree.initials[(row + 1) * tiles_per_row + col]);
+ }
+ if (col != ld->qtree.count_x - 1) {
+ lineart_list_append_pointer_pool(
+ &ba->rp, &ld->render_data_pool, &ld->qtree.initials[row * tiles_per_row + col + 1]);
+ }
+ }
+ }
+ for (int i = 0; i < total_tile_initial; i++) {
+ lineart_bounding_areas_connect_recursive(ld, &ld->qtree.initials[i]);
+ }
+}
+
/**
- * Subdivide a tile after one tile contains too many triangles.
+ * Subdivide a tile after one tile contains too many triangles, then re-link triangles into all the
+ * child tiles.
*/
-static void lineart_bounding_area_split(LineartRenderBuffer *rb,
+static void lineart_bounding_area_split(LineartData *ld,
LineartBoundingArea *root,
int recursive_level)
{
- LineartBoundingArea *ba = lineart_mem_acquire(&rb->render_data_pool,
- sizeof(LineartBoundingArea) * 4);
- LineartTriangle *tri;
+ LineartBoundingArea *ba = lineart_mem_acquire_thread(&ld->render_data_pool,
+ sizeof(LineartBoundingArea) * 4);
ba[0].l = root->cx;
ba[0].r = root->r;
ba[0].u = root->u;
@@ -3765,51 +3777,55 @@ static void lineart_bounding_area_split(LineartRenderBuffer *rb,
ba[3].cx = (ba[3].l + ba[3].r) / 2;
ba[3].cy = (ba[3].u + ba[3].b) / 2;
- root->child = ba;
-
- lineart_bounding_areas_connect_new(rb, root);
-
- /* Init linked_triangles array. */
+ /* Init linked_triangles array and locks. */
for (int i = 0; i < 4; i++) {
ba[i].max_triangle_count = LRT_TILE_SPLITTING_TRIANGLE_LIMIT;
ba[i].max_line_count = LRT_TILE_EDGE_COUNT_INITIAL;
- ba[i].linked_triangles = lineart_mem_acquire(
- &rb->render_data_pool, sizeof(LineartTriangle *) * LRT_TILE_SPLITTING_TRIANGLE_LIMIT);
- ba[i].linked_lines = lineart_mem_acquire(&rb->render_data_pool,
- sizeof(LineartEdge *) * LRT_TILE_EDGE_COUNT_INITIAL);
+ ba[i].linked_triangles = MEM_callocN(sizeof(LineartTriangle *) * ba[i].max_triangle_count,
+ "ba_linked_triangles");
+ ba[i].linked_lines = MEM_callocN(sizeof(LineartEdge *) * ba[i].max_line_count,
+ "ba_linked_lines");
+ BLI_spin_init(&ba[i].lock);
}
for (int i = 0; i < root->triangle_count; i++) {
- tri = root->linked_triangles[i];
- LineartBoundingArea *cba = root->child;
+ LineartTriangle *tri = root->linked_triangles[i];
+
double b[4];
b[0] = MIN3(tri->v[0]->fbcoord[0], tri->v[1]->fbcoord[0], tri->v[2]->fbcoord[0]);
b[1] = MAX3(tri->v[0]->fbcoord[0], tri->v[1]->fbcoord[0], tri->v[2]->fbcoord[0]);
b[2] = MAX3(tri->v[0]->fbcoord[1], tri->v[1]->fbcoord[1], tri->v[2]->fbcoord[1]);
b[3] = MIN3(tri->v[0]->fbcoord[1], tri->v[1]->fbcoord[1], tri->v[2]->fbcoord[1]);
- if (LRT_BOUND_AREA_CROSSES(b, &cba[0].l)) {
- lineart_bounding_area_link_triangle(rb, &cba[0], tri, b, 0, recursive_level + 1, false);
+
+ /* Re-link triangles into child tiles, not doing intersection lines during this because this
+ * batch of triangles are all tested with each other for intersections. */
+ if (LRT_BOUND_AREA_CROSSES(b, &ba[0].l)) {
+ lineart_bounding_area_link_triangle(ld, &ba[0], tri, b, 0, recursive_level + 1, false, NULL);
}
- if (LRT_BOUND_AREA_CROSSES(b, &cba[1].l)) {
- lineart_bounding_area_link_triangle(rb, &cba[1], tri, b, 0, recursive_level + 1, false);
+ if (LRT_BOUND_AREA_CROSSES(b, &ba[1].l)) {
+ lineart_bounding_area_link_triangle(ld, &ba[1], tri, b, 0, recursive_level + 1, false, NULL);
}
- if (LRT_BOUND_AREA_CROSSES(b, &cba[2].l)) {
- lineart_bounding_area_link_triangle(rb, &cba[2], tri, b, 0, recursive_level + 1, false);
+ if (LRT_BOUND_AREA_CROSSES(b, &ba[2].l)) {
+ lineart_bounding_area_link_triangle(ld, &ba[2], tri, b, 0, recursive_level + 1, false, NULL);
}
- if (LRT_BOUND_AREA_CROSSES(b, &cba[3].l)) {
- lineart_bounding_area_link_triangle(rb, &cba[3], tri, b, 0, recursive_level + 1, false);
+ if (LRT_BOUND_AREA_CROSSES(b, &ba[3].l)) {
+ lineart_bounding_area_link_triangle(ld, &ba[3], tri, b, 0, recursive_level + 1, false, NULL);
}
}
- rb->bounding_area_count += 3;
+ /* At this point the child tiles are fully initialized and it's safe for new triangles to be
+ * inserted, so assign root->child for #lineart_bounding_area_link_triangle to use. */
+ root->child = ba;
+
+ ld->qtree.tile_count += 3;
}
-static bool lineart_bounding_area_edge_intersect(LineartRenderBuffer *UNUSED(fb),
+static bool lineart_bounding_area_edge_intersect(LineartData *UNUSED(fb),
const double l[2],
const double r[2],
LineartBoundingArea *ba)
{
- double vx, vy;
+ double dx, dy;
double converted[4];
double c1, c;
@@ -3820,25 +3836,25 @@ static bool lineart_bounding_area_edge_intersect(LineartRenderBuffer *UNUSED(fb)
return false;
}
- vx = l[0] - r[0];
- vy = l[1] - r[1];
+ dx = l[0] - r[0];
+ dy = l[1] - r[1];
- c1 = vx * (converted[2] - l[1]) - vy * (converted[0] - l[0]);
+ c1 = dx * (converted[2] - l[1]) - dy * (converted[0] - l[0]);
c = c1;
- c1 = vx * (converted[2] - l[1]) - vy * (converted[1] - l[0]);
+ c1 = dx * (converted[2] - l[1]) - dy * (converted[1] - l[0]);
if (c1 * c <= 0) {
return true;
}
c = c1;
- c1 = vx * (converted[3] - l[1]) - vy * (converted[0] - l[0]);
+ c1 = dx * (converted[3] - l[1]) - dy * (converted[0] - l[0]);
if (c1 * c <= 0) {
return true;
}
c = c1;
- c1 = vx * (converted[3] - l[1]) - vy * (converted[1] - l[0]);
+ c1 = dx * (converted[3] - l[1]) - dy * (converted[1] - l[0]);
if (c1 * c <= 0) {
return true;
}
@@ -3847,7 +3863,7 @@ static bool lineart_bounding_area_edge_intersect(LineartRenderBuffer *UNUSED(fb)
return false;
}
-static bool lineart_bounding_area_triangle_intersect(LineartRenderBuffer *fb,
+static bool lineart_bounding_area_triangle_intersect(LineartData *fb,
LineartTriangle *tri,
LineartBoundingArea *ba)
{
@@ -3882,36 +3898,36 @@ static bool lineart_bounding_area_triangle_intersect(LineartRenderBuffer *fb,
}
/**
- * 1) Link triangles with bounding areas for later occlusion test.
- * 2) Test triangles with existing(added previously) triangles for intersection lines.
+ * This function does two things:
+ *
+ * 1) Builds a quad-tree under ld->InitialBoundingAreas to achieve good geometry separation for
+ * fast overlapping test between triangles and lines. This acceleration structure makes the
+ * occlusion stage much faster.
+ *
+ * 2) Test triangles with other triangles that are previously linked into each tile
+ * (#LineartBoundingArea) for intersection lines. When splitting the tile into 4 children and
+ * re-linking triangles into the child tiles, intersections are inhibited so we don't get
+ * duplicated intersection lines.
+ *
*/
-static void lineart_bounding_area_link_triangle(LineartRenderBuffer *rb,
+static void lineart_bounding_area_link_triangle(LineartData *ld,
LineartBoundingArea *root_ba,
LineartTriangle *tri,
double *LRUB,
int recursive,
int recursive_level,
- bool do_intersection)
+ bool do_intersection,
+ struct LineartIsecThread *th)
{
- if (!lineart_bounding_area_triangle_intersect(rb, tri, root_ba)) {
+ if (!lineart_bounding_area_triangle_intersect(ld, tri, root_ba)) {
return;
}
- if (root_ba->child == NULL) {
- lineart_bounding_area_triangle_add(rb, root_ba, tri);
- /* If splitting doesn't improve triangle separation, then shouldn't allow splitting anymore.
- * Here we use recursive limit. This is especially useful in orthographic render,
- * where a lot of faces could easily line up perfectly in image space,
- * which can not be separated by simply slicing the image tile. */
- if (root_ba->triangle_count >= LRT_TILE_SPLITTING_TRIANGLE_LIMIT && recursive &&
- recursive_level < rb->tile_recursive_level) {
- lineart_bounding_area_split(rb, root_ba, recursive_level);
- }
- if (recursive && do_intersection && rb->use_intersections) {
- lineart_triangle_intersect_in_bounding_area(rb, tri, root_ba);
- }
- }
- else {
- LineartBoundingArea *ba = root_ba->child;
+
+ LineartBoundingArea *old_ba = root_ba;
+
+ if (old_ba->child) {
+ /* If old_ba->child is not NULL, then tile splitting is fully finished, safe to directly insert
+ * into child tiles. */
double *B1 = LRUB;
double b[4];
if (!LRUB) {
@@ -3921,48 +3937,109 @@ static void lineart_bounding_area_link_triangle(LineartRenderBuffer *rb,
b[3] = MIN3(tri->v[0]->fbcoord[1], tri->v[1]->fbcoord[1], tri->v[2]->fbcoord[1]);
B1 = b;
}
- if (LRT_BOUND_AREA_CROSSES(B1, &ba[0].l)) {
- lineart_bounding_area_link_triangle(
- rb, &ba[0], tri, B1, recursive, recursive_level + 1, do_intersection);
+ for (int iba = 0; iba < 4; iba++) {
+ if (LRT_BOUND_AREA_CROSSES(B1, &old_ba->child[iba].l)) {
+ lineart_bounding_area_link_triangle(
+ ld, &old_ba->child[iba], tri, B1, recursive, recursive_level + 1, do_intersection, th);
+ }
+ }
+ return;
+ }
+
+ /* When splitting tiles, triangles are relinked into new tiles by a single thread, #th is NULL
+ * in that situation. */
+ if (th) {
+ BLI_spin_lock(&old_ba->lock);
+ }
+
+ /* If there are still space left in this tile for insertion. */
+ if (old_ba->triangle_count < old_ba->max_triangle_count) {
+ const uint32_t old_tri_count = old_ba->triangle_count;
+
+ old_ba->linked_triangles[old_ba->triangle_count++] = tri;
+
+ /* Do intersections in place. */
+ if (do_intersection && ld->conf.use_intersections) {
+ lineart_triangle_intersect_in_bounding_area(tri, old_ba, th, old_tri_count);
+ }
+
+ if (th) {
+ BLI_spin_unlock(&old_ba->lock);
}
- if (LRT_BOUND_AREA_CROSSES(B1, &ba[1].l)) {
- lineart_bounding_area_link_triangle(
- rb, &ba[1], tri, B1, recursive, recursive_level + 1, do_intersection);
+ }
+ else { /* We need to wait for either splitting or array extension to be done. */
+
+ if (recursive_level < ld->qtree.recursive_level) {
+ if (!old_ba->child) {
+ /* old_ba->child==NULL, means we are the thread that's doing the splitting. */
+ lineart_bounding_area_split(ld, old_ba, recursive_level);
+ } /* Otherwise other thread has completed the splitting process. */
}
- if (LRT_BOUND_AREA_CROSSES(B1, &ba[2].l)) {
- lineart_bounding_area_link_triangle(
- rb, &ba[2], tri, B1, recursive, recursive_level + 1, do_intersection);
+ else {
+ if (old_ba->triangle_count == old_ba->max_triangle_count) {
+ /* Means we are the thread that's doing the extension. */
+ lineart_bounding_area_triangle_reallocate(old_ba);
+ } /* Otherwise other thread has completed the extending the array. */
}
- if (LRT_BOUND_AREA_CROSSES(B1, &ba[3].l)) {
- lineart_bounding_area_link_triangle(
- rb, &ba[3], tri, B1, recursive, recursive_level + 1, do_intersection);
+
+ /* Unlock before going into recursive call. */
+ if (th) {
+ BLI_spin_unlock(&old_ba->lock);
}
+
+ /* Of course we still have our own triangle needs to be added. */
+ lineart_bounding_area_link_triangle(
+ ld, root_ba, tri, LRUB, recursive, recursive_level, do_intersection, th);
}
}
-static void lineart_bounding_area_link_edge(LineartRenderBuffer *rb,
+static void lineart_free_bounding_area_memory(LineartBoundingArea *ba, bool recursive)
+{
+ BLI_spin_end(&ba->lock);
+ if (ba->linked_lines) {
+ MEM_freeN(ba->linked_lines);
+ }
+ if (ba->linked_triangles) {
+ MEM_freeN(ba->linked_triangles);
+ }
+ if (recursive && ba->child) {
+ for (int i = 0; i < 4; i++) {
+ lineart_free_bounding_area_memory(&ba->child[i], recursive);
+ }
+ }
+}
+static void lineart_free_bounding_area_memories(LineartData *ld)
+{
+ for (int i = 0; i < ld->qtree.count_y; i++) {
+ for (int j = 0; j < ld->qtree.count_x; j++) {
+ lineart_free_bounding_area_memory(&ld->qtree.initials[i * ld->qtree.count_x + j], true);
+ }
+ }
+}
+
+static void lineart_bounding_area_link_edge(LineartData *ld,
LineartBoundingArea *root_ba,
LineartEdge *e)
{
if (root_ba->child == NULL) {
- lineart_bounding_area_line_add(rb, root_ba, e);
+ lineart_bounding_area_line_add(root_ba, e);
}
else {
if (lineart_bounding_area_edge_intersect(
- rb, e->v1->fbcoord, e->v2->fbcoord, &root_ba->child[0])) {
- lineart_bounding_area_link_edge(rb, &root_ba->child[0], e);
+ ld, e->v1->fbcoord, e->v2->fbcoord, &root_ba->child[0])) {
+ lineart_bounding_area_link_edge(ld, &root_ba->child[0], e);
}
if (lineart_bounding_area_edge_intersect(
- rb, e->v1->fbcoord, e->v2->fbcoord, &root_ba->child[1])) {
- lineart_bounding_area_link_edge(rb, &root_ba->child[1], e);
+ ld, e->v1->fbcoord, e->v2->fbcoord, &root_ba->child[1])) {
+ lineart_bounding_area_link_edge(ld, &root_ba->child[1], e);
}
if (lineart_bounding_area_edge_intersect(
- rb, e->v1->fbcoord, e->v2->fbcoord, &root_ba->child[2])) {
- lineart_bounding_area_link_edge(rb, &root_ba->child[2], e);
+ ld, e->v1->fbcoord, e->v2->fbcoord, &root_ba->child[2])) {
+ lineart_bounding_area_link_edge(ld, &root_ba->child[2], e);
}
if (lineart_bounding_area_edge_intersect(
- rb, e->v1->fbcoord, e->v2->fbcoord, &root_ba->child[3])) {
- lineart_bounding_area_link_edge(rb, &root_ba->child[3], e);
+ ld, e->v1->fbcoord, e->v2->fbcoord, &root_ba->child[3])) {
+ lineart_bounding_area_link_edge(ld, &root_ba->child[3], e);
}
}
}
@@ -3970,16 +4047,16 @@ static void lineart_bounding_area_link_edge(LineartRenderBuffer *rb,
/**
* Link lines to their respective bounding areas.
*/
-static void lineart_main_link_lines(LineartRenderBuffer *rb)
+static void lineart_main_link_lines(LineartData *ld)
{
LRT_ITER_ALL_LINES_BEGIN
{
int r1, r2, c1, c2, row, col;
- if (lineart_get_edge_bounding_areas(rb, e, &r1, &r2, &c1, &c2)) {
+ if (lineart_get_edge_bounding_areas(ld, e, &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], e);
+ ld, &ld->qtree.initials[row * ld->qtree.count_x + col], e);
}
}
}
@@ -3987,14 +4064,10 @@ static void lineart_main_link_lines(LineartRenderBuffer *rb)
LRT_ITER_ALL_LINES_END
}
-static bool lineart_get_triangle_bounding_areas(LineartRenderBuffer *rb,
- LineartTriangle *tri,
- int *rowbegin,
- int *rowend,
- int *colbegin,
- int *colend)
+static bool lineart_get_triangle_bounding_areas(
+ LineartData *ld, LineartTriangle *tri, int *rowbegin, int *rowend, int *colbegin, int *colend)
{
- double sp_w = rb->width_per_tile, sp_h = rb->height_per_tile;
+ double sp_w = ld->qtree.tile_width, sp_h = ld->qtree.tile_height;
double b[4];
if (!tri->v[0] || !tri->v[1] || !tri->v[2]) {
@@ -4012,14 +4085,14 @@ static bool lineart_get_triangle_bounding_areas(LineartRenderBuffer *rb,
(*colbegin) = (int)((b[0] + 1.0) / sp_w);
(*colend) = (int)((b[1] + 1.0) / sp_w);
- (*rowend) = rb->tile_count_y - (int)((b[2] + 1.0) / sp_h) - 1;
- (*rowbegin) = rb->tile_count_y - (int)((b[3] + 1.0) / sp_h) - 1;
+ (*rowend) = ld->qtree.count_y - (int)((b[2] + 1.0) / sp_h) - 1;
+ (*rowbegin) = ld->qtree.count_y - (int)((b[3] + 1.0) / sp_h) - 1;
- if ((*colend) >= rb->tile_count_x) {
- (*colend) = rb->tile_count_x - 1;
+ if ((*colend) >= ld->qtree.count_x) {
+ (*colend) = ld->qtree.count_x - 1;
}
- if ((*rowend) >= rb->tile_count_y) {
- (*rowend) = rb->tile_count_y - 1;
+ if ((*rowend) >= ld->qtree.count_y) {
+ (*rowend) = ld->qtree.count_y - 1;
}
if ((*colbegin) < 0) {
(*colbegin) = 0;
@@ -4031,14 +4104,10 @@ static bool lineart_get_triangle_bounding_areas(LineartRenderBuffer *rb,
return true;
}
-static bool lineart_get_edge_bounding_areas(LineartRenderBuffer *rb,
- LineartEdge *e,
- int *rowbegin,
- int *rowend,
- int *colbegin,
- int *colend)
+static bool lineart_get_edge_bounding_areas(
+ LineartData *ld, LineartEdge *e, int *rowbegin, int *rowend, int *colbegin, int *colend)
{
- double sp_w = rb->width_per_tile, sp_h = rb->height_per_tile;
+ double sp_w = ld->qtree.tile_width, sp_h = ld->qtree.tile_height;
double b[4];
if (!e->v1 || !e->v2) {
@@ -4060,31 +4129,29 @@ static bool lineart_get_edge_bounding_areas(LineartRenderBuffer *rb,
(*colbegin) = (int)((b[0] + 1.0) / sp_w);
(*colend) = (int)((b[1] + 1.0) / sp_w);
- (*rowend) = rb->tile_count_y - (int)((b[2] + 1.0) / sp_h) - 1;
- (*rowbegin) = rb->tile_count_y - (int)((b[3] + 1.0) / sp_h) - 1;
+ (*rowend) = ld->qtree.count_y - (int)((b[2] + 1.0) / sp_h) - 1;
+ (*rowbegin) = ld->qtree.count_y - (int)((b[3] + 1.0) / sp_h) - 1;
/* It's possible that the line stretches too much out to the side, resulting negative value. */
if ((*rowend) < (*rowbegin)) {
- (*rowend) = rb->tile_count_y - 1;
+ (*rowend) = ld->qtree.count_y - 1;
}
if ((*colend) < (*colbegin)) {
- (*colend) = rb->tile_count_x - 1;
+ (*colend) = ld->qtree.count_x - 1;
}
- CLAMP((*colbegin), 0, rb->tile_count_x - 1);
- CLAMP((*rowbegin), 0, rb->tile_count_y - 1);
- CLAMP((*colend), 0, rb->tile_count_x - 1);
- CLAMP((*rowend), 0, rb->tile_count_y - 1);
+ CLAMP((*colbegin), 0, ld->qtree.count_x - 1);
+ CLAMP((*rowbegin), 0, ld->qtree.count_y - 1);
+ CLAMP((*colend), 0, ld->qtree.count_x - 1);
+ CLAMP((*rowend), 0, ld->qtree.count_y - 1);
return true;
}
-LineartBoundingArea *MOD_lineart_get_parent_bounding_area(LineartRenderBuffer *rb,
- double x,
- double y)
+LineartBoundingArea *MOD_lineart_get_parent_bounding_area(LineartData *ld, double x, double y)
{
- double sp_w = rb->width_per_tile, sp_h = rb->height_per_tile;
+ double sp_w = ld->qtree.tile_width, sp_h = ld->qtree.tile_height;
int col, row;
if (x > 1 || x < -1 || y > 1 || y < -1) {
@@ -4092,13 +4159,13 @@ LineartBoundingArea *MOD_lineart_get_parent_bounding_area(LineartRenderBuffer *r
}
col = (int)((x + 1.0) / sp_w);
- row = rb->tile_count_y - (int)((y + 1.0) / sp_h) - 1;
+ row = ld->qtree.count_y - (int)((y + 1.0) / sp_h) - 1;
- if (col >= rb->tile_count_x) {
- col = rb->tile_count_x - 1;
+ if (col >= ld->qtree.count_x) {
+ col = ld->qtree.count_x - 1;
}
- if (row >= rb->tile_count_y) {
- row = rb->tile_count_y - 1;
+ if (row >= ld->qtree.count_y) {
+ row = ld->qtree.count_y - 1;
}
if (col < 0) {
col = 0;
@@ -4107,29 +4174,29 @@ LineartBoundingArea *MOD_lineart_get_parent_bounding_area(LineartRenderBuffer *r
row = 0;
}
- return &rb->initial_bounding_areas[row * LRT_BA_ROWS + col];
+ return &ld->qtree.initials[row * ld->qtree.count_x + col];
}
-static LineartBoundingArea *lineart_get_bounding_area(LineartRenderBuffer *rb, double x, double y)
+static LineartBoundingArea *lineart_get_bounding_area(LineartData *ld, double x, double y)
{
LineartBoundingArea *iba;
- double sp_w = rb->width_per_tile, sp_h = rb->height_per_tile;
+ double sp_w = ld->qtree.tile_width, sp_h = ld->qtree.tile_height;
int c = (int)((x + 1.0) / sp_w);
- int r = rb->tile_count_y - (int)((y + 1.0) / sp_h) - 1;
+ int r = ld->qtree.count_y - (int)((y + 1.0) / sp_h) - 1;
if (r < 0) {
r = 0;
}
if (c < 0) {
c = 0;
}
- if (r >= rb->tile_count_y) {
- r = rb->tile_count_y - 1;
+ if (r >= ld->qtree.count_y) {
+ r = ld->qtree.count_y - 1;
}
- if (c >= rb->tile_count_x) {
- c = rb->tile_count_x - 1;
+ if (c >= ld->qtree.count_x) {
+ c = ld->qtree.count_x - 1;
}
- iba = &rb->initial_bounding_areas[r * LRT_BA_ROWS + c];
+ iba = &ld->qtree.initials[r * ld->qtree.count_x + c];
while (iba->child) {
if (x > iba->cx) {
if (y > iba->cy) {
@@ -4151,57 +4218,160 @@ static LineartBoundingArea *lineart_get_bounding_area(LineartRenderBuffer *rb, d
return iba;
}
-LineartBoundingArea *MOD_lineart_get_bounding_area(LineartRenderBuffer *rb, double x, double y)
+LineartBoundingArea *MOD_lineart_get_bounding_area(LineartData *ld, double x, double y)
{
LineartBoundingArea *ba;
- if ((ba = MOD_lineart_get_parent_bounding_area(rb, x, y)) != NULL) {
- return lineart_get_bounding_area(rb, x, y);
+ if ((ba = MOD_lineart_get_parent_bounding_area(ld, x, y)) != NULL) {
+ return lineart_get_bounding_area(ld, x, y);
}
return NULL;
}
-/**
- * Sequentially add triangles into render buffer. This also does intersection along the way.
- */
-static void lineart_main_add_triangles(LineartRenderBuffer *rb)
+static void lineart_add_triangles_worker(TaskPool *__restrict UNUSED(pool), LineartIsecThread *th)
{
- LineartTriangle *tri;
- int i, lim;
- int x1, x2, y1, y2;
- int r, co;
-
- LISTBASE_FOREACH (LineartElementLinkNode *, eln, &rb->triangle_buffer_pointers) {
- tri = eln->pointer;
- lim = eln->element_count;
- for (i = 0; i < lim; i++) {
- if ((tri->flags & LRT_CULL_USED) || (tri->flags & LRT_CULL_DISCARD)) {
- tri = (void *)(((uchar *)tri) + rb->triangle_size);
- continue;
- }
- if (lineart_get_triangle_bounding_areas(rb, tri, &y1, &y2, &x1, &x2)) {
- for (co = x1; co <= x2; co++) {
- for (r = y1; r <= y2; r++) {
- lineart_bounding_area_link_triangle(rb,
- &rb->initial_bounding_areas[r * LRT_BA_ROWS + co],
- tri,
- 0,
- 1,
- 0,
- (!(tri->flags & LRT_TRIANGLE_NO_INTERSECTION)));
- }
+ LineartData *ld = th->ld;
+ int _dir_control = 0;
+ while (lineart_schedule_new_triangle_task(th)) {
+ for (LineartElementLinkNode *eln = th->pending_from; eln != th->pending_to->next;
+ eln = eln->next) {
+ int index_start = eln == th->pending_from ? th->index_from : 0;
+ int index_end = eln == th->pending_to ? th->index_to : eln->element_count;
+ LineartTriangle *tri = (void *)(((uchar *)eln->pointer) + ld->sizeof_triangle * index_start);
+ for (int ei = index_start; ei < index_end; ei++) {
+ int x1, x2, y1, y2;
+ int r, co;
+ if ((tri->flags & LRT_CULL_USED) || (tri->flags & LRT_CULL_DISCARD)) {
+ tri = (void *)(((uchar *)tri) + ld->sizeof_triangle);
+ continue;
}
- } /* Else throw away. */
- tri = (void *)(((uchar *)tri) + rb->triangle_size);
+ if (lineart_get_triangle_bounding_areas(ld, tri, &y1, &y2, &x1, &x2)) {
+ _dir_control++;
+ for (co = x1; co <= x2; co++) {
+ for (r = y1; r <= y2; r++) {
+ lineart_bounding_area_link_triangle(ld,
+ &ld->qtree.initials[r * ld->qtree.count_x + co],
+ tri,
+ 0,
+ 1,
+ 0,
+ (!(tri->flags & LRT_TRIANGLE_NO_INTERSECTION)),
+ th);
+ }
+ }
+ } /* Else throw away. */
+ tri = (void *)(((uchar *)tri) + ld->sizeof_triangle);
+ }
}
}
}
+static void lineart_create_edges_from_isec_data(LineartIsecData *d)
+{
+ LineartData *ld = d->ld;
+ double ZMax = ld->conf.far_clip;
+ double ZMin = ld->conf.near_clip;
+
+ for (int i = 0; i < d->thread_count; i++) {
+ LineartIsecThread *th = &d->threads[i];
+ if (G.debug_value == 4000) {
+ printf("Thread %d isec generated %d lines.\n", i, th->current);
+ }
+ if (!th->current) {
+ continue;
+ }
+ /* We don't care about removing duplicated vert in this method, chaining can handle that,
+ * and it saves us from using locks and look up tables. */
+ LineartVertIntersection *v = lineart_mem_acquire(
+ &ld->render_data_pool, sizeof(LineartVertIntersection) * th->current * 2);
+ LineartEdge *e = lineart_mem_acquire(&ld->render_data_pool, sizeof(LineartEdge) * th->current);
+ LineartEdgeSegment *es = lineart_mem_acquire(&ld->render_data_pool,
+ sizeof(LineartEdgeSegment) * th->current);
+ for (int j = 0; j < th->current; j++) {
+ LineartVertIntersection *v1i = v;
+ LineartVertIntersection *v2i = v + 1;
+ LineartIsecSingle *is = &th->array[j];
+ v1i->intersecting_with = is->tri1;
+ v2i->intersecting_with = is->tri2;
+ LineartVert *v1 = (LineartVert *)v1i;
+ LineartVert *v2 = (LineartVert *)v2i;
+ v1->flag |= LRT_VERT_HAS_INTERSECTION_DATA;
+ v2->flag |= LRT_VERT_HAS_INTERSECTION_DATA;
+ copy_v3db_v3fl(v1->gloc, is->v1);
+ copy_v3db_v3fl(v2->gloc, is->v2);
+ /* The intersection line has been generated only in geometry space, so we need to transform
+ * them as well. */
+ mul_v4_m4v3_db(v1->fbcoord, ld->conf.view_projection, v1->gloc);
+ mul_v4_m4v3_db(v2->fbcoord, ld->conf.view_projection, v2->gloc);
+ mul_v3db_db(v1->fbcoord, (1 / v1->fbcoord[3]));
+ mul_v3db_db(v2->fbcoord, (1 / v2->fbcoord[3]));
+
+ v1->fbcoord[0] -= ld->conf.shift_x * 2;
+ v1->fbcoord[1] -= ld->conf.shift_y * 2;
+ v2->fbcoord[0] -= ld->conf.shift_x * 2;
+ v2->fbcoord[1] -= ld->conf.shift_y * 2;
+
+ /* This z transformation is not the same as the rest of the part, because the data don't go
+ * through normal perspective division calls in the pipeline, but this way the 3D result and
+ * occlusion on the generated line is correct, and we don't really use 2D for viewport stroke
+ * generation anyway. */
+ v1->fbcoord[2] = ZMin * ZMax / (ZMax - fabs(v1->fbcoord[2]) * (ZMax - ZMin));
+ v2->fbcoord[2] = ZMin * ZMax / (ZMax - fabs(v2->fbcoord[2]) * (ZMax - ZMin));
+ e->v1 = v1;
+ e->v2 = v2;
+ e->t1 = is->tri1;
+ e->t2 = is->tri2;
+ e->flags = LRT_EDGE_FLAG_INTERSECTION;
+ e->intersection_mask = (is->tri1->intersection_mask | is->tri2->intersection_mask);
+ BLI_addtail(&e->segments, es);
+
+ lineart_add_edge_to_array(&ld->pending_edges, e);
+
+ v += 2;
+ e++;
+ es++;
+ }
+ }
+}
+
+/**
+ * Sequentially add triangles into render buffer, intersection lines between those triangles will
+ * also be computed at the same time.
+ */
+static void lineart_main_add_triangles(LineartData *ld)
+{
+ double t_start;
+ if (G.debug_value == 4000) {
+ t_start = PIL_check_seconds_timer();
+ }
+
+ /* Initialize per-thread data for thread task scheduling information and storing intersection
+ * results. */
+ LineartIsecData d = {0};
+ lineart_init_isec_thread(&d, ld, ld->thread_count);
+
+ TaskPool *tp = BLI_task_pool_create(NULL, TASK_PRIORITY_HIGH);
+ for (int i = 0; i < ld->thread_count; i++) {
+ BLI_task_pool_push(tp, (TaskRunFunction)lineart_add_triangles_worker, &d.threads[i], 0, NULL);
+ }
+ BLI_task_pool_work_and_wait(tp);
+ BLI_task_pool_free(tp);
+
+ /* Create actual lineart edges from intersection results. */
+ lineart_create_edges_from_isec_data(&d);
+
+ lineart_destroy_isec_thread(&d);
+
+ if (G.debug_value == 4000) {
+ double t_elapsed = PIL_check_seconds_timer() - t_start;
+ printf("Line art intersection time: %f\n", t_elapsed);
+ }
+}
+
/**
* This function gets the tile for the point `e->v1`, and later use #lineart_bounding_area_next()
* to get next along the way.
*/
-static LineartBoundingArea *lineart_edge_first_bounding_area(LineartRenderBuffer *rb,
- LineartEdge *e)
+static LineartBoundingArea *lineart_edge_first_bounding_area(LineartData *ld, LineartEdge *e)
{
double data[2] = {e->v1->fbcoord[0], e->v1->fbcoord[1]};
double LU[2] = {-1, 1}, RU[2] = {1, 1}, LB[2] = {-1, -1}, RB[2] = {1, -1};
@@ -4209,7 +4379,7 @@ static LineartBoundingArea *lineart_edge_first_bounding_area(LineartRenderBuffer
bool p_unused;
if (data[0] > -1 && data[0] < 1 && data[1] > -1 && data[1] < 1) {
- return lineart_get_bounding_area(rb, data[0], data[1]);
+ return lineart_get_bounding_area(ld, data[0], data[1]);
}
if (lineart_intersect_seg_seg(e->v1->fbcoord, e->v2->fbcoord, LU, RU, &sr, &p_unused) &&
@@ -4230,7 +4400,7 @@ static LineartBoundingArea *lineart_edge_first_bounding_area(LineartRenderBuffer
}
interp_v2_v2v2_db(data, e->v1->fbcoord, e->v2->fbcoord, r);
- return lineart_get_bounding_area(rb, data[0], data[1]);
+ return lineart_get_bounding_area(ld, data[0], data[1]);
}
/**
@@ -4461,7 +4631,7 @@ bool MOD_lineart_compute_feature_lines(Depsgraph *depsgraph,
LineartCache **cached_result,
bool enable_stroke_depth_offset)
{
- LineartRenderBuffer *rb;
+ LineartData *ld;
Scene *scene = DEG_get_evaluated_scene(depsgraph);
int intersections_only = 0; /* Not used right now, but preserve for future. */
Object *use_camera;
@@ -4472,8 +4642,6 @@ bool MOD_lineart_compute_feature_lines(Depsgraph *depsgraph,
t_start = PIL_check_seconds_timer();
}
- BKE_scene_camera_switch_update(scene);
-
if (lmd->calculation_flags & LRT_USE_CUSTOM_CAMERA) {
if (!lmd->source_camera ||
(use_camera = DEG_get_evaluated_object(depsgraph, lmd->source_camera))->type !=
@@ -4482,6 +4650,9 @@ bool MOD_lineart_compute_feature_lines(Depsgraph *depsgraph,
}
}
else {
+
+ BKE_scene_camera_switch_update(scene);
+
if (!scene->camera) {
return false;
}
@@ -4491,54 +4662,53 @@ bool MOD_lineart_compute_feature_lines(Depsgraph *depsgraph,
LineartCache *lc = lineart_init_cache();
*cached_result = lc;
- rb = lineart_create_render_buffer(scene, lmd, use_camera, scene->camera, lc);
+ ld = lineart_create_render_buffer(scene, lmd, use_camera, scene->camera, lc);
/* Triangle thread testing data size varies depending on the thread count.
* See definition of LineartTriangleThread for details. */
- rb->triangle_size = lineart_triangle_size_get(scene, rb);
-
- /* FIXME(Yiming): See definition of int #LineartRenderBuffer::_source_type for detailed. */
- rb->_source_type = lmd->source_type;
- rb->_source_collection = lmd->source_collection;
- rb->_source_object = lmd->source_object;
+ ld->sizeof_triangle = lineart_triangle_size_get(ld);
/* Get view vector before loading geometries, because we detect feature lines there. */
- lineart_main_get_view_vector(rb);
+ lineart_main_get_view_vector(ld);
lineart_main_load_geometries(
- depsgraph, scene, use_camera, rb, lmd->calculation_flags & LRT_ALLOW_DUPLI_OBJECTS);
+ depsgraph, scene, use_camera, ld, lmd->calculation_flags & LRT_ALLOW_DUPLI_OBJECTS);
- if (!rb->vertex_buffer_pointers.first) {
+ if (!ld->geom.vertex_buffer_pointers.first) {
/* No geometry loaded, return early. */
return true;
}
/* Initialize the bounding box acceleration structure, it's a lot like BVH in 3D. */
- lineart_main_bounding_area_make_initial(rb);
+ lineart_main_bounding_area_make_initial(ld);
/* We need to get cut into triangles that are crossing near/far plans, only this way can we get
* correct coordinates of those clipped lines. Done in two steps,
* setting clip_far==false for near plane. */
- lineart_main_cull_triangles(rb, false);
+ lineart_main_cull_triangles(ld, false);
/* `clip_far == true` for far plane. */
- lineart_main_cull_triangles(rb, true);
+ lineart_main_cull_triangles(ld, true);
/* At this point triangle adjacent info pointers is no longer needed, free them. */
- lineart_main_free_adjacent_data(rb);
+ lineart_main_free_adjacent_data(ld);
/* Do the perspective division after clipping is done. */
- lineart_main_perspective_division(rb);
+ lineart_main_perspective_division(ld);
- lineart_main_discard_out_of_frame_edges(rb);
+ lineart_main_discard_out_of_frame_edges(ld);
/* Triangle intersections are done here during sequential adding of them. Only after this,
* triangles and lines are all linked with acceleration structure, and the 2D occlusion stage
* can do its job. */
- lineart_main_add_triangles(rb);
+ lineart_main_add_triangles(ld);
+
+ /* Re-link bounding areas because they have been subdivided by worker threads and we need
+ * adjacent info. */
+ lineart_main_bounding_areas_connect_post(ld);
/* Link lines to acceleration structure, this can only be done after perspective division, if
* we do it after triangles being added, the acceleration structure has already been
* subdivided, this way we do less list manipulations. */
- lineart_main_link_lines(rb);
+ lineart_main_link_lines(ld);
/* "intersection_only" is preserved for being called in a standalone fashion.
* If so the data will already be available at the stage. Otherwise we do the occlusion and
@@ -4547,54 +4717,54 @@ bool MOD_lineart_compute_feature_lines(Depsgraph *depsgraph,
if (!intersections_only) {
/* Occlusion is work-and-wait. This call will not return before work is completed. */
- lineart_main_occlusion_begin(rb);
+ lineart_main_occlusion_begin(ld);
/* Chaining is all single threaded. See lineart_chain.c
* In this particular call, only lines that are geometrically connected (share the _exact_
* same end point) will be chained together. */
- MOD_lineart_chain_feature_lines(rb);
+ MOD_lineart_chain_feature_lines(ld);
/* We are unable to take care of occlusion if we only connect end points, so here we do a
* spit, where the splitting point could be any cut in e->segments. */
- MOD_lineart_chain_split_for_fixed_occlusion(rb);
+ MOD_lineart_chain_split_for_fixed_occlusion(ld);
/* Then we connect chains based on the _proximity_ of their end points in image space, here's
* the place threshold value gets involved. */
- MOD_lineart_chain_connect(rb);
+ MOD_lineart_chain_connect(ld);
float *t_image = &lmd->chaining_image_threshold;
/* This configuration ensures there won't be accidental lost of short unchained segments. */
- MOD_lineart_chain_discard_short(rb, MIN2(*t_image, 0.001f) - FLT_EPSILON);
+ MOD_lineart_chain_discard_short(ld, MIN2(*t_image, 0.001f) - FLT_EPSILON);
- if (rb->chain_smooth_tolerance > FLT_EPSILON) {
+ if (ld->conf.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. */
- MOD_lineart_smooth_chains(rb, rb->chain_smooth_tolerance / 50);
+ MOD_lineart_smooth_chains(ld, ld->conf.chain_smooth_tolerance / 50);
}
- if (rb->use_image_boundary_trimming) {
- MOD_lineart_chain_clip_at_border(rb);
+ if (ld->conf.use_image_boundary_trimming) {
+ MOD_lineart_chain_clip_at_border(ld);
}
- if (rb->angle_splitting_threshold > FLT_EPSILON) {
- MOD_lineart_chain_split_angle(rb, rb->angle_splitting_threshold);
+ if (ld->conf.angle_splitting_threshold > FLT_EPSILON) {
+ MOD_lineart_chain_split_angle(ld, ld->conf.angle_splitting_threshold);
}
if (enable_stroke_depth_offset && lmd->stroke_depth_offset > FLT_EPSILON) {
MOD_lineart_chain_offset_towards_camera(
- rb, lmd->stroke_depth_offset, lmd->flags & LRT_GPENCIL_OFFSET_TOWARDS_CUSTOM_CAMERA);
+ ld, lmd->stroke_depth_offset, lmd->flags & LRT_GPENCIL_OFFSET_TOWARDS_CUSTOM_CAMERA);
}
/* Finally transfer the result list into cache. */
- memcpy(&lc->chains, &rb->chains, sizeof(ListBase));
+ memcpy(&lc->chains, &ld->chains, sizeof(ListBase));
/* At last, we need to clear flags so we don't confuse GPencil generation calls. */
MOD_lineart_chain_clear_picked_flag(lc);
}
if (G.debug_value == 4000) {
- lineart_count_and_print_render_buffer_memory(rb);
+ lineart_count_and_print_render_buffer_memory(ld);
double t_elapsed = PIL_check_seconds_timer() - t_start;
printf("Line art total time: %lf\n", t_elapsed);
@@ -4603,15 +4773,15 @@ bool MOD_lineart_compute_feature_lines(Depsgraph *depsgraph,
return true;
}
-static int UNUSED_FUNCTION(lineart_rb_edge_types)(LineartRenderBuffer *rb)
+static int UNUSED_FUNCTION(lineart_rb_edge_types)(LineartData *ld)
{
int types = 0;
- types |= rb->use_contour ? LRT_EDGE_FLAG_CONTOUR : 0;
- types |= rb->use_crease ? LRT_EDGE_FLAG_CREASE : 0;
- types |= rb->use_material ? LRT_EDGE_FLAG_MATERIAL : 0;
- types |= rb->use_edge_marks ? LRT_EDGE_FLAG_EDGE_MARK : 0;
- types |= rb->use_intersections ? LRT_EDGE_FLAG_INTERSECTION : 0;
- types |= rb->use_loose ? LRT_EDGE_FLAG_LOOSE : 0;
+ types |= ld->conf.use_contour ? LRT_EDGE_FLAG_CONTOUR : 0;
+ types |= ld->conf.use_crease ? LRT_EDGE_FLAG_CREASE : 0;
+ types |= ld->conf.use_material ? LRT_EDGE_FLAG_MATERIAL : 0;
+ types |= ld->conf.use_edge_marks ? LRT_EDGE_FLAG_EDGE_MARK : 0;
+ types |= ld->conf.use_intersections ? LRT_EDGE_FLAG_INTERSECTION : 0;
+ types |= ld->conf.use_loose ? LRT_EDGE_FLAG_LOOSE : 0;
return types;
}
@@ -4630,7 +4800,7 @@ static void lineart_gpencil_generate(LineartCache *cache,
uchar mask_switches,
uchar material_mask_bits,
uchar intersection_mask,
- short thickness,
+ int16_t thickness,
float opacity,
const char *source_vgname,
const char *vgname,
@@ -4789,16 +4959,16 @@ void MOD_lineart_gpencil_generate(LineartCache *cache,
Object *ob,
bGPDlayer *gpl,
bGPDframe *gpf,
- char source_type,
+ int8_t source_type,
void *source_reference,
int level_start,
int level_end,
int mat_nr,
- short edge_types,
+ int16_t edge_types,
uchar mask_switches,
uchar material_mask_bits,
uchar intersection_mask,
- short thickness,
+ int16_t thickness,
float opacity,
const char *source_vgname,
const char *vgname,
@@ -4811,7 +4981,7 @@ void MOD_lineart_gpencil_generate(LineartCache *cache,
Object *source_object = NULL;
Collection *source_collection = NULL;
- short use_types = 0;
+ int16_t use_types = 0;
if (source_type == LRT_SOURCE_OBJECT) {
if (!source_reference) {
return;
diff --git a/source/blender/gpencil_modifiers/intern/lineart/lineart_intern.h b/source/blender/gpencil_modifiers/intern/lineart/lineart_intern.h
index b1aa81322a8..5e24061bd78 100644
--- a/source/blender/gpencil_modifiers/intern/lineart/lineart_intern.h
+++ b/source/blender/gpencil_modifiers/intern/lineart/lineart_intern.h
@@ -18,7 +18,7 @@
#include <string.h>
struct LineartEdge;
-struct LineartRenderBuffer;
+struct LineartData;
struct LineartStaticMemPool;
struct LineartStaticMemPoolNode;
@@ -49,7 +49,6 @@ void *lineart_mem_acquire(struct LineartStaticMemPool *smp, size_t size);
void *lineart_mem_acquire_thread(struct LineartStaticMemPool *smp, size_t size);
void lineart_mem_destroy(struct LineartStaticMemPool *smp);
-void lineart_prepend_edge_direct(void **list_head, void *node);
void lineart_prepend_pool(LinkNode **first, struct LineartStaticMemPool *smp, void *link);
void lineart_matrix_ortho_44d(double (*mProjection)[4],
@@ -62,54 +61,16 @@ void lineart_matrix_ortho_44d(double (*mProjection)[4],
void lineart_matrix_perspective_44d(
double (*mProjection)[4], double fFov_rad, double fAspect, double zMin, double zMax);
-int lineart_count_intersection_segment_count(struct LineartRenderBuffer *rb);
+int lineart_count_intersection_segment_count(struct LineartData *ld);
-void lineart_count_and_print_render_buffer_memory(struct LineartRenderBuffer *rb);
+void lineart_count_and_print_render_buffer_memory(struct LineartData *ld);
#define LRT_ITER_ALL_LINES_BEGIN \
- LineartEdge *e, *next_e; \
- void **current_head; \
- e = rb->contour.first; \
- if (!e) { \
- e = rb->crease.first; \
- } \
- if (!e) { \
- e = rb->material.first; \
- } \
- if (!e) { \
- e = rb->edge_mark.first; \
- } \
- if (!e) { \
- e = rb->intersection.first; \
- } \
- if (!e) { \
- e = rb->floating.first; \
- } \
- for (current_head = &rb->contour.first; e; e = next_e) { \
- next_e = e->next;
-
-#define LRT_ITER_ALL_LINES_NEXT \
- while (!next_e) { \
- if (current_head == &rb->contour.first) { \
- current_head = &rb->crease.first; \
- } \
- else if (current_head == &rb->crease.first) { \
- current_head = &rb->material.first; \
- } \
- else if (current_head == &rb->material.first) { \
- current_head = &rb->edge_mark.first; \
- } \
- else if (current_head == &rb->edge_mark.first) { \
- current_head = &rb->intersection.first; \
- } \
- else if (current_head == &rb->intersection.first) { \
- current_head = &rb->floating.first; \
- } \
- else { \
- break; \
- } \
- next_e = *current_head; \
- }
+ LineartEdge *e; \
+ for (int i = 0; i < ld->pending_edges.next; i++) { \
+ e = ld->pending_edges.array[i];
+
+#define LRT_ITER_ALL_LINES_NEXT ; /* Doesn't do anything now with new array setup. */
#define LRT_ITER_ALL_LINES_END \
LRT_ITER_ALL_LINES_NEXT \
@@ -118,9 +79,9 @@ void lineart_count_and_print_render_buffer_memory(struct LineartRenderBuffer *rb
#define LRT_BOUND_AREA_CROSSES(b1, b2) \
((b1)[0] < (b2)[1] && (b1)[1] > (b2)[0] && (b1)[3] < (b2)[2] && (b1)[2] > (b2)[3])
-/* Initial bounding area row/column count, setting 4 is the simplest way algorithm could function
- * efficiently. */
-#define LRT_BA_ROWS 4
+/* Initial bounding area row/column count, setting 10 is tested to be relatively optimal for the
+ * performance under current algorithm. */
+#define LRT_BA_ROWS 10
#ifdef __cplusplus
extern "C" {
diff --git a/source/blender/gpencil_modifiers/intern/lineart/lineart_ops.c b/source/blender/gpencil_modifiers/intern/lineart/lineart_ops.c
index 2b60fc45800..bbf88985e6a 100644
--- a/source/blender/gpencil_modifiers/intern/lineart/lineart_ops.c
+++ b/source/blender/gpencil_modifiers/intern/lineart/lineart_ops.c
@@ -141,8 +141,8 @@ static bool bake_strokes(Object *ob,
if (!is_first) {
MOD_lineart_clear_cache(&local_lc);
}
- /* Restore the original cache pointer so the modifiers below still have access to the
- * "global" cache. */
+ /* Restore the original cache pointer so the modifiers below still have access to the "global"
+ * cache. */
lmd->cache = gpd->runtime.lineart_cache;
}
diff --git a/source/blender/gpencil_modifiers/intern/lineart/lineart_util.c b/source/blender/gpencil_modifiers/intern/lineart/lineart_util.c
index 4ea17b25995..95647f2dd75 100644
--- a/source/blender/gpencil_modifiers/intern/lineart/lineart_util.c
+++ b/source/blender/gpencil_modifiers/intern/lineart/lineart_util.c
@@ -144,13 +144,6 @@ void lineart_mem_destroy(LineartStaticMemPool *smp)
}
}
-void lineart_prepend_edge_direct(void **list_head, void *node)
-{
- LineartEdge *e_n = (LineartEdge *)node;
- e_n->next = (*list_head);
- (*list_head) = e_n;
-}
-
void lineart_prepend_pool(LinkNode **first, LineartStaticMemPool *smp, void *link)
{
LinkNode *ln = lineart_mem_acquire_thread(smp, sizeof(LinkNode));
@@ -212,13 +205,13 @@ void lineart_matrix_ortho_44d(double (*mProjection)[4],
mProjection[3][3] = 1.0f;
}
-void lineart_count_and_print_render_buffer_memory(LineartRenderBuffer *rb)
+void lineart_count_and_print_render_buffer_memory(LineartData *ld)
{
size_t total = 0;
size_t sum_this = 0;
size_t count_this = 0;
- LISTBASE_FOREACH (LineartStaticMemPoolNode *, smpn, &rb->render_data_pool.pools) {
+ LISTBASE_FOREACH (LineartStaticMemPoolNode *, smpn, &ld->render_data_pool.pools) {
count_this++;
sum_this += LRT_MEMORY_POOL_1MB;
}
@@ -227,7 +220,7 @@ void lineart_count_and_print_render_buffer_memory(LineartRenderBuffer *rb)
sum_this = 0;
count_this = 0;
- LISTBASE_FOREACH (LineartElementLinkNode *, reln, &rb->line_buffer_pointers) {
+ LISTBASE_FOREACH (LineartElementLinkNode *, reln, &ld->geom.line_buffer_pointers) {
count_this++;
sum_this += reln->element_count * sizeof(LineartEdge);
}
@@ -236,9 +229,9 @@ void lineart_count_and_print_render_buffer_memory(LineartRenderBuffer *rb)
sum_this = 0;
count_this = 0;
- LISTBASE_FOREACH (LineartElementLinkNode *, reln, &rb->triangle_buffer_pointers) {
+ LISTBASE_FOREACH (LineartElementLinkNode *, reln, &ld->geom.triangle_buffer_pointers) {
count_this++;
- sum_this += reln->element_count * rb->triangle_size;
+ sum_this += reln->element_count * ld->sizeof_triangle;
}
printf(" allocated %zu triangle blocks, total %zu Bytes.\n", count_this, sum_this);
total += sum_this;
diff --git a/source/blender/gpu/CMakeLists.txt b/source/blender/gpu/CMakeLists.txt
index 1e54d5fb7ee..cadc2c4445b 100644
--- a/source/blender/gpu/CMakeLists.txt
+++ b/source/blender/gpu/CMakeLists.txt
@@ -21,13 +21,12 @@ set(INC
../imbuf
../makesdna
../makesrna
- ../windowmanager
+ # For theme color access.
../editors/include
- # For node muting stuff...
+ # For node muting stuff.
../nodes
- ../nodes/intern
../../../intern/atomic
../../../intern/clog
@@ -85,6 +84,7 @@ set(SRC
GPU_buffers.h
GPU_capabilities.h
GPU_common.h
+ GPU_common_types.h
GPU_compute.h
GPU_context.h
GPU_debug.h
@@ -189,6 +189,7 @@ set(METAL_SRC
metal/mtl_backend.mm
metal/mtl_context.mm
metal/mtl_debug.mm
+ metal/mtl_state.mm
metal/mtl_texture.mm
metal/mtl_texture_util.mm
@@ -197,6 +198,7 @@ set(METAL_SRC
metal/mtl_common.hh
metal/mtl_context.hh
metal/mtl_debug.hh
+ metal/mtl_state.hh
metal/mtl_texture.hh
)
@@ -301,7 +303,13 @@ set(GLSL_SRC
shaders/gpu_shader_codegen_lib.glsl
- shaders/gpu_shader_geometry.glsl
+ shaders/common/gpu_shader_common_color_ramp.glsl
+ shaders/common/gpu_shader_common_color_utils.glsl
+ shaders/common/gpu_shader_common_curves.glsl
+ shaders/common/gpu_shader_common_hash.glsl
+ shaders/common/gpu_shader_common_math.glsl
+ shaders/common/gpu_shader_common_math_utils.glsl
+ shaders/common/gpu_shader_common_mix_rgb.glsl
shaders/material/gpu_shader_material_add_shader.glsl
shaders/material/gpu_shader_material_ambient_occlusion.glsl
@@ -315,8 +323,6 @@ set(GLSL_SRC
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_color.glsl
shaders/material/gpu_shader_material_combine_hsv.glsl
shaders/material/gpu_shader_material_combine_rgb.glsl
@@ -325,7 +331,6 @@ set(GLSL_SRC
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
@@ -334,7 +339,6 @@ set(GLSL_SRC
shaders/material/gpu_shader_material_glossy.glsl
shaders/material/gpu_shader_material_hair_info.glsl
shaders/material/gpu_shader_material_hair.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
@@ -343,9 +347,6 @@ set(GLSL_SRC
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
@@ -358,7 +359,6 @@ set(GLSL_SRC
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_color.glsl
shaders/material/gpu_shader_material_separate_hsv.glsl
@@ -383,10 +383,10 @@ set(GLSL_SRC
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_transform_utils.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
@@ -405,8 +405,6 @@ set(GLSL_SRC
shaders/gpu_shader_cfg_world_clip_lib.glsl
shaders/gpu_shader_colorspace_lib.glsl
- shaders/gpu_shader_common_obinfos_lib.glsl
-
GPU_shader_shared_utils.h
)
@@ -445,20 +443,21 @@ list(APPEND INC ${CMAKE_CURRENT_BINARY_DIR})
set(SRC_SHADER_CREATE_INFOS
../draw/engines/basic/shaders/infos/basic_depth_info.hh
../draw/engines/eevee_next/shaders/infos/eevee_material_info.hh
+ ../draw/engines/eevee_next/shaders/infos/eevee_velocity_info.hh
../draw/engines/gpencil/shaders/infos/gpencil_info.hh
../draw/engines/gpencil/shaders/infos/gpencil_vfx_info.hh
- ../draw/engines/overlay/shaders/infos/antialiasing_info.hh
- ../draw/engines/overlay/shaders/infos/armature_info.hh
- ../draw/engines/overlay/shaders/infos/background_info.hh
- ../draw/engines/overlay/shaders/infos/edit_mode_info.hh
- ../draw/engines/overlay/shaders/infos/extra_info.hh
- ../draw/engines/overlay/shaders/infos/facing_info.hh
- ../draw/engines/overlay/shaders/infos/grid_info.hh
- ../draw/engines/overlay/shaders/infos/outline_info.hh
- ../draw/engines/overlay/shaders/infos/paint_info.hh
- ../draw/engines/overlay/shaders/infos/sculpt_info.hh
- ../draw/engines/overlay/shaders/infos/volume_info.hh
- ../draw/engines/overlay/shaders/infos/wireframe_info.hh
+ ../draw/engines/overlay/shaders/infos/overlay_antialiasing_info.hh
+ ../draw/engines/overlay/shaders/infos/overlay_armature_info.hh
+ ../draw/engines/overlay/shaders/infos/overlay_background_info.hh
+ ../draw/engines/overlay/shaders/infos/overlay_edit_mode_info.hh
+ ../draw/engines/overlay/shaders/infos/overlay_extra_info.hh
+ ../draw/engines/overlay/shaders/infos/overlay_facing_info.hh
+ ../draw/engines/overlay/shaders/infos/overlay_grid_info.hh
+ ../draw/engines/overlay/shaders/infos/overlay_outline_info.hh
+ ../draw/engines/overlay/shaders/infos/overlay_paint_info.hh
+ ../draw/engines/overlay/shaders/infos/overlay_sculpt_info.hh
+ ../draw/engines/overlay/shaders/infos/overlay_volume_info.hh
+ ../draw/engines/overlay/shaders/infos/overlay_wireframe_info.hh
../draw/engines/select/shaders/infos/select_id_info.hh
../draw/engines/workbench/shaders/infos/workbench_composite_info.hh
../draw/engines/workbench/shaders/infos/workbench_effect_antialiasing_info.hh
@@ -498,6 +497,7 @@ set(SRC_SHADER_CREATE_INFOS
shaders/infos/gpu_shader_2D_widget_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_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_polyline_info.hh
diff --git a/source/blender/gpu/GPU_buffers.h b/source/blender/gpu/GPU_buffers.h
index 1af0080baef..1fe3b363687 100644
--- a/source/blender/gpu/GPU_buffers.h
+++ b/source/blender/gpu/GPU_buffers.h
@@ -10,6 +10,7 @@
#include <stddef.h>
#include "BKE_attribute.h"
+#include "BKE_pbvh.h"
#ifdef __cplusplus
extern "C" {
@@ -20,6 +21,7 @@ struct CCGElem;
struct CCGKey;
struct DMFlagMat;
struct GSet;
+struct TableGSet;
struct MLoop;
struct MLoopCol;
struct MLoopTri;
@@ -29,6 +31,9 @@ struct MVert;
struct Mesh;
struct PBVH;
struct SubdivCCG;
+struct CustomData;
+
+typedef struct PBVHGPUFormat PBVHGPUFormat;
/**
* Buffers for drawing from PBVH grids.
@@ -78,36 +83,46 @@ enum {
};
/**
+ * Creates a vertex buffer (coordinate, normal, color) and,
+ * if smooth shading, an element index buffer.
* Threaded: do not call any functions that use OpenGL calls!
*/
-void GPU_pbvh_mesh_buffers_update(GPU_PBVH_Buffers *buffers,
+void GPU_pbvh_mesh_buffers_update(PBVHGPUFormat *vbo_id,
+ GPU_PBVH_Buffers *buffers,
const struct MVert *mvert,
- const float (*vert_normals)[3],
+ const CustomData *vdata,
+ const CustomData *ldata,
const float *vmask,
- const void *vcol_data,
- int vcol_type,
- AttributeDomain vcol_domain,
const int *sculpt_face_sets,
- int face_sets_color_seed,
- int face_sets_color_default,
- int update_flags);
+ const int face_sets_color_seed,
+ const int face_sets_color_default,
+ const int update_flags,
+ const float (*vert_normals)[3]);
+
+bool GPU_pbvh_attribute_names_update(PBVHType pbvh_type,
+ PBVHGPUFormat *vbo_id,
+ const struct CustomData *vdata,
+ const struct CustomData *ldata,
+ bool active_attrs_only);
/**
* Creates a vertex buffer (coordinate, normal, color) and,
* if smooth shading, an element index buffer.
* Threaded: do not call any functions that use OpenGL calls!
*/
-void GPU_pbvh_bmesh_buffers_update(GPU_PBVH_Buffers *buffers,
+void GPU_pbvh_bmesh_buffers_update(PBVHGPUFormat *vbo_id,
+ struct GPU_PBVH_Buffers *buffers,
struct BMesh *bm,
struct GSet *bm_faces,
struct GSet *bm_unique_verts,
struct GSet *bm_other_verts,
- int update_flags);
+ const int update_flags);
/**
* Threaded: do not call any functions that use OpenGL calls!
*/
-void GPU_pbvh_grid_buffers_update(GPU_PBVH_Buffers *buffers,
+void GPU_pbvh_grid_buffers_update(PBVHGPUFormat *vbo_id,
+ GPU_PBVH_Buffers *buffers,
struct SubdivCCG *subdiv_ccg,
struct CCGElem **grids,
const struct DMFlagMat *grid_flag_mats,
@@ -120,7 +135,8 @@ void GPU_pbvh_grid_buffers_update(GPU_PBVH_Buffers *buffers,
int update_flags);
/**
- * Finish update. Not thread safe, must run in OpenGL main thread.
+ * Finish update. Not thread safe, must run in OpenGL main
+ * thread.
*/
void GPU_pbvh_buffers_update_flush(GPU_PBVH_Buffers *buffers);
@@ -133,9 +149,11 @@ void GPU_pbvh_buffers_free(GPU_PBVH_Buffers *buffers);
struct GPUBatch *GPU_pbvh_buffers_batch_get(GPU_PBVH_Buffers *buffers, bool fast, bool wires);
short GPU_pbvh_buffers_material_index_get(GPU_PBVH_Buffers *buffers);
-
bool GPU_pbvh_buffers_has_overlays(GPU_PBVH_Buffers *buffers);
+PBVHGPUFormat *GPU_pbvh_make_format(void);
+void GPU_pbvh_free_format(PBVHGPUFormat *vbo_id);
+
#ifdef __cplusplus
}
#endif
diff --git a/source/blender/gpu/GPU_capabilities.h b/source/blender/gpu/GPU_capabilities.h
index 0d0542aa528..7fe467de402 100644
--- a/source/blender/gpu/GPU_capabilities.h
+++ b/source/blender/gpu/GPU_capabilities.h
@@ -30,16 +30,18 @@ int GPU_max_batch_vertices(void);
int GPU_max_vertex_attribs(void);
int GPU_max_varying_floats(void);
int GPU_max_shader_storage_buffer_bindings(void);
+int GPU_max_compute_shader_storage_blocks(void);
int GPU_extensions_len(void);
const char *GPU_extension_get(int i);
-int GPU_texture_size_with_limit(int res, bool limit_gl_texture_size);
+int GPU_texture_size_with_limit(int res);
bool GPU_mip_render_workaround(void);
bool GPU_depth_blitting_workaround(void);
bool GPU_use_main_context_workaround(void);
bool GPU_use_hq_normals_workaround(void);
+bool GPU_clear_viewport_workaround(void);
bool GPU_crappy_amd_driver(void);
bool GPU_compute_shader_support(void);
diff --git a/source/blender/gpu/GPU_common_types.h b/source/blender/gpu/GPU_common_types.h
new file mode 100644
index 00000000000..8c91d60812f
--- /dev/null
+++ b/source/blender/gpu/GPU_common_types.h
@@ -0,0 +1,18 @@
+/** \file
+ * \ingroup gpu
+ */
+
+#pragma once
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef enum eGPUFrontFace {
+ GPU_CLOCKWISE,
+ GPU_COUNTERCLOCKWISE,
+} eGPUFrontFace;
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/source/blender/gpu/GPU_legacy_stubs.h b/source/blender/gpu/GPU_legacy_stubs.h
index 369347447f8..5970738a9b3 100644
--- a/source/blender/gpu/GPU_legacy_stubs.h
+++ b/source/blender/gpu/GPU_legacy_stubs.h
@@ -23,7 +23,7 @@
#include "BLI_utildefines.h"
/**
- * Empty function, use for breakpoint when a deprecated
+ * Empty function, use for break-point when a deprecated
* OpenGL function is called.
*/
static void gl_deprecated(void)
diff --git a/source/blender/gpu/GPU_material.h b/source/blender/gpu/GPU_material.h
index fff90e6f8ff..c0633f0323d 100644
--- a/source/blender/gpu/GPU_material.h
+++ b/source/blender/gpu/GPU_material.h
@@ -7,7 +7,7 @@
#pragma once
-#include "DNA_customdata_types.h" /* for CustomDataType */
+#include "DNA_customdata_types.h" /* for eCustomDataType */
#include "DNA_image_types.h"
#include "DNA_listBase.h"
@@ -130,9 +130,9 @@ typedef void (*GPUCodegenCallbackFn)(void *thunk, GPUMaterial *mat, GPUCodegenOu
GPUNodeLink *GPU_constant(const float *num);
GPUNodeLink *GPU_uniform(const float *num);
-GPUNodeLink *GPU_attribute(GPUMaterial *mat, CustomDataType type, const char *name);
+GPUNodeLink *GPU_attribute(GPUMaterial *mat, eCustomDataType type, const char *name);
GPUNodeLink *GPU_attribute_with_default(GPUMaterial *mat,
- CustomDataType type,
+ eCustomDataType type,
const char *name,
eGPUDefaultValue default_value);
GPUNodeLink *GPU_uniform_attribute(GPUMaterial *mat, const char *name, bool use_dupli);
@@ -259,7 +259,7 @@ void GPU_pass_cache_free(void);
typedef struct GPUMaterialAttribute {
struct GPUMaterialAttribute *next, *prev;
- int type; /* CustomDataType */
+ int type; /* eCustomDataType */
char name[64]; /* MAX_CUSTOMDATA_LAYER_NAME */
char input_name[12 + 1]; /* GPU_MAX_SAFE_ATTR_NAME + 1 */
eGPUType gputype;
diff --git a/source/blender/gpu/GPU_shader.h b/source/blender/gpu/GPU_shader.h
index b620fe9cc9d..3460d33fe68 100644
--- a/source/blender/gpu/GPU_shader.h
+++ b/source/blender/gpu/GPU_shader.h
@@ -280,6 +280,16 @@ typedef enum eGPUBuiltinShader {
GPU_SHADER_2D_IMAGE_OVERLAYS_STEREO_MERGE,
GPU_SHADER_2D_IMAGE_SHUFFLE_COLOR,
/**
+ * Draw a texture in 3D. Take a 3D position and a 2D texture coordinate for each vertex.
+ *
+ * Exposed via Python-API for add-ons.
+ *
+ * \param image: uniform sampler2D
+ * \param texCoord: in vec2
+ * \param pos: in vec3
+ */
+ GPU_SHADER_3D_IMAGE,
+ /**
* Draw texture with alpha. Take a 3D position and a 2D texture coordinate for each vertex.
*
* \param alpha: uniform float
diff --git a/source/blender/gpu/GPU_state.h b/source/blender/gpu/GPU_state.h
index 99b60351dcc..7519b3bc1cb 100644
--- a/source/blender/gpu/GPU_state.h
+++ b/source/blender/gpu/GPU_state.h
@@ -35,6 +35,19 @@ typedef enum eGPUBarrier {
ENUM_OPERATORS(eGPUBarrier, GPU_BARRIER_ELEMENT_ARRAY)
+/* NOTE: For Metal and Vulkan only.
+ * TODO(Metal): Update barrier calls to use stage flags. */
+typedef enum eGPUStageBarrierBits {
+ GPU_BARRIER_STAGE_VERTEX = (1 << 0),
+ GPU_BARRIER_STAGE_FRAGMENT = (1 << 1),
+ GPU_BARRIER_STAGE_COMPUTE = (1 << 2),
+ GPU_BARRIER_STAGE_ANY_GRAPHICS = (GPU_BARRIER_STAGE_VERTEX | GPU_BARRIER_STAGE_FRAGMENT),
+ GPU_BARRIER_STAGE_ANY = (GPU_BARRIER_STAGE_VERTEX | GPU_BARRIER_STAGE_FRAGMENT |
+ GPU_BARRIER_STAGE_COMPUTE),
+} eGPUStageBarrierBits;
+
+ENUM_OPERATORS(eGPUStageBarrierBits, GPU_BARRIER_STAGE_COMPUTE)
+
/**
* Defines the fixed pipeline blending equation.
* SRC is the output color from the shader.
diff --git a/source/blender/gpu/GPU_storage_buffer.h b/source/blender/gpu/GPU_storage_buffer.h
index 1478d490e23..ca6a848786b 100644
--- a/source/blender/gpu/GPU_storage_buffer.h
+++ b/source/blender/gpu/GPU_storage_buffer.h
@@ -47,6 +47,18 @@ void GPU_storagebuf_clear(GPUStorageBuf *ssbo,
void *data);
void GPU_storagebuf_clear_to_zero(GPUStorageBuf *ssbo);
+/**
+ * \brief Copy a part of a vertex buffer to a storage buffer.
+ *
+ * \param ssbo: destination storage buffer
+ * \param src: source vertex buffer
+ * \param dst_offset: where to start copying to (in bytes).
+ * \param src_offset: where to start copying from (in bytes).
+ * \param copy_size: byte size of the segment to copy.
+ */
+void GPU_storagebuf_copy_sub_from_vertbuf(
+ GPUStorageBuf *ssbo, GPUVertBuf *src, uint dst_offset, uint src_offset, uint copy_size);
+
#ifdef __cplusplus
}
#endif
diff --git a/source/blender/gpu/GPU_texture.h b/source/blender/gpu/GPU_texture.h
index bb0912f284b..5bd20b7be98 100644
--- a/source/blender/gpu/GPU_texture.h
+++ b/source/blender/gpu/GPU_texture.h
@@ -113,7 +113,7 @@ typedef enum eGPUTextureFormat {
GPU_R16F,
GPU_R16, /* Max texture buffer format. */
- /* Special formats texture & renderbuffer */
+ /* Special formats texture & render-buffer. */
GPU_RGB10_A2,
GPU_R11F_G11F_B10F,
GPU_DEPTH32F_STENCIL8,
@@ -280,9 +280,9 @@ void *GPU_texture_read(GPUTexture *tex, eGPUDataFormat data_format, int miplvl);
/**
* Fills the whole texture with the same data for all pixels.
* \warning Only work for 2D texture for now.
- * \warning Only clears the mip 0 of the texture.
+ * \warning Only clears the MIP 0 of the texture.
* \param data_format: data format of the pixel data.
- * \note The format is float for unorm textures.
+ * \note The format is float for UNORM textures.
* \param data: 1 pixel worth of data to fill the texture with.
*/
void GPU_texture_clear(GPUTexture *tex, eGPUDataFormat data_format, const void *data);
diff --git a/source/blender/gpu/GPU_vertex_buffer.h b/source/blender/gpu/GPU_vertex_buffer.h
index fe6ed7eaf87..722ef878271 100644
--- a/source/blender/gpu/GPU_vertex_buffer.h
+++ b/source/blender/gpu/GPU_vertex_buffer.h
@@ -165,6 +165,7 @@ void GPU_vertbuf_tag_dirty(GPUVertBuf *verts);
*/
void GPU_vertbuf_use(GPUVertBuf *);
void GPU_vertbuf_bind_as_ssbo(struct GPUVertBuf *verts, int binding);
+void GPU_vertbuf_bind_as_texture(struct GPUVertBuf *verts, int binding);
void GPU_vertbuf_wrap_handle(GPUVertBuf *verts, uint64_t handle);
diff --git a/source/blender/gpu/GPU_vertex_format.h b/source/blender/gpu/GPU_vertex_format.h
index c6b0d5902fe..bf8dc409cb7 100644
--- a/source/blender/gpu/GPU_vertex_format.h
+++ b/source/blender/gpu/GPU_vertex_format.h
@@ -55,7 +55,7 @@ typedef struct GPUVertAttr {
/* 1 to 4 or 8 or 12 or 16 */
uint comp_len : 5;
/* size in bytes, 1 to 64 */
- uint sz : 7;
+ uint size : 7;
/* from beginning of vertex, in bytes */
uint offset : 11;
/* up to GPU_VERT_ATTR_MAX_NAMES */
diff --git a/source/blender/gpu/intern/gpu_batch.cc b/source/blender/gpu/intern/gpu_batch.cc
index 32b117dac12..1b34b6e6c69 100644
--- a/source/blender/gpu/intern/gpu_batch.cc
+++ b/source/blender/gpu/intern/gpu_batch.cc
@@ -14,7 +14,6 @@
#include "GPU_batch.h"
#include "GPU_batch_presets.h"
-#include "GPU_matrix.h"
#include "GPU_platform.h"
#include "GPU_shader.h"
diff --git a/source/blender/gpu/intern/gpu_batch_presets.c b/source/blender/gpu/intern/gpu_batch_presets.c
index ab5e23a846c..4dff35c3633 100644
--- a/source/blender/gpu/intern/gpu_batch_presets.c
+++ b/source/blender/gpu/intern/gpu_batch_presets.c
@@ -11,15 +11,8 @@
#include "BLI_utildefines.h"
#include "MEM_guardedalloc.h"
-#include "DNA_userdef_types.h"
-
-#include "UI_interface.h"
-#include "UI_resources.h"
-
#include "GPU_batch.h"
-#include "GPU_batch_presets.h" /* own include */
-#include "GPU_batch_utils.h"
-#include "GPU_context.h"
+#include "GPU_batch_presets.h" /* Own include. */
/* -------------------------------------------------------------------- */
/** \name Local Structures
@@ -139,7 +132,7 @@ GPUBatch *GPU_batch_preset_sphere_wire(int lod)
/** \name Create Sphere (3D)
* \{ */
-GPUBatch *gpu_batch_sphere(int lat_res, int lon_res)
+static GPUBatch *gpu_batch_sphere(int lat_res, int lon_res)
{
const float lon_inc = 2 * M_PI / lon_res;
const float lat_inc = M_PI / lat_res;
diff --git a/source/blender/gpu/intern/gpu_batch_utils.c b/source/blender/gpu/intern/gpu_batch_utils.c
index 43a47aab945..10a05fe90b9 100644
--- a/source/blender/gpu/intern/gpu_batch_utils.c
+++ b/source/blender/gpu/intern/gpu_batch_utils.c
@@ -8,7 +8,6 @@
#include "BLI_math.h"
#include "BLI_polyfill_2d.h"
-#include "BLI_rect.h"
#include "BLI_sort_utils.h"
#include "BLI_utildefines.h"
diff --git a/source/blender/gpu/intern/gpu_buffers.c b/source/blender/gpu/intern/gpu_buffers.c
index fed998bb33e..a1fe3d79223 100644
--- a/source/blender/gpu/intern/gpu_buffers.c
+++ b/source/blender/gpu/intern/gpu_buffers.c
@@ -9,20 +9,18 @@
#include <limits.h>
#include <stddef.h>
+#include <stdlib.h>
#include <string.h>
#include "MEM_guardedalloc.h"
#include "BLI_bitmap.h"
#include "BLI_ghash.h"
-#include "BLI_hash.h"
-#include "BLI_math.h"
#include "BLI_math_color.h"
-#include "BLI_math_color_blend.h"
#include "BLI_utildefines.h"
+#include "DNA_mesh_types.h"
#include "DNA_meshdata_types.h"
-#include "DNA_userdef_types.h"
#include "BKE_DerivedMesh.h"
#include "BKE_attribute.h"
@@ -36,17 +34,12 @@
#include "GPU_batch.h"
#include "GPU_buffers.h"
+#include "DRW_engine.h"
+
#include "gpu_private.h"
#include "bmesh.h"
-/* XXX: the rest of the code in this file is used for optimized PBVH
- * drawing and doesn't interact at all with the buffer code above */
-
-/* -------------------------------------------------------------------- */
-/** \name Private Types
- * \{ */
-
struct GPU_PBVH_Buffers {
GPUIndexBuf *index_buf, *index_buf_fast;
GPUIndexBuf *index_lines_buf, *index_lines_buf_fast;
@@ -88,10 +81,52 @@ struct GPU_PBVH_Buffers {
bool show_overlay;
};
-static struct {
+typedef struct GPUAttrRef {
+ uchar domain, type;
+ ushort cd_offset;
+ int layer_idx;
+} GPUAttrRef;
+
+#define MAX_GPU_ATTR 256
+
+typedef struct PBVHGPUFormat {
GPUVertFormat format;
- uint pos, nor, msk, col, fset;
-} g_vbo_id = {{0}};
+ uint pos, nor, msk, fset;
+ uint col[MAX_GPU_ATTR];
+ uint uv[MAX_GPU_ATTR];
+ int totcol, totuv;
+
+ /* Upload only the active color and UV attributes,
+ * used for workbench mode. */
+ bool active_attrs_only;
+} PBVHGPUFormat;
+
+PBVHGPUFormat *GPU_pbvh_make_format(void)
+{
+ PBVHGPUFormat *vbo_id = MEM_callocN(sizeof(PBVHGPUFormat), "PBVHGPUFormat");
+
+ GPU_pbvh_attribute_names_update(PBVH_FACES, vbo_id, NULL, NULL, false);
+
+ return vbo_id;
+}
+
+void GPU_pbvh_free_format(PBVHGPUFormat *vbo_id)
+{
+ MEM_SAFE_FREE(vbo_id);
+}
+
+static int gpu_pbvh_make_attr_offs(eAttrDomainMask domain_mask,
+ eCustomDataMask type_mask,
+ const CustomData *vdata,
+ const CustomData *edata,
+ const CustomData *ldata,
+ const CustomData *pdata,
+ GPUAttrRef r_cd_attrs[MAX_GPU_ATTR],
+ bool active_only,
+ int active_type,
+ int active_domain,
+ const CustomDataLayer *active_layer,
+ const CustomDataLayer *render_layer);
/** \} */
@@ -101,20 +136,6 @@ static struct {
void gpu_pbvh_init()
{
- /* Initialize vertex buffer (match 'VertexBufferFormat'). */
- if (g_vbo_id.format.attr_len == 0) {
- g_vbo_id.pos = GPU_vertformat_attr_add(
- &g_vbo_id.format, "pos", GPU_COMP_F32, 3, GPU_FETCH_FLOAT);
- g_vbo_id.nor = GPU_vertformat_attr_add(
- &g_vbo_id.format, "nor", GPU_COMP_I16, 3, GPU_FETCH_INT_TO_FLOAT_UNIT);
- /* TODO: Do not allocate these `.msk` and `.col` when they are not used. */
- g_vbo_id.msk = GPU_vertformat_attr_add(
- &g_vbo_id.format, "msk", GPU_COMP_U8, 1, GPU_FETCH_INT_TO_FLOAT_UNIT);
- g_vbo_id.col = GPU_vertformat_attr_add(
- &g_vbo_id.format, "ac", GPU_COMP_U16, 4, GPU_FETCH_INT_TO_FLOAT_UNIT);
- g_vbo_id.fset = GPU_vertformat_attr_add(
- &g_vbo_id.format, "fset", GPU_COMP_U8, 3, GPU_FETCH_INT_TO_FLOAT_UNIT);
- }
}
void gpu_pbvh_exit()
@@ -122,33 +143,37 @@ void gpu_pbvh_exit()
/* Nothing to do. */
}
+static CustomDataLayer *get_active_layer(const CustomData *cdata, int type)
+{
+ int idx = CustomData_get_active_layer_index(cdata, type);
+ return idx != -1 ? cdata->layers + idx : NULL;
+}
+
+static CustomDataLayer *get_render_layer(const CustomData *cdata, int type)
+{
+ int idx = CustomData_get_render_layer_index(cdata, type);
+ return idx != -1 ? cdata->layers + idx : NULL;
+}
+
/* Allocates a non-initialized buffer to be sent to GPU.
* Return is false it indicates that the memory map failed. */
-static bool gpu_pbvh_vert_buf_data_set(GPU_PBVH_Buffers *buffers, uint vert_len)
+static bool gpu_pbvh_vert_buf_data_set(PBVHGPUFormat *vbo_id,
+ GPU_PBVH_Buffers *buffers,
+ uint vert_len)
{
/* Keep so we can test #GPU_USAGE_DYNAMIC buffer use.
* Not that format initialization match in both blocks.
* Do this to keep braces balanced - otherwise indentation breaks. */
-#if 0
- if (buffers->vert_buf == NULL) {
- /* Initialize vertex buffer (match 'VertexBufferFormat'). */
- buffers->vert_buf = GPU_vertbuf_create_with_format_ex(&g_vbo_id.format, GPU_USAGE_DYNAMIC);
- GPU_vertbuf_data_alloc(buffers->vert_buf, vert_len);
- }
- else if (vert_len != buffers->vert_buf->vertex_len) {
- GPU_vertbuf_data_resize(buffers->vert_buf, vert_len);
- }
-#else
+
if (buffers->vert_buf == NULL) {
/* Initialize vertex buffer (match 'VertexBufferFormat'). */
- buffers->vert_buf = GPU_vertbuf_create_with_format_ex(&g_vbo_id.format, GPU_USAGE_STATIC);
+ buffers->vert_buf = GPU_vertbuf_create_with_format_ex(&vbo_id->format, GPU_USAGE_STATIC);
}
if (GPU_vertbuf_get_data(buffers->vert_buf) == NULL ||
GPU_vertbuf_get_vertex_len(buffers->vert_buf) != vert_len) {
/* Allocate buffer if not allocated yet or size changed. */
GPU_vertbuf_data_alloc(buffers->vert_buf, vert_len);
}
-#endif
return GPU_vertbuf_get_data(buffers->vert_buf) != NULL;
}
@@ -194,25 +219,62 @@ static bool gpu_pbvh_is_looptri_visible(const MLoopTri *lt,
sculpt_face_sets[lt->poly] > SCULPT_FACE_SET_NONE);
}
-void GPU_pbvh_mesh_buffers_update(GPU_PBVH_Buffers *buffers,
+void GPU_pbvh_mesh_buffers_update(PBVHGPUFormat *vbo_id,
+ GPU_PBVH_Buffers *buffers,
const MVert *mvert,
- const float (*vert_normals)[3],
+ const CustomData *vdata,
+ const CustomData *ldata,
const float *vmask,
- const void *vcol_data,
- int vcol_type,
- AttributeDomain vcol_domain,
const int *sculpt_face_sets,
int face_sets_color_seed,
int face_sets_color_default,
- int update_flags)
+ int update_flags,
+ const float (*vert_normals)[3])
{
- const MPropCol *vtcol = vcol_type == CD_PROP_COLOR ? vcol_data : NULL;
- const MLoopCol *vcol = vcol_type == CD_PROP_BYTE_COLOR ? vcol_data : NULL;
- const float(*f3col)[3] = vcol_type == CD_PROP_FLOAT3 ? vcol_data : NULL;
+ GPUAttrRef vcol_refs[MAX_GPU_ATTR];
+ GPUAttrRef cd_uvs[MAX_GPU_ATTR];
+
+ Mesh me_query;
+ BKE_id_attribute_copy_domains_temp(ID_ME, vdata, NULL, ldata, NULL, NULL, &me_query.id);
+
+ CustomDataLayer *actcol = BKE_id_attributes_active_color_get(&me_query.id);
+ eAttrDomain actcol_domain = actcol ? BKE_id_attribute_domain(&me_query.id, actcol) :
+ ATTR_DOMAIN_AUTO;
+
+ CustomDataLayer *rendercol = BKE_id_attributes_render_color_get(&me_query.id);
+
+ int totcol;
+
+ if (update_flags & GPU_PBVH_BUFFERS_SHOW_VCOL) {
+ totcol = gpu_pbvh_make_attr_offs(ATTR_DOMAIN_MASK_COLOR,
+ CD_MASK_COLOR_ALL,
+ vdata,
+ NULL,
+ ldata,
+ NULL,
+ vcol_refs,
+ vbo_id->active_attrs_only,
+ actcol ? actcol->type : 0,
+ actcol_domain,
+ actcol,
+ rendercol);
+ }
+ else {
+ totcol = 0;
+ }
- const bool color_loops = vcol_domain == ATTR_DOMAIN_CORNER;
- const bool show_vcol = (vtcol || vcol || f3col) &&
- (update_flags & GPU_PBVH_BUFFERS_SHOW_VCOL) != 0;
+ int totuv = gpu_pbvh_make_attr_offs(ATTR_DOMAIN_MASK_CORNER,
+ CD_MASK_MLOOPUV,
+ NULL,
+ NULL,
+ ldata,
+ NULL,
+ cd_uvs,
+ vbo_id->active_attrs_only,
+ CD_MLOOPUV,
+ ATTR_DOMAIN_CORNER,
+ get_active_layer(ldata, CD_MLOOPUV),
+ get_render_layer(ldata, CD_MLOOPUV));
const bool show_mask = vmask && (update_flags & GPU_PBVH_BUFFERS_SHOW_MASK) != 0;
const bool show_face_sets = sculpt_face_sets &&
@@ -224,25 +286,106 @@ void GPU_pbvh_mesh_buffers_update(GPU_PBVH_Buffers *buffers,
const int totelem = buffers->tot_tri * 3;
/* Build VBO */
- if (gpu_pbvh_vert_buf_data_set(buffers, totelem)) {
+ if (gpu_pbvh_vert_buf_data_set(vbo_id, buffers, totelem)) {
GPUVertBufRaw pos_step = {0};
GPUVertBufRaw nor_step = {0};
GPUVertBufRaw msk_step = {0};
GPUVertBufRaw fset_step = {0};
GPUVertBufRaw col_step = {0};
+ GPUVertBufRaw uv_step = {0};
- GPU_vertbuf_attr_get_raw_data(buffers->vert_buf, g_vbo_id.pos, &pos_step);
- GPU_vertbuf_attr_get_raw_data(buffers->vert_buf, g_vbo_id.nor, &nor_step);
- GPU_vertbuf_attr_get_raw_data(buffers->vert_buf, g_vbo_id.msk, &msk_step);
- GPU_vertbuf_attr_get_raw_data(buffers->vert_buf, g_vbo_id.fset, &fset_step);
- if (show_vcol) {
- GPU_vertbuf_attr_get_raw_data(buffers->vert_buf, g_vbo_id.col, &col_step);
- }
+ GPU_vertbuf_attr_get_raw_data(buffers->vert_buf, vbo_id->pos, &pos_step);
+ GPU_vertbuf_attr_get_raw_data(buffers->vert_buf, vbo_id->nor, &nor_step);
+ GPU_vertbuf_attr_get_raw_data(buffers->vert_buf, vbo_id->msk, &msk_step);
+ GPU_vertbuf_attr_get_raw_data(buffers->vert_buf, vbo_id->fset, &fset_step);
/* calculate normal for each polygon only once */
uint mpoly_prev = UINT_MAX;
short no[3] = {0, 0, 0};
+ if (totuv > 0) {
+ for (int uv_i = 0; uv_i < totuv; uv_i++) {
+ GPU_vertbuf_attr_get_raw_data(buffers->vert_buf, vbo_id->uv[uv_i], &uv_step);
+
+ GPUAttrRef *ref = cd_uvs + uv_i;
+ CustomDataLayer *layer = ldata->layers + ref->layer_idx;
+ MLoopUV *muv = layer->data;
+
+ for (uint i = 0; i < buffers->face_indices_len; i++) {
+ const MLoopTri *lt = &buffers->looptri[buffers->face_indices[i]];
+
+ if (!gpu_pbvh_is_looptri_visible(lt, mvert, buffers->mloop, sculpt_face_sets)) {
+ continue;
+ }
+
+ for (uint j = 0; j < 3; j++) {
+ MLoopUV *muv2 = muv + lt->tri[j];
+
+ memcpy(GPU_vertbuf_raw_step(&uv_step), muv2->uv, sizeof(muv2->uv));
+ }
+ }
+ }
+ }
+
+ for (int col_i = 0; col_i < totcol; col_i++) {
+ GPU_vertbuf_attr_get_raw_data(buffers->vert_buf, vbo_id->col[col_i], &col_step);
+
+ MPropCol *pcol = NULL;
+ MLoopCol *mcol = NULL;
+
+ GPUAttrRef *ref = vcol_refs + col_i;
+ const CustomData *cdata = ref->domain == ATTR_DOMAIN_POINT ? vdata : ldata;
+ CustomDataLayer *layer = cdata->layers + ref->layer_idx;
+
+ bool color_loops = ref->domain == ATTR_DOMAIN_CORNER;
+
+ if (layer->type == CD_PROP_COLOR) {
+ pcol = (MPropCol *)layer->data;
+ }
+ else {
+ mcol = (MLoopCol *)layer->data;
+ }
+
+ for (uint i = 0; i < buffers->face_indices_len; i++) {
+ const MLoopTri *lt = &buffers->looptri[buffers->face_indices[i]];
+ const uint vtri[3] = {
+ buffers->mloop[lt->tri[0]].v,
+ buffers->mloop[lt->tri[1]].v,
+ buffers->mloop[lt->tri[2]].v,
+ };
+
+ if (!gpu_pbvh_is_looptri_visible(lt, mvert, buffers->mloop, sculpt_face_sets)) {
+ continue;
+ }
+
+ for (uint j = 0; j < 3; j++) {
+ /* Vertex Colors. */
+ const uint loop_index = lt->tri[j];
+
+ ushort scol[4] = {USHRT_MAX, USHRT_MAX, USHRT_MAX, USHRT_MAX};
+
+ if (pcol) {
+ MPropCol *pcol2 = pcol + (color_loops ? loop_index : vtri[j]);
+
+ scol[0] = unit_float_to_ushort_clamp(pcol2->color[0]);
+ scol[1] = unit_float_to_ushort_clamp(pcol2->color[1]);
+ scol[2] = unit_float_to_ushort_clamp(pcol2->color[2]);
+ scol[3] = unit_float_to_ushort_clamp(pcol2->color[3]);
+ }
+ else {
+ const MLoopCol *mcol2 = mcol + (color_loops ? loop_index : vtri[j]);
+
+ scol[0] = unit_float_to_ushort_clamp(BLI_color_from_srgb_table[mcol2->r]);
+ scol[1] = unit_float_to_ushort_clamp(BLI_color_from_srgb_table[mcol2->g]);
+ scol[2] = unit_float_to_ushort_clamp(BLI_color_from_srgb_table[mcol2->b]);
+ scol[3] = unit_float_to_ushort_clamp(mcol2->a * (1.0f / 255.0f));
+ }
+
+ memcpy(GPU_vertbuf_raw_step(&col_step), scol, sizeof(scol));
+ }
+ }
+ }
+
for (uint i = 0; i < buffers->face_indices_len; i++) {
const MLoopTri *lt = &buffers->looptri[buffers->face_indices[i]];
const uint vtri[3] = {
@@ -296,50 +439,6 @@ void GPU_pbvh_mesh_buffers_update(GPU_PBVH_Buffers *buffers,
*(uchar *)GPU_vertbuf_raw_step(&msk_step) = cmask;
empty_mask = empty_mask && (cmask == 0);
- /* Vertex Colors. */
- if (show_vcol) {
- ushort scol[4] = {USHRT_MAX, USHRT_MAX, USHRT_MAX, USHRT_MAX};
- if (vtcol) {
- if (color_loops) {
- scol[0] = unit_float_to_ushort_clamp(vtcol[lt->tri[j]].color[0]);
- scol[1] = unit_float_to_ushort_clamp(vtcol[lt->tri[j]].color[1]);
- scol[2] = unit_float_to_ushort_clamp(vtcol[lt->tri[j]].color[2]);
- scol[3] = unit_float_to_ushort_clamp(vtcol[lt->tri[j]].color[3]);
- }
- else {
- scol[0] = unit_float_to_ushort_clamp(vtcol[vtri[j]].color[0]);
- scol[1] = unit_float_to_ushort_clamp(vtcol[vtri[j]].color[1]);
- scol[2] = unit_float_to_ushort_clamp(vtcol[vtri[j]].color[2]);
- scol[3] = unit_float_to_ushort_clamp(vtcol[vtri[j]].color[3]);
- }
- memcpy(GPU_vertbuf_raw_step(&col_step), scol, sizeof(scol));
- }
- else if (f3col) {
- if (color_loops) {
- scol[0] = unit_float_to_ushort_clamp(f3col[lt->tri[j]][0]);
- scol[1] = unit_float_to_ushort_clamp(f3col[lt->tri[j]][1]);
- scol[2] = unit_float_to_ushort_clamp(f3col[lt->tri[j]][2]);
- scol[3] = USHRT_MAX;
- }
- else {
- scol[0] = unit_float_to_ushort_clamp(f3col[vtri[j]][0]);
- scol[1] = unit_float_to_ushort_clamp(f3col[vtri[j]][1]);
- scol[2] = unit_float_to_ushort_clamp(f3col[vtri[j]][2]);
- scol[3] = USHRT_MAX;
- }
- memcpy(GPU_vertbuf_raw_step(&col_step), scol, sizeof(scol));
- }
- else if (vcol) {
- const uint loop_index = lt->tri[j];
- const MLoopCol *mcol = vcol + (color_loops ? loop_index : vtri[j]);
-
- scol[0] = unit_float_to_ushort_clamp(BLI_color_from_srgb_table[mcol->r]);
- scol[1] = unit_float_to_ushort_clamp(BLI_color_from_srgb_table[mcol->g]);
- scol[2] = unit_float_to_ushort_clamp(BLI_color_from_srgb_table[mcol->b]);
- scol[3] = unit_float_to_ushort_clamp(mcol->a * (1.0f / 255.0f));
- memcpy(GPU_vertbuf_raw_step(&col_step), scol, sizeof(scol));
- }
- }
/* Face Sets. */
memcpy(GPU_vertbuf_raw_step(&fset_step), face_set_color, sizeof(uchar[3]));
}
@@ -604,7 +703,8 @@ void GPU_pbvh_grid_buffers_update_free(GPU_PBVH_Buffers *buffers,
}
}
-void GPU_pbvh_grid_buffers_update(GPU_PBVH_Buffers *buffers,
+void GPU_pbvh_grid_buffers_update(PBVHGPUFormat *vbo_id,
+ GPU_PBVH_Buffers *buffers,
SubdivCCG *subdiv_ccg,
CCGElem **grids,
const struct DMFlagMat *grid_flag_mats,
@@ -628,8 +728,6 @@ void GPU_pbvh_grid_buffers_update(GPU_PBVH_Buffers *buffers,
/* Build VBO */
const int has_mask = key->has_mask;
- buffers->smooth = grid_flag_mats[grid_indices[0]].flag & ME_SMOOTH;
-
uint vert_per_grid = (buffers->smooth) ? key->grid_area : (square_i(key->grid_size - 1) * 4);
uint vert_count = totgrid * vert_per_grid;
@@ -653,7 +751,7 @@ void GPU_pbvh_grid_buffers_update(GPU_PBVH_Buffers *buffers,
uint vbo_index_offset = 0;
/* Build VBO */
- if (gpu_pbvh_vert_buf_data_set(buffers, vert_count)) {
+ if (gpu_pbvh_vert_buf_data_set(vbo_id, buffers, vert_count)) {
GPUIndexBufBuilder elb_lines;
if (buffers->index_lines_buf == NULL) {
@@ -683,25 +781,25 @@ void GPU_pbvh_grid_buffers_update(GPU_PBVH_Buffers *buffers,
for (x = 0; x < key->grid_size; x++) {
CCGElem *elem = CCG_grid_elem(key, grid, x, y);
GPU_vertbuf_attr_set(
- buffers->vert_buf, g_vbo_id.pos, vbo_index, CCG_elem_co(key, elem));
+ buffers->vert_buf, vbo_id->pos, vbo_index, CCG_elem_co(key, elem));
short no_short[3];
normal_float_to_short_v3(no_short, CCG_elem_no(key, elem));
- GPU_vertbuf_attr_set(buffers->vert_buf, g_vbo_id.nor, vbo_index, no_short);
+ GPU_vertbuf_attr_set(buffers->vert_buf, vbo_id->nor, vbo_index, no_short);
if (has_mask && show_mask) {
float fmask = *CCG_elem_mask(key, elem);
uchar cmask = (uchar)(fmask * 255);
- GPU_vertbuf_attr_set(buffers->vert_buf, g_vbo_id.msk, vbo_index, &cmask);
+ GPU_vertbuf_attr_set(buffers->vert_buf, vbo_id->msk, vbo_index, &cmask);
empty_mask = empty_mask && (cmask == 0);
}
if (show_vcol) {
const ushort vcol[4] = {USHRT_MAX, USHRT_MAX, USHRT_MAX, USHRT_MAX};
- GPU_vertbuf_attr_set(buffers->vert_buf, g_vbo_id.col, vbo_index, &vcol);
+ GPU_vertbuf_attr_set(buffers->vert_buf, vbo_id->col[0], vbo_index, &vcol);
}
- GPU_vertbuf_attr_set(buffers->vert_buf, g_vbo_id.fset, vbo_index, &face_set_color);
+ GPU_vertbuf_attr_set(buffers->vert_buf, vbo_id->fset, vbo_index, &face_set_color);
vbo_index += 1;
}
@@ -730,37 +828,37 @@ void GPU_pbvh_grid_buffers_update(GPU_PBVH_Buffers *buffers,
normal_quad_v3(fno, co[3], co[2], co[1], co[0]);
normal_float_to_short_v3(no_short, fno);
- GPU_vertbuf_attr_set(buffers->vert_buf, g_vbo_id.pos, vbo_index + 0, co[0]);
- GPU_vertbuf_attr_set(buffers->vert_buf, g_vbo_id.nor, vbo_index + 0, no_short);
- GPU_vertbuf_attr_set(buffers->vert_buf, g_vbo_id.pos, vbo_index + 1, co[1]);
- GPU_vertbuf_attr_set(buffers->vert_buf, g_vbo_id.nor, vbo_index + 1, no_short);
- GPU_vertbuf_attr_set(buffers->vert_buf, g_vbo_id.pos, vbo_index + 2, co[2]);
- GPU_vertbuf_attr_set(buffers->vert_buf, g_vbo_id.nor, vbo_index + 2, no_short);
- GPU_vertbuf_attr_set(buffers->vert_buf, g_vbo_id.pos, vbo_index + 3, co[3]);
- GPU_vertbuf_attr_set(buffers->vert_buf, g_vbo_id.nor, vbo_index + 3, no_short);
+ GPU_vertbuf_attr_set(buffers->vert_buf, vbo_id->pos, vbo_index + 0, co[0]);
+ GPU_vertbuf_attr_set(buffers->vert_buf, vbo_id->nor, vbo_index + 0, no_short);
+ GPU_vertbuf_attr_set(buffers->vert_buf, vbo_id->pos, vbo_index + 1, co[1]);
+ GPU_vertbuf_attr_set(buffers->vert_buf, vbo_id->nor, vbo_index + 1, no_short);
+ GPU_vertbuf_attr_set(buffers->vert_buf, vbo_id->pos, vbo_index + 2, co[2]);
+ GPU_vertbuf_attr_set(buffers->vert_buf, vbo_id->nor, vbo_index + 2, no_short);
+ GPU_vertbuf_attr_set(buffers->vert_buf, vbo_id->pos, vbo_index + 3, co[3]);
+ GPU_vertbuf_attr_set(buffers->vert_buf, vbo_id->nor, vbo_index + 3, no_short);
if (has_mask && show_mask) {
float fmask = (*CCG_elem_mask(key, elems[0]) + *CCG_elem_mask(key, elems[1]) +
*CCG_elem_mask(key, elems[2]) + *CCG_elem_mask(key, elems[3])) *
0.25f;
uchar cmask = (uchar)(fmask * 255);
- GPU_vertbuf_attr_set(buffers->vert_buf, g_vbo_id.msk, vbo_index + 0, &cmask);
- GPU_vertbuf_attr_set(buffers->vert_buf, g_vbo_id.msk, vbo_index + 1, &cmask);
- GPU_vertbuf_attr_set(buffers->vert_buf, g_vbo_id.msk, vbo_index + 2, &cmask);
- GPU_vertbuf_attr_set(buffers->vert_buf, g_vbo_id.msk, vbo_index + 3, &cmask);
+ GPU_vertbuf_attr_set(buffers->vert_buf, vbo_id->msk, vbo_index + 0, &cmask);
+ GPU_vertbuf_attr_set(buffers->vert_buf, vbo_id->msk, vbo_index + 1, &cmask);
+ GPU_vertbuf_attr_set(buffers->vert_buf, vbo_id->msk, vbo_index + 2, &cmask);
+ GPU_vertbuf_attr_set(buffers->vert_buf, vbo_id->msk, vbo_index + 3, &cmask);
empty_mask = empty_mask && (cmask == 0);
}
const ushort vcol[4] = {USHRT_MAX, USHRT_MAX, USHRT_MAX, USHRT_MAX};
- GPU_vertbuf_attr_set(buffers->vert_buf, g_vbo_id.col, vbo_index + 0, &vcol);
- GPU_vertbuf_attr_set(buffers->vert_buf, g_vbo_id.col, vbo_index + 1, &vcol);
- GPU_vertbuf_attr_set(buffers->vert_buf, g_vbo_id.col, vbo_index + 2, &vcol);
- GPU_vertbuf_attr_set(buffers->vert_buf, g_vbo_id.col, vbo_index + 3, &vcol);
+ GPU_vertbuf_attr_set(buffers->vert_buf, vbo_id->col[0], vbo_index + 0, &vcol);
+ GPU_vertbuf_attr_set(buffers->vert_buf, vbo_id->col[0], vbo_index + 1, &vcol);
+ GPU_vertbuf_attr_set(buffers->vert_buf, vbo_id->col[0], vbo_index + 2, &vcol);
+ GPU_vertbuf_attr_set(buffers->vert_buf, vbo_id->col[0], vbo_index + 3, &vcol);
- GPU_vertbuf_attr_set(buffers->vert_buf, g_vbo_id.fset, vbo_index + 0, &face_set_color);
- GPU_vertbuf_attr_set(buffers->vert_buf, g_vbo_id.fset, vbo_index + 1, &face_set_color);
- GPU_vertbuf_attr_set(buffers->vert_buf, g_vbo_id.fset, vbo_index + 2, &face_set_color);
- GPU_vertbuf_attr_set(buffers->vert_buf, g_vbo_id.fset, vbo_index + 3, &face_set_color);
+ GPU_vertbuf_attr_set(buffers->vert_buf, vbo_id->fset, vbo_index + 0, &face_set_color);
+ GPU_vertbuf_attr_set(buffers->vert_buf, vbo_id->fset, vbo_index + 1, &face_set_color);
+ GPU_vertbuf_attr_set(buffers->vert_buf, vbo_id->fset, vbo_index + 2, &face_set_color);
+ GPU_vertbuf_attr_set(buffers->vert_buf, vbo_id->fset, vbo_index + 3, &face_set_color);
vbo_index += 4;
}
@@ -805,7 +903,8 @@ GPU_PBVH_Buffers *GPU_pbvh_grid_buffers_build(int totgrid, BLI_bitmap **grid_hid
* \{ */
/* Output a BMVert into a VertexBufferFormat array at v_index. */
-static void gpu_bmesh_vert_to_buffer_copy(BMVert *v,
+static void gpu_bmesh_vert_to_buffer_copy(PBVHGPUFormat *vbo_id,
+ BMVert *v,
GPUVertBuf *vert_buf,
int v_index,
const float fno[3],
@@ -819,27 +918,27 @@ static void gpu_bmesh_vert_to_buffer_copy(BMVert *v,
BLI_assert(!BM_elem_flag_test(v, BM_ELEM_HIDDEN));
/* Set coord, normal, and mask */
- GPU_vertbuf_attr_set(vert_buf, g_vbo_id.pos, v_index, v->co);
+ GPU_vertbuf_attr_set(vert_buf, vbo_id->pos, v_index, v->co);
short no_short[3];
normal_float_to_short_v3(no_short, fno ? fno : v->no);
- GPU_vertbuf_attr_set(vert_buf, g_vbo_id.nor, v_index, no_short);
+ GPU_vertbuf_attr_set(vert_buf, vbo_id->nor, v_index, no_short);
if (show_mask) {
float effective_mask = fmask ? *fmask : BM_ELEM_CD_GET_FLOAT(v, cd_vert_mask_offset);
uchar cmask = (uchar)(effective_mask * 255);
- GPU_vertbuf_attr_set(vert_buf, g_vbo_id.msk, v_index, &cmask);
+ GPU_vertbuf_attr_set(vert_buf, vbo_id->msk, v_index, &cmask);
*empty_mask = *empty_mask && (cmask == 0);
}
if (show_vcol) {
const ushort vcol[4] = {USHRT_MAX, USHRT_MAX, USHRT_MAX, USHRT_MAX};
- GPU_vertbuf_attr_set(vert_buf, g_vbo_id.col, v_index, &vcol);
+ GPU_vertbuf_attr_set(vert_buf, vbo_id->col[0], v_index, &vcol);
}
/* Add default face sets color to avoid artifacts. */
const uchar face_set[3] = {UCHAR_MAX, UCHAR_MAX, UCHAR_MAX};
- GPU_vertbuf_attr_set(vert_buf, g_vbo_id.fset, v_index, &face_set);
+ GPU_vertbuf_attr_set(vert_buf, vbo_id->fset, v_index, &face_set);
}
/* Return the total number of vertices that don't have BM_ELEM_HIDDEN set */
@@ -896,7 +995,8 @@ void GPU_pbvh_bmesh_buffers_update_free(GPU_PBVH_Buffers *buffers)
}
}
-void GPU_pbvh_bmesh_buffers_update(GPU_PBVH_Buffers *buffers,
+void GPU_pbvh_bmesh_buffers_update(PBVHGPUFormat *vbo_id,
+ GPU_PBVH_Buffers *buffers,
BMesh *bm,
GSet *bm_faces,
GSet *bm_unique_verts,
@@ -935,7 +1035,7 @@ void GPU_pbvh_bmesh_buffers_update(GPU_PBVH_Buffers *buffers,
const int cd_vert_mask_offset = CustomData_get_offset(&bm->vdata, CD_PAINT_MASK);
/* Fill vertex buffer */
- if (!gpu_pbvh_vert_buf_data_set(buffers, totvert)) {
+ if (!gpu_pbvh_vert_buf_data_set(vbo_id, buffers, totvert)) {
/* Memory map failed */
return;
}
@@ -965,7 +1065,8 @@ void GPU_pbvh_bmesh_buffers_update(GPU_PBVH_Buffers *buffers,
/* Add vertex to the vertex buffer each time a new one is encountered */
*idx_p = POINTER_FROM_UINT(v_index);
- gpu_bmesh_vert_to_buffer_copy(v[i],
+ gpu_bmesh_vert_to_buffer_copy(vbo_id,
+ v[i],
buffers->vert_buf,
v_index,
NULL,
@@ -1032,7 +1133,8 @@ void GPU_pbvh_bmesh_buffers_update(GPU_PBVH_Buffers *buffers,
GPU_indexbuf_add_line_verts(&elb_lines, v_index + 2, v_index + 0);
for (i = 0; i < 3; i++) {
- gpu_bmesh_vert_to_buffer_copy(v[i],
+ gpu_bmesh_vert_to_buffer_copy(vbo_id,
+ v[i],
buffers->vert_buf,
v_index++,
f->no,
@@ -1075,6 +1177,250 @@ GPU_PBVH_Buffers *GPU_pbvh_bmesh_buffers_build(bool smooth_shading)
return buffers;
}
+/**
+ * Builds a list of attributes from a set of domains and a set of
+ * customdata types.
+ *
+ * \param active_only Returns only one item, a GPUAttrRef to active_layer
+ * \param active_layer CustomDataLayer to use for the active layer
+ * \param active_layer CustomDataLayer to use for the render layer
+ */
+static int gpu_pbvh_make_attr_offs(eAttrDomainMask domain_mask,
+ eCustomDataMask type_mask,
+ const CustomData *vdata,
+ const CustomData *edata,
+ const CustomData *ldata,
+ const CustomData *pdata,
+ GPUAttrRef r_cd_attrs[MAX_GPU_ATTR],
+ bool active_only,
+ int active_type,
+ int active_domain,
+ const CustomDataLayer *active_layer,
+ const CustomDataLayer *render_layer)
+{
+ const CustomData *cdata_active = active_domain == ATTR_DOMAIN_POINT ? vdata : ldata;
+
+ if (!cdata_active) {
+ return 0;
+ }
+
+ if (active_only) {
+ int idx = active_layer ? active_layer - cdata_active->layers : -1;
+
+ if (idx >= 0 && idx < cdata_active->totlayer) {
+ r_cd_attrs[0].cd_offset = cdata_active->layers[idx].offset;
+ r_cd_attrs[0].domain = active_domain;
+ r_cd_attrs[0].type = active_type;
+ r_cd_attrs[0].layer_idx = idx;
+
+ return 1;
+ }
+
+ return 0;
+ }
+
+ const CustomData *datas[4] = {vdata, edata, pdata, ldata};
+
+ int count = 0;
+ for (eAttrDomain domain = 0; domain < 4; domain++) {
+ const CustomData *cdata = datas[domain];
+
+ if (!cdata || !((1 << domain) & domain_mask)) {
+ continue;
+ }
+
+ CustomDataLayer *cl = cdata->layers;
+
+ for (int i = 0; count < MAX_GPU_ATTR && i < cdata->totlayer; i++, cl++) {
+ if ((CD_TYPE_AS_MASK(cl->type) & type_mask) && !(cl->flag & CD_FLAG_TEMPORARY)) {
+ GPUAttrRef *ref = r_cd_attrs + count;
+
+ ref->cd_offset = cl->offset;
+ ref->type = cl->type;
+ ref->layer_idx = i;
+ ref->domain = domain;
+
+ count++;
+ }
+ }
+ }
+
+ /* ensure render layer is last
+ draw cache code seems to need this
+ */
+
+ for (int i = 0; i < count; i++) {
+ GPUAttrRef *ref = r_cd_attrs + i;
+ const CustomData *cdata = datas[ref->domain];
+
+ if (cdata->layers + ref->layer_idx == render_layer) {
+ SWAP(GPUAttrRef, r_cd_attrs[i], r_cd_attrs[count - 1]);
+ break;
+ }
+ }
+
+ return count;
+}
+
+static bool gpu_pbvh_format_equals(PBVHGPUFormat *a, PBVHGPUFormat *b)
+{
+ bool bad = false;
+
+ bad |= a->active_attrs_only != b->active_attrs_only;
+
+ bad |= a->pos != b->pos;
+ bad |= a->fset != b->fset;
+ bad |= a->msk != b->msk;
+ bad |= a->nor != b->nor;
+
+ for (int i = 0; i < MIN2(a->totuv, b->totuv); i++) {
+ bad |= a->uv[i] != b->uv[i];
+ }
+
+ for (int i = 0; i < MIN2(a->totcol, b->totcol); i++) {
+ bad |= a->col[i] != b->col[i];
+ }
+
+ bad |= a->totuv != b->totuv;
+ bad |= a->totcol != b->totcol;
+
+ return !bad;
+}
+
+bool GPU_pbvh_attribute_names_update(PBVHType pbvh_type,
+ PBVHGPUFormat *vbo_id,
+ const CustomData *vdata,
+ const CustomData *ldata,
+ bool active_attrs_only)
+{
+ const bool active_only = active_attrs_only;
+ PBVHGPUFormat old_format = *vbo_id;
+
+ GPU_vertformat_clear(&vbo_id->format);
+
+ vbo_id->active_attrs_only = active_attrs_only;
+
+ if (vbo_id->format.attr_len == 0) {
+ vbo_id->pos = GPU_vertformat_attr_add(
+ &vbo_id->format, "pos", GPU_COMP_F32, 3, GPU_FETCH_FLOAT);
+ vbo_id->nor = GPU_vertformat_attr_add(
+ &vbo_id->format, "nor", GPU_COMP_I16, 3, GPU_FETCH_INT_TO_FLOAT_UNIT);
+
+ /* TODO: Do not allocate these `.msk` and `.col` when they are not used. */
+ vbo_id->msk = GPU_vertformat_attr_add(
+ &vbo_id->format, "msk", GPU_COMP_U8, 1, GPU_FETCH_INT_TO_FLOAT_UNIT);
+
+ vbo_id->totcol = 0;
+ if (pbvh_type == PBVH_FACES) {
+ int ci = 0;
+
+ Mesh me_query;
+
+ BKE_id_attribute_copy_domains_temp(ID_ME, vdata, NULL, ldata, NULL, NULL, &me_query.id);
+
+ CustomDataLayer *active_color_layer = BKE_id_attributes_active_color_get(&me_query.id);
+ CustomDataLayer *render_color_layer = BKE_id_attributes_render_color_get(&me_query.id);
+ eAttrDomain active_color_domain = active_color_layer ?
+ BKE_id_attribute_domain(&me_query.id,
+ active_color_layer) :
+ ATTR_DOMAIN_NUM;
+
+ GPUAttrRef vcol_layers[MAX_GPU_ATTR];
+ int totlayer = gpu_pbvh_make_attr_offs(ATTR_DOMAIN_MASK_COLOR,
+ CD_MASK_COLOR_ALL,
+ vdata,
+ NULL,
+ ldata,
+ NULL,
+ vcol_layers,
+ active_only,
+ active_color_layer ? active_color_layer->type : -1,
+ active_color_domain,
+ active_color_layer,
+ render_color_layer);
+
+ for (int i = 0; i < totlayer; i++) {
+ GPUAttrRef *ref = vcol_layers + i;
+ const CustomData *cdata = ref->domain == ATTR_DOMAIN_POINT ? vdata : ldata;
+
+ const CustomDataLayer *layer = cdata->layers + ref->layer_idx;
+
+ if (vbo_id->totcol < MAX_GPU_ATTR) {
+ vbo_id->col[ci++] = GPU_vertformat_attr_add(
+ &vbo_id->format, "c", GPU_COMP_U16, 4, GPU_FETCH_INT_TO_FLOAT_UNIT);
+ vbo_id->totcol++;
+
+ bool is_render = render_color_layer == layer;
+ bool is_active = active_color_layer == layer;
+
+ DRW_cdlayer_attr_aliases_add(&vbo_id->format, "c", cdata, layer, is_render, is_active);
+ }
+ }
+ }
+
+ /* ensure at least one vertex color layer */
+ if (vbo_id->totcol == 0) {
+ vbo_id->col[0] = GPU_vertformat_attr_add(
+ &vbo_id->format, "c", GPU_COMP_U16, 4, GPU_FETCH_INT_TO_FLOAT_UNIT);
+ vbo_id->totcol = 1;
+
+ GPU_vertformat_alias_add(&vbo_id->format, "ac");
+ }
+
+ vbo_id->fset = GPU_vertformat_attr_add(
+ &vbo_id->format, "fset", GPU_COMP_U8, 3, GPU_FETCH_INT_TO_FLOAT_UNIT);
+
+ vbo_id->totuv = 0;
+ if (pbvh_type == PBVH_FACES && ldata && CustomData_has_layer(ldata, CD_MLOOPUV)) {
+ GPUAttrRef uv_layers[MAX_GPU_ATTR];
+ CustomDataLayer *active = NULL, *render = NULL;
+
+ active = get_active_layer(ldata, CD_MLOOPUV);
+ render = get_render_layer(ldata, CD_MLOOPUV);
+
+ int totlayer = gpu_pbvh_make_attr_offs(ATTR_DOMAIN_MASK_CORNER,
+ CD_MASK_MLOOPUV,
+ NULL,
+ NULL,
+ ldata,
+ NULL,
+ uv_layers,
+ active_only,
+ CD_MLOOPUV,
+ ATTR_DOMAIN_CORNER,
+ active,
+ render);
+
+ vbo_id->totuv = totlayer;
+
+ for (int i = 0; i < totlayer; i++) {
+ GPUAttrRef *ref = uv_layers + i;
+
+ vbo_id->uv[i] = GPU_vertformat_attr_add(
+ &vbo_id->format, "uvs", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
+
+ CustomDataLayer *cl = ldata->layers + ref->layer_idx;
+ bool is_active = ref->layer_idx == CustomData_get_active_layer_index(ldata, CD_MLOOPUV);
+
+ DRW_cdlayer_attr_aliases_add(&vbo_id->format, "u", ldata, cl, cl == render, is_active);
+
+ /* Apparently the render attribute is 'a' while active is 'au',
+ * at least going by the draw cache extractor code.
+ */
+ if (cl == render) {
+ GPU_vertformat_alias_add(&vbo_id->format, "a");
+ }
+ }
+ }
+ }
+
+ if (!gpu_pbvh_format_equals(&old_format, vbo_id)) {
+ return true;
+ }
+
+ return false;
+}
+
GPUBatch *GPU_pbvh_buffers_batch_get(GPU_PBVH_Buffers *buffers, bool fast, bool wires)
{
if (wires) {
diff --git a/source/blender/gpu/intern/gpu_capabilities.cc b/source/blender/gpu/intern/gpu_capabilities.cc
index b750dacaca6..18748627b83 100644
--- a/source/blender/gpu/intern/gpu_capabilities.cc
+++ b/source/blender/gpu/intern/gpu_capabilities.cc
@@ -8,7 +8,7 @@
* with checks for drivers and GPU support.
*/
-#include "DNA_userdef_types.h"
+#include "DNA_userdef_types.h" /* For `U.glreslimit`. */
#include "GPU_capabilities.h"
@@ -33,11 +33,10 @@ int GPU_max_texture_size()
return GCaps.max_texture_size;
}
-int GPU_texture_size_with_limit(int res, bool limit_gl_texture_size)
+int GPU_texture_size_with_limit(int res)
{
int size = GPU_max_texture_size();
- int reslimit = (limit_gl_texture_size && (U.glreslimit != 0)) ? min_ii(U.glreslimit, size) :
- size;
+ int reslimit = (U.glreslimit != 0) ? min_ii(U.glreslimit, size) : size;
return min_ii(reslimit, res);
}
@@ -142,6 +141,11 @@ bool GPU_use_hq_normals_workaround()
return GCaps.use_hq_normals_workaround;
}
+bool GPU_clear_viewport_workaround()
+{
+ return GCaps.clear_viewport_workaround;
+}
+
bool GPU_compute_shader_support()
{
return GCaps.compute_shader_support;
@@ -162,6 +166,11 @@ int GPU_max_shader_storage_buffer_bindings()
return GCaps.max_shader_storage_buffer_bindings;
}
+int GPU_max_compute_shader_storage_blocks()
+{
+ return GCaps.max_compute_shader_storage_blocks;
+}
+
/** \} */
/* -------------------------------------------------------------------- */
diff --git a/source/blender/gpu/intern/gpu_capabilities_private.hh b/source/blender/gpu/intern/gpu_capabilities_private.hh
index 4a951eb8458..a17dbe7f8e6 100644
--- a/source/blender/gpu/intern/gpu_capabilities_private.hh
+++ b/source/blender/gpu/intern/gpu_capabilities_private.hh
@@ -36,6 +36,7 @@ struct GPUCapabilities {
int max_vertex_attribs = 0;
int max_varying_floats = 0;
int max_shader_storage_buffer_bindings = 0;
+ int max_compute_shader_storage_blocks = 0;
int extensions_len = 0;
const char *(*extension_get)(int);
@@ -51,6 +52,7 @@ struct GPUCapabilities {
bool use_main_context_workaround = false;
bool broken_amd_driver = false;
bool use_hq_normals_workaround = false;
+ bool clear_viewport_workaround = false;
/* Vulkan related workarounds. */
/* Metal related workarounds. */
diff --git a/source/blender/gpu/intern/gpu_codegen.cc b/source/blender/gpu/intern/gpu_codegen.cc
index b6b0825a993..fa7ce3a364b 100644
--- a/source/blender/gpu/intern/gpu_codegen.cc
+++ b/source/blender/gpu/intern/gpu_codegen.cc
@@ -12,8 +12,6 @@
#include "DNA_customdata_types.h"
#include "DNA_image_types.h"
-#include "BLI_blenlib.h"
-#include "BLI_dynstr.h"
#include "BLI_ghash.h"
#include "BLI_hash_mm2a.h"
#include "BLI_link_utils.h"
@@ -23,7 +21,6 @@
#include "PIL_time.h"
#include "BKE_material.h"
-#include "BKE_world.h"
#include "GPU_capabilities.h"
#include "GPU_material.h"
@@ -32,15 +29,15 @@
#include "GPU_vertex_format.h"
#include "BLI_sys_types.h" /* for intptr_t support */
+#include "BLI_vector.hh"
#include "gpu_codegen.h"
-#include "gpu_material_library.h"
#include "gpu_node_graph.h"
#include "gpu_shader_create_info.hh"
#include "gpu_shader_dependency_private.h"
-#include <stdarg.h>
-#include <string.h>
+#include <cstdarg>
+#include <cstring>
#include <sstream>
#include <string>
@@ -58,18 +55,27 @@ struct GPUCodegenCreateInfo : ShaderCreateInfo {
/** Duplicate attribute names to avoid reference the GPUNodeGraph directly. */
char attr_names[16][GPU_MAX_SAFE_ATTR_NAME + 1];
char var_names[16][8];
+ blender::Vector<std::array<char, 32>, 16> sampler_names;
+
+ /* Returns the appended name memory location */
+ const char *append_sampler_name(const char name[32])
+ {
+ auto index = sampler_names.append_and_get_index(std::array<char, 32>());
+ char *name_buffer = sampler_names[index].data();
+ memcpy(name_buffer, name, 32);
+ return name_buffer;
+ }
};
/** Optional generated interface. */
StageInterfaceInfo *interface_generated = nullptr;
/** Optional name buffer containing names referenced by StringRefNull. */
- NameBuffer *name_buffer = nullptr;
+ NameBuffer name_buffer;
GPUCodegenCreateInfo(const char *name) : ShaderCreateInfo(name){};
~GPUCodegenCreateInfo()
{
delete interface_generated;
- MEM_delete(name_buffer);
};
};
@@ -288,7 +294,6 @@ void GPUCodegen::generate_attribs()
GPUCodegenCreateInfo &info = *create_info;
- info.name_buffer = MEM_new<GPUCodegenCreateInfo::NameBuffer>("info.name_buffer");
info.interface_generated = new StageInterfaceInfo("codegen_iface", "var_attrs");
StageInterfaceInfo &iface = *info.interface_generated;
info.vertex_out(iface);
@@ -302,11 +307,11 @@ void GPUCodegen::generate_attribs()
BLI_assert_msg(0, "Too many attributes");
break;
}
- STRNCPY(info.name_buffer->attr_names[slot], attr->input_name);
- SNPRINTF(info.name_buffer->var_names[slot], "v%d", attr->id);
+ STRNCPY(info.name_buffer.attr_names[slot], attr->input_name);
+ SNPRINTF(info.name_buffer.var_names[slot], "v%d", attr->id);
- blender::StringRefNull attr_name = info.name_buffer->attr_names[slot];
- blender::StringRefNull var_name = info.name_buffer->var_names[slot];
+ blender::StringRefNull attr_name = info.name_buffer.attr_names[slot];
+ blender::StringRefNull var_name = info.name_buffer.var_names[slot];
eGPUType input_type, iface_type;
@@ -348,14 +353,19 @@ void GPUCodegen::generate_resources()
/* Textures. */
LISTBASE_FOREACH (GPUMaterialTexture *, tex, &graph.textures) {
if (tex->colorband) {
- info.sampler(0, ImageType::FLOAT_1D_ARRAY, tex->sampler_name, Frequency::BATCH);
+ const char *name = info.name_buffer.append_sampler_name(tex->sampler_name);
+ info.sampler(0, ImageType::FLOAT_1D_ARRAY, name, Frequency::BATCH);
}
else if (tex->tiled_mapping_name[0] != '\0') {
- info.sampler(0, ImageType::FLOAT_2D_ARRAY, tex->sampler_name, Frequency::BATCH);
- info.sampler(0, ImageType::FLOAT_1D_ARRAY, tex->tiled_mapping_name, Frequency::BATCH);
+ const char *name = info.name_buffer.append_sampler_name(tex->sampler_name);
+ info.sampler(0, ImageType::FLOAT_2D_ARRAY, name, Frequency::BATCH);
+
+ const char *name_mapping = info.name_buffer.append_sampler_name(tex->tiled_mapping_name);
+ info.sampler(0, ImageType::FLOAT_1D_ARRAY, name_mapping, Frequency::BATCH);
}
else {
- info.sampler(0, ImageType::FLOAT_2D, tex->sampler_name, Frequency::BATCH);
+ const char *name = info.name_buffer.append_sampler_name(tex->sampler_name);
+ info.sampler(0, ImageType::FLOAT_2D, name, Frequency::BATCH);
}
}
diff --git a/source/blender/gpu/intern/gpu_compute.cc b/source/blender/gpu/intern/gpu_compute.cc
index b45cf8211cb..277f6d22280 100644
--- a/source/blender/gpu/intern/gpu_compute.cc
+++ b/source/blender/gpu/intern/gpu_compute.cc
@@ -7,7 +7,6 @@
#include "GPU_compute.h"
#include "gpu_backend.hh"
-#include "gpu_storage_buffer_private.hh"
void GPU_compute_dispatch(GPUShader *shader,
uint groups_x_len,
diff --git a/source/blender/gpu/intern/gpu_context.cc b/source/blender/gpu/intern/gpu_context.cc
index c6eaf7defdc..9fb5826506a 100644
--- a/source/blender/gpu/intern/gpu_context.cc
+++ b/source/blender/gpu/intern/gpu_context.cc
@@ -23,8 +23,6 @@
#include "GPU_context.h"
#include "GPU_framebuffer.h"
-#include "GHOST_C-api.h"
-
#include "gpu_backend.hh"
#include "gpu_batch_private.hh"
#include "gpu_context_private.hh"
@@ -177,7 +175,7 @@ void GPU_render_step()
/** \name Backend selection
* \{ */
-static GPUBackend *g_backend;
+static GPUBackend *g_backend = nullptr;
bool GPU_backend_supported(eGPUBackendType type)
{
diff --git a/source/blender/gpu/intern/gpu_debug.cc b/source/blender/gpu/intern/gpu_debug.cc
index c62a6416f92..055207eace8 100644
--- a/source/blender/gpu/intern/gpu_debug.cc
+++ b/source/blender/gpu/intern/gpu_debug.cc
@@ -50,11 +50,11 @@ void GPU_debug_get_groups_names(int name_buf_len, char *r_name_buf)
r_name_buf[0] = '\0';
return;
}
- size_t sz = 0;
+ size_t len = 0;
for (StringRef &name : stack) {
- sz += BLI_snprintf_rlen(r_name_buf + sz, name_buf_len - sz, "%s > ", name.data());
+ len += BLI_snprintf_rlen(r_name_buf + len, name_buf_len - len, "%s > ", name.data());
}
- r_name_buf[sz - 3] = '\0';
+ r_name_buf[len - 3] = '\0';
}
bool GPU_debug_group_match(const char *ref)
diff --git a/source/blender/gpu/intern/gpu_drawlist.cc b/source/blender/gpu/intern/gpu_drawlist.cc
index b5b8d2f90bc..e1699bd0036 100644
--- a/source/blender/gpu/intern/gpu_drawlist.cc
+++ b/source/blender/gpu/intern/gpu_drawlist.cc
@@ -7,9 +7,6 @@
* Implementation of Multi Draw Indirect.
*/
-#include "MEM_guardedalloc.h"
-
-#include "GPU_batch.h"
#include "GPU_drawlist.h"
#include "gpu_backend.hh"
diff --git a/source/blender/gpu/intern/gpu_framebuffer.cc b/source/blender/gpu/intern/gpu_framebuffer.cc
index fb3c9549f18..08d761106e5 100644
--- a/source/blender/gpu/intern/gpu_framebuffer.cc
+++ b/source/blender/gpu/intern/gpu_framebuffer.cc
@@ -7,7 +7,6 @@
#include "MEM_guardedalloc.h"
-#include "BLI_blenlib.h"
#include "BLI_math_base.h"
#include "BLI_utildefines.h"
@@ -18,7 +17,6 @@
#include "gpu_backend.hh"
#include "gpu_context_private.hh"
-#include "gpu_private.h"
#include "gpu_texture_private.hh"
#include "gpu_framebuffer_private.hh"
diff --git a/source/blender/gpu/intern/gpu_immediate.cc b/source/blender/gpu/intern/gpu_immediate.cc
index 7dc1c739750..8f04b1c2dfe 100644
--- a/source/blender/gpu/intern/gpu_immediate.cc
+++ b/source/blender/gpu/intern/gpu_immediate.cc
@@ -18,7 +18,6 @@
#include "gpu_context_private.hh"
#include "gpu_immediate_private.hh"
#include "gpu_shader_private.hh"
-#include "gpu_vertex_buffer_private.hh"
#include "gpu_vertex_format_private.h"
using namespace blender::gpu;
@@ -490,7 +489,7 @@ static void immEndVertex() /* and move on to the next vertex */
#endif
uchar *data = imm->vertex_data + a->offset;
- memcpy(data, data - imm->vertex_format.stride, a->sz);
+ memcpy(data, data - imm->vertex_format.stride, a->size);
/* TODO: consolidate copy of adjacent attributes */
}
}
diff --git a/source/blender/gpu/intern/gpu_immediate_util.c b/source/blender/gpu/intern/gpu_immediate_util.c
index 67035853594..a275fd8fc6c 100644
--- a/source/blender/gpu/intern/gpu_immediate_util.c
+++ b/source/blender/gpu/intern/gpu_immediate_util.c
@@ -13,7 +13,6 @@
#include "BLI_utildefines.h"
#include "GPU_immediate.h"
-#include "GPU_immediate_util.h"
#include "UI_resources.h"
@@ -337,13 +336,27 @@ static void imm_draw_circle_3D(
/* Note(Metal/AMD): For small primitives, line list more efficient than line strip. */
immBegin(GPU_PRIM_LINES, nsegments * 2);
- immVertex3f(pos, x + radius * cosf(0.0f), y + radius * sinf(0.0f), 0.0f);
- for (int i = 1; i < nsegments; i++) {
- float angle = (float)(2 * M_PI) * ((float)i / (float)nsegments);
- immVertex3f(pos, x + radius * cosf(angle), y + radius * sinf(angle), 0.0f);
- immVertex3f(pos, x + radius * cosf(angle), y + radius * sinf(angle), 0.0f);
+ const float angle = (float)(2 * M_PI) / (float)nsegments;
+ float xprev = cosf(-angle) * radius;
+ float yprev = sinf(-angle) * radius;
+ const float alpha = 2.0f * cosf(angle);
+
+ float xr = radius;
+ float yr = 0;
+
+ for (int i = 0; i < nsegments; i++) {
+ immVertex3f(pos, x + xr, y + yr, 0.0f);
+ if (i) {
+ immVertex3f(pos, x + xr, y + yr, 0.0f);
+ }
+ const float xnext = alpha * xr - xprev;
+ const float ynext = alpha * yr - yprev;
+ xprev = xr;
+ yprev = yr;
+ xr = xnext;
+ yr = ynext;
}
- immVertex3f(pos, x + radius * cosf(0.0f), y + radius * sinf(0.0f), 0.0f);
+ immVertex3f(pos, x + radius, y, 0.0f);
immEnd();
}
else {
diff --git a/source/blender/gpu/intern/gpu_index_buffer.cc b/source/blender/gpu/intern/gpu_index_buffer.cc
index 54473b3a44d..146461d1dfb 100644
--- a/source/blender/gpu/intern/gpu_index_buffer.cc
+++ b/source/blender/gpu/intern/gpu_index_buffer.cc
@@ -232,6 +232,7 @@ void IndexBuf::init(uint indices_len, uint32_t *indices, uint min_index, uint ma
data_ = indices;
index_start_ = 0;
index_len_ = indices_len;
+ is_empty_ = min_index > max_index;
#if GPU_TRACK_INDEX_RANGE
/* Everything remains 32 bit while building to keep things simple.
diff --git a/source/blender/gpu/intern/gpu_index_buffer_private.hh b/source/blender/gpu/intern/gpu_index_buffer_private.hh
index 9323a81d393..6ce62ae852e 100644
--- a/source/blender/gpu/intern/gpu_index_buffer_private.hh
+++ b/source/blender/gpu/intern/gpu_index_buffer_private.hh
@@ -45,6 +45,8 @@ class IndexBuf {
bool is_init_ = false;
/** Is this object only a reference to a subrange of another IndexBuf. */
bool is_subrange_ = false;
+ /** True if buffer only contains restart indices. */
+ bool is_empty_ = false;
union {
/** Mapped buffer data. non-NULL indicates not yet sent to VRAM. */
@@ -61,9 +63,12 @@ class IndexBuf {
void init_subrange(IndexBuf *elem_src, uint start, uint length);
void init_build_on_device(uint index_len);
+ /* Returns render index count (not precise). */
uint32_t index_len_get() const
{
- return index_len_;
+ /* Return 0 to bypass drawing for index buffers full of restart indices.
+ * They can lead to graphical glitches on some systems. (See T96892) */
+ return is_empty_ ? 0 : index_len_;
}
/* Return size in byte of the drawable data buffer range. Actual buffer size might be bigger. */
size_t size_get() const
diff --git a/source/blender/gpu/intern/gpu_init_exit.c b/source/blender/gpu/intern/gpu_init_exit.c
index e97c9e9c829..062614fb5cb 100644
--- a/source/blender/gpu/intern/gpu_init_exit.c
+++ b/source/blender/gpu/intern/gpu_init_exit.c
@@ -6,15 +6,10 @@
*/
#include "GPU_init_exit.h" /* interface */
-#include "BKE_global.h"
#include "BLI_sys_types.h"
#include "GPU_batch.h"
-#include "GPU_buffers.h"
-#include "GPU_context.h"
-#include "GPU_immediate.h"
#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"
diff --git a/source/blender/gpu/intern/gpu_material.c b/source/blender/gpu/intern/gpu_material.c
index e8fb5fb2c45..4d3ea3e0c99 100644
--- a/source/blender/gpu/intern/gpu_material.c
+++ b/source/blender/gpu/intern/gpu_material.c
@@ -19,14 +19,11 @@
#include "BLI_listbase.h"
#include "BLI_math.h"
#include "BLI_string.h"
-#include "BLI_string_utils.h"
#include "BLI_utildefines.h"
#include "BKE_main.h"
#include "BKE_material.h"
#include "BKE_node.h"
-#include "BKE_scene.h"
-#include "BKE_world.h"
#include "NOD_shader.h"
@@ -168,6 +165,7 @@ static void gpu_material_free_single(GPUMaterial *material)
if (material->sss_tex_profile != NULL) {
GPU_texture_free(material->sss_tex_profile);
}
+ MEM_freeN(material);
}
void GPU_material_free(ListBase *gpumaterial)
@@ -176,7 +174,6 @@ void GPU_material_free(ListBase *gpumaterial)
GPUMaterial *material = link->data;
DRW_deferred_shader_remove(material);
gpu_material_free_single(material);
- MEM_freeN(material);
}
BLI_freelistN(gpumaterial);
}
@@ -626,7 +623,7 @@ eGPUMaterialFlag GPU_material_flag(const GPUMaterial *mat)
return mat->flag;
}
-/* Note: Consumes the flags. */
+/* NOTE: Consumes the flags. */
bool GPU_material_recalc_flag_get(GPUMaterial *mat)
{
bool updated = (mat->flag & GPU_MATFLAG_UPDATED) != 0;
@@ -669,7 +666,7 @@ GPUMaterial *GPU_material_from_nodetree(Scene *scene,
BLI_ghashutil_ptrhash, BLI_ghashutil_ptrcmp, "GPUNodeGraph.used_libraries");
mat->refcount = 1;
#ifndef NDEBUG
- BLI_snprintf(mat->name, sizeof(mat->name), "%s", name);
+ STRNCPY(mat->name, name);
#else
UNUSED_VARS(name);
#endif
@@ -750,6 +747,9 @@ void GPU_material_compile(GPUMaterial *mat)
mat->status = GPU_MAT_SUCCESS;
gpu_node_graph_free_nodes(&mat->graph);
}
+ else {
+ mat->status = GPU_MAT_FAILED;
+ }
}
else {
mat->status = GPU_MAT_FAILED;
diff --git a/source/blender/gpu/intern/gpu_material_library.h b/source/blender/gpu/intern/gpu_material_library.h
index ffc2228a49b..b071ab85f3a 100644
--- a/source/blender/gpu/intern/gpu_material_library.h
+++ b/source/blender/gpu/intern/gpu_material_library.h
@@ -30,7 +30,7 @@ typedef struct GPUFunction {
eGPUType paramtype[MAX_PARAMETER];
GPUFunctionQual paramqual[MAX_PARAMETER];
int totparam;
- /* TOOD(@fclem): Clean that void pointer. */
+ /* TODO(@fclem): Clean that void pointer. */
void *source; /* GPUSource */
} GPUFunction;
diff --git a/source/blender/gpu/intern/gpu_node_graph.c b/source/blender/gpu/intern/gpu_node_graph.c
index bc7ace792bb..3c6a03c56d3 100644
--- a/source/blender/gpu/intern/gpu_node_graph.c
+++ b/source/blender/gpu/intern/gpu_node_graph.c
@@ -328,11 +328,13 @@ void gpu_node_graph_finalize_uniform_attrs(GPUNodeGraph *graph)
/* Attributes and Textures */
-static char attr_prefix_get(CustomDataType type)
+static char attr_prefix_get(eCustomDataType type)
{
switch (type) {
case CD_TANGENT:
return 't';
+ case CD_MCOL:
+ return 'c';
case CD_AUTO_FROM_NAME:
return 'a';
case CD_HAIRLENGTH:
@@ -345,7 +347,7 @@ static char attr_prefix_get(CustomDataType type)
static void attr_input_name(GPUMaterialAttribute *attr)
{
- /* NOTE: Replicate changes to mesh_render_data_create() in draw_cache_impl_mesh.c */
+ /* NOTE: Replicate changes to mesh_render_data_create() in draw_cache_impl_mesh.cc */
if (attr->type == CD_ORCO) {
/* OPTI: orco is computed from local positions, but only if no modifier is present. */
STRNCPY(attr->input_name, "orco");
@@ -362,7 +364,7 @@ static void attr_input_name(GPUMaterialAttribute *attr)
/** Add a new varying attribute of given type and name. Returns NULL if out of slots. */
static GPUMaterialAttribute *gpu_node_graph_add_attribute(GPUNodeGraph *graph,
- CustomDataType type,
+ eCustomDataType type,
const char *name)
{
/* Find existing attribute. */
@@ -466,7 +468,7 @@ static GPUMaterialTexture *gpu_node_graph_add_texture(GPUNodeGraph *graph,
/* Creating Inputs */
-GPUNodeLink *GPU_attribute(GPUMaterial *mat, const CustomDataType type, const char *name)
+GPUNodeLink *GPU_attribute(GPUMaterial *mat, const eCustomDataType type, const char *name)
{
GPUNodeGraph *graph = gpu_material_node_graph(mat);
GPUMaterialAttribute *attr = gpu_node_graph_add_attribute(graph, type, name);
@@ -489,7 +491,7 @@ GPUNodeLink *GPU_attribute(GPUMaterial *mat, const CustomDataType type, const ch
}
GPUNodeLink *GPU_attribute_with_default(GPUMaterial *mat,
- const CustomDataType type,
+ const eCustomDataType type,
const char *name,
eGPUDefaultValue default_value)
{
@@ -611,7 +613,7 @@ bool GPU_link(GPUMaterial *mat, const char *name, ...)
va_start(params, name);
for (i = 0; i < function->totparam; i++) {
- if (function->paramqual[i] != FUNCTION_QUAL_IN) {
+ if (function->paramqual[i] == FUNCTION_QUAL_OUT) {
linkptr = va_arg(params, GPUNodeLink **);
gpu_node_output(node, function->paramtype[i], linkptr);
}
@@ -669,7 +671,7 @@ static bool gpu_stack_link_v(GPUMaterial *material,
}
for (i = 0; i < function->totparam; i++) {
- if (function->paramqual[i] != FUNCTION_QUAL_IN) {
+ if (function->paramqual[i] == FUNCTION_QUAL_OUT) {
if (totout == 0) {
linkptr = va_arg(params, GPUNodeLink **);
gpu_node_output(node, function->paramtype[i], linkptr);
diff --git a/source/blender/gpu/intern/gpu_select.c b/source/blender/gpu/intern/gpu_select.c
index ac33c5d5ca8..7afba20c2d9 100644
--- a/source/blender/gpu/intern/gpu_select.c
+++ b/source/blender/gpu/intern/gpu_select.c
@@ -12,12 +12,8 @@
#include "GPU_select.h"
-#include "MEM_guardedalloc.h"
-
#include "BLI_rect.h"
-#include "DNA_userdef_types.h"
-
#include "BLI_utildefines.h"
#include "gpu_select_private.h"
diff --git a/source/blender/gpu/intern/gpu_select_pick.c b/source/blender/gpu/intern/gpu_select_pick.c
index 840201c8c97..b5b2d7fa1a5 100644
--- a/source/blender/gpu/intern/gpu_select_pick.c
+++ b/source/blender/gpu/intern/gpu_select_pick.c
@@ -13,7 +13,6 @@
#include "GPU_debug.h"
#include "GPU_framebuffer.h"
-#include "GPU_immediate.h"
#include "GPU_select.h"
#include "GPU_state.h"
diff --git a/source/blender/gpu/intern/gpu_select_sample_query.cc b/source/blender/gpu/intern/gpu_select_sample_query.cc
index 26c9ed79d6c..7393dfd0d81 100644
--- a/source/blender/gpu/intern/gpu_select_sample_query.cc
+++ b/source/blender/gpu/intern/gpu_select_sample_query.cc
@@ -19,7 +19,6 @@
#include "BLI_rect.h"
-#include "BLI_bitmap.h"
#include "BLI_utildefines.h"
#include "BLI_vector.hh"
diff --git a/source/blender/gpu/intern/gpu_shader_builtin.c b/source/blender/gpu/intern/gpu_shader_builtin.c
index 13238a03688..c3a1236e814 100644
--- a/source/blender/gpu/intern/gpu_shader_builtin.c
+++ b/source/blender/gpu/intern/gpu_shader_builtin.c
@@ -5,25 +5,9 @@
* \ingroup gpu
*/
-#include "MEM_guardedalloc.h"
-
-#include "BLI_math_base.h"
-#include "BLI_math_vector.h"
-#include "BLI_path_util.h"
-#include "BLI_string.h"
-#include "BLI_string_utils.h"
#include "BLI_utildefines.h"
-#include "BKE_appdir.h"
-#include "BKE_global.h"
-
-#include "DNA_space_types.h"
-
-#include "GPU_matrix.h"
-#include "GPU_platform.h"
#include "GPU_shader.h"
-#include "GPU_texture.h"
-#include "GPU_uniform_buffer.h"
/* Adjust these constants as needed. */
#define MAX_DEFINE_LENGTH 256
@@ -150,6 +134,11 @@ static const GPUShaderStages builtin_shader_stages[GPU_SHADER_BUILTIN_LEN] = {
.name = "GPU_SHADER_SIMPLE_LIGHTING",
.create_info = "gpu_shader_simple_lighting",
},
+ [GPU_SHADER_3D_IMAGE] =
+ {
+ .name = "GPU_SHADER_3D_IMAGE",
+ .create_info = "gpu_shader_3D_image",
+ },
[GPU_SHADER_3D_IMAGE_MODULATE_ALPHA] =
{
.name = "GPU_SHADER_3D_IMAGE_MODULATE_ALPHA",
@@ -367,6 +356,16 @@ GPUShader *GPU_shader_get_builtin_shader_with_config(eGPUBuiltinShader shader,
if (sh_cfg == GPU_SHADER_CFG_DEFAULT) {
if (stages->create_info != NULL) {
*sh_p = GPU_shader_create_from_info_name(stages->create_info);
+ if (ELEM(shader,
+ GPU_SHADER_3D_POLYLINE_CLIPPED_UNIFORM_COLOR,
+ GPU_SHADER_3D_POLYLINE_UNIFORM_COLOR,
+ GPU_SHADER_3D_POLYLINE_FLAT_COLOR,
+ GPU_SHADER_3D_POLYLINE_SMOOTH_COLOR)) {
+ /* Set a default value for `lineSmooth`.
+ * Ideally this value should be set by the caller. */
+ GPU_shader_bind(*sh_p);
+ GPU_shader_uniform_1i(*sh_p, "lineSmooth", 1);
+ }
}
else {
*sh_p = GPU_shader_create_from_arrays_named(
diff --git a/source/blender/gpu/intern/gpu_shader_create_info.cc b/source/blender/gpu/intern/gpu_shader_create_info.cc
index f5b90989481..81c21e4e7e2 100644
--- a/source/blender/gpu/intern/gpu_shader_create_info.cc
+++ b/source/blender/gpu/intern/gpu_shader_create_info.cc
@@ -19,7 +19,6 @@
#include "gpu_shader_create_info.hh"
#include "gpu_shader_create_info_private.hh"
#include "gpu_shader_dependency_private.h"
-#include "gpu_shader_private.hh"
#undef GPU_SHADER_INTERFACE_INFO
#undef GPU_SHADER_CREATE_INFO
diff --git a/source/blender/gpu/intern/gpu_shader_dependency.cc b/source/blender/gpu/intern/gpu_shader_dependency.cc
index 460b6d32967..d91e15243f3 100644
--- a/source/blender/gpu/intern/gpu_shader_dependency.cc
+++ b/source/blender/gpu/intern/gpu_shader_dependency.cc
@@ -8,13 +8,13 @@
* shader files.
*/
+#include <algorithm>
#include <iomanip>
#include <iostream>
#include <sstream>
#include "BLI_ghash.h"
#include "BLI_map.hh"
-#include "BLI_set.hh"
#include "BLI_string_ref.hh"
#include "gpu_material_library.h"
@@ -98,6 +98,10 @@ struct GPUSource {
/* 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();
+ quote_preprocess();
+ }
+ else {
+ check_no_quotes();
}
if (is_from_material_library()) {
@@ -174,6 +178,44 @@ struct GPUSource {
}
/**
+ * Some drivers completely forbid quote characters even in unused preprocessor directives.
+ * We fix the cases where we can't manually patch in `enum_preprocess()`.
+ * This check ensure none are present in non-patched sources. (see T97545)
+ */
+ void check_no_quotes()
+ {
+#ifdef DEBUG
+ int64_t pos = -1;
+ do {
+ pos = source.find('"', pos + 1);
+ if (pos == -1) {
+ break;
+ }
+ if (!is_in_comment(source, pos)) {
+ print_error(source, pos, "Quote characters are forbidden in GLSL files");
+ }
+ } while (true);
+#endif
+ }
+
+ /**
+ * Some drivers completely forbid string characters even in unused preprocessor directives.
+ * This fixes the cases we cannot manually patch: Shared headers #includes. (see T97545)
+ * TODO(fclem): This could be done during the datatoc step.
+ */
+ void quote_preprocess()
+ {
+ if (source.find_first_of('"') == -1) {
+ return;
+ }
+
+ processed_source = source;
+ std::replace(processed_source.begin(), processed_source.end(), '"', ' ');
+
+ source = processed_source.c_str();
+ }
+
+ /**
* Transform C,C++ enum declaration into GLSL compatible defines and constants:
*
* \code{.cpp}
@@ -282,6 +324,7 @@ struct GPUSource {
if (last_pos != 0) {
output += input.substr(last_pos);
}
+
processed_source = output;
source = processed_source.c_str();
};
@@ -549,7 +592,9 @@ struct GPUSource {
bool is_from_material_library() const
{
- return filename.startswith("gpu_shader_material_") && filename.endswith(".glsl");
+ return (filename.startswith("gpu_shader_material_") ||
+ filename.startswith("gpu_shader_common_")) &&
+ filename.endswith(".glsl");
}
};
@@ -624,14 +669,20 @@ Vector<const char *> gpu_shader_dependency_get_resolved_source(
const StringRefNull shader_source_name)
{
Vector<const char *> result;
- GPUSource *source = g_sources->lookup(shader_source_name);
- source->build(result);
+ GPUSource *src = g_sources->lookup_default(shader_source_name, nullptr);
+ if (src == nullptr) {
+ std::cout << "Error source not found : " << shader_source_name << std::endl;
+ }
+ src->build(result);
return result;
}
StringRefNull gpu_shader_dependency_get_source(const StringRefNull shader_source_name)
{
- GPUSource *src = g_sources->lookup(shader_source_name);
+ GPUSource *src = g_sources->lookup_default(shader_source_name, nullptr);
+ if (src == nullptr) {
+ std::cout << "Error source not found : " << shader_source_name << std::endl;
+ }
return src->source;
}
diff --git a/source/blender/gpu/intern/gpu_shader_interface.cc b/source/blender/gpu/intern/gpu_shader_interface.cc
index ea138973c74..6f43b379d31 100644
--- a/source/blender/gpu/intern/gpu_shader_interface.cc
+++ b/source/blender/gpu/intern/gpu_shader_interface.cc
@@ -38,7 +38,7 @@ static void sort_input_list(MutableSpan<ShaderInput> dst)
/* Simple sorting by going through the array and selecting the biggest element each time. */
for (uint i = 0; i < dst.size(); i++) {
- ShaderInput *input_src = &src[0];
+ ShaderInput *input_src = src.data();
for (uint j = 1; j < src.size(); j++) {
if (src[j].name_hash > input_src->name_hash) {
input_src = &src[j];
diff --git a/source/blender/gpu/intern/gpu_shader_log.cc b/source/blender/gpu/intern/gpu_shader_log.cc
index 83fc34a3278..572727fa515 100644
--- a/source/blender/gpu/intern/gpu_shader_log.cc
+++ b/source/blender/gpu/intern/gpu_shader_log.cc
@@ -15,8 +15,6 @@
#include "gpu_shader_dependency_private.h"
#include "gpu_shader_private.hh"
-#include "GPU_platform.h"
-
#include "CLG_log.h"
static CLG_LogRef LOG = {"gpu.shader"};
diff --git a/source/blender/gpu/intern/gpu_state.cc b/source/blender/gpu/intern/gpu_state.cc
index f74d500340d..a1e0b8867a0 100644
--- a/source/blender/gpu/intern/gpu_state.cc
+++ b/source/blender/gpu/intern/gpu_state.cc
@@ -14,8 +14,6 @@
#include "BLI_math_vector.h"
#include "BLI_utildefines.h"
-#include "BKE_global.h"
-
#include "GPU_state.h"
#include "gpu_context_private.hh"
diff --git a/source/blender/gpu/intern/gpu_storage_buffer.cc b/source/blender/gpu/intern/gpu_storage_buffer.cc
index 806acad90fe..afa27da9c85 100644
--- a/source/blender/gpu/intern/gpu_storage_buffer.cc
+++ b/source/blender/gpu/intern/gpu_storage_buffer.cc
@@ -12,13 +12,13 @@
#include "BLI_math_base.h"
#include "gpu_backend.hh"
-#include "gpu_node_graph.h"
#include "GPU_material.h"
#include "GPU_vertex_buffer.h" /* For GPUUsageType. */
#include "GPU_storage_buffer.h"
#include "gpu_storage_buffer_private.hh"
+#include "gpu_vertex_buffer_private.hh"
/* -------------------------------------------------------------------- */
/** \name Creation & Deletion
@@ -103,4 +103,10 @@ void GPU_storagebuf_clear_to_zero(GPUStorageBuf *ssbo)
GPU_storagebuf_clear(ssbo, GPU_R32UI, GPU_DATA_UINT, &data);
}
+void GPU_storagebuf_copy_sub_from_vertbuf(
+ GPUStorageBuf *ssbo, GPUVertBuf *src, uint dst_offset, uint src_offset, uint copy_size)
+{
+ unwrap(ssbo)->copy_sub(unwrap(src), dst_offset, src_offset, copy_size);
+}
+
/** \} */
diff --git a/source/blender/gpu/intern/gpu_storage_buffer_private.hh b/source/blender/gpu/intern/gpu_storage_buffer_private.hh
index 06e7c2c0e9d..091e6c2d386 100644
--- a/source/blender/gpu/intern/gpu_storage_buffer_private.hh
+++ b/source/blender/gpu/intern/gpu_storage_buffer_private.hh
@@ -43,6 +43,7 @@ class StorageBuf {
virtual void clear(eGPUTextureFormat internal_format,
eGPUDataFormat data_format,
void *data) = 0;
+ virtual void copy_sub(VertBuf *src, uint dst_offset, uint src_offset, uint copy_size) = 0;
};
/* Syntactic sugar. */
diff --git a/source/blender/gpu/intern/gpu_texture.cc b/source/blender/gpu/intern/gpu_texture.cc
index d78dc845074..218d22ddf53 100644
--- a/source/blender/gpu/intern/gpu_texture.cc
+++ b/source/blender/gpu/intern/gpu_texture.cc
@@ -13,7 +13,6 @@
#include "gpu_backend.hh"
#include "gpu_context_private.hh"
#include "gpu_framebuffer_private.hh"
-#include "gpu_vertex_buffer_private.hh"
#include "gpu_texture_private.hh"
@@ -702,7 +701,11 @@ void GPU_texture_get_mipmap_size(GPUTexture *tex, int lvl, int *r_size)
void GPU_samplers_update()
{
- GPUBackend::get()->samplers_update();
+ /* Backend may not exist when we are updating preferences from background mode. */
+ GPUBackend *backend = GPUBackend::get();
+ if (backend) {
+ backend->samplers_update();
+ }
}
/** \} */
diff --git a/source/blender/gpu/intern/gpu_vertex_buffer.cc b/source/blender/gpu/intern/gpu_vertex_buffer.cc
index 2974547c858..0dbd565291b 100644
--- a/source/blender/gpu/intern/gpu_vertex_buffer.cc
+++ b/source/blender/gpu/intern/gpu_vertex_buffer.cc
@@ -12,7 +12,6 @@
#include "gpu_backend.hh"
#include "gpu_vertex_format_private.h"
-#include "gl_vertex_buffer.hh" /* TODO: remove. */
#include "gpu_context_private.hh" /* TODO: remove. */
#include "gpu_vertex_buffer_private.hh"
@@ -199,7 +198,7 @@ void GPU_vertbuf_attr_set(GPUVertBuf *verts_, uint a_idx, uint v_idx, const void
BLI_assert(a_idx < format->attr_len);
BLI_assert(verts->data != nullptr);
verts->flag |= GPU_VERTBUF_DATA_DIRTY;
- memcpy(verts->data + a->offset + v_idx * format->stride, data, a->sz);
+ memcpy(verts->data + a->offset + v_idx * format->stride, data, a->size);
}
void GPU_vertbuf_attr_fill(GPUVertBuf *verts_, uint a_idx, const void *data)
@@ -208,7 +207,7 @@ void GPU_vertbuf_attr_fill(GPUVertBuf *verts_, uint a_idx, const void *data)
const GPUVertFormat *format = &verts->format;
BLI_assert(a_idx < format->attr_len);
const GPUVertAttr *a = &format->attrs[a_idx];
- const uint stride = a->sz; /* tightly packed input data */
+ const uint stride = a->size; /* tightly packed input data */
verts->flag |= GPU_VERTBUF_DATA_DIRTY;
GPU_vertbuf_attr_fill_stride(verts_, a_idx, stride, data);
}
@@ -235,13 +234,13 @@ void GPU_vertbuf_attr_fill_stride(GPUVertBuf *verts_, uint a_idx, uint stride, c
if (format->attr_len == 1 && stride == format->stride) {
/* we can copy it all at once */
- memcpy(verts->data, data, vertex_len * a->sz);
+ memcpy(verts->data, data, vertex_len * a->size);
}
else {
/* we must copy it per vertex */
for (uint v = 0; v < vertex_len; v++) {
memcpy(
- verts->data + a->offset + v * format->stride, (const uchar *)data + v * stride, a->sz);
+ verts->data + a->offset + v * format->stride, (const uchar *)data + v * stride, a->size);
}
}
}
@@ -256,7 +255,7 @@ void GPU_vertbuf_attr_get_raw_data(GPUVertBuf *verts_, uint a_idx, GPUVertBufRaw
verts->flag |= GPU_VERTBUF_DATA_DIRTY;
verts->flag &= ~GPU_VERTBUF_DATA_UPLOADED;
- access->size = a->sz;
+ access->size = a->size;
access->stride = format->stride;
access->data = (uchar *)verts->data + a->offset;
access->data_init = access->data;
@@ -328,6 +327,11 @@ void GPU_vertbuf_bind_as_ssbo(struct GPUVertBuf *verts, int binding)
unwrap(verts)->bind_as_ssbo(binding);
}
+void GPU_vertbuf_bind_as_texture(struct GPUVertBuf *verts, int binding)
+{
+ unwrap(verts)->bind_as_texture(binding);
+}
+
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 e5b70de9dfa..7a0b53cf958 100644
--- a/source/blender/gpu/intern/gpu_vertex_buffer_private.hh
+++ b/source/blender/gpu/intern/gpu_vertex_buffer_private.hh
@@ -51,6 +51,7 @@ class VertBuf {
void resize(uint vert_len);
void upload();
virtual void bind_as_ssbo(uint binding) = 0;
+ virtual void bind_as_texture(uint binding) = 0;
virtual void wrap_handle(uint64_t handle) = 0;
diff --git a/source/blender/gpu/intern/gpu_vertex_format.cc b/source/blender/gpu/intern/gpu_vertex_format.cc
index a9ac191754b..59ae862aa51 100644
--- a/source/blender/gpu/intern/gpu_vertex_format.cc
+++ b/source/blender/gpu/intern/gpu_vertex_format.cc
@@ -49,7 +49,7 @@ void GPU_vertformat_copy(GPUVertFormat *dest, const GPUVertFormat *src)
memcpy(dest, src, sizeof(GPUVertFormat));
}
-static uint comp_sz(GPUVertCompType type)
+static uint comp_size(GPUVertCompType type)
{
#if TRUST_NO_ONE
assert(type <= GPU_COMP_F32); /* other types have irregular sizes (not bytes) */
@@ -58,12 +58,12 @@ static uint comp_sz(GPUVertCompType type)
return sizes[type];
}
-static uint attr_sz(const GPUVertAttr *a)
+static uint attr_size(const GPUVertAttr *a)
{
if (a->comp_type == GPU_COMP_I10) {
return 4; /* always packed as 10_10_10_2 */
}
- return a->comp_len * comp_sz(static_cast<GPUVertCompType>(a->comp_type));
+ return a->comp_len * comp_size(static_cast<GPUVertCompType>(a->comp_type));
}
static uint attr_align(const GPUVertAttr *a)
@@ -71,7 +71,7 @@ static uint attr_align(const GPUVertAttr *a)
if (a->comp_type == GPU_COMP_I10) {
return 4; /* always packed as 10_10_10_2 */
}
- uint c = comp_sz(static_cast<GPUVertCompType>(a->comp_type));
+ uint c = comp_size(static_cast<GPUVertCompType>(a->comp_type));
if (a->comp_len == 3 && c <= 2) {
return 4 * c; /* AMD HW can't fetch these well, so pad it out (other vendors too?) */
}
@@ -156,7 +156,7 @@ uint GPU_vertformat_attr_add(GPUVertFormat *format,
attr->comp_len = (comp_type == GPU_COMP_I10) ?
4 :
comp_len; /* system needs 10_10_10_2 to be 4 or BGRA */
- attr->sz = attr_sz(attr);
+ attr->size = attr_size(attr);
attr->offset = 0; /* offsets & stride are calculated later (during pack) */
attr->fetch_mode = fetch_mode;
@@ -294,13 +294,13 @@ uint padding(uint offset, uint alignment)
}
#if PACK_DEBUG
-static void show_pack(uint a_idx, uint sz, uint pad)
+static void show_pack(uint a_idx, uint size, uint pad)
{
const char c = 'A' + a_idx;
for (uint i = 0; i < pad; i++) {
putchar('-');
}
- for (uint i = 0; i < sz; i++) {
+ for (uint i = 0; i < size; i++) {
putchar(c);
}
}
@@ -310,10 +310,10 @@ void VertexFormat_pack(GPUVertFormat *format)
{
GPUVertAttr *a0 = &format->attrs[0];
a0->offset = 0;
- uint offset = a0->sz;
+ uint offset = a0->size;
#if PACK_DEBUG
- show_pack(0, a0->sz, 0);
+ show_pack(0, a0->size, 0);
#endif
for (uint a_idx = 1; a_idx < format->attr_len; a_idx++) {
@@ -321,10 +321,10 @@ void VertexFormat_pack(GPUVertFormat *format)
uint mid_padding = padding(offset, attr_align(a));
offset += mid_padding;
a->offset = offset;
- offset += a->sz;
+ offset += a->size;
#if PACK_DEBUG
- show_pack(a_idx, a->sz, mid_padding);
+ show_pack(a_idx, a->size, mid_padding);
#endif
}
diff --git a/source/blender/gpu/intern/gpu_viewport.c b/source/blender/gpu/intern/gpu_viewport.c
index a0efe12f523..71bdf9e336b 100644
--- a/source/blender/gpu/intern/gpu_viewport.c
+++ b/source/blender/gpu/intern/gpu_viewport.c
@@ -9,18 +9,16 @@
#include <string.h>
-#include "BLI_listbase.h"
#include "BLI_math_vector.h"
-#include "BLI_memblock.h"
#include "BLI_rect.h"
#include "BKE_colortools.h"
#include "IMB_colormanagement.h"
-#include "DNA_userdef_types.h"
#include "DNA_vec_types.h"
+#include "GPU_capabilities.h"
#include "GPU_framebuffer.h"
#include "GPU_immediate.h"
#include "GPU_matrix.h"
@@ -126,19 +124,23 @@ static void gpu_viewport_textures_create(GPUViewport *viewport)
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);
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_FLOAT, empty_pixel);
+ if (GPU_clear_viewport_workaround()) {
+ GPU_texture_clear(viewport->color_render_tx[0], GPU_DATA_FLOAT, empty_pixel);
+ GPU_texture_clear(viewport->color_overlay_tx[0], GPU_DATA_FLOAT, empty_pixel);
+ }
}
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);
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_FLOAT, empty_pixel);
+ if (GPU_clear_viewport_workaround()) {
+ GPU_texture_clear(viewport->color_render_tx[1], GPU_DATA_FLOAT, empty_pixel);
+ GPU_texture_clear(viewport->color_overlay_tx[1], GPU_DATA_FLOAT, empty_pixel);
+ }
}
/* Can be shared with GPUOffscreen. */
@@ -262,12 +264,15 @@ void GPU_viewport_stereo_composite(GPUViewport *viewport, Stereo3dFormat *stereo
return;
}
/* The composite framebuffer object needs to be created in the window context. */
- GPU_framebuffer_ensure_config(&viewport->stereo_comp_fb,
- {
- GPU_ATTACHMENT_NONE,
- GPU_ATTACHMENT_TEXTURE(viewport->color_overlay_tx[0]),
- GPU_ATTACHMENT_TEXTURE(viewport->color_render_tx[0]),
- });
+ GPU_framebuffer_ensure_config(
+ &viewport->stereo_comp_fb,
+ {
+ GPU_ATTACHMENT_NONE,
+ /* We need the sRGB attachment to be first for GL_FRAMEBUFFER_SRGB to be turned on.
+ * Note that this is the opposite of what the texture binding is. */
+ GPU_ATTACHMENT_TEXTURE(viewport->color_overlay_tx[0]),
+ GPU_ATTACHMENT_TEXTURE(viewport->color_render_tx[0]),
+ });
GPUVertFormat *vert_format = immVertexFormat();
uint pos = GPU_vertformat_attr_add(vert_format, "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
diff --git a/source/blender/gpu/metal/kernels/depth_2d_update_float_frag.glsl b/source/blender/gpu/metal/kernels/depth_2d_update_float_frag.glsl
index ecb2dddcd63..9fd54f3f31f 100644
--- a/source/blender/gpu/metal/kernels/depth_2d_update_float_frag.glsl
+++ b/source/blender/gpu/metal/kernels/depth_2d_update_float_frag.glsl
@@ -7,4 +7,4 @@ in vec2 texCoord_interp;
void main()
{
gl_FragDepth = textureLod(source_data, texCoord_interp, mip).r;
-} \ No newline at end of file
+}
diff --git a/source/blender/gpu/metal/kernels/depth_2d_update_int24_frag.glsl b/source/blender/gpu/metal/kernels/depth_2d_update_int24_frag.glsl
index 99661a760f0..7483343503f 100644
--- a/source/blender/gpu/metal/kernels/depth_2d_update_int24_frag.glsl
+++ b/source/blender/gpu/metal/kernels/depth_2d_update_int24_frag.glsl
@@ -10,4 +10,4 @@ void main()
uint stencil = (val >> 24) & 0xFFu;
uint depth = (val)&0xFFFFFFu;
gl_FragDepth = float(depth) / float(0xFFFFFFu);
-} \ No newline at end of file
+}
diff --git a/source/blender/gpu/metal/kernels/depth_2d_update_int32_frag.glsl b/source/blender/gpu/metal/kernels/depth_2d_update_int32_frag.glsl
index 15271ab2cdd..75d42c57f73 100644
--- a/source/blender/gpu/metal/kernels/depth_2d_update_int32_frag.glsl
+++ b/source/blender/gpu/metal/kernels/depth_2d_update_int32_frag.glsl
@@ -9,4 +9,4 @@ void main()
uint val = textureLod(source_data, texCoord_interp, mip).r;
uint depth = (val) & (0xFFFFFFFFu);
gl_FragDepth = float(depth) / float(0xFFFFFFFFu);
-} \ No newline at end of file
+}
diff --git a/source/blender/gpu/metal/kernels/depth_2d_update_vert.glsl b/source/blender/gpu/metal/kernels/depth_2d_update_vert.glsl
index 092ae45b719..faae68d2f55 100644
--- a/source/blender/gpu/metal/kernels/depth_2d_update_vert.glsl
+++ b/source/blender/gpu/metal/kernels/depth_2d_update_vert.glsl
@@ -30,4 +30,4 @@ void main()
texCoord_interp = tex.zy;
}
gl_Position = vec4(rect.xy, 0.0f, 1.0f);
-} \ No newline at end of file
+}
diff --git a/source/blender/gpu/metal/mtl_backend.mm b/source/blender/gpu/metal/mtl_backend.mm
index 8bdec962af0..1064091a036 100644
--- a/source/blender/gpu/metal/mtl_backend.mm
+++ b/source/blender/gpu/metal/mtl_backend.mm
@@ -256,7 +256,7 @@ bool MTLBackend::metal_is_supported()
NSOperatingSystemVersion version = [[NSProcessInfo processInfo] operatingSystemVersion];
- /* Metal Viewport requires macOS Version 10.15 onwards. */
+ /* Metal Viewport requires macOS Version 10.15 onward. */
bool supported_os_version = version.majorVersion >= 11 ||
(version.majorVersion == 10 ? version.minorVersion >= 15 : false);
if (!supported_os_version) {
diff --git a/source/blender/gpu/metal/mtl_context.hh b/source/blender/gpu/metal/mtl_context.hh
index aa198482291..1849a04ea48 100644
--- a/source/blender/gpu/metal/mtl_context.hh
+++ b/source/blender/gpu/metal/mtl_context.hh
@@ -7,8 +7,10 @@
#include "gpu_context_private.hh"
+#include "GPU_common_types.h"
#include "GPU_context.h"
+#include "mtl_capabilities.hh"
#include "mtl_texture.hh"
#include <Cocoa/Cocoa.h>
@@ -21,6 +23,112 @@
namespace blender::gpu {
+class MTLShader;
+class MTLUniformBuf;
+class MTLBuffer;
+
+/* Depth Stencil State */
+typedef struct MTLContextDepthStencilState {
+
+ /* Depth State. */
+ bool depth_write_enable;
+ bool depth_test_enabled;
+ float depth_range_near;
+ float depth_range_far;
+ MTLCompareFunction depth_function;
+ float depth_bias;
+ float depth_slope_scale;
+ bool depth_bias_enabled_for_points;
+ bool depth_bias_enabled_for_lines;
+ bool depth_bias_enabled_for_tris;
+
+ /* Stencil State. */
+ bool stencil_test_enabled;
+ unsigned int stencil_read_mask;
+ unsigned int stencil_write_mask;
+ unsigned int stencil_ref;
+ MTLCompareFunction stencil_func;
+
+ MTLStencilOperation stencil_op_front_stencil_fail;
+ MTLStencilOperation stencil_op_front_depth_fail;
+ MTLStencilOperation stencil_op_front_depthstencil_pass;
+
+ MTLStencilOperation stencil_op_back_stencil_fail;
+ MTLStencilOperation stencil_op_back_depth_fail;
+ MTLStencilOperation stencil_op_back_depthstencil_pass;
+
+ /* Frame-buffer State -- We need to mark this, in case stencil state remains unchanged,
+ * but attachment state has changed. */
+ bool has_depth_target;
+ bool has_stencil_target;
+
+ /* TODO(Metal): Consider optimizing this function using memcmp.
+ * Un-used, but differing, stencil state leads to over-generation
+ * of state objects when doing trivial compare. */
+ inline bool operator==(const MTLContextDepthStencilState &other) const
+ {
+ bool depth_state_equality = (has_depth_target == other.has_depth_target &&
+ depth_write_enable == other.depth_write_enable &&
+ depth_test_enabled == other.depth_test_enabled &&
+ depth_function == other.depth_function);
+
+ bool stencil_state_equality = true;
+ if (has_stencil_target) {
+ stencil_state_equality =
+ (has_stencil_target == other.has_stencil_target &&
+ stencil_test_enabled == other.stencil_test_enabled &&
+ stencil_op_front_stencil_fail == other.stencil_op_front_stencil_fail &&
+ stencil_op_front_depth_fail == other.stencil_op_front_depth_fail &&
+ stencil_op_front_depthstencil_pass == other.stencil_op_front_depthstencil_pass &&
+ stencil_op_back_stencil_fail == other.stencil_op_back_stencil_fail &&
+ stencil_op_back_depth_fail == other.stencil_op_back_depth_fail &&
+ stencil_op_back_depthstencil_pass == other.stencil_op_back_depthstencil_pass &&
+ stencil_func == other.stencil_func && stencil_read_mask == other.stencil_read_mask &&
+ stencil_write_mask == other.stencil_write_mask);
+ }
+
+ return depth_state_equality && stencil_state_equality;
+ }
+
+ /* Depth stencil state will get hashed in order to prepare
+ * MTLDepthStencilState objects. The hash should comprise of
+ * all elements which fill the MTLDepthStencilDescriptor.
+ * These are bound when [rec setDepthStencilState:...] is called.
+ * Depth bias and stencil reference value are set dynamically on the RenderCommandEncoder:
+ * - setStencilReferenceValue:
+ * - setDepthBias:slopeScale:clamp:
+ */
+ inline std::size_t hash() const
+ {
+ std::size_t boolean_bitmask = (this->depth_write_enable ? 1 : 0) |
+ ((this->depth_test_enabled ? 1 : 0) << 1) |
+ ((this->depth_bias_enabled_for_points ? 1 : 0) << 2) |
+ ((this->depth_bias_enabled_for_lines ? 1 : 0) << 3) |
+ ((this->depth_bias_enabled_for_tris ? 1 : 0) << 4) |
+ ((this->stencil_test_enabled ? 1 : 0) << 5) |
+ ((this->has_depth_target ? 1 : 0) << 6) |
+ ((this->has_stencil_target ? 1 : 0) << 7);
+
+ std::size_t stencilop_bitmask = ((std::size_t)this->stencil_op_front_stencil_fail) |
+ ((std::size_t)this->stencil_op_front_depth_fail << 3) |
+ ((std::size_t)this->stencil_op_front_depthstencil_pass << 6) |
+ ((std::size_t)this->stencil_op_back_stencil_fail << 9) |
+ ((std::size_t)this->stencil_op_back_depth_fail << 12) |
+ ((std::size_t)this->stencil_op_back_depthstencil_pass << 15);
+
+ std::size_t main_hash = (std::size_t)this->depth_function;
+ if (this->has_stencil_target) {
+ main_hash += (std::size_t)(this->stencil_read_mask & 0xFF) << 8;
+ main_hash += (std::size_t)(this->stencil_write_mask & 0xFF) << 16;
+ }
+ main_hash ^= (std::size_t)this->stencil_func << 16;
+ main_hash ^= stencilop_bitmask;
+
+ std::size_t final_hash = (main_hash << 8) | boolean_bitmask;
+ return final_hash;
+ }
+} MTLContextDepthStencilState;
+
typedef struct MTLContextTextureUtils {
/* Depth Update Utilities */
@@ -108,11 +216,149 @@ typedef struct MTLContextTextureUtils {
} MTLContextTextureUtils;
+/* Structs containing information on current binding state for textures and samplers. */
+typedef struct MTLTextureBinding {
+ bool used;
+
+ /* Same value as index in bindings array. */
+ unsigned int texture_slot_index;
+ gpu::MTLTexture *texture_resource;
+
+} MTLTextureBinding;
+
+typedef struct MTLSamplerBinding {
+ bool used;
+ MTLSamplerState state;
+
+ bool operator==(MTLSamplerBinding const &other) const
+ {
+ return (used == other.used && state == other.state);
+ }
+} MTLSamplerBinding;
+
+/* Combined sampler state configuration for Argument Buffer caching. */
+struct MTLSamplerArray {
+ unsigned int num_samplers;
+ /* MTLSamplerState permutations between 0..256 - slightly more than a byte. */
+ MTLSamplerState mtl_sampler_flags[MTL_MAX_TEXTURE_SLOTS];
+ id<MTLSamplerState> mtl_sampler[MTL_MAX_TEXTURE_SLOTS];
+
+ inline bool operator==(const MTLSamplerArray &other) const
+ {
+ if (this->num_samplers != other.num_samplers) {
+ return false;
+ }
+ return (memcmp(this->mtl_sampler_flags,
+ other.mtl_sampler_flags,
+ sizeof(MTLSamplerState) * this->num_samplers) == 0);
+ }
+
+ inline uint32_t hash() const
+ {
+ uint32_t hash = this->num_samplers;
+ for (int i = 0; i < this->num_samplers; i++) {
+ hash ^= (uint32_t)this->mtl_sampler_flags[i] << (i % 3);
+ }
+ return hash;
+ }
+};
+
+typedef enum MTLPipelineStateDirtyFlag {
+ MTL_PIPELINE_STATE_NULL_FLAG = 0,
+ /* Whether we need to call setViewport. */
+ MTL_PIPELINE_STATE_VIEWPORT_FLAG = (1 << 0),
+ /* Whether we need to call setScissor.*/
+ MTL_PIPELINE_STATE_SCISSOR_FLAG = (1 << 1),
+ /* Whether we need to update/rebind active depth stencil state. */
+ MTL_PIPELINE_STATE_DEPTHSTENCIL_FLAG = (1 << 2),
+ /* Whether we need to update/rebind active PSO. */
+ MTL_PIPELINE_STATE_PSO_FLAG = (1 << 3),
+ /* Whether we need to update the frontFacingWinding state. */
+ MTL_PIPELINE_STATE_FRONT_FACING_FLAG = (1 << 4),
+ /* Whether we need to update the culling state. */
+ MTL_PIPELINE_STATE_CULLMODE_FLAG = (1 << 5),
+ /* Full pipeline state needs applying. Occurs when beginning a new render pass. */
+ MTL_PIPELINE_STATE_ALL_FLAG =
+ (MTL_PIPELINE_STATE_VIEWPORT_FLAG | MTL_PIPELINE_STATE_SCISSOR_FLAG |
+ MTL_PIPELINE_STATE_DEPTHSTENCIL_FLAG | MTL_PIPELINE_STATE_PSO_FLAG |
+ MTL_PIPELINE_STATE_FRONT_FACING_FLAG | MTL_PIPELINE_STATE_CULLMODE_FLAG)
+} MTLPipelineStateDirtyFlag;
+
+/* Ignore full flag bit-mask `MTL_PIPELINE_STATE_ALL_FLAG`. */
+ENUM_OPERATORS(MTLPipelineStateDirtyFlag, MTL_PIPELINE_STATE_CULLMODE_FLAG);
+
+typedef struct MTLUniformBufferBinding {
+ bool bound;
+ MTLUniformBuf *ubo;
+} MTLUniformBufferBinding;
+
typedef struct MTLContextGlobalShaderPipelineState {
- /* ..TODO(Metal): More elements to be added as backend fleshed out.. */
+ bool initialised;
+
+ /* Whether the pipeline state has been modified since application.
+ * `dirty_flags` is a bitmask of the types of state which have been updated.
+ * This is in order to optimize calls and only re-apply state as needed.
+ * Some state parameters are dynamically applied on the RenderCommandEncoder,
+ * others may be encapsulated in GPU-resident state objects such as
+ * MTLDepthStencilState or MTLRenderPipelineState. */
+ bool dirty;
+ MTLPipelineStateDirtyFlag dirty_flags;
+
+ /* Shader resources. */
+ MTLShader *null_shader;
+
+ /* Active Shader State. */
+ MTLShader *active_shader;
+
+ /* Global Uniform Buffers. */
+ MTLUniformBufferBinding ubo_bindings[MTL_MAX_UNIFORM_BUFFER_BINDINGS];
+
+ /* Context Texture bindings. */
+ MTLTextureBinding texture_bindings[MTL_MAX_TEXTURE_SLOTS];
+ MTLSamplerBinding sampler_bindings[MTL_MAX_SAMPLER_SLOTS];
+
+ /*** --- Render Pipeline State --- ***/
+ /* Track global render pipeline state for the current context. The functions in GPU_state.h
+ * modify these parameters. Certain values, tagged [PSO], are parameters which are required to be
+ * passed into PSO creation, rather than dynamic state functions on the RenderCommandEncoder.
+ */
- /*** DATA and IMAGE access state ***/
+ /* Blending State. */
+ MTLColorWriteMask color_write_mask; /* [PSO] */
+ bool blending_enabled; /* [PSO] */
+ MTLBlendOperation alpha_blend_op; /* [PSO] */
+ MTLBlendOperation rgb_blend_op; /* [PSO] */
+ MTLBlendFactor dest_alpha_blend_factor; /* [PSO] */
+ MTLBlendFactor dest_rgb_blend_factor; /* [PSO] */
+ MTLBlendFactor src_alpha_blend_factor; /* [PSO] */
+ MTLBlendFactor src_rgb_blend_factor; /* [PSO] */
+
+ /* Culling State. */
+ bool culling_enabled;
+ eGPUFaceCullTest cull_mode;
+ eGPUFrontFace front_face;
+
+ /* Depth State. */
+ MTLContextDepthStencilState depth_stencil_state;
+
+ /* Viewport/Scissor Region. */
+ int viewport_offset_x;
+ int viewport_offset_y;
+ int viewport_width;
+ int viewport_height;
+ bool scissor_enabled;
+ int scissor_x;
+ int scissor_y;
+ int scissor_width;
+ int scissor_height;
+
+ /* Image data access state. */
uint unpack_row_length;
+
+ /* Render parameters. */
+ float point_size = 1.0f;
+ float line_width = 1.0f;
+
} MTLContextGlobalShaderPipelineState;
/* Metal Buffer */
@@ -127,8 +373,8 @@ typedef struct MTLTemporaryBufferRange {
bool requires_flush();
} MTLTemporaryBufferRange;
-/** MTLContext -- Core render loop and state management **/
-/* Note(Metal): Partial MTLContext stub to provide wrapper functionality
+/** MTLContext -- Core render loop and state management. **/
+/* NOTE(Metal): Partial MTLContext stub to provide wrapper functionality
* for work-in-progress MTL* classes. */
class MTLContext : public Context {
@@ -138,8 +384,24 @@ class MTLContext : public Context {
/* Compute and specialization caches. */
MTLContextTextureUtils texture_utils_;
+ /* Texture Samplers. */
+ /* Cache of generated MTLSamplerState objects based on permutations of `eGPUSamplerState`. */
+ id<MTLSamplerState> sampler_state_cache_[GPU_SAMPLER_MAX] = {0};
+ id<MTLSamplerState> default_sampler_state_ = nil;
+
+ /* When texture sampler count exceeds the resource bind limit, an
+ * argument buffer is used to pass samplers to the shader.
+ * Each unique configurations of multiple samplers can be cached, so as to not require
+ * re-generation. `samplers_` stores the current list of bound sampler objects.
+ * `cached_sampler_buffers_` is a cache of encoded argument buffers which can be re-used. */
+ MTLSamplerArray samplers_;
+ blender::Map<MTLSamplerArray, gpu::MTLBuffer *> cached_sampler_buffers_;
+
public:
- /* METAL API Resource Handles. */
+ /* Shaders and Pipeline state. */
+ MTLContextGlobalShaderPipelineState pipeline_state;
+
+ /* Metal API Resource Handles. */
id<MTLCommandQueue> queue = nil;
id<MTLDevice> device = nil;
@@ -160,24 +422,40 @@ class MTLContext : public Context {
void debug_group_begin(const char *name, int index) override;
void debug_group_end(void) override;
- /*** Context Utility functions */
+ /*** MTLContext Utility functions. */
/*
* All below functions modify the global state for the context, controlling the flow of
* rendering, binding resources, setting global state, resource management etc;
*/
- /* Metal Context Core functions */
- /* Command Buffer Management */
+ /* Metal Context Core functions. */
+ /* Command Buffer Management. */
id<MTLCommandBuffer> get_active_command_buffer();
- /* Render Pass State and Management */
+ /* Render Pass State and Management. */
void begin_render_pass();
void end_render_pass();
-
- /* Shaders and Pipeline state */
- MTLContextGlobalShaderPipelineState pipeline_state;
-
- /* Texture utilities */
+ bool is_render_pass_active();
+
+ /* Texture Binding. */
+ void texture_bind(gpu::MTLTexture *mtl_texture, unsigned int texture_unit);
+ void sampler_bind(MTLSamplerState, unsigned int sampler_unit);
+ void texture_unbind(gpu::MTLTexture *mtl_texture);
+ void texture_unbind_all(void);
+ id<MTLSamplerState> get_sampler_from_state(MTLSamplerState state);
+ id<MTLSamplerState> generate_sampler_from_state(MTLSamplerState state);
+ id<MTLSamplerState> get_default_sampler_state();
+
+ /* Metal Context pipeline state. */
+ void pipeline_state_init(void);
+ MTLShader *get_active_shader(void);
+
+ /* State assignment. */
+ void set_viewport(int origin_x, int origin_y, int width, int height);
+ void set_scissor(int scissor_x, int scissor_y, int scissor_width, int scissor_height);
+ void set_scissor_enabled(bool scissor_enabled);
+
+ /* Texture utilities. */
MTLContextTextureUtils &get_texture_utils()
{
return this->texture_utils_;
diff --git a/source/blender/gpu/metal/mtl_context.mm b/source/blender/gpu/metal/mtl_context.mm
index 18ed38c373d..94f5682b11b 100644
--- a/source/blender/gpu/metal/mtl_context.mm
+++ b/source/blender/gpu/metal/mtl_context.mm
@@ -5,6 +5,11 @@
*/
#include "mtl_context.hh"
#include "mtl_debug.hh"
+#include "mtl_state.hh"
+
+#include "DNA_userdef_types.h"
+
+#include "GPU_capabilities.h"
using namespace blender;
using namespace blender::gpu;
@@ -44,6 +49,9 @@ MTLContext::MTLContext(void *ghost_window)
/* Init debug. */
debug::mtl_debug_init();
+ /* Initialize Metal modules. */
+ this->state_manager = new MTLStateManager(this);
+
/* TODO(Metal): Implement. */
}
@@ -98,6 +106,234 @@ void MTLContext::end_render_pass()
/* TODO(Metal): Implement. */
}
+bool MTLContext::is_render_pass_active()
+{
+ /* TODO(Metal): Implement. */
+ return false;
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Global Context State
+ * \{ */
+
+/* Metal Context Pipeline State. */
+void MTLContext::pipeline_state_init()
+{
+ /*** Initialize state only once. ***/
+ if (!this->pipeline_state.initialised) {
+ this->pipeline_state.initialised = true;
+ this->pipeline_state.active_shader = NULL;
+
+ /* Clear bindings state. */
+ for (int t = 0; t < GPU_max_textures(); t++) {
+ this->pipeline_state.texture_bindings[t].used = false;
+ this->pipeline_state.texture_bindings[t].texture_slot_index = t;
+ this->pipeline_state.texture_bindings[t].texture_resource = NULL;
+ }
+ for (int s = 0; s < MTL_MAX_SAMPLER_SLOTS; s++) {
+ this->pipeline_state.sampler_bindings[s].used = false;
+ }
+ for (int u = 0; u < MTL_MAX_UNIFORM_BUFFER_BINDINGS; u++) {
+ this->pipeline_state.ubo_bindings[u].bound = false;
+ this->pipeline_state.ubo_bindings[u].ubo = NULL;
+ }
+ }
+
+ /*** State defaults -- restored by GPU_state_init. ***/
+ /* Clear blending State. */
+ this->pipeline_state.color_write_mask = MTLColorWriteMaskRed | MTLColorWriteMaskGreen |
+ MTLColorWriteMaskBlue | MTLColorWriteMaskAlpha;
+ this->pipeline_state.blending_enabled = false;
+ this->pipeline_state.alpha_blend_op = MTLBlendOperationAdd;
+ this->pipeline_state.rgb_blend_op = MTLBlendOperationAdd;
+ this->pipeline_state.dest_alpha_blend_factor = MTLBlendFactorZero;
+ this->pipeline_state.dest_rgb_blend_factor = MTLBlendFactorZero;
+ this->pipeline_state.src_alpha_blend_factor = MTLBlendFactorOne;
+ this->pipeline_state.src_rgb_blend_factor = MTLBlendFactorOne;
+
+ /* Viewport and scissor. */
+ this->pipeline_state.viewport_offset_x = 0;
+ this->pipeline_state.viewport_offset_y = 0;
+ this->pipeline_state.viewport_width = 0;
+ this->pipeline_state.viewport_height = 0;
+ this->pipeline_state.scissor_x = 0;
+ this->pipeline_state.scissor_y = 0;
+ this->pipeline_state.scissor_width = 0;
+ this->pipeline_state.scissor_height = 0;
+ this->pipeline_state.scissor_enabled = false;
+
+ /* Culling State. */
+ this->pipeline_state.culling_enabled = false;
+ this->pipeline_state.cull_mode = GPU_CULL_NONE;
+ this->pipeline_state.front_face = GPU_COUNTERCLOCKWISE;
+
+ /* DATA and IMAGE access state. */
+ this->pipeline_state.unpack_row_length = 0;
+
+ /* Depth State. */
+ this->pipeline_state.depth_stencil_state.depth_write_enable = false;
+ this->pipeline_state.depth_stencil_state.depth_test_enabled = false;
+ this->pipeline_state.depth_stencil_state.depth_range_near = 0.0;
+ this->pipeline_state.depth_stencil_state.depth_range_far = 1.0;
+ this->pipeline_state.depth_stencil_state.depth_function = MTLCompareFunctionAlways;
+ this->pipeline_state.depth_stencil_state.depth_bias = 0.0;
+ this->pipeline_state.depth_stencil_state.depth_slope_scale = 0.0;
+ this->pipeline_state.depth_stencil_state.depth_bias_enabled_for_points = false;
+ this->pipeline_state.depth_stencil_state.depth_bias_enabled_for_lines = false;
+ this->pipeline_state.depth_stencil_state.depth_bias_enabled_for_tris = false;
+
+ /* Stencil State. */
+ this->pipeline_state.depth_stencil_state.stencil_test_enabled = false;
+ this->pipeline_state.depth_stencil_state.stencil_read_mask = 0xFF;
+ this->pipeline_state.depth_stencil_state.stencil_write_mask = 0xFF;
+ this->pipeline_state.depth_stencil_state.stencil_ref = 0;
+ this->pipeline_state.depth_stencil_state.stencil_func = MTLCompareFunctionAlways;
+ this->pipeline_state.depth_stencil_state.stencil_op_front_stencil_fail = MTLStencilOperationKeep;
+ this->pipeline_state.depth_stencil_state.stencil_op_front_depth_fail = MTLStencilOperationKeep;
+ this->pipeline_state.depth_stencil_state.stencil_op_front_depthstencil_pass =
+ MTLStencilOperationKeep;
+ this->pipeline_state.depth_stencil_state.stencil_op_back_stencil_fail = MTLStencilOperationKeep;
+ this->pipeline_state.depth_stencil_state.stencil_op_back_depth_fail = MTLStencilOperationKeep;
+ this->pipeline_state.depth_stencil_state.stencil_op_back_depthstencil_pass =
+ MTLStencilOperationKeep;
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Texture State Management
+ * \{ */
+
+void MTLContext::texture_bind(gpu::MTLTexture *mtl_texture, unsigned int texture_unit)
+{
+ BLI_assert(this);
+ BLI_assert(mtl_texture);
+
+ if (texture_unit < 0 || texture_unit >= GPU_max_textures() ||
+ texture_unit >= MTL_MAX_TEXTURE_SLOTS) {
+ MTL_LOG_WARNING("Attempting to bind texture '%s' to invalid texture unit %d\n",
+ mtl_texture->get_name(),
+ texture_unit);
+ BLI_assert(false);
+ return;
+ }
+
+ /* Bind new texture. */
+ this->pipeline_state.texture_bindings[texture_unit].texture_resource = mtl_texture;
+ this->pipeline_state.texture_bindings[texture_unit].used = true;
+ mtl_texture->is_bound_ = true;
+}
+
+void MTLContext::sampler_bind(MTLSamplerState sampler_state, unsigned int sampler_unit)
+{
+ BLI_assert(this);
+ if (sampler_unit < 0 || sampler_unit >= GPU_max_textures() ||
+ sampler_unit >= MTL_MAX_SAMPLER_SLOTS) {
+ MTL_LOG_WARNING("Attempting to bind sampler to invalid sampler unit %d\n", sampler_unit);
+ BLI_assert(false);
+ return;
+ }
+
+ /* Apply binding. */
+ this->pipeline_state.sampler_bindings[sampler_unit] = {true, sampler_state};
+}
+
+void MTLContext::texture_unbind(gpu::MTLTexture *mtl_texture)
+{
+ BLI_assert(mtl_texture);
+
+ /* Iterate through textures in state and unbind. */
+ for (int i = 0; i < min_uu(GPU_max_textures(), MTL_MAX_TEXTURE_SLOTS); i++) {
+ if (this->pipeline_state.texture_bindings[i].texture_resource == mtl_texture) {
+ this->pipeline_state.texture_bindings[i].texture_resource = nullptr;
+ this->pipeline_state.texture_bindings[i].used = false;
+ }
+ }
+
+ /* Locally unbind texture. */
+ mtl_texture->is_bound_ = false;
+}
+
+void MTLContext::texture_unbind_all()
+{
+ /* Iterate through context's bound textures. */
+ for (int t = 0; t < min_uu(GPU_max_textures(), MTL_MAX_TEXTURE_SLOTS); t++) {
+ if (this->pipeline_state.texture_bindings[t].used &&
+ this->pipeline_state.texture_bindings[t].texture_resource) {
+
+ this->pipeline_state.texture_bindings[t].used = false;
+ this->pipeline_state.texture_bindings[t].texture_resource = nullptr;
+ }
+ }
+}
+
+id<MTLSamplerState> MTLContext::get_sampler_from_state(MTLSamplerState sampler_state)
+{
+ BLI_assert((unsigned int)sampler_state >= 0 && ((unsigned int)sampler_state) < GPU_SAMPLER_MAX);
+ return this->sampler_state_cache_[(unsigned int)sampler_state];
+}
+
+id<MTLSamplerState> MTLContext::generate_sampler_from_state(MTLSamplerState sampler_state)
+{
+ /* Check if sampler already exists for given state. */
+ id<MTLSamplerState> st = this->sampler_state_cache_[(unsigned int)sampler_state];
+ if (st != nil) {
+ return st;
+ }
+ else {
+ MTLSamplerDescriptor *descriptor = [[MTLSamplerDescriptor alloc] init];
+ descriptor.normalizedCoordinates = true;
+
+ MTLSamplerAddressMode clamp_type = (sampler_state.state & GPU_SAMPLER_CLAMP_BORDER) ?
+ MTLSamplerAddressModeClampToBorderColor :
+ MTLSamplerAddressModeClampToEdge;
+ descriptor.rAddressMode = (sampler_state.state & GPU_SAMPLER_REPEAT_R) ?
+ MTLSamplerAddressModeRepeat :
+ clamp_type;
+ descriptor.sAddressMode = (sampler_state.state & GPU_SAMPLER_REPEAT_S) ?
+ MTLSamplerAddressModeRepeat :
+ clamp_type;
+ descriptor.tAddressMode = (sampler_state.state & GPU_SAMPLER_REPEAT_T) ?
+ MTLSamplerAddressModeRepeat :
+ clamp_type;
+ descriptor.borderColor = MTLSamplerBorderColorTransparentBlack;
+ descriptor.minFilter = (sampler_state.state & GPU_SAMPLER_FILTER) ?
+ MTLSamplerMinMagFilterLinear :
+ MTLSamplerMinMagFilterNearest;
+ descriptor.magFilter = (sampler_state.state & GPU_SAMPLER_FILTER) ?
+ MTLSamplerMinMagFilterLinear :
+ MTLSamplerMinMagFilterNearest;
+ descriptor.mipFilter = (sampler_state.state & GPU_SAMPLER_MIPMAP) ?
+ MTLSamplerMipFilterLinear :
+ MTLSamplerMipFilterNotMipmapped;
+ descriptor.lodMinClamp = -1000;
+ descriptor.lodMaxClamp = 1000;
+ float aniso_filter = max_ff(16, U.anisotropic_filter);
+ descriptor.maxAnisotropy = (sampler_state.state & GPU_SAMPLER_MIPMAP) ? aniso_filter : 1;
+ descriptor.compareFunction = (sampler_state.state & GPU_SAMPLER_COMPARE) ?
+ MTLCompareFunctionLessEqual :
+ MTLCompareFunctionAlways;
+ descriptor.supportArgumentBuffers = true;
+
+ id<MTLSamplerState> state = [this->device newSamplerStateWithDescriptor:descriptor];
+ this->sampler_state_cache_[(unsigned int)sampler_state] = state;
+
+ BLI_assert(state != nil);
+ [descriptor autorelease];
+ return state;
+ }
+}
+
+id<MTLSamplerState> MTLContext::get_default_sampler_state()
+{
+ if (this->default_sampler_state_ == nil) {
+ this->default_sampler_state_ = this->get_sampler_from_state(DEFAULT_SAMPLER_STATE);
+ }
+ return this->default_sampler_state_;
+}
+
/** \} */
} // blender::gpu
diff --git a/source/blender/gpu/metal/mtl_state.hh b/source/blender/gpu/metal/mtl_state.hh
new file mode 100644
index 00000000000..f2d85f9648b
--- /dev/null
+++ b/source/blender/gpu/metal/mtl_state.hh
@@ -0,0 +1,73 @@
+/** \file
+ * \ingroup gpu
+ */
+
+#include "MEM_guardedalloc.h"
+
+#include "BLI_utildefines.h"
+
+#include "GPU_state.h"
+#include "gpu_state_private.hh"
+
+namespace blender::gpu {
+
+/* Forward Declarations. */
+class MTLContext;
+
+/**
+ * State manager keeping track of the draw state and applying it before drawing.
+ * Metal Implementation.
+ **/
+class MTLStateManager : public StateManager {
+ public:
+ private:
+ /* Current state of the associated MTLContext.
+ * Avoids resetting the whole state for every change. */
+ GPUState current_;
+ GPUStateMutable current_mutable_;
+ MTLContext *context_;
+
+ public:
+ MTLStateManager(MTLContext *ctx);
+
+ void apply_state(void) override;
+ void force_state(void) override;
+
+ void issue_barrier(eGPUBarrier barrier_bits) override;
+
+ void texture_bind(Texture *tex, eGPUSamplerState sampler, int unit) override;
+ void texture_unbind(Texture *tex) override;
+ void texture_unbind_all(void) override;
+
+ void image_bind(Texture *tex, int unit) override;
+ void image_unbind(Texture *tex) override;
+ void image_unbind_all(void) override;
+
+ void texture_unpack_row_length_set(uint len) override;
+
+ private:
+ void set_write_mask(const eGPUWriteMask value);
+ void set_depth_test(const eGPUDepthTest value);
+ void set_stencil_test(const eGPUStencilTest test, const eGPUStencilOp operation);
+ void set_stencil_mask(const eGPUStencilTest test, const GPUStateMutable state);
+ void set_clip_distances(const int new_dist_len, const int old_dist_len);
+ void set_logic_op(const bool enable);
+ void set_facing(const bool invert);
+ void set_backface_culling(const eGPUFaceCullTest test);
+ void set_provoking_vert(const eGPUProvokingVertex vert);
+ void set_shadow_bias(const bool enable);
+ void set_blend(const eGPUBlend value);
+
+ void set_state(const GPUState &state);
+ void set_mutable_state(const GPUStateMutable &state);
+
+ /* METAL State utility functions. */
+ void mtl_state_init(void);
+ void mtl_depth_range(float near, float far);
+ void mtl_stencil_mask(unsigned int mask);
+ void mtl_stencil_set_func(eGPUStencilTest stencil_func, int ref, unsigned int mask);
+
+ MEM_CXX_CLASS_ALLOC_FUNCS("MTLStateManager")
+};
+
+} // namespace blender::gpu
diff --git a/source/blender/gpu/metal/mtl_state.mm b/source/blender/gpu/metal/mtl_state.mm
new file mode 100644
index 00000000000..fa2f5c54391
--- /dev/null
+++ b/source/blender/gpu/metal/mtl_state.mm
@@ -0,0 +1,677 @@
+/** \file
+ * \ingroup gpu
+ */
+
+#include "BLI_math_base.h"
+#include "BLI_math_bits.h"
+
+#include "GPU_framebuffer.h"
+
+#include "mtl_context.hh"
+#include "mtl_state.hh"
+
+namespace blender::gpu {
+
+/* -------------------------------------------------------------------- */
+/** \name MTLStateManager
+ * \{ */
+
+void MTLStateManager::mtl_state_init(void)
+{
+ BLI_assert(this->context_);
+ this->context_->pipeline_state_init();
+}
+
+MTLStateManager::MTLStateManager(MTLContext *ctx) : StateManager()
+{
+ /* Initialize State. */
+ this->context_ = ctx;
+ mtl_state_init();
+
+ /* Force update using default state. */
+ current_ = ~state;
+ current_mutable_ = ~mutable_state;
+ set_state(state);
+ set_mutable_state(mutable_state);
+}
+
+void MTLStateManager::apply_state(void)
+{
+ this->set_state(this->state);
+ this->set_mutable_state(this->mutable_state);
+ /* TODO(Metal): Enable after integration of MTLFrameBuffer. */
+ /* static_cast<MTLFrameBuffer *>(this->context_->active_fb)->apply_state(); */
+};
+
+void MTLStateManager::force_state(void)
+{
+ /* Little exception for clip distances since they need to keep the old count correct. */
+ uint32_t clip_distances = current_.clip_distances;
+ current_ = ~this->state;
+ current_.clip_distances = clip_distances;
+ current_mutable_ = ~this->mutable_state;
+ this->set_state(this->state);
+ this->set_mutable_state(this->mutable_state);
+};
+
+void MTLStateManager::set_state(const GPUState &state)
+{
+ GPUState changed = state ^ current_;
+
+ if (changed.blend != 0) {
+ set_blend((eGPUBlend)state.blend);
+ }
+ if (changed.write_mask != 0) {
+ set_write_mask((eGPUWriteMask)state.write_mask);
+ }
+ if (changed.depth_test != 0) {
+ set_depth_test((eGPUDepthTest)state.depth_test);
+ }
+ if (changed.stencil_test != 0 || changed.stencil_op != 0) {
+ set_stencil_test((eGPUStencilTest)state.stencil_test, (eGPUStencilOp)state.stencil_op);
+ set_stencil_mask((eGPUStencilTest)state.stencil_test, mutable_state);
+ }
+ if (changed.clip_distances != 0) {
+ set_clip_distances(state.clip_distances, current_.clip_distances);
+ }
+ if (changed.culling_test != 0) {
+ set_backface_culling((eGPUFaceCullTest)state.culling_test);
+ }
+ if (changed.logic_op_xor != 0) {
+ set_logic_op(state.logic_op_xor);
+ }
+ if (changed.invert_facing != 0) {
+ set_facing(state.invert_facing);
+ }
+ if (changed.provoking_vert != 0) {
+ set_provoking_vert((eGPUProvokingVertex)state.provoking_vert);
+ }
+ if (changed.shadow_bias != 0) {
+ set_shadow_bias(state.shadow_bias);
+ }
+
+ /* TODO remove (Following GLState). */
+ if (changed.polygon_smooth) {
+ /* NOTE: Unsupported in Metal. */
+ }
+ if (changed.line_smooth) {
+ /* NOTE: Unsupported in Metal. */
+ }
+
+ current_ = state;
+}
+
+void MTLStateManager::mtl_depth_range(float near, float far)
+{
+ BLI_assert(this->context_);
+ BLI_assert(near >= 0.0 && near < 1.0);
+ BLI_assert(far > 0.0 && far <= 1.0);
+ MTLContextGlobalShaderPipelineState &pipeline_state = this->context_->pipeline_state;
+ MTLContextDepthStencilState &ds_state = pipeline_state.depth_stencil_state;
+
+ ds_state.depth_range_near = near;
+ ds_state.depth_range_far = far;
+ pipeline_state.dirty_flags |= MTL_PIPELINE_STATE_VIEWPORT_FLAG;
+}
+
+void MTLStateManager::set_mutable_state(const GPUStateMutable &state)
+{
+ GPUStateMutable changed = state ^ current_mutable_;
+ MTLContextGlobalShaderPipelineState &pipeline_state = this->context_->pipeline_state;
+
+ if (float_as_uint(changed.point_size) != 0) {
+ pipeline_state.point_size = state.point_size;
+ pipeline_state.dirty_flags |= MTL_PIPELINE_STATE_PSO_FLAG;
+ }
+
+ if (changed.line_width != 0) {
+ pipeline_state.line_width = state.line_width;
+ pipeline_state.dirty_flags |= MTL_PIPELINE_STATE_PSO_FLAG;
+ }
+
+ if (changed.depth_range[0] != 0 || changed.depth_range[1] != 0) {
+ /* TODO remove, should modify the projection matrix instead. */
+ mtl_depth_range(state.depth_range[0], state.depth_range[1]);
+ }
+
+ if (changed.stencil_compare_mask != 0 || changed.stencil_reference != 0 ||
+ changed.stencil_write_mask != 0) {
+ set_stencil_mask((eGPUStencilTest)current_.stencil_test, state);
+ }
+
+ current_mutable_ = state;
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name State setting functions
+ * \{ */
+
+void MTLStateManager::set_write_mask(const eGPUWriteMask value)
+{
+ BLI_assert(this->context_);
+ MTLContextGlobalShaderPipelineState &pipeline_state = this->context_->pipeline_state;
+ pipeline_state.depth_stencil_state.depth_write_enable = ((value & GPU_WRITE_DEPTH) != 0);
+ pipeline_state.color_write_mask =
+ (((value & GPU_WRITE_RED) != 0) ? MTLColorWriteMaskRed : MTLColorWriteMaskNone) |
+ (((value & GPU_WRITE_GREEN) != 0) ? MTLColorWriteMaskGreen : MTLColorWriteMaskNone) |
+ (((value & GPU_WRITE_BLUE) != 0) ? MTLColorWriteMaskBlue : MTLColorWriteMaskNone) |
+ (((value & GPU_WRITE_ALPHA) != 0) ? MTLColorWriteMaskAlpha : MTLColorWriteMaskNone);
+ pipeline_state.dirty_flags |= MTL_PIPELINE_STATE_PSO_FLAG;
+}
+
+static MTLCompareFunction gpu_depth_function_to_metal(eGPUDepthTest depth_func)
+{
+ switch (depth_func) {
+ case GPU_DEPTH_NONE:
+ return MTLCompareFunctionNever;
+ case GPU_DEPTH_LESS:
+ return MTLCompareFunctionLess;
+ case GPU_DEPTH_EQUAL:
+ return MTLCompareFunctionEqual;
+ case GPU_DEPTH_LESS_EQUAL:
+ return MTLCompareFunctionLessEqual;
+ case GPU_DEPTH_GREATER:
+ return MTLCompareFunctionGreater;
+ case GPU_DEPTH_GREATER_EQUAL:
+ return MTLCompareFunctionGreaterEqual;
+ case GPU_DEPTH_ALWAYS:
+ return MTLCompareFunctionAlways;
+ default:
+ BLI_assert(false && "Invalid eGPUDepthTest");
+ break;
+ }
+ return MTLCompareFunctionAlways;
+}
+
+static MTLCompareFunction gpu_stencil_func_to_metal(eGPUStencilTest stencil_func)
+{
+ switch (stencil_func) {
+ case GPU_STENCIL_NONE:
+ return MTLCompareFunctionAlways;
+ case GPU_STENCIL_EQUAL:
+ return MTLCompareFunctionEqual;
+ case GPU_STENCIL_NEQUAL:
+ return MTLCompareFunctionNotEqual;
+ case GPU_STENCIL_ALWAYS:
+ return MTLCompareFunctionAlways;
+ default:
+ BLI_assert(false && "Unrecognised eGPUStencilTest function");
+ break;
+ }
+ return MTLCompareFunctionAlways;
+}
+
+void MTLStateManager::set_depth_test(const eGPUDepthTest value)
+{
+ BLI_assert(this->context_);
+ MTLContextGlobalShaderPipelineState &pipeline_state = this->context_->pipeline_state;
+ MTLContextDepthStencilState &ds_state = pipeline_state.depth_stencil_state;
+
+ ds_state.depth_test_enabled = (value != GPU_DEPTH_NONE);
+ ds_state.depth_function = gpu_depth_function_to_metal(value);
+ pipeline_state.dirty_flags |= MTL_PIPELINE_STATE_DEPTHSTENCIL_FLAG;
+}
+
+void MTLStateManager::mtl_stencil_mask(unsigned int mask)
+{
+ BLI_assert(this->context_);
+ MTLContextGlobalShaderPipelineState &pipeline_state = this->context_->pipeline_state;
+ pipeline_state.depth_stencil_state.stencil_write_mask = mask;
+ pipeline_state.dirty_flags |= MTL_PIPELINE_STATE_DEPTHSTENCIL_FLAG;
+}
+
+void MTLStateManager::mtl_stencil_set_func(eGPUStencilTest stencil_func,
+ int ref,
+ unsigned int mask)
+{
+ BLI_assert(this->context_);
+ MTLContextGlobalShaderPipelineState &pipeline_state = this->context_->pipeline_state;
+ MTLContextDepthStencilState &ds_state = pipeline_state.depth_stencil_state;
+
+ ds_state.stencil_func = gpu_stencil_func_to_metal(stencil_func);
+ ds_state.stencil_ref = ref;
+ ds_state.stencil_read_mask = mask;
+ pipeline_state.dirty_flags |= MTL_PIPELINE_STATE_DEPTHSTENCIL_FLAG;
+}
+
+static void mtl_stencil_set_op_separate(MTLContext *context,
+ eGPUFaceCullTest face,
+ MTLStencilOperation stencil_fail,
+ MTLStencilOperation depth_test_fail,
+ MTLStencilOperation depthstencil_pass)
+{
+ BLI_assert(context);
+ MTLContextGlobalShaderPipelineState &pipeline_state = context->pipeline_state;
+ MTLContextDepthStencilState &ds_state = pipeline_state.depth_stencil_state;
+
+ if (face == GPU_CULL_FRONT) {
+ ds_state.stencil_op_front_stencil_fail = stencil_fail;
+ ds_state.stencil_op_front_depth_fail = depth_test_fail;
+ ds_state.stencil_op_front_depthstencil_pass = depthstencil_pass;
+ }
+ else if (face == GPU_CULL_BACK) {
+ ds_state.stencil_op_back_stencil_fail = stencil_fail;
+ ds_state.stencil_op_back_depth_fail = depth_test_fail;
+ ds_state.stencil_op_back_depthstencil_pass = depthstencil_pass;
+ }
+
+ pipeline_state.dirty_flags |= MTL_PIPELINE_STATE_DEPTHSTENCIL_FLAG;
+}
+
+static void mtl_stencil_set_op(MTLContext *context,
+ MTLStencilOperation stencil_fail,
+ MTLStencilOperation depth_test_fail,
+ MTLStencilOperation depthstencil_pass)
+{
+ mtl_stencil_set_op_separate(
+ context, GPU_CULL_FRONT, stencil_fail, depth_test_fail, depthstencil_pass);
+ mtl_stencil_set_op_separate(
+ context, GPU_CULL_BACK, stencil_fail, depth_test_fail, depthstencil_pass);
+}
+
+void MTLStateManager::set_stencil_test(const eGPUStencilTest test, const eGPUStencilOp operation)
+{
+ switch (operation) {
+ case GPU_STENCIL_OP_REPLACE:
+ mtl_stencil_set_op(this->context_,
+ MTLStencilOperationKeep,
+ MTLStencilOperationKeep,
+ MTLStencilOperationReplace);
+ break;
+ case GPU_STENCIL_OP_COUNT_DEPTH_PASS:
+ /* Winding inversed due to flipped Y coordinate system in Metal. */
+ mtl_stencil_set_op_separate(this->context_,
+ GPU_CULL_FRONT,
+ MTLStencilOperationKeep,
+ MTLStencilOperationKeep,
+ MTLStencilOperationIncrementWrap);
+ mtl_stencil_set_op_separate(this->context_,
+ GPU_CULL_BACK,
+ MTLStencilOperationKeep,
+ MTLStencilOperationKeep,
+ MTLStencilOperationDecrementWrap);
+ break;
+ case GPU_STENCIL_OP_COUNT_DEPTH_FAIL:
+ /* Winding inversed due to flipped Y coordinate system in Metal. */
+ mtl_stencil_set_op_separate(this->context_,
+ GPU_CULL_FRONT,
+ MTLStencilOperationKeep,
+ MTLStencilOperationDecrementWrap,
+ MTLStencilOperationKeep);
+ mtl_stencil_set_op_separate(this->context_,
+ GPU_CULL_BACK,
+ MTLStencilOperationKeep,
+ MTLStencilOperationIncrementWrap,
+ MTLStencilOperationKeep);
+ break;
+ case GPU_STENCIL_OP_NONE:
+ default:
+ mtl_stencil_set_op(this->context_,
+ MTLStencilOperationKeep,
+ MTLStencilOperationKeep,
+ MTLStencilOperationKeep);
+ }
+
+ BLI_assert(this->context_);
+ MTLContextGlobalShaderPipelineState &pipeline_state = this->context_->pipeline_state;
+ pipeline_state.depth_stencil_state.stencil_test_enabled = (test != GPU_STENCIL_NONE);
+ pipeline_state.dirty_flags |= MTL_PIPELINE_STATE_DEPTHSTENCIL_FLAG;
+}
+
+void MTLStateManager::set_stencil_mask(const eGPUStencilTest test, const GPUStateMutable state)
+{
+ if (test == GPU_STENCIL_NONE) {
+ mtl_stencil_mask(0x00);
+ mtl_stencil_set_func(GPU_STENCIL_ALWAYS, 0x00, 0x00);
+ }
+ else {
+ mtl_stencil_mask(state.stencil_write_mask);
+ mtl_stencil_set_func(test, state.stencil_reference, state.stencil_compare_mask);
+ }
+}
+
+void MTLStateManager::set_clip_distances(const int new_dist_len, const int old_dist_len)
+{
+ /* TODO(Metal): Support Clip distances in METAL. Clip distance
+ * assignment via shader is supported, but global clip-states require
+ * support. */
+}
+
+void MTLStateManager::set_logic_op(const bool enable)
+{
+ /* NOTE(Metal): Logic Operations not directly supported. */
+}
+
+void MTLStateManager::set_facing(const bool invert)
+{
+ /* Check Current Context. */
+ BLI_assert(this->context_);
+ MTLContextGlobalShaderPipelineState &pipeline_state = this->context_->pipeline_state;
+
+ /* Apply State -- opposite of GL, as METAL default is GPU_CLOCKWISE, GL default is
+ * COUNTERCLOCKWISE. This needs to be the inverse of the default. */
+ pipeline_state.front_face = (invert) ? GPU_COUNTERCLOCKWISE : GPU_CLOCKWISE;
+
+ /* Mark Dirty - Ensure context updates state between draws. */
+ pipeline_state.dirty_flags |= MTL_PIPELINE_STATE_FRONT_FACING_FLAG;
+ pipeline_state.dirty = true;
+}
+
+void MTLStateManager::set_backface_culling(const eGPUFaceCullTest test)
+{
+ /* Check Current Context. */
+ BLI_assert(this->context_);
+ MTLContextGlobalShaderPipelineState &pipeline_state = this->context_->pipeline_state;
+
+ /* Apply State. */
+ pipeline_state.culling_enabled = (test != GPU_CULL_NONE);
+ pipeline_state.cull_mode = test;
+
+ /* Mark Dirty - Ensure context updates state between draws. */
+ pipeline_state.dirty_flags |= MTL_PIPELINE_STATE_CULLMODE_FLAG;
+ pipeline_state.dirty = true;
+}
+
+void MTLStateManager::set_provoking_vert(const eGPUProvokingVertex vert)
+{
+ /* NOTE(Metal): Provoking vertex is not a feature in the Metal API.
+ * Shaders are handled on a case-by-case basis using a modified vertex shader.
+ * For example, wireframe rendering and edit-mesh shaders utilize an SSBO-based
+ * vertex fetching mechanism which considers the inverse convention for flat
+ * shading, to ensure consistent results with OpenGL. */
+}
+
+void MTLStateManager::set_shadow_bias(const bool enable)
+{
+ /* Check Current Context. */
+ BLI_assert(this->context_);
+ MTLContextGlobalShaderPipelineState &pipeline_state = this->context_->pipeline_state;
+ MTLContextDepthStencilState &ds_state = pipeline_state.depth_stencil_state;
+
+ /* Apply State. */
+ if (enable) {
+ ds_state.depth_bias_enabled_for_lines = true;
+ ds_state.depth_bias_enabled_for_tris = true;
+ ds_state.depth_bias = 2.0f;
+ ds_state.depth_slope_scale = 1.0f;
+ }
+ else {
+ ds_state.depth_bias_enabled_for_lines = false;
+ ds_state.depth_bias_enabled_for_tris = false;
+ ds_state.depth_bias = 0.0f;
+ ds_state.depth_slope_scale = 0.0f;
+ }
+
+ /* Mark Dirty - Ensure context updates depth-stencil state between draws. */
+ pipeline_state.dirty_flags |= MTL_PIPELINE_STATE_DEPTHSTENCIL_FLAG;
+ pipeline_state.dirty = true;
+}
+
+void MTLStateManager::set_blend(const eGPUBlend value)
+{
+ /**
+ * Factors to the equation.
+ * SRC is fragment shader output.
+ * DST is framebuffer color.
+ * final.rgb = SRC.rgb * src_rgb + DST.rgb * dst_rgb;
+ * final.a = SRC.a * src_alpha + DST.a * dst_alpha;
+ **/
+ MTLBlendFactor src_rgb;
+ MTLBlendFactor dst_rgb;
+ MTLBlendFactor src_alpha;
+ MTLBlendFactor dst_alpha;
+ switch (value) {
+ default:
+ case GPU_BLEND_ALPHA: {
+ src_rgb = MTLBlendFactorSourceAlpha;
+ dst_rgb = MTLBlendFactorOneMinusSourceAlpha;
+ src_alpha = MTLBlendFactorOne;
+ dst_alpha = MTLBlendFactorOneMinusSourceAlpha;
+ break;
+ }
+ case GPU_BLEND_ALPHA_PREMULT: {
+ src_rgb = MTLBlendFactorOne;
+ dst_rgb = MTLBlendFactorOneMinusSourceAlpha;
+ src_alpha = MTLBlendFactorOne;
+ dst_alpha = MTLBlendFactorOneMinusSourceAlpha;
+ break;
+ }
+ case GPU_BLEND_ADDITIVE: {
+ /* Do not let alpha accumulate but pre-multiply the source RGB by it. */
+ src_rgb = MTLBlendFactorSourceAlpha;
+ dst_rgb = MTLBlendFactorOne;
+ src_alpha = MTLBlendFactorZero;
+ dst_alpha = MTLBlendFactorOne;
+ break;
+ }
+ case GPU_BLEND_SUBTRACT:
+ case GPU_BLEND_ADDITIVE_PREMULT: {
+ /* Let alpha accumulate. */
+ src_rgb = MTLBlendFactorOne;
+ dst_rgb = MTLBlendFactorOne;
+ src_alpha = MTLBlendFactorOne;
+ dst_alpha = MTLBlendFactorOne;
+ break;
+ }
+ case GPU_BLEND_MULTIPLY: {
+ src_rgb = MTLBlendFactorDestinationColor;
+ dst_rgb = MTLBlendFactorZero;
+ src_alpha = MTLBlendFactorDestinationAlpha;
+ dst_alpha = MTLBlendFactorZero;
+ break;
+ }
+ case GPU_BLEND_INVERT: {
+ src_rgb = MTLBlendFactorOneMinusDestinationColor;
+ dst_rgb = MTLBlendFactorZero;
+ src_alpha = MTLBlendFactorZero;
+ dst_alpha = MTLBlendFactorOne;
+ break;
+ }
+ case GPU_BLEND_OIT: {
+ src_rgb = MTLBlendFactorOne;
+ dst_rgb = MTLBlendFactorOne;
+ src_alpha = MTLBlendFactorZero;
+ dst_alpha = MTLBlendFactorOneMinusSourceAlpha;
+ break;
+ }
+ case GPU_BLEND_BACKGROUND: {
+ src_rgb = MTLBlendFactorOneMinusDestinationAlpha;
+ dst_rgb = MTLBlendFactorSourceAlpha;
+ src_alpha = MTLBlendFactorZero;
+ dst_alpha = MTLBlendFactorSourceAlpha;
+ break;
+ }
+ case GPU_BLEND_ALPHA_UNDER_PREMUL: {
+ src_rgb = MTLBlendFactorOneMinusDestinationAlpha;
+ dst_rgb = MTLBlendFactorOne;
+ src_alpha = MTLBlendFactorOneMinusDestinationAlpha;
+ dst_alpha = MTLBlendFactorOne;
+ break;
+ }
+ case GPU_BLEND_CUSTOM: {
+ src_rgb = MTLBlendFactorOne;
+ dst_rgb = MTLBlendFactorSource1Color;
+ src_alpha = MTLBlendFactorOne;
+ dst_alpha = MTLBlendFactorSource1Alpha;
+ break;
+ }
+ }
+
+ /* Check Current Context. */
+ BLI_assert(this->context_);
+ MTLContextGlobalShaderPipelineState &pipeline_state = this->context_->pipeline_state;
+
+ if (value == GPU_BLEND_SUBTRACT) {
+ pipeline_state.rgb_blend_op = MTLBlendOperationReverseSubtract;
+ pipeline_state.alpha_blend_op = MTLBlendOperationReverseSubtract;
+ }
+ else {
+ pipeline_state.rgb_blend_op = MTLBlendOperationAdd;
+ pipeline_state.alpha_blend_op = MTLBlendOperationAdd;
+ }
+
+ /* Apply State. */
+ pipeline_state.blending_enabled = (value != GPU_BLEND_NONE);
+ pipeline_state.src_rgb_blend_factor = src_rgb;
+ pipeline_state.dest_rgb_blend_factor = dst_rgb;
+ pipeline_state.src_alpha_blend_factor = src_alpha;
+ pipeline_state.dest_alpha_blend_factor = dst_alpha;
+
+ /* Mark Dirty - Ensure context updates PSOs between draws. */
+ pipeline_state.dirty_flags |= MTL_PIPELINE_STATE_PSO_FLAG;
+ pipeline_state.dirty = true;
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Memory barrier
+ * \{ */
+
+/* NOTE(Metal): Granular option for specifying before/after stages for a barrier
+ * Would be a useful feature. */
+#if 0
+void MTLStateManager::issue_barrier(eGPUBarrier barrier_bits,
+ eGPUStageBarrierBits before_stages,
+ eGPUStageBarrierBits after_stages)
+#endif
+void MTLStateManager::issue_barrier(eGPUBarrier barrier_bits)
+{
+ /* NOTE(Metal): The Metal API implicitly tracks dependencies between resources.
+ * Memory barriers and execution barriers (Fences/Events) can be used to coordinate
+ * this explicitly, however, in most cases, the driver will be able to
+ * resolve these dependencies automatically.
+ * For untracked resources, such as MTLHeap's, explicit barriers are necessary. */
+ eGPUStageBarrierBits before_stages = GPU_BARRIER_STAGE_ANY;
+ eGPUStageBarrierBits after_stages = GPU_BARRIER_STAGE_ANY;
+
+ MTLContext *ctx = reinterpret_cast<MTLContext *>(GPU_context_active_get());
+ BLI_assert(ctx);
+ if (ctx->is_render_pass_active()) {
+
+ /* Apple Silicon does not support memory barriers.
+ * We do not currently need these due to implicit API guarantees.
+ * NOTE(Metal): MTLFence/MTLEvent may be required to synchronize work if
+ * untracked resources are ever used. */
+ if ([ctx->device hasUnifiedMemory]) {
+ return;
+ }
+
+ /* Issue barrier. */
+ /* TODO(Metal): To be completed pending implementation of RenderCommandEncoder management. */
+ id<MTLRenderCommandEncoder> rec = nil; // ctx->get_active_render_command_encoder();
+ BLI_assert(rec);
+
+ /* Only supporting Metal on 10.15 onward anyway - Check required for warnings. */
+ if (@available(macOS 10.14, *)) {
+ MTLBarrierScope scope = 0;
+ if (barrier_bits & GPU_BARRIER_SHADER_IMAGE_ACCESS ||
+ barrier_bits & GPU_BARRIER_TEXTURE_FETCH) {
+ scope = scope | MTLBarrierScopeTextures | MTLBarrierScopeRenderTargets;
+ }
+ if (barrier_bits & GPU_BARRIER_SHADER_STORAGE ||
+ barrier_bits & GPU_BARRIER_VERTEX_ATTRIB_ARRAY ||
+ barrier_bits & GPU_BARRIER_ELEMENT_ARRAY) {
+ scope = scope | MTLBarrierScopeBuffers;
+ }
+
+ MTLRenderStages before_stage_flags = 0;
+ MTLRenderStages after_stage_flags = 0;
+ if (before_stages & GPU_BARRIER_STAGE_VERTEX &&
+ !(before_stages & GPU_BARRIER_STAGE_FRAGMENT)) {
+ before_stage_flags = before_stage_flags | MTLRenderStageVertex;
+ }
+ if (before_stages & GPU_BARRIER_STAGE_FRAGMENT) {
+ before_stage_flags = before_stage_flags | MTLRenderStageFragment;
+ }
+ if (after_stages & GPU_BARRIER_STAGE_VERTEX) {
+ after_stage_flags = after_stage_flags | MTLRenderStageVertex;
+ }
+ if (after_stages & GPU_BARRIER_STAGE_FRAGMENT) {
+ after_stage_flags = MTLRenderStageFragment;
+ }
+
+ if (scope != 0) {
+ [rec memoryBarrierWithScope:scope
+ afterStages:after_stage_flags
+ beforeStages:before_stage_flags];
+ }
+ }
+ }
+}
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Texture State Management
+ * \{ */
+
+void MTLStateManager::texture_unpack_row_length_set(uint len)
+{
+ /* Set source image row data stride when uploading image data to the GPU. */
+ MTLContext *ctx = static_cast<MTLContext *>(unwrap(GPU_context_active_get()));
+ ctx->pipeline_state.unpack_row_length = len;
+}
+
+void MTLStateManager::texture_bind(Texture *tex_, eGPUSamplerState sampler_type, int unit)
+{
+ BLI_assert(tex_);
+ gpu::MTLTexture *mtl_tex = static_cast<gpu::MTLTexture *>(tex_);
+ BLI_assert(mtl_tex);
+
+ MTLContext *ctx = static_cast<MTLContext *>(unwrap(GPU_context_active_get()));
+ if (unit >= 0) {
+ ctx->texture_bind(mtl_tex, unit);
+
+ /* Fetching textures default sampler configuration and applying
+ * eGPUSampler State on top. This path exists to support
+ * Any of the sampler state which is associated with the
+ * texture itself such as min/max mip levels. */
+ MTLSamplerState sampler = mtl_tex->get_sampler_state();
+ sampler.state = sampler_type;
+
+ ctx->sampler_bind(sampler, unit);
+ }
+}
+
+void MTLStateManager::texture_unbind(Texture *tex_)
+{
+ BLI_assert(tex_);
+ gpu::MTLTexture *mtl_tex = static_cast<gpu::MTLTexture *>(tex_);
+ BLI_assert(mtl_tex);
+ MTLContext *ctx = static_cast<MTLContext *>(unwrap(GPU_context_active_get()));
+ ctx->texture_unbind(mtl_tex);
+}
+
+void MTLStateManager::texture_unbind_all(void)
+{
+ MTLContext *ctx = static_cast<MTLContext *>(unwrap(GPU_context_active_get()));
+ BLI_assert(ctx);
+ ctx->texture_unbind_all();
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Image Binding (from image load store)
+ * \{ */
+
+void MTLStateManager::image_bind(Texture *tex_, int unit)
+{
+ this->texture_bind(tex_, GPU_SAMPLER_DEFAULT, unit);
+}
+
+void MTLStateManager::image_unbind(Texture *tex_)
+{
+ this->texture_unbind(tex_);
+}
+
+void MTLStateManager::image_unbind_all(void)
+{
+ this->texture_unbind_all();
+}
+
+/** \} */
+
+} // blender::gpu
diff --git a/source/blender/gpu/metal/mtl_texture.hh b/source/blender/gpu/metal/mtl_texture.hh
index 47f03a5777b..b4b1e91c496 100644
--- a/source/blender/gpu/metal/mtl_texture.hh
+++ b/source/blender/gpu/metal/mtl_texture.hh
@@ -47,16 +47,13 @@ struct TextureUpdateRoutineSpecialisation {
(component_count_input == other.component_count_input) &&
(component_count_output == other.component_count_output));
}
-};
-template<> struct blender::DefaultHash<TextureUpdateRoutineSpecialisation> {
- inline uint64_t operator()(const TextureUpdateRoutineSpecialisation &key) const
+ inline uint64_t hash() const
{
-
- DefaultHash<std::string> string_hasher;
+ blender::DefaultHash<std::string> string_hasher;
return (uint64_t)string_hasher(
- key.input_data_type + key.output_data_type +
- std::to_string((key.component_count_input << 8) + key.component_count_output));
+ this->input_data_type + this->output_data_type +
+ std::to_string((this->component_count_input << 8) + this->component_count_output));
}
};
@@ -78,12 +75,10 @@ struct DepthTextureUpdateRoutineSpecialisation {
{
return ((data_mode == other.data_mode));
}
-};
-template<> struct blender::DefaultHash<DepthTextureUpdateRoutineSpecialisation> {
- inline uint64_t operator()(const DepthTextureUpdateRoutineSpecialisation &key) const
+ inline uint64_t hash() const
{
- return (uint64_t)(key.data_mode);
+ return (uint64_t)(this->data_mode);
}
};
@@ -109,17 +104,14 @@ struct TextureReadRoutineSpecialisation {
(component_count_output == other.component_count_output) &&
(depth_format_mode == other.depth_format_mode));
}
-};
-template<> struct blender::DefaultHash<TextureReadRoutineSpecialisation> {
- inline uint64_t operator()(const TextureReadRoutineSpecialisation &key) const
+ inline uint64_t hash() const
{
-
- DefaultHash<std::string> string_hasher;
- return (uint64_t)string_hasher(key.input_data_type + key.output_data_type +
- std::to_string((key.component_count_input << 8) +
- key.component_count_output +
- (key.depth_format_mode << 28)));
+ blender::DefaultHash<std::string> string_hasher;
+ return (uint64_t)string_hasher(this->input_data_type + this->output_data_type +
+ std::to_string((this->component_count_input << 8) +
+ this->component_count_output +
+ (this->depth_format_mode << 28)));
}
};
@@ -158,21 +150,6 @@ typedef struct MTLSamplerState {
const MTLSamplerState DEFAULT_SAMPLER_STATE = {GPU_SAMPLER_DEFAULT /*, 0, 9999*/};
-} // namespace blender::gpu
-
-template<> struct blender::DefaultHash<blender::gpu::MTLSamplerState> {
- inline uint64_t operator()(const blender::gpu::MTLSamplerState &key) const
- {
- const DefaultHash<unsigned int> uint_hasher;
- uint64_t main_hash = (uint64_t)uint_hasher((unsigned int)(key.state));
-
- /* Hash other parameters as needed. */
- return main_hash;
- }
-};
-
-namespace blender::gpu {
-
class MTLTexture : public Texture {
friend class MTLContext;
friend class MTLStateManager;
@@ -372,7 +349,7 @@ class MTLTexture : public Texture {
* - Per-component size matches (e.g. GPU_DATA_UBYTE)
* OR GPU_DATA_10_11_11_REV && GPU_R11G11B10 (equiv)
* OR D24S8 and GPU_DATA_UINT_24_8
- * We can Use BLIT ENCODER.
+ * We can use BLIT ENCODER.
*
* OTHERWISE TRIGGER COMPUTE:
* - Compute sizes will vary. Threads per grid WILL match 'extent'.
diff --git a/source/blender/gpu/metal/mtl_texture.mm b/source/blender/gpu/metal/mtl_texture.mm
index 7ec3d390416..ca19d1f9e4b 100644
--- a/source/blender/gpu/metal/mtl_texture.mm
+++ b/source/blender/gpu/metal/mtl_texture.mm
@@ -1163,7 +1163,7 @@ void gpu::MTLTexture::mip_range_set(int min, int max)
{
BLI_assert(min <= max && min >= 0 && max <= mipmaps_);
- /* Note:
+ /* NOTE:
* - mip_min_ and mip_max_ are used to Clamp LODs during sampling.
* - Given functions like Framebuffer::recursive_downsample modifies the mip range
* between each layer, we do not want to be re-baking the texture.
diff --git a/source/blender/gpu/opengl/gl_backend.cc b/source/blender/gpu/opengl/gl_backend.cc
index 610fd5d980f..4869bff2737 100644
--- a/source/blender/gpu/opengl/gl_backend.cc
+++ b/source/blender/gpu/opengl/gl_backend.cc
@@ -10,8 +10,6 @@
#include "gpu_capabilities_private.hh"
#include "gpu_platform_private.hh"
-#include "glew-mx.h"
-
#include "gl_debug.hh"
#include "gl_backend.hh"
@@ -291,26 +289,12 @@ static void detect_workarounds()
}
/* See T82856: AMD drivers since 20.11 running on a polaris architecture doesn't support the
* `GL_INT_2_10_10_10_REV` data type correctly. This data type is used to pack normals and flags.
- * The work around uses `GPU_RGBA16I`.
+ * The work around uses `GPU_RGBA16I`. In 22.?.? drivers this has been fixed for
+ * polaris platform. Keeping legacy platforms around just in case.
*/
if (GPU_type_matches(GPU_DEVICE_ATI, GPU_OS_ANY, GPU_DRIVER_OFFICIAL)) {
- const Vector<std::string> matches = {"RX 460",
- "RX 470",
- "RX 480",
- "RX 490",
- "RX 560",
- "RX 560X",
- "RX 570",
- "RX 580",
- "RX 580X",
- "RX 590",
- "RX550/550",
- "(TM) 520",
- "(TM) 530",
- "(TM) 535",
- "R5",
- "R7",
- "R9"};
+ const Vector<std::string> matches = {
+ "RX550/550", "(TM) 520", "(TM) 530", "(TM) 535", "R5", "R7", "R9"};
if (match_renderer(renderer, matches)) {
GCaps.use_hq_normals_workaround = true;
@@ -419,6 +403,13 @@ static void detect_workarounds()
GCaps.shader_storage_buffer_objects_support = false;
}
+ /* Certain Intel/AMD based platforms don't clear the viewport textures. Always clearing leads to
+ * noticeable performance regressions on other platforms as well. */
+ if (GPU_type_matches(GPU_DEVICE_ANY, GPU_OS_MAC, GPU_DRIVER_ANY) ||
+ GPU_type_matches(GPU_DEVICE_INTEL, GPU_OS_ANY, GPU_DRIVER_ANY)) {
+ GCaps.clear_viewport_workaround = true;
+ }
+
/* Metal-related Workarounds. */
/* Minimum Per-Vertex stride is 1 byte for OpenGL. */
@@ -503,6 +494,7 @@ void GLBackend::capabilities_init()
glGetIntegeri_v(GL_MAX_COMPUTE_WORK_GROUP_SIZE, 2, &GCaps.max_work_group_size[2]);
glGetIntegerv(GL_MAX_SHADER_STORAGE_BUFFER_BINDINGS,
&GCaps.max_shader_storage_buffer_bindings);
+ glGetIntegerv(GL_MAX_COMPUTE_SHADER_STORAGE_BLOCKS, &GCaps.max_compute_shader_storage_blocks);
}
GCaps.shader_storage_buffer_objects_support = GLEW_ARB_shader_storage_buffer_object;
/* GL specific capabilities. */
diff --git a/source/blender/gpu/opengl/gl_batch.cc b/source/blender/gpu/opengl/gl_batch.cc
index e738413879e..fde2a53bb0f 100644
--- a/source/blender/gpu/opengl/gl_batch.cc
+++ b/source/blender/gpu/opengl/gl_batch.cc
@@ -11,12 +11,9 @@
#include "BLI_assert.h"
-#include "glew-mx.h"
-
#include "gpu_batch_private.hh"
#include "gpu_shader_private.hh"
-#include "gl_backend.hh"
#include "gl_context.hh"
#include "gl_debug.hh"
#include "gl_index_buffer.hh"
diff --git a/source/blender/gpu/opengl/gl_compute.cc b/source/blender/gpu/opengl/gl_compute.cc
index 2fbf23c227d..1f8bb69dc3a 100644
--- a/source/blender/gpu/opengl/gl_compute.cc
+++ b/source/blender/gpu/opengl/gl_compute.cc
@@ -8,8 +8,6 @@
#include "gl_debug.hh"
-#include "glew-mx.h"
-
namespace blender::gpu {
void GLCompute::dispatch(int group_x_len, int group_y_len, int group_z_len)
diff --git a/source/blender/gpu/opengl/gl_context.cc b/source/blender/gpu/opengl/gl_context.cc
index 72892ffcd34..f4f060821b0 100644
--- a/source/blender/gpu/opengl/gl_context.cc
+++ b/source/blender/gpu/opengl/gl_context.cc
@@ -6,7 +6,6 @@
*/
#include "BLI_assert.h"
-#include "BLI_system.h"
#include "BLI_utildefines.h"
#include "BKE_global.h"
diff --git a/source/blender/gpu/opengl/gl_debug.cc b/source/blender/gpu/opengl/gl_debug.cc
index a3288ff4cff..f82138e0d65 100644
--- a/source/blender/gpu/opengl/gl_debug.cc
+++ b/source/blender/gpu/opengl/gl_debug.cc
@@ -331,11 +331,21 @@ void object_label(GLenum type, GLuint object, const char *name)
char label[64];
SNPRINTF(label, "%s%s%s", to_str_prefix(type), name, to_str_suffix(type));
/* Small convenience for caller. */
- if (ELEM(type, GL_FRAGMENT_SHADER, GL_GEOMETRY_SHADER, GL_VERTEX_SHADER, GL_COMPUTE_SHADER)) {
- type = GL_SHADER;
- }
- if (ELEM(type, GL_UNIFORM_BUFFER)) {
- type = GL_BUFFER;
+ switch (type) {
+ case GL_FRAGMENT_SHADER:
+ case GL_GEOMETRY_SHADER:
+ case GL_VERTEX_SHADER:
+ case GL_COMPUTE_SHADER:
+ type = GL_SHADER;
+ break;
+ case GL_UNIFORM_BUFFER:
+ case GL_SHADER_STORAGE_BUFFER:
+ case GL_ARRAY_BUFFER:
+ case GL_ELEMENT_ARRAY_BUFFER:
+ type = GL_BUFFER;
+ break;
+ default:
+ break;
}
glObjectLabel(type, object, -1, label);
}
diff --git a/source/blender/gpu/opengl/gl_debug_layer.cc b/source/blender/gpu/opengl/gl_debug_layer.cc
index c02b6b26068..79d1b54828d 100644
--- a/source/blender/gpu/opengl/gl_debug_layer.cc
+++ b/source/blender/gpu/opengl/gl_debug_layer.cc
@@ -10,8 +10,6 @@
#include "BLI_utildefines.h"
-#include "glew-mx.h"
-
#include "gl_debug.hh"
using GPUvoidptr = void *;
diff --git a/source/blender/gpu/opengl/gl_drawlist.cc b/source/blender/gpu/opengl/gl_drawlist.cc
index 2f87c859273..fd76d8c58f8 100644
--- a/source/blender/gpu/opengl/gl_drawlist.cc
+++ b/source/blender/gpu/opengl/gl_drawlist.cc
@@ -11,9 +11,6 @@
#include "BLI_assert.h"
#include "GPU_batch.h"
-#include "GPU_capabilities.h"
-
-#include "glew-mx.h"
#include "gpu_context_private.hh"
#include "gpu_drawlist_private.hh"
diff --git a/source/blender/gpu/opengl/gl_framebuffer.cc b/source/blender/gpu/opengl/gl_framebuffer.cc
index 57eeabba0a0..bd9fba4250d 100644
--- a/source/blender/gpu/opengl/gl_framebuffer.cc
+++ b/source/blender/gpu/opengl/gl_framebuffer.cc
@@ -7,8 +7,6 @@
#include "BKE_global.h"
-#include "GPU_capabilities.h"
-
#include "gl_backend.hh"
#include "gl_debug.hh"
#include "gl_state.hh"
diff --git a/source/blender/gpu/opengl/gl_immediate.cc b/source/blender/gpu/opengl/gl_immediate.cc
index c32a6afd8cf..a332a2fbc7c 100644
--- a/source/blender/gpu/opengl/gl_immediate.cc
+++ b/source/blender/gpu/opengl/gl_immediate.cc
@@ -7,8 +7,6 @@
* Mimics old style opengl immediate mode drawing.
*/
-#include "BKE_global.h"
-
#include "gpu_context_private.hh"
#include "gpu_shader_private.hh"
#include "gpu_vertex_format_private.h"
diff --git a/source/blender/gpu/opengl/gl_index_buffer.cc b/source/blender/gpu/opengl/gl_index_buffer.cc
index 8cedb831272..566169182e3 100644
--- a/source/blender/gpu/opengl/gl_index_buffer.cc
+++ b/source/blender/gpu/opengl/gl_index_buffer.cc
@@ -6,7 +6,6 @@
*/
#include "gl_context.hh"
-#include "gl_debug.hh"
#include "gl_index_buffer.hh"
diff --git a/source/blender/gpu/opengl/gl_shader.cc b/source/blender/gpu/opengl/gl_shader.cc
index 957bc8b24be..ccdf10c1ed2 100644
--- a/source/blender/gpu/opengl/gl_shader.cc
+++ b/source/blender/gpu/opengl/gl_shader.cc
@@ -13,7 +13,6 @@
#include "GPU_capabilities.h"
#include "GPU_platform.h"
-#include "gl_backend.hh"
#include "gl_debug.hh"
#include "gl_vertex_buffer.hh"
@@ -613,7 +612,7 @@ std::string GLShader::fragment_interface_declare(const ShaderCreateInfo &info) c
if (info.early_fragment_test_) {
ss << "layout(early_fragment_tests) in;\n";
}
- if (GLEW_VERSION_4_2 || GLEW_ARB_conservative_depth) {
+ if (GLEW_ARB_conservative_depth) {
ss << "layout(" << to_string(info.depth_write_) << ") out float gl_FragDepth;\n";
}
ss << "\n/* Outputs. */\n";
@@ -836,7 +835,7 @@ static char *glsl_patch_default_get()
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_VERSION_4_2 && GLEW_ARB_conservative_depth) {
+ if (GLEW_ARB_conservative_depth) {
STR_CONCAT(patch, slen, "#extension GL_ARB_conservative_depth : enable\n");
}
if (GPU_shader_image_load_store_support()) {
@@ -876,7 +875,7 @@ static char *glsl_patch_default_get()
static char *glsl_patch_compute_get()
{
/** Used for shader patching. Init once. */
- static char patch[512] = "\0";
+ static char patch[2048] = "\0";
if (patch[0] != '\0') {
return patch;
}
@@ -889,6 +888,8 @@ static char *glsl_patch_compute_get()
/* Array compat. */
STR_CONCAT(patch, slen, "#define gpu_Array(_type) _type[]\n");
+ STR_CONCAT(patch, slen, datatoc_glsl_shader_defines_glsl);
+
BLI_assert(slen < sizeof(patch));
return patch;
}
diff --git a/source/blender/gpu/opengl/gl_shader_interface.cc b/source/blender/gpu/opengl/gl_shader_interface.cc
index f6a7eee80c3..1b3ab2941a8 100644
--- a/source/blender/gpu/opengl/gl_shader_interface.cc
+++ b/source/blender/gpu/opengl/gl_shader_interface.cc
@@ -9,7 +9,6 @@
#include "BLI_bitmap.h"
-#include "gl_backend.hh"
#include "gl_batch.hh"
#include "gl_context.hh"
diff --git a/source/blender/gpu/opengl/gl_state.cc b/source/blender/gpu/opengl/gl_state.cc
index 68a88938f69..8be4ac29af6 100644
--- a/source/blender/gpu/opengl/gl_state.cc
+++ b/source/blender/gpu/opengl/gl_state.cc
@@ -12,10 +12,7 @@
#include "GPU_capabilities.h"
-#include "glew-mx.h"
-
#include "gl_context.hh"
-#include "gl_debug.hh"
#include "gl_framebuffer.hh"
#include "gl_texture.hh"
diff --git a/source/blender/gpu/opengl/gl_storage_buffer.cc b/source/blender/gpu/opengl/gl_storage_buffer.cc
index 109bb65fcb7..4592adc3a61 100644
--- a/source/blender/gpu/opengl/gl_storage_buffer.cc
+++ b/source/blender/gpu/opengl/gl_storage_buffer.cc
@@ -5,8 +5,6 @@
* \ingroup gpu
*/
-#include "BKE_global.h"
-
#include "BLI_string.h"
#include "gpu_backend.hh"
@@ -144,6 +142,30 @@ void GLStorageBuf::clear(eGPUTextureFormat internal_format, eGPUDataFormat data_
}
}
+void GLStorageBuf::copy_sub(VertBuf *src_, uint dst_offset, uint src_offset, uint copy_size)
+{
+ GLVertBuf *src = static_cast<GLVertBuf *>(src_);
+ GLStorageBuf *dst = this;
+
+ if (dst->ssbo_id_ == 0) {
+ dst->init();
+ }
+ if (src->vbo_id_ == 0) {
+ src->bind();
+ }
+
+ if (GLContext::direct_state_access_support) {
+ glCopyNamedBufferSubData(src->vbo_id_, dst->ssbo_id_, src_offset, dst_offset, copy_size);
+ }
+ else {
+ /* This binds the buffer to GL_ARRAY_BUFFER and upload the data if any. */
+ src->bind();
+ glBindBuffer(GL_COPY_WRITE_BUFFER, dst->ssbo_id_);
+ glCopyBufferSubData(GL_ARRAY_BUFFER, GL_COPY_WRITE_BUFFER, src_offset, dst_offset, copy_size);
+ glBindBuffer(GL_COPY_WRITE_BUFFER, 0);
+ }
+}
+
/** \} */
} // namespace blender::gpu
diff --git a/source/blender/gpu/opengl/gl_storage_buffer.hh b/source/blender/gpu/opengl/gl_storage_buffer.hh
index c808a0bdda1..96052fe0065 100644
--- a/source/blender/gpu/opengl/gl_storage_buffer.hh
+++ b/source/blender/gpu/opengl/gl_storage_buffer.hh
@@ -36,6 +36,7 @@ class GLStorageBuf : public StorageBuf {
void bind(int slot) override;
void unbind() override;
void clear(eGPUTextureFormat internal_format, eGPUDataFormat data_format, void *data) override;
+ void copy_sub(VertBuf *src, uint dst_offset, uint src_offset, uint copy_size) override;
/* Special internal function to bind SSBOs to indirect argument targets. */
void bind_as(GLenum target);
diff --git a/source/blender/gpu/opengl/gl_texture.cc b/source/blender/gpu/opengl/gl_texture.cc
index 14f84273925..055c8d104e2 100644
--- a/source/blender/gpu/opengl/gl_texture.cc
+++ b/source/blender/gpu/opengl/gl_texture.cc
@@ -5,8 +5,6 @@
* \ingroup gpu
*/
-#include "BKE_global.h"
-
#include "DNA_userdef_types.h"
#include "GPU_capabilities.h"
diff --git a/source/blender/gpu/opengl/gl_texture.hh b/source/blender/gpu/opengl/gl_texture.hh
index 2dde8d6c86b..e5b879f1f15 100644
--- a/source/blender/gpu/opengl/gl_texture.hh
+++ b/source/blender/gpu/opengl/gl_texture.hh
@@ -363,7 +363,7 @@ inline GLenum to_gl_data_format(eGPUTextureFormat format)
}
/**
- * Assume Unorm / Float target. Used with #glReadPixels.
+ * Assume UNORM/Float target. Used with #glReadPixels.
*/
inline GLenum channel_len_to_gl(int channel_len)
{
diff --git a/source/blender/gpu/opengl/gl_uniform_buffer.cc b/source/blender/gpu/opengl/gl_uniform_buffer.cc
index b8bcaf0047e..e58cea9de43 100644
--- a/source/blender/gpu/opengl/gl_uniform_buffer.cc
+++ b/source/blender/gpu/opengl/gl_uniform_buffer.cc
@@ -5,14 +5,10 @@
* \ingroup gpu
*/
-#include "BKE_global.h"
-
#include "BLI_string.h"
-#include "gpu_backend.hh"
#include "gpu_context_private.hh"
-#include "gl_backend.hh"
#include "gl_debug.hh"
#include "gl_uniform_buffer.hh"
diff --git a/source/blender/gpu/opengl/gl_vertex_array.cc b/source/blender/gpu/opengl/gl_vertex_array.cc
index 04f60f10d41..a3299fc3325 100644
--- a/source/blender/gpu/opengl/gl_vertex_array.cc
+++ b/source/blender/gpu/opengl/gl_vertex_array.cc
@@ -7,7 +7,6 @@
#include "gpu_shader_interface.hh"
#include "gpu_vertex_buffer_private.hh"
-#include "gpu_vertex_format_private.h"
#include "gl_batch.hh"
#include "gl_context.hh"
@@ -39,8 +38,8 @@ static uint16_t vbo_bind(const ShaderInterface *interface,
const GPUVertAttr *a = &format->attrs[a_idx];
if (format->deinterleaved) {
- offset += ((a_idx == 0) ? 0 : format->attrs[a_idx - 1].sz) * v_len;
- stride = a->sz;
+ offset += ((a_idx == 0) ? 0 : format->attrs[a_idx - 1].size) * v_len;
+ stride = a->size;
}
else {
offset = a->offset;
diff --git a/source/blender/gpu/opengl/gl_vertex_buffer.cc b/source/blender/gpu/opengl/gl_vertex_buffer.cc
index a7a0c92431f..6942a220892 100644
--- a/source/blender/gpu/opengl/gl_vertex_buffer.cc
+++ b/source/blender/gpu/opengl/gl_vertex_buffer.cc
@@ -5,6 +5,8 @@
* \ingroup gpu
*/
+#include "GPU_texture.h"
+
#include "gl_context.hh"
#include "gl_vertex_buffer.hh"
@@ -38,6 +40,7 @@ void GLVertBuf::release_data()
}
if (vbo_id_ != 0) {
+ GPU_TEXTURE_FREE_SAFE(buffer_texture_);
GLContext::buf_free(vbo_id_);
vbo_id_ = 0;
memory_usage -= vbo_size_;
@@ -51,6 +54,7 @@ void GLVertBuf::duplicate_data(VertBuf *dst_)
BLI_assert(GLContext::get() != nullptr);
GLVertBuf *src = this;
GLVertBuf *dst = static_cast<GLVertBuf *>(dst_);
+ dst->buffer_texture_ = nullptr;
if (src->vbo_id_ != 0) {
dst->vbo_size_ = src->size_used_get();
@@ -111,6 +115,16 @@ void GLVertBuf::bind_as_ssbo(uint binding)
glBindBufferBase(GL_SHADER_STORAGE_BUFFER, binding, vbo_id_);
}
+void GLVertBuf::bind_as_texture(uint binding)
+{
+ bind();
+ BLI_assert(vbo_id_ != 0);
+ if (buffer_texture_ == nullptr) {
+ buffer_texture_ = GPU_texture_create_from_vertbuf("vertbuf_as_texture", wrap(this));
+ }
+ GPU_texture_bind(buffer_texture_, binding);
+}
+
const void *GLVertBuf::read() const
{
BLI_assert(is_active());
diff --git a/source/blender/gpu/opengl/gl_vertex_buffer.hh b/source/blender/gpu/opengl/gl_vertex_buffer.hh
index 4c29c17dcf7..e0a21587b60 100644
--- a/source/blender/gpu/opengl/gl_vertex_buffer.hh
+++ b/source/blender/gpu/opengl/gl_vertex_buffer.hh
@@ -11,18 +11,23 @@
#include "glew-mx.h"
+#include "GPU_texture.h"
+
#include "gpu_vertex_buffer_private.hh"
namespace blender {
namespace gpu {
class GLVertBuf : public VertBuf {
- friend class GLTexture; /* For buffer texture. */
- friend class GLShader; /* For transform feedback. */
+ friend class GLTexture; /* For buffer texture. */
+ friend class GLShader; /* For transform feedback. */
+ friend class GLStorageBuf; /* For sub copy. */
private:
/** OpenGL buffer handle. Init on first upload. Immutable after that. */
GLuint vbo_id_ = 0;
+ /** Texture used if the buffer is bound as buffer texture. Init on first use. */
+ struct ::GPUTexture *buffer_texture_ = nullptr;
/** 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;
@@ -46,6 +51,7 @@ class GLVertBuf : public VertBuf {
void upload_data() override;
void duplicate_data(VertBuf *dst) override;
void bind_as_ssbo(uint binding) override;
+ void bind_as_texture(uint binding) override;
private:
bool is_active() const;
diff --git a/source/blender/gpu/shaders/material/gpu_shader_material_color_ramp.glsl b/source/blender/gpu/shaders/common/gpu_shader_common_color_ramp.glsl
index 17240da4050..17240da4050 100644
--- a/source/blender/gpu/shaders/material/gpu_shader_material_color_ramp.glsl
+++ b/source/blender/gpu/shaders/common/gpu_shader_common_color_ramp.glsl
diff --git a/source/blender/gpu/shaders/material/gpu_shader_material_color_util.glsl b/source/blender/gpu/shaders/common/gpu_shader_common_color_utils.glsl
index fe89985ae7f..fe89985ae7f 100644
--- a/source/blender/gpu/shaders/material/gpu_shader_material_color_util.glsl
+++ b/source/blender/gpu/shaders/common/gpu_shader_common_color_utils.glsl
diff --git a/source/blender/gpu/shaders/common/gpu_shader_common_curves.glsl b/source/blender/gpu/shaders/common/gpu_shader_common_curves.glsl
new file mode 100644
index 00000000000..8948ed77557
--- /dev/null
+++ b/source/blender/gpu/shaders/common/gpu_shader_common_curves.glsl
@@ -0,0 +1,162 @@
+vec4 white_balance(vec4 color, vec4 black_level, vec4 white_level)
+{
+ vec4 range = max(white_level - black_level, vec4(1e-5f));
+ return (color - black_level) / range;
+}
+
+float extrapolate_if_needed(float parameter, float value, float start_slope, float end_slope)
+{
+ if (parameter < 0.0) {
+ return value + parameter * start_slope;
+ }
+
+ if (parameter > 1.0) {
+ return value + (parameter - 1.0) * end_slope;
+ }
+
+ return value;
+}
+
+/* Same as extrapolate_if_needed but vectorized. */
+vec3 extrapolate_if_needed(vec3 parameters, vec3 values, vec3 start_slopes, vec3 end_slopes)
+{
+ vec3 end_or_zero_slopes = mix(vec3(0.0), end_slopes, greaterThan(parameters, vec3(1.0)));
+ vec3 slopes = mix(end_or_zero_slopes, start_slopes, lessThan(parameters, vec3(0.0)));
+ parameters = parameters - mix(vec3(0.0), vec3(1.0), greaterThan(parameters, vec3(1.0)));
+ return values + parameters * slopes;
+}
+
+/* Curve maps are stored in sampler objects that are evaluated in the [0, 1] range, so normalize
+ * parameters accordingly. */
+#define NORMALIZE_PARAMETER(parameter, minimum, range) ((parameter - minimum) * range)
+
+void curves_combined_rgb(float factor,
+ vec4 color,
+ vec4 black_level,
+ vec4 white_level,
+ sampler1DArray curve_map,
+ const float layer,
+ vec4 range_minimums,
+ vec4 range_dividers,
+ vec4 start_slopes,
+ vec4 end_slopes,
+ out vec4 result)
+{
+ vec4 balanced = white_balance(color, black_level, white_level);
+
+ /* First, evaluate alpha curve map at all channels. The alpha curve is the Combined curve in the
+ * UI. */
+ vec3 parameters = NORMALIZE_PARAMETER(balanced.rgb, range_minimums.aaa, range_dividers.aaa);
+ result.r = texture(curve_map, vec2(parameters.x, layer)).a;
+ result.g = texture(curve_map, vec2(parameters.y, layer)).a;
+ result.b = texture(curve_map, vec2(parameters.z, layer)).a;
+
+ /* Then, extrapolate if needed. */
+ result.rgb = extrapolate_if_needed(parameters, result.rgb, start_slopes.aaa, end_slopes.aaa);
+
+ /* Then, evaluate each channel on its curve map. */
+ parameters = NORMALIZE_PARAMETER(result.rgb, range_minimums.rgb, range_dividers.rgb);
+ result.r = texture(curve_map, vec2(parameters.r, layer)).r;
+ result.g = texture(curve_map, vec2(parameters.g, layer)).g;
+ result.b = texture(curve_map, vec2(parameters.b, layer)).b;
+
+ /* Then, extrapolate again if needed. */
+ result.rgb = extrapolate_if_needed(parameters, result.rgb, start_slopes.rgb, end_slopes.rgb);
+ result.a = color.a;
+
+ result = mix(color, result, factor);
+}
+
+void curves_combined_only(float factor,
+ vec4 color,
+ vec4 black_level,
+ vec4 white_level,
+ sampler1DArray curve_map,
+ const float layer,
+ float range_minimum,
+ float range_divider,
+ float start_slope,
+ float end_slope,
+ out vec4 result)
+{
+ vec4 balanced = white_balance(color, black_level, white_level);
+
+ /* Evaluate alpha curve map at all channels. The alpha curve is the Combined curve in the
+ * UI. */
+ vec3 parameters = NORMALIZE_PARAMETER(balanced.rgb, range_minimum, range_divider);
+ result.r = texture(curve_map, vec2(parameters.x, layer)).a;
+ result.g = texture(curve_map, vec2(parameters.y, layer)).a;
+ result.b = texture(curve_map, vec2(parameters.z, layer)).a;
+
+ /* Then, extrapolate if needed. */
+ result.rgb = extrapolate_if_needed(parameters, result.rgb, vec3(start_slope), vec3(end_slope));
+ result.a = color.a;
+
+ result = mix(color, result, factor);
+}
+
+void curves_vector(vec3 vector,
+ sampler1DArray curve_map,
+ const float layer,
+ vec3 range_minimums,
+ vec3 range_dividers,
+ vec3 start_slopes,
+ vec3 end_slopes,
+ out vec3 result)
+{
+ /* Evaluate each component on its curve map. */
+ vec3 parameters = NORMALIZE_PARAMETER(vector, range_minimums, range_dividers);
+ result.x = texture(curve_map, vec2(parameters.x, layer)).x;
+ result.y = texture(curve_map, vec2(parameters.y, layer)).y;
+ result.z = texture(curve_map, vec2(parameters.z, layer)).z;
+
+ /* Then, extrapolate if needed. */
+ result = extrapolate_if_needed(parameters, result, start_slopes, end_slopes);
+}
+
+void curves_vector_mixed(float factor,
+ vec3 vector,
+ sampler1DArray curve_map,
+ const float layer,
+ vec3 range_minimums,
+ vec3 range_dividers,
+ vec3 start_slopes,
+ vec3 end_slopes,
+ out vec3 result)
+{
+ curves_vector(
+ vector, curve_map, layer, range_minimums, range_dividers, start_slopes, end_slopes, result);
+ result = mix(vector, result, factor);
+}
+
+void curves_float(float value,
+ sampler1DArray curve_map,
+ const float layer,
+ float range_minimum,
+ float range_divider,
+ float start_slope,
+ float end_slope,
+ out float result)
+{
+ /* Evaluate the normalized value on the first curve map. */
+ float parameter = NORMALIZE_PARAMETER(value, range_minimum, range_divider);
+ result = texture(curve_map, vec2(parameter, layer)).x;
+
+ /* Then, extrapolate if needed. */
+ result = extrapolate_if_needed(parameter, result, start_slope, end_slope);
+}
+
+void curves_float_mixed(float factor,
+ float value,
+ sampler1DArray curve_map,
+ const float layer,
+ float range_minimum,
+ float range_divider,
+ float start_slope,
+ float end_slope,
+ out float result)
+{
+ curves_float(
+ value, curve_map, layer, range_minimum, range_divider, start_slope, end_slope, result);
+ result = mix(value, result, factor);
+}
diff --git a/source/blender/gpu/shaders/material/gpu_shader_material_hash.glsl b/source/blender/gpu/shaders/common/gpu_shader_common_hash.glsl
index 32d61f06a65..32d61f06a65 100644
--- a/source/blender/gpu/shaders/material/gpu_shader_material_hash.glsl
+++ b/source/blender/gpu/shaders/common/gpu_shader_common_hash.glsl
diff --git a/source/blender/gpu/shaders/material/gpu_shader_material_math.glsl b/source/blender/gpu/shaders/common/gpu_shader_common_math.glsl
index 0948ce2c9fa..5f640f64056 100644
--- a/source/blender/gpu/shaders/material/gpu_shader_material_math.glsl
+++ b/source/blender/gpu/shaders/common/gpu_shader_common_math.glsl
@@ -1,4 +1,4 @@
-#pragma BLENDER_REQUIRE(gpu_shader_material_math_util.glsl)
+#pragma BLENDER_REQUIRE(gpu_shader_common_math_utils.glsl)
void math_add(float a, float b, float c, out float result)
{
diff --git a/source/blender/gpu/shaders/material/gpu_shader_material_math_util.glsl b/source/blender/gpu/shaders/common/gpu_shader_common_math_utils.glsl
index 91a8996939a..124654963fd 100644
--- a/source/blender/gpu/shaders/material/gpu_shader_material_math_util.glsl
+++ b/source/blender/gpu/shaders/common/gpu_shader_common_math_utils.glsl
@@ -139,75 +139,3 @@ mat3 euler_to_mat3(vec3 euler)
mat[2][2] = cy * cx;
return mat;
}
-
-void normal_transform_object_to_world(vec3 vin, out vec3 vout)
-{
- vout = normal_object_to_world(vin);
-}
-
-void normal_transform_world_to_object(vec3 vin, out vec3 vout)
-{
- vout = normal_world_to_object(vin);
-}
-
-void direction_transform_object_to_world(vec3 vin, out vec3 vout)
-{
- vout = transform_direction(ModelMatrix, vin);
-}
-
-void direction_transform_object_to_view(vec3 vin, out vec3 vout)
-{
- vout = transform_direction(ModelMatrix, vin);
- vout = transform_direction(ViewMatrix, vout);
-}
-
-void direction_transform_view_to_world(vec3 vin, out vec3 vout)
-{
- vout = transform_direction(ViewMatrixInverse, vin);
-}
-
-void direction_transform_view_to_object(vec3 vin, out vec3 vout)
-{
- vout = transform_direction(ViewMatrixInverse, vin);
- vout = transform_direction(ModelMatrixInverse, vout);
-}
-
-void direction_transform_world_to_view(vec3 vin, out vec3 vout)
-{
- vout = transform_direction(ViewMatrix, vin);
-}
-
-void direction_transform_world_to_object(vec3 vin, out vec3 vout)
-{
- vout = transform_direction(ModelMatrixInverse, vin);
-}
-
-void point_transform_object_to_world(vec3 vin, out vec3 vout)
-{
- vout = point_object_to_world(vin);
-}
-
-void point_transform_object_to_view(vec3 vin, out vec3 vout)
-{
- vout = point_object_to_view(vin);
-}
-
-void point_transform_view_to_world(vec3 vin, out vec3 vout)
-{
- vout = point_view_to_world(vin);
-}
-
-void point_transform_view_to_object(vec3 vin, out vec3 vout)
-{
- vout = point_view_to_object(vin);
-}
-
-void point_transform_world_to_view(vec3 vin, out vec3 vout)
-{
- vout = point_world_to_view(vin);
-}
-
-void point_transform_world_to_object(vec3 vin, out vec3 vout)
-{
- vout = point_world_to_object(vin);
-}
diff --git a/source/blender/gpu/shaders/material/gpu_shader_material_mix_rgb.glsl b/source/blender/gpu/shaders/common/gpu_shader_common_mix_rgb.glsl
index 157a6a27c15..f9652f1150b 100644
--- a/source/blender/gpu/shaders/material/gpu_shader_material_mix_rgb.glsl
+++ b/source/blender/gpu/shaders/common/gpu_shader_common_mix_rgb.glsl
@@ -1,4 +1,4 @@
-#pragma BLENDER_REQUIRE(gpu_shader_material_color_util.glsl)
+#pragma BLENDER_REQUIRE(gpu_shader_common_color_utils.glsl)
void mix_blend(float fac, vec4 col1, vec4 col2, out vec4 outcol)
{
diff --git a/source/blender/gpu/shaders/gpu_shader_codegen_lib.glsl b/source/blender/gpu/shaders/gpu_shader_codegen_lib.glsl
index 5c97eada77d..6091a5c834a 100644
--- a/source/blender/gpu/shaders/gpu_shader_codegen_lib.glsl
+++ b/source/blender/gpu/shaders/gpu_shader_codegen_lib.glsl
@@ -191,8 +191,8 @@ struct GlobalData {
vec3 N;
/** Geometric Normal. */
vec3 Ng;
- /** Surface default Tangent. */
- vec3 T;
+ /** Curve Tangent Space. */
+ vec3 curve_T, curve_B, curve_N;
/** Barycentric coordinates. */
vec2 barycentric_coords;
vec3 barycentric_dists;
diff --git a/source/blender/gpu/shaders/gpu_shader_common_obinfos_lib.glsl b/source/blender/gpu/shaders/gpu_shader_common_obinfos_lib.glsl
deleted file mode 100644
index f5b6de4899f..00000000000
--- a/source/blender/gpu/shaders/gpu_shader_common_obinfos_lib.glsl
+++ /dev/null
@@ -1,23 +0,0 @@
-
-#pragma BLENDER_REQUIRE(common_view_lib.glsl)
-
-#ifndef GPU_OBINFOS_UBO
-# define GPU_OBINFOS_UBO
-struct ObjectInfos {
- vec4 drw_OrcoTexCoFactors[2];
- vec4 drw_ObjectColor;
- 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)
-#endif
diff --git a/source/blender/gpu/shaders/gpu_shader_geometry.glsl b/source/blender/gpu/shaders/gpu_shader_geometry.glsl
deleted file mode 100644
index e0e899cfb35..00000000000
--- a/source/blender/gpu/shaders/gpu_shader_geometry.glsl
+++ /dev/null
@@ -1,93 +0,0 @@
-
-#define INTERP_FACE_VARYING_2(result, fvarOffset, tessCoord) \
- { \
- vec2 v[4]; \
- int primOffset = (gl_PrimitiveID + PrimitiveIdBase) * 4; \
- for (int i = 0; i < 4; i++) { \
- int index = (primOffset + i) * osd_fvar_count + fvarOffset; \
- v[i] = vec2(texelFetch(FVarDataBuffer, index).s, texelFetch(FVarDataBuffer, index + 1).s); \
- } \
- result = mix(mix(v[0], v[1], tessCoord.s), mix(v[3], v[2], tessCoord.s), tessCoord.t); \
- }
-
-#define INTERP_FACE_VARYING_ATT_2(result, fvarOffset, tessCoord) \
- { \
- vec2 tmp; \
- INTERP_FACE_VARYING_2(tmp, fvarOffset, tessCoord); \
- result = vec3(tmp, 0); \
- }
-
-out block
-{
- VertexData v;
-}
-outpt;
-
-void set_mtface_vertex_attrs(vec2 st);
-
-void emit_flat(int index, vec3 normal)
-{
- outpt.v.position = inpt[index].v.position;
- outpt.v.normal = normal;
-
- /* Compatibility */
- varnormal = outpt.v.normal;
- varposition = outpt.v.position.xyz;
-
- /* TODO(sergey): Only uniform subdivisions atm. */
- vec2 quadst[4] = vec2[](vec2(0, 0), vec2(1, 0), vec2(1, 1), vec2(0, 1));
- vec2 st = quadst[index];
-
- INTERP_FACE_VARYING_2(outpt.v.uv, osd_active_uv_offset, st);
-
- set_mtface_vertex_attrs(st);
-
- gl_Position = ProjectionMatrix * inpt[index].v.position;
- EmitVertex();
-}
-
-void emit_smooth(int index)
-{
- outpt.v.position = inpt[index].v.position;
- outpt.v.normal = inpt[index].v.normal;
-
- /* Compatibility */
- varnormal = outpt.v.normal;
- varposition = outpt.v.position.xyz;
-
- /* TODO(sergey): Only uniform subdivisions atm. */
- vec2 quadst[4] = vec2[](vec2(0, 0), vec2(1, 0), vec2(1, 1), vec2(0, 1));
- vec2 st = quadst[index];
-
- INTERP_FACE_VARYING_2(outpt.v.uv, osd_active_uv_offset, st);
-
- set_mtface_vertex_attrs(st);
-
- gl_Position = ProjectionMatrix * inpt[index].v.position;
- EmitVertex();
-}
-
-void main()
-{
- gl_PrimitiveID = gl_PrimitiveIDIn;
-
- if (osd_flat_shading) {
- vec3 A = (inpt[0].v.position - inpt[1].v.position).xyz;
- vec3 B = (inpt[3].v.position - inpt[1].v.position).xyz;
- vec3 flat_normal = normalize(cross(B, A));
- emit_flat(0, flat_normal);
- emit_flat(1, flat_normal);
- emit_flat(3, flat_normal);
- emit_flat(2, flat_normal);
- }
- else {
- emit_smooth(0);
- emit_smooth(1);
- emit_smooth(3);
- emit_smooth(2);
- }
- EndPrimitive();
-}
-
-void set_mtface_vertex_attrs(vec2 st)
-{
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 9b1e6fe9d23..522f6de169d 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
@@ -5,18 +5,6 @@
#define S3D_INTERLACE_COLUMN 1
#define S3D_INTERLACE_CHECKERBOARD 2
-/* 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)
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 4962fb01c88..b0da035ef09 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
@@ -5,7 +5,7 @@ void main()
float dist_squared = dot(centered, centered);
const float rad_squared = 0.25;
- // round point with jaggy edges
+ /* Round point with jaggy edges. */
if (dist_squared > rad_squared) {
discard;
}
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
index 4b2d59cc159..3cacd0f4b8d 100644
--- 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
@@ -9,8 +9,8 @@
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")
+ .fragment_out(0, Type::VEC4, "overlayColor")
+ .fragment_out(1, Type::VEC4, "imageColor")
.sampler(0, ImageType::FLOAT_2D, "imageTexture")
.sampler(1, ImageType::FLOAT_2D, "overlayTexture")
.push_constant(Type::MAT4, "ModelViewProjectionMatrix")
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
index e74e7df1a09..0a4da8d17fe 100644
--- 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
@@ -18,4 +18,5 @@ GPU_SHADER_CREATE_INFO(gpu_shader_3D_depth_only)
GPU_SHADER_CREATE_INFO(gpu_shader_3D_depth_only_clipped)
.additional_info("gpu_shader_3D_depth_only")
- .additional_info("gpu_clip_planes");
+ .additional_info("gpu_clip_planes")
+ .do_static_compilation(true);
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
index d23c8985a5d..17d865dbaea 100644
--- 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
@@ -21,4 +21,5 @@ GPU_SHADER_CREATE_INFO(gpu_shader_3D_flat_color)
GPU_SHADER_CREATE_INFO(gpu_shader_3D_flat_color_clipped)
.additional_info("gpu_shader_3D_flat_color")
- .additional_info("gpu_clip_planes");
+ .additional_info("gpu_clip_planes")
+ .do_static_compilation(true);
diff --git a/source/blender/gpu/shaders/infos/gpu_shader_3D_image_info.hh b/source/blender/gpu/shaders/infos/gpu_shader_3D_image_info.hh
new file mode 100644
index 00000000000..94cf58933af
--- /dev/null
+++ b/source/blender/gpu/shaders/infos/gpu_shader_3D_image_info.hh
@@ -0,0 +1,20 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later
+ * Copyright 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)
+ .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")
+ .sampler(0, ImageType::FLOAT_2D, "image")
+ .vertex_source("gpu_shader_3D_image_vert.glsl")
+ .fragment_source("gpu_shader_image_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
index 1f9c0056f7d..895787e4f1e 100644
--- a/source/blender/gpu/shaders/infos/gpu_shader_3D_point_info.hh
+++ b/source/blender/gpu/shaders/infos/gpu_shader_3D_point_info.hh
@@ -41,4 +41,5 @@ GPU_SHADER_CREATE_INFO(gpu_shader_3D_point_uniform_size_uniform_color_aa)
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");
+ .additional_info("gpu_clip_planes")
+ .do_static_compilation(true);
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
index 6840dfe25de..396ee64454c 100644
--- a/source/blender/gpu/shaders/infos/gpu_shader_3D_polyline_info.hh
+++ b/source/blender/gpu/shaders/infos/gpu_shader_3D_polyline_info.hh
@@ -37,7 +37,7 @@ GPU_SHADER_CREATE_INFO(gpu_shader_3D_polyline_uniform_color)
GPU_SHADER_CREATE_INFO(gpu_shader_3D_polyline_uniform_color_clipped)
.do_static_compilation(true)
- /* TODO(fclem): Put in an UBO to fit the 128byte requirement. */
+ /* TODO(fclem): Put in a UBO to fit the 128byte requirement. */
.push_constant(Type::MAT4, "ModelMatrix")
.push_constant(Type::VEC4, "ClipPlane")
.define("CLIP")
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
index a0c21a4ac7c..4cabe110999 100644
--- 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
@@ -21,4 +21,5 @@ GPU_SHADER_CREATE_INFO(gpu_shader_3D_smooth_color)
GPU_SHADER_CREATE_INFO(gpu_shader_3D_smooth_color_clipped)
.additional_info("gpu_shader_3D_smooth_color")
- .additional_info("gpu_clip_planes");
+ .additional_info("gpu_clip_planes")
+ .do_static_compilation(true);
diff --git a/source/blender/gpu/shaders/material/gpu_shader_material_add_shader.glsl b/source/blender/gpu/shaders/material/gpu_shader_material_add_shader.glsl
index 99117400c57..3f42b6d9094 100644
--- a/source/blender/gpu/shaders/material/gpu_shader_material_add_shader.glsl
+++ b/source/blender/gpu/shaders/material/gpu_shader_material_add_shader.glsl
@@ -1,4 +1,4 @@
-void node_add_shader(Closure shader1, Closure shader2, out Closure shader)
+void node_add_shader(inout Closure shader1, inout Closure shader2, out Closure shader)
{
shader = closure_add(shader1, shader2);
}
diff --git a/source/blender/gpu/shaders/material/gpu_shader_material_blackbody.glsl b/source/blender/gpu/shaders/material/gpu_shader_material_blackbody.glsl
index d0111aa3839..e257483f364 100644
--- a/source/blender/gpu/shaders/material/gpu_shader_material_blackbody.glsl
+++ b/source/blender/gpu/shaders/material/gpu_shader_material_blackbody.glsl
@@ -1,13 +1,5 @@
void node_blackbody(float temperature, sampler1DArray spectrummap, float layer, out vec4 color)
{
- if (temperature >= 12000.0) {
- color = vec4(0.826270103, 0.994478524, 1.56626022, 1.0);
- }
- else if (temperature < 965.0) {
- color = vec4(4.70366907, 0.0, 0.0, 1.0);
- }
- else {
- float t = (temperature - 965.0) / (12000.0 - 965.0);
- color = vec4(texture(spectrummap, vec2(t, layer)).rgb, 1.0);
- }
+ float t = (temperature - 800.0) / (12000.0 - 800.0);
+ color = vec4(texture(spectrummap, vec2(t, layer)).rgb, 1.0);
}
diff --git a/source/blender/gpu/shaders/material/gpu_shader_material_camera.glsl b/source/blender/gpu/shaders/material/gpu_shader_material_camera.glsl
index ff84a0a334c..b1a29833d77 100644
--- a/source/blender/gpu/shaders/material/gpu_shader_material_camera.glsl
+++ b/source/blender/gpu/shaders/material/gpu_shader_material_camera.glsl
@@ -1,6 +1,8 @@
void camera(out vec3 outview, out float outdepth, out float outdist)
{
- outdepth = abs(transform_point(ViewMatrix, g_data.P).z);
- outdist = distance(g_data.P, cameraPos);
- outview = normalize(g_data.P - cameraPos);
+ vec3 vP = transform_point(ViewMatrix, g_data.P);
+ vP.z = -vP.z;
+ outdepth = abs(vP.z);
+ outdist = length(vP);
+ outview = normalize(vP);
}
diff --git a/source/blender/gpu/shaders/material/gpu_shader_material_combine_color.glsl b/source/blender/gpu/shaders/material/gpu_shader_material_combine_color.glsl
index 3a250fcae8b..e68d0d98484 100644
--- a/source/blender/gpu/shaders/material/gpu_shader_material_combine_color.glsl
+++ b/source/blender/gpu/shaders/material/gpu_shader_material_combine_color.glsl
@@ -1,4 +1,4 @@
-#pragma BLENDER_REQUIRE(gpu_shader_material_color_util.glsl)
+#pragma BLENDER_REQUIRE(gpu_shader_common_color_utils.glsl)
void combine_color_rgb(float r, float g, float b, out vec4 col)
{
diff --git a/source/blender/gpu/shaders/material/gpu_shader_material_combine_hsv.glsl b/source/blender/gpu/shaders/material/gpu_shader_material_combine_hsv.glsl
index e8f444080b9..4d9e16afe66 100644
--- a/source/blender/gpu/shaders/material/gpu_shader_material_combine_hsv.glsl
+++ b/source/blender/gpu/shaders/material/gpu_shader_material_combine_hsv.glsl
@@ -1,4 +1,4 @@
-#pragma BLENDER_REQUIRE(gpu_shader_material_color_util.glsl)
+#pragma BLENDER_REQUIRE(gpu_shader_common_color_utils.glsl)
void combine_hsv(float h, float s, float v, out vec4 col)
{
diff --git a/source/blender/gpu/shaders/material/gpu_shader_material_eevee_specular.glsl b/source/blender/gpu/shaders/material/gpu_shader_material_eevee_specular.glsl
index c81880184e3..c95a41c58fc 100644
--- a/source/blender/gpu/shaders/material/gpu_shader_material_eevee_specular.glsl
+++ b/source/blender/gpu/shaders/material/gpu_shader_material_eevee_specular.glsl
@@ -34,6 +34,13 @@ void node_eevee_specular(vec4 diffuse,
diffuse_data.N = N;
diffuse_data.sss_id = 0u;
+ /* WORKAROUND: Nasty workaround to the current interface with the closure evaluation.
+ * Ideally the occlusion input should be move to the output node or removed all-together.
+ * This is temporary to avoid a regression in 3.2 and should be removed after EEVEE-Next rewrite.
+ */
+ diffuse_data.sss_radius.r = occlusion;
+ diffuse_data.sss_radius.g = -1.0; /* Flag */
+
ClosureReflection reflection_data;
reflection_data.weight = alpha;
if (true) {
@@ -41,7 +48,7 @@ void node_eevee_specular(vec4 diffuse,
vec2 split_sum = brdf_lut(NV, roughness);
vec3 brdf = F_brdf_single_scatter(specular.rgb, vec3(1.0), split_sum);
- reflection_data.color = specular.rgb * brdf;
+ reflection_data.color = brdf;
reflection_data.N = N;
reflection_data.roughness = roughness;
}
@@ -64,6 +71,8 @@ void node_eevee_specular(vec4 diffuse,
else {
result = closure_eval(diffuse_data, reflection_data);
}
- result = closure_add(result, closure_eval(emission_data));
- result = closure_add(result, closure_eval(transparency_data));
+ Closure emission_cl = closure_eval(emission_data);
+ Closure transparency_cl = closure_eval(transparency_data);
+ result = closure_add(result, emission_cl);
+ result = closure_add(result, transparency_cl);
}
diff --git a/source/blender/gpu/shaders/material/gpu_shader_material_float_curve.glsl b/source/blender/gpu/shaders/material/gpu_shader_material_float_curve.glsl
deleted file mode 100644
index 514409f7fdf..00000000000
--- a/source/blender/gpu/shaders/material/gpu_shader_material_float_curve.glsl
+++ /dev/null
@@ -1,33 +0,0 @@
-/* ext is vec4(in_x, in_dy, out_x, out_dy). */
-float curve_float_extrapolate(float x, float y, vec4 ext)
-{
- if (x < 0.0) {
- return y + x * ext.y;
- }
- else if (x > 1.0) {
- return y + (x - 1.0) * ext.w;
- }
- else {
- return y;
- }
-}
-
-#define RANGE_RESCALE(x, min, range) ((x - min) * range)
-
-void curve_float(float fac,
- float vec,
- sampler1DArray curvemap,
- float layer,
- float range,
- vec4 ext,
- out float outvec)
-{
- float xyz_min = ext.x;
- vec = RANGE_RESCALE(vec, xyz_min, range);
-
- outvec = texture(curvemap, vec2(vec, layer)).x;
-
- outvec = curve_float_extrapolate(vec, outvec, ext);
-
- outvec = mix(vec, outvec, fac);
-}
diff --git a/source/blender/gpu/shaders/material/gpu_shader_material_fractal_noise.glsl b/source/blender/gpu/shaders/material/gpu_shader_material_fractal_noise.glsl
index 7f502f74c0c..6d52e97cca1 100644
--- a/source/blender/gpu/shaders/material/gpu_shader_material_fractal_noise.glsl
+++ b/source/blender/gpu/shaders/material/gpu_shader_material_fractal_noise.glsl
@@ -1,4 +1,4 @@
-#pragma BLENDER_REQUIRE(gpu_shader_material_hash.glsl)
+#pragma BLENDER_REQUIRE(gpu_shader_common_hash.glsl)
#pragma BLENDER_REQUIRE(gpu_shader_material_noise.glsl)
/* The fractal_noise functions are all exactly the same except for the input type. */
diff --git a/source/blender/gpu/shaders/material/gpu_shader_material_gamma.glsl b/source/blender/gpu/shaders/material/gpu_shader_material_gamma.glsl
index 29fb09ceebd..64681cd795a 100644
--- a/source/blender/gpu/shaders/material/gpu_shader_material_gamma.glsl
+++ b/source/blender/gpu/shaders/material/gpu_shader_material_gamma.glsl
@@ -1,4 +1,4 @@
-#pragma BLENDER_REQUIRE(gpu_shader_material_math_util.glsl)
+#pragma BLENDER_REQUIRE(gpu_shader_common_math_utils.glsl)
void node_gamma(vec4 col, float gamma, out vec4 outcol)
{
diff --git a/source/blender/gpu/shaders/material/gpu_shader_material_geometry.glsl b/source/blender/gpu/shaders/material/gpu_shader_material_geometry.glsl
index 5e86a4577ee..fed7ac7df66 100644
--- a/source/blender/gpu/shaders/material/gpu_shader_material_geometry.glsl
+++ b/source/blender/gpu/shaders/material/gpu_shader_material_geometry.glsl
@@ -1,6 +1,6 @@
#pragma BLENDER_REQUIRE(gpu_shader_material_tangent.glsl)
-void node_geometry(vec3 orco,
+void node_geometry(vec3 orco_attr,
out vec3 position,
out vec3 normal,
out vec3 tangent,
@@ -18,11 +18,11 @@ void node_geometry(vec3 orco,
true_normal = g_data.Ng;
if (g_data.is_strand) {
- tangent = g_data.T;
+ tangent = g_data.curve_T;
}
else {
- tangent_orco_z(orco, orco);
- node_tangent(orco, tangent);
+ tangent_orco_z(orco_attr, orco_attr);
+ node_tangent(orco_attr, tangent);
}
parametric = vec3(g_data.barycentric_coords, 0.0);
diff --git a/source/blender/gpu/shaders/material/gpu_shader_material_hair.glsl b/source/blender/gpu/shaders/material/gpu_shader_material_hair.glsl
index 7bf8795495a..b24f9ab65f0 100644
--- a/source/blender/gpu/shaders/material/gpu_shader_material_hair.glsl
+++ b/source/blender/gpu/shaders/material/gpu_shader_material_hair.glsl
@@ -40,7 +40,7 @@ void node_bsdf_hair_principled(vec4 color,
hair_data.color = color.rgb;
hair_data.offset = offset;
hair_data.roughness = vec2(0.0);
- hair_data.T = g_data.T;
+ hair_data.T = g_data.curve_B;
result = closure_eval(hair_data);
}
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 a8b4b039370..61458b05c86 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,18 +1,18 @@
-#pragma BLENDER_REQUIRE(gpu_shader_material_hash.glsl)
+#pragma BLENDER_REQUIRE(gpu_shader_common_hash.glsl)
void node_hair_info(float hair_length,
out float is_strand,
out float intercept,
out float out_length,
out float thickness,
- out vec3 tangent,
+ out vec3 normal,
out float random)
{
is_strand = float(g_data.is_strand);
intercept = g_data.hair_time;
thickness = g_data.hair_thickness;
out_length = hair_length;
- tangent = g_data.T;
+ normal = g_data.curve_N;
/* TODO: could be precomputed per strand instead. */
random = wang_hash_noise(uint(g_data.hair_strand_id));
}
diff --git a/source/blender/gpu/shaders/material/gpu_shader_material_hue_sat_val.glsl b/source/blender/gpu/shaders/material/gpu_shader_material_hue_sat_val.glsl
index 30b808508e9..5223828e176 100644
--- a/source/blender/gpu/shaders/material/gpu_shader_material_hue_sat_val.glsl
+++ b/source/blender/gpu/shaders/material/gpu_shader_material_hue_sat_val.glsl
@@ -1,4 +1,4 @@
-#pragma BLENDER_REQUIRE(gpu_shader_material_color_util.glsl)
+#pragma BLENDER_REQUIRE(gpu_shader_common_color_utils.glsl)
void hue_sat(float hue, float sat, float value, float fac, vec4 col, out vec4 outcol)
{
diff --git a/source/blender/gpu/shaders/material/gpu_shader_material_map_range.glsl b/source/blender/gpu/shaders/material/gpu_shader_material_map_range.glsl
index 119ee3c0eaa..a81e6d36a55 100644
--- a/source/blender/gpu/shaders/material/gpu_shader_material_map_range.glsl
+++ b/source/blender/gpu/shaders/material/gpu_shader_material_map_range.glsl
@@ -1,4 +1,4 @@
-#pragma BLENDER_REQUIRE(gpu_shader_material_math_util.glsl)
+#pragma BLENDER_REQUIRE(gpu_shader_common_math_utils.glsl)
float smootherstep(float edge0, float edge1, float x)
{
diff --git a/source/blender/gpu/shaders/material/gpu_shader_material_mapping.glsl b/source/blender/gpu/shaders/material/gpu_shader_material_mapping.glsl
index 312c57231c5..b59257506c9 100644
--- a/source/blender/gpu/shaders/material/gpu_shader_material_mapping.glsl
+++ b/source/blender/gpu/shaders/material/gpu_shader_material_mapping.glsl
@@ -1,4 +1,4 @@
-#pragma BLENDER_REQUIRE(gpu_shader_material_math_util.glsl)
+#pragma BLENDER_REQUIRE(gpu_shader_common_math_utils.glsl)
void mapping_mat4(
vec3 vec, vec4 m0, vec4 m1, vec4 m2, vec4 m3, vec3 minvec, vec3 maxvec, out vec3 outvec)
diff --git a/source/blender/gpu/shaders/material/gpu_shader_material_mix_shader.glsl b/source/blender/gpu/shaders/material/gpu_shader_material_mix_shader.glsl
index c303d21d7c1..00cfba3ca12 100644
--- a/source/blender/gpu/shaders/material/gpu_shader_material_mix_shader.glsl
+++ b/source/blender/gpu/shaders/material/gpu_shader_material_mix_shader.glsl
@@ -1,4 +1,4 @@
-void node_mix_shader(float fac, Closure shader1, Closure shader2, out Closure shader)
+void node_mix_shader(float fac, inout Closure shader1, inout Closure shader2, out Closure shader)
{
shader = closure_mix(shader1, shader2, fac);
}
diff --git a/source/blender/gpu/shaders/material/gpu_shader_material_noise.glsl b/source/blender/gpu/shaders/material/gpu_shader_material_noise.glsl
index c84f34a834c..881e38ea11a 100644
--- a/source/blender/gpu/shaders/material/gpu_shader_material_noise.glsl
+++ b/source/blender/gpu/shaders/material/gpu_shader_material_noise.glsl
@@ -1,4 +1,4 @@
-#pragma BLENDER_REQUIRE(gpu_shader_material_hash.glsl)
+#pragma BLENDER_REQUIRE(gpu_shader_common_hash.glsl)
/* clang-format off */
#define FLOORFRAC(x, x_int, x_fract) { float x_floor = floor(x); x_int = int(x_floor); x_fract = x - x_floor; }
diff --git a/source/blender/gpu/shaders/material/gpu_shader_material_normal_map.glsl b/source/blender/gpu/shaders/material/gpu_shader_material_normal_map.glsl
index e219e2b9bbe..a54dc59ddfe 100644
--- a/source/blender/gpu/shaders/material/gpu_shader_material_normal_map.glsl
+++ b/source/blender/gpu/shaders/material/gpu_shader_material_normal_map.glsl
@@ -1,3 +1,5 @@
+
+#ifdef OBINFO_LIB
void node_normal_map(vec4 tangent, vec3 texnormal, out vec3 outnormal)
{
if (all(equal(tangent, vec4(0.0, 0.0, 0.0, 1.0)))) {
@@ -10,6 +12,7 @@ void node_normal_map(vec4 tangent, vec3 texnormal, out vec3 outnormal)
outnormal = texnormal.x * tangent.xyz + texnormal.y * B + texnormal.z * g_data.N;
outnormal = normalize(outnormal);
}
+#endif
void color_to_normal_new_shading(vec3 color, out vec3 normal)
{
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
index ad3d4737193..251103ae57c 100644
--- a/source/blender/gpu/shaders/material/gpu_shader_material_point_info.glsl
+++ b/source/blender/gpu/shaders/material/gpu_shader_material_point_info.glsl
@@ -1,4 +1,4 @@
-#pragma BLENDER_REQUIRE(gpu_shader_material_hash.glsl)
+#pragma BLENDER_REQUIRE(gpu_shader_common_hash.glsl)
void node_point_info(out vec3 position, out float radius, out float random)
{
diff --git a/source/blender/gpu/shaders/material/gpu_shader_material_principled.glsl b/source/blender/gpu/shaders/material/gpu_shader_material_principled.glsl
index 033dc05c57d..2e695fa3e14 100644
--- a/source/blender/gpu/shaders/material/gpu_shader_material_principled.glsl
+++ b/source/blender/gpu/shaders/material/gpu_shader_material_principled.glsl
@@ -169,6 +169,8 @@ void node_bsdf_principled(vec4 base_color,
/* Un-optimized case. */
result = closure_eval(diffuse_data, reflection_data, clearcoat_data, refraction_data);
}
- result = closure_add(result, closure_eval(emission_data));
- result = closure_add(result, closure_eval(transparency_data));
+ Closure emission_cl = closure_eval(emission_data);
+ Closure transparency_cl = closure_eval(transparency_data);
+ result = closure_add(result, emission_cl);
+ result = closure_add(result, transparency_cl);
}
diff --git a/source/blender/gpu/shaders/material/gpu_shader_material_rgb_curves.glsl b/source/blender/gpu/shaders/material/gpu_shader_material_rgb_curves.glsl
deleted file mode 100644
index 054fdddf7c3..00000000000
--- a/source/blender/gpu/shaders/material/gpu_shader_material_rgb_curves.glsl
+++ /dev/null
@@ -1,73 +0,0 @@
-/* ext is vec4(in_x, in_dy, out_x, out_dy). */
-float curve_extrapolate(float x, float y, vec4 ext)
-{
- if (x < 0.0) {
- return y + x * ext.y;
- }
- else if (x > 1.0) {
- return y + (x - 1.0) * ext.w;
- }
- else {
- return y;
- }
-}
-
-#define RANGE_RESCALE(x, min, range) ((x - min) * range)
-
-void curves_rgb(float fac,
- vec4 col,
- sampler1DArray curvemap,
- float layer,
- vec4 range,
- vec4 ext_r,
- vec4 ext_g,
- vec4 ext_b,
- vec4 ext_a,
- out vec4 outcol)
-{
- vec4 co = vec4(RANGE_RESCALE(col.rgb, ext_a.x, range.a), layer);
- vec3 samp;
- samp.r = texture(curvemap, co.xw).a;
- samp.g = texture(curvemap, co.yw).a;
- samp.b = texture(curvemap, co.zw).a;
-
- samp.r = curve_extrapolate(co.x, samp.r, ext_a);
- samp.g = curve_extrapolate(co.y, samp.g, ext_a);
- samp.b = curve_extrapolate(co.z, samp.b, ext_a);
-
- vec3 rgb_min = vec3(ext_r.x, ext_g.x, ext_b.x);
- co.xyz = RANGE_RESCALE(samp.rgb, rgb_min, range.rgb);
-
- samp.r = texture(curvemap, co.xw).r;
- samp.g = texture(curvemap, co.yw).g;
- samp.b = texture(curvemap, co.zw).b;
-
- outcol.r = curve_extrapolate(co.x, samp.r, ext_r);
- outcol.g = curve_extrapolate(co.y, samp.g, ext_g);
- outcol.b = curve_extrapolate(co.z, samp.b, ext_b);
- outcol.a = col.a;
-
- outcol = mix(col, outcol, fac);
-}
-
-void curves_rgb_opti(float fac,
- vec4 col,
- sampler1DArray curvemap,
- float layer,
- vec4 range,
- vec4 ext_a,
- out vec4 outcol)
-{
- vec4 co = vec4(RANGE_RESCALE(col.rgb, ext_a.x, range.a), layer);
- vec3 samp;
- samp.r = texture(curvemap, co.xw).a;
- samp.g = texture(curvemap, co.yw).a;
- samp.b = texture(curvemap, co.zw).a;
-
- outcol.r = curve_extrapolate(co.x, samp.r, ext_a);
- outcol.g = curve_extrapolate(co.y, samp.g, ext_a);
- outcol.b = curve_extrapolate(co.z, samp.b, ext_a);
- outcol.a = col.a;
-
- outcol = mix(col, outcol, fac);
-}
diff --git a/source/blender/gpu/shaders/material/gpu_shader_material_separate_color.glsl b/source/blender/gpu/shaders/material/gpu_shader_material_separate_color.glsl
index 7425e53ce7b..2dd51029cef 100644
--- a/source/blender/gpu/shaders/material/gpu_shader_material_separate_color.glsl
+++ b/source/blender/gpu/shaders/material/gpu_shader_material_separate_color.glsl
@@ -1,4 +1,4 @@
-#pragma BLENDER_REQUIRE(gpu_shader_material_color_util.glsl)
+#pragma BLENDER_REQUIRE(gpu_shader_common_color_utils.glsl)
void separate_color_rgb(vec4 col, out float r, out float g, out float b)
{
diff --git a/source/blender/gpu/shaders/material/gpu_shader_material_separate_hsv.glsl b/source/blender/gpu/shaders/material/gpu_shader_material_separate_hsv.glsl
index 180e0fd1940..8e475ec39a7 100644
--- a/source/blender/gpu/shaders/material/gpu_shader_material_separate_hsv.glsl
+++ b/source/blender/gpu/shaders/material/gpu_shader_material_separate_hsv.glsl
@@ -1,4 +1,4 @@
-#pragma BLENDER_REQUIRE(gpu_shader_material_color_util.glsl)
+#pragma BLENDER_REQUIRE(gpu_shader_common_color_utils.glsl)
void separate_hsv(vec4 col, out float h, out float s, out float v)
{
diff --git a/source/blender/gpu/shaders/material/gpu_shader_material_tex_brick.glsl b/source/blender/gpu/shaders/material/gpu_shader_material_tex_brick.glsl
index edc2fa32177..8d9773913ff 100644
--- a/source/blender/gpu/shaders/material/gpu_shader_material_tex_brick.glsl
+++ b/source/blender/gpu/shaders/material/gpu_shader_material_tex_brick.glsl
@@ -1,5 +1,5 @@
-#pragma BLENDER_REQUIRE(gpu_shader_material_math_util.glsl)
-#pragma BLENDER_REQUIRE(gpu_shader_material_hash.glsl)
+#pragma BLENDER_REQUIRE(gpu_shader_common_hash.glsl)
+#pragma BLENDER_REQUIRE(gpu_shader_common_math_utils.glsl)
vec2 calc_brick_texture(vec3 p,
float mortar_size,
diff --git a/source/blender/gpu/shaders/material/gpu_shader_material_tex_environment.glsl b/source/blender/gpu/shaders/material/gpu_shader_material_tex_environment.glsl
index da131978f72..cf7d6ae18e6 100644
--- a/source/blender/gpu/shaders/material/gpu_shader_material_tex_environment.glsl
+++ b/source/blender/gpu/shaders/material/gpu_shader_material_tex_environment.glsl
@@ -1,4 +1,4 @@
-#pragma BLENDER_REQUIRE(gpu_shader_material_math_util.glsl)
+#pragma BLENDER_REQUIRE(gpu_shader_common_math_utils.glsl)
void node_tex_environment_equirectangular(vec3 co, out vec3 uv)
{
diff --git a/source/blender/gpu/shaders/material/gpu_shader_material_tex_musgrave.glsl b/source/blender/gpu/shaders/material/gpu_shader_material_tex_musgrave.glsl
index 1552a2facc3..961fe23e67e 100644
--- a/source/blender/gpu/shaders/material/gpu_shader_material_tex_musgrave.glsl
+++ b/source/blender/gpu/shaders/material/gpu_shader_material_tex_musgrave.glsl
@@ -1,4 +1,4 @@
-#pragma BLENDER_REQUIRE(gpu_shader_material_hash.glsl)
+#pragma BLENDER_REQUIRE(gpu_shader_common_hash.glsl)
#pragma BLENDER_REQUIRE(gpu_shader_material_noise.glsl)
/* 1D Musgrave fBm
diff --git a/source/blender/gpu/shaders/material/gpu_shader_material_tex_noise.glsl b/source/blender/gpu/shaders/material/gpu_shader_material_tex_noise.glsl
index c90b2211dcf..3df6f7b29fb 100644
--- a/source/blender/gpu/shaders/material/gpu_shader_material_tex_noise.glsl
+++ b/source/blender/gpu/shaders/material/gpu_shader_material_tex_noise.glsl
@@ -1,4 +1,4 @@
-#pragma BLENDER_REQUIRE(gpu_shader_material_hash.glsl)
+#pragma BLENDER_REQUIRE(gpu_shader_common_hash.glsl)
#pragma BLENDER_REQUIRE(gpu_shader_material_noise.glsl)
#pragma BLENDER_REQUIRE(gpu_shader_material_fractal_noise.glsl)
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 dd12b602edf..0fb8ef15f5f 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
@@ -1,5 +1,5 @@
-#pragma BLENDER_REQUIRE(gpu_shader_material_hash.glsl)
-#pragma BLENDER_REQUIRE(gpu_shader_material_math_util.glsl)
+#pragma BLENDER_REQUIRE(gpu_shader_common_hash.glsl)
+#pragma BLENDER_REQUIRE(gpu_shader_common_math_utils.glsl)
/*
* Original code is under the MIT License, Copyright (c) 2013 Inigo Quilez.
diff --git a/source/blender/gpu/shaders/material/gpu_shader_material_tex_wave.glsl b/source/blender/gpu/shaders/material/gpu_shader_material_tex_wave.glsl
index eed98232d0b..c24a9417219 100644
--- a/source/blender/gpu/shaders/material/gpu_shader_material_tex_wave.glsl
+++ b/source/blender/gpu/shaders/material/gpu_shader_material_tex_wave.glsl
@@ -1,4 +1,4 @@
-#pragma BLENDER_REQUIRE(gpu_shader_material_hash.glsl)
+#pragma BLENDER_REQUIRE(gpu_shader_common_hash.glsl)
#pragma BLENDER_REQUIRE(gpu_shader_material_noise.glsl)
#pragma BLENDER_REQUIRE(gpu_shader_material_fractal_noise.glsl)
diff --git a/source/blender/gpu/shaders/material/gpu_shader_material_tex_white_noise.glsl b/source/blender/gpu/shaders/material/gpu_shader_material_tex_white_noise.glsl
index 030b58f0736..c5081372aa4 100644
--- a/source/blender/gpu/shaders/material/gpu_shader_material_tex_white_noise.glsl
+++ b/source/blender/gpu/shaders/material/gpu_shader_material_tex_white_noise.glsl
@@ -1,4 +1,4 @@
-#pragma BLENDER_REQUIRE(gpu_shader_material_hash.glsl)
+#pragma BLENDER_REQUIRE(gpu_shader_common_hash.glsl)
/* White Noise */
diff --git a/source/blender/gpu/shaders/material/gpu_shader_material_transform_utils.glsl b/source/blender/gpu/shaders/material/gpu_shader_material_transform_utils.glsl
new file mode 100644
index 00000000000..87048e5c5d6
--- /dev/null
+++ b/source/blender/gpu/shaders/material/gpu_shader_material_transform_utils.glsl
@@ -0,0 +1,71 @@
+void normal_transform_object_to_world(vec3 vin, out vec3 vout)
+{
+ vout = normal_object_to_world(vin);
+}
+
+void normal_transform_world_to_object(vec3 vin, out vec3 vout)
+{
+ vout = normal_world_to_object(vin);
+}
+
+void direction_transform_object_to_world(vec3 vin, out vec3 vout)
+{
+ vout = transform_direction(ModelMatrix, vin);
+}
+
+void direction_transform_object_to_view(vec3 vin, out vec3 vout)
+{
+ vout = transform_direction(ModelMatrix, vin);
+ vout = transform_direction(ViewMatrix, vout);
+}
+
+void direction_transform_view_to_world(vec3 vin, out vec3 vout)
+{
+ vout = transform_direction(ViewMatrixInverse, vin);
+}
+
+void direction_transform_view_to_object(vec3 vin, out vec3 vout)
+{
+ vout = transform_direction(ViewMatrixInverse, vin);
+ vout = transform_direction(ModelMatrixInverse, vout);
+}
+
+void direction_transform_world_to_view(vec3 vin, out vec3 vout)
+{
+ vout = transform_direction(ViewMatrix, vin);
+}
+
+void direction_transform_world_to_object(vec3 vin, out vec3 vout)
+{
+ vout = transform_direction(ModelMatrixInverse, vin);
+}
+
+void point_transform_object_to_world(vec3 vin, out vec3 vout)
+{
+ vout = point_object_to_world(vin);
+}
+
+void point_transform_object_to_view(vec3 vin, out vec3 vout)
+{
+ vout = point_object_to_view(vin);
+}
+
+void point_transform_view_to_world(vec3 vin, out vec3 vout)
+{
+ vout = point_view_to_world(vin);
+}
+
+void point_transform_view_to_object(vec3 vin, out vec3 vout)
+{
+ vout = point_view_to_object(vin);
+}
+
+void point_transform_world_to_view(vec3 vin, out vec3 vout)
+{
+ vout = point_world_to_view(vin);
+}
+
+void point_transform_world_to_object(vec3 vin, out vec3 vout)
+{
+ vout = point_world_to_object(vin);
+}
diff --git a/source/blender/gpu/shaders/material/gpu_shader_material_vector_curves.glsl b/source/blender/gpu/shaders/material/gpu_shader_material_vector_curves.glsl
deleted file mode 100644
index f6dec1b24e2..00000000000
--- a/source/blender/gpu/shaders/material/gpu_shader_material_vector_curves.glsl
+++ /dev/null
@@ -1,41 +0,0 @@
-/* ext is vec4(in_x, in_dy, out_x, out_dy). */
-float curve_vec_extrapolate(float x, float y, vec4 ext)
-{
- if (x < 0.0) {
- return y + x * ext.y;
- }
- else if (x > 1.0) {
- return y + (x - 1.0) * ext.w;
- }
- else {
- return y;
- }
-}
-
-#define RANGE_RESCALE(x, min, range) ((x - min) * range)
-
-void curves_vec(float fac,
- vec3 vec,
- sampler1DArray curvemap,
- float layer,
- vec3 range,
- vec4 ext_x,
- vec4 ext_y,
- vec4 ext_z,
- out vec3 outvec)
-{
- vec4 co = vec4(vec, layer);
-
- vec3 xyz_min = vec3(ext_x.x, ext_y.x, ext_z.x);
- co.xyz = RANGE_RESCALE(co.xyz, xyz_min, range);
-
- outvec.x = texture(curvemap, co.xw).x;
- outvec.y = texture(curvemap, co.yw).y;
- outvec.z = texture(curvemap, co.zw).z;
-
- outvec.x = curve_vec_extrapolate(co.x, outvec.r, ext_x);
- outvec.y = curve_vec_extrapolate(co.y, outvec.g, ext_y);
- outvec.z = curve_vec_extrapolate(co.z, outvec.b, ext_z);
-
- outvec = mix(vec, outvec, fac);
-}
diff --git a/source/blender/gpu/shaders/material/gpu_shader_material_vector_math.glsl b/source/blender/gpu/shaders/material/gpu_shader_material_vector_math.glsl
index 8f6bf17f195..018784c42a5 100644
--- a/source/blender/gpu/shaders/material/gpu_shader_material_vector_math.glsl
+++ b/source/blender/gpu/shaders/material/gpu_shader_material_vector_math.glsl
@@ -1,4 +1,4 @@
-#pragma BLENDER_REQUIRE(gpu_shader_material_math_util.glsl)
+#pragma BLENDER_REQUIRE(gpu_shader_common_math_utils.glsl)
void vector_math_add(vec3 a, vec3 b, vec3 c, float scale, out vec3 outVector, out float outValue)
{
diff --git a/source/blender/gpu/shaders/material/gpu_shader_material_vector_rotate.glsl b/source/blender/gpu/shaders/material/gpu_shader_material_vector_rotate.glsl
index ff0fb1c0418..8f7bd26ca18 100644
--- a/source/blender/gpu/shaders/material/gpu_shader_material_vector_rotate.glsl
+++ b/source/blender/gpu/shaders/material/gpu_shader_material_vector_rotate.glsl
@@ -1,4 +1,4 @@
-#pragma BLENDER_REQUIRE(gpu_shader_material_math_util.glsl)
+#pragma BLENDER_REQUIRE(gpu_shader_common_math_utils.glsl)
vec3 rotate_around_axis(vec3 p, vec3 axis, float angle)
{
diff --git a/source/blender/gpu/shaders/material/gpu_shader_material_wavelength.glsl b/source/blender/gpu/shaders/material/gpu_shader_material_wavelength.glsl
index 2c5d38eabbe..48d627dcd0b 100644
--- a/source/blender/gpu/shaders/material/gpu_shader_material_wavelength.glsl
+++ b/source/blender/gpu/shaders/material/gpu_shader_material_wavelength.glsl
@@ -1,15 +1,7 @@
-void node_wavelength(float wavelength,
- sampler1DArray spectrummap,
- float layer,
- vec3 xyz_to_r,
- vec3 xyz_to_g,
- vec3 xyz_to_b,
- out vec4 color)
+void node_wavelength(float wavelength, sampler1DArray spectrummap, float layer, out vec4 color)
{
- mat3 xyz_to_rgb = mat3(xyz_to_r, xyz_to_g, xyz_to_b);
float t = (wavelength - 380.0) / (780.0 - 380.0);
- vec3 xyz = texture(spectrummap, vec2(t, layer)).rgb;
- vec3 rgb = xyz * xyz_to_rgb;
+ vec3 rgb = texture(spectrummap, vec2(t, layer)).rgb;
rgb *= 1.0 / 2.52; /* Empirical scale from lg to make all comps <= 1. */
color = vec4(clamp(rgb, 0.0, 1.0), 1.0);
}
diff --git a/source/blender/gpu/tests/gpu_shader_builtin_test.cc b/source/blender/gpu/tests/gpu_shader_builtin_test.cc
index 6ef8a032a73..5dc70a8bf0f 100644
--- a/source/blender/gpu/tests/gpu_shader_builtin_test.cc
+++ b/source/blender/gpu/tests/gpu_shader_builtin_test.cc
@@ -35,6 +35,7 @@ static void test_shader_builtin()
test_compile_builtin_shader(GPU_SHADER_2D_UNIFORM_COLOR, GPU_SHADER_CFG_DEFAULT);
test_compile_builtin_shader(GPU_SHADER_2D_FLAT_COLOR, GPU_SHADER_CFG_DEFAULT);
test_compile_builtin_shader(GPU_SHADER_2D_SMOOTH_COLOR, GPU_SHADER_CFG_DEFAULT);
+ test_compile_builtin_shader(GPU_SHADER_3D_IMAGE, GPU_SHADER_CFG_DEFAULT);
test_compile_builtin_shader(GPU_SHADER_2D_IMAGE, GPU_SHADER_CFG_DEFAULT);
test_compile_builtin_shader(GPU_SHADER_2D_IMAGE_COLOR, GPU_SHADER_CFG_DEFAULT);
test_compile_builtin_shader(GPU_SHADER_2D_IMAGE_DESATURATE_COLOR, GPU_SHADER_CFG_DEFAULT);
diff --git a/source/blender/imbuf/CMakeLists.txt b/source/blender/imbuf/CMakeLists.txt
index e46326467cc..1309e3810be 100644
--- a/source/blender/imbuf/CMakeLists.txt
+++ b/source/blender/imbuf/CMakeLists.txt
@@ -178,13 +178,13 @@ if(WITH_IMAGE_WEBP)
list(APPEND SRC
intern/webp.c
)
- list(APPEND INC_SYS
- ${WEBP_INCLUDE_DIRS}
- )
+ list(APPEND INC_SYS
+ ${WEBP_INCLUDE_DIRS}
+ )
list(APPEND LIB
${WEBP_LIBRARIES}
)
- add_definitions(-DWITH_WEBP)
+ add_definitions(-DWITH_WEBP)
endif()
list(APPEND INC
diff --git a/source/blender/imbuf/IMB_colormanagement.h b/source/blender/imbuf/IMB_colormanagement.h
index 97030d44047..2f0d2f9b449 100644
--- a/source/blender/imbuf/IMB_colormanagement.h
+++ b/source/blender/imbuf/IMB_colormanagement.h
@@ -54,6 +54,7 @@ bool IMB_colormanagement_space_is_scene_linear(struct ColorSpace *colorspace);
bool IMB_colormanagement_space_is_srgb(struct ColorSpace *colorspace);
bool IMB_colormanagement_space_name_is_data(const char *name);
bool IMB_colormanagement_space_name_is_scene_linear(const char *name);
+bool IMB_colormanagement_space_name_is_srgb(const char *name);
/**
* Convert a float RGB triplet to the correct luminance weighted average.
@@ -71,9 +72,21 @@ BLI_INLINE float IMB_colormanagement_get_luminance(const float rgb[3]);
* Byte equivalent of #IMB_colormanagement_get_luminance().
*/
BLI_INLINE unsigned char IMB_colormanagement_get_luminance_byte(const unsigned char[3]);
-BLI_INLINE void IMB_colormanagement_xyz_to_rgb(float rgb[3], const float xyz[3]);
-BLI_INLINE void IMB_colormanagement_rgb_to_xyz(float xyz[3], const float rgb[3]);
-const float *IMB_colormanagement_get_xyz_to_rgb(void);
+
+/**
+ * Conversion between scene linear and other color spaces.
+ */
+BLI_INLINE void IMB_colormanagement_xyz_to_scene_linear(float scene_linear[3], const float xyz[3]);
+BLI_INLINE void IMB_colormanagement_scene_linear_to_xyz(float xyz[3], const float scene_linear[3]);
+BLI_INLINE void IMB_colormanagement_rec709_to_scene_linear(float scene_linear[3],
+ const float rec709[3]);
+BLI_INLINE void IMB_colormanagement_scene_linear_to_rec709(float rec709[3],
+ const float scene_linear[3]);
+BLI_INLINE void IMB_colormanagement_aces_to_scene_linear(float scene_linear[3],
+ const float aces[3]);
+BLI_INLINE void IMB_colormanagement_scene_linear_to_aces(float aces[3],
+ const float scene_linear[3]);
+const float *IMB_colormanagement_get_xyz_to_scene_linear(void);
/** \} */
@@ -168,7 +181,6 @@ void IMB_colormanagement_imbuf_to_byte_texture(unsigned char *out_buffer,
int width,
int height,
const struct ImBuf *ibuf,
- bool compress_as_srgb,
bool store_premultiplied);
void IMB_colormanagement_imbuf_to_float_texture(float *out_buffer,
int offset_x,
@@ -187,15 +199,19 @@ void IMB_colormanagement_imbuf_to_float_texture(float *out_buffer,
* - Color picking values 0..1 map to scene linear values in the 0..1 range,
* so that picked albedo values are energy conserving.
*/
-void IMB_colormanagement_scene_linear_to_color_picking_v3(float pixel[3]);
-void IMB_colormanagement_color_picking_to_scene_linear_v3(float pixel[3]);
+void IMB_colormanagement_scene_linear_to_color_picking_v3(float color_picking[3],
+ const float scene_linear[3]);
+void IMB_colormanagement_color_picking_to_scene_linear_v3(float scene_linear[3],
+ const float color_picking[3]);
/**
* Conversion between sRGB, for rare cases like hex color or copy/pasting
* between UI theme and scene linear colors.
*/
-void IMB_colormanagement_scene_linear_to_srgb_v3(float pixel[3]);
-void IMB_colormanagement_srgb_to_scene_linear_v3(float pixel[3]);
+BLI_INLINE void IMB_colormanagement_scene_linear_to_srgb_v3(float srgb[3],
+ const float scene_linear[3]);
+BLI_INLINE void IMB_colormanagement_srgb_to_scene_linear_v3(float scene_linear[3],
+ const float srgb[3]);
/**
* Convert pixel from scene linear to display space using default view
@@ -497,6 +513,18 @@ enum {
/** \} */
+/* -------------------------------------------------------------------- */
+/** \name Rendering Tables
+ * \{ */
+
+void IMB_colormanagement_blackbody_temperature_to_rgb_table(float *r_table,
+ int width,
+ float min,
+ float max);
+void IMB_colormanagement_wavelength_to_rgb_table(float *r_table, int width);
+
+/** \} */
+
#ifdef __cplusplus
}
#endif
diff --git a/source/blender/imbuf/IMB_imbuf.h b/source/blender/imbuf/IMB_imbuf.h
index 8796c99629e..20c414bb1ad 100644
--- a/source/blender/imbuf/IMB_imbuf.h
+++ b/source/blender/imbuf/IMB_imbuf.h
@@ -530,7 +530,6 @@ 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(bool isfloat, struct ImBuf *ibuf);
/**
*
@@ -554,12 +553,6 @@ bool IMB_isanim(const char *filepath);
int imb_get_anim_type(const char *filepath);
/**
- *
- * \attention Defined in util.c
- */
-bool IMB_isfloat(const struct ImBuf *ibuf);
-
-/**
* Test if color-space conversions of pixels in buffer need to take into account alpha.
*/
bool IMB_alpha_affects_rgb(const struct ImBuf *ibuf);
@@ -943,8 +936,7 @@ const char *IMB_ffmpeg_last_error(void);
struct GPUTexture *IMB_create_gpu_texture(const char *name,
struct ImBuf *ibuf,
bool use_high_bitdepth,
- bool use_premult,
- bool limit_gl_texture_size);
+ bool use_premult);
/**
* The `ibuf` is only here to detect the storage type. The produced texture will have undefined
* content. It will need to be populated by using #IMB_update_gpu_texture_sub().
diff --git a/source/blender/imbuf/IMB_imbuf_types.h b/source/blender/imbuf/IMB_imbuf_types.h
index 934163846e4..1b32bef0a98 100644
--- a/source/blender/imbuf/IMB_imbuf_types.h
+++ b/source/blender/imbuf/IMB_imbuf_types.h
@@ -41,13 +41,12 @@ typedef struct DDSData {
/**
* \ingroup imbuf
- * This is the abstraction of an image. ImBuf is the basic type used for all
- * imbuf operations.
+ * This is the abstraction of an image. ImBuf is the basic type used for all imbuf operations.
*
* Also; add new variables to the end to save pain!
*/
-/* Warning: Keep explicit value assignments here,
+/* WARNING: Keep explicit value assignments here,
* this file is included in areas where not all format defines are set
* (e.g. intern/dds only get WITH_DDS, even if TIFF, HDR etc are also defined).
* See T46524. */
@@ -176,7 +175,7 @@ typedef struct ImBuf {
* avoid problems and use int. - campbell */
int x, y;
- /** Active amount of bits/bitplanes */
+ /** Active amount of bits/bit-planes. */
unsigned char planes;
/** Number of channels in `rect_float` (0 = 4 channel default) */
int channels;
@@ -276,7 +275,7 @@ typedef struct ImBuf {
} ImBuf;
/**
- * \brief userflags: Flags used internally by blender for imagebuffers
+ * \brief userflags: Flags used internally by blender for image-buffers.
*/
enum {
diff --git a/source/blender/imbuf/IMB_thumbs.h b/source/blender/imbuf/IMB_thumbs.h
index 623a3b2b5f4..b55a6f653b8 100644
--- a/source/blender/imbuf/IMB_thumbs.h
+++ b/source/blender/imbuf/IMB_thumbs.h
@@ -50,7 +50,7 @@ typedef enum ThumbSource {
/**
* Create thumbnail for file and returns new imbuf for thumbnail.
*/
-struct ImBuf *IMB_thumb_create(const char *path,
+struct ImBuf *IMB_thumb_create(const char *filepath,
ThumbSize size,
ThumbSource source,
struct ImBuf *img);
@@ -58,17 +58,17 @@ struct ImBuf *IMB_thumb_create(const char *path,
/**
* Read thumbnail for file and returns new imbuf for thumbnail.
*/
-struct ImBuf *IMB_thumb_read(const char *path, ThumbSize size);
+struct ImBuf *IMB_thumb_read(const char *filepath, ThumbSize size);
/**
* Delete all thumbs for the file.
*/
-void IMB_thumb_delete(const char *path, ThumbSize size);
+void IMB_thumb_delete(const char *filepath, ThumbSize size);
/**
* Create the thumb if necessary and manage failed and old thumbs.
*/
-struct ImBuf *IMB_thumb_manage(const char *path, ThumbSize size, ThumbSource source);
+struct ImBuf *IMB_thumb_manage(const char *filepath, ThumbSize size, ThumbSource source);
/**
* Create the necessary directories to store the thumbnails.
@@ -85,7 +85,7 @@ struct ImBuf *IMB_thumb_load_blend(const char *blen_path,
/**
* Special function for previewing fonts.
*/
-struct ImBuf *IMB_thumb_load_font(const char *filename, unsigned int x, unsigned int y);
+struct ImBuf *IMB_thumb_load_font(const char *filepath, unsigned int x, unsigned int y);
bool IMB_thumb_load_font_get_hash(char *r_hash);
void IMB_thumb_clear_translations(void);
void IMB_thumb_ensure_translations(void);
diff --git a/source/blender/imbuf/intern/IMB_colormanagement_intern.h b/source/blender/imbuf/intern/IMB_colormanagement_intern.h
index c89b15480a2..23b3f0191b7 100644
--- a/source/blender/imbuf/intern/IMB_colormanagement_intern.h
+++ b/source/blender/imbuf/intern/IMB_colormanagement_intern.h
@@ -18,8 +18,12 @@ struct ImBuf;
struct OCIO_ConstCPUProcessorRcPtr;
extern float imbuf_luma_coefficients[3];
-extern float imbuf_xyz_to_rgb[3][3];
-extern float imbuf_rgb_to_xyz[3][3];
+extern float imbuf_scene_linear_to_xyz[3][3];
+extern float imbuf_xyz_to_scene_linear[3][3];
+extern float imbuf_scene_linear_to_aces[3][3];
+extern float imbuf_aces_to_scene_linear[3][3];
+extern float imbuf_scene_linear_to_rec709[3][3];
+extern float imbuf_rec709_to_scene_linear[3][3];
#define MAX_COLORSPACE_NAME 64
#define MAX_COLORSPACE_DESCRIPTION 512
diff --git a/source/blender/imbuf/intern/IMB_filetype.h b/source/blender/imbuf/intern/IMB_filetype.h
index 67d1aefeacb..9a0a6998fab 100644
--- a/source/blender/imbuf/intern/IMB_filetype.h
+++ b/source/blender/imbuf/intern/IMB_filetype.h
@@ -42,8 +42,8 @@ typedef struct ImFileType {
* dimensions of the full-size image in r_width & r_height.
*/
struct ImBuf *(*load_filepath_thumbnail)(const char *filepath,
- const int flags,
- const size_t max_thumb_size,
+ int flags,
+ size_t max_thumb_size,
char colorspace[IM_MAX_SPACE],
size_t *r_width,
size_t *r_height);
@@ -155,8 +155,8 @@ struct ImBuf *imb_load_jpeg(const unsigned char *buffer,
int flags,
char colorspace[IM_MAX_SPACE]);
struct ImBuf *imb_thumbnail_jpeg(const char *filepath,
- const int flags,
- const size_t max_thumb_size,
+ int flags,
+ size_t max_thumb_size,
char colorspace[IM_MAX_SPACE],
size_t *r_width,
size_t *r_height);
@@ -240,11 +240,10 @@ void imb_loadtiletiff(
/**
* Saves a TIFF file.
*
- * #ImBuf structures with 1, 3 or 4 bytes per pixel (GRAY, RGB, RGBA
- * respectively) are accepted, and interpreted correctly. Note that the TIFF
- * convention is to use pre-multiplied alpha, which can be achieved within
- * Blender by setting "Premul" alpha handling. Other alpha conventions are
- * not strictly correct, but are permitted anyhow.
+ * #ImBuf structures with 1, 3 or 4 bytes per pixel (GRAY, RGB, RGBA respectively)
+ * are accepted, and interpreted correctly. Note that the TIFF convention is to use
+ * pre-multiplied alpha, which can be achieved within Blender by setting `premul` alpha handling.
+ * Other alpha conventions are not strictly correct, but are permitted anyhow.
*
* \param ibuf: Image buffer.
* \param filepath: Name of the TIFF file to create.
diff --git a/source/blender/imbuf/intern/anim_movie.c b/source/blender/imbuf/intern/anim_movie.c
index 096089d4c41..0052ce19aa1 100644
--- a/source/blender/imbuf/intern/anim_movie.c
+++ b/source/blender/imbuf/intern/anim_movie.c
@@ -423,7 +423,7 @@ static int startavi(struct anim *anim)
anim->cur_position = 0;
# if 0
- printf("x:%d y:%d size:%d interl:%d dur:%d\n",
+ printf("x:%d y:%d size:%d interlace:%d dur:%d\n",
anim->x,
anim->y,
anim->framesize,
diff --git a/source/blender/imbuf/intern/cineon/cineon_dpx.c b/source/blender/imbuf/intern/cineon/cineon_dpx.c
index d1cd30cfe84..1a99d2a34d9 100644
--- a/source/blender/imbuf/intern/cineon/cineon_dpx.c
+++ b/source/blender/imbuf/intern/cineon/cineon_dpx.c
@@ -69,7 +69,7 @@ static struct ImBuf *imb_load_dpx_cineon(const unsigned char *mem,
return ibuf;
}
-static int imb_save_dpx_cineon(ImBuf *ibuf, const char *filename, int use_cineon, int flags)
+static int imb_save_dpx_cineon(ImBuf *ibuf, const char *filepath, int use_cineon, int flags)
{
LogImageFile *logImage;
float *fbuf;
@@ -86,7 +86,7 @@ static int imb_save_dpx_cineon(ImBuf *ibuf, const char *filename, int use_cineon
depth = (ibuf->planes + 7) >> 3;
if (depth > 4 || depth < 3) {
- printf("DPX/Cineon: unsupported depth: %d for file: '%s'\n", depth, filename);
+ printf("DPX/Cineon: unsupported depth: %d for file: '%s'\n", depth, filepath);
return 0;
}
@@ -103,7 +103,7 @@ static int imb_save_dpx_cineon(ImBuf *ibuf, const char *filename, int use_cineon
bitspersample = 8;
}
- logImage = logImageCreate(filename,
+ logImage = logImageCreate(filepath,
use_cineon,
ibuf->x,
ibuf->y,
@@ -121,8 +121,8 @@ static int imb_save_dpx_cineon(ImBuf *ibuf, const char *filename, int use_cineon
}
if (ibuf->rect_float != NULL && bitspersample != 8) {
- /* don't use the float buffer to save 8 bpp picture to prevent color banding
- * (there's no dithering algorithm behind the logImageSetDataRGBA function) */
+ /* Don't use the float buffer to save 8 BPP picture to prevent color banding
+ * (there's no dithering algorithm behind the #logImageSetDataRGBA function). */
fbuf = (float *)MEM_mallocN(sizeof(float[4]) * ibuf->x * ibuf->y,
"fbuf in imb_save_dpx_cineon");
diff --git a/source/blender/imbuf/intern/cineon/cineonlib.c b/source/blender/imbuf/intern/cineon/cineonlib.c
index 3bdfcb60292..8312476bda0 100644
--- a/source/blender/imbuf/intern/cineon/cineonlib.c
+++ b/source/blender/imbuf/intern/cineon/cineonlib.c
@@ -35,7 +35,7 @@ void cineonSetVerbose(int verbosity)
static void fillCineonMainHeader(LogImageFile *cineon,
CineonMainHeader *header,
- const char *filename,
+ const char *filepath,
const char *creator)
{
time_t fileClock;
@@ -57,7 +57,7 @@ static void fillCineonMainHeader(LogImageFile *cineon,
getRowLength(cineon->width, cineon->element[0]),
cineon->isMSB);
strcpy(header->fileHeader.version, "v4.5");
- strncpy(header->fileHeader.file_name, filename, 99);
+ strncpy(header->fileHeader.file_name, filepath, 99);
header->fileHeader.file_name[99] = 0;
fileClock = time(NULL);
fileTime = localtime(&fileClock);
@@ -126,7 +126,7 @@ LogImageFile *cineonOpen(const unsigned char *byteStuff, int fromMemory, size_t
{
CineonMainHeader header;
LogImageFile *cineon = (LogImageFile *)MEM_mallocN(sizeof(LogImageFile), __func__);
- const char *filename = (const char *)byteStuff;
+ const char *filepath = (const char *)byteStuff;
int i;
unsigned int dataOffset;
@@ -144,11 +144,11 @@ LogImageFile *cineonOpen(const unsigned char *byteStuff, int fromMemory, size_t
cineon->file = NULL;
if (fromMemory == 0) {
- /* byteStuff is then the filename */
- cineon->file = BLI_fopen(filename, "rb");
+ /* byteStuff is then the filepath */
+ cineon->file = BLI_fopen(filepath, "rb");
if (cineon->file == NULL) {
if (verbose) {
- printf("Cineon: Failed to open file \"%s\".\n", filename);
+ printf("Cineon: Failed to open file \"%s\".\n", filepath);
}
logImageClose(cineon);
return NULL;
@@ -350,7 +350,7 @@ LogImageFile *cineonOpen(const unsigned char *byteStuff, int fromMemory, size_t
}
LogImageFile *cineonCreate(
- const char *filename, int width, int height, int bitsPerSample, const char *creator)
+ const char *filepath, int width, int height, int bitsPerSample, const char *creator)
{
CineonMainHeader header;
const char *shortFilename = NULL;
@@ -393,18 +393,18 @@ LogImageFile *cineonCreate(
cineon->referenceBlack = 95.0f;
cineon->gamma = 1.7f;
- shortFilename = strrchr(filename, '/');
+ shortFilename = strrchr(filepath, PATHSEP_CHAR);
if (shortFilename == NULL) {
- shortFilename = filename;
+ shortFilename = filepath;
}
else {
shortFilename++;
}
- cineon->file = BLI_fopen(filename, "wb");
+ cineon->file = BLI_fopen(filepath, "wb");
if (cineon->file == NULL) {
if (verbose) {
- printf("cineon: Couldn't open file %s\n", filename);
+ printf("cineon: Couldn't open file %s\n", filepath);
}
logImageClose(cineon);
return NULL;
diff --git a/source/blender/imbuf/intern/cineon/cineonlib.h b/source/blender/imbuf/intern/cineon/cineonlib.h
index 37b27d19539..13d40461728 100644
--- a/source/blender/imbuf/intern/cineon/cineonlib.h
+++ b/source/blender/imbuf/intern/cineon/cineonlib.h
@@ -114,7 +114,7 @@ typedef struct {
void cineonSetVerbose(int);
LogImageFile *cineonOpen(const unsigned char *byteStuff, int fromMemory, size_t bufferSize);
LogImageFile *cineonCreate(
- const char *filename, int width, int height, int bitsPerSample, const char *creator);
+ const char *filepath, int width, int height, int bitsPerSample, const char *creator);
#ifdef __cplusplus
}
diff --git a/source/blender/imbuf/intern/cineon/dpxlib.c b/source/blender/imbuf/intern/cineon/dpxlib.c
index 2d28a477c8a..28c19116361 100644
--- a/source/blender/imbuf/intern/cineon/dpxlib.c
+++ b/source/blender/imbuf/intern/cineon/dpxlib.c
@@ -124,7 +124,7 @@ LogImageFile *dpxOpen(const unsigned char *byteStuff, int fromMemory, size_t buf
{
DpxMainHeader header;
LogImageFile *dpx = (LogImageFile *)MEM_mallocN(sizeof(LogImageFile), __func__);
- const char *filename = (const char *)byteStuff;
+ const char *filepath = (const char *)byteStuff;
int i;
if (dpx == NULL) {
@@ -141,11 +141,11 @@ LogImageFile *dpxOpen(const unsigned char *byteStuff, int fromMemory, size_t buf
dpx->file = NULL;
if (fromMemory == 0) {
- /* byteStuff is then the filename */
- dpx->file = BLI_fopen(filename, "rb");
+ /* byteStuff is then the filepath */
+ dpx->file = BLI_fopen(filepath, "rb");
if (dpx->file == NULL) {
if (verbose) {
- printf("DPX: Failed to open file \"%s\".\n", filename);
+ printf("DPX: Failed to open file \"%s\".\n", filepath);
}
logImageClose(dpx);
return NULL;
@@ -406,7 +406,7 @@ LogImageFile *dpxOpen(const unsigned char *byteStuff, int fromMemory, size_t buf
return dpx;
}
-LogImageFile *dpxCreate(const char *filename,
+LogImageFile *dpxCreate(const char *filepath,
int width,
int height,
int bitsPerSample,
@@ -502,19 +502,19 @@ LogImageFile *dpxCreate(const char *filename,
dpx->gamma = 1.7f;
}
- shortFilename = strrchr(filename, '/');
+ shortFilename = strrchr(filepath, PATHSEP_CHAR);
if (shortFilename == NULL) {
- shortFilename = filename;
+ shortFilename = filepath;
}
else {
shortFilename++;
}
- dpx->file = BLI_fopen(filename, "wb");
+ dpx->file = BLI_fopen(filepath, "wb");
if (dpx->file == NULL) {
if (verbose) {
- printf("DPX: Couldn't open file %s\n", filename);
+ printf("DPX: Couldn't open file %s\n", filepath);
}
logImageClose(dpx);
return NULL;
diff --git a/source/blender/imbuf/intern/cineon/dpxlib.h b/source/blender/imbuf/intern/cineon/dpxlib.h
index d8ed5dc6f67..aac424d52d6 100644
--- a/source/blender/imbuf/intern/cineon/dpxlib.h
+++ b/source/blender/imbuf/intern/cineon/dpxlib.h
@@ -133,7 +133,7 @@ typedef struct {
void dpxSetVerbose(int verbosity);
LogImageFile *dpxOpen(const unsigned char *byteStuff, int fromMemory, size_t bufferSize);
-LogImageFile *dpxCreate(const char *filename,
+LogImageFile *dpxCreate(const char *filepath,
int width,
int height,
int bitsPerSample,
diff --git a/source/blender/imbuf/intern/cineon/logImageCore.c b/source/blender/imbuf/intern/cineon/logImageCore.c
index 36e12e07316..e693aa6f891 100644
--- a/source/blender/imbuf/intern/cineon/logImageCore.c
+++ b/source/blender/imbuf/intern/cineon/logImageCore.c
@@ -101,10 +101,10 @@ int logImageIsCineon(const void *buffer, const unsigned int size)
return (magicNum == CINEON_FILE_MAGIC || magicNum == swap_uint(CINEON_FILE_MAGIC, 1));
}
-LogImageFile *logImageOpenFromFile(const char *filename, int cineon)
+LogImageFile *logImageOpenFromFile(const char *filepath, int cineon)
{
unsigned int magicNum;
- FILE *f = BLI_fopen(filename, "rb");
+ FILE *f = BLI_fopen(filepath, "rb");
(void)cineon;
@@ -120,10 +120,10 @@ LogImageFile *logImageOpenFromFile(const char *filename, int cineon)
fclose(f);
if (logImageIsDpx(&magicNum, sizeof(magicNum))) {
- return dpxOpen((const unsigned char *)filename, 0, 0);
+ return dpxOpen((const unsigned char *)filepath, 0, 0);
}
if (logImageIsCineon(&magicNum, sizeof(magicNum))) {
- return cineonOpen((const unsigned char *)filename, 0, 0);
+ return cineonOpen((const unsigned char *)filepath, 0, 0);
}
return NULL;
@@ -141,7 +141,7 @@ LogImageFile *logImageOpenFromMemory(const unsigned char *buffer, unsigned int s
return NULL;
}
-LogImageFile *logImageCreate(const char *filename,
+LogImageFile *logImageCreate(const char *filepath,
int cineon,
int width,
int height,
@@ -155,10 +155,10 @@ LogImageFile *logImageCreate(const char *filename,
{
/* referenceWhite, referenceBlack and gamma values are only supported for DPX file */
if (cineon) {
- return cineonCreate(filename, width, height, bitsPerSample, creator);
+ return cineonCreate(filepath, width, height, bitsPerSample, creator);
}
- return dpxCreate(filename,
+ return dpxCreate(filepath,
width,
height,
bitsPerSample,
diff --git a/source/blender/imbuf/intern/cineon/logImageCore.h b/source/blender/imbuf/intern/cineon/logImageCore.h
index 6875dba3f87..35540497828 100644
--- a/source/blender/imbuf/intern/cineon/logImageCore.h
+++ b/source/blender/imbuf/intern/cineon/logImageCore.h
@@ -19,6 +19,12 @@
#include "BLI_sys_types.h"
#include "BLI_utildefines.h"
+#ifdef _WIN32
+# define PATHSEP_CHAR '\\'
+#else
+# define PATHSEP_CHAR '/'
+#endif
+
#ifdef __cplusplus
extern "C" {
#endif
@@ -169,9 +175,9 @@ void logImageSetVerbose(int verbosity);
int logImageIsDpx(const void *buffer, unsigned int size);
int logImageIsCineon(const void *buffer, unsigned int size);
LogImageFile *logImageOpenFromMemory(const unsigned char *buffer, unsigned int size);
-LogImageFile *logImageOpenFromFile(const char *filename, int cineon);
+LogImageFile *logImageOpenFromFile(const char *filepath, int cineon);
void logImageGetSize(LogImageFile *logImage, int *width, int *height, int *depth);
-LogImageFile *logImageCreate(const char *filename,
+LogImageFile *logImageCreate(const char *filepath,
int cineon,
int width,
int height,
diff --git a/source/blender/imbuf/intern/colormanagement.c b/source/blender/imbuf/intern/colormanagement.c
index 53aa74edc61..33873b5daa7 100644
--- a/source/blender/imbuf/intern/colormanagement.c
+++ b/source/blender/imbuf/intern/colormanagement.c
@@ -73,10 +73,12 @@ static int global_tot_looks = 0;
/* Luma coefficients and XYZ to RGB to be initialized by OCIO. */
float imbuf_luma_coefficients[3] = {0.0f};
-float imbuf_xyz_to_rgb[3][3] = {{0.0f}};
-float imbuf_rgb_to_xyz[3][3] = {{0.0f}};
-static float imbuf_xyz_to_linear_srgb[3][3] = {{0.0f}};
-static float imbuf_linear_srgb_to_xyz[3][3] = {{0.0f}};
+float imbuf_scene_linear_to_xyz[3][3] = {{0.0f}};
+float imbuf_xyz_to_scene_linear[3][3] = {{0.0f}};
+float imbuf_scene_linear_to_rec709[3][3] = {{0.0f}};
+float imbuf_rec709_to_scene_linear[3][3] = {{0.0f}};
+float imbuf_scene_linear_to_aces[3][3] = {{0.0f}};
+float imbuf_aces_to_scene_linear[3][3] = {{0.0f}};
/* lock used by pre-cached processors getters, so processor wouldn't
* be created several times
@@ -573,10 +575,16 @@ static void colormanage_load_config(OCIO_ConstConfigRcPtr *config)
/* Load luminance coefficients. */
OCIO_configGetDefaultLumaCoefs(config, imbuf_luma_coefficients);
- OCIO_configGetXYZtoRGB(config, imbuf_xyz_to_rgb);
- invert_m3_m3(imbuf_rgb_to_xyz, imbuf_xyz_to_rgb);
- copy_m3_m3(imbuf_xyz_to_linear_srgb, OCIO_XYZ_TO_LINEAR_SRGB);
- invert_m3_m3(imbuf_linear_srgb_to_xyz, imbuf_xyz_to_linear_srgb);
+
+ /* Load standard color spaces. */
+ OCIO_configGetXYZtoSceneLinear(config, imbuf_xyz_to_scene_linear);
+ invert_m3_m3(imbuf_scene_linear_to_xyz, imbuf_xyz_to_scene_linear);
+
+ mul_m3_m3m3(imbuf_scene_linear_to_rec709, OCIO_XYZ_TO_REC709, imbuf_scene_linear_to_xyz);
+ invert_m3_m3(imbuf_rec709_to_scene_linear, imbuf_scene_linear_to_rec709);
+
+ mul_m3_m3m3(imbuf_aces_to_scene_linear, imbuf_xyz_to_scene_linear, OCIO_ACES_TO_XYZ);
+ invert_m3_m3(imbuf_scene_linear_to_aces, imbuf_aces_to_scene_linear);
}
static void colormanage_free_config(void)
@@ -589,7 +597,7 @@ static void colormanage_free_config(void)
while (colorspace) {
ColorSpace *colorspace_next = colorspace->next;
- /* free precomputer processors */
+ /* Free precomputed processors. */
if (colorspace->to_scene_linear) {
OCIO_cpuProcessorRelease((OCIO_ConstCPUProcessorRcPtr *)colorspace->to_scene_linear);
}
@@ -665,7 +673,7 @@ void colormanagement_init(void)
#ifdef WIN32
{
- /* quite a hack to support loading configuration from path with non-acii symbols */
+ /* Quite a hack to support loading configuration from path with non-ACII symbols. */
char short_name[256];
BLI_get_short_name(short_name, configfile);
@@ -1412,9 +1420,15 @@ bool IMB_colormanagement_space_name_is_scene_linear(const char *name)
return (colorspace && IMB_colormanagement_space_is_scene_linear(colorspace));
}
-const float *IMB_colormanagement_get_xyz_to_rgb()
+bool IMB_colormanagement_space_name_is_srgb(const char *name)
{
- return &imbuf_xyz_to_rgb[0][0];
+ ColorSpace *colorspace = colormanage_colorspace_get_named(name);
+ return (colorspace && IMB_colormanagement_space_is_srgb(colorspace));
+}
+
+const float *IMB_colormanagement_get_xyz_to_scene_linear()
+{
+ return &imbuf_xyz_to_scene_linear[0][0];
}
/** \} */
@@ -2197,21 +2211,14 @@ void IMB_colormanagement_imbuf_to_byte_texture(unsigned char *out_buffer,
const int width,
const int height,
const struct ImBuf *ibuf,
- const bool compress_as_srgb,
const bool store_premultiplied)
{
- /* Convert byte buffer for texture storage on the GPU. These have builtin
- * support for converting sRGB to linear, which allows us to store textures
- * without precision or performance loss at minimal memory usage. */
+ /* Byte buffer storage, only for sRGB and data texture since other
+ * color space conversions can't be done on the GPU. */
BLI_assert(ibuf->rect && ibuf->rect_float == NULL);
+ BLI_assert(IMB_colormanagement_space_is_srgb(ibuf->rect_colorspace) ||
+ IMB_colormanagement_space_is_data(ibuf->rect_colorspace));
- OCIO_ConstCPUProcessorRcPtr *processor = NULL;
- if (compress_as_srgb && ibuf->rect_colorspace &&
- !IMB_colormanagement_space_is_srgb(ibuf->rect_colorspace)) {
- processor = colorspace_to_scene_linear_cpu_processor(ibuf->rect_colorspace);
- }
-
- /* TODO(brecht): make this multi-threaded, or at least process in batches. */
const unsigned char *in_buffer = (unsigned char *)ibuf->rect;
const bool use_premultiply = IMB_alpha_affects_rgb(ibuf) && store_premultiplied;
@@ -2221,20 +2228,7 @@ void IMB_colormanagement_imbuf_to_byte_texture(unsigned char *out_buffer,
const unsigned char *in = in_buffer + in_offset * 4;
unsigned char *out = out_buffer + out_offset * 4;
- if (processor != NULL) {
- /* Convert to scene linear, to sRGB and premultiply. */
- for (int x = 0; x < width; x++, in += 4, out += 4) {
- float pixel[4];
- rgba_uchar_to_float(pixel, in);
- OCIO_cpuProcessorApplyRGB(processor, pixel);
- linearrgb_to_srgb_v3_v3(pixel, pixel);
- if (use_premultiply) {
- mul_v3_fl(pixel, pixel[3]);
- }
- rgba_float_to_uchar(out, pixel);
- }
- }
- else if (use_premultiply) {
+ if (use_premultiply) {
/* Premultiply only. */
for (int x = 0; x < width; x++, in += 4, out += 4) {
out[0] = (in[0] * in[3]) >> 8;
@@ -2265,49 +2259,87 @@ void IMB_colormanagement_imbuf_to_float_texture(float *out_buffer,
{
/* Float texture are stored in scene linear color space, with premultiplied
* alpha depending on the image alpha mode. */
- const float *in_buffer = ibuf->rect_float;
- const int in_channels = ibuf->channels;
- const bool use_unpremultiply = IMB_alpha_affects_rgb(ibuf) && !store_premultiplied;
-
- for (int y = 0; y < height; y++) {
- const size_t in_offset = (offset_y + y) * ibuf->x + offset_x;
- const size_t out_offset = y * width;
- const float *in = in_buffer + in_offset * in_channels;
- float *out = out_buffer + out_offset * 4;
-
- if (in_channels == 1) {
- /* Copy single channel. */
- for (int x = 0; x < width; x++, in += 1, out += 4) {
- out[0] = in[0];
- out[1] = in[0];
- out[2] = in[0];
- out[3] = in[0];
+ if (ibuf->rect_float) {
+ /* Float source buffer. */
+ const float *in_buffer = ibuf->rect_float;
+ const int in_channels = ibuf->channels;
+ const bool use_unpremultiply = IMB_alpha_affects_rgb(ibuf) && !store_premultiplied;
+
+ for (int y = 0; y < height; y++) {
+ const size_t in_offset = (offset_y + y) * ibuf->x + offset_x;
+ const size_t out_offset = y * width;
+ const float *in = in_buffer + in_offset * in_channels;
+ float *out = out_buffer + out_offset * 4;
+
+ if (in_channels == 1) {
+ /* Copy single channel. */
+ for (int x = 0; x < width; x++, in += 1, out += 4) {
+ out[0] = in[0];
+ out[1] = in[0];
+ out[2] = in[0];
+ out[3] = in[0];
+ }
}
- }
- else if (in_channels == 3) {
- /* Copy RGB. */
- for (int x = 0; x < width; x++, in += 3, out += 4) {
- out[0] = in[0];
- out[1] = in[1];
- out[2] = in[2];
- out[3] = 1.0f;
+ else if (in_channels == 3) {
+ /* Copy RGB. */
+ for (int x = 0; x < width; x++, in += 3, out += 4) {
+ out[0] = in[0];
+ out[1] = in[1];
+ out[2] = in[2];
+ out[3] = 1.0f;
+ }
}
- }
- else if (in_channels == 4) {
- /* Copy or convert RGBA. */
- if (use_unpremultiply) {
- for (int x = 0; x < width; x++, in += 4, out += 4) {
- premul_to_straight_v4_v4(out, in);
+ else if (in_channels == 4) {
+ /* Copy or convert RGBA. */
+ if (use_unpremultiply) {
+ for (int x = 0; x < width; x++, in += 4, out += 4) {
+ premul_to_straight_v4_v4(out, in);
+ }
+ }
+ else {
+ memcpy(out, in, sizeof(float[4]) * width);
}
}
- else {
- memcpy(out, in, sizeof(float[4]) * width);
+ }
+ }
+ else {
+ /* Byte source buffer. */
+ const unsigned char *in_buffer = (unsigned char *)ibuf->rect;
+ const bool use_premultiply = IMB_alpha_affects_rgb(ibuf) && store_premultiplied;
+
+ /* TODO(brecht): make this multi-threaded, or at least process in batches. */
+ OCIO_ConstCPUProcessorRcPtr *processor = (ibuf->rect_colorspace) ?
+ colorspace_to_scene_linear_cpu_processor(
+ ibuf->rect_colorspace) :
+ NULL;
+
+ for (int y = 0; y < height; y++) {
+ const size_t in_offset = (offset_y + y) * ibuf->x + offset_x;
+ const size_t out_offset = y * width;
+ const unsigned char *in = in_buffer + in_offset * 4;
+ float *out = out_buffer + out_offset * 4;
+
+ /* Convert to scene linear, to sRGB and premultiply. */
+ for (int x = 0; x < width; x++, in += 4, out += 4) {
+ float pixel[4];
+ rgba_uchar_to_float(pixel, in);
+ if (processor) {
+ OCIO_cpuProcessorApplyRGB(processor, pixel);
+ }
+ else {
+ srgb_to_linearrgb_v3_v3(pixel, pixel);
+ }
+ if (use_premultiply) {
+ mul_v3_fl(pixel, pixel[3]);
+ }
+ copy_v4_v4(out, pixel);
}
}
}
}
-void IMB_colormanagement_scene_linear_to_color_picking_v3(float pixel[3])
+void IMB_colormanagement_scene_linear_to_color_picking_v3(float color_picking[3],
+ const float scene_linear[3])
{
if (!global_color_picking_state.cpu_processor_to && !global_color_picking_state.failed) {
/* Create processor if none exists. */
@@ -2329,12 +2361,15 @@ void IMB_colormanagement_scene_linear_to_color_picking_v3(float pixel[3])
BLI_mutex_unlock(&processor_lock);
}
+ copy_v3_v3(color_picking, scene_linear);
+
if (global_color_picking_state.cpu_processor_to) {
- OCIO_cpuProcessorApplyRGB(global_color_picking_state.cpu_processor_to, pixel);
+ OCIO_cpuProcessorApplyRGB(global_color_picking_state.cpu_processor_to, color_picking);
}
}
-void IMB_colormanagement_color_picking_to_scene_linear_v3(float pixel[3])
+void IMB_colormanagement_color_picking_to_scene_linear_v3(float scene_linear[3],
+ const float color_picking[3])
{
if (!global_color_picking_state.cpu_processor_from && !global_color_picking_state.failed) {
/* Create processor if none exists. */
@@ -2356,25 +2391,13 @@ void IMB_colormanagement_color_picking_to_scene_linear_v3(float pixel[3])
BLI_mutex_unlock(&processor_lock);
}
+ copy_v3_v3(scene_linear, color_picking);
+
if (global_color_picking_state.cpu_processor_from) {
- OCIO_cpuProcessorApplyRGB(global_color_picking_state.cpu_processor_from, pixel);
+ OCIO_cpuProcessorApplyRGB(global_color_picking_state.cpu_processor_from, scene_linear);
}
}
-void IMB_colormanagement_scene_linear_to_srgb_v3(float pixel[3])
-{
- mul_m3_v3(imbuf_rgb_to_xyz, pixel);
- mul_m3_v3(imbuf_xyz_to_linear_srgb, pixel);
- linearrgb_to_srgb_v3_v3(pixel, pixel);
-}
-
-void IMB_colormanagement_srgb_to_scene_linear_v3(float pixel[3])
-{
- srgb_to_linearrgb_v3_v3(pixel, pixel);
- mul_m3_v3(imbuf_linear_srgb_to_xyz, pixel);
- mul_m3_v3(imbuf_xyz_to_rgb, pixel);
-}
-
void IMB_colormanagement_scene_linear_to_display_v3(float pixel[3], ColorManagedDisplay *display)
{
OCIO_ConstCPUProcessorRcPtr *processor = display_from_scene_linear_processor(display);
@@ -2445,68 +2468,77 @@ void IMB_colormanagement_imbuf_make_display_space(
colormanagement_imbuf_make_display_space(ibuf, view_settings, display_settings, false);
}
+static ImBuf *imbuf_ensure_editable(ImBuf *ibuf, ImBuf *colormanaged_ibuf, bool allocate_result)
+{
+ if (colormanaged_ibuf != ibuf) {
+ /* Is already an editable copy. */
+ return colormanaged_ibuf;
+ }
+
+ if (allocate_result) {
+ /* Copy full image buffer. */
+ colormanaged_ibuf = IMB_dupImBuf(ibuf);
+ IMB_metadata_copy(colormanaged_ibuf, ibuf);
+ return colormanaged_ibuf;
+ }
+ else {
+ /* Render pipeline is constructing image buffer itself,
+ * but it's re-using byte and float buffers from render result make copy of this buffers
+ * here sine this buffers would be transformed to other color space here. */
+ if (ibuf->rect && (ibuf->mall & IB_rect) == 0) {
+ ibuf->rect = MEM_dupallocN(ibuf->rect);
+ ibuf->mall |= IB_rect;
+ }
+
+ if (ibuf->rect_float && (ibuf->mall & IB_rectfloat) == 0) {
+ ibuf->rect_float = MEM_dupallocN(ibuf->rect_float);
+ ibuf->mall |= IB_rectfloat;
+ }
+
+ return ibuf;
+ }
+}
+
ImBuf *IMB_colormanagement_imbuf_for_write(ImBuf *ibuf,
bool save_as_render,
bool allocate_result,
const ImageFormatData *image_format)
{
ImBuf *colormanaged_ibuf = ibuf;
- const bool is_movie = BKE_imtype_is_movie(image_format->imtype);
- const bool requires_linear_float = BKE_imtype_requires_linear_float(image_format->imtype);
- const bool do_alpha_under = image_format->planes != R_IMF_PLANES_RGBA;
+ /* Update byte buffer if exists but invalid. */
if (ibuf->rect_float && ibuf->rect &&
(ibuf->userflags & (IB_DISPLAY_BUFFER_INVALID | IB_RECT_INVALID)) != 0) {
IMB_rect_from_float(ibuf);
ibuf->userflags &= ~(IB_RECT_INVALID | IB_DISPLAY_BUFFER_INVALID);
}
- const bool do_colormanagement_display = save_as_render && (is_movie || !requires_linear_float);
- const bool do_colormanagement_linear = save_as_render && requires_linear_float &&
- image_format->linear_colorspace_settings.name[0] &&
- !IMB_colormanagement_space_name_is_scene_linear(
- image_format->linear_colorspace_settings.name);
+ /* Detect if we are writing to a file format that needs a linear float buffer. */
+ const bool linear_float_output = BKE_imtype_requires_linear_float(image_format->imtype);
- if (do_colormanagement_display || do_colormanagement_linear || do_alpha_under) {
- if (allocate_result) {
- colormanaged_ibuf = IMB_dupImBuf(ibuf);
- }
- else {
- /* Render pipeline is constructing image buffer itself,
- * but it's re-using byte and float buffers from render result make copy of this buffers
- * here sine this buffers would be transformed to other color space here.
- */
+ /* Detect if we are writing output a byte buffer, which we would need to create
+ * with color management conversions applied. This may be for either applying the
+ * display transform for renders, or a user specified color space for the file. */
+ const bool byte_output = BKE_image_format_is_byte(image_format);
- if (ibuf->rect && (ibuf->mall & IB_rect) == 0) {
- ibuf->rect = MEM_dupallocN(ibuf->rect);
- ibuf->mall |= IB_rect;
- }
-
- if (ibuf->rect_float && (ibuf->mall & IB_rectfloat) == 0) {
- ibuf->rect_float = MEM_dupallocN(ibuf->rect_float);
- ibuf->mall |= IB_rectfloat;
- }
- }
- }
+ BLI_assert(!(byte_output && linear_float_output));
- /* If we're saving from RGBA to RGB buffer then it's not
- * so much useful to just ignore alpha -- it leads to bad
- * artifacts especially when saving byte images.
+ /* If we're saving from RGBA to RGB buffer then it's not so much useful to just ignore alpha --
+ * it leads to bad artifacts especially when saving byte images.
*
- * What we do here is we're overlaying our image on top of
- * background color (which is currently black).
+ * What we do here is we're overlaying our image on top of background color (which is currently
+ * black). This is quite much the same as what Gimp does and it seems to be what artists expects
+ * from saving.
*
- * This is quite much the same as what Gimp does and it
- * seems to be what artists expects from saving.
- *
- * Do a conversion here, so image format writers could
- * happily assume all the alpha tricks were made already.
- * helps keep things locally here, not spreading it to
- * all possible image writers we've got.
+ * Do a conversion here, so image format writers could happily assume all the alpha tricks were
+ * made already. helps keep things locally here, not spreading it to all possible image writers
+ * we've got.
*/
- if (do_alpha_under) {
+ if (image_format->planes != R_IMF_PLANES_RGBA) {
float color[3] = {0, 0, 0};
+ colormanaged_ibuf = imbuf_ensure_editable(ibuf, colormanaged_ibuf, allocate_result);
+
if (colormanaged_ibuf->rect_float && colormanaged_ibuf->channels == 4) {
IMB_alpha_under_color_float(
colormanaged_ibuf->rect_float, colormanaged_ibuf->x, colormanaged_ibuf->y, color);
@@ -2520,69 +2552,95 @@ ImBuf *IMB_colormanagement_imbuf_for_write(ImBuf *ibuf,
}
}
- if (do_colormanagement_display) {
- /* Color management with display and view transform. */
- bool make_byte = false;
+ if (save_as_render && !linear_float_output) {
+ /* Render output: perform conversion to display space using view transform. */
+ colormanaged_ibuf = imbuf_ensure_editable(ibuf, colormanaged_ibuf, allocate_result);
- /* for proper check whether byte buffer is required by a format or not
- * should be pretty safe since this image buffer is supposed to be used for
- * saving only and ftype would be overwritten a bit later by BKE_imbuf_write
- */
- colormanaged_ibuf->ftype = BKE_imtype_to_ftype(image_format->imtype,
- &colormanaged_ibuf->foptions);
-
- /* if file format isn't able to handle float buffer itself,
- * we need to allocate byte buffer and store color managed
- * image there
- */
- const ImFileType *type = IMB_file_type_from_ibuf(colormanaged_ibuf);
- if (type != NULL) {
- if ((type->save != NULL) && (type->flag & IM_FTYPE_FLOAT) == 0) {
- make_byte = true;
- }
- }
-
- /* perform color space conversions */
colormanagement_imbuf_make_display_space(colormanaged_ibuf,
&image_format->view_settings,
&image_format->display_settings,
- make_byte);
+ byte_output);
if (colormanaged_ibuf->rect_float) {
- /* float buffer isn't linear anymore,
+ /* Float buffer isn't linear anymore,
* image format write callback should check for this flag and assume
- * no space conversion should happen if ibuf->float_colorspace != NULL
- */
+ * no space conversion should happen if ibuf->float_colorspace != NULL. */
colormanaged_ibuf->float_colorspace = display_transform_get_colorspace(
&image_format->view_settings, &image_format->display_settings);
+ if (byte_output) {
+ colormanaged_ibuf->rect_colorspace = colormanaged_ibuf->float_colorspace;
+ }
}
}
- else if (do_colormanagement_linear) {
- /* Color management transform to another linear color space. */
- if (!colormanaged_ibuf->rect_float) {
- IMB_float_from_rect(colormanaged_ibuf);
- imb_freerectImBuf(colormanaged_ibuf);
+ else {
+ /* Linear render or regular file output: conversion between two color spaces. */
+
+ /* Detect which color space we need to convert between. */
+ const char *from_colorspace = (ibuf->rect_float && !(byte_output && ibuf->rect)) ?
+ /* From float buffer. */
+ (ibuf->float_colorspace) ? ibuf->float_colorspace->name :
+ global_role_scene_linear :
+ /* From byte buffer. */
+ (ibuf->rect_colorspace) ? ibuf->rect_colorspace->name :
+ global_role_default_byte;
+
+ const char *to_colorspace = image_format->linear_colorspace_settings.name;
+
+ /* TODO: can we check with OCIO if color spaces are the same but have different names? */
+ if (to_colorspace[0] == '\0' || STREQ(from_colorspace, to_colorspace)) {
+ /* No conversion needed, but may still need to allocate byte buffer for output. */
+ if (byte_output && !ibuf->rect) {
+ ibuf->rect_colorspace = ibuf->float_colorspace;
+ IMB_rect_from_float(ibuf);
+ }
}
+ else {
+ /* Color space conversion needed. */
+ colormanaged_ibuf = imbuf_ensure_editable(ibuf, colormanaged_ibuf, allocate_result);
+
+ if (byte_output) {
+ colormanaged_ibuf->rect_colorspace = colormanage_colorspace_get_named(to_colorspace);
+
+ if (colormanaged_ibuf->rect) {
+ /* Byte to byte. */
+ IMB_colormanagement_transform_byte_threaded((unsigned char *)colormanaged_ibuf->rect,
+ colormanaged_ibuf->x,
+ colormanaged_ibuf->y,
+ colormanaged_ibuf->channels,
+ from_colorspace,
+ to_colorspace);
+ }
+ else {
+ /* Float to byte. */
+ IMB_rect_from_float(colormanaged_ibuf);
+ }
+ }
+ else {
+ if (!colormanaged_ibuf->rect_float) {
+ /* Byte to float. */
+ IMB_float_from_rect(colormanaged_ibuf);
+ imb_freerectImBuf(colormanaged_ibuf);
- if (colormanaged_ibuf->rect_float) {
- const char *from_colorspace = (ibuf->float_colorspace) ? ibuf->float_colorspace->name :
- global_role_scene_linear;
- const char *to_colorspace = image_format->linear_colorspace_settings.name;
+ /* This conversion always goes to scene linear. */
+ from_colorspace = global_role_scene_linear;
+ }
- IMB_colormanagement_transform(colormanaged_ibuf->rect_float,
- colormanaged_ibuf->x,
- colormanaged_ibuf->y,
- colormanaged_ibuf->channels,
- from_colorspace,
- to_colorspace,
- false);
+ if (colormanaged_ibuf->rect_float) {
+ /* Float to float. */
+ IMB_colormanagement_transform(colormanaged_ibuf->rect_float,
+ colormanaged_ibuf->x,
+ colormanaged_ibuf->y,
+ colormanaged_ibuf->channels,
+ from_colorspace,
+ to_colorspace,
+ false);
+
+ colormanaged_ibuf->float_colorspace = colormanage_colorspace_get_named(to_colorspace);
+ }
+ }
}
}
- if (colormanaged_ibuf != ibuf) {
- IMB_metadata_copy(colormanaged_ibuf, ibuf);
- }
-
return colormanaged_ibuf;
}
@@ -4076,3 +4134,170 @@ void IMB_colormanagement_finish_glsl_draw(void)
}
/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Rendering Tables
+ * \{ */
+
+/* Calculate color in range 800..12000 using an approximation
+ * a/x+bx+c for R and G and ((at + b)t + c)t + d) for B
+ *
+ * The result of this can be negative to support gamut wider than
+ * than rec.709, just needs to be clamped. */
+
+static const float blackbody_table_r[7][3] = {{1.61919106e+03f, -2.05010916e-03f, 5.02995757e+00f},
+ {2.48845471e+03f, -1.11330907e-03f, 3.22621544e+00f},
+ {3.34143193e+03f, -4.86551192e-04f, 1.76486769e+00f},
+ {4.09461742e+03f, -1.27446582e-04f, 7.25731635e-01f},
+ {4.67028036e+03f, 2.91258199e-05f, 1.26703442e-01f},
+ {4.59509185e+03f, 2.87495649e-05f, 1.50345020e-01f},
+ {3.78717450e+03f, 9.35907826e-06f, 3.99075871e-01f}};
+
+static const float blackbody_table_g[7][3] = {
+ {-4.88999748e+02f, 6.04330754e-04f, -7.55807526e-02f},
+ {-7.55994277e+02f, 3.16730098e-04f, 4.78306139e-01f},
+ {-1.02363977e+03f, 1.20223470e-04f, 9.36662319e-01f},
+ {-1.26571316e+03f, 4.87340896e-06f, 1.27054498e+00f},
+ {-1.42529332e+03f, -4.01150431e-05f, 1.43972784e+00f},
+ {-1.17554822e+03f, -2.16378048e-05f, 1.30408023e+00f},
+ {-5.00799571e+02f, -4.59832026e-06f, 1.09098763e+00f}};
+
+static const float blackbody_table_b[7][4] = {
+ {5.96945309e-11f, -4.85742887e-08f, -9.70622247e-05f, -4.07936148e-03f},
+ {2.40430366e-11f, 5.55021075e-08f, -1.98503712e-04f, 2.89312858e-02f},
+ {-1.40949732e-11f, 1.89878968e-07f, -3.56632824e-04f, 9.10767778e-02f},
+ {-3.61460868e-11f, 2.84822009e-07f, -4.93211319e-04f, 1.56723440e-01f},
+ {-1.97075738e-11f, 1.75359352e-07f, -2.50542825e-04f, -2.22783266e-02f},
+ {-1.61997957e-13f, -1.64216008e-08f, 3.86216271e-04f, -7.38077418e-01f},
+ {6.72650283e-13f, -2.73078809e-08f, 4.24098264e-04f, -7.52335691e-01f}};
+
+static void blackbody_temperature_to_rec709(float rec709[3], float t)
+{
+ if (t >= 12000.0f) {
+ rec709[0] = 0.8262954810464208f;
+ rec709[1] = 0.9945080501520986f;
+ rec709[2] = 1.566307710274283f;
+ }
+ else if (t < 800.0f) {
+ rec709[0] = 5.413294490189271f;
+ rec709[1] = -0.20319390035873933f;
+ rec709[2] = -0.0822535242887164f;
+ }
+ else {
+ int i = (t >= 6365.0f) ? 6 :
+ (t >= 3315.0f) ? 5 :
+ (t >= 1902.0f) ? 4 :
+ (t >= 1449.0f) ? 3 :
+ (t >= 1167.0f) ? 2 :
+ (t >= 965.0f) ? 1 :
+ 0;
+
+ const float *r = blackbody_table_r[i];
+ const float *g = blackbody_table_g[i];
+ const float *b = blackbody_table_b[i];
+
+ const float t_inv = 1.0f / t;
+ rec709[0] = r[0] * t_inv + r[1] * t + r[2];
+ rec709[1] = g[0] * t_inv + g[1] * t + g[2];
+ rec709[2] = ((b[0] * t + b[1]) * t + b[2]) * t + b[3];
+ }
+}
+
+void IMB_colormanagement_blackbody_temperature_to_rgb_table(float *r_table,
+ const int width,
+ const float min,
+ const float max)
+{
+ for (int i = 0; i < width; i++) {
+ float temperature = min + (max - min) / (float)width * (float)i;
+
+ float rec709[3];
+ blackbody_temperature_to_rec709(rec709, temperature);
+
+ float rgb[3];
+ IMB_colormanagement_rec709_to_scene_linear(rgb, rec709);
+ clamp_v3(rgb, 0.0f, FLT_MAX);
+
+ copy_v3_v3(&r_table[i * 4], rgb);
+ r_table[i * 4 + 3] = 0.0f;
+ }
+}
+
+/**
+ * CIE color matching functions `xBar`, `yBar`, and `zBar` for
+ * wavelengths from 380 through 780 nanometers, every 5 nanometers.
+ *
+ * For a wavelength lambda in this range:
+ * \code{.txt}
+ * cie_color_match[(lambda - 380) / 5][0] = xBar
+ * cie_color_match[(lambda - 380) / 5][1] = yBar
+ * cie_color_match[(lambda - 380) / 5][2] = zBar
+ * \endcode
+ */
+
+static float cie_colour_match[81][3] = {
+ {0.0014f, 0.0000f, 0.0065f}, {0.0022f, 0.0001f, 0.0105f}, {0.0042f, 0.0001f, 0.0201f},
+ {0.0076f, 0.0002f, 0.0362f}, {0.0143f, 0.0004f, 0.0679f}, {0.0232f, 0.0006f, 0.1102f},
+ {0.0435f, 0.0012f, 0.2074f}, {0.0776f, 0.0022f, 0.3713f}, {0.1344f, 0.0040f, 0.6456f},
+ {0.2148f, 0.0073f, 1.0391f}, {0.2839f, 0.0116f, 1.3856f}, {0.3285f, 0.0168f, 1.6230f},
+ {0.3483f, 0.0230f, 1.7471f}, {0.3481f, 0.0298f, 1.7826f}, {0.3362f, 0.0380f, 1.7721f},
+ {0.3187f, 0.0480f, 1.7441f}, {0.2908f, 0.0600f, 1.6692f}, {0.2511f, 0.0739f, 1.5281f},
+ {0.1954f, 0.0910f, 1.2876f}, {0.1421f, 0.1126f, 1.0419f}, {0.0956f, 0.1390f, 0.8130f},
+ {0.0580f, 0.1693f, 0.6162f}, {0.0320f, 0.2080f, 0.4652f}, {0.0147f, 0.2586f, 0.3533f},
+ {0.0049f, 0.3230f, 0.2720f}, {0.0024f, 0.4073f, 0.2123f}, {0.0093f, 0.5030f, 0.1582f},
+ {0.0291f, 0.6082f, 0.1117f}, {0.0633f, 0.7100f, 0.0782f}, {0.1096f, 0.7932f, 0.0573f},
+ {0.1655f, 0.8620f, 0.0422f}, {0.2257f, 0.9149f, 0.0298f}, {0.2904f, 0.9540f, 0.0203f},
+ {0.3597f, 0.9803f, 0.0134f}, {0.4334f, 0.9950f, 0.0087f}, {0.5121f, 1.0000f, 0.0057f},
+ {0.5945f, 0.9950f, 0.0039f}, {0.6784f, 0.9786f, 0.0027f}, {0.7621f, 0.9520f, 0.0021f},
+ {0.8425f, 0.9154f, 0.0018f}, {0.9163f, 0.8700f, 0.0017f}, {0.9786f, 0.8163f, 0.0014f},
+ {1.0263f, 0.7570f, 0.0011f}, {1.0567f, 0.6949f, 0.0010f}, {1.0622f, 0.6310f, 0.0008f},
+ {1.0456f, 0.5668f, 0.0006f}, {1.0026f, 0.5030f, 0.0003f}, {0.9384f, 0.4412f, 0.0002f},
+ {0.8544f, 0.3810f, 0.0002f}, {0.7514f, 0.3210f, 0.0001f}, {0.6424f, 0.2650f, 0.0000f},
+ {0.5419f, 0.2170f, 0.0000f}, {0.4479f, 0.1750f, 0.0000f}, {0.3608f, 0.1382f, 0.0000f},
+ {0.2835f, 0.1070f, 0.0000f}, {0.2187f, 0.0816f, 0.0000f}, {0.1649f, 0.0610f, 0.0000f},
+ {0.1212f, 0.0446f, 0.0000f}, {0.0874f, 0.0320f, 0.0000f}, {0.0636f, 0.0232f, 0.0000f},
+ {0.0468f, 0.0170f, 0.0000f}, {0.0329f, 0.0119f, 0.0000f}, {0.0227f, 0.0082f, 0.0000f},
+ {0.0158f, 0.0057f, 0.0000f}, {0.0114f, 0.0041f, 0.0000f}, {0.0081f, 0.0029f, 0.0000f},
+ {0.0058f, 0.0021f, 0.0000f}, {0.0041f, 0.0015f, 0.0000f}, {0.0029f, 0.0010f, 0.0000f},
+ {0.0020f, 0.0007f, 0.0000f}, {0.0014f, 0.0005f, 0.0000f}, {0.0010f, 0.0004f, 0.0000f},
+ {0.0007f, 0.0002f, 0.0000f}, {0.0005f, 0.0002f, 0.0000f}, {0.0003f, 0.0001f, 0.0000f},
+ {0.0002f, 0.0001f, 0.0000f}, {0.0002f, 0.0001f, 0.0000f}, {0.0001f, 0.0000f, 0.0000f},
+ {0.0001f, 0.0000f, 0.0000f}, {0.0001f, 0.0000f, 0.0000f}, {0.0000f, 0.0000f, 0.0000f}};
+
+static void wavelength_to_xyz(float xyz[3], float lambda_nm)
+{
+ float ii = (lambda_nm - 380.0f) * (1.0f / 5.0f); /* Scaled 0..80. */
+ int i = (int)ii;
+
+ if (i < 0 || i >= 80) {
+ xyz[0] = 0.0f;
+ xyz[1] = 0.0f;
+ xyz[2] = 0.0f;
+ }
+ else {
+ ii -= (float)i;
+ const float *c = cie_colour_match[i];
+ xyz[0] = c[0] + ii * (c[3] - c[0]);
+ xyz[1] = c[1] + ii * (c[4] - c[1]);
+ xyz[2] = c[2] + ii * (c[5] - c[2]);
+ }
+}
+
+void IMB_colormanagement_wavelength_to_rgb_table(float *r_table, const int width)
+{
+ for (int i = 0; i < width; i++) {
+ float temperature = 380 + 400 / (float)width * (float)i;
+
+ float xyz[3];
+ wavelength_to_xyz(xyz, temperature);
+
+ float rgb[3];
+ IMB_colormanagement_xyz_to_scene_linear(rgb, xyz);
+ clamp_v3(rgb, 0.0f, FLT_MAX);
+
+ copy_v3_v3(&r_table[i * 4], rgb);
+ r_table[i * 4 + 3] = 0.0f;
+ }
+}
+
+/** \} */
diff --git a/source/blender/imbuf/intern/colormanagement_inline.c b/source/blender/imbuf/intern/colormanagement_inline.c
index 411cf9af802..668307ec802 100644
--- a/source/blender/imbuf/intern/colormanagement_inline.c
+++ b/source/blender/imbuf/intern/colormanagement_inline.c
@@ -27,14 +27,46 @@ unsigned char IMB_colormanagement_get_luminance_byte(const unsigned char rgb[3])
return unit_float_to_uchar_clamp(val);
}
-void IMB_colormanagement_xyz_to_rgb(float rgb[3], const float xyz[3])
+void IMB_colormanagement_xyz_to_scene_linear(float scene_linear[3], const float xyz[3])
{
- mul_v3_m3v3(rgb, imbuf_xyz_to_rgb, xyz);
+ mul_v3_m3v3(scene_linear, imbuf_xyz_to_scene_linear, xyz);
}
-void IMB_colormanagement_rgb_to_xyz(float xyz[3], const float rgb[3])
+void IMB_colormanagement_scene_linear_to_xyz(float xyz[3], const float scene_linear[3])
{
- mul_v3_m3v3(xyz, imbuf_rgb_to_xyz, rgb);
+ mul_v3_m3v3(xyz, imbuf_scene_linear_to_xyz, scene_linear);
+}
+
+void IMB_colormanagement_rec709_to_scene_linear(float scene_linear[3], const float rec709[3])
+{
+ mul_v3_m3v3(scene_linear, imbuf_rec709_to_scene_linear, rec709);
+}
+
+void IMB_colormanagement_scene_linear_to_rec709(float rec709[3], const float scene_linear[3])
+{
+ mul_v3_m3v3(rec709, imbuf_scene_linear_to_rec709, scene_linear);
+}
+
+void IMB_colormanagement_scene_linear_to_srgb_v3(float srgb[3], const float scene_linear[3])
+{
+ mul_v3_m3v3(srgb, imbuf_scene_linear_to_rec709, scene_linear);
+ linearrgb_to_srgb_v3_v3(srgb, srgb);
+}
+
+void IMB_colormanagement_srgb_to_scene_linear_v3(float scene_linear[3], const float srgb[3])
+{
+ srgb_to_linearrgb_v3_v3(scene_linear, srgb);
+ mul_m3_v3(imbuf_rec709_to_scene_linear, scene_linear);
+}
+
+void IMB_colormanagement_aces_to_scene_linear(float scene_linear[3], const float aces[3])
+{
+ mul_v3_m3v3(scene_linear, imbuf_aces_to_scene_linear, aces);
+}
+
+void IMB_colormanagement_scene_linear_to_aces(float aces[3], const float scene_linear[3])
+{
+ mul_v3_m3v3(aces, imbuf_scene_linear_to_aces, scene_linear);
}
#endif /* __IMB_COLORMANAGEMENT_INLINE_H__ */
diff --git a/source/blender/imbuf/intern/dds/Color.h b/source/blender/imbuf/intern/dds/Color.h
index 3918ef31052..5b00333ad77 100644
--- a/source/blender/imbuf/intern/dds/Color.h
+++ b/source/blender/imbuf/intern/dds/Color.h
@@ -21,9 +21,8 @@ class Color32 {
Color32()
{
}
- Color32(const Color32 &c) : u(c.u)
- {
- }
+ Color32(const Color32 &) = default;
+
Color32(unsigned char R, unsigned char G, unsigned char B)
{
setRGBA(R, G, B, 0xFF);
diff --git a/source/blender/imbuf/intern/dds/Stream.cpp b/source/blender/imbuf/intern/dds/Stream.cpp
index 34f3654aa3f..566891dac8b 100644
--- a/source/blender/imbuf/intern/dds/Stream.cpp
+++ b/source/blender/imbuf/intern/dds/Stream.cpp
@@ -45,7 +45,7 @@ unsigned int mem_read(Stream &mem, unsigned long long &i)
mem.set_failed(msg_error_seek);
return 0;
}
- memcpy(&i, mem.mem + mem.pos, 8); /* @@ todo: make sure little endian */
+ memcpy(&i, mem.mem + mem.pos, 8); /* TODO: make sure little endian. */
mem.pos += 8;
return 8;
}
@@ -56,7 +56,7 @@ unsigned int mem_read(Stream &mem, unsigned int &i)
mem.set_failed(msg_error_read);
return 0;
}
- memcpy(&i, mem.mem + mem.pos, 4); /* @@ todo: make sure little endian */
+ memcpy(&i, mem.mem + mem.pos, 4); /* TODO: make sure little endian. */
mem.pos += 4;
return 4;
}
@@ -67,7 +67,7 @@ unsigned int mem_read(Stream &mem, unsigned short &i)
mem.set_failed(msg_error_read);
return 0;
}
- memcpy(&i, mem.mem + mem.pos, 2); /* @@ todo: make sure little endian */
+ memcpy(&i, mem.mem + mem.pos, 2); /* TODO: make sure little endian. */
mem.pos += 2;
return 2;
}
diff --git a/source/blender/imbuf/intern/filetype.c b/source/blender/imbuf/intern/filetype.c
index 74042ef75be..92fa980cd7f 100644
--- a/source/blender/imbuf/intern/filetype.c
+++ b/source/blender/imbuf/intern/filetype.c
@@ -157,7 +157,7 @@ const ImFileType IMB_FILE_TYPES[] = {
.is_a = imb_is_a_openexr,
.load = imb_load_openexr,
.load_filepath = NULL,
- .load_filepath_thumbnail = NULL,
+ .load_filepath_thumbnail = imb_load_filepath_thumbnail_openexr,
.save = imb_save_openexr,
.load_tile = NULL,
.flag = IM_FTYPE_FLOAT,
diff --git a/source/blender/imbuf/intern/indexer.c b/source/blender/imbuf/intern/indexer.c
index 1cc91d25d2a..cbc5d984755 100644
--- a/source/blender/imbuf/intern/indexer.c
+++ b/source/blender/imbuf/intern/indexer.c
@@ -376,10 +376,10 @@ int IMB_timecode_to_array_index(IMB_Timecode_Type tc)
static void get_index_dir(struct anim *anim, char *index_dir, size_t index_dir_len)
{
if (!anim->index_dir[0]) {
- char fname[FILE_MAXFILE];
- BLI_split_dirfile(anim->name, index_dir, fname, index_dir_len, sizeof(fname));
+ char filename[FILE_MAXFILE];
+ BLI_split_dirfile(anim->name, index_dir, filename, index_dir_len, sizeof(filename));
BLI_path_append(index_dir, index_dir_len, "BL_proxy");
- BLI_path_append(index_dir, index_dir_len, fname);
+ BLI_path_append(index_dir, index_dir_len, filename);
}
else {
BLI_strncpy(index_dir, anim->index_dir, index_dir_len);
@@ -388,14 +388,14 @@ static void get_index_dir(struct anim *anim, char *index_dir, size_t index_dir_l
void IMB_anim_get_fname(struct anim *anim, char *file, int size)
{
- char fname[FILE_MAXFILE];
- BLI_split_dirfile(anim->name, file, fname, size, sizeof(fname));
- BLI_strncpy(file, fname, size);
+ char filename[FILE_MAXFILE];
+ BLI_split_dirfile(anim->name, file, filename, size, sizeof(filename));
+ BLI_strncpy(file, filename, size);
}
-static bool get_proxy_filename(struct anim *anim,
+static bool get_proxy_filepath(struct anim *anim,
IMB_Proxy_Size preview_size,
- char *fname,
+ char *filepath,
bool temp)
{
char index_dir[FILE_MAXDIR];
@@ -426,11 +426,11 @@ static bool get_proxy_filename(struct anim *anim,
return false;
}
- BLI_join_dirfile(fname, FILE_MAXFILE + FILE_MAXDIR, index_dir, proxy_name);
+ BLI_join_dirfile(filepath, FILE_MAXFILE + FILE_MAXDIR, index_dir, proxy_name);
return true;
}
-static void get_tc_filename(struct anim *anim, IMB_Timecode_Type tc, char *fname)
+static void get_tc_filename(struct anim *anim, IMB_Timecode_Type tc, char *filepath)
{
char index_dir[FILE_MAXDIR];
int i = IMB_timecode_to_array_index(tc);
@@ -457,7 +457,7 @@ static void get_tc_filename(struct anim *anim, IMB_Timecode_Type tc, char *fname
get_index_dir(anim, index_dir, sizeof(index_dir));
- BLI_join_dirfile(fname, FILE_MAXFILE + FILE_MAXDIR, index_dir, index_name);
+ BLI_join_dirfile(filepath, FILE_MAXFILE + FILE_MAXDIR, index_dir, index_name);
}
/* ----------------------------------------------------------------------
@@ -492,18 +492,18 @@ static struct proxy_output_ctx *alloc_proxy_output_ffmpeg(
{
struct proxy_output_ctx *rv = MEM_callocN(sizeof(struct proxy_output_ctx), "alloc_proxy_output");
- char fname[FILE_MAX];
+ char filepath[FILE_MAX];
rv->proxy_size = proxy_size;
rv->anim = anim;
- get_proxy_filename(rv->anim, rv->proxy_size, fname, true);
- BLI_make_existing_file(fname);
+ get_proxy_filepath(rv->anim, rv->proxy_size, filepath, true);
+ BLI_make_existing_file(filepath);
rv->of = avformat_alloc_context();
rv->of->oformat = av_guess_format("avi", NULL, NULL);
- rv->of->url = av_strdup(fname);
+ rv->of->url = av_strdup(filepath);
fprintf(stderr, "Starting work on proxy: %s\n", rv->of->url);
@@ -577,7 +577,7 @@ static struct proxy_output_ctx *alloc_proxy_output_ffmpeg(
avcodec_parameters_from_context(rv->st->codecpar, rv->c);
- int ret = avio_open(&rv->of->pb, fname, AVIO_FLAG_WRITE);
+ int ret = avio_open(&rv->of->pb, filepath, AVIO_FLAG_WRITE);
if (ret < 0) {
fprintf(stderr,
@@ -723,8 +723,8 @@ static void add_to_proxy_output_ffmpeg(struct proxy_output_ctx *ctx, AVFrame *fr
static void free_proxy_output_ffmpeg(struct proxy_output_ctx *ctx, int rollback)
{
- char fname[FILE_MAX];
- char fname_tmp[FILE_MAX];
+ char filepath[FILE_MAX];
+ char filepath_tmp[FILE_MAX];
if (!ctx) {
return;
@@ -755,15 +755,15 @@ static void free_proxy_output_ffmpeg(struct proxy_output_ctx *ctx, int rollback)
av_free(ctx->frame);
}
- get_proxy_filename(ctx->anim, ctx->proxy_size, fname_tmp, true);
+ get_proxy_filepath(ctx->anim, ctx->proxy_size, filepath_tmp, true);
if (rollback) {
- unlink(fname_tmp);
+ unlink(filepath_tmp);
}
else {
- get_proxy_filename(ctx->anim, ctx->proxy_size, fname, false);
- unlink(fname);
- BLI_rename(fname_tmp, fname);
+ get_proxy_filepath(ctx->anim, ctx->proxy_size, filepath, false);
+ unlink(filepath);
+ BLI_rename(filepath_tmp, filepath);
}
MEM_freeN(ctx);
@@ -907,11 +907,11 @@ static IndexBuildContext *index_ffmpeg_create_context(struct anim *anim,
for (i = 0; i < num_indexers; i++) {
if (tcs_in_use & tc_types[i]) {
- char fname[FILE_MAX];
+ char filepath[FILE_MAX];
- get_tc_filename(anim, tc_types[i], fname);
+ get_tc_filename(anim, tc_types[i], filepath);
- context->indexer[i] = IMB_index_builder_create(fname);
+ context->indexer[i] = IMB_index_builder_create(filepath);
if (!context->indexer[i]) {
tcs_in_use &= ~tc_types[i];
}
@@ -1212,7 +1212,7 @@ typedef struct FallbackIndexBuilderContext {
} FallbackIndexBuilderContext;
static AviMovie *alloc_proxy_output_avi(
- struct anim *anim, char *filename, int width, int height, int quality)
+ struct anim *anim, char *filepath, int width, int height, int quality)
{
int x, y;
AviFormat format;
@@ -1233,7 +1233,7 @@ static AviMovie *alloc_proxy_output_avi(
format = AVI_FORMAT_MJPEG;
- if (AVI_open_compress(filename, avi, 1, format) != AVI_ERROR_NONE) {
+ if (AVI_open_compress(filepath, avi, 1, format) != AVI_ERROR_NONE) {
MEM_freeN(avi);
return NULL;
}
@@ -1275,13 +1275,13 @@ static IndexBuildContext *index_fallback_create_context(struct anim *anim,
for (i = 0; i < IMB_PROXY_MAX_SLOT; i++) {
if (context->proxy_sizes_in_use & proxy_sizes[i]) {
- char fname[FILE_MAX];
+ char filepath[FILE_MAX];
- get_proxy_filename(anim, proxy_sizes[i], fname, true);
- BLI_make_existing_file(fname);
+ get_proxy_filepath(anim, proxy_sizes[i], filepath, true);
+ BLI_make_existing_file(filepath);
context->proxy_ctx[i] = alloc_proxy_output_avi(
- anim, fname, anim->x * proxy_fac[i], anim->y * proxy_fac[i], quality);
+ anim, filepath, anim->x * proxy_fac[i], anim->y * proxy_fac[i], quality);
}
}
@@ -1291,8 +1291,8 @@ static IndexBuildContext *index_fallback_create_context(struct anim *anim,
static void index_rebuild_fallback_finish(FallbackIndexBuilderContext *context, int stop)
{
struct anim *anim = context->anim;
- char fname[FILE_MAX];
- char fname_tmp[FILE_MAX];
+ char filepath[FILE_MAX];
+ char filepath_tmp[FILE_MAX];
int i;
for (i = 0; i < IMB_PROXY_MAX_SLOT; i++) {
@@ -1300,15 +1300,15 @@ static void index_rebuild_fallback_finish(FallbackIndexBuilderContext *context,
AVI_close_compress(context->proxy_ctx[i]);
MEM_freeN(context->proxy_ctx[i]);
- get_proxy_filename(anim, proxy_sizes[i], fname_tmp, true);
- get_proxy_filename(anim, proxy_sizes[i], fname, false);
+ get_proxy_filepath(anim, proxy_sizes[i], filepath_tmp, true);
+ get_proxy_filepath(anim, proxy_sizes[i], filepath, false);
if (stop) {
- unlink(fname_tmp);
+ unlink(filepath_tmp);
}
else {
- unlink(fname);
- rename(fname_tmp, fname);
+ unlink(filepath);
+ rename(filepath_tmp, filepath);
}
}
}
@@ -1388,7 +1388,7 @@ IndexBuildContext *IMB_anim_index_rebuild_context(struct anim *anim,
IMB_Proxy_Size proxy_size = proxy_sizes[i];
if (proxy_size & proxy_sizes_to_build) {
char filename[FILE_MAX];
- if (get_proxy_filename(anim, proxy_size, filename, false) == false) {
+ if (get_proxy_filepath(anim, proxy_size, filename, false) == false) {
return NULL;
}
void **filename_key_p;
@@ -1411,7 +1411,7 @@ IndexBuildContext *IMB_anim_index_rebuild_context(struct anim *anim,
IMB_Proxy_Size proxy_size = proxy_sizes[i];
if (proxy_size & built_proxies) {
char filename[FILE_MAX];
- if (get_proxy_filename(anim, proxy_size, filename, false) == false) {
+ if (get_proxy_filepath(anim, proxy_size, filename, false) == false) {
return NULL;
}
printf("Skipping proxy: %s\n", filename);
@@ -1532,7 +1532,7 @@ void IMB_anim_set_index_dir(struct anim *anim, const char *dir)
struct anim *IMB_anim_open_proxy(struct anim *anim, IMB_Proxy_Size preview_size)
{
- char fname[FILE_MAX];
+ char filepath[FILE_MAX];
int i = IMB_proxy_size_to_array_index(preview_size);
if (i < 0) {
@@ -1547,10 +1547,10 @@ struct anim *IMB_anim_open_proxy(struct anim *anim, IMB_Proxy_Size preview_size)
return NULL;
}
- get_proxy_filename(anim, preview_size, fname, false);
+ get_proxy_filepath(anim, preview_size, filepath, false);
/* proxies are generated in the same color space as animation itself */
- anim->proxy_anim[i] = IMB_open_anim(fname, 0, 0, anim->colorspace);
+ anim->proxy_anim[i] = IMB_open_anim(filepath, 0, 0, anim->colorspace);
anim->proxies_tried |= preview_size;
@@ -1559,7 +1559,7 @@ struct anim *IMB_anim_open_proxy(struct anim *anim, IMB_Proxy_Size preview_size)
struct anim_index *IMB_anim_open_index(struct anim *anim, IMB_Timecode_Type tc)
{
- char fname[FILE_MAX];
+ char filepath[FILE_MAX];
int i = IMB_timecode_to_array_index(tc);
if (i < 0) {
@@ -1574,9 +1574,9 @@ struct anim_index *IMB_anim_open_index(struct anim *anim, IMB_Timecode_Type tc)
return NULL;
}
- get_tc_filename(anim, tc, fname);
+ get_tc_filename(anim, tc, filepath);
- anim->curr_idx[i] = IMB_indexer_open(fname);
+ anim->curr_idx[i] = IMB_indexer_open(filepath);
anim->indices_tried |= tc;
@@ -1602,7 +1602,7 @@ IMB_Proxy_Size IMB_anim_proxy_get_existing(struct anim *anim)
for (i = 0; i < num_proxy_sizes; i++) {
IMB_Proxy_Size proxy_size = proxy_sizes[i];
char filename[FILE_MAX];
- get_proxy_filename(anim, proxy_size, filename, false);
+ get_proxy_filepath(anim, proxy_size, filename, false);
if (BLI_exists(filename)) {
existing |= proxy_size;
}
diff --git a/source/blender/imbuf/intern/iris.c b/source/blender/imbuf/intern/iris.c
index eb0a2c4a47f..a8150fd1648 100644
--- a/source/blender/imbuf/intern/iris.c
+++ b/source/blender/imbuf/intern/iris.c
@@ -105,7 +105,7 @@ static int expandrow2(
float *optr, const float *optr_end, const uchar *iptr, const uchar *iptr_end, int z);
static void interleaverow(uchar *lptr, const uchar *cptr, int z, int n);
static void interleaverow2(float *lptr, const uchar *cptr, int z, int n);
-static int compressrow(uchar *lbuf, uchar *rlebuf, int z, int row_len);
+static int compressrow(const uchar *lbuf, uchar *rlebuf, int z, int row_len);
static void lumrow(const uchar *rgbptr, uchar *lumptr, int n);
/*
@@ -779,18 +779,24 @@ fail:
}
/**
- * Copy an array of ints to an iris image file.
- * Each int represents one pixel. xsize and ysize specify the dimensions of
- * the pixel array. zsize specifies what kind of image file to
- * write out. if zsize is 1, the luminance of the pixels are
- * calculated, and a single channel black and white image is saved.
- * If zsize is 3, an RGB image file is saved. If zsize is 4, an
- * RGBA image file is saved.
- *
- * Added: zbuf write
+ * \param filepath: The file path to write to.
+ * \param lptr: an array of integers to an iris image file (each int represents one pixel).
+ * \param zptr: depth-buffer (optional, may be NULL).
+ * \param xsize: with width of the pixel-array.
+ * \param ysize: height of the pixel-array.
+ * \param zsize: specifies what kind of image file to write out.
+ * - 1: the luminance of the pixels are calculated,
+ * and a single channel black and white image is saved.
+ * - 3: an RGB image file is saved.
+ * - 4: an RGBA image file is saved.
+ * - 8: an RGBA image and a Z-buffer (non-null `zptr`).
*/
-
-static bool output_iris(uint *lptr, int xsize, int ysize, int zsize, const char *name, int *zptr)
+static bool output_iris(const char *filepath,
+ const uint *lptr,
+ const int *zptr,
+ const int xsize,
+ const int ysize,
+ const int zsize)
{
FILE *outf;
IMAGE *image;
@@ -801,7 +807,7 @@ static bool output_iris(uint *lptr, int xsize, int ysize, int zsize, const char
int rlebuflen, goodwrite;
goodwrite = 1;
- outf = BLI_fopen(name, "wb");
+ outf = BLI_fopen(filepath, "wb");
if (!outf) {
return 0;
}
@@ -837,21 +843,20 @@ static bool output_iris(uint *lptr, int xsize, int ysize, int zsize, const char
for (z = 0; z < zsize; z++) {
if (zsize == 1) {
- lumrow((uchar *)lptr, (uchar *)lumbuf, xsize);
- len = compressrow((uchar *)lumbuf, rlebuf, CHANOFFSET(z), xsize);
+ lumrow((const uchar *)lptr, (uchar *)lumbuf, xsize);
+ len = compressrow((const uchar *)lumbuf, rlebuf, CHANOFFSET(z), xsize);
}
else {
if (z < 4) {
- len = compressrow((uchar *)lptr, rlebuf, CHANOFFSET(z), xsize);
+ len = compressrow((const uchar *)lptr, rlebuf, CHANOFFSET(z), xsize);
}
else if (z < 8 && zptr) {
- len = compressrow((uchar *)zptr, rlebuf, CHANOFFSET(z - 4), xsize);
+ len = compressrow((const uchar *)zptr, rlebuf, CHANOFFSET(z - 4), xsize);
}
}
- if (len > rlebuflen) {
- fprintf(stderr, "output_iris: rlebuf is too small - bad poop\n");
- exit(1);
- }
+
+ BLI_assert_msg(len <= rlebuflen, "The length calculated for 'rlebuflen' was too small!");
+
goodwrite *= fwrite(rlebuf, len, 1, outf);
starttab[y + z * ysize] = pos;
lengthtab[y + z * ysize] = len;
@@ -892,9 +897,10 @@ static void lumrow(const uchar *rgbptr, uchar *lumptr, int n)
}
}
-static int compressrow(uchar *lbuf, uchar *rlebuf, int z, int row_len)
+static int compressrow(const uchar *lbuf, uchar *rlebuf, const int z, const int row_len)
{
- uchar *iptr, *ibufend, *sptr, *optr;
+ const uchar *iptr, *ibufend, *sptr;
+ uchar *optr;
short todo, cc;
int count;
@@ -964,7 +970,7 @@ bool imb_saveiris(struct ImBuf *ibuf, const char *filepath, int flags)
IMB_convert_rgba_to_abgr(ibuf);
test_endian_zbuf(ibuf);
- const bool ok = output_iris(ibuf->rect, ibuf->x, ibuf->y, zsize, filepath, ibuf->zbuf);
+ const bool ok = output_iris(filepath, ibuf->rect, ibuf->zbuf, ibuf->x, ibuf->y, zsize);
/* restore! Quite clumsy, 2 times a switch... maybe better a malloc ? */
IMB_convert_rgba_to_abgr(ibuf);
diff --git a/source/blender/imbuf/intern/jpeg.c b/source/blender/imbuf/intern/jpeg.c
index 80fcceb0aa7..cffa61977f7 100644
--- a/source/blender/imbuf/intern/jpeg.c
+++ b/source/blender/imbuf/intern/jpeg.c
@@ -286,8 +286,8 @@ static ImBuf *ibJpegImageFromCinfo(struct jpeg_decompress_struct *cinfo,
}
if (max_size > 0) {
- /* libjpeg can more quickly decompress while scaling down to 1/2, 1/4, 1/8,
- * while libjpeg-turbo can also do 3/8, 5/8, etc. But max is 1/8. */
+ /* `libjpeg` can more quickly decompress while scaling down to 1/2, 1/4, 1/8,
+ * while `libjpeg-turbo` can also do 3/8, 5/8, etc. But max is 1/8. */
float scale = (float)max_size / MAX2(cinfo->image_width, cinfo->image_height);
cinfo->scale_denom = 8;
cinfo->scale_num = max_uu(1, min_uu(8, ceill(scale * (float)cinfo->scale_denom)));
@@ -520,9 +520,9 @@ struct ImBuf *imb_thumbnail_jpeg(const char *filepath,
if ((fgetc(infile) == JPEG_MARKER_MSB) && (fgetc(infile) == JPEG_MARKER_SOI) &&
(fgetc(infile) == JPEG_MARKER_MSB) && (fgetc(infile) == JPEG_MARKER_APP1)) {
- /* This is a JPEG in Exif format (SOI + APP1), not JFIF (SOI + APP0). */
+ /* This is a JPEG in EXIF format (SOI + APP1), not JFIF (SOI + APP0). */
unsigned int i = JPEG_APP1_MAX;
- /* All Exif data is within this 64K header segment. Skip ahead until next SOI for thumbnail. */
+ /* All EXIF data is within this 64K header segment. Skip ahead until next SOI for thumbnail. */
while (!((fgetc(infile) == JPEG_MARKER_MSB) && (fgetc(infile) == JPEG_MARKER_SOI)) &&
!feof(infile) && i--)
;
diff --git a/source/blender/imbuf/intern/openexr/openexr_api.cpp b/source/blender/imbuf/intern/openexr/openexr_api.cpp
index 9948aaac5da..0414fa1268d 100644
--- a/source/blender/imbuf/intern/openexr/openexr_api.cpp
+++ b/source/blender/imbuf/intern/openexr/openexr_api.cpp
@@ -10,6 +10,7 @@
#include <cstddef>
#include <cstdio>
#include <cstdlib>
+#include <fcntl.h>
#include <fstream>
#include <iostream>
#include <set>
@@ -43,6 +44,8 @@
#include <OpenEXR/ImfInputFile.h>
#include <OpenEXR/ImfOutputFile.h>
#include <OpenEXR/ImfPixelType.h>
+#include <OpenEXR/ImfPreviewImage.h>
+#include <OpenEXR/ImfRgbaFile.h>
#include <OpenEXR/ImfStandardAttributes.h>
#include <OpenEXR/ImfStringAttribute.h>
#include <OpenEXR/ImfVersion.h>
@@ -63,6 +66,9 @@
#if defined(WIN32)
# include "utfconv.h"
+# include <io.h>
+#else
+# include <unistd.h>
#endif
#include "MEM_guardedalloc.h"
@@ -77,7 +83,9 @@ _CRTIMP void __cdecl _invalid_parameter_noinfo(void)
#endif
}
#include "BLI_blenlib.h"
+#include "BLI_fileops.h"
#include "BLI_math_color.h"
+#include "BLI_mmap.h"
#include "BLI_string_utils.h"
#include "BLI_threads.h"
@@ -151,6 +159,66 @@ class IMemStream : public Imf::IStream {
unsigned char *_exrbuf;
};
+/* Memory-Mapped Input Stream */
+
+class IMMapStream : public Imf::IStream {
+ public:
+ IMMapStream(const char *filepath) : IStream(filepath)
+ {
+ int file = BLI_open(filepath, O_BINARY | O_RDONLY, 0);
+ if (file < 0) {
+ throw IEX_NAMESPACE::InputExc("file not found");
+ }
+ _exrpos = 0;
+ _exrsize = BLI_file_descriptor_size(file);
+ imb_mmap_lock();
+ _mmap_file = BLI_mmap_open(file);
+ imb_mmap_unlock();
+ if (_mmap_file == nullptr) {
+ throw IEX_NAMESPACE::InputExc("BLI_mmap_open failed");
+ }
+ close(file);
+ _exrbuf = (unsigned char *)BLI_mmap_get_pointer(_mmap_file);
+ }
+
+ ~IMMapStream() override
+ {
+ imb_mmap_lock();
+ BLI_mmap_free(_mmap_file);
+ imb_mmap_unlock();
+ }
+
+ /* This is implementing regular `read`, not `readMemoryMapped`, because DWAA and DWAB
+ * decompressors load on unaligned offsets. Therefore we can't avoid the memory copy. */
+
+ bool read(char c[], int n) override
+ {
+ if (_exrpos + n > _exrsize) {
+ throw Iex::InputExc("Unexpected end of file.");
+ }
+ memcpy(c, _exrbuf + _exrpos, n);
+ _exrpos += n;
+
+ return _exrpos < _exrsize;
+ }
+
+ exr_file_offset_t tellg() override
+ {
+ return _exrpos;
+ }
+
+ void seekg(exr_file_offset_t pos) override
+ {
+ _exrpos = pos;
+ }
+
+ private:
+ BLI_mmap_file *_mmap_file;
+ exr_file_offset_t _exrpos;
+ exr_file_offset_t _exrsize;
+ unsigned char *_exrbuf;
+};
+
/* File Input Stream */
class IFileStream : public Imf::IStream {
@@ -363,7 +431,7 @@ static void openexr_header_compression(Header *header, int compression)
case R_IMF_EXR_CODEC_B44A:
header->compression() = B44A_COMPRESSION;
break;
-#if OPENEXR_VERSION_MAJOR >= 2 && OPENEXR_VERSION_MINOR >= 2
+#if OPENEXR_VERSION_MAJOR > 2 || (OPENEXR_VERSION_MAJOR >= 2 && OPENEXR_VERSION_MINOR >= 2)
case R_IMF_EXR_CODEC_DWAA:
header->compression() = DWAA_COMPRESSION;
break;
@@ -444,7 +512,7 @@ static bool imb_save_openexr_half(ImBuf *ibuf, const char *name, const int flags
/* we store first everything in half array */
std::vector<RGBAZ> pixels(height * width);
- RGBAZ *to = &pixels[0];
+ RGBAZ *to = pixels.data();
int xstride = sizeof(RGBAZ);
int ystride = xstride * width;
@@ -942,7 +1010,7 @@ void IMB_exrtile_begin_write(
/* manually create ofstream, so we can handle utf-8 filepaths on windows */
try {
data->ofile_stream = new OFileStream(filepath);
- data->mpofile = new MultiPartOutputFile(*(data->ofile_stream), &headers[0], headers.size());
+ data->mpofile = new MultiPartOutputFile(*(data->ofile_stream), headers.data(), headers.size());
}
catch (const std::exception &) {
delete data->mpofile;
@@ -1394,12 +1462,10 @@ static int imb_exr_split_channel_name(ExrChannel *echan, char *layname, char *pa
const char *name = echan->m->name.c_str();
const char *end = name + strlen(name);
const char *token;
- char tokenbuf[EXR_TOT_MAXNAME];
- int len;
/* some multilayers have the combined buffer with names A B G R saved */
if (name[1] == 0) {
- echan->chan_id = name[0];
+ echan->chan_id = BLI_toupper_ascii(name[0]);
layname[0] = '\0';
if (ELEM(name[0], 'R', 'G', 'B', 'A')) {
@@ -1416,13 +1482,17 @@ static int imb_exr_split_channel_name(ExrChannel *echan, char *layname, char *pa
}
/* last token is channel identifier */
- len = imb_exr_split_token(name, end, &token);
+ size_t len = imb_exr_split_token(name, end, &token);
if (len == 0) {
printf("multilayer read: bad channel name: %s\n", name);
return 0;
}
+
+ char channelname[EXR_TOT_MAXNAME];
+ BLI_strncpy(channelname, token, std::min(len + 1, sizeof(channelname)));
+
if (len == 1) {
- echan->chan_id = token[0];
+ echan->chan_id = BLI_toupper_ascii(channelname[0]);
}
else if (len > 1) {
bool ok = false;
@@ -1436,36 +1506,35 @@ static int imb_exr_split_channel_name(ExrChannel *echan, char *layname, char *pa
*
* Here we do some magic to distinguish such cases.
*/
- if (ELEM(token[1], 'X', 'Y', 'Z') || ELEM(token[1], 'R', 'G', 'B') ||
- ELEM(token[1], 'U', 'V', 'A')) {
- echan->chan_id = token[1];
+ const char chan_id = BLI_toupper_ascii(channelname[1]);
+ if (ELEM(chan_id, 'X', 'Y', 'Z', 'R', 'G', 'B', 'U', 'V', 'A')) {
+ echan->chan_id = chan_id;
ok = true;
}
}
- else if (BLI_strcaseeq(token, "red")) {
+ else if (BLI_strcaseeq(channelname, "red")) {
echan->chan_id = 'R';
ok = true;
}
- else if (BLI_strcaseeq(token, "green")) {
+ else if (BLI_strcaseeq(channelname, "green")) {
echan->chan_id = 'G';
ok = true;
}
- else if (BLI_strcaseeq(token, "blue")) {
+ else if (BLI_strcaseeq(channelname, "blue")) {
echan->chan_id = 'B';
ok = true;
}
- else if (BLI_strcaseeq(token, "alpha")) {
+ else if (BLI_strcaseeq(channelname, "alpha")) {
echan->chan_id = 'A';
ok = true;
}
- else if (BLI_strcaseeq(token, "depth")) {
+ else if (BLI_strcaseeq(channelname, "depth")) {
echan->chan_id = 'Z';
ok = true;
}
if (ok == false) {
- BLI_strncpy(tokenbuf, token, std::min(len + 1, EXR_TOT_MAXNAME));
- printf("multilayer read: unknown channel token: %s\n", tokenbuf);
+ printf("multilayer read: unknown channel token: %s\n", channelname);
return 0;
}
}
@@ -2098,19 +2167,122 @@ struct ImBuf *imb_load_openexr(const unsigned char *mem,
}
}
-void imb_initopenexr(void)
+struct ImBuf *imb_load_filepath_thumbnail_openexr(const char *filepath,
+ const int UNUSED(flags),
+ const size_t max_thumb_size,
+ char colorspace[],
+ size_t *r_width,
+ size_t *r_height)
{
- int num_threads = BLI_system_thread_count();
+ IStream *stream = nullptr;
+ Imf::RgbaInputFile *file = nullptr;
+
+ /* OpenExr uses exceptions for error-handling. */
+ try {
- setGlobalThreadCount(num_threads);
+ /* The memory-mapped stream is faster, but don't use for huge files as it requires contiguous
+ * address space and we are processing multiple files at once (typically one per processor
+ * core). The 100 MB limit here is arbitrary, but seems reasonable and conservative. */
+ if (BLI_file_size(filepath) < 100 * 1024 * 1024) {
+ stream = new IMMapStream(filepath);
+ }
+ else {
+ stream = new IFileStream(filepath);
+ }
+
+ /* imb_initopenexr() creates a global pool of worker threads. But we thumbnail multiple images
+ * at once, and by default each file will attempt to use the entire pool for itself, stalling
+ * the others. So each thumbnail should use a single thread of the pool. */
+ file = new RgbaInputFile(*stream, 1);
+
+ if (!file->isComplete()) {
+ return nullptr;
+ }
+
+ Imath::Box2i dw = file->dataWindow();
+ int source_w = dw.max.x - dw.min.x + 1;
+ int source_h = dw.max.y - dw.min.y + 1;
+ *r_width = source_w;
+ *r_height = source_h;
+
+ /* If there is an embedded thumbnail, return that instead of making a new one. */
+ if (file->header().hasPreviewImage()) {
+ const Imf::PreviewImage &preview = file->header().previewImage();
+ ImBuf *ibuf = IMB_allocFromBuffer(
+ (unsigned int *)preview.pixels(), nullptr, preview.width(), preview.height(), 4);
+ delete file;
+ delete stream;
+ IMB_flipy(ibuf);
+ return ibuf;
+ }
+
+ /* Create a new thumbnail. */
+
+ if (colorspace && colorspace[0]) {
+ colorspace_set_default_role(colorspace, IM_MAX_SPACE, COLOR_ROLE_DEFAULT_FLOAT);
+ }
+
+ float scale_factor = MIN2((float)max_thumb_size / (float)source_w,
+ (float)max_thumb_size / (float)source_h);
+ int dest_w = (int)(source_w * scale_factor);
+ int dest_h = (int)(source_h * scale_factor);
+
+ struct ImBuf *ibuf = IMB_allocImBuf(dest_w, dest_h, 32, IB_rectfloat);
+
+ /* A single row of source pixels. */
+ Imf::Array<Imf::Rgba> pixels(source_w);
+
+ /* Loop through destination thumbnail rows. */
+ for (int h = 0; h < dest_h; h++) {
+
+ /* Load the single source row that corresponds with destination row. */
+ int source_y = (int)((float)h / scale_factor) + dw.min.y;
+ file->setFrameBuffer(&pixels[0] - dw.min.x - source_y * source_w, 1, source_w);
+ file->readPixels(source_y);
+
+ for (int w = 0; w < dest_w; w++) {
+ /* For each destination pixel find single corresponding source pixel. */
+ int source_x = (int)(MIN2((w / scale_factor), dw.max.x - 1));
+ float *dest_px = &ibuf->rect_float[(h * dest_w + w) * 4];
+ dest_px[0] = pixels[source_x].r;
+ dest_px[1] = pixels[source_x].g;
+ dest_px[2] = pixels[source_x].b;
+ dest_px[3] = pixels[source_x].a;
+ }
+ }
+
+ if (file->lineOrder() == INCREASING_Y) {
+ IMB_flipy(ibuf);
+ }
+
+ delete file;
+ delete stream;
+
+ return ibuf;
+ }
+
+ catch (const std::exception &exc) {
+ std::cerr << exc.what() << std::endl;
+ delete file;
+ delete stream;
+ return nullptr;
+ }
+
+ return nullptr;
+}
+
+void imb_initopenexr(void)
+{
+ /* In a multithreaded program, staticInitialize() must be called once during startup, before the
+ * program accesses any other functions or classes in the IlmImf library. */
+ Imf::staticInitialize();
+ Imf::setGlobalThreadCount(BLI_system_thread_count());
}
void imb_exitopenexr(void)
{
- /* Tells OpenEXR to free thread pool, also ensures there is no running
- * tasks.
- */
- setGlobalThreadCount(0);
+ /* Tells OpenEXR to free thread pool, also ensures there is no running tasks. */
+ Imf::setGlobalThreadCount(0);
}
} /* export "C" */
diff --git a/source/blender/imbuf/intern/openexr/openexr_api.h b/source/blender/imbuf/intern/openexr/openexr_api.h
index c02b03dbe6c..40a724c9f42 100644
--- a/source/blender/imbuf/intern/openexr/openexr_api.h
+++ b/source/blender/imbuf/intern/openexr/openexr_api.h
@@ -26,6 +26,13 @@ bool imb_save_openexr(struct ImBuf *ibuf, const char *name, int flags);
struct ImBuf *imb_load_openexr(const unsigned char *mem, size_t size, int flags, char *colorspace);
+struct ImBuf *imb_load_filepath_thumbnail_openexr(const char *filepath,
+ int flags,
+ size_t max_thumb_size,
+ char colorspace[],
+ size_t *r_width,
+ size_t *r_height);
+
#ifdef __cplusplus
}
#endif
diff --git a/source/blender/imbuf/intern/readimage.c b/source/blender/imbuf/intern/readimage.c
index 805a7e8d687..4b433836767 100644
--- a/source/blender/imbuf/intern/readimage.c
+++ b/source/blender/imbuf/intern/readimage.c
@@ -189,21 +189,21 @@ ImBuf *IMB_loadifffile(
return ibuf;
}
-static void imb_cache_filename(char *filename, const char *name, int flags)
+static void imb_cache_filename(char *filepath, const char *name, int flags)
{
/* read .tx instead if it exists and is not older */
if (flags & IB_tilecache) {
- BLI_strncpy(filename, name, IMB_FILENAME_SIZE);
- if (!BLI_path_extension_replace(filename, IMB_FILENAME_SIZE, ".tx")) {
+ BLI_strncpy(filepath, name, IMB_FILENAME_SIZE);
+ if (!BLI_path_extension_replace(filepath, IMB_FILENAME_SIZE, ".tx")) {
return;
}
- if (BLI_file_older(name, filename)) {
+ if (BLI_file_older(name, filepath)) {
return;
}
}
- BLI_strncpy(filename, name, IMB_FILENAME_SIZE);
+ BLI_strncpy(filepath, name, IMB_FILENAME_SIZE);
}
ImBuf *IMB_loadiffname(const char *filepath, int flags, char colorspace[IM_MAX_SPACE])
diff --git a/source/blender/imbuf/intern/stereoimbuf.c b/source/blender/imbuf/intern/stereoimbuf.c
index 52756891f21..2a0baaf6172 100644
--- a/source/blender/imbuf/intern/stereoimbuf.c
+++ b/source/blender/imbuf/intern/stereoimbuf.c
@@ -702,21 +702,21 @@ int *IMB_stereo3d_from_rect(const ImageFormatData *im_format,
int *rect_left,
int *rect_right)
{
- int *r_rect;
+ int *rect_result;
Stereo3DData s3d_data = {{NULL}};
size_t width, height;
const bool is_float = im_format->depth > 8;
IMB_stereo3d_write_dimensions(
im_format->stereo3d_format.display_mode, false, x, y, &width, &height);
- r_rect = MEM_mallocN(channels * sizeof(int) * width * height, __func__);
+ rect_result = MEM_mallocN(channels * sizeof(int) * width * height, __func__);
imb_stereo3d_data_init(
- &s3d_data, is_float, x, y, channels, rect_left, rect_right, r_rect, NULL, NULL, NULL);
+ &s3d_data, is_float, x, y, channels, rect_left, rect_right, rect_result, NULL, NULL, NULL);
imb_stereo3d_write_doit(&s3d_data, &im_format->stereo3d_format);
- imb_stereo3d_squeeze_rect(r_rect, &im_format->stereo3d_format, x, y, channels);
+ imb_stereo3d_squeeze_rect(rect_result, &im_format->stereo3d_format, x, y, channels);
- return r_rect;
+ return rect_result;
}
float *IMB_stereo3d_from_rectf(const ImageFormatData *im_format,
@@ -726,21 +726,30 @@ float *IMB_stereo3d_from_rectf(const ImageFormatData *im_format,
float *rectf_left,
float *rectf_right)
{
- float *r_rectf;
+ float *rectf_result;
Stereo3DData s3d_data = {{NULL}};
size_t width, height;
const bool is_float = im_format->depth > 8;
IMB_stereo3d_write_dimensions(
im_format->stereo3d_format.display_mode, false, x, y, &width, &height);
- r_rectf = MEM_mallocN(channels * sizeof(float) * width * height, __func__);
+ rectf_result = MEM_mallocN(channels * sizeof(float) * width * height, __func__);
- imb_stereo3d_data_init(
- &s3d_data, is_float, x, y, channels, NULL, NULL, NULL, rectf_left, rectf_right, r_rectf);
+ imb_stereo3d_data_init(&s3d_data,
+ is_float,
+ x,
+ y,
+ channels,
+ NULL,
+ NULL,
+ NULL,
+ rectf_left,
+ rectf_right,
+ rectf_result);
imb_stereo3d_write_doit(&s3d_data, &im_format->stereo3d_format);
- imb_stereo3d_squeeze_rectf(r_rectf, &im_format->stereo3d_format, x, y, channels);
+ imb_stereo3d_squeeze_rectf(rectf_result, &im_format->stereo3d_format, x, y, channels);
- return r_rectf;
+ return rectf_result;
}
ImBuf *IMB_stereo3d_ImBuf(const ImageFormatData *im_format, ImBuf *ibuf_left, ImBuf *ibuf_right)
diff --git a/source/blender/imbuf/intern/thumbs.c b/source/blender/imbuf/intern/thumbs.c
index 51951aa9605..6f39009d38d 100644
--- a/source/blender/imbuf/intern/thumbs.c
+++ b/source/blender/imbuf/intern/thumbs.c
@@ -30,7 +30,6 @@
#include "IMB_thumbs.h"
#include <ctype.h>
-#include <stdio.h>
#include <string.h>
#include <sys/stat.h>
#include <sys/types.h>
@@ -466,27 +465,27 @@ static ImBuf *thumb_create_or_fail(const char *file_path,
return img;
}
-ImBuf *IMB_thumb_create(const char *path, ThumbSize size, ThumbSource source, ImBuf *img)
+ImBuf *IMB_thumb_create(const char *filepath, ThumbSize size, ThumbSource source, ImBuf *img)
{
char uri[URI_MAX] = "";
char thumb_name[40];
- if (!uri_from_filename(path, uri)) {
+ if (!uri_from_filename(filepath, uri)) {
return NULL;
}
thumbname_from_uri(uri, thumb_name, sizeof(thumb_name));
return thumb_create_ex(
- path, uri, thumb_name, false, THUMB_DEFAULT_HASH, NULL, NULL, size, source, img);
+ filepath, uri, thumb_name, false, THUMB_DEFAULT_HASH, NULL, NULL, size, source, img);
}
-ImBuf *IMB_thumb_read(const char *path, ThumbSize size)
+ImBuf *IMB_thumb_read(const char *filepath, ThumbSize size)
{
char thumb[FILE_MAX];
char uri[URI_MAX];
ImBuf *img = NULL;
- if (!uri_from_filename(path, uri)) {
+ if (!uri_from_filename(filepath, uri)) {
return NULL;
}
if (thumbpath_from_uri(uri, thumb, sizeof(thumb), size)) {
@@ -496,16 +495,16 @@ ImBuf *IMB_thumb_read(const char *path, ThumbSize size)
return img;
}
-void IMB_thumb_delete(const char *path, ThumbSize size)
+void IMB_thumb_delete(const char *filepath, ThumbSize size)
{
char thumb[FILE_MAX];
char uri[URI_MAX];
- if (!uri_from_filename(path, uri)) {
+ if (!uri_from_filename(filepath, uri)) {
return;
}
if (thumbpath_from_uri(uri, thumb, sizeof(thumb), size)) {
- if (BLI_path_ncmp(path, thumb, sizeof(thumb)) == 0) {
+ if (BLI_path_ncmp(filepath, thumb, sizeof(thumb)) == 0) {
return;
}
if (BLI_exists(thumb)) {
@@ -514,7 +513,7 @@ void IMB_thumb_delete(const char *path, ThumbSize size)
}
}
-ImBuf *IMB_thumb_manage(const char *org_path, ThumbSize size, ThumbSource source)
+ImBuf *IMB_thumb_manage(const char *filepath, ThumbSize size, ThumbSource source)
{
char thumb_path[FILE_MAX];
char thumb_name[40];
@@ -526,7 +525,7 @@ ImBuf *IMB_thumb_manage(const char *org_path, ThumbSize size, ThumbSource source
ImBuf *img = NULL;
char *blen_group = NULL, *blen_id = NULL;
- path = file_path = org_path;
+ path = file_path = filepath;
if (source == THB_SOURCE_BLEND) {
if (BLO_library_path_explode(path, path_buff, &blen_group, &blen_id)) {
if (blen_group) {
diff --git a/source/blender/imbuf/intern/thumbs_font.c b/source/blender/imbuf/intern/thumbs_font.c
index 7a1c4947c99..c0a33f608a5 100644
--- a/source/blender/imbuf/intern/thumbs_font.c
+++ b/source/blender/imbuf/intern/thumbs_font.c
@@ -41,7 +41,7 @@ void IMB_thumb_ensure_translations(void)
}
}
-struct ImBuf *IMB_thumb_load_font(const char *filename, unsigned int x, unsigned int y)
+struct ImBuf *IMB_thumb_load_font(const char *filepath, unsigned int x, unsigned int y)
{
const int font_size = y / 4;
@@ -60,7 +60,7 @@ struct ImBuf *IMB_thumb_load_font(const char *filename, unsigned int x, unsigned
/* draw with full alpha */
font_color[3] = 1.0f;
- BLF_thumb_preview(filename,
+ BLF_thumb_preview(filepath,
thumb_str,
i18n_thumb_str,
ARRAY_SIZE(thumb_str),
diff --git a/source/blender/imbuf/intern/tiff.c b/source/blender/imbuf/intern/tiff.c
index 1372aa31713..2f13ef409e3 100644
--- a/source/blender/imbuf/intern/tiff.c
+++ b/source/blender/imbuf/intern/tiff.c
@@ -8,15 +8,15 @@
* Provides TIFF file loading and saving for Blender, via libtiff.
*
* The task of loading is complicated somewhat by the fact that Blender has
- * already loaded the file into a memory buffer. libtiff is not well
+ * already loaded the file into a memory buffer. libtiff is not well
* configured to handle files in memory, so a client wrapper is written to
- * surround the memory and turn it into a virtual file. Currently, reading
- * of TIFF files is done using libtiff's RGBAImage support. This is a
+ * surround the memory and turn it into a virtual file. Currently, reading
+ * of TIFF files is done using libtiff's RGBAImage support. This is a
* 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 (gray-scale) images correctly, with
- * 8 bits per channel in all cases. The "deflate" compression algorithm is
+ * 8 bits per channel in all cases. The "deflate" compression algorithm is
* used to compress images.
*/
@@ -151,8 +151,8 @@ static tsize_t imb_tiff_ReadProc(thandle_t handle, tdata_t data, tsize_t n)
/**
* Writes data to an in-memory TIFF file.
*
- * NOTE: The current Blender implementation should not need this function. It
- * is simply a stub.
+ * NOTE: The current Blender implementation should not need this function.
+ * It is simply a stub.
*/
static tsize_t imb_tiff_WriteProc(thandle_t handle, tdata_t data, tsize_t n)
{
@@ -176,7 +176,7 @@ static tsize_t imb_tiff_WriteProc(thandle_t handle, tdata_t data, tsize_t n)
* error).
*
* \return Resulting offset location within the file, measured in bytes from
- * the beginning of the file. (-1) indicates an error.
+ * the beginning of the file. (-1) indicates an error.
*/
static toff_t imb_tiff_SeekProc(thandle_t handle, toff_t ofs, int whence)
{
@@ -215,8 +215,8 @@ static toff_t imb_tiff_SeekProc(thandle_t handle, toff_t ofs, int whence)
* Closes (virtually) an in-memory TIFF file.
*
* NOTE: All this function actually does is sets the data pointer within the
- * TIFF file to NULL. That should trigger assertion errors if attempts
- * are made to access the file after that point. However, no such
+ * TIFF file to NULL. That should trigger assertion errors if attempts
+ * are made to access the file after that point. However, no such
* attempts should ever be made (in theory).
*
* \param handle: Handle of the TIFF file (pointer to #ImbTIFFMemFile).
@@ -734,7 +734,7 @@ bool imb_savetiff(ImBuf *ibuf, const char *filepath, int flags)
int x, y, from_i, to_i, i;
int compress_mode = COMPRESSION_NONE;
- /* check for a valid number of bytes per pixel. Like the PNG writer,
+ /* check for a valid number of bytes per pixel. Like the PNG writer,
* the TIFF writer supports 1, 3 or 4 bytes per pixel, corresponding
* to gray, RGB, RGBA respectively. */
samplesperpixel = (uint16_t)((ibuf->planes + 7) >> 3);
@@ -838,7 +838,7 @@ bool imb_savetiff(ImBuf *ibuf, const char *filepath, int flags)
TIFFSetField(image, TIFFTAG_PHOTOMETRIC, PHOTOMETRIC_MINISBLACK);
}
- /* copy pixel data. While copying, we flip the image vertically. */
+ /* copy pixel data. While copying, we flip the image vertically. */
const int channels_in_float = ibuf->channels ? ibuf->channels : 4;
for (x = 0; x < ibuf->x; x++) {
for (y = 0; y < ibuf->y; y++) {
diff --git a/source/blender/imbuf/intern/transform.cc b/source/blender/imbuf/intern/transform.cc
index edb47c8c7ce..1499c1071e3 100644
--- a/source/blender/imbuf/intern/transform.cc
+++ b/source/blender/imbuf/intern/transform.cc
@@ -293,30 +293,37 @@ class Sampler {
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);
+ bilinear_interpolation_color_fl(source, nullptr, r_sample.data(), 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);
+ nearest_interpolation_color_char(source, r_sample.data(), 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);
+ bilinear_interpolation_color_char(source, r_sample.data(), 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.data(),
+ 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],
+ r_sample.data(),
source->x,
source->y,
NumChannels,
@@ -390,11 +397,11 @@ class ChannelConverter {
BLI_STATIC_ASSERT(SourceNumChannels == 4, "Unsigned chars always have 4 channels.");
BLI_STATIC_ASSERT(DestinationNumChannels == 4, "Unsigned chars always have 4 channels.");
- copy_v4_v4_uchar(pixel_pointer.get_pointer(), &sample[0]);
+ copy_v4_v4_uchar(pixel_pointer.get_pointer(), sample.data());
}
else if constexpr (std::is_same_v<StorageType, float> && SourceNumChannels == 4 &&
DestinationNumChannels == 4) {
- copy_v4_v4(pixel_pointer.get_pointer(), &sample[0]);
+ copy_v4_v4(pixel_pointer.get_pointer(), sample.data());
}
else if constexpr (std::is_same_v<StorageType, float> && SourceNumChannels == 3 &&
DestinationNumChannels == 4) {
diff --git a/source/blender/imbuf/intern/util.c b/source/blender/imbuf/intern/util.c
index 45b50c866fe..ffa989a29b4 100644
--- a/source/blender/imbuf/intern/util.c
+++ b/source/blender/imbuf/intern/util.c
@@ -390,14 +390,3 @@ bool IMB_isanim(const char *filepath)
return (type && type != ANIM_SEQUENCE);
}
-
-bool IMB_isfloat(const ImBuf *ibuf)
-{
- const ImFileType *type = IMB_file_type_from_ibuf(ibuf);
- if (type != NULL) {
- if (type->flag & IM_FTYPE_FLOAT) {
- return true;
- }
- }
- return false;
-}
diff --git a/source/blender/imbuf/intern/util_gpu.c b/source/blender/imbuf/intern/util_gpu.c
index 5abbc84b0ea..5feb0ceb515 100644
--- a/source/blender/imbuf/intern/util_gpu.c
+++ b/source/blender/imbuf/intern/util_gpu.c
@@ -28,17 +28,30 @@ static void imb_gpu_get_format(const ImBuf *ibuf,
eGPUTextureFormat *r_texture_format)
{
const bool float_rect = (ibuf->rect_float != NULL);
- const bool use_srgb = (!IMB_colormanagement_space_is_data(ibuf->rect_colorspace) &&
- !IMB_colormanagement_space_is_scene_linear(ibuf->rect_colorspace));
- high_bitdepth = (!(ibuf->flags & IB_halffloat) && high_bitdepth);
-
- *r_data_format = (float_rect) ? GPU_DATA_FLOAT : GPU_DATA_UBYTE;
if (float_rect) {
- *r_texture_format = high_bitdepth ? GPU_RGBA32F : GPU_RGBA16F;
+ /* Float. */
+ const bool use_high_bitdepth = (!(ibuf->flags & IB_halffloat) && high_bitdepth);
+ *r_data_format = GPU_DATA_FLOAT;
+ *r_texture_format = use_high_bitdepth ? GPU_RGBA32F : GPU_RGBA16F;
}
else {
- *r_texture_format = use_srgb ? GPU_SRGB8_A8 : GPU_RGBA8;
+ if (IMB_colormanagement_space_is_data(ibuf->rect_colorspace) ||
+ IMB_colormanagement_space_is_scene_linear(ibuf->rect_colorspace)) {
+ /* Non-color data or scene linear, just store buffer as is. */
+ *r_data_format = GPU_DATA_UBYTE;
+ *r_texture_format = GPU_RGBA8;
+ }
+ else if (IMB_colormanagement_space_is_srgb(ibuf->rect_colorspace)) {
+ /* sRGB, store as byte texture that the GPU can decode directly. */
+ *r_data_format = GPU_DATA_UBYTE;
+ *r_texture_format = GPU_SRGB8_A8;
+ }
+ else {
+ /* Other colorspace, store as half float texture to avoid precision loss. */
+ *r_data_format = GPU_DATA_FLOAT;
+ *r_texture_format = GPU_RGBA16F;
+ }
}
}
@@ -74,7 +87,6 @@ static bool IMB_gpu_get_compressed_format(const ImBuf *ibuf, eGPUTextureFormat *
static void *imb_gpu_get_data(const ImBuf *ibuf,
const bool do_rescale,
const int rescale_size[2],
- const bool compress_as_srgb,
const bool store_premultiplied,
bool *r_freedata)
{
@@ -99,14 +111,16 @@ static void *imb_gpu_get_data(const ImBuf *ibuf,
}
}
else {
- /* Byte image is in original colorspace from the file. If the file is sRGB
- * scene linear, or non-color data no conversion is needed. Otherwise we
- * compress as scene linear + sRGB transfer function to avoid precision loss
- * in common cases.
+ /* Byte image is in original colorspace from the file, and may need conversion.
*
* We must also convert to premultiplied for correct texture interpolation
* and consistency with float images. */
- if (!IMB_colormanagement_space_is_data(ibuf->rect_colorspace)) {
+ if (IMB_colormanagement_space_is_data(ibuf->rect_colorspace)) {
+ /* Non-color data, just store buffer as is. */
+ }
+ else if (IMB_colormanagement_space_is_srgb(ibuf->rect_colorspace) ||
+ IMB_colormanagement_space_is_scene_linear(ibuf->rect_colorspace)) {
+ /* sRGB or scene linear, store as byte texture that the GPU can decode directly. */
data_rect = MEM_mallocN(sizeof(uchar[4]) * ibuf->x * ibuf->y, __func__);
*r_freedata = freedata = true;
@@ -120,7 +134,24 @@ static void *imb_gpu_get_data(const ImBuf *ibuf,
* zero alpha areas, and appears generally closer to what game engines that we
* want to be compatible with do. */
IMB_colormanagement_imbuf_to_byte_texture(
- (uchar *)data_rect, 0, 0, ibuf->x, ibuf->y, ibuf, compress_as_srgb, store_premultiplied);
+ (uchar *)data_rect, 0, 0, ibuf->x, ibuf->y, ibuf, store_premultiplied);
+ }
+ else {
+ /* Other colorspace, store as float texture to avoid precision loss. */
+ data_rect = MEM_mallocN(sizeof(float[4]) * ibuf->x * ibuf->y, __func__);
+ *r_freedata = freedata = true;
+
+ if (data_rect == NULL) {
+ return NULL;
+ }
+
+ /* Texture storage of images is defined by the alpha mode of the image. The
+ * downside of this is that there can be artifacts near alpha edges. However,
+ * this allows us to use sRGB texture formats and preserves color values in
+ * zero alpha areas, and appears generally closer to what game engines that we
+ * want to be compatible with do. */
+ IMB_colormanagement_imbuf_to_float_texture(
+ (float *)data_rect, 0, 0, ibuf->x, ibuf->y, ibuf, store_premultiplied);
}
}
@@ -154,7 +185,7 @@ GPUTexture *IMB_touch_gpu_texture(
GPUTexture *tex;
if (layers > 0) {
- tex = GPU_texture_create_2d_array(name, w, h, layers, 1, tex_format, NULL);
+ tex = GPU_texture_create_2d_array(name, w, h, layers, 9999, tex_format, NULL);
}
else {
tex = GPU_texture_create_2d(name, w, h, 9999, tex_format, NULL);
@@ -181,10 +212,9 @@ void IMB_update_gpu_texture_sub(GPUTexture *tex,
eGPUTextureFormat tex_format;
imb_gpu_get_format(ibuf, use_high_bitdepth, &data_format, &tex_format);
- const bool compress_as_srgb = (tex_format == GPU_SRGB8_A8);
bool freebuf = false;
- void *data = imb_gpu_get_data(ibuf, do_rescale, size, compress_as_srgb, use_premult, &freebuf);
+ void *data = imb_gpu_get_data(ibuf, do_rescale, size, use_premult, &freebuf);
/* Update Texture. */
GPU_texture_update_sub(tex, data_format, data, x, y, z, w, h, 1);
@@ -197,12 +227,10 @@ void IMB_update_gpu_texture_sub(GPUTexture *tex,
GPUTexture *IMB_create_gpu_texture(const char *name,
ImBuf *ibuf,
bool use_high_bitdepth,
- bool use_premult,
- bool limit_gl_texture_size)
+ bool use_premult)
{
GPUTexture *tex = NULL;
- int size[2] = {GPU_texture_size_with_limit(ibuf->x, limit_gl_texture_size),
- GPU_texture_size_with_limit(ibuf->y, limit_gl_texture_size)};
+ int size[2] = {GPU_texture_size_with_limit(ibuf->x), GPU_texture_size_with_limit(ibuf->y)};
bool do_rescale = (ibuf->x != size[0]) || (ibuf->y != size[1]);
#ifdef WITH_DDS
@@ -240,7 +268,6 @@ GPUTexture *IMB_create_gpu_texture(const char *name,
eGPUTextureFormat tex_format;
imb_gpu_get_format(ibuf, use_high_bitdepth, &data_format, &tex_format);
- const bool compress_as_srgb = (tex_format == GPU_SRGB8_A8);
bool freebuf = false;
/* Create Texture. */
@@ -252,7 +279,7 @@ GPUTexture *IMB_create_gpu_texture(const char *name,
do_rescale = true;
}
BLI_assert(tex != NULL);
- void *data = imb_gpu_get_data(ibuf, do_rescale, size, compress_as_srgb, use_premult, &freebuf);
+ void *data = imb_gpu_get_data(ibuf, do_rescale, size, use_premult, &freebuf);
GPU_texture_update(tex, data_format, data);
GPU_texture_anisotropic_filter(tex, true);
diff --git a/source/blender/imbuf/intern/writeimage.c b/source/blender/imbuf/intern/writeimage.c
index 56c9384a330..d2c0b61c1c5 100644
--- a/source/blender/imbuf/intern/writeimage.c
+++ b/source/blender/imbuf/intern/writeimage.c
@@ -19,11 +19,6 @@
#include "IMB_colormanagement.h"
#include "IMB_colormanagement_intern.h"
-static bool prepare_write_imbuf(const ImFileType *type, ImBuf *ibuf)
-{
- return IMB_prepare_write_ImBuf((type->flag & IM_FTYPE_FLOAT), ibuf);
-}
-
bool IMB_saveiff(struct ImBuf *ibuf, const char *filepath, int flags)
{
errno = 0;
@@ -36,34 +31,22 @@ bool IMB_saveiff(struct ImBuf *ibuf, const char *filepath, int flags)
ibuf->flags = flags;
const ImFileType *type = IMB_file_type_from_ibuf(ibuf);
- if (type != NULL) {
- if (type->save != NULL) {
- prepare_write_imbuf(type, ibuf);
- return type->save(ibuf, filepath, flags);
- }
+ if (type == NULL || type->save == NULL) {
+ fprintf(stderr, "Couldn't save picture.\n");
+ return false;
}
- fprintf(stderr, "Couldn't save picture.\n");
-
- return false;
-}
-
-bool IMB_prepare_write_ImBuf(const bool isfloat, ImBuf *ibuf)
-{
- bool changed = false;
-
- if (isfloat) {
- /* pass */
- }
- else {
+ /* If writing byte image from float buffer, create a byte buffer for writing.
+ *
+ * For color managed image writing, IMB_colormanagement_imbuf_for_write should
+ * have already created this byte buffer. This is a basic fallback for other
+ * cases where we do not have a specific desired output colorspace. */
+ if (!(type->flag & IM_FTYPE_FLOAT)) {
if (ibuf->rect == NULL && ibuf->rect_float) {
ibuf->rect_colorspace = colormanage_colorspace_get_roled(COLOR_ROLE_DEFAULT_BYTE);
IMB_rect_from_float(ibuf);
- if (ibuf->rect != NULL) {
- changed = true;
- }
}
}
- return changed;
+ return type->save(ibuf, filepath, flags);
}
diff --git a/source/blender/io/CMakeLists.txt b/source/blender/io/CMakeLists.txt
index b5f2694c2da..8b20b50a181 100644
--- a/source/blender/io/CMakeLists.txt
+++ b/source/blender/io/CMakeLists.txt
@@ -1,8 +1,21 @@
# SPDX-License-Identifier: GPL-2.0-or-later
# Copyright 2020 Blender Foundation. All rights reserved.
-add_subdirectory(common)
-add_subdirectory(wavefront_obj)
+if(WITH_IO_WAVEFRONT_OBJ OR WITH_IO_STL OR WITH_IO_GPENCIL OR WITH_ALEMBIC OR WITH_USD)
+ add_subdirectory(common)
+endif()
+
+if(WITH_IO_WAVEFRONT_OBJ)
+ add_subdirectory(wavefront_obj)
+endif()
+
+if(WITH_IO_STL)
+ add_subdirectory(stl)
+endif()
+
+if(WITH_IO_GPENCIL)
+ add_subdirectory(gpencil)
+endif()
if(WITH_ALEMBIC)
add_subdirectory(alembic)
@@ -19,5 +32,3 @@ endif()
if(WITH_USD)
add_subdirectory(usd)
endif()
-
-add_subdirectory(gpencil)
diff --git a/source/blender/io/alembic/exporter/abc_custom_props.cc b/source/blender/io/alembic/exporter/abc_custom_props.cc
index 23a39ca2ee6..c5cc4631e18 100644
--- a/source/blender/io/alembic/exporter/abc_custom_props.cc
+++ b/source/blender/io/alembic/exporter/abc_custom_props.cc
@@ -150,7 +150,7 @@ void CustomPropertiesExporter::write_idparray_of_strings(const IDProperty *idp_a
}
/* Alembic needs a pointer to the first value of the array. */
- const std::string *array_of_strings = &strings[0];
+ const std::string *array_of_strings = strings.data();
set_array_property<OStringArrayProperty, std::string>(
idp_array->name, array_of_strings, strings.size());
}
@@ -204,7 +204,7 @@ void CustomPropertiesExporter::write_idparray_flattened_typed(const IDProperty *
}
set_array_property<ABCPropertyType, BlenderValueType>(
- idp_array->name, &matrix_values[0], matrix_values.size());
+ idp_array->name, matrix_values.data(), matrix_values.size());
}
template<typename ABCPropertyType, typename BlenderValueType>
diff --git a/source/blender/io/alembic/exporter/abc_export_capi.cc b/source/blender/io/alembic/exporter/abc_export_capi.cc
index c1ff7df0c37..edaf53b3efa 100644
--- a/source/blender/io/alembic/exporter/abc_export_capi.cc
+++ b/source/blender/io/alembic/exporter/abc_export_capi.cc
@@ -115,7 +115,7 @@ static void export_startjob(void *customdata,
return;
}
- ABCHierarchyIterator iter(data->depsgraph, abc_archive.get(), data->params);
+ ABCHierarchyIterator iter(data->bmain, data->depsgraph, abc_archive.get(), data->params);
if (export_animation) {
CLOG_INFO(&LOG, 2, "Exporting animation");
diff --git a/source/blender/io/alembic/exporter/abc_hierarchy_iterator.cc b/source/blender/io/alembic/exporter/abc_hierarchy_iterator.cc
index d33adfdb4b9..ab62694b802 100644
--- a/source/blender/io/alembic/exporter/abc_hierarchy_iterator.cc
+++ b/source/blender/io/alembic/exporter/abc_hierarchy_iterator.cc
@@ -26,10 +26,11 @@
namespace blender::io::alembic {
-ABCHierarchyIterator::ABCHierarchyIterator(Depsgraph *depsgraph,
+ABCHierarchyIterator::ABCHierarchyIterator(Main *bmain,
+ Depsgraph *depsgraph,
ABCArchive *abc_archive,
const AlembicExportParams &params)
- : AbstractHierarchyIterator(depsgraph), abc_archive_(abc_archive), params_(params)
+ : AbstractHierarchyIterator(bmain, depsgraph), abc_archive_(abc_archive), params_(params)
{
}
diff --git a/source/blender/io/alembic/exporter/abc_hierarchy_iterator.h b/source/blender/io/alembic/exporter/abc_hierarchy_iterator.h
index 24d3f319fbd..f7814c28a55 100644
--- a/source/blender/io/alembic/exporter/abc_hierarchy_iterator.h
+++ b/source/blender/io/alembic/exporter/abc_hierarchy_iterator.h
@@ -13,6 +13,7 @@
#include <Alembic/Abc/OObject.h>
struct Depsgraph;
+struct Main;
struct Object;
namespace blender::io::alembic {
@@ -36,7 +37,8 @@ class ABCHierarchyIterator : public AbstractHierarchyIterator {
const AlembicExportParams &params_;
public:
- ABCHierarchyIterator(Depsgraph *depsgraph,
+ ABCHierarchyIterator(Main *bmain,
+ Depsgraph *depsgraph,
ABCArchive *abc_archive_,
const AlembicExportParams &params);
diff --git a/source/blender/io/alembic/intern/abc_customdata.cc b/source/blender/io/alembic/intern/abc_customdata.cc
index 45bf898f3f5..2820a128072 100644
--- a/source/blender/io/alembic/intern/abc_customdata.cc
+++ b/source/blender/io/alembic/intern/abc_customdata.cc
@@ -48,9 +48,9 @@ static const std::string propNameOriginalCoordinates("Pref");
static void get_uvs(const CDStreamConfig &config,
std::vector<Imath::V2f> &uvs,
std::vector<uint32_t> &uvidx,
- void *cd_data)
+ const void *cd_data)
{
- MLoopUV *mloopuv_array = static_cast<MLoopUV *>(cd_data);
+ const MLoopUV *mloopuv_array = static_cast<const MLoopUV *>(cd_data);
if (!mloopuv_array) {
return;
@@ -68,7 +68,7 @@ static void get_uvs(const CDStreamConfig &config,
/* Iterate in reverse order to match exported polygons. */
for (int i = 0; i < num_poly; i++) {
MPoly &current_poly = polygons[i];
- MLoopUV *loopuv = mloopuv_array + current_poly.loopstart + current_poly.totloop;
+ const MLoopUV *loopuv = mloopuv_array + current_poly.loopstart + current_poly.totloop;
for (int j = 0; j < current_poly.totloop; j++, count++) {
loopuv--;
@@ -87,7 +87,7 @@ static void get_uvs(const CDStreamConfig &config,
for (int i = 0; i < num_poly; i++) {
MPoly &current_poly = polygons[i];
MLoop *looppoly = mloop + current_poly.loopstart + current_poly.totloop;
- MLoopUV *loopuv = mloopuv_array + current_poly.loopstart + current_poly.totloop;
+ const MLoopUV *loopuv = mloopuv_array + current_poly.loopstart + current_poly.totloop;
for (int j = 0; j < current_poly.totloop; j++) {
looppoly--;
@@ -125,7 +125,7 @@ const char *get_uv_sample(UVSample &sample, const CDStreamConfig &config, Custom
return "";
}
- void *cd_data = CustomData_get_layer_n(data, CD_MLOOPUV, active_uvlayer);
+ const void *cd_data = CustomData_get_layer_n(data, CD_MLOOPUV, active_uvlayer);
get_uvs(config, sample.uvs, sample.indices, cd_data);
@@ -139,7 +139,7 @@ const char *get_uv_sample(UVSample &sample, const CDStreamConfig &config, Custom
*/
static void write_uv(const OCompoundProperty &prop,
CDStreamConfig &config,
- void *data,
+ const void *data,
const char *name)
{
std::vector<uint32_t> indices;
@@ -169,12 +169,12 @@ static void write_uv(const OCompoundProperty &prop,
static void get_cols(const CDStreamConfig &config,
std::vector<Imath::C4f> &buffer,
std::vector<uint32_t> &uvidx,
- void *cd_data)
+ const void *cd_data)
{
const float cscale = 1.0f / 255.0f;
- MPoly *polys = config.mpoly;
- MLoop *mloops = config.mloop;
- MCol *cfaces = static_cast<MCol *>(cd_data);
+ const MPoly *polys = config.mpoly;
+ const MLoop *mloops = config.mloop;
+ const MCol *cfaces = static_cast<const MCol *>(cd_data);
buffer.reserve(config.totvert);
uvidx.reserve(config.totvert);
@@ -182,9 +182,9 @@ static void get_cols(const CDStreamConfig &config,
Imath::C4f col;
for (int i = 0; i < config.totpoly; i++) {
- MPoly *p = &polys[i];
- MCol *cface = &cfaces[p->loopstart + p->totloop];
- MLoop *mloop = &mloops[p->loopstart + p->totloop];
+ const MPoly *p = &polys[i];
+ const MCol *cface = &cfaces[p->loopstart + p->totloop];
+ const MLoop *mloop = &mloops[p->loopstart + p->totloop];
for (int j = 0; j < p->totloop; j++) {
cface--;
@@ -207,7 +207,7 @@ static void get_cols(const CDStreamConfig &config,
*/
static void write_mcol(const OCompoundProperty &prop,
CDStreamConfig &config,
- void *data,
+ const void *data,
const char *name)
{
std::vector<uint32_t> indices;
@@ -257,7 +257,7 @@ void write_generated_coordinates(const OCompoundProperty &prop, CDStreamConfig &
/* ORCOs are always stored in the normalized 0..1 range in Blender, but Alembic stores them
* unnormalized, so we need to unnormalize (invert transform) them. */
BKE_mesh_orco_verts_transform(
- mesh, reinterpret_cast<float(*)[3]>(&coords[0]), mesh->totvert, true);
+ mesh, reinterpret_cast<float(*)[3]>(coords.data()), mesh->totvert, true);
if (!config.abc_orco.valid()) {
/* Create the Alembic property and keep a reference so future frames can reuse it. */
@@ -273,7 +273,7 @@ void write_custom_data(const OCompoundProperty &prop,
CustomData *data,
int data_type)
{
- CustomDataType cd_data_type = static_cast<CustomDataType>(data_type);
+ eCustomDataType cd_data_type = static_cast<eCustomDataType>(data_type);
if (!CustomData_has_layer(data, cd_data_type)) {
return;
@@ -283,7 +283,7 @@ void write_custom_data(const OCompoundProperty &prop,
const int tot_layers = CustomData_number_of_layers(data, cd_data_type);
for (int i = 0; i < tot_layers; i++) {
- void *cd_data = CustomData_get_layer_n(data, cd_data_type, i);
+ const void *cd_data = CustomData_get_layer_n(data, cd_data_type, i);
const char *name = CustomData_get_layer_name(data, cd_data_type, i);
if (cd_data_type == CD_MLOOPUV) {
diff --git a/source/blender/io/alembic/intern/abc_reader_mesh.cc b/source/blender/io/alembic/intern/abc_reader_mesh.cc
index 2d2dcfb1f42..d8c48357fc0 100644
--- a/source/blender/io/alembic/intern/abc_reader_mesh.cc
+++ b/source/blender/io/alembic/intern/abc_reader_mesh.cc
@@ -376,26 +376,23 @@ BLI_INLINE void read_uvs_params(CDStreamConfig &config,
static void *add_customdata_cb(Mesh *mesh, const char *name, int data_type)
{
- CustomDataType cd_data_type = static_cast<CustomDataType>(data_type);
- void *cd_ptr;
- CustomData *loopdata;
- int numloops;
+ eCustomDataType cd_data_type = static_cast<eCustomDataType>(data_type);
/* unsupported custom data type -- don't do anything. */
if (!ELEM(cd_data_type, CD_MLOOPUV, CD_PROP_BYTE_COLOR)) {
return nullptr;
}
- loopdata = &mesh->ldata;
- cd_ptr = CustomData_get_layer_named(loopdata, cd_data_type, name);
+ void *cd_ptr = CustomData_get_layer_named(&mesh->ldata, cd_data_type, name);
if (cd_ptr != nullptr) {
/* layer already exists, so just return it. */
return cd_ptr;
}
/* Create a new layer. */
- numloops = mesh->totloop;
- cd_ptr = CustomData_add_layer_named(loopdata, cd_data_type, CD_DEFAULT, nullptr, numloops, name);
+ int numloops = mesh->totloop;
+ cd_ptr = CustomData_add_layer_named(
+ &mesh->ldata, cd_data_type, CD_DEFAULT, nullptr, numloops, name);
return cd_ptr;
}
@@ -622,7 +619,7 @@ void AbcMeshReader::readObjectData(Main *bmain, const Alembic::Abc::ISampleSelec
if (read_mesh != mesh) {
/* XXX FIXME: after 2.80; mesh->flag isn't copied by #BKE_mesh_nomain_to_mesh(). */
/* read_mesh can be freed by BKE_mesh_nomain_to_mesh(), so get the flag before that happens. */
- short autosmooth = (read_mesh->flag & ME_AUTOSMOOTH);
+ uint16_t autosmooth = (read_mesh->flag & ME_AUTOSMOOTH);
BKE_mesh_nomain_to_mesh(read_mesh, mesh, m_object, &CD_MASK_EVERYTHING, true);
mesh->flag |= autosmooth;
}
diff --git a/source/blender/io/alembic/intern/alembic_capi.cc b/source/blender/io/alembic/intern/alembic_capi.cc
index 0d4e1d04db0..1fb535a57f2 100644
--- a/source/blender/io/alembic/intern/alembic_capi.cc
+++ b/source/blender/io/alembic/intern/alembic_capi.cc
@@ -573,12 +573,10 @@ static void import_endjob(void *user_data)
ImportJobData *data = static_cast<ImportJobData *>(user_data);
- std::vector<AbcObjectReader *>::iterator iter;
-
/* Delete objects on cancellation. */
if (data->was_cancelled) {
- for (iter = data->readers.begin(); iter != data->readers.end(); ++iter) {
- Object *ob = (*iter)->object();
+ for (AbcObjectReader *reader : data->readers) {
+ Object *ob = reader->object();
/* It's possible that cancellation occurred between the creation of
* the reader and the creation of the Blender object. */
@@ -590,7 +588,6 @@ static void import_endjob(void *user_data)
}
}
else {
- /* Add object to scene. */
Base *base;
LayerCollection *lc;
ViewLayer *view_layer = data->view_layer;
@@ -599,11 +596,17 @@ static void import_endjob(void *user_data)
lc = BKE_layer_collection_get_active(view_layer);
- for (iter = data->readers.begin(); iter != data->readers.end(); ++iter) {
- Object *ob = (*iter)->object();
-
+ /* Add all objects to the collection (don't do sync for each object). */
+ BKE_layer_collection_resync_forbid();
+ for (AbcObjectReader *reader : data->readers) {
+ Object *ob = reader->object();
BKE_collection_object_add(data->bmain, lc->collection, ob);
-
+ }
+ /* Sync the collection, and do view layer operations. */
+ BKE_layer_collection_resync_allow();
+ BKE_main_collection_sync(data->bmain);
+ for (AbcObjectReader *reader : data->readers) {
+ Object *ob = reader->object();
base = BKE_view_layer_base_find(view_layer, ob);
/* TODO: is setting active needed? */
BKE_view_layer_base_select_and_set_active(view_layer, base);
@@ -625,8 +628,7 @@ static void import_endjob(void *user_data)
}
}
- for (iter = data->readers.begin(); iter != data->readers.end(); ++iter) {
- AbcObjectReader *reader = *iter;
+ for (AbcObjectReader *reader : data->readers) {
reader->decref();
if (reader->refcount() == 0) {
diff --git a/source/blender/io/avi/AVI_avi.h b/source/blender/io/avi/AVI_avi.h
index e3af171355d..0857b9191b2 100644
--- a/source/blender/io/avi/AVI_avi.h
+++ b/source/blender/io/avi/AVI_avi.h
@@ -235,7 +235,8 @@ AviError AVI_close_compress(AviMovie *movie);
*/
AviError AVI_set_compress_option(
AviMovie *movie, int option_type, int stream, AviOption option, void *opt_data);
-/* Hmmm... there should be some explanation about what these mean */
+
+/* TODO: there should be some explanation about what these mean. */
/**
* Compression option, for use in avi_set_compress_option
*/
diff --git a/source/blender/io/collada/AnimationImporter.h b/source/blender/io/collada/AnimationImporter.h
index 7c5b38f5f8d..1c5b7570b9d 100644
--- a/source/blender/io/collada/AnimationImporter.h
+++ b/source/blender/io/collada/AnimationImporter.h
@@ -228,7 +228,7 @@ class AnimationImporter : private TransformReader, public AnimationImporterBase
COLLADAFW::Transformation::TransformationType tm_type);
/**
* Internal, better make it private
- * warning: evaluates only rotation and only assigns matrix transforms now
+ * WARNING: evaluates only rotation and only assigns matrix transforms now
* prerequisites: animlist_map, curve_map.
*/
void evaluate_transform_at_frame(float mat[4][4], COLLADAFW::Node *node, float fra);
diff --git a/source/blender/io/collada/BCAnimationSampler.cpp b/source/blender/io/collada/BCAnimationSampler.cpp
index 29c17b500f3..cbb30ccf51d 100644
--- a/source/blender/io/collada/BCAnimationSampler.cpp
+++ b/source/blender/io/collada/BCAnimationSampler.cpp
@@ -225,24 +225,26 @@ bool BCAnimationSampler::is_animated_by_constraint(Object *ob,
for (con = (bConstraint *)conlist->first; con; con = con->next) {
ListBase targets = {nullptr, nullptr};
- const bConstraintTypeInfo *cti = BKE_constraint_typeinfo_get(con);
-
if (!bc_validateConstraints(con)) {
continue;
}
- if (cti && cti->get_constraint_targets) {
+ if (BKE_constraint_targets_get(con, &targets)) {
bConstraintTarget *ct;
Object *obtar;
- cti->get_constraint_targets(con, &targets);
+ bool found = false;
+
for (ct = (bConstraintTarget *)targets.first; ct; ct = ct->next) {
obtar = ct->tar;
if (obtar) {
if (animated_objects.find(obtar) != animated_objects.end()) {
- return true;
+ found = true;
+ break;
}
}
}
+ BKE_constraint_targets_flush(con, &targets, true);
+ return found;
}
}
return false;
diff --git a/source/blender/io/collada/BCMath.cpp b/source/blender/io/collada/BCMath.cpp
index fc97110611a..d48e46ca115 100644
--- a/source/blender/io/collada/BCMath.cpp
+++ b/source/blender/io/collada/BCMath.cpp
@@ -49,11 +49,7 @@ BCMatrix::BCMatrix(BC_global_forward_axis global_forward_axis, BC_global_up_axis
float mrot[3][3];
float mat[4][4];
mat3_from_axis_conversion(
- BC_DEFAULT_FORWARD, BC_DEFAULT_UP, global_forward_axis, global_up_axis, mrot);
-
- /* TODO: Verify that `mat3_from_axis_conversion()` returns a transposed matrix */
- transpose_m3(mrot);
-
+ global_forward_axis, global_up_axis, BC_DEFAULT_FORWARD, BC_DEFAULT_UP, mrot);
copy_m4_m3(mat, mrot);
set_transform(mat);
}
diff --git a/source/blender/io/collada/GeometryExporter.cpp b/source/blender/io/collada/GeometryExporter.cpp
index 3952a4ae334..7e2a24aeb41 100644
--- a/source/blender/io/collada/GeometryExporter.cpp
+++ b/source/blender/io/collada/GeometryExporter.cpp
@@ -477,7 +477,8 @@ void GeometryExporter::createVertexColorSource(std::string geom_id, Mesh *me)
for (int a = 0; a < totlayer_mcol; a++) {
map_index++;
- MLoopCol *mloopcol = (MLoopCol *)CustomData_get_layer_n(&me->ldata, CD_PROP_BYTE_COLOR, a);
+ const MLoopCol *mloopcol = (const MLoopCol *)CustomData_get_layer_n(
+ &me->ldata, CD_PROP_BYTE_COLOR, a);
COLLADASW::FloatSourceF source(mSW);
@@ -502,7 +503,7 @@ void GeometryExporter::createVertexColorSource(std::string geom_id, Mesh *me)
MPoly *mpoly;
int i;
for (i = 0, mpoly = me->mpoly; i < me->totpoly; i++, mpoly++) {
- MLoopCol *mlc = mloopcol + mpoly->loopstart;
+ const MLoopCol *mlc = mloopcol + mpoly->loopstart;
for (int j = 0; j < mpoly->totloop; j++, mlc++) {
source.appendValues(mlc->r / 255.0f, mlc->g / 255.0f, mlc->b / 255.0f, mlc->a / 255.0f);
}
@@ -619,7 +620,7 @@ void GeometryExporter::create_normals(std::vector<Normal> &normals,
MVert *verts = me->mvert;
const float(*vert_normals)[3] = BKE_mesh_vertex_normals_ensure(me);
MLoop *mloops = me->mloop;
- float(*lnors)[3] = nullptr;
+ const float(*lnors)[3] = nullptr;
bool use_custom_normals = false;
BKE_mesh_calc_normals_split(me);
diff --git a/source/blender/io/collada/MeshImporter.h b/source/blender/io/collada/MeshImporter.h
index 79b9778738d..416b5728b66 100644
--- a/source/blender/io/collada/MeshImporter.h
+++ b/source/blender/io/collada/MeshImporter.h
@@ -72,7 +72,7 @@ class MeshImporter : public MeshImporterBase {
std::map<std::string, std::string> mesh_geom_map; /* needed for correct shape key naming */
std::map<COLLADAFW::UniqueId, Mesh *> uid_mesh_map; /* geometry unique id-to-mesh map */
- std::map<COLLADAFW::UniqueId, Object *> uid_object_map; /* geom uid-to-object */
+ std::map<COLLADAFW::UniqueId, Object *> uid_object_map; /* geom UID-to-object */
std::vector<Object *> imported_objects; /* list of imported objects */
/* this structure is used to assign material indices to polygons
@@ -86,7 +86,7 @@ class MeshImporter : public MeshImporterBase {
/* crazy name! */
std::map<COLLADAFW::UniqueId, MaterialIdPrimitiveArrayMap> geom_uid_mat_mapping_map;
/* < materials that have already been mapped to a geometry.
- * A pair/of geom uid and mat uid, one geometry can have several materials */
+ * A pair/of geom UID and mat UID, one geometry can have several materials. */
std::multimap<COLLADAFW::UniqueId, COLLADAFW::UniqueId> materials_mapped_to_geom;
bool set_poly_indices(
@@ -142,7 +142,7 @@ class MeshImporter : public MeshImporterBase {
/**
* Return the number of faces by summing up
* the face-counts of the parts.
- * hint: This is done because `mesh->getFacesCount()` does
+ * HINT: This is done because `mesh->getFacesCount()` does
* count loose edges as extra faces, which is not what we want here.
*/
void allocate_poly_data(COLLADAFW::Mesh *collada_mesh, Mesh *me);
@@ -150,7 +150,7 @@ class MeshImporter : public MeshImporterBase {
/* TODO: import uv set names */
/**
* Read all faces from TRIANGLES, TRIANGLE_FANS, POLYLIST, POLYGON
- * Important: This function MUST be called before read_lines()
+ * IMPORTANT: This function MUST be called before read_lines()
* Otherwise we will lose all edges from faces (see read_lines() above)
*
* TODO: import uv set names.
@@ -158,7 +158,7 @@ class MeshImporter : public MeshImporterBase {
void read_polys(COLLADAFW::Mesh *mesh, Mesh *me);
/**
* Read all loose edges.
- * Important: This function assumes that all edges from existing
+ * IMPORTANT: This function assumes that all edges from existing
* faces have already been generated and added to me->medge
* So this function MUST be called after read_faces() (see below)
*/
diff --git a/source/blender/io/collada/SceneExporter.cpp b/source/blender/io/collada/SceneExporter.cpp
index ea95729666a..1b1da110573 100644
--- a/source/blender/io/collada/SceneExporter.cpp
+++ b/source/blender/io/collada/SceneExporter.cpp
@@ -191,24 +191,19 @@ void SceneExporter::writeNode(Object *ob)
/* not ideal: add the target object name as another parameter.
* No real mapping in the `.dae`.
* Need support for multiple target objects also. */
- const bConstraintTypeInfo *cti = BKE_constraint_typeinfo_get(con);
- ListBase targets = {nullptr, nullptr};
- if (cti && cti->get_constraint_targets) {
+ ListBase targets = {nullptr, nullptr};
+ if (BKE_constraint_targets_get(con, &targets)) {
bConstraintTarget *ct;
Object *obtar;
- cti->get_constraint_targets(con, &targets);
-
for (ct = (bConstraintTarget *)targets.first; ct; ct = ct->next) {
obtar = ct->tar;
std::string tar_id((obtar) ? id_name(obtar) : "");
colladaNode.addExtraTechniqueChildParameter("blender", con_tag, "target_id", tar_id);
}
- if (cti->flush_constraint_targets) {
- cti->flush_constraint_targets(con, &targets, true);
- }
+ BKE_constraint_targets_flush(con, &targets, true);
}
con = con->next;
diff --git a/source/blender/io/common/CMakeLists.txt b/source/blender/io/common/CMakeLists.txt
index b1add38bf01..a6818c0bf5d 100644
--- a/source/blender/io/common/CMakeLists.txt
+++ b/source/blender/io/common/CMakeLists.txt
@@ -8,7 +8,7 @@ set(INC
../../depsgraph
../../makesdna
../../../../intern/guardedalloc
- ../../../../extern/fast_float
+ ../../makesrna
)
set(INC_SYS
@@ -19,12 +19,15 @@ set(SRC
intern/dupli_parent_finder.cc
intern/dupli_persistent_id.cc
intern/object_identifier.cc
- intern/string_utils.cc
+ intern/path_util.cc
+ intern/orientation.c
IO_abstract_hierarchy_iterator.h
IO_dupli_persistent_id.hh
- IO_string_utils.hh
+ IO_path_util.hh
+ IO_path_util_types.h
IO_types.h
+ IO_orientation.h
intern/dupli_parent_finder.hh
)
@@ -42,7 +45,6 @@ if(WITH_GTESTS)
intern/abstract_hierarchy_iterator_test.cc
intern/hierarchy_context_order_test.cc
intern/object_identifier_test.cc
- intern/string_utils_test.cc
)
set(TEST_INC
../../blenloader
diff --git a/source/blender/io/common/IO_abstract_hierarchy_iterator.h b/source/blender/io/common/IO_abstract_hierarchy_iterator.h
index 3c6b6cc631e..a67cfe6a9d6 100644
--- a/source/blender/io/common/IO_abstract_hierarchy_iterator.h
+++ b/source/blender/io/common/IO_abstract_hierarchy_iterator.h
@@ -30,6 +30,7 @@
struct Depsgraph;
struct DupliObject;
struct ID;
+struct Main;
struct Object;
struct ParticleSystem;
@@ -58,9 +59,8 @@ struct HierarchyContext {
*
* The export hierarchy is kept as close to the hierarchy in Blender as possible. As such, an
* object that serves as a parent for another object, but which should NOT be exported itself, is
- * exported only as transform (i.e. as empty). This happens with objects that are part of a
- * holdout collection (which prevents them from being exported) but also parent of an exported
- * object. */
+ * exported only as transform (i.e. as empty). This happens with objects that are invisible when
+ * exporting with "Visible Only" enabled, for example. */
bool weak_export;
/* When true, this object should check its parents for animation data when determining whether
@@ -204,12 +204,13 @@ class AbstractHierarchyIterator {
protected:
ExportGraph export_graph_;
ExportPathMap duplisource_export_path_;
+ Main *bmain_;
Depsgraph *depsgraph_;
WriterMap writers_;
ExportSubset export_subset_;
public:
- explicit AbstractHierarchyIterator(Depsgraph *depsgraph);
+ explicit AbstractHierarchyIterator(Main *bmain, Depsgraph *depsgraph);
virtual ~AbstractHierarchyIterator();
/* Iterate over the depsgraph, create writers, and tell the writers to write.
diff --git a/source/blender/io/common/IO_orientation.h b/source/blender/io/common/IO_orientation.h
new file mode 100644
index 00000000000..09fcbc7045c
--- /dev/null
+++ b/source/blender/io/common/IO_orientation.h
@@ -0,0 +1,16 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+
+#pragma once
+
+#include "RNA_types.h"
+
+typedef enum {
+ IO_AXIS_X = 0,
+ IO_AXIS_Y = 1,
+ IO_AXIS_Z = 2,
+ IO_AXIS_NEGATIVE_X = 3,
+ IO_AXIS_NEGATIVE_Y = 4,
+ IO_AXIS_NEGATIVE_Z = 5,
+} eIOAxis;
+
+extern const EnumPropertyItem io_transform_axis[];
diff --git a/source/blender/io/common/IO_path_util.hh b/source/blender/io/common/IO_path_util.hh
new file mode 100644
index 00000000000..eeb5a9dbcfe
--- /dev/null
+++ b/source/blender/io/common/IO_path_util.hh
@@ -0,0 +1,29 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+#pragma once
+
+#include "BLI_set.hh"
+#include "BLI_string_ref.hh"
+
+#include "IO_path_util_types.h"
+
+namespace blender::io {
+
+/**
+ * Return a filepath relative to a destination directory, for use with
+ * exporters.
+ *
+ * When PATH_REFERENCE_COPY mode is used, the file path pair (source
+ * path, destination path) is added to the `copy_set`.
+ *
+ * Equivalent of bpy_extras.io_utils.path_reference.
+ */
+std::string path_reference(StringRefNull filepath,
+ StringRefNull base_src,
+ StringRefNull base_dst,
+ ePathReferenceMode mode,
+ Set<std::pair<std::string, std::string>> *copy_set = nullptr);
+
+/** Execute copying files of path_reference. */
+void path_reference_copy(const Set<std::pair<std::string, std::string>> &copy_set);
+
+} // namespace blender::io
diff --git a/source/blender/io/common/IO_path_util_types.h b/source/blender/io/common/IO_path_util_types.h
new file mode 100644
index 00000000000..0233f601a81
--- /dev/null
+++ b/source/blender/io/common/IO_path_util_types.h
@@ -0,0 +1,18 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+#pragma once
+
+/** Method used to reference paths. Equivalent of bpy_extras.io_utils.path_reference_mode. */
+typedef enum {
+ /** Use Relative paths with subdirectories only. */
+ PATH_REFERENCE_AUTO = 0,
+ /** Always write absolute paths. */
+ PATH_REFERENCE_ABSOLUTE = 1,
+ /** Write relative paths where possible. */
+ PATH_REFERENCE_RELATIVE = 2,
+ /** Match Absolute/Relative setting with input path. */
+ PATH_REFERENCE_MATCH = 3,
+ /** Filename only. */
+ PATH_REFERENCE_STRIP = 4,
+ /** Copy the file to the destination path. */
+ PATH_REFERENCE_COPY = 5,
+} ePathReferenceMode;
diff --git a/source/blender/io/common/IO_string_utils.hh b/source/blender/io/common/IO_string_utils.hh
deleted file mode 100644
index 25f1f01c6ed..00000000000
--- a/source/blender/io/common/IO_string_utils.hh
+++ /dev/null
@@ -1,69 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0-or-later */
-
-#pragma once
-
-#include "BLI_string_ref.hh"
-
-/*
- * Various text parsing utilities commonly used by text-based input formats.
- */
-
-namespace blender::io {
-
-/**
- * Fetches next line from an input string buffer.
- *
- * The returned line will not have '\n' characters at the end;
- * the `buffer` is modified to contain remaining text without
- * the input line.
- *
- * Note that backslash (\) character is treated as a line
- * continuation, similar to OBJ file format or a C preprocessor.
- */
-StringRef read_next_line(StringRef &buffer);
-
-/**
- * Drop leading white-space from a StringRef.
- * Note that backslash character is considered white-space.
- */
-StringRef drop_whitespace(StringRef str);
-
-/**
- * Drop leading non-white-space from a StringRef.
- * Note that backslash character is considered white-space.
- */
-StringRef drop_non_whitespace(StringRef str);
-
-/**
- * Parse an integer from an input string.
- * The parsed result is stored in `dst`. The function skips
- * leading white-space unless `skip_space=false`. If the
- * number can't be parsed (invalid syntax, out of range),
- * `fallback` value is stored instead.
- *
- * Returns the remainder of the input string after parsing.
- */
-StringRef parse_int(StringRef str, int fallback, int &dst, bool skip_space = true);
-
-/**
- * Parse a float from an input string.
- * The parsed result is stored in `dst`. The function skips
- * leading white-space unless `skip_space=false`. If the
- * number can't be parsed (invalid syntax, out of range),
- * `fallback` value is stored instead.
- *
- * Returns the remainder of the input string after parsing.
- */
-StringRef parse_float(StringRef str, float fallback, float &dst, bool skip_space = true);
-
-/**
- * Parse a number of white-space separated floats from an input string.
- * The parsed `count` numbers are stored in `dst`. If a
- * number can't be parsed (invalid syntax, out of range),
- * `fallback` value is stored instead.
- *
- * Returns the remainder of the input string after parsing.
- */
-StringRef parse_floats(StringRef str, float fallback, float *dst, int count);
-
-} // namespace blender::io
diff --git a/source/blender/io/common/intern/abstract_hierarchy_iterator.cc b/source/blender/io/common/intern/abstract_hierarchy_iterator.cc
index f0501d4cf62..1fbddc45964 100644
--- a/source/blender/io/common/intern/abstract_hierarchy_iterator.cc
+++ b/source/blender/io/common/intern/abstract_hierarchy_iterator.cc
@@ -161,8 +161,8 @@ bool AbstractHierarchyWriter::check_has_deforming_physics(const HierarchyContext
return rbo != nullptr && rbo->type == RBO_TYPE_ACTIVE && (rbo->flag & RBO_FLAG_USE_DEFORM) != 0;
}
-AbstractHierarchyIterator::AbstractHierarchyIterator(Depsgraph *depsgraph)
- : depsgraph_(depsgraph), export_subset_({true, true})
+AbstractHierarchyIterator::AbstractHierarchyIterator(Main *bmain, Depsgraph *depsgraph)
+ : bmain_(bmain), depsgraph_(depsgraph), export_subset_({true, true})
{
}
@@ -267,6 +267,11 @@ void AbstractHierarchyIterator::export_graph_construct()
{
Scene *scene = DEG_get_evaluated_scene(depsgraph_);
+ /* Add a "null" root node with no children immediately for the case where the top-most node in
+ * the scene is not being exported and a root node otherwise wouldn't get added. */
+ ExportGraph::key_type root_node_id = ObjectIdentifier::for_real_object(nullptr);
+ export_graph_[root_node_id] = ExportChildren();
+
DEG_OBJECT_ITER_BEGIN (depsgraph_,
object,
DEG_ITER_OBJECT_FLAG_LINKED_DIRECTLY |
diff --git a/source/blender/io/common/intern/abstract_hierarchy_iterator_test.cc b/source/blender/io/common/intern/abstract_hierarchy_iterator_test.cc
index 52cae89c2e8..81a3546259e 100644
--- a/source/blender/io/common/intern/abstract_hierarchy_iterator_test.cc
+++ b/source/blender/io/common/intern/abstract_hierarchy_iterator_test.cc
@@ -54,7 +54,8 @@ class TestingHierarchyIterator : public AbstractHierarchyIterator {
used_writers hair_writers;
used_writers particle_writers;
- explicit TestingHierarchyIterator(Depsgraph *depsgraph) : AbstractHierarchyIterator(depsgraph)
+ explicit TestingHierarchyIterator(Main *bmain, Depsgraph *depsgraph)
+ : AbstractHierarchyIterator(bmain, depsgraph)
{
}
~TestingHierarchyIterator() override
@@ -105,7 +106,7 @@ class AbstractHierarchyIteratorTest : public BlendfileLoadingBaseTest {
/* Create a test iterator. */
void iterator_create()
{
- iterator = new TestingHierarchyIterator(depsgraph);
+ iterator = new TestingHierarchyIterator(bfile->main, depsgraph);
}
/* Free the test iterator if it is not nullptr. */
void iterator_free()
diff --git a/source/blender/io/common/intern/orientation.c b/source/blender/io/common/intern/orientation.c
new file mode 100644
index 00000000000..0ffbaa8fe8e
--- /dev/null
+++ b/source/blender/io/common/intern/orientation.c
@@ -0,0 +1,14 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+
+#include "RNA_types.h"
+
+#include "IO_orientation.h"
+
+const EnumPropertyItem io_transform_axis[] = {
+ {IO_AXIS_X, "X", 0, "X", "Positive X axis"},
+ {IO_AXIS_Y, "Y", 0, "Y", "Positive Y axis"},
+ {IO_AXIS_Z, "Z", 0, "Z", "Positive Z axis"},
+ {IO_AXIS_NEGATIVE_X, "NEGATIVE_X", 0, "-X", "Negative X axis"},
+ {IO_AXIS_NEGATIVE_Y, "NEGATIVE_Y", 0, "-Y", "Negative Y axis"},
+ {IO_AXIS_NEGATIVE_Z, "NEGATIVE_Z", 0, "-Z", "Negative Z axis"},
+ {0, NULL, 0, NULL, NULL}};
diff --git a/source/blender/io/common/intern/path_util.cc b/source/blender/io/common/intern/path_util.cc
new file mode 100644
index 00000000000..902cf552bf0
--- /dev/null
+++ b/source/blender/io/common/intern/path_util.cc
@@ -0,0 +1,82 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+#include "IO_path_util.hh"
+
+#include "BLI_fileops.h"
+#include "BLI_path_util.h"
+
+namespace blender::io {
+
+std::string path_reference(StringRefNull filepath,
+ StringRefNull base_src,
+ StringRefNull base_dst,
+ ePathReferenceMode mode,
+ Set<std::pair<std::string, std::string>> *copy_set)
+{
+ const bool is_relative = BLI_path_is_rel(filepath.c_str());
+ char filepath_abs[PATH_MAX];
+ BLI_strncpy(filepath_abs, filepath.c_str(), PATH_MAX);
+ BLI_path_abs(filepath_abs, base_src.c_str());
+ BLI_path_normalize(nullptr, filepath_abs);
+
+ /* Figure out final mode to be used. */
+ if (mode == PATH_REFERENCE_MATCH) {
+ mode = is_relative ? PATH_REFERENCE_RELATIVE : PATH_REFERENCE_ABSOLUTE;
+ }
+ else if (mode == PATH_REFERENCE_AUTO) {
+ mode = BLI_path_contains(base_dst.c_str(), filepath_abs) ? PATH_REFERENCE_RELATIVE :
+ PATH_REFERENCE_ABSOLUTE;
+ }
+ else if (mode == PATH_REFERENCE_COPY) {
+ char filepath_cpy[PATH_MAX];
+ BLI_path_join(
+ filepath_cpy, PATH_MAX, base_dst.c_str(), BLI_path_basename(filepath_abs), nullptr);
+ copy_set->add(std::make_pair(filepath_abs, filepath_cpy));
+ BLI_strncpy(filepath_abs, filepath_cpy, PATH_MAX);
+ mode = PATH_REFERENCE_RELATIVE;
+ }
+
+ /* Now we know the final path mode. */
+ if (mode == PATH_REFERENCE_ABSOLUTE) {
+ return filepath_abs;
+ }
+ else if (mode == PATH_REFERENCE_RELATIVE) {
+ char rel_path[PATH_MAX];
+ BLI_strncpy(rel_path, filepath_abs, PATH_MAX);
+ BLI_path_rel(rel_path, base_dst.c_str());
+ /* Can't always find relative path (e.g. between different drives). */
+ if (!BLI_path_is_rel(rel_path)) {
+ return filepath_abs;
+ }
+ return rel_path + 2; /* Skip blender's internal "//" prefix. */
+ }
+ else if (mode == PATH_REFERENCE_STRIP) {
+ return BLI_path_basename(filepath_abs);
+ }
+ BLI_assert_msg(false, "Invalid path reference mode");
+ return filepath_abs;
+}
+
+void path_reference_copy(const Set<std::pair<std::string, std::string>> &copy_set)
+{
+ for (const auto &copy : copy_set) {
+ const char *src = copy.first.c_str();
+ const char *dst = copy.second.c_str();
+ if (!BLI_exists(src)) {
+ fprintf(stderr, "Missing source file '%s', not copying\n", src);
+ continue;
+ }
+ if (0 == BLI_path_cmp_normalized(src, dst)) {
+ continue; /* Source and dest are the same. */
+ }
+ if (!BLI_make_existing_file(dst)) {
+ fprintf(stderr, "Can't make directory for '%s', not copying\n", dst);
+ continue;
+ }
+ if (!BLI_copy(src, dst)) {
+ fprintf(stderr, "Can't copy '%s' to '%s'\n", src, dst);
+ continue;
+ }
+ }
+}
+
+} // namespace blender::io
diff --git a/source/blender/io/common/intern/string_utils.cc b/source/blender/io/common/intern/string_utils.cc
deleted file mode 100644
index 3a12250e14b..00000000000
--- a/source/blender/io/common/intern/string_utils.cc
+++ /dev/null
@@ -1,99 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0-or-later */
-
-#include "IO_string_utils.hh"
-
-/* Note: we could use C++17 <charconv> from_chars to parse
- * floats, but even if some compilers claim full support,
- * their standard libraries are not quite there yet.
- * LLVM/libc++ only has a float parser since LLVM 14,
- * and gcc/libstdc++ since 11.1. So until at least these are
- * the minimum spec, use an external library. */
-#include "fast_float.h"
-#include <charconv>
-
-namespace blender::io {
-
-StringRef read_next_line(StringRef &buffer)
-{
- const char *start = buffer.begin();
- const char *end = buffer.end();
- size_t len = 0;
- char prev = 0;
- const char *ptr = start;
- while (ptr < end) {
- char c = *ptr++;
- if (c == '\n' && prev != '\\') {
- break;
- }
- prev = c;
- ++len;
- }
-
- buffer = StringRef(ptr, end);
- return StringRef(start, len);
-}
-
-static bool is_whitespace(char c)
-{
- return c <= ' ' || c == '\\';
-}
-
-StringRef drop_whitespace(StringRef str)
-{
- while (!str.is_empty() && is_whitespace(str[0])) {
- str = str.drop_prefix(1);
- }
- return str;
-}
-
-StringRef drop_non_whitespace(StringRef str)
-{
- while (!str.is_empty() && !is_whitespace(str[0])) {
- str = str.drop_prefix(1);
- }
- return str;
-}
-
-static StringRef drop_plus(StringRef str)
-{
- if (!str.is_empty() && str[0] == '+') {
- str = str.drop_prefix(1);
- }
- return str;
-}
-
-StringRef parse_float(StringRef str, float fallback, float &dst, bool skip_space)
-{
- if (skip_space) {
- str = drop_whitespace(str);
- }
- str = drop_plus(str);
- fast_float::from_chars_result res = fast_float::from_chars(str.begin(), str.end(), dst);
- if (res.ec == std::errc::invalid_argument || res.ec == std::errc::result_out_of_range) {
- dst = fallback;
- }
- return StringRef(res.ptr, str.end());
-}
-
-StringRef parse_floats(StringRef str, float fallback, float *dst, int count)
-{
- for (int i = 0; i < count; ++i) {
- str = parse_float(str, fallback, dst[i]);
- }
- return str;
-}
-
-StringRef parse_int(StringRef str, int fallback, int &dst, bool skip_space)
-{
- if (skip_space) {
- str = drop_whitespace(str);
- }
- str = drop_plus(str);
- std::from_chars_result res = std::from_chars(str.begin(), str.end(), dst);
- if (res.ec == std::errc::invalid_argument || res.ec == std::errc::result_out_of_range) {
- dst = fallback;
- }
- return StringRef(res.ptr, str.end());
-}
-
-} // namespace blender::io
diff --git a/source/blender/io/stl/CMakeLists.txt b/source/blender/io/stl/CMakeLists.txt
new file mode 100644
index 00000000000..e0c48bbbf7e
--- /dev/null
+++ b/source/blender/io/stl/CMakeLists.txt
@@ -0,0 +1,44 @@
+# SPDX-License-Identifier: GPL-2.0-or-later
+
+set(INC
+ .
+ ./importer
+ ../common
+ ../../blenkernel
+ ../../blenlib
+ ../../bmesh
+ ../../bmesh/intern
+ ../../depsgraph
+ ../../editors/include
+ ../../makesdna
+ ../../makesrna
+ ../../nodes
+ ../../windowmanager
+ ../../../../extern/fast_float
+ ../../../../intern/guardedalloc
+)
+
+set(INC_SYS
+
+)
+
+set(SRC
+ IO_stl.cc
+ importer/stl_import_mesh.cc
+ importer/stl_import_ascii_reader.cc
+ importer/stl_import_binary_reader.cc
+ importer/stl_import.cc
+
+ IO_stl.h
+ importer/stl_import_mesh.hh
+ importer/stl_import_ascii_reader.hh
+ importer/stl_import_binary_reader.hh
+ importer/stl_import.hh
+)
+
+set(LIB
+ bf_blenkernel
+ bf_io_common
+)
+
+blender_add_lib(bf_stl "${SRC}" "${INC}" "${INC_SYS}" "${LIB}")
diff --git a/source/blender/io/stl/IO_stl.cc b/source/blender/io/stl/IO_stl.cc
new file mode 100644
index 00000000000..b26c1533692
--- /dev/null
+++ b/source/blender/io/stl/IO_stl.cc
@@ -0,0 +1,16 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+
+/** \file
+ * \ingroup stl
+ */
+
+#include "BLI_timeit.hh"
+
+#include "IO_stl.h"
+#include "stl_import.hh"
+
+void STL_import(bContext *C, const struct STLImportParams *import_params)
+{
+ SCOPED_TIMER("STL Import");
+ blender::io::stl::importer_main(C, *import_params);
+}
diff --git a/source/blender/io/stl/IO_stl.h b/source/blender/io/stl/IO_stl.h
new file mode 100644
index 00000000000..bbe537948e8
--- /dev/null
+++ b/source/blender/io/stl/IO_stl.h
@@ -0,0 +1,35 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+
+/** \file
+ * \ingroup stl
+ */
+
+#pragma once
+
+#include "BKE_context.h"
+#include "BLI_path_util.h"
+#include "IO_orientation.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+struct STLImportParams {
+ /** Full path to the source STL file to import. */
+ char filepath[FILE_MAX];
+ eIOAxis forward_axis;
+ eIOAxis up_axis;
+ bool use_facet_normal;
+ bool use_scene_unit;
+ float global_scale;
+ bool use_mesh_validate;
+};
+
+/**
+ * C-interface for the importer.
+ */
+void STL_import(bContext *C, const struct STLImportParams *import_params);
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/source/blender/io/stl/importer/stl_import.cc b/source/blender/io/stl/importer/stl_import.cc
new file mode 100644
index 00000000000..f358598a216
--- /dev/null
+++ b/source/blender/io/stl/importer/stl_import.cc
@@ -0,0 +1,114 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+
+/** \file
+ * \ingroup stl
+ */
+
+#include <cstdio>
+
+#include "BKE_customdata.h"
+#include "BKE_layer.h"
+#include "BKE_mesh.h"
+#include "BKE_object.h"
+
+#include "DNA_collection_types.h"
+#include "DNA_scene_types.h"
+
+#include "BLI_fileops.hh"
+#include "BLI_math_vector.h"
+#include "BLI_memory_utils.hh"
+
+#include "DNA_object_types.h"
+
+#include "DEG_depsgraph.h"
+#include "DEG_depsgraph_build.h"
+
+#include "stl_import.hh"
+#include "stl_import_ascii_reader.hh"
+#include "stl_import_binary_reader.hh"
+
+namespace blender::io::stl {
+
+void importer_main(bContext *C, const STLImportParams &import_params)
+{
+ Main *bmain = CTX_data_main(C);
+ Scene *scene = CTX_data_scene(C);
+ ViewLayer *view_layer = CTX_data_view_layer(C);
+ importer_main(bmain, scene, view_layer, import_params);
+}
+
+void importer_main(Main *bmain,
+ Scene *scene,
+ ViewLayer *view_layer,
+ const STLImportParams &import_params)
+{
+ FILE *file = BLI_fopen(import_params.filepath, "rb");
+ if (!file) {
+ fprintf(stderr, "Failed to open STL file:'%s'.\n", import_params.filepath);
+ return;
+ }
+ BLI_SCOPED_DEFER([&]() { fclose(file); });
+
+ /* Detect STL file type by comparing file size with expected file size,
+ * could check if file starts with "solid", but some files do not adhere,
+ * this is the same as the old Python importer.
+ */
+ uint32_t num_tri = 0;
+ size_t file_size = BLI_file_size(import_params.filepath);
+ fseek(file, BINARY_HEADER_SIZE, SEEK_SET);
+ fread(&num_tri, sizeof(uint32_t), 1, file);
+ bool is_ascii_stl = (file_size != (BINARY_HEADER_SIZE + 4 + BINARY_STRIDE * num_tri));
+
+ /* Name used for both mesh and object. */
+ char ob_name[FILE_MAX];
+ BLI_strncpy(ob_name, BLI_path_basename(import_params.filepath), FILE_MAX);
+ BLI_path_extension_replace(ob_name, FILE_MAX, "");
+
+ Mesh *mesh;
+ if (is_ascii_stl) {
+ mesh = read_stl_ascii(import_params.filepath, bmain, ob_name, import_params.use_facet_normal);
+ }
+ else {
+ mesh = read_stl_binary(file, bmain, ob_name, import_params.use_facet_normal);
+ }
+
+ if (import_params.use_mesh_validate) {
+ bool verbose_validate = false;
+#ifdef DEBUG
+ verbose_validate = true;
+#endif
+ BKE_mesh_validate(mesh, verbose_validate, false);
+ }
+
+ BKE_view_layer_base_deselect_all(view_layer);
+ LayerCollection *lc = BKE_layer_collection_get_active(view_layer);
+ Object *obj = BKE_object_add_only_object(bmain, OB_MESH, ob_name);
+ BKE_mesh_assign_object(bmain, obj, mesh);
+ BKE_collection_object_add(bmain, lc->collection, obj);
+ Base *base = BKE_view_layer_base_find(view_layer, obj);
+ BKE_view_layer_base_select_and_set_active(view_layer, base);
+
+ float global_scale = import_params.global_scale;
+ if ((scene->unit.system != USER_UNIT_NONE) && import_params.use_scene_unit) {
+ global_scale *= scene->unit.scale_length;
+ }
+ float scale_vec[3] = {global_scale, global_scale, global_scale};
+ float obmat3x3[3][3];
+ unit_m3(obmat3x3);
+ float obmat4x4[4][4];
+ unit_m4(obmat4x4);
+ /* +Y-forward and +Z-up are the Blender's default axis settings. */
+ mat3_from_axis_conversion(
+ IO_AXIS_Y, IO_AXIS_Z, import_params.forward_axis, import_params.up_axis, obmat3x3);
+ copy_m4_m3(obmat4x4, obmat3x3);
+ rescale_m4(obmat4x4, scale_vec);
+ BKE_object_apply_mat4(obj, obmat4x4, true, false);
+
+ DEG_id_tag_update(&lc->collection->id, ID_RECALC_COPY_ON_WRITE);
+ int flags = ID_RECALC_TRANSFORM | ID_RECALC_GEOMETRY | ID_RECALC_ANIMATION |
+ ID_RECALC_BASE_FLAGS;
+ DEG_id_tag_update_ex(bmain, &obj->id, flags);
+ DEG_id_tag_update(&scene->id, ID_RECALC_BASE_FLAGS);
+ DEG_relations_tag_update(bmain);
+}
+} // namespace blender::io::stl
diff --git a/source/blender/io/stl/importer/stl_import.hh b/source/blender/io/stl/importer/stl_import.hh
new file mode 100644
index 00000000000..377544c26af
--- /dev/null
+++ b/source/blender/io/stl/importer/stl_import.hh
@@ -0,0 +1,22 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+
+/** \file
+ * \ingroup stl
+ */
+
+#pragma once
+
+#include "IO_stl.h"
+
+namespace blender::io::stl {
+
+/* Main import function used from within Blender. */
+void importer_main(bContext *C, const STLImportParams &import_params);
+
+/* Used from tests, where full bContext does not exist. */
+void importer_main(Main *bmain,
+ Scene *scene,
+ ViewLayer *view_layer,
+ const STLImportParams &import_params);
+
+} // namespace blender::io::stl
diff --git a/source/blender/io/stl/importer/stl_import_ascii_reader.cc b/source/blender/io/stl/importer/stl_import_ascii_reader.cc
new file mode 100644
index 00000000000..2edb3c6a114
--- /dev/null
+++ b/source/blender/io/stl/importer/stl_import_ascii_reader.cc
@@ -0,0 +1,160 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+
+/** \file
+ * \ingroup stl
+ */
+
+#include <cstdint>
+#include <cstdio>
+
+#include "BKE_mesh.h"
+
+#include "BLI_fileops.hh"
+#include "BLI_memory_utils.hh"
+#include "BLI_string_ref.hh"
+
+#include "DNA_mesh_types.h"
+
+/* NOTE: we could use C++17 <charconv> from_chars to parse
+ * floats, but even if some compilers claim full support,
+ * their standard libraries are not quite there yet.
+ * LLVM/libc++ only has a float parser since LLVM 14,
+ * and gcc/libstdc++ since 11.1. So until at least these are
+ * the minimum spec, use an external library. */
+#include "fast_float.h"
+
+#include "stl_import.hh"
+#include "stl_import_ascii_reader.hh"
+#include "stl_import_mesh.hh"
+
+namespace blender::io::stl {
+
+class StringBuffer {
+ private:
+ char *start;
+ const char *end;
+
+ public:
+ StringBuffer(char *buf, size_t len)
+ {
+ start = buf;
+ end = start + len;
+ }
+
+ bool is_empty() const
+ {
+ return start == end;
+ }
+
+ void drop_leading_control_chars()
+ {
+ while ((start < end) && (*start) <= ' ') {
+ start++;
+ }
+ }
+
+ void drop_leading_non_control_chars()
+ {
+ while ((start < end) && (*start) > ' ') {
+ start++;
+ }
+ }
+
+ void drop_line()
+ {
+ while (start < end && *start != '\n') {
+ start++;
+ }
+ }
+
+ bool parse_token(const char *token, size_t token_length)
+ {
+ drop_leading_control_chars();
+ if (end - start < token_length + 1) {
+ return false;
+ }
+ if (memcmp(start, token, token_length) != 0) {
+ return false;
+ }
+ if (start[token_length] > ' ') {
+ return false;
+ }
+ start += token_length + 1;
+ return true;
+ }
+
+ void drop_token()
+ {
+ drop_leading_non_control_chars();
+ drop_leading_control_chars();
+ }
+
+ void parse_float(float &out)
+ {
+ drop_leading_control_chars();
+ /* Skip '+' */
+ if (start < end && *start == '+') {
+ start++;
+ }
+ fast_float::from_chars_result res = fast_float::from_chars(start, end, out);
+ if (res.ec == std::errc::invalid_argument || res.ec == std::errc::result_out_of_range) {
+ out = 0.0f;
+ }
+ start = const_cast<char *>(res.ptr);
+ }
+};
+
+static inline void parse_float3(StringBuffer &buf, float out[3])
+{
+ for (int i = 0; i < 3; i++) {
+ buf.parse_float(out[i]);
+ }
+}
+
+Mesh *read_stl_ascii(const char *filepath, Main *bmain, char *mesh_name, bool use_custom_normals)
+{
+ size_t buffer_len;
+ void *buffer = BLI_file_read_text_as_mem(filepath, 0, &buffer_len);
+ if (buffer == nullptr) {
+ fprintf(stderr, "STL Importer: cannot read from ASCII STL file: '%s'\n", filepath);
+ return BKE_mesh_add(bmain, mesh_name);
+ }
+ BLI_SCOPED_DEFER([&]() { MEM_freeN(buffer); });
+
+ int num_reserved_tris = 1024;
+
+ StringBuffer str_buf(static_cast<char *>(buffer), buffer_len);
+ STLMeshHelper stl_mesh(num_reserved_tris, use_custom_normals);
+ float triangle_buf[3][3];
+ float custom_normal_buf[3];
+ str_buf.drop_line(); /* Skip header line */
+ while (!str_buf.is_empty()) {
+ if (str_buf.parse_token("vertex", 6)) {
+ parse_float3(str_buf, triangle_buf[0]);
+ if (str_buf.parse_token("vertex", 6)) {
+ parse_float3(str_buf, triangle_buf[1]);
+ }
+ if (str_buf.parse_token("vertex", 6)) {
+ parse_float3(str_buf, triangle_buf[2]);
+ }
+ if (use_custom_normals) {
+ stl_mesh.add_triangle(
+ triangle_buf[0], triangle_buf[1], triangle_buf[2], custom_normal_buf);
+ }
+ else {
+ stl_mesh.add_triangle(triangle_buf[0], triangle_buf[1], triangle_buf[2]);
+ }
+ }
+ else if (str_buf.parse_token("facet", 5)) {
+ str_buf.drop_token(); /* Expecting "normal" */
+ parse_float3(str_buf, custom_normal_buf);
+ }
+ else {
+ str_buf.drop_token();
+ }
+ }
+
+ return stl_mesh.to_mesh(bmain, mesh_name);
+}
+
+} // namespace blender::io::stl
diff --git a/source/blender/io/stl/importer/stl_import_ascii_reader.hh b/source/blender/io/stl/importer/stl_import_ascii_reader.hh
new file mode 100644
index 00000000000..e8aed911bf1
--- /dev/null
+++ b/source/blender/io/stl/importer/stl_import_ascii_reader.hh
@@ -0,0 +1,35 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+
+/** \file
+ * \ingroup stl
+ */
+
+#pragma once
+
+#include <cstdio>
+
+#include "BKE_mesh.h"
+
+#include "stl_import.hh"
+
+/**
+ * ASCII STL spec:
+ * <pre>
+ * solid name
+ * facet normal ni nj nk
+ * outer loop
+ * vertex v1x v1y v1z
+ * vertex v2x v2y v2z
+ * vertex v3x v3y v3z
+ * endloop
+ * endfacet
+ * ...
+ * endsolid name
+ * </pre>
+ */
+
+namespace blender::io::stl {
+
+Mesh *read_stl_ascii(const char *filepath, Main *bmain, char *mesh_name, bool use_custom_normals);
+
+} // namespace blender::io::stl
diff --git a/source/blender/io/stl/importer/stl_import_binary_reader.cc b/source/blender/io/stl/importer/stl_import_binary_reader.cc
new file mode 100644
index 00000000000..6eaed16160e
--- /dev/null
+++ b/source/blender/io/stl/importer/stl_import_binary_reader.cc
@@ -0,0 +1,58 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+
+/** \file
+ * \ingroup stl
+ */
+
+#include <cstdint>
+#include <cstdio>
+
+#include "BKE_main.h"
+#include "BKE_mesh.h"
+
+#include "BLI_array.hh"
+#include "BLI_memory_utils.hh"
+
+#include "DNA_mesh_types.h"
+
+#include "stl_import_binary_reader.hh"
+#include "stl_import_mesh.hh"
+
+namespace blender::io::stl {
+
+#pragma pack(push, 1)
+struct STLBinaryTriangle {
+ float normal[3];
+ float v1[3], v2[3], v3[3];
+ uint16_t attribute_byte_count;
+};
+#pragma pack(pop)
+
+Mesh *read_stl_binary(FILE *file, Main *bmain, char *mesh_name, bool use_custom_normals)
+{
+ const int chunk_size = 1024;
+ uint32_t num_tris = 0;
+ fseek(file, BINARY_HEADER_SIZE, SEEK_SET);
+ fread(&num_tris, sizeof(uint32_t), 1, file);
+ if (num_tris == 0) {
+ return BKE_mesh_add(bmain, mesh_name);
+ }
+
+ Array<STLBinaryTriangle> tris_buf(chunk_size);
+ STLMeshHelper stl_mesh(num_tris, use_custom_normals);
+ size_t num_read_tris;
+ while ((num_read_tris = fread(tris_buf.data(), sizeof(STLBinaryTriangle), chunk_size, file))) {
+ for (size_t i = 0; i < num_read_tris; i++) {
+ if (use_custom_normals) {
+ stl_mesh.add_triangle(tris_buf[i].v1, tris_buf[i].v2, tris_buf[i].v3, tris_buf[i].normal);
+ }
+ else {
+ stl_mesh.add_triangle(tris_buf[i].v1, tris_buf[i].v2, tris_buf[i].v3);
+ }
+ }
+ }
+
+ return stl_mesh.to_mesh(bmain, mesh_name);
+}
+
+} // namespace blender::io::stl
diff --git a/source/blender/io/stl/importer/stl_import_binary_reader.hh b/source/blender/io/stl/importer/stl_import_binary_reader.hh
new file mode 100644
index 00000000000..71d5dbbbe58
--- /dev/null
+++ b/source/blender/io/stl/importer/stl_import_binary_reader.hh
@@ -0,0 +1,31 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+
+/** \file
+ * \ingroup stl
+ */
+
+#pragma once
+
+#include <cstdio>
+
+#include "BKE_mesh.h"
+
+/* Binary STL spec.:
+ * UINT8[80] – Header - 80 bytes
+ * UINT32 – Number of triangles - 4 bytes
+ * For each triangle - 50 bytes:
+ * REAL32[3] – Normal vector - 12 bytes
+ * REAL32[3] – Vertex 1 - 12 bytes
+ * REAL32[3] – Vertex 2 - 12 bytes
+ * REAL32[3] – Vertex 3 - 12 bytes
+ * UINT16 – Attribute byte count - 2 bytes
+ */
+
+namespace blender::io::stl {
+
+const size_t BINARY_HEADER_SIZE = 80;
+const size_t BINARY_STRIDE = 12 * 4 + 2;
+
+Mesh *read_stl_binary(FILE *file, Main *bmain, char *mesh_name, bool use_custom_normals);
+
+} // namespace blender::io::stl
diff --git a/source/blender/io/stl/importer/stl_import_mesh.cc b/source/blender/io/stl/importer/stl_import_mesh.cc
new file mode 100644
index 00000000000..b9ed441f0d9
--- /dev/null
+++ b/source/blender/io/stl/importer/stl_import_mesh.cc
@@ -0,0 +1,114 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+
+/** \file
+ * \ingroup stl
+ */
+
+#include "BKE_customdata.h"
+#include "BKE_lib_id.h"
+#include "BKE_main.h"
+#include "BKE_mesh.h"
+
+#include "BLI_array.hh"
+#include "BLI_math_vector.h"
+#include "BLI_math_vector.hh"
+#include "BLI_task.hh"
+
+#include "DNA_mesh_types.h"
+#include "DNA_meshdata_types.h"
+
+#include "stl_import_mesh.hh"
+
+namespace blender::io::stl {
+
+STLMeshHelper::STLMeshHelper(int tris_num, bool use_custom_normals)
+ : use_custom_normals_(use_custom_normals)
+{
+ degenerate_tris_num_ = 0;
+ duplicate_tris_num_ = 0;
+ tris_.reserve(tris_num);
+ /* Upper bound (all vertices are unique). */
+ verts_.reserve(tris_num * 3);
+ if (use_custom_normals) {
+ loop_normals_.reserve(tris_num * 3);
+ }
+}
+
+bool STLMeshHelper::add_triangle(const float3 &a, const float3 &b, const float3 &c)
+{
+ int v1_id = verts_.index_of_or_add(a);
+ int v2_id = verts_.index_of_or_add(b);
+ int v3_id = verts_.index_of_or_add(c);
+ if ((v1_id == v2_id) || (v1_id == v3_id) || (v2_id == v3_id)) {
+ degenerate_tris_num_++;
+ return false;
+ }
+ if (!tris_.add({v1_id, v2_id, v3_id})) {
+ duplicate_tris_num_++;
+ return false;
+ }
+ return true;
+}
+
+void STLMeshHelper::add_triangle(const float3 &a,
+ const float3 &b,
+ const float3 &c,
+ const float3 &custom_normal)
+{
+ if (add_triangle(a, b, c)) {
+ loop_normals_.append_n_times(custom_normal, 3);
+ }
+}
+
+Mesh *STLMeshHelper::to_mesh(Main *bmain, char *mesh_name)
+{
+ if (degenerate_tris_num_ > 0) {
+ std::cout << "STL Importer: " << degenerate_tris_num_ << " degenerate triangles were removed"
+ << std::endl;
+ }
+ if (duplicate_tris_num_ > 0) {
+ std::cout << "STL Importer: " << duplicate_tris_num_ << " duplicate triangles were removed"
+ << std::endl;
+ }
+
+ Mesh *mesh = BKE_mesh_add(bmain, mesh_name);
+ /* User count is already 1 here, but will be set later in #BKE_mesh_assign_object. */
+ id_us_min(&mesh->id);
+
+ mesh->totvert = verts_.size();
+ mesh->mvert = static_cast<MVert *>(
+ CustomData_add_layer(&mesh->vdata, CD_MVERT, CD_CALLOC, nullptr, mesh->totvert));
+ for (int i = 0; i < mesh->totvert; i++) {
+ copy_v3_v3(mesh->mvert[i].co, verts_[i]);
+ }
+
+ mesh->totpoly = tris_.size();
+ mesh->totloop = tris_.size() * 3;
+ mesh->mpoly = static_cast<MPoly *>(
+ CustomData_add_layer(&mesh->pdata, CD_MPOLY, CD_CALLOC, nullptr, mesh->totpoly));
+ mesh->mloop = static_cast<MLoop *>(
+ CustomData_add_layer(&mesh->ldata, CD_MLOOP, CD_CALLOC, nullptr, mesh->totloop));
+
+ threading::parallel_for(tris_.index_range(), 2048, [&](IndexRange tris_range) {
+ for (const int i : tris_range) {
+ mesh->mpoly[i].loopstart = 3 * i;
+ mesh->mpoly[i].totloop = 3;
+
+ mesh->mloop[3 * i].v = tris_[i].v1;
+ mesh->mloop[3 * i + 1].v = tris_[i].v2;
+ mesh->mloop[3 * i + 2].v = tris_[i].v3;
+ }
+ });
+
+ /* NOTE: edges must be calculated first before setting custom normals. */
+ BKE_mesh_calc_edges(mesh, false, false);
+
+ if (use_custom_normals_ && loop_normals_.size() == mesh->totloop) {
+ BKE_mesh_set_custom_normals(mesh, reinterpret_cast<float(*)[3]>(loop_normals_.data()));
+ mesh->flag |= ME_AUTOSMOOTH;
+ }
+
+ return mesh;
+}
+
+} // namespace blender::io::stl
diff --git a/source/blender/io/stl/importer/stl_import_mesh.hh b/source/blender/io/stl/importer/stl_import_mesh.hh
new file mode 100644
index 00000000000..f1c0d2126a9
--- /dev/null
+++ b/source/blender/io/stl/importer/stl_import_mesh.hh
@@ -0,0 +1,71 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+
+/** \file
+ * \ingroup stl
+ */
+
+#pragma once
+
+#include <cstdint>
+
+#include "BLI_math_vec_types.hh"
+#include "BLI_set.hh"
+#include "BLI_vector.hh"
+#include "BLI_vector_set.hh"
+
+#include "DNA_mesh_types.h"
+
+namespace blender::io::stl {
+class Triangle {
+ public:
+ int v1, v2, v3;
+ /* Based on an old version of Python's frozen-set hash
+ * https://web.archive.org/web/20220520211017/https://stackoverflow.com/questions/20832279/python-frozenset-hashing-algorithm-implementation
+ */
+ uint64_t hash() const
+ {
+ uint64_t res = 1927868237UL;
+ res *= 4;
+ res ^= (v1 ^ (v1 << 16) ^ 89869747UL) * 3644798167UL;
+ res ^= (v2 ^ (v2 << 16) ^ 89869747UL) * 3644798167UL;
+ res ^= (v3 ^ (v3 << 16) ^ 89869747UL) * 3644798167UL;
+ return res * 69069U + 907133923UL;
+ }
+ friend bool operator==(const Triangle &a, const Triangle &b)
+ {
+ bool i = (a.v1 == b.v1) && (a.v2 == b.v2) && (a.v3 == b.v3);
+ bool j = (a.v1 == b.v1) && (a.v3 == b.v2) && (a.v2 == b.v3);
+ bool k = (a.v2 == b.v1) && (a.v1 == b.v2) && (a.v3 == b.v3);
+
+ bool l = (a.v2 == b.v1) && (a.v3 == b.v2) && (a.v1 == b.v3);
+ bool m = (a.v3 == b.v1) && (a.v1 == b.v2) && (a.v2 == b.v3);
+ bool n = (a.v3 == b.v1) && (a.v2 == b.v2) && (a.v1 == b.v3);
+
+ return i || j || k || l || m || n;
+ }
+};
+
+class STLMeshHelper {
+ private:
+ VectorSet<float3> verts_;
+ VectorSet<Triangle> tris_;
+ Vector<float3> loop_normals_;
+ int degenerate_tris_num_;
+ int duplicate_tris_num_;
+ const bool use_custom_normals_;
+
+ public:
+ STLMeshHelper(int tris_num, bool use_custom_normals);
+
+ /* Creates a new triangle from specified vertex locations,
+ * duplicate vertices and triangles are merged.
+ */
+ bool add_triangle(const float3 &a, const float3 &b, const float3 &c);
+ void add_triangle(const float3 &a,
+ const float3 &b,
+ const float3 &c,
+ const float3 &custom_normal);
+ Mesh *to_mesh(Main *bmain, char *mesh_name);
+};
+
+} // namespace blender::io::stl
diff --git a/source/blender/io/usd/CMakeLists.txt b/source/blender/io/usd/CMakeLists.txt
index e2e959814fa..1205ae74e6f 100644
--- a/source/blender/io/usd/CMakeLists.txt
+++ b/source/blender/io/usd/CMakeLists.txt
@@ -43,6 +43,7 @@ set(INC
../../bmesh
../../depsgraph
../../editors/include
+ ../../imbuf
../../makesdna
../../makesrna
../../windowmanager
@@ -69,6 +70,7 @@ set(SRC
intern/usd_writer_mesh.cc
intern/usd_writer_metaball.cc
intern/usd_writer_transform.cc
+ intern/usd_writer_volume.cc
intern/usd_reader_camera.cc
intern/usd_reader_curve.cc
@@ -95,6 +97,7 @@ set(SRC
intern/usd_writer_mesh.h
intern/usd_writer_metaball.h
intern/usd_writer_transform.h
+ intern/usd_writer_volume.h
intern/usd_reader_camera.h
intern/usd_reader_curve.h
@@ -112,6 +115,7 @@ set(SRC
set(LIB
bf_blenkernel
bf_blenlib
+ bf_imbuf
bf_io_common
)
@@ -119,8 +123,15 @@ list(APPEND LIB
${BOOST_LIBRARIES}
)
-list(APPEND LIB
-)
+if(WITH_OPENVDB)
+ add_definitions(-DWITH_OPENVDB ${OPENVDB_DEFINITIONS})
+ list(APPEND INC_SYS
+ ${OPENVDB_INCLUDE_DIRS}
+ )
+ list(APPEND LIB
+ ${OPENVDB_LIBRARIES}
+ )
+endif()
blender_add_lib(bf_usd "${SRC}" "${INC}" "${INC_SYS}" "${LIB}")
diff --git a/source/blender/io/usd/intern/usd_capi_export.cc b/source/blender/io/usd/intern/usd_capi_export.cc
index d7c1a5adc7c..2049c631671 100644
--- a/source/blender/io/usd/intern/usd_capi_export.cc
+++ b/source/blender/io/usd/intern/usd_capi_export.cc
@@ -38,7 +38,7 @@ struct ExportJobData {
Depsgraph *depsgraph;
wmWindowManager *wm;
- char filename[FILE_MAX];
+ char filepath[FILE_MAX];
USDExportParams params;
bool export_ok;
@@ -74,13 +74,13 @@ static void export_startjob(void *customdata,
/* For restoring the current frame after exporting animation is done. */
const int orig_frame = CFRA;
- pxr::UsdStageRefPtr usd_stage = pxr::UsdStage::CreateNew(data->filename);
+ pxr::UsdStageRefPtr usd_stage = pxr::UsdStage::CreateNew(data->filepath);
if (!usd_stage) {
/* This happens when the USD JSON files cannot be found. When that happens,
* the USD library doesn't know it has the functionality to write USDA and
* USDC files, and creating a new UsdStage fails. */
WM_reportf(
- RPT_ERROR, "USD Export: unable to find suitable USD plugin to write %s", data->filename);
+ RPT_ERROR, "USD Export: unable to find suitable USD plugin to write %s", data->filepath);
return;
}
@@ -97,7 +97,7 @@ static void export_startjob(void *customdata,
usd_stage->SetEndTimeCode(scene->r.efra);
}
- USDHierarchyIterator iter(data->depsgraph, usd_stage, data->params);
+ USDHierarchyIterator iter(data->bmain, data->depsgraph, usd_stage, data->params);
if (data->params.export_animation) {
/* Writing the animated frames is not 100% of the work, but it's our best guess. */
@@ -145,8 +145,8 @@ static void export_endjob(void *customdata)
DEG_graph_free(data->depsgraph);
- if (!data->export_ok && BLI_exists(data->filename)) {
- BLI_delete(data->filename, false, false);
+ if (!data->export_ok && BLI_exists(data->filepath)) {
+ BLI_delete(data->filepath, false, false);
}
G.is_rendering = false;
@@ -171,7 +171,7 @@ bool USD_export(bContext *C,
job->bmain = CTX_data_main(C);
job->wm = CTX_wm_manager(C);
job->export_ok = false;
- BLI_strncpy(job->filename, filepath, sizeof(job->filename));
+ BLI_strncpy(job->filepath, filepath, sizeof(job->filepath));
job->depsgraph = DEG_graph_new(job->bmain, scene, view_layer, params->evaluation_mode);
job->params = *params;
diff --git a/source/blender/io/usd/intern/usd_capi_import.cc b/source/blender/io/usd/intern/usd_capi_import.cc
index 58cd7d5014e..4118205d87f 100644
--- a/source/blender/io/usd/intern/usd_capi_import.cc
+++ b/source/blender/io/usd/intern/usd_capi_import.cc
@@ -119,7 +119,7 @@ struct ImportJobData {
ViewLayer *view_layer;
wmWindowManager *wm;
- char filename[1024];
+ char filepath[1024];
USDImportParams params;
ImportSettings settings;
@@ -150,7 +150,7 @@ static void import_startjob(void *customdata, short *stop, short *do_update, flo
if (data->params.create_collection) {
char display_name[1024];
BLI_path_to_display_name(
- display_name, strlen(data->filename), BLI_path_basename(data->filename));
+ display_name, strlen(data->filepath), BLI_path_basename(data->filepath));
Collection *import_collection = BKE_collection_add(
data->bmain, data->scene->master_collection, display_name);
id_fake_user_set(&import_collection->id);
@@ -164,10 +164,10 @@ static void import_startjob(void *customdata, short *stop, short *do_update, flo
data->view_layer, import_collection);
}
- BLI_path_abs(data->filename, BKE_main_blendfile_path_from_global());
+ BLI_path_abs(data->filepath, BKE_main_blendfile_path_from_global());
CacheFile *cache_file = static_cast<CacheFile *>(
- BKE_cachefile_add(data->bmain, BLI_path_basename(data->filename)));
+ BKE_cachefile_add(data->bmain, BLI_path_basename(data->filepath)));
/* Decrement the ID ref-count because it is going to be incremented for each
* modifier and constraint that it will be attached to, so since currently
@@ -176,7 +176,7 @@ static void import_startjob(void *customdata, short *stop, short *do_update, flo
cache_file->is_sequence = data->params.is_sequence;
cache_file->scale = data->params.scale;
- STRNCPY(cache_file->filepath, data->filename);
+ STRNCPY(cache_file->filepath, data->filepath);
data->settings.cache_file = cache_file;
@@ -191,10 +191,10 @@ static void import_startjob(void *customdata, short *stop, short *do_update, flo
*data->do_update = true;
*data->progress = 0.1f;
- pxr::UsdStageRefPtr stage = pxr::UsdStage::Open(data->filename);
+ pxr::UsdStageRefPtr stage = pxr::UsdStage::Open(data->filepath);
if (!stage) {
- WM_reportf(RPT_ERROR, "USD Import: unable to open stage to read %s", data->filename);
+ WM_reportf(RPT_ERROR, "USD Import: unable to open stage to read %s", data->filepath);
data->import_ok = false;
return;
}
@@ -277,7 +277,6 @@ static void import_endjob(void *customdata)
}
}
else if (data->archive) {
- /* Add object to scene. */
Base *base;
LayerCollection *lc;
ViewLayer *view_layer = data->view_layer;
@@ -286,20 +285,30 @@ static void import_endjob(void *customdata)
lc = BKE_layer_collection_get_active(view_layer);
+ /* Add all objects to the collection (don't do sync for each object). */
+ BKE_layer_collection_resync_forbid();
for (USDPrimReader *reader : data->archive->readers()) {
-
if (!reader) {
continue;
}
-
Object *ob = reader->object();
-
if (!ob) {
continue;
}
-
BKE_collection_object_add(data->bmain, lc->collection, ob);
+ }
+ /* Sync the collection, and do view layer operations. */
+ BKE_layer_collection_resync_allow();
+ BKE_main_collection_sync(data->bmain);
+ for (USDPrimReader *reader : data->archive->readers()) {
+ if (!reader) {
+ continue;
+ }
+ Object *ob = reader->object();
+ if (!ob) {
+ continue;
+ }
base = BKE_view_layer_base_find(view_layer, ob);
/* TODO: is setting active needed? */
BKE_view_layer_base_select_and_set_active(view_layer, base);
@@ -356,7 +365,7 @@ bool USD_import(struct bContext *C,
job->view_layer = CTX_data_view_layer(C);
job->wm = CTX_wm_manager(C);
job->import_ok = false;
- BLI_strncpy(job->filename, filepath, 1024);
+ BLI_strncpy(job->filepath, filepath, 1024);
job->settings.scale = params->scale;
job->settings.sequence_offset = params->offset;
@@ -499,13 +508,13 @@ void USD_CacheReader_free(CacheReader *reader)
}
CacheArchiveHandle *USD_create_handle(struct Main * /*bmain*/,
- const char *filename,
+ const char *filepath,
ListBase *object_paths)
{
/* Must call this so that USD file format plugins are loaded. */
ensure_usd_plugin_path_registered();
- pxr::UsdStageRefPtr stage = pxr::UsdStage::Open(filename);
+ pxr::UsdStageRefPtr stage = pxr::UsdStage::Open(filepath);
if (!stage) {
return nullptr;
diff --git a/source/blender/io/usd/intern/usd_exporter_context.h b/source/blender/io/usd/intern/usd_exporter_context.h
index 5a3f94d01f8..a636d849296 100644
--- a/source/blender/io/usd/intern/usd_exporter_context.h
+++ b/source/blender/io/usd/intern/usd_exporter_context.h
@@ -8,12 +8,14 @@
#include <pxr/usd/usd/common.h>
struct Depsgraph;
+struct Main;
namespace blender::io::usd {
class USDHierarchyIterator;
struct USDExporterContext {
+ Main *bmain;
Depsgraph *depsgraph;
const pxr::UsdStageRefPtr stage;
const pxr::SdfPath usd_path;
diff --git a/source/blender/io/usd/intern/usd_hierarchy_iterator.cc b/source/blender/io/usd/intern/usd_hierarchy_iterator.cc
index 7a0d896fb3e..51261c4d91e 100644
--- a/source/blender/io/usd/intern/usd_hierarchy_iterator.cc
+++ b/source/blender/io/usd/intern/usd_hierarchy_iterator.cc
@@ -10,6 +10,7 @@
#include "usd_writer_mesh.h"
#include "usd_writer_metaball.h"
#include "usd_writer_transform.h"
+#include "usd_writer_volume.h"
#include <string>
@@ -28,10 +29,11 @@
namespace blender::io::usd {
-USDHierarchyIterator::USDHierarchyIterator(Depsgraph *depsgraph,
+USDHierarchyIterator::USDHierarchyIterator(Main *bmain,
+ Depsgraph *depsgraph,
pxr::UsdStageRefPtr stage,
const USDExportParams &params)
- : AbstractHierarchyIterator(depsgraph), stage_(stage), params_(params)
+ : AbstractHierarchyIterator(bmain, depsgraph), stage_(stage), params_(params)
{
}
@@ -59,6 +61,15 @@ void USDHierarchyIterator::set_export_frame(float frame_nr)
export_time_ = pxr::UsdTimeCode(frame_nr);
}
+std::string USDHierarchyIterator::get_export_file_path() const
+{
+ /* Returns the same path that was passed to `stage_` object during it's creation (via
+ * `pxr::UsdStage::CreateNew` function). */
+ const pxr::SdfLayerHandle root_layer = stage_->GetRootLayer();
+ const std::string usd_export_file_path = root_layer->GetRealPath();
+ return usd_export_file_path;
+}
+
const pxr::UsdTimeCode &USDHierarchyIterator::get_export_time_code() const
{
return export_time_;
@@ -66,7 +77,8 @@ const pxr::UsdTimeCode &USDHierarchyIterator::get_export_time_code() const
USDExporterContext USDHierarchyIterator::create_usd_export_context(const HierarchyContext *context)
{
- return USDExporterContext{depsgraph_, stage_, pxr::SdfPath(context->export_path), this, params_};
+ return USDExporterContext{
+ bmain_, depsgraph_, stage_, pxr::SdfPath(context->export_path), this, params_};
}
AbstractHierarchyWriter *USDHierarchyIterator::create_transform_writer(
@@ -93,6 +105,9 @@ AbstractHierarchyWriter *USDHierarchyIterator::create_data_writer(const Hierarch
case OB_MBALL:
data_writer = new USDMetaballWriter(usd_export_context);
break;
+ case OB_VOLUME:
+ data_writer = new USDVolumeWriter(usd_export_context);
+ break;
case OB_EMPTY:
case OB_CURVES_LEGACY:
diff --git a/source/blender/io/usd/intern/usd_hierarchy_iterator.h b/source/blender/io/usd/intern/usd_hierarchy_iterator.h
index d5566103af4..445c37238be 100644
--- a/source/blender/io/usd/intern/usd_hierarchy_iterator.h
+++ b/source/blender/io/usd/intern/usd_hierarchy_iterator.h
@@ -12,6 +12,7 @@
#include <pxr/usd/usd/timeCode.h>
struct Depsgraph;
+struct Main;
struct Object;
namespace blender::io::usd {
@@ -27,11 +28,13 @@ class USDHierarchyIterator : public AbstractHierarchyIterator {
const USDExportParams &params_;
public:
- USDHierarchyIterator(Depsgraph *depsgraph,
+ USDHierarchyIterator(Main *bmain,
+ Depsgraph *depsgraph,
pxr::UsdStageRefPtr stage,
const USDExportParams &params);
void set_export_frame(float frame_nr);
+ std::string get_export_file_path() const;
const pxr::UsdTimeCode &get_export_time_code() const;
virtual std::string make_valid_name(const std::string &name) const override;
diff --git a/source/blender/io/usd/intern/usd_reader_mesh.cc b/source/blender/io/usd/intern/usd_reader_mesh.cc
index 328b4109616..36e1a40953c 100644
--- a/source/blender/io/usd/intern/usd_reader_mesh.cc
+++ b/source/blender/io/usd/intern/usd_reader_mesh.cc
@@ -62,11 +62,57 @@ static void build_mat_map(const Main *bmain, std::map<std::string, Material *> *
}
}
+static pxr::UsdShadeMaterial compute_bound_material(const pxr::UsdPrim &prim)
+{
+ return pxr::UsdShadeMaterialBindingAPI(prim).ComputeBoundMaterial();
+}
+
+/* Returns an existing Blender material that corresponds to the USD
+ * material with with the given path. Returns null if no such material
+ * exists. */
+static Material *find_existing_material(
+ const pxr::SdfPath &usd_mat_path,
+ const USDImportParams &params,
+ const std::map<std::string, Material *> &mat_map,
+ const std::map<std::string, std::string> &usd_path_to_mat_name)
+{
+ if (params.mtl_name_collision_mode == USD_MTL_NAME_COLLISION_MAKE_UNIQUE) {
+ /* Check if we've already created the Blender material with a modified name. */
+ std::map<std::string, std::string>::const_iterator path_to_name_iter =
+ usd_path_to_mat_name.find(usd_mat_path.GetAsString());
+
+ if (path_to_name_iter != usd_path_to_mat_name.end()) {
+ std::string mat_name = path_to_name_iter->second;
+ std::map<std::string, Material *>::const_iterator mat_iter = mat_map.find(mat_name);
+ if (mat_iter != mat_map.end()) {
+ return mat_iter->second;
+ }
+ else {
+ /* We can't find the Blender material which was previously created for this USD
+ * material, which should never happen. */
+ BLI_assert_unreachable();
+ }
+ }
+ }
+ else {
+ std::string mat_name = usd_mat_path.GetName();
+ std::map<std::string, Material *>::const_iterator mat_iter = mat_map.find(mat_name);
+
+ if (mat_iter != mat_map.end()) {
+ return mat_iter->second;
+ }
+ }
+
+ return nullptr;
+}
+
static void assign_materials(Main *bmain,
Object *ob,
const std::map<pxr::SdfPath, int> &mat_index_map,
const USDImportParams &params,
- pxr::UsdStageRefPtr stage)
+ pxr::UsdStageRefPtr stage,
+ std::map<std::string, Material *> &mat_name_to_mat,
+ std::map<std::string, std::string> &usd_path_to_mat_name)
{
if (!(stage && bmain && ob)) {
return;
@@ -87,20 +133,13 @@ static void assign_materials(Main *bmain,
return;
}
- /* TODO(kevin): use global map? */
- std::map<std::string, Material *> mat_map;
- build_mat_map(bmain, &mat_map);
-
blender::io::usd::USDMaterialReader mat_reader(params, bmain);
for (it = mat_index_map.begin(); it != mat_index_map.end(); ++it) {
- std::string mat_name = it->first.GetName();
-
- std::map<std::string, Material *>::iterator mat_iter = mat_map.find(mat_name);
-
- Material *assigned_mat = nullptr;
- if (mat_iter == mat_map.end()) {
+ Material *assigned_mat = find_existing_material(
+ it->first, params, mat_name_to_mat, usd_path_to_mat_name);
+ if (!assigned_mat) {
/* Blender material doesn't exist, so create it now. */
/* Look up the USD material. */
@@ -122,11 +161,14 @@ static void assign_materials(Main *bmain,
continue;
}
- mat_map[mat_name] = assigned_mat;
- }
- else {
- /* We found an existing Blender material. */
- assigned_mat = mat_iter->second;
+ const std::string mat_name = pxr::TfMakeValidIdentifier(assigned_mat->id.name + 2);
+ mat_name_to_mat[mat_name] = assigned_mat;
+
+ if (params.mtl_name_collision_mode == USD_MTL_NAME_COLLISION_MAKE_UNIQUE) {
+ /* Record the name of the Blender material we created for the USD material
+ * with the given path. */
+ usd_path_to_mat_name[it->first.GetAsString()] = mat_name;
+ }
}
if (assigned_mat) {
@@ -134,7 +176,7 @@ static void assign_materials(Main *bmain,
}
else {
/* This shouldn't happen. */
- std::cout << "WARNING: Couldn't assign material " << mat_name << std::endl;
+ std::cout << "WARNING: Couldn't assign material " << it->first << std::endl;
}
}
}
@@ -143,7 +185,7 @@ static void assign_materials(Main *bmain,
static void *add_customdata_cb(Mesh *mesh, const char *name, const int data_type)
{
- CustomDataType cd_data_type = static_cast<CustomDataType>(data_type);
+ eCustomDataType cd_data_type = static_cast<eCustomDataType>(data_type);
void *cd_ptr;
CustomData *loopdata;
int numloops;
@@ -200,7 +242,7 @@ void USDMeshReader::read_object_data(Main *bmain, const double motionSampleTime)
if (read_mesh != mesh) {
/* FIXME: after 2.80; `mesh->flag` isn't copied by #BKE_mesh_nomain_to_mesh() */
/* read_mesh can be freed by BKE_mesh_nomain_to_mesh(), so get the flag before that happens. */
- short autosmooth = (read_mesh->flag & ME_AUTOSMOOTH);
+ uint16_t autosmooth = (read_mesh->flag & ME_AUTOSMOOTH);
BKE_mesh_nomain_to_mesh(read_mesh, mesh, object_, &CD_MASK_MESH, true);
mesh->flag |= autosmooth;
}
@@ -710,11 +752,8 @@ void USDMeshReader::assign_facesets_to_mpoly(double motionSampleTime,
int current_mat = 0;
if (!subsets.empty()) {
for (const pxr::UsdGeomSubset &subset : subsets) {
- pxr::UsdShadeMaterialBindingAPI subset_api = pxr::UsdShadeMaterialBindingAPI(
- subset.GetPrim());
-
- pxr::UsdShadeMaterial subset_mtl = subset_api.ComputeBoundMaterial();
+ pxr::UsdShadeMaterial subset_mtl = utils::compute_bound_material(subset.GetPrim());
if (!subset_mtl) {
continue;
}
@@ -743,10 +782,9 @@ void USDMeshReader::assign_facesets_to_mpoly(double motionSampleTime,
}
if (r_mat_map->empty()) {
- pxr::UsdShadeMaterialBindingAPI api = pxr::UsdShadeMaterialBindingAPI(prim_);
-
- if (pxr::UsdShadeMaterial mtl = api.ComputeBoundMaterial()) {
+ pxr::UsdShadeMaterial mtl = utils::compute_bound_material(prim_);
+ if (mtl) {
pxr::SdfPath mtl_path = mtl.GetPath();
if (!mtl_path.IsEmpty()) {
@@ -764,7 +802,17 @@ void USDMeshReader::readFaceSetsSample(Main *bmain, Mesh *mesh, const double mot
std::map<pxr::SdfPath, int> mat_map;
assign_facesets_to_mpoly(motionSampleTime, mesh->mpoly, mesh->totpoly, &mat_map);
- utils::assign_materials(bmain, object_, mat_map, this->import_params_, this->prim_.GetStage());
+ /* Build material name map if it's not built yet. */
+ if (this->settings_->mat_name_to_mat.empty()) {
+ utils::build_mat_map(bmain, &this->settings_->mat_name_to_mat);
+ }
+ utils::assign_materials(bmain,
+ object_,
+ mat_map,
+ this->import_params_,
+ this->prim_.GetStage(),
+ this->settings_->mat_name_to_mat,
+ this->settings_->usd_path_to_mat_name);
}
Mesh *USDMeshReader::read_mesh(Mesh *existing_mesh,
diff --git a/source/blender/io/usd/intern/usd_reader_prim.h b/source/blender/io/usd/intern/usd_reader_prim.h
index fdf6247de16..c44c4a14ad7 100644
--- a/source/blender/io/usd/intern/usd_reader_prim.h
+++ b/source/blender/io/usd/intern/usd_reader_prim.h
@@ -7,7 +7,11 @@
#include <pxr/usd/usd/prim.h>
+#include <map>
+#include <string>
+
struct Main;
+struct Material;
struct Object;
namespace blender::io::usd {
@@ -33,6 +37,17 @@ struct ImportSettings {
CacheFile *cache_file;
+ /* Map a USD material prim path to a Blender material name.
+ * This map is updated by readers during stage traversal.
+ * This field is mutable because it is used to keep track
+ * of what the importer is doing. This is necessary even
+ * when all the other import settings are to remain const. */
+ mutable std::map<std::string, std::string> usd_path_to_mat_name;
+ /* Map a material name to Blender material.
+ * This map is updated by readers during stage traversal,
+ * and is mutable similar to the map above. */
+ mutable std::map<std::string, Material *> mat_name_to_mat;
+
ImportSettings()
: do_convert_mat(false),
from_up(0),
diff --git a/source/blender/io/usd/intern/usd_writer_abstract.cc b/source/blender/io/usd/intern/usd_writer_abstract.cc
index dbeb9df1ee8..2be9b1c065a 100644
--- a/source/blender/io/usd/intern/usd_writer_abstract.cc
+++ b/source/blender/io/usd/intern/usd_writer_abstract.cc
@@ -47,6 +47,11 @@ bool USDAbstractWriter::is_supported(const HierarchyContext * /*context*/) const
return true;
}
+std::string USDAbstractWriter::get_export_file_path() const
+{
+ return usd_export_context_.hierarchy_iterator->get_export_file_path();
+}
+
pxr::UsdTimeCode USDAbstractWriter::get_export_time_code() const
{
if (is_animated_) {
diff --git a/source/blender/io/usd/intern/usd_writer_abstract.h b/source/blender/io/usd/intern/usd_writer_abstract.h
index 66feb6e1070..8adc054c2c2 100644
--- a/source/blender/io/usd/intern/usd_writer_abstract.h
+++ b/source/blender/io/usd/intern/usd_writer_abstract.h
@@ -51,6 +51,7 @@ class USDAbstractWriter : public AbstractHierarchyWriter {
protected:
virtual void do_write(HierarchyContext &context) = 0;
+ std::string get_export_file_path() const;
pxr::UsdTimeCode get_export_time_code() const;
pxr::UsdShadeMaterial ensure_usd_material(const HierarchyContext &context, Material *material);
diff --git a/source/blender/io/usd/intern/usd_writer_material.cc b/source/blender/io/usd/intern/usd_writer_material.cc
index 1bfc0e50f69..6862f3835cf 100644
--- a/source/blender/io/usd/intern/usd_writer_material.cc
+++ b/source/blender/io/usd/intern/usd_writer_material.cc
@@ -10,6 +10,8 @@
#include "BKE_main.h"
#include "BKE_node.h"
+#include "IMB_colormanagement.h"
+
#include "BLI_fileops.h"
#include "BLI_linklist.h"
#include "BLI_listbase.h"
@@ -414,13 +416,10 @@ static pxr::TfToken get_node_tex_image_color_space(bNode *node)
Image *ima = reinterpret_cast<Image *>(node->id);
- if (strcmp(ima->colorspace_settings.name, "Raw") == 0) {
- return usdtokens::raw;
- }
- if (strcmp(ima->colorspace_settings.name, "Non-Color") == 0) {
+ if (IMB_colormanagement_space_name_is_data(ima->colorspace_settings.name)) {
return usdtokens::raw;
}
- if (strcmp(ima->colorspace_settings.name, "sRGB") == 0) {
+ if (IMB_colormanagement_space_name_is_srgb(ima->colorspace_settings.name)) {
return usdtokens::sRGB;
}
@@ -576,7 +575,7 @@ static std::string get_tex_image_asset_path(bNode *node,
char file_path[FILE_MAX];
BLI_split_file_part(path.c_str(), file_path, FILE_MAX);
- if (export_params.relative_texture_paths) {
+ if (export_params.relative_paths) {
BLI_path_join(exp_path, FILE_MAX, ".", "textures", file_path, nullptr);
}
else {
@@ -591,10 +590,11 @@ static std::string get_tex_image_asset_path(bNode *node,
BLI_split_dir_part(stage_path.c_str(), dir_path, FILE_MAX);
BLI_path_join(exp_path, FILE_MAX, dir_path, "textures", file_path, nullptr);
}
+ BLI_str_replace_char(exp_path, '\\', '/');
return exp_path;
}
- if (export_params.relative_texture_paths) {
+ if (export_params.relative_paths) {
/* Get the path relative to the USD. */
pxr::SdfLayerHandle layer = stage->GetRootLayer();
std::string stage_path = layer->GetRealPath();
@@ -606,14 +606,10 @@ static std::string get_tex_image_asset_path(bNode *node,
strcpy(rel_path, path.c_str());
BLI_path_rel(rel_path, stage_path.c_str());
-
- /* BLI_path_rel adds '//' as a prefix to the path, if
- * generating the relative path was successful. */
- if (rel_path[0] != '/' || rel_path[1] != '/') {
- /* No relative path generated. */
+ if (!BLI_path_is_rel(rel_path)) {
return path;
}
-
+ BLI_str_replace_char(rel_path, '\\', '/');
return rel_path + 2;
}
diff --git a/source/blender/io/usd/intern/usd_writer_volume.cc b/source/blender/io/usd/intern/usd_writer_volume.cc
new file mode 100644
index 00000000000..4126be6966a
--- /dev/null
+++ b/source/blender/io/usd/intern/usd_writer_volume.cc
@@ -0,0 +1,188 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+
+#include "usd_writer_volume.h"
+
+#include <pxr/base/tf/pathUtils.h>
+#include <pxr/usd/usdVol/openVDBAsset.h>
+#include <pxr/usd/usdVol/volume.h>
+
+#include "DNA_volume_types.h"
+#include "DNA_windowmanager_types.h"
+
+#include "BKE_volume.h"
+
+#include "BLI_fileops.h"
+#include "BLI_index_range.hh"
+#include "BLI_path_util.h"
+#include "BLI_string.h"
+
+#include "WM_api.h"
+
+#include "usd_hierarchy_iterator.h"
+
+namespace blender::io::usd {
+
+USDVolumeWriter::USDVolumeWriter(const USDExporterContext &ctx) : USDAbstractWriter(ctx)
+{
+}
+
+bool USDVolumeWriter::check_is_animated(const HierarchyContext &context) const
+{
+ const Volume *volume = static_cast<Volume *>(context.object->data);
+ return volume->is_sequence;
+}
+
+void USDVolumeWriter::do_write(HierarchyContext &context)
+{
+ Volume *volume = static_cast<Volume *>(context.object->data);
+ if (!BKE_volume_load(volume, usd_export_context_.bmain)) {
+ return;
+ }
+
+ const int num_grids = BKE_volume_num_grids(volume);
+ if (!num_grids) {
+ return;
+ }
+
+ auto vdb_file_path = resolve_vdb_file(volume);
+ if (!vdb_file_path.has_value()) {
+ WM_reportf(RPT_WARNING,
+ "USD Export: failed to resolve .vdb file for object: %s",
+ volume->id.name + 2);
+ return;
+ }
+
+ if (usd_export_context_.export_params.relative_paths) {
+ if (auto relative_vdb_file_path = construct_vdb_relative_file_path(*vdb_file_path)) {
+ vdb_file_path = relative_vdb_file_path;
+ }
+ else {
+ WM_reportf(RPT_WARNING,
+ "USD Export: couldn't construct relative file path for .vdb file, absolute path "
+ "will be used instead");
+ }
+ }
+
+ const pxr::UsdTimeCode timecode = get_export_time_code();
+ const pxr::SdfPath &volume_path = usd_export_context_.usd_path;
+ pxr::UsdStageRefPtr stage = usd_export_context_.stage;
+ pxr::UsdVolVolume usd_volume = pxr::UsdVolVolume::Define(stage, volume_path);
+
+ for (const int i : IndexRange(num_grids)) {
+ const VolumeGrid *grid = BKE_volume_grid_get_for_read(volume, i);
+ const std::string grid_name = BKE_volume_grid_name(grid);
+ const std::string grid_id = pxr::TfMakeValidIdentifier(grid_name);
+ const pxr::SdfPath grid_path = volume_path.AppendPath(pxr::SdfPath(grid_id));
+ pxr::UsdVolOpenVDBAsset usd_grid = pxr::UsdVolOpenVDBAsset::Define(stage, grid_path);
+ usd_grid.GetFieldNameAttr().Set(pxr::TfToken(grid_name), timecode);
+ usd_grid.GetFilePathAttr().Set(pxr::SdfAssetPath(*vdb_file_path), timecode);
+ usd_volume.CreateFieldRelationship(pxr::TfToken(grid_id), grid_path);
+ }
+
+ float3 volume_bound_min(std::numeric_limits<float>::max());
+ float3 volume_bound_max(std::numeric_limits<float>::min());
+ if (BKE_volume_min_max(volume, volume_bound_min, volume_bound_max)) {
+ const pxr::VtArray<pxr::GfVec3f> volume_extent = {pxr::GfVec3f(&volume_bound_min[0]),
+ pxr::GfVec3f(&volume_bound_max[0])};
+ usd_volume.GetExtentAttr().Set(volume_extent, timecode);
+ }
+
+ BKE_volume_unload(volume);
+}
+
+std::optional<std::string> USDVolumeWriter::resolve_vdb_file(const Volume *volume) const
+{
+ std::optional<std::string> vdb_file_path;
+ if (volume->filepath[0] == '\0') {
+ /* Entering this section should mean that Volume object contains OpenVDB data that is not
+ * obtained from external .vdb file but rather generated inside of Blender (i.e. by 'Mesh to
+ * Volume' modifier). Try to save this data to a .vdb file. */
+
+ vdb_file_path = construct_vdb_file_path(volume);
+ if (!BKE_volume_save(
+ volume, usd_export_context_.bmain, NULL, vdb_file_path.value_or("").c_str())) {
+ return std::nullopt;
+ }
+ }
+
+ if (!vdb_file_path.has_value()) {
+ vdb_file_path = BKE_volume_grids_frame_filepath(volume);
+ if (vdb_file_path->empty()) {
+ return std::nullopt;
+ }
+ }
+
+ return vdb_file_path;
+}
+
+std::optional<std::string> USDVolumeWriter::construct_vdb_file_path(const Volume *volume) const
+{
+ const std::string usd_file_path = get_export_file_path();
+ if (usd_file_path.empty()) {
+ return std::nullopt;
+ }
+
+ char usd_directory_path[FILE_MAX];
+ char usd_file_name[FILE_MAXFILE];
+ BLI_split_dirfile(usd_file_path.c_str(),
+ usd_directory_path,
+ usd_file_name,
+ sizeof(usd_directory_path),
+ sizeof(usd_file_name));
+
+ if (usd_directory_path[0] == '\0' || usd_file_name[0] == '\0') {
+ return std::nullopt;
+ }
+
+ const char *vdb_directory_name = "volumes";
+
+ char vdb_directory_path[FILE_MAX];
+ BLI_strncpy(vdb_directory_path, usd_directory_path, FILE_MAX);
+ strcat(vdb_directory_path, vdb_directory_name);
+ BLI_dir_create_recursive(vdb_directory_path);
+
+ char vdb_file_name[FILE_MAXFILE];
+ BLI_strncpy(vdb_file_name, volume->id.name + 2, FILE_MAXFILE);
+ const pxr::UsdTimeCode timecode = get_export_time_code();
+ if (!timecode.IsDefault()) {
+ const int frame = (int)timecode.GetValue();
+ const int num_frame_digits = frame == 0 ? 1 : integer_digits_i(abs(frame));
+ BLI_path_frame(vdb_file_name, frame, num_frame_digits);
+ }
+ strcat(vdb_file_name, ".vdb");
+
+ char vdb_file_path[FILE_MAX];
+ BLI_path_join(vdb_file_path, sizeof(vdb_file_path), vdb_directory_path, vdb_file_name, NULL);
+
+ return vdb_file_path;
+}
+
+std::optional<std::string> USDVolumeWriter::construct_vdb_relative_file_path(
+ const std::string &vdb_file_path) const
+{
+ const std::string usd_file_path = get_export_file_path();
+ if (usd_file_path.empty()) {
+ return std::nullopt;
+ }
+
+ char relative_path[FILE_MAX];
+ BLI_strncpy(relative_path, vdb_file_path.c_str(), FILE_MAX);
+ BLI_path_rel(relative_path, usd_file_path.c_str());
+ if (!BLI_path_is_rel(relative_path)) {
+ return std::nullopt;
+ }
+
+ /* Following code was written with an assumption that Blender's relative paths start with
+ * // characters as well as have OS dependent slashes. Inside of USD files those relative
+ * paths should start with either ./ or ../ characters and have always forward slashes (/)
+ * separating directories. This is the convention used in USD documentation (and it seems
+ * to be used in other DCC packages as well). */
+ std::string relative_path_processed = pxr::TfNormPath(relative_path + 2);
+ if (relative_path_processed[0] != '.') {
+ relative_path_processed.insert(0, "./");
+ }
+
+ return relative_path_processed;
+}
+
+} // namespace blender::io::usd
diff --git a/source/blender/io/usd/intern/usd_writer_volume.h b/source/blender/io/usd/intern/usd_writer_volume.h
new file mode 100644
index 00000000000..8c1e36b7e53
--- /dev/null
+++ b/source/blender/io/usd/intern/usd_writer_volume.h
@@ -0,0 +1,36 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+#pragma once
+
+#include <optional>
+
+#include "BLI_math_vec_types.hh"
+#include "usd_writer_abstract.h"
+
+struct Volume;
+
+namespace blender::io::usd {
+
+/* Writer for writing OpenVDB assets to UsdVolVolume. Volume data is stored in separate .vdb files
+ * which are referenced in USD file. */
+class USDVolumeWriter : public USDAbstractWriter {
+ public:
+ USDVolumeWriter(const USDExporterContext &ctx);
+
+ protected:
+ virtual bool check_is_animated(const HierarchyContext &context) const override;
+ virtual void do_write(HierarchyContext &context) override;
+
+ private:
+ /* Try to ensure that external .vdb file is available for USD to be referenced. Blender can
+ * either reference external OpenVDB data or generate such data internally. Latter option will
+ * mean that `resolve_vdb_file` method will try to export volume data to a new .vdb file. If
+ * successful, this method returns absolute file path to the resolved .vdb file, if not, returns
+ * `std::nullopt`. */
+ std::optional<std::string> resolve_vdb_file(const Volume *volume) const;
+
+ std::optional<std::string> construct_vdb_file_path(const Volume *volume) const;
+ std::optional<std::string> construct_vdb_relative_file_path(
+ const std::string &vdb_file_path) const;
+};
+
+} // namespace blender::io::usd
diff --git a/source/blender/io/usd/tests/usd_tests_common.h b/source/blender/io/usd/tests/usd_tests_common.h
index 7f6ae558354..949348da959 100644
--- a/source/blender/io/usd/tests/usd_tests_common.h
+++ b/source/blender/io/usd/tests/usd_tests_common.h
@@ -12,7 +12,7 @@ namespace blender::io::usd {
* Thus function must be called before instantiating a USD
* stage to avoid errors. The returned string is the path to
* the USD data files directory from which the plugins were
- * loaded. If the USD data files directory can't be determined,
+ * loaded. If the USD data files directory can't be determined,
* plugin registration is skipped and the empty string is
* returned. */
std::string register_usd_plugins_for_tests();
diff --git a/source/blender/io/usd/usd.h b/source/blender/io/usd/usd.h
index e63cd0a4e04..a07315d8b4e 100644
--- a/source/blender/io/usd/usd.h
+++ b/source/blender/io/usd/usd.h
@@ -15,6 +15,13 @@ struct CacheReader;
struct Object;
struct bContext;
+/* Behavior when the name of an imported material
+ * conflicts with an existing material. */
+typedef enum eUSDMtlNameCollisionMode {
+ USD_MTL_NAME_COLLISION_MAKE_UNIQUE = 0,
+ USD_MTL_NAME_COLLISION_REFERENCE_EXISTING = 1,
+} eUSDMtlNameCollisionMode;
+
struct USDExportParams {
bool export_animation;
bool export_hair;
@@ -28,7 +35,7 @@ struct USDExportParams {
bool generate_preview_surface;
bool export_textures;
bool overwrite_textures;
- bool relative_texture_paths;
+ bool relative_paths;
};
struct USDImportParams {
@@ -57,6 +64,7 @@ struct USDImportParams {
bool import_usd_preview;
bool set_material_blend;
float light_intensity_scale;
+ eUSDMtlNameCollisionMode mtl_name_collision_mode;
};
/* The USD_export takes a as_background_job parameter, and returns a boolean.
@@ -83,7 +91,7 @@ int USD_get_version(void);
/* USD Import and Mesh Cache interface. */
struct CacheArchiveHandle *USD_create_handle(struct Main *bmain,
- const char *filename,
+ const char *filepath,
struct ListBase *object_paths);
void USD_free_handle(struct CacheArchiveHandle *handle);
diff --git a/source/blender/io/wavefront_obj/CMakeLists.txt b/source/blender/io/wavefront_obj/CMakeLists.txt
index e0fe7ed4992..f7958ef4ec6 100644
--- a/source/blender/io/wavefront_obj/CMakeLists.txt
+++ b/source/blender/io/wavefront_obj/CMakeLists.txt
@@ -15,6 +15,7 @@ set(INC
../../makesrna
../../nodes
../../windowmanager
+ ../../../../extern/fast_float
../../../../extern/fmtlib/include
../../../../intern/guardedalloc
)
@@ -35,6 +36,7 @@ set(SRC
importer/obj_import_mesh.cc
importer/obj_import_mtl.cc
importer/obj_import_nurbs.cc
+ importer/obj_import_string_utils.cc
importer/obj_importer.cc
IO_wavefront_obj.h
@@ -50,6 +52,7 @@ set(SRC
importer/obj_import_mtl.hh
importer/obj_import_nurbs.hh
importer/obj_import_objects.hh
+ importer/obj_import_string_utils.hh
importer/obj_importer.hh
)
@@ -69,6 +72,7 @@ blender_add_lib(bf_wavefront_obj "${SRC}" "${INC}" "${INC_SYS}" "${LIB}")
if(WITH_GTESTS)
set(TEST_SRC
tests/obj_exporter_tests.cc
+ tests/obj_import_string_utils_tests.cc
tests/obj_importer_tests.cc
tests/obj_mtl_parser_tests.cc
diff --git a/source/blender/io/wavefront_obj/IO_wavefront_obj.h b/source/blender/io/wavefront_obj/IO_wavefront_obj.h
index 8b71ec750c0..b4a00deb99c 100644
--- a/source/blender/io/wavefront_obj/IO_wavefront_obj.h
+++ b/source/blender/io/wavefront_obj/IO_wavefront_obj.h
@@ -9,34 +9,20 @@
#include "BKE_context.h"
#include "BLI_path_util.h"
#include "DEG_depsgraph.h"
+#include "IO_orientation.h"
+#include "IO_path_util_types.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];
+ /** Pretend that destination file folder is this, if non-empty. Used only for tests. */
+ char file_base_for_tests[FILE_MAX];
/** Full path to current blender file (used for comments in output). */
const char *blen_filepath;
@@ -49,8 +35,8 @@ struct OBJExportParams {
int end_frame;
/* Geometry Transform options. */
- eTransformAxisForward forward_axis;
- eTransformAxisUp up_axis;
+ eIOAxis forward_axis;
+ eIOAxis up_axis;
float scaling_factor;
/* File Write Options. */
@@ -59,9 +45,11 @@ struct OBJExportParams {
eEvaluationMode export_eval_mode;
bool export_uv;
bool export_normals;
+ bool export_colors;
bool export_materials;
bool export_triangulated_mesh;
bool export_curves_as_nurbs;
+ ePathReferenceMode path_mode;
/* Grouping options. */
bool export_object_groups;
@@ -82,18 +70,21 @@ struct OBJImportParams {
char filepath[FILE_MAX];
/** Value 0 disables clamping. */
float clamp_size;
- eTransformAxisForward forward_axis;
- eTransformAxisUp up_axis;
+ eIOAxis forward_axis;
+ eIOAxis up_axis;
+ bool import_vertex_groups;
bool validate_meshes;
};
/**
- * Time the full import process.
+ * Perform the full import process.
+ * Import also changes the selection & the active object; callers
+ * need to update the UI bits if needed.
*/
void OBJ_import(bContext *C, const struct OBJImportParams *import_params);
/**
- * C-interface for the exporter.
+ * Perform the full export process.
*/
void OBJ_export(bContext *C, const struct OBJExportParams *export_params);
diff --git a/source/blender/io/wavefront_obj/exporter/obj_export_file_writer.cc b/source/blender/io/wavefront_obj/exporter/obj_export_file_writer.cc
index 194583e71fe..cb95c561547 100644
--- a/source/blender/io/wavefront_obj/exporter/obj_export_file_writer.cc
+++ b/source/blender/io/wavefront_obj/exporter/obj_export_file_writer.cc
@@ -8,11 +8,15 @@
#include <cstdio>
#include "BKE_blender_version.h"
+#include "BKE_geometry_set.hh"
+#include "BLI_color.hh"
#include "BLI_enumerable_thread_specific.hh"
#include "BLI_path_util.h"
#include "BLI_task.hh"
+#include "IO_path_util.hh"
+
#include "obj_export_mesh.hh"
#include "obj_export_mtl.hh"
#include "obj_export_nurbs.hh"
@@ -239,13 +243,38 @@ void obj_parallel_chunked_output(FormatHandler<eFileType::OBJ> &fh,
}
void OBJWriter::write_vertex_coords(FormatHandler<eFileType::OBJ> &fh,
- const OBJMesh &obj_mesh_data) const
+ const OBJMesh &obj_mesh_data,
+ bool write_colors) const
{
const int tot_count = obj_mesh_data.tot_vertices();
- obj_parallel_chunked_output(fh, tot_count, [&](FormatHandler<eFileType::OBJ> &buf, int i) {
- float3 vertex = obj_mesh_data.calc_vertex_coords(i, export_params_.scaling_factor);
- buf.write<eOBJSyntaxElement::vertex_coords>(vertex[0], vertex[1], vertex[2]);
- });
+
+ Mesh *mesh = obj_mesh_data.get_mesh();
+ CustomDataLayer *colors_layer = nullptr;
+ if (write_colors) {
+ colors_layer = BKE_id_attributes_active_color_get(&mesh->id);
+ }
+ if (write_colors && (colors_layer != nullptr)) {
+ MeshComponent component;
+ component.replace(mesh, GeometryOwnershipType::ReadOnly);
+ VArray<ColorGeometry4f> attribute = component.attribute_get_for_read<ColorGeometry4f>(
+ colors_layer->name, ATTR_DOMAIN_POINT, {0.0f, 0.0f, 0.0f, 0.0f});
+
+ BLI_assert(tot_count == attribute.size());
+ obj_parallel_chunked_output(fh, tot_count, [&](FormatHandler<eFileType::OBJ> &buf, int i) {
+ float3 vertex = obj_mesh_data.calc_vertex_coords(i, export_params_.scaling_factor);
+ ColorGeometry4f linear = attribute.get(i);
+ float srgb[3];
+ linearrgb_to_srgb_v3_v3(srgb, linear);
+ buf.write<eOBJSyntaxElement::vertex_coords_color>(
+ vertex[0], vertex[1], vertex[2], srgb[0], srgb[1], srgb[2]);
+ });
+ }
+ else {
+ obj_parallel_chunked_output(fh, tot_count, [&](FormatHandler<eFileType::OBJ> &buf, int i) {
+ float3 vertex = obj_mesh_data.calc_vertex_coords(i, export_params_.scaling_factor);
+ buf.write<eOBJSyntaxElement::vertex_coords>(vertex[0], vertex[1], vertex[2]);
+ });
+ }
}
void OBJWriter::write_uv_coords(FormatHandler<eFileType::OBJ> &fh, OBJMesh &r_obj_mesh_data) const
@@ -383,7 +412,7 @@ void OBJWriter::write_edges_indices(FormatHandler<eFileType::OBJ> &fh,
const IndexOffsets &offsets,
const OBJMesh &obj_mesh_data) const
{
- /* Note: ensure_mesh_edges should be called before. */
+ /* NOTE: ensure_mesh_edges should be called before. */
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 =
@@ -530,7 +559,11 @@ void MTLWriter::write_bsdf_properties(const MTLMaterial &mtl_material)
void MTLWriter::write_texture_map(
const MTLMaterial &mtl_material,
- const Map<const eMTLSyntaxElement, tex_map_XX>::Item &texture_map)
+ const Map<const eMTLSyntaxElement, tex_map_XX>::Item &texture_map,
+ const char *blen_filedir,
+ const char *dest_dir,
+ ePathReferenceMode path_mode,
+ Set<std::pair<std::string, std::string>> &copy_set)
{
std::string options;
/* Option strings should have their own leading spaces. */
@@ -546,7 +579,11 @@ void MTLWriter::write_texture_map(
#define SYNTAX_DISPATCH(eMTLSyntaxElement) \
if (texture_map.key == eMTLSyntaxElement) { \
- fmt_handler_.write<eMTLSyntaxElement>(options, texture_map.value.image_path); \
+ std::string path = path_reference( \
+ texture_map.value.image_path.c_str(), blen_filedir, dest_dir, path_mode, &copy_set); \
+ /* Always emit forward slashes for cross-platform compatibility. */ \
+ std::replace(path.begin(), path.end(), '\\', '/'); \
+ fmt_handler_.write<eMTLSyntaxElement>(options, path.c_str()); \
return; \
}
@@ -561,25 +598,35 @@ void MTLWriter::write_texture_map(
BLI_assert(!"This map type was not written to the file.");
}
-void MTLWriter::write_materials()
+void MTLWriter::write_materials(const char *blen_filepath,
+ ePathReferenceMode path_mode,
+ const char *dest_dir)
{
if (mtlmaterials_.size() == 0) {
return;
}
+
+ char blen_filedir[PATH_MAX];
+ BLI_split_dir_part(blen_filepath, blen_filedir, PATH_MAX);
+ BLI_path_slash_native(blen_filedir);
+ BLI_path_normalize(nullptr, blen_filedir);
+
std::sort(mtlmaterials_.begin(),
mtlmaterials_.end(),
[](const MTLMaterial &a, const MTLMaterial &b) { return a.name < b.name; });
+ Set<std::pair<std::string, std::string>> copy_set;
for (const MTLMaterial &mtlmat : mtlmaterials_) {
fmt_handler_.write<eMTLSyntaxElement::string>("\n");
fmt_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);
+ for (const auto &tex : mtlmat.texture_maps.items()) {
+ if (tex.value.image_path.empty()) {
+ continue;
}
+ write_texture_map(mtlmat, tex, blen_filedir, dest_dir, path_mode, copy_set);
}
}
+ path_reference_copy(copy_set);
}
Vector<int> MTLWriter::add_materials(const OBJMesh &mesh_to_export)
diff --git a/source/blender/io/wavefront_obj/exporter/obj_export_file_writer.hh b/source/blender/io/wavefront_obj/exporter/obj_export_file_writer.hh
index 96f7d434338..97c23484426 100644
--- a/source/blender/io/wavefront_obj/exporter/obj_export_file_writer.hh
+++ b/source/blender/io/wavefront_obj/exporter/obj_export_file_writer.hh
@@ -9,6 +9,7 @@
#include "DNA_meshdata_types.h"
#include "BLI_map.hh"
+#include "BLI_set.hh"
#include "BLI_vector.hh"
#include "IO_wavefront_obj.h"
@@ -71,9 +72,11 @@ class OBJWriter : NonMovable, NonCopyable {
*/
void write_mtllib_name(const StringRefNull mtl_filepath) const;
/**
- * Write vertex coordinates for all vertices as "v x y z".
+ * Write vertex coordinates for all vertices as "v x y z" or "v x y z r g b".
*/
- void write_vertex_coords(FormatHandler<eFileType::OBJ> &fh, const OBJMesh &obj_mesh_data) const;
+ void write_vertex_coords(FormatHandler<eFileType::OBJ> &fh,
+ const OBJMesh &obj_mesh_data,
+ bool write_colors) const;
/**
* Write UV vertex coordinates for all vertices as `vt u v`.
* \note UV indices are stored here, but written with polygons later.
@@ -181,7 +184,9 @@ class MTLWriter : NonMovable, NonCopyable {
* For consistency of output from run to run (useful for testing),
* the materials are sorted by name before writing.
*/
- void write_materials();
+ void write_materials(const char *blen_filepath,
+ ePathReferenceMode path_mode,
+ const char *dest_dir);
StringRefNull mtl_file_path() const;
/**
* Add the materials of the given object to #MTLWriter, de-duplicating
@@ -203,6 +208,10 @@ class MTLWriter : NonMovable, NonCopyable {
* 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);
+ const Map<const eMTLSyntaxElement, tex_map_XX>::Item &texture_map,
+ const char *blen_filedir,
+ const char *dest_dir,
+ ePathReferenceMode mode,
+ Set<std::pair<std::string, std::string>> &copy_set);
};
} // 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
index 0d7c089ec14..5413c9969e3 100644
--- a/source/blender/io/wavefront_obj/exporter/obj_export_io.hh
+++ b/source/blender/io/wavefront_obj/exporter/obj_export_io.hh
@@ -30,6 +30,7 @@ enum class eFileType {
enum class eOBJSyntaxElement {
vertex_coords,
+ vertex_coords_color,
uv_vertex_coords,
normal,
poly_element_begin,
@@ -130,6 +131,9 @@ constexpr FormattingSyntax syntax_elem_to_formatting(const eOBJSyntaxElement key
case eOBJSyntaxElement::vertex_coords: {
return {"v {:.6f} {:.6f} {:.6f}\n", 3, is_type_float<T...>};
}
+ case eOBJSyntaxElement::vertex_coords_color: {
+ return {"v {:.6f} {:.6f} {:.6f} {:.4f} {:.4f} {:.4f}\n", 6, is_type_float<T...>};
+ }
case eOBJSyntaxElement::uv_vertex_coords: {
return {"vt {:.6f} {:.6f}\n", 2, is_type_float<T...>};
}
@@ -236,7 +240,7 @@ constexpr FormattingSyntax syntax_elem_to_formatting(const eMTLSyntaxElement key
case eMTLSyntaxElement::Ke: {
return {"Ke {:.6f} {:.6f} {:.6f}\n", 3, is_type_float<T...>};
}
- /* Note: first texture map related argument, if present, will have its own leading space. */
+ /* NOTE: first texture map related argument, if present, will have its own leading space. */
case eMTLSyntaxElement::map_Kd: {
return {"map_Kd{} {}\n", 2, is_type_string_related<T...>};
}
diff --git a/source/blender/io/wavefront_obj/exporter/obj_export_mesh.cc b/source/blender/io/wavefront_obj/exporter/obj_export_mesh.cc
index c2a9e0574eb..e2ecda32717 100644
--- a/source/blender/io/wavefront_obj/exporter/obj_export_mesh.cc
+++ b/source/blender/io/wavefront_obj/exporter/obj_export_mesh.cc
@@ -117,15 +117,12 @@ std::pair<Mesh *, bool> OBJMesh::triangulate_mesh_eval()
return {triangulated, true};
}
-void OBJMesh::set_world_axes_transform(const eTransformAxisForward forward,
- const eTransformAxisUp up)
+void OBJMesh::set_world_axes_transform(const eIOAxis forward, const eIOAxis 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);
+ mat3_from_axis_conversion(forward, up, IO_AXIS_Y, IO_AXIS_Z, 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]);
@@ -290,7 +287,7 @@ void OBJMesh::store_uv_coords_and_indices()
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 *>(
+ const MLoopUV *mloopuv = static_cast<const MLoopUV *>(
CustomData_get_layer(&export_mesh_eval_->ldata, CD_MLOOPUV));
if (!mloopuv) {
tot_uv_vertices_ = 0;
@@ -382,8 +379,8 @@ void OBJMesh::store_normal_coords_and_indices()
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));
+ const float(*lnors)[3] = static_cast<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 = lnors != nullptr || (mpoly.flag & ME_SMOOTH);
@@ -453,7 +450,7 @@ int16_t OBJMesh::get_poly_deform_group_index(const int poly_index,
BLI_assert(poly_index < export_mesh_eval_->totpoly);
BLI_assert(group_weights.size() == BKE_object_defgroup_count(&export_object_eval_));
- const MDeformVert *dvert_layer = static_cast<MDeformVert *>(
+ const MDeformVert *dvert_layer = static_cast<const MDeformVert *>(
CustomData_get_layer(&export_mesh_eval_->vdata, CD_MDEFORMVERT));
if (!dvert_layer) {
return NOT_FOUND;
diff --git a/source/blender/io/wavefront_obj/exporter/obj_export_mesh.hh b/source/blender/io/wavefront_obj/exporter/obj_export_mesh.hh
index f47ca423dbc..ee2e6227700 100644
--- a/source/blender/io/wavefront_obj/exporter/obj_export_mesh.hh
+++ b/source/blender/io/wavefront_obj/exporter/obj_export_mesh.hh
@@ -241,6 +241,11 @@ class OBJMesh : NonCopyable {
return i < 0 || i >= poly_order_.size() ? i : poly_order_[i];
}
+ Mesh *get_mesh() const
+ {
+ return export_mesh_eval_;
+ }
+
private:
/**
* Free the mesh if _the exporter_ created it.
@@ -256,6 +261,6 @@ class OBJMesh : NonCopyable {
/**
* Set the final transform after applying axes settings and an Object's world transform.
*/
- void set_world_axes_transform(eTransformAxisForward forward, eTransformAxisUp up);
+ void set_world_axes_transform(eIOAxis forward, eIOAxis 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
index c48d5a5f7f0..4ed148ec64e 100644
--- a/source/blender/io/wavefront_obj/exporter/obj_export_mtl.cc
+++ b/source/blender/io/wavefront_obj/exporter/obj_export_mtl.cc
@@ -113,8 +113,7 @@ static const bNode *get_node_of_type(Span<const nodes::OutputSocketRef *> socket
/**
* 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.
+ * If packed image is found, only the file "name" is returned.
*/
static const char *get_image_filepath(const bNode *tex_node)
{
@@ -134,9 +133,6 @@ static const char *get_image_filepath(const bNode *tex_node)
"directory as the .MTL file.\n",
path);
}
- if (path[0] == '/' && path[1] == '/') {
- path += 2;
- }
return path;
}
diff --git a/source/blender/io/wavefront_obj/exporter/obj_export_nurbs.cc b/source/blender/io/wavefront_obj/exporter/obj_export_nurbs.cc
index c247048ce13..172a59e5341 100644
--- a/source/blender/io/wavefront_obj/exporter/obj_export_nurbs.cc
+++ b/source/blender/io/wavefront_obj/exporter/obj_export_nurbs.cc
@@ -25,15 +25,12 @@ OBJCurve::OBJCurve(const Depsgraph *depsgraph,
set_world_axes_transform(export_params.forward_axis, export_params.up_axis);
}
-void OBJCurve::set_world_axes_transform(const eTransformAxisForward forward,
- const eTransformAxisUp up)
+void OBJCurve::set_world_axes_transform(const eIOAxis forward, const eIOAxis 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);
+ mat3_from_axis_conversion(forward, up, IO_AXIS_Y, IO_AXIS_Z, 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]);
diff --git a/source/blender/io/wavefront_obj/exporter/obj_export_nurbs.hh b/source/blender/io/wavefront_obj/exporter/obj_export_nurbs.hh
index fe826725daf..65389d44f59 100644
--- a/source/blender/io/wavefront_obj/exporter/obj_export_nurbs.hh
+++ b/source/blender/io/wavefront_obj/exporter/obj_export_nurbs.hh
@@ -56,7 +56,7 @@ class OBJCurve : NonCopyable {
/**
* Set the final transform after applying axes settings and an Object's world transform.
*/
- void set_world_axes_transform(eTransformAxisForward forward, eTransformAxisUp up);
+ void set_world_axes_transform(eIOAxis forward, eIOAxis 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
index 78b709c884a..b0938084efb 100644
--- a/source/blender/io/wavefront_obj/exporter/obj_exporter.cc
+++ b/source/blender/io/wavefront_obj/exporter/obj_exporter.cc
@@ -195,7 +195,7 @@ static void write_mesh_objects(Vector<std::unique_ptr<OBJMesh>> exportable_as_me
auto &fh = buffers[i];
obj_writer.write_object_name(fh, obj);
- obj_writer.write_vertex_coords(fh, obj);
+ obj_writer.write_vertex_coords(fh, obj, export_params.export_colors);
if (obj.tot_polygons() > 0) {
if (export_params.export_smooth_groups) {
@@ -284,7 +284,16 @@ void export_frame(Depsgraph *depsgraph, const OBJExportParams &export_params, co
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();
+ char dest_dir[PATH_MAX];
+ if (export_params.file_base_for_tests[0] == '\0') {
+ BLI_split_dir_part(export_params.filepath, dest_dir, PATH_MAX);
+ }
+ else {
+ BLI_strncpy(dest_dir, export_params.file_base_for_tests, PATH_MAX);
+ }
+ BLI_path_slash_native(dest_dir);
+ BLI_path_normalize(nullptr, dest_dir);
+ mtl_writer->write_materials(export_params.blen_filepath, export_params.path_mode, dest_dir);
}
write_nurbs_curve_objects(std::move(exportable_as_nurbs), *frame_writer);
}
diff --git a/source/blender/io/wavefront_obj/importer/importer_mesh_utils.cc b/source/blender/io/wavefront_obj/importer/importer_mesh_utils.cc
index 7019e67419e..f33753d720d 100644
--- a/source/blender/io/wavefront_obj/importer/importer_mesh_utils.cc
+++ b/source/blender/io/wavefront_obj/importer/importer_mesh_utils.cc
@@ -99,13 +99,8 @@ void transform_object(Object *object, const OBJImportParams &import_params)
float obmat[4][4];
unit_m4(obmat);
/* +Y-forward and +Z-up are the default Blender axis settings. */
- mat3_from_axis_conversion(import_params.forward_axis,
- import_params.up_axis,
- OBJ_AXIS_Y_FORWARD,
- OBJ_AXIS_Z_UP,
- axes_transform);
- /* mat3_from_axis_conversion returns a transposed matrix! */
- transpose_m3(axes_transform);
+ mat3_from_axis_conversion(
+ IO_AXIS_Y, IO_AXIS_Z, import_params.forward_axis, import_params.up_axis, axes_transform);
copy_m4_m3(obmat, axes_transform);
BKE_object_apply_mat4(object, obmat, true, false);
diff --git a/source/blender/io/wavefront_obj/importer/obj_import_file_reader.cc b/source/blender/io/wavefront_obj/importer/obj_import_file_reader.cc
index be322f49840..3cc17e7d8e6 100644
--- a/source/blender/io/wavefront_obj/importer/obj_import_file_reader.cc
+++ b/source/blender/io/wavefront_obj/importer/obj_import_file_reader.cc
@@ -5,12 +5,15 @@
*/
#include "BLI_map.hh"
+#include "BLI_math_color.h"
+#include "BLI_math_vector.h"
#include "BLI_string_ref.hh"
#include "BLI_vector.hh"
-#include "IO_string_utils.hh"
-
#include "obj_import_file_reader.hh"
+#include "obj_import_string_utils.hh"
+
+#include <charconv>
namespace blender::io::obj {
@@ -35,6 +38,7 @@ static Geometry *create_geometry(Geometry *const prev_geometry,
g->geom_type_ = new_type;
g->geometry_name_ = name.is_empty() ? "New object" : name;
g->vertex_start_ = global_vertices.vertices.size();
+ g->vertex_color_start_ = global_vertices.vertex_colors.size();
r_offset.set_index_offset(g->vertex_start_);
return g;
};
@@ -67,40 +71,89 @@ static Geometry *create_geometry(Geometry *const prev_geometry,
}
static void geom_add_vertex(Geometry *geom,
- const StringRef line,
+ const char *p,
+ const char *end,
GlobalVertices &r_global_vertices)
{
float3 vert;
- parse_floats(line, 0.0f, vert, 3);
+ p = parse_floats(p, end, 0.0f, vert, 3);
r_global_vertices.vertices.append(vert);
geom->vertex_count_++;
+ /* OBJ extension: `xyzrgb` vertex colors, when the vertex position
+ * is followed by 3 more RGB color components. See
+ * http://paulbourke.net/dataformats/obj/colour.html */
+ if (p < end) {
+ float3 srgb;
+ p = parse_floats(p, end, -1.0f, srgb, 3);
+ if (srgb.x >= 0 && srgb.y >= 0 && srgb.z >= 0) {
+ float3 linear;
+ srgb_to_linearrgb_v3_v3(linear, srgb);
+ r_global_vertices.vertex_colors.append(linear);
+ geom->vertex_color_count_++;
+ }
+ }
+}
+
+static void geom_add_mrgb_colors(Geometry *geom,
+ const char *p,
+ const char *end,
+ GlobalVertices &r_global_vertices)
+{
+ /* MRGB color extension, in the form of
+ * "#MRGB MMRRGGBBMMRRGGBB ..."
+ * http://paulbourke.net/dataformats/obj/colour.html */
+ p = drop_whitespace(p, end);
+ const int mrgb_length = 8;
+ while (p + mrgb_length <= end) {
+ uint32_t value = 0;
+ std::from_chars_result res = std::from_chars(p, p + mrgb_length, value, 16);
+ if (res.ec == std::errc::invalid_argument || res.ec == std::errc::result_out_of_range) {
+ return;
+ }
+ unsigned char srgb[4];
+ srgb[0] = (value >> 16) & 0xFF;
+ srgb[1] = (value >> 8) & 0xFF;
+ srgb[2] = value & 0xFF;
+ srgb[3] = 0xFF;
+ float linear[4];
+ srgb_to_linearrgb_uchar4(linear, srgb);
+ r_global_vertices.vertex_colors.append({linear[0], linear[1], linear[2]});
+ geom->vertex_color_count_++;
+ p += mrgb_length;
+ }
}
static void geom_add_vertex_normal(Geometry *geom,
- const StringRef line,
+ const char *p,
+ const char *end,
GlobalVertices &r_global_vertices)
{
float3 normal;
- parse_floats(line, 0.0f, normal, 3);
+ parse_floats(p, end, 0.0f, normal, 3);
+ /* Normals can be printed with only several digits in the file,
+ * making them ever-so-slightly non unit length. Make sure they are
+ * normalized. */
+ normalize_v3(normal);
r_global_vertices.vertex_normals.append(normal);
geom->has_vertex_normals_ = true;
}
-static void geom_add_uv_vertex(const StringRef line, GlobalVertices &r_global_vertices)
+static void geom_add_uv_vertex(const char *p, const char *end, GlobalVertices &r_global_vertices)
{
float2 uv;
- parse_floats(line, 0.0f, uv, 2);
+ parse_floats(p, end, 0.0f, uv, 2);
r_global_vertices.uv_vertices.append(uv);
}
static void geom_add_edge(Geometry *geom,
- StringRef line,
+ const char *p,
+ const char *end,
const VertexIndexOffset &offsets,
GlobalVertices &r_global_vertices)
{
int edge_v1, edge_v2;
- line = parse_int(line, -1, edge_v1);
- line = parse_int(line, -1, edge_v2);
+ p = parse_int(p, end, -1, edge_v1);
+ p = parse_int(p, end, -1, edge_v2);
/* Always keep stored indices non-negative and zero-based. */
edge_v1 += edge_v1 < 0 ? r_global_vertices.vertices.size() : -offsets.get_index_offset() - 1;
edge_v2 += edge_v2 < 0 ? r_global_vertices.vertices.size() : -offsets.get_index_offset() - 1;
@@ -109,7 +162,8 @@ static void geom_add_edge(Geometry *geom,
}
static void geom_add_polygon(Geometry *geom,
- StringRef line,
+ const char *p,
+ const char *end,
const GlobalVertices &global_vertices,
const VertexIndexOffset &offsets,
const int material_index,
@@ -121,32 +175,32 @@ static void geom_add_polygon(Geometry *geom,
curr_face.material_index = material_index;
if (group_index >= 0) {
curr_face.vertex_group_index = group_index;
- geom->use_vertex_groups_ = true;
+ geom->has_vertex_groups_ = true;
}
const int orig_corners_size = geom->face_corners_.size();
curr_face.start_index_ = orig_corners_size;
bool face_valid = true;
- line = drop_whitespace(line);
- while (!line.is_empty() && face_valid) {
+ p = drop_whitespace(p, end);
+ while (p < end && face_valid) {
PolyCorner corner;
bool got_uv = false, got_normal = false;
/* Parse vertex index. */
- line = parse_int(line, INT32_MAX, corner.vert_index, false);
+ p = parse_int(p, end, INT32_MAX, corner.vert_index, false);
face_valid &= corner.vert_index != INT32_MAX;
- if (!line.is_empty() && line[0] == '/') {
+ if (p < end && *p == '/') {
/* Parse UV index. */
- line = line.drop_prefix(1);
- if (!line.is_empty() && line[0] != '/') {
- line = parse_int(line, INT32_MAX, corner.uv_vert_index, false);
+ ++p;
+ if (p < end && *p != '/') {
+ p = parse_int(p, end, INT32_MAX, corner.uv_vert_index, false);
got_uv = corner.uv_vert_index != INT32_MAX;
}
/* Parse normal index. */
- if (!line.is_empty() && line[0] == '/') {
- line = line.drop_prefix(1);
- line = parse_int(line, INT32_MAX, corner.vertex_normal_index, false);
- got_normal = corner.uv_vert_index != INT32_MAX;
+ if (p < end && *p == '/') {
+ ++p;
+ p = parse_int(p, end, INT32_MAX, corner.vertex_normal_index, false);
+ got_normal = corner.vertex_normal_index != INT32_MAX;
}
}
/* Always keep stored indices non-negative and zero-based. */
@@ -169,7 +223,10 @@ static void geom_add_polygon(Geometry *geom,
face_valid = false;
}
}
- if (got_normal) {
+ /* Ignore corner normal index, if the geometry does not have any normals.
+ * Some obj files out there do have face definitions that refer to normal indices,
+ * without any normals being present (T98782). */
+ if (got_normal && geom->has_vertex_normals_) {
corner.vertex_normal_index += corner.vertex_normal_index < 0 ?
global_vertices.vertex_normals.size() :
-1;
@@ -186,7 +243,7 @@ static void geom_add_polygon(Geometry *geom,
curr_face.corner_count_++;
/* Skip whitespace to get to the next face corner. */
- line = drop_whitespace(line);
+ p = drop_whitespace(p, end);
}
if (face_valid) {
@@ -201,14 +258,16 @@ static void geom_add_polygon(Geometry *geom,
}
static Geometry *geom_set_curve_type(Geometry *geom,
- const StringRef rest_line,
+ const char *p,
+ const char *end,
const GlobalVertices &global_vertices,
const StringRef group_name,
VertexIndexOffset &r_offsets,
Vector<std::unique_ptr<Geometry>> &r_all_geometries)
{
- if (rest_line.find("bspline") == StringRef::not_found) {
- std::cerr << "Curve type not supported:'" << rest_line << "'" << std::endl;
+ p = drop_whitespace(p, end);
+ if (!StringRef(p, end).startswith("bspline")) {
+ std::cerr << "Curve type not supported: '" << std::string(p, end) << "'" << std::endl;
return geom;
}
geom = create_geometry(
@@ -217,22 +276,23 @@ static Geometry *geom_set_curve_type(Geometry *geom,
return geom;
}
-static void geom_set_curve_degree(Geometry *geom, const StringRef line)
+static void geom_set_curve_degree(Geometry *geom, const char *p, const char *end)
{
- parse_int(line, 3, geom->nurbs_element_.degree);
+ parse_int(p, end, 3, geom->nurbs_element_.degree);
}
static void geom_add_curve_vertex_indices(Geometry *geom,
- StringRef line,
+ const char *p,
+ const char *end,
const GlobalVertices &global_vertices)
{
/* Curve lines always have "0.0" and "1.0", skip over them. */
float dummy[2];
- line = parse_floats(line, 0, dummy, 2);
+ p = parse_floats(p, end, 0, dummy, 2);
/* Parse indices. */
- while (!line.is_empty()) {
+ while (p < end) {
int index;
- line = parse_int(line, INT32_MAX, index);
+ p = parse_int(p, end, INT32_MAX, index);
if (index == INT32_MAX) {
return;
}
@@ -242,22 +302,22 @@ static void geom_add_curve_vertex_indices(Geometry *geom,
}
}
-static void geom_add_curve_parameters(Geometry *geom, StringRef line)
+static void geom_add_curve_parameters(Geometry *geom, const char *p, const char *end)
{
- line = drop_whitespace(line);
- if (line.is_empty()) {
- std::cerr << "Invalid OBJ curve parm line: '" << line << "'" << std::endl;
+ p = drop_whitespace(p, end);
+ if (p == end) {
+ std::cerr << "Invalid OBJ curve parm line" << std::endl;
return;
}
- if (line[0] != 'u') {
- std::cerr << "OBJ curve surfaces are not supported: '" << line[0] << "'" << std::endl;
+ if (*p != 'u') {
+ std::cerr << "OBJ curve surfaces are not supported: '" << *p << "'" << std::endl;
return;
}
- line = line.drop_prefix(1);
+ ++p;
- while (!line.is_empty()) {
+ while (p < end) {
float val;
- line = parse_float(line, FLT_MAX, val);
+ p = parse_float(p, end, FLT_MAX, val);
if (val != FLT_MAX) {
geom->nurbs_element_.parm.append(val);
}
@@ -270,7 +330,6 @@ static void geom_add_curve_parameters(Geometry *geom, StringRef line)
static void geom_update_group(const StringRef rest_line, std::string &r_group_name)
{
-
if (rest_line.find("off") != string::npos || rest_line.find("null") != string::npos ||
rest_line.find("default") != string::npos) {
/* Set group for future elements like faces or curves to empty. */
@@ -280,17 +339,18 @@ static void geom_update_group(const StringRef rest_line, std::string &r_group_na
r_group_name = rest_line;
}
-static void geom_update_smooth_group(StringRef line, bool &r_state_shaded_smooth)
+static void geom_update_smooth_group(const char *p, const char *end, bool &r_state_shaded_smooth)
{
- line = drop_whitespace(line);
+ p = drop_whitespace(p, end);
/* Some implementations use "0" and "null" too, in addition to "off". */
+ const StringRef line = StringRef(p, end);
if (line == "0" || line.startswith("off") || line.startswith("null")) {
r_state_shaded_smooth = false;
return;
}
int smooth = 0;
- parse_int(line, 0, smooth);
+ parse_int(p, end, 0, smooth);
r_state_shaded_smooth = smooth != 0;
}
@@ -312,21 +372,21 @@ OBJParser::~OBJParser()
}
/* If line starts with keyword followed by whitespace, returns true and drops it from the line. */
-static bool parse_keyword(StringRef &line, StringRef keyword)
+static bool parse_keyword(const char *&p, const char *end, StringRef keyword)
{
const size_t keyword_len = keyword.size();
- if (line.size() < keyword_len + 1) {
+ if (end - p < keyword_len + 1) {
return false;
}
- if (!line.startswith(keyword)) {
+ if (memcmp(p, keyword.data(), keyword_len) != 0) {
return false;
}
/* Treat any ASCII control character as white-space;
* don't use `isspace()` for performance reasons. */
- if (line[keyword_len] > ' ') {
+ if (p[keyword_len] > ' ') {
return false;
}
- line = line.drop_prefix(keyword_len + 1);
+ p += keyword_len + 1;
return true;
}
@@ -337,9 +397,14 @@ void OBJParser::parse(Vector<std::unique_ptr<Geometry>> &r_all_geometries,
return;
}
+ /* Use the filename as the default name given to the initial object. */
+ char ob_name[FILE_MAXFILE];
+ BLI_strncpy(ob_name, BLI_path_basename(import_params_.filepath), FILE_MAXFILE);
+ BLI_path_extension_replace(ob_name, FILE_MAXFILE, "");
+
VertexIndexOffset offsets;
Geometry *curr_geom = create_geometry(
- nullptr, GEOM_MESH, "", r_global_vertices, r_all_geometries, offsets);
+ nullptr, GEOM_MESH, ob_name, r_global_vertices, r_all_geometries, offsets);
/* State variables: once set, they remain the same for the remaining
* elements in the object. */
@@ -400,27 +465,29 @@ void OBJParser::parse(Vector<std::unique_ptr<Geometry>> &r_all_geometries,
StringRef buffer_str{buffer.data(), (int64_t)last_nl};
while (!buffer_str.is_empty()) {
StringRef line = read_next_line(buffer_str);
- line = drop_whitespace(line);
+ const char *p = line.begin(), *end = line.end();
+ p = drop_whitespace(p, end);
++line_number;
- if (line.is_empty()) {
+ if (p == end) {
continue;
}
/* Most common things that start with 'v': vertices, normals, UVs. */
- if (line[0] == 'v') {
- if (parse_keyword(line, "v")) {
- geom_add_vertex(curr_geom, line, r_global_vertices);
+ if (*p == 'v') {
+ if (parse_keyword(p, end, "v")) {
+ geom_add_vertex(curr_geom, p, end, r_global_vertices);
}
- else if (parse_keyword(line, "vn")) {
- geom_add_vertex_normal(curr_geom, line, r_global_vertices);
+ else if (parse_keyword(p, end, "vn")) {
+ geom_add_vertex_normal(curr_geom, p, end, r_global_vertices);
}
- else if (parse_keyword(line, "vt")) {
- geom_add_uv_vertex(line, r_global_vertices);
+ else if (parse_keyword(p, end, "vt")) {
+ geom_add_uv_vertex(p, end, r_global_vertices);
}
}
/* Faces. */
- else if (parse_keyword(line, "f")) {
+ else if (parse_keyword(p, end, "f")) {
geom_add_polygon(curr_geom,
- line,
+ p,
+ end,
r_global_vertices,
offsets,
state_material_index,
@@ -428,20 +495,24 @@ void OBJParser::parse(Vector<std::unique_ptr<Geometry>> &r_all_geometries,
state_shaded_smooth);
}
/* Faces. */
- else if (parse_keyword(line, "l")) {
- geom_add_edge(curr_geom, line, offsets, r_global_vertices);
+ else if (parse_keyword(p, end, "l")) {
+ geom_add_edge(curr_geom, p, end, offsets, r_global_vertices);
}
/* Objects. */
- else if (parse_keyword(line, "o")) {
+ else if (parse_keyword(p, end, "o")) {
state_shaded_smooth = false;
state_group_name = "";
state_material_name = "";
- curr_geom = create_geometry(
- curr_geom, GEOM_MESH, line.trim(), r_global_vertices, r_all_geometries, offsets);
+ curr_geom = create_geometry(curr_geom,
+ GEOM_MESH,
+ StringRef(p, end).trim(),
+ r_global_vertices,
+ r_all_geometries,
+ offsets);
}
/* Groups. */
- else if (parse_keyword(line, "g")) {
- geom_update_group(line.trim(), state_group_name);
+ else if (parse_keyword(p, end, "g")) {
+ geom_update_group(StringRef(p, end).trim(), state_group_name);
int new_index = curr_geom->group_indices_.size();
state_group_index = curr_geom->group_indices_.lookup_or_add(state_group_name, new_index);
if (new_index == state_group_index) {
@@ -449,12 +520,12 @@ void OBJParser::parse(Vector<std::unique_ptr<Geometry>> &r_all_geometries,
}
}
/* Smoothing groups. */
- else if (parse_keyword(line, "s")) {
- geom_update_smooth_group(line, state_shaded_smooth);
+ else if (parse_keyword(p, end, "s")) {
+ geom_update_smooth_group(p, end, state_shaded_smooth);
}
/* Materials and their libraries. */
- else if (parse_keyword(line, "usemtl")) {
- state_material_name = line.trim();
+ else if (parse_keyword(p, end, "usemtl")) {
+ state_material_name = StringRef(p, end).trim();
int new_mat_index = curr_geom->material_indices_.size();
state_material_index = curr_geom->material_indices_.lookup_or_add(state_material_name,
new_mat_index);
@@ -462,32 +533,35 @@ void OBJParser::parse(Vector<std::unique_ptr<Geometry>> &r_all_geometries,
curr_geom->material_order_.append(state_material_name);
}
}
- else if (parse_keyword(line, "mtllib")) {
- add_mtl_library(line.trim());
+ else if (parse_keyword(p, end, "mtllib")) {
+ add_mtl_library(StringRef(p, end).trim());
+ }
+ else if (parse_keyword(p, end, "#MRGB")) {
+ geom_add_mrgb_colors(curr_geom, p, end, r_global_vertices);
}
/* Comments. */
- else if (line.startswith("#")) {
+ else if (*p == '#') {
/* Nothing to do. */
}
/* Curve related things. */
- else if (parse_keyword(line, "cstype")) {
+ else if (parse_keyword(p, end, "cstype")) {
curr_geom = geom_set_curve_type(
- curr_geom, line, r_global_vertices, state_group_name, offsets, r_all_geometries);
+ curr_geom, p, end, r_global_vertices, state_group_name, offsets, r_all_geometries);
}
- else if (parse_keyword(line, "deg")) {
- geom_set_curve_degree(curr_geom, line);
+ else if (parse_keyword(p, end, "deg")) {
+ geom_set_curve_degree(curr_geom, p, end);
}
- else if (parse_keyword(line, "curv")) {
- geom_add_curve_vertex_indices(curr_geom, line, r_global_vertices);
+ else if (parse_keyword(p, end, "curv")) {
+ geom_add_curve_vertex_indices(curr_geom, p, end, r_global_vertices);
}
- else if (parse_keyword(line, "parm")) {
- geom_add_curve_parameters(curr_geom, line);
+ else if (parse_keyword(p, end, "parm")) {
+ geom_add_curve_parameters(curr_geom, p, end);
}
- else if (line.startswith("end")) {
+ else if (StringRef(p, end).startswith("end")) {
/* End of curve definition, nothing else to do. */
}
else {
- std::cout << "OBJ element not recognized: '" << line << "'" << std::endl;
+ std::cout << "OBJ element not recognized: '" << std::string(p, end) << "'" << std::endl;
}
}
@@ -501,33 +575,33 @@ void OBJParser::parse(Vector<std::unique_ptr<Geometry>> &r_all_geometries,
add_default_mtl_library();
}
-static eMTLSyntaxElement mtl_line_start_to_enum(StringRef &line)
+static eMTLSyntaxElement mtl_line_start_to_enum(const char *&p, const char *end)
{
- if (parse_keyword(line, "map_Kd")) {
+ if (parse_keyword(p, end, "map_Kd")) {
return eMTLSyntaxElement::map_Kd;
}
- if (parse_keyword(line, "map_Ks")) {
+ if (parse_keyword(p, end, "map_Ks")) {
return eMTLSyntaxElement::map_Ks;
}
- if (parse_keyword(line, "map_Ns")) {
+ if (parse_keyword(p, end, "map_Ns")) {
return eMTLSyntaxElement::map_Ns;
}
- if (parse_keyword(line, "map_d")) {
+ if (parse_keyword(p, end, "map_d")) {
return eMTLSyntaxElement::map_d;
}
- if (parse_keyword(line, "refl")) {
+ if (parse_keyword(p, end, "refl")) {
return eMTLSyntaxElement::map_refl;
}
- if (parse_keyword(line, "map_refl")) {
+ if (parse_keyword(p, end, "map_refl")) {
return eMTLSyntaxElement::map_refl;
}
- if (parse_keyword(line, "map_Ke")) {
+ if (parse_keyword(p, end, "map_Ke")) {
return eMTLSyntaxElement::map_Ke;
}
- if (parse_keyword(line, "bump")) {
+ if (parse_keyword(p, end, "bump")) {
return eMTLSyntaxElement::map_Bump;
}
- if (parse_keyword(line, "map_Bump") || parse_keyword(line, "map_bump")) {
+ if (parse_keyword(p, end, "map_Bump") || parse_keyword(p, end, "map_bump")) {
return eMTLSyntaxElement::map_Bump;
}
return eMTLSyntaxElement::string;
@@ -545,39 +619,43 @@ static const std::pair<StringRef, int> unsupported_texture_options[] = {
{"-texres", 1},
};
-static bool parse_texture_option(StringRef &line, MTLMaterial *material, tex_map_XX &tex_map)
+static bool parse_texture_option(const char *&p,
+ const char *end,
+ MTLMaterial *material,
+ tex_map_XX &tex_map)
{
- line = drop_whitespace(line);
- if (parse_keyword(line, "-o")) {
- line = parse_floats(line, 0.0f, tex_map.translation, 3);
+ p = drop_whitespace(p, end);
+ if (parse_keyword(p, end, "-o")) {
+ p = parse_floats(p, end, 0.0f, tex_map.translation, 3);
return true;
}
- if (parse_keyword(line, "-s")) {
- line = parse_floats(line, 1.0f, tex_map.scale, 3);
+ if (parse_keyword(p, end, "-s")) {
+ p = parse_floats(p, end, 1.0f, tex_map.scale, 3);
return true;
}
- if (parse_keyword(line, "-bm")) {
- line = parse_float(line, 1.0f, material->map_Bump_strength);
+ if (parse_keyword(p, end, "-bm")) {
+ p = parse_float(p, end, 1.0f, material->map_Bump_strength);
return true;
}
- if (parse_keyword(line, "-type")) {
- line = drop_whitespace(line);
+ if (parse_keyword(p, end, "-type")) {
+ p = drop_whitespace(p, end);
/* Only sphere is supported. */
tex_map.projection_type = SHD_PROJ_SPHERE;
+ const StringRef line = StringRef(p, end);
if (!line.startswith("sphere")) {
std::cerr << "OBJ import: only sphere MTL projection type is supported: '" << line << "'"
<< std::endl;
}
- line = drop_non_whitespace(line);
+ p = drop_non_whitespace(p, end);
return true;
}
/* Check for unsupported options and skip them. */
for (const auto &opt : unsupported_texture_options) {
- if (parse_keyword(line, opt.first)) {
+ if (parse_keyword(p, end, opt.first)) {
/* Drop the arguments. */
for (int i = 0; i < opt.second; ++i) {
- line = drop_whitespace(line);
- line = drop_non_whitespace(line);
+ p = drop_whitespace(p, end);
+ p = drop_non_whitespace(p, end);
}
return true;
}
@@ -586,15 +664,19 @@ static bool parse_texture_option(StringRef &line, MTLMaterial *material, tex_map
return false;
}
-static void parse_texture_map(StringRef line, MTLMaterial *material, const char *mtl_dir_path)
+static void parse_texture_map(const char *p,
+ const char *end,
+ MTLMaterial *material,
+ const char *mtl_dir_path)
{
+ const StringRef line = StringRef(p, end);
bool is_map = line.startswith("map_");
bool is_refl = line.startswith("refl");
bool is_bump = line.startswith("bump");
if (!is_map && !is_refl && !is_bump) {
return;
}
- eMTLSyntaxElement key = mtl_line_start_to_enum(line);
+ eMTLSyntaxElement key = mtl_line_start_to_enum(p, end);
if (key == eMTLSyntaxElement::string || !material->texture_maps.contains(key)) {
/* No supported texture map found. */
std::cerr << "OBJ import: MTL texture map type not supported: '" << line << "'" << std::endl;
@@ -604,12 +686,11 @@ static void parse_texture_map(StringRef line, MTLMaterial *material, const char
tex_map.mtl_dir_path = mtl_dir_path;
/* Parse texture map options. */
- while (parse_texture_option(line, material, tex_map)) {
+ while (parse_texture_option(p, end, material, tex_map)) {
}
/* What remains is the image path. */
- line = line.trim();
- tex_map.image_path = line;
+ tex_map.image_path = StringRef(p, end).trim();
}
Span<std::string> OBJParser::mtl_libraries() const
@@ -667,51 +748,53 @@ void MTLParser::parse_and_store(Map<string, std::unique_ptr<MTLMaterial>> &r_mat
StringRef buffer_str{(const char *)buffer, (int64_t)buffer_len};
while (!buffer_str.is_empty()) {
- StringRef line = read_next_line(buffer_str);
- line = drop_whitespace(line);
- if (line.is_empty()) {
+ const StringRef line = read_next_line(buffer_str);
+ const char *p = line.begin(), *end = line.end();
+ p = drop_whitespace(p, end);
+ if (p == end) {
continue;
}
- if (parse_keyword(line, "newmtl")) {
- line = line.trim();
- if (r_materials.contains(line)) {
+ if (parse_keyword(p, end, "newmtl")) {
+ StringRef mat_name = StringRef(p, end).trim();
+ if (r_materials.contains(mat_name)) {
material = nullptr;
}
else {
- material = r_materials.lookup_or_add(string(line), std::make_unique<MTLMaterial>()).get();
+ material =
+ r_materials.lookup_or_add(string(mat_name), std::make_unique<MTLMaterial>()).get();
}
}
else if (material != nullptr) {
- if (parse_keyword(line, "Ns")) {
- parse_float(line, 324.0f, material->Ns);
+ if (parse_keyword(p, end, "Ns")) {
+ parse_float(p, end, 324.0f, material->Ns);
}
- else if (parse_keyword(line, "Ka")) {
- parse_floats(line, 0.0f, material->Ka, 3);
+ else if (parse_keyword(p, end, "Ka")) {
+ parse_floats(p, end, 0.0f, material->Ka, 3);
}
- else if (parse_keyword(line, "Kd")) {
- parse_floats(line, 0.8f, material->Kd, 3);
+ else if (parse_keyword(p, end, "Kd")) {
+ parse_floats(p, end, 0.8f, material->Kd, 3);
}
- else if (parse_keyword(line, "Ks")) {
- parse_floats(line, 0.5f, material->Ks, 3);
+ else if (parse_keyword(p, end, "Ks")) {
+ parse_floats(p, end, 0.5f, material->Ks, 3);
}
- else if (parse_keyword(line, "Ke")) {
- parse_floats(line, 0.0f, material->Ke, 3);
+ else if (parse_keyword(p, end, "Ke")) {
+ parse_floats(p, end, 0.0f, material->Ke, 3);
}
- else if (parse_keyword(line, "Ni")) {
- parse_float(line, 1.45f, material->Ni);
+ else if (parse_keyword(p, end, "Ni")) {
+ parse_float(p, end, 1.45f, material->Ni);
}
- else if (parse_keyword(line, "d")) {
- parse_float(line, 1.0f, material->d);
+ else if (parse_keyword(p, end, "d")) {
+ parse_float(p, end, 1.0f, material->d);
}
- else if (parse_keyword(line, "illum")) {
+ else if (parse_keyword(p, end, "illum")) {
/* Some files incorrectly use a float (T60135). */
float val;
- parse_float(line, 1.0f, val);
+ parse_float(p, end, 1.0f, val);
material->illum = val;
}
else {
- parse_texture_map(line, material, mtl_dir_path_);
+ parse_texture_map(p, end, material, mtl_dir_path_);
}
}
}
diff --git a/source/blender/io/wavefront_obj/importer/obj_import_file_reader.hh b/source/blender/io/wavefront_obj/importer/obj_import_file_reader.hh
index e41a7f8518e..8bfc5fe8bf0 100644
--- a/source/blender/io/wavefront_obj/importer/obj_import_file_reader.hh
+++ b/source/blender/io/wavefront_obj/importer/obj_import_file_reader.hh
@@ -13,7 +13,7 @@
namespace blender::io::obj {
-/* Note: the OBJ parser implementation is planned to get fairly large changes "soon",
+/* NOTE: the OBJ parser implementation is planned to get fairly large changes "soon",
* so don't read too much into current implementation... */
class OBJParser {
private:
diff --git a/source/blender/io/wavefront_obj/importer/obj_import_mesh.cc b/source/blender/io/wavefront_obj/importer/obj_import_mesh.cc
index fc40333c24d..aa38a4d6715 100644
--- a/source/blender/io/wavefront_obj/importer/obj_import_mesh.cc
+++ b/source/blender/io/wavefront_obj/importer/obj_import_mesh.cc
@@ -8,7 +8,9 @@
#include "DNA_mesh_types.h"
#include "DNA_scene_types.h"
+#include "BKE_attribute.h"
#include "BKE_customdata.h"
+#include "BKE_deform.h"
#include "BKE_material.h"
#include "BKE_mesh.h"
#include "BKE_node_tree_update.h"
@@ -46,10 +48,11 @@ Object *MeshFromGeometry::create_mesh(Main *bmain,
obj->data = BKE_object_obdata_add_from_type(bmain, OB_MESH, ob_name.c_str());
create_vertices(mesh);
- create_polys_loops(obj, mesh);
+ create_polys_loops(mesh, import_params.import_vertex_groups);
create_edges(mesh);
create_uv_verts(mesh);
create_normals(mesh);
+ create_colors(mesh);
create_materials(bmain, materials, created_materials, obj);
if (import_params.validate_meshes || mesh_geometry_.has_invalid_polys_) {
@@ -62,11 +65,14 @@ Object *MeshFromGeometry::create_mesh(Main *bmain,
transform_object(obj, import_params);
/* FIXME: after 2.80; `mesh->flag` isn't copied by #BKE_mesh_nomain_to_mesh() */
- const short autosmooth = (mesh->flag & ME_AUTOSMOOTH);
+ const uint16_t autosmooth = (mesh->flag & ME_AUTOSMOOTH);
Mesh *dst = static_cast<Mesh *>(obj->data);
BKE_mesh_nomain_to_mesh(mesh, dst, obj, &CD_MASK_EVERYTHING, true);
dst->flag |= autosmooth;
+ /* Note: vertex groups have to be created after final mesh is assigned to the object. */
+ create_vertex_groups(obj);
+
return obj;
}
@@ -161,19 +167,13 @@ void MeshFromGeometry::create_vertices(Mesh *mesh)
}
}
-void MeshFromGeometry::create_polys_loops(Object *obj, Mesh *mesh)
+void MeshFromGeometry::create_polys_loops(Mesh *mesh, bool use_vertex_groups)
{
- /* Will not be used if vertex groups are not imported. */
mesh->dvert = nullptr;
- float weight = 0.0f;
const int64_t total_verts = mesh_geometry_.vertex_count_;
- if (total_verts && mesh_geometry_.use_vertex_groups_) {
+ if (use_vertex_groups && total_verts && mesh_geometry_.has_vertex_groups_) {
mesh->dvert = static_cast<MDeformVert *>(
CustomData_add_layer(&mesh->vdata, CD_MDEFORMVERT, CD_CALLOC, nullptr, total_verts));
- weight = 1.0f / total_verts;
- }
- else {
- UNUSED_VARS(weight);
}
const int64_t tot_face_elems{mesh->totpoly};
@@ -206,28 +206,23 @@ void MeshFromGeometry::create_polys_loops(Object *obj, Mesh *mesh)
tot_loop_idx++;
mloop.v = curr_corner.vert_index;
+ /* Setup vertex group data, if needed. */
if (!mesh->dvert) {
continue;
}
- /* Iterating over mloop results in finding the same vertex multiple times.
- * Another way is to allocate memory for dvert while creating vertices and fill them here.
- */
- MDeformVert &def_vert = mesh->dvert[mloop.v];
- if (!def_vert.dw) {
- def_vert.dw = static_cast<MDeformWeight *>(
- MEM_callocN(sizeof(MDeformWeight), "OBJ Import Deform Weight"));
- }
- /* Every vertex in a face is assigned the same deform group. */
- int group_idx = curr_face.vertex_group_index;
- /* Deform group number (def_nr) must behave like an index into the names' list. */
- *(def_vert.dw) = {static_cast<unsigned int>(group_idx), weight};
+ const int group_index = curr_face.vertex_group_index;
+ MDeformWeight *dw = BKE_defvert_ensure_index(mesh->dvert + mloop.v, group_index);
+ dw->weight = 1.0f;
}
}
+}
- if (!mesh->dvert) {
+void MeshFromGeometry::create_vertex_groups(Object *obj)
+{
+ Mesh *mesh = static_cast<Mesh *>(obj->data);
+ if (mesh->dvert == nullptr) {
return;
}
- /* Add deform group names. */
for (const std::string &name : mesh_geometry_.group_order_) {
BKE_object_defgroup_add_name(obj, name.data());
}
@@ -289,7 +284,7 @@ static Material *get_or_create_material(Main *bmain,
/* We have not, will have to create it. Create a new default
* MTLMaterial too, in case the OBJ file tries to use a material
* that was not in the MTL file. */
- const MTLMaterial &mtl = *materials.lookup_or_add(name, std::make_unique<MTLMaterial>()).get();
+ const MTLMaterial &mtl = *materials.lookup_or_add(name, std::make_unique<MTLMaterial>());
Material *mat = BKE_material_add(bmain, name.c_str());
ShaderNodetreeWrap mat_wrap{bmain, mtl, mat};
@@ -345,4 +340,26 @@ void MeshFromGeometry::create_normals(Mesh *mesh)
MEM_freeN(loop_normals);
}
+void MeshFromGeometry::create_colors(Mesh *mesh)
+{
+ /* Nothing to do if we don't have vertex colors. */
+ if (mesh_geometry_.vertex_color_count_ < 1) {
+ return;
+ }
+ if (mesh_geometry_.vertex_color_count_ != mesh_geometry_.vertex_count_) {
+ std::cerr << "Mismatching number of vertices (" << mesh_geometry_.vertex_count_
+ << ") and colors (" << mesh_geometry_.vertex_color_count_ << ") on object '"
+ << mesh_geometry_.geometry_name_ << "', ignoring colors." << std::endl;
+ return;
+ }
+
+ CustomDataLayer *color_layer = BKE_id_attribute_new(
+ &mesh->id, "Color", CD_PROP_COLOR, ATTR_DOMAIN_POINT, nullptr);
+ float4 *colors = (float4 *)color_layer->data;
+ for (int i = 0; i < mesh_geometry_.vertex_color_count_; ++i) {
+ float3 c = global_vertices_.vertex_colors[mesh_geometry_.vertex_color_start_ + i];
+ colors[i] = float4(c.x, c.y, c.z, 1.0f);
+ }
+}
+
} // namespace blender::io::obj
diff --git a/source/blender/io/wavefront_obj/importer/obj_import_mesh.hh b/source/blender/io/wavefront_obj/importer/obj_import_mesh.hh
index cf4a2aee394..591a7b81e63 100644
--- a/source/blender/io/wavefront_obj/importer/obj_import_mesh.hh
+++ b/source/blender/io/wavefront_obj/importer/obj_import_mesh.hh
@@ -45,10 +45,9 @@ class MeshFromGeometry : NonMovable, NonCopyable {
void fixup_invalid_faces();
void create_vertices(Mesh *mesh);
/**
- * Create polygons for the Mesh, set smooth shading flags, deform group names,
- * Materials.
+ * Create polygons for the Mesh, set smooth shading flags, Materials.
*/
- void create_polys_loops(Object *obj, Mesh *mesh);
+ void create_polys_loops(Mesh *mesh, bool use_vertex_groups);
/**
* Add explicitly imported OBJ edges to the mesh.
*/
@@ -65,6 +64,8 @@ class MeshFromGeometry : NonMovable, NonCopyable {
Map<std::string, Material *> &created_materials,
Object *obj);
void create_normals(Mesh *mesh);
+ void create_colors(Mesh *mesh);
+ void create_vertex_groups(Object *obj);
};
} // namespace blender::io::obj
diff --git a/source/blender/io/wavefront_obj/importer/obj_import_mtl.cc b/source/blender/io/wavefront_obj/importer/obj_import_mtl.cc
index c2ecd8a37de..f39def0a4af 100644
--- a/source/blender/io/wavefront_obj/importer/obj_import_mtl.cc
+++ b/source/blender/io/wavefront_obj/importer/obj_import_mtl.cc
@@ -13,13 +13,12 @@
#include "DNA_material_types.h"
#include "DNA_node_types.h"
-#include "IO_string_utils.hh"
-
#include "NOD_shader.h"
/* TODO: move eMTLSyntaxElement out of following file into a more neutral place */
#include "obj_export_io.hh"
#include "obj_import_mtl.hh"
+#include "obj_import_string_utils.hh"
namespace blender::io::obj {
diff --git a/source/blender/io/wavefront_obj/importer/obj_import_objects.hh b/source/blender/io/wavefront_obj/importer/obj_import_objects.hh
index b67ba46af03..3d6733d661e 100644
--- a/source/blender/io/wavefront_obj/importer/obj_import_objects.hh
+++ b/source/blender/io/wavefront_obj/importer/obj_import_objects.hh
@@ -26,6 +26,7 @@ struct GlobalVertices {
Vector<float3> vertices;
Vector<float2> uv_vertices;
Vector<float3> vertex_normals;
+ Vector<float3> vertex_colors;
};
/**
@@ -102,6 +103,8 @@ struct Geometry {
int vertex_start_ = 0;
int vertex_count_ = 0;
+ int vertex_color_start_ = 0;
+ int vertex_color_count_ = 0;
/** Edges written in the file in addition to (or even without polygon) elements. */
Vector<MEdge> edges_;
@@ -110,7 +113,7 @@ struct Geometry {
bool has_invalid_polys_ = false;
bool has_vertex_normals_ = false;
- bool use_vertex_groups_ = false;
+ bool has_vertex_groups_ = false;
NurbsElement nurbs_element_;
int total_loops_ = 0;
};
diff --git a/source/blender/io/wavefront_obj/importer/obj_import_string_utils.cc b/source/blender/io/wavefront_obj/importer/obj_import_string_utils.cc
new file mode 100644
index 00000000000..c8eaa046e68
--- /dev/null
+++ b/source/blender/io/wavefront_obj/importer/obj_import_string_utils.cc
@@ -0,0 +1,100 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+
+#include "obj_import_string_utils.hh"
+
+/* NOTE: we could use C++17 <charconv> from_chars to parse
+ * floats, but even if some compilers claim full support,
+ * their standard libraries are not quite there yet.
+ * LLVM/libc++ only has a float parser since LLVM 14,
+ * and gcc/libstdc++ since 11.1. So until at least these are
+ * the minimum spec, use an external library. */
+#include "fast_float.h"
+#include <charconv>
+
+namespace blender::io::obj {
+
+StringRef read_next_line(StringRef &buffer)
+{
+ const char *start = buffer.begin();
+ const char *end = buffer.end();
+ size_t len = 0;
+ char prev = 0;
+ const char *ptr = start;
+ while (ptr < end) {
+ char c = *ptr++;
+ if (c == '\n' && prev != '\\') {
+ break;
+ }
+ prev = c;
+ ++len;
+ }
+
+ buffer = StringRef(ptr, end);
+ return StringRef(start, len);
+}
+
+static bool is_whitespace(char c)
+{
+ return c <= ' ' || c == '\\';
+}
+
+const char *drop_whitespace(const char *p, const char *end)
+{
+ while (p < end && is_whitespace(*p)) {
+ ++p;
+ }
+ return p;
+}
+
+const char *drop_non_whitespace(const char *p, const char *end)
+{
+ while (p < end && !is_whitespace(*p)) {
+ ++p;
+ }
+ return p;
+}
+
+static const char *drop_plus(const char *p, const char *end)
+{
+ if (p < end && *p == '+') {
+ ++p;
+ }
+ return p;
+}
+
+const char *parse_float(
+ const char *p, const char *end, float fallback, float &dst, bool skip_space)
+{
+ if (skip_space) {
+ p = drop_whitespace(p, end);
+ }
+ p = drop_plus(p, end);
+ fast_float::from_chars_result res = fast_float::from_chars(p, end, dst);
+ if (res.ec == std::errc::invalid_argument || res.ec == std::errc::result_out_of_range) {
+ dst = fallback;
+ }
+ return res.ptr;
+}
+
+const char *parse_floats(const char *p, const char *end, float fallback, float *dst, int count)
+{
+ for (int i = 0; i < count; ++i) {
+ p = parse_float(p, end, fallback, dst[i]);
+ }
+ return p;
+}
+
+const char *parse_int(const char *p, const char *end, int fallback, int &dst, bool skip_space)
+{
+ if (skip_space) {
+ p = drop_whitespace(p, end);
+ }
+ p = drop_plus(p, end);
+ std::from_chars_result res = std::from_chars(p, end, dst);
+ if (res.ec == std::errc::invalid_argument || res.ec == std::errc::result_out_of_range) {
+ dst = fallback;
+ }
+ return res.ptr;
+}
+
+} // namespace blender::io::obj
diff --git a/source/blender/io/wavefront_obj/importer/obj_import_string_utils.hh b/source/blender/io/wavefront_obj/importer/obj_import_string_utils.hh
new file mode 100644
index 00000000000..3f428b1ab5c
--- /dev/null
+++ b/source/blender/io/wavefront_obj/importer/obj_import_string_utils.hh
@@ -0,0 +1,82 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+
+#pragma once
+
+#include "BLI_string_ref.hh"
+
+/*
+ * Various text parsing utilities used by OBJ importer.
+ * The utilities are not directly usable by other formats, since
+ * they treat backslash (\) as a whitespace character (OBJ format
+ * allows backslashes to function as a line-continuation character).
+ *
+ * Many of these functions take two pointers (p, end) indicating
+ * which part of a string to operate on, and return a possibly
+ * changed new start of the string. They could be taking a StringRef
+ * as input and returning a new StringRef, but this is a hot path
+ * in OBJ parsing, and the StringRef approach does lose performance
+ * (mostly due to return of StringRef being two register-size values
+ * instead of just one pointer).
+ */
+
+namespace blender::io::obj {
+
+/**
+ * Fetches next line from an input string buffer.
+ *
+ * The returned line will not have '\n' characters at the end;
+ * the `buffer` is modified to contain remaining text without
+ * the input line.
+ *
+ * Note that backslash (\) character is treated as a line
+ * continuation.
+ */
+StringRef read_next_line(StringRef &buffer);
+
+/**
+ * Drop leading white-space from a string part.
+ * Note that backslash character is considered white-space.
+ */
+const char *drop_whitespace(const char *p, const char *end);
+
+/**
+ * Drop leading non-white-space from a string part.
+ * Note that backslash character is considered white-space.
+ */
+const char *drop_non_whitespace(const char *p, const char *end);
+
+/**
+ * Parse an integer from an input string.
+ * The parsed result is stored in `dst`. The function skips
+ * leading white-space unless `skip_space=false`. If the
+ * number can't be parsed (invalid syntax, out of range),
+ * `fallback` value is stored instead.
+ *
+ * Returns the start of remainder of the input string after parsing.
+ */
+const char *parse_int(
+ const char *p, const char *end, int fallback, int &dst, bool skip_space = true);
+
+/**
+ * Parse a float from an input string.
+ * The parsed result is stored in `dst`. The function skips
+ * leading white-space unless `skip_space=false`. If the
+ * number can't be parsed (invalid syntax, out of range),
+ * `fallback` value is stored instead.
+ *
+ * Returns the start of remainder of the input string after parsing.
+ */
+const char *parse_float(
+ const char *p, const char *end, float fallback, float &dst, bool skip_space = true);
+
+/**
+ * Parse a number of white-space separated floats from an input string.
+ * The parsed `count` numbers are stored in `dst`. If a
+ * number can't be parsed (invalid syntax, out of range),
+ * `fallback` value is stored instead.
+ *
+ * Returns the start of remainder of the input string after parsing.
+ */
+const char *parse_floats(const char *p, const char *end, float fallback, float *dst, int count);
+
+} // namespace blender::io::obj
diff --git a/source/blender/io/wavefront_obj/importer/obj_importer.cc b/source/blender/io/wavefront_obj/importer/obj_importer.cc
index b18ff2cf454..f2051d195c8 100644
--- a/source/blender/io/wavefront_obj/importer/obj_importer.cc
+++ b/source/blender/io/wavefront_obj/importer/obj_importer.cc
@@ -88,7 +88,6 @@ void importer_main(bContext *C, const OBJImportParams &import_params)
Scene *scene = CTX_data_scene(C);
ViewLayer *view_layer = CTX_data_view_layer(C);
importer_main(bmain, scene, view_layer, import_params);
- static_cast<void>(CTX_data_ensure_evaluated_depsgraph(C));
}
void importer_main(Main *bmain,
diff --git a/source/blender/io/wavefront_obj/tests/obj_exporter_tests.cc b/source/blender/io/wavefront_obj/tests/obj_exporter_tests.cc
index f74bfc155dd..6aec848573f 100644
--- a/source/blender/io/wavefront_obj/tests/obj_exporter_tests.cc
+++ b/source/blender/io/wavefront_obj/tests/obj_exporter_tests.cc
@@ -11,12 +11,15 @@
#include "BKE_appdir.h"
#include "BKE_blender_version.h"
+#include "BKE_main.h"
#include "BLI_fileops.h"
#include "BLI_index_range.hh"
#include "BLI_string_utf8.h"
#include "BLI_vector.hh"
+#include "BLO_readfile.h"
+
#include "DEG_depsgraph.h"
#include "obj_export_file_writer.hh"
@@ -259,11 +262,12 @@ class obj_exporter_regression_test : public obj_exporter_test {
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();
+ params.blen_filepath = bfile->main->filepath;
+ std::string golden_file_path = blender::tests::flags_test_asset_dir() + "/" + golden_obj;
+ BLI_split_dir_part(golden_file_path.c_str(), params.file_base_for_tests, PATH_MAX);
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) {
@@ -311,8 +315,8 @@ TEST_F(obj_exporter_regression_test, all_quads)
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.forward_axis = IO_AXIS_Y;
+ _export.params.up_axis = IO_AXIS_Z;
_export.params.export_materials = false;
compare_obj_export_to_golden(
"io_tests/blend_geometry/fgons.blend", "io_tests/obj/fgons.obj", "", _export.params);
@@ -321,8 +325,8 @@ TEST_F(obj_exporter_regression_test, fgons)
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.forward_axis = IO_AXIS_Y;
+ _export.params.up_axis = IO_AXIS_Z;
_export.params.export_materials = false;
compare_obj_export_to_golden(
"io_tests/blend_geometry/edges.blend", "io_tests/obj/edges.obj", "", _export.params);
@@ -331,8 +335,8 @@ TEST_F(obj_exporter_regression_test, edges)
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.forward_axis = IO_AXIS_Y;
+ _export.params.up_axis = IO_AXIS_Z;
_export.params.export_materials = false;
compare_obj_export_to_golden(
"io_tests/blend_geometry/vertices.blend", "io_tests/obj/vertices.obj", "", _export.params);
@@ -351,8 +355,8 @@ TEST_F(obj_exporter_regression_test, non_uniform_scale)
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.forward_axis = IO_AXIS_Y;
+ _export.params.up_axis = IO_AXIS_Z;
_export.params.export_materials = false;
_export.params.export_curves_as_nurbs = true;
compare_obj_export_to_golden(
@@ -362,8 +366,8 @@ TEST_F(obj_exporter_regression_test, nurbs_as_nurbs)
TEST_F(obj_exporter_regression_test, nurbs_curves_as_nurbs)
{
OBJExportParamsDefault _export;
- _export.params.forward_axis = OBJ_AXIS_Y_FORWARD;
- _export.params.up_axis = OBJ_AXIS_Z_UP;
+ _export.params.forward_axis = IO_AXIS_Y;
+ _export.params.up_axis = IO_AXIS_Z;
_export.params.export_materials = false;
_export.params.export_curves_as_nurbs = true;
compare_obj_export_to_golden("io_tests/blend_geometry/nurbs_curves.blend",
@@ -375,8 +379,8 @@ TEST_F(obj_exporter_regression_test, nurbs_curves_as_nurbs)
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.forward_axis = IO_AXIS_Y;
+ _export.params.up_axis = IO_AXIS_Z;
_export.params.export_materials = false;
_export.params.export_curves_as_nurbs = false;
compare_obj_export_to_golden(
@@ -386,8 +390,8 @@ TEST_F(obj_exporter_regression_test, nurbs_as_mesh)
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.forward_axis = IO_AXIS_Y;
+ _export.params.up_axis = IO_AXIS_Z;
_export.params.export_materials = false;
_export.params.export_triangulated_mesh = true;
compare_obj_export_to_golden("io_tests/blend_geometry/cube_all_data.blend",
@@ -399,8 +403,8 @@ TEST_F(obj_exporter_regression_test, cube_all_data_triangulated)
TEST_F(obj_exporter_regression_test, cube_normal_edit)
{
OBJExportParamsDefault _export;
- _export.params.forward_axis = OBJ_AXIS_Y_FORWARD;
- _export.params.up_axis = OBJ_AXIS_Z_UP;
+ _export.params.forward_axis = IO_AXIS_Y;
+ _export.params.up_axis = IO_AXIS_Z;
_export.params.export_materials = false;
compare_obj_export_to_golden("io_tests/blend_geometry/cube_normal_edit.blend",
"io_tests/obj/cube_normal_edit.obj",
@@ -432,24 +436,44 @@ TEST_F(obj_exporter_regression_test, cubes_positioned)
_export.params);
}
-/* Note: texture paths in the resulting mtl file currently are always
- * as they are stored in the source .blend file; not relative to where
- * the export is done. When that is properly fixed, the expected .mtl
- * file should be updated. */
-TEST_F(obj_exporter_regression_test, cubes_with_textures)
+TEST_F(obj_exporter_regression_test, cubes_vertex_colors)
+{
+ OBJExportParamsDefault _export;
+ _export.params.export_colors = true;
+ _export.params.export_normals = false;
+ _export.params.export_uv = false;
+ _export.params.export_materials = false;
+ compare_obj_export_to_golden("io_tests/blend_geometry/cubes_vertex_colors.blend",
+ "io_tests/obj/cubes_vertex_colors.obj",
+ "",
+ _export.params);
+}
+
+TEST_F(obj_exporter_regression_test, cubes_with_textures_strip)
{
OBJExportParamsDefault _export;
+ _export.params.path_mode = PATH_REFERENCE_STRIP;
compare_obj_export_to_golden("io_tests/blend_geometry/cubes_with_textures.blend",
"io_tests/obj/cubes_with_textures.obj",
"io_tests/obj/cubes_with_textures.mtl",
_export.params);
}
+TEST_F(obj_exporter_regression_test, cubes_with_textures_relative)
+{
+ OBJExportParamsDefault _export;
+ _export.params.path_mode = PATH_REFERENCE_RELATIVE;
+ compare_obj_export_to_golden("io_tests/blend_geometry/cubes_with_textures.blend",
+ "io_tests/obj/cubes_with_textures_rel.obj",
+ "io_tests/obj/cubes_with_textures_rel.mtl",
+ _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.forward_axis = IO_AXIS_Y;
+ _export.params.up_axis = IO_AXIS_Z;
_export.params.export_materials = false;
_export.params.export_smooth_groups = true;
compare_obj_export_to_golden("io_tests/blend_geometry/suzanne_all_data.blend",
@@ -480,9 +504,10 @@ TEST_F(obj_exporter_regression_test, all_curves_as_nurbs)
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.forward_axis = IO_AXIS_Y;
+ _export.params.up_axis = IO_AXIS_Z;
_export.params.export_smooth_groups = true;
+ _export.params.export_colors = 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",
@@ -492,8 +517,8 @@ TEST_F(obj_exporter_regression_test, all_objects)
TEST_F(obj_exporter_regression_test, all_objects_mat_groups)
{
OBJExportParamsDefault _export;
- _export.params.forward_axis = OBJ_AXIS_Y_FORWARD;
- _export.params.up_axis = OBJ_AXIS_Z_UP;
+ _export.params.forward_axis = IO_AXIS_Y;
+ _export.params.up_axis = IO_AXIS_Z;
_export.params.export_smooth_groups = true;
_export.params.export_material_groups = true;
compare_obj_export_to_golden("io_tests/blend_scene/all_objects.blend",
diff --git a/source/blender/io/wavefront_obj/tests/obj_exporter_tests.hh b/source/blender/io/wavefront_obj/tests/obj_exporter_tests.hh
index 6a821e0b1bf..7d3b41ed527 100644
--- a/source/blender/io/wavefront_obj/tests/obj_exporter_tests.hh
+++ b/source/blender/io/wavefront_obj/tests/obj_exporter_tests.hh
@@ -11,13 +11,14 @@ struct OBJExportParamsDefault {
OBJExportParamsDefault()
{
params.filepath[0] = '\0';
+ params.file_base_for_tests[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.forward_axis = IO_AXIS_NEGATIVE_Z;
+ params.up_axis = IO_AXIS_Y;
params.scaling_factor = 1.f;
params.apply_modifiers = true;
@@ -25,7 +26,9 @@ struct OBJExportParamsDefault {
params.export_selected_objects = false;
params.export_uv = true;
params.export_normals = true;
+ params.export_colors = false;
params.export_materials = true;
+ params.path_mode = PATH_REFERENCE_AUTO;
params.export_triangulated_mesh = false;
params.export_curves_as_nurbs = false;
diff --git a/source/blender/io/common/intern/string_utils_test.cc b/source/blender/io/wavefront_obj/tests/obj_import_string_utils_tests.cc
index a78bd7ab8a3..46e093bb8a7 100644
--- a/source/blender/io/common/intern/string_utils_test.cc
+++ b/source/blender/io/wavefront_obj/tests/obj_import_string_utils_tests.cc
@@ -1,14 +1,14 @@
/* SPDX-License-Identifier: Apache-2.0 */
-#include "IO_string_utils.hh"
+#include "obj_import_string_utils.hh"
#include "testing/testing.h"
-namespace blender::io {
+namespace blender::io::obj {
#define EXPECT_STRREF_EQ(str1, str2) EXPECT_STREQ(str1, std::string(str2).c_str())
-TEST(string_utils, read_next_line)
+TEST(obj_import_string_utils, read_next_line)
{
std::string str = "abc\n \n\nline with \\\ncontinuation\nCRLF ending:\r\na";
StringRef s = str;
@@ -21,7 +21,20 @@ TEST(string_utils, read_next_line)
EXPECT_TRUE(s.is_empty());
}
-TEST(string_utils, drop_whitespace)
+static StringRef drop_whitespace(StringRef s)
+{
+ return StringRef(drop_whitespace(s.begin(), s.end()), s.end());
+}
+static StringRef parse_int(StringRef s, int fallback, int &dst, bool skip_space = true)
+{
+ return StringRef(parse_int(s.begin(), s.end(), fallback, dst, skip_space), s.end());
+}
+static StringRef parse_float(StringRef s, float fallback, float &dst, bool skip_space = true)
+{
+ return StringRef(parse_float(s.begin(), s.end(), fallback, dst, skip_space), s.end());
+}
+
+TEST(obj_import_string_utils, drop_whitespace)
{
/* Empty */
EXPECT_STRREF_EQ("", drop_whitespace(""));
@@ -39,7 +52,7 @@ TEST(string_utils, drop_whitespace)
EXPECT_STRREF_EQ("d", drop_whitespace(" \\ d"));
}
-TEST(string_utils, parse_int_valid)
+TEST(obj_import_string_utils, parse_int_valid)
{
std::string str = "1 -10 \t 1234 1234567890 +7 123a";
StringRef s = str;
@@ -59,7 +72,7 @@ TEST(string_utils, parse_int_valid)
EXPECT_STRREF_EQ("a", s);
}
-TEST(string_utils, parse_int_invalid)
+TEST(obj_import_string_utils, parse_int_invalid)
{
int val;
/* Invalid syntax */
@@ -75,7 +88,7 @@ TEST(string_utils, parse_int_invalid)
EXPECT_EQ(val, -4);
}
-TEST(string_utils, parse_float_valid)
+TEST(obj_import_string_utils, parse_float_valid)
{
std::string str = "1 -10 123.5 -17.125 0.1 1e6 50.0e-1";
StringRef s = str;
@@ -97,7 +110,7 @@ TEST(string_utils, parse_float_valid)
EXPECT_TRUE(s.is_empty());
}
-TEST(string_utils, parse_float_invalid)
+TEST(obj_import_string_utils, parse_float_invalid)
{
float val;
/* Invalid syntax */
@@ -115,4 +128,4 @@ TEST(string_utils, parse_float_invalid)
EXPECT_EQ(val, -4.0f);
}
-} // namespace blender::io
+} // namespace blender::io::obj
diff --git a/source/blender/io/wavefront_obj/tests/obj_importer_tests.cc b/source/blender/io/wavefront_obj/tests/obj_importer_tests.cc
index 3d34fb6f9c6..eeb81f5e23e 100644
--- a/source/blender/io/wavefront_obj/tests/obj_importer_tests.cc
+++ b/source/blender/io/wavefront_obj/tests/obj_importer_tests.cc
@@ -39,6 +39,7 @@ struct Expectation {
float3 vert_first, vert_last;
float3 normal_first;
float2 uv_first;
+ float4 color_first = {-1, -1, -1, -1};
};
class obj_importer_test : public BlendfileLoadingBaseTest {
@@ -55,8 +56,10 @@ class obj_importer_test : public BlendfileLoadingBaseTest {
OBJImportParams params;
params.clamp_size = 0;
- params.forward_axis = OBJ_AXIS_NEGATIVE_Z_FORWARD;
- params.up_axis = OBJ_AXIS_Y_UP;
+ params.forward_axis = IO_AXIS_NEGATIVE_Z;
+ params.up_axis = IO_AXIS_Y;
+ params.validate_meshes = true;
+ params.import_vertex_groups = false;
std::string obj_path = blender::tests::flags_test_asset_dir() + "/io_tests/obj/" + path;
strncpy(params.filepath, obj_path.c_str(), FILE_MAX - 1);
@@ -98,6 +101,15 @@ class obj_importer_test : public BlendfileLoadingBaseTest {
CustomData_get_layer(&mesh->ldata, CD_MLOOPUV));
float2 uv_first = mloopuv ? float2(mloopuv->uv) : float2(0, 0);
EXPECT_V2_NEAR(uv_first, exp.uv_first, 0.0001f);
+ if (exp.color_first.x >= 0) {
+ const float4 *colors = (const float4 *)(CustomData_get_layer(&mesh->vdata,
+ CD_PROP_COLOR));
+ EXPECT_TRUE(colors != nullptr);
+ EXPECT_V4_NEAR(colors[0], exp.color_first, 0.0001f);
+ }
+ else {
+ EXPECT_FALSE(CustomData_has_layer(&mesh->vdata, CD_PROP_COLOR));
+ }
}
if (object->type == OB_CURVES_LEGACY) {
Curve *curve = static_cast<Curve *>(DEG_get_evaluated_object(depsgraph, object)->data);
@@ -111,7 +123,7 @@ class obj_importer_test : public BlendfileLoadingBaseTest {
int endpoint = (nurb->flagu & CU_NURB_ENDPOINT) ? 1 : 0;
EXPECT_EQ(nurb->orderu, exp.mesh_totpoly_or_curve_order);
EXPECT_EQ(endpoint, exp.mesh_totedge_or_curve_endp);
- // Cyclic flag is not set by the importer yet
+ /* Cyclic flag is not set by the importer yet. */
// int cyclic = (nurb->flagu & CU_NURB_CYCLIC) ? 1 : 0;
// EXPECT_EQ(cyclic, exp.mesh_totloop_or_curve_cyclic);
}
@@ -133,7 +145,7 @@ TEST_F(obj_importer_test, import_cube)
{
Expectation expect[] = {
{"OBCube", OB_MESH, 8, 12, 6, 24, float3(1, 1, -1), float3(-1, 1, 1)},
- {"OBNew object",
+ {"OBcube",
OB_MESH,
8,
12,
@@ -168,7 +180,7 @@ TEST_F(obj_importer_test, import_nurbs)
{
Expectation expect[] = {
{"OBCube", OB_MESH, 8, 12, 6, 24, float3(1, 1, -1), float3(-1, 1, 1)},
- {"OBNew object",
+ {"OBnurbs",
OB_CURVES_LEGACY,
12,
0,
@@ -184,7 +196,7 @@ TEST_F(obj_importer_test, import_nurbs_curves)
{
Expectation expect[] = {
{"OBCube", OB_MESH, 8, 12, 6, 24, float3(1, 1, -1), float3(-1, 1, 1)},
- {"OBNew object", OB_CURVES_LEGACY, 4, 0, 4, 0, float3(2, -2, 0), float3(-2, -2, 0)},
+ {"OBnurbs_curves", OB_CURVES_LEGACY, 4, 0, 4, 0, float3(2, -2, 0), float3(-2, -2, 0)},
{"OBNurbsCurveDiffWeights",
OB_CURVES_LEGACY,
4,
@@ -211,7 +223,7 @@ TEST_F(obj_importer_test, import_nurbs_cyclic)
{
Expectation expect[] = {
{"OBCube", OB_MESH, 8, 12, 6, 24, float3(1, 1, -1), float3(-1, 1, 1)},
- {"OBNew object",
+ {"OBnurbs_cyclic",
OB_CURVES_LEGACY,
31,
0,
@@ -262,7 +274,7 @@ TEST_F(obj_importer_test, import_materials)
{
Expectation expect[] = {
{"OBCube", OB_MESH, 8, 12, 6, 24, float3(1, 1, -1), float3(-1, 1, 1)},
- {"OBNew object", OB_MESH, 8, 12, 6, 24, float3(-1, -1, 1), float3(1, -1, -1)},
+ {"OBmaterials", OB_MESH, 8, 12, 6, 24, float3(-1, -1, 1), float3(1, -1, -1)},
};
import_and_check("materials.obj", expect, std::size(expect), 4);
}
@@ -333,7 +345,7 @@ TEST_F(obj_importer_test, import_invalid_syntax)
{"OBCube", OB_MESH, 8, 12, 6, 24, float3(1, 1, -1), float3(-1, 1, 1)},
{"OBObjectWithAReallyLongNameToCheckHowImportHandlesNamesThatAreLon",
OB_MESH,
- 10, /* Note: right now parses some invalid obj syntax as valid vertices. */
+ 10, /* NOTE: right now parses some invalid obj syntax as valid vertices. */
3,
1,
3,
@@ -434,7 +446,17 @@ TEST_F(obj_importer_test, import_all_objects)
float3(16, 1, -1),
float3(14, 1, 1),
float3(0, 0, 1)},
- {"OBVColCube", OB_MESH, 8, 13, 7, 26, float3(13, 1, -1), float3(11, 1, 1), float3(0, 0, 1)},
+ {"OBVColCube",
+ OB_MESH,
+ 8,
+ 13,
+ 7,
+ 26,
+ float3(13, 1, -1),
+ float3(11, 1, 1),
+ float3(0, 0, 1),
+ float2(0, 0),
+ float4(0.0f, 0.002125f, 1.0f, 1.0f)},
{"OBUVCube",
OB_MESH,
8,
@@ -490,4 +512,103 @@ TEST_F(obj_importer_test, import_all_objects)
import_and_check("all_objects.obj", expect, std::size(expect), 7);
}
+TEST_F(obj_importer_test, import_cubes_vertex_colors)
+{
+ Expectation expect[] = {
+ {"OBCube", OB_MESH, 8, 12, 6, 24, float3(1, 1, -1), float3(-1, 1, 1)},
+ {"OBCubeVertexByte",
+ OB_MESH,
+ 8,
+ 12,
+ 6,
+ 24,
+ float3(1.0f, 1.0f, -1.0f),
+ float3(-1.0f, -1.0f, 1.0f),
+ float3(0, 0, 0),
+ float2(0, 0),
+ float4(0.846873f, 0.027321f, 0.982123f, 1.0f)},
+ {"OBCubeVertexFloat",
+ OB_MESH,
+ 8,
+ 12,
+ 6,
+ 24,
+ float3(3.392028f, 1.0f, -1.0f),
+ float3(1.392028f, -1.0f, 1.0f),
+ float3(0, 0, 0),
+ float2(0, 0),
+ float4(49.99467f, 0.027321f, 0.982123f, 1.0f)},
+ {"OBCubeCornerByte",
+ OB_MESH,
+ 8,
+ 12,
+ 6,
+ 24,
+ float3(1.0f, 1.0f, -3.812445f),
+ float3(-1.0f, -1.0f, -1.812445f),
+ float3(0, 0, 0),
+ float2(0, 0),
+ float4(0.89627f, 0.036889f, 0.47932f, 1.0f)},
+ {"OBCubeCornerFloat",
+ OB_MESH,
+ 8,
+ 12,
+ 6,
+ 24,
+ float3(3.481967f, 1.0f, -3.812445f),
+ float3(1.481967f, -1.0f, -1.812445f),
+ float3(0, 0, 0),
+ float2(0, 0),
+ float4(1.564582f, 0.039217f, 0.664309f, 1.0f)},
+ {"OBCubeMultiColorAttribs",
+ OB_MESH,
+ 8,
+ 12,
+ 6,
+ 24,
+ float3(-4.725068f, -1.0f, 1.0f),
+ float3(-2.725068f, 1.0f, -1.0f),
+ float3(0, 0, 0),
+ float2(0, 0),
+ float4(0.270498f, 0.47932f, 0.262251f, 1.0f)},
+ {"OBCubeNoColors",
+ OB_MESH,
+ 8,
+ 12,
+ 6,
+ 24,
+ float3(-4.550208f, -1.0f, -1.918042f),
+ float3(-2.550208f, 1.0f, -3.918042f)},
+ };
+ import_and_check("cubes_vertex_colors.obj", expect, std::size(expect), 0);
+}
+
+TEST_F(obj_importer_test, import_cubes_vertex_colors_mrgb)
+{
+ Expectation expect[] = {{"OBCube", OB_MESH, 8, 12, 6, 24, float3(1, 1, -1), float3(-1, 1, 1)},
+ {"OBCubeXYZRGB",
+ OB_MESH,
+ 8,
+ 12,
+ 6,
+ 24,
+ float3(1, 1, -1),
+ float3(-1, -1, 1),
+ float3(0, 0, 0),
+ float2(0, 0),
+ float4(0.6038f, 0.3185f, 0.1329f, 1.0f)},
+ {"OBCubeMRGB",
+ OB_MESH,
+ 8,
+ 12,
+ 6,
+ 24,
+ float3(4, 1, -1),
+ float3(2, -1, 1),
+ float3(0, 0, 0),
+ float2(0, 0),
+ float4(0.8714f, 0.6308f, 0.5271f, 1.0f)}};
+ import_and_check("cubes_vertex_colors_mrgb.obj", expect, std::size(expect), 0);
+}
+
} // namespace blender::io::obj
diff --git a/source/blender/makesdna/DNA_ID.h b/source/blender/makesdna/DNA_ID.h
index 17d783d3ebf..451c921c4ef 100644
--- a/source/blender/makesdna/DNA_ID.h
+++ b/source/blender/makesdna/DNA_ID.h
@@ -472,7 +472,7 @@ typedef struct Library {
ushort tag;
char _pad_0[6];
- /* Temp data needed by read/write code, and liboverride recursive resync. */
+ /** Temp data needed by read/write code, and lib-override recursive re-synchronized. */
int temp_index;
/** See BLENDER_FILE_VERSION, BLENDER_FILE_SUBVERSION, needed for do_versions. */
short versionfile, subversionfile;
@@ -597,6 +597,8 @@ typedef struct PreviewImage {
* Keep in sync with #BKE_id_eval_properties_copy. */
#define ID_TYPE_SUPPORTS_PARAMS_WITHOUT_COW(id_type) ELEM(id_type, ID_ME)
+#define ID_TYPE_IS_DEPRECATED(id_type) ELEM(id_type, ID_IP)
+
#ifdef GS
# undef GS
#endif
diff --git a/source/blender/makesdna/DNA_ID_enums.h b/source/blender/makesdna/DNA_ID_enums.h
index b0ca13615b8..5999af8bf5c 100644
--- a/source/blender/makesdna/DNA_ID_enums.h
+++ b/source/blender/makesdna/DNA_ID_enums.h
@@ -38,6 +38,8 @@ enum eIconSizes {
*
* Written to #BHead.code (for file IO)
* and the first 2 bytes of #ID.name (for runtime checks, see #GS macro).
+ *
+ * Update #ID_TYPE_IS_DEPRECATED() when deprecating types.
*/
typedef enum ID_Type {
ID_SCE = MAKE_ID2('S', 'C'), /* Scene */
diff --git a/source/blender/makesdna/DNA_anim_types.h b/source/blender/makesdna/DNA_anim_types.h
index c1dfab8a041..e2b58cefef6 100644
--- a/source/blender/makesdna/DNA_anim_types.h
+++ b/source/blender/makesdna/DNA_anim_types.h
@@ -771,7 +771,7 @@ typedef enum eNlaStrip_Blend_Mode {
NLASTRIP_MODE_COMBINE,
} eNlaStrip_Blend_Mode;
-/** NLA Strip Extrpolation Mode. */
+/** NLA Strip Extrapolation Mode. */
typedef enum eNlaStrip_Extrapolate_Mode {
/* extend before first frame if no previous strips in track,
* and always hold+extend last frame */
diff --git a/source/blender/makesdna/DNA_brush_enums.h b/source/blender/makesdna/DNA_brush_enums.h
index 1d5f1351de0..f2cd49b6dea 100644
--- a/source/blender/makesdna/DNA_brush_enums.h
+++ b/source/blender/makesdna/DNA_brush_enums.h
@@ -468,6 +468,7 @@ typedef enum eBrushCurvesSculptTool {
CURVES_SCULPT_TOOL_SNAKE_HOOK = 2,
CURVES_SCULPT_TOOL_ADD = 3,
CURVES_SCULPT_TOOL_GROW_SHRINK = 4,
+ CURVES_SCULPT_TOOL_SELECTION_PAINT = 5,
} eBrushCurvesSculptTool;
/** When #BRUSH_ACCUMULATE is used */
@@ -618,6 +619,7 @@ typedef enum eBrushCurvesSculptFlag {
BRUSH_CURVES_SCULPT_FLAG_GROW_SHRINK_INVERT = (1 << 1),
BRUSH_CURVES_SCULPT_FLAG_INTERPOLATE_LENGTH = (1 << 2),
BRUSH_CURVES_SCULPT_FLAG_INTERPOLATE_SHAPE = (1 << 3),
+ BRUSH_CURVES_SCULPT_FLAG_INTERPOLATE_POINT_COUNT = (1 << 4),
} eBrushCurvesSculptFlag;
#define MAX_BRUSH_PIXEL_RADIUS 500
diff --git a/source/blender/makesdna/DNA_brush_types.h b/source/blender/makesdna/DNA_brush_types.h
index 24e77ecf87f..d13496b21f7 100644
--- a/source/blender/makesdna/DNA_brush_types.h
+++ b/source/blender/makesdna/DNA_brush_types.h
@@ -97,7 +97,7 @@ typedef struct BrushGpencilSettings {
/** Simplify adaptive factor */
float simplify_f;
- /** Mix colorfactor */
+ /** Mix color-factor. */
float vertex_factor;
int vertex_mode;
diff --git a/source/blender/makesdna/DNA_camera_types.h b/source/blender/makesdna/DNA_camera_types.h
index 9b3adc4c8dd..e0aec298cd0 100644
--- a/source/blender/makesdna/DNA_camera_types.h
+++ b/source/blender/makesdna/DNA_camera_types.h
@@ -194,6 +194,9 @@ enum {
/* Axis flip options */
CAM_BGIMG_FLAG_FLIP_X = (1 << 7),
CAM_BGIMG_FLAG_FLIP_Y = (1 << 8),
+
+ /* That background image has been inserted in local override (i.e. it can be fully edited!). */
+ CAM_BGIMG_FLAG_OVERRIDE_LIBRARY_LOCAL = (1 << 9),
};
/* CameraBGImage->source */
diff --git a/source/blender/makesdna/DNA_cloth_types.h b/source/blender/makesdna/DNA_cloth_types.h
index e79a53704c9..8ac899df701 100644
--- a/source/blender/makesdna/DNA_cloth_types.h
+++ b/source/blender/makesdna/DNA_cloth_types.h
@@ -20,8 +20,8 @@ extern "C" {
* Mass-Spring Model to Describe Rigid Cloth Behavior by Xavier Provot.
*
* I've tried to keep similar, if not exact names for the variables as
- * are presented in the paper. Where I've changed the concept slightly,
- * as in stepsPerFrame compared to the time step in the paper, I've used
+ * are presented in the paper. Where I've changed the concept slightly,
+ * as in `stepsPerFrame` compared to the time step in the paper, I've used
* variables with different names to minimize confusion.
*/
diff --git a/source/blender/makesdna/DNA_constraint_types.h b/source/blender/makesdna/DNA_constraint_types.h
index 6557f35970d..8e0ce68f71a 100644
--- a/source/blender/makesdna/DNA_constraint_types.h
+++ b/source/blender/makesdna/DNA_constraint_types.h
@@ -105,8 +105,10 @@ typedef struct bConstraintTarget {
/* bConstraintTarget -> flag */
typedef enum eConstraintTargetFlag {
- /** temporary target-struct that needs to be freed after use */
+ /** Temporary target-struct that needs to be freed after use. */
CONSTRAINT_TAR_TEMP = (1 << 0),
+ /** Temporary target for the custom space reference. */
+ CONSTRAINT_TAR_CUSTOM_SPACE = (1 << 1),
} eConstraintTargetFlag;
/* bConstraintTarget/bConstraintOb -> type */
@@ -247,10 +249,9 @@ typedef struct bArmatureConstraint {
typedef struct bTrackToConstraint {
struct Object *tar;
/**
- * I'll be using reserved1 and reserved2 as Track and Up flags,
+ * NOTE(@theeth): I'll be using reserved1 and reserved2 as Track and Up flags,
* not sure if that's what they were intended for anyway.
* Not sure either if it would create backward incompatibility if I were to rename them.
- * - theeth
*/
int reserved1;
int reserved2;
diff --git a/source/blender/makesdna/DNA_curves_types.h b/source/blender/makesdna/DNA_curves_types.h
index e2ad5d38bbc..ed909c283c4 100644
--- a/source/blender/makesdna/DNA_curves_types.h
+++ b/source/blender/makesdna/DNA_curves_types.h
@@ -110,11 +110,11 @@ typedef struct CurvesGeometry {
/**
* The total number of control points in all curves.
*/
- int point_size;
+ int point_num;
/**
* The number of curves in the data-block.
*/
- int curve_size;
+ int curve_num;
/**
* Runtime data for curves, stored as a pointer to allow defining this as a C++ class.
@@ -141,7 +141,12 @@ typedef struct Curves {
* symmetrical geometry.
*/
char symmetry;
- char _pad2[5];
+ /**
+ * #eAttrDomain. The active selection mode domain. At most one selection mode can be active
+ * at a time.
+ */
+ char selection_domain;
+ char _pad[4];
/**
* Used as base mesh when curves represent e.g. hair or fur. This surface is used in edit modes.
@@ -152,6 +157,13 @@ typedef struct Curves {
*/
struct Object *surface;
+ /**
+ * The name of the attribute on the surface #Mesh used to give meaning to the UV attachment
+ * coordinates stored on each curve. Expected to be a 2D vector attribute on the face corner
+ * domain.
+ */
+ char *surface_uv_map;
+
/* Draw Cache. */
void *batch_cache;
} Curves;
@@ -159,6 +171,7 @@ typedef struct Curves {
/** #Curves.flag */
enum {
HA_DS_EXPAND = (1 << 0),
+ CV_SCULPT_SELECTION_ENABLED = (1 << 1),
};
/** #Curves.symmetry */
diff --git a/source/blender/makesdna/DNA_customdata_types.h b/source/blender/makesdna/DNA_customdata_types.h
index ef937fb139b..bc29de66cf9 100644
--- a/source/blender/makesdna/DNA_customdata_types.h
+++ b/source/blender/makesdna/DNA_customdata_types.h
@@ -81,7 +81,7 @@ typedef struct CustomData {
} CustomData;
/** #CustomData.type */
-typedef enum CustomDataType {
+typedef enum eCustomDataType {
/* Used by GLSL attributes in the cases when we need a delayed CD type
* assignment (in the cases when we don't know in advance which layer
* we are addressing).
@@ -161,9 +161,9 @@ typedef enum CustomDataType {
CD_HAIRLENGTH = 51,
CD_NUMTYPES = 52,
-} CustomDataType;
+} eCustomDataType;
-/* Bits for CustomDataMask */
+/* Bits for eCustomDataMask */
#define CD_MASK_MVERT (1 << CD_MVERT)
// #define CD_MASK_MSTICKY (1 << CD_MSTICKY) /* DEPRECATED */
#define CD_MASK_MDEFORMVERT (1 << CD_MDEFORMVERT)
@@ -260,8 +260,6 @@ enum {
#define DYNTOPO_NODE_NONE -1
-#define CD_TEMP_CHUNK_SIZE 128
-
#ifdef __cplusplus
}
#endif
diff --git a/source/blender/makesdna/DNA_gpencil_modifier_defaults.h b/source/blender/makesdna/DNA_gpencil_modifier_defaults.h
index 750f97bb3c6..ae47bf5d524 100644
--- a/source/blender/makesdna/DNA_gpencil_modifier_defaults.h
+++ b/source/blender/makesdna/DNA_gpencil_modifier_defaults.h
@@ -303,7 +303,8 @@
.crease_threshold = DEG2RAD(140.0f), \
.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), \
+ /* Do not split by default, this is for better chaining quality. */ \
+ .angle_splitting_threshold = 0.0f, \
.chaining_image_threshold = 0.001f, \
.chain_smooth_tolerance = 0.2f,\
.stroke_depth_offset = 0.05,\
diff --git a/source/blender/makesdna/DNA_gpencil_modifier_types.h b/source/blender/makesdna/DNA_gpencil_modifier_types.h
index 535533565dd..56963bae3e1 100644
--- a/source/blender/makesdna/DNA_gpencil_modifier_types.h
+++ b/source/blender/makesdna/DNA_gpencil_modifier_types.h
@@ -229,6 +229,7 @@ typedef enum eTimeGpencil_Mode {
GP_TIME_MODE_NORMAL = 0,
GP_TIME_MODE_REVERSE = 1,
GP_TIME_MODE_FIX = 2,
+ GP_TIME_MODE_PINGPONG = 3,
} eTimeGpencil_Mode;
typedef enum eModifyColorGpencil_Flag {
@@ -1097,7 +1098,7 @@ typedef struct LineartGpencilModifierData {
struct LineartCache *cache;
/* Keep a pointer to the render buffer so we can call destroy from ModifierData. */
- struct LineartRenderBuffer *render_buffer_ptr;
+ struct LineartData *la_data_ptr;
} LineartGpencilModifierData;
diff --git a/source/blender/makesdna/DNA_image_types.h b/source/blender/makesdna/DNA_image_types.h
index 4e66e2446f0..6e4e515a0fe 100644
--- a/source/blender/makesdna/DNA_image_types.h
+++ b/source/blender/makesdna/DNA_image_types.h
@@ -64,6 +64,11 @@ typedef struct ImageView {
typedef struct ImagePackedFile {
struct ImagePackedFile *next, *prev;
struct PackedFile *packedfile;
+
+ /* Which view and tile this ImagePackedFile represents. Normal images will use 0 and 1001
+ * respectively when creating their ImagePackedFile. Must be provided for each packed image. */
+ int view;
+ int tile_number;
/** 1024 = FILE_MAX. */
char filepath[1024];
} ImagePackedFile;
@@ -75,17 +80,11 @@ typedef struct RenderSlot {
struct RenderResult *render;
} RenderSlot;
-typedef struct ImageTile_RuntimeTextureSlot {
+typedef struct ImageTile_Runtime {
int tilearray_layer;
int _pad;
int tilearray_offset[2];
int tilearray_size[2];
-} ImageTile_RuntimeTextureSlot;
-
-typedef struct ImageTile_Runtime {
- /* Data per `eImageTextureResolution`.
- * Should match `IMA_TEXTURE_RESOLUTION_LEN` */
- ImageTile_RuntimeTextureSlot slots[2];
} ImageTile_Runtime;
typedef struct ImageTile {
@@ -104,10 +103,7 @@ typedef struct ImageTile {
/* #define IMA_UNUSED_2 (1 << 2) */
#define IMA_NEED_FRAME_RECALC (1 << 3)
#define IMA_SHOW_STEREO (1 << 4)
-/* Do not limit the resolution by the limit texture size option in the user preferences.
- * Images in the image editor or used as a backdrop are always shown using the maximum
- * possible resolution. */
-#define IMA_SHOW_MAX_RESOLUTION (1 << 5)
+/* #define IMA_UNUSED_5 (1 << 5) */
/* Used to get the correct gpu texture from an Image datablock. */
typedef enum eGPUTextureTarget {
@@ -117,15 +113,6 @@ typedef enum eGPUTextureTarget {
TEXTARGET_COUNT,
} eGPUTextureTarget;
-/* Resolution variations that can be cached for an image. */
-typedef enum eImageTextureResolution {
- IMA_TEXTURE_RESOLUTION_FULL = 0,
- IMA_TEXTURE_RESOLUTION_LIMITED,
-
- /* Not an option, but holds the number of options defined for this struct. */
- IMA_TEXTURE_RESOLUTION_LEN
-} eImageTextureResolution;
-
/* Defined in BKE_image.h. */
struct PartialUpdateRegister;
struct PartialUpdateUser;
@@ -150,8 +137,8 @@ typedef struct Image {
/** Not written in file. */
struct MovieCache *cache;
- /** Not written in file 3 = TEXTARGET_COUNT, 2 = stereo eyes, 2 = IMA_TEXTURE_RESOLUTION_LEN. */
- struct GPUTexture *gputexture[3][2][2];
+ /** Not written in file 3 = TEXTARGET_COUNT, 2 = stereo eyes. */
+ struct GPUTexture *gputexture[3][2];
/* sources from: */
ListBase anims;
@@ -239,11 +226,6 @@ enum {
enum {
/** All mipmap levels in OpenGL texture set? */
IMA_GPU_MIPMAP_COMPLETE = (1 << 0),
- /* Reuse the max resolution textures as they fit in the limited scale. */
- IMA_GPU_REUSE_MAX_RESOLUTION = (1 << 1),
- /* Has any limited scale textures been allocated.
- * Adds additional checks to reuse max resolution images when they fit inside limited scale. */
- IMA_GPU_HAS_LIMITED_SCALE_TEXTURES = (1 << 2),
};
/* Image.source, where the image comes from */
diff --git a/source/blender/makesdna/DNA_ipo_types.h b/source/blender/makesdna/DNA_ipo_types.h
index 70ee7c99d01..ef35b72d2ab 100644
--- a/source/blender/makesdna/DNA_ipo_types.h
+++ b/source/blender/makesdna/DNA_ipo_types.h
@@ -338,7 +338,7 @@ typedef struct Ipo {
#define CAM_STA 2
#define CAM_END 3
-/* yafray aperture & focal distance curves */
+/* YAFRAY aperture & focal distance curves. */
#define CAM_YF_APERT 4
#define CAM_YF_FDIST 5
diff --git a/source/blender/makesdna/DNA_light_types.h b/source/blender/makesdna/DNA_light_types.h
index 9202d7c2d51..f1bf0580b94 100644
--- a/source/blender/makesdna/DNA_light_types.h
+++ b/source/blender/makesdna/DNA_light_types.h
@@ -120,7 +120,7 @@ typedef struct Light {
/* #define LA_NO_DIFF (1 << 11) */ /* not used anywhere */
/* #define LA_NO_SPEC (1 << 12) */ /* not used anywhere */
/* #define LA_SHAD_RAY (1 << 13) */ /* not used anywhere - cleaned */
-/* yafray: light shadowbuffer flag, softlight */
+/* YAFRAY: light shadow-buffer flag, soft-light. */
/* Since it is used with LOCAL light, can't use LA_SHAD */
/* #define LA_YF_SOFT (1 << 14) */ /* not used anymore */
/* #define LA_LAYER_SHADOW (1 << 15) */ /* not used anymore */
diff --git a/source/blender/makesdna/DNA_lineart_types.h b/source/blender/makesdna/DNA_lineart_types.h
index 39b75b6eda2..444a0e6f247 100644
--- a/source/blender/makesdna/DNA_lineart_types.h
+++ b/source/blender/makesdna/DNA_lineart_types.h
@@ -14,7 +14,7 @@
* Edge flags and usage flags are used by with scene/object/gpencil modifier bits, and those values
* needs to stay consistent throughout. */
-/* These flags are used for 1 time calculation, not stroke selection afterwards. */
+/** These flags are used for 1 time calculation, not stroke selection afterwards. */
typedef enum eLineartMainFlags {
LRT_INTERSECTION_AS_CONTOUR = (1 << 0),
LRT_EVERYTHING_AS_CONTOUR = (1 << 1),
@@ -48,15 +48,19 @@ typedef enum eLineartEdgeFlag {
LRT_EDGE_FLAG_INTERSECTION = (1 << 4),
LRT_EDGE_FLAG_LOOSE = (1 << 5),
/* LRT_EDGE_FLAG_FOR_FUTURE = (1 << 7), */
- /* Limited to 8 bits for edge type flag, don't add anymore because BMEdge->head.eflag only has 8
- bits. So unless we changed this into a non-single-bit flag thing, we keep it this way. */
- /** Also used as discarded line mark. */
+ /**
+ * It's a legacy limit of 8 bits for feature lines that come from original mesh edges. It should
+ * not be needed in current object loading scheme, but might still be relevant if we are to
+ * implement edit-mesh loading, so don't exceed 8 bits just yet.
+ */
LRT_EDGE_FLAG_CHAIN_PICKED = (1 << 8),
LRT_EDGE_FLAG_CLIPPED = (1 << 9),
/** Limited to 16 bits for the entire thing. */
/** For object loading code to use only. */
LRT_EDGE_FLAG_INHIBIT = (1 << 14),
+ /** For discarding duplicated edge types in culling stage. */
+ LRT_EDGE_FLAG_NEXT_IS_DUPLICATION = (1 << 15),
} eLineartEdgeFlag;
#define LRT_EDGE_FLAG_ALL_TYPE 0x3f
diff --git a/source/blender/makesdna/DNA_mask_types.h b/source/blender/makesdna/DNA_mask_types.h
index 8efcef5addf..df4e6f788ff 100644
--- a/source/blender/makesdna/DNA_mask_types.h
+++ b/source/blender/makesdna/DNA_mask_types.h
@@ -198,6 +198,7 @@ enum {
/* SpaceClip->mask_draw_flag */
#define MASK_DRAWFLAG_SMOOTH (1 << 0)
#define MASK_DRAWFLAG_OVERLAY (1 << 1)
+#define MASK_DRAWFLAG_SPLINE (1 << 2)
/* copy of eSpaceImage_UVDT */
/* SpaceClip->mask_draw_type */
diff --git a/source/blender/makesdna/DNA_mesh_types.h b/source/blender/makesdna/DNA_mesh_types.h
index 97e057361c1..2eca84959b8 100644
--- a/source/blender/makesdna/DNA_mesh_types.h
+++ b/source/blender/makesdna/DNA_mesh_types.h
@@ -32,6 +32,7 @@ struct MVert;
struct Material;
struct Mesh;
struct SubdivCCG;
+struct SubsurfRuntimeData;
#
#
@@ -83,7 +84,7 @@ typedef struct Mesh_Runtime {
/**
* Data used to efficiently draw the mesh in the viewport, especially useful when
- * the same mesh is used in many objects or instances. See `draw_cache_impl_mesh.c`.
+ * the same mesh is used in many objects or instances. See `draw_cache_impl_mesh.cc`.
*/
void *batch_cache;
@@ -123,26 +124,18 @@ typedef struct Mesh_Runtime {
/**
* Settings for lazily evaluating the subdivision on the CPU if needed. These are
- * set in the modifier when GPU subdivision can be performed.
+ * set in the modifier when GPU subdivision can be performed, and owned by the by
+ * the modifier in the object.
*/
- SessionUUID subsurf_session_uuid;
- char subsurf_resolution;
- char subsurf_do_loop_normals;
- char subsurf_apply_render;
- char subsurf_use_optimal_display;
-
- /* Cached from the draw code for stats display. */
- int subsurf_totvert;
- int subsurf_totedge;
- int subsurf_totpoly;
- int subsurf_totloop;
- char _pad2[2];
+ struct SubsurfRuntimeData *subsurf_runtime_data;
+ void *_pad1;
/**
* Caches for lazily computed vertex and polygon normals. These are stored here rather than in
* #CustomData because they can be calculated on a const mesh, and adding custom data layers on a
* const mesh is not thread-safe.
*/
+ char _pad2[6];
char vert_normals_dirty;
char poly_normals_dirty;
float (*vert_normals)[3];
@@ -280,7 +273,7 @@ typedef struct Mesh {
/** Various flags used when editing the mesh. */
char editflag;
/** Mostly more flags used when editing or displaying the mesh. */
- unsigned short flag;
+ uint16_t flag;
/**
* The angle for auto smooth in radians. `M_PI` (180 degrees) causes all edges to be smooth.
diff --git a/source/blender/makesdna/DNA_modifier_types.h b/source/blender/makesdna/DNA_modifier_types.h
index 6e3ce7e98a8..f148116eba8 100644
--- a/source/blender/makesdna/DNA_modifier_types.h
+++ b/source/blender/makesdna/DNA_modifier_types.h
@@ -178,13 +178,6 @@ 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;
diff --git a/source/blender/makesdna/DNA_node_types.h b/source/blender/makesdna/DNA_node_types.h
index 92c4d8fe938..25c8a1f1514 100644
--- a/source/blender/makesdna/DNA_node_types.h
+++ b/source/blender/makesdna/DNA_node_types.h
@@ -71,11 +71,22 @@ namespace blender::nodes {
class NodeDeclaration;
class SocketDeclaration;
} // namespace blender::nodes
+namespace blender::bke {
+class bNodeTreeRuntime;
+class bNodeRuntime;
+class bNodeSocketRuntime;
+} // namespace blender::bke
using NodeDeclarationHandle = blender::nodes::NodeDeclaration;
using SocketDeclarationHandle = blender::nodes::SocketDeclaration;
+using bNodeTreeRuntimeHandle = blender::bke::bNodeTreeRuntime;
+using bNodeRuntimeHandle = blender::bke::bNodeRuntime;
+using bNodeSocketRuntimeHandle = blender::bke::bNodeSocketRuntime;
#else
typedef struct NodeDeclarationHandle NodeDeclarationHandle;
typedef struct SocketDeclarationHandle SocketDeclarationHandle;
+typedef struct bNodeTreeRuntimeHandle bNodeTreeRuntimeHandle;
+typedef struct bNodeRuntimeHandle bNodeRuntimeHandle;
+typedef struct bNodeSocketRuntimeHandle bNodeSocketRuntimeHandle;
#endif
typedef struct bNodeSocket {
@@ -129,7 +140,7 @@ typedef struct bNodeSocket {
short stack_type DNA_DEPRECATED;
char display_shape;
- /* #AttributeDomain used when the geometry nodes modifier creates an attribute for a group
+ /* #eAttrDomain used when the geometry nodes modifier creates an attribute for a group
* output. */
char attribute_domain;
/* Runtime-only cache of the number of input links, for multi-input sockets. */
@@ -169,15 +180,7 @@ typedef struct bNodeSocket {
/** Custom data for inputs, only UI writes in this. */
bNodeStack ns DNA_DEPRECATED;
- /**
- * References a socket declaration that is owned by `node->declaration`. This is only runtime
- * data. It has to be updated when the node declaration changes.
- */
- const SocketDeclarationHandle *declaration;
-
- /** #eNodeTreeChangedFlag. */
- uint32_t changed_flag;
- char _pad[4];
+ bNodeSocketRuntimeHandle *runtime;
} bNodeSocket;
/** #bNodeSocket.type & #bNodeSocketType.type */
@@ -266,9 +269,7 @@ typedef struct bNode {
/** Used as a boolean for execution. */
uint8_t need_exec;
- char _pad2[5];
- /** #eNodeTreeChangedFlag. */
- uint32_t changed_flag;
+ char _pad2[1];
/** Custom user-defined color. */
float color[3];
@@ -331,25 +332,7 @@ typedef struct bNode {
/** Used at runtime when iterating over node branches. */
char iter_flag;
- /**
- * Describes the desired interface of the node. This is run-time data only.
- * The actual interface of the node may deviate from the declaration temporarily.
- * It's possible to sync the actual state of the node to the desired state. Currently, this is
- * only done when a node is created or loaded.
- *
- * In the future, we may want to keep more data only in the declaration, so that it does not have
- * to be synced to other places that are stored in files. That especially applies to data that
- * can't be edited by users directly (e.g. min/max values of sockets, tooltips, ...).
- *
- * The declaration of a node can be recreated at any time when it is used. Caching it here is
- * just a bit more efficient when it is used a lot. To make sure that the cache is up-to-date,
- * call #nodeDeclarationEnsure before using it.
- *
- * Currently, the declaration is the same for every node of the same type. Going forward, that is
- * intended to change though. Especially when nodes become more dynamic with respect to how many
- * sockets they have.
- */
- NodeDeclarationHandle *declaration;
+ bNodeRuntimeHandle *runtime;
} bNode;
/* node->flag */
@@ -462,16 +445,6 @@ typedef struct bNodeLink {
#define NTREE_CHUNKSIZE_512 512
#define NTREE_CHUNKSIZE_1024 1024
-/** Workaround to forward-declare C++ type in C header. */
-#ifdef __cplusplus
-namespace blender::nodes {
-struct FieldInferencingInterface;
-}
-using FieldInferencingInterfaceHandle = blender::nodes::FieldInferencingInterface;
-#else
-typedef struct FieldInferencingInterfaceHandle FieldInferencingInterfaceHandle;
-#endif
-
/* the basis for a Node tree, all links and nodes reside internal here */
/* only re-usable node trees are in the library though,
* materials and textures allocate own tree struct */
@@ -494,25 +467,15 @@ typedef struct bNodeTree {
float view_center[2];
ListBase nodes, links;
- /** Information about how inputs and outputs of the node group interact with fields. */
- FieldInferencingInterfaceHandle *field_inferencing_interface;
int type;
- char _pad1[4];
-
/**
* Sockets in groups have unique identifiers, adding new sockets always
* will increase this counter.
*/
int cur_index;
int flag;
- /**
- * 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,11 +509,8 @@ typedef struct bNodeTree {
* in case multiple different editors are used and make context ambiguous.
*/
bNodeInstanceKey active_viewer_key;
- /**
- * 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;
+
+ char _pad[4];
/** Execution data.
*
@@ -573,6 +533,8 @@ typedef struct bNodeTree {
/** Image representing what the node group does. */
struct PreviewImage *preview;
+
+ bNodeTreeRuntimeHandle *runtime;
} bNodeTree;
/** #NodeTree.type, index */
@@ -601,6 +563,13 @@ typedef enum eNodeTreeExecutionMode {
NTREE_EXECUTION_MODE_FULL_FRAME = 1,
} eNodeTreeExecutionMode;
+typedef enum eNodeTreeRuntimeFlag {
+ /** There is a node that references an image with animation. */
+ NTREE_RUNTIME_FLAG_HAS_IMAGE_ANIMATION = 1 << 0,
+ /** There is a material output node in the group. */
+ NTREE_RUNTIME_FLAG_HAS_MATERIAL_OUTPUT = 1 << 1,
+} eNodeTreeRuntimeFlag;
+
/* socket value structs for input buttons
* DEPRECATED now using ID properties
*/
@@ -1206,7 +1175,7 @@ typedef struct NodeDenoise {
} NodeDenoise;
typedef struct NodeMapRange {
- /* CustomDataType */
+ /* eCustomDataType */
uint8_t data_type;
/* NodeMapRangeType. */
@@ -1216,14 +1185,14 @@ typedef struct NodeMapRange {
} NodeMapRange;
typedef struct NodeRandomValue {
- /* CustomDataType. */
+ /* eCustomDataType. */
uint8_t data_type;
} NodeRandomValue;
typedef struct NodeAccumulateField {
- /* CustomDataType. */
+ /* eCustomDataType. */
uint8_t data_type;
- /* AttributeDomain. */
+ /* eAttrDomain. */
uint8_t domain;
} NodeAccumulateField;
@@ -1393,9 +1362,9 @@ typedef struct NodeGeometryCurveSample {
} NodeGeometryCurveSample;
typedef struct NodeGeometryTransferAttribute {
- /* CustomDataType. */
+ /* eCustomDataType. */
int8_t data_type;
- /* AttributeDomain. */
+ /* eAttrDomain. */
int8_t domain;
/* GeometryNodeAttributeTransferMode. */
uint8_t mode;
@@ -1406,7 +1375,7 @@ typedef struct NodeGeometryRaycast {
/* GeometryNodeRaycastMapMode. */
uint8_t mapping;
- /* CustomDataType. */
+ /* eCustomDataType. */
int8_t data_type;
/* Deprecated input types in new Ray-cast node. Can be removed when legacy nodes are no longer
@@ -1425,21 +1394,21 @@ typedef struct NodeGeometryMeshToPoints {
} NodeGeometryMeshToPoints;
typedef struct NodeGeometryAttributeCapture {
- /* CustomDataType. */
+ /* eCustomDataType. */
int8_t data_type;
- /* AttributeDomain. */
+ /* eAttrDomain. */
int8_t domain;
} NodeGeometryAttributeCapture;
typedef struct NodeGeometryStoreNamedAttribute {
- /* CustomDataType. */
+ /* eCustomDataType. */
int8_t data_type;
- /* AttributeDomain. */
+ /* eAttrDomain. */
int8_t domain;
} NodeGeometryStoreNamedAttribute;
typedef struct NodeGeometryInputNamedAttribute {
- /* CustomDataType. */
+ /* eCustomDataType. */
int8_t data_type;
} NodeGeometryInputNamedAttribute;
@@ -1455,19 +1424,19 @@ typedef struct NodeGeometryStringToCurves {
} NodeGeometryStringToCurves;
typedef struct NodeGeometryDeleteGeometry {
- /* AttributeDomain. */
+ /* eAttrDomain. */
int8_t domain;
/* GeometryNodeDeleteGeometryMode. */
int8_t mode;
} NodeGeometryDeleteGeometry;
typedef struct NodeGeometryDuplicateElements {
- /* AttributeDomain. */
+ /* eAttrDomain. */
int8_t domain;
} NodeGeometryDuplicateElements;
typedef struct NodeGeometrySeparateGeometry {
- /* AttributeDomain. */
+ /* eAttrDomain. */
int8_t domain;
} NodeGeometrySeparateGeometry;
@@ -1477,7 +1446,7 @@ typedef struct NodeGeometryImageTexture {
} NodeGeometryImageTexture;
typedef struct NodeGeometryViewer {
- /* CustomDataType. */
+ /* eCustomDataType. */
int8_t data_type;
} NodeGeometryViewer;
@@ -1946,12 +1915,6 @@ typedef enum GeometryNodeBooleanOperation {
GEO_NODE_BOOLEAN_DIFFERENCE = 2,
} GeometryNodeBooleanOperation;
-typedef enum GeometryNodeSplineType {
- GEO_NODE_SPLINE_TYPE_BEZIER = 0,
- GEO_NODE_SPLINE_TYPE_NURBS = 1,
- GEO_NODE_SPLINE_TYPE_POLY = 2,
-} GeometryNodeSplineType;
-
typedef enum GeometryNodeCurvePrimitiveCircleMode {
GEO_NODE_CURVE_PRIMITIVE_CIRCLE_TYPE_POINTS = 0,
GEO_NODE_CURVE_PRIMITIVE_CIRCLE_TYPE_RADIUS = 1
diff --git a/source/blender/makesdna/DNA_object_types.h b/source/blender/makesdna/DNA_object_types.h
index f257833efe8..698fbe8ee8f 100644
--- a/source/blender/makesdna/DNA_object_types.h
+++ b/source/blender/makesdna/DNA_object_types.h
@@ -374,7 +374,7 @@ typedef struct Object {
/** Dupliface scale. */
float instance_faces_scale;
- /** Custom index, for renderpasses. */
+ /** Custom index, for render-passes. */
short index;
/** Current deformation group, NOTE: index starts at 1. */
unsigned short actdef DNA_DEPRECATED;
diff --git a/source/blender/makesdna/DNA_scene_types.h b/source/blender/makesdna/DNA_scene_types.h
index bfe967fcde5..1c62a550e60 100644
--- a/source/blender/makesdna/DNA_scene_types.h
+++ b/source/blender/makesdna/DNA_scene_types.h
@@ -991,6 +991,9 @@ typedef struct Sculpt {
// float pivot[3]; XXX not used?
int flags;
+ /* Transform tool. */
+ int transform_mode;
+
int automasking_flags;
/* Control tablet input */
@@ -1011,6 +1014,8 @@ typedef struct Sculpt {
float constant_detail;
float detail_percent;
+ char _pad[4];
+
struct Object *gravity_object;
} Sculpt;
@@ -1255,8 +1260,7 @@ typedef struct UnifiedPaintSettings {
* In case of anchored brushes contains the anchored radius */
float pixel_radius;
float initial_pixel_radius;
-
- char _pad[4];
+ float start_pixel_radius;
/* drawing pressure */
float size_pressure_value;
@@ -1491,18 +1495,19 @@ typedef struct ToolSettings {
/* Transform */
char transform_pivot_point;
char transform_flag;
- /** Snap elements (per spacetype). */
+ /** Snap elements (per spacetype), #eSnapMode. */
char snap_mode;
char snap_node_mode;
char snap_uv_mode;
- /** Generic flags (per spacetype). */
+ /** Generic flags (per spacetype), #eSnapFlag. */
char snap_flag;
char snap_flag_node;
char snap_flag_seq;
char snap_uv_flag;
- /** Default snap source. */
+ /** Default snap source, #eSnapSourceSelect. */
+ /* TODO(@gfxcoder): Rename `snap_target` to `snap_source_point`, because target is incorrect. */
char snap_target;
- /** Snap mask for transform modes. */
+ /** Snap mask for transform modes, #eSnapTransformMode. */
char snap_transform_mode_flag;
char proportional_edit, prop_mode;
@@ -2076,30 +2081,64 @@ enum {
};
/** #ToolSettings.snap_flag */
-#define SCE_SNAP (1 << 0)
-#define SCE_SNAP_ROTATE (1 << 1)
-#define SCE_SNAP_PEEL_OBJECT (1 << 2)
-#define SCE_SNAP_PROJECT (1 << 3)
-#define SCE_SNAP_NO_SELF (1 << 4)
-#define SCE_SNAP_ABS_GRID (1 << 5)
-#define SCE_SNAP_BACKFACE_CULLING (1 << 6)
-
-/** #ToolSettings.snap_target */
-#define SCE_SNAP_TARGET_CLOSEST 0
-#define SCE_SNAP_TARGET_CENTER 1
-#define SCE_SNAP_TARGET_MEDIAN 2
-#define SCE_SNAP_TARGET_ACTIVE 3
+typedef enum eSnapFlag {
+ SCE_SNAP = (1 << 0),
+ SCE_SNAP_ROTATE = (1 << 1),
+ SCE_SNAP_PEEL_OBJECT = (1 << 2),
+ SCE_SNAP_PROJECT = (1 << 3),
+ SCE_SNAP_NO_SELF = (1 << 4),
+ SCE_SNAP_ABS_GRID = (1 << 5),
+ SCE_SNAP_BACKFACE_CULLING = (1 << 6),
+} eSnapFlag;
+/* Due to dependency conflicts with Cycles, header cannot directly include `BLI_utildefines.h`. */
+/* TODO: move this macro to a more general place. */
+#ifdef ENUM_OPERATORS
+ENUM_OPERATORS(eSnapFlag, SCE_SNAP_BACKFACE_CULLING)
+#endif
+
+/** #ToolSettings.snap_target and #TransSnap.source_select */
+typedef enum eSnapSourceSelect {
+ SCE_SNAP_SOURCE_CLOSEST = 0,
+ SCE_SNAP_SOURCE_CENTER = 1,
+ SCE_SNAP_SOURCE_MEDIAN = 2,
+ SCE_SNAP_SOURCE_ACTIVE = 3,
+} eSnapSourceSelect;
+
+/** #TransSnap.target_select and #ToolSettings.snap_flag (SCE_SNAP_NO_SELF) */
+typedef enum eSnapTargetSelect {
+ SCE_SNAP_TARGET_ALL = 0,
+ SCE_SNAP_TARGET_NOT_SELECTED = 1,
+ SCE_SNAP_TARGET_NOT_ACTIVE = 2,
+ SCE_SNAP_TARGET_NOT_EDITED = 3,
+ SCE_SNAP_TARGET_ONLY_SELECTABLE = 4,
+} eSnapTargetSelect;
/** #ToolSettings.snap_mode */
-#define SCE_SNAP_MODE_VERTEX (1 << 0)
-#define SCE_SNAP_MODE_EDGE (1 << 1)
-#define SCE_SNAP_MODE_FACE (1 << 2)
-#define SCE_SNAP_MODE_VOLUME (1 << 3)
-#define SCE_SNAP_MODE_EDGE_MIDPOINT (1 << 4)
-#define SCE_SNAP_MODE_EDGE_PERPENDICULAR (1 << 5)
-#define SCE_SNAP_MODE_GEOM \
- (SCE_SNAP_MODE_VERTEX | SCE_SNAP_MODE_EDGE | SCE_SNAP_MODE_FACE | \
- SCE_SNAP_MODE_EDGE_PERPENDICULAR | SCE_SNAP_MODE_EDGE_MIDPOINT)
+typedef enum eSnapMode {
+ SCE_SNAP_MODE_NONE = 0,
+ SCE_SNAP_MODE_VERTEX = (1 << 0),
+ SCE_SNAP_MODE_EDGE = (1 << 1),
+ SCE_SNAP_MODE_FACE = (1 << 2), /* TODO(@gfxcoder): Rename to `SCE_SNAP_MODE_FACE_RAYCAST`
+ when other face snapping methods are added. */
+ SCE_SNAP_MODE_VOLUME = (1 << 3),
+ SCE_SNAP_MODE_EDGE_MIDPOINT = (1 << 4),
+ SCE_SNAP_MODE_EDGE_PERPENDICULAR = (1 << 5),
+ SCE_SNAP_MODE_GEOM = (SCE_SNAP_MODE_VERTEX | SCE_SNAP_MODE_EDGE | SCE_SNAP_MODE_FACE |
+ SCE_SNAP_MODE_EDGE_PERPENDICULAR | SCE_SNAP_MODE_EDGE_MIDPOINT),
+
+ /** #ToolSettings.snap_node_mode */
+ SCE_SNAP_MODE_NODE_X = (1 << 0),
+ SCE_SNAP_MODE_NODE_Y = (1 << 1),
+
+ /* #ToolSettings.snap_mode and #ToolSettings.snap_node_mode and #ToolSettings.snap_uv_mode */
+ SCE_SNAP_MODE_INCREMENT = (1 << 6),
+ SCE_SNAP_MODE_GRID = (1 << 7),
+} eSnapMode;
+/* Due to dependency conflicts with Cycles, header cannot directly include `BLI_utildefines.h`. */
+/* TODO: move this macro to a more general place. */
+#ifdef ENUM_OPERATORS
+ENUM_OPERATORS(eSnapMode, SCE_SNAP_MODE_GRID)
+#endif
/** #SequencerToolSettings.snap_mode */
#define SEQ_SNAP_TO_STRIPS (1 << 0)
@@ -2111,22 +2150,12 @@ enum {
#define SEQ_SNAP_IGNORE_SOUND (1 << 1)
#define SEQ_SNAP_CURRENT_FRAME_TO_STRIPS (1 << 2)
-/** #ToolSettings.snap_node_mode */
-#define SCE_SNAP_MODE_NODE_X (1 << 0)
-#define SCE_SNAP_MODE_NODE_Y (1 << 1)
-
-/**
- * #ToolSettings.snap_mode and #ToolSettings.snap_node_mode
- */
-#define SCE_SNAP_MODE_INCREMENT (1 << 6)
-#define SCE_SNAP_MODE_GRID (1 << 7)
-
/** #ToolSettings.snap_transform_mode_flag */
-enum {
+typedef enum eSnapTransformMode {
SCE_SNAP_TRANSFORM_MODE_TRANSLATE = (1 << 0),
SCE_SNAP_TRANSFORM_MODE_ROTATE = (1 << 1),
SCE_SNAP_TRANSFORM_MODE_SCALE = (1 << 2),
-};
+} eSnapTransformMode;
/** #ToolSettings.selectmode */
#define SCE_SELECT_VERTEX (1 << 0) /* for mesh */
@@ -2280,6 +2309,12 @@ typedef enum eSculptFlags {
SCULPT_HIDE_FACE_SETS = (1 << 17),
} eSculptFlags;
+/* Sculpt.transform_mode */
+typedef enum eSculptTransformMode {
+ SCULPT_TRANSFORM_MODE_ALL_VERTICES = 0,
+ SCULPT_TRANSFORM_MODE_RADIUS_ELASTIC = 1,
+} eSculptTrasnformMode;
+
/** PaintModeSettings.mode */
typedef enum ePaintCanvasSource {
/** Paint on the active node of the active material slot. */
diff --git a/source/blender/makesdna/DNA_sequence_types.h b/source/blender/makesdna/DNA_sequence_types.h
index d28550b5456..db24a775edb 100644
--- a/source/blender/makesdna/DNA_sequence_types.h
+++ b/source/blender/makesdna/DNA_sequence_types.h
@@ -165,7 +165,7 @@ typedef struct Sequence {
/** Machine: the strip channel */
int machine;
int _pad3;
- /** Starting and ending points of the strip in the sequence. */
+ /** Starting and ending points of the effect strip. Undefined for other strip types. */
int startdisp, enddisp;
float sat;
float mul;
diff --git a/source/blender/makesdna/DNA_sound_types.h b/source/blender/makesdna/DNA_sound_types.h
index df59dd84662..ba926f0f4fa 100644
--- a/source/blender/makesdna/DNA_sound_types.h
+++ b/source/blender/makesdna/DNA_sound_types.h
@@ -77,6 +77,12 @@ typedef struct bSound {
void *spinlock;
/* XXX unused currently (SOUND_TYPE_LIMITER) */
/* float start, end; */
+
+ /* Description of Audio channels, as of eSoundChannels*/
+ int audio_channels;
+
+ int samplerate;
+
} bSound;
/* XXX unused currently */
diff --git a/source/blender/makesdna/DNA_space_defaults.h b/source/blender/makesdna/DNA_space_defaults.h
index e826cb4c2ef..6193c8c2ad1 100644
--- a/source/blender/makesdna/DNA_space_defaults.h
+++ b/source/blender/makesdna/DNA_space_defaults.h
@@ -15,9 +15,10 @@
#define _DNA_DEFAULT_MaskSpaceInfo \
{ \
- .draw_flag = 0, \
+ .draw_flag = MASK_DRAWFLAG_SPLINE, \
.draw_type = MASK_DT_OUTLINE, \
.overlay_mode = MASK_OVERLAY_ALPHACHANNEL, \
+ .blend_factor = 0.7f, \
}
#define _DNA_DEFAULT_SpaceClip \
diff --git a/source/blender/makesdna/DNA_space_types.h b/source/blender/makesdna/DNA_space_types.h
index ef93128e5a0..2905ef06833 100644
--- a/source/blender/makesdna/DNA_space_types.h
+++ b/source/blender/makesdna/DNA_space_types.h
@@ -173,7 +173,7 @@ typedef struct SpaceProperties {
/* button defines (deprecated) */
#ifdef DNA_DEPRECATED_ALLOW
-/* warning: the values of these defines are used in SpaceProperties.tabs[8] */
+/* WARNING: the values of these defines are used in SpaceProperties.tabs[8] */
/* SpaceProperties.mainb new */
# define CONTEXT_SCENE 0
# define CONTEXT_OBJECT 1
@@ -732,7 +732,8 @@ typedef struct MaskSpaceInfo {
char draw_flag;
char draw_type;
char overlay_mode;
- char _pad3[5];
+ char _pad3[1];
+ float blend_factor;
} MaskSpaceInfo;
/** #SpaceSeq.gizmo_flag */
@@ -1340,7 +1341,7 @@ enum {
typedef struct SpaceText_Runtime {
- /** Actual line height, scaled by dpi. */
+ /** Actual line height, scaled by DPI. */
int lheight_px;
/** Runtime computed, character width. */
@@ -1936,7 +1937,7 @@ typedef struct SpaceSpreadsheet {
/* #GeometryComponentType. */
uint8_t geometry_component_type;
- /* #AttributeDomain. */
+ /* #eAttrDomain. */
uint8_t attribute_domain;
/* eSpaceSpreadsheet_ObjectContext. */
uint8_t object_eval_state;
@@ -2014,6 +2015,7 @@ typedef enum eSpreadsheetColumnValueType {
SPREADSHEET_VALUE_TYPE_INSTANCES = 6,
SPREADSHEET_VALUE_TYPE_STRING = 7,
SPREADSHEET_VALUE_TYPE_BYTE_COLOR = 8,
+ SPREADSHEET_VALUE_TYPE_INT8 = 9,
} eSpreadsheetColumnValueType;
/**
diff --git a/source/blender/makesdna/DNA_texture_types.h b/source/blender/makesdna/DNA_texture_types.h
index b725939dbab..e32d9dbe300 100644
--- a/source/blender/makesdna/DNA_texture_types.h
+++ b/source/blender/makesdna/DNA_texture_types.h
@@ -397,8 +397,7 @@ typedef struct ColorMapping {
/* return value */
#define TEX_INT 0
-#define TEX_RGB (1 << 0)
-#define TEX_NOR (1 << 1)
+#define TEX_RGB 1
/* pr_texture in material, world, light. */
#define TEX_PR_TEXTURE 0
diff --git a/source/blender/makesdna/DNA_userdef_types.h b/source/blender/makesdna/DNA_userdef_types.h
index 4d6e0eba915..d00826208be 100644
--- a/source/blender/makesdna/DNA_userdef_types.h
+++ b/source/blender/makesdna/DNA_userdef_types.h
@@ -57,7 +57,7 @@ typedef struct uiFontStyle {
/** Saved in file, 0 is default. */
short uifont_id;
char _pad1[2];
- /** Actual size depends on 'global' dpi. */
+ /** Actual size depends on 'global' DPI. */
float points;
/** Style hint. */
short italic, bold;
@@ -146,6 +146,7 @@ typedef struct ThemeUI {
uiWidgetColors wcol_num, wcol_numslider, wcol_tab;
uiWidgetColors wcol_menu, wcol_pulldown, wcol_menu_back, wcol_menu_item, wcol_tooltip;
uiWidgetColors wcol_box, wcol_scroll, wcol_progress, wcol_list_item, wcol_pie_menu;
+ uiWidgetColors wcol_view_item;
uiWidgetStateColors wcol_state;
@@ -314,7 +315,7 @@ typedef struct ThemeSpace {
char _pad5[3];
float dash_alpha;
- /* syntax for textwindow and nodes */
+ /* Syntax for text-window and nodes. */
unsigned char syntaxl[4], syntaxs[4]; /* in nodespace used for backdrop matte */
unsigned char syntaxb[4], syntaxn[4]; /* in nodespace used for color input */
unsigned char syntaxv[4], syntaxc[4]; /* in nodespace used for converter group */
@@ -652,7 +653,7 @@ typedef struct UserDef_Experimental {
char use_override_templates;
char enable_eevee_next;
char use_sculpt_texture_paint;
- char _pad0[1];
+ char use_draw_manager_acquire_lock;
/** `makesdna` does not allow empty structs. */
} UserDef_Experimental;
@@ -858,7 +859,7 @@ typedef struct UserDef {
float glalphaclip;
- /** #eAutokey_Mode, autokeying mode. */
+ /** #eAutokey_Mode, auto-keying mode. */
short autokey_mode;
/** Flags for autokeying. */
short autokey_flag;
diff --git a/source/blender/makesdna/DNA_volume_defaults.h b/source/blender/makesdna/DNA_volume_defaults.h
index ee98f0ea4fd..1057fc75d34 100644
--- a/source/blender/makesdna/DNA_volume_defaults.h
+++ b/source/blender/makesdna/DNA_volume_defaults.h
@@ -23,6 +23,7 @@
#define _DNA_DEFAULT_VolumeRender \
{ \
+ .precision = VOLUME_PRECISION_HALF, \
.space = VOLUME_SPACE_OBJECT, \
.step_size = 0.0f, \
.clipping = 0.001f, \
diff --git a/source/blender/makesdna/DNA_volume_types.h b/source/blender/makesdna/DNA_volume_types.h
index a2e558aa790..a25bfe0ebec 100644
--- a/source/blender/makesdna/DNA_volume_types.h
+++ b/source/blender/makesdna/DNA_volume_types.h
@@ -126,6 +126,13 @@ typedef enum VolumeWireframeDetail {
VOLUME_WIREFRAME_FINE = 1,
} VolumeWireframeDetail;
+/** #VolumeRender.precision */
+typedef enum VolumeRenderPrecision {
+ VOLUME_PRECISION_HALF = 0,
+ VOLUME_PRECISION_FULL = 1,
+ VOLUME_PRECISION_VARIABLE = 2,
+} VolumeRenderPrecision;
+
/** #VolumeRender.space */
typedef enum VolumeRenderSpace {
VOLUME_SPACE_OBJECT = 0,
diff --git a/source/blender/makesdna/DNA_windowmanager_types.h b/source/blender/makesdna/DNA_windowmanager_types.h
index cfd0c986df9..f7aaa1186db 100644
--- a/source/blender/makesdna/DNA_windowmanager_types.h
+++ b/source/blender/makesdna/DNA_windowmanager_types.h
@@ -463,14 +463,19 @@ typedef struct wmKeyMap {
/** #wmKeyMap.flag */
enum {
- KEYMAP_MODAL = (1 << 0), /* modal map, not using operatornames */
- KEYMAP_USER = (1 << 1), /* user keymap */
+ /** Modal map, not using operator-names. */
+ KEYMAP_MODAL = (1 << 0),
+ /** User key-map. */
+ KEYMAP_USER = (1 << 1),
KEYMAP_EXPANDED = (1 << 2),
KEYMAP_CHILDREN_EXPANDED = (1 << 3),
- KEYMAP_DIFF = (1 << 4), /* diff keymap for user preferences */
- KEYMAP_USER_MODIFIED = (1 << 5), /* keymap has user modifications */
+ /** Diff key-map for user preferences. */
+ KEYMAP_DIFF = (1 << 4),
+ /** Key-map has user modifications. */
+ KEYMAP_USER_MODIFIED = (1 << 5),
KEYMAP_UPDATE = (1 << 6),
- KEYMAP_TOOL = (1 << 7), /* keymap for active tool system */
+ /** key-map for active tool system. */
+ KEYMAP_TOOL = (1 << 7),
};
/**
diff --git a/source/blender/makesdna/intern/CMakeLists.txt b/source/blender/makesdna/intern/CMakeLists.txt
index 2afaf04a8d7..c26696b4572 100644
--- a/source/blender/makesdna/intern/CMakeLists.txt
+++ b/source/blender/makesdna/intern/CMakeLists.txt
@@ -13,6 +13,19 @@ blender_include_dirs(
..
)
+set(dna_header_include_file "${CMAKE_CURRENT_BINARY_DIR}/dna_includes_all.h")
+set(dna_header_string_file "${CMAKE_CURRENT_BINARY_DIR}/dna_includes_as_strings.h")
+
+set(DNA_INCLUDE_TEXT "/* Do not edit manually, changes will be overwritten. */\n")
+set(DNA_FILE_LIST "/* Do not edit manually, changes will be overwritten. */\n")
+foreach(header ${SRC_DNA_INC})
+ get_filename_component(dna_header_file ${header} NAME)
+ string(APPEND DNA_INCLUDE_TEXT "#include \"${header}\"\n")
+ string(APPEND DNA_FILE_LIST "\t\"${dna_header_file}\",\n")
+endforeach()
+
+file(GENERATE OUTPUT ${dna_header_include_file} CONTENT "${DNA_INCLUDE_TEXT}")
+file(GENERATE OUTPUT ${dna_header_string_file} CONTENT "${DNA_FILE_LIST}")
# -----------------------------------------------------------------------------
# Build makesdna executable
@@ -29,6 +42,8 @@ set(SRC
../../../../intern/guardedalloc/intern/mallocn.c
../../../../intern/guardedalloc/intern/mallocn_guarded_impl.c
../../../../intern/guardedalloc/intern/mallocn_lockfree_impl.c
+ ${dna_header_include_file}
+ ${dna_header_string_file}
)
# SRC_DNA_INC is defined in the parent dir
@@ -115,40 +130,7 @@ set(SRC
../../blenlib/intern/hash_mm2a.c
../../blenlib/intern/listbase.c
- ../DNA_armature_defaults.h
- ../DNA_asset_defaults.h
- ../DNA_brush_defaults.h
- ../DNA_cachefile_defaults.h
- ../DNA_camera_defaults.h
- ../DNA_collection_defaults.h
- ../DNA_curve_defaults.h
- ../DNA_curves_defaults.h
- ../DNA_defaults.h
- ../DNA_fluid_defaults.h
- ../DNA_gpencil_modifier_defaults.h
- ../DNA_image_defaults.h
- ../DNA_lattice_defaults.h
- ../DNA_light_defaults.h
- ../DNA_lightprobe_defaults.h
- ../DNA_linestyle_defaults.h
- ../DNA_material_defaults.h
- ../DNA_mesh_defaults.h
- ../DNA_meta_defaults.h
- ../DNA_modifier_defaults.h
- ../DNA_modifier_types.h
- ../DNA_movieclip_defaults.h
- ../DNA_object_defaults.h
- ../DNA_particle_defaults.h
- ../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
- ../DNA_view3d_defaults.h
- ../DNA_volume_defaults.h
- ../DNA_world_defaults.h
+ ${SRC_DNA_DEFAULTS_INC}
)
set(LIB
diff --git a/source/blender/makesdna/intern/dna_rename_defs.h b/source/blender/makesdna/intern/dna_rename_defs.h
index 281aeae7a60..f25ff5fbbb8 100644
--- a/source/blender/makesdna/intern/dna_rename_defs.h
+++ b/source/blender/makesdna/intern/dna_rename_defs.h
@@ -61,6 +61,8 @@ DNA_STRUCT_RENAME_ELEM(Curve, ext1, extrude)
DNA_STRUCT_RENAME_ELEM(Curve, ext2, bevel_radius)
DNA_STRUCT_RENAME_ELEM(Curve, len_wchar, len_char32)
DNA_STRUCT_RENAME_ELEM(Curve, width, offset)
+DNA_STRUCT_RENAME_ELEM(CurvesGeometry, curve_size, curve_num)
+DNA_STRUCT_RENAME_ELEM(CurvesGeometry, point_size, point_num)
DNA_STRUCT_RENAME_ELEM(CustomDataExternal, filename, filepath)
DNA_STRUCT_RENAME_ELEM(Editing, over_border, overlay_frame_rect)
DNA_STRUCT_RENAME_ELEM(Editing, over_cfra, overlay_frame_abs)
diff --git a/source/blender/makesdna/intern/makesdna.c b/source/blender/makesdna/intern/makesdna.c
index 12ec7262906..806513009be 100644
--- a/source/blender/makesdna/intern/makesdna.c
+++ b/source/blender/makesdna/intern/makesdna.c
@@ -43,92 +43,11 @@
#define SDNA_MAX_FILENAME_LENGTH 255
-/* Included the path relative from /source/blender/ here,
- * so we can move headers around with more freedom. */
+/* The include file below is automatically generated from the `SRC_DNA_INC`
+ * variable in 'source/blender/CMakeLists.txt'. */
static const char *includefiles[] = {
- /* if you add files here, please add them at the end
- * of makesdna.c (this file) as well */
- "DNA_listBase.h",
- "DNA_vec_types.h",
- "DNA_ID.h",
- "DNA_ipo_types.h",
- "DNA_key_types.h",
- "DNA_text_types.h",
- "DNA_packedFile_types.h",
- "DNA_gpu_types.h",
- "DNA_camera_types.h",
- "DNA_image_types.h",
- "DNA_texture_types.h",
- "DNA_light_types.h",
- "DNA_material_types.h",
- "DNA_vfont_types.h",
- "DNA_meta_types.h",
- "DNA_curve_types.h",
- "DNA_mesh_types.h",
- "DNA_meshdata_types.h",
- "DNA_modifier_types.h",
- "DNA_lineart_types.h",
- "DNA_lattice_types.h",
- "DNA_object_types.h",
- "DNA_object_force_types.h",
- "DNA_object_fluidsim_types.h",
- "DNA_world_types.h",
- "DNA_scene_types.h",
- "DNA_view3d_types.h",
- "DNA_view2d_types.h",
- "DNA_space_types.h",
- "DNA_userdef_types.h",
- "DNA_screen_types.h",
- "DNA_sdna_types.h",
- "DNA_fileglobal_types.h",
- "DNA_sequence_types.h",
- "DNA_session_uuid_types.h",
- "DNA_effect_types.h",
- "DNA_outliner_types.h",
- "DNA_sound_types.h",
- "DNA_collection_types.h",
- "DNA_armature_types.h",
- "DNA_action_types.h",
- "DNA_constraint_types.h",
- "DNA_nla_types.h",
- "DNA_node_types.h",
- "DNA_color_types.h",
- "DNA_brush_types.h",
- "DNA_customdata_types.h",
- "DNA_particle_types.h",
- "DNA_cloth_types.h",
- "DNA_gpencil_types.h",
- "DNA_gpencil_modifier_types.h",
- "DNA_shader_fx_types.h",
- "DNA_windowmanager_types.h",
- "DNA_anim_types.h",
- "DNA_boid_types.h",
- "DNA_fluid_types.h",
- "DNA_speaker_types.h",
- "DNA_movieclip_types.h",
- "DNA_tracking_types.h",
- "DNA_dynamicpaint_types.h",
- "DNA_mask_types.h",
- "DNA_rigidbody_types.h",
- "DNA_freestyle_types.h",
- "DNA_linestyle_types.h",
- "DNA_cachefile_types.h",
- "DNA_layer_types.h",
- "DNA_workspace_types.h",
- "DNA_lightprobe_types.h",
- "DNA_curveprofile_types.h",
- "DNA_xr_types.h",
- "DNA_curves_types.h",
- "DNA_pointcloud_types.h",
- "DNA_volume_types.h",
- "DNA_simulation_types.h",
- "DNA_pointcache_types.h",
- "DNA_uuid_types.h",
- "DNA_asset_types.h",
-
- /* see comment above before editing! */
-
- /* empty string to indicate end of includefiles */
+#include "dna_includes_as_strings.h"
+ /* Empty string to indicate end of include files. */
"",
};
@@ -235,7 +154,7 @@ static int preprocess_include(char *maindata, const int maindata_len);
/**
* Scan this file for serializable types.
*/
-static int convert_include(const char *filename);
+static int convert_include(const char *filepath);
/**
* Determine how many bytes are needed for each struct.
@@ -670,12 +589,12 @@ static int preprocess_include(char *maindata, const int maindata_len)
return newlen;
}
-static void *read_file_data(const char *filename, int *r_len)
+static void *read_file_data(const char *filepath, int *r_len)
{
#ifdef WIN32
- FILE *fp = fopen(filename, "rb");
+ FILE *fp = fopen(filepath, "rb");
#else
- FILE *fp = fopen(filename, "r");
+ FILE *fp = fopen(filepath, "r");
#endif
void *data;
@@ -711,17 +630,17 @@ static void *read_file_data(const char *filename, int *r_len)
return data;
}
-static int convert_include(const char *filename)
+static int convert_include(const char *filepath)
{
/* read include file, skip structs with a '#' before it.
* store all data in temporal arrays.
*/
int maindata_len;
- char *maindata = read_file_data(filename, &maindata_len);
+ char *maindata = read_file_data(filepath, &maindata_len);
char *md = maindata;
if (maindata_len == -1) {
- fprintf(stderr, "Can't read file %s\n", filename);
+ fprintf(stderr, "Can't read file %s\n", filepath);
return 1;
}
@@ -759,7 +678,7 @@ static int convert_include(const char *filename)
const int strct = add_type(md1, 0);
if (strct == -1) {
- fprintf(stderr, "File '%s' contains struct we can't parse \"%s\"\n", filename, md1);
+ fprintf(stderr, "File '%s' contains struct we can't parse \"%s\"\n", filepath, md1);
return 1;
}
@@ -799,7 +718,7 @@ static int convert_include(const char *filename)
fprintf(stderr,
"File '%s' contains non white space character "
"\"%c\" after identifier \"%s\"\n",
- filename,
+ filepath,
*md1,
md1_prev);
return 1;
@@ -812,7 +731,7 @@ static int convert_include(const char *filename)
const int type = add_type(md1, 0);
if (type == -1) {
fprintf(
- stderr, "File '%s' contains struct we can't parse \"%s\"\n", filename, md1);
+ stderr, "File '%s' contains struct we can't parse \"%s\"\n", filepath, md1);
return 1;
}
@@ -838,7 +757,7 @@ static int convert_include(const char *filename)
if (name == -1) {
fprintf(stderr,
"File '%s' contains struct with name that can't be added \"%s\"\n",
- filename,
+ filepath,
md1);
return 1;
}
@@ -861,7 +780,7 @@ static int convert_include(const char *filename)
if (name == -1) {
fprintf(stderr,
"File '%s' contains struct with name that can't be added \"%s\"\n",
- filename,
+ filepath,
md1);
return 1;
}
@@ -1617,82 +1536,9 @@ int main(int argc, char **argv)
# pragma GCC poison long
#endif
-#include "DNA_ID.h"
-#include "DNA_action_types.h"
-#include "DNA_anim_types.h"
-#include "DNA_armature_types.h"
-#include "DNA_asset_types.h"
-#include "DNA_boid_types.h"
-#include "DNA_brush_types.h"
-#include "DNA_cachefile_types.h"
-#include "DNA_camera_types.h"
-#include "DNA_cloth_types.h"
-#include "DNA_collection_types.h"
-#include "DNA_color_types.h"
-#include "DNA_constraint_types.h"
-#include "DNA_curve_types.h"
-#include "DNA_curveprofile_types.h"
-#include "DNA_curves_types.h"
-#include "DNA_customdata_types.h"
-#include "DNA_dynamicpaint_types.h"
-#include "DNA_effect_types.h"
-#include "DNA_fileglobal_types.h"
-#include "DNA_fluid_types.h"
-#include "DNA_freestyle_types.h"
-#include "DNA_gpencil_modifier_types.h"
-#include "DNA_gpencil_types.h"
-#include "DNA_image_types.h"
-#include "DNA_ipo_types.h"
-#include "DNA_key_types.h"
-#include "DNA_lattice_types.h"
-#include "DNA_layer_types.h"
-#include "DNA_light_types.h"
-#include "DNA_lightprobe_types.h"
-#include "DNA_lineart_types.h"
-#include "DNA_linestyle_types.h"
-#include "DNA_listBase.h"
-#include "DNA_mask_types.h"
-#include "DNA_material_types.h"
-#include "DNA_mesh_types.h"
-#include "DNA_meshdata_types.h"
-#include "DNA_meta_types.h"
-#include "DNA_modifier_types.h"
-#include "DNA_movieclip_types.h"
-#include "DNA_nla_types.h"
-#include "DNA_node_types.h"
-#include "DNA_object_fluidsim_types.h"
-#include "DNA_object_force_types.h"
-#include "DNA_object_types.h"
-#include "DNA_outliner_types.h"
-#include "DNA_packedFile_types.h"
-#include "DNA_particle_types.h"
-#include "DNA_pointcache_types.h"
-#include "DNA_pointcloud_types.h"
-#include "DNA_rigidbody_types.h"
-#include "DNA_scene_types.h"
-#include "DNA_screen_types.h"
-#include "DNA_sdna_types.h"
-#include "DNA_sequence_types.h"
-#include "DNA_session_uuid_types.h"
-#include "DNA_shader_fx_types.h"
-#include "DNA_simulation_types.h"
-#include "DNA_sound_types.h"
-#include "DNA_space_types.h"
-#include "DNA_speaker_types.h"
-#include "DNA_text_types.h"
-#include "DNA_texture_types.h"
-#include "DNA_tracking_types.h"
-#include "DNA_userdef_types.h"
-#include "DNA_uuid_types.h"
-#include "DNA_vec_types.h"
-#include "DNA_vfont_types.h"
-#include "DNA_view2d_types.h"
-#include "DNA_view3d_types.h"
-#include "DNA_volume_types.h"
-#include "DNA_windowmanager_types.h"
-#include "DNA_workspace_types.h"
-#include "DNA_world_types.h"
-#include "DNA_xr_types.h"
+/* The include file below is automatically generated from the `SRC_DNA_INC`
+ * variable in 'source/blender/CMakeLists.txt'. */
+#include "dna_includes_all.h"
/* end of list */
diff --git a/source/blender/makesrna/RNA_access.h b/source/blender/makesrna/RNA_access.h
index e1e655fad4b..67605201a9f 100644
--- a/source/blender/makesrna/RNA_access.h
+++ b/source/blender/makesrna/RNA_access.h
@@ -177,7 +177,7 @@ int RNA_property_multi_array_length(PointerRNA *ptr, PropertyRNA *prop, int dime
/**
* Used by BPY to make an array from the python object.
*/
-int RNA_property_array_dimension(PointerRNA *ptr, PropertyRNA *prop, int length[]);
+int RNA_property_array_dimension(const PointerRNA *ptr, PropertyRNA *prop, int length[]);
char RNA_property_array_item_char(PropertyRNA *prop, int index);
int RNA_property_array_item_index(PropertyRNA *prop, char name);
@@ -284,7 +284,7 @@ bool RNA_property_editable_index(PointerRNA *ptr, PropertyRNA *prop, const int i
*/
bool RNA_property_editable_flag(PointerRNA *ptr, PropertyRNA *prop);
-bool RNA_property_animateable(PointerRNA *ptr, PropertyRNA *prop);
+bool RNA_property_animateable(const PointerRNA *ptr, PropertyRNA *prop);
bool RNA_property_animated(PointerRNA *ptr, PropertyRNA *prop);
/**
* \note Does not take into account editable status, this has to be checked separately
@@ -358,6 +358,21 @@ char *RNA_property_string_get_alloc(
PointerRNA *ptr, PropertyRNA *prop, char *fixedbuf, int fixedlen, int *r_len);
void RNA_property_string_set(PointerRNA *ptr, PropertyRNA *prop, const char *value);
void RNA_property_string_set_bytes(PointerRNA *ptr, PropertyRNA *prop, const char *value, int len);
+
+eStringPropertySearchFlag RNA_property_string_search_flag(PropertyRNA *prop);
+/**
+ * Search candidates for string `prop` by calling `visit_fn` with each string.
+ * Typically these strings are collected in `visit_user_data` in a format defined by the caller.
+ *
+ * See #PropStringSearchFunc for details.
+ */
+void RNA_property_string_search(const struct bContext *C,
+ PointerRNA *ptr,
+ PropertyRNA *prop,
+ const char *edit_text,
+ StringPropertySearchVisitFunc visit_fn,
+ void *visit_user_data);
+
/**
* \return the length without `\0` terminator.
*/
@@ -402,7 +417,9 @@ int RNA_property_collection_length(PointerRNA *ptr, PropertyRNA *prop);
* without having to iterate over items in the collection (needed for some kinds of collections).
*/
bool RNA_property_collection_is_empty(PointerRNA *ptr, PropertyRNA *prop);
-int RNA_property_collection_lookup_index(PointerRNA *ptr, PropertyRNA *prop, PointerRNA *t_ptr);
+int RNA_property_collection_lookup_index(PointerRNA *ptr,
+ PropertyRNA *prop,
+ const PointerRNA *t_ptr);
int RNA_property_collection_lookup_int(PointerRNA *ptr,
PropertyRNA *prop,
int key,
@@ -468,11 +485,23 @@ bool RNA_property_assign_default(PointerRNA *ptr, PropertyRNA *prop);
* UI code or Actions, though efficiency is a concern. */
char *RNA_path_append(
- const char *path, PointerRNA *ptr, PropertyRNA *prop, int intkey, const char *strkey);
+ const char *path, const PointerRNA *ptr, PropertyRNA *prop, int intkey, const char *strkey);
#if 0 /* UNUSED. */
char *RNA_path_back(const char *path);
#endif
+/**
+ * Search for the start of the 'rna array index' part of the given `rna_path`.
+ *
+ * Given the root RNA pointer and resolved RNA property, and the RNA path, return the first
+ * character in `rna_path` that is part of the array index for the given property. Return NULL if
+ * none can be found, e.g. because the property is not an RNA array.
+ *
+ * \param array_prop if not NULL, the PropertyRNA assumed to be the last one from the RNA path.
+ * Only used to ensure it is a valid array property.
+ */
+const char *RNA_path_array_index_token_find(const char *rna_path, const PropertyRNA *array_prop);
+
/* RNA_path_resolve() variants only ensure that a valid pointer (and optionally property) exist. */
/**
@@ -486,7 +515,10 @@ char *RNA_path_back(const char *path);
* \note Assumes all pointers provided are valid
* \return True if path can be resolved to a valid "pointer + property" OR "pointer only"
*/
-bool RNA_path_resolve(PointerRNA *ptr, const char *path, PointerRNA *r_ptr, PropertyRNA **r_prop);
+bool RNA_path_resolve(const PointerRNA *ptr,
+ const char *path,
+ PointerRNA *r_ptr,
+ PropertyRNA **r_prop);
/**
* Resolve the given RNA Path to find the pointer and/or property + array index
@@ -495,16 +527,22 @@ bool RNA_path_resolve(PointerRNA *ptr, const char *path, PointerRNA *r_ptr, Prop
* \note Assumes all pointers provided are valid.
* \return True if path can be resolved to a valid "pointer + property" OR "pointer only"
*/
-bool RNA_path_resolve_full(
- PointerRNA *ptr, const char *path, PointerRNA *r_ptr, PropertyRNA **r_prop, int *r_index);
+bool RNA_path_resolve_full(const PointerRNA *ptr,
+ const char *path,
+ PointerRNA *r_ptr,
+ PropertyRNA **r_prop,
+ int *r_index);
/**
* A version of #RNA_path_resolve_full doesn't check the value of #PointerRNA.data.
*
* \note While it's correct to ignore the value of #PointerRNA.data
* most callers need to know if the resulting pointer was found and not null.
*/
-bool RNA_path_resolve_full_maybe_null(
- PointerRNA *ptr, const char *path, PointerRNA *r_ptr, PropertyRNA **r_prop, int *r_index);
+bool RNA_path_resolve_full_maybe_null(const PointerRNA *ptr,
+ const char *path,
+ PointerRNA *r_ptr,
+ PropertyRNA **r_prop,
+ int *r_index);
/* RNA_path_resolve_property() variants ensure that pointer + property both exist. */
@@ -516,7 +554,7 @@ bool RNA_path_resolve_full_maybe_null(
* \note Assumes all pointers provided are valid
* \return True only if both a valid pointer and property are found after resolving the path
*/
-bool RNA_path_resolve_property(PointerRNA *ptr,
+bool RNA_path_resolve_property(const PointerRNA *ptr,
const char *path,
PointerRNA *r_ptr,
PropertyRNA **r_prop);
@@ -529,8 +567,11 @@ bool RNA_path_resolve_property(PointerRNA *ptr,
* \note Assumes all pointers provided are valid
* \return True only if both a valid pointer and property are found after resolving the path
*/
-bool RNA_path_resolve_property_full(
- PointerRNA *ptr, const char *path, PointerRNA *r_ptr, PropertyRNA **r_prop, int *r_index);
+bool RNA_path_resolve_property_full(const PointerRNA *ptr,
+ const char *path,
+ PointerRNA *r_ptr,
+ PropertyRNA **r_prop,
+ int *r_index);
/* RNA_path_resolve_property_and_item_pointer() variants ensure that pointer + property both exist,
* and resolve last Pointer value if possible (Pointer prop or item of a Collection prop). */
@@ -547,7 +588,7 @@ bool RNA_path_resolve_property_full(
* You must check for its validity before use!
* \return True only if both a valid pointer and property are found after resolving the path
*/
-bool RNA_path_resolve_property_and_item_pointer(PointerRNA *ptr,
+bool RNA_path_resolve_property_and_item_pointer(const PointerRNA *ptr,
const char *path,
PointerRNA *r_ptr,
PropertyRNA **r_prop,
@@ -566,7 +607,7 @@ bool RNA_path_resolve_property_and_item_pointer(PointerRNA *ptr,
* You must check for its validity before use!
* \return True only if both a valid pointer and property are found after resolving the path
*/
-bool RNA_path_resolve_property_and_item_pointer_full(PointerRNA *ptr,
+bool RNA_path_resolve_property_and_item_pointer_full(const PointerRNA *ptr,
const char *path,
PointerRNA *r_ptr,
PropertyRNA **r_prop,
@@ -614,21 +655,23 @@ struct ID *RNA_find_real_ID_and_path(struct Main *bmain, struct ID *id, const ch
char *RNA_path_from_ID_to_struct(const PointerRNA *ptr);
-char *RNA_path_from_real_ID_to_struct(struct Main *bmain, PointerRNA *ptr, struct ID **r_real);
+char *RNA_path_from_real_ID_to_struct(struct Main *bmain,
+ const PointerRNA *ptr,
+ struct ID **r_real);
-char *RNA_path_from_ID_to_property(PointerRNA *ptr, PropertyRNA *prop);
+char *RNA_path_from_ID_to_property(const PointerRNA *ptr, PropertyRNA *prop);
/**
* \param index_dim: The dimension to show, 0 disables. 1 for 1d array, 2 for 2d. etc.
* \param index: The *flattened* index to use when \a `index_dim > 0`,
* this is expanded when used with multi-dimensional arrays.
*/
-char *RNA_path_from_ID_to_property_index(PointerRNA *ptr,
+char *RNA_path_from_ID_to_property_index(const PointerRNA *ptr,
PropertyRNA *prop,
int index_dim,
int index);
char *RNA_path_from_real_ID_to_property_index(struct Main *bmain,
- PointerRNA *ptr,
+ const PointerRNA *ptr,
PropertyRNA *prop,
int index_dim,
int index,
@@ -638,8 +681,8 @@ char *RNA_path_from_real_ID_to_property_index(struct Main *bmain,
* \return the path to given ptr/prop from the closest ancestor of given type,
* if any (else return NULL).
*/
-char *RNA_path_resolve_from_type_to_property(struct PointerRNA *ptr,
- struct PropertyRNA *prop,
+char *RNA_path_resolve_from_type_to_property(const PointerRNA *ptr,
+ PropertyRNA *prop,
const struct StructRNA *type);
/**
@@ -651,27 +694,27 @@ char *RNA_path_full_ID_py(struct Main *bmain, struct ID *id);
* Get the ID.struct as a python representation, eg:
* bpy.data.foo["bar"].some_struct
*/
-char *RNA_path_full_struct_py(struct Main *bmain, struct PointerRNA *ptr);
+char *RNA_path_full_struct_py(struct Main *bmain, const PointerRNA *ptr);
/**
* Get the ID.struct.property as a python representation, eg:
* bpy.data.foo["bar"].some_struct.some_prop[10]
*/
char *RNA_path_full_property_py_ex(
- struct Main *bmain, PointerRNA *ptr, PropertyRNA *prop, int index, bool use_fallback);
+ struct Main *bmain, const PointerRNA *ptr, PropertyRNA *prop, int index, bool use_fallback);
char *RNA_path_full_property_py(struct Main *bmain,
- struct PointerRNA *ptr,
- struct PropertyRNA *prop,
+ const PointerRNA *ptr,
+ PropertyRNA *prop,
int index);
/**
* Get the struct.property as a python representation, eg:
* some_struct.some_prop[10]
*/
-char *RNA_path_struct_property_py(struct PointerRNA *ptr, struct PropertyRNA *prop, int index);
+char *RNA_path_struct_property_py(PointerRNA *ptr, PropertyRNA *prop, int index);
/**
* Get the struct.property as a python representation, eg:
* some_prop[10]
*/
-char *RNA_path_property_py(const struct PointerRNA *ptr, struct PropertyRNA *prop, int index);
+char *RNA_path_property_py(const PointerRNA *ptr, PropertyRNA *prop, int index);
/* Quick name based property access
*
diff --git a/source/blender/makesrna/RNA_define.h b/source/blender/makesrna/RNA_define.h
index 13a5ec66a16..0389d1b3b16 100644
--- a/source/blender/makesrna/RNA_define.h
+++ b/source/blender/makesrna/RNA_define.h
@@ -446,6 +446,9 @@ void RNA_def_property_string_funcs(PropertyRNA *prop,
const char *get,
const char *length,
const char *set);
+void RNA_def_property_string_search_func(PropertyRNA *prop,
+ const char *search,
+ eStringPropertySearchFlag search_flag);
void RNA_def_property_pointer_funcs(
PropertyRNA *prop, const char *get, const char *set, const char *type_fn, const char *poll);
void RNA_def_property_collection_funcs(PropertyRNA *prop,
@@ -490,6 +493,9 @@ void RNA_def_property_string_funcs_runtime(PropertyRNA *prop,
StringPropertyGetFunc getfunc,
StringPropertyLengthFunc lengthfunc,
StringPropertySetFunc setfunc);
+void RNA_def_property_string_search_func_runtime(PropertyRNA *prop,
+ StringPropertySearchFunc search_fn,
+ eStringPropertySearchFlag search_flag);
void RNA_def_property_translation_context(PropertyRNA *prop, const char *context);
diff --git a/source/blender/makesrna/RNA_enum_items.h b/source/blender/makesrna/RNA_enum_items.h
index 127c8465243..61c5c1a6c72 100644
--- a/source/blender/makesrna/RNA_enum_items.h
+++ b/source/blender/makesrna/RNA_enum_items.h
@@ -21,7 +21,7 @@ DEF_ENUM(rna_enum_metaelem_type_items)
DEF_ENUM(rna_enum_proportional_falloff_items)
DEF_ENUM(rna_enum_proportional_falloff_curve_only_items)
-DEF_ENUM(rna_enum_snap_target_items)
+DEF_ENUM(rna_enum_snap_source_items)
DEF_ENUM(rna_enum_snap_element_items)
DEF_ENUM(rna_enum_snap_node_element_items)
DEF_ENUM(rna_enum_curve_fit_method_items)
@@ -108,7 +108,7 @@ DEF_ENUM(rna_enum_brush_gpencil_types_items)
DEF_ENUM(rna_enum_brush_gpencil_vertex_types_items)
DEF_ENUM(rna_enum_brush_gpencil_sculpt_types_items)
DEF_ENUM(rna_enum_brush_gpencil_weight_types_items)
-DEF_ENUM(rna_enum_brush_curves_sculpt_tool_items);
+DEF_ENUM(rna_enum_brush_curves_sculpt_tool_items)
DEF_ENUM(rna_enum_brush_image_tool_items)
DEF_ENUM(rna_enum_axis_xy_items)
@@ -147,10 +147,19 @@ DEF_ENUM(rna_enum_keymap_propvalue_items)
DEF_ENUM(rna_enum_operator_context_items)
DEF_ENUM(rna_enum_wm_report_items)
+DEF_ENUM(rna_enum_wm_job_type_items)
DEF_ENUM(rna_enum_property_type_items)
DEF_ENUM(rna_enum_property_subtype_items)
+DEF_ENUM(rna_enum_property_subtype_string_items)
+DEF_ENUM(rna_enum_property_subtype_number_items)
+DEF_ENUM(rna_enum_property_subtype_number_array_items)
DEF_ENUM(rna_enum_property_unit_items)
+DEF_ENUM(rna_enum_property_flag_items)
+DEF_ENUM(rna_enum_property_flag_enum_items)
+DEF_ENUM(rna_enum_property_override_flag_items)
+DEF_ENUM(rna_enum_property_override_flag_collection_items)
+DEF_ENUM(rna_enum_property_string_search_flag_items)
DEF_ENUM(rna_enum_shading_type_items)
@@ -201,6 +210,7 @@ DEF_ENUM(rna_enum_attribute_type_items)
DEF_ENUM(rna_enum_color_attribute_type_items)
DEF_ENUM(rna_enum_attribute_type_with_auto_items)
DEF_ENUM(rna_enum_attribute_domain_items)
+DEF_ENUM(rna_enum_attribute_curves_domain_items)
DEF_ENUM(rna_enum_color_attribute_domain_items)
DEF_ENUM(rna_enum_attribute_domain_without_corner_items)
DEF_ENUM(rna_enum_attribute_domain_with_auto_items)
@@ -218,6 +228,8 @@ DEF_ENUM(rna_enum_transform_orientation_items)
DEF_ENUM(rna_enum_velocity_unit_items)
+DEF_ENUM(rna_enum_curves_types)
+
/* Not available to RNA pre-processing (`makesrna`).
* Defined in editors for example. */
#ifndef RNA_MAKESRNA
diff --git a/source/blender/makesrna/RNA_types.h b/source/blender/makesrna/RNA_types.h
index 3ebcae5f947..5346228050a 100644
--- a/source/blender/makesrna/RNA_types.h
+++ b/source/blender/makesrna/RNA_types.h
@@ -467,6 +467,27 @@ typedef struct EnumPropertyItem {
const char *description;
} EnumPropertyItem;
+/**
+ * Heading for RNA enum items (shown in the UI).
+ *
+ * The description is currently only shown in the Python documentation.
+ * By convention the value should be a non-empty string or NULL when there is no description
+ * (never an empty string).
+ */
+#define RNA_ENUM_ITEM_HEADING(name, description) \
+ { \
+ 0, "", 0, name, description \
+ }
+
+/** Separator for RNA enum items (shown in the UI). */
+#define RNA_ENUM_ITEM_SEPR \
+ { \
+ 0, "", 0, NULL, NULL \
+ }
+
+/** Separator for RNA enum that begins a new column in menus (shown in the UI). */
+#define RNA_ENUM_ITEM_SEPR_COLUMN RNA_ENUM_ITEM_HEADING("", NULL)
+
/* extended versions with PropertyRNA argument */
typedef bool (*BooleanPropertyGetFunc)(struct PointerRNA *ptr, struct PropertyRNA *prop);
typedef void (*BooleanPropertySetFunc)(struct PointerRNA *ptr,
@@ -515,6 +536,55 @@ typedef int (*StringPropertyLengthFunc)(struct PointerRNA *ptr, struct PropertyR
typedef void (*StringPropertySetFunc)(struct PointerRNA *ptr,
struct PropertyRNA *prop,
const char *value);
+
+typedef struct StringPropertySearchVisitParams {
+ /** Text being searched for (never NULL). */
+ const char *text;
+ /** Additional information to display (optional, may be NULL). */
+ const char *info;
+} StringPropertySearchVisitParams;
+
+typedef enum eStringPropertySearchFlag {
+ /**
+ * Used so the result of #RNA_property_string_search_flag can be used to check
+ * if search is supported.
+ */
+ PROP_STRING_SEARCH_SUPPORTED = (1 << 0),
+ /** Items resulting from the search must be sorted. */
+ PROP_STRING_SEARCH_SORT = (1 << 1),
+ /**
+ * Allow members besides the ones listed to be entered.
+ *
+ * \warning disabling this options causes the search callback to run on redraw and should
+ * only be enabled this doesn't cause performance issues.
+ */
+ PROP_STRING_SEARCH_SUGGESTION = (1 << 2),
+} eStringPropertySearchFlag;
+
+/**
+ * Visit string search candidates, `text` may be freed once this callback has finished,
+ * so references to it should not be held.
+ */
+typedef void (*StringPropertySearchVisitFunc)(void *visit_user_data,
+ const StringPropertySearchVisitParams *params);
+/**
+ * \param C: context, may be NULL (in this case all available items should be shown).
+ * \param ptr: RNA pointer.
+ * \param prop: RNA property. This must have it's #StringPropertyRNA.search callback set,
+ * to check this use `RNA_property_string_search_flag(prop) & PROP_STRING_SEARCH_SUPPORTED`.
+ * \param edit_text: Optionally use the string being edited by the user as a basis
+ * for the search results (auto-complete Python attributes for e.g.).
+ * \param visit_fn: This function is called with every search candidate and is typically
+ * responsible for storing the search results.
+ * \param visit_user_data: Caller defined data, passed to `visit_fn`.
+ */
+typedef void (*StringPropertySearchFunc)(const struct bContext *C,
+ struct PointerRNA *ptr,
+ struct PropertyRNA *prop,
+ const char *edit_text,
+ StringPropertySearchVisitFunc visit_fn,
+ void *visit_user_data);
+
typedef int (*EnumPropertyGetFunc)(struct PointerRNA *ptr, struct PropertyRNA *prop);
typedef void (*EnumPropertySetFunc)(struct PointerRNA *ptr, struct PropertyRNA *prop, int value);
/* same as PropEnumItemFunc */
diff --git a/source/blender/makesrna/intern/CMakeLists.txt b/source/blender/makesrna/intern/CMakeLists.txt
index 9980545c19d..af8767a1220 100644
--- a/source/blender/makesrna/intern/CMakeLists.txt
+++ b/source/blender/makesrna/intern/CMakeLists.txt
@@ -237,7 +237,7 @@ if(WITH_IMAGE_HDR)
endif()
if(WITH_IMAGE_WEBP)
- add_definitions(-DWITH_WEBP)
+ add_definitions(-DWITH_WEBP)
endif()
if(WITH_AUDASPACE)
diff --git a/source/blender/makesrna/intern/makesrna.c b/source/blender/makesrna/intern/makesrna.c
index c3ca57b38bf..400944d60d4 100644
--- a/source/blender/makesrna/intern/makesrna.c
+++ b/source/blender/makesrna/intern/makesrna.c
@@ -1039,6 +1039,38 @@ static void rna_clamp_value(FILE *f, PropertyRNA *prop, int array)
}
}
+static char *rna_def_property_search_func(FILE *f,
+ StructRNA *srna,
+ PropertyRNA *prop,
+ PropertyDefRNA *UNUSED(dp),
+ const char *manualfunc)
+{
+ char *func;
+
+ if (prop->flag & PROP_IDPROPERTY && manualfunc == NULL) {
+ return NULL;
+ }
+ if (!manualfunc) {
+ return NULL;
+ }
+
+ func = rna_alloc_function_name(srna->identifier, rna_safe_id(prop->identifier), "search");
+
+ fprintf(f,
+ "void %s("
+ "const bContext *C, "
+ "PointerRNA *ptr, "
+ "PropertyRNA *prop, "
+ "const char *edit_text, "
+ "StringPropertySearchVisitFunc visit_fn, "
+ "void *visit_user_data)\n",
+ func);
+ fprintf(f, "{\n");
+ fprintf(f, "\n %s(C, ptr, prop, edit_text, visit_fn, visit_user_data);\n", manualfunc);
+ fprintf(f, "}\n\n");
+ return func;
+}
+
static char *rna_def_property_set_func(
FILE *f, StructRNA *srna, PropertyRNA *prop, PropertyDefRNA *dp, const char *manualfunc)
{
@@ -1895,6 +1927,8 @@ static void rna_def_property_funcs(FILE *f, StructRNA *srna, PropertyDefRNA *dp)
sprop->length = (void *)rna_def_property_length_func(
f, srna, prop, dp, (const char *)sprop->length);
sprop->set = (void *)rna_def_property_set_func(f, srna, prop, dp, (const char *)sprop->set);
+ sprop->search = (void *)rna_def_property_search_func(
+ f, srna, prop, dp, (const char *)sprop->search);
break;
}
case PROP_POINTER: {
@@ -4081,13 +4115,15 @@ static void rna_generate_property(FILE *f, StructRNA *srna, const char *nest, Pr
case PROP_STRING: {
StringPropertyRNA *sprop = (StringPropertyRNA *)prop;
fprintf(f,
- "\t%s, %s, %s, %s, %s, %s, %d, ",
+ "\t%s, %s, %s, %s, %s, %s, %s, %d, %d, ",
rna_function_string(sprop->get),
rna_function_string(sprop->length),
rna_function_string(sprop->set),
rna_function_string(sprop->get_ex),
rna_function_string(sprop->length_ex),
rna_function_string(sprop->set_ex),
+ rna_function_string(sprop->search),
+ (int)sprop->search_flag,
sprop->maxlength);
rna_print_c_string(f, sprop->defaultvalue);
fprintf(f, "\n");
diff --git a/source/blender/makesrna/intern/rna_ID.c b/source/blender/makesrna/intern/rna_ID.c
index b65e08311fe..8d2ee0ab534 100644
--- a/source/blender/makesrna/intern/rna_ID.c
+++ b/source/blender/makesrna/intern/rna_ID.c
@@ -33,41 +33,41 @@ const EnumPropertyItem rna_enum_id_type_items[] = {
{ID_AC, "ACTION", ICON_ACTION, "Action", ""},
{ID_AR, "ARMATURE", ICON_ARMATURE_DATA, "Armature", ""},
{ID_BR, "BRUSH", ICON_BRUSH_DATA, "Brush", ""},
- {ID_CA, "CAMERA", ICON_CAMERA_DATA, "Camera", ""},
{ID_CF, "CACHEFILE", ICON_FILE, "Cache File", ""},
+ {ID_CA, "CAMERA", ICON_CAMERA_DATA, "Camera", ""},
+ {ID_GR, "COLLECTION", ICON_OUTLINER_COLLECTION, "Collection", ""},
{ID_CU_LEGACY, "CURVE", ICON_CURVE_DATA, "Curve", ""},
+ {ID_CV, "CURVES", ICON_CURVES_DATA, "Curves", ""},
{ID_VF, "FONT", ICON_FONT_DATA, "Font", ""},
{ID_GD, "GREASEPENCIL", ICON_GREASEPENCIL, "Grease Pencil", ""},
- {ID_GR, "COLLECTION", ICON_OUTLINER_COLLECTION, "Collection", ""},
{ID_IM, "IMAGE", ICON_IMAGE_DATA, "Image", ""},
{ID_KE, "KEY", ICON_SHAPEKEY_DATA, "Key", ""},
- {ID_LA, "LIGHT", ICON_LIGHT_DATA, "Light", ""},
+ {ID_LT, "LATTICE", ICON_LATTICE_DATA, "Lattice", ""},
{ID_LI, "LIBRARY", ICON_LIBRARY_DATA_DIRECT, "Library", ""},
+ {ID_LA, "LIGHT", ICON_LIGHT_DATA, "Light", ""},
+ {ID_LP, "LIGHT_PROBE", ICON_LIGHTPROBE_CUBEMAP, "Light Probe", ""},
{ID_LS, "LINESTYLE", ICON_LINE_DATA, "Line Style", ""},
- {ID_LT, "LATTICE", ICON_LATTICE_DATA, "Lattice", ""},
{ID_MSK, "MASK", ICON_MOD_MASK, "Mask", ""},
{ID_MA, "MATERIAL", ICON_MATERIAL_DATA, "Material", ""},
- {ID_MB, "META", ICON_META_DATA, "Metaball", ""},
{ID_ME, "MESH", ICON_MESH_DATA, "Mesh", ""},
+ {ID_MB, "META", ICON_META_DATA, "Metaball", ""},
{ID_MC, "MOVIECLIP", ICON_TRACKER, "Movie Clip", ""},
{ID_NT, "NODETREE", ICON_NODETREE, "Node Tree", ""},
{ID_OB, "OBJECT", ICON_OBJECT_DATA, "Object", ""},
{ID_PC, "PAINTCURVE", ICON_CURVE_BEZCURVE, "Paint Curve", ""},
{ID_PAL, "PALETTE", ICON_COLOR, "Palette", ""},
{ID_PA, "PARTICLE", ICON_PARTICLE_DATA, "Particle", ""},
- {ID_LP, "LIGHT_PROBE", ICON_LIGHTPROBE_CUBEMAP, "Light Probe", ""},
+ {ID_PT, "POINTCLOUD", ICON_POINTCLOUD_DATA, "Point Cloud", ""},
{ID_SCE, "SCENE", ICON_SCENE_DATA, "Scene", ""},
{ID_SIM, "SIMULATION", ICON_PHYSICS, "Simulation", ""}, /* TODO: Use correct icon. */
{ID_SO, "SOUND", ICON_SOUND, "Sound", ""},
{ID_SPK, "SPEAKER", ICON_SPEAKER, "Speaker", ""},
{ID_TXT, "TEXT", ICON_TEXT, "Text", ""},
{ID_TE, "TEXTURE", ICON_TEXTURE_DATA, "Texture", ""},
- {ID_CV, "CURVES", ICON_CURVES_DATA, "Hair Curves", ""},
- {ID_PT, "POINTCLOUD", ICON_POINTCLOUD_DATA, "Point Cloud", ""},
{ID_VO, "VOLUME", ICON_VOLUME_DATA, "Volume", ""},
{ID_WM, "WINDOWMANAGER", ICON_WINDOW, "Window Manager", ""},
- {ID_WO, "WORLD", ICON_WORLD_DATA, "World", ""},
{ID_WS, "WORKSPACE", ICON_WORKSPACE, "Workspace", ""},
+ {ID_WO, "WORLD", ICON_WORLD_DATA, "World", ""},
{0, NULL, 0, NULL, NULL},
};
@@ -722,7 +722,7 @@ static ID *rna_ID_override_hierarchy_create(
ID *id_root_override = NULL;
BKE_lib_override_library_create(
- bmain, scene, view_layer, NULL, id, id, id_instance_hint, &id_root_override);
+ bmain, scene, view_layer, NULL, id, id, id_instance_hint, &id_root_override, false);
WM_main_add_notifier(NC_ID | NA_ADDED, NULL);
WM_main_add_notifier(NC_WM | ND_LIB_OVERRIDE_CHANGED, NULL);
@@ -1131,7 +1131,7 @@ static void rna_ImagePreview_size_set(PointerRNA *ptr, const int *values, enum e
prv_img->flag[size] |= (PRV_CHANGED | PRV_USER_EDITED);
}
-static int rna_ImagePreview_pixels_get_length(PointerRNA *ptr,
+static int rna_ImagePreview_pixels_get_length(const PointerRNA *ptr,
int length[RNA_MAX_ARRAY_DIMENSION],
enum eIconSizes size)
{
@@ -1176,7 +1176,7 @@ static void rna_ImagePreview_pixels_set(PointerRNA *ptr, const int *values, enum
prv_img->flag[size] |= PRV_USER_EDITED;
}
-static int rna_ImagePreview_pixels_float_get_length(PointerRNA *ptr,
+static int rna_ImagePreview_pixels_float_get_length(const PointerRNA *ptr,
int length[RNA_MAX_ARRAY_DIMENSION],
enum eIconSizes size)
{
@@ -1256,7 +1256,7 @@ static void rna_ImagePreview_image_size_set(PointerRNA *ptr, const int *values)
rna_ImagePreview_size_set(ptr, values, ICON_SIZE_PREVIEW);
}
-static int rna_ImagePreview_image_pixels_get_length(PointerRNA *ptr,
+static int rna_ImagePreview_image_pixels_get_length(const PointerRNA *ptr,
int length[RNA_MAX_ARRAY_DIMENSION])
{
return rna_ImagePreview_pixels_get_length(ptr, length, ICON_SIZE_PREVIEW);
@@ -1272,7 +1272,7 @@ static void rna_ImagePreview_image_pixels_set(PointerRNA *ptr, const int *values
rna_ImagePreview_pixels_set(ptr, values, ICON_SIZE_PREVIEW);
}
-static int rna_ImagePreview_image_pixels_float_get_length(PointerRNA *ptr,
+static int rna_ImagePreview_image_pixels_float_get_length(const PointerRNA *ptr,
int length[RNA_MAX_ARRAY_DIMENSION])
{
return rna_ImagePreview_pixels_float_get_length(ptr, length, ICON_SIZE_PREVIEW);
@@ -1303,7 +1303,7 @@ static void rna_ImagePreview_icon_size_set(PointerRNA *ptr, const int *values)
rna_ImagePreview_size_set(ptr, values, ICON_SIZE_ICON);
}
-static int rna_ImagePreview_icon_pixels_get_length(PointerRNA *ptr,
+static int rna_ImagePreview_icon_pixels_get_length(const PointerRNA *ptr,
int length[RNA_MAX_ARRAY_DIMENSION])
{
return rna_ImagePreview_pixels_get_length(ptr, length, ICON_SIZE_ICON);
@@ -1319,7 +1319,7 @@ static void rna_ImagePreview_icon_pixels_set(PointerRNA *ptr, const int *values)
rna_ImagePreview_pixels_set(ptr, values, ICON_SIZE_ICON);
}
-static int rna_ImagePreview_icon_pixels_float_get_length(PointerRNA *ptr,
+static int rna_ImagePreview_icon_pixels_float_get_length(const PointerRNA *ptr,
int length[RNA_MAX_ARRAY_DIMENSION])
{
return rna_ImagePreview_pixels_float_get_length(ptr, length, ICON_SIZE_ICON);
@@ -1976,7 +1976,7 @@ static void rna_def_ID(BlenderRNA *brna)
RNA_def_property_ui_text(
prop,
"Extra User",
- "Indicates wether an extra user is set or not (mainly for internal/debug usages)");
+ "Indicates whether an extra user is set or not (mainly for internal/debug usages)");
RNA_def_property_boolean_funcs(prop, NULL, "rna_ID_extra_user_set");
prop = RNA_def_property(srna, "is_embedded_data", PROP_BOOLEAN, PROP_NONE);
diff --git a/source/blender/makesrna/intern/rna_access.c b/source/blender/makesrna/intern/rna_access.c
index 91bee19481c..0bc35d86490 100644
--- a/source/blender/makesrna/intern/rna_access.c
+++ b/source/blender/makesrna/intern/rna_access.c
@@ -302,7 +302,8 @@ static int rna_ensure_property_array_length(PointerRNA *ptr, PropertyRNA *prop)
{
if (prop->magic == RNA_MAGIC) {
int arraylen[RNA_MAX_ARRAY_DIMENSION];
- return (prop->getlength && ptr->data) ? prop->getlength(ptr, arraylen) : prop->totarraylength;
+ return (prop->getlength && ptr->data) ? prop->getlength(ptr, arraylen) :
+ (int)prop->totarraylength;
}
IDProperty *idprop = (IDProperty *)prop;
@@ -322,7 +323,7 @@ static bool rna_ensure_property_array_check(PropertyRNA *prop)
return (idprop->type == IDP_ARRAY);
}
-static void rna_ensure_property_multi_array_length(PointerRNA *ptr,
+static void rna_ensure_property_multi_array_length(const PointerRNA *ptr,
PropertyRNA *prop,
int length[])
{
@@ -1080,7 +1081,7 @@ bool RNA_property_array_check(PropertyRNA *prop)
return rna_ensure_property_array_check(prop);
}
-int RNA_property_array_dimension(PointerRNA *ptr, PropertyRNA *prop, int length[])
+int RNA_property_array_dimension(const PointerRNA *ptr, PropertyRNA *prop, int length[])
{
PropertyRNA *rprop = rna_ensure_property(prop);
@@ -1988,7 +1989,7 @@ bool RNA_property_editable_index(PointerRNA *ptr, PropertyRNA *prop, const int i
return rna_property_editable_do(ptr, prop, index, NULL);
}
-bool RNA_property_animateable(PointerRNA *ptr, PropertyRNA *prop)
+bool RNA_property_animateable(const PointerRNA *ptr, PropertyRNA *prop)
{
/* check that base ID-block can support animation data */
if (!id_can_have_animdata(ptr->owner_id)) {
@@ -3368,6 +3369,34 @@ int RNA_property_string_default_length(PointerRNA *UNUSED(ptr), PropertyRNA *pro
return strlen(sprop->defaultvalue);
}
+eStringPropertySearchFlag RNA_property_string_search_flag(PropertyRNA *prop)
+{
+ StringPropertyRNA *sprop = (StringPropertyRNA *)rna_ensure_property(prop);
+ if (prop->magic != RNA_MAGIC) {
+ return false;
+ }
+ BLI_assert(RNA_property_type(prop) == PROP_STRING);
+ if (sprop->search) {
+ BLI_assert(sprop->search_flag & PROP_STRING_SEARCH_SUPPORTED);
+ }
+ else {
+ BLI_assert(sprop->search_flag == 0);
+ }
+ return sprop->search_flag;
+}
+
+void RNA_property_string_search(const bContext *C,
+ PointerRNA *ptr,
+ PropertyRNA *prop,
+ const char *edit_text,
+ StringPropertySearchVisitFunc visit_fn,
+ void *visit_user_data)
+{
+ BLI_assert(RNA_property_string_search_flag(prop) & PROP_STRING_SEARCH_SUPPORTED);
+ StringPropertyRNA *sprop = (StringPropertyRNA *)rna_ensure_property(prop);
+ sprop->search(C, ptr, prop, edit_text, visit_fn, visit_user_data);
+}
+
int RNA_property_enum_get(PointerRNA *ptr, PropertyRNA *prop)
{
EnumPropertyRNA *eprop = (EnumPropertyRNA *)prop;
@@ -4025,7 +4054,9 @@ void RNA_property_collection_clear(PointerRNA *ptr, PropertyRNA *prop)
}
}
-int RNA_property_collection_lookup_index(PointerRNA *ptr, PropertyRNA *prop, PointerRNA *t_ptr)
+int RNA_property_collection_lookup_index(PointerRNA *ptr,
+ PropertyRNA *prop,
+ const PointerRNA *t_ptr)
{
CollectionPropertyIterator iter;
int index = 0;
@@ -5105,7 +5136,7 @@ static bool rna_path_parse_array_index(const char **path,
*
* \return \a true on success, \a false if the path is somehow invalid.
*/
-static bool rna_path_parse(PointerRNA *ptr,
+static bool rna_path_parse(const PointerRNA *ptr,
const char *path,
PointerRNA *r_ptr,
PropertyRNA **r_prop,
@@ -5262,7 +5293,10 @@ static bool rna_path_parse(PointerRNA *ptr,
return true;
}
-bool RNA_path_resolve(PointerRNA *ptr, const char *path, PointerRNA *r_ptr, PropertyRNA **r_prop)
+bool RNA_path_resolve(const PointerRNA *ptr,
+ const char *path,
+ PointerRNA *r_ptr,
+ PropertyRNA **r_prop)
{
if (!rna_path_parse(ptr, path, r_ptr, r_prop, NULL, NULL, NULL, true)) {
return false;
@@ -5272,7 +5306,7 @@ bool RNA_path_resolve(PointerRNA *ptr, const char *path, PointerRNA *r_ptr, Prop
}
bool RNA_path_resolve_full(
- PointerRNA *ptr, const char *path, PointerRNA *r_ptr, PropertyRNA **r_prop, int *r_index)
+ const PointerRNA *ptr, const char *path, PointerRNA *r_ptr, PropertyRNA **r_prop, int *r_index)
{
if (!rna_path_parse(ptr, path, r_ptr, r_prop, r_index, NULL, NULL, true)) {
return false;
@@ -5282,12 +5316,12 @@ bool RNA_path_resolve_full(
}
bool RNA_path_resolve_full_maybe_null(
- PointerRNA *ptr, const char *path, PointerRNA *r_ptr, PropertyRNA **r_prop, int *r_index)
+ const PointerRNA *ptr, const char *path, PointerRNA *r_ptr, PropertyRNA **r_prop, int *r_index)
{
return rna_path_parse(ptr, path, r_ptr, r_prop, r_index, NULL, NULL, true);
}
-bool RNA_path_resolve_property(PointerRNA *ptr,
+bool RNA_path_resolve_property(const PointerRNA *ptr,
const char *path,
PointerRNA *r_ptr,
PropertyRNA **r_prop)
@@ -5300,7 +5334,7 @@ bool RNA_path_resolve_property(PointerRNA *ptr,
}
bool RNA_path_resolve_property_full(
- PointerRNA *ptr, const char *path, PointerRNA *r_ptr, PropertyRNA **r_prop, int *r_index)
+ const PointerRNA *ptr, const char *path, PointerRNA *r_ptr, PropertyRNA **r_prop, int *r_index)
{
if (!rna_path_parse(ptr, path, r_ptr, r_prop, r_index, NULL, NULL, false)) {
return false;
@@ -5309,7 +5343,7 @@ bool RNA_path_resolve_property_full(
return r_ptr->data != NULL && *r_prop != NULL;
}
-bool RNA_path_resolve_property_and_item_pointer(PointerRNA *ptr,
+bool RNA_path_resolve_property_and_item_pointer(const PointerRNA *ptr,
const char *path,
PointerRNA *r_ptr,
PropertyRNA **r_prop,
@@ -5322,7 +5356,7 @@ bool RNA_path_resolve_property_and_item_pointer(PointerRNA *ptr,
return r_ptr->data != NULL && *r_prop != NULL;
}
-bool RNA_path_resolve_property_and_item_pointer_full(PointerRNA *ptr,
+bool RNA_path_resolve_property_and_item_pointer_full(const PointerRNA *ptr,
const char *path,
PointerRNA *r_ptr,
PropertyRNA **r_prop,
@@ -5340,8 +5374,11 @@ bool RNA_path_resolve_elements(PointerRNA *ptr, const char *path, ListBase *r_el
return rna_path_parse(ptr, path, NULL, NULL, NULL, NULL, r_elements, false);
}
-char *RNA_path_append(
- const char *path, PointerRNA *UNUSED(ptr), PropertyRNA *prop, int intkey, const char *strkey)
+char *RNA_path_append(const char *path,
+ const PointerRNA *UNUSED(ptr),
+ PropertyRNA *prop,
+ int intkey,
+ const char *strkey)
{
DynStr *dynstr;
char *result;
@@ -5445,6 +5482,52 @@ static UNUSED_FUNCTION_WITH_RETURN_TYPE(char *, RNA_path_back)(const char *path)
return result;
}
+const char *RNA_path_array_index_token_find(const char *rna_path, const PropertyRNA *array_prop)
+{
+ if (array_prop != NULL) {
+ if (!ELEM(array_prop->type, PROP_BOOLEAN, PROP_INT, PROP_FLOAT)) {
+ BLI_assert(array_prop->arraydimension == 0);
+ return NULL;
+ }
+ if (array_prop->arraydimension == 0) {
+ return NULL;
+ }
+ }
+
+ /* Valid 'array part' of a rna path can only have '[', ']' and digit characters.
+ * It may have more than one of those (e.g. `[12][1]`) in case of multi-dimensional arrays. */
+ off_t rna_path_len = (off_t)strlen(rna_path);
+ if (rna_path[rna_path_len] != ']') {
+ return NULL;
+ }
+ const char *last_valid_index_token_start = NULL;
+ for (rna_path_len--; rna_path_len >= 0; rna_path_len--) {
+ switch (rna_path[rna_path_len]) {
+ case '[':
+ if (rna_path_len <= 0 || rna_path[rna_path_len - 1] != ']') {
+ return &rna_path[rna_path_len];
+ }
+ last_valid_index_token_start = &rna_path[rna_path_len];
+ rna_path_len--;
+ break;
+ case '0':
+ case '1':
+ case '2':
+ case '3':
+ case '4':
+ case '5':
+ case '6':
+ case '7':
+ case '8':
+ case '9':
+ break;
+ default:
+ return last_valid_index_token_start;
+ }
+ }
+ return last_valid_index_token_start;
+}
+
/* generic path search func
* if its needed this could also reference the IDProperty direct */
typedef struct IDP_Chain {
@@ -5546,7 +5629,12 @@ static char *rna_idp_path(PointerRNA *ptr,
if (iter->type == IDP_GROUP) {
if (prop->type == PROP_POINTER) {
PointerRNA child_ptr = RNA_property_pointer_get(ptr, prop);
- BLI_assert(!RNA_pointer_is_null(&child_ptr));
+ if (RNA_pointer_is_null(&child_ptr)) {
+ /* Pointer ID prop might be a 'leaf' in the IDProp group hierarchy, in which case a NULL
+ * value is perfectly valid. Just means it won't match the searched needle. */
+ continue;
+ }
+
link.name = iter->name;
link.index = -1;
if ((path = rna_idp_path(&child_ptr, iter, needle, &link))) {
@@ -5568,7 +5656,11 @@ static char *rna_idp_path(PointerRNA *ptr,
for (j = 0; j < iter->len; j++, array++) {
PointerRNA child_ptr;
if (RNA_property_collection_lookup_int(ptr, prop, j, &child_ptr)) {
- BLI_assert(!RNA_pointer_is_null(&child_ptr));
+ if (RNA_pointer_is_null(&child_ptr)) {
+ /* Array item ID prop might be a 'leaf' in the IDProp group hierarchy, in which case
+ * a NULL value is perfectly valid. Just means it won't match the searched needle. */
+ continue;
+ }
link.index = j;
if ((path = rna_idp_path(&child_ptr, array, needle, &link))) {
break;
@@ -5715,7 +5807,7 @@ char *RNA_path_from_ID_to_struct(const PointerRNA *ptr)
return ptrpath;
}
-char *RNA_path_from_real_ID_to_struct(Main *bmain, PointerRNA *ptr, struct ID **r_real)
+char *RNA_path_from_real_ID_to_struct(Main *bmain, const PointerRNA *ptr, struct ID **r_real)
{
char *path = RNA_path_from_ID_to_struct(ptr);
@@ -5744,7 +5836,7 @@ static void rna_path_array_multi_from_flat_index(const int dimsize[RNA_MAX_ARRAY
BLI_assert(index == 0);
}
-static void rna_path_array_multi_string_from_flat_index(PointerRNA *ptr,
+static void rna_path_array_multi_string_from_flat_index(const PointerRNA *ptr,
PropertyRNA *prop,
int index_dim,
int index,
@@ -5763,7 +5855,7 @@ static void rna_path_array_multi_string_from_flat_index(PointerRNA *ptr,
}
}
-char *RNA_path_from_ID_to_property_index(PointerRNA *ptr,
+char *RNA_path_from_ID_to_property_index(const PointerRNA *ptr,
PropertyRNA *prop,
int index_dim,
int index)
@@ -5819,13 +5911,17 @@ char *RNA_path_from_ID_to_property_index(PointerRNA *ptr,
return path;
}
-char *RNA_path_from_ID_to_property(PointerRNA *ptr, PropertyRNA *prop)
+char *RNA_path_from_ID_to_property(const PointerRNA *ptr, PropertyRNA *prop)
{
return RNA_path_from_ID_to_property_index(ptr, prop, 0, -1);
}
-char *RNA_path_from_real_ID_to_property_index(
- Main *bmain, PointerRNA *ptr, PropertyRNA *prop, int index_dim, int index, ID **r_real_id)
+char *RNA_path_from_real_ID_to_property_index(Main *bmain,
+ const PointerRNA *ptr,
+ PropertyRNA *prop,
+ int index_dim,
+ int index,
+ ID **r_real_id)
{
char *path = RNA_path_from_ID_to_property_index(ptr, prop, index_dim, index);
@@ -5834,7 +5930,7 @@ char *RNA_path_from_real_ID_to_property_index(
return path != NULL ? rna_prepend_real_ID_path(bmain, ptr->owner_id, path, r_real_id) : NULL;
}
-char *RNA_path_resolve_from_type_to_property(PointerRNA *ptr,
+char *RNA_path_resolve_from_type_to_property(const PointerRNA *ptr,
PropertyRNA *prop,
const StructRNA *type)
{
@@ -5907,7 +6003,7 @@ char *RNA_path_full_ID_py(Main *bmain, ID *id)
path);
}
-char *RNA_path_full_struct_py(Main *bmain, struct PointerRNA *ptr)
+char *RNA_path_full_struct_py(Main *bmain, const PointerRNA *ptr)
{
char *id_path;
char *data_path;
@@ -5936,7 +6032,7 @@ char *RNA_path_full_struct_py(Main *bmain, struct PointerRNA *ptr)
}
char *RNA_path_full_property_py_ex(
- Main *bmain, PointerRNA *ptr, PropertyRNA *prop, int index, bool use_fallback)
+ Main *bmain, const PointerRNA *ptr, PropertyRNA *prop, int index, bool use_fallback)
{
char *id_path;
const char *data_delim;
@@ -5983,7 +6079,7 @@ char *RNA_path_full_property_py_ex(
return ret;
}
-char *RNA_path_full_property_py(Main *bmain, PointerRNA *ptr, PropertyRNA *prop, int index)
+char *RNA_path_full_property_py(Main *bmain, const PointerRNA *ptr, PropertyRNA *prop, int index)
{
return RNA_path_full_property_py_ex(bmain, ptr, prop, index, false);
}
@@ -6012,7 +6108,7 @@ char *RNA_path_struct_property_py(PointerRNA *ptr, PropertyRNA *prop, int index)
}
if ((index == -1) || (RNA_property_array_check(prop) == false)) {
- ret = BLI_sprintfN("%s", data_path);
+ ret = BLI_strdup(data_path);
}
else {
ret = BLI_sprintfN("%s[%d]", data_path, index);
@@ -6714,23 +6810,27 @@ static void *rna_array_as_string_alloc(
int type, int len, PointerRNA *ptr, PropertyRNA *prop, void **r_buf_end)
{
void *buf_ret = NULL;
- if (type == PROP_BOOLEAN) {
- bool *buf = buf_ret = MEM_mallocN(sizeof(*buf) * len, __func__);
- RNA_property_boolean_get_array(ptr, prop, buf);
- *r_buf_end = buf + len;
- }
- else if (type == PROP_INT) {
- int *buf = buf_ret = MEM_mallocN(sizeof(*buf) * len, __func__);
- RNA_property_int_get_array(ptr, prop, buf);
- *r_buf_end = buf + len;
- }
- else if (type == PROP_FLOAT) {
- float *buf = buf_ret = MEM_mallocN(sizeof(*buf) * len, __func__);
- RNA_property_float_get_array(ptr, prop, buf);
- *r_buf_end = buf + len;
- }
- else {
- BLI_assert(0);
+ switch (type) {
+ case PROP_BOOLEAN: {
+ bool *buf = buf_ret = MEM_mallocN(sizeof(*buf) * len, __func__);
+ RNA_property_boolean_get_array(ptr, prop, buf);
+ *r_buf_end = buf + len;
+ break;
+ }
+ case PROP_INT: {
+ int *buf = buf_ret = MEM_mallocN(sizeof(*buf) * len, __func__);
+ RNA_property_int_get_array(ptr, prop, buf);
+ *r_buf_end = buf + len;
+ break;
+ }
+ case PROP_FLOAT: {
+ float *buf = buf_ret = MEM_mallocN(sizeof(*buf) * len, __func__);
+ RNA_property_float_get_array(ptr, prop, buf);
+ *r_buf_end = buf + len;
+ break;
+ }
+ default:
+ BLI_assert_unreachable();
}
return buf_ret;
}
@@ -6740,29 +6840,33 @@ static void rna_array_as_string_elem(int type, void **buf_p, int len, DynStr *dy
/* This will print a comma separated string of the array elements from
* buf start to len. We will add a comma if len == 1 to preserve tuples. */
const int end = len - 1;
- if (type == PROP_BOOLEAN) {
- bool *buf = *buf_p;
- for (int i = 0; i < len; i++, buf++) {
- BLI_dynstr_appendf(dynstr, (i < end || !end) ? "%s, " : "%s", bool_as_py_string(*buf));
+ switch (type) {
+ case PROP_BOOLEAN: {
+ bool *buf = *buf_p;
+ for (int i = 0; i < len; i++, buf++) {
+ BLI_dynstr_appendf(dynstr, (i < end || !end) ? "%s, " : "%s", bool_as_py_string(*buf));
+ }
+ *buf_p = buf;
+ break;
}
- *buf_p = buf;
- }
- else if (type == PROP_INT) {
- int *buf = *buf_p;
- for (int i = 0; i < len; i++, buf++) {
- BLI_dynstr_appendf(dynstr, (i < end || !end) ? "%d, " : "%d", *buf);
+ case PROP_INT: {
+ int *buf = *buf_p;
+ for (int i = 0; i < len; i++, buf++) {
+ BLI_dynstr_appendf(dynstr, (i < end || !end) ? "%d, " : "%d", *buf);
+ }
+ *buf_p = buf;
+ break;
}
- *buf_p = buf;
- }
- else if (type == PROP_FLOAT) {
- float *buf = *buf_p;
- for (int i = 0; i < len; i++, buf++) {
- BLI_dynstr_appendf(dynstr, (i < end || !end) ? "%g, " : "%g", *buf);
+ case PROP_FLOAT: {
+ float *buf = *buf_p;
+ for (int i = 0; i < len; i++, buf++) {
+ BLI_dynstr_appendf(dynstr, (i < end || !end) ? "%g, " : "%g", *buf);
+ }
+ *buf_p = buf;
+ break;
}
- *buf_p = buf;
- }
- else {
- BLI_assert(0);
+ default:
+ BLI_assert_unreachable();
}
}
diff --git a/source/blender/makesrna/intern/rna_access_compare_override.c b/source/blender/makesrna/intern/rna_access_compare_override.c
index 5974788884e..17c00923efa 100644
--- a/source/blender/makesrna/intern/rna_access_compare_override.c
+++ b/source/blender/makesrna/intern/rna_access_compare_override.c
@@ -12,6 +12,7 @@
#include "DNA_ID.h"
#include "DNA_anim_types.h"
+#include "DNA_camera_types.h"
#include "DNA_constraint_types.h"
#include "DNA_gpencil_modifier_types.h"
#include "DNA_key_types.h"
@@ -87,7 +88,7 @@ static ID *rna_property_override_property_real_id_owner(Main *bmain,
owner_id = RNA_find_real_ID_and_path(bmain, id, &rna_path_prefix);
break;
default:
- BLI_assert(0);
+ BLI_assert_unreachable();
}
}
@@ -145,6 +146,12 @@ bool RNA_property_overridable_get(PointerRNA *ptr, PropertyRNA *prop)
return true;
}
}
+ else if (RNA_struct_is_a(ptr->type, &RNA_CameraBackgroundImage)) {
+ CameraBGImage *bgpic = ptr->data;
+ if (bgpic->flag & CAM_BGIMG_FLAG_OVERRIDE_LIBRARY_LOCAL) {
+ return true;
+ }
+ }
/* If this is a RNA-defined property (real or 'virtual' IDProp),
* we want to use RNA prop flag. */
return !(prop->flag_override & PROPOVERRIDE_NO_COMPARISON) &&
@@ -354,7 +361,7 @@ static int rna_property_override_diff(Main *bmain,
if (is_array_a != is_array_b) {
/* Should probably never happen actually... */
- BLI_assert(0);
+ BLI_assert_unreachable();
return is_array_a ? 1 : -1;
}
@@ -400,7 +407,7 @@ static int rna_property_override_diff(Main *bmain,
rna_path ? rna_path : prop_a->identifier,
!prop_a->is_idprop,
!prop_b->is_idprop);
- BLI_assert(0);
+ BLI_assert_unreachable();
return 1;
}
@@ -491,7 +498,7 @@ static bool rna_property_override_operation_store(Main *bmain,
op->rna_path,
prop_local->magic == RNA_MAGIC,
prop_reference->magic == RNA_MAGIC);
- BLI_assert(0);
+ BLI_assert_unreachable();
return changed;
}
@@ -580,7 +587,7 @@ static bool rna_property_override_operation_apply(Main *bmain,
prop_dst->identifier,
prop_dst->magic == RNA_MAGIC,
prop_src->magic == RNA_MAGIC);
- BLI_assert(0);
+ BLI_assert_unreachable();
return false;
}
diff --git a/source/blender/makesrna/intern/rna_action.c b/source/blender/makesrna/intern/rna_action.c
index 76d2087d904..a1266443631 100644
--- a/source/blender/makesrna/intern/rna_action.c
+++ b/source/blender/makesrna/intern/rna_action.c
@@ -340,7 +340,7 @@ bool rna_Action_actedit_assign_poll(PointerRNA *ptr, PointerRNA value)
return 0;
}
-static char *rna_DopeSheet_path(PointerRNA *UNUSED(ptr))
+static char *rna_DopeSheet_path(const PointerRNA *UNUSED(ptr))
{
return BLI_strdup("dopesheet");
}
diff --git a/source/blender/makesrna/intern/rna_armature.c b/source/blender/makesrna/intern/rna_armature.c
index df92601dd0c..a4094630266 100644
--- a/source/blender/makesrna/intern/rna_armature.c
+++ b/source/blender/makesrna/intern/rna_armature.c
@@ -216,10 +216,10 @@ static void rna_Bone_select_update(Main *UNUSED(bmain), Scene *UNUSED(scene), Po
WM_main_add_notifier(NC_ANIMATION | ND_ANIMCHAN, id);
}
-static char *rna_Bone_path(PointerRNA *ptr)
+static char *rna_Bone_path(const PointerRNA *ptr)
{
- ID *id = ptr->owner_id;
- Bone *bone = (Bone *)ptr->data;
+ const ID *id = ptr->owner_id;
+ const Bone *bone = (const Bone *)ptr->data;
char name_esc[sizeof(bone->name) * 2];
BLI_str_escape(name_esc, bone->name, sizeof(name_esc));
diff --git a/source/blender/makesrna/intern/rna_attribute.c b/source/blender/makesrna/intern/rna_attribute.c
index 2d9517ce1ee..5e17f22ecf5 100644
--- a/source/blender/makesrna/intern/rna_attribute.c
+++ b/source/blender/makesrna/intern/rna_attribute.c
@@ -106,6 +106,11 @@ const EnumPropertyItem rna_enum_color_attribute_domain_items[] = {
{ATTR_DOMAIN_CORNER, "CORNER", 0, "Face Corner", ""},
{0, NULL, 0, NULL, NULL}};
+const EnumPropertyItem rna_enum_attribute_curves_domain_items[] = {
+ {ATTR_DOMAIN_POINT, "POINT", 0, "Control Point", ""},
+ {ATTR_DOMAIN_CURVE, "CURVE", 0, "Curve", ""},
+ {0, NULL, 0, NULL, NULL}};
+
#ifdef RNA_RUNTIME
# include "BLI_math.h"
@@ -118,13 +123,13 @@ const EnumPropertyItem rna_enum_color_attribute_domain_items[] = {
/* Attribute */
-static char *rna_Attribute_path(PointerRNA *ptr)
+static char *rna_Attribute_path(const PointerRNA *ptr)
{
- CustomDataLayer *layer = ptr->data;
+ const CustomDataLayer *layer = ptr->data;
return BLI_sprintfN("attributes['%s']", layer->name);
}
-static StructRNA *srna_by_custom_data_layer_type(const CustomDataType type)
+static StructRNA *srna_by_custom_data_layer_type(const eCustomDataType type)
{
switch (type) {
case CD_PROP_FLOAT:
@@ -158,13 +163,14 @@ static StructRNA *rna_Attribute_refine(PointerRNA *ptr)
static void rna_Attribute_name_set(PointerRNA *ptr, const char *value)
{
- BKE_id_attribute_rename(ptr->owner_id, ptr->data, value, NULL);
+ const CustomDataLayer *layer = (const CustomDataLayer *)ptr->data;
+ BKE_id_attribute_rename(ptr->owner_id, layer->name, value, NULL);
}
static int rna_Attribute_name_editable(PointerRNA *ptr, const char **r_info)
{
CustomDataLayer *layer = ptr->data;
- if (BKE_id_attribute_required(ptr->owner_id, layer)) {
+ if (BKE_id_attribute_required(ptr->owner_id, layer->name)) {
*r_info = N_("Cannot modify name of required geometry attribute");
return false;
}
@@ -232,6 +238,12 @@ static int rna_Attribute_domain_get(PointerRNA *ptr)
return BKE_id_attribute_domain(ptr->owner_id, ptr->data);
}
+static bool rna_Attribute_is_internal_get(PointerRNA *ptr)
+{
+ const CustomDataLayer *layer = (const CustomDataLayer *)ptr->data;
+ return BKE_attribute_allow_procedural_access(layer->name);
+}
+
static void rna_Attribute_data_begin(CollectionPropertyIterator *iter, PointerRNA *ptr)
{
ID *id = ptr->owner_id;
@@ -347,8 +359,8 @@ static PointerRNA rna_AttributeGroup_new(
static void rna_AttributeGroup_remove(ID *id, ReportList *reports, PointerRNA *attribute_ptr)
{
- CustomDataLayer *layer = (CustomDataLayer *)attribute_ptr->data;
- BKE_id_attribute_remove(id, layer, reports);
+ const CustomDataLayer *layer = (const CustomDataLayer *)attribute_ptr->data;
+ BKE_id_attribute_remove(id, layer->name, reports);
RNA_POINTER_INVALIDATE(attribute_ptr);
DEG_id_tag_update(id, ID_RECALC_GEOMETRY);
@@ -367,7 +379,7 @@ static int rna_Attributes_noncolor_layer_skip(CollectionPropertyIterator *iter,
/* Check valid domain here, too, keep in line with rna_AttributeGroup_color_length(). */
ID *id = iter->parent.owner_id;
- AttributeDomain domain = BKE_id_attribute_domain(id, layer);
+ eAttrDomain domain = BKE_id_attribute_domain(id, layer);
if (!ELEM(domain, ATTR_DOMAIN_POINT, ATTR_DOMAIN_CORNER)) {
return 1;
}
@@ -527,7 +539,7 @@ static void rna_AttributeGroup_active_color_set(PointerRNA *ptr,
static int rna_AttributeGroup_active_color_index_get(PointerRNA *ptr)
{
- CustomDataLayer *layer = BKE_id_attributes_active_color_get(ptr->owner_id);
+ const CustomDataLayer *layer = BKE_id_attributes_active_color_get(ptr->owner_id);
return BKE_id_attribute_to_index(
ptr->owner_id, layer, ATTR_DOMAIN_MASK_COLOR, CD_MASK_COLOR_ALL);
@@ -930,6 +942,12 @@ static void rna_def_attribute(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "Domain", "Domain of the Attribute");
RNA_def_property_clear_flag(prop, PROP_EDITABLE);
+ prop = RNA_def_property(srna, "is_internal", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_funcs(prop, "rna_Attribute_is_internal_get", NULL);
+ RNA_def_property_ui_text(
+ prop, "Is Internal", "The attribute is meant for internal use by Blender");
+ RNA_def_property_clear_flag(prop, PROP_EDITABLE);
+
/* types */
rna_def_attribute_float(brna);
rna_def_attribute_float_vector(brna);
@@ -942,7 +960,7 @@ static void rna_def_attribute(BlenderRNA *brna)
rna_def_attribute_int8(brna);
}
-/* Mesh/PointCloud/Hair.attributes */
+/* Mesh/PointCloud/Curves.attributes */
static void rna_def_attribute_group(BlenderRNA *brna)
{
StructRNA *srna;
diff --git a/source/blender/makesrna/intern/rna_boid.c b/source/blender/makesrna/intern/rna_boid.c
index 0818f009d1f..d65c8a1b4e3 100644
--- a/source/blender/makesrna/intern/rna_boid.c
+++ b/source/blender/makesrna/intern/rna_boid.c
@@ -162,9 +162,9 @@ static StructRNA *rna_BoidRule_refine(struct PointerRNA *ptr)
}
}
-static char *rna_BoidRule_path(PointerRNA *ptr)
+static char *rna_BoidRule_path(const PointerRNA *ptr)
{
- BoidRule *rule = (BoidRule *)ptr->data;
+ const BoidRule *rule = (BoidRule *)ptr->data;
char name_esc[sizeof(rule->name) * 2];
BLI_str_escape(name_esc, rule->name, sizeof(name_esc));
@@ -222,16 +222,16 @@ static void rna_BoidState_active_boid_rule_index_set(struct PointerRNA *ptr, int
}
}
-static int particle_id_check(PointerRNA *ptr)
+static int particle_id_check(const PointerRNA *ptr)
{
- ID *id = ptr->owner_id;
+ const ID *id = ptr->owner_id;
return (GS(id->name) == ID_PA);
}
-static char *rna_BoidSettings_path(PointerRNA *ptr)
+static char *rna_BoidSettings_path(const PointerRNA *ptr)
{
- BoidSettings *boids = (BoidSettings *)ptr->data;
+ const BoidSettings *boids = (BoidSettings *)ptr->data;
if (particle_id_check(ptr)) {
ParticleSettings *part = (ParticleSettings *)ptr->owner_id;
diff --git a/source/blender/makesrna/intern/rna_brush.c b/source/blender/makesrna/intern/rna_brush.c
index f7edba24dea..423cb084f27 100644
--- a/source/blender/makesrna/intern/rna_brush.c
+++ b/source/blender/makesrna/intern/rna_brush.c
@@ -98,14 +98,14 @@ const EnumPropertyItem rna_enum_brush_sculpt_tool_items[] = {
{SCULPT_TOOL_INFLATE, "INFLATE", ICON_BRUSH_INFLATE, "Inflate", ""},
{SCULPT_TOOL_BLOB, "BLOB", ICON_BRUSH_BLOB, "Blob", ""},
{SCULPT_TOOL_CREASE, "CREASE", ICON_BRUSH_CREASE, "Crease", ""},
- {0, "", 0, NULL, NULL},
+ RNA_ENUM_ITEM_SEPR,
{SCULPT_TOOL_SMOOTH, "SMOOTH", ICON_BRUSH_SMOOTH, "Smooth", ""},
{SCULPT_TOOL_FLATTEN, "FLATTEN", ICON_BRUSH_FLATTEN, "Flatten", ""},
{SCULPT_TOOL_FILL, "FILL", ICON_BRUSH_FILL, "Fill", ""},
{SCULPT_TOOL_SCRAPE, "SCRAPE", ICON_BRUSH_SCRAPE, "Scrape", ""},
{SCULPT_TOOL_MULTIPLANE_SCRAPE, "MULTIPLANE_SCRAPE", ICON_BRUSH_SCRAPE, "Multi-plane Scrape", ""},
{SCULPT_TOOL_PINCH, "PINCH", ICON_BRUSH_PINCH, "Pinch", ""},
- {0, "", 0, NULL, NULL},
+ RNA_ENUM_ITEM_SEPR,
{SCULPT_TOOL_GRAB, "GRAB", ICON_BRUSH_GRAB, "Grab", ""},
{SCULPT_TOOL_ELASTIC_DEFORM, "ELASTIC_DEFORM", ICON_BRUSH_GRAB, "Elastic Deform", ""},
{SCULPT_TOOL_SNAKE_HOOK, "SNAKE_HOOK", ICON_BRUSH_SNAKE_HOOK, "Snake Hook", ""},
@@ -115,7 +115,7 @@ const EnumPropertyItem rna_enum_brush_sculpt_tool_items[] = {
{SCULPT_TOOL_ROTATE, "ROTATE", ICON_BRUSH_ROTATE, "Rotate", ""},
{SCULPT_TOOL_SLIDE_RELAX, "TOPOLOGY", ICON_BRUSH_GRAB, "Slide Relax", ""},
{SCULPT_TOOL_BOUNDARY, "BOUNDARY", ICON_BRUSH_GRAB, "Boundary", ""},
- {0, "", 0, NULL, NULL},
+ RNA_ENUM_ITEM_SEPR,
{SCULPT_TOOL_CLOTH, "CLOTH", ICON_BRUSH_SCULPT_DRAW, "Cloth", ""},
{SCULPT_TOOL_SIMPLIFY, "SIMPLIFY", ICON_BRUSH_DATA, "Simplify", ""},
{SCULPT_TOOL_MASK, "MASK", ICON_BRUSH_MASK, "Mask", ""},
@@ -243,14 +243,17 @@ const EnumPropertyItem rna_enum_brush_gpencil_weight_types_items[] = {
{0, NULL, 0, NULL, NULL},
};
+/* clang-format off */
const EnumPropertyItem rna_enum_brush_curves_sculpt_tool_items[] = {
- {CURVES_SCULPT_TOOL_COMB, "COMB", ICON_NONE, "Comb Curves", ""},
- {CURVES_SCULPT_TOOL_DELETE, "DELETE", ICON_NONE, "Delete Curves", ""},
- {CURVES_SCULPT_TOOL_SNAKE_HOOK, "SNAKE_HOOK", ICON_NONE, "Curves Snake Hook", ""},
- {CURVES_SCULPT_TOOL_ADD, "ADD", ICON_NONE, "Add Curves", ""},
- {CURVES_SCULPT_TOOL_GROW_SHRINK, "GROW_SHRINK", ICON_NONE, "Grow / Shrink Curves", ""},
+ {CURVES_SCULPT_TOOL_COMB, "COMB", ICON_BRUSH_CURVES_COMB, "Comb Curves", ""},
+ {CURVES_SCULPT_TOOL_DELETE, "DELETE", ICON_BRUSH_CURVES_DELETE, "Delete Curves", ""},
+ {CURVES_SCULPT_TOOL_SNAKE_HOOK, "SNAKE_HOOK", ICON_BRUSH_CURVES_SNAKE_HOOK, "Curves Snake Hook", ""},
+ {CURVES_SCULPT_TOOL_ADD, "ADD", ICON_BRUSH_CURVES_ADD, "Add Curves", ""},
+ {CURVES_SCULPT_TOOL_GROW_SHRINK, "GROW_SHRINK", ICON_BRUSH_CURVES_GROW_SHRINK, "Grow / Shrink Curves", ""},
+ {CURVES_SCULPT_TOOL_SELECTION_PAINT, "SELECTION_PAINT", ICON_BRUSH_PAINT_SELECT, "Paint Selection", ""},
{0, NULL, 0, NULL, NULL},
};
+/* clang-format om */
#ifndef RNA_RUNTIME
static EnumPropertyItem rna_enum_gpencil_brush_eraser_modes_items[] = {
@@ -885,6 +888,7 @@ static const EnumPropertyItem *rna_Brush_direction_itemf(bContext *C,
case PAINT_MODE_SCULPT_CURVES:
switch (me->curves_sculpt_tool) {
case CURVES_SCULPT_TOOL_GROW_SHRINK:
+ case CURVES_SCULPT_TOOL_SELECTION_PAINT:
return prop_direction_items;
default:
return DummyRNA_DEFAULT_items;
@@ -934,7 +938,7 @@ static const EnumPropertyItem *rna_Brush_stroke_itemf(bContext *C,
}
/* Grease Pencil Drawing Brushes Settings */
-static char *rna_BrushGpencilSettings_path(PointerRNA *UNUSED(ptr))
+static char *rna_BrushGpencilSettings_path(const PointerRNA *UNUSED(ptr))
{
return BLI_strdup("tool_settings.gpencil_paint.brush.gpencil_settings");
}
@@ -1951,7 +1955,7 @@ static void rna_def_curves_sculpt_options(BlenderRNA *brna)
prop = RNA_def_property(srna, "add_amount", PROP_INT, PROP_NONE);
RNA_def_property_range(prop, 1, INT32_MAX);
- RNA_def_property_ui_text(prop, "Add Amount", "Number of curves added by the Add brush");
+ RNA_def_property_ui_text(prop, "Count", "Number of curves added by the Add brush");
prop = RNA_def_property(srna, "points_per_curve", PROP_INT, PROP_NONE);
RNA_def_property_range(prop, 2, INT32_MAX);
@@ -1975,6 +1979,13 @@ static void rna_def_curves_sculpt_options(BlenderRNA *brna)
RNA_def_property_ui_text(
prop, "Interpolate Length", "Use length of the curves in close proximity");
+ prop = RNA_def_property(srna, "interpolate_point_count", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(
+ prop, NULL, "flag", BRUSH_CURVES_SCULPT_FLAG_INTERPOLATE_POINT_COUNT);
+ RNA_def_property_ui_text(prop,
+ "Interpolate Point Count",
+ "Use the number of points from the curves in close proximity");
+
prop = RNA_def_property(srna, "interpolate_shape", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flag", BRUSH_CURVES_SCULPT_FLAG_INTERPOLATE_SHAPE);
RNA_def_property_ui_text(
@@ -1995,7 +2006,7 @@ static void rna_def_brush(BlenderRNA *brna)
static const EnumPropertyItem prop_blend_items[] = {
{IMB_BLEND_MIX, "MIX", 0, "Mix", "Use Mix blending mode while painting"},
- {0, "", ICON_NONE, NULL, NULL},
+ RNA_ENUM_ITEM_SEPR,
{IMB_BLEND_DARKEN, "DARKEN", 0, "Darken", "Use Darken blending mode while painting"},
{IMB_BLEND_MUL, "MUL", 0, "Multiply", "Use Multiply blending mode while painting"},
{IMB_BLEND_COLORBURN,
@@ -2008,7 +2019,7 @@ static void rna_def_brush(BlenderRNA *brna)
0,
"Linear Burn",
"Use Linear Burn blending mode while painting"},
- {0, "", ICON_NONE, NULL, NULL},
+ RNA_ENUM_ITEM_SEPR,
{IMB_BLEND_LIGHTEN, "LIGHTEN", 0, "Lighten", "Use Lighten blending mode while painting"},
{IMB_BLEND_SCREEN, "SCREEN", 0, "Screen", "Use Screen blending mode while painting"},
{IMB_BLEND_COLORDODGE,
@@ -2017,7 +2028,7 @@ static void rna_def_brush(BlenderRNA *brna)
"Color Dodge",
"Use Color Dodge blending mode while painting"},
{IMB_BLEND_ADD, "ADD", 0, "Add", "Use Add blending mode while painting"},
- {0, "", ICON_NONE, NULL, NULL},
+ RNA_ENUM_ITEM_SEPR,
{IMB_BLEND_OVERLAY, "OVERLAY", 0, "Overlay", "Use Overlay blending mode while painting"},
{IMB_BLEND_SOFTLIGHT,
"SOFTLIGHT",
@@ -2044,7 +2055,7 @@ static void rna_def_brush(BlenderRNA *brna)
0,
"Pin Light",
"Use Pin Light blending mode while painting"},
- {0, "", ICON_NONE, NULL, NULL},
+ RNA_ENUM_ITEM_SEPR,
{IMB_BLEND_DIFFERENCE,
"DIFFERENCE",
0,
@@ -2056,7 +2067,7 @@ static void rna_def_brush(BlenderRNA *brna)
"Exclusion",
"Use Exclusion blending mode while painting"},
{IMB_BLEND_SUB, "SUB", 0, "Subtract", "Use Subtract blending mode while painting"},
- {0, "", ICON_NONE, NULL, NULL},
+ RNA_ENUM_ITEM_SEPR,
{IMB_BLEND_HUE, "HUE", 0, "Hue", "Use Hue blending mode while painting"},
{IMB_BLEND_SATURATION,
"SATURATION",
@@ -2065,7 +2076,7 @@ static void rna_def_brush(BlenderRNA *brna)
"Use Saturation blending mode while painting"},
{IMB_BLEND_COLOR, "COLOR", 0, "Color", "Use Color blending mode while painting"},
{IMB_BLEND_LUMINOSITY, "LUMINOSITY", 0, "Value", "Use Value blending mode while painting"},
- {0, "", ICON_NONE, NULL, NULL},
+ RNA_ENUM_ITEM_SEPR,
{IMB_BLEND_ERASE_ALPHA, "ERASE_ALPHA", 0, "Erase Alpha", "Erase alpha while painting"},
{IMB_BLEND_ADD_ALPHA, "ADD_ALPHA", 0, "Add Alpha", "Add alpha while painting"},
{0, NULL, 0, NULL, NULL},
diff --git a/source/blender/makesrna/intern/rna_camera.c b/source/blender/makesrna/intern/rna_camera.c
index f535cdcee96..9628c6b2d65 100644
--- a/source/blender/makesrna/intern/rna_camera.c
+++ b/source/blender/makesrna/intern/rna_camera.c
@@ -111,13 +111,88 @@ static void rna_Camera_background_images_clear(Camera *cam)
WM_main_add_notifier(NC_CAMERA | ND_DRAW_RENDER_VIEWPORT, cam);
}
+static char *rna_Camera_background_image_path(const PointerRNA *ptr)
+{
+ const CameraBGImage *bgpic = ptr->data;
+ Camera *camera = (Camera *)ptr->owner_id;
+
+ const int bgpic_index = BLI_findindex(&camera->bg_images, bgpic);
+
+ if (bgpic_index >= 0) {
+ return BLI_sprintfN("background_images[%d]", bgpic_index);
+ }
+
+ return NULL;
+}
+
+char *rna_CameraBackgroundImage_image_or_movieclip_user_path(const PointerRNA *ptr)
+{
+ const char *user = ptr->data;
+ Camera *camera = (Camera *)ptr->owner_id;
+
+ int bgpic_index = BLI_findindex(&camera->bg_images, user - offsetof(CameraBGImage, iuser));
+ if (bgpic_index >= 0) {
+ return BLI_sprintfN("background_images[%d].image_user", bgpic_index);
+ }
+
+ bgpic_index = BLI_findindex(&camera->bg_images, user - offsetof(CameraBGImage, cuser));
+ if (bgpic_index >= 0) {
+ return BLI_sprintfN("background_images[%d].clip_user", bgpic_index);
+ }
+
+ return NULL;
+}
+
+static bool rna_Camera_background_images_override_apply(Main *bmain,
+ PointerRNA *ptr_dst,
+ PointerRNA *ptr_src,
+ PointerRNA *UNUSED(ptr_storage),
+ PropertyRNA *prop_dst,
+ PropertyRNA *UNUSED(prop_src),
+ PropertyRNA *UNUSED(prop_storage),
+ const int UNUSED(len_dst),
+ const int UNUSED(len_src),
+ const int UNUSED(len_storage),
+ PointerRNA *UNUSED(ptr_item_dst),
+ PointerRNA *UNUSED(ptr_item_src),
+ PointerRNA *UNUSED(ptr_item_storage),
+ IDOverrideLibraryPropertyOperation *opop)
+{
+ BLI_assert_msg(opop->operation == IDOVERRIDE_LIBRARY_OP_INSERT_AFTER,
+ "Unsupported RNA override operation on background images collection");
+
+ Camera *cam_dst = (Camera *)ptr_dst->owner_id;
+ Camera *cam_src = (Camera *)ptr_src->owner_id;
+
+ /* Remember that insertion operations are defined and stored in correct order, which means that
+ * even if we insert several items in a row, we always insert first one, then second one, etc.
+ * So we should always find 'anchor' constraint in both _src *and* _dst. */
+ CameraBGImage *bgpic_anchor = BLI_findlink(&cam_dst->bg_images, opop->subitem_reference_index);
+
+ /* If `bgpic_anchor` is NULL, `bgpic_src` will be inserted in first position. */
+ CameraBGImage *bgpic_src = BLI_findlink(&cam_src->bg_images, opop->subitem_local_index);
+
+ if (bgpic_src == NULL) {
+ BLI_assert(bgpic_src != NULL);
+ return false;
+ }
+
+ CameraBGImage *bgpic_dst = BKE_camera_background_image_copy(bgpic_src, 0);
+
+ /* This handles NULL anchor as expected by adding at head of list. */
+ BLI_insertlinkafter(&cam_dst->bg_images, bgpic_anchor, bgpic_dst);
+
+ RNA_property_update_main(bmain, NULL, ptr_dst, prop_dst);
+ return true;
+}
+
static void rna_Camera_dof_update(Main *bmain, Scene *scene, PointerRNA *UNUSED(ptr))
{
SEQ_relations_invalidate_scene_strips(bmain, scene);
WM_main_add_notifier(NC_SCENE | ND_SEQUENCER, scene);
}
-char *rna_CameraDOFSettings_path(PointerRNA *ptr)
+char *rna_CameraDOFSettings_path(const PointerRNA *ptr)
{
/* if there is ID-data, resolve the path using the index instead of by name,
* since the name used is the name of the texture assigned, but the texture
@@ -179,6 +254,17 @@ static void rna_def_camera_background_image(BlenderRNA *brna)
RNA_def_struct_sdna(srna, "CameraBGImage");
RNA_def_struct_ui_text(
srna, "Background Image", "Image and settings for display in the 3D View background");
+ RNA_def_struct_path_func(srna, "rna_Camera_background_image_path");
+
+ prop = RNA_def_boolean(srna,
+ "is_override_data",
+ false,
+ "Override Background Image",
+ "In a local override camera, whether this background image comes from "
+ "the linked reference camera, or is local to the override");
+ RNA_def_property_clear_flag(prop, PROP_EDITABLE);
+ RNA_def_property_boolean_negative_sdna(
+ prop, NULL, "flag", CAM_BGIMG_FLAG_OVERRIDE_LIBRARY_LOCAL);
RNA_define_lib_overridable(true);
@@ -204,6 +290,7 @@ static void rna_def_camera_background_image(BlenderRNA *brna)
prop = RNA_def_property(srna, "image_user", PROP_POINTER, PROP_NONE);
RNA_def_property_flag(prop, PROP_NEVER_NULL);
+ RNA_def_property_struct_type(prop, "ImageUser");
RNA_def_property_pointer_sdna(prop, NULL, "iuser");
RNA_def_property_ui_text(
prop,
@@ -736,6 +823,8 @@ void RNA_def_camera(BlenderRNA *brna)
RNA_def_property_collection_sdna(prop, NULL, "bg_images", NULL);
RNA_def_property_struct_type(prop, "CameraBackgroundImage");
RNA_def_property_ui_text(prop, "Background Images", "List of background images");
+ RNA_def_property_override_flag(prop, PROPOVERRIDE_LIBRARY_INSERTION | PROPOVERRIDE_NO_PROP_NAME);
+ RNA_def_property_override_funcs(prop, NULL, NULL, "rna_Camera_background_images_override_apply");
RNA_def_property_update(prop, NC_CAMERA | ND_DRAW_RENDER_VIEWPORT, NULL);
RNA_define_lib_overridable(false);
diff --git a/source/blender/makesrna/intern/rna_cloth.c b/source/blender/makesrna/intern/rna_cloth.c
index 3ad901e5397..e45a1a3cc33 100644
--- a/source/blender/makesrna/intern/rna_cloth.c
+++ b/source/blender/makesrna/intern/rna_cloth.c
@@ -436,10 +436,10 @@ static void rna_ClothSettings_gravity_set(PointerRNA *ptr, const float *values)
sim->gravity[2] = values[2];
}
-static char *rna_ClothSettings_path(PointerRNA *ptr)
+static char *rna_ClothSettings_path(const PointerRNA *ptr)
{
- Object *ob = (Object *)ptr->owner_id;
- ModifierData *md = BKE_modifiers_findby_type(ob, eModifierType_Cloth);
+ const Object *ob = (Object *)ptr->owner_id;
+ const ModifierData *md = BKE_modifiers_findby_type(ob, eModifierType_Cloth);
if (md) {
char name_esc[sizeof(md->name) * 2];
@@ -451,10 +451,10 @@ static char *rna_ClothSettings_path(PointerRNA *ptr)
}
}
-static char *rna_ClothCollisionSettings_path(PointerRNA *ptr)
+static char *rna_ClothCollisionSettings_path(const PointerRNA *ptr)
{
- Object *ob = (Object *)ptr->owner_id;
- ModifierData *md = BKE_modifiers_findby_type(ob, eModifierType_Cloth);
+ const Object *ob = (Object *)ptr->owner_id;
+ const ModifierData *md = BKE_modifiers_findby_type(ob, eModifierType_Cloth);
if (md) {
char name_esc[sizeof(md->name) * 2];
diff --git a/source/blender/makesrna/intern/rna_color.c b/source/blender/makesrna/intern/rna_color.c
index 840674c7bc6..92cdcc6d781 100644
--- a/source/blender/makesrna/intern/rna_color.c
+++ b/source/blender/makesrna/intern/rna_color.c
@@ -157,7 +157,7 @@ static void rna_CurveMapping_clipmaxy_range(
*max = 100.0f;
}
-static char *rna_ColorRamp_path(PointerRNA *ptr)
+static char *rna_ColorRamp_path(const PointerRNA *ptr)
{
char *path = NULL;
@@ -208,7 +208,7 @@ static char *rna_ColorRamp_path(PointerRNA *ptr)
return path;
}
-static char *rna_ColorRampElement_path(PointerRNA *ptr)
+static char *rna_ColorRampElement_path(const PointerRNA *ptr)
{
PointerRNA ramp_ptr;
PropertyRNA *prop;
@@ -438,7 +438,7 @@ static void rna_ColorManagedDisplaySettings_display_device_update(Main *bmain,
}
}
-static char *rna_ColorManagedDisplaySettings_path(PointerRNA *UNUSED(ptr))
+static char *rna_ColorManagedDisplaySettings_path(const PointerRNA *UNUSED(ptr))
{
return BLI_strdup("display_settings");
}
@@ -526,7 +526,7 @@ static void rna_ColorManagedViewSettings_use_curves_set(PointerRNA *ptr, bool va
}
}
-static char *rna_ColorManagedViewSettings_path(PointerRNA *UNUSED(ptr))
+static char *rna_ColorManagedViewSettings_path(const PointerRNA *UNUSED(ptr))
{
return BLI_strdup("view_settings");
}
@@ -662,12 +662,12 @@ static void rna_ColorManagedColorspaceSettings_reload_update(Main *bmain,
}
}
-static char *rna_ColorManagedSequencerColorspaceSettings_path(PointerRNA *UNUSED(ptr))
+static char *rna_ColorManagedSequencerColorspaceSettings_path(const PointerRNA *UNUSED(ptr))
{
return BLI_strdup("sequencer_colorspace_settings");
}
-static char *rna_ColorManagedInputColorspaceSettings_path(PointerRNA *UNUSED(ptr))
+static char *rna_ColorManagedInputColorspaceSettings_path(const PointerRNA *UNUSED(ptr))
{
return BLI_strdup("colorspace_settings");
}
diff --git a/source/blender/makesrna/intern/rna_constraint.c b/source/blender/makesrna/intern/rna_constraint.c
index 63d8876ec8b..1420ef36493 100644
--- a/source/blender/makesrna/intern/rna_constraint.c
+++ b/source/blender/makesrna/intern/rna_constraint.c
@@ -29,11 +29,12 @@
/* please keep the names in sync with constraint.c */
const EnumPropertyItem rna_enum_constraint_type_items[] = {
- {0, "", 0, N_("Motion Tracking"), ""},
+ RNA_ENUM_ITEM_HEADING(N_("Motion Tracking"), NULL),
{CONSTRAINT_TYPE_CAMERASOLVER, "CAMERA_SOLVER", ICON_CON_CAMERASOLVER, "Camera Solver", ""},
{CONSTRAINT_TYPE_FOLLOWTRACK, "FOLLOW_TRACK", ICON_CON_FOLLOWTRACK, "Follow Track", ""},
{CONSTRAINT_TYPE_OBJECTSOLVER, "OBJECT_SOLVER", ICON_CON_OBJECTSOLVER, "Object Solver", ""},
- {0, "", 0, N_("Transform"), ""},
+
+ RNA_ENUM_ITEM_HEADING(N_("Transform"), NULL),
{CONSTRAINT_TYPE_LOCLIKE,
"COPY_LOCATION",
ICON_CON_LOCLIKE,
@@ -91,7 +92,8 @@ const EnumPropertyItem rna_enum_constraint_type_items[] = {
ICON_CON_TRANSFORM_CACHE,
"Transform Cache",
"Look up the transformation matrix from an external file"},
- {0, "", 0, N_("Tracking"), ""},
+
+ RNA_ENUM_ITEM_HEADING(N_("Tracking"), NULL),
{CONSTRAINT_TYPE_CLAMPTO,
"CLAMP_TO",
ICON_CON_CLAMPTO,
@@ -127,7 +129,8 @@ const EnumPropertyItem rna_enum_constraint_type_items[] = {
ICON_CON_TRACKTO,
"Track To",
"Legacy tracking constraint prone to twisting artifacts"},
- {0, "", 0, N_("Relationship"), ""},
+
+ RNA_ENUM_ITEM_HEADING(N_("Relationship"), NULL),
{CONSTRAINT_TYPE_ACTION,
"ACTION",
ICON_ACTION,
@@ -192,7 +195,7 @@ static const EnumPropertyItem target_space_pchan_items[] = {
"Custom Space",
"The transformation of the target is evaluated relative to a custom object/bone/vertex "
"group"},
- {0, "", 0, NULL, NULL},
+ RNA_ENUM_ITEM_SEPR,
{CONSTRAINT_SPACE_POSE,
"POSE",
0,
@@ -233,7 +236,7 @@ static const EnumPropertyItem owner_space_pchan_items[] = {
0,
"Custom Space",
"The constraint is applied in local space of a custom object/bone/vertex group"},
- {0, "", 0, NULL, NULL},
+ RNA_ENUM_ITEM_SEPR,
{CONSTRAINT_SPACE_POSE,
"POSE",
0,
@@ -440,7 +443,7 @@ static char *rna_Constraint_do_compute_path(Object *ob, bConstraint *con)
}
}
-static char *rna_Constraint_path(PointerRNA *ptr)
+static char *rna_Constraint_path(const PointerRNA *ptr)
{
Object *ob = (Object *)ptr->owner_id;
bConstraint *con = ptr->data;
@@ -448,7 +451,7 @@ static char *rna_Constraint_path(PointerRNA *ptr)
return rna_Constraint_do_compute_path(ob, con);
}
-static bConstraint *rna_constraint_from_target(PointerRNA *ptr)
+static bConstraint *rna_constraint_from_target(const PointerRNA *ptr)
{
Object *ob = (Object *)ptr->owner_id;
bConstraintTarget *tgt = ptr->data;
@@ -456,7 +459,7 @@ static bConstraint *rna_constraint_from_target(PointerRNA *ptr)
return BKE_constraint_find_from_target(ob, tgt, NULL);
}
-static char *rna_ConstraintTarget_path(PointerRNA *ptr)
+static char *rna_ConstraintTarget_path(const PointerRNA *ptr)
{
Object *ob = (Object *)ptr->owner_id;
bConstraintTarget *tgt = ptr->data;
@@ -595,22 +598,17 @@ static const EnumPropertyItem *rna_Constraint_target_space_itemf(bContext *UNUSE
bool *UNUSED(r_free))
{
bConstraint *con = (bConstraint *)ptr->data;
- const bConstraintTypeInfo *cti = BKE_constraint_typeinfo_get(con);
ListBase targets = {NULL, NULL};
bConstraintTarget *ct;
- if (cti && cti->get_constraint_targets) {
- cti->get_constraint_targets(con, &targets);
-
+ if (BKE_constraint_targets_get(con, &targets)) {
for (ct = targets.first; ct; ct = ct->next) {
if (ct->tar && ct->tar->type == OB_ARMATURE) {
break;
}
}
- if (cti->flush_constraint_targets) {
- cti->flush_constraint_targets(con, &targets, 1);
- }
+ BKE_constraint_targets_flush(con, &targets, 1);
if (ct) {
return target_space_pchan_items;
@@ -691,11 +689,11 @@ static void rna_ActionConstraint_minmax_range(
}
}
-static int rna_SplineIKConstraint_joint_bindings_get_length(PointerRNA *ptr,
+static int rna_SplineIKConstraint_joint_bindings_get_length(const PointerRNA *ptr,
int length[RNA_MAX_ARRAY_DIMENSION])
{
- bConstraint *con = (bConstraint *)ptr->data;
- bSplineIKConstraint *ikData = (bSplineIKConstraint *)con->data;
+ const bConstraint *con = (bConstraint *)ptr->data;
+ const bSplineIKConstraint *ikData = (bSplineIKConstraint *)con->data;
if (ikData) {
length[0] = ikData->numpoints;
@@ -1623,7 +1621,7 @@ static void rna_def_constraint_transform_like(BlenderRNA *brna)
0,
"Replace",
"Replace the original transformation with copied"},
- {0, "", 0, NULL, NULL},
+ RNA_ENUM_ITEM_SEPR,
{TRANSLIKE_MIX_BEFORE_FULL,
"BEFORE_FULL",
0,
@@ -1644,7 +1642,7 @@ static void rna_def_constraint_transform_like(BlenderRNA *brna)
"Before Original (Split Channels)",
"Apply copied transformation before original, handling location, rotation and scale "
"separately, similar to a sequence of three Copy constraints"},
- {0, "", 0, NULL, NULL},
+ RNA_ENUM_ITEM_SEPR,
{TRANSLIKE_MIX_AFTER_FULL,
"AFTER_FULL",
0,
@@ -1782,7 +1780,7 @@ static void rna_def_constraint_action(BlenderRNA *brna)
"Before Original (Split Channels)",
"Apply the action channels before the original transformation, handling location, rotation "
"and scale separately"},
- {0, "", 0, NULL, NULL},
+ RNA_ENUM_ITEM_SEPR,
{ACTCON_MIX_AFTER_FULL,
"AFTER_FULL",
0,
diff --git a/source/blender/makesrna/intern/rna_curve.c b/source/blender/makesrna/intern/rna_curve.c
index fb911725836..fff3f479a3f 100644
--- a/source/blender/makesrna/intern/rna_curve.c
+++ b/source/blender/makesrna/intern/rna_curve.c
@@ -66,8 +66,8 @@ const EnumPropertyItem rna_enum_keyframe_handle_type_items[] = {
* Changes here will likely apply there too.
*/
const EnumPropertyItem rna_enum_beztriple_interpolation_mode_items[] = {
- /* interpolation */
- {0, "", 0, N_("Interpolation"), "Standard transitions between keyframes"},
+ /* Interpolation. */
+ RNA_ENUM_ITEM_HEADING(N_("Interpolation"), "Standard transitions between keyframes"),
{BEZT_IPO_CONST,
"CONSTANT",
ICON_IPO_CONSTANT,
@@ -84,13 +84,10 @@ const EnumPropertyItem rna_enum_beztriple_interpolation_mode_items[] = {
"Bezier",
"Smooth interpolation between A and B, with some control over curve shape"},
- /* easing */
- {0,
- "",
- 0,
- N_("Easing (by strength)"),
- "Predefined inertial transitions, useful for motion graphics (from least to most "
- "''dramatic'')"},
+ /* Easing. */
+ RNA_ENUM_ITEM_HEADING(N_("Easing (by strength)"),
+ "Predefined inertial transitions, useful for motion graphics "
+ "(from least to most \"dramatic\")"),
{BEZT_IPO_SINE,
"SINE",
ICON_IPO_SINE,
@@ -107,7 +104,7 @@ const EnumPropertyItem rna_enum_beztriple_interpolation_mode_items[] = {
"Circular",
"Circular easing (strongest and most dynamic)"},
- {0, "", 0, N_("Dynamic Effects"), "Simple physics-inspired easing effects"},
+ RNA_ENUM_ITEM_HEADING(N_("Dynamic Effects"), "Simple physics-inspired easing effects"),
{BEZT_IPO_BACK, "BACK", ICON_IPO_BACK, "Back", "Cubic easing with overshoot and settle"},
{BEZT_IPO_BOUNCE,
"BOUNCE",
@@ -770,7 +767,7 @@ static void rna_Curve_active_spline_set(PointerRNA *ptr,
}
}
-static char *rna_Curve_spline_path(PointerRNA *ptr)
+static char *rna_Curve_spline_path(const PointerRNA *ptr)
{
Curve *cu = (Curve *)ptr->owner_id;
ListBase *nubase = BKE_curve_nurbs_get(cu);
@@ -786,7 +783,7 @@ static char *rna_Curve_spline_path(PointerRNA *ptr)
}
/* use for both bezier and nurbs */
-static char *rna_Curve_spline_point_path(PointerRNA *ptr)
+static char *rna_Curve_spline_point_path(const PointerRNA *ptr)
{
Curve *cu = (Curve *)ptr->owner_id;
Nurb *nu;
@@ -808,10 +805,10 @@ static char *rna_Curve_spline_point_path(PointerRNA *ptr)
}
}
-static char *rna_TextBox_path(PointerRNA *ptr)
+static char *rna_TextBox_path(const PointerRNA *ptr)
{
- Curve *cu = (Curve *)ptr->owner_id;
- TextBox *tb = ptr->data;
+ const Curve *cu = (Curve *)ptr->owner_id;
+ const TextBox *tb = ptr->data;
int index = (int)(tb - cu->tb);
if (index >= 0 && index < cu->totbox) {
diff --git a/source/blender/makesrna/intern/rna_curves.c b/source/blender/makesrna/intern/rna_curves.c
index 2dc568d0b8a..bc3e5203ed0 100644
--- a/source/blender/makesrna/intern/rna_curves.c
+++ b/source/blender/makesrna/intern/rna_curves.c
@@ -18,6 +18,14 @@
#include "WM_types.h"
+const EnumPropertyItem rna_enum_curves_types[] = {
+ {CURVE_TYPE_CATMULL_ROM, "CATMULL_ROM", 0, "Catmull Rom", ""},
+ {CURVE_TYPE_POLY, "POLY", 0, "Poly", ""},
+ {CURVE_TYPE_BEZIER, "BEZIER", 0, "Bezier", ""},
+ {CURVE_TYPE_NURBS, "NURBS", 0, "NURBS", ""},
+ {0, NULL, 0, NULL, NULL},
+};
+
#ifdef RNA_RUNTIME
# include "BLI_math_vector.h"
@@ -30,7 +38,7 @@
# include "WM_api.h"
# include "WM_types.h"
-static Curves *rna_curves(PointerRNA *ptr)
+static Curves *rna_curves(const PointerRNA *ptr)
{
return (Curves *)ptr->owner_id;
}
@@ -38,7 +46,7 @@ static Curves *rna_curves(PointerRNA *ptr)
static int rna_Curves_curve_offset_data_length(PointerRNA *ptr)
{
const Curves *curves = rna_curves(ptr);
- return curves->geometry.curve_size + 1;
+ return curves->geometry.curve_num + 1;
}
static void rna_Curves_curve_offset_data_begin(CollectionPropertyIterator *iter, PointerRNA *ptr)
@@ -47,18 +55,23 @@ static void rna_Curves_curve_offset_data_begin(CollectionPropertyIterator *iter,
rna_iterator_array_begin(iter,
(void *)curves->geometry.curve_offsets,
sizeof(int),
- curves->geometry.curve_size + 1,
+ curves->geometry.curve_num + 1,
false,
NULL);
}
-static int rna_CurvePoint_index_get(PointerRNA *ptr)
+static int rna_CurvePoint_index_get_const(const PointerRNA *ptr)
{
const Curves *curves = rna_curves(ptr);
const float(*co)[3] = ptr->data;
return (int)(co - curves->geometry.position);
}
+static int rna_CurvePoint_index_get(PointerRNA *ptr)
+{
+ return rna_CurvePoint_index_get_const(ptr);
+}
+
static void rna_CurvePoint_location_get(PointerRNA *ptr, float value[3])
{
copy_v3_v3(value, (const float *)ptr->data);
@@ -89,20 +102,25 @@ static void rna_CurvePoint_radius_set(PointerRNA *ptr, float value)
curves->geometry.radius[co - curves->geometry.position] = value;
}
-static char *rna_CurvePoint_path(PointerRNA *ptr)
+static char *rna_CurvePoint_path(const PointerRNA *ptr)
{
- return BLI_sprintfN("points[%d]", rna_CurvePoint_index_get(ptr));
+ return BLI_sprintfN("points[%d]", rna_CurvePoint_index_get_const(ptr));
}
-static int rna_CurveSlice_index_get(PointerRNA *ptr)
+static int rna_CurveSlice_index_get_const(const PointerRNA *ptr)
{
Curves *curves = rna_curves(ptr);
return (int)((int *)ptr->data - curves->geometry.curve_offsets);
}
-static char *rna_CurveSlice_path(PointerRNA *ptr)
+static int rna_CurveSlice_index_get(PointerRNA *ptr)
+{
+ return rna_CurveSlice_index_get_const(ptr);
+}
+
+static char *rna_CurveSlice_path(const PointerRNA *ptr)
{
- return BLI_sprintfN("curves[%d]", rna_CurveSlice_index_get(ptr));
+ return BLI_sprintfN("curves[%d]", rna_CurveSlice_index_get_const(ptr));
}
static void rna_CurveSlice_points_begin(CollectionPropertyIterator *iter, PointerRNA *ptr)
@@ -133,14 +151,22 @@ static void rna_Curves_update_data(struct Main *UNUSED(bmain),
PointerRNA *ptr)
{
ID *id = ptr->owner_id;
-
- /* cheating way for importers to avoid slow updates */
+ /* Avoid updates for importers creating curves. */
if (id->us > 0) {
DEG_id_tag_update(id, 0);
WM_main_add_notifier(NC_GEOM | ND_DATA, id);
}
}
+void rna_Curves_update_draw(Main *UNUSED(bmain), Scene *UNUSED(scene), PointerRNA *ptr)
+{
+ ID *id = ptr->owner_id;
+ /* Avoid updates for importers creating curves. */
+ if (id->us > 0) {
+ WM_main_add_notifier(NC_GEOM | ND_DATA, id);
+ }
+}
+
#else
static void rna_def_curves_point(BlenderRNA *brna)
@@ -222,7 +248,7 @@ static void rna_def_curves(BlenderRNA *brna)
/* Point and Curve RNA API helpers. */
prop = RNA_def_property(srna, "curves", PROP_COLLECTION, PROP_NONE);
- RNA_def_property_collection_sdna(prop, NULL, "geometry.curve_offsets", "geometry.curve_size");
+ RNA_def_property_collection_sdna(prop, NULL, "geometry.curve_offsets", "geometry.curve_num");
RNA_def_property_struct_type(prop, "CurveSlice");
RNA_def_property_ui_text(prop, "Curves", "All curves in the data-block");
@@ -230,7 +256,7 @@ static void rna_def_curves(BlenderRNA *brna)
RNA_define_verify_sdna(0);
prop = RNA_def_property(srna, "points", PROP_COLLECTION, PROP_NONE);
- RNA_def_property_collection_sdna(prop, NULL, "geometry.position", "geometry.point_size");
+ RNA_def_property_collection_sdna(prop, NULL, "geometry.position", "geometry.point_num");
RNA_def_property_struct_type(prop, "CurvePoint");
RNA_def_property_ui_text(prop, "Points", "Control points of all curves");
RNA_define_verify_sdna(1);
@@ -239,7 +265,7 @@ static void rna_def_curves(BlenderRNA *brna)
RNA_define_verify_sdna(0);
prop = RNA_def_property(srna, "position_data", PROP_COLLECTION, PROP_NONE);
- RNA_def_property_collection_sdna(prop, NULL, "geometry.position", "geometry.point_size");
+ RNA_def_property_collection_sdna(prop, NULL, "geometry.position", "geometry.point_num");
RNA_def_property_struct_type(prop, "FloatVectorAttributeValue");
RNA_def_property_update(prop, 0, "rna_Curves_update_data");
RNA_define_verify_sdna(1);
@@ -274,21 +300,41 @@ static void rna_def_curves(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "Surface", "Mesh object that the curves can be attached to");
RNA_def_property_update(prop, NC_OBJECT | ND_DRAW, NULL);
+ prop = RNA_def_property(srna, "surface_uv_map", PROP_STRING, PROP_NONE);
+ RNA_def_property_string_sdna(prop, NULL, "surface_uv_map");
+ RNA_def_property_ui_text(prop,
+ "Surface UV Map",
+ "The name of the attribute on the surface mesh used to define the "
+ "attachment of each curve");
+ RNA_def_property_update(prop, 0, "rna_Curves_update_draw");
+
/* Symmetry. */
prop = RNA_def_property(srna, "use_mirror_x", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "symmetry", CURVES_SYMMETRY_X);
RNA_def_property_ui_text(prop, "X", "Enable symmetry in the X axis");
- RNA_def_property_update(prop, 0, "rna_Mesh_update_draw");
+ RNA_def_property_update(prop, 0, "rna_Curves_update_draw");
prop = RNA_def_property(srna, "use_mirror_y", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "symmetry", CURVES_SYMMETRY_Y);
RNA_def_property_ui_text(prop, "Y", "Enable symmetry in the Y axis");
- RNA_def_property_update(prop, 0, "rna_Mesh_update_draw");
+ RNA_def_property_update(prop, 0, "rna_Curves_update_draw");
prop = RNA_def_property(srna, "use_mirror_z", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "symmetry", CURVES_SYMMETRY_Z);
RNA_def_property_ui_text(prop, "Z", "Enable symmetry in the Z axis");
- RNA_def_property_update(prop, 0, "rna_Mesh_update_draw");
+ RNA_def_property_update(prop, 0, "rna_Curves_update_draw");
+
+ prop = RNA_def_property(srna, "selection_domain", PROP_ENUM, PROP_NONE);
+ RNA_def_property_enum_items(prop, rna_enum_attribute_curves_domain_items);
+ RNA_def_property_ui_text(prop, "Selection Domain", "");
+ RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
+ RNA_def_property_update(prop, 0, "rna_Curves_update_data");
+
+ prop = RNA_def_property(srna, "use_sculpt_selection", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "flag", CV_SCULPT_SELECTION_ENABLED);
+ RNA_def_property_ui_text(prop, "Use Sculpt Selection", "");
+ RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
+ RNA_def_property_update(prop, 0, "rna_Curves_update_draw");
/* attributes */
rna_def_attributes_common(srna);
diff --git a/source/blender/makesrna/intern/rna_define.c b/source/blender/makesrna/intern/rna_define.c
index 8e2b9c1d937..9d26797aa88 100644
--- a/source/blender/makesrna/intern/rna_define.c
+++ b/source/blender/makesrna/intern/rna_define.c
@@ -208,7 +208,7 @@ static int DNA_struct_find_nr_wrapper(const struct SDNA *sdna, const char *struc
struct_name = DNA_struct_rename_legacy_hack_static_from_alias(struct_name);
#ifdef RNA_RUNTIME
/* We may support this at some point but for now we don't. */
- BLI_assert(0);
+ BLI_assert_unreachable();
#else
struct_name = BLI_ghash_lookup_default(
g_version_data.struct_map_static_from_alias, struct_name, (void *)struct_name);
@@ -3316,6 +3316,33 @@ void RNA_def_property_string_funcs(PropertyRNA *prop,
}
}
+void RNA_def_property_string_search_func(PropertyRNA *prop,
+ const char *search,
+ const eStringPropertySearchFlag search_flag)
+{
+ StructRNA *srna = DefRNA.laststruct;
+
+ if (!DefRNA.preprocess) {
+ CLOG_ERROR(&LOG, "only during preprocessing.");
+ return;
+ }
+
+ switch (prop->type) {
+ case PROP_STRING: {
+ StringPropertyRNA *sprop = (StringPropertyRNA *)prop;
+ sprop->search = (StringPropertySearchFunc)search;
+ if (search != NULL) {
+ sprop->search_flag = search_flag | PROP_STRING_SEARCH_SUPPORTED;
+ }
+ break;
+ }
+ default:
+ CLOG_ERROR(&LOG, "\"%s.%s\", type is not string.", srna->identifier, prop->identifier);
+ DefRNA.error = true;
+ break;
+ }
+}
+
void RNA_def_property_string_funcs_runtime(PropertyRNA *prop,
StringPropertyGetFunc getfunc,
StringPropertyLengthFunc lengthfunc,
@@ -3343,6 +3370,18 @@ void RNA_def_property_string_funcs_runtime(PropertyRNA *prop,
}
}
+void RNA_def_property_string_search_func_runtime(PropertyRNA *prop,
+ StringPropertySearchFunc search_fn,
+ const eStringPropertySearchFlag search_flag)
+{
+ StringPropertyRNA *sprop = (StringPropertyRNA *)prop;
+
+ sprop->search = search_fn;
+ if (search_fn != NULL) {
+ sprop->search_flag = search_flag | PROP_STRING_SEARCH_SUPPORTED;
+ }
+}
+
void RNA_def_property_pointer_funcs(
PropertyRNA *prop, const char *get, const char *set, const char *type_fn, const char *poll)
{
@@ -4409,7 +4448,7 @@ void RNA_enum_item_add(EnumPropertyItem **items, int *totitem, const EnumPropert
void RNA_enum_item_add_separator(EnumPropertyItem **items, int *totitem)
{
- static const EnumPropertyItem sepr = {0, "", 0, NULL, NULL};
+ static const EnumPropertyItem sepr = RNA_ENUM_ITEM_SEPR;
RNA_enum_item_add(items, totitem, &sepr);
}
diff --git a/source/blender/makesrna/intern/rna_dynamicpaint.c b/source/blender/makesrna/intern/rna_dynamicpaint.c
index ed6d4996c1e..6f9fe3741f7 100644
--- a/source/blender/makesrna/intern/rna_dynamicpaint.c
+++ b/source/blender/makesrna/intern/rna_dynamicpaint.c
@@ -37,30 +37,30 @@ const EnumPropertyItem rna_enum_prop_dynamicpaint_type_items[] = {
# include "DEG_depsgraph.h"
# include "DEG_depsgraph_build.h"
-static char *rna_DynamicPaintCanvasSettings_path(PointerRNA *ptr)
+static char *rna_DynamicPaintCanvasSettings_path(const PointerRNA *ptr)
{
- DynamicPaintCanvasSettings *settings = (DynamicPaintCanvasSettings *)ptr->data;
- ModifierData *md = (ModifierData *)settings->pmd;
+ const DynamicPaintCanvasSettings *settings = (DynamicPaintCanvasSettings *)ptr->data;
+ const ModifierData *md = (ModifierData *)settings->pmd;
char name_esc[sizeof(md->name) * 2];
BLI_str_escape(name_esc, md->name, sizeof(name_esc));
return BLI_sprintfN("modifiers[\"%s\"].canvas_settings", name_esc);
}
-static char *rna_DynamicPaintBrushSettings_path(PointerRNA *ptr)
+static char *rna_DynamicPaintBrushSettings_path(const PointerRNA *ptr)
{
- DynamicPaintBrushSettings *settings = (DynamicPaintBrushSettings *)ptr->data;
- ModifierData *md = (ModifierData *)settings->pmd;
+ const DynamicPaintBrushSettings *settings = (DynamicPaintBrushSettings *)ptr->data;
+ const ModifierData *md = (ModifierData *)settings->pmd;
char name_esc[sizeof(md->name) * 2];
BLI_str_escape(name_esc, md->name, sizeof(name_esc));
return BLI_sprintfN("modifiers[\"%s\"].brush_settings", name_esc);
}
-static char *rna_DynamicPaintSurface_path(PointerRNA *ptr)
+static char *rna_DynamicPaintSurface_path(const PointerRNA *ptr)
{
- DynamicPaintSurface *surface = (DynamicPaintSurface *)ptr->data;
- ModifierData *md = (ModifierData *)surface->canvas->pmd;
+ const DynamicPaintSurface *surface = (DynamicPaintSurface *)ptr->data;
+ const ModifierData *md = (ModifierData *)surface->canvas->pmd;
char name_esc[sizeof(md->name) * 2];
char name_esc_surface[sizeof(surface->name) * 2];
diff --git a/source/blender/makesrna/intern/rna_fcurve.c b/source/blender/makesrna/intern/rna_fcurve.c
index af14a169d68..ac8aebd2fdd 100644
--- a/source/blender/makesrna/intern/rna_fcurve.c
+++ b/source/blender/makesrna/intern/rna_fcurve.c
@@ -786,11 +786,11 @@ static void rna_FModifier_active_update(Main *bmain, Scene *scene, PointerRNA *p
rna_FModifier_update(bmain, scene, ptr);
}
-static int rna_FModifierGenerator_coefficients_get_length(PointerRNA *ptr,
+static int rna_FModifierGenerator_coefficients_get_length(const PointerRNA *ptr,
int length[RNA_MAX_ARRAY_DIMENSION])
{
- FModifier *fcm = (FModifier *)ptr->data;
- FMod_Generator *gen = fcm->data;
+ const FModifier *fcm = (FModifier *)ptr->data;
+ const FMod_Generator *gen = fcm->data;
if (gen) {
length[0] = gen->arraysize;
@@ -1776,12 +1776,12 @@ static void rna_def_drivertarget(BlenderRNA *brna)
{DTAR_TRANSCHAN_LOCX, "LOC_X", 0, "X Location", ""},
{DTAR_TRANSCHAN_LOCY, "LOC_Y", 0, "Y Location", ""},
{DTAR_TRANSCHAN_LOCZ, "LOC_Z", 0, "Z Location", ""},
- {0, "", 0, NULL, NULL},
+ RNA_ENUM_ITEM_SEPR,
{DTAR_TRANSCHAN_ROTX, "ROT_X", 0, "X Rotation", ""},
{DTAR_TRANSCHAN_ROTY, "ROT_Y", 0, "Y Rotation", ""},
{DTAR_TRANSCHAN_ROTZ, "ROT_Z", 0, "Z Rotation", ""},
{DTAR_TRANSCHAN_ROTW, "ROT_W", 0, "W Rotation", ""},
- {0, "", 0, NULL, NULL},
+ RNA_ENUM_ITEM_SEPR,
{DTAR_TRANSCHAN_SCALEX, "SCALE_X", 0, "X Scale", ""},
{DTAR_TRANSCHAN_SCALEY, "SCALE_Y", 0, "Y Scale", ""},
{DTAR_TRANSCHAN_SCALEZ, "SCALE_Z", 0, "Z Scale", ""},
diff --git a/source/blender/makesrna/intern/rna_fluid.c b/source/blender/makesrna/intern/rna_fluid.c
index e0ec146a248..3b22ae9d40f 100644
--- a/source/blender/makesrna/intern/rna_fluid.c
+++ b/source/blender/makesrna/intern/rna_fluid.c
@@ -857,30 +857,30 @@ static void rna_Fluid_domaintype_set(struct PointerRNA *ptr, int value)
BKE_fluid_fields_sanitize(settings);
}
-static char *rna_FluidDomainSettings_path(PointerRNA *ptr)
+static char *rna_FluidDomainSettings_path(const PointerRNA *ptr)
{
- FluidDomainSettings *settings = (FluidDomainSettings *)ptr->data;
- ModifierData *md = (ModifierData *)settings->fmd;
+ const FluidDomainSettings *settings = (FluidDomainSettings *)ptr->data;
+ const ModifierData *md = (ModifierData *)settings->fmd;
char name_esc[sizeof(md->name) * 2];
BLI_str_escape(name_esc, md->name, sizeof(name_esc));
return BLI_sprintfN("modifiers[\"%s\"].domain_settings", name_esc);
}
-static char *rna_FluidFlowSettings_path(PointerRNA *ptr)
+static char *rna_FluidFlowSettings_path(const PointerRNA *ptr)
{
- FluidFlowSettings *settings = (FluidFlowSettings *)ptr->data;
- ModifierData *md = (ModifierData *)settings->fmd;
+ const FluidFlowSettings *settings = (FluidFlowSettings *)ptr->data;
+ const ModifierData *md = (ModifierData *)settings->fmd;
char name_esc[sizeof(md->name) * 2];
BLI_str_escape(name_esc, md->name, sizeof(name_esc));
return BLI_sprintfN("modifiers[\"%s\"].flow_settings", name_esc);
}
-static char *rna_FluidEffectorSettings_path(PointerRNA *ptr)
+static char *rna_FluidEffectorSettings_path(const PointerRNA *ptr)
{
- FluidEffectorSettings *settings = (FluidEffectorSettings *)ptr->data;
- ModifierData *md = (ModifierData *)settings->fmd;
+ const FluidEffectorSettings *settings = (FluidEffectorSettings *)ptr->data;
+ const ModifierData *md = (ModifierData *)settings->fmd;
char name_esc[sizeof(md->name) * 2];
BLI_str_escape(name_esc, md->name, sizeof(name_esc));
@@ -893,9 +893,10 @@ static char *rna_FluidEffectorSettings_path(PointerRNA *ptr)
# ifdef WITH_FLUID
-static int rna_FluidModifier_grid_get_length(PointerRNA *ptr, int length[RNA_MAX_ARRAY_DIMENSION])
+static int rna_FluidModifier_grid_get_length(const PointerRNA *ptr,
+ int length[RNA_MAX_ARRAY_DIMENSION])
{
- FluidDomainSettings *fds = (FluidDomainSettings *)ptr->data;
+ const FluidDomainSettings *fds = (FluidDomainSettings *)ptr->data;
float *density = NULL;
int size = 0;
@@ -918,7 +919,7 @@ static int rna_FluidModifier_grid_get_length(PointerRNA *ptr, int length[RNA_MAX
return length[0];
}
-static int rna_FluidModifier_color_grid_get_length(PointerRNA *ptr,
+static int rna_FluidModifier_color_grid_get_length(const PointerRNA *ptr,
int length[RNA_MAX_ARRAY_DIMENSION])
{
rna_FluidModifier_grid_get_length(ptr, length);
@@ -927,10 +928,10 @@ static int rna_FluidModifier_color_grid_get_length(PointerRNA *ptr,
return length[0];
}
-static int rna_FluidModifier_velocity_grid_get_length(PointerRNA *ptr,
+static int rna_FluidModifier_velocity_grid_get_length(const PointerRNA *ptr,
int length[RNA_MAX_ARRAY_DIMENSION])
{
- FluidDomainSettings *fds = (FluidDomainSettings *)ptr->data;
+ const FluidDomainSettings *fds = (FluidDomainSettings *)ptr->data;
float *vx = NULL;
float *vy = NULL;
float *vz = NULL;
@@ -948,10 +949,10 @@ static int rna_FluidModifier_velocity_grid_get_length(PointerRNA *ptr,
return length[0];
}
-static int rna_FluidModifier_heat_grid_get_length(PointerRNA *ptr,
+static int rna_FluidModifier_heat_grid_get_length(const PointerRNA *ptr,
int length[RNA_MAX_ARRAY_DIMENSION])
{
- FluidDomainSettings *fds = (FluidDomainSettings *)ptr->data;
+ const FluidDomainSettings *fds = (FluidDomainSettings *)ptr->data;
float *heat = NULL;
int size = 0;
diff --git a/source/blender/makesrna/intern/rna_gpencil.c b/source/blender/makesrna/intern/rna_gpencil.c
index 9a9b6d582e5..6854ce37c94 100644
--- a/source/blender/makesrna/intern/rna_gpencil.c
+++ b/source/blender/makesrna/intern/rna_gpencil.c
@@ -307,7 +307,7 @@ bool rna_GPencil_datablocks_obdata_poll(PointerRNA *UNUSED(ptr), const PointerRN
return (gpd->flag & GP_DATA_ANNOTATIONS) == 0;
}
-static char *rna_GPencilLayer_path(PointerRNA *ptr)
+static char *rna_GPencilLayer_path(const PointerRNA *ptr)
{
bGPDlayer *gpl = (bGPDlayer *)ptr->data;
char name_esc[sizeof(gpl->info) * 2];
@@ -407,7 +407,7 @@ static void rna_GPencilLayer_parent_bone_set(PointerRNA *ptr, const char *value)
}
}
-static char *rna_GPencilLayerMask_path(PointerRNA *ptr)
+static char *rna_GPencilLayerMask_path(const PointerRNA *ptr)
{
bGPdata *gpd = (bGPdata *)ptr->owner_id;
bGPDlayer *gpl = BKE_gpencil_layer_active_get(gpd);
@@ -1122,7 +1122,7 @@ static void rna_GPencil_clear(bGPdata *gpd)
WM_main_add_notifier(NC_GPENCIL | ND_DATA | NA_EDITED, NULL);
}
-static char *rna_GreasePencilGrid_path(PointerRNA *UNUSED(ptr))
+static char *rna_GreasePencilGrid_path(const PointerRNA *UNUSED(ptr))
{
return BLI_strdup("grid");
}
diff --git a/source/blender/makesrna/intern/rna_gpencil_modifier.c b/source/blender/makesrna/intern/rna_gpencil_modifier.c
index 08986afe15e..47bed955b54 100644
--- a/source/blender/makesrna/intern/rna_gpencil_modifier.c
+++ b/source/blender/makesrna/intern/rna_gpencil_modifier.c
@@ -46,7 +46,7 @@
#include "WM_types.h"
const EnumPropertyItem rna_enum_object_greasepencil_modifier_type_items[] = {
- {0, "", 0, N_("Modify"), ""},
+ RNA_ENUM_ITEM_HEADING(N_("Modify"), NULL),
{eGpencilModifierType_Texture,
"GP_TEXTURE",
ICON_MOD_UVPROJECT,
@@ -63,7 +63,8 @@ const EnumPropertyItem rna_enum_object_greasepencil_modifier_type_items[] = {
ICON_MOD_VERTEX_WEIGHT,
"Vertex Weight Proximity",
"Generate Vertex Weights base on distance to object"},
- {0, "", 0, N_("Generate"), ""},
+
+ RNA_ENUM_ITEM_HEADING(N_("Generate"), NULL),
{eGpencilModifierType_Array,
"GP_ARRAY",
ICON_MOD_ARRAY,
@@ -114,7 +115,7 @@ const EnumPropertyItem rna_enum_object_greasepencil_modifier_type_items[] = {
ICON_MOD_SUBSURF,
"Subdivide",
"Subdivide stroke adding more control points"},
- {0, "", 0, N_("Deform"), ""},
+ RNA_ENUM_ITEM_HEADING(N_("Deform"), NULL),
{eGpencilModifierType_Armature,
"GP_ARMATURE",
ICON_MOD_ARMATURE,
@@ -147,7 +148,7 @@ const EnumPropertyItem rna_enum_object_greasepencil_modifier_type_items[] = {
ICON_MOD_THICKNESS,
"Thickness",
"Change stroke thickness"},
- {0, "", 0, N_("Color"), ""},
+ RNA_ENUM_ITEM_HEADING(N_("Color"), NULL),
{eGpencilModifierType_Color,
"GP_COLOR",
ICON_MOD_HUE_SATURATION,
@@ -195,6 +196,7 @@ static const EnumPropertyItem rna_enum_time_mode_items[] = {
{GP_TIME_MODE_NORMAL, "NORMAL", 0, "Regular", "Apply offset in usual animation direction"},
{GP_TIME_MODE_REVERSE, "REVERSE", 0, "Reverse", "Apply offset in reverse animation direction"},
{GP_TIME_MODE_FIX, "FIX", 0, "Fixed Frame", "Keep frame and do not change with time"},
+ {GP_TIME_MODE_PINGPONG, "PINGPONG", 0, "Ping Pong", "Loop back and forth"},
{0, NULL, 0, NULL, NULL},
};
@@ -233,8 +235,8 @@ static const EnumPropertyItem gpencil_envelope_mode_items[] = {
{0, NULL, 0, NULL, NULL},
};
static const EnumPropertyItem modifier_noise_random_mode_items[] = {
- {GP_NOISE_RANDOM_STEP, "STEP", 0, "Steps", "Apply random every N steps"},
- {GP_NOISE_RANDOM_KEYFRAME, "KEYFRAME", 0, "On Keyframes", "Apply random every keyframe"},
+ {GP_NOISE_RANDOM_STEP, "STEP", 0, "Steps", "Randomize every number of frames"},
+ {GP_NOISE_RANDOM_KEYFRAME, "KEYFRAME", 0, "Keyframes", "Randomize on keyframes only"},
{0, NULL, 0, NULL, NULL},
};
#endif
@@ -340,9 +342,9 @@ static void rna_GpencilModifier_name_set(PointerRNA *ptr, const char *value)
BKE_animdata_fix_paths_rename_all(NULL, "grease_pencil_modifiers", oldname, gmd->name);
}
-static char *rna_GpencilModifier_path(PointerRNA *ptr)
+static char *rna_GpencilModifier_path(const PointerRNA *ptr)
{
- GpencilModifierData *gmd = ptr->data;
+ const GpencilModifierData *gmd = ptr->data;
char name_esc[sizeof(gmd->name) * 2];
BLI_str_escape(name_esc, gmd->name, sizeof(name_esc));
@@ -751,11 +753,11 @@ static void rna_GpencilDash_segments_begin(CollectionPropertyIterator *iter, Poi
iter, dmd->segments, sizeof(DashGpencilModifierSegment), dmd->segments_len, false, NULL);
}
-static char *rna_DashGpencilModifierSegment_path(PointerRNA *ptr)
+static char *rna_DashGpencilModifierSegment_path(const PointerRNA *ptr)
{
- DashGpencilModifierSegment *ds = (DashGpencilModifierSegment *)ptr->data;
+ const DashGpencilModifierSegment *ds = (DashGpencilModifierSegment *)ptr->data;
- DashGpencilModifierData *dmd = (DashGpencilModifierData *)ds->dmd;
+ const DashGpencilModifierData *dmd = (DashGpencilModifierData *)ds->dmd;
BLI_assert(dmd != NULL);
@@ -929,8 +931,7 @@ static void rna_def_modifier_gpencilnoise(BlenderRNA *brna)
prop = RNA_def_property(srna, "step", PROP_INT, PROP_NONE);
RNA_def_property_int_sdna(prop, NULL, "step");
RNA_def_property_range(prop, 1, 100);
- RNA_def_property_ui_text(
- prop, "Step", "Number of frames before recalculate random values again");
+ RNA_def_property_ui_text(prop, "Step", "Number of frames between randomization steps");
RNA_def_property_update(prop, 0, "rna_GpencilModifier_update");
prop = RNA_def_property(srna, "invert_layers", PROP_BOOLEAN, PROP_NONE);
@@ -967,7 +968,7 @@ static void rna_def_modifier_gpencilnoise(BlenderRNA *brna)
prop = RNA_def_property(srna, "random_mode", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_sdna(prop, NULL, "noise_mode");
RNA_def_property_enum_items(prop, modifier_noise_random_mode_items);
- RNA_def_property_ui_text(prop, "Mode", "How the random changes are applied");
+ RNA_def_property_ui_text(prop, "Mode", "Where to perform randomization");
RNA_def_property_update(prop, 0, "rna_GpencilModifier_update");
RNA_define_lib_overridable(false);
@@ -1278,8 +1279,8 @@ static void rna_def_modifier_gpencilsimplify(BlenderRNA *brna)
/* Sample */
prop = RNA_def_property(srna, "length", PROP_FLOAT, PROP_DISTANCE);
RNA_def_property_float_sdna(prop, NULL, "length");
- RNA_def_property_range(prop, 0, FLT_MAX);
- RNA_def_property_ui_range(prop, 0, 1.0, 0.01, 3);
+ RNA_def_property_range(prop, 0.005, FLT_MAX);
+ RNA_def_property_ui_range(prop, 0, 1.0, 0.05, 3);
RNA_def_property_ui_text(prop, "Length", "Length of each segment");
RNA_def_property_update(prop, 0, "rna_GpencilModifier_update");
@@ -2122,17 +2123,17 @@ static void rna_def_modifier_gpencilbuild(BlenderRNA *brna)
static EnumPropertyItem prop_gpencil_build_mode_items[] = {
{GP_BUILD_MODE_SEQUENTIAL,
"SEQUENTIAL",
- ICON_PARTICLE_POINT,
+ 0,
"Sequential",
"Strokes appear/disappear one after the other, but only a single one changes at a time"},
{GP_BUILD_MODE_CONCURRENT,
"CONCURRENT",
- ICON_PARTICLE_TIP,
+ 0,
"Concurrent",
"Multiple strokes appear/disappear at once"},
{GP_BUILD_MODE_ADDITIVE,
"ADDITIVE",
- ICON_PARTICLE_PATH,
+ 0,
"Additive",
"Builds only new strokes (assuming 'additive' drawing)"},
{0, NULL, 0, NULL, NULL},
diff --git a/source/blender/makesrna/intern/rna_image.c b/source/blender/makesrna/intern/rna_image.c
index 3a93a44e0d1..39f5b6e0e9f 100644
--- a/source/blender/makesrna/intern/rna_image.c
+++ b/source/blender/makesrna/intern/rna_image.c
@@ -175,19 +175,19 @@ static void rna_ImageUser_relations_update(Main *bmain, Scene *scene, PointerRNA
DEG_relations_tag_update(bmain);
}
-static char *rna_ImageUser_path(PointerRNA *ptr)
+static char *rna_ImageUser_path(const PointerRNA *ptr)
{
if (ptr->owner_id) {
/* ImageUser *iuser = ptr->data; */
switch (GS(ptr->owner_id->name)) {
case ID_OB:
- case ID_TE: {
+ case ID_TE:
return BLI_strdup("image_user");
- }
- case ID_NT: {
+ case ID_NT:
return rna_Node_ImageUser_path(ptr);
- }
+ case ID_CA:
+ return rna_CameraBackgroundImage_image_or_movieclip_user_path(ptr);
default:
break;
}
@@ -257,6 +257,51 @@ static void rna_Image_file_format_set(PointerRNA *ptr, int value)
}
}
+static void rna_UDIMTile_size_get(PointerRNA *ptr, int *values)
+{
+ ImageTile *tile = (ImageTile *)ptr->data;
+ Image *image = (Image *)ptr->owner_id;
+
+ ImageUser image_user;
+ BKE_imageuser_default(&image_user);
+ image_user.tile = tile->tile_number;
+
+ void *lock;
+ ImBuf *ibuf = BKE_image_acquire_ibuf(image, &image_user, &lock);
+ if (ibuf) {
+ values[0] = ibuf->x;
+ values[1] = ibuf->y;
+ }
+ else {
+ values[0] = 0;
+ values[1] = 0;
+ }
+
+ BKE_image_release_ibuf(image, ibuf, lock);
+}
+
+static int rna_UDIMTile_channels_get(PointerRNA *ptr)
+{
+ ImageTile *tile = (ImageTile *)ptr->data;
+ Image *image = (Image *)ptr->owner_id;
+
+ ImageUser image_user;
+ BKE_imageuser_default(&image_user);
+ image_user.tile = tile->tile_number;
+
+ int channels = 0;
+
+ void *lock;
+ ImBuf *ibuf = BKE_image_acquire_ibuf(image, &image_user, &lock);
+ if (ibuf) {
+ channels = ibuf->channels;
+ }
+
+ BKE_image_release_ibuf(image, ibuf, lock);
+
+ return channels;
+}
+
static void rna_UDIMTile_label_get(PointerRNA *ptr, char *value)
{
ImageTile *tile = (ImageTile *)ptr->data;
@@ -397,7 +442,7 @@ static void rna_Image_resolution_set(PointerRNA *ptr, const float *values)
static int rna_Image_bindcode_get(PointerRNA *ptr)
{
Image *ima = (Image *)ptr->data;
- GPUTexture *tex = ima->gputexture[TEXTARGET_2D][0][IMA_TEXTURE_RESOLUTION_FULL];
+ GPUTexture *tex = ima->gputexture[TEXTARGET_2D][0];
return (tex) ? GPU_texture_opengl_bindcode(tex) : 0;
}
@@ -446,7 +491,7 @@ static int rna_Image_frame_duration_get(PointerRNA *ptr)
return duration;
}
-static int rna_Image_pixels_get_length(PointerRNA *ptr, int length[RNA_MAX_ARRAY_DIMENSION])
+static int rna_Image_pixels_get_length(const PointerRNA *ptr, int length[RNA_MAX_ARRAY_DIMENSION])
{
Image *ima = (Image *)ptr->owner_id;
ImBuf *ibuf;
@@ -656,6 +701,8 @@ static void rna_def_imageuser(BlenderRNA *brna)
"Parameters defining how an Image data-block is used by another data-block");
RNA_def_struct_path_func(srna, "rna_ImageUser_path");
+ RNA_define_lib_overridable(true);
+
prop = RNA_def_property(srna, "use_auto_refresh", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flag", IMA_ANIM_ALWAYS);
RNA_def_property_ui_text(prop, "Auto Refresh", "Always refresh image on frame changes");
@@ -717,6 +764,8 @@ static void rna_def_imageuser(BlenderRNA *brna)
RNA_def_property_int_sdna(prop, NULL, "tile");
RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
RNA_def_property_ui_text(prop, "Tile", "Tile in tiled image");
+
+ RNA_define_lib_overridable(false);
}
/* image.packed_files */
@@ -737,6 +786,16 @@ static void rna_def_image_packed_files(BlenderRNA *brna)
RNA_def_property_string_sdna(prop, NULL, "filepath");
RNA_def_struct_name_property(srna, prop);
+ prop = RNA_def_property(srna, "view", PROP_INT, PROP_NONE);
+ RNA_def_property_int_sdna(prop, NULL, "view");
+ RNA_def_property_ui_text(prop, "View Index", "");
+ RNA_def_property_clear_flag(prop, PROP_EDITABLE);
+
+ prop = RNA_def_property(srna, "tile_number", PROP_INT, PROP_NONE);
+ RNA_def_property_int_sdna(prop, NULL, "tile_number");
+ RNA_def_property_ui_text(prop, "Tile Number", "");
+ RNA_def_property_clear_flag(prop, PROP_EDITABLE);
+
RNA_api_image_packed_file(srna);
}
@@ -816,6 +875,26 @@ static void rna_def_udim_tile(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "Number", "Number of the position that this tile covers");
RNA_def_property_int_funcs(prop, NULL, "rna_UDIMTile_tile_number_set", NULL);
RNA_def_property_update(prop, NC_IMAGE | ND_DISPLAY, NULL);
+
+ prop = RNA_def_int_vector(
+ srna,
+ "size",
+ 2,
+ NULL,
+ 0,
+ 0,
+ "Size",
+ "Width and height of the tile buffer in pixels, zero when image data can't be loaded",
+ 0,
+ 0);
+ RNA_def_property_subtype(prop, PROP_PIXEL);
+ RNA_def_property_int_funcs(prop, "rna_UDIMTile_size_get", NULL, NULL);
+ RNA_def_property_clear_flag(prop, PROP_EDITABLE);
+
+ prop = RNA_def_property(srna, "channels", PROP_INT, PROP_UNSIGNED);
+ RNA_def_property_int_funcs(prop, "rna_UDIMTile_channels_get", NULL, NULL);
+ RNA_def_property_ui_text(prop, "Channels", "Number of channels in the tile pixels buffer");
+ RNA_def_property_clear_flag(prop, PROP_EDITABLE);
}
static void rna_def_udim_tiles(BlenderRNA *brna, PropertyRNA *cprop)
@@ -1073,22 +1152,31 @@ static void rna_def_image(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "Depth", "Image bit depth");
RNA_def_property_clear_flag(prop, PROP_EDITABLE);
- prop = RNA_def_int_vector(srna,
- "size",
- 2,
- NULL,
- 0,
- 0,
- "Size",
- "Width and height in pixels, zero when image data can't be loaded",
- 0,
- 0);
+ prop = RNA_def_int_vector(
+ srna,
+ "size",
+ 2,
+ NULL,
+ 0,
+ 0,
+ "Size",
+ "Width and height of the image buffer in pixels, zero when image data can't be loaded",
+ 0,
+ 0);
RNA_def_property_subtype(prop, PROP_PIXEL);
RNA_def_property_int_funcs(prop, "rna_Image_size_get", NULL, NULL);
RNA_def_property_clear_flag(prop, PROP_EDITABLE);
- prop = RNA_def_float_vector(
- srna, "resolution", 2, NULL, 0, 0, "Resolution", "X/Y pixels per meter", 0, 0);
+ prop = RNA_def_float_vector(srna,
+ "resolution",
+ 2,
+ NULL,
+ 0,
+ 0,
+ "Resolution",
+ "X/Y pixels per meter, for the image buffer",
+ 0,
+ 0);
RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_LIBRARY);
RNA_def_property_float_funcs(prop, "rna_Image_resolution_get", "rna_Image_resolution_set", NULL);
@@ -1105,7 +1193,7 @@ static void rna_def_image(BlenderRNA *brna)
prop = RNA_def_property(srna, "pixels", PROP_FLOAT, PROP_NONE);
RNA_def_property_flag(prop, PROP_DYNAMIC);
RNA_def_property_multi_array(prop, 1, NULL);
- RNA_def_property_ui_text(prop, "Pixels", "Image pixels in floating-point values");
+ RNA_def_property_ui_text(prop, "Pixels", "Image buffer pixels in floating-point values");
RNA_def_property_dynamic_array_funcs(prop, "rna_Image_pixels_get_length");
RNA_def_property_float_funcs(prop, "rna_Image_pixels_get", "rna_Image_pixels_set", NULL);
diff --git a/source/blender/makesrna/intern/rna_image_api.c b/source/blender/makesrna/intern/rna_image_api.c
index 0b188b2b3db..be1e344d73f 100644
--- a/source/blender/makesrna/intern/rna_image_api.c
+++ b/source/blender/makesrna/intern/rna_image_api.c
@@ -26,6 +26,7 @@
# include "BKE_image.h"
# include "BKE_image_format.h"
+# include "BKE_image_save.h"
# include "BKE_main.h"
# include "BKE_scene.h"
# include <errno.h>
@@ -50,77 +51,39 @@ static void rna_ImagePackedFile_save(ImagePackedFile *imapf, Main *bmain, Report
static void rna_Image_save_render(
Image *image, bContext *C, ReportList *reports, const char *path, Scene *scene)
{
- ImBuf *ibuf;
+ Main *bmain = CTX_data_main(C);
if (scene == NULL) {
scene = CTX_data_scene(C);
}
- if (scene) {
- ImageUser iuser = {NULL};
- void *lock;
+ ImageSaveOptions opts;
- iuser.scene = scene;
+ if (BKE_image_save_options_init(&opts, bmain, scene, image, NULL, false, true)) {
+ opts.save_copy = true;
+ STRNCPY(opts.filepath, path);
- ibuf = BKE_image_acquire_ibuf(image, &iuser, &lock);
-
- if (ibuf == NULL) {
- BKE_report(reports, RPT_ERROR, "Could not acquire buffer from image");
+ if (!BKE_image_save(reports, bmain, image, NULL, &opts)) {
+ BKE_reportf(
+ reports, RPT_ERROR, "Image '%s' could not be saved to '%s'", image->id.name + 2, path);
}
- else {
- ImBuf *write_ibuf;
-
- ImageFormatData image_format;
- BKE_image_format_init_for_write(&image_format, scene, NULL);
-
- write_ibuf = IMB_colormanagement_imbuf_for_write(ibuf, true, true, &image_format);
-
- write_ibuf->planes = image_format.planes;
- write_ibuf->dither = scene->r.dither_intensity;
-
- if (!BKE_imbuf_write(write_ibuf, path, &image_format)) {
- BKE_reportf(reports, RPT_ERROR, "Could not write image: %s, '%s'", strerror(errno), path);
- }
-
- if (write_ibuf != ibuf) {
- IMB_freeImBuf(write_ibuf);
- }
-
- BKE_image_format_free(&image_format);
- }
-
- BKE_image_release_ibuf(image, ibuf, lock);
}
else {
- BKE_report(reports, RPT_ERROR, "Scene not in context, could not get save parameters");
+ BKE_reportf(reports, RPT_ERROR, "Image '%s' does not have any image data", image->id.name + 2);
}
+
+ BKE_image_save_options_free(&opts);
+
+ WM_event_add_notifier(C, NC_IMAGE | NA_EDITED, image);
}
static void rna_Image_save(Image *image, Main *bmain, bContext *C, ReportList *reports)
{
- void *lock;
-
- ImBuf *ibuf = BKE_image_acquire_ibuf(image, NULL, &lock);
- if (ibuf) {
- char filepath[FILE_MAX];
- BLI_strncpy(filepath, image->filepath, sizeof(filepath));
- BLI_path_abs(filepath, ID_BLEND_PATH(bmain, &image->id));
-
- /* NOTE: we purposefully ignore packed files here,
- * developers need to explicitly write them via 'packed_files' */
-
- if (IMB_saveiff(ibuf, filepath, ibuf->flags)) {
- image->type = IMA_TYPE_IMAGE;
-
- if (image->source == IMA_SRC_GENERATED) {
- image->source = IMA_SRC_FILE;
- }
+ Scene *scene = CTX_data_scene(C);
+ ImageSaveOptions opts;
- IMB_colormanagement_colorspace_from_ibuf_ftype(&image->colorspace_settings, ibuf);
-
- ibuf->userflags &= ~IB_BITMAPDIRTY;
- }
- else {
+ if (BKE_image_save_options_init(&opts, bmain, scene, image, NULL, false, false)) {
+ if (!BKE_image_save(reports, bmain, image, NULL, &opts)) {
BKE_reportf(reports,
RPT_ERROR,
"Image '%s' could not be saved to '%s'",
@@ -132,7 +95,8 @@ static void rna_Image_save(Image *image, Main *bmain, bContext *C, ReportList *r
BKE_reportf(reports, RPT_ERROR, "Image '%s' does not have any image data", image->id.name + 2);
}
- BKE_image_release_ibuf(image, ibuf, lock);
+ BKE_image_save_options_free(&opts);
+
WM_event_add_notifier(C, NC_IMAGE | NA_EDITED, image);
}
@@ -161,9 +125,8 @@ static void rna_Image_unpack(Image *image, Main *bmain, ReportList *reports, int
if (!BKE_image_has_packedfile(image)) {
BKE_report(reports, RPT_ERROR, "Image not packed");
}
- else if (BKE_image_has_multiple_ibufs(image)) {
- BKE_report(
- reports, RPT_ERROR, "Unpacking movies, image sequences or tiled images not supported");
+ else if (ELEM(image->source, IMA_SRC_MOVIE, IMA_SRC_SEQUENCE)) {
+ BKE_report(reports, RPT_ERROR, "Unpacking movies or image sequences not supported");
return;
}
else {
@@ -192,6 +155,7 @@ static void rna_Image_update(Image *image, ReportList *reports)
}
ibuf->userflags |= IB_DISPLAY_BUFFER_INVALID;
+ BKE_image_partial_update_mark_full_update(image);
BKE_image_release_ibuf(image, ibuf, NULL);
}
@@ -200,7 +164,10 @@ static void rna_Image_scale(Image *image, ReportList *reports, int width, int he
{
if (!BKE_image_scale(image, width, height)) {
BKE_reportf(reports, RPT_ERROR, "Image '%s' does not have any image data", image->id.name + 2);
+ return;
}
+ BKE_image_partial_update_mark_full_update(image);
+ WM_main_add_notifier(NC_IMAGE | NA_EDITED, image);
}
static int rna_Image_gl_load(
@@ -233,7 +200,7 @@ static int rna_Image_gl_touch(
BKE_image_tag_time(image);
- if (image->gputexture[TEXTARGET_2D][0][IMA_TEXTURE_RESOLUTION_FULL] == NULL) {
+ if (image->gputexture[TEXTARGET_2D][0] == NULL) {
error = rna_Image_gl_load(image, reports, frame, layer_index, pass_index);
}
@@ -316,7 +283,7 @@ void RNA_api_image(StructRNA *srna)
RNA_def_function_flag(func, FUNC_USE_REPORTS);
func = RNA_def_function(srna, "scale", "rna_Image_scale");
- RNA_def_function_ui_description(func, "Scale the image in pixels");
+ RNA_def_function_ui_description(func, "Scale the buffer of the image, in pixels");
RNA_def_function_flag(func, FUNC_USE_REPORTS);
parm = RNA_def_int(func, "width", 1, 1, INT_MAX, "", "Width", 1, INT_MAX);
RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
diff --git a/source/blender/makesrna/intern/rna_internal.h b/source/blender/makesrna/intern/rna_internal.h
index bf4eec433c4..9e743a4f205 100644
--- a/source/blender/makesrna/intern/rna_internal.h
+++ b/source/blender/makesrna/intern/rna_internal.h
@@ -373,7 +373,7 @@ void rna_ViewLayer_active_lightgroup_index_set(PointerRNA *ptr, int value);
* `rna_path_buffer_size` should be at least `sizeof(ViewLayer.name) * 3`.
* \return actual length of the generated RNA path.
*/
-size_t rna_ViewLayer_path_buffer_get(struct ViewLayer *view_layer,
+size_t rna_ViewLayer_path_buffer_get(const struct ViewLayer *view_layer,
char *r_rna_path,
const size_t rna_path_buffer_size);
@@ -402,8 +402,9 @@ bool rna_GPencil_datablocks_annotations_poll(struct PointerRNA *ptr,
const struct PointerRNA value);
bool rna_GPencil_datablocks_obdata_poll(struct PointerRNA *ptr, const struct PointerRNA value);
-char *rna_TextureSlot_path(struct PointerRNA *ptr);
-char *rna_Node_ImageUser_path(struct PointerRNA *ptr);
+char *rna_TextureSlot_path(const struct PointerRNA *ptr);
+char *rna_Node_ImageUser_path(const struct PointerRNA *ptr);
+char *rna_CameraBackgroundImage_image_or_movieclip_user_path(const struct PointerRNA *ptr);
/* Set U.is_dirty and redraw. */
diff --git a/source/blender/makesrna/intern/rna_internal_types.h b/source/blender/makesrna/intern/rna_internal_types.h
index 4db438f04b4..a5b06cabade 100644
--- a/source/blender/makesrna/intern/rna_internal_types.h
+++ b/source/blender/makesrna/intern/rna_internal_types.h
@@ -50,9 +50,10 @@ typedef int (*EditableFunc)(struct PointerRNA *ptr, const char **r_info);
typedef int (*ItemEditableFunc)(struct PointerRNA *ptr, int index);
typedef struct IDProperty **(*IDPropertiesFunc)(struct PointerRNA *ptr);
typedef struct StructRNA *(*StructRefineFunc)(struct PointerRNA *ptr);
-typedef char *(*StructPathFunc)(struct PointerRNA *ptr);
+typedef char *(*StructPathFunc)(const struct PointerRNA *ptr);
-typedef int (*PropArrayLengthGetFunc)(struct PointerRNA *ptr, int length[RNA_MAX_ARRAY_DIMENSION]);
+typedef int (*PropArrayLengthGetFunc)(const struct PointerRNA *ptr,
+ int length[RNA_MAX_ARRAY_DIMENSION]);
typedef bool (*PropBooleanGetFunc)(struct PointerRNA *ptr);
typedef void (*PropBooleanSetFunc)(struct PointerRNA *ptr, bool value);
typedef void (*PropBooleanArrayGetFunc)(struct PointerRNA *ptr, bool *values);
@@ -439,6 +440,15 @@ typedef struct StringPropertyRNA {
PropStringLengthFuncEx length_ex;
PropStringSetFuncEx set_ex;
+ /**
+ * Optional callback to list candidates for a string.
+ * This is only for use as suggestions in UI, other values may be assigned.
+ *
+ * \note The callback type is public, hence the difference in naming convention.
+ */
+ StringPropertySearchFunc search;
+ eStringPropertySearchFlag search_flag;
+
int maxlength; /* includes string terminator! */
const char *defaultvalue;
@@ -522,7 +532,7 @@ struct StructRNA {
/* property to iterate over properties */
PropertyRNA *iteratorproperty;
- /* struct this is derivedfrom */
+ /** Struct this is derived from. */
struct StructRNA *base;
/* only use for nested structs, where both the parent and child access
diff --git a/source/blender/makesrna/intern/rna_key.c b/source/blender/makesrna/intern/rna_key.c
index 50b25157989..b16d127a643 100644
--- a/source/blender/makesrna/intern/rna_key.c
+++ b/source/blender/makesrna/intern/rna_key.c
@@ -26,6 +26,14 @@
#include "rna_internal.h"
+const EnumPropertyItem rna_enum_keyblock_type_items[] = {
+ {KEY_LINEAR, "KEY_LINEAR", 0, "Linear", ""},
+ {KEY_CARDINAL, "KEY_CARDINAL", 0, "Cardinal", ""},
+ {KEY_CATMULL_ROM, "KEY_CATMULL_ROM", 0, "Catmull-Rom", ""},
+ {KEY_BSPLINE, "KEY_BSPLINE", 0, "BSpline", ""},
+ {0, NULL, 0, NULL, NULL},
+};
+
#ifdef RNA_RUNTIME
# include <stddef.h>
@@ -159,7 +167,7 @@ static void rna_ShapeKey_slider_max_set(PointerRNA *ptr, float value)
* such case looks rather unlikely - and not worth adding some kind of caching in key-blocks.
*/
-static Mesh *rna_KeyBlock_normals_get_mesh(PointerRNA *ptr, ID *id)
+static Mesh *rna_KeyBlock_normals_get_mesh(const PointerRNA *ptr, ID *id)
{
Key *key = rna_ShapeKey_find_key((id == NULL && ptr != NULL) ? ptr->owner_id : id);
id = key ? key->from : NULL;
@@ -182,9 +190,10 @@ static Mesh *rna_KeyBlock_normals_get_mesh(PointerRNA *ptr, ID *id)
return NULL;
}
-static int rna_KeyBlock_normals_vert_len(PointerRNA *ptr, int length[RNA_MAX_ARRAY_DIMENSION])
+static int rna_KeyBlock_normals_vert_len(const PointerRNA *ptr,
+ int length[RNA_MAX_ARRAY_DIMENSION])
{
- Mesh *me = rna_KeyBlock_normals_get_mesh(ptr, NULL);
+ const Mesh *me = rna_KeyBlock_normals_get_mesh(ptr, NULL);
length[0] = me ? me->totvert : 0;
length[1] = 3;
@@ -211,9 +220,10 @@ static void rna_KeyBlock_normals_vert_calc(ID *id,
BKE_keyblock_mesh_calc_normals(data, me, (float(*)[3])(*normals), NULL, NULL);
}
-static int rna_KeyBlock_normals_poly_len(PointerRNA *ptr, int length[RNA_MAX_ARRAY_DIMENSION])
+static int rna_KeyBlock_normals_poly_len(const PointerRNA *ptr,
+ int length[RNA_MAX_ARRAY_DIMENSION])
{
- Mesh *me = rna_KeyBlock_normals_get_mesh(ptr, NULL);
+ const Mesh *me = rna_KeyBlock_normals_get_mesh(ptr, NULL);
length[0] = me ? me->totpoly : 0;
length[1] = 3;
@@ -240,9 +250,10 @@ static void rna_KeyBlock_normals_poly_calc(ID *id,
BKE_keyblock_mesh_calc_normals(data, me, NULL, (float(*)[3])(*normals), NULL);
}
-static int rna_KeyBlock_normals_loop_len(PointerRNA *ptr, int length[RNA_MAX_ARRAY_DIMENSION])
+static int rna_KeyBlock_normals_loop_len(const PointerRNA *ptr,
+ int length[RNA_MAX_ARRAY_DIMENSION])
{
- Mesh *me = rna_KeyBlock_normals_get_mesh(ptr, NULL);
+ const Mesh *me = rna_KeyBlock_normals_get_mesh(ptr, NULL);
length[0] = me ? me->totloop : 0;
length[1] = 3;
@@ -656,10 +667,10 @@ int rna_ShapeKey_data_lookup_int(PointerRNA *ptr, int index, PointerRNA *r_ptr)
return false;
}
-static char *rna_ShapeKey_path(PointerRNA *ptr)
+static char *rna_ShapeKey_path(const PointerRNA *ptr)
{
- KeyBlock *kb = (KeyBlock *)ptr->data;
- ID *id = ptr->owner_id;
+ const KeyBlock *kb = (KeyBlock *)ptr->data;
+ const ID *id = ptr->owner_id;
char name_esc[sizeof(kb->name) * 2];
BLI_str_escape(name_esc, kb->name, sizeof(name_esc));
@@ -750,7 +761,7 @@ static int rna_ShapeKeyPoint_get_index(Key *key, KeyBlock *kb, float *point)
return (int)(pt - start) / key->elemsize;
}
-static char *rna_ShapeKeyPoint_path(PointerRNA *ptr)
+static char *rna_ShapeKeyPoint_path(const PointerRNA *ptr)
{
ID *id = ptr->owner_id;
Key *key = rna_ShapeKey_find_key(ptr->owner_id);
@@ -786,14 +797,6 @@ static char *rna_ShapeKeyPoint_path(PointerRNA *ptr)
#else
-const EnumPropertyItem rna_enum_keyblock_type_items[] = {
- {KEY_LINEAR, "KEY_LINEAR", 0, "Linear", ""},
- {KEY_CARDINAL, "KEY_CARDINAL", 0, "Cardinal", ""},
- {KEY_CATMULL_ROM, "KEY_CATMULL_ROM", 0, "Catmull-Rom", ""},
- {KEY_BSPLINE, "KEY_BSPLINE", 0, "BSpline", ""},
- {0, NULL, 0, NULL, NULL},
-};
-
static const float tilt_limit = DEG2RADF(21600.0f);
static void rna_def_keydata(BlenderRNA *brna)
diff --git a/source/blender/makesrna/intern/rna_lattice.c b/source/blender/makesrna/intern/rna_lattice.c
index 8fb36c035b7..f94804cb609 100644
--- a/source/blender/makesrna/intern/rna_lattice.c
+++ b/source/blender/makesrna/intern/rna_lattice.c
@@ -209,11 +209,11 @@ static void rna_Lattice_vg_name_set(PointerRNA *ptr, const char *value)
}
/* annoying, but is a consequence of RNA structures... */
-static char *rna_LatticePoint_path(PointerRNA *ptr)
+static char *rna_LatticePoint_path(const PointerRNA *ptr)
{
- Lattice *lt = (Lattice *)ptr->owner_id;
- void *point = ptr->data;
- BPoint *points = NULL;
+ const Lattice *lt = (Lattice *)ptr->owner_id;
+ const void *point = ptr->data;
+ const BPoint *points = NULL;
if (lt->editlatt && lt->editlatt->latt->def) {
points = lt->editlatt->latt->def;
diff --git a/source/blender/makesrna/intern/rna_layer.c b/source/blender/makesrna/intern/rna_layer.c
index 42414a9931b..6ab9d3a46ad 100644
--- a/source/blender/makesrna/intern/rna_layer.c
+++ b/source/blender/makesrna/intern/rna_layer.c
@@ -98,7 +98,7 @@ static void rna_LayerObjects_active_object_set(PointerRNA *ptr,
}
}
-size_t rna_ViewLayer_path_buffer_get(ViewLayer *view_layer,
+size_t rna_ViewLayer_path_buffer_get(const ViewLayer *view_layer,
char *r_rna_path,
const size_t rna_path_buffer_size)
{
@@ -108,9 +108,9 @@ size_t rna_ViewLayer_path_buffer_get(ViewLayer *view_layer,
return BLI_snprintf_rlen(r_rna_path, rna_path_buffer_size, "view_layers[\"%s\"]", name_esc);
}
-static char *rna_ViewLayer_path(PointerRNA *ptr)
+static char *rna_ViewLayer_path(const PointerRNA *ptr)
{
- ViewLayer *view_layer = (ViewLayer *)ptr->data;
+ const ViewLayer *view_layer = (ViewLayer *)ptr->data;
char rna_path[sizeof(view_layer->name) * 3];
rna_ViewLayer_path_buffer_get(view_layer, rna_path, sizeof(rna_path));
@@ -339,6 +339,7 @@ static void rna_LayerCollection_update(Main *UNUSED(bmain), Scene *UNUSED(scene)
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_IMAGE | ND_LAYER_CONTENT, NULL);
}
static bool rna_LayerCollection_has_objects(LayerCollection *lc)
diff --git a/source/blender/makesrna/intern/rna_linestyle.c b/source/blender/makesrna/intern/rna_linestyle.c
index 2a8a3a76c6d..c18ee461fae 100644
--- a/source/blender/makesrna/intern/rna_linestyle.c
+++ b/source/blender/makesrna/intern/rna_linestyle.c
@@ -239,33 +239,33 @@ static StructRNA *rna_LineStyle_geometry_modifier_refine(struct PointerRNA *ptr)
}
}
-static char *rna_LineStyle_color_modifier_path(PointerRNA *ptr)
+static char *rna_LineStyle_color_modifier_path(const PointerRNA *ptr)
{
- LineStyleModifier *m = (LineStyleModifier *)ptr->data;
+ const LineStyleModifier *m = (LineStyleModifier *)ptr->data;
char name_esc[sizeof(m->name) * 2];
BLI_str_escape(name_esc, m->name, sizeof(name_esc));
return BLI_sprintfN("color_modifiers[\"%s\"]", name_esc);
}
-static char *rna_LineStyle_alpha_modifier_path(PointerRNA *ptr)
+static char *rna_LineStyle_alpha_modifier_path(const PointerRNA *ptr)
{
- LineStyleModifier *m = (LineStyleModifier *)ptr->data;
+ const LineStyleModifier *m = (LineStyleModifier *)ptr->data;
char name_esc[sizeof(m->name) * 2];
BLI_str_escape(name_esc, m->name, sizeof(name_esc));
return BLI_sprintfN("alpha_modifiers[\"%s\"]", name_esc);
}
-static char *rna_LineStyle_thickness_modifier_path(PointerRNA *ptr)
+static char *rna_LineStyle_thickness_modifier_path(const PointerRNA *ptr)
{
- LineStyleModifier *m = (LineStyleModifier *)ptr->data;
+ const LineStyleModifier *m = (LineStyleModifier *)ptr->data;
char name_esc[sizeof(m->name) * 2];
BLI_str_escape(name_esc, m->name, sizeof(name_esc));
return BLI_sprintfN("thickness_modifiers[\"%s\"]", name_esc);
}
-static char *rna_LineStyle_geometry_modifier_path(PointerRNA *ptr)
+static char *rna_LineStyle_geometry_modifier_path(const PointerRNA *ptr)
{
- LineStyleModifier *m = (LineStyleModifier *)ptr->data;
+ const LineStyleModifier *m = (LineStyleModifier *)ptr->data;
char name_esc[sizeof(m->name) * 2];
BLI_str_escape(name_esc, m->name, sizeof(name_esc));
return BLI_sprintfN("geometry_modifiers[\"%s\"]", name_esc);
diff --git a/source/blender/makesrna/intern/rna_mask.c b/source/blender/makesrna/intern/rna_mask.c
index 2247a16a7a0..3dac148f7d4 100644
--- a/source/blender/makesrna/intern/rna_mask.c
+++ b/source/blender/makesrna/intern/rna_mask.c
@@ -165,9 +165,9 @@ static void rna_Mask_layer_active_index_range(
*softmax = *max;
}
-static char *rna_MaskLayer_path(PointerRNA *ptr)
+static char *rna_MaskLayer_path(const PointerRNA *ptr)
{
- MaskLayer *masklay = (MaskLayer *)ptr->data;
+ const MaskLayer *masklay = (MaskLayer *)ptr->data;
char name_esc[sizeof(masklay->name) * 2];
BLI_str_escape(name_esc, masklay->name, sizeof(name_esc));
return BLI_sprintfN("layers[\"%s\"]", name_esc);
diff --git a/source/blender/makesrna/intern/rna_material.c b/source/blender/makesrna/intern/rna_material.c
index 15e7e12bbf8..4fb7495bac8 100644
--- a/source/blender/makesrna/intern/rna_material.c
+++ b/source/blender/makesrna/intern/rna_material.c
@@ -25,24 +25,24 @@
const EnumPropertyItem rna_enum_ramp_blend_items[] = {
{MA_RAMP_BLEND, "MIX", 0, "Mix", ""},
- {0, "", ICON_NONE, NULL, NULL},
+ RNA_ENUM_ITEM_SEPR,
{MA_RAMP_DARK, "DARKEN", 0, "Darken", ""},
{MA_RAMP_MULT, "MULTIPLY", 0, "Multiply", ""},
{MA_RAMP_BURN, "BURN", 0, "Color Burn", ""},
- {0, "", ICON_NONE, NULL, NULL},
+ RNA_ENUM_ITEM_SEPR,
{MA_RAMP_LIGHT, "LIGHTEN", 0, "Lighten", ""},
{MA_RAMP_SCREEN, "SCREEN", 0, "Screen", ""},
{MA_RAMP_DODGE, "DODGE", 0, "Color Dodge", ""},
{MA_RAMP_ADD, "ADD", 0, "Add", ""},
- {0, "", ICON_NONE, NULL, NULL},
+ RNA_ENUM_ITEM_SEPR,
{MA_RAMP_OVERLAY, "OVERLAY", 0, "Overlay", ""},
{MA_RAMP_SOFT, "SOFT_LIGHT", 0, "Soft Light", ""},
{MA_RAMP_LINEAR, "LINEAR_LIGHT", 0, "Linear Light", ""},
- {0, "", ICON_NONE, NULL, NULL},
+ RNA_ENUM_ITEM_SEPR,
{MA_RAMP_DIFF, "DIFFERENCE", 0, "Difference", ""},
{MA_RAMP_SUB, "SUBTRACT", 0, "Subtract", ""},
{MA_RAMP_DIV, "DIVIDE", 0, "Divide", ""},
- {0, "", ICON_NONE, NULL, NULL},
+ RNA_ENUM_ITEM_SEPR,
{MA_RAMP_HUE, "HUE", 0, "Hue", ""},
{MA_RAMP_SAT, "SATURATION", 0, "Saturation", ""},
{MA_RAMP_COLOR, "COLOR", 0, "Color", ""},
@@ -362,7 +362,7 @@ static void rna_gpcolordata_uv_update(Main *bmain, Scene *scene, PointerRNA *ptr
rna_MaterialGpencil_update(bmain, scene, ptr);
}
-static char *rna_GpencilColorData_path(PointerRNA *UNUSED(ptr))
+static char *rna_GpencilColorData_path(const PointerRNA *UNUSED(ptr))
{
return BLI_strdup("grease_pencil");
}
diff --git a/source/blender/makesrna/intern/rna_mesh.c b/source/blender/makesrna/intern/rna_mesh.c
index 38d473f04dd..fd548ea6a56 100644
--- a/source/blender/makesrna/intern/rna_mesh.c
+++ b/source/blender/makesrna/intern/rna_mesh.c
@@ -71,7 +71,7 @@ static const EnumPropertyItem rna_enum_mesh_remesh_mode_items[] = {
/** \name Generic Helpers
* \{ */
-static Mesh *rna_mesh(PointerRNA *ptr)
+static Mesh *rna_mesh(const PointerRNA *ptr)
{
Mesh *me = (Mesh *)ptr->owner_id;
return me;
@@ -102,7 +102,7 @@ static CustomData *rna_mesh_fdata_helper(Mesh *me)
return (me->edit_mesh) ? NULL : &me->fdata;
}
-static CustomData *rna_mesh_vdata(PointerRNA *ptr)
+static CustomData *rna_mesh_vdata(const PointerRNA *ptr)
{
Mesh *me = rna_mesh(ptr);
return rna_mesh_vdata_helper(me);
@@ -114,13 +114,13 @@ static CustomData *rna_mesh_edata(PointerRNA *ptr)
return rna_mesh_edata_helper(me);
}
# endif
-static CustomData *rna_mesh_pdata(PointerRNA *ptr)
+static CustomData *rna_mesh_pdata(const PointerRNA *ptr)
{
Mesh *me = rna_mesh(ptr);
return rna_mesh_pdata_helper(me);
}
-static CustomData *rna_mesh_ldata(PointerRNA *ptr)
+static CustomData *rna_mesh_ldata(const PointerRNA *ptr)
{
Mesh *me = rna_mesh(ptr);
return rna_mesh_ldata_helper(me);
@@ -560,7 +560,7 @@ static void rna_MeshVertex_undeformed_co_get(PointerRNA *ptr, float values[3])
{
Mesh *me = rna_mesh(ptr);
MVert *mvert = (MVert *)ptr->data;
- float(*orco)[3] = CustomData_get_layer(&me->vdata, CD_ORCO);
+ const float(*orco)[3] = CustomData_get_layer(&me->vdata, CD_ORCO);
if (orco) {
/* orco is normalized to 0..1, we do inverse to match mvert->co */
@@ -626,9 +626,10 @@ static void rna_CustomDataLayer_clone_set(PointerRNA *ptr, CustomData *data, int
static bool rna_MEdge_freestyle_edge_mark_get(PointerRNA *ptr)
{
- Mesh *me = rna_mesh(ptr);
- MEdge *medge = (MEdge *)ptr->data;
- FreestyleEdge *fed = CustomData_get(&me->edata, (int)(medge - me->medge), CD_FREESTYLE_EDGE);
+ const Mesh *me = rna_mesh(ptr);
+ const MEdge *medge = (MEdge *)ptr->data;
+ const FreestyleEdge *fed = CustomData_get(
+ &me->edata, (int)(medge - me->medge), CD_FREESTYLE_EDGE);
return fed && (fed->flag & FREESTYLE_EDGE_MARK) != 0;
}
@@ -652,9 +653,10 @@ static void rna_MEdge_freestyle_edge_mark_set(PointerRNA *ptr, bool value)
static bool rna_MPoly_freestyle_face_mark_get(PointerRNA *ptr)
{
- Mesh *me = rna_mesh(ptr);
- MPoly *mpoly = (MPoly *)ptr->data;
- FreestyleFace *ffa = CustomData_get(&me->pdata, (int)(mpoly - me->mpoly), CD_FREESTYLE_FACE);
+ const Mesh *me = rna_mesh(ptr);
+ const MPoly *mpoly = (MPoly *)ptr->data;
+ const FreestyleFace *ffa = CustomData_get(
+ &me->pdata, (int)(mpoly - me->mpoly), CD_FREESTYLE_FACE);
return ffa && (ffa->flag & FREESTYLE_FACE_MARK) != 0;
}
@@ -687,9 +689,9 @@ DEFINE_CUSTOMDATA_LAYER_COLLECTION_ACTIVEITEM(uv_layer, ldata, CD_MLOOPUV, rende
/* MeshUVLoopLayer */
-static char *rna_MeshUVLoopLayer_path(PointerRNA *ptr)
+static char *rna_MeshUVLoopLayer_path(const PointerRNA *ptr)
{
- CustomDataLayer *cdl = ptr->data;
+ const CustomDataLayer *cdl = ptr->data;
char name_esc[sizeof(cdl->name) * 2];
BLI_str_escape(name_esc, cdl->name, sizeof(name_esc));
return BLI_sprintfN("uv_layers[\"%s\"]", name_esc);
@@ -930,16 +932,16 @@ static int rna_Mesh_polygon_string_layers_length(PointerRNA *ptr)
/* Skin vertices */
DEFINE_CUSTOMDATA_LAYER_COLLECTION(skin_vertice, vdata, CD_MVERT_SKIN)
-static char *rna_MeshSkinVertexLayer_path(PointerRNA *ptr)
+static char *rna_MeshSkinVertexLayer_path(const PointerRNA *ptr)
{
- CustomDataLayer *cdl = ptr->data;
+ const CustomDataLayer *cdl = ptr->data;
char name_esc[sizeof(cdl->name) * 2];
BLI_str_escape(name_esc, cdl->name, sizeof(name_esc));
return BLI_sprintfN("skin_vertices[\"%s\"]", name_esc);
}
-static char *rna_VertCustomData_data_path(PointerRNA *ptr, const char *collection, int type);
-static char *rna_MeshSkinVertex_path(PointerRNA *ptr)
+static char *rna_VertCustomData_data_path(const PointerRNA *ptr, const char *collection, int type);
+static char *rna_MeshSkinVertex_path(const PointerRNA *ptr)
{
return rna_VertCustomData_data_path(ptr, "skin_vertices", CD_MVERT_SKIN);
}
@@ -962,8 +964,7 @@ static int rna_MeshSkinVertexLayer_data_length(PointerRNA *ptr)
/* 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)
+static char *rna_MeshVertexCreaseLayer_path(const PointerRNA *ptr)
{
return rna_VertCustomData_data_path(ptr, "vertex_creases", CD_CREASE);
}
@@ -986,15 +987,15 @@ static int rna_MeshVertexCreaseLayer_data_length(PointerRNA *ptr)
/* Paint mask */
DEFINE_CUSTOMDATA_LAYER_COLLECTION(vertex_paint_mask, vdata, CD_PAINT_MASK)
-static char *rna_MeshPaintMaskLayer_path(PointerRNA *ptr)
+static char *rna_MeshPaintMaskLayer_path(const PointerRNA *ptr)
{
- CustomDataLayer *cdl = ptr->data;
+ const CustomDataLayer *cdl = ptr->data;
char name_esc[sizeof(cdl->name) * 2];
BLI_str_escape(name_esc, cdl->name, sizeof(name_esc));
return BLI_sprintfN("vertex_paint_masks[\"%s\"]", name_esc);
}
-static char *rna_MeshPaintMask_path(PointerRNA *ptr)
+static char *rna_MeshPaintMask_path(const PointerRNA *ptr)
{
return rna_VertCustomData_data_path(ptr, "vertex_paint_masks", CD_PAINT_MASK);
}
@@ -1021,9 +1022,9 @@ DEFINE_CUSTOMDATA_LAYER_COLLECTION(face_map, pdata, CD_FACEMAP)
DEFINE_CUSTOMDATA_LAYER_COLLECTION_ACTIVEITEM(
face_map, pdata, CD_FACEMAP, active, MeshFaceMapLayer)
-static char *rna_MeshFaceMapLayer_path(PointerRNA *ptr)
+static char *rna_MeshFaceMapLayer_path(const PointerRNA *ptr)
{
- CustomDataLayer *cdl = ptr->data;
+ const CustomDataLayer *cdl = ptr->data;
char name_esc[sizeof(cdl->name) * 2];
BLI_str_escape(name_esc, cdl->name, sizeof(name_esc));
return BLI_sprintfN("face_maps[\"%s\"]", name_esc);
@@ -1088,11 +1089,12 @@ static void rna_Mesh_face_map_remove(struct Mesh *me,
/* End face maps */
/* poly.vertices - this is faked loop access for convenience */
-static int rna_MeshPoly_vertices_get_length(PointerRNA *ptr, int length[RNA_MAX_ARRAY_DIMENSION])
+static int rna_MeshPoly_vertices_get_length(const PointerRNA *ptr,
+ int length[RNA_MAX_ARRAY_DIMENSION])
{
- MPoly *mp = (MPoly *)ptr->data;
+ const MPoly *mp = (MPoly *)ptr->data;
/* NOTE: raw access uses dummy item, this _could_ crash,
- * watch out for this, mface uses it but it can't work here. */
+ * watch out for this, #MFace uses it but it can't work here. */
return (length[0] = mp->totloop);
}
@@ -1180,11 +1182,11 @@ static int rna_MeshLoop_index_get(PointerRNA *ptr)
/* path construction */
-static char *rna_VertexGroupElement_path(PointerRNA *ptr)
+static char *rna_VertexGroupElement_path(const PointerRNA *ptr)
{
- Mesh *me = rna_mesh(ptr); /* XXX not always! */
- MDeformWeight *dw = (MDeformWeight *)ptr->data;
- MDeformVert *dvert;
+ const Mesh *me = rna_mesh(ptr); /* XXX not always! */
+ const MDeformWeight *dw = (MDeformWeight *)ptr->data;
+ const MDeformVert *dvert;
int a, b;
for (a = 0, dvert = me->dvert; a < me->totvert; a++, dvert++) {
@@ -1198,37 +1200,37 @@ static char *rna_VertexGroupElement_path(PointerRNA *ptr)
return NULL;
}
-static char *rna_MeshPolygon_path(PointerRNA *ptr)
+static char *rna_MeshPolygon_path(const PointerRNA *ptr)
{
return BLI_sprintfN("polygons[%d]", (int)((MPoly *)ptr->data - rna_mesh(ptr)->mpoly));
}
-static char *rna_MeshLoopTriangle_path(PointerRNA *ptr)
+static char *rna_MeshLoopTriangle_path(const PointerRNA *ptr)
{
return BLI_sprintfN("loop_triangles[%d]",
(int)((MLoopTri *)ptr->data - rna_mesh(ptr)->runtime.looptris.array));
}
-static char *rna_MeshEdge_path(PointerRNA *ptr)
+static char *rna_MeshEdge_path(const PointerRNA *ptr)
{
return BLI_sprintfN("edges[%d]", (int)((MEdge *)ptr->data - rna_mesh(ptr)->medge));
}
-static char *rna_MeshLoop_path(PointerRNA *ptr)
+static char *rna_MeshLoop_path(const PointerRNA *ptr)
{
return BLI_sprintfN("loops[%d]", (int)((MLoop *)ptr->data - rna_mesh(ptr)->mloop));
}
-static char *rna_MeshVertex_path(PointerRNA *ptr)
+static char *rna_MeshVertex_path(const PointerRNA *ptr)
{
return BLI_sprintfN("vertices[%d]", (int)((MVert *)ptr->data - rna_mesh(ptr)->mvert));
}
-static char *rna_VertCustomData_data_path(PointerRNA *ptr, const char *collection, int type)
+static char *rna_VertCustomData_data_path(const PointerRNA *ptr, const char *collection, int type)
{
- CustomDataLayer *cdl;
- Mesh *me = rna_mesh(ptr);
- CustomData *vdata = rna_mesh_vdata(ptr);
+ const CustomDataLayer *cdl;
+ const Mesh *me = rna_mesh(ptr);
+ const CustomData *vdata = rna_mesh_vdata(ptr);
int a, b, totvert = (me->edit_mesh) ? 0 : me->totvert;
for (cdl = vdata->layers, a = 0; a < vdata->totlayer; cdl++, a++) {
@@ -1245,11 +1247,11 @@ static char *rna_VertCustomData_data_path(PointerRNA *ptr, const char *collectio
return NULL;
}
-static char *rna_PolyCustomData_data_path(PointerRNA *ptr, const char *collection, int type)
+static char *rna_PolyCustomData_data_path(const PointerRNA *ptr, const char *collection, int type)
{
- CustomDataLayer *cdl;
- Mesh *me = rna_mesh(ptr);
- CustomData *pdata = rna_mesh_pdata(ptr);
+ const CustomDataLayer *cdl;
+ const Mesh *me = rna_mesh(ptr);
+ const CustomData *pdata = rna_mesh_pdata(ptr);
int a, b, totpoly = (me->edit_mesh) ? 0 : me->totpoly;
for (cdl = pdata->layers, a = 0; a < pdata->totlayer; cdl++, a++) {
@@ -1266,11 +1268,11 @@ static char *rna_PolyCustomData_data_path(PointerRNA *ptr, const char *collectio
return NULL;
}
-static char *rna_LoopCustomData_data_path(PointerRNA *ptr, const char *collection, int type)
+static char *rna_LoopCustomData_data_path(const PointerRNA *ptr, const char *collection, int type)
{
- CustomDataLayer *cdl;
- Mesh *me = rna_mesh(ptr);
- CustomData *ldata = rna_mesh_ldata(ptr);
+ const CustomDataLayer *cdl;
+ const Mesh *me = rna_mesh(ptr);
+ const CustomData *ldata = rna_mesh_ldata(ptr);
int a, b, totloop = (me->edit_mesh) ? 0 : me->totloop;
for (cdl = ldata->layers, a = 0; a < ldata->totlayer; cdl++, a++) {
@@ -1313,58 +1315,58 @@ static int rna_Mesh_poly_normals_length(PointerRNA *ptr)
return mesh->totpoly;
}
-static char *rna_MeshUVLoop_path(PointerRNA *ptr)
+static char *rna_MeshUVLoop_path(const PointerRNA *ptr)
{
return rna_LoopCustomData_data_path(ptr, "uv_layers", CD_MLOOPUV);
}
-static char *rna_MeshLoopColorLayer_path(PointerRNA *ptr)
+static char *rna_MeshLoopColorLayer_path(const PointerRNA *ptr)
{
- CustomDataLayer *cdl = ptr->data;
+ const CustomDataLayer *cdl = ptr->data;
char name_esc[sizeof(cdl->name) * 2];
BLI_str_escape(name_esc, cdl->name, sizeof(name_esc));
return BLI_sprintfN("vertex_colors[\"%s\"]", name_esc);
}
-static char *rna_MeshColor_path(PointerRNA *ptr)
+static char *rna_MeshColor_path(const PointerRNA *ptr)
{
return rna_LoopCustomData_data_path(ptr, "vertex_colors", CD_PROP_BYTE_COLOR);
}
-static char *rna_MeshVertColorLayer_path(PointerRNA *ptr)
+static char *rna_MeshVertColorLayer_path(const PointerRNA *ptr)
{
- CustomDataLayer *cdl = ptr->data;
+ const CustomDataLayer *cdl = ptr->data;
char name_esc[sizeof(cdl->name) * 2];
BLI_str_escape(name_esc, cdl->name, sizeof(name_esc));
return BLI_sprintfN("sculpt_vertex_colors[\"%s\"]", name_esc);
}
-static char *rna_MeshVertColor_path(PointerRNA *ptr)
+static char *rna_MeshVertColor_path(const PointerRNA *ptr)
{
return rna_VertCustomData_data_path(ptr, "sculpt_vertex_colors", CD_PROP_COLOR);
}
/**** Float Property Layer API ****/
-static char *rna_MeshVertexFloatPropertyLayer_path(PointerRNA *ptr)
+static char *rna_MeshVertexFloatPropertyLayer_path(const PointerRNA *ptr)
{
- CustomDataLayer *cdl = ptr->data;
+ const CustomDataLayer *cdl = ptr->data;
char name_esc[sizeof(cdl->name) * 2];
BLI_str_escape(name_esc, cdl->name, sizeof(name_esc));
return BLI_sprintfN("vertex_float_layers[\"%s\"]", name_esc);
}
-static char *rna_MeshPolygonFloatPropertyLayer_path(PointerRNA *ptr)
+static char *rna_MeshPolygonFloatPropertyLayer_path(const PointerRNA *ptr)
{
- CustomDataLayer *cdl = ptr->data;
+ const CustomDataLayer *cdl = ptr->data;
char name_esc[sizeof(cdl->name) * 2];
BLI_str_escape(name_esc, cdl->name, sizeof(name_esc));
return BLI_sprintfN("polygon_float_layers[\"%s\"]", name_esc);
}
-static char *rna_MeshVertexFloatProperty_path(PointerRNA *ptr)
+static char *rna_MeshVertexFloatProperty_path(const PointerRNA *ptr)
{
return rna_VertCustomData_data_path(ptr, "vertex_layers_float", CD_PROP_FLOAT);
}
-static char *rna_MeshPolygonFloatProperty_path(PointerRNA *ptr)
+static char *rna_MeshPolygonFloatProperty_path(const PointerRNA *ptr)
{
return rna_PolyCustomData_data_path(ptr, "polygon_layers_float", CD_PROP_FLOAT);
}
@@ -1396,26 +1398,26 @@ static int rna_MeshPolygonFloatPropertyLayer_data_length(PointerRNA *ptr)
}
/**** Int Property Layer API ****/
-static char *rna_MeshVertexIntPropertyLayer_path(PointerRNA *ptr)
+static char *rna_MeshVertexIntPropertyLayer_path(const PointerRNA *ptr)
{
- CustomDataLayer *cdl = ptr->data;
+ const CustomDataLayer *cdl = ptr->data;
char name_esc[sizeof(cdl->name) * 2];
BLI_str_escape(name_esc, cdl->name, sizeof(name_esc));
return BLI_sprintfN("vertex_int_layers[\"%s\"]", name_esc);
}
-static char *rna_MeshPolygonIntPropertyLayer_path(PointerRNA *ptr)
+static char *rna_MeshPolygonIntPropertyLayer_path(const PointerRNA *ptr)
{
- CustomDataLayer *cdl = ptr->data;
+ const CustomDataLayer *cdl = ptr->data;
char name_esc[sizeof(cdl->name) * 2];
BLI_str_escape(name_esc, cdl->name, sizeof(name_esc));
return BLI_sprintfN("polygon_int_layers[\"%s\"]", name_esc);
}
-static char *rna_MeshVertexIntProperty_path(PointerRNA *ptr)
+static char *rna_MeshVertexIntProperty_path(const PointerRNA *ptr)
{
return rna_VertCustomData_data_path(ptr, "vertex_layers_int", CD_PROP_INT32);
}
-static char *rna_MeshPolygonIntProperty_path(PointerRNA *ptr)
+static char *rna_MeshPolygonIntProperty_path(const PointerRNA *ptr)
{
return rna_PolyCustomData_data_path(ptr, "polygon_layers_int", CD_PROP_INT32);
}
@@ -1447,26 +1449,26 @@ static int rna_MeshPolygonIntPropertyLayer_data_length(PointerRNA *ptr)
}
/**** String Property Layer API ****/
-static char *rna_MeshVertexStringPropertyLayer_path(PointerRNA *ptr)
+static char *rna_MeshVertexStringPropertyLayer_path(const PointerRNA *ptr)
{
- CustomDataLayer *cdl = ptr->data;
+ const CustomDataLayer *cdl = ptr->data;
char name_esc[sizeof(cdl->name) * 2];
BLI_str_escape(name_esc, cdl->name, sizeof(name_esc));
return BLI_sprintfN("vertex_string_layers[\"%s\"]", name_esc);
}
-static char *rna_MeshPolygonStringPropertyLayer_path(PointerRNA *ptr)
+static char *rna_MeshPolygonStringPropertyLayer_path(const PointerRNA *ptr)
{
- CustomDataLayer *cdl = ptr->data;
+ const CustomDataLayer *cdl = ptr->data;
char name_esc[sizeof(cdl->name) * 2];
BLI_str_escape(name_esc, cdl->name, sizeof(name_esc));
return BLI_sprintfN("polygon_string_layers[\"%s\"]", name_esc);
}
-static char *rna_MeshVertexStringProperty_path(PointerRNA *ptr)
+static char *rna_MeshVertexStringProperty_path(const PointerRNA *ptr)
{
return rna_VertCustomData_data_path(ptr, "vertex_layers_string", CD_PROP_STRING);
}
-static char *rna_MeshPolygonStringProperty_path(PointerRNA *ptr)
+static char *rna_MeshPolygonStringProperty_path(const PointerRNA *ptr)
{
return rna_PolyCustomData_data_path(ptr, "polygon_layers_string", CD_PROP_STRING);
}
@@ -1517,7 +1519,7 @@ void rna_MeshStringProperty_s_set(PointerRNA *ptr, const char *value)
BLI_strncpy(ms->s, value, sizeof(ms->s));
}
-static char *rna_MeshFaceMap_path(PointerRNA *ptr)
+static char *rna_MeshFaceMap_path(const PointerRNA *ptr)
{
return rna_PolyCustomData_data_path(ptr, "face_maps", CD_FACEMAP);
}
@@ -1636,7 +1638,7 @@ static PointerRNA rna_Mesh_uv_layers_new(struct Mesh *me,
PointerRNA ptr;
CustomData *ldata;
CustomDataLayer *cdl = NULL;
- int index = ED_mesh_uv_texture_add(me, name, false, do_init, reports);
+ int index = ED_mesh_uv_add(me, name, false, do_init, reports);
if (index != -1) {
ldata = rna_mesh_ldata_helper(me);
@@ -1649,7 +1651,7 @@ static PointerRNA rna_Mesh_uv_layers_new(struct Mesh *me,
static void rna_Mesh_uv_layers_remove(struct Mesh *me, ReportList *reports, CustomDataLayer *layer)
{
- if (ED_mesh_uv_texture_remove_named(me, layer->name) == false) {
+ if (ED_mesh_uv_remove_named(me, layer->name) == false) {
BKE_reportf(reports, RPT_ERROR, "Texture layer '%s' not found", layer->name);
}
}
@@ -2195,7 +2197,7 @@ static void rna_def_mloopcol(BlenderRNA *brna)
RNA_def_property_range(prop, 0.0f, 1.0f);
RNA_def_property_float_funcs(
prop, "rna_MeshLoopColor_color_get", "rna_MeshLoopColor_color_set", NULL);
- RNA_def_property_ui_text(prop, "Color", "");
+ RNA_def_property_ui_text(prop, "Color", "Color in sRGB color space");
RNA_def_property_update(prop, 0, "rna_Mesh_update_data_legacy_deg_tag_all");
}
@@ -3210,7 +3212,9 @@ static void rna_def_mesh(BlenderRNA *brna)
NULL);
RNA_def_property_struct_type(prop, "MeshLoopColorLayer");
RNA_def_property_override_flag(prop, PROPOVERRIDE_IGNORE);
- RNA_def_property_ui_text(prop, "Vertex Colors", "All vertex colors");
+ RNA_def_property_ui_text(prop,
+ "Vertex Colors",
+ "Legacy vertex color layers. Deprecated, use color attributes instead");
rna_def_loop_colors(brna, prop);
/* Sculpt Vertex colors */
@@ -3228,7 +3232,9 @@ static void rna_def_mesh(BlenderRNA *brna)
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_property_ui_text(prop,
+ "Sculpt Vertex Colors",
+ "Sculpt vertex color layers. Deprecated, use color attributes instead");
rna_def_vert_colors(brna, prop);
/* TODO: edge customdata layers (bmesh py api can access already). */
diff --git a/source/blender/makesrna/intern/rna_meta.c b/source/blender/makesrna/intern/rna_meta.c
index f160388c5d2..e6cf743e167 100644
--- a/source/blender/makesrna/intern/rna_meta.c
+++ b/source/blender/makesrna/intern/rna_meta.c
@@ -156,10 +156,10 @@ static bool rna_Meta_is_editmode_get(PointerRNA *ptr)
return (mb->editelems != NULL);
}
-static char *rna_MetaElement_path(PointerRNA *ptr)
+static char *rna_MetaElement_path(const PointerRNA *ptr)
{
- MetaBall *mb = (MetaBall *)ptr->owner_id;
- MetaElem *ml = ptr->data;
+ const MetaBall *mb = (MetaBall *)ptr->owner_id;
+ const MetaElem *ml = ptr->data;
int index = -1;
if (mb->editelems) {
diff --git a/source/blender/makesrna/intern/rna_modifier.c b/source/blender/makesrna/intern/rna_modifier.c
index 456f774648a..4810784b3f7 100644
--- a/source/blender/makesrna/intern/rna_modifier.c
+++ b/source/blender/makesrna/intern/rna_modifier.c
@@ -47,7 +47,7 @@
#include "MOD_nodes.h"
const EnumPropertyItem rna_enum_object_modifier_type_items[] = {
- {0, "", 0, N_("Modify"), ""},
+ RNA_ENUM_ITEM_HEADING(N_("Modify"), NULL),
{eModifierType_DataTransfer,
"DATA_TRANSFER",
ICON_MOD_DATA_TRANSFER,
@@ -99,7 +99,8 @@ const EnumPropertyItem rna_enum_object_modifier_type_items[] = {
ICON_MOD_VERTEX_WEIGHT,
"Vertex Weight Proximity",
"Set the vertex group weights based on the distance to another target object"},
- {0, "", 0, N_("Generate"), ""},
+
+ RNA_ENUM_ITEM_HEADING(N_("Generate"), NULL),
{eModifierType_Array,
"ARRAY",
ICON_MOD_ARRAY,
@@ -130,7 +131,7 @@ const EnumPropertyItem rna_enum_object_modifier_type_items[] = {
ICON_MOD_EDGESPLIT,
"Edge Split",
"Split away joined faces at the edges"},
- {eModifierType_Nodes, "NODES", ICON_NODETREE, "Geometry Nodes", ""},
+ {eModifierType_Nodes, "NODES", ICON_GEOMETRY_NODES, "Geometry Nodes", ""},
{eModifierType_Mask,
"MASK",
ICON_MOD_MASK,
@@ -193,7 +194,8 @@ const EnumPropertyItem rna_enum_object_modifier_type_items[] = {
ICON_MOD_WIREFRAME,
"Wireframe",
"Convert faces into thickened edges"},
- {0, "", 0, N_("Deform"), ""},
+
+ RNA_ENUM_ITEM_HEADING(N_("Deform"), NULL),
{eModifierType_Armature,
"ARMATURE",
ICON_MOD_ARMATURE,
@@ -272,7 +274,8 @@ const EnumPropertyItem rna_enum_object_modifier_type_items[] = {
ICON_VOLUME_DATA,
"Volume Displace",
"Deform volume based on noise or other vector fields"}, /* TODO: Use correct icon. */
- {0, "", 0, N_("Physics"), ""},
+
+ RNA_ENUM_ITEM_HEADING(N_("Physics"), NULL),
{eModifierType_Cloth, "CLOTH", ICON_MOD_CLOTH, "Cloth", ""},
{eModifierType_Collision, "COLLISION", ICON_MOD_PHYSICS, "Collision", ""},
{eModifierType_DynamicPaint, "DYNAMIC_PAINT", ICON_MOD_DYNAMICPAINT, "Dynamic Paint", ""},
@@ -722,9 +725,9 @@ static void rna_Modifier_name_set(PointerRNA *ptr, const char *value)
BKE_animdata_fix_paths_rename_all(NULL, "modifiers", oldname, md->name);
}
-static char *rna_Modifier_path(PointerRNA *ptr)
+static char *rna_Modifier_path(const PointerRNA *ptr)
{
- ModifierData *md = ptr->data;
+ const ModifierData *md = ptr->data;
char name_esc[sizeof(md->name) * 2];
BLI_str_escape(name_esc, md->name, sizeof(name_esc));
@@ -947,10 +950,10 @@ static void rna_HookModifier_subtarget_set(PointerRNA *ptr, const char *value)
BKE_object_modifier_hook_reset(owner, hmd);
}
-static int rna_HookModifier_vertex_indices_get_length(PointerRNA *ptr,
+static int rna_HookModifier_vertex_indices_get_length(const PointerRNA *ptr,
int length[RNA_MAX_ARRAY_DIMENSION])
{
- HookModifierData *hmd = ptr->data;
+ const HookModifierData *hmd = ptr->data;
int indexar_num = hmd->indexar ? hmd->indexar_num : 0;
return (length[0] = indexar_num);
}
@@ -1366,10 +1369,9 @@ static const EnumPropertyItem *rna_DataTransferModifier_layers_select_src_itemf(
Object *ob_src = dtmd->ob_source;
if (ob_src) {
- AttributeDomain domain = STREQ(RNA_property_identifier(prop),
- "layers_vcol_vert_select_src") ?
- ATTR_DOMAIN_POINT :
- ATTR_DOMAIN_CORNER;
+ eAttrDomain domain = STREQ(RNA_property_identifier(prop), "layers_vcol_vert_select_src") ?
+ ATTR_DOMAIN_POINT :
+ ATTR_DOMAIN_CORNER;
Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C);
Scene *scene_eval = DEG_get_evaluated_scene(depsgraph);
@@ -1389,7 +1391,7 @@ static const EnumPropertyItem *rna_DataTransferModifier_layers_select_src_itemf(
cdata = &me_eval->ldata;
}
- CustomDataType types[2] = {CD_PROP_COLOR, CD_PROP_BYTE_COLOR};
+ eCustomDataType types[2] = {CD_PROP_COLOR, CD_PROP_BYTE_COLOR};
int idx = 0;
for (int i = 0; i < 2; i++) {
@@ -1489,7 +1491,7 @@ static const EnumPropertyItem *rna_DataTransferModifier_layers_select_dst_itemf(
Object *ob_dst = CTX_data_active_object(C); /* XXX Is this OK? */
if (ob_dst && ob_dst->data) {
- CustomDataType types[2] = {CD_PROP_COLOR, CD_PROP_BYTE_COLOR};
+ eCustomDataType types[2] = {CD_PROP_COLOR, CD_PROP_BYTE_COLOR};
Mesh *me_dst = ob_dst->data;
CustomData *cdata = STREQ(RNA_property_identifier(prop), "layers_vcol_vert_select_dst") ?
@@ -4991,7 +4993,7 @@ static void rna_def_modifier_weightvg_mask(BlenderRNA *UNUSED(brna),
0,
"Object",
"Use local generated coordinates of another object"},
- {MOD_DISP_MAP_UV, "UV", 0, "UV", "Use coordinates from an UV layer"},
+ {MOD_DISP_MAP_UV, "UV", 0, "UV", "Use coordinates from a UV layer"},
{0, NULL, 0, NULL, NULL},
};
@@ -6991,7 +6993,7 @@ static void rna_def_modifier_nodes(BlenderRNA *brna)
RNA_def_struct_ui_text(srna, "Nodes Modifier", "");
RNA_def_struct_sdna(srna, "NodesModifierData");
RNA_def_struct_idprops_func(srna, "rna_NodesModifier_properties");
- RNA_def_struct_ui_icon(srna, ICON_NODETREE);
+ RNA_def_struct_ui_icon(srna, ICON_GEOMETRY_NODES);
RNA_define_lib_overridable(true);
diff --git a/source/blender/makesrna/intern/rna_movieclip.c b/source/blender/makesrna/intern/rna_movieclip.c
index e9b49dbe7d1..b5302eca1bf 100644
--- a/source/blender/makesrna/intern/rna_movieclip.c
+++ b/source/blender/makesrna/intern/rna_movieclip.c
@@ -118,6 +118,22 @@ static PointerRNA rna_MovieClip_metadata_get(MovieClip *clip)
return ptr;
}
+static char *rna_MovieClipUser_path(const PointerRNA *ptr)
+{
+ if (ptr->owner_id) {
+ /* MovieClipUser *mc_user = ptr->data; */
+
+ switch (GS(ptr->owner_id->name)) {
+ case ID_CA:
+ return rna_CameraBackgroundImage_image_or_movieclip_user_path(ptr);
+ default:
+ break;
+ }
+ }
+
+ return BLI_strdup("");
+}
+
#else
static void rna_def_movieclip_proxy(BlenderRNA *brna)
@@ -244,7 +260,7 @@ static void rna_def_movieclip_proxy(BlenderRNA *brna)
RNA_def_property_update(prop, NC_MOVIECLIP | ND_DISPLAY, "rna_MovieClip_reload_update");
}
-static void rna_def_moviecliUser(BlenderRNA *brna)
+static void rna_def_movieclipUser(BlenderRNA *brna)
{
StructRNA *srna;
PropertyRNA *prop;
@@ -263,6 +279,9 @@ static void rna_def_moviecliUser(BlenderRNA *brna)
srna,
"Movie Clip User",
"Parameters defining how a MovieClip data-block is used by another data-block");
+ RNA_def_struct_path_func(srna, "rna_MovieClipUser_path");
+
+ RNA_define_lib_overridable(true);
prop = RNA_def_property(srna, "frame_current", PROP_INT, PROP_TIME);
RNA_def_property_int_sdna(prop, NULL, "framenr");
@@ -286,6 +305,8 @@ static void rna_def_moviecliUser(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "Render Undistorted", "Render preview using undistorted proxy");
RNA_def_property_update(
prop, NC_MOVIECLIP | ND_DISPLAY, "rna_MovieClipUser_proxy_render_settings_update");
+
+ RNA_define_lib_overridable(false);
}
static void rna_def_movieClipScopes(BlenderRNA *brna)
@@ -435,7 +456,7 @@ void RNA_def_movieclip(BlenderRNA *brna)
{
rna_def_movieclip(brna);
rna_def_movieclip_proxy(brna);
- rna_def_moviecliUser(brna);
+ rna_def_movieclipUser(brna);
rna_def_movieClipScopes(brna);
}
diff --git a/source/blender/makesrna/intern/rna_nla.c b/source/blender/makesrna/intern/rna_nla.c
index f8a35246581..978a94ca7b0 100644
--- a/source/blender/makesrna/intern/rna_nla.c
+++ b/source/blender/makesrna/intern/rna_nla.c
@@ -23,6 +23,49 @@
#include "WM_api.h"
#include "WM_types.h"
+/* enum defines exported for rna_animation.c */
+const EnumPropertyItem rna_enum_nla_mode_blend_items[] = {
+ {NLASTRIP_MODE_REPLACE,
+ "REPLACE",
+ 0,
+ "Replace",
+ "The strip values replace the accumulated results by amount specified by influence"},
+ {NLASTRIP_MODE_COMBINE,
+ "COMBINE",
+ 0,
+ "Combine",
+ "The strip values are combined with accumulated results by appropriately using addition, "
+ "multiplication, or quaternion math, based on channel type"},
+ RNA_ENUM_ITEM_SEPR,
+ {NLASTRIP_MODE_ADD,
+ "ADD",
+ 0,
+ "Add",
+ "Weighted result of strip is added to the accumulated results"},
+ {NLASTRIP_MODE_SUBTRACT,
+ "SUBTRACT",
+ 0,
+ "Subtract",
+ "Weighted result of strip is removed from the accumulated results"},
+ {NLASTRIP_MODE_MULTIPLY,
+ "MULTIPLY",
+ 0,
+ "Multiply",
+ "Weighted result of strip is multiplied with the accumulated results"},
+ {0, NULL, 0, NULL, NULL},
+};
+
+const EnumPropertyItem rna_enum_nla_mode_extend_items[] = {
+ {NLASTRIP_EXTEND_NOTHING, "NOTHING", 0, "Nothing", "Strip has no influence past its extents"},
+ {NLASTRIP_EXTEND_HOLD,
+ "HOLD",
+ 0,
+ "Hold",
+ "Hold the first frame if no previous strips in track, and always hold last frame"},
+ {NLASTRIP_EXTEND_HOLD_FORWARD, "HOLD_FORWARD", 0, "Hold Forward", "Only hold last frame"},
+ {0, NULL, 0, NULL, NULL},
+};
+
#ifdef RNA_RUNTIME
# include <math.h>
@@ -57,7 +100,7 @@ static void rna_NlaStrip_name_set(PointerRNA *ptr, const char *value)
}
}
-static char *rna_NlaStrip_path(PointerRNA *ptr)
+static char *rna_NlaStrip_path(const PointerRNA *ptr)
{
NlaStrip *strip = (NlaStrip *)ptr->data;
AnimData *adt = BKE_animdata_from_id(ptr->owner_id);
@@ -494,49 +537,6 @@ static void rna_NlaTrack_solo_set(PointerRNA *ptr, bool value)
#else
-/* enum defines exported for rna_animation.c */
-const EnumPropertyItem rna_enum_nla_mode_blend_items[] = {
- {NLASTRIP_MODE_REPLACE,
- "REPLACE",
- 0,
- "Replace",
- "The strip values replace the accumulated results by amount specified by influence"},
- {NLASTRIP_MODE_COMBINE,
- "COMBINE",
- 0,
- "Combine",
- "The strip values are combined with accumulated results by appropriately using addition, "
- "multiplication, or quaternion math, based on channel type"},
- {0, "", 0, NULL, NULL},
- {NLASTRIP_MODE_ADD,
- "ADD",
- 0,
- "Add",
- "Weighted result of strip is added to the accumulated results"},
- {NLASTRIP_MODE_SUBTRACT,
- "SUBTRACT",
- 0,
- "Subtract",
- "Weighted result of strip is removed from the accumulated results"},
- {NLASTRIP_MODE_MULTIPLY,
- "MULTIPLY",
- 0,
- "Multiply",
- "Weighted result of strip is multiplied with the accumulated results"},
- {0, NULL, 0, NULL, NULL},
-};
-
-const EnumPropertyItem rna_enum_nla_mode_extend_items[] = {
- {NLASTRIP_EXTEND_NOTHING, "NOTHING", 0, "Nothing", "Strip has no influence past its extents"},
- {NLASTRIP_EXTEND_HOLD,
- "HOLD",
- 0,
- "Hold",
- "Hold the first frame if no previous strips in track, and always hold last frame"},
- {NLASTRIP_EXTEND_HOLD_FORWARD, "HOLD_FORWARD", 0, "Hold Forward", "Only hold last frame"},
- {0, NULL, 0, NULL, NULL},
-};
-
static void rna_def_strip_fcurves(BlenderRNA *brna, PropertyRNA *cprop)
{
StructRNA *srna;
diff --git a/source/blender/makesrna/intern/rna_nodetree.c b/source/blender/makesrna/intern/rna_nodetree.c
index 4cd12acd038..65a8d8bf24a 100644
--- a/source/blender/makesrna/intern/rna_nodetree.c
+++ b/source/blender/makesrna/intern/rna_nodetree.c
@@ -164,20 +164,20 @@ static const EnumPropertyItem rna_enum_vector_rotate_type_items[] = {
};
const EnumPropertyItem rna_enum_node_math_items[] = {
- {0, "", 0, N_("Functions"), ""},
+ RNA_ENUM_ITEM_HEADING(N_("Functions"), NULL),
{NODE_MATH_ADD, "ADD", 0, "Add", "A + B"},
{NODE_MATH_SUBTRACT, "SUBTRACT", 0, "Subtract", "A - B"},
{NODE_MATH_MULTIPLY, "MULTIPLY", 0, "Multiply", "A * B"},
{NODE_MATH_DIVIDE, "DIVIDE", 0, "Divide", "A / B"},
{NODE_MATH_MULTIPLY_ADD, "MULTIPLY_ADD", 0, "Multiply Add", "A * B + C"},
- {0, "", ICON_NONE, NULL, NULL},
+ RNA_ENUM_ITEM_SEPR,
{NODE_MATH_POWER, "POWER", 0, "Power", "A power B"},
{NODE_MATH_LOGARITHM, "LOGARITHM", 0, "Logarithm", "Logarithm A base B"},
{NODE_MATH_SQRT, "SQRT", 0, "Square Root", "Square root of A"},
{NODE_MATH_INV_SQRT, "INVERSE_SQRT", 0, "Inverse Square Root", "1 / Square root of A"},
{NODE_MATH_ABSOLUTE, "ABSOLUTE", 0, "Absolute", "Magnitude of A"},
{NODE_MATH_EXPONENT, "EXPONENT", 0, "Exponent", "exp(A)"},
- {0, "", 0, N_("Comparison"), ""},
+ RNA_ENUM_ITEM_HEADING(N_("Comparison"), NULL),
{NODE_MATH_MINIMUM, "MINIMUM", 0, "Minimum", "The minimum from A and B"},
{NODE_MATH_MAXIMUM, "MAXIMUM", 0, "Maximum", "The maximum from A and B"},
{NODE_MATH_LESS_THAN, "LESS_THAN", 0, "Less Than", "1 if A < B else 0"},
@@ -194,7 +194,7 @@ const EnumPropertyItem rna_enum_node_math_items[] = {
0,
"Smooth Maximum",
"The maximum from A and B with smoothing C"},
- {0, "", 0, N_("Rounding"), ""},
+ RNA_ENUM_ITEM_HEADING(N_("Rounding"), NULL),
{NODE_MATH_ROUND,
"ROUND",
0,
@@ -203,7 +203,7 @@ const EnumPropertyItem rna_enum_node_math_items[] = {
{NODE_MATH_FLOOR, "FLOOR", 0, "Floor", "The largest integer smaller than or equal A"},
{NODE_MATH_CEIL, "CEIL", 0, "Ceil", "The smallest integer greater than or equal A"},
{NODE_MATH_TRUNC, "TRUNC", 0, "Truncate", "The integer part of A, removing fractional digits"},
- {0, "", ICON_NONE, NULL, NULL},
+ RNA_ENUM_ITEM_SEPR,
{NODE_MATH_FRACTION, "FRACT", 0, "Fraction", "The fraction part of A"},
{NODE_MATH_MODULO, "MODULO", 0, "Modulo", "Modulo using fmod(A,B)"},
{NODE_MATH_WRAP, "WRAP", 0, "Wrap", "Wrap value to range, wrap(A,B)"},
@@ -213,20 +213,20 @@ const EnumPropertyItem rna_enum_node_math_items[] = {
0,
"Ping-Pong",
"Wraps a value and reverses every other cycle (A,B)"},
- {0, "", 0, N_("Trigonometric"), ""},
+ RNA_ENUM_ITEM_HEADING(N_("Trigonometric"), NULL),
{NODE_MATH_SINE, "SINE", 0, "Sine", "sin(A)"},
{NODE_MATH_COSINE, "COSINE", 0, "Cosine", "cos(A)"},
{NODE_MATH_TANGENT, "TANGENT", 0, "Tangent", "tan(A)"},
- {0, "", ICON_NONE, NULL, NULL},
+ RNA_ENUM_ITEM_SEPR,
{NODE_MATH_ARCSINE, "ARCSINE", 0, "Arcsine", "arcsin(A)"},
{NODE_MATH_ARCCOSINE, "ARCCOSINE", 0, "Arccosine", "arccos(A)"},
{NODE_MATH_ARCTANGENT, "ARCTANGENT", 0, "Arctangent", "arctan(A)"},
{NODE_MATH_ARCTAN2, "ARCTAN2", 0, "Arctan2", "The signed angle arctan(A / B)"},
- {0, "", ICON_NONE, NULL, NULL},
+ RNA_ENUM_ITEM_SEPR,
{NODE_MATH_SINH, "SINH", 0, "Hyperbolic Sine", "sinh(A)"},
{NODE_MATH_COSH, "COSH", 0, "Hyperbolic Cosine", "cosh(A)"},
{NODE_MATH_TANH, "TANH", 0, "Hyperbolic Tangent", "tanh(A)"},
- {0, "", 0, N_("Conversion"), ""},
+ RNA_ENUM_ITEM_HEADING(N_("Conversion"), NULL),
{NODE_MATH_RADIANS, "RADIANS", 0, "To Radians", "Convert from degrees to radians"},
{NODE_MATH_DEGREES, "DEGREES", 0, "To Degrees", "Convert from radians to degrees"},
{0, NULL, 0, NULL, NULL},
@@ -238,7 +238,7 @@ const EnumPropertyItem rna_enum_node_vec_math_items[] = {
{NODE_VECTOR_MATH_MULTIPLY, "MULTIPLY", 0, "Multiply", "Entry-wise multiply"},
{NODE_VECTOR_MATH_DIVIDE, "DIVIDE", 0, "Divide", "Entry-wise divide"},
{NODE_VECTOR_MATH_MULTIPLY_ADD, "MULTIPLY_ADD", 0, "Multiply Add", "A * B + C"},
- {0, "", ICON_NONE, NULL, NULL},
+ RNA_ENUM_ITEM_SEPR,
{NODE_VECTOR_MATH_CROSS_PRODUCT, "CROSS_PRODUCT", 0, "Cross Product", "A cross B"},
{NODE_VECTOR_MATH_PROJECT, "PROJECT", 0, "Project", "Project A onto B"},
{NODE_VECTOR_MATH_REFLECT,
@@ -259,12 +259,12 @@ const EnumPropertyItem rna_enum_node_vec_math_items[] = {
"Orients a vector A to point away from a surface B as defined by its normal C. "
"Returns (dot(B, C) < 0) ? A : -A"},
{NODE_VECTOR_MATH_DOT_PRODUCT, "DOT_PRODUCT", 0, "Dot Product", "A dot B"},
- {0, "", ICON_NONE, NULL, NULL},
+ RNA_ENUM_ITEM_SEPR,
{NODE_VECTOR_MATH_DISTANCE, "DISTANCE", 0, "Distance", "Distance between A and B"},
{NODE_VECTOR_MATH_LENGTH, "LENGTH", 0, "Length", "Length of A"},
{NODE_VECTOR_MATH_SCALE, "SCALE", 0, "Scale", "A multiplied by Scale"},
{NODE_VECTOR_MATH_NORMALIZE, "NORMALIZE", 0, "Normalize", "Normalize A"},
- {0, "", ICON_NONE, NULL, NULL},
+ RNA_ENUM_ITEM_SEPR,
{NODE_VECTOR_MATH_ABSOLUTE, "ABSOLUTE", 0, "Absolute", "Entry-wise absolute"},
{NODE_VECTOR_MATH_MINIMUM, "MINIMUM", 0, "Minimum", "Entry-wise minimum"},
{NODE_VECTOR_MATH_MAXIMUM, "MAXIMUM", 0, "Maximum", "Entry-wise maximum"},
@@ -278,7 +278,7 @@ const EnumPropertyItem rna_enum_node_vec_math_items[] = {
0,
"Snap",
"Round A to the largest integer multiple of B less than or equal A"},
- {0, "", ICON_NONE, NULL, NULL},
+ RNA_ENUM_ITEM_SEPR,
{NODE_VECTOR_MATH_SINE, "SINE", 0, "Sine", "Entry-wise sin(A)"},
{NODE_VECTOR_MATH_COSINE, "COSINE", 0, "Cosine", "Entry-wise cos(A)"},
{NODE_VECTOR_MATH_TANGENT, "TANGENT", 0, "Tangent", "Entry-wise tan(A)"},
@@ -289,7 +289,7 @@ const EnumPropertyItem rna_enum_node_boolean_math_items[] = {
{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},
+ RNA_ENUM_ITEM_SEPR,
{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,
@@ -302,7 +302,7 @@ const EnumPropertyItem rna_enum_node_boolean_math_items[] = {
0,
"Not Equal",
"True when both inputs are different (exclusive or)"},
- {0, "", ICON_NONE, NULL, NULL},
+ RNA_ENUM_ITEM_SEPR,
{NODE_BOOLEAN_MATH_IMPLY,
"IMPLY",
0,
@@ -443,9 +443,9 @@ const EnumPropertyItem rna_enum_node_clamp_items[] = {
static const EnumPropertyItem rna_enum_node_tex_dimensions_items[] = {
{1, "1D", 0, "1D", "Use the scalar value W as input"},
- {2, "2D", 0, "2D", "Use the 2D vector (x, y) as input. The z component is ignored"},
- {3, "3D", 0, "3D", "Use the 3D vector (x, y, z) as input"},
- {4, "4D", 0, "4D", "Use the 4D vector (x, y, z, w) as input"},
+ {2, "2D", 0, "2D", "Use the 2D vector (X, Y) as input. The Z component is ignored"},
+ {3, "3D", 0, "3D", "Use the 3D vector (X, Y, Z) as input"},
+ {4, "4D", 0, "4D", "Use the 4D vector (X, Y, Z, W) as input"},
{0, NULL, 0, NULL, NULL},
};
@@ -1598,38 +1598,43 @@ static StructRNA *rna_Node_refine(struct PointerRNA *ptr)
}
}
-static char *rna_Node_path(PointerRNA *ptr)
+static char *rna_Node_path(const PointerRNA *ptr)
{
- bNode *node = (bNode *)ptr->data;
+ const bNode *node = (bNode *)ptr->data;
char name_esc[sizeof(node->name) * 2];
BLI_str_escape(name_esc, node->name, sizeof(name_esc));
return BLI_sprintfN("nodes[\"%s\"]", name_esc);
}
-char *rna_Node_ImageUser_path(PointerRNA *ptr)
+char *rna_Node_ImageUser_path(const PointerRNA *ptr)
{
bNodeTree *ntree = (bNodeTree *)ptr->owner_id;
- bNode *node;
- char name_esc[sizeof(node->name) * 2];
+ if (!ELEM(ntree->type, NTREE_SHADER, NTREE_CUSTOM)) {
+ return NULL;
+ }
- for (node = ntree->nodes.first; node; node = node->next) {
- if (node->type == SH_NODE_TEX_ENVIRONMENT) {
- NodeTexEnvironment *data = node->storage;
- if (&data->iuser != ptr->data) {
- continue;
+ for (bNode *node = ntree->nodes.first; node; node = node->next) {
+ switch (node->type) {
+ case SH_NODE_TEX_ENVIRONMENT: {
+ NodeTexEnvironment *data = node->storage;
+ if (&data->iuser != ptr->data) {
+ continue;
+ }
+ break;
}
- }
- else if (node->type == SH_NODE_TEX_IMAGE) {
- NodeTexImage *data = node->storage;
- if (&data->iuser != ptr->data) {
- continue;
+ case SH_NODE_TEX_IMAGE: {
+ NodeTexImage *data = node->storage;
+ if (&data->iuser != ptr->data) {
+ continue;
+ }
+ break;
}
- }
- else {
- continue;
+ default:
+ continue;
}
+ char name_esc[sizeof(node->name) * 2];
BLI_str_escape(name_esc, node->name, sizeof(name_esc));
return BLI_sprintfN("nodes[\"%s\"].image_user", name_esc);
}
@@ -2756,7 +2761,7 @@ static StructRNA *rna_NodeSocket_refine(PointerRNA *ptr)
}
}
-static char *rna_NodeSocket_path(PointerRNA *ptr)
+static char *rna_NodeSocket_path(const PointerRNA *ptr)
{
bNodeTree *ntree = (bNodeTree *)ptr->owner_id;
bNodeSocket *sock = (bNodeSocket *)ptr->data;
@@ -3070,10 +3075,10 @@ static StructRNA *rna_NodeSocketInterface_refine(PointerRNA *ptr)
}
}
-static char *rna_NodeSocketInterface_path(PointerRNA *ptr)
+static char *rna_NodeSocketInterface_path(const PointerRNA *ptr)
{
- bNodeTree *ntree = (bNodeTree *)ptr->owner_id;
- bNodeSocket *sock = (bNodeSocket *)ptr->data;
+ const bNodeTree *ntree = (bNodeTree *)ptr->owner_id;
+ const bNodeSocket *sock = (bNodeSocket *)ptr->data;
int socketindex;
socketindex = BLI_findindex(&ntree->inputs, sock);
@@ -4523,9 +4528,9 @@ static const EnumPropertyItem prop_view_layer_items[] = {
};
static const EnumPropertyItem prop_tri_channel_items[] = {
- {1, "R", 0, "R", ""},
- {2, "G", 0, "G", ""},
- {3, "B", 0, "B", ""},
+ {1, "R", 0, "R", "Red"},
+ {2, "G", 0, "G", "Green"},
+ {3, "B", 0, "B", "Blue"},
{0, NULL, 0, NULL, NULL},
};
@@ -4544,46 +4549,81 @@ static const EnumPropertyItem node_ycc_items[] = {
};
static const EnumPropertyItem node_glossy_items[] = {
- {SHD_GLOSSY_SHARP, "SHARP", 0, "Sharp", ""},
+ {SHD_GLOSSY_SHARP,
+ "SHARP",
+ 0,
+ "Sharp",
+ "Results in perfectly sharp reflections like a mirror. The Roughness value is not used"},
{SHD_GLOSSY_BECKMANN, "BECKMANN", 0, "Beckmann", ""},
{SHD_GLOSSY_GGX, "GGX", 0, "GGX", ""},
{SHD_GLOSSY_ASHIKHMIN_SHIRLEY, "ASHIKHMIN_SHIRLEY", 0, "Ashikhmin-Shirley", ""},
- {SHD_GLOSSY_MULTI_GGX, "MULTI_GGX", 0, "Multiscatter GGX", ""},
+ {SHD_GLOSSY_MULTI_GGX,
+ "MULTI_GGX",
+ 0,
+ "Multiscatter GGX",
+ "Slower than GGX but gives a more energy conserving results, which would otherwise be "
+ "visible as excessive darkening"},
{0, NULL, 0, NULL, NULL},
};
static const EnumPropertyItem node_anisotropic_items[] = {
{SHD_GLOSSY_BECKMANN, "BECKMANN", 0, "Beckmann", ""},
{SHD_GLOSSY_GGX, "GGX", 0, "GGX", ""},
- {SHD_GLOSSY_MULTI_GGX, "MULTI_GGX", 0, "Multiscatter GGX", ""},
+ {SHD_GLOSSY_MULTI_GGX,
+ "MULTI_GGX",
+ 0,
+ "Multiscatter GGX",
+ "Slower than GGX but gives a more energy conserving results, which would otherwise be "
+ "visible as excessive darkening"},
{SHD_GLOSSY_ASHIKHMIN_SHIRLEY, "ASHIKHMIN_SHIRLEY", 0, "Ashikhmin-Shirley", ""},
{0, NULL, 0, NULL, NULL},
};
static const EnumPropertyItem node_glass_items[] = {
- {SHD_GLOSSY_SHARP, "SHARP", 0, "Sharp", ""},
+ {SHD_GLOSSY_SHARP,
+ "SHARP",
+ 0,
+ "Sharp",
+ "Results in perfectly sharp reflections like a mirror. The Roughness value is not used"},
{SHD_GLOSSY_BECKMANN, "BECKMANN", 0, "Beckmann", ""},
{SHD_GLOSSY_GGX, "GGX", 0, "GGX", ""},
- {SHD_GLOSSY_MULTI_GGX, "MULTI_GGX", 0, "Multiscatter GGX", ""},
+ {SHD_GLOSSY_MULTI_GGX,
+ "MULTI_GGX",
+ 0,
+ "Multiscatter GGX",
+ "Slower than GGX but gives a more energy conserving results, which would otherwise be "
+ "visible as excessive darkening"},
{0, NULL, 0, NULL, NULL},
};
static const EnumPropertyItem node_refraction_items[] = {
- {SHD_GLOSSY_SHARP, "SHARP", 0, "Sharp", ""},
+ {SHD_GLOSSY_SHARP,
+ "SHARP",
+ 0,
+ "Sharp",
+ "Results in perfectly sharp reflections like a mirror. The Roughness value is not used"},
{SHD_GLOSSY_BECKMANN, "BECKMANN", 0, "Beckmann", ""},
{SHD_GLOSSY_GGX, "GGX", 0, "GGX", ""},
{0, NULL, 0, NULL, NULL},
};
static const EnumPropertyItem node_toon_items[] = {
- {SHD_TOON_DIFFUSE, "DIFFUSE", 0, "Diffuse", ""},
- {SHD_TOON_GLOSSY, "GLOSSY", 0, "Glossy", ""},
+ {SHD_TOON_DIFFUSE, "DIFFUSE", 0, "Diffuse", "Use diffuse BSDF"},
+ {SHD_TOON_GLOSSY, "GLOSSY", 0, "Glossy", "Use glossy BSDF"},
{0, NULL, 0, NULL, NULL},
};
static const EnumPropertyItem node_hair_items[] = {
- {SHD_HAIR_REFLECTION, "Reflection", 0, "Reflection", ""},
- {SHD_HAIR_TRANSMISSION, "Transmission", 0, "Transmission", ""},
+ {SHD_HAIR_REFLECTION,
+ "Reflection",
+ 0,
+ "Reflection",
+ "The light that bounces off the surface of the hair"},
+ {SHD_HAIR_TRANSMISSION,
+ "Transmission",
+ 0,
+ "Transmission",
+ "The light that passes through the hair and exits on the other side"},
{0, NULL, 0, NULL, NULL},
};
@@ -4623,7 +4663,12 @@ static EnumPropertyItem node_ies_mode_items[] = {
static const EnumPropertyItem node_principled_distribution_items[] = {
{SHD_GLOSSY_GGX, "GGX", 0, "GGX", ""},
- {SHD_GLOSSY_MULTI_GGX, "MULTI_GGX", 0, "Multiscatter GGX", ""},
+ {SHD_GLOSSY_MULTI_GGX,
+ "MULTI_GGX",
+ 0,
+ "Multiscatter GGX",
+ "Slower than GGX but gives a more energy conserving results, which would otherwise be "
+ "visible as excessive darkening"},
{0, NULL, 0, NULL, NULL},
};
@@ -5517,8 +5562,7 @@ static void def_sh_tex_noise(StructRNA *srna)
prop = RNA_def_property(srna, "noise_dimensions", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_sdna(prop, NULL, "dimensions");
RNA_def_property_enum_items(prop, rna_enum_node_tex_dimensions_items);
- RNA_def_property_ui_text(
- prop, "Dimensions", "The dimensions of the space to evaluate the noise in");
+ RNA_def_property_ui_text(prop, "Dimensions", "Number of dimensions to output noise for");
RNA_def_property_update(prop, 0, "rna_ShaderNode_socket_update");
}
@@ -5581,11 +5625,28 @@ static void def_sh_tex_magic(StructRNA *srna)
static void def_sh_tex_musgrave(StructRNA *srna)
{
static const EnumPropertyItem prop_musgrave_type[] = {
- {SHD_MUSGRAVE_MULTIFRACTAL, "MULTIFRACTAL", 0, "Multifractal", ""},
- {SHD_MUSGRAVE_RIDGED_MULTIFRACTAL, "RIDGED_MULTIFRACTAL", 0, "Ridged Multifractal", ""},
- {SHD_MUSGRAVE_HYBRID_MULTIFRACTAL, "HYBRID_MULTIFRACTAL", 0, "Hybrid Multifractal", ""},
- {SHD_MUSGRAVE_FBM, "FBM", 0, "fBM", ""},
- {SHD_MUSGRAVE_HETERO_TERRAIN, "HETERO_TERRAIN", 0, "Hetero Terrain", ""},
+ {SHD_MUSGRAVE_MULTIFRACTAL,
+ "MULTIFRACTAL",
+ 0,
+ "Multifractal",
+ "More uneven result (varies with location), more similar to a real terrain"},
+ {SHD_MUSGRAVE_RIDGED_MULTIFRACTAL,
+ "RIDGED_MULTIFRACTAL",
+ 0,
+ "Ridged Multifractal",
+ "Create sharp peaks"},
+ {SHD_MUSGRAVE_HYBRID_MULTIFRACTAL,
+ "HYBRID_MULTIFRACTAL",
+ 0,
+ "Hybrid Multifractal",
+ "Create peaks and valleys with different roughness values"},
+ {SHD_MUSGRAVE_FBM, "FBM", 0, "fBM", "Produce an unnatural homogeneous and isotropic result"},
+ {SHD_MUSGRAVE_HETERO_TERRAIN,
+ "HETERO_TERRAIN",
+ 0,
+ "Hetero Terrain",
+ "Similar to Hybrid Multifractal creates a heterogeneous terrain, but with the likeness of "
+ "river channels"},
{0, NULL, 0, NULL, NULL},
};
@@ -5597,13 +5658,13 @@ static void def_sh_tex_musgrave(StructRNA *srna)
prop = RNA_def_property(srna, "musgrave_dimensions", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_sdna(prop, NULL, "dimensions");
RNA_def_property_enum_items(prop, rna_enum_node_tex_dimensions_items);
- RNA_def_property_ui_text(prop, "Dimensions", "");
+ RNA_def_property_ui_text(prop, "Dimensions", "Number of dimensions to output noise for");
RNA_def_property_update(prop, 0, "rna_ShaderNode_socket_update");
prop = RNA_def_property(srna, "musgrave_type", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_sdna(prop, NULL, "musgrave_type");
RNA_def_property_enum_items(prop, prop_musgrave_type);
- RNA_def_property_ui_text(prop, "Type", "");
+ RNA_def_property_ui_text(prop, "Type", "Type of the Musgrave texture");
RNA_def_property_update(prop, 0, "rna_ShaderNode_socket_update");
}
@@ -5652,19 +5713,21 @@ static void def_sh_tex_voronoi(StructRNA *srna)
prop = RNA_def_property(srna, "voronoi_dimensions", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_sdna(prop, NULL, "dimensions");
RNA_def_property_enum_items(prop, rna_enum_node_tex_dimensions_items);
- RNA_def_property_ui_text(prop, "Dimensions", "");
+ RNA_def_property_ui_text(prop, "Dimensions", "Number of dimensions to output noise for");
RNA_def_property_update(prop, 0, "rna_ShaderNode_socket_update");
prop = RNA_def_property(srna, "distance", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_sdna(prop, NULL, "distance");
RNA_def_property_enum_items(prop, prop_distance_items);
- RNA_def_property_ui_text(prop, "Distance Metric", "");
+ RNA_def_property_ui_text(
+ prop, "Distance Metric", "The distance metric used to compute the texture");
RNA_def_property_update(prop, 0, "rna_ShaderNode_socket_update");
prop = RNA_def_property(srna, "feature", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_sdna(prop, NULL, "feature");
RNA_def_property_enum_items(prop, prop_feature_items);
- RNA_def_property_ui_text(prop, "Feature Output", "");
+ RNA_def_property_ui_text(
+ prop, "Feature Output", "The Voronoi feature that the node will compute");
RNA_def_property_update(prop, 0, "rna_ShaderNode_socket_update");
}
@@ -5740,8 +5803,7 @@ static void def_sh_tex_white_noise(StructRNA *srna)
prop = RNA_def_property(srna, "noise_dimensions", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_sdna(prop, NULL, "custom1");
RNA_def_property_enum_items(prop, rna_enum_node_tex_dimensions_items);
- RNA_def_property_ui_text(
- prop, "Dimensions", "The dimensions of the space to evaluate the noise in");
+ RNA_def_property_ui_text(prop, "Dimensions", "Number of dimensions to output noise for");
RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_ShaderNode_socket_update");
}
@@ -5983,7 +6045,7 @@ static void def_glossy(StructRNA *srna)
prop = RNA_def_property(srna, "distribution", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_sdna(prop, NULL, "custom1");
RNA_def_property_enum_items(prop, node_glossy_items);
- RNA_def_property_ui_text(prop, "Distribution", "");
+ RNA_def_property_ui_text(prop, "Distribution", "Light scattering distribution on rough surface");
RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update");
}
@@ -5994,7 +6056,7 @@ static void def_glass(StructRNA *srna)
prop = RNA_def_property(srna, "distribution", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_sdna(prop, NULL, "custom1");
RNA_def_property_enum_items(prop, node_glass_items);
- RNA_def_property_ui_text(prop, "Distribution", "");
+ RNA_def_property_ui_text(prop, "Distribution", "Light scattering distribution on rough surface");
RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update");
}
@@ -6005,7 +6067,7 @@ static void def_principled(StructRNA *srna)
prop = RNA_def_property(srna, "distribution", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_sdna(prop, NULL, "custom1");
RNA_def_property_enum_items(prop, node_principled_distribution_items);
- RNA_def_property_ui_text(prop, "Distribution", "");
+ RNA_def_property_ui_text(prop, "Distribution", "Light scattering distribution on rough surface");
RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_ShaderNode_socket_update");
prop = RNA_def_property(srna, "subsurface_method", PROP_ENUM, PROP_NONE);
@@ -6023,7 +6085,7 @@ static void def_refraction(StructRNA *srna)
prop = RNA_def_property(srna, "distribution", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_sdna(prop, NULL, "custom1");
RNA_def_property_enum_items(prop, node_refraction_items);
- RNA_def_property_ui_text(prop, "Distribution", "");
+ RNA_def_property_ui_text(prop, "Distribution", "Light scattering distribution on rough surface");
RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update");
}
@@ -6034,7 +6096,7 @@ static void def_anisotropic(StructRNA *srna)
prop = RNA_def_property(srna, "distribution", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_sdna(prop, NULL, "custom1");
RNA_def_property_enum_items(prop, node_anisotropic_items);
- RNA_def_property_ui_text(prop, "Distribution", "");
+ RNA_def_property_ui_text(prop, "Distribution", "Light scattering distribution on rough surface");
RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update");
}
@@ -6045,7 +6107,7 @@ static void def_toon(StructRNA *srna)
prop = RNA_def_property(srna, "component", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_sdna(prop, NULL, "custom1");
RNA_def_property_enum_items(prop, node_toon_items);
- RNA_def_property_ui_text(prop, "Component", "");
+ RNA_def_property_ui_text(prop, "Component", "Toon BSDF component to use");
RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update");
}
@@ -6067,7 +6129,7 @@ static void def_hair(StructRNA *srna)
prop = RNA_def_property(srna, "component", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_sdna(prop, NULL, "custom1");
RNA_def_property_enum_items(prop, node_hair_items);
- RNA_def_property_ui_text(prop, "Component", "");
+ RNA_def_property_ui_text(prop, "Component", "Hair BSDF component to use");
RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update");
}
@@ -9518,18 +9580,14 @@ static void def_geo_distribute_points_on_faces(StructRNA *srna)
static void def_geo_curve_spline_type(StructRNA *srna)
{
- static const EnumPropertyItem type_items[] = {
- {GEO_NODE_SPLINE_TYPE_BEZIER, "BEZIER", ICON_NONE, "Bezier", "Set the splines to Bezier"},
- {GEO_NODE_SPLINE_TYPE_NURBS, "NURBS", ICON_NONE, "NURBS", "Set the splines to NURBS"},
- {GEO_NODE_SPLINE_TYPE_POLY, "POLY", ICON_NONE, "Poly", "Set the splines to Poly"},
- {0, NULL, 0, NULL, NULL}};
-
PropertyRNA *prop;
RNA_def_struct_sdna_from(srna, "NodeGeometryCurveSplineType", "storage");
prop = RNA_def_property(srna, "spline_type", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_sdna(prop, NULL, "spline_type");
- RNA_def_property_enum_items(prop, type_items);
+ RNA_def_property_enum_items(prop, rna_enum_curves_types);
+ RNA_def_property_ui_text(prop, "Type", "The curve type to change the selected curves to");
+
RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_socket_update");
}
@@ -12369,7 +12427,7 @@ static void rna_def_nodetree(BlenderRNA *brna)
{NTREE_SHADER, "SHADER", ICON_MATERIAL, "Shader", "Shader nodes"},
{NTREE_TEXTURE, "TEXTURE", ICON_TEXTURE, "Texture", "Texture nodes"},
{NTREE_COMPOSIT, "COMPOSITING", ICON_RENDERLAYERS, "Compositing", "Compositing nodes"},
- {NTREE_GEOMETRY, "GEOMETRY", ICON_NODETREE, "Geometry", "Geometry nodes"},
+ {NTREE_GEOMETRY, "GEOMETRY", ICON_GEOMETRY_NODES, "Geometry", "Geometry nodes"},
{0, NULL, 0, NULL, NULL},
};
diff --git a/source/blender/makesrna/intern/rna_object.c b/source/blender/makesrna/intern/rna_object.c
index 1fb41bf792f..56652a35ecb 100644
--- a/source/blender/makesrna/intern/rna_object.c
+++ b/source/blender/makesrna/intern/rna_object.c
@@ -149,7 +149,7 @@ const EnumPropertyItem rna_enum_object_gpencil_type_items[] = {
{GP_EMPTY, "EMPTY", ICON_EMPTY_AXIS, "Blank", "Create an empty grease pencil object"},
{GP_STROKE, "STROKE", ICON_STROKE, "Stroke", "Create a simple stroke with basic colors"},
{GP_MONKEY, "MONKEY", ICON_MONKEY, "Monkey", "Construct a Suzanne grease pencil object"},
- {0, "", 0, NULL, NULL},
+ RNA_ENUM_ITEM_SEPR,
{GP_LRT_SCENE,
"LRT_SCENE",
ICON_SCENE_DATA,
@@ -256,17 +256,17 @@ const EnumPropertyItem rna_enum_object_type_items[] = {
{OB_POINTCLOUD, "POINTCLOUD", ICON_OUTLINER_OB_POINTCLOUD, "Point Cloud", ""},
{OB_VOLUME, "VOLUME", ICON_OUTLINER_OB_VOLUME, "Volume", ""},
{OB_GPENCIL, "GPENCIL", ICON_OUTLINER_OB_GREASEPENCIL, "Grease Pencil", ""},
- {0, "", 0, NULL, NULL},
+ RNA_ENUM_ITEM_SEPR,
{OB_ARMATURE, "ARMATURE", ICON_OUTLINER_OB_ARMATURE, "Armature", ""},
{OB_LATTICE, "LATTICE", ICON_OUTLINER_OB_LATTICE, "Lattice", ""},
- {0, "", 0, NULL, NULL},
+ RNA_ENUM_ITEM_SEPR,
{OB_EMPTY, "EMPTY", ICON_OUTLINER_OB_EMPTY, "Empty", ""},
- {0, "", 0, NULL, NULL},
+ RNA_ENUM_ITEM_SEPR,
{OB_LAMP, "LIGHT", ICON_OUTLINER_OB_LIGHT, "Light", ""},
{OB_LIGHTPROBE, "LIGHT_PROBE", ICON_OUTLINER_OB_LIGHTPROBE, "Light Probe", ""},
- {0, "", 0, NULL, NULL},
+ RNA_ENUM_ITEM_SEPR,
{OB_CAMERA, "CAMERA", ICON_OUTLINER_OB_CAMERA, "Camera", ""},
- {0, "", 0, NULL, NULL},
+ RNA_ENUM_ITEM_SEPR,
{OB_SPEAKER, "SPEAKER", ICON_OUTLINER_OB_SPEAKER, "Speaker", ""},
{0, NULL, 0, NULL, NULL},
};
@@ -1320,12 +1320,17 @@ static int rna_Object_rotation_4d_editable(PointerRNA *ptr, int index)
return PROP_EDITABLE;
}
-static int rna_MaterialSlot_index(PointerRNA *ptr)
+static int rna_MaterialSlot_index(const PointerRNA *ptr)
{
/* There is an offset, so that `ptr->data` is not null and unique across IDs. */
return (uintptr_t)ptr->data - (uintptr_t)ptr->owner_id;
}
+static int rna_MaterialSlot_index_get(PointerRNA *ptr)
+{
+ return rna_MaterialSlot_index(ptr);
+}
+
static int rna_MaterialSlot_material_editable(PointerRNA *ptr, const char **UNUSED(r_info))
{
Object *ob = (Object *)ptr->owner_id;
@@ -1451,7 +1456,7 @@ static void rna_MaterialSlot_update(Main *bmain, Scene *scene, PointerRNA *ptr)
DEG_relations_tag_update(bmain);
}
-static char *rna_MaterialSlot_path(PointerRNA *ptr)
+static char *rna_MaterialSlot_path(const PointerRNA *ptr)
{
int index = rna_MaterialSlot_index(ptr);
return BLI_sprintfN("material_slots[%d]", index);
@@ -1504,7 +1509,7 @@ static PointerRNA rna_Object_display_get(PointerRNA *ptr)
return rna_pointer_inherit_refine(ptr, &RNA_ObjectDisplay, ptr->data);
}
-static char *rna_ObjectDisplay_path(PointerRNA *UNUSED(ptr))
+static char *rna_ObjectDisplay_path(const PointerRNA *UNUSED(ptr))
{
return BLI_strdup("display");
}
@@ -1829,6 +1834,24 @@ bool rna_Object_modifiers_override_apply(Main *bmain,
ModifierData *mod_dst = ED_object_modifier_add(
NULL, bmain, NULL, ob_dst, mod_src->name, mod_src->type);
+ if (mod_dst == NULL) {
+ /* This can happen e.g. when a modifier type is tagged as `eModifierTypeFlag_Single`, and that
+ * modifier has somehow been added already by another code path (e.g.
+ * `rna_CollisionSettings_dependency_update` does add the `eModifierType_Collision` singleton
+ * modifier).
+ *
+ * Try to handle this by finding already existing one here. */
+ const ModifierTypeInfo *mti = BKE_modifier_get_info((ModifierType)mod_src->type);
+ if (mti->flags & eModifierTypeFlag_Single) {
+ mod_dst = BKE_modifiers_findby_type(ob_dst, (ModifierType)mod_src->type);
+ }
+
+ if (mod_dst == NULL) {
+ BLI_assert(mod_src != NULL);
+ return false;
+ }
+ }
+
/* XXX Current handling of 'copy' from particle-system modifier is *very* bad (it keeps same psys
* pointer as source, then calling code copies psys of object separately and do some magic
* remapping of pointers...), unfortunately several pieces of code in Object editing area rely on
@@ -2466,7 +2489,7 @@ static void rna_def_material_slot(BlenderRNA *brna)
prop = RNA_def_property(srna, "slot_index", PROP_INT, PROP_NONE);
RNA_def_property_clear_flag(prop, PROP_EDITABLE);
- RNA_def_property_int_funcs(prop, "rna_MaterialSlot_index", NULL, NULL);
+ RNA_def_property_int_funcs(prop, "rna_MaterialSlot_index_get", NULL, NULL);
prop = RNA_def_property(srna, "name", PROP_STRING, PROP_NONE);
RNA_def_property_string_funcs(
diff --git a/source/blender/makesrna/intern/rna_object_force.c b/source/blender/makesrna/intern/rna_object_force.c
index f92ea8df459..2ed539aa511 100644
--- a/source/blender/makesrna/intern/rna_object_force.c
+++ b/source/blender/makesrna/intern/rna_object_force.c
@@ -130,7 +130,7 @@ static bool rna_Cache_get_valid_owner_ID(PointerRNA *ptr, Object **ob, Scene **s
return (*ob != NULL || *scene != NULL);
}
-static char *rna_PointCache_path(PointerRNA *ptr)
+static char *rna_PointCache_path(const PointerRNA *ptr)
{
ModifierData *md;
Object *ob = (Object *)ptr->owner_id;
@@ -443,7 +443,7 @@ int rna_Cache_info_length(PointerRNA *ptr)
return (int)strlen(cache->info);
}
-static char *rna_CollisionSettings_path(PointerRNA *UNUSED(ptr))
+static char *rna_CollisionSettings_path(const PointerRNA *UNUSED(ptr))
{
/* both methods work ok, but return the shorter path */
# if 0
@@ -619,17 +619,17 @@ static void rna_SoftBodySettings_spring_vgroup_set(PointerRNA *ptr, const char *
rna_object_vgroup_name_set(ptr, value, sb->namedVG_Spring_K, sizeof(sb->namedVG_Spring_K));
}
-static char *rna_SoftBodySettings_path(PointerRNA *ptr)
+static char *rna_SoftBodySettings_path(const PointerRNA *ptr)
{
- Object *ob = (Object *)ptr->owner_id;
- ModifierData *md = (ModifierData *)BKE_modifiers_findby_type(ob, eModifierType_Softbody);
+ const Object *ob = (Object *)ptr->owner_id;
+ const ModifierData *md = BKE_modifiers_findby_type(ob, eModifierType_Softbody);
char name_esc[sizeof(md->name) * 2];
BLI_str_escape(name_esc, md->name, sizeof(name_esc));
return BLI_sprintfN("modifiers[\"%s\"].settings", name_esc);
}
-static int particle_id_check(PointerRNA *ptr)
+static int particle_id_check(const PointerRNA *ptr)
{
ID *id = ptr->owner_id;
@@ -731,7 +731,7 @@ static void rna_FieldSettings_dependency_update(Main *bmain, Scene *scene, Point
}
}
-static char *rna_FieldSettings_path(PointerRNA *ptr)
+static char *rna_FieldSettings_path(const PointerRNA *ptr)
{
PartDeflect *pd = (PartDeflect *)ptr->data;
@@ -787,7 +787,7 @@ static void rna_EffectorWeight_dependency_update(Main *bmain,
WM_main_add_notifier(NC_OBJECT | ND_DRAW, NULL);
}
-static char *rna_EffectorWeight_path(PointerRNA *ptr)
+static char *rna_EffectorWeight_path(const PointerRNA *ptr)
{
EffectorWeights *ew = (EffectorWeights *)ptr->data;
/* Check through all possible places the settings can be to find the right one */
@@ -1395,97 +1395,97 @@ static void rna_def_field(BlenderRNA *brna)
PropertyRNA *prop;
static const EnumPropertyItem field_type_items[] = {
- {0, "NONE", 0, "None", ""},
+ {0, "NONE", ICON_BLANK1, "None", ""},
+ {PFIELD_BOID,
+ "BOID",
+ ICON_FORCE_BOID,
+ "Boid",
+ "Create a force that acts as a boid's predators or target"},
+ {PFIELD_CHARGE,
+ "CHARGE",
+ ICON_FORCE_CHARGE,
+ "Charge",
+ "Spherical forcefield based on the charge of particles, "
+ "only influences other charge force fields"},
+ {PFIELD_GUIDE,
+ "GUIDE",
+ ICON_FORCE_CURVE,
+ "Curve Guide",
+ "Create a force along a curve object"},
+ {PFIELD_DRAG, "DRAG", ICON_FORCE_DRAG, "Drag", "Create a force that dampens motion"},
+ {PFIELD_FLUIDFLOW,
+ "FLUID_FLOW",
+ ICON_FORCE_FLUIDFLOW,
+ "Fluid Flow",
+ "Create a force based on fluid simulation velocities"},
{PFIELD_FORCE,
"FORCE",
ICON_FORCE_FORCE,
"Force",
"Radial field toward the center of object"},
- {PFIELD_WIND,
- "WIND",
- ICON_FORCE_WIND,
- "Wind",
- "Constant force along the force object's local Z axis"},
- {PFIELD_VORTEX,
- "VORTEX",
- ICON_FORCE_VORTEX,
- "Vortex",
- "Spiraling force that twists the force object's local Z axis"},
- {PFIELD_MAGNET,
- "MAGNET",
- ICON_FORCE_MAGNETIC,
- "Magnetic",
- "Forcefield depends on the speed of the particles"},
{PFIELD_HARMONIC,
"HARMONIC",
ICON_FORCE_HARMONIC,
"Harmonic",
"The source of this force field is the zero point of a harmonic oscillator"},
- {PFIELD_CHARGE,
- "CHARGE",
- ICON_FORCE_CHARGE,
- "Charge",
- "Spherical forcefield based on the charge of particles, "
- "only influences other charge force fields"},
{PFIELD_LENNARDJ,
"LENNARDJ",
ICON_FORCE_LENNARDJONES,
"Lennard-Jones",
"Forcefield based on the Lennard-Jones potential"},
+ {PFIELD_MAGNET,
+ "MAGNET",
+ ICON_FORCE_MAGNETIC,
+ "Magnetic",
+ "Forcefield depends on the speed of the particles"},
{PFIELD_TEXTURE, "TEXTURE", ICON_FORCE_TEXTURE, "Texture", "Force field based on a texture"},
- {PFIELD_GUIDE,
- "GUIDE",
- ICON_FORCE_CURVE,
- "Curve Guide",
- "Create a force along a curve object"},
- {PFIELD_BOID,
- "BOID",
- ICON_FORCE_BOID,
- "Boid",
- "Create a force that acts as a boid's predators or target"},
{PFIELD_TURBULENCE,
"TURBULENCE",
ICON_FORCE_TURBULENCE,
"Turbulence",
"Create turbulence with a noise field"},
- {PFIELD_DRAG, "DRAG", ICON_FORCE_DRAG, "Drag", "Create a force that dampens motion"},
- {PFIELD_FLUIDFLOW,
- "FLUID_FLOW",
- ICON_FORCE_FLUIDFLOW,
- "Fluid Flow",
- "Create a force based on fluid simulation velocities"},
+ {PFIELD_VORTEX,
+ "VORTEX",
+ ICON_FORCE_VORTEX,
+ "Vortex",
+ "Spiraling force that twists the force object's local Z axis"},
+ {PFIELD_WIND,
+ "WIND",
+ ICON_FORCE_WIND,
+ "Wind",
+ "Constant force along the force object's local Z axis"},
{0, NULL, 0, NULL, NULL},
};
static const EnumPropertyItem falloff_items[] = {
+ {PFIELD_FALL_CONE, "CONE", 0, "Cone", ""},
{PFIELD_FALL_SPHERE, "SPHERE", 0, "Sphere", ""},
{PFIELD_FALL_TUBE, "TUBE", 0, "Tube", ""},
- {PFIELD_FALL_CONE, "CONE", 0, "Cone", ""},
{0, NULL, 0, NULL, NULL},
};
static const EnumPropertyItem texture_items[] = {
- {PFIELD_TEX_RGB, "RGB", 0, "RGB", ""},
- {PFIELD_TEX_GRAD, "GRADIENT", 0, "Gradient", ""},
{PFIELD_TEX_CURL, "CURL", 0, "Curl", ""},
+ {PFIELD_TEX_GRAD, "GRADIENT", 0, "Gradient", ""},
+ {PFIELD_TEX_RGB, "RGB", 0, "RGB", ""},
{0, NULL, 0, NULL, NULL},
};
static const EnumPropertyItem zdirection_items[] = {
- {PFIELD_Z_BOTH, "BOTH", 0, "Both Z", ""},
{PFIELD_Z_POS, "POSITIVE", 0, "+Z", ""},
{PFIELD_Z_NEG, "NEGATIVE", 0, "-Z", ""},
+ {PFIELD_Z_BOTH, "BOTH", 0, "Both Z", ""},
{0, NULL, 0, NULL, NULL},
};
static const EnumPropertyItem guide_kink_items[] = {
- {0, "NONE", 0, "Nothing", ""},
+ {0, "NONE", 0, "None", ""},
+ {4, "BRAID", 0, "Braid", ""},
{1, "CURL", 0, "Curl", ""},
{2, "RADIAL", 0, "Radial", ""},
- {3, "WAVE", 0, "Wave", ""},
- {4, "BRAID", 0, "Braid", ""},
- {5, "ROTATION", 0, "Rotation", ""},
{6, "ROLL", 0, "Roll", ""},
+ {5, "ROTATION", 0, "Rotation", ""},
+ {3, "WAVE", 0, "Wave", ""},
{0, NULL, 0, NULL, NULL},
};
diff --git a/source/blender/makesrna/intern/rna_particle.c b/source/blender/makesrna/intern/rna_particle.c
index 6f2264680c8..a67b0f7c8e6 100644
--- a/source/blender/makesrna/intern/rna_particle.c
+++ b/source/blender/makesrna/intern/rna_particle.c
@@ -660,7 +660,7 @@ static void rna_ParticleSystem_uv_on_emitter(ParticleSystem *particlesystem,
}
else {
MFace *mface = &modifier->mesh_final->mface[num];
- MTFace *mtface = (MTFace *)CustomData_get_layer_n(
+ const MTFace *mtface = (const MTFace *)CustomData_get_layer_n(
&modifier->mesh_final->fdata, CD_MTFACE, uv_no);
psys_interpolate_uvs(&mtface[num], mface->v4, *fuv, r_uv);
@@ -694,7 +694,8 @@ static void rna_ParticleSystem_mcol_on_emitter(ParticleSystem *particlesystem,
}
else {
MFace *mface = &modifier->mesh_final->mface[num];
- MCol *mc = (MCol *)CustomData_get_layer_n(&modifier->mesh_final->fdata, CD_MCOL, vcol_no);
+ const MCol *mc = (const MCol *)CustomData_get_layer_n(
+ &modifier->mesh_final->fdata, CD_MCOL, vcol_no);
MCol mcol;
psys_interpolate_mcol(&mc[num * 4], mface->v4, *fuv, &mcol);
@@ -1207,19 +1208,19 @@ static int rna_ParticleTarget_name_length(PointerRNA *ptr)
return strlen(tstr);
}
-static int particle_id_check(PointerRNA *ptr)
+static int particle_id_check(const PointerRNA *ptr)
{
- ID *id = ptr->owner_id;
+ const ID *id = ptr->owner_id;
return (GS(id->name) == ID_PA);
}
-static char *rna_SPHFluidSettings_path(PointerRNA *ptr)
+static char *rna_SPHFluidSettings_path(const PointerRNA *ptr)
{
- SPHFluidSettings *fluid = (SPHFluidSettings *)ptr->data;
+ const SPHFluidSettings *fluid = (SPHFluidSettings *)ptr->data;
if (particle_id_check(ptr)) {
- ParticleSettings *part = (ParticleSettings *)ptr->owner_id;
+ const ParticleSettings *part = (ParticleSettings *)ptr->owner_id;
if (part->fluid == fluid) {
return BLI_strdup("fluid");
@@ -1462,9 +1463,9 @@ static void psys_vg_name_set__internal(PointerRNA *ptr, const char *value, int i
}
}
-static char *rna_ParticleSystem_path(PointerRNA *ptr)
+static char *rna_ParticleSystem_path(const PointerRNA *ptr)
{
- ParticleSystem *psys = (ParticleSystem *)ptr->data;
+ const ParticleSystem *psys = (ParticleSystem *)ptr->data;
char name_esc[sizeof(psys->name) * 2];
BLI_str_escape(name_esc, psys->name, sizeof(name_esc));
diff --git a/source/blender/makesrna/intern/rna_pointcloud.c b/source/blender/makesrna/intern/rna_pointcloud.c
index 075d660ba2b..4c5dcd5a587 100644
--- a/source/blender/makesrna/intern/rna_pointcloud.c
+++ b/source/blender/makesrna/intern/rna_pointcloud.c
@@ -27,18 +27,23 @@
# include "WM_api.h"
# include "WM_types.h"
-static PointCloud *rna_pointcloud(PointerRNA *ptr)
+static PointCloud *rna_pointcloud(const PointerRNA *ptr)
{
return (PointCloud *)ptr->owner_id;
}
-static int rna_Point_index_get(PointerRNA *ptr)
+static int rna_Point_index_get_const(const PointerRNA *ptr)
{
const PointCloud *pointcloud = rna_pointcloud(ptr);
const float(*co)[3] = ptr->data;
return (int)(co - pointcloud->co);
}
+static int rna_Point_index_get(PointerRNA *ptr)
+{
+ return rna_Point_index_get_const(ptr);
+}
+
static void rna_Point_location_get(PointerRNA *ptr, float value[3])
{
copy_v3_v3(value, (const float *)ptr->data);
@@ -69,9 +74,9 @@ static void rna_Point_radius_set(PointerRNA *ptr, float value)
pointcloud->radius[co - pointcloud->co] = value;
}
-static char *rna_Point_path(PointerRNA *ptr)
+static char *rna_Point_path(const PointerRNA *ptr)
{
- return BLI_sprintfN("points[%d]", rna_Point_index_get(ptr));
+ return BLI_sprintfN("points[%d]", rna_Point_index_get_const(ptr));
}
static void rna_PointCloud_update_data(struct Main *UNUSED(bmain),
diff --git a/source/blender/makesrna/intern/rna_pose.c b/source/blender/makesrna/intern/rna_pose.c
index a80e9573657..30df8e20e8d 100644
--- a/source/blender/makesrna/intern/rna_pose.c
+++ b/source/blender/makesrna/intern/rna_pose.c
@@ -108,14 +108,14 @@ static void rna_Pose_IK_update(Main *UNUSED(bmain), Scene *UNUSED(scene), Pointe
BIK_clear_data(ob->pose);
}
-static char *rna_Pose_path(PointerRNA *UNUSED(ptr))
+static char *rna_Pose_path(const PointerRNA *UNUSED(ptr))
{
return BLI_strdup("pose");
}
-static char *rna_PoseBone_path(PointerRNA *ptr)
+static char *rna_PoseBone_path(const PointerRNA *ptr)
{
- bPoseChannel *pchan = ptr->data;
+ const bPoseChannel *pchan = ptr->data;
char name_esc[sizeof(pchan->name) * 2];
BLI_str_escape(name_esc, pchan->name, sizeof(name_esc));
@@ -698,16 +698,18 @@ bool rna_PoseChannel_constraints_override_apply(Main *bmain,
return true;
}
-static int rna_PoseChannel_proxy_editable(PointerRNA *ptr, const char **r_info)
+static int rna_PoseChannel_proxy_editable(PointerRNA *UNUSED(ptr), const char **UNUSED(r_info))
{
+# if 0
Object *ob = (Object *)ptr->owner_id;
bArmature *arm = ob->data;
bPoseChannel *pchan = (bPoseChannel *)ptr->data;
- if (false && pchan->bone && (pchan->bone->layer & arm->layer_protected)) {
+ if (pchan->bone && (pchan->bone->layer & arm->layer_protected)) {
*r_info = "Can't edit property of a proxy on a protected layer";
return 0;
}
+# endif
return PROP_EDITABLE;
}
diff --git a/source/blender/makesrna/intern/rna_render.c b/source/blender/makesrna/intern/rna_render.c
index 997c110134d..11a7be69f68 100644
--- a/source/blender/makesrna/intern/rna_render.c
+++ b/source/blender/makesrna/intern/rna_render.c
@@ -483,9 +483,10 @@ static void rna_RenderLayer_passes_begin(CollectionPropertyIterator *iter, Point
rna_iterator_listbase_begin(iter, &rl->passes, NULL);
}
-static int rna_RenderPass_rect_get_length(PointerRNA *ptr, int length[RNA_MAX_ARRAY_DIMENSION])
+static int rna_RenderPass_rect_get_length(const PointerRNA *ptr,
+ int length[RNA_MAX_ARRAY_DIMENSION])
{
- RenderPass *rpass = (RenderPass *)ptr->data;
+ const RenderPass *rpass = (RenderPass *)ptr->data;
length[0] = rpass->rectx * rpass->recty;
length[1] = rpass->channels;
diff --git a/source/blender/makesrna/intern/rna_rigidbody.c b/source/blender/makesrna/intern/rna_rigidbody.c
index c1012f67c5a..0c1fd8cab3c 100644
--- a/source/blender/makesrna/intern/rna_rigidbody.c
+++ b/source/blender/makesrna/intern/rna_rigidbody.c
@@ -148,7 +148,7 @@ static void rna_RigidBodyWorld_reset(Main *UNUSED(bmain), Scene *UNUSED(scene),
BKE_rigidbody_cache_reset(rbw);
}
-static char *rna_RigidBodyWorld_path(PointerRNA *UNUSED(ptr))
+static char *rna_RigidBodyWorld_path(const PointerRNA *UNUSED(ptr))
{
return BLI_strdup("rigidbody_world");
}
@@ -240,7 +240,7 @@ static void rna_RigidBodyOb_mesh_source_update(Main *bmain, Scene *scene, Pointe
WM_main_add_notifier(NC_OBJECT | ND_DRAW, ob);
}
-static char *rna_RigidBodyOb_path(PointerRNA *UNUSED(ptr))
+static char *rna_RigidBodyOb_path(const PointerRNA *UNUSED(ptr))
{
/* NOTE: this hardcoded path should work as long as only Objects have this */
return BLI_strdup("rigid_body");
@@ -432,7 +432,7 @@ static void rna_RigidBodyOb_angular_damping_set(PointerRNA *ptr, float value)
# endif
}
-static char *rna_RigidBodyCon_path(PointerRNA *UNUSED(ptr))
+static char *rna_RigidBodyCon_path(const PointerRNA *UNUSED(ptr))
{
/* NOTE: this hardcoded path should work as long as only Objects have this */
return BLI_strdup("rigid_body_constraint");
diff --git a/source/blender/makesrna/intern/rna_rna.c b/source/blender/makesrna/intern/rna_rna.c
index a7d673d3fe1..16a4dfe71cf 100644
--- a/source/blender/makesrna/intern/rna_rna.c
+++ b/source/blender/makesrna/intern/rna_rna.c
@@ -50,56 +50,85 @@ const EnumPropertyItem rna_enum_property_type_items[] = {
{0, NULL, 0, NULL, NULL},
};
-/* Keep in sync with RNA_types.h PropertySubType and bpy_props.c's property_subtype_xxx_items */
+/* Wraps multiple enums onto a single line in a way that is difficult to read.
+ * NOTE: these enums are split up based on their use in `bpy.props` Python module. */
+
+/* clang-format off */
+#define RNA_ENUM_PROPERTY_SUBTYPE_STRING_ITEMS \
+ {PROP_FILEPATH, "FILE_PATH", 0, "File Path", ""}, \
+ {PROP_DIRPATH, "DIR_PATH", 0, "Directory Path", ""}, \
+ {PROP_FILENAME, "FILE_NAME", 0, "File Name", ""}, \
+ {PROP_BYTESTRING, "BYTE_STRING", 0, "Byte String", ""}, \
+ {PROP_PASSWORD, "PASSWORD", 0, "Password", "A string that is displayed hidden ('********')"}
+
+#define RNA_ENUM_PROPERTY_SUBTYPE_NUMBER_ITEMS \
+ {PROP_PIXEL, "PIXEL", 0, "Pixel", ""}, \
+ {PROP_UNSIGNED, "UNSIGNED", 0, "Unsigned", ""}, \
+ {PROP_PERCENTAGE, "PERCENTAGE", 0, "Percentage", ""}, \
+ {PROP_FACTOR, "FACTOR", 0, "Factor", ""}, \
+ {PROP_ANGLE, "ANGLE", 0, "Angle", ""}, \
+ {PROP_TIME, "TIME", 0, "Time (Scene Relative)", \
+ "Time specified in frames, converted to seconds based on scene frame rate"}, \
+ {PROP_TIME_ABSOLUTE, "TIME_ABSOLUTE", 0, "Time (Absolute)", \
+ "Time specified in seconds, independent of the scene"}, \
+ {PROP_DISTANCE, "DISTANCE", 0, "Distance", ""}, \
+ {PROP_DISTANCE_CAMERA, "DISTANCE_CAMERA", 0, "Camera Distance", ""}, \
+ {PROP_POWER, "POWER", 0, "Power", ""}, \
+ {PROP_TEMPERATURE, "TEMPERATURE", 0, "Temperature", ""}
+
+#define RNA_ENUM_PROPERTY_SUBTYPE_NUMBER_ARRAY_ITEMS \
+ {PROP_COLOR, "COLOR", 0, "Color", ""}, \
+ {PROP_TRANSLATION, "TRANSLATION", 0, "Translation", ""}, \
+ {PROP_DIRECTION, "DIRECTION", 0, "Direction", ""}, \
+ {PROP_VELOCITY, "VELOCITY", 0, "Velocity", ""}, \
+ {PROP_ACCELERATION, "ACCELERATION", 0, "Acceleration", ""}, \
+ {PROP_MATRIX, "MATRIX", 0, "Matrix", ""}, \
+ {PROP_EULER, "EULER", 0, "Euler Angles", ""}, \
+ {PROP_QUATERNION, "QUATERNION", 0, "Quaternion", ""}, \
+ {PROP_AXISANGLE, "AXISANGLE", 0, "Axis-Angle", ""}, \
+ {PROP_XYZ, "XYZ", 0, "XYZ", ""}, \
+ {PROP_XYZ_LENGTH, "XYZ_LENGTH", 0, "XYZ Length", ""}, \
+ {PROP_COLOR_GAMMA, "COLOR_GAMMA", 0, "Color", ""}, \
+ {PROP_COORDS, "COORDINATES", 0, "Coordinates", ""}, \
+ /* Boolean. */ \
+ {PROP_LAYER, "LAYER", 0, "Layer", ""}, \
+ {PROP_LAYER_MEMBER, "LAYER_MEMBER", 0, "Layer Member", ""}
+
+/* clang-format on */
+
+const EnumPropertyItem rna_enum_property_subtype_string_items[] = {
+ RNA_ENUM_PROPERTY_SUBTYPE_STRING_ITEMS,
+
+ {PROP_NONE, "NONE", 0, "None", ""},
+ {0, NULL, 0, NULL, NULL},
+};
+
+const EnumPropertyItem rna_enum_property_subtype_number_items[] = {
+ RNA_ENUM_PROPERTY_SUBTYPE_NUMBER_ITEMS,
+
+ {PROP_NONE, "NONE", 0, "None", ""},
+ {0, NULL, 0, NULL, NULL},
+};
+
+const EnumPropertyItem rna_enum_property_subtype_number_array_items[] = {
+ RNA_ENUM_PROPERTY_SUBTYPE_NUMBER_ARRAY_ITEMS,
+
+ {PROP_NONE, "NONE", 0, "None", ""},
+ {0, NULL, 0, NULL, NULL},
+};
+
const EnumPropertyItem rna_enum_property_subtype_items[] = {
{PROP_NONE, "NONE", 0, "None", ""},
- /* strings */
- {PROP_FILEPATH, "FILEPATH", 0, "File Path", ""},
- {PROP_DIRPATH, "DIRPATH", 0, "Directory Path", ""},
- {PROP_FILENAME, "FILENAME", 0, "File Name", ""},
- {PROP_BYTESTRING, "BYTESTRING", 0, "Byte String", ""},
- {PROP_PASSWORD, "PASSWORD", 0, "Password", "A string that is displayed hidden ('********')"},
-
- /* numbers */
- {PROP_PIXEL, "PIXEL", 0, "Pixel", ""},
- {PROP_UNSIGNED, "UNSIGNED", 0, "Unsigned", ""},
- {PROP_PERCENTAGE, "PERCENTAGE", 0, "Percentage", ""},
- {PROP_FACTOR, "FACTOR", 0, "Factor", ""},
- {PROP_ANGLE, "ANGLE", 0, "Angle", ""},
- {PROP_TIME,
- "TIME",
- 0,
- "Time (Scene Relative)",
- "Time specified in frames, converted to seconds based on scene frame rate"},
- {PROP_TIME_ABSOLUTE,
- "TIME_ABSOLUTE",
- 0,
- "Time (Absolute)",
- "Time specified in seconds, independent of the scene"},
- {PROP_DISTANCE, "DISTANCE", 0, "Distance", ""},
- {PROP_DISTANCE_CAMERA, "DISTANCE_CAMERA", 0, "Camera Distance", ""},
- {PROP_POWER, "POWER", 0, "Power", ""},
- {PROP_TEMPERATURE, "TEMPERATURE", 0, "Temperature", ""},
-
- /* number arrays */
- {PROP_COLOR, "COLOR", 0, "Color", ""},
- {PROP_TRANSLATION, "TRANSLATION", 0, "Translation", ""},
- {PROP_DIRECTION, "DIRECTION", 0, "Direction", ""},
- {PROP_VELOCITY, "VELOCITY", 0, "Velocity", ""},
- {PROP_ACCELERATION, "ACCELERATION", 0, "Acceleration", ""},
- {PROP_MATRIX, "MATRIX", 0, "Matrix", ""},
- {PROP_EULER, "EULER", 0, "Euler Angles", ""},
- {PROP_QUATERNION, "QUATERNION", 0, "Quaternion", ""},
- {PROP_AXISANGLE, "AXISANGLE", 0, "Axis-Angle", ""},
- {PROP_XYZ, "XYZ", 0, "XYZ", ""},
- {PROP_XYZ_LENGTH, "XYZ_LENGTH", 0, "XYZ Length", ""},
- {PROP_COLOR_GAMMA, "COLOR_GAMMA", 0, "Color", ""},
- {PROP_COORDS, "COORDS", 0, "Coordinates", ""},
-
- /* booleans */
- {PROP_LAYER, "LAYER", 0, "Layer", ""},
- {PROP_LAYER_MEMBER, "LAYER_MEMBER", 0, "Layer Member", ""},
+ /* String. */
+ RNA_ENUM_PROPERTY_SUBTYPE_STRING_ITEMS,
+
+ /* Number. */
+ RNA_ENUM_PROPERTY_SUBTYPE_NUMBER_ITEMS,
+
+ /* Number array. */
+ RNA_ENUM_PROPERTY_SUBTYPE_NUMBER_ARRAY_ITEMS,
+
{0, NULL, 0, NULL, NULL},
};
@@ -120,6 +149,69 @@ const EnumPropertyItem rna_enum_property_unit_items[] = {
{0, NULL, 0, NULL, NULL},
};
+const EnumPropertyItem rna_enum_property_flag_items[] = {
+ {PROP_HIDDEN, "HIDDEN", 0, "Hidden", ""},
+ {PROP_SKIP_SAVE, "SKIP_SAVE", 0, "Skip Save", ""},
+ {PROP_ANIMATABLE, "ANIMATABLE", 0, "Animatable", ""},
+ {PROP_LIB_EXCEPTION, "LIBRARY_EDITABLE", 0, "Library Editable", ""},
+ {PROP_PROPORTIONAL, "PROPORTIONAL", 0, "Adjust values proportionally to each other", ""},
+ {PROP_TEXTEDIT_UPDATE,
+ "TEXTEDIT_UPDATE",
+ 0,
+ "Update on every keystroke in textedit 'mode'",
+ ""},
+ {0, NULL, 0, NULL, NULL},
+};
+
+/** Only for enum type properties. */
+const EnumPropertyItem rna_enum_property_flag_enum_items[] = {
+ {PROP_HIDDEN, "HIDDEN", 0, "Hidden", ""},
+ {PROP_SKIP_SAVE, "SKIP_SAVE", 0, "Skip Save", ""},
+ {PROP_ANIMATABLE, "ANIMATABLE", 0, "Animatable", ""},
+ {PROP_LIB_EXCEPTION, "LIBRARY_EDITABLE", 0, "Library Editable", ""},
+ {PROP_ENUM_FLAG, "ENUM_FLAG", 0, "Enum Flag", ""},
+ {0, NULL, 0, NULL, NULL},
+};
+
+const EnumPropertyItem rna_enum_property_override_flag_items[] = {
+ {PROPOVERRIDE_OVERRIDABLE_LIBRARY,
+ "LIBRARY_OVERRIDABLE",
+ 0,
+ "Library Overridable",
+ "Make that property editable in library overrides of linked data-blocks"},
+ {0, NULL, 0, NULL, NULL},
+};
+
+const EnumPropertyItem rna_enum_property_override_flag_collection_items[] = {
+ {PROPOVERRIDE_OVERRIDABLE_LIBRARY,
+ "LIBRARY_OVERRIDABLE",
+ 0,
+ "Library Overridable",
+ "Make that property editable in library overrides of linked data-blocks"},
+ {PROPOVERRIDE_NO_PROP_NAME,
+ "NO_PROPERTY_NAME",
+ 0,
+ "No Name",
+ "Do not use the names of the items, only their indices in the collection"},
+ {PROPOVERRIDE_LIBRARY_INSERTION,
+ "USE_INSERTION",
+ 0,
+ "Use Insertion",
+ "Allow users to add new items in that collection in library overrides"},
+ {0, NULL, 0, NULL, NULL},
+};
+
+const EnumPropertyItem rna_enum_property_string_search_flag_items[] = {
+ {PROP_STRING_SEARCH_SORT, "SORT", 0, "Sort Search Results", ""},
+ {PROP_STRING_SEARCH_SUGGESTION,
+ "SUGGESTION",
+ 0,
+ "Suggestion",
+ "Search results are suggestions (other values may be entered)"},
+
+ {0, NULL, 0, NULL, NULL},
+};
+
/** \} */
#ifdef RNA_RUNTIME
@@ -721,7 +813,7 @@ static int rna_IntProperty_default_get(PointerRNA *ptr)
return ((IntPropertyRNA *)prop)->defaultvalue;
}
/* int/float/bool */
-static int rna_NumberProperty_default_array_get_length(PointerRNA *ptr,
+static int rna_NumberProperty_default_array_get_length(const PointerRNA *ptr,
int length[RNA_MAX_ARRAY_DIMENSION])
{
PropertyRNA *prop = (PropertyRNA *)ptr->data;
@@ -941,17 +1033,29 @@ static int rna_EnumPropertyItem_identifier_length(PointerRNA *ptr)
static void rna_EnumPropertyItem_name_get(PointerRNA *ptr, char *value)
{
- strcpy(value, ((EnumPropertyItem *)ptr->data)->name);
+ const EnumPropertyItem *eprop = ptr->data;
+ /* Name can be NULL in the case of separators
+ * which are exposed via `_bpy.rna_enum_items_static`. */
+ if (eprop->name) {
+ strcpy(value, eprop->name);
+ }
+ else {
+ value[0] = '\0';
+ }
}
static int rna_EnumPropertyItem_name_length(PointerRNA *ptr)
{
- return strlen(((EnumPropertyItem *)ptr->data)->name);
+ const EnumPropertyItem *eprop = ptr->data;
+ if (eprop->name) {
+ return strlen(eprop->name);
+ }
+ return 0;
}
static void rna_EnumPropertyItem_description_get(PointerRNA *ptr, char *value)
{
- EnumPropertyItem *eprop = (EnumPropertyItem *)ptr->data;
+ const EnumPropertyItem *eprop = ptr->data;
if (eprop->description) {
strcpy(value, eprop->description);
@@ -968,9 +1072,7 @@ static int rna_EnumPropertyItem_description_length(PointerRNA *ptr)
if (eprop->description) {
return strlen(eprop->description);
}
- else {
- return 0;
- }
+ return 0;
}
static int rna_EnumPropertyItem_value_get(PointerRNA *ptr)
@@ -2655,7 +2757,7 @@ bool rna_property_override_apply_default(Main *bmain,
break;
}
default:
- BLI_assert(0);
+ BLI_assert_unreachable();
return false;
}
diff --git a/source/blender/makesrna/intern/rna_scene.c b/source/blender/makesrna/intern/rna_scene.c
index b647a823929..cc7df54e648 100644
--- a/source/blender/makesrna/intern/rna_scene.c
+++ b/source/blender/makesrna/intern/rna_scene.c
@@ -92,11 +92,11 @@ static const EnumPropertyItem uv_sculpt_relaxation_items[] = {
};
#endif
-const EnumPropertyItem rna_enum_snap_target_items[] = {
- {SCE_SNAP_TARGET_CLOSEST, "CLOSEST", 0, "Closest", "Snap closest point onto target"},
- {SCE_SNAP_TARGET_CENTER, "CENTER", 0, "Center", "Snap transformation center onto target"},
- {SCE_SNAP_TARGET_MEDIAN, "MEDIAN", 0, "Median", "Snap median onto target"},
- {SCE_SNAP_TARGET_ACTIVE, "ACTIVE", 0, "Active", "Snap active onto target"},
+const EnumPropertyItem rna_enum_snap_source_items[] = {
+ {SCE_SNAP_SOURCE_CLOSEST, "CLOSEST", 0, "Closest", "Snap closest point onto target"},
+ {SCE_SNAP_SOURCE_CENTER, "CENTER", 0, "Center", "Snap transformation center onto target"},
+ {SCE_SNAP_SOURCE_MEDIAN, "MEDIAN", 0, "Median", "Snap median onto target"},
+ {SCE_SNAP_SOURCE_ACTIVE, "ACTIVE", 0, "Active", "Snap active onto target"},
{0, NULL, 0, NULL, NULL},
};
@@ -345,9 +345,9 @@ const EnumPropertyItem rna_enum_curve_fit_method_items[] = {
R_IMF_ENUM_JPEG \
R_IMF_ENUM_JPEG2K \
R_IMF_ENUM_TAGA \
- R_IMF_ENUM_TAGA_RAW{0, "", 0, " ", NULL}, \
- R_IMF_ENUM_CINEON R_IMF_ENUM_DPX R_IMF_ENUM_EXR_MULTILAYER R_IMF_ENUM_EXR R_IMF_ENUM_HDR \
- R_IMF_ENUM_TIFF R_IMF_ENUM_WEBP
+ R_IMF_ENUM_TAGA_RAW \
+ RNA_ENUM_ITEM_SEPR_COLUMN, R_IMF_ENUM_CINEON R_IMF_ENUM_DPX R_IMF_ENUM_EXR_MULTILAYER \
+ R_IMF_ENUM_EXR R_IMF_ENUM_HDR R_IMF_ENUM_TIFF R_IMF_ENUM_WEBP
#ifdef RNA_RUNTIME
static const EnumPropertyItem image_only_type_items[] = {
@@ -359,11 +359,11 @@ static const EnumPropertyItem image_only_type_items[] = {
#endif
const EnumPropertyItem rna_enum_image_type_items[] = {
- {0, "", 0, N_("Image"), NULL},
+ RNA_ENUM_ITEM_HEADING(N_("Image"), NULL),
IMAGE_TYPE_ITEMS_IMAGE_ONLY
- {0, "", 0, N_("Movie"), NULL},
+ RNA_ENUM_ITEM_HEADING(N_("Movie"), NULL),
{R_IMF_IMTYPE_AVIJPEG,
"AVI_JPEG",
ICON_FILE_MOVIE,
@@ -447,8 +447,8 @@ const EnumPropertyItem rna_enum_bake_target_items[] = {
{R_BAKE_TARGET_VERTEX_COLORS,
"VERTEX_COLORS",
0,
- "Color Attributes",
- "Bake to active color attribute layer on meshes"},
+ "Active Color Attribute",
+ "Bake to the active color attribute on meshes"},
{0, NULL, 0, NULL, NULL},
};
@@ -1100,12 +1100,12 @@ static void rna_Scene_all_keyingsets_next(CollectionPropertyIterator *iter)
iter->valid = (internal->link != NULL);
}
-static char *rna_SceneEEVEE_path(PointerRNA *UNUSED(ptr))
+static char *rna_SceneEEVEE_path(const PointerRNA *UNUSED(ptr))
{
return BLI_strdup("eevee");
}
-static char *rna_SceneGpencil_path(PointerRNA *UNUSED(ptr))
+static char *rna_SceneGpencil_path(const PointerRNA *UNUSED(ptr))
{
return BLI_strdup("grease_pencil_settings");
}
@@ -1129,17 +1129,17 @@ static void rna_RenderSettings_stereoViews_begin(CollectionPropertyIterator *ite
rna_iterator_listbase_begin(iter, &rd->views, rna_RenderSettings_stereoViews_skip);
}
-static char *rna_RenderSettings_path(PointerRNA *UNUSED(ptr))
+static char *rna_RenderSettings_path(const PointerRNA *UNUSED(ptr))
{
return BLI_strdup("render");
}
-static char *rna_BakeSettings_path(PointerRNA *UNUSED(ptr))
+static char *rna_BakeSettings_path(const PointerRNA *UNUSED(ptr))
{
return BLI_strdup("render.bake");
}
-static char *rna_ImageFormatSettings_path(PointerRNA *ptr)
+static char *rna_ImageFormatSettings_path(const PointerRNA *ptr)
{
ImageFormatData *imf = (ImageFormatData *)ptr->data;
ID *id = ptr->owner_id;
@@ -1787,10 +1787,11 @@ void rna_ViewLayer_pass_update(Main *bmain, Scene *activescene, PointerRNA *ptr)
rna_Scene_glsl_update(bmain, activescene, ptr);
}
-static char *rna_ViewLayerEEVEE_path(PointerRNA *ptr)
+static char *rna_ViewLayerEEVEE_path(const PointerRNA *ptr)
{
- ViewLayerEEVEE *view_layer_eevee = (ViewLayerEEVEE *)ptr->data;
- ViewLayer *view_layer = (ViewLayer *)((uint8_t *)view_layer_eevee - offsetof(ViewLayer, eevee));
+ const ViewLayerEEVEE *view_layer_eevee = (ViewLayerEEVEE *)ptr->data;
+ const ViewLayer *view_layer = (ViewLayer *)((uint8_t *)view_layer_eevee -
+ offsetof(ViewLayer, eevee));
char rna_path[sizeof(view_layer->name) * 3];
const size_t view_layer_path_len = rna_ViewLayer_path_buffer_get(
@@ -1801,9 +1802,9 @@ static char *rna_ViewLayerEEVEE_path(PointerRNA *ptr)
return BLI_strdup(rna_path);
}
-static char *rna_SceneRenderView_path(PointerRNA *ptr)
+static char *rna_SceneRenderView_path(const PointerRNA *ptr)
{
- SceneRenderView *srv = (SceneRenderView *)ptr->data;
+ const SceneRenderView *srv = (SceneRenderView *)ptr->data;
char srv_name_esc[sizeof(srv->name) * 2];
BLI_str_escape(srv_name_esc, srv->name, sizeof(srv_name_esc));
return BLI_sprintfN("render.views[\"%s\"]", srv_name_esc);
@@ -2071,10 +2072,10 @@ static void rna_View3DCursor_matrix_set(PointerRNA *ptr, const float *values)
BKE_scene_cursor_from_mat4(cursor, unit_mat, false);
}
-static char *rna_TransformOrientationSlot_path(PointerRNA *ptr)
+static char *rna_TransformOrientationSlot_path(const PointerRNA *ptr)
{
- Scene *scene = (Scene *)ptr->owner_id;
- TransformOrientationSlot *orientation_slot = ptr->data;
+ const Scene *scene = (Scene *)ptr->owner_id;
+ const TransformOrientationSlot *orientation_slot = ptr->data;
if (!ELEM(NULL, scene, orientation_slot)) {
for (int i = 0; i < ARRAY_SIZE(scene->orientation_slots); i++) {
@@ -2085,11 +2086,11 @@ static char *rna_TransformOrientationSlot_path(PointerRNA *ptr)
}
/* Should not happen, but in case, just return default path. */
- BLI_assert(0);
+ BLI_assert_unreachable();
return BLI_strdup("transform_orientation_slots[0]");
}
-static char *rna_View3DCursor_path(PointerRNA *UNUSED(ptr))
+static char *rna_View3DCursor_path(const PointerRNA *UNUSED(ptr))
{
return BLI_strdup("cursor");
}
@@ -2188,17 +2189,17 @@ static void rna_UnifiedPaintSettings_radius_update(bContext *C, PointerRNA *ptr)
rna_UnifiedPaintSettings_update(C, ptr);
}
-static char *rna_UnifiedPaintSettings_path(PointerRNA *UNUSED(ptr))
+static char *rna_UnifiedPaintSettings_path(const PointerRNA *UNUSED(ptr))
{
return BLI_strdup("tool_settings.unified_paint_settings");
}
-static char *rna_CurvePaintSettings_path(PointerRNA *UNUSED(ptr))
+static char *rna_CurvePaintSettings_path(const PointerRNA *UNUSED(ptr))
{
return BLI_strdup("tool_settings.curve_paint_settings");
}
-static char *rna_SequencerToolSettings_path(PointerRNA *UNUSED(ptr))
+static char *rna_SequencerToolSettings_path(const PointerRNA *UNUSED(ptr))
{
return BLI_strdup("tool_settings.sequencer_tool_settings");
}
@@ -2222,7 +2223,7 @@ static void rna_EditMesh_update(bContext *C, PointerRNA *UNUSED(ptr))
}
}
-static char *rna_MeshStatVis_path(PointerRNA *UNUSED(ptr))
+static char *rna_MeshStatVis_path(const PointerRNA *UNUSED(ptr))
{
return BLI_strdup("tool_settings.statvis");
}
@@ -2260,7 +2261,7 @@ static void rna_SceneSequencer_update(Main *UNUSED(bmain), Scene *UNUSED(scene),
SEQ_cache_cleanup((Scene *)ptr->owner_id);
}
-static char *rna_ToolSettings_path(PointerRNA *UNUSED(ptr))
+static char *rna_ToolSettings_path(const PointerRNA *UNUSED(ptr))
{
return BLI_strdup("tool_settings");
}
@@ -2701,16 +2702,33 @@ static void rna_UnitSettings_system_update(Main *UNUSED(bmain),
}
}
-static char *rna_UnitSettings_path(PointerRNA *UNUSED(ptr))
+static char *rna_UnitSettings_path(const PointerRNA *UNUSED(ptr))
{
return BLI_strdup("unit_settings");
}
-static char *rna_FFmpegSettings_path(PointerRNA *UNUSED(ptr))
+static char *rna_FFmpegSettings_path(const PointerRNA *UNUSED(ptr))
{
return BLI_strdup("render.ffmpeg");
}
+# ifdef WITH_FFMPEG
+/* FFMpeg Codec setting update hook. */
+static void rna_FFmpegSettings_codec_update(Main *UNUSED(bmain),
+ Scene *UNUSED(scene),
+ PointerRNA *ptr)
+{
+ FFMpegCodecData *codec_data = (FFMpegCodecData *)ptr->data;
+ if (!ELEM(codec_data->codec, AV_CODEC_ID_H264, AV_CODEC_ID_MPEG4, AV_CODEC_ID_VP9)) {
+ /* Constant Rate Factor (CRF) setting is only available for H264,
+ * MPEG4 and WEBM/VP9 codecs. So changing encoder quality mode to
+ * CBR as CRF is not supported.
+ */
+ codec_data->constant_rate_factor = FFM_CRF_NONE;
+ }
+}
+# endif
+
#else
/* Grease Pencil Interpolation tool settings */
@@ -3305,9 +3323,12 @@ static void rna_def_tool_settings(BlenderRNA *brna)
"Absolute grid alignment while translating (based on the pivot center)");
RNA_def_property_update(prop, NC_SCENE | ND_TOOLSETTINGS, NULL); /* header redraw */
+ /* TODO(@gfxcoder): Rename `snap_target` to `snap_source` to avoid
+ * previous ambiguity of "target" (now, "source" is geometry to be moved and "target" is
+ * geometry to which moved geometry is snapped). */
prop = RNA_def_property(srna, "snap_target", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_sdna(prop, NULL, "snap_target");
- RNA_def_property_enum_items(prop, rna_enum_snap_target_items);
+ RNA_def_property_enum_items(prop, rna_enum_snap_source_items);
RNA_def_property_ui_text(prop, "Snap Target", "Which part to snap onto the target");
RNA_def_property_update(prop, NC_SCENE | ND_TOOLSETTINGS, NULL); /* header redraw */
@@ -5918,6 +5939,7 @@ static void rna_def_scene_ffmpeg_settings(BlenderRNA *brna)
RNA_def_property_enum_items(prop, ffmpeg_codec_items);
RNA_def_property_enum_default(prop, AV_CODEC_ID_H264);
RNA_def_property_ui_text(prop, "Video Codec", "FFmpeg codec to use for video output");
+ RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, "rna_FFmpegSettings_codec_update");
prop = RNA_def_property(srna, "video_bitrate", PROP_INT, PROP_NONE);
RNA_def_property_int_sdna(prop, NULL, "video_bitrate");
diff --git a/source/blender/makesrna/intern/rna_scene_api.c b/source/blender/makesrna/intern/rna_scene_api.c
index 200e1d65caf..3953fc66fc8 100644
--- a/source/blender/makesrna/intern/rna_scene_api.c
+++ b/source/blender/makesrna/intern/rna_scene_api.c
@@ -140,7 +140,7 @@ static void rna_Scene_ray_cast(Scene *scene,
depsgraph,
NULL,
&(const struct SnapObjectParams){
- .snap_select = SNAP_ALL,
+ .snap_target_select = SCE_SNAP_TARGET_ALL,
},
origin,
direction,
diff --git a/source/blender/makesrna/intern/rna_sculpt_paint.c b/source/blender/makesrna/intern/rna_sculpt_paint.c
index 017e8bde7a1..3de9e632ff6 100644
--- a/source/blender/makesrna/intern/rna_sculpt_paint.c
+++ b/source/blender/makesrna/intern/rna_sculpt_paint.c
@@ -259,7 +259,7 @@ static bool rna_ParticleEdit_hair_get(PointerRNA *ptr)
return 0;
}
-static char *rna_ParticleEdit_path(PointerRNA *UNUSED(ptr))
+static char *rna_ParticleEdit_path(const PointerRNA *UNUSED(ptr))
{
return BLI_strdup("tool_settings.particle_edit");
}
@@ -403,15 +403,15 @@ static void rna_Sculpt_ShowMask_update(bContext *C, PointerRNA *UNUSED(ptr))
WM_main_add_notifier(NC_OBJECT | ND_MODIFIER, object);
}
-static char *rna_Sculpt_path(PointerRNA *UNUSED(ptr))
+static char *rna_Sculpt_path(const PointerRNA *UNUSED(ptr))
{
return BLI_strdup("tool_settings.sculpt");
}
-static char *rna_VertexPaint_path(PointerRNA *ptr)
+static char *rna_VertexPaint_path(const PointerRNA *ptr)
{
- Scene *scene = (Scene *)ptr->owner_id;
- ToolSettings *ts = scene->toolsettings;
+ const Scene *scene = (Scene *)ptr->owner_id;
+ const ToolSettings *ts = scene->toolsettings;
if (ptr->data == ts->vpaint) {
return BLI_strdup("tool_settings.vertex_paint");
}
@@ -420,47 +420,47 @@ static char *rna_VertexPaint_path(PointerRNA *ptr)
}
}
-static char *rna_ImagePaintSettings_path(PointerRNA *UNUSED(ptr))
+static char *rna_ImagePaintSettings_path(const PointerRNA *UNUSED(ptr))
{
return BLI_strdup("tool_settings.image_paint");
}
-static char *rna_PaintModeSettings_path(PointerRNA *UNUSED(ptr))
+static char *rna_PaintModeSettings_path(const PointerRNA *UNUSED(ptr))
{
return BLI_strdup("tool_settings.paint_mode");
}
-static char *rna_UvSculpt_path(PointerRNA *UNUSED(ptr))
+static char *rna_UvSculpt_path(const PointerRNA *UNUSED(ptr))
{
return BLI_strdup("tool_settings.uv_sculpt");
}
-static char *rna_CurvesSculpt_path(PointerRNA *UNUSED(ptr))
+static char *rna_CurvesSculpt_path(const PointerRNA *UNUSED(ptr))
{
return BLI_strdup("tool_settings.curves_sculpt");
}
-static char *rna_GpPaint_path(PointerRNA *UNUSED(ptr))
+static char *rna_GpPaint_path(const PointerRNA *UNUSED(ptr))
{
return BLI_strdup("tool_settings.gpencil_paint");
}
-static char *rna_GpVertexPaint_path(PointerRNA *UNUSED(ptr))
+static char *rna_GpVertexPaint_path(const PointerRNA *UNUSED(ptr))
{
return BLI_strdup("tool_settings.gpencil_vertex_paint");
}
-static char *rna_GpSculptPaint_path(PointerRNA *UNUSED(ptr))
+static char *rna_GpSculptPaint_path(const PointerRNA *UNUSED(ptr))
{
return BLI_strdup("tool_settings.gpencil_sculpt_paint");
}
-static char *rna_GpWeightPaint_path(PointerRNA *UNUSED(ptr))
+static char *rna_GpWeightPaint_path(const PointerRNA *UNUSED(ptr))
{
return BLI_strdup("tool_settings.gpencil_weight_paint");
}
-static char *rna_ParticleBrush_path(PointerRNA *UNUSED(ptr))
+static char *rna_ParticleBrush_path(const PointerRNA *UNUSED(ptr))
{
return BLI_strdup("tool_settings.particle_edit.brush");
}
@@ -578,12 +578,12 @@ static bool rna_ImaPaint_detect_data(ImagePaintSettings *imapaint)
return imapaint->missing_data == 0;
}
-static char *rna_GPencilSculptSettings_path(PointerRNA *UNUSED(ptr))
+static char *rna_GPencilSculptSettings_path(const PointerRNA *UNUSED(ptr))
{
return BLI_strdup("tool_settings.gpencil_sculpt");
}
-static char *rna_GPencilSculptGuide_path(PointerRNA *UNUSED(ptr))
+static char *rna_GPencilSculptGuide_path(const PointerRNA *UNUSED(ptr))
{
return BLI_strdup("tool_settings.gpencil_sculpt.guide");
}
@@ -774,6 +774,20 @@ static void rna_def_sculpt(BlenderRNA *brna)
{0, NULL, 0, NULL, NULL},
};
+ static const EnumPropertyItem sculpt_transform_mode_items[] = {
+ {SCULPT_TRANSFORM_MODE_ALL_VERTICES,
+ "ALL_VERTICES",
+ 0,
+ "All Vertices",
+ "Applies the transformation to all vertices in the mesh"},
+ {SCULPT_TRANSFORM_MODE_RADIUS_ELASTIC,
+ "RADIUS_ELASTIC",
+ 0,
+ "Elastic",
+ "Applies the transformation simulating elasticity using the radius of the cursor"},
+ {0, NULL, 0, NULL, NULL},
+ };
+
StructRNA *srna;
PropertyRNA *prop;
@@ -912,6 +926,12 @@ static void rna_def_sculpt(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "Gravity", "Amount of gravity after each dab");
RNA_def_property_update(prop, NC_SCENE | ND_TOOLSETTINGS, NULL);
+ prop = RNA_def_property(srna, "transform_mode", PROP_ENUM, PROP_NONE);
+ RNA_def_property_enum_items(prop, sculpt_transform_mode_items);
+ RNA_def_property_ui_text(
+ prop, "Transform Mode", "How the transformation is going to be applied to the target");
+ RNA_def_property_update(prop, NC_SCENE | ND_TOOLSETTINGS, NULL);
+
prop = RNA_def_property(srna, "gravity_object", PROP_POINTER, PROP_NONE);
RNA_def_property_flag(prop, PROP_EDITABLE);
RNA_def_property_ui_text(
diff --git a/source/blender/makesrna/intern/rna_sequencer.c b/source/blender/makesrna/intern/rna_sequencer.c
index 51f62b62c8e..100d90df5d6 100644
--- a/source/blender/makesrna/intern/rna_sequencer.c
+++ b/source/blender/makesrna/intern/rna_sequencer.c
@@ -240,7 +240,7 @@ static int rna_SequenceEditor_sequences_all_lookup_string(PointerRNA *ptr,
ID *id = ptr->owner_id;
Scene *scene = (Scene *)id;
- Sequence *seq = SEQ_sequence_lookup_by_name(scene, key);
+ Sequence *seq = SEQ_sequence_lookup_seq_by_name(scene, key);
if (seq) {
RNA_pointer_create(ptr->owner_id, &RNA_Sequence, seq, r_ptr);
return true;
@@ -289,26 +289,11 @@ static void rna_Sequence_views_format_update(Main *bmain, Scene *scene, PointerR
static void do_sequence_frame_change_update(Scene *scene, Sequence *seq)
{
- Editing *ed = SEQ_editing_get(scene);
- ListBase *seqbase = SEQ_get_seqbase_by_seq(&ed->seqbase, seq);
- Sequence *tseq;
- SEQ_time_update_sequence(scene, seqbase, seq);
-
- /* ensure effects are always fit in length to their input */
-
- /* TODO(sergey): probably could be optimized.
- * in terms skipping update of non-changing strips
- */
- for (tseq = seqbase->first; tseq; tseq = tseq->next) {
- if (tseq->seq1 || tseq->seq2 || tseq->seq3) {
- SEQ_time_update_sequence(scene, seqbase, tseq);
- }
- }
+ ListBase *seqbase = SEQ_get_seqbase_by_seq(scene, seq);
if (SEQ_transform_test_overlap(seqbase, seq)) {
- SEQ_transform_seqbase_shuffle(seqbase, seq, scene); /* XXX: BROKEN!, uses context seqbasep. */
+ SEQ_transform_seqbase_shuffle(seqbase, seq, scene);
}
- SEQ_sort(seqbase);
if (seq->type == SEQ_TYPE_SOUND_RAM) {
DEG_id_tag_update(&scene->id, ID_RECALC_SEQUENCER_STRIPS);
@@ -341,8 +326,8 @@ static void rna_Sequence_start_frame_final_set(PointerRNA *ptr, int value)
Sequence *seq = (Sequence *)ptr->data;
Scene *scene = (Scene *)ptr->owner_id;
- SEQ_transform_set_left_handle_frame(seq, value);
- SEQ_transform_fix_single_image_seq_offsets(seq);
+ SEQ_time_left_handle_frame_set(scene, seq, value);
+ SEQ_transform_fix_single_image_seq_offsets(scene, seq);
do_sequence_frame_change_update(scene, seq);
SEQ_relations_invalidate_cache_composite(scene, seq);
}
@@ -352,8 +337,8 @@ static void rna_Sequence_end_frame_final_set(PointerRNA *ptr, int value)
Sequence *seq = (Sequence *)ptr->data;
Scene *scene = (Scene *)ptr->owner_id;
- SEQ_transform_set_right_handle_frame(seq, value);
- SEQ_transform_fix_single_image_seq_offsets(seq);
+ SEQ_time_right_handle_frame_set(scene, seq, value);
+ SEQ_transform_fix_single_image_seq_offsets(scene, seq);
do_sequence_frame_change_update(scene, seq);
SEQ_relations_invalidate_cache_composite(scene, seq);
}
@@ -376,24 +361,6 @@ static void rna_Sequence_frame_offset_end_set(PointerRNA *ptr, int value)
seq->endofs = value;
}
-static void rna_Sequence_frame_still_start_set(PointerRNA *ptr, int value)
-{
- Sequence *seq = (Sequence *)ptr->data;
- Scene *scene = (Scene *)ptr->owner_id;
-
- SEQ_relations_invalidate_cache_composite(scene, seq);
- seq->startstill = value;
-}
-
-static void rna_Sequence_frame_still_end_set(PointerRNA *ptr, int value)
-{
- Sequence *seq = (Sequence *)ptr->data;
- Scene *scene = (Scene *)ptr->owner_id;
-
- SEQ_relations_invalidate_cache_composite(scene, seq);
- seq->endstill = value;
-}
-
static void rna_Sequence_anim_startofs_final_set(PointerRNA *ptr, int value)
{
Sequence *seq = (Sequence *)ptr->data;
@@ -455,7 +422,7 @@ static void rna_Sequence_frame_length_set(PointerRNA *ptr, int value)
Sequence *seq = (Sequence *)ptr->data;
Scene *scene = (Scene *)ptr->owner_id;
- SEQ_transform_set_right_handle_frame(seq, SEQ_transform_get_left_handle_frame(seq) + value);
+ SEQ_time_right_handle_frame_set(scene, seq, SEQ_time_left_handle_frame_get(seq) + value);
do_sequence_frame_change_update(scene, seq);
SEQ_relations_invalidate_cache_composite(scene, seq);
}
@@ -463,7 +430,7 @@ static void rna_Sequence_frame_length_set(PointerRNA *ptr, int value)
static int rna_Sequence_frame_length_get(PointerRNA *ptr)
{
Sequence *seq = (Sequence *)ptr->data;
- return SEQ_transform_get_right_handle_frame(seq) - SEQ_transform_get_left_handle_frame(seq);
+ return SEQ_time_right_handle_frame_get(seq) - SEQ_time_left_handle_frame_get(seq);
}
static int rna_Sequence_frame_editable(PointerRNA *ptr, const char **UNUSED(r_info))
@@ -477,18 +444,15 @@ static void rna_Sequence_channel_set(PointerRNA *ptr, int value)
{
Sequence *seq = (Sequence *)ptr->data;
Scene *scene = (Scene *)ptr->owner_id;
- Editing *ed = SEQ_editing_get(scene);
- ListBase *seqbase = SEQ_get_seqbase_by_seq(&ed->seqbase, seq);
+ ListBase *seqbase = SEQ_get_seqbase_by_seq(scene, seq);
/* check channel increment or decrement */
const int channel_delta = (value >= seq->machine) ? 1 : -1;
seq->machine = value;
if (SEQ_transform_test_overlap(seqbase, seq)) {
- /* XXX: BROKEN!, uses context seqbasep. */
SEQ_transform_seqbase_shuffle_ex(seqbase, seq, scene, channel_delta);
}
- SEQ_sort(seqbase);
SEQ_relations_invalidate_cache_composite(scene, seq);
}
@@ -522,13 +486,13 @@ static Sequence *sequence_get_by_transform(Editing *ed, StripTransform *transfor
return data.seq;
}
-static char *rna_SequenceTransform_path(PointerRNA *ptr)
+static char *rna_SequenceTransform_path(const PointerRNA *ptr)
{
Scene *scene = (Scene *)ptr->owner_id;
Editing *ed = SEQ_editing_get(scene);
Sequence *seq = sequence_get_by_transform(ed, ptr->data);
- if (seq && seq->name + 2) {
+ if (seq) {
char name_esc[(sizeof(seq->name) - 2) * 2];
BLI_str_escape(name_esc, seq->name + 2, sizeof(name_esc));
@@ -574,13 +538,13 @@ static Sequence *sequence_get_by_crop(Editing *ed, StripCrop *crop)
return data.seq;
}
-static char *rna_SequenceCrop_path(PointerRNA *ptr)
+static char *rna_SequenceCrop_path(const PointerRNA *ptr)
{
Scene *scene = (Scene *)ptr->owner_id;
Editing *ed = SEQ_editing_get(scene);
Sequence *seq = sequence_get_by_crop(ed, ptr->data);
- if (seq && seq->name + 2) {
+ if (seq) {
char name_esc[(sizeof(seq->name) - 2) * 2];
BLI_str_escape(name_esc, seq->name + 2, sizeof(name_esc));
@@ -718,22 +682,17 @@ static StructRNA *rna_Sequence_refine(struct PointerRNA *ptr)
}
}
-static char *rna_Sequence_path(PointerRNA *ptr)
+static char *rna_Sequence_path(const PointerRNA *ptr)
{
- Sequence *seq = (Sequence *)ptr->data;
+ const Sequence *seq = (Sequence *)ptr->data;
/* sequencer data comes from scene...
* TODO: would be nice to make SequenceEditor data a data-block of its own (for shorter paths)
*/
- if (seq->name + 2) {
- char name_esc[(sizeof(seq->name) - 2) * 2];
+ char name_esc[(sizeof(seq->name) - 2) * 2];
- BLI_str_escape(name_esc, seq->name + 2, sizeof(name_esc));
- return BLI_sprintfN("sequence_editor.sequences_all[\"%s\"]", name_esc);
- }
- else {
- return BLI_strdup("");
- }
+ BLI_str_escape(name_esc, seq->name + 2, sizeof(name_esc));
+ return BLI_sprintfN("sequence_editor.sequences_all[\"%s\"]", name_esc);
}
static IDProperty **rna_Sequence_idprops(PointerRNA *ptr)
@@ -745,8 +704,6 @@ static IDProperty **rna_Sequence_idprops(PointerRNA *ptr)
static bool rna_MovieSequence_reload_if_needed(ID *scene_id, Sequence *seq, Main *bmain)
{
Scene *scene = (Scene *)scene_id;
- Editing *ed = SEQ_editing_get(scene);
- ListBase *seqbase = SEQ_get_seqbase_by_seq(&ed->seqbase, seq);
bool has_reloaded;
bool can_produce_frames;
@@ -754,7 +711,6 @@ static bool rna_MovieSequence_reload_if_needed(ID *scene_id, Sequence *seq, Main
SEQ_add_movie_reload_if_needed(bmain, scene, seq, &has_reloaded, &can_produce_frames);
if (has_reloaded && can_produce_frames) {
- SEQ_time_update_sequence(scene, seqbase, seq);
SEQ_relations_invalidate_cache_raw(scene, seq);
DEG_id_tag_update(&scene->id, ID_RECALC_SEQUENCER_STRIPS);
@@ -942,9 +898,6 @@ static void rna_Sequence_filepath_update(Main *bmain, Scene *UNUSED(scene), Poin
Scene *scene = (Scene *)ptr->owner_id;
Sequence *seq = (Sequence *)(ptr->data);
SEQ_add_reload_new_file(bmain, scene, seq, true);
- Editing *ed = SEQ_editing_get(scene);
- ListBase *seqbase = SEQ_get_seqbase_by_seq(&ed->seqbase, seq);
- SEQ_time_update_sequence(scene, seqbase, seq);
rna_Sequence_invalidate_raw_update(bmain, scene, ptr);
}
@@ -1057,14 +1010,14 @@ static Sequence *sequence_get_by_colorbalance(Editing *ed,
return data.seq;
}
-static char *rna_SequenceColorBalance_path(PointerRNA *ptr)
+static char *rna_SequenceColorBalance_path(const PointerRNA *ptr)
{
Scene *scene = (Scene *)ptr->owner_id;
SequenceModifierData *smd;
Editing *ed = SEQ_editing_get(scene);
Sequence *seq = sequence_get_by_colorbalance(ed, ptr->data, &smd);
- if (seq && seq->name + 2) {
+ if (seq) {
char name_esc[(sizeof(seq->name) - 2) * 2];
BLI_str_escape(name_esc, seq->name + 2, sizeof(name_esc));
@@ -1201,14 +1154,14 @@ static StructRNA *rna_SequenceModifier_refine(struct PointerRNA *ptr)
}
}
-static char *rna_SequenceModifier_path(PointerRNA *ptr)
+static char *rna_SequenceModifier_path(const PointerRNA *ptr)
{
Scene *scene = (Scene *)ptr->owner_id;
Editing *ed = SEQ_editing_get(scene);
SequenceModifierData *smd = ptr->data;
Sequence *seq = sequence_get_by_modifier(ed, smd);
- if (seq && seq->name + 2) {
+ if (seq) {
char name_esc[(sizeof(seq->name) - 2) * 2];
char name_esc_smd[sizeof(smd->name) * 2];
@@ -1360,8 +1313,7 @@ static void rna_Sequence_separate(ID *id, Sequence *seqm, Main *bmain)
Scene *scene = (Scene *)id;
/* Find the appropriate seqbase */
- Editing *ed = SEQ_editing_get(scene);
- ListBase *seqbase = SEQ_get_seqbase_by_seq(&ed->seqbase, seqm);
+ ListBase *seqbase = SEQ_get_seqbase_by_seq(scene, seqm);
LISTBASE_FOREACH_MUTABLE (Sequence *, seq, &seqm->seqbase) {
SEQ_edit_move_strip_to_seqbase(scene, &seqm->seqbase, seq, seqbase);
@@ -1419,7 +1371,7 @@ static void rna_SequenceTimelineChannel_name_set(PointerRNA *ptr, const char *va
sizeof(channel->name));
}
-static char *rna_SeqTimelineChannel_path(PointerRNA *ptr)
+static char *rna_SeqTimelineChannel_path(const PointerRNA *ptr)
{
Scene *scene = (Scene *)ptr->owner_id;
Editing *ed = SEQ_editing_get(scene);
@@ -1802,33 +1754,33 @@ static void rna_def_strip_color_balance(BlenderRNA *brna)
static const EnumPropertyItem blend_mode_items[] = {
{SEQ_BLEND_REPLACE, "REPLACE", 0, "Replace", ""},
{SEQ_TYPE_CROSS, "CROSS", 0, "Cross", ""},
- {0, "", ICON_NONE, NULL, NULL},
+ RNA_ENUM_ITEM_SEPR,
{SEQ_TYPE_DARKEN, "DARKEN", 0, "Darken", ""},
{SEQ_TYPE_MUL, "MULTIPLY", 0, "Multiply", ""},
{SEQ_TYPE_COLOR_BURN, "BURN", 0, "Color Burn", ""},
{SEQ_TYPE_LINEAR_BURN, "LINEAR_BURN", 0, "Linear Burn", ""},
- {0, "", ICON_NONE, NULL, NULL},
+ RNA_ENUM_ITEM_SEPR,
{SEQ_TYPE_LIGHTEN, "LIGHTEN", 0, "Lighten", ""},
{SEQ_TYPE_SCREEN, "SCREEN", 0, "Screen", ""},
{SEQ_TYPE_DODGE, "DODGE", 0, "Color Dodge", ""},
{SEQ_TYPE_ADD, "ADD", 0, "Add", ""},
- {0, "", ICON_NONE, NULL, NULL},
+ RNA_ENUM_ITEM_SEPR,
{SEQ_TYPE_OVERLAY, "OVERLAY", 0, "Overlay", ""},
{SEQ_TYPE_SOFT_LIGHT, "SOFT_LIGHT", 0, "Soft Light", ""},
{SEQ_TYPE_HARD_LIGHT, "HARD_LIGHT", 0, "Hard Light", ""},
{SEQ_TYPE_VIVID_LIGHT, "VIVID_LIGHT", 0, "Vivid Light", ""},
{SEQ_TYPE_LIN_LIGHT, "LINEAR_LIGHT", 0, "Linear Light", ""},
{SEQ_TYPE_PIN_LIGHT, "PIN_LIGHT", 0, "Pin Light", ""},
- {0, "", ICON_NONE, NULL, NULL},
+ RNA_ENUM_ITEM_SEPR,
{SEQ_TYPE_DIFFERENCE, "DIFFERENCE", 0, "Difference", ""},
{SEQ_TYPE_EXCLUSION, "EXCLUSION", 0, "Exclusion", ""},
{SEQ_TYPE_SUB, "SUBTRACT", 0, "Subtract", ""},
- {0, "", ICON_NONE, NULL, NULL},
+ RNA_ENUM_ITEM_SEPR,
{SEQ_TYPE_HUE, "HUE", 0, "Hue", ""},
{SEQ_TYPE_SATURATION, "SATURATION", 0, "Saturation", ""},
{SEQ_TYPE_BLEND_COLOR, "COLOR", 0, "Color", ""},
{SEQ_TYPE_VALUE, "VALUE", 0, "Value", ""},
- {0, "", ICON_NONE, NULL, NULL},
+ RNA_ENUM_ITEM_SEPR,
{SEQ_TYPE_ALPHAOVER, "ALPHA_OVER", 0, "Alpha Over", ""},
{SEQ_TYPE_ALPHAUNDER, "ALPHA_UNDER", 0, "Alpha Under", ""},
{SEQ_TYPE_GAMCROSS, "GAMMA_CROSS", 0, "Gamma Cross", ""},
@@ -2037,22 +1989,6 @@ static void rna_def_sequence(BlenderRNA *brna)
prop, NULL, "rna_Sequence_frame_offset_end_set", "rna_Sequence_frame_offset_end_range");
RNA_def_property_update(prop, NC_SCENE | ND_SEQUENCER, "rna_Sequence_frame_change_update");
- prop = RNA_def_property(srna, "frame_still_start", PROP_INT, PROP_TIME);
- RNA_def_property_int_sdna(prop, NULL, "startstill");
- // RNA_def_property_clear_flag(prop, PROP_EDITABLE); /* overlap tests */
- RNA_def_property_range(prop, 0, MAXFRAME);
- RNA_def_property_ui_text(prop, "Start Still", "");
- RNA_def_property_int_funcs(prop, NULL, "rna_Sequence_frame_still_start_set", NULL);
- RNA_def_property_update(prop, NC_SCENE | ND_SEQUENCER, "rna_Sequence_frame_change_update");
-
- prop = RNA_def_property(srna, "frame_still_end", PROP_INT, PROP_TIME);
- RNA_def_property_int_sdna(prop, NULL, "endstill");
- // RNA_def_property_clear_flag(prop, PROP_EDITABLE); /* overlap tests */
- RNA_def_property_range(prop, 0, MAXFRAME);
- RNA_def_property_ui_text(prop, "End Still", "");
- RNA_def_property_int_funcs(prop, NULL, "rna_Sequence_frame_still_end_set", NULL);
- RNA_def_property_update(prop, NC_SCENE | ND_SEQUENCER, "rna_Sequence_frame_change_update");
-
prop = RNA_def_property(srna, "channel", PROP_INT, PROP_UNSIGNED);
RNA_def_property_int_sdna(prop, NULL, "machine");
RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
@@ -3203,23 +3139,23 @@ static void rna_def_color_mix(StructRNA *srna)
{SEQ_TYPE_MUL, "MULTIPLY", 0, "Multiply", ""},
{SEQ_TYPE_COLOR_BURN, "BURN", 0, "Color Burn", ""},
{SEQ_TYPE_LINEAR_BURN, "LINEAR_BURN", 0, "Linear Burn", ""},
- {0, "", ICON_NONE, NULL, NULL},
+ RNA_ENUM_ITEM_SEPR,
{SEQ_TYPE_LIGHTEN, "LIGHTEN", 0, "Lighten", ""},
{SEQ_TYPE_SCREEN, "SCREEN", 0, "Screen", ""},
{SEQ_TYPE_DODGE, "DODGE", 0, "Color Dodge", ""},
{SEQ_TYPE_ADD, "ADD", 0, "Add", ""},
- {0, "", ICON_NONE, NULL, NULL},
+ RNA_ENUM_ITEM_SEPR,
{SEQ_TYPE_OVERLAY, "OVERLAY", 0, "Overlay", ""},
{SEQ_TYPE_SOFT_LIGHT, "SOFT_LIGHT", 0, "Soft Light", ""},
{SEQ_TYPE_HARD_LIGHT, "HARD_LIGHT", 0, "Hard Light", ""},
{SEQ_TYPE_VIVID_LIGHT, "VIVID_LIGHT", 0, "Vivid Light", ""},
{SEQ_TYPE_LIN_LIGHT, "LINEAR_LIGHT", 0, "Linear Light", ""},
{SEQ_TYPE_PIN_LIGHT, "PIN_LIGHT", 0, "Pin Light", ""},
- {0, "", ICON_NONE, NULL, NULL},
+ RNA_ENUM_ITEM_SEPR,
{SEQ_TYPE_DIFFERENCE, "DIFFERENCE", 0, "Difference", ""},
{SEQ_TYPE_EXCLUSION, "EXCLUSION", 0, "Exclusion", ""},
{SEQ_TYPE_SUB, "SUBTRACT", 0, "Subtract", ""},
- {0, "", ICON_NONE, NULL, NULL},
+ RNA_ENUM_ITEM_SEPR,
{SEQ_TYPE_HUE, "HUE", 0, "Hue", ""},
{SEQ_TYPE_SATURATION, "SATURATION", 0, "Saturation", ""},
{SEQ_TYPE_BLEND_COLOR, "COLOR", 0, "Color", ""},
diff --git a/source/blender/makesrna/intern/rna_sequencer_api.c b/source/blender/makesrna/intern/rna_sequencer_api.c
index 36bc50e73fb..52de98be502 100644
--- a/source/blender/makesrna/intern/rna_sequencer_api.c
+++ b/source/blender/makesrna/intern/rna_sequencer_api.c
@@ -49,20 +49,6 @@
# include "WM_api.h"
-static void rna_Sequence_update_rnafunc(ID *id, Sequence *self, bool do_data)
-{
- Scene *scene = (Scene *)id;
- Editing *ed = SEQ_editing_get(scene);
- ListBase *seqbase = SEQ_get_seqbase_by_seq(&ed->seqbase, self);
-
- if (do_data) {
- SEQ_time_update_recursive(scene, self);
- // new_tstripdata(self); /* need 2.6x version of this. */
- }
-
- SEQ_time_update_sequence(scene, seqbase, self);
-}
-
static void rna_Sequence_swap_internal(Sequence *seq_self,
ReportList *reports,
Sequence *seq_other)
@@ -96,8 +82,7 @@ static Sequence *rna_Sequence_split(
ID *id, Sequence *seq, Main *bmain, ReportList *reports, int frame, int split_method)
{
Scene *scene = (Scene *)id;
- Editing *ed = SEQ_editing_get(scene);
- ListBase *seqbase = SEQ_get_seqbase_by_seq(&ed->seqbase, seq);
+ ListBase *seqbase = SEQ_get_seqbase_by_seq(scene, seq);
const char *error_msg = NULL;
Sequence *r_seq = SEQ_edit_strip_split(
@@ -576,8 +561,6 @@ static void rna_Sequences_meta_remove(
static StripElem *rna_SequenceElements_append(ID *id, Sequence *seq, const char *filename)
{
Scene *scene = (Scene *)id;
- Editing *ed = SEQ_editing_get(scene);
- ListBase *seqbase = SEQ_get_seqbase_by_seq(&ed->seqbase, seq);
StripElem *se;
seq->strip->stripdata = se = MEM_reallocN(seq->strip->stripdata,
@@ -586,7 +569,6 @@ static StripElem *rna_SequenceElements_append(ID *id, Sequence *seq, const char
BLI_strncpy(se->name, filename, sizeof(se->name));
seq->len++;
- SEQ_time_update_sequence(scene, seqbase, seq);
WM_main_add_notifier(NC_SCENE | ND_SEQUENCER, scene);
return se;
@@ -595,8 +577,6 @@ static StripElem *rna_SequenceElements_append(ID *id, Sequence *seq, const char
static void rna_SequenceElements_pop(ID *id, Sequence *seq, ReportList *reports, int index)
{
Scene *scene = (Scene *)id;
- Editing *ed = SEQ_editing_get(scene);
- ListBase *seqbase = SEQ_get_seqbase_by_seq(&ed->seqbase, seq);
StripElem *new_seq, *se;
if (seq->len == 1) {
@@ -629,8 +609,6 @@ static void rna_SequenceElements_pop(ID *id, Sequence *seq, ReportList *reports,
MEM_freeN(seq->strip->stripdata);
seq->strip->stripdata = new_seq;
- SEQ_time_update_sequence(scene, seqbase, seq);
-
WM_main_add_notifier(NC_SCENE | ND_SEQUENCER, scene);
}
@@ -669,11 +647,6 @@ void RNA_api_sequence_strip(StructRNA *srna)
{0, NULL, 0, NULL, NULL},
};
- func = RNA_def_function(srna, "update", "rna_Sequence_update_rnafunc");
- RNA_def_function_flag(func, FUNC_USE_SELF_ID);
- RNA_def_function_ui_description(func, "Update the strip dimensions");
- parm = RNA_def_boolean(func, "data", false, "Data", "Update strip data");
-
func = RNA_def_function(srna, "strip_elem_from_frame", "SEQ_render_give_stripelem");
RNA_def_function_ui_description(func, "Return the strip element from a given frame or None");
parm = RNA_def_int(func,
diff --git a/source/blender/makesrna/intern/rna_shader_fx.c b/source/blender/makesrna/intern/rna_shader_fx.c
index cefa445740d..0a656222fd5 100644
--- a/source/blender/makesrna/intern/rna_shader_fx.c
+++ b/source/blender/makesrna/intern/rna_shader_fx.c
@@ -142,9 +142,9 @@ static void rna_ShaderFx_name_set(PointerRNA *ptr, const char *value)
BKE_animdata_fix_paths_rename_all(NULL, "shader_effects", oldname, gmd->name);
}
-static char *rna_ShaderFx_path(PointerRNA *ptr)
+static char *rna_ShaderFx_path(const PointerRNA *ptr)
{
- ShaderFxData *gmd = ptr->data;
+ const ShaderFxData *gmd = ptr->data;
char name_esc[sizeof(gmd->name) * 2];
BLI_str_escape(name_esc, gmd->name, sizeof(name_esc));
diff --git a/source/blender/makesrna/intern/rna_sound.c b/source/blender/makesrna/intern/rna_sound.c
index 3d51f80adde..e38481a845a 100644
--- a/source/blender/makesrna/intern/rna_sound.c
+++ b/source/blender/makesrna/intern/rna_sound.c
@@ -12,6 +12,22 @@
#include "DNA_sound_types.h"
+#include "BKE_sound.h"
+
+/* Enumeration for Audio Channels, compatible with eSoundChannels */
+static const EnumPropertyItem rna_enum_audio_channels_items[] = {
+ {SOUND_CHANNELS_INVALID, "INVALID", ICON_NONE, "Invalid", "Invalid"},
+ {SOUND_CHANNELS_MONO, "MONO", ICON_NONE, "Mono", "Mono"},
+ {SOUND_CHANNELS_STEREO, "STEREO", ICON_NONE, "Stereo", "Stereo"},
+ {SOUND_CHANNELS_STEREO_LFE, "STEREO_LFE", ICON_NONE, "Stereo LFE", "Stereo FX"},
+ {SOUND_CHANNELS_SURROUND4, "CHANNELS_4", ICON_NONE, "4 Channels", "4 Channels"},
+ {SOUND_CHANNELS_SURROUND5, "CHANNELS_5", ICON_NONE, "5 Channels", "5 Channels"},
+ {SOUND_CHANNELS_SURROUND51, "SURROUND_51", ICON_NONE, "5.1 Surround", "5.1 Surround"},
+ {SOUND_CHANNELS_SURROUND61, "SURROUND_61", ICON_NONE, "6.1 Surround", "6.1 Surround"},
+ {SOUND_CHANNELS_SURROUND71, "SURROUND_71", ICON_NONE, "7.1 Surround", "7.1 Surround"},
+ {0, NULL, 0, NULL, NULL},
+};
+
#ifdef RNA_RUNTIME
# include "BKE_context.h"
@@ -70,6 +86,18 @@ static void rna_def_sound(BlenderRNA *brna)
"If the file contains multiple audio channels they are rendered to a single one");
RNA_def_property_update(prop, 0, "rna_Sound_update");
+ prop = RNA_def_property(srna, "samplerate", PROP_INT, PROP_NONE);
+ RNA_def_property_int_sdna(prop, NULL, "samplerate");
+ RNA_def_property_clear_flag(prop, PROP_EDITABLE);
+ RNA_def_property_ui_text(prop, "Samplerate", "Samplerate of the audio in Hz");
+
+ prop = RNA_def_property(srna, "channels", PROP_ENUM, PROP_NONE);
+ RNA_def_property_enum_sdna(prop, NULL, "audio_channels");
+ RNA_def_property_enum_items(prop, rna_enum_audio_channels_items);
+ RNA_def_property_enum_default(prop, SOUND_CHANNELS_INVALID);
+ RNA_def_property_clear_flag(prop, PROP_EDITABLE);
+ RNA_def_property_ui_text(prop, "Audio channels", "Definition of audio channels");
+
RNA_api_sound(srna);
}
diff --git a/source/blender/makesrna/intern/rna_space.c b/source/blender/makesrna/intern/rna_space.c
index 11a1cf95d52..0b780a3fcc6 100644
--- a/source/blender/makesrna/intern/rna_space.c
+++ b/source/blender/makesrna/intern/rna_space.c
@@ -87,8 +87,8 @@ const EnumPropertyItem rna_enum_space_type_items[] = {
/* empty must be here for python, is skipped for UI */
{SPACE_EMPTY, "EMPTY", ICON_NONE, "Empty", ""},
- /* General */
- {0, "", ICON_NONE, "General", ""},
+ /* General. */
+ RNA_ENUM_ITEM_HEADING("General", NULL),
{SPACE_VIEW3D,
"VIEW_3D",
ICON_VIEW3D,
@@ -107,8 +107,8 @@ const EnumPropertyItem rna_enum_space_type_items[] = {
{SPACE_SEQ, "SEQUENCE_EDITOR", ICON_SEQUENCE, "Video Sequencer", "Video editing tools"},
{SPACE_CLIP, "CLIP_EDITOR", ICON_TRACKER, "Movie Clip Editor", "Motion tracking tools"},
- /* Animation */
- {0, "", ICON_NONE, "Animation", ""},
+ /* Animation. */
+ RNA_ENUM_ITEM_HEADING("Animation", NULL),
#if 0
{SPACE_ACTION,
"TIMELINE",
@@ -124,8 +124,8 @@ const EnumPropertyItem rna_enum_space_type_items[] = {
"Edit drivers and keyframe interpolation"},
{SPACE_NLA, "NLA_EDITOR", ICON_NLA, "Nonlinear Animation", "Combine and layer Actions"},
- /* Scripting */
- {0, "", ICON_NONE, "Scripting", ""},
+ /* Scripting. */
+ RNA_ENUM_ITEM_HEADING("Scripting", NULL),
{SPACE_TEXT,
"TEXT_EDITOR",
ICON_TEXT,
@@ -152,8 +152,8 @@ const EnumPropertyItem rna_enum_space_type_items[] = {
"Global bar at the bottom of the "
"screen for general status information"},
- /* Data */
- {0, "", ICON_NONE, "Data", ""},
+ /* Data. */
+ RNA_ENUM_ITEM_HEADING("Data", NULL),
{SPACE_OUTLINER,
"OUTLINER",
ICON_OUTLINER,
@@ -435,28 +435,28 @@ static const EnumPropertyItem rna_enum_studio_light_items[] = {
};
static const EnumPropertyItem rna_enum_view3dshading_render_pass_type_items[] = {
- {0, "", ICON_NONE, "General", ""},
+ RNA_ENUM_ITEM_HEADING("General", NULL),
{EEVEE_RENDER_PASS_COMBINED, "COMBINED", 0, "Combined", ""},
{EEVEE_RENDER_PASS_EMIT, "EMISSION", 0, "Emission", ""},
{EEVEE_RENDER_PASS_ENVIRONMENT, "ENVIRONMENT", 0, "Environment", ""},
{EEVEE_RENDER_PASS_AO, "AO", 0, "Ambient Occlusion", ""},
{EEVEE_RENDER_PASS_SHADOW, "SHADOW", 0, "Shadow", ""},
- {0, "", ICON_NONE, "Light", ""},
+ RNA_ENUM_ITEM_HEADING("Light", NULL),
{EEVEE_RENDER_PASS_DIFFUSE_LIGHT, "DIFFUSE_LIGHT", 0, "Diffuse Light", ""},
{EEVEE_RENDER_PASS_DIFFUSE_COLOR, "DIFFUSE_COLOR", 0, "Diffuse Color", ""},
{EEVEE_RENDER_PASS_SPECULAR_LIGHT, "SPECULAR_LIGHT", 0, "Specular Light", ""},
{EEVEE_RENDER_PASS_SPECULAR_COLOR, "SPECULAR_COLOR", 0, "Specular Color", ""},
{EEVEE_RENDER_PASS_VOLUME_LIGHT, "VOLUME_LIGHT", 0, "Volume Light", ""},
- {0, "", ICON_NONE, "Effects", ""},
+ RNA_ENUM_ITEM_HEADING("Effects", NULL),
{EEVEE_RENDER_PASS_BLOOM, "BLOOM", 0, "Bloom", ""},
- {0, "", ICON_NONE, "Data", ""},
+ RNA_ENUM_ITEM_HEADING("Data", NULL),
{EEVEE_RENDER_PASS_NORMAL, "NORMAL", 0, "Normal", ""},
{EEVEE_RENDER_PASS_MIST, "MIST", 0, "Mist", ""},
- {0, "", ICON_NONE, "Shader AOV", ""},
+ RNA_ENUM_ITEM_HEADING("Shader AOV", NULL),
{EEVEE_RENDER_PASS_AOV, "AOV", 0, "AOV", ""},
{0, NULL, 0, NULL, NULL},
@@ -1040,6 +1040,24 @@ static void rna_RegionView3D_quadview_clip_update(Main *UNUSED(main),
}
}
+/**
+ * After the rotation changes, either clear the view axis
+ * or update it not to be aligned to an axis, without this the viewport will show
+ * text that doesn't match the rotation.
+ */
+static void rna_RegionView3D_view_rotation_set_validate_view_axis(RegionView3D *rv3d)
+{
+ /* Never rotate from a "User" view into an axis aligned view,
+ * otherwise rotation could be aligned by accident - giving unexpected behavior. */
+ if (!RV3D_VIEW_IS_AXIS(rv3d->view)) {
+ return;
+ }
+ /* Keep this small as script authors wont expect the assigned value to change. */
+ const float eps_quat = 1e-6f;
+ ED_view3d_quat_to_axis_view_and_reset_quat(
+ rv3d->viewquat, eps_quat, &rv3d->view, &rv3d->view_axis_roll);
+}
+
static void rna_RegionView3D_view_location_get(PointerRNA *ptr, float *values)
{
RegionView3D *rv3d = (RegionView3D *)(ptr->data);
@@ -1062,6 +1080,7 @@ static void rna_RegionView3D_view_rotation_set(PointerRNA *ptr, const float *val
{
RegionView3D *rv3d = (RegionView3D *)(ptr->data);
invert_qt_qt(rv3d->viewquat, values);
+ rna_RegionView3D_view_rotation_set_validate_view_axis(rv3d);
}
static void rna_RegionView3D_view_matrix_set(PointerRNA *ptr, const float *values)
@@ -1070,14 +1089,41 @@ static void rna_RegionView3D_view_matrix_set(PointerRNA *ptr, const float *value
float mat[4][4];
invert_m4_m4(mat, (float(*)[4])values);
ED_view3d_from_m4(mat, rv3d->ofs, rv3d->viewquat, &rv3d->dist);
+ rna_RegionView3D_view_rotation_set_validate_view_axis(rv3d);
}
static bool rna_RegionView3D_is_orthographic_side_view_get(PointerRNA *ptr)
{
+ /* NOTE: only checks axis alignment, not orthographic,
+ * we may deprecate the current name to reflect this. */
RegionView3D *rv3d = (RegionView3D *)(ptr->data);
return RV3D_VIEW_IS_AXIS(rv3d->view);
}
+static void rna_RegionView3D_is_orthographic_side_view_set(PointerRNA *ptr, int value)
+{
+ RegionView3D *rv3d = (RegionView3D *)(ptr->data);
+ const bool was_axis_view = RV3D_VIEW_IS_AXIS(rv3d->view);
+ if (value) {
+ /* Already axis aligned, nothing to do. */
+ if (was_axis_view) {
+ return;
+ }
+ /* Use a large value as we always want to set this to the closest axis. */
+ const float eps_quat = FLT_MAX;
+ ED_view3d_quat_to_axis_view_and_reset_quat(
+ rv3d->viewquat, eps_quat, &rv3d->view, &rv3d->view_axis_roll);
+ }
+ else {
+ /* Only allow changing from axis-views to user view as camera view for e.g.
+ * doesn't make sense to update. */
+ if (!was_axis_view) {
+ return;
+ }
+ rv3d->view = RV3D_VIEW_USER;
+ }
+}
+
static IDProperty **rna_View3DShading_idprops(PointerRNA *ptr)
{
View3DShading *shading = ptr->data;
@@ -1519,7 +1565,7 @@ static int rna_SpaceView3D_icon_from_show_object_viewport_get(PointerRNA *ptr)
&v3d->object_type_exclude_select);
}
-static char *rna_View3DShading_path(PointerRNA *UNUSED(ptr))
+static char *rna_View3DShading_path(const PointerRNA *UNUSED(ptr))
{
return BLI_strdup("shading");
}
@@ -1529,7 +1575,7 @@ static PointerRNA rna_SpaceView3D_overlay_get(PointerRNA *ptr)
return rna_pointer_inherit_refine(ptr, &RNA_View3DOverlay, ptr->data);
}
-static char *rna_View3DOverlay_path(PointerRNA *UNUSED(ptr))
+static char *rna_View3DOverlay_path(const PointerRNA *UNUSED(ptr))
{
return BLI_strdup("overlay");
}
@@ -1541,12 +1587,12 @@ static PointerRNA rna_SpaceImage_overlay_get(PointerRNA *ptr)
return rna_pointer_inherit_refine(ptr, &RNA_SpaceImageOverlay, ptr->data);
}
-static char *rna_SpaceImageOverlay_path(PointerRNA *UNUSED(ptr))
+static char *rna_SpaceImageOverlay_path(const PointerRNA *UNUSED(ptr))
{
return BLI_strdup("overlay");
}
-static char *rna_SpaceUVEditor_path(PointerRNA *UNUSED(ptr))
+static char *rna_SpaceUVEditor_path(const PointerRNA *UNUSED(ptr))
{
return BLI_strdup("uv_editor");
}
@@ -1978,7 +2024,7 @@ static void rna_SpaceProperties_context_update(Main *UNUSED(bmain),
}
}
-static int rna_SpaceProperties_tab_search_results_getlength(PointerRNA *ptr,
+static int rna_SpaceProperties_tab_search_results_getlength(const PointerRNA *ptr,
int length[RNA_MAX_ARRAY_DIMENSION])
{
SpaceProperties *sbuts = ptr->data;
@@ -2380,12 +2426,12 @@ static void rna_Sequencer_view_type_update(Main *UNUSED(bmain),
ED_area_tag_refresh(area);
}
-static char *rna_SpaceSequencerPreviewOverlay_path(PointerRNA *UNUSED(ptr))
+static char *rna_SpaceSequencerPreviewOverlay_path(const PointerRNA *UNUSED(ptr))
{
return BLI_strdup("preview_overlay");
}
-static char *rna_SpaceSequencerTimelineOverlay_path(PointerRNA *UNUSED(ptr))
+static char *rna_SpaceSequencerTimelineOverlay_path(const PointerRNA *UNUSED(ptr))
{
return BLI_strdup("timeline_overlay");
}
@@ -2396,7 +2442,7 @@ static PointerRNA rna_SpaceNode_overlay_get(PointerRNA *ptr)
return rna_pointer_inherit_refine(ptr, &RNA_SpaceNodeOverlay, ptr->data);
}
-static char *rna_SpaceNodeOverlay_path(PointerRNA *UNUSED(ptr))
+static char *rna_SpaceNodeOverlay_path(const PointerRNA *UNUSED(ptr))
{
return BLI_strdup("overlay");
}
@@ -2589,7 +2635,7 @@ static void rna_SpaceClipEditor_view_type_update(Main *UNUSED(bmain),
/* File browser. */
-static char *rna_FileSelectParams_path(PointerRNA *UNUSED(ptr))
+static char *rna_FileSelectParams_path(const PointerRNA *UNUSED(ptr))
{
return BLI_strdup("params");
}
@@ -3292,7 +3338,7 @@ static struct IDFilterEnumPropertyItem rna_enum_space_file_id_filter_categories[
{FILTER_ID_AR | FILTER_ID_CU_LEGACY | FILTER_ID_LT | FILTER_ID_MB | FILTER_ID_ME |
FILTER_ID_CV | FILTER_ID_PT | FILTER_ID_VO,
"category_geometry",
- ICON_NODETREE,
+ ICON_GEOMETRY_NODES,
"Geometry",
"Show meshes, curves, lattice, armatures and metaballs data"},
{FILTER_ID_LS | FILTER_ID_MA | FILTER_ID_NT | FILTER_ID_TE,
@@ -3437,6 +3483,11 @@ static void rna_def_space_mask_info(StructRNA *srna, int noteflag, const char *m
RNA_def_property_ui_text(prop, "Display Smooth Splines", "");
RNA_def_property_update(prop, noteflag, NULL);
+ prop = RNA_def_property(srna, "show_mask_spline", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "mask_info.draw_flag", MASK_DRAWFLAG_SPLINE);
+ RNA_def_property_ui_text(prop, "Show Mask Spline", "");
+ RNA_def_property_update(prop, noteflag, NULL);
+
prop = RNA_def_property(srna, "show_mask_overlay", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "mask_info.draw_flag", MASK_DRAWFLAG_OVERLAY);
RNA_def_property_ui_text(prop, "Show Mask Overlay", "");
@@ -3447,6 +3498,13 @@ static void rna_def_space_mask_info(StructRNA *srna, int noteflag, const char *m
RNA_def_property_enum_items(prop, overlay_mode_items);
RNA_def_property_ui_text(prop, "Overlay Mode", "Overlay mode of rasterized mask");
RNA_def_property_update(prop, noteflag, NULL);
+
+ prop = RNA_def_property(srna, "blend_factor", PROP_FLOAT, PROP_FACTOR);
+ RNA_def_property_float_sdna(prop, NULL, "mask_info.blend_factor");
+ RNA_def_property_range(prop, 0.0f, 1.0f);
+ RNA_def_property_ui_range(prop, 0, 1., 0.1, 1);
+ RNA_def_property_ui_text(prop, "Blending Factor", "Overlay blending factor of rasterized mask");
+ RNA_def_property_update(prop, noteflag, NULL);
}
static void rna_def_space_image_uv(BlenderRNA *brna)
@@ -5077,10 +5135,18 @@ static void rna_def_space_view3d(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "Is Perspective", "");
RNA_def_property_flag(prop, PROP_EDITABLE);
+ /* WARNING: Using "orthographic" in this name isn't correct and could be changed. */
prop = RNA_def_property(srna, "is_orthographic_side_view", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "view", 0);
- RNA_def_property_boolean_funcs(prop, "rna_RegionView3D_is_orthographic_side_view_get", NULL);
- RNA_def_property_ui_text(prop, "Is Axis Aligned", "Is current view an orthographic side view");
+ RNA_def_property_boolean_funcs(prop,
+ "rna_RegionView3D_is_orthographic_side_view_get",
+ "rna_RegionView3D_is_orthographic_side_view_set");
+ RNA_def_property_ui_text(
+ prop,
+ "Is Axis Aligned",
+ "Is current view aligned to an axis "
+ "(does not check the view is orthographic use \"is_perspective\" for that). "
+ "Assignment sets the \"view_rotation\" to the closest axis aligned view");
/* This isn't directly accessible from the UI, only an operator. */
prop = RNA_def_property(srna, "use_clip_planes", PROP_BOOLEAN, PROP_NONE);
@@ -7764,6 +7830,12 @@ static void rna_def_spreadsheet_row_filter(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "Integer Value", "");
RNA_def_property_update(prop, NC_SPACE | ND_SPACE_SPREADSHEET, NULL);
+ prop = RNA_def_property(srna, "value_int8", PROP_INT, PROP_NONE);
+ RNA_def_property_int_sdna(prop, NULL, "value_int");
+ RNA_def_property_range(prop, -128, 127);
+ RNA_def_property_ui_text(prop, "8-Bit Integer Value", "");
+ RNA_def_property_update(prop, NC_SPACE | ND_SPACE_SPREADSHEET, NULL);
+
prop = RNA_def_property(srna, "value_boolean", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flag", SPREADSHEET_ROW_FILTER_BOOL_VALUE);
RNA_def_property_ui_text(prop, "Boolean Value", "");
diff --git a/source/blender/makesrna/intern/rna_texture.c b/source/blender/makesrna/intern/rna_texture.c
index 6f7ee966723..3b28dc70e9e 100644
--- a/source/blender/makesrna/intern/rna_texture.c
+++ b/source/blender/makesrna/intern/rna_texture.c
@@ -98,22 +98,22 @@ const EnumPropertyItem rna_enum_texture_type_items[] = {
#ifndef RNA_RUNTIME
static const EnumPropertyItem blend_type_items[] = {
{MTEX_BLEND, "MIX", 0, "Mix", ""},
- {0, "", ICON_NONE, NULL, NULL},
+ RNA_ENUM_ITEM_SEPR,
{MTEX_DARK, "DARKEN", 0, "Darken", ""},
{MTEX_MUL, "MULTIPLY", 0, "Multiply", ""},
- {0, "", ICON_NONE, NULL, NULL},
+ RNA_ENUM_ITEM_SEPR,
{MTEX_LIGHT, "LIGHTEN", 0, "Lighten", ""},
{MTEX_SCREEN, "SCREEN", 0, "Screen", ""},
{MTEX_ADD, "ADD", 0, "Add", ""},
- {0, "", ICON_NONE, NULL, NULL},
+ RNA_ENUM_ITEM_SEPR,
{MTEX_OVERLAY, "OVERLAY", 0, "Overlay", ""},
{MTEX_SOFT_LIGHT, "SOFT_LIGHT", 0, "Soft Light", ""},
{MTEX_LIN_LIGHT, "LINEAR_LIGHT", 0, "Linear Light", ""},
- {0, "", ICON_NONE, NULL, NULL},
+ RNA_ENUM_ITEM_SEPR,
{MTEX_DIFF, "DIFFERENCE", 0, "Difference", ""},
{MTEX_SUB, "SUBTRACT", 0, "Subtract", ""},
{MTEX_DIV, "DIVIDE", 0, "Divide", ""},
- {0, "", ICON_NONE, NULL, NULL},
+ RNA_ENUM_ITEM_SEPR,
{MTEX_BLEND_HUE, "HUE", 0, "Hue", ""},
{MTEX_BLEND_SAT, "SATURATION", 0, "Saturation", ""},
{MTEX_BLEND_COLOR, "COLOR", 0, "Color", ""},
@@ -291,7 +291,7 @@ void rna_TextureSlot_update(bContext *C, PointerRNA *ptr)
}
}
-char *rna_TextureSlot_path(PointerRNA *ptr)
+char *rna_TextureSlot_path(const PointerRNA *ptr)
{
MTex *mtex = ptr->data;
diff --git a/source/blender/makesrna/intern/rna_tracking.c b/source/blender/makesrna/intern/rna_tracking.c
index e604469e3fd..b9acd57430b 100644
--- a/source/blender/makesrna/intern/rna_tracking.c
+++ b/source/blender/makesrna/intern/rna_tracking.c
@@ -41,7 +41,7 @@
# include "WM_api.h"
-static char *rna_tracking_path(PointerRNA *UNUSED(ptr))
+static char *rna_tracking_path(const PointerRNA *UNUSED(ptr))
{
return BLI_strdup("tracking");
}
@@ -72,7 +72,7 @@ static void rna_tracking_defaultSettings_searchUpdate(Main *UNUSED(bmain),
}
}
-static char *rna_trackingTrack_path(PointerRNA *ptr)
+static char *rna_trackingTrack_path(const PointerRNA *ptr)
{
MovieClip *clip = (MovieClip *)ptr->owner_id;
MovieTrackingTrack *track = (MovieTrackingTrack *)ptr->data;
@@ -255,7 +255,7 @@ static void rna_trackingPlaneMarker_frame_set(PointerRNA *ptr, int value)
}
}
-static char *rna_trackingPlaneTrack_path(PointerRNA *ptr)
+static char *rna_trackingPlaneTrack_path(const PointerRNA *ptr)
{
MovieClip *clip = (MovieClip *)ptr->owner_id;
MovieTrackingPlaneTrack *plane_track = (MovieTrackingPlaneTrack *)ptr->data;
@@ -289,7 +289,7 @@ static void rna_trackingPlaneTrack_name_set(PointerRNA *ptr, const char *value)
}
}
-static char *rna_trackingCamera_path(PointerRNA *UNUSED(ptr))
+static char *rna_trackingCamera_path(const PointerRNA *UNUSED(ptr))
{
return BLI_strdup("tracking.camera");
}
@@ -321,7 +321,7 @@ static void rna_trackingCamera_focal_mm_set(PointerRNA *ptr, float value)
}
}
-static char *rna_trackingStabilization_path(PointerRNA *UNUSED(ptr))
+static char *rna_trackingStabilization_path(const PointerRNA *UNUSED(ptr))
{
return BLI_strdup("tracking.stabilization");
}
@@ -557,7 +557,7 @@ static void rna_tracking_markerPattern_update(Main *UNUSED(bmain),
{
MovieTrackingMarker *marker = (MovieTrackingMarker *)ptr->data;
- BKE_tracking_marker_clamp(marker, CLAMP_PAT_DIM);
+ BKE_tracking_marker_clamp_search_size(marker);
}
static void rna_tracking_markerSearch_update(Main *UNUSED(bmain),
@@ -566,7 +566,7 @@ static void rna_tracking_markerSearch_update(Main *UNUSED(bmain),
{
MovieTrackingMarker *marker = (MovieTrackingMarker *)ptr->data;
- BKE_tracking_marker_clamp(marker, CLAMP_SEARCH_DIM);
+ BKE_tracking_marker_clamp_search_size(marker);
}
static void rna_tracking_markerPattern_boundbox_get(PointerRNA *ptr, float *values)
diff --git a/source/blender/makesrna/intern/rna_ui.c b/source/blender/makesrna/intern/rna_ui.c
index 1d0723851ad..dabb89bcd5e 100644
--- a/source/blender/makesrna/intern/rna_ui.c
+++ b/source/blender/makesrna/intern/rna_ui.c
@@ -393,7 +393,14 @@ static StructRNA *rna_Panel_register(Main *bmain,
if (parent) {
pt->parent = parent;
- BLI_addtail(&parent->children, BLI_genericNodeN(pt));
+ LinkData *pt_child_iter = parent->children.last;
+ for (; pt_child_iter; pt_child_iter = pt_child_iter->prev) {
+ PanelType *pt_child = pt_child_iter->data;
+ if (pt_child->order <= pt->order) {
+ break;
+ }
+ }
+ BLI_insertlinkafter(&parent->children, pt_child_iter, BLI_genericNodeN(pt));
}
{
diff --git a/source/blender/makesrna/intern/rna_userdef.c b/source/blender/makesrna/intern/rna_userdef.c
index 5ac324b3627..40dc1254a7d 100644
--- a/source/blender/makesrna/intern/rna_userdef.c
+++ b/source/blender/makesrna/intern/rna_userdef.c
@@ -62,23 +62,23 @@ const EnumPropertyItem rna_enum_preference_section_items[] = {
{USER_SECTION_LIGHT, "LIGHTS", 0, "Lights", ""},
{USER_SECTION_EDITING, "EDITING", 0, "Editing", ""},
{USER_SECTION_ANIMATION, "ANIMATION", 0, "Animation", ""},
- {0, "", 0, NULL, NULL},
+ RNA_ENUM_ITEM_SEPR,
{USER_SECTION_ADDONS, "ADDONS", 0, "Add-ons", ""},
#if 0 /* def WITH_USERDEF_WORKSPACES */
- {0, "", 0, NULL, NULL},
+ RNA_ENUM_ITEM_SEPR,
{USER_SECTION_WORKSPACE_CONFIG, "WORKSPACE_CONFIG", 0, "Configuration File", ""},
{USER_SECTION_WORKSPACE_ADDONS, "WORKSPACE_ADDONS", 0, "Add-on Overrides", ""},
{USER_SECTION_WORKSPACE_KEYMAPS, "WORKSPACE_KEYMAPS", 0, "Keymap Overrides", ""},
#endif
- {0, "", 0, NULL, NULL},
+ RNA_ENUM_ITEM_SEPR,
{USER_SECTION_INPUT, "INPUT", 0, "Input", ""},
{USER_SECTION_NAVIGATION, "NAVIGATION", 0, "Navigation", ""},
{USER_SECTION_KEYMAP, "KEYMAP", 0, "Keymap", ""},
- {0, "", 0, NULL, NULL},
+ RNA_ENUM_ITEM_SEPR,
{USER_SECTION_SYSTEM, "SYSTEM", 0, "System", ""},
{USER_SECTION_SAVE_LOAD, "SAVE_LOAD", 0, "Save & Load", ""},
{USER_SECTION_FILE_PATHS, "FILE_PATHS", 0, "File Paths", ""},
- {0, "", 0, NULL, NULL},
+ RNA_ENUM_ITEM_SEPR,
{USER_SECTION_EXPERIMENTAL, "EXPERIMENTAL", 0, "Experimental", ""},
{0, NULL, 0, NULL, NULL},
};
@@ -1531,6 +1531,11 @@ static void rna_def_userdef_theme_ui(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "List Item Colors", "");
RNA_def_property_update(prop, 0, "rna_userdef_theme_update");
+ prop = RNA_def_property(srna, "wcol_view_item", PROP_POINTER, PROP_NONE);
+ RNA_def_property_flag(prop, PROP_NEVER_NULL);
+ RNA_def_property_ui_text(prop, "Data-View Item Colors", "");
+ RNA_def_property_update(prop, 0, "rna_userdef_theme_update");
+
prop = RNA_def_property(srna, "wcol_state", PROP_POINTER, PROP_NONE);
RNA_def_property_flag(prop, PROP_NEVER_NULL);
RNA_def_property_ui_text(prop, "State Colors", "");
@@ -6424,6 +6429,11 @@ static void rna_def_userdef_experimental(BlenderRNA *brna)
RNA_def_property_boolean_sdna(prop, NULL, "use_sculpt_texture_paint", 1);
RNA_def_property_ui_text(prop, "Sculpt Texture Paint", "Use texture painting in Sculpt Mode");
+ prop = RNA_def_property(srna, "use_draw_manager_acquire_lock", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "use_draw_manager_acquire_lock", 1);
+ RNA_def_property_ui_text(
+ prop, "Draw Manager Locking", "Don't lock UI during background rendering");
+
prop = RNA_def_property(srna, "use_extended_asset_browser", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_ui_text(prop,
"Extended Asset Browser",
diff --git a/source/blender/makesrna/intern/rna_volume.c b/source/blender/makesrna/intern/rna_volume.c
index 12cb35b239d..6d4ea18fc38 100644
--- a/source/blender/makesrna/intern/rna_volume.c
+++ b/source/blender/makesrna/intern/rna_volume.c
@@ -46,12 +46,12 @@ const EnumPropertyItem rna_enum_volume_grid_data_type_items[] = {
# include "WM_api.h"
# include "WM_types.h"
-static char *rna_VolumeRender_path(PointerRNA *UNUSED(ptr))
+static char *rna_VolumeRender_path(const PointerRNA *UNUSED(ptr))
{
return BLI_strdup("render");
}
-static char *rna_VolumeDisplay_path(PointerRNA *UNUSED(ptr))
+static char *rna_VolumeDisplay_path(const PointerRNA *UNUSED(ptr))
{
return BLI_strdup("display");
}
@@ -485,6 +485,21 @@ static void rna_def_volume_render(BlenderRNA *brna)
RNA_def_struct_sdna(srna, "VolumeRender");
RNA_def_struct_path_func(srna, "rna_VolumeRender_path");
+ static const EnumPropertyItem precision_items[] = {
+ {VOLUME_PRECISION_FULL, "FULL", 0, "Full", "Full float (Use 32 bit for all data)"},
+ {VOLUME_PRECISION_HALF, "HALF", 0, "Half", "Half float (Use 16 bit for all data)"},
+ {VOLUME_PRECISION_VARIABLE, "VARIABLE", 0, "Variable", "Use variable bit quantization"},
+ {0, NULL, 0, NULL, NULL},
+ };
+
+ prop = RNA_def_property(srna, "precision", PROP_ENUM, PROP_NONE);
+ RNA_def_property_enum_items(prop, precision_items);
+ RNA_def_property_ui_text(prop,
+ "Precision",
+ "Specify volume data precision. Lower values reduce memory consumption "
+ "at the cost of detail");
+ RNA_def_property_update(prop, 0, "rna_Volume_update_display");
+
static const EnumPropertyItem space_items[] = {
{VOLUME_SPACE_OBJECT,
"OBJECT",
diff --git a/source/blender/makesrna/intern/rna_wm.c b/source/blender/makesrna/intern/rna_wm.c
index 0ac6dc7aaa9..3ff9e6be3ce 100644
--- a/source/blender/makesrna/intern/rna_wm.c
+++ b/source/blender/makesrna/intern/rna_wm.c
@@ -24,6 +24,7 @@
#include "rna_internal.h"
+#include "WM_api.h"
#include "WM_types.h"
#ifdef RNA_RUNTIME
@@ -36,16 +37,16 @@ static const EnumPropertyItem event_mouse_type_items[] = {
{BUTTON5MOUSE, "BUTTON5MOUSE", 0, "Button5", ""},
{BUTTON6MOUSE, "BUTTON6MOUSE", 0, "Button6", ""},
{BUTTON7MOUSE, "BUTTON7MOUSE", 0, "Button7", ""},
- {0, "", 0, NULL, NULL},
+ RNA_ENUM_ITEM_SEPR,
{TABLET_STYLUS, "PEN", 0, "Pen", ""},
{TABLET_ERASER, "ERASER", 0, "Eraser", ""},
- {0, "", 0, NULL, NULL},
+ RNA_ENUM_ITEM_SEPR,
{MOUSEMOVE, "MOUSEMOVE", 0, "Move", ""},
{MOUSEPAN, "TRACKPADPAN", 0, "Mouse/Trackpad Pan", ""},
{MOUSEZOOM, "TRACKPADZOOM", 0, "Mouse/Trackpad Zoom", ""},
{MOUSEROTATE, "MOUSEROTATE", 0, "Mouse/Trackpad Rotate", ""},
{MOUSESMARTZOOM, "MOUSESMARTZOOM", 0, "Mouse/Trackpad Smart Zoom", ""},
- {0, "", 0, NULL, NULL},
+ RNA_ENUM_ITEM_SEPR,
{WHEELUPMOUSE, "WHEELUPMOUSE", 0, "Wheel Up", ""},
{WHEELDOWNMOUSE, "WHEELDOWNMOUSE", 0, "Wheel Down", ""},
{WHEELINMOUSE, "WHEELINMOUSE", 0, "Wheel In", ""},
@@ -123,6 +124,23 @@ static const EnumPropertyItem event_ndof_type_items[] = {
};
#endif /* RNA_RUNTIME */
+/**
+ * Job types for use in the `bpy.app.is_job_running(job_type)` call.
+ *
+ * This is a subset of the `WM_JOB_TYPE_...` anonymous enum defined in `WM_api.h`. It is
+ * intentionally kept as a subset, such that by default how jobs are handled is kept as an
+ * "internal implementation detail" of Blender, rather than a public, reliable part of the API.
+ *
+ * This array can be expanded on a case-by-case basis, when there is a clear and testable use case.
+ */
+const EnumPropertyItem rna_enum_wm_job_type_items[] = {
+ {WM_JOB_TYPE_RENDER, "RENDER", 0, "Regular rendering", ""},
+ {WM_JOB_TYPE_RENDER_PREVIEW, "RENDER_PREVIEW", 0, "Rendering previews", ""},
+ {WM_JOB_TYPE_OBJECT_BAKE, "OBJECT_BAKE", 0, "Object Baking", ""},
+ {WM_JOB_TYPE_COMPOSITE, "COMPOSITE", 0, "Compositing", ""},
+ {0, NULL, 0, NULL, NULL},
+};
+
const EnumPropertyItem rna_enum_event_type_items[] = {
/* - Note we abuse 'tooltip' message here to store a 'compact' form of some (too) long names.
* - Intentionally excluded: #CAPSLOCKKEY, #UNKNOWNKEY.
@@ -135,22 +153,22 @@ const EnumPropertyItem rna_enum_event_type_items[] = {
{BUTTON5MOUSE, "BUTTON5MOUSE", 0, "Button5 Mouse", "MB5"},
{BUTTON6MOUSE, "BUTTON6MOUSE", 0, "Button6 Mouse", "MB6"},
{BUTTON7MOUSE, "BUTTON7MOUSE", 0, "Button7 Mouse", "MB7"},
- {0, "", 0, NULL, NULL},
+ RNA_ENUM_ITEM_SEPR,
{TABLET_STYLUS, "PEN", 0, "Pen", ""},
{TABLET_ERASER, "ERASER", 0, "Eraser", ""},
- {0, "", 0, NULL, NULL},
+ RNA_ENUM_ITEM_SEPR,
{MOUSEMOVE, "MOUSEMOVE", 0, "Mouse Move", "MsMov"},
{INBETWEEN_MOUSEMOVE, "INBETWEEN_MOUSEMOVE", 0, "In-between Move", "MsSubMov"},
{MOUSEPAN, "TRACKPADPAN", 0, "Mouse/Trackpad Pan", "MsPan"},
{MOUSEZOOM, "TRACKPADZOOM", 0, "Mouse/Trackpad Zoom", "MsZoom"},
{MOUSEROTATE, "MOUSEROTATE", 0, "Mouse/Trackpad Rotate", "MsRot"},
{MOUSESMARTZOOM, "MOUSESMARTZOOM", 0, "Mouse/Trackpad Smart Zoom", "MsSmartZoom"},
- {0, "", 0, NULL, NULL},
+ RNA_ENUM_ITEM_SEPR,
{WHEELUPMOUSE, "WHEELUPMOUSE", 0, "Wheel Up", "WhUp"},
{WHEELDOWNMOUSE, "WHEELDOWNMOUSE", 0, "Wheel Down", "WhDown"},
{WHEELINMOUSE, "WHEELINMOUSE", 0, "Wheel In", "WhIn"},
{WHEELOUTMOUSE, "WHEELOUTMOUSE", 0, "Wheel Out", "WhOut"},
- {0, "", 0, NULL, NULL},
+ RNA_ENUM_ITEM_SEPR,
{EVT_AKEY, "A", 0, "A", ""},
{EVT_BKEY, "B", 0, "B", ""},
{EVT_CKEY, "C", 0, "C", ""},
@@ -177,7 +195,7 @@ const EnumPropertyItem rna_enum_event_type_items[] = {
{EVT_XKEY, "X", 0, "X", ""},
{EVT_YKEY, "Y", 0, "Y", ""},
{EVT_ZKEY, "Z", 0, "Z", ""},
- {0, "", 0, NULL, NULL},
+ RNA_ENUM_ITEM_SEPR,
{EVT_ZEROKEY, "ZERO", 0, "0", ""},
{EVT_ONEKEY, "ONE", 0, "1", ""},
{EVT_TWOKEY, "TWO", 0, "2", ""},
@@ -188,14 +206,14 @@ const EnumPropertyItem rna_enum_event_type_items[] = {
{EVT_SEVENKEY, "SEVEN", 0, "7", ""},
{EVT_EIGHTKEY, "EIGHT", 0, "8", ""},
{EVT_NINEKEY, "NINE", 0, "9", ""},
- {0, "", 0, NULL, NULL},
+ RNA_ENUM_ITEM_SEPR,
{EVT_LEFTCTRLKEY, "LEFT_CTRL", 0, "Left Ctrl", "CtrlL"},
{EVT_LEFTALTKEY, "LEFT_ALT", 0, "Left Alt", "AltL"},
{EVT_LEFTSHIFTKEY, "LEFT_SHIFT", 0, "Left Shift", "ShiftL"},
{EVT_RIGHTALTKEY, "RIGHT_ALT", 0, "Right Alt", "AltR"},
{EVT_RIGHTCTRLKEY, "RIGHT_CTRL", 0, "Right Ctrl", "CtrlR"},
{EVT_RIGHTSHIFTKEY, "RIGHT_SHIFT", 0, "Right Shift", "ShiftR"},
- {0, "", 0, NULL, NULL},
+ RNA_ENUM_ITEM_SEPR,
{EVT_OSKEY, "OSKEY", 0, "OS Key", "Cmd"},
{EVT_APPKEY, "APP", 0, "Application", "App"},
{EVT_GRLESSKEY, "GRLESS", 0, "Grless", ""},
@@ -268,14 +286,14 @@ const EnumPropertyItem rna_enum_event_type_items[] = {
{EVT_PAGEUPKEY, "PAGE_UP", 0, "Page Up", "PgUp"},
{EVT_PAGEDOWNKEY, "PAGE_DOWN", 0, "Page Down", "PgDown"},
{EVT_ENDKEY, "END", 0, "End", ""},
- {0, "", 0, NULL, NULL},
+ RNA_ENUM_ITEM_SEPR,
{EVT_MEDIAPLAY, "MEDIA_PLAY", 0, "Media Play/Pause", ">/||"},
{EVT_MEDIASTOP, "MEDIA_STOP", 0, "Media Stop", "Stop"},
{EVT_MEDIAFIRST, "MEDIA_FIRST", 0, "Media First", "|<<"},
{EVT_MEDIALAST, "MEDIA_LAST", 0, "Media Last", ">>|"},
- {0, "", 0, NULL, NULL},
+ RNA_ENUM_ITEM_SEPR,
{KM_TEXTINPUT, "TEXTINPUT", 0, "Text Input", "TxtIn"},
- {0, "", 0, NULL, NULL},
+ RNA_ENUM_ITEM_SEPR,
{WINDEACTIVATE, "WINDOW_DEACTIVATE", 0, "Window Deactivate", ""},
{TIMER, "TIMER", 0, "Timer", "Tmr"},
{TIMER0, "TIMER0", 0, "Timer 0", "Tmr0"},
@@ -285,7 +303,7 @@ const EnumPropertyItem rna_enum_event_type_items[] = {
{TIMERAUTOSAVE, "TIMER_AUTOSAVE", 0, "Timer Autosave", "TmrSave"},
{TIMERREPORT, "TIMER_REPORT", 0, "Timer Report", "TmrReport"},
{TIMERREGION, "TIMERREGION", 0, "Timer Region", "TmrReg"},
- {0, "", 0, NULL, NULL},
+ RNA_ENUM_ITEM_SEPR,
{NDOF_MOTION, "NDOF_MOTION", 0, "NDOF Motion", "NdofMov"},
/* buttons on all 3dconnexion devices */
{NDOF_BUTTON_MENU, "NDOF_BUTTON_MENU", 0, "NDOF Menu", "NdofMenu"},
@@ -898,7 +916,7 @@ static void rna_wmKeyMapItem_map_type_set(PointerRNA *ptr, int value)
/**
* Assumes value to be an enum from rna_enum_event_type_items.
- * Function makes sure keymodifiers are only valid keys, ESC keeps it unaltered.
+ * Function makes sure key-modifiers are only valid keys, ESC keeps it unaltered.
*/
static void rna_wmKeyMapItem_keymodifier_set(PointerRNA *ptr, int value)
{
@@ -1157,9 +1175,7 @@ static int rna_wmKeyMapItem_idname_length(PointerRNA *ptr)
{
wmKeyMapItem *kmi = ptr->data;
char pyname[OP_MAX_TYPENAME];
-
- WM_operator_py_idname(pyname, kmi->idname);
- return strlen(pyname);
+ return WM_operator_py_idname(pyname, kmi->idname);
}
static void rna_wmKeyMapItem_idname_set(PointerRNA *ptr, const char *value)
@@ -2601,6 +2617,9 @@ static void rna_def_keyconfig(BlenderRNA *brna)
"rna_wmKeyMapItem_idname_get",
"rna_wmKeyMapItem_idname_length",
"rna_wmKeyMapItem_idname_set");
+ RNA_def_property_string_search_func(prop,
+ "WM_operatortype_idname_visit_for_search",
+ PROP_STRING_SEARCH_SORT | PROP_STRING_SEARCH_SUGGESTION);
RNA_def_struct_name_property(srna, prop);
RNA_def_property_update(prop, 0, "rna_KeyMapItem_update");
diff --git a/source/blender/makesrna/intern/rna_wm_api.c b/source/blender/makesrna/intern/rna_wm_api.c
index 5da65510399..b9f36d35ee8 100644
--- a/source/blender/makesrna/intern/rna_wm_api.c
+++ b/source/blender/makesrna/intern/rna_wm_api.c
@@ -23,6 +23,7 @@
#include "wm_cursors.h"
#include "wm_event_types.h"
+#include "WM_api.h"
#include "WM_types.h"
#include "rna_internal.h" /* own include */
diff --git a/source/blender/makesrna/intern/rna_xr.c b/source/blender/makesrna/intern/rna_xr.c
index a04b29b8815..dcfa1bbca51 100644
--- a/source/blender/makesrna/intern/rna_xr.c
+++ b/source/blender/makesrna/intern/rna_xr.c
@@ -849,7 +849,7 @@ bool rna_XrSessionState_active_action_set_set(bContext *C, const char *action_se
{
# ifdef WITH_XR_OPENXR
wmWindowManager *wm = CTX_wm_manager(C);
- return WM_xr_active_action_set_set(&wm->xr, action_set_name);
+ return WM_xr_active_action_set_set(&wm->xr, action_set_name, true);
# else
UNUSED_VARS(C, action_set_name);
return false;
@@ -1196,6 +1196,50 @@ static int rna_XrEventData_action_length(PointerRNA *ptr)
# endif
}
+static void rna_XrEventData_user_path_get(PointerRNA *ptr, char *r_value)
+{
+# ifdef WITH_XR_OPENXR
+ const wmXrActionData *data = ptr->data;
+ strcpy(r_value, data->user_path);
+# else
+ UNUSED_VARS(ptr);
+ r_value[0] = '\0';
+# endif
+}
+
+static int rna_XrEventData_user_path_length(PointerRNA *ptr)
+{
+# ifdef WITH_XR_OPENXR
+ const wmXrActionData *data = ptr->data;
+ return strlen(data->user_path);
+# else
+ UNUSED_VARS(ptr);
+ return 0;
+# endif
+}
+
+static void rna_XrEventData_user_path_other_get(PointerRNA *ptr, char *r_value)
+{
+# ifdef WITH_XR_OPENXR
+ const wmXrActionData *data = ptr->data;
+ strcpy(r_value, data->user_path_other);
+# else
+ UNUSED_VARS(ptr);
+ r_value[0] = '\0';
+# endif
+}
+
+static int rna_XrEventData_user_path_other_length(PointerRNA *ptr)
+{
+# ifdef WITH_XR_OPENXR
+ const wmXrActionData *data = ptr->data;
+ return strlen(data->user_path_other);
+# else
+ UNUSED_VARS(ptr);
+ return 0;
+# endif
+}
+
static int rna_XrEventData_type_get(PointerRNA *ptr)
{
# ifdef WITH_XR_OPENXR
@@ -2402,6 +2446,19 @@ static void rna_def_xr_eventdata(BlenderRNA *brna)
prop, "rna_XrEventData_action_get", "rna_XrEventData_action_length", NULL);
RNA_def_property_ui_text(prop, "Action", "XR action name");
+ prop = RNA_def_property(srna, "user_path", PROP_STRING, PROP_NONE);
+ RNA_def_property_clear_flag(prop, PROP_EDITABLE);
+ RNA_def_property_string_funcs(
+ prop, "rna_XrEventData_user_path_get", "rna_XrEventData_user_path_length", NULL);
+ RNA_def_property_ui_text(prop, "User Path", "User path of the action. E.g. \"/user/hand/left\"");
+
+ prop = RNA_def_property(srna, "user_path_other", PROP_STRING, PROP_NONE);
+ RNA_def_property_clear_flag(prop, PROP_EDITABLE);
+ RNA_def_property_string_funcs(
+ prop, "rna_XrEventData_user_path_other_get", "rna_XrEventData_user_path_other_length", NULL);
+ RNA_def_property_ui_text(
+ prop, "User Path Other", "Other user path, for bimanual actions. E.g. \"/user/hand/right\"");
+
prop = RNA_def_property(srna, "type", PROP_ENUM, PROP_NONE);
RNA_def_property_clear_flag(prop, PROP_EDITABLE);
RNA_def_property_enum_items(prop, rna_enum_xr_action_types);
diff --git a/source/blender/modifiers/CMakeLists.txt b/source/blender/modifiers/CMakeLists.txt
index a5e5bf36dcd..1aac3c2191d 100644
--- a/source/blender/modifiers/CMakeLists.txt
+++ b/source/blender/modifiers/CMakeLists.txt
@@ -70,7 +70,7 @@ set(SRC
intern/MOD_normal_edit.c
intern/MOD_ocean.c
intern/MOD_particleinstance.c
- intern/MOD_particlesystem.c
+ intern/MOD_particlesystem.cc
intern/MOD_remesh.c
intern/MOD_screw.c
intern/MOD_shapekey.c
diff --git a/source/blender/modifiers/intern/MOD_array.c b/source/blender/modifiers/intern/MOD_array.c
index c44a4e0b438..77915702ee4 100644
--- a/source/blender/modifiers/intern/MOD_array.c
+++ b/source/blender/modifiers/intern/MOD_array.c
@@ -328,7 +328,7 @@ static void mesh_merge_transform(Mesh *result,
ml->e += cap_edges_index;
}
- /* set origindex */
+ /* Set #CD_ORIGINDEX. */
index_orig = CustomData_get_layer(&result->vdata, CD_ORIGINDEX);
if (index_orig) {
copy_vn_i(index_orig + cap_verts_index, cap_nverts, ORIGINDEX_NONE);
@@ -464,7 +464,7 @@ static Mesh *arrayModifier_doArray(ArrayModifierData *amd,
copy_m4_m4(offset, result_mat);
}
- /* Check if there is some scaling. If scaling, then we will not translate mapping */
+ /* Check if there is some scaling. If scaling, then we will not translate mapping */
mat4_to_size(scale, offset);
offset_has_scale = !is_one_v3(scale);
diff --git a/source/blender/modifiers/intern/MOD_bevel.c b/source/blender/modifiers/intern/MOD_bevel.c
index a7364af10a3..c634873cfe4 100644
--- a/source/blender/modifiers/intern/MOD_bevel.c
+++ b/source/blender/modifiers/intern/MOD_bevel.c
@@ -39,7 +39,6 @@
#include "BLO_read_write.h"
-#include "BKE_curveprofile.h"
#include "bmesh.h"
#include "bmesh_tools.h"
@@ -396,10 +395,12 @@ static void panelRegister(ARegionType *region_type)
region_type, "shading", "Shading", NULL, shading_panel_draw, panel_type);
}
-static void blendWrite(BlendWriter *writer, const ModifierData *md)
+static void blendWrite(BlendWriter *writer, const ID *UNUSED(id_owner), const ModifierData *md)
{
const BevelModifierData *bmd = (const BevelModifierData *)md;
+ BLO_write_struct(writer, BevelModifierData, bmd);
+
if (bmd->custom_profile) {
BKE_curveprofile_blend_write(writer, bmd->custom_profile);
}
diff --git a/source/blender/modifiers/intern/MOD_boolean.cc b/source/blender/modifiers/intern/MOD_boolean.cc
index d47f2a130e3..5739de1c65c 100644
--- a/source/blender/modifiers/intern/MOD_boolean.cc
+++ b/source/blender/modifiers/intern/MOD_boolean.cc
@@ -223,7 +223,7 @@ static BMesh *BMD_mesh_bm_create(
Mesh *mesh, Object *object, Mesh *mesh_operand_ob, Object *operand_ob, bool *r_is_flip)
{
#ifdef DEBUG_TIME
- SCOPED_TIMER(__func__)
+ SCOPED_TIMER(__func__);
#endif
*r_is_flip = (is_negative_m4(object->obmat) != is_negative_m4(operand_ob->obmat));
@@ -270,7 +270,7 @@ static void BMD_mesh_intersection(BMesh *bm,
bool is_flip)
{
#ifdef DEBUG_TIME
- SCOPED_TIMER(__func__)
+ SCOPED_TIMER(__func__);
#endif
BooleanModifierData *bmd = (BooleanModifierData *)md;
@@ -399,7 +399,7 @@ static Mesh *exact_boolean_mesh(BooleanModifierData *bmd,
Vector<Array<short>> material_remaps;
# ifdef DEBUG_TIME
- SCOPED_TIMER(__func__)
+ SCOPED_TIMER(__func__);
# endif
if ((bmd->flag & eBooleanModifierFlag_Object) && bmd->object == nullptr) {
@@ -447,7 +447,8 @@ static Mesh *exact_boolean_mesh(BooleanModifierData *bmd,
material_remaps,
use_self,
hole_tolerant,
- bmd->operation);
+ bmd->operation,
+ nullptr);
}
#endif
@@ -470,7 +471,7 @@ static Mesh *modifyMesh(ModifierData *md, const ModifierEvalContext *ctx, Mesh *
#endif
#ifdef DEBUG_TIME
- SCOPED_TIMER(__func__)
+ SCOPED_TIMER(__func__);
#endif
if (bmd->flag & eBooleanModifierFlag_Object) {
@@ -518,24 +519,29 @@ static Mesh *modifyMesh(ModifierData *md, const ModifierEvalContext *ctx, Mesh *
Mesh *mesh_operand_ob = BKE_modifier_get_evaluated_mesh_from_evaluated_object(operand_ob,
false);
- if (mesh_operand_ob) {
- /* XXX This is utterly non-optimal, we may go from a bmesh to a mesh back to a bmesh!
- * But for 2.90 better not try to be smart here. */
- BKE_mesh_wrapper_ensure_mdata(mesh_operand_ob);
+ if (mesh_operand_ob == nullptr) {
+ continue;
+ }
- bool is_flip;
- BMesh *bm = BMD_mesh_bm_create(mesh, object, mesh_operand_ob, operand_ob, &is_flip);
+ /* XXX This is utterly non-optimal, we may go from a bmesh to a mesh back to a bmesh!
+ * But for 2.90 better not try to be smart here. */
+ BKE_mesh_wrapper_ensure_mdata(mesh_operand_ob);
- BMD_mesh_intersection(bm, md, ctx, mesh_operand_ob, object, operand_ob, is_flip);
+ bool is_flip;
+ BMesh *bm = BMD_mesh_bm_create(result, object, mesh_operand_ob, operand_ob, &is_flip);
- /* Needed for multiple objects to work. */
- BMeshToMeshParams bmesh_to_mesh_params{};
- bmesh_to_mesh_params.calc_object_remap = false;
- BM_mesh_bm_to_me(nullptr, bm, mesh, &bmesh_to_mesh_params);
+ BMD_mesh_intersection(bm, md, ctx, mesh_operand_ob, object, operand_ob, is_flip);
+ /* Needed for multiple objects to work. */
+ if (result == mesh) {
result = BKE_mesh_from_bmesh_for_eval_nomain(bm, nullptr, mesh);
- BM_mesh_free(bm);
}
+ else {
+ BMeshToMeshParams bmesh_to_mesh_params{};
+ bmesh_to_mesh_params.calc_object_remap = false;
+ BM_mesh_bm_to_me(nullptr, bm, result, &bmesh_to_mesh_params);
+ }
+ BM_mesh_free(bm);
}
}
FOREACH_COLLECTION_OBJECT_RECURSIVE_END;
diff --git a/source/blender/modifiers/intern/MOD_correctivesmooth.c b/source/blender/modifiers/intern/MOD_correctivesmooth.c
index 52162eaacc5..3698f4403a1 100644
--- a/source/blender/modifiers/intern/MOD_correctivesmooth.c
+++ b/source/blender/modifiers/intern/MOD_correctivesmooth.c
@@ -798,12 +798,26 @@ static void panelRegister(ARegionType *region_type)
modifier_panel_register(region_type, eModifierType_CorrectiveSmooth, panel_draw);
}
-static void blendWrite(BlendWriter *writer, const ModifierData *md)
+static void blendWrite(BlendWriter *writer, const ID *id_owner, const ModifierData *md)
{
- const CorrectiveSmoothModifierData *csmd = (const CorrectiveSmoothModifierData *)md;
+ CorrectiveSmoothModifierData csmd = *(const CorrectiveSmoothModifierData *)md;
+ const bool is_undo = BLO_write_is_undo(writer);
+
+ if (ID_IS_OVERRIDE_LIBRARY(id_owner) && !is_undo) {
+ BLI_assert(!ID_IS_LINKED(id_owner));
+ const bool is_local = (md->flag & eModifierFlag_OverrideLibrary_Local) != 0;
+ if (!is_local) {
+ /* Modifier coming from linked data cannot be bound from an override, so we can remove all
+ * binding data, can save a significant amount of memory. */
+ csmd.bind_coords_num = 0;
+ csmd.bind_coords = NULL;
+ }
+ }
- if (csmd->bind_coords) {
- BLO_write_float3_array(writer, csmd->bind_coords_num, (float *)csmd->bind_coords);
+ BLO_write_struct_at_address(writer, CorrectiveSmoothModifierData, md, &csmd);
+
+ if (csmd.bind_coords != NULL) {
+ BLO_write_float3_array(writer, csmd.bind_coords_num, (float *)csmd.bind_coords);
}
}
diff --git a/source/blender/modifiers/intern/MOD_displace.c b/source/blender/modifiers/intern/MOD_displace.c
index 7ad7d6eef3d..1e2224e3a65 100644
--- a/source/blender/modifiers/intern/MOD_displace.c
+++ b/source/blender/modifiers/intern/MOD_displace.c
@@ -197,7 +197,6 @@ static void displaceModifier_do_task(void *__restrict userdata,
}
if (data->tex_target) {
- texres.nor = NULL;
BKE_texture_get_value_ex(
data->scene, data->tex_target, tex_co[iter], &texres, data->pool, false);
delta = texres.tin - dmd->midlevel;
@@ -310,13 +309,11 @@ static void displaceModifier_do(DisplaceModifierData *dmd,
CustomData *ldata = &mesh->ldata;
if (CustomData_has_layer(ldata, CD_CUSTOMLOOPNORMAL)) {
- float(*clnors)[3] = NULL;
-
if (!CustomData_has_layer(ldata, CD_NORMAL)) {
BKE_mesh_calc_normals_split(mesh);
}
- clnors = CustomData_get_layer(ldata, CD_NORMAL);
+ float(*clnors)[3] = CustomData_get_layer(ldata, CD_NORMAL);
vert_clnors = MEM_malloc_arrayN(verts_num, sizeof(*vert_clnors), __func__);
BKE_mesh_normals_loop_to_vertex(
verts_num, mesh->mloop, mesh->totloop, (const float(*)[3])clnors, vert_clnors);
diff --git a/source/blender/modifiers/intern/MOD_dynamicpaint.c b/source/blender/modifiers/intern/MOD_dynamicpaint.c
index 1891ac5df7c..6b0578c77f1 100644
--- a/source/blender/modifiers/intern/MOD_dynamicpaint.c
+++ b/source/blender/modifiers/intern/MOD_dynamicpaint.c
@@ -83,17 +83,17 @@ static void requiredDataMask(Object *UNUSED(ob),
if (pmd->canvas) {
DynamicPaintSurface *surface = pmd->canvas->surfaces.first;
for (; surface; surface = surface->next) {
- /* tface */
+ /* UV's: #CD_MLOOPUV. */
if (surface->format == MOD_DPAINT_SURFACE_F_IMAGESEQ ||
surface->init_color_type == MOD_DPAINT_INITIAL_TEXTURE) {
r_cddata_masks->lmask |= CD_MASK_MLOOPUV;
}
- /* mcol */
+ /* Vertex Colors: #CD_PROP_BYTE_COLOR. */
if (surface->type == MOD_DPAINT_SURFACE_T_PAINT ||
surface->init_color_type == MOD_DPAINT_INITIAL_VERTEXCOLOR) {
r_cddata_masks->lmask |= CD_MASK_PROP_BYTE_COLOR;
}
- /* CD_MDEFORMVERT */
+ /* Vertex Weights: #CD_MDEFORMVERT. */
if (surface->type == MOD_DPAINT_SURFACE_T_WEIGHT) {
r_cddata_masks->vmask |= CD_MASK_MDEFORMVERT;
}
diff --git a/source/blender/modifiers/intern/MOD_explode.c b/source/blender/modifiers/intern/MOD_explode.c
index 9e2bb79138e..8e85cb1bfb3 100644
--- a/source/blender/modifiers/intern/MOD_explode.c
+++ b/source/blender/modifiers/intern/MOD_explode.c
@@ -124,7 +124,7 @@ static void createFacepa(ExplodeModifierData *emd, ParticleSystemModifierData *p
/* set protected verts */
if (emd->vgroup) {
- MDeformVert *dvert = CustomData_get_layer(&mesh->vdata, CD_MDEFORMVERT);
+ const MDeformVert *dvert = CustomData_get_layer(&mesh->vdata, CD_MDEFORMVERT);
if (dvert) {
const int defgrp_index = emd->vgroup - 1;
for (i = 0; i < totvert; i++, dvert++) {
@@ -897,7 +897,7 @@ static Mesh *explodeMesh(ExplodeModifierData *emd,
{
Mesh *explode, *mesh = to_explode;
MFace *mf = NULL, *mface;
- /* ParticleSettings *part=psmd->psys->part; */ /* UNUSED */
+ // ParticleSettings *part=psmd->psys->part; /* UNUSED */
ParticleSimulationData sim = {NULL};
ParticleData *pa = NULL, *pars = psmd->psys->particles;
ParticleKey state, birth;
@@ -906,12 +906,11 @@ static Mesh *explodeMesh(ExplodeModifierData *emd,
float *vertco = NULL, imat[4][4];
float rot[4];
float ctime;
- /* float timestep; */
+ // float timestep;
const int *facepa = emd->facepa;
int totdup = 0, totvert = 0, totface = 0, totpart = 0, delface = 0;
int i, v, u;
uint ed_v1, ed_v2, mindex = 0;
- MTFace *mtface = NULL, *mtf;
totface = mesh->totface;
totvert = mesh->totvert;
@@ -924,7 +923,7 @@ static Mesh *explodeMesh(ExplodeModifierData *emd,
sim.psys = psmd->psys;
sim.psmd = psmd;
- /* timestep = psys_get_timestep(&sim); */
+ // timestep = psys_get_timestep(&sim);
ctime = BKE_scene_ctime_get(scene);
@@ -977,7 +976,7 @@ static Mesh *explodeMesh(ExplodeModifierData *emd,
/* the final duplicated vertices */
explode = BKE_mesh_new_nomain_from_template(mesh, totdup, 0, totface - delface, 0, 0);
- mtface = CustomData_get_layer_named(&explode->fdata, CD_MTFACE, emd->uvname);
+ MTFace *mtface = CustomData_get_layer_named(&explode->fdata, CD_MTFACE, emd->uvname);
/* getting back to object space */
invert_m4_m4(imat, ctx->object->obmat);
@@ -1086,7 +1085,7 @@ static Mesh *explodeMesh(ExplodeModifierData *emd,
/* Clamp to this range to avoid flipping to the other side of the coordinates. */
CLAMP(age, 0.001f, 0.999f);
- mtf = mtface + u;
+ MTFace *mtf = mtface + u;
mtf->uv[0][0] = mtf->uv[1][0] = mtf->uv[2][0] = mtf->uv[3][0] = age;
mtf->uv[0][1] = mtf->uv[1][1] = mtf->uv[2][1] = mtf->uv[3][1] = 0.5f;
diff --git a/source/blender/modifiers/intern/MOD_hook.c b/source/blender/modifiers/intern/MOD_hook.c
index 1000bbf45d6..3649ece12e1 100644
--- a/source/blender/modifiers/intern/MOD_hook.c
+++ b/source/blender/modifiers/intern/MOD_hook.c
@@ -519,10 +519,12 @@ static void panelRegister(ARegionType *region_type)
region_type, "falloff", "Falloff", NULL, falloff_panel_draw, panel_type);
}
-static void blendWrite(BlendWriter *writer, const ModifierData *md)
+static void blendWrite(BlendWriter *writer, const ID *UNUSED(id_owner), const ModifierData *md)
{
const HookModifierData *hmd = (const HookModifierData *)md;
+ BLO_write_struct(writer, HookModifierData, hmd);
+
if (hmd->curfalloff) {
BKE_curvemapping_blend_write(writer, hmd->curfalloff);
}
diff --git a/source/blender/modifiers/intern/MOD_laplaciandeform.c b/source/blender/modifiers/intern/MOD_laplaciandeform.c
index 239cb7f5a5a..a22f4b35e0d 100644
--- a/source/blender/modifiers/intern/MOD_laplaciandeform.c
+++ b/source/blender/modifiers/intern/MOD_laplaciandeform.c
@@ -843,11 +843,27 @@ static void panelRegister(ARegionType *region_type)
modifier_panel_register(region_type, eModifierType_LaplacianDeform, panel_draw);
}
-static void blendWrite(BlendWriter *writer, const ModifierData *md)
+static void blendWrite(BlendWriter *writer, const ID *id_owner, const ModifierData *md)
{
- LaplacianDeformModifierData *lmd = (LaplacianDeformModifierData *)md;
+ LaplacianDeformModifierData lmd = *(const LaplacianDeformModifierData *)md;
+ const bool is_undo = BLO_write_is_undo(writer);
+
+ if (ID_IS_OVERRIDE_LIBRARY(id_owner) && !is_undo) {
+ BLI_assert(!ID_IS_LINKED(id_owner));
+ const bool is_local = (md->flag & eModifierFlag_OverrideLibrary_Local) != 0;
+ if (!is_local) {
+ /* Modifier coming from linked data cannot be bound from an override, so we can remove all
+ * binding data, can save a significant amount of memory. */
+ lmd.verts_num = 0;
+ lmd.vertexco = NULL;
+ }
+ }
- BLO_write_float3_array(writer, lmd->verts_num, lmd->vertexco);
+ BLO_write_struct_at_address(writer, LaplacianDeformModifierData, md, &lmd);
+
+ if (lmd.vertexco != NULL) {
+ BLO_write_float3_array(writer, lmd.verts_num, lmd.vertexco);
+ }
}
static void blendRead(BlendDataReader *reader, ModifierData *md)
diff --git a/source/blender/modifiers/intern/MOD_mask.cc b/source/blender/modifiers/intern/MOD_mask.cc
index 900dee98268..0813901fc49 100644
--- a/source/blender/modifiers/intern/MOD_mask.cc
+++ b/source/blender/modifiers/intern/MOD_mask.cc
@@ -91,7 +91,7 @@ static void updateDepsgraph(ModifierData *md, const ModifierUpdateDepsgraphConte
}
/* A vertex will be in the mask if a selected bone influences it more than a certain threshold. */
-static void compute_vertex_mask__armature_mode(MDeformVert *dvert,
+static void compute_vertex_mask__armature_mode(const MDeformVert *dvert,
Mesh *mesh,
Object *armature_ob,
float threshold,
@@ -125,7 +125,7 @@ static void compute_vertex_mask__armature_mode(MDeformVert *dvert,
}
/* A vertex will be in the mask if the vertex group influences it more than a certain threshold. */
-static void compute_vertex_mask__vertex_group_mode(MDeformVert *dvert,
+static void compute_vertex_mask__vertex_group_mode(const MDeformVert *dvert,
int defgrp_index,
float threshold,
MutableSpan<bool> r_vertex_mask)
@@ -347,7 +347,7 @@ static void copy_masked_vertices_to_new_mesh(const Mesh &src_mesh,
}
static float get_interp_factor_from_vgroup(
- MDeformVert *dvert, int defgrp_index, float threshold, uint v1, uint v2)
+ const MDeformVert *dvert, int defgrp_index, float threshold, uint v1, uint v2)
{
/* NOTE: this calculation is done twice for every vertex,
* instead of storing it the first time and then reusing it. */
@@ -360,7 +360,7 @@ static void add_interp_verts_copy_edges_to_new_mesh(const Mesh &src_mesh,
Mesh &dst_mesh,
Span<bool> vertex_mask,
Span<int> vertex_map,
- MDeformVert *dvert,
+ const MDeformVert *dvert,
int defgrp_index,
float threshold,
uint edges_masked_num,
@@ -478,7 +478,7 @@ static void add_interpolated_polys_to_new_mesh(const Mesh &src_mesh,
Span<bool> vertex_mask,
Span<int> vertex_map,
Span<int> edge_map,
- MDeformVert *dvert,
+ const MDeformVert *dvert,
int defgrp_index,
float threshold,
Span<int> masked_poly_indices,
@@ -619,7 +619,8 @@ static Mesh *modifyMesh(ModifierData *md, const ModifierEvalContext *UNUSED(ctx)
(mmd->flag & MOD_MASK_SMOOTH);
/* Return empty or input mesh when there are no vertex groups. */
- MDeformVert *dvert = (MDeformVert *)CustomData_get_layer(&mesh->vdata, CD_MDEFORMVERT);
+ const MDeformVert *dvert = (const MDeformVert *)CustomData_get_layer(&mesh->vdata,
+ CD_MDEFORMVERT);
if (dvert == nullptr) {
return invert_mask ? mesh : BKE_mesh_new_nomain_from_template(mesh, 0, 0, 0, 0, 0);
}
diff --git a/source/blender/modifiers/intern/MOD_meshdeform.c b/source/blender/modifiers/intern/MOD_meshdeform.c
index 09e6819a2ae..5dac31ac1df 100644
--- a/source/blender/modifiers/intern/MOD_meshdeform.c
+++ b/source/blender/modifiers/intern/MOD_meshdeform.c
@@ -581,17 +581,50 @@ static void panelRegister(ARegionType *region_type)
modifier_panel_register(region_type, eModifierType_MeshDeform, panel_draw);
}
-static void blendWrite(BlendWriter *writer, const ModifierData *md)
+static void blendWrite(BlendWriter *writer, const ID *id_owner, const ModifierData *md)
{
- MeshDeformModifierData *mmd = (MeshDeformModifierData *)md;
- int size = mmd->dyngridsize;
-
- BLO_write_struct_array(writer, MDefInfluence, mmd->influences_num, mmd->bindinfluences);
- BLO_write_int32_array(writer, mmd->verts_num + 1, mmd->bindoffsets);
- BLO_write_float3_array(writer, mmd->cage_verts_num, mmd->bindcagecos);
- BLO_write_struct_array(writer, MDefCell, size * size * size, mmd->dyngrid);
- BLO_write_struct_array(writer, MDefInfluence, mmd->influences_num, mmd->dyninfluences);
- BLO_write_int32_array(writer, mmd->verts_num, mmd->dynverts);
+ MeshDeformModifierData mmd = *(const MeshDeformModifierData *)md;
+ const bool is_undo = BLO_write_is_undo(writer);
+
+ if (ID_IS_OVERRIDE_LIBRARY(id_owner) && !is_undo) {
+ BLI_assert(!ID_IS_LINKED(id_owner));
+ const bool is_local = (md->flag & eModifierFlag_OverrideLibrary_Local) != 0;
+ if (!is_local) {
+ /* Modifier coming from linked data cannot be bound from an override, so we can remove all
+ * binding data, can save a significant amount of memory. */
+ mmd.influences_num = 0;
+ mmd.bindinfluences = NULL;
+ mmd.verts_num = 0;
+ mmd.bindoffsets = NULL;
+ mmd.cage_verts_num = 0;
+ mmd.bindcagecos = NULL;
+ mmd.dyngridsize = 0;
+ mmd.dyngrid = NULL;
+ mmd.influences_num = 0;
+ mmd.dyninfluences = NULL;
+ mmd.dynverts = NULL;
+ }
+ }
+
+ const int size = mmd.dyngridsize;
+
+ BLO_write_struct_at_address(writer, MeshDeformModifierData, md, &mmd);
+
+ BLO_write_struct_array(writer, MDefInfluence, mmd.influences_num, mmd.bindinfluences);
+
+ /* NOTE: `bindoffset` is abusing `verts_num + 1` as its size, this becomes an incorrect value in
+ * case `verts_num == 0`, since `bindoffset` is then NULL, not a size 1 allocated array. */
+ if (mmd.verts_num > 0) {
+ BLO_write_int32_array(writer, mmd.verts_num + 1, mmd.bindoffsets);
+ }
+ else {
+ BLI_assert(mmd.bindoffsets == NULL);
+ }
+
+ BLO_write_float3_array(writer, mmd.cage_verts_num, mmd.bindcagecos);
+ BLO_write_struct_array(writer, MDefCell, size * size * size, mmd.dyngrid);
+ BLO_write_struct_array(writer, MDefInfluence, mmd.influences_num, mmd.dyninfluences);
+ BLO_write_int32_array(writer, mmd.verts_num, mmd.dynverts);
}
static void blendRead(BlendDataReader *reader, ModifierData *md)
@@ -599,7 +632,13 @@ static void blendRead(BlendDataReader *reader, ModifierData *md)
MeshDeformModifierData *mmd = (MeshDeformModifierData *)md;
BLO_read_data_address(reader, &mmd->bindinfluences);
- BLO_read_int32_array(reader, mmd->verts_num + 1, &mmd->bindoffsets);
+
+ /* NOTE: `bindoffset` is abusing `verts_num + 1` as its size, this becomes an incorrect value in
+ * case `verts_num == 0`, since `bindoffset` is then NULL, not a size 1 allocated array. */
+ if (mmd->verts_num > 0) {
+ BLO_read_int32_array(reader, mmd->verts_num + 1, &mmd->bindoffsets);
+ }
+
BLO_read_float3_array(reader, mmd->cage_verts_num, &mmd->bindcagecos);
BLO_read_data_address(reader, &mmd->dyngrid);
BLO_read_data_address(reader, &mmd->dyninfluences);
diff --git a/source/blender/modifiers/intern/MOD_meshsequencecache.cc b/source/blender/modifiers/intern/MOD_meshsequencecache.cc
index 998fb0a94a3..273050eafd8 100644
--- a/source/blender/modifiers/intern/MOD_meshsequencecache.cc
+++ b/source/blender/modifiers/intern/MOD_meshsequencecache.cc
@@ -5,8 +5,9 @@
*/
#include <cstring>
+#include <limits>
-#include "BLI_math_vector.h"
+#include "BLI_math_vector.hh"
#include "BLI_string.h"
#include "BLI_utildefines.h"
@@ -15,7 +16,6 @@
#include "DNA_cachefile_types.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_scene_types.h"
@@ -42,6 +42,8 @@
#include "DEG_depsgraph_build.h"
#include "DEG_depsgraph_query.h"
+#include "GEO_mesh_primitive_cuboid.hh"
+
#include "MOD_modifiertypes.h"
#include "MOD_ui_common.h"
@@ -104,40 +106,17 @@ static bool isDisabled(const struct Scene *UNUSED(scene),
return (mcmd->cache_file == nullptr) || (mcmd->object_path[0] == '\0');
}
-static Mesh *generate_bounding_box_mesh(Object *object, Mesh *org_mesh)
+static Mesh *generate_bounding_box_mesh(const Mesh *org_mesh)
{
- const BoundBox *bb = BKE_object_boundbox_get(object);
- Mesh *result = BKE_mesh_new_nomain_from_template(org_mesh, 8, 0, 0, 24, 6);
-
- MVert *mvert = result->mvert;
- for (int i = 0; i < 8; ++i) {
- copy_v3_v3(mvert[i].co, bb->vec[i]);
- }
-
- /* See DNA_object_types.h for the diagram showing the order of the vertices for a BoundBox. */
- static unsigned int loops_v[6][4] = {
- {0, 4, 5, 1},
- {4, 7, 6, 5},
- {7, 3, 2, 6},
- {3, 0, 1, 2},
- {1, 5, 6, 2},
- {3, 7, 4, 0},
- };
-
- MLoop *mloop = result->mloop;
- for (int i = 0; i < 6; ++i) {
- for (int j = 0; j < 4; ++j, ++mloop) {
- mloop->v = loops_v[i][j];
- }
- }
-
- MPoly *mpoly = result->mpoly;
- for (int i = 0; i < 6; ++i) {
- mpoly[i].loopstart = i * 4;
- mpoly[i].totloop = 4;
+ using namespace blender;
+ float3 min(std::numeric_limits<float>::max());
+ float3 max(-std::numeric_limits<float>::max());
+ if (!BKE_mesh_minmax(org_mesh, min, max)) {
+ return nullptr;
}
- BKE_mesh_calc_edges(result, false, false);
+ Mesh *result = geometry::create_cuboid_mesh(max - min, 2, 2, 2);
+ BKE_mesh_translate(result, math::midpoint(min, max), false);
return result;
}
@@ -170,7 +149,7 @@ static Mesh *modifyMesh(ModifierData *md, const ModifierEvalContext *ctx, Mesh *
/* Do not process data if using a render procedural, return a box instead for displaying in the
* viewport. */
if (BKE_cache_file_uses_render_procedural(cache_file, scene)) {
- return generate_bounding_box_mesh(ctx->object, org_mesh);
+ return generate_bounding_box_mesh(org_mesh);
}
/* If this invocation is for the ORCO mesh, and the mesh hasn't changed topology, we
diff --git a/source/blender/modifiers/intern/MOD_nodes.cc b/source/blender/modifiers/intern/MOD_nodes.cc
index 21041e8e1b2..73db56186de 100644
--- a/source/blender/modifiers/intern/MOD_nodes.cc
+++ b/source/blender/modifiers/intern/MOD_nodes.cc
@@ -45,6 +45,7 @@
#include "BKE_main.h"
#include "BKE_mesh.h"
#include "BKE_modifier.h"
+#include "BKE_node_runtime.hh"
#include "BKE_node_tree_update.h"
#include "BKE_object.h"
#include "BKE_pointcloud.h"
@@ -118,8 +119,8 @@ using blender::nodes::InputSocketFieldType;
using blender::threading::EnumerableThreadSpecific;
using namespace blender::fn::multi_function_types;
using namespace blender::nodes::derived_node_tree_types;
+using geo_log::eNamedAttrUsage;
using geo_log::GeometryAttributeInfo;
-using geo_log::NamedAttributeUsage;
static void initData(ModifierData *md)
{
@@ -396,8 +397,9 @@ static bool socket_type_has_attribute_toggle(const bNodeSocket &socket)
*/
static bool input_has_attribute_toggle(const bNodeTree &node_tree, const int socket_index)
{
- BLI_assert(node_tree.field_inferencing_interface != nullptr);
- const FieldInferencingInterface &field_interface = *node_tree.field_inferencing_interface;
+ BLI_assert(node_tree.runtime->field_inferencing_interface);
+ const FieldInferencingInterface &field_interface =
+ *node_tree.runtime->field_inferencing_interface;
return field_interface.inputs[socket_index] != InputSocketFieldType::None;
}
@@ -753,6 +755,7 @@ static void initialize_group_input(NodesModifierData &nmd,
{
const bNodeSocketType &socket_type = *socket.typeinfo();
const bNodeSocket &bsocket = *socket.bsocket();
+ const eNodeSocketDatatype socket_data_type = static_cast<eNodeSocketDatatype>(bsocket.type);
if (nmd.settings.properties == nullptr) {
socket_type.get_geometry_nodes_cpp_value(bsocket, r_value);
return;
@@ -769,8 +772,7 @@ static void initialize_group_input(NodesModifierData &nmd,
}
if (!input_has_attribute_toggle(*nmd.node_group, socket.index())) {
- init_socket_cpp_value_from_property(
- *property, static_cast<eNodeSocketDatatype>(bsocket.type), r_value);
+ init_socket_cpp_value_from_property(*property, socket_data_type, r_value);
return;
}
@@ -779,14 +781,17 @@ static void initialize_group_input(NodesModifierData &nmd,
const IDProperty *property_attribute_name = IDP_GetPropertyFromGroup(
nmd.settings.properties, (socket.identifier() + attribute_name_suffix).c_str());
if (property_use_attribute == nullptr || property_attribute_name == nullptr) {
- init_socket_cpp_value_from_property(
- *property, static_cast<eNodeSocketDatatype>(bsocket.type), r_value);
+ init_socket_cpp_value_from_property(*property, socket_data_type, r_value);
return;
}
const bool use_attribute = IDP_Int(property_use_attribute) != 0;
if (use_attribute) {
const StringRef attribute_name{IDP_String(property_attribute_name)};
+ if (!blender::bke::allow_procedural_attribute_access(attribute_name)) {
+ init_socket_cpp_value_from_property(*property, socket_data_type, r_value);
+ return;
+ }
auto attribute_input = std::make_shared<blender::bke::AttributeFieldInput>(
attribute_name, *socket_type.base_cpp_type);
GField attribute_field{std::move(attribute_input), 0};
@@ -797,8 +802,7 @@ static void initialize_group_input(NodesModifierData &nmd,
cpp_type->construct_from_field(r_value, std::move(attribute_field));
}
else {
- init_socket_cpp_value_from_property(
- *property, static_cast<eNodeSocketDatatype>(bsocket.type), r_value);
+ init_socket_cpp_value_from_property(*property, socket_data_type, r_value);
}
}
@@ -917,7 +921,7 @@ struct OutputAttributeInfo {
struct OutputAttributeToStore {
GeometryComponentType component_type;
- AttributeDomain domain;
+ eAttrDomain domain;
StringRefNull name;
GMutableSpan data;
};
@@ -926,10 +930,10 @@ struct OutputAttributeToStore {
* The output attributes are organized based on their domain, because attributes on the same domain
* can be evaluated together.
*/
-static MultiValueMap<AttributeDomain, OutputAttributeInfo> find_output_attributes_to_store(
+static MultiValueMap<eAttrDomain, OutputAttributeInfo> find_output_attributes_to_store(
const NodesModifierData &nmd, const NodeRef &output_node, Span<GMutablePointer> output_values)
{
- MultiValueMap<AttributeDomain, OutputAttributeInfo> outputs_by_domain;
+ MultiValueMap<eAttrDomain, OutputAttributeInfo> outputs_by_domain;
for (const InputSocketRef *socket : output_node.inputs().drop_front(1).drop_back(1)) {
if (!socket_type_has_attribute_toggle(*socket->bsocket())) {
continue;
@@ -944,6 +948,9 @@ static MultiValueMap<AttributeDomain, OutputAttributeInfo> find_output_attribute
if (attribute_name.is_empty()) {
continue;
}
+ if (!blender::bke::allow_procedural_attribute_access(attribute_name)) {
+ continue;
+ }
const int index = socket->index();
const GPointer value = output_values[index];
@@ -953,7 +960,7 @@ static MultiValueMap<AttributeDomain, OutputAttributeInfo> find_output_attribute
const bNodeSocket *interface_socket = (const bNodeSocket *)BLI_findlink(
&nmd.node_group->outputs, socket->index());
- const AttributeDomain domain = (AttributeDomain)interface_socket->attribute_domain;
+ const eAttrDomain domain = (eAttrDomain)interface_socket->attribute_domain;
OutputAttributeInfo output_info;
output_info.field = std::move(field);
output_info.name = attribute_name;
@@ -968,7 +975,7 @@ static MultiValueMap<AttributeDomain, OutputAttributeInfo> find_output_attribute
*/
static Vector<OutputAttributeToStore> compute_attributes_to_store(
const GeometrySet &geometry,
- const MultiValueMap<AttributeDomain, OutputAttributeInfo> &outputs_by_domain)
+ const MultiValueMap<eAttrDomain, OutputAttributeInfo> &outputs_by_domain)
{
Vector<OutputAttributeToStore> attributes_to_store;
for (const GeometryComponentType component_type : {GEO_COMPONENT_TYPE_MESH,
@@ -980,22 +987,21 @@ static Vector<OutputAttributeToStore> compute_attributes_to_store(
}
const GeometryComponent &component = *geometry.get_component_for_read(component_type);
for (const auto item : outputs_by_domain.items()) {
- const AttributeDomain domain = item.key;
+ const eAttrDomain domain = item.key;
const Span<OutputAttributeInfo> outputs_info = item.value;
if (!component.attribute_domain_supported(domain)) {
continue;
}
- const int domain_size = component.attribute_domain_size(domain);
+ const int domain_num = component.attribute_domain_num(domain);
blender::bke::GeometryComponentFieldContext field_context{component, domain};
- blender::fn::FieldEvaluator field_evaluator{field_context, domain_size};
+ blender::fn::FieldEvaluator field_evaluator{field_context, domain_num};
for (const OutputAttributeInfo &output_info : outputs_info) {
const CPPType &type = output_info.field.cpp_type();
OutputAttributeToStore store{
component_type,
domain,
output_info.name,
- GMutableSpan{
- type, MEM_malloc_arrayN(domain_size, type.size(), __func__), domain_size}};
+ GMutableSpan{type, MEM_malloc_arrayN(domain_num, type.size(), __func__), domain_num}};
field_evaluator.add_with_destination(output_info.field, store.data);
attributes_to_store.append(store);
}
@@ -1010,7 +1016,8 @@ static void store_computed_output_attributes(
{
for (const OutputAttributeToStore &store : attributes_to_store) {
GeometryComponent &component = geometry.get_component_for_write(store.component_type);
- const CustomDataType data_type = blender::bke::cpp_type_to_custom_data_type(store.data.type());
+ const eCustomDataType data_type = blender::bke::cpp_type_to_custom_data_type(
+ store.data.type());
const std::optional<AttributeMetaData> meta_data = component.attribute_get_meta_data(
store.name);
@@ -1051,7 +1058,7 @@ static void store_output_attributes(GeometrySet &geometry,
{
/* All new attribute values have to be computed before the geometry is actually changed. This is
* necessary because some fields might depend on attributes that are overwritten. */
- MultiValueMap<AttributeDomain, OutputAttributeInfo> outputs_by_domain =
+ MultiValueMap<eAttrDomain, OutputAttributeInfo> outputs_by_domain =
find_output_attributes_to_store(nmd, output_node, output_values);
Vector<OutputAttributeToStore> attributes_to_store = compute_attributes_to_store(
geometry, outputs_by_domain);
@@ -1430,6 +1437,14 @@ static void add_attribute_search_button(const bContext &C,
nullptr,
attribute_search_exec_fn,
nullptr);
+
+ char *attribute_name = RNA_string_get_alloc(
+ md_ptr, rna_path_attribute_name.c_str(), nullptr, 0, nullptr);
+ const bool access_allowed = blender::bke::allow_procedural_attribute_access(attribute_name);
+ MEM_freeN(attribute_name);
+ if (!access_allowed) {
+ UI_but_flag_enable(but, UI_BUT_REDALERT);
+ }
}
static void add_attribute_search_or_value_buttons(const bContext &C,
@@ -1650,7 +1665,7 @@ static void internal_dependencies_panel_draw(const bContext *UNUSED(C), Panel *p
return;
}
const geo_log::ModifierLog &log = *static_cast<geo_log::ModifierLog *>(nmd->runtime_eval_log);
- Map<std::string, NamedAttributeUsage> usage_by_attribute;
+ Map<std::string, eNamedAttrUsage> usage_by_attribute;
log.foreach_node_log([&](const geo_log::NodeLog &node_log) {
for (const geo_log::UsedNamedAttribute &used_attribute : node_log.used_named_attributes()) {
usage_by_attribute.lookup_or_add_as(used_attribute.name,
@@ -1665,7 +1680,7 @@ static void internal_dependencies_panel_draw(const bContext *UNUSED(C), Panel *p
struct NameWithUsage {
StringRefNull name;
- NamedAttributeUsage usage;
+ eNamedAttrUsage usage;
};
Vector<NameWithUsage> sorted_used_attribute;
@@ -1680,20 +1695,20 @@ static void internal_dependencies_panel_draw(const bContext *UNUSED(C), Panel *p
for (const NameWithUsage &attribute : sorted_used_attribute) {
const StringRefNull attribute_name = attribute.name;
- const NamedAttributeUsage usage = attribute.usage;
+ const eNamedAttrUsage usage = attribute.usage;
/* #uiLayoutRowWithHeading doesn't seem to work in this case. */
uiLayout *split = uiLayoutSplit(layout, 0.4f, false);
std::stringstream ss;
Vector<std::string> usages;
- if ((usage & NamedAttributeUsage::Read) != NamedAttributeUsage::None) {
+ if ((usage & eNamedAttrUsage::Read) != eNamedAttrUsage::None) {
usages.append(TIP_("Read"));
}
- if ((usage & NamedAttributeUsage::Write) != NamedAttributeUsage::None) {
+ if ((usage & eNamedAttrUsage::Write) != eNamedAttrUsage::None) {
usages.append(TIP_("Write"));
}
- if ((usage & NamedAttributeUsage::Remove) != NamedAttributeUsage::None) {
+ if ((usage & eNamedAttrUsage::Remove) != eNamedAttrUsage::None) {
usages.append(TIP_("Remove"));
}
for (const int i : usages.index_range()) {
@@ -1730,9 +1745,12 @@ static void panelRegister(ARegionType *region_type)
panel_type);
}
-static void blendWrite(BlendWriter *writer, const ModifierData *md)
+static void blendWrite(BlendWriter *writer, const ID *UNUSED(id_owner), const ModifierData *md)
{
const NodesModifierData *nmd = reinterpret_cast<const NodesModifierData *>(md);
+
+ BLO_write_struct(writer, NodesModifierData, nmd);
+
if (nmd->settings.properties != nullptr) {
/* Note that the property settings are based on the socket type info
* and don't necessarily need to be written, but we can't just free them. */
@@ -1799,7 +1817,7 @@ ModifierTypeInfo modifierType_Nodes = {
eModifierTypeFlag_SupportsEditmode |
eModifierTypeFlag_EnableInEditmode |
eModifierTypeFlag_SupportsMapping),
- /* icon */ ICON_NODETREE,
+ /* icon */ ICON_GEOMETRY_NODES,
/* copyData */ copyData,
diff --git a/source/blender/modifiers/intern/MOD_normal_edit.c b/source/blender/modifiers/intern/MOD_normal_edit.c
index fe05f48a868..c215ac601a1 100644
--- a/source/blender/modifiers/intern/MOD_normal_edit.c
+++ b/source/blender/modifiers/intern/MOD_normal_edit.c
@@ -136,7 +136,7 @@ static void mix_normals(const float mix_factor,
if (dvert) {
facs = MEM_malloc_arrayN((size_t)loops_num, sizeof(*facs), __func__);
BKE_defvert_extract_vgroup_to_loopweights(
- dvert, defgrp_index, verts_num, mloop, loops_num, facs, use_invert_vgroup);
+ dvert, defgrp_index, verts_num, mloop, loops_num, use_invert_vgroup, facs);
}
for (i = loops_num, no_new = nos_new, no_old = nos_old, wfac = facs; i--;
@@ -532,14 +532,13 @@ static Mesh *normalEditModifier_do(NormalEditModifierData *enmd,
MDeformVert *dvert;
float(*loopnors)[3] = NULL;
- short(*clnors)[2] = NULL;
CustomData *ldata = &result->ldata;
const float(*vert_normals)[3] = BKE_mesh_vertex_normals_ensure(result);
const float(*poly_normals)[3] = BKE_mesh_poly_normals_ensure(result);
- clnors = CustomData_get_layer(ldata, CD_CUSTOMLOOPNORMAL);
+ short(*clnors)[2] = CustomData_get_layer(ldata, CD_CUSTOMLOOPNORMAL);
if (use_current_clnors) {
clnors = CustomData_duplicate_referenced_layer(ldata, CD_CUSTOMLOOPNORMAL, loops_num);
loopnors = MEM_malloc_arrayN((size_t)loops_num, sizeof(*loopnors), __func__);
diff --git a/source/blender/modifiers/intern/MOD_particlesystem.c b/source/blender/modifiers/intern/MOD_particlesystem.cc
index 032227307e7..f410915cad8 100644
--- a/source/blender/modifiers/intern/MOD_particlesystem.c
+++ b/source/blender/modifiers/intern/MOD_particlesystem.cc
@@ -5,8 +5,8 @@
* \ingroup modifiers
*/
-#include <stddef.h>
-#include <string.h>
+#include <cstddef>
+#include <cstring>
#include "BLI_utildefines.h"
@@ -51,11 +51,11 @@ static void freeData(ModifierData *md)
ParticleSystemModifierData *psmd = (ParticleSystemModifierData *)md;
if (psmd->mesh_final) {
- BKE_id_free(NULL, psmd->mesh_final);
- psmd->mesh_final = NULL;
+ BKE_id_free(nullptr, psmd->mesh_final);
+ psmd->mesh_final = nullptr;
if (psmd->mesh_original) {
- BKE_id_free(NULL, psmd->mesh_original);
- psmd->mesh_original = NULL;
+ BKE_id_free(nullptr, psmd->mesh_original);
+ psmd->mesh_original = nullptr;
}
}
psmd->totdmvert = psmd->totdmedge = psmd->totdmface = 0;
@@ -81,8 +81,8 @@ static void copyData(const ModifierData *md, ModifierData *target, const int fla
* code has to be called then to ensure proper remapping of that pointer. See e.g.
* `BKE_object_copy_particlesystems` or `BKE_object_copy_modifier`. */
- tpsmd->mesh_final = NULL;
- tpsmd->mesh_original = NULL;
+ tpsmd->mesh_final = nullptr;
+ tpsmd->mesh_original = nullptr;
tpsmd->totdmvert = tpsmd->totdmedge = tpsmd->totdmface = 0;
}
@@ -104,7 +104,7 @@ static void deformVerts(ModifierData *md,
{
Mesh *mesh_src = mesh;
ParticleSystemModifierData *psmd = (ParticleSystemModifierData *)md;
- ParticleSystem *psys = NULL;
+ ParticleSystem *psys = nullptr;
if (ctx->object->particlesystem.first) {
psys = psmd->psys;
@@ -117,28 +117,28 @@ static void deformVerts(ModifierData *md,
return;
}
- if (mesh_src == NULL) {
+ if (mesh_src == nullptr) {
mesh_src = MOD_deform_mesh_eval_get(
- ctx->object, NULL, NULL, vertexCos, verts_num, false, true);
- if (mesh_src == NULL) {
+ ctx->object, nullptr, nullptr, vertexCos, verts_num, false, true);
+ if (mesh_src == nullptr) {
return;
}
}
/* clear old dm */
- bool had_mesh_final = (psmd->mesh_final != NULL);
+ bool had_mesh_final = (psmd->mesh_final != nullptr);
if (psmd->mesh_final) {
- BKE_id_free(NULL, psmd->mesh_final);
- psmd->mesh_final = NULL;
+ BKE_id_free(nullptr, psmd->mesh_final);
+ psmd->mesh_final = nullptr;
if (psmd->mesh_original) {
- BKE_id_free(NULL, psmd->mesh_original);
- psmd->mesh_original = NULL;
+ BKE_id_free(nullptr, psmd->mesh_original);
+ psmd->mesh_original = nullptr;
}
}
else if (psmd->flag & eParticleSystemFlag_file_loaded) {
/* in file read mesh just wasn't saved in file so no need to reset everything */
psmd->flag &= ~eParticleSystemFlag_file_loaded;
- if (psys->particles == NULL) {
+ if (psys->particles == nullptr) {
psys->recalc |= ID_RECALC_PSYS_RESET;
}
/* TODO(sergey): This is not how particles were working prior to copy on
@@ -165,18 +165,18 @@ static void deformVerts(ModifierData *md,
/* Get the original mesh from the object, this is what the particles
* are attached to so in case of non-deform modifiers we need to remap
* them to the final mesh (typically subdivision surfaces). */
- Mesh *mesh_original = NULL;
+ Mesh *mesh_original = nullptr;
if (ctx->object->type == OB_MESH) {
BMEditMesh *em = BKE_editmesh_from_object(ctx->object);
if (em) {
/* In edit mode get directly from the edit mesh. */
- psmd->mesh_original = BKE_mesh_from_bmesh_for_eval_nomain(em->bm, NULL, mesh);
+ psmd->mesh_original = BKE_mesh_from_bmesh_for_eval_nomain(em->bm, nullptr, mesh);
}
else {
/* Otherwise get regular mesh. */
- mesh_original = ctx->object->data;
+ mesh_original = static_cast<Mesh *>(ctx->object->data);
}
}
else {
@@ -193,8 +193,8 @@ static void deformVerts(ModifierData *md,
BKE_mesh_tessface_ensure(psmd->mesh_original);
}
- if (!ELEM(mesh_src, NULL, mesh, psmd->mesh_final)) {
- BKE_id_free(NULL, mesh_src);
+ if (!ELEM(mesh_src, nullptr, mesh, psmd->mesh_final)) {
+ BKE_id_free(nullptr, mesh_src);
}
/* Report change in mesh structure.
@@ -221,7 +221,7 @@ static void deformVerts(ModifierData *md,
if (DEG_is_active(ctx->depsgraph)) {
Object *object_orig = DEG_get_original_object(ctx->object);
ModifierData *md_orig = BKE_modifiers_findby_name(object_orig, psmd->modifier.name);
- BLI_assert(md_orig != NULL);
+ BLI_assert(md_orig != nullptr);
ParticleSystemModifierData *psmd_orig = (ParticleSystemModifierData *)md_orig;
psmd_orig->flag = psmd->flag;
}
@@ -237,16 +237,16 @@ static void deformVertsEM(ModifierData *md,
float (*vertexCos)[3],
int verts_num)
{
- const bool do_temp_mesh = (mesh == NULL);
+ const bool do_temp_mesh = (mesh == nullptr);
if (do_temp_mesh) {
mesh = BKE_id_new_nomain(ID_ME, ((ID *)ob->data)->name);
- BM_mesh_bm_to_me(NULL, editData->bm, mesh, &((BMeshToMeshParams){0}));
+ BM_mesh_bm_to_me(nullptr, editData->bm, mesh, &((BMeshToMeshParams){0}));
}
deformVerts(md, ob, mesh, vertexCos, verts_num);
if (derivedData) {
- BKE_id_free(NULL, mesh);
+ BKE_id_free(nullptr, mesh);
}
}
#endif
@@ -258,7 +258,7 @@ static void panel_draw(const bContext *UNUSED(C), Panel *panel)
PointerRNA ob_ptr;
PointerRNA *ptr = modifier_panel_get_property_pointers(panel, &ob_ptr);
- Object *ob = ob_ptr.data;
+ Object *ob = static_cast<Object *>(ob_ptr.data);
ModifierData *md = (ModifierData *)ptr->data;
ParticleSystem *psys = ((ParticleSystemModifierData *)md)->psys;
@@ -291,8 +291,8 @@ static void blendRead(BlendDataReader *reader, ModifierData *md)
{
ParticleSystemModifierData *psmd = (ParticleSystemModifierData *)md;
- psmd->mesh_final = NULL;
- psmd->mesh_original = NULL;
+ psmd->mesh_final = nullptr;
+ psmd->mesh_original = nullptr;
/* This is written as part of ob->particlesystem. */
BLO_read_data_address(reader, &psmd->psys);
psmd->flag &= ~eParticleSystemFlag_psys_updated;
@@ -306,32 +306,33 @@ ModifierTypeInfo modifierType_ParticleSystem = {
/* srna */ &RNA_ParticleSystemModifier,
/* type */ eModifierTypeType_OnlyDeform,
/* flags */ eModifierTypeFlag_AcceptsMesh | eModifierTypeFlag_SupportsMapping |
- eModifierTypeFlag_UsesPointCache /* |
- eModifierTypeFlag_SupportsEditmode |
- eModifierTypeFlag_EnableInEditmode */
+ eModifierTypeFlag_UsesPointCache
+#if 0
+ | eModifierTypeFlag_SupportsEditmode | eModifierTypeFlag_EnableInEditmode
+#endif
,
/* icon */ ICON_MOD_PARTICLES,
/* copyData */ copyData,
/* deformVerts */ deformVerts,
- /* deformMatrices */ NULL,
- /* deformVertsEM */ NULL,
- /* deformMatricesEM */ NULL,
- /* modifyMesh */ NULL,
- /* modifyGeometrySet */ NULL,
+ /* deformMatrices */ nullptr,
+ /* deformVertsEM */ nullptr,
+ /* deformMatricesEM */ nullptr,
+ /* modifyMesh */ nullptr,
+ /* modifyGeometrySet */ nullptr,
/* initData */ initData,
/* requiredDataMask */ requiredDataMask,
/* freeData */ freeData,
- /* isDisabled */ NULL,
- /* updateDepsgraph */ NULL,
- /* dependsOnTime */ NULL,
- /* dependsOnNormals */ NULL,
- /* foreachIDLink */ NULL,
- /* foreachTexLink */ NULL,
- /* freeRuntimeData */ NULL,
+ /* isDisabled */ nullptr,
+ /* updateDepsgraph */ nullptr,
+ /* dependsOnTime */ nullptr,
+ /* dependsOnNormals */ nullptr,
+ /* foreachIDLink */ nullptr,
+ /* foreachTexLink */ nullptr,
+ /* freeRuntimeData */ nullptr,
/* panelRegister */ panelRegister,
- /* blendWrite */ NULL,
+ /* blendWrite */ nullptr,
/* blendRead */ blendRead,
};
diff --git a/source/blender/modifiers/intern/MOD_screw.c b/source/blender/modifiers/intern/MOD_screw.c
index 05072cf340c..0e22f59c2fb 100644
--- a/source/blender/modifiers/intern/MOD_screw.c
+++ b/source/blender/modifiers/intern/MOD_screw.c
@@ -182,7 +182,6 @@ static Mesh *modifyMesh(ModifierData *md, const ModifierEvalContext *ctx, Mesh *
ScrewModifierData *ltmd = (ScrewModifierData *)md;
const bool use_render_params = (ctx->flag & MOD_APPLY_RENDER) != 0;
- int *origindex;
int mpoly_index = 0;
uint step;
uint i, j;
@@ -375,6 +374,12 @@ static Mesh *modifyMesh(ModifierData *md, const ModifierEvalContext *ctx, Mesh *
uv_u_scale = (uv_u_scale / (float)ltmd->iter) * (angle / ((float)M_PI * 2.0f));
}
+ /* The `screw_ofs` cannot change from now on. */
+ const bool do_remove_doubles = (ltmd->flag & MOD_SCREW_MERGE) && (screw_ofs == 0.0f);
+ /* Only calculate normals if `do_remove_doubles` since removing doubles frees the normals. */
+ const bool do_normal_create = (ltmd->flag & MOD_SCREW_NORMAL_CALC) &&
+ (do_remove_doubles == false);
+
result = BKE_mesh_new_nomain_from_template(
mesh, (int)maxVerts, (int)maxEdges, 0, (int)maxPolys * 4, (int)maxPolys);
@@ -383,7 +388,6 @@ 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);
mpoly_new = result->mpoly;
mloop_new = result->mloop;
medge_new = result->medge;
@@ -392,7 +396,7 @@ static Mesh *modifyMesh(ModifierData *md, const ModifierEvalContext *ctx, Mesh *
CustomData_add_layer(&result->pdata, CD_ORIGINDEX, CD_CALLOC, NULL, (int)maxPolys);
}
- origindex = CustomData_get_layer(&result->pdata, CD_ORIGINDEX);
+ int *origindex = CustomData_get_layer(&result->pdata, CD_ORIGINDEX);
CustomData_copy_data(&mesh->vdata, &result->vdata, 0, 0, (int)totvert);
@@ -439,7 +443,7 @@ static Mesh *modifyMesh(ModifierData *md, const ModifierEvalContext *ctx, Mesh *
/* Tag mvert as not loose. */
BLI_BITMAP_ENABLE(vert_tag, med_orig->v1);
- BLI_BITMAP_ENABLE(vert_tag, med_orig->v1);
+ BLI_BITMAP_ENABLE(vert_tag, med_orig->v2);
}
/* build polygon -> edge map */
@@ -472,7 +476,11 @@ static Mesh *modifyMesh(ModifierData *md, const ModifierEvalContext *ctx, Mesh *
}
}
+ float(*vert_normals_new)[3] = do_normal_create ? BKE_mesh_vertex_normals_for_write(result) :
+ NULL;
+
if (ltmd->flag & MOD_SCREW_NORMAL_CALC) {
+
/*
* Normal Calculation (for face flipping)
* Sort edge verts for correct face flipping
@@ -766,68 +774,69 @@ static Mesh *modifyMesh(ModifierData *md, const ModifierEvalContext *ctx, Mesh *
*
* calculate vertex normals that can be propagated on lathing
* use edge connectivity work this out */
- if (SV_IS_VALID(vc->v[0])) {
- if (SV_IS_VALID(vc->v[1])) {
- /* 2 edges connected. */
- /* make 2 connecting vert locations relative to the middle vert */
- sub_v3_v3v3(tmp_vec1, mvert_new[vc->v[0]].co, mvert_new[i].co);
- sub_v3_v3v3(tmp_vec2, mvert_new[vc->v[1]].co, mvert_new[i].co);
- /* normalize so both edges have the same influence, no matter their length */
- normalize_v3(tmp_vec1);
- normalize_v3(tmp_vec2);
-
- /* vc_no_tmp1 - this line is the average direction of both connecting edges
- *
- * Use the edge order to make the subtraction, flip the normal the right way
- * edge should be there but check just in case... */
- if (vc->e[0]->v1 == i) {
- sub_v3_v3(tmp_vec1, tmp_vec2);
- }
- else {
- sub_v3_v3v3(tmp_vec1, tmp_vec2, tmp_vec1);
- }
- }
- else {
- /* only 1 edge connected - same as above except
- * don't need to average edge direction */
- if (vc->e[0]->v2 == i) {
- sub_v3_v3v3(tmp_vec1, mvert_new[i].co, mvert_new[vc->v[0]].co);
+ if (do_normal_create) {
+ if (SV_IS_VALID(vc->v[0])) {
+ if (SV_IS_VALID(vc->v[1])) {
+ /* 2 edges connected. */
+ /* make 2 connecting vert locations relative to the middle vert */
+ sub_v3_v3v3(tmp_vec1, mvert_new[vc->v[0]].co, mvert_new[i].co);
+ sub_v3_v3v3(tmp_vec2, mvert_new[vc->v[1]].co, mvert_new[i].co);
+ /* normalize so both edges have the same influence, no matter their length */
+ normalize_v3(tmp_vec1);
+ normalize_v3(tmp_vec2);
+
+ /* vc_no_tmp1 - this line is the average direction of both connecting edges
+ *
+ * Use the edge order to make the subtraction, flip the normal the right way
+ * edge should be there but check just in case... */
+ if (vc->e[0]->v1 == i) {
+ sub_v3_v3(tmp_vec1, tmp_vec2);
+ }
+ else {
+ sub_v3_v3v3(tmp_vec1, tmp_vec2, tmp_vec1);
+ }
}
else {
- sub_v3_v3v3(tmp_vec1, mvert_new[vc->v[0]].co, mvert_new[i].co);
+ /* only 1 edge connected - same as above except
+ * don't need to average edge direction */
+ if (vc->e[0]->v2 == i) {
+ sub_v3_v3v3(tmp_vec1, mvert_new[i].co, mvert_new[vc->v[0]].co);
+ }
+ else {
+ sub_v3_v3v3(tmp_vec1, mvert_new[vc->v[0]].co, mvert_new[i].co);
+ }
}
- }
- /* tmp_vec2 - is a line 90d from the pivot to the vec
- * This is used so the resulting normal points directly away from the middle */
- cross_v3_v3v3(tmp_vec2, axis_vec, vc->co);
+ /* tmp_vec2 - is a line 90d from the pivot to the vec
+ * This is used so the resulting normal points directly away from the middle */
+ cross_v3_v3v3(tmp_vec2, axis_vec, vc->co);
- if (UNLIKELY(is_zero_v3(tmp_vec2))) {
- /* we're _on_ the axis, so copy it based on our winding */
- if (vc->e[0]->v2 == i) {
- negate_v3_v3(vc->no, axis_vec);
+ if (UNLIKELY(is_zero_v3(tmp_vec2))) {
+ /* we're _on_ the axis, so copy it based on our winding */
+ if (vc->e[0]->v2 == i) {
+ negate_v3_v3(vc->no, axis_vec);
+ }
+ else {
+ copy_v3_v3(vc->no, axis_vec);
+ }
}
else {
- copy_v3_v3(vc->no, axis_vec);
+ /* edge average vector and right angle to the pivot make the normal */
+ cross_v3_v3v3(vc->no, tmp_vec1, tmp_vec2);
}
}
else {
- /* edge average vector and right angle to the pivot make the normal */
- cross_v3_v3v3(vc->no, tmp_vec1, tmp_vec2);
+ copy_v3_v3(vc->no, vc->co);
}
- }
- else {
- copy_v3_v3(vc->no, vc->co);
- }
-
- /* we won't be looping on this data again so copy normals here */
- if ((angle < 0.0f) != do_flip) {
- negate_v3(vc->no);
- }
- normalize_v3(vc->no);
- copy_v3_v3(vert_normals_new[i], vc->no);
+ /* we won't be looping on this data again so copy normals here */
+ if ((angle < 0.0f) != do_flip) {
+ negate_v3(vc->no);
+ }
+ normalize_v3(vc->no);
+ copy_v3_v3(vert_normals_new[i], vc->no);
+ }
/* Done with normals */
}
}
@@ -846,7 +855,6 @@ static Mesh *modifyMesh(ModifierData *md, const ModifierEvalContext *ctx, Mesh *
for (step = 1; step < step_tot; step++) {
const uint varray_stride = totvert * step;
float step_angle;
- float nor_tx[3];
float mat[4][4];
/* Rotation Matrix */
step_angle = (angle / (float)(step_tot - (!close))) * (float)step;
@@ -872,10 +880,10 @@ static Mesh *modifyMesh(ModifierData *md, const ModifierEvalContext *ctx, Mesh *
for (j = 0; j < totvert; j++, mv_new_base++, mv_new++) {
/* set normal */
if (vert_connect) {
- mul_v3_m3v3(nor_tx, mat3, vert_connect[j].no);
-
- /* set the normal now its transformed */
- copy_v3_v3(vert_normals_new[mv_new - mvert_new], nor_tx);
+ if (do_normal_create) {
+ /* Set the normal now its transformed. */
+ mul_v3_m3v3(vert_normals_new[mv_new - mvert_new], mat3, vert_connect[j].no);
+ }
}
/* set location */
@@ -1118,7 +1126,11 @@ static Mesh *modifyMesh(ModifierData *md, const ModifierEvalContext *ctx, Mesh *
MEM_freeN(vert_loop_map);
}
- if ((ltmd->flag & MOD_SCREW_MERGE) && (screw_ofs == 0.0f)) {
+ if (do_normal_create) {
+ BKE_mesh_vertex_normals_clear_dirty(result);
+ }
+
+ if (do_remove_doubles) {
result = mesh_remove_doubles_on_axis(result,
mvert_new,
totvert,
@@ -1128,10 +1140,6 @@ static Mesh *modifyMesh(ModifierData *md, const ModifierEvalContext *ctx, Mesh *
ltmd->merge_dist);
}
- if ((ltmd->flag & MOD_SCREW_NORMAL_CALC)) {
- BKE_mesh_vertex_normals_clear_dirty(result);
- }
-
return result;
}
diff --git a/source/blender/modifiers/intern/MOD_skin.c b/source/blender/modifiers/intern/MOD_skin.c
index 7f96dcb82fb..5f238209015 100644
--- a/source/blender/modifiers/intern/MOD_skin.c
+++ b/source/blender/modifiers/intern/MOD_skin.c
@@ -881,34 +881,29 @@ static int calc_edge_subdivisions(const MVert *mvert,
/* Take a Mesh and subdivide its edges to keep skin nodes
* reasonably close. */
-static Mesh *subdivide_base(Mesh *orig)
+static Mesh *subdivide_base(const Mesh *orig)
{
- Mesh *result;
- MVertSkin *orignode, *outnode;
- MVert *origvert, *outvert;
- MEdge *origedge, *outedge, *e;
- MDeformVert *origdvert, *outdvert;
- int orig_vert_num, orig_edge_num;
- int subd_num, *degree, *edge_subd;
+ const MEdge *e;
+ int subd_num;
int i, j, k, u, v;
float radrat;
- orignode = CustomData_get_layer(&orig->vdata, CD_MVERT_SKIN);
- origvert = orig->mvert;
- origedge = orig->medge;
- origdvert = orig->dvert;
- orig_vert_num = orig->totvert;
- orig_edge_num = orig->totedge;
+ const MVertSkin *orignode = CustomData_get_layer(&orig->vdata, CD_MVERT_SKIN);
+ const MVert *origvert = orig->mvert;
+ const MEdge *origedge = orig->medge;
+ const MDeformVert *origdvert = orig->dvert;
+ int orig_vert_num = orig->totvert;
+ int orig_edge_num = orig->totedge;
/* Get degree of all vertices */
- degree = MEM_calloc_arrayN(orig_vert_num, sizeof(int), "degree");
+ int *degree = MEM_calloc_arrayN(orig_vert_num, sizeof(int), "degree");
for (i = 0; i < orig_edge_num; i++) {
degree[origedge[i].v1]++;
degree[origedge[i].v2]++;
}
/* Per edge, store how many subdivisions are needed */
- edge_subd = MEM_calloc_arrayN((uint)orig_edge_num, sizeof(int), "edge_subd");
+ int *edge_subd = MEM_calloc_arrayN((uint)orig_edge_num, sizeof(int), "edge_subd");
for (i = 0, subd_num = 0; i < orig_edge_num; i++) {
edge_subd[i] += calc_edge_subdivisions(origvert, orignode, &origedge[i], degree);
BLI_assert(edge_subd[i] >= 0);
@@ -918,13 +913,13 @@ static Mesh *subdivide_base(Mesh *orig)
MEM_freeN(degree);
/* Allocate output mesh */
- result = BKE_mesh_new_nomain_from_template(
+ Mesh *result = BKE_mesh_new_nomain_from_template(
orig, orig_vert_num + subd_num, orig_edge_num + subd_num, 0, 0, 0);
- outvert = result->mvert;
- outedge = result->medge;
- outnode = CustomData_get_layer(&result->vdata, CD_MVERT_SKIN);
- outdvert = result->dvert;
+ MVert *outvert = result->mvert;
+ MEdge *outedge = result->medge;
+ MVertSkin *outnode = CustomData_get_layer(&result->vdata, CD_MVERT_SKIN);
+ MDeformVert *outdvert = result->dvert;
/* Copy original vertex data */
CustomData_copy_data(&orig->vdata, &result->vdata, 0, 0, orig_vert_num);
diff --git a/source/blender/modifiers/intern/MOD_solidify.c b/source/blender/modifiers/intern/MOD_solidify.c
index 48154a3670d..1f0aee7d689 100644
--- a/source/blender/modifiers/intern/MOD_solidify.c
+++ b/source/blender/modifiers/intern/MOD_solidify.c
@@ -75,7 +75,7 @@ static Mesh *modifyMesh(ModifierData *md, const ModifierEvalContext *ctx, Mesh *
case MOD_SOLIDIFY_MODE_NONMANIFOLD:
return MOD_solidify_nonmanifold_modifyMesh(md, ctx, mesh);
default:
- BLI_assert(0);
+ BLI_assert_unreachable();
}
return mesh;
}
diff --git a/source/blender/modifiers/intern/MOD_subsurf.c b/source/blender/modifiers/intern/MOD_subsurf.c
index 571e564f583..23f447f2469 100644
--- a/source/blender/modifiers/intern/MOD_subsurf.c
+++ b/source/blender/modifiers/intern/MOD_subsurf.c
@@ -196,16 +196,21 @@ static Mesh *subdiv_as_ccg(SubsurfModifierData *smd,
/* Cache settings for lazy CPU evaluation. */
-static void subdiv_cache_cpu_evaluation_settings(const ModifierEvalContext *ctx,
- Mesh *me,
- SubsurfModifierData *smd)
+static void subdiv_cache_mesh_wrapper_settings(const ModifierEvalContext *ctx,
+ Mesh *mesh,
+ SubsurfModifierData *smd,
+ SubsurfRuntimeData *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;
- me->runtime.subsurf_session_uuid = smd->modifier.session_uuid;
+
+ runtime_data->has_gpu_subdiv = true;
+ runtime_data->resolution = mesh_settings.resolution;
+ runtime_data->use_optimal_display = mesh_settings.use_optimal_display;
+ runtime_data->calc_loop_normals = false; /* Set at the end of modifier stack evaluation. */
+ runtime_data->use_loop_normals = (smd->flags & eSubsurfModifierFlag_UseCustomNormals);
+
+ mesh->runtime.subsurf_runtime_data = runtime_data;
}
/* Modifier itself. */
@@ -218,13 +223,11 @@ static Mesh *modifyMesh(ModifierData *md, const ModifierEvalContext *ctx, Mesh *
return result;
#endif
SubsurfModifierData *smd = (SubsurfModifierData *)md;
- SubdivSettings subdiv_settings;
- BKE_subsurf_modifier_subdiv_settings_init(
- &subdiv_settings, smd, (ctx->flag & MOD_APPLY_RENDER) != 0);
- if (subdiv_settings.level == 0) {
+ if (!BKE_subsurf_modifier_runtime_init(smd, (ctx->flag & MOD_APPLY_RENDER) != 0)) {
return result;
}
- SubsurfRuntimeData *runtime_data = BKE_subsurf_modifier_ensure_runtime(smd);
+
+ SubsurfRuntimeData *runtime_data = (SubsurfRuntimeData *)smd->modifier.runtime;
/* Delay evaluation to the draw code if possible, provided we do not have to apply the modifier.
*/
@@ -236,15 +239,13 @@ static Mesh *modifyMesh(ModifierData *md, const ModifierEvalContext *ctx, Mesh *
* 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, mesh, smd, required_mode, false)) {
- subdiv_cache_cpu_evaluation_settings(ctx, mesh, smd);
+ if (BKE_subsurf_modifier_can_do_gpu_subdiv(scene, ctx->object, mesh, smd, required_mode)) {
+ subdiv_cache_mesh_wrapper_settings(ctx, mesh, smd, runtime_data);
return result;
}
}
- Subdiv *subdiv = BKE_subsurf_modifier_subdiv_descriptor_ensure(
- smd, &subdiv_settings, mesh, false);
+ Subdiv *subdiv = BKE_subsurf_modifier_subdiv_descriptor_ensure(runtime_data, mesh, false);
if (subdiv == NULL) {
/* Happens on bad topology, but also on empty input mesh. */
return result;
@@ -295,15 +296,11 @@ static void deformMatrices(ModifierData *md,
(void)deform_matrices;
SubsurfModifierData *smd = (SubsurfModifierData *)md;
- SubdivSettings subdiv_settings;
- BKE_subsurf_modifier_subdiv_settings_init(
- &subdiv_settings, smd, (ctx->flag & MOD_APPLY_RENDER) != 0);
- if (subdiv_settings.level == 0) {
+ if (!BKE_subsurf_modifier_runtime_init(smd, (ctx->flag & MOD_APPLY_RENDER) != 0)) {
return;
}
- SubsurfRuntimeData *runtime_data = BKE_subsurf_modifier_ensure_runtime(smd);
- Subdiv *subdiv = BKE_subsurf_modifier_subdiv_descriptor_ensure(
- smd, &subdiv_settings, mesh, false);
+ SubsurfRuntimeData *runtime_data = (SubsurfRuntimeData *)smd->modifier.runtime;
+ Subdiv *subdiv = BKE_subsurf_modifier_subdiv_descriptor_ensure(runtime_data, mesh, false);
if (subdiv == NULL) {
/* Happens on bad topology, but also on empty input mesh. */
return;
diff --git a/source/blender/modifiers/intern/MOD_surfacedeform.c b/source/blender/modifiers/intern/MOD_surfacedeform.c
index 8a0f49efb65..20cc9b2392f 100644
--- a/source/blender/modifiers/intern/MOD_surfacedeform.c
+++ b/source/blender/modifiers/intern/MOD_surfacedeform.c
@@ -1669,27 +1669,42 @@ static void panelRegister(ARegionType *region_type)
modifier_panel_register(region_type, eModifierType_SurfaceDeform, panel_draw);
}
-static void blendWrite(BlendWriter *writer, const ModifierData *md)
+static void blendWrite(BlendWriter *writer, const ID *id_owner, const ModifierData *md)
{
- const SurfaceDeformModifierData *smd = (const SurfaceDeformModifierData *)md;
+ SurfaceDeformModifierData smd = *(const SurfaceDeformModifierData *)md;
+ const bool is_undo = BLO_write_is_undo(writer);
+
+ if (ID_IS_OVERRIDE_LIBRARY(id_owner) && !is_undo) {
+ BLI_assert(!ID_IS_LINKED(id_owner));
+ const bool is_local = (md->flag & eModifierFlag_OverrideLibrary_Local) != 0;
+ if (!is_local) {
+ /* Modifier coming from linked data cannot be bound from an override, so we can remove all
+ * binding data, can save a significant amount of memory. */
+ smd.bind_verts_num = 0;
+ smd.verts = NULL;
+ }
+ }
- BLO_write_struct_array(writer, SDefVert, smd->bind_verts_num, smd->verts);
+ BLO_write_struct_at_address(writer, SurfaceDeformModifierData, md, &smd);
- if (smd->verts) {
- for (int i = 0; i < smd->bind_verts_num; i++) {
- BLO_write_struct_array(writer, SDefBind, smd->verts[i].binds_num, smd->verts[i].binds);
+ if (smd.verts != NULL) {
+ SDefVert *bind_verts = smd.verts;
+ BLO_write_struct_array(writer, SDefVert, smd.bind_verts_num, bind_verts);
- if (smd->verts[i].binds) {
- for (int j = 0; j < smd->verts[i].binds_num; j++) {
+ for (int i = 0; i < smd.bind_verts_num; i++) {
+ BLO_write_struct_array(writer, SDefBind, bind_verts[i].binds_num, bind_verts[i].binds);
+
+ if (bind_verts[i].binds) {
+ for (int j = 0; j < bind_verts[i].binds_num; j++) {
BLO_write_uint32_array(
- writer, smd->verts[i].binds[j].verts_num, smd->verts[i].binds[j].vert_inds);
+ writer, bind_verts[i].binds[j].verts_num, bind_verts[i].binds[j].vert_inds);
- if (ELEM(smd->verts[i].binds[j].mode, MOD_SDEF_MODE_CENTROID, MOD_SDEF_MODE_LOOPTRI)) {
- BLO_write_float3_array(writer, 1, smd->verts[i].binds[j].vert_weights);
+ if (ELEM(bind_verts[i].binds[j].mode, MOD_SDEF_MODE_CENTROID, MOD_SDEF_MODE_LOOPTRI)) {
+ BLO_write_float3_array(writer, 1, bind_verts[i].binds[j].vert_weights);
}
else {
BLO_write_float_array(
- writer, smd->verts[i].binds[j].verts_num, smd->verts[i].binds[j].vert_weights);
+ writer, bind_verts[i].binds[j].verts_num, bind_verts[i].binds[j].vert_weights);
}
}
}
diff --git a/source/blender/modifiers/intern/MOD_util.c b/source/blender/modifiers/intern/MOD_util.c
index a58e8e23147..575182a846b 100644
--- a/source/blender/modifiers/intern/MOD_util.c
+++ b/source/blender/modifiers/intern/MOD_util.c
@@ -100,10 +100,9 @@ void MOD_get_texture_coords(MappingInfoModifierData *dmd,
BLI_bitmap *done = BLI_BITMAP_NEW(verts_num, __func__);
const int polys_num = mesh->totpoly;
char uvname[MAX_CUSTOMDATA_LAYER_NAME];
- MLoopUV *mloop_uv;
CustomData_validate_layer_name(&mesh->ldata, CD_MLOOPUV, dmd->uvlayer_name, uvname);
- mloop_uv = CustomData_get_layer_named(&mesh->ldata, CD_MLOOPUV, uvname);
+ const MLoopUV *mloop_uv = CustomData_get_layer_named(&mesh->ldata, CD_MLOOPUV, uvname);
/* verts are given the UV from the first face that uses them */
for (i = 0, mp = mpoly; i < polys_num; i++, mp++) {
diff --git a/source/blender/modifiers/intern/MOD_util.h b/source/blender/modifiers/intern/MOD_util.h
index aef254b1103..b3b75898557 100644
--- a/source/blender/modifiers/intern/MOD_util.h
+++ b/source/blender/modifiers/intern/MOD_util.h
@@ -11,6 +11,10 @@
#include "DEG_depsgraph_build.h"
+#ifdef __cplusplus
+extern "C" {
+#endif
+
struct MDeformVert;
struct Mesh;
struct ModifierData;
@@ -51,3 +55,7 @@ void MOD_depsgraph_update_object_bone_relation(struct DepsNodeHandle *node,
struct Object *object,
const char *bonename,
const char *description);
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/source/blender/modifiers/intern/MOD_warp.c b/source/blender/modifiers/intern/MOD_warp.c
index e95d2983639..9693cf0c0f2 100644
--- a/source/blender/modifiers/intern/MOD_warp.c
+++ b/source/blender/modifiers/intern/MOD_warp.c
@@ -302,7 +302,6 @@ static void warpModifier_do(WarpModifierData *wmd,
if (tex_co) {
struct Scene *scene = DEG_get_evaluated_scene(ctx->depsgraph);
TexResult texres;
- texres.nor = NULL;
BKE_texture_get_value(scene, tex_target, tex_co[i], &texres, false);
fac *= texres.tin;
}
@@ -489,22 +488,24 @@ static void panelRegister(ARegionType *region_type)
region_type, "texture", "Texture", NULL, texture_panel_draw, panel_type);
}
-static void blendWrite(BlendWriter *writer, const ModifierData *md)
+static void blendWrite(BlendWriter *writer, const ID *UNUSED(id_owner), const ModifierData *md)
{
- const WarpModifierData *tmd = (const WarpModifierData *)md;
+ const WarpModifierData *wmd = (const WarpModifierData *)md;
+
+ BLO_write_struct(writer, WarpModifierData, wmd);
- if (tmd->curfalloff) {
- BKE_curvemapping_blend_write(writer, tmd->curfalloff);
+ if (wmd->curfalloff) {
+ BKE_curvemapping_blend_write(writer, wmd->curfalloff);
}
}
static void blendRead(BlendDataReader *reader, ModifierData *md)
{
- WarpModifierData *tmd = (WarpModifierData *)md;
+ WarpModifierData *wmd = (WarpModifierData *)md;
- BLO_read_data_address(reader, &tmd->curfalloff);
- if (tmd->curfalloff) {
- BKE_curvemapping_blend_read(reader, tmd->curfalloff);
+ BLO_read_data_address(reader, &wmd->curfalloff);
+ if (wmd->curfalloff) {
+ BKE_curvemapping_blend_read(reader, wmd->curfalloff);
}
}
diff --git a/source/blender/modifiers/intern/MOD_wave.c b/source/blender/modifiers/intern/MOD_wave.c
index 73b26dc29cd..4073f028db5 100644
--- a/source/blender/modifiers/intern/MOD_wave.c
+++ b/source/blender/modifiers/intern/MOD_wave.c
@@ -262,7 +262,6 @@ static void waveModifier_do(WaveModifierData *md,
if (tex_co) {
Scene *scene = DEG_get_evaluated_scene(ctx->depsgraph);
TexResult texres;
- texres.nor = NULL;
BKE_texture_get_value(scene, tex_target, tex_co[i], &texres, false);
amplit *= texres.tin;
}
diff --git a/source/blender/modifiers/intern/MOD_weighted_normal.c b/source/blender/modifiers/intern/MOD_weighted_normal.c
index c79dbdb0b1a..d436acb8ad5 100644
--- a/source/blender/modifiers/intern/MOD_weighted_normal.c
+++ b/source/blender/modifiers/intern/MOD_weighted_normal.c
@@ -82,7 +82,7 @@ typedef struct WeightedNormalData {
MPoly *mpoly;
const float (*polynors)[3];
- int *poly_strength;
+ const int *poly_strength;
MDeformVert *dvert;
const int defgrp_index;
@@ -195,7 +195,7 @@ static void apply_weights_vertex_normal(WeightedNormalModifierData *wnmd,
MPoly *mpoly = wn_data->mpoly;
const float(*polynors)[3] = wn_data->polynors;
- int *poly_strength = wn_data->poly_strength;
+ const int *poly_strength = wn_data->poly_strength;
MDeformVert *dvert = wn_data->dvert;
@@ -326,7 +326,7 @@ static void apply_weights_vertex_normal(WeightedNormalModifierData *wnmd,
}
break;
default:
- BLI_assert(0);
+ BLI_assert_unreachable();
}
/* Validate computed weighted normals. */
@@ -603,15 +603,13 @@ static Mesh *modifyMesh(ModifierData *md, const ModifierEvalContext *ctx, Mesh *
}
const float split_angle = mesh->smoothresh;
- short(*clnors)[2];
- CustomData *ldata = &result->ldata;
- clnors = CustomData_get_layer(ldata, CD_CUSTOMLOOPNORMAL);
+ short(*clnors)[2] = CustomData_get_layer(&result->ldata, CD_CUSTOMLOOPNORMAL);
/* Keep info whether we had clnors,
* it helps when generating clnor spaces and default normals. */
const bool has_clnors = clnors != NULL;
if (!clnors) {
- clnors = CustomData_add_layer(ldata, CD_CUSTOMLOOPNORMAL, CD_CALLOC, NULL, loops_num);
+ clnors = CustomData_add_layer(&result->ldata, CD_CUSTOMLOOPNORMAL, CD_CALLOC, NULL, loops_num);
}
MDeformVert *dvert;
diff --git a/source/blender/modifiers/intern/MOD_weightvg_util.c b/source/blender/modifiers/intern/MOD_weightvg_util.c
index b251825cd95..3302384568b 100644
--- a/source/blender/modifiers/intern/MOD_weightvg_util.c
+++ b/source/blender/modifiers/intern/MOD_weightvg_util.c
@@ -96,7 +96,7 @@ void weightvg_do_map(
BLI_assert(do_invert);
break;
default:
- BLI_assert(0);
+ BLI_assert_unreachable();
}
new_w[i] = do_invert ? 1.0f - fac : fac;
@@ -162,7 +162,6 @@ void weightvg_do_mask(const ModifierEvalContext *ctx,
do_color_manage = tex_use_channel != MOD_WVG_MASK_TEX_USE_INT;
- texres.nor = NULL;
BKE_texture_get_value(scene, texture, tex_co[idx], &texres, do_color_manage);
/* Get the good channel value... */
switch (tex_use_channel) {
@@ -206,8 +205,6 @@ void weightvg_do_mask(const ModifierEvalContext *ctx,
MEM_freeN(tex_co);
}
else if ((ref_didx = BKE_id_defgroup_name_index(&mesh->id, defgrp_name)) != -1) {
- MDeformVert *dvert = NULL;
-
/* Check whether we want to set vgroup weights from a constant weight factor or a vertex
* group.
*/
@@ -215,7 +212,7 @@ void weightvg_do_mask(const ModifierEvalContext *ctx,
/* Proceed only if vgroup is valid, else use constant factor. */
/* Get actual dverts (ie vertex group data). */
- dvert = CustomData_get_layer(&mesh->vdata, CD_MDEFORMVERT);
+ const MDeformVert *dvert = CustomData_get_layer(&mesh->vdata, CD_MDEFORMVERT);
/* Proceed only if vgroup is valid, else assume factor = O. */
if (dvert == NULL) {
return;
diff --git a/source/blender/modifiers/intern/MOD_weightvgedit.c b/source/blender/modifiers/intern/MOD_weightvgedit.c
index 2c733542e51..e1b43157adb 100644
--- a/source/blender/modifiers/intern/MOD_weightvgedit.c
+++ b/source/blender/modifiers/intern/MOD_weightvgedit.c
@@ -375,10 +375,12 @@ static void panelRegister(ARegionType *region_type)
region_type, "influence", "Influence", NULL, influence_panel_draw, panel_type);
}
-static void blendWrite(BlendWriter *writer, const ModifierData *md)
+static void blendWrite(BlendWriter *writer, const ID *UNUSED(id_owner), const ModifierData *md)
{
const WeightVGEditModifierData *wmd = (const WeightVGEditModifierData *)md;
+ BLO_write_struct(writer, WeightVGEditModifierData, wmd);
+
if (wmd->cmap_curve) {
BKE_curvemapping_blend_write(writer, wmd->cmap_curve);
}
diff --git a/source/blender/modifiers/intern/MOD_weightvgproximity.c b/source/blender/modifiers/intern/MOD_weightvgproximity.c
index 43a90b2a4ac..1bea5b93c97 100644
--- a/source/blender/modifiers/intern/MOD_weightvgproximity.c
+++ b/source/blender/modifiers/intern/MOD_weightvgproximity.c
@@ -715,10 +715,12 @@ static void panelRegister(ARegionType *region_type)
region_type, "influence", "Influence", NULL, influence_panel_draw, panel_type);
}
-static void blendWrite(BlendWriter *writer, const ModifierData *md)
+static void blendWrite(BlendWriter *writer, const ID *UNUSED(id_owner), const ModifierData *md)
{
const WeightVGProximityModifierData *wmd = (const WeightVGProximityModifierData *)md;
+ BLO_write_struct(writer, WeightVGProximityModifierData, wmd);
+
if (wmd->cmap_curve) {
BKE_curvemapping_blend_write(writer, wmd->cmap_curve);
}
diff --git a/source/blender/nodes/NOD_geometry.h b/source/blender/nodes/NOD_geometry.h
index 61e89409882..b9da2b17319 100644
--- a/source/blender/nodes/NOD_geometry.h
+++ b/source/blender/nodes/NOD_geometry.h
@@ -63,6 +63,8 @@ void register_node_type_geo_input_curve_handles(void);
void register_node_type_geo_input_curve_tilt(void);
void register_node_type_geo_input_id(void);
void register_node_type_geo_input_index(void);
+void register_node_type_geo_input_instance_rotation(void);
+void register_node_type_geo_input_instance_scale(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);
@@ -134,6 +136,7 @@ void register_node_type_geo_transform(void);
void register_node_type_geo_translate_instances(void);
void register_node_type_geo_triangulate(void);
void register_node_type_geo_viewer(void);
+void register_node_type_geo_volume_cube(void);
void register_node_type_geo_volume_to_mesh(void);
#ifdef __cplusplus
diff --git a/source/blender/nodes/NOD_geometry_exec.hh b/source/blender/nodes/NOD_geometry_exec.hh
index bac4d0165e9..b82c05f33be 100644
--- a/source/blender/nodes/NOD_geometry_exec.hh
+++ b/source/blender/nodes/NOD_geometry_exec.hh
@@ -40,7 +40,7 @@ using fn::FieldInput;
using fn::FieldOperation;
using fn::GField;
using fn::ValueOrField;
-using geometry_nodes_eval_log::NamedAttributeUsage;
+using geometry_nodes_eval_log::eNamedAttrUsage;
using geometry_nodes_eval_log::NodeWarningType;
/**
@@ -298,52 +298,11 @@ class GeoNodeExecParams {
*/
void error_message_add(const NodeWarningType type, std::string message) const;
- /**
- * Creates a read-only attribute based on node inputs. The method automatically detects which
- * input socket with the given name is available.
- *
- * \note This will add an error message if the string socket is active and
- * the input attribute does not exist.
- */
- GVArray get_input_attribute(const StringRef name,
- const GeometryComponent &component,
- AttributeDomain domain,
- const CustomDataType type,
- const void *default_value) const;
-
- template<typename T>
- VArray<T> get_input_attribute(const StringRef name,
- const GeometryComponent &component,
- const AttributeDomain domain,
- const T &default_value) const
- {
- const CustomDataType type = bke::cpp_type_to_custom_data_type(CPPType::get<T>());
- GVArray varray = this->get_input_attribute(name, component, domain, type, &default_value);
- return varray.typed<T>();
- }
-
- /**
- * Get the type of an input property or the associated constant socket types with the
- * same names. Fall back to the default value if no attribute exists with the name.
- */
- CustomDataType get_input_attribute_data_type(const StringRef name,
- const GeometryComponent &component,
- const CustomDataType default_type) const;
-
- /**
- * If any of the corresponding input sockets are attributes instead of single values,
- * use the highest priority attribute domain from among them.
- * Otherwise return the default domain.
- */
- AttributeDomain get_highest_priority_input_domain(Span<std::string> names,
- const GeometryComponent &component,
- AttributeDomain default_domain) const;
-
std::string attribute_producer_name() const;
void set_default_remaining_outputs();
- void used_named_attribute(std::string attribute_name, NamedAttributeUsage usage);
+ void used_named_attribute(std::string attribute_name, eNamedAttrUsage usage);
private:
/* Utilities for detecting common errors at when using this class. */
diff --git a/source/blender/nodes/NOD_geometry_nodes_eval_log.hh b/source/blender/nodes/NOD_geometry_nodes_eval_log.hh
index 1ad859aa47b..05c97c3903d 100644
--- a/source/blender/nodes/NOD_geometry_nodes_eval_log.hh
+++ b/source/blender/nodes/NOD_geometry_nodes_eval_log.hh
@@ -89,8 +89,9 @@ class GFieldValueLog : public ValueLog {
struct GeometryAttributeInfo {
std::string name;
- AttributeDomain domain;
- CustomDataType data_type;
+ /** Can be empty when #name does not actually exist on a geometry yet. */
+ std::optional<eAttrDomain> domain;
+ std::optional<eCustomDataType> data_type;
};
/** Contains information about a geometry set. In most cases this does not store the entire
@@ -103,16 +104,16 @@ class GeometryValueLog : public ValueLog {
public:
struct MeshInfo {
- int tot_verts, tot_edges, tot_faces;
+ int verts_num, edges_num, faces_num;
};
struct CurveInfo {
- int tot_splines;
+ int splines_num;
};
struct PointCloudInfo {
- int tot_points;
+ int points_num;
};
struct InstancesInfo {
- int tot_instances;
+ int instances_num;
};
std::optional<MeshInfo> mesh_info;
@@ -170,17 +171,17 @@ struct ValueOfSockets {
destruct_ptr<ValueLog> value;
};
-enum class NamedAttributeUsage {
+enum class eNamedAttrUsage {
None = 0,
Read = 1 << 0,
Write = 1 << 1,
Remove = 1 << 2,
};
-ENUM_OPERATORS(NamedAttributeUsage, NamedAttributeUsage::Remove);
+ENUM_OPERATORS(eNamedAttrUsage, eNamedAttrUsage::Remove);
struct UsedNamedAttribute {
std::string name;
- NamedAttributeUsage usage;
+ eNamedAttrUsage usage;
};
struct NodeWithUsedNamedAttribute {
@@ -218,7 +219,7 @@ class LocalGeoLogger {
void log_multi_value_socket(DSocket socket, Span<GPointer> values);
void log_node_warning(DNode node, NodeWarningType type, std::string message);
void log_execution_time(DNode node, std::chrono::microseconds exec_time);
- void log_used_named_attribute(DNode node, std::string attribute_name, NamedAttributeUsage usage);
+ void log_used_named_attribute(DNode node, std::string attribute_name, eNamedAttrUsage usage);
/**
* Log a message that will be displayed in the node editor next to the node.
* This should only be used for debugging purposes and not to display information to users.
diff --git a/source/blender/nodes/NOD_node_tree_ref.hh b/source/blender/nodes/NOD_node_tree_ref.hh
index 61d1d11d859..257aa5f4110 100644
--- a/source/blender/nodes/NOD_node_tree_ref.hh
+++ b/source/blender/nodes/NOD_node_tree_ref.hh
@@ -41,6 +41,7 @@
#include "BLI_vector.hh"
#include "BKE_node.h"
+#include "BKE_node_runtime.hh"
#include "DNA_node_types.h"
@@ -597,7 +598,7 @@ inline bNodeType *NodeRef::typeinfo() const
inline const NodeDeclaration *NodeRef::declaration() const
{
nodeDeclarationEnsure(this->tree().btree(), bnode_);
- return bnode_->declaration;
+ return bnode_->runtime->declaration;
}
inline int NodeRef::id() const
diff --git a/source/blender/nodes/NOD_static_types.h b/source/blender/nodes/NOD_static_types.h
index 69f2e29eb41..54336ac65d0 100644
--- a/source/blender/nodes/NOD_static_types.h
+++ b/source/blender/nodes/NOD_static_types.h
@@ -44,7 +44,7 @@ DefNode(ShaderNode, SH_NODE_SQUEEZE, 0, "SQUEEZ
DefNode(ShaderNode, SH_NODE_INVERT, 0, "INVERT", Invert, "Invert", "" )
DefNode(ShaderNode, SH_NODE_SEPRGB_LEGACY, 0, "SEPRGB", SeparateRGB, "Separate RGB", "" )
DefNode(ShaderNode, SH_NODE_COMBRGB_LEGACY, 0, "COMBRGB", CombineRGB, "Combine RGB", "" )
-DefNode(ShaderNode, SH_NODE_HUE_SAT, 0, "HUE_SAT", HueSaturation, "Hue/Saturation", "" )
+DefNode(ShaderNode, SH_NODE_HUE_SAT, 0, "HUE_SAT", HueSaturation, "Hue Saturation Value", "" )
DefNode(ShaderNode, SH_NODE_OUTPUT_MATERIAL, def_sh_output, "OUTPUT_MATERIAL", OutputMaterial, "Material Output", "" )
DefNode(ShaderNode, SH_NODE_EEVEE_SPECULAR, 0, "EEVEE_SPECULAR", EeveeSpecular, "Specular BSDF", "" )
@@ -216,7 +216,7 @@ 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_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(CompositorNode, CMP_NODE_COMBINE_XYZ, 0, "COMBINE_XYZ", CombineXYZ, "Combine XYZ", "" )
DefNode(CompositorNode, CMP_NODE_SEPARATE_XYZ, 0, "SEPARATE_XYZ", SeparateXYZ, "Separate XYZ", "" )
@@ -234,7 +234,7 @@ DefNode(TextureNode, TEX_NODE_VALTORGB, def_colorramp, "VALTOR
DefNode(TextureNode, TEX_NODE_IMAGE, def_tex_image, "IMAGE", Image, "Image", "" )
DefNode(TextureNode, TEX_NODE_CURVE_RGB, def_rgb_curve, "CURVE_RGB", CurveRGB, "RGB Curves", "" )
DefNode(TextureNode, TEX_NODE_INVERT, 0, "INVERT", Invert, "Invert", "" )
-DefNode(TextureNode, TEX_NODE_HUE_SAT, 0, "HUE_SAT", HueSaturation, "Hue/Saturation", "" )
+DefNode(TextureNode, TEX_NODE_HUE_SAT, 0, "HUE_SAT", HueSaturation, "Hue Saturation Value", "" )
DefNode(TextureNode, TEX_NODE_CURVE_TIME, def_time, "CURVE_TIME", CurveTime, "Curve Time", "" )
DefNode(TextureNode, TEX_NODE_ROTATE, 0, "ROTATE", Rotate, "Rotate", "" )
DefNode(TextureNode, TEX_NODE_VIEWER, 0, "VIEWER", Viewer, "Viewer", "" )
@@ -318,6 +318,8 @@ DefNode(GeometryNode, GEO_NODE_INPUT_CURVE_HANDLES, 0, "INPUT_CURVE_HANDLES", In
DefNode(GeometryNode, GEO_NODE_INPUT_CURVE_TILT, 0, "INPUT_CURVE_TILT", InputCurveTilt, "Curve Tilt", "")
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_INSTANCE_ROTATION, 0, "INPUT_INSTANCE_ROTATION", InputInstanceRotation, "Instance Rotation", "")
+DefNode(GeometryNode, GEO_NODE_INPUT_INSTANCE_SCALE, 0, "INPUT_INSTANCE_SCALE", InputInstanceScale, "Instance Scale", "")
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", "")
@@ -395,6 +397,7 @@ DefNode(GeometryNode, GEO_NODE_TRANSLATE_INSTANCES, 0, "TRANSLATE_INSTANCES", Tr
DefNode(GeometryNode, GEO_NODE_TRIANGULATE, def_geo_triangulate, "TRIANGULATE", Triangulate, "Triangulate", "")
DefNode(GeometryNode, GEO_NODE_TRIM_CURVE, def_geo_curve_trim, "TRIM_CURVE", TrimCurve, "Trim Curve", "")
DefNode(GeometryNode, GEO_NODE_VIEWER, def_geo_viewer, "VIEWER", Viewer, "Viewer", "")
+DefNode(GeometryNode, GEO_NODE_VOLUME_CUBE, 0, "VOLUME_CUBE", VolumeCube, "Volume Cube", "")
DefNode(GeometryNode, GEO_NODE_VOLUME_TO_MESH, def_geo_volume_to_mesh, "VOLUME_TO_MESH", VolumeToMesh, "Volume to Mesh", "")
DefNode(GeometryNode, GEO_NODE_DEFORM_CURVES_WITH_SURFACE, 0, "DEFORM_CURVES_WITH_SURFACE", DeformCurvesWithSurface, "Deform Curves with Surface", "")
diff --git a/source/blender/nodes/composite/nodes/node_composite_map_range.cc b/source/blender/nodes/composite/nodes/node_composite_map_range.cc
index 9b88e99060c..e52c6d096b9 100644
--- a/source/blender/nodes/composite/nodes/node_composite_map_range.cc
+++ b/source/blender/nodes/composite/nodes/node_composite_map_range.cc
@@ -18,9 +18,9 @@ static void cmp_node_map_range_declare(NodeDeclarationBuilder &b)
{
b.add_input<decl::Float>(N_("Value")).default_value(1.0f).min(0.0f).max(1.0f);
b.add_input<decl::Float>(N_("From Min")).default_value(0.0f).min(-10000.0f).max(10000.0f);
- b.add_input<decl::Float>(N_("From Max")).default_value(0.0f).min(-10000.0f).max(10000.0f);
+ b.add_input<decl::Float>(N_("From Max")).default_value(1.0f).min(-10000.0f).max(10000.0f);
b.add_input<decl::Float>(N_("To Min")).default_value(0.0f).min(-10000.0f).max(10000.0f);
- b.add_input<decl::Float>(N_("To Max")).default_value(0.0f).min(-10000.0f).max(10000.0f);
+ b.add_input<decl::Float>(N_("To Max")).default_value(1.0f).min(-10000.0f).max(10000.0f);
b.add_output<decl::Float>(N_("Value"));
}
diff --git a/source/blender/nodes/function/nodes/node_fn_compare.cc b/source/blender/nodes/function/nodes/node_fn_compare.cc
index 7bc9d2d79e8..e3f13dc7d6b 100644
--- a/source/blender/nodes/function/nodes/node_fn_compare.cc
+++ b/source/blender/nodes/function/nodes/node_fn_compare.cc
@@ -487,7 +487,7 @@ static const fn::MultiFunction *get_multi_function(bNode &node)
static fn::CustomMF_SI_SI_SI_SO<float3, float3, float, bool> fn{
"Not Equal - Element-wise",
[](float3 a, float3 b, float epsilon) {
- return abs(a.x - b.x) > epsilon && abs(a.y - b.y) > epsilon &&
+ return abs(a.x - b.x) > epsilon || abs(a.y - b.y) > epsilon ||
abs(a.z - b.z) > epsilon;
},
exec_preset_first_two};
@@ -522,7 +522,7 @@ static const fn::MultiFunction *get_multi_function(bNode &node)
static fn::CustomMF_SI_SI_SI_SO<ColorGeometry4f, ColorGeometry4f, float, bool> fn{
"Not Equal",
[](ColorGeometry4f a, ColorGeometry4f b, float epsilon) {
- return abs(a.r - b.r) > epsilon && abs(a.g - b.g) > epsilon &&
+ return abs(a.r - b.r) > epsilon || abs(a.g - b.g) > epsilon ||
abs(a.b - b.b) > epsilon;
},
exec_preset_first_two};
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 a0942ced1be..360695299cb 100644
--- a/source/blender/nodes/function/nodes/node_fn_random_value.cc
+++ b/source/blender/nodes/function/nodes/node_fn_random_value.cc
@@ -57,7 +57,7 @@ static void fn_node_random_value_init(bNodeTree *UNUSED(tree), bNode *node)
static void fn_node_random_value_update(bNodeTree *ntree, bNode *node)
{
const NodeRandomValue &storage = node_storage(*node);
- const CustomDataType data_type = static_cast<CustomDataType>(storage.data_type);
+ const eCustomDataType data_type = static_cast<eCustomDataType>(storage.data_type);
bNodeSocket *sock_min_vector = (bNodeSocket *)node->inputs.first;
bNodeSocket *sock_max_vector = sock_min_vector->next;
@@ -86,7 +86,7 @@ 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)
+static std::optional<eCustomDataType> node_type_from_other_socket(const bNodeSocket &socket)
{
switch (socket.type) {
case SOCK_FLOAT:
@@ -106,7 +106,7 @@ static std::optional<CustomDataType> node_type_from_other_socket(const bNodeSock
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());
+ const std::optional<eCustomDataType> type = node_type_from_other_socket(params.other_socket());
if (!type) {
return;
}
@@ -137,7 +137,7 @@ static void fn_node_random_value_gather_link_search(GatherLinkSearchOpParams &pa
static void fn_node_random_value_build_multi_function(NodeMultiFunctionBuilder &builder)
{
const NodeRandomValue &storage = node_storage(builder.node());
- const CustomDataType data_type = static_cast<CustomDataType>(storage.data_type);
+ const eCustomDataType data_type = static_cast<eCustomDataType>(storage.data_type);
switch (data_type) {
case CD_PROP_FLOAT3: {
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 6abcc79cf29..4b493438a45 100644
--- a/source/blender/nodes/function/nodes/node_fn_replace_string.cc
+++ b/source/blender/nodes/function/nodes/node_fn_replace_string.cc
@@ -15,19 +15,17 @@ static void fn_node_replace_string_declare(NodeDeclarationBuilder &b)
b.add_output<decl::String>(N_("String"));
}
-static std::string replace_all(std::string str, const std::string &from, const std::string &to)
+static std::string replace_all(const StringRefNull str,
+ const StringRefNull from,
+ const StringRefNull to)
{
- if (from.length() <= 0) {
+ if (from.is_empty()) {
return str;
}
- const size_t step = to.length() > 0 ? to.length() : 1;
-
- size_t offset = 0;
- while ((offset = str.find(from, offset)) != std::string::npos) {
- str.replace(offset, from.length(), to);
- offset += step;
- }
- return str;
+ char *new_str_ptr = BLI_str_replaceN(str.c_str(), from.c_str(), to.c_str());
+ std::string new_str{new_str_ptr};
+ MEM_freeN(new_str_ptr);
+ return new_str;
}
static void fn_node_replace_string_build_multi_function(NodeMultiFunctionBuilder &builder)
diff --git a/source/blender/nodes/geometry/CMakeLists.txt b/source/blender/nodes/geometry/CMakeLists.txt
index 52fd5f49e8f..fba13db0a49 100644
--- a/source/blender/nodes/geometry/CMakeLists.txt
+++ b/source/blender/nodes/geometry/CMakeLists.txt
@@ -72,6 +72,8 @@ set(SRC
nodes/node_geo_input_curve_tilt.cc
nodes/node_geo_input_id.cc
nodes/node_geo_input_index.cc
+ nodes/node_geo_input_instance_rotation.cc
+ nodes/node_geo_input_instance_scale.cc
nodes/node_geo_input_material.cc
nodes/node_geo_input_material_index.cc
nodes/node_geo_input_mesh_edge_angle.cc
@@ -143,6 +145,7 @@ set(SRC
nodes/node_geo_translate_instances.cc
nodes/node_geo_triangulate.cc
nodes/node_geo_viewer.cc
+ nodes/node_geo_volume_cube.cc
nodes/node_geo_volume_to_mesh.cc
node_geometry_exec.cc
diff --git a/source/blender/nodes/geometry/node_geometry_tree.cc b/source/blender/nodes/geometry/node_geometry_tree.cc
index e081e007c81..38e914b9a9f 100644
--- a/source/blender/nodes/geometry/node_geometry_tree.cc
+++ b/source/blender/nodes/geometry/node_geometry_tree.cc
@@ -110,7 +110,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 = ICON_NODETREE;
+ tt->ui_icon = ICON_GEOMETRY_NODES;
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 7f9ec329efd..8f673d2264e 100644
--- a/source/blender/nodes/geometry/node_geometry_util.cc
+++ b/source/blender/nodes/geometry/node_geometry_util.cc
@@ -14,7 +14,7 @@
namespace blender::nodes {
-std::optional<CustomDataType> node_data_type_to_custom_data_type(const eNodeSocketDatatype type)
+std::optional<eCustomDataType> node_data_type_to_custom_data_type(const eNodeSocketDatatype type)
{
switch (type) {
case SOCK_FLOAT:
@@ -34,7 +34,7 @@ std::optional<CustomDataType> node_data_type_to_custom_data_type(const eNodeSock
}
}
-std::optional<CustomDataType> node_socket_to_custom_data_type(const bNodeSocket &socket)
+std::optional<eCustomDataType> node_socket_to_custom_data_type(const bNodeSocket &socket)
{
return node_data_type_to_custom_data_type(static_cast<eNodeSocketDatatype>(socket.type));
}
diff --git a/source/blender/nodes/geometry/node_geometry_util.hh b/source/blender/nodes/geometry/node_geometry_util.hh
index 5b7211e44b4..efb7efaf1cc 100644
--- a/source/blender/nodes/geometry/node_geometry_util.hh
+++ b/source/blender/nodes/geometry/node_geometry_util.hh
@@ -57,8 +57,6 @@ Mesh *create_cylinder_or_cone_mesh(float radius_top,
GeometryNodeMeshCircleFillType fill_type,
ConeAttributeOutputs &attribute_outputs);
-Mesh *create_cuboid_mesh(float3 size, int verts_x, int verts_y, int verts_z);
-
/**
* Copies the point domain attributes from `in_component` that are in the mask to `out_component`.
*/
@@ -72,13 +70,12 @@ void copy_point_attributes_based_on_mask(const GeometryComponent &in_component,
* component. If no component can work with the domain, then `error_message` is set to true.
*/
void separate_geometry(GeometrySet &geometry_set,
- AttributeDomain domain,
+ eAttrDomain domain,
GeometryNodeDeleteGeometryMode mode,
const Field<bool> &selection_field,
- bool invert,
bool &r_is_error);
-std::optional<CustomDataType> node_data_type_to_custom_data_type(eNodeSocketDatatype type);
-std::optional<CustomDataType> node_socket_to_custom_data_type(const bNodeSocket &socket);
+std::optional<eCustomDataType> node_data_type_to_custom_data_type(eNodeSocketDatatype type);
+std::optional<eCustomDataType> node_socket_to_custom_data_type(const bNodeSocket &socket);
} // namespace blender::nodes
diff --git a/source/blender/nodes/geometry/nodes/node_geo_accumulate_field.cc b/source/blender/nodes/geometry/nodes/node_geo_accumulate_field.cc
index ea26eec0c15..a7404af8564 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_accumulate_field.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_accumulate_field.cc
@@ -87,7 +87,7 @@ static void node_init(bNodeTree *UNUSED(tree), bNode *node)
static void node_update(bNodeTree *ntree, bNode *node)
{
const NodeAccumulateField &storage = node_storage(*node);
- const CustomDataType data_type = static_cast<CustomDataType>(storage.data_type);
+ const eCustomDataType data_type = static_cast<eCustomDataType>(storage.data_type);
bNodeSocket *sock_in_vector = (bNodeSocket *)node->inputs.first;
bNodeSocket *sock_in_float = sock_in_vector->next;
@@ -123,7 +123,7 @@ static void node_update(bNodeTree *ntree, bNode *node)
enum class AccumulationMode { Leading = 0, Trailing = 1 };
-static std::optional<CustomDataType> node_type_from_other_socket(const bNodeSocket &socket)
+static std::optional<eCustomDataType> node_type_from_other_socket(const bNodeSocket &socket)
{
switch (socket.type) {
case SOCK_FLOAT:
@@ -141,7 +141,7 @@ static std::optional<CustomDataType> node_type_from_other_socket(const bNodeSock
static void node_gather_link_searches(GatherLinkSearchOpParams &params)
{
- const std::optional<CustomDataType> type = node_type_from_other_socket(params.other_socket());
+ const std::optional<eCustomDataType> type = node_type_from_other_socket(params.other_socket());
if (!type) {
return;
}
@@ -196,11 +196,11 @@ template<typename T> class AccumulateFieldInput final : public GeometryFieldInpu
private:
Field<T> input_;
Field<int> group_index_;
- AttributeDomain source_domain_;
+ eAttrDomain source_domain_;
AccumulationMode accumulation_mode_;
public:
- AccumulateFieldInput(const AttributeDomain source_domain,
+ AccumulateFieldInput(const eAttrDomain source_domain,
Field<T> input,
Field<int> group_index,
AccumulationMode accumulation_mode)
@@ -213,20 +213,20 @@ template<typename T> class AccumulateFieldInput final : public GeometryFieldInpu
}
GVArray get_varray_for_context(const GeometryComponent &component,
- const AttributeDomain domain,
+ const eAttrDomain domain,
IndexMask UNUSED(mask)) const final
{
const GeometryComponentFieldContext field_context{component, source_domain_};
- const int domain_size = component.attribute_domain_size(field_context.domain());
+ const int domain_num = component.attribute_domain_num(field_context.domain());
- fn::FieldEvaluator evaluator{field_context, domain_size};
+ fn::FieldEvaluator evaluator{field_context, domain_num};
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);
+ Array<T> accumulations_out(domain_num);
if (group_indices.is_single()) {
T accumulation = T();
@@ -287,10 +287,10 @@ template<typename T> class TotalFieldInput final : public GeometryFieldInput {
private:
Field<T> input_;
Field<int> group_index_;
- AttributeDomain source_domain_;
+ eAttrDomain source_domain_;
public:
- TotalFieldInput(const AttributeDomain source_domain, Field<T> input, Field<int> group_index)
+ TotalFieldInput(const eAttrDomain source_domain, Field<T> input, Field<int> group_index)
: GeometryFieldInput(CPPType::get<T>(), "Total Value"),
input_(input),
group_index_(group_index),
@@ -299,13 +299,13 @@ template<typename T> class TotalFieldInput final : public GeometryFieldInput {
}
GVArray get_varray_for_context(const GeometryComponent &component,
- const AttributeDomain domain,
+ const eAttrDomain domain,
IndexMask UNUSED(mask)) const final
{
const GeometryComponentFieldContext field_context{component, source_domain_};
- const int domain_size = component.attribute_domain_size(field_context.domain());
+ const int domain_num = component.attribute_domain_num(field_context.domain());
- fn::FieldEvaluator evaluator{field_context, domain_size};
+ fn::FieldEvaluator evaluator{field_context, domain_num};
evaluator.add(input_);
evaluator.add(group_index_);
evaluator.evaluate();
@@ -317,10 +317,10 @@ template<typename T> class TotalFieldInput final : public GeometryFieldInput {
for (const int i : values.index_range()) {
accumulation = values[i] + accumulation;
}
- return VArray<T>::ForSingle(accumulation, domain_size);
+ return VArray<T>::ForSingle(accumulation, domain_num);
}
- Array<T> accumulations_out(domain_size);
+ Array<T> accumulations_out(domain_num);
Map<int, T> accumulations;
for (const int i : values.index_range()) {
T &value = accumulations.lookup_or_add_default(group_indices[i]);
@@ -365,8 +365,8 @@ template<typename T> std::string identifier_suffix()
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);
+ const eCustomDataType data_type = static_cast<eCustomDataType>(storage.data_type);
+ const eAttrDomain source_domain = static_cast<eAttrDomain>(storage.domain);
Field<int> group_index_field = params.extract_input<Field<int>>("Group Index");
attribute_math::convert_to_static_type(data_type, [&](auto dummy) {
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 45a6aabeb03..496fb081d6b 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_attribute_capture.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_attribute_capture.cc
@@ -50,7 +50,7 @@ static void node_init(bNodeTree *UNUSED(tree), bNode *node)
static void node_update(bNodeTree *ntree, bNode *node)
{
const NodeGeometryAttributeCapture &storage = node_storage(*node);
- const CustomDataType data_type = static_cast<CustomDataType>(storage.data_type);
+ const eCustomDataType data_type = static_cast<eCustomDataType>(storage.data_type);
bNodeSocket *socket_value_geometry = (bNodeSocket *)node->inputs.first;
bNodeSocket *socket_value_vector = socket_value_geometry->next;
@@ -86,7 +86,7 @@ static void node_gather_link_searches(GatherLinkSearchOpParams &params)
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(
+ const std::optional<eCustomDataType> 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) {
@@ -108,14 +108,14 @@ static void node_gather_link_searches(GatherLinkSearchOpParams &params)
static void try_capture_field_on_geometry(GeometryComponent &component,
const AttributeIDRef &attribute_id,
- const AttributeDomain domain,
+ const eAttrDomain domain,
const GField &field)
{
GeometryComponentFieldContext field_context{component, domain};
- const int domain_size = component.attribute_domain_size(domain);
- const IndexMask mask{IndexMask(domain_size)};
+ const int domain_num = component.attribute_domain_num(domain);
+ const IndexMask mask{IndexMask(domain_num)};
- const CustomDataType data_type = bke::cpp_type_to_custom_data_type(field.cpp_type());
+ const eCustomDataType data_type = bke::cpp_type_to_custom_data_type(field.cpp_type());
OutputAttribute output_attribute = component.attribute_try_get_for_output_only(
attribute_id, domain, data_type);
@@ -126,30 +126,66 @@ static void try_capture_field_on_geometry(GeometryComponent &component,
output_attribute.save();
}
+static StringRefNull identifier_suffix(eCustomDataType data_type)
+{
+ switch (data_type) {
+ case CD_PROP_FLOAT:
+ return "_001";
+ case CD_PROP_INT32:
+ return "_004";
+ case CD_PROP_COLOR:
+ return "_002";
+ case CD_PROP_BOOL:
+ return "_003";
+ case CD_PROP_FLOAT3:
+ return "";
+ default:
+ BLI_assert_unreachable();
+ return "";
+ }
+}
+
static void node_geo_exec(GeoNodeExecParams params)
{
GeometrySet geometry_set = params.extract_input<GeometrySet>("Geometry");
+ if (!params.output_is_required("Geometry")) {
+ params.error_message_add(
+ NodeWarningType::Info,
+ TIP_("The attribute output can not be used without the geometry output"));
+ params.set_default_remaining_outputs();
+ return;
+ }
+
const NodeGeometryAttributeCapture &storage = node_storage(params.node());
- const CustomDataType data_type = static_cast<CustomDataType>(storage.data_type);
- const AttributeDomain domain = static_cast<AttributeDomain>(storage.domain);
+ const eCustomDataType data_type = static_cast<eCustomDataType>(storage.data_type);
+ const eAttrDomain domain = static_cast<eAttrDomain>(storage.domain);
+ const std::string output_identifier = "Attribute" + identifier_suffix(data_type);
+
+ if (!params.output_is_required(output_identifier)) {
+ params.set_output("Geometry", geometry_set);
+ return;
+ }
+
+ const std::string input_identifier = "Value" + identifier_suffix(data_type);
GField field;
+
switch (data_type) {
case CD_PROP_FLOAT:
- field = params.get_input<Field<float>>("Value_001");
+ field = params.get_input<Field<float>>(input_identifier);
break;
case CD_PROP_FLOAT3:
- field = params.get_input<Field<float3>>("Value");
+ field = params.get_input<Field<float3>>(input_identifier);
break;
case CD_PROP_COLOR:
- field = params.get_input<Field<ColorGeometry4f>>("Value_002");
+ field = params.get_input<Field<ColorGeometry4f>>(input_identifier);
break;
case CD_PROP_BOOL:
- field = params.get_input<Field<bool>>("Value_003");
+ field = params.get_input<Field<bool>>(input_identifier);
break;
case CD_PROP_INT32:
- field = params.get_input<Field<int>>("Value_004");
+ field = params.get_input<Field<int>>(input_identifier);
break;
default:
break;
@@ -185,23 +221,23 @@ static void node_geo_exec(GeoNodeExecParams params)
switch (data_type) {
case CD_PROP_FLOAT: {
- params.set_output("Attribute_001", Field<float>(output_field));
+ params.set_output(output_identifier, Field<float>(output_field));
break;
}
case CD_PROP_FLOAT3: {
- params.set_output("Attribute", Field<float3>(output_field));
+ params.set_output(output_identifier, Field<float3>(output_field));
break;
}
case CD_PROP_COLOR: {
- params.set_output("Attribute_002", Field<ColorGeometry4f>(output_field));
+ params.set_output(output_identifier, Field<ColorGeometry4f>(output_field));
break;
}
case CD_PROP_BOOL: {
- params.set_output("Attribute_003", Field<bool>(output_field));
+ params.set_output(output_identifier, Field<bool>(output_field));
break;
}
case CD_PROP_INT32: {
- params.set_output("Attribute_004", Field<int>(output_field));
+ params.set_output(output_identifier, Field<int>(output_field));
break;
}
default:
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 b3fe9d160b3..8ab0eb678e7 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
@@ -72,11 +72,11 @@ static void node_geo_exec(GeoNodeExecParams params)
case GEO_COMPONENT_TYPE_MESH: {
if (geometry_set.has_mesh()) {
const MeshComponent *component = geometry_set.get_component_for_read<MeshComponent>();
- params.set_output("Point Count", component->attribute_domain_size(ATTR_DOMAIN_POINT));
- params.set_output("Edge Count", component->attribute_domain_size(ATTR_DOMAIN_EDGE));
- params.set_output("Face Count", component->attribute_domain_size(ATTR_DOMAIN_FACE));
+ params.set_output("Point Count", component->attribute_domain_num(ATTR_DOMAIN_POINT));
+ params.set_output("Edge Count", component->attribute_domain_num(ATTR_DOMAIN_EDGE));
+ params.set_output("Face Count", component->attribute_domain_num(ATTR_DOMAIN_FACE));
params.set_output("Face Corner Count",
- component->attribute_domain_size(ATTR_DOMAIN_CORNER));
+ component->attribute_domain_num(ATTR_DOMAIN_CORNER));
}
else {
params.set_default_remaining_outputs();
@@ -86,8 +86,8 @@ static void node_geo_exec(GeoNodeExecParams params)
case GEO_COMPONENT_TYPE_CURVE: {
if (geometry_set.has_curves()) {
const CurveComponent *component = geometry_set.get_component_for_read<CurveComponent>();
- params.set_output("Point Count", component->attribute_domain_size(ATTR_DOMAIN_POINT));
- params.set_output("Spline Count", component->attribute_domain_size(ATTR_DOMAIN_CURVE));
+ params.set_output("Point Count", component->attribute_domain_num(ATTR_DOMAIN_POINT));
+ params.set_output("Spline Count", component->attribute_domain_num(ATTR_DOMAIN_CURVE));
}
else {
params.set_default_remaining_outputs();
@@ -98,7 +98,7 @@ static void node_geo_exec(GeoNodeExecParams params)
if (geometry_set.has_pointcloud()) {
const PointCloudComponent *component =
geometry_set.get_component_for_read<PointCloudComponent>();
- params.set_output("Point Count", component->attribute_domain_size(ATTR_DOMAIN_POINT));
+ params.set_output("Point Count", component->attribute_domain_num(ATTR_DOMAIN_POINT));
}
else {
params.set_default_remaining_outputs();
@@ -109,8 +109,7 @@ static void node_geo_exec(GeoNodeExecParams params)
if (geometry_set.has_instances()) {
const InstancesComponent *component =
geometry_set.get_component_for_read<InstancesComponent>();
- params.set_output("Instance Count",
- component->attribute_domain_size(ATTR_DOMAIN_INSTANCE));
+ params.set_output("Instance Count", component->attribute_domain_num(ATTR_DOMAIN_INSTANCE));
}
else {
params.set_default_remaining_outputs();
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 1153f18ffd4..35404725998 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_attribute_statistic.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_attribute_statistic.cc
@@ -77,7 +77,7 @@ static void node_update(bNodeTree *ntree, bNode *node)
bNodeSocket *socket_vector_std = socket_vector_range->next;
bNodeSocket *socket_vector_variance = socket_vector_std->next;
- const CustomDataType data_type = static_cast<CustomDataType>(node->custom1);
+ const eCustomDataType data_type = static_cast<eCustomDataType>(node->custom1);
nodeSetSocketAvailability(ntree, socket_float_attr, data_type == CD_PROP_FLOAT);
nodeSetSocketAvailability(ntree, socket_float_mean, data_type == CD_PROP_FLOAT);
@@ -100,7 +100,7 @@ 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)
+static std::optional<eCustomDataType> node_type_from_other_socket(const bNodeSocket &socket)
{
switch (socket.type) {
case SOCK_FLOAT:
@@ -121,7 +121,7 @@ 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(2));
- const std::optional<CustomDataType> type = node_type_from_other_socket(params.other_socket());
+ const std::optional<eCustomDataType> type = node_type_from_other_socket(params.other_socket());
if (!type) {
return;
}
@@ -184,8 +184,8 @@ static void node_geo_exec(GeoNodeExecParams params)
{
GeometrySet geometry_set = params.get_input<GeometrySet>("Geometry");
const bNode &node = params.node();
- const CustomDataType data_type = static_cast<CustomDataType>(node.custom1);
- const AttributeDomain domain = static_cast<AttributeDomain>(node.custom2);
+ const eCustomDataType data_type = static_cast<eCustomDataType>(node.custom1);
+ const eAttrDomain domain = static_cast<eAttrDomain>(node.custom2);
Vector<const GeometryComponent *> components = geometry_set.get_components_for_read();
const Field<bool> selection_field = params.get_input<Field<bool>>("Selection");
@@ -197,9 +197,9 @@ static void node_geo_exec(GeoNodeExecParams params)
for (const GeometryComponent *component : components) {
if (component->attribute_domain_supported(domain)) {
GeometryComponentFieldContext field_context{*component, domain};
- const int domain_size = component->attribute_domain_size(domain);
+ const int domain_num = component->attribute_domain_num(domain);
- fn::FieldEvaluator data_evaluator{field_context, domain_size};
+ fn::FieldEvaluator data_evaluator{field_context, domain_num};
data_evaluator.add(input_field);
data_evaluator.set_selection(selection_field);
data_evaluator.evaluate();
@@ -275,9 +275,9 @@ static void node_geo_exec(GeoNodeExecParams params)
for (const GeometryComponent *component : components) {
if (component->attribute_domain_supported(domain)) {
GeometryComponentFieldContext field_context{*component, domain};
- const int domain_size = component->attribute_domain_size(domain);
+ const int domain_num = component->attribute_domain_num(domain);
- fn::FieldEvaluator data_evaluator{field_context, domain_size};
+ fn::FieldEvaluator data_evaluator{field_context, domain_num};
data_evaluator.add(input_field);
data_evaluator.set_selection(selection_field);
data_evaluator.evaluate();
diff --git a/source/blender/nodes/geometry/nodes/node_geo_boolean.cc b/source/blender/nodes/geometry/nodes/node_geo_boolean.cc
index df2be8e7d37..daeca311e08 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_boolean.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_boolean.cc
@@ -20,6 +20,7 @@ static void node_declare(NodeDeclarationBuilder &b)
b.add_input<decl::Bool>(N_("Self Intersection"));
b.add_input<decl::Bool>(N_("Hole Tolerant"));
b.add_output<decl::Geometry>(N_("Mesh"));
+ b.add_output<decl::Bool>(N_("Intersecting Edges")).field_source();
}
static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
@@ -27,6 +28,10 @@ static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
uiItemR(layout, ptr, "operation", 0, "", ICON_NONE);
}
+struct AttributeOutputs {
+ StrongAnonymousAttributeID intersecting_edges_id;
+};
+
static void node_update(bNodeTree *ntree, bNode *node)
{
GeometryNodeBooleanOperation operation = (GeometryNodeBooleanOperation)node->custom1;
@@ -56,15 +61,11 @@ static void node_init(bNodeTree *UNUSED(tree), bNode *node)
static void node_geo_exec(GeoNodeExecParams params)
{
+#ifdef WITH_GMP
GeometryNodeBooleanOperation operation = (GeometryNodeBooleanOperation)params.node().custom1;
const bool use_self = params.get_input<bool>("Self Intersection");
const bool hole_tolerant = params.get_input<bool>("Hole Tolerant");
-#ifndef WITH_GMP
- params.error_message_add(NodeWarningType::Error,
- TIP_("Disabled, Blender was compiled without GMP"));
-#endif
-
Vector<const Mesh *> meshes;
Vector<const float4x4 *> transforms;
@@ -125,20 +126,57 @@ static void node_geo_exec(GeoNodeExecParams params)
}
}
- Mesh *result = blender::meshintersect::direct_mesh_boolean(meshes,
- transforms,
- float4x4::identity(),
- material_remaps,
- use_self,
- hole_tolerant,
- operation);
+ AttributeOutputs attribute_outputs;
+ if (params.output_is_required("Intersecting Edges")) {
+ attribute_outputs.intersecting_edges_id = StrongAnonymousAttributeID("Intersecting Edges");
+ }
+
+ Vector<int> intersecting_edges;
+ Mesh *result = blender::meshintersect::direct_mesh_boolean(
+ meshes,
+ transforms,
+ float4x4::identity(),
+ material_remaps,
+ use_self,
+ hole_tolerant,
+ operation,
+ attribute_outputs.intersecting_edges_id ? &intersecting_edges : nullptr);
+ if (!result) {
+ params.set_default_remaining_outputs();
+ return;
+ }
MEM_SAFE_FREE(result->mat);
result->mat = (Material **)MEM_malloc_arrayN(materials.size(), sizeof(Material *), __func__);
result->totcol = materials.size();
MutableSpan(result->mat, result->totcol).copy_from(materials);
+ /* Store intersecting edges in attribute. */
+ if (attribute_outputs.intersecting_edges_id) {
+ MeshComponent mesh_component;
+ mesh_component.replace(result, GeometryOwnershipType::Editable);
+ OutputAttribute_Typed<bool> attribute = mesh_component.attribute_try_get_for_output_only<bool>(
+ attribute_outputs.intersecting_edges_id.get(), ATTR_DOMAIN_EDGE);
+ MutableSpan<bool> selection = attribute.as_span();
+ selection.fill(false);
+ for (const int i : intersecting_edges) {
+ selection[i] = true;
+ }
+
+ attribute.save();
+
+ params.set_output(
+ "Intersecting Edges",
+ AnonymousAttributeFieldInput::Create<bool>(
+ std::move(attribute_outputs.intersecting_edges_id), params.attribute_producer_name()));
+ }
+
params.set_output("Mesh", GeometrySet::create_with_mesh(result));
+#else
+ params.error_message_add(NodeWarningType::Error,
+ TIP_("Disabled, Blender was compiled without GMP"));
+ params.set_default_remaining_outputs();
+#endif
}
} // namespace blender::nodes::node_geo_boolean_cc
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 558129fb384..00b10cc8a2f 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_bounding_box.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_bounding_box.cc
@@ -1,5 +1,7 @@
/* SPDX-License-Identifier: GPL-2.0-or-later */
+#include "GEO_mesh_primitive_cuboid.hh"
+
#include "node_geometry_util.hh"
namespace blender::nodes::node_geo_bounding_box_cc {
@@ -53,7 +55,7 @@ static void node_geo_exec(GeoNodeExecParams params)
else {
const float3 scale = sub_max - sub_min;
const float3 center = sub_min + scale / 2.0f;
- Mesh *mesh = create_cuboid_mesh(scale, 2, 2, 2);
+ Mesh *mesh = geometry::create_cuboid_mesh(scale, 2, 2, 2, "uv_map");
transform_mesh(*mesh, center, float3(0), float3(1));
sub_geometry.replace_mesh(mesh);
sub_geometry.keep_only({GEO_COMPONENT_TYPE_MESH, GEO_COMPONENT_TYPE_INSTANCES});
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 09d0f13c50d..31f706c497c 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_convex_hull.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_convex_hull.cc
@@ -138,14 +138,14 @@ static Mesh *compute_hull(const GeometrySet &geometry_set)
{
int span_count = 0;
int count = 0;
- int total_size = 0;
+ int total_num = 0;
Span<float3> positions_span;
if (geometry_set.has_mesh()) {
count++;
const MeshComponent *component = geometry_set.get_component_for_read<MeshComponent>();
- total_size += component->attribute_domain_size(ATTR_DOMAIN_POINT);
+ total_num += component->attribute_domain_num(ATTR_DOMAIN_POINT);
}
if (geometry_set.has_pointcloud()) {
@@ -155,7 +155,7 @@ static Mesh *compute_hull(const GeometrySet &geometry_set)
geometry_set.get_component_for_read<PointCloudComponent>();
VArray<float3> varray = component->attribute_get_for_read<float3>(
"position", ATTR_DOMAIN_POINT, {0, 0, 0});
- total_size += varray.size();
+ total_num += varray.size();
positions_span = varray.get_internal_span();
}
@@ -165,7 +165,7 @@ static Mesh *compute_hull(const GeometrySet &geometry_set)
const Curves &curves_id = *geometry_set.get_curves_for_read();
const bke::CurvesGeometry &curves = bke::CurvesGeometry::wrap(curves_id.geometry);
positions_span = curves.evaluated_positions();
- total_size += positions_span.size();
+ total_num += positions_span.size();
}
if (count == 0) {
@@ -178,7 +178,7 @@ static Mesh *compute_hull(const GeometrySet &geometry_set)
return hull_from_bullet(nullptr, positions_span);
}
- Array<float3> positions(total_size);
+ Array<float3> positions(total_num);
int offset = 0;
if (geometry_set.has_mesh()) {
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 bbc8758952d..b52bf2571b5 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
@@ -41,7 +41,7 @@ class EndpointFieldInput final : public GeometryFieldInput {
}
GVArray get_varray_for_context(const GeometryComponent &component,
- const AttributeDomain domain,
+ const eAttrDomain domain,
IndexMask UNUSED(mask)) const final
{
if (component.type() != GEO_COMPONENT_TYPE_CURVE || domain != ATTR_DOMAIN_POINT) {
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 95ea978541c..fb8a488ddae 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_curve_fillet.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_curve_fillet.cc
@@ -106,13 +106,13 @@ static float3 get_center(const float3 vec_pos2prev, const FilletData &fd, const
/* Calculate the direction vectors from each vertex to their previous vertex. */
static Array<float3> calculate_directions(const Span<float3> positions)
{
- const int size = positions.size();
- Array<float3> directions(size);
+ const int num = positions.size();
+ Array<float3> directions(num);
- for (const int i : IndexRange(size - 1)) {
+ for (const int i : IndexRange(num - 1)) {
directions[i] = math::normalize(positions[i + 1] - positions[i]);
}
- directions[size - 1] = math::normalize(positions[0] - positions[size - 1]);
+ directions[num - 1] = math::normalize(positions[0] - positions[num - 1]);
return directions;
}
@@ -120,11 +120,11 @@ static Array<float3> calculate_directions(const Span<float3> positions)
/* Calculate the axes around which the fillet is built. */
static Array<float3> calculate_axes(const Span<float3> directions)
{
- const int size = directions.size();
- Array<float3> axes(size);
+ const int num = directions.size();
+ Array<float3> axes(num);
- axes[0] = math::normalize(math::cross(-directions[size - 1], directions[0]));
- for (const int i : IndexRange(1, size - 1)) {
+ axes[0] = math::normalize(math::cross(-directions[num - 1], directions[0]));
+ for (const int i : IndexRange(1, num - 1)) {
axes[i] = math::normalize(math::cross(-directions[i - 1], directions[i]));
}
@@ -134,11 +134,11 @@ static Array<float3> calculate_axes(const Span<float3> directions)
/* Calculate the angle of the arc formed by the fillet. */
static Array<float> calculate_angles(const Span<float3> directions)
{
- const int size = directions.size();
- Array<float> angles(size);
+ const int num = directions.size();
+ Array<float> angles(num);
- angles[0] = M_PI - angle_v3v3(-directions[size - 1], directions[0]);
- for (const int i : IndexRange(1, size - 1)) {
+ angles[0] = M_PI - angle_v3v3(-directions[num - 1], directions[0]);
+ for (const int i : IndexRange(1, num - 1)) {
angles[i] = M_PI - angle_v3v3(-directions[i - 1], directions[i]);
}
@@ -147,18 +147,18 @@ static Array<float> calculate_angles(const Span<float3> directions)
/* Calculate the segment count in each filleted arc. */
static Array<int> calculate_counts(const FilletParam &fillet_param,
- const int size,
+ const int num,
const int spline_offset,
const bool cyclic)
{
- Array<int> counts(size, 1);
+ Array<int> counts(num, 1);
if (fillet_param.mode == GEO_NODE_CURVE_FILLET_POLY) {
- for (const int i : IndexRange(size)) {
+ for (const int i : IndexRange(num)) {
counts[i] = fillet_param.counts[spline_offset + i];
}
}
if (!cyclic) {
- counts[0] = counts[size - 1] = 0;
+ counts[0] = counts[num - 1] = 0;
}
return counts;
@@ -166,17 +166,17 @@ static Array<int> calculate_counts(const FilletParam &fillet_param,
/* Calculate the radii for the vertices to be filleted. */
static Array<float> calculate_radii(const FilletParam &fillet_param,
- const int size,
+ const int num,
const int spline_offset)
{
- Array<float> radii(size, 0.0f);
+ Array<float> radii(num, 0.0f);
if (fillet_param.limit_radius) {
- for (const int i : IndexRange(size)) {
+ for (const int i : IndexRange(num)) {
radii[i] = std::max(fillet_param.radii[spline_offset + i], 0.0f);
}
}
else {
- for (const int i : IndexRange(size)) {
+ for (const int i : IndexRange(num)) {
radii[i] = fillet_param.radii[spline_offset + i];
}
}
@@ -207,15 +207,15 @@ static FilletData calculate_fillet_data(const Spline &spline,
MutableSpan<int> point_counts,
const int spline_offset)
{
- const int size = spline.size();
+ const int num = spline.size();
FilletData fd;
fd.directions = calculate_directions(spline.positions());
fd.positions = spline.positions();
fd.axes = calculate_axes(fd.directions);
fd.angles = calculate_angles(fd.directions);
- fd.counts = calculate_counts(fillet_param, size, spline_offset, spline.is_cyclic());
- fd.radii = calculate_radii(fillet_param, size, spline_offset);
+ fd.counts = calculate_counts(fillet_param, num, spline_offset, spline.is_cyclic());
+ fd.radii = calculate_radii(fillet_param, num, spline_offset);
added_count = calculate_point_counts(point_counts, fd.radii, fd.counts);
@@ -229,19 +229,19 @@ static void limit_radii(FilletData &fd, const bool cyclic)
Span<float> angles(fd.angles);
Span<float3> positions(fd.positions);
- const int size = radii.size();
- const int fillet_count = cyclic ? size : size - 2;
+ const int num = radii.size();
+ const int fillet_count = cyclic ? num : num - 2;
const int start = cyclic ? 0 : 1;
- Array<float> max_radii(size, FLT_MAX);
+ Array<float> max_radii(num, FLT_MAX);
if (cyclic) {
/* Calculate lengths between adjacent control points. */
- const float len_prev = math::distance(positions[0], positions[size - 1]);
+ const float len_prev = math::distance(positions[0], positions[num - 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);
- const float tan_len_prev = radii[size - 1] * tan(angles[size - 1] / 2.0f);
+ const float tan_len_prev = radii[num - 1] * tan(angles[num - 1] / 2.0f);
const float tan_len_next = radii[1] * tan(angles[1] / 2.0f);
float factor_prev = 1.0f, factor_next = 1.0f;
@@ -255,12 +255,12 @@ static void limit_radii(FilletData &fd, const bool cyclic)
/* Scale max radii by calculated factors. */
max_radii[0] = radii[0] * std::min(factor_next, factor_prev);
max_radii[1] = radii[1] * factor_next;
- max_radii[size - 1] = radii[size - 1] * factor_prev;
+ max_radii[num - 1] = radii[num - 1] * factor_prev;
}
/* Initialize max_radii to largest possible radii. */
float prev_dist = math::distance(positions[1], positions[0]);
- for (const int i : IndexRange(1, size - 2)) {
+ for (const int i : IndexRange(1, num - 2)) {
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;
@@ -282,7 +282,7 @@ static void limit_radii(FilletData &fd, const bool cyclic)
}
/* Assign the max_radii to the fillet data's radii. */
- for (const int i : IndexRange(size)) {
+ for (const int i : IndexRange(num)) {
radii[i] = std::min(radii[i], max_radii[i]);
}
}
@@ -358,10 +358,10 @@ static void update_bezier_positions(const FilletData &fd,
Span<float3> positions(fd.positions);
Span<float3> directions(fd.directions);
- const int size = radii.size();
+ const int num = radii.size();
int i_dst = 0;
- for (const int i_src : IndexRange(size)) {
+ for (const int i_src : IndexRange(num)) {
const int count = point_counts[i_src];
/* Skip if the point count for the vertex is 1. */
@@ -385,7 +385,7 @@ static void update_bezier_positions(const FilletData &fd,
/* Position the end points of the arc and their handles. */
const int end_i = i_dst + count - 1;
- const float3 prev_dir = i_src == 0 ? -directions[size - 1] : -directions[i_src - 1];
+ const float3 prev_dir = i_src == 0 ? -directions[num - 1] : -directions[i_src - 1];
const float3 next_dir = directions[i_src];
dst_spline.positions()[i_dst] = positions[i_src] + displacement * prev_dir;
dst_spline.positions()[end_i] = positions[i_src] + displacement * next_dir;
@@ -442,10 +442,10 @@ static void update_poly_positions(const FilletData &fd,
Span<float3> positions(fd.positions);
Span<float3> directions(fd.directions);
- const int size = radii.size();
+ const int num = radii.size();
int i_dst = 0;
- for (const int i_src : IndexRange(size)) {
+ for (const int i_src : IndexRange(num)) {
const int count = point_counts[i_src];
/* Skip if the point count for the vertex is 1. */
@@ -460,7 +460,7 @@ static void update_poly_positions(const FilletData &fd,
/* Position the end points of the arc. */
const int end_i = i_dst + count - 1;
- const float3 prev_dir = i_src == 0 ? -directions[size - 1] : -directions[i_src - 1];
+ const float3 prev_dir = i_src == 0 ? -directions[num - 1] : -directions[i_src - 1];
const float3 next_dir = directions[i_src];
dst_spline.positions()[i_dst] = positions[i_src] + displacement * prev_dir;
dst_spline.positions()[end_i] = positions[i_src] + displacement * next_dir;
@@ -487,15 +487,15 @@ static SplinePtr fillet_spline(const Spline &spline,
const FilletParam &fillet_param,
const int spline_offset)
{
- const int size = spline.size();
+ const int num = spline.size();
const bool cyclic = spline.is_cyclic();
- if (size < 3) {
+ if (num < 3) {
return spline.copy();
}
/* Initialize the point_counts with 1s (at least one vertex on dst for each vertex on src). */
- Array<int> point_counts(size, 1);
+ Array<int> point_counts(num, 1);
int added_count = 0;
/* Update point_counts array and added_count. */
@@ -505,7 +505,7 @@ static SplinePtr fillet_spline(const Spline &spline,
limit_radii(fd, cyclic);
}
- const int total_points = added_count + size;
+ const int total_points = added_count + num;
const Array<int> dst_to_src = create_dst_to_src_map(point_counts, total_points);
SplinePtr dst_spline_ptr = spline.copy_only_settings();
(*dst_spline_ptr).resize(total_points);
@@ -581,8 +581,8 @@ static void calculate_curve_fillet(GeometrySet &geometry_set,
CurveComponent &component = geometry_set.get_component_for_write<CurveComponent>();
GeometryComponentFieldContext field_context{component, ATTR_DOMAIN_POINT};
- const int domain_size = component.attribute_domain_size(ATTR_DOMAIN_POINT);
- fn::FieldEvaluator field_evaluator{field_context, domain_size};
+ const int domain_num = component.attribute_domain_num(ATTR_DOMAIN_POINT);
+ fn::FieldEvaluator field_evaluator{field_context, domain_num};
field_evaluator.add(radius_field);
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 dc2b9d40894..5ef20f03f28 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
@@ -84,7 +84,7 @@ class HandleTypeFieldInput final : public GeometryFieldInput {
}
GVArray get_varray_for_context(const GeometryComponent &component,
- const AttributeDomain domain,
+ const eAttrDomain domain,
IndexMask mask) const final
{
if (component.type() != GEO_COMPONENT_TYPE_CURVE || domain != ATTR_DOMAIN_POINT) {
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 471d6af560f..78a132064ed 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_curve_resample.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_curve_resample.cc
@@ -1,12 +1,7 @@
/* SPDX-License-Identifier: GPL-2.0-or-later */
-#include "BLI_array.hh"
-#include "BLI_index_mask_ops.hh"
-#include "BLI_length_parameterize.hh"
-#include "BLI_task.hh"
-#include "BLI_timeit.hh"
+#include "GEO_resample_curves.hh"
-#include "BKE_attribute_math.hh"
#include "BKE_curves.hh"
#include "UI_interface.h"
@@ -56,495 +51,6 @@ static void node_update(bNodeTree *ntree, bNode *node)
nodeSetSocketAvailability(ntree, length_socket, mode == GEO_NODE_CURVE_RESAMPLE_LENGTH);
}
-/**
- * Return true if the attribute should be copied/interpolated to the result curves.
- * Don't output attributes that correspond to curve types that have no curves in the result.
- */
-static bool interpolate_attribute_to_curves(const AttributeIDRef &attribute_id,
- const std::array<int, CURVE_TYPES_NUM> &type_counts)
-{
- if (!attribute_id.is_named()) {
- return true;
- }
- if (ELEM(attribute_id.name(),
- "handle_type_left",
- "handle_type_right",
- "handle_left",
- "handle_right")) {
- return type_counts[CURVE_TYPE_BEZIER] != 0;
- }
- if (ELEM(attribute_id.name(), "nurbs_weight")) {
- return type_counts[CURVE_TYPE_NURBS] != 0;
- }
- return true;
-}
-
-/**
- * Return true if the attribute should be copied to poly curves.
- */
-static bool interpolate_attribute_to_poly_curve(const AttributeIDRef &attribute_id)
-{
- static const Set<StringRef> no_interpolation{{
- "handle_type_left",
- "handle_type_right",
- "handle_position_right",
- "handle_position_left",
- "nurbs_weight",
- }};
- return !(attribute_id.is_named() && no_interpolation.contains(attribute_id.name()));
-}
-
-/**
- * Retrieve spans from source and result attributes.
- */
-static void retrieve_attribute_spans(const Span<AttributeIDRef> ids,
- const CurveComponent &src_component,
- CurveComponent &dst_component,
- Vector<GSpan> &src,
- Vector<GMutableSpan> &dst,
- Vector<OutputAttribute> &dst_attributes)
-{
- for (const int i : ids.index_range()) {
- GVArray src_attribute = src_component.attribute_try_get_for_read(ids[i], ATTR_DOMAIN_POINT);
- BLI_assert(src_attribute);
- src.append(src_attribute.get_internal_span());
-
- const CustomDataType data_type = bke::cpp_type_to_custom_data_type(src_attribute.type());
- OutputAttribute dst_attribute = dst_component.attribute_try_get_for_output_only(
- ids[i], ATTR_DOMAIN_POINT, data_type);
- dst.append(dst_attribute.as_span());
- dst_attributes.append(std::move(dst_attribute));
- }
-}
-
-struct AttributesForInterpolation : NonCopyable, NonMovable {
- Vector<GSpan> src;
- Vector<GMutableSpan> dst;
-
- Vector<OutputAttribute> dst_attributes;
-
- Vector<GSpan> src_no_interpolation;
- Vector<GMutableSpan> dst_no_interpolation;
-};
-
-/**
- * Gather a set of all generic attribute IDs to copy to the result curves.
- */
-static void gather_point_attributes_to_interpolate(const CurveComponent &src_component,
- CurveComponent &dst_component,
- AttributesForInterpolation &result)
-{
- const Curves &dst_curves_id = *dst_component.get_for_read();
- const bke::CurvesGeometry &dst_curves = bke::CurvesGeometry::wrap(dst_curves_id.geometry);
-
- VectorSet<AttributeIDRef> ids;
- VectorSet<AttributeIDRef> ids_no_interpolation;
- src_component.attribute_foreach(
- [&](const AttributeIDRef &id, const AttributeMetaData meta_data) {
- if (meta_data.domain != ATTR_DOMAIN_POINT) {
- return true;
- }
- if (!interpolate_attribute_to_curves(id, dst_curves.curve_type_counts())) {
- return true;
- }
- if (interpolate_attribute_to_poly_curve(id)) {
- ids.add_new(id);
- }
- else {
- ids_no_interpolation.add_new(id);
- }
- return true;
- });
-
- /* Position is handled differently since it has non-generic interpolation for Bezier
- * curves and because the evaluated positions are cached for each evaluated point. */
- ids.remove_contained("position");
-
- retrieve_attribute_spans(
- ids, src_component, dst_component, result.src, result.dst, result.dst_attributes);
-
- /* Attributes that aren't interpolated like Bezier handles still have to be be copied
- * to the result when there are any unselected curves of the corresponding type. */
- retrieve_attribute_spans(ids_no_interpolation,
- src_component,
- dst_component,
- result.src_no_interpolation,
- result.dst_no_interpolation,
- result.dst_attributes);
-}
-
-/**
- * Copy the provided point attribute values between all curves in the #curve_ranges index
- * ranges, assuming that all curves are the same size in #src_curves and #dst_curves.
- */
-template<typename T>
-static void copy_between_curves(const bke::CurvesGeometry &src_curves,
- const bke::CurvesGeometry &dst_curves,
- const Span<IndexRange> curve_ranges,
- const Span<T> src,
- const MutableSpan<T> dst)
-{
- threading::parallel_for(curve_ranges.index_range(), 512, [&](IndexRange range) {
- for (const IndexRange range : curve_ranges.slice(range)) {
- const IndexRange src_points = src_curves.points_for_curves(range);
- const IndexRange dst_points = dst_curves.points_for_curves(range);
- /* The arrays might be large, so a threaded copy might make sense here too. */
- dst.slice(dst_points).copy_from(src.slice(src_points));
- }
- });
-}
-static void copy_between_curves(const bke::CurvesGeometry &src_curves,
- const bke::CurvesGeometry &dst_curves,
- const Span<IndexRange> unselected_ranges,
- const GSpan src,
- const GMutableSpan dst)
-{
- attribute_math::convert_to_static_type(src.type(), [&](auto dummy) {
- using T = decltype(dummy);
- copy_between_curves(src_curves, dst_curves, unselected_ranges, src.typed<T>(), dst.typed<T>());
- });
-}
-
-/**
- * Copy the size of every curve in #curve_ranges to the corresponding index in #counts.
- */
-static void fill_curve_counts(const bke::CurvesGeometry &src_curves,
- const Span<IndexRange> curve_ranges,
- MutableSpan<int> counts)
-{
- threading::parallel_for(curve_ranges.index_range(), 512, [&](IndexRange ranges_range) {
- for (const IndexRange curves_range : curve_ranges.slice(ranges_range)) {
- for (const int i : curves_range) {
- counts[i] = src_curves.points_for_curve(i).size();
- }
- }
- });
-}
-
-/**
- * Turn an array of sizes into the offset at each index including all previous sizes.
- */
-static void accumulate_counts_to_offsets(MutableSpan<int> counts_to_offsets)
-{
- int total = 0;
- for (const int i : counts_to_offsets.index_range().drop_back(1)) {
- const int count = counts_to_offsets[i];
- BLI_assert(count > 0);
- counts_to_offsets[i] = total;
- total += count;
- }
- counts_to_offsets.last() = total;
-}
-
-/**
- * Create new curves where the selected curves have been resampled with a number of uniform-length
- * samples defined by the count field. Interpolate attributes to the result, with an accuracy that
- * depends on the curve's resolution parameter.
- *
- * \warning The values provided by the #count_field must be 1 or greater.
- * \warning Curves with no evaluated points must not be selected.
- */
-static Curves *resample_to_uniform_count(const CurveComponent &src_component,
- const Field<bool> &selection_field,
- const Field<int> &count_field)
-{
- const Curves &src_curves_id = *src_component.get_for_read();
- const bke::CurvesGeometry &src_curves = bke::CurvesGeometry::wrap(src_curves_id.geometry);
-
- /* Create the new curves without any points and evaluate the final count directly
- * into the offsets array, in order to be accumulated into offsets later. */
- Curves *dst_curves_id = bke::curves_new_nomain(0, src_curves.curves_num());
- bke::CurvesGeometry &dst_curves = bke::CurvesGeometry::wrap(dst_curves_id->geometry);
- CurveComponent dst_component;
- dst_component.replace(dst_curves_id, GeometryOwnershipType::Editable);
- /* Directly copy curve attributes, since they stay the same (except for curve types). */
- CustomData_copy(&src_curves.curve_data,
- &dst_curves.curve_data,
- CD_MASK_ALL,
- CD_DUPLICATE,
- src_curves.curves_num());
- MutableSpan<int> dst_offsets = dst_curves.offsets_for_write();
-
- GeometryComponentFieldContext field_context{src_component, ATTR_DOMAIN_CURVE};
- fn::FieldEvaluator evaluator{field_context, src_curves.curves_num()};
- evaluator.set_selection(selection_field);
- evaluator.add_with_destination(count_field, dst_offsets);
- evaluator.evaluate();
- const IndexMask selection = evaluator.get_evaluated_selection_as_mask();
- const Vector<IndexRange> unselected_ranges = selection.extract_ranges_invert(
- src_curves.curves_range(), nullptr);
-
- /* Fill the counts for the curves that aren't selected and accumulate the counts into offsets. */
- fill_curve_counts(src_curves, unselected_ranges, dst_offsets);
- accumulate_counts_to_offsets(dst_offsets);
- dst_curves.resize(dst_offsets.last(), dst_curves.curves_num());
-
- /* All resampled curves are poly curves. */
- dst_curves.fill_curve_types(selection, CURVE_TYPE_POLY);
-
- VArray<bool> curves_cyclic = src_curves.cyclic();
- VArray<int8_t> curve_types = src_curves.curve_types();
- Span<float3> evaluated_positions = src_curves.evaluated_positions();
- MutableSpan<float3> dst_positions = dst_curves.positions_for_write();
-
- AttributesForInterpolation attributes;
- gather_point_attributes_to_interpolate(src_component, dst_component, attributes);
-
- src_curves.ensure_evaluated_lengths();
-
- /* Sampling arbitrary attributes works by first interpolating them to the curve's standard
- * "evaluated points" and then interpolating that result with the uniform samples. This is
- * potentially wasteful when down-sampling a curve to many fewer points. There are two possible
- * solutions: only sample the necessary points for interpolation, or first sample curve
- * parameter/segment indices and evaluate the curve directly. */
- Array<int> sample_indices(dst_curves.points_num());
- Array<float> sample_factors(dst_curves.points_num());
-
- /* Use a "for each group of curves: for each attribute: for each curve" pattern to work on
- * smaller sections of data that ideally fit into CPU cache better than simply one attribute at a
- * time or one curve at a time. */
- threading::parallel_for(selection.index_range(), 512, [&](IndexRange selection_range) {
- const IndexMask sliced_selection = selection.slice(selection_range);
-
- Vector<std::byte> evaluated_buffer;
-
- /* Gather uniform samples based on the accumulated lengths of the original curve. */
- for (const int i_curve : sliced_selection) {
- const bool cyclic = curves_cyclic[i_curve];
- const IndexRange dst_points = dst_curves.points_for_curve(i_curve);
- length_parameterize::create_uniform_samples(
- src_curves.evaluated_lengths_for_curve(i_curve, cyclic),
- curves_cyclic[i_curve],
- sample_indices.as_mutable_span().slice(dst_points),
- sample_factors.as_mutable_span().slice(dst_points));
- }
-
- /* For every attribute, evaluate attributes from every curve in the range in the original
- * curve's "evaluated points", then use linear interpolation to sample to the result. */
- for (const int i_attribute : attributes.dst.index_range()) {
- attribute_math::convert_to_static_type(attributes.src[i_attribute].type(), [&](auto dummy) {
- using T = decltype(dummy);
- Span<T> src = attributes.src[i_attribute].typed<T>();
- MutableSpan<T> dst = attributes.dst[i_attribute].typed<T>();
-
- for (const int i_curve : sliced_selection) {
- const IndexRange src_points = src_curves.points_for_curve(i_curve);
- const IndexRange dst_points = dst_curves.points_for_curve(i_curve);
-
- if (curve_types[i_curve] == CURVE_TYPE_POLY) {
- length_parameterize::linear_interpolation(src.slice(src_points),
- sample_indices.as_span().slice(dst_points),
- sample_factors.as_span().slice(dst_points),
- dst.slice(dst_points));
- }
- else {
- const int evaluated_size = src_curves.evaluated_points_for_curve(i_curve).size();
- evaluated_buffer.clear();
- evaluated_buffer.resize(sizeof(T) * evaluated_size);
- MutableSpan<T> evaluated = evaluated_buffer.as_mutable_span().cast<T>();
- src_curves.interpolate_to_evaluated(i_curve, src.slice(src_points), evaluated);
-
- length_parameterize::linear_interpolation(evaluated.as_span(),
- sample_indices.as_span().slice(dst_points),
- sample_factors.as_span().slice(dst_points),
- dst.slice(dst_points));
- }
- }
- });
- }
-
- /* Interpolate the evaluated positions to the resampled curves. */
- for (const int i_curve : sliced_selection) {
- const IndexRange src_points = src_curves.evaluated_points_for_curve(i_curve);
- const IndexRange dst_points = dst_curves.points_for_curve(i_curve);
- length_parameterize::linear_interpolation(evaluated_positions.slice(src_points),
- sample_indices.as_span().slice(dst_points),
- sample_factors.as_span().slice(dst_points),
- dst_positions.slice(dst_points));
- }
-
- /* Fill the default value for non-interpolating attributes that still must be copied. */
- for (GMutableSpan dst : attributes.dst_no_interpolation) {
- for (const int i_curve : sliced_selection) {
- const IndexRange dst_points = dst_curves.points_for_curve(i_curve);
- dst.type().value_initialize_n(dst.slice(dst_points).data(), dst_points.size());
- }
- }
- });
-
- /* Any attribute data from unselected curve points can be directly copied. */
- for (const int i : attributes.src.index_range()) {
- copy_between_curves(
- src_curves, dst_curves, unselected_ranges, attributes.src[i], attributes.dst[i]);
- }
- for (const int i : attributes.src_no_interpolation.index_range()) {
- copy_between_curves(src_curves,
- dst_curves,
- unselected_ranges,
- attributes.src_no_interpolation[i],
- attributes.dst_no_interpolation[i]);
- }
-
- /* Copy positions for unselected curves. */
- Span<float3> src_positions = src_curves.positions();
- copy_between_curves(src_curves, dst_curves, unselected_ranges, src_positions, dst_positions);
-
- for (OutputAttribute &attribute : attributes.dst_attributes) {
- attribute.save();
- }
-
- return dst_curves_id;
-}
-
-/**
- * Evaluate each selected curve to its implicit evaluated points.
- */
-static Curves *resample_to_evaluated(const CurveComponent &src_component,
- const Field<bool> &selection_field)
-{
- const Curves &src_curves_id = *src_component.get_for_read();
- const bke::CurvesGeometry &src_curves = bke::CurvesGeometry::wrap(src_curves_id.geometry);
-
- GeometryComponentFieldContext field_context{src_component, ATTR_DOMAIN_CURVE};
- fn::FieldEvaluator evaluator{field_context, src_curves.curves_num()};
- evaluator.set_selection(selection_field);
- evaluator.evaluate();
- const IndexMask selection = evaluator.get_evaluated_selection_as_mask();
- const Vector<IndexRange> unselected_ranges = selection.extract_ranges_invert(
- src_curves.curves_range(), nullptr);
-
- Curves *dst_curves_id = bke::curves_new_nomain(0, src_curves.curves_num());
- bke::CurvesGeometry &dst_curves = bke::CurvesGeometry::wrap(dst_curves_id->geometry);
- CurveComponent dst_component;
- dst_component.replace(dst_curves_id, GeometryOwnershipType::Editable);
- /* Directly copy curve attributes, since they stay the same (except for curve types). */
- CustomData_copy(&src_curves.curve_data,
- &dst_curves.curve_data,
- CD_MASK_ALL,
- CD_DUPLICATE,
- src_curves.curves_num());
- /* All resampled curves are poly curves. */
- dst_curves.fill_curve_types(selection, CURVE_TYPE_POLY);
- MutableSpan<int> dst_offsets = dst_curves.offsets_for_write();
-
- src_curves.ensure_evaluated_offsets();
- threading::parallel_for(selection.index_range(), 4096, [&](IndexRange range) {
- for (const int i : selection.slice(range)) {
- dst_offsets[i] = src_curves.evaluated_points_for_curve(i).size();
- }
- });
- fill_curve_counts(src_curves, unselected_ranges, dst_offsets);
- accumulate_counts_to_offsets(dst_offsets);
-
- dst_curves.resize(dst_offsets.last(), dst_curves.curves_num());
-
- /* Create the correct number of uniform-length samples for every selected curve. */
- Span<float3> evaluated_positions = src_curves.evaluated_positions();
- MutableSpan<float3> dst_positions = dst_curves.positions_for_write();
-
- AttributesForInterpolation attributes;
- gather_point_attributes_to_interpolate(src_component, dst_component, attributes);
-
- threading::parallel_for(selection.index_range(), 512, [&](IndexRange selection_range) {
- const IndexMask sliced_selection = selection.slice(selection_range);
-
- /* Evaluate generic point attributes directly to the result attributes. */
- for (const int i_attribute : attributes.dst.index_range()) {
- attribute_math::convert_to_static_type(attributes.src[i_attribute].type(), [&](auto dummy) {
- using T = decltype(dummy);
- Span<T> src = attributes.src[i_attribute].typed<T>();
- MutableSpan<T> dst = attributes.dst[i_attribute].typed<T>();
-
- for (const int i_curve : sliced_selection) {
- const IndexRange src_points = src_curves.points_for_curve(i_curve);
- const IndexRange dst_points = dst_curves.points_for_curve(i_curve);
- src_curves.interpolate_to_evaluated(
- i_curve, src.slice(src_points), dst.slice(dst_points));
- }
- });
- }
-
- /* Copy the evaluated positions to the selected curves. */
- for (const int i_curve : sliced_selection) {
- const IndexRange src_points = src_curves.evaluated_points_for_curve(i_curve);
- const IndexRange dst_points = dst_curves.points_for_curve(i_curve);
- dst_positions.slice(dst_points).copy_from(evaluated_positions.slice(src_points));
- }
-
- /* Fill the default value for non-interpolating attributes that still must be copied. */
- for (GMutableSpan dst : attributes.dst_no_interpolation) {
- for (const int i_curve : sliced_selection) {
- const IndexRange dst_points = dst_curves.points_for_curve(i_curve);
- dst.type().value_initialize_n(dst.slice(dst_points).data(), dst_points.size());
- }
- }
- });
-
- /* Any attribute data from unselected curve points can be directly copied. */
- for (const int i : attributes.src.index_range()) {
- copy_between_curves(
- src_curves, dst_curves, unselected_ranges, attributes.src[i], attributes.dst[i]);
- }
- for (const int i : attributes.src_no_interpolation.index_range()) {
- copy_between_curves(src_curves,
- dst_curves,
- unselected_ranges,
- attributes.src_no_interpolation[i],
- attributes.dst_no_interpolation[i]);
- }
-
- /* Copy positions for unselected curves. */
- Span<float3> src_positions = src_curves.positions();
- copy_between_curves(src_curves, dst_curves, unselected_ranges, src_positions, dst_positions);
-
- for (OutputAttribute &attribute : attributes.dst_attributes) {
- attribute.save();
- }
-
- return dst_curves_id;
-}
-
-/**
- * Create a resampled curve point count field for both "uniform" options.
- * The complexity is handled here in order to make the actual resampling functions simpler.
- */
-static Field<int> get_curve_count_field(GeoNodeExecParams params,
- const GeometryNodeCurveResampleMode mode)
-{
- if (mode == GEO_NODE_CURVE_RESAMPLE_COUNT) {
- static fn::CustomMF_SI_SO<int, int> max_one_fn(
- "Clamp Above One",
- [](int value) { return std::max(1, value); },
- fn::CustomMF_presets::AllSpanOrSingle());
- auto clamp_op = std::make_shared<FieldOperation>(
- FieldOperation(max_one_fn, {Field<int>(params.extract_input<Field<int>>("Count"))}));
-
- return Field<int>(std::move(clamp_op));
- }
-
- if (mode == GEO_NODE_CURVE_RESAMPLE_LENGTH) {
- static fn::CustomMF_SI_SI_SO<float, float, int> get_count_fn(
- "Length Input to Count",
- [](const float curve_length, const float sample_length) {
- /* Find the number of sampled segments by dividing the total length by
- * the sample length. Then there is one more sampled point than segment. */
- const int count = int(curve_length / sample_length) + 1;
- return std::max(1, count);
- },
- fn::CustomMF_presets::AllSpanOrSingle());
-
- auto get_count_op = std::make_shared<FieldOperation>(
- FieldOperation(get_count_fn,
- {Field<float>(std::make_shared<bke::CurveLengthFieldInput>()),
- params.extract_input<Field<float>>("Length")}));
-
- return Field<int>(std::move(get_count_op));
- }
-
- BLI_assert_unreachable();
- return {};
-}
-
static void node_geo_exec(GeoNodeExecParams params)
{
GeometrySet geometry_set = params.extract_input<GeometrySet>("Curve");
@@ -555,32 +61,35 @@ static void node_geo_exec(GeoNodeExecParams params)
const Field<bool> selection = params.extract_input<Field<bool>>("Selection");
switch (mode) {
- case GEO_NODE_CURVE_RESAMPLE_COUNT:
+ case GEO_NODE_CURVE_RESAMPLE_COUNT: {
+ Field<int> count = params.extract_input<Field<int>>("Count");
+ geometry_set.modify_geometry_sets([&](GeometrySet &geometry) {
+ if (const CurveComponent *component = geometry.get_component_for_read<CurveComponent>()) {
+ if (!component->is_empty()) {
+ geometry.replace_curves(geometry::resample_to_count(*component, selection, count));
+ }
+ }
+ });
+ break;
+ }
case GEO_NODE_CURVE_RESAMPLE_LENGTH: {
- Field<int> count = get_curve_count_field(params, mode);
-
- geometry_set.modify_geometry_sets([&](GeometrySet &geometry_set) {
- if (!geometry_set.has_curves()) {
- return;
+ Field<float> length = params.extract_input<Field<float>>("Length");
+ geometry_set.modify_geometry_sets([&](GeometrySet &geometry) {
+ if (const CurveComponent *component = geometry.get_component_for_read<CurveComponent>()) {
+ if (!component->is_empty()) {
+ geometry.replace_curves(geometry::resample_to_length(*component, selection, length));
+ }
}
-
- Curves *result = resample_to_uniform_count(
- *geometry_set.get_component_for_read<CurveComponent>(), selection, count);
-
- geometry_set.replace_curves(result);
});
break;
}
case GEO_NODE_CURVE_RESAMPLE_EVALUATED:
- geometry_set.modify_geometry_sets([&](GeometrySet &geometry_set) {
- if (!geometry_set.has_curves()) {
- return;
+ geometry_set.modify_geometry_sets([&](GeometrySet &geometry) {
+ if (const CurveComponent *component = geometry.get_component_for_read<CurveComponent>()) {
+ if (!component->is_empty()) {
+ geometry.replace_curves(geometry::resample_to_evaluated(*component, selection));
+ }
}
-
- Curves *result = resample_to_evaluated(
- *geometry_set.get_component_for_read<CurveComponent>(), selection);
-
- geometry_set.replace_curves(result);
});
break;
}
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 de29735bd2d..64a174df599 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_curve_reverse.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_curve_reverse.cc
@@ -27,9 +27,9 @@ static void node_geo_exec(GeoNodeExecParams params)
Field<bool> selection_field = params.get_input<Field<bool>>("Selection");
const CurveComponent &component = *geometry_set.get_component_for_read<CurveComponent>();
GeometryComponentFieldContext field_context{component, ATTR_DOMAIN_CURVE};
- const int domain_size = component.attribute_domain_size(ATTR_DOMAIN_CURVE);
+ const int domain_num = component.attribute_domain_num(ATTR_DOMAIN_CURVE);
- fn::FieldEvaluator selection_evaluator{field_context, domain_size};
+ fn::FieldEvaluator selection_evaluator{field_context, domain_num};
selection_evaluator.add(selection_field);
selection_evaluator.evaluate();
const IndexMask selection = selection_evaluator.get_evaluated_as_mask(0);
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 a548becf24e..ae2b4fd779d 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
@@ -75,7 +75,7 @@ static Array<float> curve_length_point_domain(const bke::CurvesGeometry &curves)
case CURVE_TYPE_CATMULL_ROM: {
const int resolution = resolutions[i_curve];
for (const int i : IndexRange(points.size()).drop_back(1)) {
- lengths[i + 1] = evaluated_lengths[resolution * i - 1];
+ lengths[i + 1] = evaluated_lengths[resolution * (i + 1) - 1];
}
break;
}
@@ -107,7 +107,7 @@ static Array<float> curve_length_point_domain(const bke::CurvesGeometry &curves)
static VArray<float> construct_curve_parameter_varray(const bke::CurvesGeometry &curves,
const IndexMask UNUSED(mask),
- const AttributeDomain domain)
+ const eAttrDomain domain)
{
VArray<bool> cyclic = curves.cyclic();
@@ -146,7 +146,7 @@ static VArray<float> construct_curve_parameter_varray(const bke::CurvesGeometry
static VArray<float> construct_curve_length_parameter_varray(const bke::CurvesGeometry &curves,
const IndexMask UNUSED(mask),
- const AttributeDomain domain)
+ const eAttrDomain domain)
{
curves.ensure_evaluated_lengths();
@@ -165,7 +165,7 @@ static VArray<float> construct_curve_length_parameter_varray(const bke::CurvesGe
static VArray<int> construct_index_on_spline_varray(const bke::CurvesGeometry &curves,
const IndexMask UNUSED(mask),
- const AttributeDomain domain)
+ const eAttrDomain domain)
{
if (domain == ATTR_DOMAIN_POINT) {
Array<int> result(curves.points_num());
@@ -191,7 +191,7 @@ class CurveParameterFieldInput final : public GeometryFieldInput {
}
GVArray get_varray_for_context(const GeometryComponent &component,
- const AttributeDomain domain,
+ const eAttrDomain domain,
IndexMask mask) const final
{
if (component.type() == GEO_COMPONENT_TYPE_CURVE) {
@@ -225,7 +225,7 @@ class CurveLengthParameterFieldInput final : public GeometryFieldInput {
}
GVArray get_varray_for_context(const GeometryComponent &component,
- const AttributeDomain domain,
+ const eAttrDomain domain,
IndexMask mask) const final
{
if (component.type() == GEO_COMPONENT_TYPE_CURVE) {
@@ -259,7 +259,7 @@ class IndexOnSplineFieldInput final : public GeometryFieldInput {
}
GVArray get_varray_for_context(const GeometryComponent &component,
- const AttributeDomain domain,
+ const eAttrDomain domain,
IndexMask mask) const final
{
if (component.type() == GEO_COMPONENT_TYPE_CURVE) {
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 6e45411a9af..8479d61a890 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
@@ -1,6 +1,10 @@
/* SPDX-License-Identifier: GPL-2.0-or-later */
-#include "BKE_spline.hh"
+#include <numeric>
+
+#include "BKE_attribute_math.hh"
+#include "BKE_curves.hh"
+#include "BKE_curves_utils.hh"
#include "BLI_task.hh"
@@ -29,10 +33,39 @@ static void node_init(bNodeTree *UNUSED(tree), bNode *node)
{
NodeGeometryCurveSplineType *data = MEM_cnew<NodeGeometryCurveSplineType>(__func__);
- data->spline_type = GEO_NODE_SPLINE_TYPE_POLY;
+ data->spline_type = CURVE_TYPE_POLY;
node->storage = data;
}
+/**
+ * This function answers the question about possible conversion method for NURBS-to-Bezier. In
+ * general for 3rd degree NURBS curves there is one-to-one relation with 3rd degree Bezier curves
+ * that can be exploit for conversion - Bezier handles sit on NURBS hull segments and in the middle
+ * between those handles are Bezier anchor points.
+ */
+static bool is_nurbs_to_bezier_one_to_one(const KnotsMode knots_mode)
+{
+ if (ELEM(knots_mode, NURBS_KNOT_MODE_NORMAL, NURBS_KNOT_MODE_ENDPOINT)) {
+ return true;
+ }
+ return false;
+}
+
+/**
+ * As an optimization, just change the types on a mutable curves data-block when the conversion is
+ * simple. This could be expanded to more cases where the number of points doesn't change in the
+ * future, though that might require properly initializing some attributes, or removing others.
+ */
+static bool conversion_can_change_point_num(const CurveType dst_type)
+{
+ if (ELEM(dst_type, CURVE_TYPE_CATMULL_ROM, CURVE_TYPE_POLY)) {
+ /* The conversion to Catmull Rom or Poly should never change the number of points, no matter
+ * the source type (Bezier to Catmull Rom conversion cannot maintain the same shape anyway). */
+ return false;
+ }
+ return true;
+}
+
template<typename T>
static void scale_input_assign(const Span<T> src,
const int scale,
@@ -44,32 +77,97 @@ static void scale_input_assign(const Span<T> src,
}
}
-template<typename T>
-static void scale_output_assign(const Span<T> src,
- const int scale,
- const int offset,
- MutableSpan<T> dst)
+/**
+ * The Bezier control point and its handles become three control points on the NURBS curve,
+ * so each attribute value is duplicated three times.
+ */
+template<typename T> static void bezier_generic_to_nurbs(const Span<T> src, MutableSpan<T> dst)
{
for (const int i : src.index_range()) {
- dst[i * scale + offset] = src[i];
+ dst[i * 3] = src[i];
+ dst[i * 3 + 1] = src[i];
+ dst[i * 3 + 2] = src[i];
+ }
+}
+
+static void bezier_generic_to_nurbs(const GSpan src, GMutableSpan dst)
+{
+ attribute_math::convert_to_static_type(src.type(), [&](auto dummy) {
+ using T = decltype(dummy);
+ bezier_generic_to_nurbs(src.typed<T>(), dst.typed<T>());
+ });
+}
+
+static void bezier_positions_to_nurbs(const Span<float3> src_positions,
+ const Span<float3> src_handles_l,
+ const Span<float3> src_handles_r,
+ MutableSpan<float3> dst_positions)
+{
+ for (const int i : src_positions.index_range()) {
+ dst_positions[i * 3] = src_handles_l[i];
+ dst_positions[i * 3 + 1] = src_positions[i];
+ dst_positions[i * 3 + 2] = src_handles_r[i];
+ }
+}
+
+static void catmull_rom_to_bezier_handles(const Span<float3> src_positions,
+ const bool cyclic,
+ MutableSpan<float3> dst_handles_l,
+ MutableSpan<float3> dst_handles_r)
+{
+ /* Catmull Rom curves are the same as Bezier curves with automatically defined handle positions.
+ * This constant defines the portion of the distance between the next/previous points to use for
+ * the length of the handles. */
+ constexpr float handle_scale = 1.0f / 6.0f;
+
+ if (src_positions.size() == 1) {
+ dst_handles_l.first() = src_positions.first();
+ dst_handles_r.first() = src_positions.first();
+ return;
+ }
+
+ const float3 first_offset = cyclic ? src_positions[1] - src_positions.last() :
+ src_positions[1] - src_positions[0];
+ dst_handles_r.first() = src_positions.first() + first_offset * handle_scale;
+ dst_handles_l.first() = src_positions.first() - first_offset * handle_scale;
+
+ const float3 last_offset = cyclic ? src_positions.first() - src_positions.last(1) :
+ src_positions.last() - src_positions.last(1);
+ dst_handles_l.last() = src_positions.last() - last_offset * handle_scale;
+ dst_handles_r.last() = src_positions.last() + last_offset * handle_scale;
+
+ for (const int i : src_positions.index_range().drop_front(1).drop_back(1)) {
+ const float3 left_offset = src_positions[i - 1] - src_positions[i + 1];
+ dst_handles_l[i] = src_positions[i] + left_offset * handle_scale;
+
+ const float3 right_offset = src_positions[i + 1] - src_positions[i - 1];
+ dst_handles_r[i] = src_positions[i] + right_offset * handle_scale;
}
}
+static void catmull_rom_to_nurbs_positions(const Span<float3> src_positions,
+ const bool cyclic,
+ MutableSpan<float3> dst_positions)
+{
+ /* Convert the Catmull Rom position data to Bezier handles in order to reuse the Bezier to
+ * NURBS positions assignment. If this becomes a bottleneck, this step could be avoided. */
+ Array<float3, 32> bezier_handles_l(src_positions.size());
+ Array<float3, 32> bezier_handles_r(src_positions.size());
+ catmull_rom_to_bezier_handles(src_positions, cyclic, bezier_handles_l, bezier_handles_r);
+ bezier_positions_to_nurbs(src_positions, bezier_handles_l, bezier_handles_r, dst_positions);
+}
+
template<typename T>
static void nurbs_to_bezier_assign(const Span<T> src,
const MutableSpan<T> dst,
const KnotsMode knots_mode)
{
switch (knots_mode) {
- case NURBS_KNOT_MODE_BEZIER:
- scale_input_assign<T>(src, 3, 1, dst);
- break;
case NURBS_KNOT_MODE_NORMAL:
for (const int i : dst.index_range()) {
dst[i] = src[(i + 1) % src.size()];
}
break;
- case NURBS_KNOT_MODE_ENDPOINT_BEZIER:
case NURBS_KNOT_MODE_ENDPOINT:
for (const int i : dst.index_range().drop_back(1).drop_front(1)) {
dst[i] = src[i + 1];
@@ -77,54 +175,28 @@ static void nurbs_to_bezier_assign(const Span<T> src,
dst.first() = src.first();
dst.last() = src.last();
break;
+ default:
+ /* Every 3rd NURBS position (starting from index 1) should have its attributes transferred.
+ */
+ scale_input_assign<T>(src, 3, 1, dst);
}
}
-template<typename CopyFn>
-static void copy_attributes(const Spline &input_spline, Spline &output_spline, CopyFn copy_fn)
+static void nurbs_to_bezier_assign(const GSpan src, const KnotsMode knots_mode, GMutableSpan dst)
{
- input_spline.attributes.foreach_attribute(
- [&](const AttributeIDRef &attribute_id, const AttributeMetaData &meta_data) {
- std::optional<GSpan> src = input_spline.attributes.get_for_read(attribute_id);
- BLI_assert(src);
- if (!output_spline.attributes.create(attribute_id, meta_data.data_type)) {
- BLI_assert_unreachable();
- return false;
- }
- std::optional<GMutableSpan> dst = output_spline.attributes.get_for_write(attribute_id);
- if (!dst) {
- BLI_assert_unreachable();
- return false;
- }
-
- copy_fn(*src, *dst);
-
- return true;
- },
- ATTR_DOMAIN_POINT);
+ attribute_math::convert_to_static_type(src.type(), [&](auto dummy) {
+ using T = decltype(dummy);
+ nurbs_to_bezier_assign(src.typed<T>(), dst.typed<T>(), knots_mode);
+ });
}
static Vector<float3> create_nurbs_to_bezier_handles(const Span<float3> nurbs_positions,
const KnotsMode knots_mode)
{
- const int nurbs_positions_size = nurbs_positions.size();
+ const int nurbs_positions_num = nurbs_positions.size();
Vector<float3> handle_positions;
- if (knots_mode == NURBS_KNOT_MODE_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 {
+
+ if (is_nurbs_to_bezier_one_to_one(knots_mode)) {
const bool is_periodic = knots_mode == NURBS_KNOT_MODE_NORMAL;
if (is_periodic) {
handle_positions.append(nurbs_positions[1] +
@@ -134,11 +206,15 @@ static Vector<float3> create_nurbs_to_bezier_handles(const Span<float3> nurbs_po
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;
+
+ /* Place Bezier handles on interior NURBS hull segments. Those handles can be either placed on
+ * endpoints, midpoints or 1/3 of the distance of a hull segment. */
+ const int segments_num = nurbs_positions_num - 1;
+ const bool ignore_interior_segment = segments_num == 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 float mid_offset = (float)(segments_num - 1) / 2.0f;
+ for (const int i : IndexRange(1, segments_num - 2)) {
+ /* Divisor can have values: 1, 2 or 3. */
const int divisor = is_periodic ?
3 :
std::min(3, (int)(-std::abs(i - mid_offset) + mid_offset + 1.0f));
@@ -151,7 +227,8 @@ static Vector<float3> create_nurbs_to_bezier_handles(const Span<float3> nurbs_po
}
}
}
- const int last_index = nurbs_positions_size - 1;
+
+ const int last_index = nurbs_positions_num - 1;
if (is_periodic) {
handle_positions.append(
nurbs_positions[last_index - 1] +
@@ -162,199 +239,433 @@ static Vector<float3> create_nurbs_to_bezier_handles(const Span<float3> nurbs_po
handle_positions.append(2 * nurbs_positions[last_index] - nurbs_positions[last_index - 1]);
}
}
+ else {
+ for (const int i : IndexRange(nurbs_positions_num)) {
+ if (i % 3 == 1) {
+ continue;
+ }
+ handle_positions.append(nurbs_positions[i]);
+ }
+ if (nurbs_positions_num % 3 == 1) {
+ handle_positions.pop_last();
+ }
+ else if (nurbs_positions_num % 3 == 2) {
+ const int last_index = nurbs_positions_num - 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 KnotsMode knots_mode)
+static void create_nurbs_to_bezier_positions(const Span<float3> nurbs_positions,
+ const Span<float3> handle_positions,
+ const KnotsMode knots_mode,
+ MutableSpan<float3> bezier_positions)
{
- if (knots_mode == NURBS_KNOT_MODE_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;
+ if (is_nurbs_to_bezier_one_to_one(knots_mode)) {
+ for (const int i : bezier_positions.index_range()) {
+ bezier_positions[i] = math::interpolate(
+ handle_positions[i * 2], handle_positions[i * 2 + 1], 0.5f);
+ }
}
-
- 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);
+ else {
+ /* Every 3rd NURBS position (starting from index 1) should be converted to Bezier position. */
+ scale_input_assign(nurbs_positions, 3, 1, bezier_positions);
}
- return bezier_positions;
}
-static SplinePtr convert_to_poly_spline(const Spline &input)
+static int to_bezier_size(const CurveType src_type,
+ const bool cyclic,
+ const KnotsMode knots_mode,
+ const int src_size)
{
- std::unique_ptr<PolySpline> output = std::make_unique<PolySpline>();
- output->resize(input.positions().size());
- output->positions().copy_from(input.positions());
- output->radii().copy_from(input.radii());
- output->tilts().copy_from(input.tilts());
- Spline::copy_base_settings(input, *output);
- output->attributes = input.attributes;
- return output;
+ switch (src_type) {
+ case CURVE_TYPE_NURBS: {
+ if (is_nurbs_to_bezier_one_to_one(knots_mode)) {
+ return cyclic ? src_size : src_size - 2;
+ }
+ return (src_size + 1) / 3;
+ }
+ default:
+ return src_size;
+ }
}
-static SplinePtr poly_to_nurbs(const Spline &input)
+static int to_nurbs_size(const CurveType src_type, const int src_size)
{
- std::unique_ptr<NURBSpline> output = std::make_unique<NURBSpline>();
- output->resize(input.positions().size());
- output->positions().copy_from(input.positions());
- output->radii().copy_from(input.radii());
- output->tilts().copy_from(input.tilts());
- output->weights().fill(1.0f);
- output->set_resolution(12);
- output->set_order(4);
- Spline::copy_base_settings(input, *output);
- output->knots_mode = NURBS_KNOT_MODE_BEZIER;
- output->attributes = input.attributes;
- return output;
+ switch (src_type) {
+ case CURVE_TYPE_BEZIER:
+ case CURVE_TYPE_CATMULL_ROM:
+ return src_size * 3;
+ default:
+ return src_size;
+ }
}
-static SplinePtr bezier_to_nurbs(const Spline &input)
+static void retrieve_curve_sizes(const bke::CurvesGeometry &curves, MutableSpan<int> sizes)
{
- const BezierSpline &bezier_spline = static_cast<const BezierSpline &>(input);
- std::unique_ptr<NURBSpline> output = std::make_unique<NURBSpline>();
- output->resize(input.size() * 3);
-
- scale_output_assign(bezier_spline.handle_positions_left(), 3, 0, output->positions());
- scale_output_assign(input.radii(), 3, 0, output->radii());
- scale_output_assign(input.tilts(), 3, 0, output->tilts());
-
- scale_output_assign(bezier_spline.positions(), 3, 1, output->positions());
- scale_output_assign(input.radii(), 3, 1, output->radii());
- scale_output_assign(input.tilts(), 3, 1, output->tilts());
-
- scale_output_assign(bezier_spline.handle_positions_right(), 3, 2, output->positions());
- scale_output_assign(input.radii(), 3, 2, output->radii());
- scale_output_assign(input.tilts(), 3, 2, output->tilts());
-
- Spline::copy_base_settings(input, *output);
- output->weights().fill(1.0f);
- output->set_resolution(12);
- output->set_order(4);
- output->set_cyclic(input.is_cyclic());
- output->knots_mode = NURBS_KNOT_MODE_BEZIER;
- output->attributes.reallocate(output->size());
- copy_attributes(input, *output, [](GSpan src, GMutableSpan dst) {
- attribute_math::convert_to_static_type(src.type(), [&](auto dummy) {
- using T = decltype(dummy);
- scale_output_assign<T>(src.typed<T>(), 3, 0, dst.typed<T>());
- scale_output_assign<T>(src.typed<T>(), 3, 1, dst.typed<T>());
- scale_output_assign<T>(src.typed<T>(), 3, 2, dst.typed<T>());
- });
+ threading::parallel_for(curves.curves_range(), 4096, [&](IndexRange range) {
+ for (const int i : range) {
+ sizes[i] = curves.points_for_curve(i).size();
+ }
});
- return output;
}
-static SplinePtr poly_to_bezier(const Spline &input)
+struct GenericAttributes : NonCopyable, NonMovable {
+ Vector<GSpan> src;
+ Vector<GMutableSpan> dst;
+
+ Vector<OutputAttribute> attributes;
+};
+
+static void retrieve_generic_point_attributes(const CurveComponent &src_component,
+ CurveComponent &dst_component,
+ GenericAttributes &attributes)
{
- std::unique_ptr<BezierSpline> output = std::make_unique<BezierSpline>();
- output->resize(input.size());
- output->positions().copy_from(input.positions());
- output->radii().copy_from(input.radii());
- output->tilts().copy_from(input.tilts());
- output->handle_types_left().fill(BEZIER_HANDLE_VECTOR);
- output->handle_types_right().fill(BEZIER_HANDLE_VECTOR);
- output->set_resolution(12);
- Spline::copy_base_settings(input, *output);
- output->attributes = input.attributes;
- return output;
+ src_component.attribute_foreach(
+ [&](const AttributeIDRef &id, const AttributeMetaData meta_data) {
+ if (meta_data.domain != ATTR_DOMAIN_POINT) {
+ /* Curve domain attributes are all copied directly to the result in one step. */
+ return true;
+ }
+ if (src_component.attribute_is_builtin(id)) {
+ if (!(id.is_named() && ELEM(id, "tilt", "radius"))) {
+ return true;
+ }
+ }
+
+ GVArray src_attribute = src_component.attribute_try_get_for_read(id, ATTR_DOMAIN_POINT);
+ BLI_assert(src_attribute);
+ attributes.src.append(src_attribute.get_internal_span());
+
+ OutputAttribute dst_attribute = dst_component.attribute_try_get_for_output_only(
+ id, ATTR_DOMAIN_POINT, meta_data.data_type);
+ attributes.dst.append(dst_attribute.as_span());
+ attributes.attributes.append(std::move(dst_attribute));
+
+ return true;
+ });
}
-static SplinePtr nurbs_to_bezier(const Spline &input)
+static void convert_to_bezier(const CurveComponent &src_component,
+ const bke::CurvesGeometry &src_curves,
+ const IndexMask selection,
+ CurveComponent &dst_component,
+ bke::CurvesGeometry &dst_curves)
{
- const NURBSpline &nurbs_spline = static_cast<const NURBSpline &>(input);
- Span<float3> nurbs_positions;
- Vector<float3> nurbs_positions_vector;
- 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 = NURBS_KNOT_MODE_NORMAL;
+ const VArray<int8_t> src_knot_modes = src_curves.nurbs_knots_modes();
+ const VArray<int8_t> src_types = src_curves.curve_types();
+ const VArray<bool> src_cyclic = src_curves.cyclic();
+ const Span<float3> src_positions = src_curves.positions();
+
+ MutableSpan<int> dst_offsets = dst_curves.offsets_for_write();
+ retrieve_curve_sizes(src_curves, dst_curves.offsets_for_write());
+ threading::parallel_for(selection.index_range(), 1024, [&](IndexRange range) {
+ for (const int i : selection.slice(range)) {
+ dst_offsets[i] = to_bezier_size(
+ CurveType(src_types[i]), src_cyclic[i], KnotsMode(src_knot_modes[i]), dst_offsets[i]);
+ }
+ });
+ bke::curves::accumulate_counts_to_offsets(dst_offsets);
+ dst_curves.resize(dst_offsets.last(), dst_curves.curves_num());
+
+ GenericAttributes attributes;
+ retrieve_generic_point_attributes(src_component, dst_component, attributes);
+
+ MutableSpan<float3> dst_positions = dst_curves.positions_for_write();
+ MutableSpan<float3> dst_handles_l = dst_curves.handle_positions_left_for_write();
+ MutableSpan<float3> dst_handles_r = dst_curves.handle_positions_right_for_write();
+ MutableSpan<int8_t> dst_types_l = dst_curves.handle_types_left_for_write();
+ MutableSpan<int8_t> dst_types_r = dst_curves.handle_types_right_for_write();
+ MutableSpan<float> dst_weights = dst_curves.nurbs_weights_for_write();
+
+ auto catmull_rom_to_bezier = [&](IndexMask selection) {
+ bke::curves::fill_points<int8_t>(dst_curves, selection, BEZIER_HANDLE_ALIGN, dst_types_l);
+ bke::curves::fill_points<int8_t>(dst_curves, selection, BEZIER_HANDLE_ALIGN, dst_types_r);
+ bke::curves::copy_point_data(src_curves, dst_curves, selection, src_positions, dst_positions);
+
+ threading::parallel_for(selection.index_range(), 512, [&](IndexRange range) {
+ for (const int i : selection.slice(range)) {
+ const IndexRange src_points = src_curves.points_for_curve(i);
+ const IndexRange dst_points = dst_curves.points_for_curve(i);
+ catmull_rom_to_bezier_handles(src_positions.slice(src_points),
+ src_cyclic[i],
+ dst_handles_l.slice(dst_points),
+ dst_handles_r.slice(dst_points));
+ }
+ });
+
+ for (const int i : attributes.src.index_range()) {
+ bke::curves::copy_point_data(
+ src_curves, dst_curves, selection, attributes.src[i], attributes.dst[i]);
+ }
+ };
+
+ auto poly_to_bezier = [&](IndexMask selection) {
+ bke::curves::copy_point_data(src_curves, dst_curves, selection, src_positions, dst_positions);
+ bke::curves::fill_points<int8_t>(dst_curves, selection, BEZIER_HANDLE_VECTOR, dst_types_l);
+ bke::curves::fill_points<int8_t>(dst_curves, selection, BEZIER_HANDLE_VECTOR, dst_types_r);
+ dst_curves.calculate_bezier_auto_handles();
+ for (const int i : attributes.src.index_range()) {
+ bke::curves::copy_point_data(
+ src_curves, dst_curves, selection, attributes.src[i], attributes.dst[i]);
+ }
+ };
+
+ auto bezier_to_bezier = [&](IndexMask selection) {
+ const VArray_Span<int8_t> src_types_l = src_curves.handle_types_left();
+ const VArray_Span<int8_t> src_types_r = src_curves.handle_types_right();
+ const Span<float3> src_handles_l = src_curves.handle_positions_left();
+ const Span<float3> src_handles_r = src_curves.handle_positions_right();
+
+ bke::curves::copy_point_data(src_curves, dst_curves, selection, src_positions, dst_positions);
+ bke::curves::copy_point_data(src_curves, dst_curves, selection, src_handles_l, dst_handles_l);
+ bke::curves::copy_point_data(src_curves, dst_curves, selection, src_handles_r, dst_handles_r);
+ bke::curves::copy_point_data(src_curves, dst_curves, selection, src_types_l, dst_types_l);
+ bke::curves::copy_point_data(src_curves, dst_curves, selection, src_types_r, dst_types_r);
+
+ dst_curves.calculate_bezier_auto_handles();
+
+ for (const int i : attributes.src.index_range()) {
+ bke::curves::copy_point_data(
+ src_curves, dst_curves, selection, attributes.src[i], attributes.dst[i]);
+ }
+ };
+
+ auto nurbs_to_bezier = [&](IndexMask selection) {
+ bke::curves::fill_points<int8_t>(dst_curves, selection, BEZIER_HANDLE_ALIGN, dst_types_l);
+ bke::curves::fill_points<int8_t>(dst_curves, selection, BEZIER_HANDLE_ALIGN, dst_types_r);
+ bke::curves::fill_points<float>(dst_curves, selection, 0.0f, dst_weights);
+
+ threading::parallel_for(selection.index_range(), 64, [&](IndexRange range) {
+ for (const int i : selection.slice(range)) {
+ const IndexRange src_points = src_curves.points_for_curve(i);
+ const IndexRange dst_points = dst_curves.points_for_curve(i);
+ const Span<float3> src_curve_positions = src_positions.slice(src_points);
+
+ KnotsMode knots_mode = KnotsMode(src_knot_modes[i]);
+ Span<float3> nurbs_positions = src_curve_positions;
+ Vector<float3> nurbs_positions_vector;
+ if (src_cyclic[i] && is_nurbs_to_bezier_one_to_one(knots_mode)) {
+ /* For conversion treat this as periodic closed curve. Extend NURBS hull to first and
+ * second point which will act as a skeleton for placing Bezier handles. */
+ nurbs_positions_vector.extend(src_curve_positions);
+ nurbs_positions_vector.append(src_curve_positions[0]);
+ nurbs_positions_vector.append(src_curve_positions[1]);
+ nurbs_positions = nurbs_positions_vector;
+ knots_mode = NURBS_KNOT_MODE_NORMAL;
+ }
+
+ const Vector<float3> handle_positions = create_nurbs_to_bezier_handles(nurbs_positions,
+ knots_mode);
+
+ scale_input_assign(handle_positions.as_span(), 2, 0, dst_handles_l.slice(dst_points));
+ scale_input_assign(handle_positions.as_span(), 2, 1, dst_handles_r.slice(dst_points));
+
+ create_nurbs_to_bezier_positions(
+ nurbs_positions, handle_positions, knots_mode, dst_positions.slice(dst_points));
+ }
+ });
+
+ for (const int i_attribute : attributes.src.index_range()) {
+ threading::parallel_for(selection.index_range(), 512, [&](IndexRange range) {
+ for (const int i : selection.slice(range)) {
+ const IndexRange src_points = src_curves.points_for_curve(i);
+ const IndexRange dst_points = dst_curves.points_for_curve(i);
+ nurbs_to_bezier_assign(attributes.src[i_attribute].slice(src_points),
+ KnotsMode(src_knot_modes[i]),
+ attributes.dst[i_attribute].slice(dst_points));
+ }
+ });
+ }
+ };
+
+ bke::curves::foreach_curve_by_type(src_curves.curve_types(),
+ src_curves.curve_type_counts(),
+ selection,
+ catmull_rom_to_bezier,
+ poly_to_bezier,
+ bezier_to_bezier,
+ nurbs_to_bezier);
+
+ const Vector<IndexRange> unselected_ranges = selection.extract_ranges_invert(
+ src_curves.curves_range());
+
+ for (const int i : attributes.src.index_range()) {
+ bke::curves::copy_point_data(
+ src_curves, dst_curves, unselected_ranges, attributes.src[i], attributes.dst[i]);
}
- else {
- nurbs_positions = nurbs_spline.positions();
- knots_mode = nurbs_spline.knots_mode;
+
+ for (OutputAttribute &attribute : attributes.attributes) {
+ attribute.save();
}
- 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(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(BEZIER_HANDLE_ALIGN);
- output->handle_types_right().fill(BEZIER_HANDLE_ALIGN);
- output->set_resolution(nurbs_spline.resolution());
- Spline::copy_base_settings(nurbs_spline, *output);
- output->attributes.reallocate(output->size());
- 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);
- nurbs_to_bezier_assign(src.typed<T>(), dst.typed<T>(), knots_mode);
- });
- });
- return output;
}
-static SplinePtr convert_to_bezier(const Spline &input, GeoNodeExecParams params)
+static void convert_to_nurbs(const CurveComponent &src_component,
+ const bke::CurvesGeometry &src_curves,
+ const IndexMask selection,
+ CurveComponent &dst_component,
+ bke::CurvesGeometry &dst_curves)
{
- switch (input.type()) {
- case CURVE_TYPE_BEZIER:
- return input.copy();
- case CURVE_TYPE_POLY:
- return poly_to_bezier(input);
- case CURVE_TYPE_NURBS:
- if (input.size() < 4) {
- params.error_message_add(
- NodeWarningType::Info,
- TIP_("NURBS must have minimum of 4 points for Bezier Conversion"));
- return input.copy();
+ const VArray<int8_t> src_types = src_curves.curve_types();
+ const VArray<bool> src_cyclic = src_curves.cyclic();
+ const Span<float3> src_positions = src_curves.positions();
+
+ MutableSpan<int> dst_offsets = dst_curves.offsets_for_write();
+ retrieve_curve_sizes(src_curves, dst_curves.offsets_for_write());
+ threading::parallel_for(selection.index_range(), 1024, [&](IndexRange range) {
+ for (const int i : selection.slice(range)) {
+ dst_offsets[i] = to_nurbs_size(CurveType(src_types[i]), dst_offsets[i]);
+ }
+ });
+ bke::curves::accumulate_counts_to_offsets(dst_offsets);
+ dst_curves.resize(dst_offsets.last(), dst_curves.curves_num());
+
+ GenericAttributes attributes;
+ retrieve_generic_point_attributes(src_component, dst_component, attributes);
+
+ MutableSpan<float3> dst_positions = dst_curves.positions_for_write();
+
+ auto fill_weights_if_necessary = [&](const IndexMask selection) {
+ if (!src_curves.nurbs_weights().is_empty()) {
+ bke::curves::fill_points(dst_curves, selection, 1.0f, dst_curves.nurbs_weights_for_write());
+ }
+ };
+
+ auto catmull_rom_to_nurbs = [&](IndexMask selection) {
+ dst_curves.nurbs_orders_for_write().fill_indices(selection, 4);
+ dst_curves.nurbs_knots_modes_for_write().fill_indices(selection, NURBS_KNOT_MODE_BEZIER);
+ fill_weights_if_necessary(selection);
+
+ threading::parallel_for(selection.index_range(), 512, [&](IndexRange range) {
+ for (const int i : selection.slice(range)) {
+ const IndexRange src_points = src_curves.points_for_curve(i);
+ const IndexRange dst_points = dst_curves.points_for_curve(i);
+ catmull_rom_to_nurbs_positions(
+ src_positions.slice(src_points), src_cyclic[i], dst_positions.slice(dst_points));
}
- return nurbs_to_bezier(input);
- case CURVE_TYPE_CATMULL_ROM: {
- BLI_assert_unreachable();
- return {};
+ });
+
+ for (const int i_attribute : attributes.src.index_range()) {
+ threading::parallel_for(selection.index_range(), 512, [&](IndexRange range) {
+ for (const int i : selection.slice(range)) {
+ const IndexRange src_points = src_curves.points_for_curve(i);
+ const IndexRange dst_points = dst_curves.points_for_curve(i);
+ bezier_generic_to_nurbs(attributes.src[i_attribute].slice(src_points),
+ attributes.dst[i_attribute].slice(dst_points));
+ }
+ });
+ }
+ };
+
+ auto poly_to_nurbs = [&](IndexMask selection) {
+ dst_curves.nurbs_orders_for_write().fill_indices(selection, 4);
+ bke::curves::copy_point_data(src_curves, dst_curves, selection, src_positions, dst_positions);
+ fill_weights_if_necessary(selection);
+
+ /* Avoid using "Endpoint" knots modes for cyclic curves, since it adds a sharp point at the
+ * start/end. */
+ if (src_cyclic.is_single()) {
+ dst_curves.nurbs_knots_modes_for_write().fill_indices(
+ selection,
+ src_cyclic.get_internal_single() ? NURBS_KNOT_MODE_NORMAL : NURBS_KNOT_MODE_ENDPOINT);
+ }
+ else {
+ VArray_Span<bool> cyclic{src_cyclic};
+ MutableSpan<int8_t> knots_modes = dst_curves.nurbs_knots_modes_for_write();
+ threading::parallel_for(selection.index_range(), 1024, [&](IndexRange range) {
+ for (const int i : selection.slice(range)) {
+ knots_modes[i] = cyclic[i] ? NURBS_KNOT_MODE_NORMAL : NURBS_KNOT_MODE_ENDPOINT;
+ }
+ });
+ }
+
+ for (const int i_attribute : attributes.src.index_range()) {
+ bke::curves::copy_point_data(src_curves,
+ dst_curves,
+ selection,
+ attributes.src[i_attribute],
+ attributes.dst[i_attribute]);
+ }
+ };
+
+ auto bezier_to_nurbs = [&](IndexMask selection) {
+ const Span<float3> src_handles_l = src_curves.handle_positions_left();
+ const Span<float3> src_handles_r = src_curves.handle_positions_right();
+
+ dst_curves.nurbs_orders_for_write().fill_indices(selection, 4);
+ dst_curves.nurbs_knots_modes_for_write().fill_indices(selection, NURBS_KNOT_MODE_BEZIER);
+ fill_weights_if_necessary(selection);
+
+ threading::parallel_for(selection.index_range(), 512, [&](IndexRange range) {
+ for (const int i : selection.slice(range)) {
+ const IndexRange src_points = src_curves.points_for_curve(i);
+ const IndexRange dst_points = dst_curves.points_for_curve(i);
+ bezier_positions_to_nurbs(src_positions.slice(src_points),
+ src_handles_l.slice(src_points),
+ src_handles_r.slice(src_points),
+ dst_positions.slice(dst_points));
+ }
+ });
+
+ for (const int i_attribute : attributes.src.index_range()) {
+ threading::parallel_for(selection.index_range(), 512, [&](IndexRange range) {
+ for (const int i : selection.slice(range)) {
+ const IndexRange src_points = src_curves.points_for_curve(i);
+ const IndexRange dst_points = dst_curves.points_for_curve(i);
+ bezier_generic_to_nurbs(attributes.src[i_attribute].slice(src_points),
+ attributes.dst[i_attribute].slice(dst_points));
+ }
+ });
+ }
+ };
+
+ auto nurbs_to_nurbs = [&](IndexMask selection) {
+ bke::curves::copy_point_data(src_curves, dst_curves, selection, src_positions, dst_positions);
+
+ if (!src_curves.nurbs_weights().is_empty()) {
+ bke::curves::copy_point_data(src_curves,
+ dst_curves,
+ selection,
+ src_curves.nurbs_weights(),
+ dst_curves.nurbs_weights_for_write());
+ }
+
+ for (const int i_attribute : attributes.src.index_range()) {
+ bke::curves::copy_point_data(src_curves,
+ dst_curves,
+ selection,
+ attributes.src[i_attribute],
+ attributes.dst[i_attribute]);
}
+ };
+
+ bke::curves::foreach_curve_by_type(src_curves.curve_types(),
+ src_curves.curve_type_counts(),
+ selection,
+ catmull_rom_to_nurbs,
+ poly_to_nurbs,
+ bezier_to_nurbs,
+ nurbs_to_nurbs);
+
+ const Vector<IndexRange> unselected_ranges = selection.extract_ranges_invert(
+ src_curves.curves_range());
+
+ for (const int i : attributes.src.index_range()) {
+ bke::curves::copy_point_data(
+ src_curves, dst_curves, unselected_ranges, attributes.src[i], attributes.dst[i]);
}
- BLI_assert_unreachable();
- return {};
-}
-static SplinePtr convert_to_nurbs(const Spline &input)
-{
- switch (input.type()) {
- case CURVE_TYPE_NURBS:
- return input.copy();
- case CURVE_TYPE_BEZIER:
- return bezier_to_nurbs(input);
- case CURVE_TYPE_POLY:
- return poly_to_nurbs(input);
- case CURVE_TYPE_CATMULL_ROM:
- BLI_assert_unreachable();
- return {};
+ for (OutputAttribute &attribute : attributes.attributes) {
+ attribute.save();
}
- BLI_assert_unreachable();
- return {};
}
static void node_geo_exec(GeoNodeExecParams params)
{
const NodeGeometryCurveSplineType &storage = node_storage(params.node());
- const GeometryNodeSplineType dst_type = (const GeometryNodeSplineType)storage.spline_type;
+ const CurveType dst_type = CurveType(storage.spline_type);
GeometrySet geometry_set = params.extract_input<GeometrySet>("Curve");
Field<bool> selection_field = params.extract_input<Field<bool>>("Selection");
@@ -363,45 +674,58 @@ static void node_geo_exec(GeoNodeExecParams params)
if (!geometry_set.has_curves()) {
return;
}
+ const CurveComponent &src_component = *geometry_set.get_component_for_read<CurveComponent>();
+ const Curves &src_curves_id = *src_component.get_for_read();
+ const bke::CurvesGeometry &src_curves = bke::CurvesGeometry::wrap(src_curves_id.geometry);
+ if (src_curves.is_single_type(dst_type)) {
+ return;
+ }
- const CurveComponent *curve_component = geometry_set.get_component_for_read<CurveComponent>();
- const std::unique_ptr<CurveEval> curve = curves_to_curve_eval(
- *curve_component->get_for_read());
- GeometryComponentFieldContext field_context{*curve_component, ATTR_DOMAIN_CURVE};
- const int domain_size = curve_component->attribute_domain_size(ATTR_DOMAIN_CURVE);
-
- Span<SplinePtr> src_splines = curve->splines();
-
- fn::FieldEvaluator selection_evaluator{field_context, domain_size};
- selection_evaluator.add(selection_field);
- selection_evaluator.evaluate();
- const VArray<bool> &selection = selection_evaluator.get_evaluated<bool>(0);
-
- std::unique_ptr<CurveEval> new_curve = std::make_unique<CurveEval>();
- new_curve->resize(src_splines.size());
-
- threading::parallel_for(src_splines.index_range(), 512, [&](IndexRange range) {
- for (const int i : range) {
- if (selection[i]) {
- switch (dst_type) {
- case GEO_NODE_SPLINE_TYPE_POLY:
- new_curve->splines()[i] = convert_to_poly_spline(*src_splines[i]);
- break;
- case GEO_NODE_SPLINE_TYPE_BEZIER:
- new_curve->splines()[i] = convert_to_bezier(*src_splines[i], params);
- break;
- case GEO_NODE_SPLINE_TYPE_NURBS:
- new_curve->splines()[i] = convert_to_nurbs(*src_splines[i]);
- break;
- }
- }
- else {
- new_curve->splines()[i] = src_splines[i]->copy();
- }
- }
- });
- new_curve->attributes = curve->attributes;
- geometry_set.replace_curves(curve_eval_to_curves(*new_curve));
+ GeometryComponentFieldContext field_context{src_component, ATTR_DOMAIN_CURVE};
+ const int domain_size = src_component.attribute_domain_num(ATTR_DOMAIN_CURVE);
+
+ fn::FieldEvaluator evaluator{field_context, domain_size};
+ evaluator.set_selection(selection_field);
+ evaluator.evaluate();
+ const IndexMask selection = evaluator.get_evaluated_selection_as_mask();
+ if (!conversion_can_change_point_num(dst_type)) {
+ CurveComponent &dst_component = geometry_set.get_component_for_write<CurveComponent>();
+ Curves &curves_id = *dst_component.get_for_write();
+ bke::CurvesGeometry &curves = bke::CurvesGeometry::wrap(curves_id.geometry);
+ curves.fill_curve_types(selection, dst_type);
+ curves.remove_attributes_based_on_types();
+ return;
+ }
+
+ Curves *dst_curves_id = bke::curves_new_nomain(0, src_curves.curves_num());
+ bke::CurvesGeometry &dst_curves = bke::CurvesGeometry::wrap(dst_curves_id->geometry);
+ CurveComponent dst_component;
+ dst_component.replace(dst_curves_id, GeometryOwnershipType::Editable);
+ /* Directly copy curve attributes, since they stay the same (except for curve types). */
+ CustomData_copy(&src_curves.curve_data,
+ &dst_curves.curve_data,
+ CD_MASK_ALL,
+ CD_DUPLICATE,
+ src_curves.curves_num());
+
+ dst_curves.fill_curve_types(selection, dst_type);
+
+ switch (dst_type) {
+ case CURVE_TYPE_CATMULL_ROM:
+ case CURVE_TYPE_POLY:
+ /* Converting to Catmull Rom curves or poly curves should be handled
+ * above by the optimization to avoid changing the point count. */
+ BLI_assert_unreachable();
+ break;
+ case CURVE_TYPE_BEZIER:
+ convert_to_bezier(src_component, src_curves, selection, dst_component, dst_curves);
+ break;
+ case CURVE_TYPE_NURBS:
+ convert_to_nurbs(src_component, src_curves, selection, dst_component, dst_curves);
+ break;
+ }
+
+ geometry_set.replace_curves(dst_curves_id);
});
params.set_output("Curve", std::move(geometry_set));
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 371556c04f1..4d8745bf79e 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_curve_subdivide.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_curve_subdivide.cc
@@ -30,9 +30,9 @@ static Array<int> get_subdivided_offsets(const Spline &spline,
const VArray<int> &cuts,
const int spline_offset)
{
- Array<int> offsets(spline.segments_size() + 1);
+ Array<int> offsets(spline.segments_num() + 1);
int offset = 0;
- for (const int i : IndexRange(spline.segments_size())) {
+ for (const int i : IndexRange(spline.segments_num())) {
offsets[i] = offset;
offset = offset + std::max(cuts[spline_offset + i], 0) + 1;
}
@@ -46,8 +46,8 @@ static void subdivide_attribute(Span<T> src,
const bool is_cyclic,
MutableSpan<T> dst)
{
- const int src_size = src.size();
- threading::parallel_for(IndexRange(src_size - 1), 1024, [&](IndexRange range) {
+ const int src_num = src.size();
+ threading::parallel_for(IndexRange(src_num - 1), 1024, [&](IndexRange range) {
for (const int i : range) {
const int cuts = offsets[i + 1] - offsets[i];
dst[offsets[i]] = src[i];
@@ -60,7 +60,7 @@ static void subdivide_attribute(Span<T> src,
});
if (is_cyclic) {
- const int i = src_size - 1;
+ const int i = src_num - 1;
const int cuts = offsets[i + 1] - offsets[i];
dst[offsets[i]] = src.last();
const float factor_delta = cuts == 0 ? 1.0f : 1.0f / cuts;
@@ -86,7 +86,7 @@ static void subdivide_attribute(Span<T> src,
static void subdivide_bezier_segment(const BezierSpline &src,
const int index,
const int offset,
- const int result_size,
+ const int result_num,
Span<float3> src_positions,
Span<float3> src_handles_left,
Span<float3> src_handles_right,
@@ -106,11 +106,11 @@ static void subdivide_bezier_segment(const BezierSpline &src,
if (is_last_cyclic_segment) {
dst_type_left.first() = BEZIER_HANDLE_VECTOR;
}
- dst_type_left.slice(offset + 1, result_size).fill(BEZIER_HANDLE_VECTOR);
- dst_type_right.slice(offset, result_size).fill(BEZIER_HANDLE_VECTOR);
+ dst_type_left.slice(offset + 1, result_num).fill(BEZIER_HANDLE_VECTOR);
+ dst_type_right.slice(offset, result_num).fill(BEZIER_HANDLE_VECTOR);
- const float factor_delta = 1.0f / result_size;
- for (const int cut : IndexRange(result_size)) {
+ const float factor_delta = 1.0f / result_num;
+ for (const int cut : IndexRange(result_num)) {
const float factor = cut * factor_delta;
dst_positions[offset + cut] = attribute_math::mix2(
factor, src_positions[index], src_positions[next_index]);
@@ -120,10 +120,10 @@ static void subdivide_bezier_segment(const BezierSpline &src,
if (is_last_cyclic_segment) {
dst_type_left.first() = BEZIER_HANDLE_FREE;
}
- dst_type_left.slice(offset + 1, result_size).fill(BEZIER_HANDLE_FREE);
- dst_type_right.slice(offset, result_size).fill(BEZIER_HANDLE_FREE);
+ dst_type_left.slice(offset + 1, result_num).fill(BEZIER_HANDLE_FREE);
+ dst_type_right.slice(offset, result_num).fill(BEZIER_HANDLE_FREE);
- const int i_segment_last = is_last_cyclic_segment ? 0 : offset + result_size;
+ const int i_segment_last = is_last_cyclic_segment ? 0 : offset + result_num;
/* Create a Bezier segment to update iteratively for every subdivision
* and references to the meaningful values for ease of use. */
@@ -138,8 +138,8 @@ static void subdivide_bezier_segment(const BezierSpline &src,
handle_prev = src_handles_right[index];
handle_next = src_handles_left[next_index];
- for (const int cut : IndexRange(result_size - 1)) {
- const float parameter = 1.0f / (result_size - cut);
+ for (const int cut : IndexRange(result_num - 1)) {
+ const float parameter = 1.0f / (result_num - cut);
const BezierSpline::InsertResult insert = temp.calculate_segment_insertion(0, 1, parameter);
/* Copy relevant temporary data to the result. */
@@ -154,7 +154,7 @@ static void subdivide_bezier_segment(const BezierSpline &src,
}
/* Copy the handles for the last segment from the temporary spline. */
- dst_handles_right[offset + result_size - 1] = handle_prev;
+ dst_handles_right[offset + result_num - 1] = handle_prev;
dst_handles_left[i_segment_last] = handle_next;
}
}
@@ -287,9 +287,9 @@ static SplinePtr subdivide_spline(const Spline &spline,
* of cuts is a real span (especially considering the note below). Using the offset at each
* point facilitates subdividing in parallel later. */
Array<int> offsets = get_subdivided_offsets(spline, cuts, spline_offset);
- const int result_size = offsets.last() + int(!spline.is_cyclic());
+ const int result_num = offsets.last() + int(!spline.is_cyclic());
SplinePtr new_spline = spline.copy_only_settings();
- new_spline->resize(result_size);
+ new_spline->resize(result_num);
subdivide_builtin_attributes(spline, offsets, *new_spline);
subdivide_dynamic_attributes(spline, offsets, *new_spline);
return new_spline;
@@ -334,9 +334,9 @@ static void node_geo_exec(GeoNodeExecParams params)
const CurveComponent &component = *geometry_set.get_component_for_read<CurveComponent>();
GeometryComponentFieldContext field_context{component, ATTR_DOMAIN_POINT};
- const int domain_size = component.attribute_domain_size(ATTR_DOMAIN_POINT);
+ const int domain_num = component.attribute_domain_num(ATTR_DOMAIN_POINT);
- fn::FieldEvaluator evaluator{field_context, domain_size};
+ fn::FieldEvaluator evaluator{field_context, domain_num};
evaluator.add(cuts_field);
evaluator.evaluate();
const VArray<int> &cuts = evaluator.get_evaluated<int>(0);
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 894580f2932..7d83b4b3ecb 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
@@ -90,7 +90,7 @@ static Array<int> calculate_spline_point_offsets(GeoNodeExecParams &params,
int offset = 0;
for (const int i : IndexRange(size)) {
offsets[i] = offset;
- if (splines[i]->evaluated_points_size() > 0) {
+ if (splines[i]->evaluated_points_num() > 0) {
offset += count;
}
}
@@ -104,7 +104,7 @@ static Array<int> calculate_spline_point_offsets(GeoNodeExecParams &params,
int offset = 0;
for (const int i : IndexRange(size)) {
offsets[i] = offset;
- if (splines[i]->evaluated_points_size() > 0) {
+ if (splines[i]->evaluated_points_num() > 0) {
offset += splines[i]->length() / resolution + 1;
}
}
@@ -120,11 +120,11 @@ static Array<int> calculate_spline_point_offsets(GeoNodeExecParams &params,
}
/**
- * \note: Relies on the fact that all attributes on point clouds are stored contiguously.
+ * \note Relies on the fact that all attributes on point clouds are stored contiguously.
*/
static GMutableSpan ensure_point_attribute(PointCloudComponent &points,
const AttributeIDRef &attribute_id,
- const CustomDataType data_type)
+ const eCustomDataType data_type)
{
points.attribute_try_create(attribute_id, ATTR_DOMAIN_POINT, data_type, AttributeInitDefault());
WriteAttributeLookup attribute = points.attribute_try_get_for_write(attribute_id);
@@ -240,18 +240,18 @@ static void copy_uniform_sample_point_attributes(const Span<SplinePtr> splines,
for (const int i : range) {
const Spline &spline = *splines[i];
const int offset = offsets[i];
- const int size = offsets[i + 1] - offsets[i];
- if (size == 0) {
+ const int num = offsets[i + 1] - offsets[i];
+ if (num == 0) {
continue;
}
- const Array<float> uniform_samples = spline.sample_uniform_index_factors(size);
+ const Array<float> uniform_samples = spline.sample_uniform_index_factors(num);
spline.sample_with_index_factors<float3>(
- spline.evaluated_positions(), uniform_samples, data.positions.slice(offset, size));
+ spline.evaluated_positions(), uniform_samples, data.positions.slice(offset, num));
spline.sample_with_index_factors<float>(spline.interpolate_to_evaluated(spline.radii()),
uniform_samples,
- data.radii.slice(offset, size));
+ data.radii.slice(offset, num));
for (const Map<AttributeIDRef, GMutableSpan>::Item item : data.point_attributes.items()) {
const AttributeIDRef attribute_id = item.key;
@@ -260,14 +260,13 @@ static void copy_uniform_sample_point_attributes(const Span<SplinePtr> splines,
BLI_assert(spline.attributes.get_for_read(attribute_id));
GSpan spline_span = *spline.attributes.get_for_read(attribute_id);
- spline.sample_with_index_factors(spline.interpolate_to_evaluated(spline_span),
- uniform_samples,
- dst.slice(offset, size));
+ spline.sample_with_index_factors(
+ spline.interpolate_to_evaluated(spline_span), uniform_samples, dst.slice(offset, num));
}
if (!data.tangents.is_empty()) {
Span<float3> src_tangents = spline.evaluated_tangents();
- MutableSpan<float3> sampled_tangents = data.tangents.slice(offset, size);
+ MutableSpan<float3> sampled_tangents = data.tangents.slice(offset, num);
spline.sample_with_index_factors<float3>(src_tangents, uniform_samples, sampled_tangents);
for (float3 &vector : sampled_tangents) {
vector = math::normalize(vector);
@@ -276,7 +275,7 @@ static void copy_uniform_sample_point_attributes(const Span<SplinePtr> splines,
if (!data.normals.is_empty()) {
Span<float3> src_normals = spline.evaluated_normals();
- MutableSpan<float3> sampled_normals = data.normals.slice(offset, size);
+ MutableSpan<float3> sampled_normals = data.normals.slice(offset, num);
spline.sample_with_index_factors<float3>(src_normals, uniform_samples, sampled_normals);
for (float3 &vector : sampled_normals) {
vector = math::normalize(vector);
@@ -298,8 +297,8 @@ static void copy_spline_domain_attributes(const CurveEval &curve,
for (const int i : curve.splines().index_range()) {
const int offset = offsets[i];
- const int size = offsets[i + 1] - offsets[i];
- type.fill_assign_n(curve_attribute[i], dst[offset], size);
+ const int num = offsets[i + 1] - offsets[i];
+ type.fill_assign_n(curve_attribute[i], dst[offset], num);
}
return true;
@@ -329,13 +328,13 @@ static void node_geo_exec(GeoNodeExecParams params)
curve->assert_valid_point_attributes();
const Array<int> offsets = calculate_spline_point_offsets(params, mode, *curve, splines);
- const int total_size = offsets.last();
- if (total_size == 0) {
+ const int total_num = offsets.last();
+ if (total_num == 0) {
geometry_set.keep_only({GEO_COMPONENT_TYPE_INSTANCES});
return;
}
- geometry_set.replace_pointcloud(BKE_pointcloud_new_nomain(total_size));
+ geometry_set.replace_pointcloud(BKE_pointcloud_new_nomain(total_num));
PointCloudComponent &points = geometry_set.get_component_for_write<PointCloudComponent>();
ResultAttributes point_attributes = create_attributes_for_transfer(
points, *curve, attribute_outputs);
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 df360818313..c993a3d305d 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_curve_trim.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_curve_trim.cc
@@ -117,10 +117,10 @@ struct TrimLocation {
};
template<typename T>
-static void shift_slice_to_start(MutableSpan<T> data, const int start_index, const int size)
+static void shift_slice_to_start(MutableSpan<T> data, const int start_index, const int num)
{
- BLI_assert(start_index + size - 1 <= data.size());
- memmove(data.data(), &data[start_index], sizeof(T) * size);
+ BLI_assert(start_index + num - 1 <= data.size());
+ memmove(data.data(), &data[start_index], sizeof(T) * num);
}
/* Shift slice to start of span and modifies start and end data. */
@@ -129,17 +129,17 @@ static void linear_trim_data(const TrimLocation &start,
const TrimLocation &end,
MutableSpan<T> data)
{
- const int size = end.right_index - start.left_index + 1;
+ const int num = end.right_index - start.left_index + 1;
if (start.left_index > 0) {
- shift_slice_to_start<T>(data, start.left_index, size);
+ shift_slice_to_start<T>(data, start.left_index, num);
}
const T start_data = mix2<T>(start.factor, data.first(), data[1]);
- const T end_data = mix2<T>(end.factor, data[size - 2], data[size - 1]);
+ const T end_data = mix2<T>(end.factor, data[num - 2], data[num - 1]);
data.first() = start_data;
- data[size - 1] = end_data;
+ data[num - 1] = end_data;
}
/**
@@ -152,12 +152,12 @@ static void linear_trim_to_output_data(const TrimLocation &start,
Span<T> src,
MutableSpan<T> dst)
{
- const int size = end.right_index - start.left_index + 1;
+ const int num = end.right_index - start.left_index + 1;
const T start_data = mix2<T>(start.factor, src[start.left_index], src[start.right_index]);
const T end_data = mix2<T>(end.factor, src[end.left_index], src[end.right_index]);
- dst.copy_from(src.slice(start.left_index, size));
+ dst.copy_from(src.slice(start.left_index, num));
dst.first() = start_data;
dst.last() = end_data;
}
@@ -175,8 +175,8 @@ static TrimLocation lookup_control_point_position(const Spline::LookupResult &lo
const int right = left == (spline.size() - 1) ? 0 : left + 1;
const float offset_in_segment = lookup.evaluated_index + lookup.factor - offsets[left];
- const int segment_eval_size = offsets[left + 1] - offsets[left];
- const float factor = std::clamp(offset_in_segment / segment_eval_size, 0.0f, 1.0f);
+ const int segment_eval_num = offsets[left + 1] - offsets[left];
+ const float factor = std::clamp(offset_in_segment / segment_eval_num, 0.0f, 1.0f);
return {left, right, factor};
}
@@ -191,7 +191,7 @@ static void trim_poly_spline(Spline &spline,
const TrimLocation end = {
end_lookup.evaluated_index, end_lookup.next_evaluated_index, end_lookup.factor};
- const int size = end.right_index - start.left_index + 1;
+ const int num = end.right_index - start.left_index + 1;
linear_trim_data<float3>(start, end, spline.positions());
linear_trim_data<float>(start, end, spline.radii());
@@ -209,7 +209,7 @@ static void trim_poly_spline(Spline &spline,
},
ATTR_DOMAIN_POINT);
- spline.resize(size);
+ spline.resize(num);
}
/**
@@ -225,11 +225,11 @@ static PolySpline trim_nurbs_spline(const Spline &spline,
const TrimLocation end = {
end_lookup.evaluated_index, end_lookup.next_evaluated_index, end_lookup.factor};
- const int size = end.right_index - start.left_index + 1;
+ const int num = end.right_index - start.left_index + 1;
/* Create poly spline and copy trimmed data to it. */
PolySpline new_spline;
- new_spline.resize(size);
+ new_spline.resize(num);
/* Copy generic attribute data. */
spline.attributes.foreach_attribute(
@@ -283,7 +283,7 @@ static void trim_bezier_spline(Spline &spline,
const Span<int> control_offsets = bezier_spline.control_point_offsets();
/* The number of control points in the resulting spline. */
- const int size = end.right_index - start.left_index + 1;
+ const int num = end.right_index - start.left_index + 1;
/* Trim the spline attributes. Done before end.factor recalculation as it needs
* the original end.factor value. */
@@ -301,10 +301,10 @@ static void trim_bezier_spline(Spline &spline,
},
ATTR_DOMAIN_POINT);
- /* Recalculate end.factor if the size is two, because the adjustment in the
+ /* Recalculate end.factor if the `num` is two, because the adjustment in the
* position of the control point of the spline to the left of the new end point will change the
* factor between them. */
- if (size == 2) {
+ if (num == 2) {
if (start_lookup.factor == 1.0f) {
end.factor = 0.0f;
}
@@ -328,38 +328,38 @@ static void trim_bezier_spline(Spline &spline,
const BezierSpline::InsertResult end_point = bezier_spline.calculate_segment_insertion(
end.left_index, end.right_index, end.factor);
- /* If size is two, then the start point right handle needs to change to reflect the end point
+ /* If `num` is two, then the start point right handle needs to change to reflect the end point
* previous handle update. */
- if (size == 2) {
+ if (num == 2) {
start_point.right_handle = end_point.handle_prev;
}
/* Shift control point position data to start at beginning of array. */
if (start.left_index > 0) {
- shift_slice_to_start(bezier_spline.positions(), start.left_index, size);
- shift_slice_to_start(bezier_spline.handle_positions_left(), start.left_index, size);
- shift_slice_to_start(bezier_spline.handle_positions_right(), start.left_index, size);
+ shift_slice_to_start(bezier_spline.positions(), start.left_index, num);
+ shift_slice_to_start(bezier_spline.handle_positions_left(), start.left_index, num);
+ shift_slice_to_start(bezier_spline.handle_positions_right(), start.left_index, num);
}
bezier_spline.positions().first() = start_point.position;
- bezier_spline.positions()[size - 1] = end_point.position;
+ bezier_spline.positions()[num - 1] = end_point.position;
bezier_spline.handle_positions_left().first() = start_point.left_handle;
- bezier_spline.handle_positions_left()[size - 1] = end_point.left_handle;
+ bezier_spline.handle_positions_left()[num - 1] = end_point.left_handle;
bezier_spline.handle_positions_right().first() = start_point.right_handle;
- bezier_spline.handle_positions_right()[size - 1] = end_point.right_handle;
+ bezier_spline.handle_positions_right()[num - 1] = end_point.right_handle;
/* If there is at least one control point between the endpoints, update the control
* point handle to the right of the start point and to the left of the end point. */
- if (size > 2) {
+ if (num > 2) {
bezier_spline.handle_positions_left()[start.right_index - start.left_index] =
start_point.handle_next;
bezier_spline.handle_positions_right()[end.left_index - start.left_index] =
end_point.handle_prev;
}
- bezier_spline.resize(size);
+ bezier_spline.resize(num);
}
static void trim_spline(SplinePtr &spline,
@@ -506,9 +506,9 @@ static void geometry_set_curve_trim(GeometrySet &geometry_set,
CurveComponent &component = geometry_set.get_component_for_write<CurveComponent>();
GeometryComponentFieldContext field_context{component, ATTR_DOMAIN_CURVE};
- const int domain_size = component.attribute_domain_size(ATTR_DOMAIN_CURVE);
+ const int domain_num = component.attribute_domain_num(ATTR_DOMAIN_CURVE);
- fn::FieldEvaluator evaluator{field_context, domain_size};
+ fn::FieldEvaluator evaluator{field_context, domain_num};
evaluator.add(start_field);
evaluator.add(end_field);
evaluator.evaluate();
@@ -527,7 +527,7 @@ static void geometry_set_curve_trim(GeometrySet &geometry_set,
continue;
}
- if (spline->evaluated_edges_size() == 0) {
+ if (spline->evaluated_edges_num() == 0) {
continue;
}
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 8a0c900fbde..352411dd8f5 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_delete_geometry.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_delete_geometry.cc
@@ -8,10 +8,11 @@
#include "DNA_mesh_types.h"
#include "DNA_meshdata_types.h"
+#include "BKE_attribute_math.hh"
+#include "BKE_curves.hh"
#include "BKE_customdata.h"
#include "BKE_mesh.h"
#include "BKE_pointcloud.h"
-#include "BKE_spline.hh"
#include "node_geometry_util.hh"
@@ -38,26 +39,13 @@ static void copy_data_based_on_map(Span<T> src, MutableSpan<T> dst, Span<int> in
}
}
-/** Utility function for making an IndexMask from a boolean selection. The indices vector should
- * live at least as long as the returned IndexMask.
- */
-static IndexMask index_mask_indices(Span<bool> mask, const bool invert, Vector<int64_t> &indices)
-{
- for (const int i : mask.index_range()) {
- if (mask[i] != invert) {
- indices.append(i);
- }
- }
- return IndexMask(indices);
-}
-
/**
* Copies the attributes with a domain in `domains` to `result_component`.
*/
static void copy_attributes(const Map<AttributeIDRef, AttributeKind> &attributes,
const GeometryComponent &in_component,
GeometryComponent &result_component,
- const Span<AttributeDomain> domains)
+ const Span<eAttrDomain> domains)
{
for (Map<AttributeIDRef, AttributeKind>::Item entry : attributes.items()) {
const AttributeIDRef attribute_id = entry.key;
@@ -70,7 +58,7 @@ static void copy_attributes(const Map<AttributeIDRef, AttributeKind> &attributes
if (!domains.contains(attribute.domain)) {
continue;
}
- const CustomDataType data_type = bke::cpp_type_to_custom_data_type(attribute.varray.type());
+ const eCustomDataType data_type = bke::cpp_type_to_custom_data_type(attribute.varray.type());
OutputAttribute result_attribute = result_component.attribute_try_get_for_output_only(
attribute_id, attribute.domain, data_type);
@@ -96,7 +84,7 @@ static void copy_attributes(const Map<AttributeIDRef, AttributeKind> &attributes
static void copy_attributes_based_on_mask(const Map<AttributeIDRef, AttributeKind> &attributes,
const GeometryComponent &in_component,
GeometryComponent &result_component,
- const AttributeDomain domain,
+ const eAttrDomain domain,
const IndexMask mask)
{
for (Map<AttributeIDRef, AttributeKind>::Item entry : attributes.items()) {
@@ -110,7 +98,7 @@ static void copy_attributes_based_on_mask(const Map<AttributeIDRef, AttributeKin
if (domain != attribute.domain) {
continue;
}
- const CustomDataType data_type = bke::cpp_type_to_custom_data_type(attribute.varray.type());
+ const eCustomDataType data_type = bke::cpp_type_to_custom_data_type(attribute.varray.type());
OutputAttribute result_attribute = result_component.attribute_try_get_for_output_only(
attribute_id, attribute.domain, data_type);
@@ -132,7 +120,7 @@ static void copy_attributes_based_on_mask(const Map<AttributeIDRef, AttributeKin
static void copy_attributes_based_on_map(const Map<AttributeIDRef, AttributeKind> &attributes,
const GeometryComponent &in_component,
GeometryComponent &result_component,
- const AttributeDomain domain,
+ const eAttrDomain domain,
const Span<int> index_map)
{
for (Map<AttributeIDRef, AttributeKind>::Item entry : attributes.items()) {
@@ -146,7 +134,7 @@ static void copy_attributes_based_on_map(const Map<AttributeIDRef, AttributeKind
if (domain != attribute.domain) {
continue;
}
- const CustomDataType data_type = bke::cpp_type_to_custom_data_type(attribute.varray.type());
+ const eCustomDataType data_type = bke::cpp_type_to_custom_data_type(attribute.varray.type());
OutputAttribute result_attribute = result_component.attribute_try_get_for_output_only(
attribute_id, attribute.domain, data_type);
@@ -324,190 +312,56 @@ static void copy_masked_polys_to_new_mesh(const Mesh &src_mesh,
}
}
-static void spline_copy_builtin_attributes(const Spline &spline,
- Spline &r_spline,
- const IndexMask mask)
-{
- copy_data_based_on_mask(spline.positions(), r_spline.positions(), mask);
- copy_data_based_on_mask(spline.radii(), r_spline.radii(), mask);
- copy_data_based_on_mask(spline.tilts(), r_spline.tilts(), mask);
- switch (spline.type()) {
- case CURVE_TYPE_POLY:
- break;
- case CURVE_TYPE_BEZIER: {
- const BezierSpline &src = static_cast<const BezierSpline &>(spline);
- BezierSpline &dst = static_cast<BezierSpline &>(r_spline);
- copy_data_based_on_mask(src.handle_positions_left(), dst.handle_positions_left(), mask);
- copy_data_based_on_mask(src.handle_positions_right(), dst.handle_positions_right(), mask);
- copy_data_based_on_mask(src.handle_types_left(), dst.handle_types_left(), mask);
- copy_data_based_on_mask(src.handle_types_right(), dst.handle_types_right(), mask);
- break;
- }
- case CURVE_TYPE_NURBS: {
- const NURBSpline &src = static_cast<const NURBSpline &>(spline);
- NURBSpline &dst = static_cast<NURBSpline &>(r_spline);
- copy_data_based_on_mask(src.weights(), dst.weights(), mask);
- break;
- }
- case CURVE_TYPE_CATMULL_ROM: {
- BLI_assert_unreachable();
- break;
- }
- }
-}
-
-static void copy_dynamic_attributes(const CustomDataAttributes &src,
- CustomDataAttributes &dst,
- const IndexMask mask)
-{
- src.foreach_attribute(
- [&](const AttributeIDRef &attribute_id, const AttributeMetaData &meta_data) {
- std::optional<GSpan> src_attribute = src.get_for_read(attribute_id);
- BLI_assert(src_attribute);
-
- if (!dst.create(attribute_id, meta_data.data_type)) {
- /* Since the source spline of the same type had the attribute, adding it should work.
- */
- BLI_assert_unreachable();
- }
-
- std::optional<GMutableSpan> new_attribute = dst.get_for_write(attribute_id);
- BLI_assert(new_attribute);
-
- attribute_math::convert_to_static_type(new_attribute->type(), [&](auto dummy) {
- using T = decltype(dummy);
- copy_data_based_on_mask(src_attribute->typed<T>(), new_attribute->typed<T>(), mask);
- });
- return true;
- },
- ATTR_DOMAIN_POINT);
-}
-
-/**
- * Deletes points in the spline. Those not in the mask are deleted. The spline is not split into
- * multiple newer splines.
- */
-static SplinePtr spline_delete(const Spline &spline, const IndexMask mask)
-{
- SplinePtr new_spline = spline.copy_only_settings();
- new_spline->resize(mask.size());
-
- spline_copy_builtin_attributes(spline, *new_spline, mask);
- copy_dynamic_attributes(spline.attributes, new_spline->attributes, mask);
-
- return new_spline;
-}
-
-static std::unique_ptr<CurveEval> curve_separate(const CurveEval &input_curve,
- const Span<bool> selection,
- const AttributeDomain selection_domain,
- const bool invert)
+static void delete_curves_selection(GeometrySet &geometry_set,
+ const Field<bool> &selection_field,
+ const eAttrDomain selection_domain)
{
- Span<SplinePtr> input_splines = input_curve.splines();
- std::unique_ptr<CurveEval> output_curve = std::make_unique<CurveEval>();
-
- /* Keep track of which splines were copied to the result to copy spline domain attributes. */
- Vector<int64_t> copied_splines;
-
- if (selection_domain == ATTR_DOMAIN_CURVE) {
- /* Operates on each of the splines as a whole, i.e. not on the points in the splines
- * themselves. */
- for (const int i : selection.index_range()) {
- if (selection[i] != invert) {
- output_curve->add_spline(input_splines[i]->copy());
- copied_splines.append(i);
- }
- }
- }
- else {
- /* Operates on the points in the splines themselves. */
-
- /* Reuse index vector for each spline. */
- Vector<int64_t> indices_to_copy;
-
- int selection_index = 0;
- for (const int i : input_splines.index_range()) {
- const Spline &spline = *input_splines[i];
-
- indices_to_copy.clear();
- for (const int i_point : IndexRange(spline.size())) {
- if (selection[selection_index] != invert) {
- /* Append i_point instead of selection_index because we need indices local to the spline
- * for copying. */
- indices_to_copy.append(i_point);
- }
- selection_index++;
- }
-
- /* Avoid creating an empty spline. */
- if (indices_to_copy.is_empty()) {
- continue;
- }
+ const CurveComponent &src_component = *geometry_set.get_component_for_read<CurveComponent>();
+ GeometryComponentFieldContext field_context{src_component, selection_domain};
- SplinePtr new_spline = spline_delete(spline, IndexMask(indices_to_copy));
- output_curve->add_spline(std::move(new_spline));
- copied_splines.append(i);
- }
+ const int domain_num = src_component.attribute_domain_num(selection_domain);
+ fn::FieldEvaluator evaluator{field_context, domain_num};
+ evaluator.set_selection(selection_field);
+ evaluator.evaluate();
+ const IndexMask selection = evaluator.get_evaluated_selection_as_mask();
+ if (selection.is_empty()) {
+ return;
}
-
- if (copied_splines.is_empty()) {
- return {};
+ if (selection.size() == domain_num) {
+ geometry_set.remove<CurveComponent>();
+ return;
}
- output_curve->attributes.reallocate(output_curve->splines().size());
- copy_dynamic_attributes(
- input_curve.attributes, output_curve->attributes, IndexMask(copied_splines));
-
- return output_curve;
-}
-
-static void separate_curve_selection(GeometrySet &geometry_set,
- const Field<bool> &selection_field,
- const AttributeDomain selection_domain,
- const bool invert)
-{
- const CurveComponent &src_component = *geometry_set.get_component_for_read<CurveComponent>();
- GeometryComponentFieldContext field_context{src_component, selection_domain};
+ CurveComponent &component = geometry_set.get_component_for_write<CurveComponent>();
+ Curves &curves_id = *component.get_for_write();
+ bke::CurvesGeometry &curves = bke::CurvesGeometry::wrap(curves_id.geometry);
- fn::FieldEvaluator selection_evaluator{field_context,
- src_component.attribute_domain_size(selection_domain)};
- selection_evaluator.add(selection_field);
- selection_evaluator.evaluate();
- const VArray_Span<bool> &selection = selection_evaluator.get_evaluated<bool>(0);
- std::unique_ptr<CurveEval> r_curve = curve_separate(
- *curves_to_curve_eval(*src_component.get_for_read()), selection, selection_domain, invert);
- if (r_curve) {
- geometry_set.replace_curves(curve_eval_to_curves(*r_curve));
+ if (selection_domain == ATTR_DOMAIN_POINT) {
+ curves.remove_points(selection);
}
- else {
- geometry_set.replace_curves(nullptr);
+ else if (selection_domain == ATTR_DOMAIN_CURVE) {
+ curves.remove_curves(selection);
}
}
static void separate_point_cloud_selection(GeometrySet &geometry_set,
- const Field<bool> &selection_field,
- const bool invert)
+ const Field<bool> &selection_field)
{
const PointCloudComponent &src_points =
*geometry_set.get_component_for_read<PointCloudComponent>();
GeometryComponentFieldContext field_context{src_points, ATTR_DOMAIN_POINT};
- fn::FieldEvaluator selection_evaluator{field_context,
- src_points.attribute_domain_size(ATTR_DOMAIN_POINT)};
- selection_evaluator.add(selection_field);
- selection_evaluator.evaluate();
- const VArray_Span<bool> &selection = selection_evaluator.get_evaluated<bool>(0);
-
- Vector<int64_t> indices;
- const IndexMask mask = index_mask_indices(selection, invert, indices);
- const int total = mask.size();
- PointCloud *pointcloud = BKE_pointcloud_new_nomain(total);
-
- if (total == 0) {
- geometry_set.replace_pointcloud(pointcloud);
+ fn::FieldEvaluator evaluator{field_context, src_points.attribute_domain_num(ATTR_DOMAIN_POINT)};
+ evaluator.set_selection(selection_field);
+ evaluator.evaluate();
+ const IndexMask selection = evaluator.get_evaluated_selection_as_mask();
+ if (selection.is_empty()) {
+ geometry_set.replace_pointcloud(nullptr);
return;
}
+ PointCloud *pointcloud = BKE_pointcloud_new_nomain(selection.size());
+
PointCloudComponent dst_points;
dst_points.replace(pointcloud, GeometryOwnershipType::Editable);
@@ -515,36 +369,30 @@ static void separate_point_cloud_selection(GeometrySet &geometry_set,
geometry_set.gather_attributes_for_propagation(
{GEO_COMPONENT_TYPE_POINT_CLOUD}, GEO_COMPONENT_TYPE_POINT_CLOUD, false, attributes);
- copy_attributes_based_on_mask(attributes, src_points, dst_points, ATTR_DOMAIN_POINT, mask);
+ copy_attributes_based_on_mask(attributes, src_points, dst_points, ATTR_DOMAIN_POINT, selection);
geometry_set.replace_pointcloud(pointcloud);
}
-static void separate_instance_selection(GeometrySet &geometry_set,
- const Field<bool> &selection_field,
- const bool invert)
+static void delete_selected_instances(GeometrySet &geometry_set,
+ const Field<bool> &selection_field)
{
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);
+ fn::FieldEvaluator evaluator{field_context,
+ instances.attribute_domain_num(ATTR_DOMAIN_INSTANCE)};
+ evaluator.set_selection(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()) {
+ const IndexMask selection = evaluator.get_evaluated_selection_as_mask();
+ if (selection.is_empty()) {
geometry_set.remove<InstancesComponent>();
return;
}
- instances.remove_instances(mask);
+ instances.remove_instances(selection);
}
static void compute_selected_vertices_from_vertex_selection(const Span<bool> vertex_selection,
- const bool invert,
MutableSpan<int> r_vertex_map,
int *r_selected_vertices_num)
{
@@ -552,7 +400,7 @@ static void compute_selected_vertices_from_vertex_selection(const Span<bool> ver
int selected_verts_num = 0;
for (const int i : r_vertex_map.index_range()) {
- if (vertex_selection[i] != invert) {
+ if (vertex_selection[i]) {
r_vertex_map[i] = selected_verts_num;
selected_verts_num++;
}
@@ -566,7 +414,6 @@ static void compute_selected_vertices_from_vertex_selection(const Span<bool> ver
static void compute_selected_edges_from_vertex_selection(const Mesh &mesh,
const Span<bool> vertex_selection,
- const bool invert,
MutableSpan<int> r_edge_map,
int *r_selected_edges_num)
{
@@ -577,7 +424,7 @@ static void compute_selected_edges_from_vertex_selection(const Mesh &mesh,
const MEdge &edge = mesh.medge[i];
/* Only add the edge if both vertices will be in the new mesh. */
- if (vertex_selection[edge.v1] != invert && vertex_selection[edge.v2] != invert) {
+ if (vertex_selection[edge.v1] && vertex_selection[edge.v2]) {
r_edge_map[i] = selected_edges_num;
selected_edges_num++;
}
@@ -591,7 +438,6 @@ static void compute_selected_edges_from_vertex_selection(const Mesh &mesh,
static void compute_selected_polygons_from_vertex_selection(const Mesh &mesh,
const Span<bool> vertex_selection,
- const bool invert,
Vector<int> &r_selected_poly_indices,
Vector<int> &r_loop_starts,
int *r_selected_polys_num,
@@ -609,7 +455,7 @@ static void compute_selected_polygons_from_vertex_selection(const Mesh &mesh,
bool all_verts_in_selection = true;
Span<MLoop> loops_src(&mesh.mloop[poly_src.loopstart], poly_src.totloop);
for (const MLoop &loop : loops_src) {
- if (vertex_selection[loop.v] == invert) {
+ if (!vertex_selection[loop.v]) {
all_verts_in_selection = false;
break;
}
@@ -633,7 +479,6 @@ static void compute_selected_polygons_from_vertex_selection(const Mesh &mesh,
static void compute_selected_vertices_and_edges_from_edge_selection(
const Mesh &mesh,
const Span<bool> edge_selection,
- const bool invert,
MutableSpan<int> r_vertex_map,
MutableSpan<int> r_edge_map,
int *r_selected_vertices_num,
@@ -645,7 +490,7 @@ static void compute_selected_vertices_and_edges_from_edge_selection(
int selected_verts_num = 0;
for (const int i : IndexRange(mesh.totedge)) {
const MEdge &edge = mesh.medge[i];
- if (edge_selection[i] != invert) {
+ if (edge_selection[i]) {
r_edge_map[i] = selected_edges_num;
selected_edges_num++;
if (r_vertex_map[edge.v1] == -1) {
@@ -671,7 +516,6 @@ static void compute_selected_vertices_and_edges_from_edge_selection(
*/
static void compute_selected_edges_from_edge_selection(const Mesh &mesh,
const Span<bool> edge_selection,
- const bool invert,
MutableSpan<int> r_edge_map,
int *r_selected_edges_num)
{
@@ -679,7 +523,7 @@ static void compute_selected_edges_from_edge_selection(const Mesh &mesh,
int selected_edges_num = 0;
for (const int i : IndexRange(mesh.totedge)) {
- if (edge_selection[i] != invert) {
+ if (edge_selection[i]) {
r_edge_map[i] = selected_edges_num;
selected_edges_num++;
}
@@ -697,7 +541,6 @@ static void compute_selected_edges_from_edge_selection(const Mesh &mesh,
*/
static void compute_selected_polygons_from_edge_selection(const Mesh &mesh,
const Span<bool> edge_selection,
- const bool invert,
Vector<int> &r_selected_poly_indices,
Vector<int> &r_loop_starts,
int *r_selected_polys_num,
@@ -713,7 +556,7 @@ static void compute_selected_polygons_from_edge_selection(const Mesh &mesh,
bool all_edges_in_selection = true;
Span<MLoop> loops_src(&mesh.mloop[poly_src.loopstart], poly_src.totloop);
for (const MLoop &loop : loops_src) {
- if (edge_selection[loop.e] == invert) {
+ if (!edge_selection[loop.e]) {
all_edges_in_selection = false;
break;
}
@@ -736,7 +579,6 @@ static void compute_selected_polygons_from_edge_selection(const Mesh &mesh,
static void compute_selected_mesh_data_from_vertex_selection_edge_face(
const Mesh &mesh,
const Span<bool> vertex_selection,
- const bool invert,
MutableSpan<int> r_edge_map,
Vector<int> &r_selected_poly_indices,
Vector<int> &r_loop_starts,
@@ -746,11 +588,10 @@ static void compute_selected_mesh_data_from_vertex_selection_edge_face(
{
compute_selected_edges_from_vertex_selection(
- mesh, vertex_selection, invert, r_edge_map, r_selected_edges_num);
+ mesh, vertex_selection, r_edge_map, r_selected_edges_num);
compute_selected_polygons_from_vertex_selection(mesh,
vertex_selection,
- invert,
r_selected_poly_indices,
r_loop_starts,
r_selected_polys_num,
@@ -763,7 +604,6 @@ static void compute_selected_mesh_data_from_vertex_selection_edge_face(
*/
static void compute_selected_mesh_data_from_vertex_selection(const Mesh &mesh,
const Span<bool> vertex_selection,
- const bool invert,
MutableSpan<int> r_vertex_map,
MutableSpan<int> r_edge_map,
Vector<int> &r_selected_poly_indices,
@@ -774,14 +614,13 @@ static void compute_selected_mesh_data_from_vertex_selection(const Mesh &mesh,
int *r_selected_loops_num)
{
compute_selected_vertices_from_vertex_selection(
- vertex_selection, invert, r_vertex_map, r_selected_vertices_num);
+ vertex_selection, r_vertex_map, r_selected_vertices_num);
compute_selected_edges_from_vertex_selection(
- mesh, vertex_selection, invert, r_edge_map, r_selected_edges_num);
+ mesh, vertex_selection, r_edge_map, r_selected_edges_num);
compute_selected_polygons_from_vertex_selection(mesh,
vertex_selection,
- invert,
r_selected_poly_indices,
r_loop_starts,
r_selected_polys_num,
@@ -795,7 +634,6 @@ static void compute_selected_mesh_data_from_vertex_selection(const Mesh &mesh,
static void compute_selected_mesh_data_from_edge_selection_edge_face(
const Mesh &mesh,
const Span<bool> edge_selection,
- const bool invert,
MutableSpan<int> r_edge_map,
Vector<int> &r_selected_poly_indices,
Vector<int> &r_loop_starts,
@@ -804,10 +642,9 @@ static void compute_selected_mesh_data_from_edge_selection_edge_face(
int *r_selected_loops_num)
{
compute_selected_edges_from_edge_selection(
- mesh, edge_selection, invert, r_edge_map, r_selected_edges_num);
+ mesh, edge_selection, r_edge_map, r_selected_edges_num);
compute_selected_polygons_from_edge_selection(mesh,
edge_selection,
- invert,
r_selected_poly_indices,
r_loop_starts,
r_selected_polys_num,
@@ -820,7 +657,6 @@ static void compute_selected_mesh_data_from_edge_selection_edge_face(
*/
static void compute_selected_mesh_data_from_edge_selection(const Mesh &mesh,
const Span<bool> edge_selection,
- const bool invert,
MutableSpan<int> r_vertex_map,
MutableSpan<int> r_edge_map,
Vector<int> &r_selected_poly_indices,
@@ -833,14 +669,12 @@ static void compute_selected_mesh_data_from_edge_selection(const Mesh &mesh,
r_vertex_map.fill(-1);
compute_selected_vertices_and_edges_from_edge_selection(mesh,
edge_selection,
- invert,
r_vertex_map,
r_edge_map,
r_selected_vertices_num,
r_selected_edges_num);
compute_selected_polygons_from_edge_selection(mesh,
edge_selection,
- invert,
r_selected_poly_indices,
r_loop_starts,
r_selected_polys_num,
@@ -852,7 +686,6 @@ static void compute_selected_mesh_data_from_edge_selection(const Mesh &mesh,
*/
static void compute_selected_polygons_from_poly_selection(const Mesh &mesh,
const Span<bool> poly_selection,
- const bool invert,
Vector<int> &r_selected_poly_indices,
Vector<int> &r_loop_starts,
int *r_selected_polys_num,
@@ -867,7 +700,7 @@ static void compute_selected_polygons_from_poly_selection(const Mesh &mesh,
for (const int i : IndexRange(mesh.totpoly)) {
const MPoly &poly_src = mesh.mpoly[i];
/* We keep this one. */
- if (poly_selection[i] != invert) {
+ if (poly_selection[i]) {
r_selected_poly_indices.append_unchecked(i);
r_loop_starts.append_unchecked(selected_loops_num);
selected_loops_num += poly_src.totloop;
@@ -883,7 +716,6 @@ static void compute_selected_polygons_from_poly_selection(const Mesh &mesh,
static void compute_selected_mesh_data_from_poly_selection_edge_face(
const Mesh &mesh,
const Span<bool> poly_selection,
- const bool invert,
MutableSpan<int> r_edge_map,
Vector<int> &r_selected_poly_indices,
Vector<int> &r_loop_starts,
@@ -903,7 +735,7 @@ static void compute_selected_mesh_data_from_poly_selection_edge_face(
for (const int i : IndexRange(mesh.totpoly)) {
const MPoly &poly_src = mesh.mpoly[i];
/* We keep this one. */
- if (poly_selection[i] != invert) {
+ if (poly_selection[i]) {
r_selected_poly_indices.append_unchecked(i);
r_loop_starts.append_unchecked(selected_loops_num);
selected_loops_num += poly_src.totloop;
@@ -930,7 +762,6 @@ static void compute_selected_mesh_data_from_poly_selection_edge_face(
*/
static void compute_selected_mesh_data_from_poly_selection(const Mesh &mesh,
const Span<bool> poly_selection,
- const bool invert,
MutableSpan<int> r_vertex_map,
MutableSpan<int> r_edge_map,
Vector<int> &r_selected_poly_indices,
@@ -954,7 +785,7 @@ static void compute_selected_mesh_data_from_poly_selection(const Mesh &mesh,
for (const int i : IndexRange(mesh.totpoly)) {
const MPoly &poly_src = mesh.mpoly[i];
/* We keep this one. */
- if (poly_selection[i] != invert) {
+ if (poly_selection[i]) {
r_selected_poly_indices.append_unchecked(i);
r_loop_starts.append_unchecked(selected_loops_num);
selected_loops_num += poly_src.totloop;
@@ -985,9 +816,8 @@ static void compute_selected_mesh_data_from_poly_selection(const Mesh &mesh,
*/
static void do_mesh_separation(GeometrySet &geometry_set,
const MeshComponent &in_component,
- const VArray_Span<bool> &selection,
- const bool invert,
- const AttributeDomain domain,
+ const Span<bool> selection,
+ const eAttrDomain domain,
const GeometryNodeDeleteGeometryMode mode)
{
/* Needed in all cases. */
@@ -1017,7 +847,6 @@ static void do_mesh_separation(GeometrySet &geometry_set,
case ATTR_DOMAIN_POINT:
compute_selected_mesh_data_from_vertex_selection(mesh_in,
selection,
- invert,
vertex_map,
edge_map,
selected_poly_indices,
@@ -1030,7 +859,6 @@ static void do_mesh_separation(GeometrySet &geometry_set,
case ATTR_DOMAIN_EDGE:
compute_selected_mesh_data_from_edge_selection(mesh_in,
selection,
- invert,
vertex_map,
edge_map,
selected_poly_indices,
@@ -1043,7 +871,6 @@ static void do_mesh_separation(GeometrySet &geometry_set,
case ATTR_DOMAIN_FACE:
compute_selected_mesh_data_from_poly_selection(mesh_in,
selection,
- invert,
vertex_map,
edge_map,
selected_poly_indices,
@@ -1098,7 +925,6 @@ static void do_mesh_separation(GeometrySet &geometry_set,
case ATTR_DOMAIN_POINT:
compute_selected_mesh_data_from_vertex_selection_edge_face(mesh_in,
selection,
- invert,
edge_map,
selected_poly_indices,
new_loop_starts,
@@ -1109,7 +935,6 @@ static void do_mesh_separation(GeometrySet &geometry_set,
case ATTR_DOMAIN_EDGE:
compute_selected_mesh_data_from_edge_selection_edge_face(mesh_in,
selection,
- invert,
edge_map,
selected_poly_indices,
new_loop_starts,
@@ -1120,7 +945,6 @@ static void do_mesh_separation(GeometrySet &geometry_set,
case ATTR_DOMAIN_FACE:
compute_selected_mesh_data_from_poly_selection_edge_face(mesh_in,
selection,
- invert,
edge_map,
selected_poly_indices,
new_loop_starts,
@@ -1169,7 +993,6 @@ static void do_mesh_separation(GeometrySet &geometry_set,
case ATTR_DOMAIN_POINT:
compute_selected_polygons_from_vertex_selection(mesh_in,
selection,
- invert,
selected_poly_indices,
new_loop_starts,
&selected_polys_num,
@@ -1178,7 +1001,6 @@ static void do_mesh_separation(GeometrySet &geometry_set,
case ATTR_DOMAIN_EDGE:
compute_selected_polygons_from_edge_selection(mesh_in,
selection,
- invert,
selected_poly_indices,
new_loop_starts,
&selected_polys_num,
@@ -1187,7 +1009,6 @@ static void do_mesh_separation(GeometrySet &geometry_set,
case ATTR_DOMAIN_FACE:
compute_selected_polygons_from_poly_selection(mesh_in,
selection,
- invert,
selected_poly_indices,
new_loop_starts,
&selected_polys_num,
@@ -1230,32 +1051,25 @@ static void do_mesh_separation(GeometrySet &geometry_set,
static void separate_mesh_selection(GeometrySet &geometry_set,
const Field<bool> &selection_field,
- const AttributeDomain selection_domain,
- const GeometryNodeDeleteGeometryMode mode,
- const bool invert)
+ const eAttrDomain selection_domain,
+ const GeometryNodeDeleteGeometryMode mode)
{
const MeshComponent &src_component = *geometry_set.get_component_for_read<MeshComponent>();
GeometryComponentFieldContext field_context{src_component, selection_domain};
- fn::FieldEvaluator selection_evaluator{field_context,
- src_component.attribute_domain_size(selection_domain)};
- selection_evaluator.add(selection_field);
- selection_evaluator.evaluate();
- const VArray_Span<bool> &selection = selection_evaluator.get_evaluated<bool>(0);
-
+ fn::FieldEvaluator evaluator{field_context,
+ src_component.attribute_domain_num(selection_domain)};
+ evaluator.add(selection_field);
+ evaluator.evaluate();
+ const VArray<bool> selection = evaluator.get_evaluated<bool>(0);
/* Check if there is anything to delete. */
- bool delete_nothing = true;
- for (const int i : selection.index_range()) {
- if (selection[i] == invert) {
- delete_nothing = false;
- break;
- }
- }
- if (delete_nothing) {
+ if (selection.is_single() && selection.get_internal_single()) {
return;
}
- do_mesh_separation(geometry_set, src_component, selection, invert, selection_domain, mode);
+ const VArray_Span<bool> selection_span{selection};
+
+ do_mesh_separation(geometry_set, src_component, selection_span, selection_domain, mode);
}
} // namespace blender::nodes::node_geo_delete_geometry_cc
@@ -1263,10 +1077,9 @@ static void separate_mesh_selection(GeometrySet &geometry_set,
namespace blender::nodes {
void separate_geometry(GeometrySet &geometry_set,
- const AttributeDomain domain,
+ const eAttrDomain domain,
const GeometryNodeDeleteGeometryMode mode,
const Field<bool> &selection_field,
- const bool invert,
bool &r_is_error)
{
namespace file_ns = blender::nodes::node_geo_delete_geometry_cc;
@@ -1274,25 +1087,26 @@ void separate_geometry(GeometrySet &geometry_set,
bool some_valid_domain = false;
if (geometry_set.has_pointcloud()) {
if (domain == ATTR_DOMAIN_POINT) {
- file_ns::separate_point_cloud_selection(geometry_set, selection_field, invert);
+ file_ns::separate_point_cloud_selection(geometry_set, selection_field);
some_valid_domain = true;
}
}
if (geometry_set.has_mesh()) {
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);
+ file_ns::separate_mesh_selection(geometry_set, selection_field, domain, mode);
some_valid_domain = true;
}
}
if (geometry_set.has_curves()) {
if (ELEM(domain, ATTR_DOMAIN_POINT, ATTR_DOMAIN_CURVE)) {
- file_ns::separate_curve_selection(geometry_set, selection_field, domain, invert);
+ file_ns::delete_curves_selection(
+ geometry_set, fn::invert_boolean_field(selection_field), domain);
some_valid_domain = true;
}
}
if (geometry_set.has_instances()) {
if (domain == ATTR_DOMAIN_INSTANCE) {
- file_ns::separate_instance_selection(geometry_set, selection_field, invert);
+ file_ns::delete_selected_instances(geometry_set, selection_field);
some_valid_domain = true;
}
}
@@ -1320,7 +1134,7 @@ static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
{
const bNode *node = static_cast<bNode *>(ptr->data);
const NodeGeometryDeleteGeometry &storage = node_storage(*node);
- const AttributeDomain domain = static_cast<AttributeDomain>(storage.domain);
+ const eAttrDomain domain = static_cast<eAttrDomain>(storage.domain);
uiItemR(layout, ptr, "domain", 0, "", ICON_NONE);
/* Only show the mode when it is relevant. */
@@ -1342,21 +1156,25 @@ static void node_geo_exec(GeoNodeExecParams params)
{
GeometrySet geometry_set = params.extract_input<GeometrySet>("Geometry");
- const Field<bool> selection_field = params.extract_input<Field<bool>>("Selection");
+ /* The node's input is a selection of elements that should be deleted, but the code is
+ * implemented as a separation operation that copies the selected elements to a new geometry.
+ * Invert the selection to avoid the need to keep track of both cases in the code. */
+ const Field<bool> selection = fn::invert_boolean_field(
+ params.extract_input<Field<bool>>("Selection"));
const NodeGeometryDeleteGeometry &storage = node_storage(params.node());
- const AttributeDomain domain = static_cast<AttributeDomain>(storage.domain);
+ const eAttrDomain domain = static_cast<eAttrDomain>(storage.domain);
const GeometryNodeDeleteGeometryMode mode = (GeometryNodeDeleteGeometryMode)storage.mode;
if (domain == ATTR_DOMAIN_INSTANCE) {
bool is_error;
- separate_geometry(geometry_set, domain, mode, selection_field, true, is_error);
+ separate_geometry(geometry_set, domain, mode, selection, 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);
+ separate_geometry(geometry_set, domain, mode, selection, is_error);
});
}
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 d9f29d1ef1c..f95601813a3 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
@@ -247,7 +247,7 @@ BLI_NOINLINE static void eliminate_points_based_on_mask(const Span<bool> elimina
BLI_NOINLINE static void interpolate_attribute(const Mesh &mesh,
const Span<float3> bary_coords,
const Span<int> looptri_indices,
- const AttributeDomain source_domain,
+ const eAttrDomain source_domain,
const GVArray &source_data,
GMutableSpan output_data)
{
@@ -293,7 +293,7 @@ BLI_NOINLINE static void propagate_existing_attributes(
for (Map<AttributeIDRef, AttributeKind>::Item entry : attributes.items()) {
const AttributeIDRef attribute_id = entry.key;
- const CustomDataType output_data_type = entry.value.data_type;
+ const eCustomDataType output_data_type = entry.value.data_type;
ReadAttributeLookup source_attribute = mesh_component.attribute_try_get_for_read(attribute_id);
if (!source_attribute) {
@@ -396,13 +396,13 @@ static Array<float> calc_full_density_factors_with_selection(const MeshComponent
const Field<float> &density_field,
const Field<bool> &selection_field)
{
- const AttributeDomain attribute_domain = ATTR_DOMAIN_CORNER;
+ const eAttrDomain attribute_domain = ATTR_DOMAIN_CORNER;
GeometryComponentFieldContext field_context{component, attribute_domain};
- const int domain_size = component.attribute_domain_size(attribute_domain);
+ const int domain_num = component.attribute_domain_num(attribute_domain);
- Array<float> densities(domain_size, 0.0f);
+ Array<float> densities(domain_num, 0.0f);
- fn::FieldEvaluator evaluator{field_context, domain_size};
+ fn::FieldEvaluator evaluator{field_context, domain_num};
evaluator.set_selection(selection_field);
evaluator.add_with_destination(density_field, densities.as_mutable_span());
evaluator.evaluate();
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 dcd9bcfb034..52156b59c51 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_dual_mesh.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_dual_mesh.cc
@@ -153,7 +153,7 @@ static void transfer_attributes(
continue;
}
- AttributeDomain out_domain;
+ eAttrDomain out_domain;
if (src_attribute.domain == ATTR_DOMAIN_FACE) {
out_domain = ATTR_DOMAIN_POINT;
}
@@ -164,7 +164,7 @@ static void transfer_attributes(
/* Edges and Face Corners. */
out_domain = src_attribute.domain;
}
- const CustomDataType data_type = bke::cpp_type_to_custom_data_type(
+ const eCustomDataType data_type = bke::cpp_type_to_custom_data_type(
src_attribute.varray.type());
OutputAttribute dst_attribute = dst_component.attribute_try_get_for_output_only(
attribute_id, out_domain, data_type);
diff --git a/source/blender/nodes/geometry/nodes/node_geo_duplicate_elements.cc b/source/blender/nodes/geometry/nodes/node_geo_duplicate_elements.cc
index 1b26cfe31fe..691f341b518 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_duplicate_elements.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_duplicate_elements.cc
@@ -92,12 +92,16 @@ static Array<int> accumulate_counts_to_offsets(const IndexMask selection,
/* Utility functions for threaded copying of attribute data where possible. */
template<typename T>
-static void threaded_slice_fill(Span<int> offsets, Span<T> src, MutableSpan<T> dst)
+static void threaded_slice_fill(Span<int> offsets,
+ const IndexMask selection,
+ Span<T> src,
+ MutableSpan<T> dst)
{
BLI_assert(offsets.last() == dst.size());
+ BLI_assert(selection.size() == offsets.size() - 1);
threading::parallel_for(IndexRange(offsets.size() - 1), 512, [&](IndexRange range) {
for (const int i : range) {
- dst.slice(range_for_offsets_index(offsets, i)).fill(src[i]);
+ dst.slice(range_for_offsets_index(offsets, i)).fill(src[selection[i]]);
}
});
}
@@ -128,6 +132,9 @@ static void threaded_id_offset_copy(const Span<int> offsets,
for (const int i : range) {
dst[offsets[i]] = src[i];
const int count = offsets[i + 1] - offsets[i];
+ if (count == 0) {
+ continue;
+ }
for (const int i_duplicate : IndexRange(1, count - 1)) {
dst[offsets[i] + i_duplicate] = noise::hash(src[i], i_duplicate);
}
@@ -137,7 +144,7 @@ static void threaded_id_offset_copy(const Span<int> offsets,
/** Create the copy indices for the duplication domain. */
static void create_duplicate_index_attribute(GeometryComponent &component,
- const AttributeDomain output_domain,
+ const eAttrDomain output_domain,
const IndexMask selection,
const IndexAttributes &attribute_outputs,
const Span<int> offsets)
@@ -188,6 +195,7 @@ static void copy_point_attributes_without_id(GeometrySet &geometry_set,
const GeometryComponentType component_type,
const bool include_instances,
const Span<int> offsets,
+ const IndexMask selection,
const GeometryComponent &src_component,
GeometryComponent &dst_component)
{
@@ -200,8 +208,8 @@ static void copy_point_attributes_without_id(GeometrySet &geometry_set,
if (!src_attribute || src_attribute.domain != ATTR_DOMAIN_POINT) {
continue;
}
- AttributeDomain out_domain = src_attribute.domain;
- const CustomDataType data_type = bke::cpp_type_to_custom_data_type(
+ eAttrDomain out_domain = src_attribute.domain;
+ const eCustomDataType data_type = bke::cpp_type_to_custom_data_type(
src_attribute.varray.type());
OutputAttribute dst_attribute = dst_component.attribute_try_get_for_output_only(
attribute_id, out_domain, data_type);
@@ -212,7 +220,7 @@ static void copy_point_attributes_without_id(GeometrySet &geometry_set,
using T = decltype(dummy);
VArray_Span<T> src = src_attribute.varray.typed<T>();
MutableSpan<T> dst = dst_attribute.as_span<T>();
- threaded_slice_fill<T>(offsets, src, dst);
+ threaded_slice_fill<T>(offsets, selection, src, dst);
});
dst_attribute.save();
}
@@ -246,8 +254,8 @@ static void copy_curve_attributes_without_id(const GeometrySet &geometry_set,
continue;
}
- AttributeDomain out_domain = src_attribute.domain;
- const CustomDataType data_type = bke::cpp_type_to_custom_data_type(
+ eAttrDomain out_domain = src_attribute.domain;
+ const eCustomDataType data_type = bke::cpp_type_to_custom_data_type(
src_attribute.varray.type());
OutputAttribute dst_attribute = dst_component.attribute_try_get_for_output_only(
attribute_id, out_domain, data_type);
@@ -262,7 +270,7 @@ static void copy_curve_attributes_without_id(const GeometrySet &geometry_set,
switch (out_domain) {
case ATTR_DOMAIN_CURVE:
- threaded_slice_fill<T>(curve_offsets, src, dst);
+ threaded_slice_fill<T>(curve_offsets, selection, src, dst);
break;
case ATTR_DOMAIN_POINT:
threading::parallel_for(selection.index_range(), 512, [&](IndexRange range) {
@@ -351,19 +359,19 @@ static void duplicate_curves(GeometrySet &geometry_set,
Array<int> curve_offsets(selection.size() + 1);
Array<int> point_offsets(selection.size() + 1);
- int dst_curves_size = 0;
- int dst_points_size = 0;
+ int dst_curves_num = 0;
+ int dst_points_num = 0;
for (const int i_curve : selection.index_range()) {
const int count = std::max(counts[selection[i_curve]], 0);
- curve_offsets[i_curve] = dst_curves_size;
- point_offsets[i_curve] = dst_points_size;
- dst_curves_size += count;
- dst_points_size += count * curves.points_for_curve(selection[i_curve]).size();
+ curve_offsets[i_curve] = dst_curves_num;
+ point_offsets[i_curve] = dst_points_num;
+ dst_curves_num += count;
+ dst_points_num += count * curves.points_for_curve(selection[i_curve]).size();
}
- curve_offsets.last() = dst_curves_size;
- point_offsets.last() = dst_points_size;
+ curve_offsets.last() = dst_curves_num;
+ point_offsets.last() = dst_points_num;
- Curves *new_curves_id = bke::curves_new_nomain(dst_points_size, dst_curves_size);
+ Curves *new_curves_id = bke::curves_new_nomain(dst_points_num, dst_curves_num);
bke::CurvesGeometry &new_curves = bke::CurvesGeometry::wrap(new_curves_id->geometry);
MutableSpan<int> all_dst_offsets = new_curves.offsets_for_write();
@@ -379,7 +387,7 @@ static void duplicate_curves(GeometrySet &geometry_set,
}
}
});
- all_dst_offsets.last() = dst_points_size;
+ all_dst_offsets.last() = dst_points_num;
CurveComponent dst_component;
dst_component.replace(new_curves_id, GeometryOwnershipType::Editable);
@@ -413,6 +421,7 @@ static void copy_face_attributes_without_id(GeometrySet &geometry_set,
const Span<int> vert_mapping,
const Span<int> loop_mapping,
const Span<int> offsets,
+ const IndexMask selection,
const GeometryComponent &src_component,
GeometryComponent &dst_component)
{
@@ -426,8 +435,8 @@ static void copy_face_attributes_without_id(GeometrySet &geometry_set,
continue;
}
- AttributeDomain out_domain = src_attribute.domain;
- const CustomDataType data_type = bke::cpp_type_to_custom_data_type(
+ eAttrDomain out_domain = src_attribute.domain;
+ const eCustomDataType data_type = bke::cpp_type_to_custom_data_type(
src_attribute.varray.type());
OutputAttribute dst_attribute = dst_component.attribute_try_get_for_output_only(
attribute_id, out_domain, data_type);
@@ -442,7 +451,7 @@ static void copy_face_attributes_without_id(GeometrySet &geometry_set,
switch (out_domain) {
case ATTR_DOMAIN_FACE:
- threaded_slice_fill<T>(offsets, src, dst);
+ threaded_slice_fill<T>(offsets, selection, src, dst);
break;
case ATTR_DOMAIN_EDGE:
threaded_mapped_copy<T>(edge_mapping, src, dst);
@@ -598,6 +607,7 @@ static void duplicate_faces(GeometrySet &geometry_set,
vert_mapping,
loop_mapping,
offsets,
+ selection,
src_component,
dst_component);
@@ -624,6 +634,7 @@ static void duplicate_faces(GeometrySet &geometry_set,
static void copy_edge_attributes_without_id(GeometrySet &geometry_set,
const Span<int> point_mapping,
const Span<int> offsets,
+ const IndexMask selection,
const GeometryComponent &src_component,
GeometryComponent &dst_component)
{
@@ -637,8 +648,8 @@ static void copy_edge_attributes_without_id(GeometrySet &geometry_set,
continue;
}
- const AttributeDomain out_domain = src_attribute.domain;
- const CustomDataType data_type = bke::cpp_type_to_custom_data_type(
+ const eAttrDomain out_domain = src_attribute.domain;
+ const eCustomDataType data_type = bke::cpp_type_to_custom_data_type(
src_attribute.varray.type());
OutputAttribute dst_attribute = dst_component.attribute_try_get_for_output_only(
attribute_id, out_domain, data_type);
@@ -652,7 +663,7 @@ static void copy_edge_attributes_without_id(GeometrySet &geometry_set,
switch (out_domain) {
case ATTR_DOMAIN_EDGE:
- threaded_slice_fill<T>(offsets, src, dst);
+ threaded_slice_fill<T>(offsets, selection, src, dst);
break;
case ATTR_DOMAIN_POINT:
threaded_mapped_copy<T>(point_mapping, src, dst);
@@ -690,12 +701,12 @@ static void copy_stable_id_edges(const Mesh &mesh,
VArray_Span<int> src{src_attribute.varray.typed<int>()};
MutableSpan<int> dst = dst_attribute.as_span<int>();
threading::parallel_for(IndexRange(selection.size()), 1024, [&](IndexRange range) {
- for (const int i_edge : range) {
- const IndexRange edge_range = range_for_offsets_index(edge_offsets, i_edge);
+ for (const int i_selection : range) {
+ const IndexRange edge_range = range_for_offsets_index(edge_offsets, i_selection);
if (edge_range.size() == 0) {
continue;
}
- const MEdge &edge = edges[i_edge];
+ const MEdge &edge = edges[selection[i_selection]];
const IndexRange vert_range = {edge_range.start() * 2, edge_range.size() * 2};
dst[vert_range[0]] = src[edge.v1];
@@ -739,9 +750,9 @@ static void duplicate_edges(GeometrySet &geometry_set,
Array<int> vert_orig_indices(edge_offsets.last() * 2);
threading::parallel_for(selection.index_range(), 1024, [&](IndexRange range) {
- for (const int i_edge : range) {
- const MEdge &edge = edges[i_edge];
- const IndexRange edge_range = range_for_offsets_index(edge_offsets, i_edge);
+ for (const int i_selection : range) {
+ const MEdge &edge = edges[selection[i_selection]];
+ const IndexRange edge_range = range_for_offsets_index(edge_offsets, i_selection);
const IndexRange vert_range(edge_range.start() * 2, edge_range.size() * 2);
for (const int i_duplicate : IndexRange(edge_range.size())) {
@@ -752,8 +763,8 @@ static void duplicate_edges(GeometrySet &geometry_set,
});
threading::parallel_for(selection.index_range(), 1024, [&](IndexRange range) {
- for (const int i_edge : range) {
- const IndexRange edge_range = range_for_offsets_index(edge_offsets, i_edge);
+ for (const int i_selection : range) {
+ const IndexRange edge_range = range_for_offsets_index(edge_offsets, i_selection);
const IndexRange vert_range(edge_range.start() * 2, edge_range.size() * 2);
for (const int i_duplicate : IndexRange(edge_range.size())) {
MEdge &new_edge = new_edges[edge_range[i_duplicate]];
@@ -768,7 +779,7 @@ static void duplicate_edges(GeometrySet &geometry_set,
dst_component.replace(new_mesh, GeometryOwnershipType::Editable);
copy_edge_attributes_without_id(
- geometry_set, vert_orig_indices, edge_offsets, src_component, dst_component);
+ geometry_set, vert_orig_indices, edge_offsets, selection, src_component, dst_component);
copy_stable_id_edges(mesh, selection, edge_offsets, src_component, dst_component);
@@ -807,23 +818,23 @@ static void duplicate_points_curve(GeometrySet &geometry_set,
const IndexMask selection = evaluator.get_evaluated_selection_as_mask();
Array<int> offsets = accumulate_counts_to_offsets(selection, counts);
- const int dst_size = offsets.last();
+ const int dst_num = offsets.last();
Array<int> point_to_curve_map(src_curves.points_num());
threading::parallel_for(src_curves.curves_range(), 1024, [&](const IndexRange range) {
for (const int i_curve : range) {
- const IndexRange point_range = src_curves.points_for_curve(i_curve);
- point_to_curve_map.as_mutable_span().slice(point_range).fill(i_curve);
+ const IndexRange points = src_curves.points_for_curve(i_curve);
+ point_to_curve_map.as_mutable_span().slice(points).fill(i_curve);
}
});
- Curves *new_curves_id = bke::curves_new_nomain(dst_size, dst_size);
+ Curves *new_curves_id = bke::curves_new_nomain(dst_num, dst_num);
bke::CurvesGeometry &new_curves = bke::CurvesGeometry::wrap(new_curves_id->geometry);
MutableSpan<int> new_curve_offsets = new_curves.offsets_for_write();
for (const int i : new_curves.curves_range()) {
new_curve_offsets[i] = i;
}
- new_curve_offsets.last() = dst_size;
+ new_curve_offsets.last() = dst_num;
CurveComponent dst_component;
dst_component.replace(new_curves_id, GeometryOwnershipType::Editable);
@@ -838,8 +849,8 @@ static void duplicate_points_curve(GeometrySet &geometry_set,
continue;
}
- AttributeDomain domain = src_attribute.domain;
- const CustomDataType data_type = bke::cpp_type_to_custom_data_type(
+ eAttrDomain domain = src_attribute.domain;
+ const eCustomDataType data_type = bke::cpp_type_to_custom_data_type(
src_attribute.varray.type());
OutputAttribute dst_attribute = dst_component.attribute_try_get_for_output_only(
attribute_id, domain, data_type);
@@ -863,7 +874,7 @@ static void duplicate_points_curve(GeometrySet &geometry_set,
});
break;
case ATTR_DOMAIN_POINT:
- threaded_slice_fill(offsets, src, dst);
+ threaded_slice_fill(offsets, selection, src, dst);
break;
default:
break;
@@ -910,12 +921,17 @@ static void duplicate_points_mesh(GeometrySet &geometry_set,
Mesh *new_mesh = BKE_mesh_new_nomain(offsets.last(), 0, 0, 0, 0);
MutableSpan<MVert> dst_verts(new_mesh->mvert, new_mesh->totvert);
- threaded_slice_fill(offsets.as_span(), src_verts, dst_verts);
+ threaded_slice_fill(offsets.as_span(), selection, src_verts, dst_verts);
MeshComponent dst_component;
dst_component.replace(new_mesh, GeometryOwnershipType::Editable);
- copy_point_attributes_without_id(
- geometry_set, GEO_COMPONENT_TYPE_MESH, false, offsets, src_component, dst_component);
+ copy_point_attributes_without_id(geometry_set,
+ GEO_COMPONENT_TYPE_MESH,
+ false,
+ offsets,
+ selection,
+ src_component,
+ dst_component);
copy_stable_id_point(offsets, src_component, dst_component);
@@ -940,10 +956,10 @@ static void duplicate_points_pointcloud(GeometrySet &geometry_set,
{
const PointCloudComponent &src_points =
*geometry_set.get_component_for_read<PointCloudComponent>();
- const int point_size = src_points.attribute_domain_size(ATTR_DOMAIN_POINT);
+ const int point_num = src_points.attribute_domain_num(ATTR_DOMAIN_POINT);
GeometryComponentFieldContext field_context{src_points, ATTR_DOMAIN_POINT};
- FieldEvaluator evaluator{field_context, point_size};
+ FieldEvaluator evaluator{field_context, point_num};
evaluator.add(count_field);
evaluator.set_selection(selection_field);
evaluator.evaluate();
@@ -956,8 +972,13 @@ static void duplicate_points_pointcloud(GeometrySet &geometry_set,
PointCloudComponent dst_component;
dst_component.replace(pointcloud, GeometryOwnershipType::Editable);
- copy_point_attributes_without_id(
- geometry_set, GEO_COMPONENT_TYPE_POINT_CLOUD, false, offsets, src_points, dst_component);
+ copy_point_attributes_without_id(geometry_set,
+ GEO_COMPONENT_TYPE_POINT_CLOUD,
+ false,
+ offsets,
+ selection,
+ src_points,
+ dst_component);
copy_stable_id_point(offsets, src_points, dst_component);
@@ -1026,7 +1047,7 @@ static void duplicate_instances(GeometrySet &geometry_set,
*geometry_set.get_component_for_read<InstancesComponent>();
GeometryComponentFieldContext field_context{src_instances, ATTR_DOMAIN_INSTANCE};
- FieldEvaluator evaluator{field_context, src_instances.instances_amount()};
+ FieldEvaluator evaluator{field_context, src_instances.instances_num()};
evaluator.add(count_field);
evaluator.set_selection(selection_field);
evaluator.evaluate();
@@ -1055,8 +1076,13 @@ static void duplicate_instances(GeometrySet &geometry_set,
dst_instances.instance_reference_handles().slice(range).fill(new_handle);
}
- copy_point_attributes_without_id(
- geometry_set, GEO_COMPONENT_TYPE_INSTANCES, true, offsets, src_instances, dst_instances);
+ copy_point_attributes_without_id(geometry_set,
+ GEO_COMPONENT_TYPE_INSTANCES,
+ true,
+ offsets,
+ selection,
+ src_instances,
+ dst_instances);
if (attribute_outputs.duplicate_index) {
create_duplicate_index_attribute(
@@ -1077,7 +1103,7 @@ static void node_geo_exec(GeoNodeExecParams params)
GeometrySet geometry_set = params.extract_input<GeometrySet>("Geometry");
const NodeGeometryDuplicateElements &storage = node_storage(params.node());
- const AttributeDomain duplicate_domain = AttributeDomain(storage.domain);
+ const eAttrDomain duplicate_domain = eAttrDomain(storage.domain);
Field<int> count_field = params.extract_input<Field<int>>("Amount");
Field<bool> selection_field = params.extract_input<Field<bool>>("Selection");
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 84acab47661..94fbec66bfe 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_edge_split.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_edge_split.cc
@@ -57,8 +57,8 @@ static void node_geo_exec(GeoNodeExecParams params)
const MeshComponent &mesh_component = *geometry_set.get_component_for_read<MeshComponent>();
GeometryComponentFieldContext field_context{mesh_component, ATTR_DOMAIN_EDGE};
- const int domain_size = mesh_component.attribute_domain_size(ATTR_DOMAIN_EDGE);
- fn::FieldEvaluator selection_evaluator{field_context, domain_size};
+ const int domain_num = mesh_component.attribute_domain_num(ATTR_DOMAIN_EDGE);
+ fn::FieldEvaluator selection_evaluator{field_context, domain_num};
selection_evaluator.add(selection_field);
selection_evaluator.evaluate();
const IndexMask selection = selection_evaluator.get_evaluated_as_mask(0);
diff --git a/source/blender/nodes/geometry/nodes/node_geo_extrude_mesh.cc b/source/blender/nodes/geometry/nodes/node_geo_extrude_mesh.cc
index 4591cfa1da2..3eca92e37a3 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_extrude_mesh.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_extrude_mesh.cc
@@ -63,7 +63,7 @@ struct AttributeOutputs {
static void save_selection_as_attribute(MeshComponent &component,
const AnonymousAttributeID *id,
- const AttributeDomain domain,
+ const eAttrDomain domain,
const IndexMask selection)
{
BLI_assert(!component.attribute_exists(id));
@@ -109,7 +109,7 @@ static MutableSpan<MLoop> mesh_loops(Mesh &mesh)
}
/**
- * \note: Some areas in this file rely on the new sections of attributes from #CustomData_realloc
+ * \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,
@@ -145,6 +145,34 @@ static void expand_mesh(Mesh &mesh,
BKE_mesh_update_customdata_pointers(&mesh, false);
}
+static CustomData &get_customdata(Mesh &mesh, const eAttrDomain domain)
+{
+ switch (domain) {
+ case ATTR_DOMAIN_POINT:
+ return mesh.vdata;
+ case ATTR_DOMAIN_EDGE:
+ return mesh.edata;
+ case ATTR_DOMAIN_FACE:
+ return mesh.pdata;
+ case ATTR_DOMAIN_CORNER:
+ return mesh.ldata;
+ default:
+ BLI_assert_unreachable();
+ return mesh.vdata;
+ }
+}
+
+static MutableSpan<int> get_orig_index_layer(Mesh &mesh, const eAttrDomain domain)
+{
+ MeshComponent component;
+ component.replace(&mesh, GeometryOwnershipType::ReadOnly);
+ CustomData &custom_data = get_customdata(mesh, domain);
+ if (int *orig_indices = static_cast<int *>(CustomData_get_layer(&custom_data, CD_ORIGINDEX))) {
+ return {orig_indices, component.attribute_domain_num(domain)};
+ }
+ return {};
+}
+
static MEdge new_edge(const int v1, const int v2)
{
MEdge edge;
@@ -292,6 +320,9 @@ static void extrude_mesh_vertices(MeshComponent &component,
});
});
+ MutableSpan<int> vert_orig_indices = get_orig_index_layer(mesh, ATTR_DOMAIN_POINT);
+ vert_orig_indices.slice(new_vert_range).fill(ORIGINDEX_NONE);
+
if (attribute_outputs.top_id) {
save_selection_as_attribute(
component, attribute_outputs.top_id.get(), ATTR_DOMAIN_POINT, new_vert_range);
@@ -615,6 +646,13 @@ static void extrude_mesh_edges(MeshComponent &component,
});
}
+ MutableSpan<int> vert_orig_indices = get_orig_index_layer(mesh, ATTR_DOMAIN_POINT);
+ vert_orig_indices.slice(new_vert_range).fill(ORIGINDEX_NONE);
+
+ MutableSpan<int> edge_orig_indices = get_orig_index_layer(mesh, ATTR_DOMAIN_EDGE);
+ edge_orig_indices.slice(connect_edge_range).fill(ORIGINDEX_NONE);
+ edge_orig_indices.slice(duplicate_edge_range).fill(ORIGINDEX_NONE);
+
if (attribute_outputs.top_id) {
save_selection_as_attribute(
component, attribute_outputs.top_id.get(), ATTR_DOMAIN_EDGE, duplicate_edge_range);
@@ -983,6 +1021,17 @@ static void extrude_mesh_face_regions(MeshComponent &component,
});
}
+ MutableSpan<int> vert_orig_indices = get_orig_index_layer(mesh, ATTR_DOMAIN_POINT);
+ vert_orig_indices.slice(new_vert_range).fill(ORIGINDEX_NONE);
+
+ MutableSpan<int> edge_orig_indices = get_orig_index_layer(mesh, ATTR_DOMAIN_EDGE);
+ edge_orig_indices.slice(connect_edge_range).fill(ORIGINDEX_NONE);
+ edge_orig_indices.slice(new_inner_edge_range).fill(ORIGINDEX_NONE);
+ edge_orig_indices.slice(boundary_edge_range).fill(ORIGINDEX_NONE);
+
+ MutableSpan<int> poly_orig_indices = get_orig_index_layer(mesh, ATTR_DOMAIN_FACE);
+ poly_orig_indices.slice(side_poly_range).fill(ORIGINDEX_NONE);
+
if (attribute_outputs.top_id) {
save_selection_as_attribute(
component, attribute_outputs.top_id.get(), ATTR_DOMAIN_FACE, poly_selection);
@@ -1232,6 +1281,16 @@ static void extrude_individual_mesh_faces(MeshComponent &component,
}
});
+ MutableSpan<int> vert_orig_indices = get_orig_index_layer(mesh, ATTR_DOMAIN_POINT);
+ vert_orig_indices.slice(new_vert_range).fill(ORIGINDEX_NONE);
+
+ MutableSpan<int> edge_orig_indices = get_orig_index_layer(mesh, ATTR_DOMAIN_EDGE);
+ edge_orig_indices.slice(connect_edge_range).fill(ORIGINDEX_NONE);
+ edge_orig_indices.slice(duplicate_edge_range).fill(ORIGINDEX_NONE);
+
+ MutableSpan<int> poly_orig_indices = get_orig_index_layer(mesh, ATTR_DOMAIN_FACE);
+ poly_orig_indices.slice(side_poly_range).fill(ORIGINDEX_NONE);
+
/* 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. */
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
index 77be98f169e..58281df43d3 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_field_at_index.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_field_at_index.cc
@@ -42,7 +42,7 @@ static void node_init(bNodeTree *UNUSED(tree), bNode *node)
static void node_update(bNodeTree *ntree, bNode *node)
{
- const CustomDataType data_type = static_cast<CustomDataType>(node->custom2);
+ const eCustomDataType data_type = static_cast<eCustomDataType>(node->custom2);
bNodeSocket *sock_index = static_cast<bNodeSocket *>(node->inputs.first);
bNodeSocket *sock_in_float = sock_index->next;
@@ -74,10 +74,10 @@ class FieldAtIndex final : public GeometryFieldInput {
private:
Field<int> index_field_;
GField value_field_;
- AttributeDomain value_field_domain_;
+ eAttrDomain value_field_domain_;
public:
- FieldAtIndex(Field<int> index_field, GField value_field, AttributeDomain value_field_domain)
+ FieldAtIndex(Field<int> index_field, GField value_field, eAttrDomain value_field_domain)
: GeometryFieldInput(value_field.cpp_type(), "Field at Index"),
index_field_(std::move(index_field)),
value_field_(std::move(value_field)),
@@ -86,12 +86,12 @@ class FieldAtIndex final : public GeometryFieldInput {
}
GVArray get_varray_for_context(const GeometryComponent &component,
- const AttributeDomain domain,
+ const eAttrDomain 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_)};
+ component.attribute_domain_num(value_field_domain_)};
value_evaluator.add(value_field_);
value_evaluator.evaluate();
const GVArray &values = value_evaluator.get_evaluated(0);
@@ -125,7 +125,7 @@ class FieldAtIndex final : public GeometryFieldInput {
}
};
-static StringRefNull identifier_suffix(CustomDataType data_type)
+static StringRefNull identifier_suffix(eCustomDataType data_type)
{
switch (data_type) {
case CD_PROP_BOOL:
@@ -147,8 +147,8 @@ static StringRefNull identifier_suffix(CustomDataType data_type)
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);
+ const eAttrDomain domain = static_cast<eAttrDomain>(node.custom1);
+ const eCustomDataType data_type = static_cast<eCustomDataType>(node.custom2);
Field<int> index_field = params.extract_input<Field<int>>("Index");
attribute_math::convert_to_static_type(data_type, [&](auto dummy) {
diff --git a/source/blender/nodes/geometry/nodes/node_geo_flip_faces.cc b/source/blender/nodes/geometry/nodes/node_geo_flip_faces.cc
index 34c3169065c..0484017cf3b 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_flip_faces.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_flip_faces.cc
@@ -22,11 +22,11 @@ static void node_declare(NodeDeclarationBuilder &b)
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) {
+ const int domain_num = component.attribute_domain_num(ATTR_DOMAIN_FACE);
+ if (domain_num == 0) {
return;
}
- fn::FieldEvaluator evaluator{field_context, domain_size};
+ fn::FieldEvaluator evaluator{field_context, domain_num};
evaluator.add(selection_field);
evaluator.evaluate();
const IndexMask selection = evaluator.get_evaluated_as_mask(0);
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 3ba1378abe1..da249278867 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
@@ -26,7 +26,7 @@ class HandlePositionFieldInput final : public GeometryFieldInput {
}
GVArray get_varray_for_context(const GeometryComponent &component,
- const AttributeDomain domain,
+ const eAttrDomain domain,
IndexMask mask) const final
{
if (component.type() != GEO_COMPONENT_TYPE_CURVE) {
diff --git a/source/blender/nodes/geometry/nodes/node_geo_input_instance_rotation.cc b/source/blender/nodes/geometry/nodes/node_geo_input_instance_rotation.cc
new file mode 100644
index 00000000000..4c7a148a797
--- /dev/null
+++ b/source/blender/nodes/geometry/nodes/node_geo_input_instance_rotation.cc
@@ -0,0 +1,65 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+
+#include "node_geometry_util.hh"
+
+namespace blender::nodes::node_geo_input_instance_rotation_cc {
+
+static void node_declare(NodeDeclarationBuilder &b)
+{
+ b.add_output<decl::Vector>(N_("Rotation")).field_source();
+}
+
+class VectorFieldInput final : public GeometryFieldInput {
+ public:
+ VectorFieldInput() : GeometryFieldInput(CPPType::get<float3>(), "Rotation")
+ {
+ }
+
+ GVArray get_varray_for_context(const GeometryComponent &component,
+ const eAttrDomain UNUSED(domain),
+ IndexMask UNUSED(mask)) const final
+ {
+ if (component.type() != GEO_COMPONENT_TYPE_INSTANCES) {
+ return {};
+ }
+
+ const InstancesComponent &instance_component = static_cast<const InstancesComponent &>(
+ component);
+
+ auto rotation_fn = [&](const int i) -> float3 {
+ return instance_component.instance_transforms()[i].to_euler();
+ };
+
+ return VArray<float3>::ForFunc(instance_component.instances_num(), rotation_fn);
+ }
+
+ uint64_t hash() const override
+ {
+ return 22374372;
+ }
+
+ bool is_equal_to(const fn::FieldNode &other) const override
+ {
+ return dynamic_cast<const VectorFieldInput *>(&other) != nullptr;
+ }
+};
+
+static void node_geo_exec(GeoNodeExecParams params)
+{
+ Field<float3> rotation{std::make_shared<VectorFieldInput>()};
+ params.set_output("Rotation", std::move(rotation));
+}
+
+} // namespace blender::nodes::node_geo_input_instance_rotation_cc
+
+void register_node_type_geo_input_instance_rotation()
+{
+ namespace file_ns = blender::nodes::node_geo_input_instance_rotation_cc;
+
+ static bNodeType ntype;
+ geo_node_type_base(
+ &ntype, GEO_NODE_INPUT_INSTANCE_ROTATION, "Instance Rotation", 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_instance_scale.cc b/source/blender/nodes/geometry/nodes/node_geo_input_instance_scale.cc
new file mode 100644
index 00000000000..b3a362fbf3e
--- /dev/null
+++ b/source/blender/nodes/geometry/nodes/node_geo_input_instance_scale.cc
@@ -0,0 +1,64 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+
+#include "node_geometry_util.hh"
+
+namespace blender::nodes::node_geo_input_instance_scale_cc {
+
+static void node_declare(NodeDeclarationBuilder &b)
+{
+ b.add_output<decl::Vector>(N_("Scale")).field_source();
+}
+
+class VectorFieldInput final : public GeometryFieldInput {
+ public:
+ VectorFieldInput() : GeometryFieldInput(CPPType::get<float3>(), "Scale")
+ {
+ }
+
+ GVArray get_varray_for_context(const GeometryComponent &component,
+ const eAttrDomain UNUSED(domain),
+ IndexMask UNUSED(mask)) const final
+ {
+ if (component.type() != GEO_COMPONENT_TYPE_INSTANCES) {
+ return {};
+ }
+
+ const InstancesComponent &instance_component = static_cast<const InstancesComponent &>(
+ component);
+
+ auto scale_fn = [&](const int i) -> float3 {
+ return instance_component.instance_transforms()[i].scale();
+ };
+
+ return VArray<float3>::ForFunc(instance_component.instances_num(), scale_fn);
+ }
+
+ uint64_t hash() const override
+ {
+ return 8346343;
+ }
+
+ bool is_equal_to(const fn::FieldNode &other) const override
+ {
+ return dynamic_cast<const VectorFieldInput *>(&other) != nullptr;
+ }
+};
+
+static void node_geo_exec(GeoNodeExecParams params)
+{
+ Field<float3> scale{std::make_shared<VectorFieldInput>()};
+ params.set_output("Scale", std::move(scale));
+}
+
+} // namespace blender::nodes::node_geo_input_instance_scale_cc
+
+void register_node_type_geo_input_instance_scale()
+{
+ namespace file_ns = blender::nodes::node_geo_input_instance_scale_cc;
+
+ static bNodeType ntype;
+ geo_node_type_base(&ntype, GEO_NODE_INPUT_INSTANCE_SCALE, "Instance Scale", 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
index 60640bcb112..f27e0305c7d 100644
--- 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
@@ -61,7 +61,7 @@ class AngleFieldInput final : public GeometryFieldInput {
}
GVArray get_varray_for_context(const GeometryComponent &component,
- const AttributeDomain domain,
+ const eAttrDomain domain,
IndexMask UNUSED(mask)) const final
{
if (component.type() != GEO_COMPONENT_TYPE_MESH) {
@@ -115,7 +115,7 @@ class SignedAngleFieldInput final : public GeometryFieldInput {
}
GVArray get_varray_for_context(const GeometryComponent &component,
- const AttributeDomain domain,
+ const eAttrDomain domain,
IndexMask UNUSED(mask)) const final
{
if (component.type() != GEO_COMPONENT_TYPE_MESH) {
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 92172ce7ebd..cbc2ebc3e68 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
@@ -25,7 +25,7 @@ class EdgeNeighborCountFieldInput final : public GeometryFieldInput {
}
GVArray get_varray_for_context(const GeometryComponent &component,
- const AttributeDomain domain,
+ const eAttrDomain domain,
IndexMask UNUSED(mask)) const final
{
if (component.type() == GEO_COMPONENT_TYPE_MESH) {
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 213a692d80f..6201ad26bfb 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
@@ -29,7 +29,7 @@ enum VertexNumber { VERTEX_ONE, VERTEX_TWO };
static VArray<int> construct_edge_vertices_gvarray(const MeshComponent &component,
const VertexNumber vertex,
- const AttributeDomain domain)
+ const eAttrDomain domain)
{
const Mesh *mesh = component.get_for_read();
if (mesh == nullptr) {
@@ -58,7 +58,7 @@ class EdgeVerticesFieldInput final : public GeometryFieldInput {
}
GVArray get_varray_for_context(const GeometryComponent &component,
- const AttributeDomain domain,
+ const eAttrDomain domain,
IndexMask UNUSED(mask)) const final
{
if (component.type() == GEO_COMPONENT_TYPE_MESH) {
@@ -85,7 +85,7 @@ class EdgeVerticesFieldInput final : public GeometryFieldInput {
static VArray<float3> construct_edge_positions_gvarray(const MeshComponent &component,
const VertexNumber vertex,
- const AttributeDomain domain)
+ const eAttrDomain domain)
{
const Mesh *mesh = component.get_for_read();
if (mesh == nullptr) {
@@ -120,7 +120,7 @@ class EdgePositionFieldInput final : public GeometryFieldInput {
}
GVArray get_varray_for_context(const GeometryComponent &component,
- const AttributeDomain domain,
+ const eAttrDomain domain,
IndexMask UNUSED(mask)) const final
{
if (component.type() == GEO_COMPONENT_TYPE_MESH) {
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 6f58d28100a..7a0e3e37a65 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
@@ -17,7 +17,7 @@ static void node_declare(NodeDeclarationBuilder &b)
}
static VArray<float> construct_face_area_gvarray(const MeshComponent &component,
- const AttributeDomain domain)
+ const eAttrDomain domain)
{
const Mesh *mesh = component.get_for_read();
if (mesh == nullptr) {
@@ -41,7 +41,7 @@ class FaceAreaFieldInput final : public GeometryFieldInput {
}
GVArray get_varray_for_context(const GeometryComponent &component,
- const AttributeDomain domain,
+ const eAttrDomain domain,
IndexMask UNUSED(mask)) const final
{
if (component.type() == GEO_COMPONENT_TYPE_MESH) {
diff --git a/source/blender/nodes/geometry/nodes/node_geo_input_mesh_face_is_planar.cc b/source/blender/nodes/geometry/nodes/node_geo_input_mesh_face_is_planar.cc
index 62af0476057..532c3dc81e5 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_input_mesh_face_is_planar.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_input_mesh_face_is_planar.cc
@@ -34,7 +34,7 @@ class PlanarFieldInput final : public GeometryFieldInput {
}
GVArray get_varray_for_context(const GeometryComponent &component,
- const AttributeDomain domain,
+ const eAttrDomain domain,
[[maybe_unused]] IndexMask mask) const final
{
if (component.type() != GEO_COMPONENT_TYPE_MESH) {
@@ -65,7 +65,7 @@ class PlanarFieldInput final : public GeometryFieldInput {
float3 reference_normal = poly_normals[i_poly];
float min = FLT_MAX;
- float max = FLT_MIN;
+ float max = -FLT_MAX;
for (const int i_loop : poly_loops.index_range()) {
const float3 vert = mesh->mvert[poly_loops[i_loop].v].co;
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 9968c53f649..67a21cb06f0 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
@@ -20,7 +20,7 @@ static void node_declare(NodeDeclarationBuilder &b)
}
static VArray<int> construct_neighbor_count_gvarray(const MeshComponent &component,
- const AttributeDomain domain)
+ const eAttrDomain domain)
{
const Mesh *mesh = component.get_for_read();
if (mesh == nullptr) {
@@ -53,7 +53,7 @@ class FaceNeighborCountFieldInput final : public GeometryFieldInput {
}
GVArray get_varray_for_context(const GeometryComponent &component,
- const AttributeDomain domain,
+ const eAttrDomain domain,
IndexMask UNUSED(mask)) const final
{
if (component.type() == GEO_COMPONENT_TYPE_MESH) {
@@ -76,7 +76,7 @@ class FaceNeighborCountFieldInput final : public GeometryFieldInput {
};
static VArray<int> construct_vertex_count_gvarray(const MeshComponent &component,
- const AttributeDomain domain)
+ const eAttrDomain domain)
{
const Mesh *mesh = component.get_for_read();
if (mesh == nullptr) {
@@ -98,7 +98,7 @@ class FaceVertexCountFieldInput final : public GeometryFieldInput {
}
GVArray get_varray_for_context(const GeometryComponent &component,
- const AttributeDomain domain,
+ const eAttrDomain domain,
IndexMask UNUSED(mask)) const final
{
if (component.type() == GEO_COMPONENT_TYPE_MESH) {
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 d39291a2a7e..bd57924d685 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
@@ -30,7 +30,7 @@ class IslandFieldInput final : public GeometryFieldInput {
}
GVArray get_varray_for_context(const GeometryComponent &component,
- const AttributeDomain domain,
+ const eAttrDomain domain,
IndexMask UNUSED(mask)) const final
{
if (component.type() != GEO_COMPONENT_TYPE_MESH) {
@@ -78,7 +78,7 @@ class IslandCountFieldInput final : public GeometryFieldInput {
}
GVArray get_varray_for_context(const GeometryComponent &component,
- const AttributeDomain domain,
+ const eAttrDomain domain,
IndexMask UNUSED(mask)) const final
{
if (component.type() != GEO_COMPONENT_TYPE_MESH) {
@@ -101,8 +101,7 @@ class IslandCountFieldInput final : public GeometryFieldInput {
island_list.add(root);
}
- return VArray<int>::ForSingle(island_list.size(),
- mesh_component.attribute_domain_size(domain));
+ return VArray<int>::ForSingle(island_list.size(), mesh_component.attribute_domain_num(domain));
}
uint64_t hash() const override
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 b81016eda18..62b3f9d0e92 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
@@ -21,7 +21,7 @@ static void node_declare(NodeDeclarationBuilder &b)
}
static VArray<int> construct_vertex_count_gvarray(const MeshComponent &component,
- const AttributeDomain domain)
+ const eAttrDomain domain)
{
const Mesh *mesh = component.get_for_read();
if (mesh == nullptr) {
@@ -47,7 +47,7 @@ class VertexCountFieldInput final : public GeometryFieldInput {
}
GVArray get_varray_for_context(const GeometryComponent &component,
- const AttributeDomain domain,
+ const eAttrDomain domain,
IndexMask UNUSED(mask)) const final
{
if (component.type() == GEO_COMPONENT_TYPE_MESH) {
@@ -70,7 +70,7 @@ class VertexCountFieldInput final : public GeometryFieldInput {
};
static VArray<int> construct_face_count_gvarray(const MeshComponent &component,
- const AttributeDomain domain)
+ const eAttrDomain domain)
{
const Mesh *mesh = component.get_for_read();
if (mesh == nullptr) {
@@ -96,7 +96,7 @@ class VertexFaceCountFieldInput final : public GeometryFieldInput {
}
GVArray get_varray_for_context(const GeometryComponent &component,
- const AttributeDomain domain,
+ const eAttrDomain domain,
IndexMask UNUSED(mask)) const final
{
if (component.type() == GEO_COMPONENT_TYPE_MESH) {
diff --git a/source/blender/nodes/geometry/nodes/node_geo_input_named_attribute.cc b/source/blender/nodes/geometry/nodes/node_geo_input_named_attribute.cc
index 72dfff7cb39..122c7b352c7 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_input_named_attribute.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_input_named_attribute.cc
@@ -37,7 +37,7 @@ static void node_init(bNodeTree *UNUSED(tree), bNode *node)
static void node_update(bNodeTree *ntree, bNode *node)
{
const NodeGeometryInputNamedAttribute &storage = node_storage(*node);
- const CustomDataType data_type = static_cast<CustomDataType>(storage.data_type);
+ const eCustomDataType data_type = static_cast<eCustomDataType>(storage.data_type);
bNodeSocket *socket_vector = (bNodeSocket *)node->outputs.first;
bNodeSocket *socket_float = socket_vector->next;
@@ -58,7 +58,7 @@ static void node_gather_link_searches(GatherLinkSearchOpParams &params)
search_link_ops_for_declarations(params, declaration.inputs());
if (params.in_out() == SOCK_OUT) {
- const std::optional<CustomDataType> type = node_data_type_to_custom_data_type(
+ const std::optional<eCustomDataType> type = node_data_type_to_custom_data_type(
static_cast<eNodeSocketDatatype>(params.other_socket().type));
if (type && *type != CD_PROP_STRING) {
/* The input and output sockets have the same name. */
@@ -74,7 +74,7 @@ static void node_gather_link_searches(GatherLinkSearchOpParams &params)
static void node_geo_exec(GeoNodeExecParams params)
{
const NodeGeometryInputNamedAttribute &storage = node_storage(params.node());
- const CustomDataType data_type = static_cast<CustomDataType>(storage.data_type);
+ const eCustomDataType data_type = static_cast<eCustomDataType>(storage.data_type);
const std::string name = params.extract_input<std::string>("Name");
@@ -82,8 +82,13 @@ static void node_geo_exec(GeoNodeExecParams params)
params.set_default_remaining_outputs();
return;
}
+ if (!bke::allow_procedural_attribute_access(name)) {
+ params.error_message_add(NodeWarningType::Info, TIP_(bke::no_procedural_access_message));
+ params.set_default_remaining_outputs();
+ return;
+ }
- params.used_named_attribute(name, NamedAttributeUsage::Read);
+ params.used_named_attribute(name, eNamedAttrUsage::Read);
switch (data_type) {
case CD_PROP_FLOAT:
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 84d773ff8eb..def82eefca5 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
@@ -17,7 +17,7 @@ static void node_declare(NodeDeclarationBuilder &b)
*/
static VArray<int> construct_curve_point_count_gvarray(const CurveComponent &component,
- const AttributeDomain domain)
+ const eAttrDomain domain)
{
if (!component.has_curves()) {
return {};
@@ -47,7 +47,7 @@ class SplineCountFieldInput final : public GeometryFieldInput {
}
GVArray get_varray_for_context(const GeometryComponent &component,
- const AttributeDomain domain,
+ const eAttrDomain domain,
IndexMask UNUSED(mask)) const final
{
if (component.type() == GEO_COMPONENT_TYPE_CURVE) {
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 039d6b69585..f5831941094 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_input_tangent.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_input_tangent.cc
@@ -64,7 +64,7 @@ static Array<float3> curve_tangent_point_domain(const bke::CurvesGeometry &curve
}
static VArray<float3> construct_curve_tangent_gvarray(const CurveComponent &component,
- const AttributeDomain domain)
+ const eAttrDomain domain)
{
if (!component.has_curves()) {
return {};
@@ -101,7 +101,7 @@ class TangentFieldInput final : public GeometryFieldInput {
}
GVArray get_varray_for_context(const GeometryComponent &component,
- const AttributeDomain domain,
+ const eAttrDomain domain,
IndexMask UNUSED(mask)) const final
{
if (component.type() == GEO_COMPONENT_TYPE_CURVE) {
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 61f719ade4e..21ef8765e43 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
@@ -49,8 +49,8 @@ static void add_instances_from_component(
const GeoNodeExecParams &params,
const Map<AttributeIDRef, AttributeKind> &attributes_to_propagate)
{
- const AttributeDomain domain = ATTR_DOMAIN_POINT;
- const int domain_size = src_component.attribute_domain_size(domain);
+ const eAttrDomain domain = ATTR_DOMAIN_POINT;
+ const int domain_num = src_component.attribute_domain_num(domain);
VArray<bool> pick_instance;
VArray<int> indices;
@@ -59,7 +59,7 @@ static void add_instances_from_component(
GeometryComponentFieldContext field_context{src_component, domain};
const Field<bool> selection_field = params.get_input<Field<bool>>("Selection");
- fn::FieldEvaluator evaluator{field_context, domain_size};
+ fn::FieldEvaluator evaluator{field_context, domain_num};
evaluator.set_selection(selection_field);
/* The evaluator could use the component's stable IDs as a destination directly, but only the
* selected indices should be copied. */
@@ -73,7 +73,7 @@ static void add_instances_from_component(
/* The initial size of the component might be non-zero when this function is called for multiple
* component types. */
- const int start_len = dst_component.instances_amount();
+ const int start_len = dst_component.instances_num();
const int select_len = selection.index_range().size();
dst_component.resize(start_len + select_len);
@@ -119,12 +119,12 @@ static void add_instances_from_component(
const bool use_individual_instance = pick_instance[i];
if (use_individual_instance) {
if (src_instances != nullptr) {
- const int src_instances_amount = src_instances->instances_amount();
+ const int src_instances_num = src_instances->instances_num();
const int original_index = indices[i];
/* Use #mod_i instead of `%` to get the desirable wrap around behavior where -1
* refers to the last element. */
- const int index = mod_i(original_index, std::max(src_instances_amount, 1));
- if (index < src_instances_amount) {
+ const int index = mod_i(original_index, std::max(src_instances_num, 1));
+ if (index < src_instances_num) {
/* Get the reference to the source instance. */
const int src_handle = src_instances->instance_reference_handles()[index];
dst_handle = handle_mapping[src_handle];
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 e35f152ce49..2126a5cc329 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
@@ -40,9 +40,9 @@ static void convert_instances_to_points(GeometrySet &geometry_set,
const InstancesComponent &instances = *geometry_set.get_component_for_read<InstancesComponent>();
GeometryComponentFieldContext field_context{instances, ATTR_DOMAIN_INSTANCE};
- const int domain_size = instances.attribute_domain_size(ATTR_DOMAIN_INSTANCE);
+ const int domain_num = instances.attribute_domain_num(ATTR_DOMAIN_INSTANCE);
- fn::FieldEvaluator evaluator{field_context, domain_size};
+ fn::FieldEvaluator evaluator{field_context, domain_num};
evaluator.set_selection(std::move(selection_field));
evaluator.add(std::move(position_field));
evaluator.add(std::move(radius_field));
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 0e2803cd035..0c56b0e9804 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_join_geometry.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_join_geometry.cc
@@ -47,8 +47,8 @@ static Map<AttributeIDRef, AttributeMetaData> get_final_attribute_info(
static void fill_new_attribute(Span<const GeometryComponent *> src_components,
const AttributeIDRef &attribute_id,
- const CustomDataType data_type,
- const AttributeDomain domain,
+ const eCustomDataType data_type,
+ const eAttrDomain domain,
GMutableSpan dst_span)
{
const CPPType *cpp_type = bke::custom_data_type_to_cpp_type(data_type);
@@ -56,8 +56,8 @@ static void fill_new_attribute(Span<const GeometryComponent *> src_components,
int offset = 0;
for (const GeometryComponent *component : src_components) {
- const int domain_size = component->attribute_domain_size(domain);
- if (domain_size == 0) {
+ const int domain_num = component->attribute_domain_num(domain);
+ if (domain_num == 0) {
continue;
}
GVArray read_attribute = component->attribute_get_for_read(
@@ -66,9 +66,9 @@ static void fill_new_attribute(Span<const GeometryComponent *> src_components,
GVArray_GSpan src_span{read_attribute};
const void *src_buffer = src_span.data();
void *dst_buffer = dst_span[offset];
- cpp_type->copy_assign_n(src_buffer, dst_buffer, domain_size);
+ cpp_type->copy_assign_n(src_buffer, dst_buffer, domain_num);
- offset += domain_size;
+ offset += domain_num;
}
}
@@ -101,7 +101,7 @@ static void join_components(Span<const InstancesComponent *> src_components, Geo
int tot_instances = 0;
for (const InstancesComponent *src_component : src_components) {
- tot_instances += src_component->instances_amount();
+ tot_instances += src_component->instances_num();
}
dst_component.reserve(tot_instances);
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 c245260f259..5875606da97 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_material_selection.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_material_selection.cc
@@ -51,7 +51,7 @@ class MaterialSelectionFieldInput final : public GeometryFieldInput {
}
GVArray get_varray_for_context(const GeometryComponent &component,
- const AttributeDomain domain,
+ const eAttrDomain domain,
IndexMask mask) const final
{
if (component.type() != GEO_COMPONENT_TYPE_MESH) {
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
index 1ec97858d4d..1def4089115 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_merge_by_distance.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_merge_by_distance.cc
@@ -39,9 +39,9 @@ static PointCloud *pointcloud_merge_by_distance(const PointCloudComponent &src_p
const float merge_distance,
const Field<bool> &selection_field)
{
- const int src_size = src_points.attribute_domain_size(ATTR_DOMAIN_POINT);
+ const int src_num = src_points.attribute_domain_num(ATTR_DOMAIN_POINT);
GeometryComponentFieldContext context{src_points, ATTR_DOMAIN_POINT};
- FieldEvaluator evaluator{context, src_size};
+ FieldEvaluator evaluator{context, src_num};
evaluator.add(selection_field);
evaluator.evaluate();
@@ -57,10 +57,10 @@ static std::optional<Mesh *> mesh_merge_by_distance_connected(const MeshComponen
const float merge_distance,
const Field<bool> &selection_field)
{
- const int src_size = mesh_component.attribute_domain_size(ATTR_DOMAIN_POINT);
- Array<bool> selection(src_size);
+ const int src_num = mesh_component.attribute_domain_num(ATTR_DOMAIN_POINT);
+ Array<bool> selection(src_num);
GeometryComponentFieldContext context{mesh_component, ATTR_DOMAIN_POINT};
- FieldEvaluator evaluator{context, src_size};
+ FieldEvaluator evaluator{context, src_num};
evaluator.add_with_destination(selection_field, selection.as_mutable_span());
evaluator.evaluate();
@@ -72,9 +72,9 @@ static std::optional<Mesh *> mesh_merge_by_distance_all(const MeshComponent &mes
const float merge_distance,
const Field<bool> &selection_field)
{
- const int src_size = mesh_component.attribute_domain_size(ATTR_DOMAIN_POINT);
+ const int src_num = mesh_component.attribute_domain_num(ATTR_DOMAIN_POINT);
GeometryComponentFieldContext context{mesh_component, ATTR_DOMAIN_POINT};
- FieldEvaluator evaluator{context, src_size};
+ FieldEvaluator evaluator{context, src_num};
evaluator.add(selection_field);
evaluator.evaluate();
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 636ecb8ab41..0029b547375 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
@@ -6,414 +6,9 @@
#include "BKE_material.h"
#include "BKE_mesh.h"
-#include "node_geometry_util.hh"
-
-namespace blender::nodes {
-
-struct CuboidConfig {
- float3 size;
- int verts_x;
- int verts_y;
- int verts_z;
- int edges_x;
- int edges_y;
- int edges_z;
- int vertex_count;
- int poly_count;
- int loop_count;
-
- CuboidConfig(float3 size, int verts_x, int verts_y, int verts_z)
- : size(size),
- verts_x(verts_x),
- verts_y(verts_y),
- verts_z(verts_z),
- edges_x(verts_x - 1),
- edges_y(verts_y - 1),
- edges_z(verts_z - 1)
- {
- BLI_assert(edges_x > 0 && edges_y > 0 && edges_z > 0);
- this->vertex_count = this->get_vertex_count();
- this->poly_count = this->get_poly_count();
- this->loop_count = this->poly_count * 4;
- }
-
- private:
- int get_vertex_count()
- {
- const int inner_position_count = (verts_x - 2) * (verts_y - 2) * (verts_z - 2);
- return verts_x * verts_y * verts_z - inner_position_count;
- }
-
- int get_poly_count()
- {
- return 2 * (edges_x * edges_y + edges_y * edges_z + edges_z * edges_x);
- }
-};
-
-static void calculate_vertices(const CuboidConfig &config, MutableSpan<MVert> verts)
-{
- const float z_bottom = -config.size.z / 2.0f;
- const float z_delta = config.size.z / config.edges_z;
-
- const float x_left = -config.size.x / 2.0f;
- const float x_delta = config.size.x / config.edges_x;
-
- const float y_front = -config.size.y / 2.0f;
- const float y_delta = config.size.y / config.edges_y;
-
- int vert_index = 0;
-
- for (const int z : IndexRange(config.verts_z)) {
- if (ELEM(z, 0, config.edges_z)) {
- /* Fill bottom and top. */
- const float z_pos = z_bottom + z_delta * z;
- for (const int y : IndexRange(config.verts_y)) {
- const float y_pos = y_front + y_delta * y;
- for (const int x : IndexRange(config.verts_x)) {
- const float x_pos = x_left + x_delta * x;
- copy_v3_v3(verts[vert_index++].co, float3(x_pos, y_pos, z_pos));
- }
- }
- }
- else {
- for (const int y : IndexRange(config.verts_y)) {
- if (ELEM(y, 0, config.edges_y)) {
- /* Fill y-sides. */
- const float y_pos = y_front + y_delta * y;
- const float z_pos = z_bottom + z_delta * z;
- for (const int x : IndexRange(config.verts_x)) {
- const float x_pos = x_left + x_delta * x;
- copy_v3_v3(verts[vert_index++].co, float3(x_pos, y_pos, z_pos));
- }
- }
- else {
- /* Fill x-sides. */
- const float x_pos = x_left;
- const float y_pos = y_front + y_delta * y;
- const float z_pos = z_bottom + z_delta * z;
- copy_v3_v3(verts[vert_index++].co, float3(x_pos, y_pos, z_pos));
- const float x_pos2 = x_left + x_delta * config.edges_x;
- copy_v3_v3(verts[vert_index++].co, float3(x_pos2, y_pos, z_pos));
- }
- }
- }
- }
-}
-
-/* vert_1 = bottom left, vert_2 = bottom right, vert_3 = top right, vert_4 = top left.
- * Hence they are passed as 1,4,3,2 when calculating polys clockwise, and 1,2,3,4 for
- * anti-clockwise.
- */
-static void define_quad(MutableSpan<MPoly> polys,
- MutableSpan<MLoop> loops,
- const int poly_index,
- const int loop_index,
- const int vert_1,
- const int vert_2,
- const int vert_3,
- const int vert_4)
-{
- MPoly &poly = polys[poly_index];
- poly.loopstart = loop_index;
- poly.totloop = 4;
-
- MLoop &loop_1 = loops[loop_index];
- loop_1.v = vert_1;
- MLoop &loop_2 = loops[loop_index + 1];
- loop_2.v = vert_2;
- MLoop &loop_3 = loops[loop_index + 2];
- loop_3.v = vert_3;
- MLoop &loop_4 = loops[loop_index + 3];
- loop_4.v = vert_4;
-}
-
-static void calculate_polys(const CuboidConfig &config,
- MutableSpan<MPoly> polys,
- MutableSpan<MLoop> loops)
-{
- int loop_index = 0;
- int poly_index = 0;
-
- /* Number of vertices in an XY cross-section of the cube (barring top and bottom faces). */
- const int xy_cross_section_vert_count = config.verts_x * config.verts_y -
- (config.verts_x - 2) * (config.verts_y - 2);
+#include "GEO_mesh_primitive_cuboid.hh"
- /* Calculate polys for Bottom faces. */
- int vert_1_start = 0;
-
- 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;
- const int vert_3 = vert_2 + 1;
- const int vert_4 = vert_1 + 1;
-
- define_quad(polys, loops, poly_index, loop_index, vert_1, vert_2, vert_3, vert_4);
- loop_index += 4;
- poly_index++;
- }
- vert_1_start += config.verts_x;
- }
-
- /* Calculate polys for Front faces. */
- vert_1_start = 0;
- int vert_2_start = config.verts_x * config.verts_y;
-
- for ([[maybe_unused]] const int z : IndexRange(config.edges_z)) {
- for (const int x : IndexRange(config.edges_x)) {
- define_quad(polys,
- loops,
- poly_index,
- loop_index,
- vert_1_start + x,
- vert_1_start + x + 1,
- vert_2_start + x + 1,
- vert_2_start + x);
- loop_index += 4;
- poly_index++;
- }
- vert_1_start = vert_2_start;
- vert_2_start += config.verts_x * config.verts_y - (config.verts_x - 2) * (config.verts_y - 2);
- }
-
- /* Calculate polys for Top faces. */
- vert_1_start = config.verts_x * config.verts_y +
- (config.verts_z - 2) * (config.verts_x * config.verts_y -
- (config.verts_x - 2) * (config.verts_y - 2));
- vert_2_start = vert_1_start + config.verts_x;
-
- for ([[maybe_unused]] const int y : IndexRange(config.edges_y)) {
- for (const int x : IndexRange(config.edges_x)) {
- define_quad(polys,
- loops,
- poly_index,
- loop_index,
- vert_1_start + x,
- vert_1_start + x + 1,
- vert_2_start + x + 1,
- vert_2_start + x);
- loop_index += 4;
- poly_index++;
- }
- vert_2_start += config.verts_x;
- vert_1_start += config.verts_x;
- }
-
- /* Calculate polys for Back faces. */
- vert_1_start = config.verts_x * config.edges_y;
- vert_2_start = vert_1_start + xy_cross_section_vert_count;
-
- for (const int z : IndexRange(config.edges_z)) {
- if (z == (config.edges_z - 1)) {
- vert_2_start += (config.verts_x - 2) * (config.verts_y - 2);
- }
- for (const int x : IndexRange(config.edges_x)) {
- define_quad(polys,
- loops,
- poly_index,
- loop_index,
- vert_1_start + x,
- vert_2_start + x,
- vert_2_start + x + 1,
- vert_1_start + x + 1);
- loop_index += 4;
- poly_index++;
- }
- vert_2_start += xy_cross_section_vert_count;
- vert_1_start += xy_cross_section_vert_count;
- }
-
- /* Calculate polys for Left faces. */
- vert_1_start = 0;
- vert_2_start = config.verts_x * config.verts_y;
-
- for (const int z : IndexRange(config.edges_z)) {
- for (const int y : IndexRange(config.edges_y)) {
- int vert_1;
- int vert_2;
- int vert_3;
- int vert_4;
-
- if (z == 0 || y == 0) {
- vert_1 = vert_1_start + config.verts_x * y;
- vert_4 = vert_1 + config.verts_x;
- }
- else {
- vert_1 = vert_1_start + 2 * y;
- vert_1 += config.verts_x - 2;
- vert_4 = vert_1 + 2;
- }
-
- if (y == 0 || z == (config.edges_z - 1)) {
- vert_2 = vert_2_start + config.verts_x * y;
- vert_3 = vert_2 + config.verts_x;
- }
- else {
- vert_2 = vert_2_start + 2 * y;
- vert_2 += config.verts_x - 2;
- vert_3 = vert_2 + 2;
- }
-
- define_quad(polys, loops, poly_index, loop_index, vert_1, vert_2, vert_3, vert_4);
- loop_index += 4;
- poly_index++;
- }
- if (z == 0) {
- vert_1_start += config.verts_x * config.verts_y;
- }
- else {
- vert_1_start += xy_cross_section_vert_count;
- }
- vert_2_start += xy_cross_section_vert_count;
- }
-
- /* Calculate polys for Right faces. */
- vert_1_start = config.edges_x;
- vert_2_start = vert_1_start + config.verts_x * config.verts_y;
-
- for (const int z : IndexRange(config.edges_z)) {
- for (const int y : IndexRange(config.edges_y)) {
- int vert_1 = vert_1_start;
- int vert_2 = vert_2_start;
- int vert_3 = vert_2_start + 2;
- int vert_4 = vert_1 + config.verts_x;
-
- if (z == 0) {
- vert_1 = vert_1_start + config.verts_x * y;
- vert_4 = vert_1 + config.verts_x;
- }
- else {
- vert_1 = vert_1_start + 2 * y;
- vert_4 = vert_1 + 2;
- }
-
- if (z == (config.edges_z - 1)) {
- vert_2 = vert_2_start + config.verts_x * y;
- vert_3 = vert_2 + config.verts_x;
- }
- else {
- vert_2 = vert_2_start + 2 * y;
- vert_3 = vert_2 + 2;
- }
-
- if (y == (config.edges_y - 1)) {
- vert_3 = vert_2 + config.verts_x;
- vert_4 = vert_1 + config.verts_x;
- }
-
- define_quad(polys, loops, poly_index, loop_index, vert_1, vert_4, vert_3, vert_2);
- loop_index += 4;
- poly_index++;
- }
- if (z == 0) {
- vert_1_start += config.verts_x * config.verts_y;
- }
- else {
- vert_1_start += xy_cross_section_vert_count;
- }
- vert_2_start += xy_cross_section_vert_count;
- }
-}
-
-static void calculate_uvs(const CuboidConfig &config, Mesh *mesh)
-{
- MeshComponent mesh_component;
- mesh_component.replace(mesh, GeometryOwnershipType::Editable);
- OutputAttribute_Typed<float2> uv_attribute =
- mesh_component.attribute_try_get_for_output_only<float2>("uv_map", ATTR_DOMAIN_CORNER);
- MutableSpan<float2> uvs = uv_attribute.as_span();
-
- int loop_index = 0;
-
- const float x_delta = 0.25f / static_cast<float>(config.edges_x);
- const float y_delta = 0.25f / static_cast<float>(config.edges_y);
- const float z_delta = 0.25f / static_cast<float>(config.edges_z);
-
- /* Calculate bottom face UVs. */
- for (const int y : IndexRange(config.edges_y)) {
- for (const int x : IndexRange(config.edges_x)) {
- uvs[loop_index++] = float2(0.25f + x * x_delta, 0.375f - y * y_delta);
- uvs[loop_index++] = float2(0.25f + x * x_delta, 0.375f - (y + 1) * y_delta);
- uvs[loop_index++] = float2(0.25f + (x + 1) * x_delta, 0.375f - (y + 1) * y_delta);
- uvs[loop_index++] = float2(0.25f + (x + 1) * x_delta, 0.375f - y * y_delta);
- }
- }
-
- /* Calculate front face UVs. */
- for (const int z : IndexRange(config.edges_z)) {
- for (const int x : IndexRange(config.edges_x)) {
- uvs[loop_index++] = float2(0.25f + x * x_delta, 0.375f + z * z_delta);
- uvs[loop_index++] = float2(0.25f + (x + 1) * x_delta, 0.375f + z * z_delta);
- uvs[loop_index++] = float2(0.25f + (x + 1) * x_delta, 0.375f + (z + 1) * z_delta);
- uvs[loop_index++] = float2(0.25f + x * x_delta, 0.375f + (z + 1) * z_delta);
- }
- }
-
- /* Calculate top face UVs. */
- for (const int y : IndexRange(config.edges_y)) {
- for (const int x : IndexRange(config.edges_x)) {
- uvs[loop_index++] = float2(0.25f + x * x_delta, 0.625f + y * y_delta);
- uvs[loop_index++] = float2(0.25f + (x + 1) * x_delta, 0.625f + y * y_delta);
- uvs[loop_index++] = float2(0.25f + (x + 1) * x_delta, 0.625f + (y + 1) * y_delta);
- uvs[loop_index++] = float2(0.25f + x * x_delta, 0.625f + (y + 1) * y_delta);
- }
- }
-
- /* Calculate back face UVs. */
- for (const int z : IndexRange(config.edges_z)) {
- for (const int x : IndexRange(config.edges_x)) {
- uvs[loop_index++] = float2(1.0f - x * x_delta, 0.375f + z * z_delta);
- uvs[loop_index++] = float2(1.0f - x * x_delta, 0.375f + (z + 1) * z_delta);
- uvs[loop_index++] = float2(1.0f - (x + 1) * x_delta, 0.375f + (z + 1) * z_delta);
- uvs[loop_index++] = float2(1.0f - (x + 1) * x_delta, 0.375f + z * z_delta);
- }
- }
-
- /* Calculate left face UVs. */
- for (const int z : IndexRange(config.edges_z)) {
- for (const int y : IndexRange(config.edges_y)) {
- uvs[loop_index++] = float2(0.25f - y * y_delta, 0.375f + z * z_delta);
- uvs[loop_index++] = float2(0.25f - y * y_delta, 0.375f + (z + 1) * z_delta);
- uvs[loop_index++] = float2(0.25f - (y + 1) * y_delta, 0.375f + (z + 1) * z_delta);
- uvs[loop_index++] = float2(0.25f - (y + 1) * y_delta, 0.375f + z * z_delta);
- }
- }
-
- /* Calculate right face UVs. */
- for (const int z : IndexRange(config.edges_z)) {
- for (const int y : IndexRange(config.edges_y)) {
- uvs[loop_index++] = float2(0.50f + y * y_delta, 0.375f + z * z_delta);
- uvs[loop_index++] = float2(0.50f + (y + 1) * y_delta, 0.375f + z * z_delta);
- uvs[loop_index++] = float2(0.50f + (y + 1) * y_delta, 0.375f + (z + 1) * z_delta);
- uvs[loop_index++] = float2(0.50f + y * y_delta, 0.375f + (z + 1) * z_delta);
- }
- }
-
- uv_attribute.save();
-}
-
-Mesh *create_cuboid_mesh(const float3 size,
- const int verts_x,
- const int verts_y,
- const int verts_z)
-{
- const CuboidConfig config(size, verts_x, verts_y, verts_z);
-
- Mesh *mesh = BKE_mesh_new_nomain(
- config.vertex_count, 0, 0, config.loop_count, config.poly_count);
- BKE_id_material_eval_ensure_default_slot(&mesh->id);
-
- calculate_vertices(config, {mesh->mvert, mesh->totvert});
-
- calculate_polys(config, {mesh->mpoly, mesh->totpoly}, {mesh->mloop, mesh->totloop});
- BKE_mesh_calc_edges(mesh, false, false);
-
- calculate_uvs(config, mesh);
-
- return mesh;
-}
-
-} // namespace blender::nodes
+#include "node_geometry_util.hh"
namespace blender::nodes::node_geo_mesh_primitive_cube_cc {
@@ -442,6 +37,16 @@ static void node_declare(NodeDeclarationBuilder &b)
b.add_output<decl::Geometry>(N_("Mesh"));
}
+static Mesh *create_cuboid_mesh(const float3 &size,
+ const int verts_x,
+ const int verts_y,
+ const int verts_z)
+{
+ Mesh *mesh = geometry::create_cuboid_mesh(size, verts_x, verts_y, verts_z, "uv_map");
+ BKE_id_material_eval_ensure_default_slot(&mesh->id);
+ return mesh;
+}
+
static Mesh *create_cube_mesh(const float3 size,
const int verts_x,
const int verts_y,
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 f6ee3d00dee..ec6acf55dd8 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
@@ -25,7 +25,7 @@ static void node_geo_exec(GeoNodeExecParams params)
const MeshComponent &component = *geometry_set.get_component_for_read<MeshComponent>();
GeometryComponentFieldContext context{component, ATTR_DOMAIN_EDGE};
- fn::FieldEvaluator evaluator{context, component.attribute_domain_size(ATTR_DOMAIN_EDGE)};
+ fn::FieldEvaluator evaluator{context, component.attribute_domain_num(ATTR_DOMAIN_EDGE)};
evaluator.add(params.get_input<Field<bool>>("Selection"));
evaluator.evaluate();
const IndexMask selection = evaluator.get_evaluated_as_mask(0);
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 2ed6d555684..7463eb01471 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
@@ -58,7 +58,7 @@ static void geometry_set_mesh_to_points(GeometrySet &geometry_set,
Field<float3> &position_field,
Field<float> &radius_field,
Field<bool> &selection_field,
- const AttributeDomain domain)
+ const eAttrDomain domain)
{
const MeshComponent *mesh_component = geometry_set.get_component_for_read<MeshComponent>();
if (mesh_component == nullptr) {
@@ -66,12 +66,12 @@ static void geometry_set_mesh_to_points(GeometrySet &geometry_set,
return;
}
GeometryComponentFieldContext field_context{*mesh_component, domain};
- const int domain_size = mesh_component->attribute_domain_size(domain);
- if (domain_size == 0) {
+ const int domain_num = mesh_component->attribute_domain_num(domain);
+ if (domain_num == 0) {
geometry_set.keep_only({GEO_COMPONENT_TYPE_INSTANCES});
return;
}
- fn::FieldEvaluator evaluator{field_context, domain_size};
+ fn::FieldEvaluator evaluator{field_context, domain_num};
evaluator.set_selection(selection_field);
/* Evaluating directly into the point cloud doesn't work because we are not using the full
* "min_array_size" array but compressing the selected elements into the final array with no
@@ -105,7 +105,7 @@ static void geometry_set_mesh_to_points(GeometrySet &geometry_set,
for (Map<AttributeIDRef, AttributeKind>::Item entry : attributes.items()) {
const AttributeIDRef attribute_id = entry.key;
- const CustomDataType data_type = entry.value.data_type;
+ const eCustomDataType data_type = entry.value.data_type;
GVArray src = mesh_component->attribute_get_for_read(attribute_id, domain, data_type);
OutputAttribute dst = point_component.attribute_try_get_for_output_only(
attribute_id, ATTR_DOMAIN_POINT, data_type);
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 0f6586617bc..00b3d167755 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
@@ -38,13 +38,13 @@ static void geometry_set_points_to_vertices(GeometrySet &geometry_set,
}
GeometryComponentFieldContext field_context{*point_component, ATTR_DOMAIN_POINT};
- const int domain_size = point_component->attribute_domain_size(ATTR_DOMAIN_POINT);
- if (domain_size == 0) {
+ const int domain_num = point_component->attribute_domain_num(ATTR_DOMAIN_POINT);
+ if (domain_num == 0) {
geometry_set.keep_only({GEO_COMPONENT_TYPE_INSTANCES});
return;
}
- fn::FieldEvaluator selection_evaluator{field_context, domain_size};
+ fn::FieldEvaluator selection_evaluator{field_context, domain_num};
selection_evaluator.add(selection_field);
selection_evaluator.evaluate();
const IndexMask selection = selection_evaluator.get_evaluated_as_mask(0);
@@ -59,7 +59,7 @@ static void geometry_set_points_to_vertices(GeometrySet &geometry_set,
for (Map<AttributeIDRef, AttributeKind>::Item entry : attributes.items()) {
const AttributeIDRef attribute_id = entry.key;
- const CustomDataType data_type = entry.value.data_type;
+ const eCustomDataType data_type = entry.value.data_type;
GVArray src = point_component->attribute_get_for_read(
attribute_id, ATTR_DOMAIN_POINT, data_type);
OutputAttribute dst = mesh_component.attribute_try_get_for_output_only(
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 c99b51ffd4c..42cee4c0efe 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
@@ -168,14 +168,14 @@ static void gather_point_data_from_component(GeoNodeExecParams &params,
Field<float> radius_field = params.get_input<Field<float>>("Radius");
GeometryComponentFieldContext field_context{component, ATTR_DOMAIN_POINT};
- const int domain_size = component.attribute_domain_size(ATTR_DOMAIN_POINT);
+ const int domain_num = component.attribute_domain_num(ATTR_DOMAIN_POINT);
- r_positions.resize(r_positions.size() + domain_size);
- positions.materialize(r_positions.as_mutable_span().take_back(domain_size));
+ r_positions.resize(r_positions.size() + domain_num);
+ positions.materialize(r_positions.as_mutable_span().take_back(domain_num));
- r_radii.resize(r_radii.size() + domain_size);
- fn::FieldEvaluator evaluator{field_context, domain_size};
- evaluator.add_with_destination(radius_field, r_radii.as_mutable_span().take_back(domain_size));
+ r_radii.resize(r_radii.size() + domain_num);
+ fn::FieldEvaluator evaluator{field_context, domain_num};
+ evaluator.add_with_destination(radius_field, r_radii.as_mutable_span().take_back(domain_num));
evaluator.evaluate();
}
diff --git a/source/blender/nodes/geometry/nodes/node_geo_raycast.cc b/source/blender/nodes/geometry/nodes/node_geo_raycast.cc
index 368954447c9..a92cee2d066 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_raycast.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_raycast.cc
@@ -70,7 +70,7 @@ static void node_init(bNodeTree *UNUSED(tree), bNode *node)
static void node_update(bNodeTree *ntree, bNode *node)
{
const NodeGeometryRaycast &storage = node_storage(*node);
- const CustomDataType data_type = static_cast<CustomDataType>(storage.data_type);
+ const eCustomDataType data_type = static_cast<eCustomDataType>(storage.data_type);
bNodeSocket *socket_vector = (bNodeSocket *)BLI_findlink(&node->inputs, 1);
bNodeSocket *socket_float = socket_vector->next;
@@ -104,7 +104,7 @@ static void node_gather_link_searches(GatherLinkSearchOpParams &params)
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(
+ const std::optional<eCustomDataType> 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. */
@@ -215,7 +215,7 @@ class RaycastFunction : public fn::MultiFunction {
/* Always evaluate the target domain data on the face corner domain because it contains the most
* information. Eventually this could be exposed as an option or determined automatically from
* the field inputs for better performance. */
- const AttributeDomain domain_ = ATTR_DOMAIN_CORNER;
+ const eAttrDomain domain_ = ATTR_DOMAIN_CORNER;
fn::MFSignature signature_;
@@ -312,15 +312,15 @@ class RaycastFunction : public fn::MultiFunction {
}
const MeshComponent &mesh_component = *target_.get_component_for_read<MeshComponent>();
target_context_.emplace(GeometryComponentFieldContext{mesh_component, domain_});
- const int domain_size = mesh_component.attribute_domain_size(domain_);
- target_evaluator_ = std::make_unique<FieldEvaluator>(*target_context_, domain_size);
+ const int domain_num = mesh_component.attribute_domain_num(domain_);
+ target_evaluator_ = std::make_unique<FieldEvaluator>(*target_context_, domain_num);
target_evaluator_->add(std::move(src_field));
target_evaluator_->evaluate();
target_data_ = &target_evaluator_->get_evaluated(0);
}
};
-static GField get_input_attribute_field(GeoNodeExecParams &params, const CustomDataType data_type)
+static GField get_input_attribute_field(GeoNodeExecParams &params, const eCustomDataType data_type)
{
switch (data_type) {
case CD_PROP_FLOAT:
@@ -387,7 +387,7 @@ static void node_geo_exec(GeoNodeExecParams params)
GeometrySet target = params.extract_input<GeometrySet>("Target Geometry");
const NodeGeometryRaycast &storage = node_storage(params.node());
const GeometryNodeRaycastMapMode mapping = (GeometryNodeRaycastMapMode)storage.mapping;
- const CustomDataType data_type = static_cast<CustomDataType>(storage.data_type);
+ const eCustomDataType data_type = static_cast<eCustomDataType>(storage.data_type);
if (target.is_empty()) {
params.set_default_remaining_outputs();
diff --git a/source/blender/nodes/geometry/nodes/node_geo_remove_attribute.cc b/source/blender/nodes/geometry/nodes/node_geo_remove_attribute.cc
index effeac5a37f..da42b8c5ee0 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_remove_attribute.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_remove_attribute.cc
@@ -21,6 +21,11 @@ static void node_geo_exec(GeoNodeExecParams params)
params.set_output("Geometry", std::move(geometry_set));
return;
}
+ if (!bke::allow_procedural_attribute_access(name)) {
+ params.error_message_add(NodeWarningType::Info, TIP_(bke::no_procedural_access_message));
+ params.set_output("Geometry", std::move(geometry_set));
+ return;
+ }
std::atomic<bool> attribute_exists = false;
std::atomic<bool> cannot_delete = false;
@@ -50,7 +55,7 @@ static void node_geo_exec(GeoNodeExecParams params)
});
if (attribute_exists && !cannot_delete) {
- params.used_named_attribute(name, NamedAttributeUsage::Remove);
+ params.used_named_attribute(name, eNamedAttrUsage::Remove);
}
if (!attribute_exists) {
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 6eb95859e50..59e203afd08 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_rotate_instances.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_rotate_instances.cc
@@ -19,9 +19,9 @@ static void node_declare(NodeDeclarationBuilder &b)
static void rotate_instances(GeoNodeExecParams &params, InstancesComponent &instances_component)
{
GeometryComponentFieldContext field_context{instances_component, ATTR_DOMAIN_INSTANCE};
- const int domain_size = instances_component.instances_amount();
+ const int domain_num = instances_component.instances_num();
- fn::FieldEvaluator evaluator{field_context, domain_size};
+ fn::FieldEvaluator evaluator{field_context, domain_num};
evaluator.set_selection(params.extract_input<Field<bool>>("Selection"));
evaluator.add(params.extract_input<Field<float3>>("Rotation"));
evaluator.add(params.extract_input<Field<float3>>("Pivot Point"));
diff --git a/source/blender/nodes/geometry/nodes/node_geo_scale_elements.cc b/source/blender/nodes/geometry/nodes/node_geo_scale_elements.cc
index 7923ad6264d..698efa8865d 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_scale_elements.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_scale_elements.cc
@@ -397,7 +397,7 @@ static void scale_edges_on_axis(MeshComponent &mesh_component, const AxisScaleFi
static void node_geo_exec(GeoNodeExecParams params)
{
const bNode &node = params.node();
- const AttributeDomain domain = static_cast<AttributeDomain>(node.custom1);
+ const eAttrDomain domain = static_cast<eAttrDomain>(node.custom1);
const GeometryNodeScaleElementsMode scale_mode = static_cast<GeometryNodeScaleElementsMode>(
node.custom2);
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 4ca21874f8f..d4716a6b6f0 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_scale_instances.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_scale_instances.cc
@@ -23,7 +23,7 @@ static void scale_instances(GeoNodeExecParams &params, InstancesComponent &insta
{
GeometryComponentFieldContext field_context{instances_component, ATTR_DOMAIN_INSTANCE};
- fn::FieldEvaluator evaluator{field_context, instances_component.instances_amount()};
+ fn::FieldEvaluator evaluator{field_context, instances_component.instances_num()};
evaluator.set_selection(params.extract_input<Field<bool>>("Selection"));
evaluator.add(params.extract_input<Field<float3>>("Scale"));
evaluator.add(params.extract_input<Field<float3>>("Center"));
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 a48d422e4c0..d785694f253 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_separate_geometry.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_separate_geometry.cc
@@ -43,38 +43,31 @@ static void node_geo_exec(GeoNodeExecParams params)
const Field<bool> selection_field = params.extract_input<Field<bool>>("Selection");
const NodeGeometrySeparateGeometry &storage = node_storage(params.node());
- const AttributeDomain domain = static_cast<AttributeDomain>(storage.domain);
+ const eAttrDomain domain = static_cast<eAttrDomain>(storage.domain);
- auto separate_geometry_maybe_recursively = [&](GeometrySet &geometry_set, bool invert) {
+ auto separate_geometry_maybe_recursively = [&](GeometrySet &geometry_set,
+ const Field<bool> &selection) {
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,
- invert,
- is_error);
+ separate_geometry(
+ geometry_set, domain, GEO_NODE_DELETE_GEOMETRY_MODE_ALL, selection, 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);
+ separate_geometry(
+ geometry_set, domain, GEO_NODE_DELETE_GEOMETRY_MODE_ALL, selection, is_error);
});
}
};
GeometrySet second_set(geometry_set);
if (params.output_is_required("Selection")) {
- separate_geometry_maybe_recursively(geometry_set, false);
+ separate_geometry_maybe_recursively(geometry_set, selection_field);
params.set_output("Selection", std::move(geometry_set));
}
if (params.output_is_required("Inverted")) {
- separate_geometry_maybe_recursively(second_set, true);
+ separate_geometry_maybe_recursively(second_set, fn::invert_boolean_field(selection_field));
params.set_output("Inverted", std::move(second_set));
}
}
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 73e49c7d037..d2082924fa7 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
@@ -75,12 +75,12 @@ static void set_position_in_component(CurveComponent &component,
const Field<float3> &offset_field)
{
GeometryComponentFieldContext field_context{component, ATTR_DOMAIN_POINT};
- const int domain_size = component.attribute_domain_size(ATTR_DOMAIN_POINT);
- if (domain_size == 0) {
+ const int domain_num = component.attribute_domain_num(ATTR_DOMAIN_POINT);
+ if (domain_num == 0) {
return;
}
- fn::FieldEvaluator evaluator{field_context, domain_size};
+ fn::FieldEvaluator evaluator{field_context, domain_num};
evaluator.set_selection(selection_field);
evaluator.add(position_field);
evaluator.add(offset_field);
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 a23a6c09551..4c84093bfcb 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
@@ -21,15 +21,15 @@ static void set_radius_in_component(GeometryComponent &component,
const Field<float> &radius_field)
{
GeometryComponentFieldContext field_context{component, ATTR_DOMAIN_POINT};
- const int domain_size = component.attribute_domain_size(ATTR_DOMAIN_POINT);
- if (domain_size == 0) {
+ const int domain_num = component.attribute_domain_num(ATTR_DOMAIN_POINT);
+ if (domain_num == 0) {
return;
}
OutputAttribute_Typed<float> radii = component.attribute_try_get_for_output_only<float>(
"radius", ATTR_DOMAIN_POINT);
- fn::FieldEvaluator evaluator{field_context, domain_size};
+ fn::FieldEvaluator evaluator{field_context, domain_num};
evaluator.set_selection(selection_field);
evaluator.add_with_destination(radius_field, radii.varray());
evaluator.evaluate();
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 1155c97dc38..8b1e5935a61 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
@@ -17,15 +17,15 @@ static void set_tilt_in_component(GeometryComponent &component,
const Field<float> &tilt_field)
{
GeometryComponentFieldContext field_context{component, ATTR_DOMAIN_POINT};
- const int domain_size = component.attribute_domain_size(ATTR_DOMAIN_POINT);
- if (domain_size == 0) {
+ const int domain_num = component.attribute_domain_num(ATTR_DOMAIN_POINT);
+ if (domain_num == 0) {
return;
}
OutputAttribute_Typed<float> tilts = component.attribute_try_get_for_output_only<float>(
"tilt", ATTR_DOMAIN_POINT);
- fn::FieldEvaluator evaluator{field_context, domain_size};
+ fn::FieldEvaluator evaluator{field_context, domain_num};
evaluator.set_selection(selection_field);
evaluator.add_with_destination(tilt_field, tilts.varray());
evaluator.evaluate();
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 0892e068ce2..87d48daddea 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_set_id.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_set_id.cc
@@ -16,16 +16,16 @@ static void set_id_in_component(GeometryComponent &component,
const Field<bool> &selection_field,
const Field<int> &id_field)
{
- const AttributeDomain domain = (component.type() == GEO_COMPONENT_TYPE_INSTANCES) ?
- ATTR_DOMAIN_INSTANCE :
- ATTR_DOMAIN_POINT;
+ const eAttrDomain domain = (component.type() == GEO_COMPONENT_TYPE_INSTANCES) ?
+ ATTR_DOMAIN_INSTANCE :
+ ATTR_DOMAIN_POINT;
GeometryComponentFieldContext field_context{component, domain};
- const int domain_size = component.attribute_domain_size(domain);
- if (domain_size == 0) {
+ const int domain_num = component.attribute_domain_num(domain);
+ if (domain_num == 0) {
return;
}
- fn::FieldEvaluator evaluator{field_context, domain_size};
+ fn::FieldEvaluator evaluator{field_context, domain_num};
evaluator.set_selection(selection_field);
/* Since adding the ID attribute can change the result of the field evaluation (the random value
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 a0b38209f97..58613dae832 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
@@ -17,15 +17,15 @@ static void set_material_index_in_component(GeometryComponent &component,
const Field<int> &index_field)
{
GeometryComponentFieldContext field_context{component, ATTR_DOMAIN_FACE};
- const int domain_size = component.attribute_domain_size(ATTR_DOMAIN_FACE);
- if (domain_size == 0) {
+ const int domain_num = component.attribute_domain_num(ATTR_DOMAIN_FACE);
+ if (domain_num == 0) {
return;
}
OutputAttribute_Typed<int> indices = component.attribute_try_get_for_output_only<int>(
"material_index", ATTR_DOMAIN_FACE);
- fn::FieldEvaluator evaluator{field_context, domain_size};
+ fn::FieldEvaluator evaluator{field_context, domain_num};
evaluator.set_selection(selection_field);
evaluator.add_with_destination(index_field, indices.varray());
evaluator.evaluate();
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 93024fd81d6..571bead9743 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
@@ -21,15 +21,15 @@ static void set_radius_in_component(GeometryComponent &component,
const Field<float> &radius_field)
{
GeometryComponentFieldContext field_context{component, ATTR_DOMAIN_POINT};
- const int domain_size = component.attribute_domain_size(ATTR_DOMAIN_POINT);
- if (domain_size == 0) {
+ const int domain_num = component.attribute_domain_num(ATTR_DOMAIN_POINT);
+ if (domain_num == 0) {
return;
}
OutputAttribute_Typed<float> radii = component.attribute_try_get_for_output_only<float>(
"radius", ATTR_DOMAIN_POINT);
- fn::FieldEvaluator evaluator{field_context, domain_size};
+ fn::FieldEvaluator evaluator{field_context, domain_num};
evaluator.set_selection(selection_field);
evaluator.add_with_destination(radius_field, radii.varray());
evaluator.evaluate();
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 d2ff9753897..e9ed87e552f 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_set_position.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_set_position.cc
@@ -25,7 +25,7 @@ static void node_declare(NodeDeclarationBuilder &b)
static void set_computed_position_and_offset(GeometryComponent &component,
const VArray<float3> &in_positions,
const VArray<float3> &in_offsets,
- const AttributeDomain domain,
+ const eAttrDomain domain,
const IndexMask selection)
{
@@ -139,16 +139,15 @@ static void set_position_in_component(GeometryComponent &component,
const Field<float3> &position_field,
const Field<float3> &offset_field)
{
- AttributeDomain domain = component.type() == GEO_COMPONENT_TYPE_INSTANCES ?
- ATTR_DOMAIN_INSTANCE :
- ATTR_DOMAIN_POINT;
+ eAttrDomain domain = component.type() == GEO_COMPONENT_TYPE_INSTANCES ? ATTR_DOMAIN_INSTANCE :
+ ATTR_DOMAIN_POINT;
GeometryComponentFieldContext field_context{component, domain};
- const int domain_size = component.attribute_domain_size(domain);
- if (domain_size == 0) {
+ const int domain_num = component.attribute_domain_num(domain);
+ if (domain_num == 0) {
return;
}
- fn::FieldEvaluator evaluator{field_context, domain_size};
+ fn::FieldEvaluator evaluator{field_context, domain_num};
evaluator.set_selection(selection_field);
evaluator.add(position_field);
evaluator.add(offset_field);
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 3420e17cc10..b98fbd0a0fe 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
@@ -17,15 +17,15 @@ static void set_smooth_in_component(GeometryComponent &component,
const Field<bool> &shade_field)
{
GeometryComponentFieldContext field_context{component, ATTR_DOMAIN_FACE};
- const int domain_size = component.attribute_domain_size(ATTR_DOMAIN_FACE);
- if (domain_size == 0) {
+ const int domain_num = component.attribute_domain_num(ATTR_DOMAIN_FACE);
+ if (domain_num == 0) {
return;
}
OutputAttribute_Typed<bool> shades = component.attribute_try_get_for_output_only<bool>(
"shade_smooth", ATTR_DOMAIN_FACE);
- fn::FieldEvaluator evaluator{field_context, domain_size};
+ fn::FieldEvaluator evaluator{field_context, domain_num};
evaluator.set_selection(selection_field);
evaluator.add_with_destination(shade_field, shades.varray());
evaluator.evaluate();
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 dc7f3b1343a..976857883f0 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
@@ -17,15 +17,15 @@ static void set_cyclic_in_component(GeometryComponent &component,
const Field<bool> &cyclic_field)
{
GeometryComponentFieldContext field_context{component, ATTR_DOMAIN_CURVE};
- const int domain_size = component.attribute_domain_size(ATTR_DOMAIN_CURVE);
- if (domain_size == 0) {
+ const int domain_num = component.attribute_domain_num(ATTR_DOMAIN_CURVE);
+ if (domain_num == 0) {
return;
}
OutputAttribute_Typed<bool> cyclics = component.attribute_try_get_for_output_only<bool>(
"cyclic", ATTR_DOMAIN_CURVE);
- fn::FieldEvaluator evaluator{field_context, domain_size};
+ fn::FieldEvaluator evaluator{field_context, domain_num};
evaluator.set_selection(selection_field);
evaluator.add_with_destination(cyclic_field, cyclics.varray());
evaluator.evaluate();
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 f3031ff3678..8b665376c01 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
@@ -17,15 +17,15 @@ static void set_resolution_in_component(GeometryComponent &component,
const Field<int> &resolution_field)
{
GeometryComponentFieldContext field_context{component, ATTR_DOMAIN_CURVE};
- const int domain_size = component.attribute_domain_size(ATTR_DOMAIN_CURVE);
- if (domain_size == 0) {
+ const int domain_num = component.attribute_domain_num(ATTR_DOMAIN_CURVE);
+ if (domain_num == 0) {
return;
}
OutputAttribute_Typed<int> resolutions = component.attribute_try_get_for_output_only<int>(
"resolution", ATTR_DOMAIN_CURVE);
- fn::FieldEvaluator evaluator{field_context, domain_size};
+ fn::FieldEvaluator evaluator{field_context, domain_num};
evaluator.set_selection(selection_field);
evaluator.add_with_destination(resolution_field, resolutions.varray());
evaluator.evaluate();
diff --git a/source/blender/nodes/geometry/nodes/node_geo_store_named_attribute.cc b/source/blender/nodes/geometry/nodes/node_geo_store_named_attribute.cc
index de206be5367..7ccdae2e5a6 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_store_named_attribute.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_store_named_attribute.cc
@@ -45,7 +45,7 @@ static void node_init(bNodeTree *UNUSED(tree), bNode *node)
static void node_update(bNodeTree *ntree, bNode *node)
{
const NodeGeometryStoreNamedAttribute &storage = node_storage(*node);
- const CustomDataType data_type = static_cast<CustomDataType>(storage.data_type);
+ const eCustomDataType data_type = static_cast<eCustomDataType>(storage.data_type);
bNodeSocket *socket_geometry = (bNodeSocket *)node->inputs.first;
bNodeSocket *socket_name = socket_geometry->next;
@@ -69,7 +69,7 @@ static void node_gather_link_searches(GatherLinkSearchOpParams &params)
search_link_ops_for_declarations(params, declaration.inputs().take_front(2));
if (params.in_out() == SOCK_OUT) {
- const std::optional<CustomDataType> type = node_data_type_to_custom_data_type(
+ const std::optional<eCustomDataType> type = node_data_type_to_custom_data_type(
static_cast<eNodeSocketDatatype>(params.other_socket().type));
if (type && *type != CD_PROP_STRING) {
/* The input and output sockets have the same name. */
@@ -84,23 +84,23 @@ static void node_gather_link_searches(GatherLinkSearchOpParams &params)
static void try_capture_field_on_geometry(GeometryComponent &component,
const StringRef name,
- const AttributeDomain domain,
+ const eAttrDomain domain,
const GField &field)
{
GeometryComponentFieldContext field_context{component, domain};
- const int domain_size = component.attribute_domain_size(domain);
- const IndexMask mask{IndexMask(domain_size)};
+ const int domain_num = component.attribute_domain_num(domain);
+ const IndexMask mask{IndexMask(domain_num)};
const CPPType &type = field.cpp_type();
- const CustomDataType data_type = bke::cpp_type_to_custom_data_type(type);
+ const eCustomDataType data_type = bke::cpp_type_to_custom_data_type(type);
/* Could avoid allocating a new buffer if:
* - We are writing to an attribute that exists already.
* - The field does not depend on that attribute (we can't easily check for that yet). */
- void *buffer = MEM_mallocN(type.size() * domain_size, __func__);
+ void *buffer = MEM_mallocN(type.size() * domain_num, __func__);
fn::FieldEvaluator evaluator{field_context, &mask};
- evaluator.add_with_destination(field, GMutableSpan{type, buffer, domain_size});
+ evaluator.add_with_destination(field, GMutableSpan{type, buffer, domain_num});
evaluator.evaluate();
component.attribute_try_delete(name);
@@ -114,7 +114,7 @@ static void try_capture_field_on_geometry(GeometryComponent &component,
else {
/* Cannot change type of built-in attribute. */
}
- type.destruct_n(buffer, domain_size);
+ type.destruct_n(buffer, domain_num);
MEM_freeN(buffer);
}
else {
@@ -131,12 +131,17 @@ static void node_geo_exec(GeoNodeExecParams params)
params.set_output("Geometry", std::move(geometry_set));
return;
}
+ if (!bke::allow_procedural_attribute_access(name)) {
+ params.error_message_add(NodeWarningType::Info, TIP_(bke::no_procedural_access_message));
+ params.set_output("Geometry", std::move(geometry_set));
+ return;
+ }
- params.used_named_attribute(name, NamedAttributeUsage::Write);
+ params.used_named_attribute(name, eNamedAttrUsage::Write);
const NodeGeometryStoreNamedAttribute &storage = node_storage(params.node());
- const CustomDataType data_type = static_cast<CustomDataType>(storage.data_type);
- const AttributeDomain domain = static_cast<AttributeDomain>(storage.domain);
+ const eCustomDataType data_type = static_cast<eCustomDataType>(storage.data_type);
+ const eAttrDomain domain = static_cast<eAttrDomain>(storage.domain);
GField field;
switch (data_type) {
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 658de02fdab..33f5eccd719 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
@@ -97,12 +97,8 @@ static void node_update(bNodeTree *ntree, bNode *node)
ntree, socket_remainder, overflow == GEO_NODE_STRING_TO_CURVES_MODE_TRUNCATE);
bNodeSocket *height_socket = (bNodeSocket *)node->inputs.last;
- bNodeSocket *width_socket = height_socket->prev;
nodeSetSocketAvailability(
ntree, height_socket, overflow != GEO_NODE_STRING_TO_CURVES_MODE_OVERFLOW);
- node_sock_label(width_socket,
- overflow == GEO_NODE_STRING_TO_CURVES_MODE_OVERFLOW ? N_("Max Width") :
- N_("Text Box Width"));
}
static float3 get_pivot_point(GeoNodeExecParams &params, CurveEval &curve)
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 f2a859065c6..9eda5bb34ff 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_subdivision_surface.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_subdivision_surface.cc
@@ -118,8 +118,8 @@ static void node_geo_exec(GeoNodeExecParams params)
}
const MeshComponent &mesh_component = *geometry_set.get_component_for_read<MeshComponent>();
- const int verts_num = mesh_component.attribute_domain_size(ATTR_DOMAIN_POINT);
- const int edges_num = mesh_component.attribute_domain_size(ATTR_DOMAIN_EDGE);
+ const int verts_num = mesh_component.attribute_domain_num(ATTR_DOMAIN_POINT);
+ const int edges_num = mesh_component.attribute_domain_num(ATTR_DOMAIN_EDGE);
if (verts_num == 0 || edges_num == 0) {
return;
}
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 12e306ba480..0af6c76feaf 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_transfer_attribute.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_transfer_attribute.cc
@@ -81,7 +81,7 @@ static void node_init(bNodeTree *UNUSED(tree), bNode *node)
static void node_update(bNodeTree *ntree, bNode *node)
{
const NodeGeometryTransferAttribute &storage = node_storage(*node);
- const CustomDataType data_type = static_cast<CustomDataType>(storage.data_type);
+ const eCustomDataType data_type = static_cast<eCustomDataType>(storage.data_type);
const GeometryNodeAttributeTransferMode mapping = (GeometryNodeAttributeTransferMode)
storage.mode;
@@ -123,7 +123,7 @@ static void node_gather_link_searches(GatherLinkSearchOpParams &params)
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(
+ const std::optional<eCustomDataType> 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. */
@@ -356,7 +356,7 @@ void copy_with_indices_and_comparison(const VArray<T> &src_1,
static bool component_is_available(const GeometrySet &geometry,
const GeometryComponentType type,
- const AttributeDomain domain)
+ const eAttrDomain domain)
{
if (!geometry.has(type)) {
return false;
@@ -365,7 +365,7 @@ static bool component_is_available(const GeometrySet &geometry,
if (component.is_empty()) {
return false;
}
- return component.attribute_domain_size(domain) != 0;
+ return component.attribute_domain_num(domain) != 0;
}
/**
@@ -383,7 +383,7 @@ class NearestInterpolatedTransferFunction : public fn::MultiFunction {
* future, it should be possible to use the most complex domain required by the field inputs, to
* simplify sampling and avoid domain conversions.
*/
- AttributeDomain domain_ = ATTR_DOMAIN_CORNER;
+ eAttrDomain domain_ = ATTR_DOMAIN_CORNER;
fn::MFSignature signature_;
@@ -433,8 +433,8 @@ class NearestInterpolatedTransferFunction : public fn::MultiFunction {
{
const MeshComponent &mesh_component = *source_.get_component_for_read<MeshComponent>();
source_context_.emplace(GeometryComponentFieldContext{mesh_component, domain_});
- const int domain_size = mesh_component.attribute_domain_size(domain_);
- source_evaluator_ = std::make_unique<FieldEvaluator>(*source_context_, domain_size);
+ const int domain_num = mesh_component.attribute_domain_num(domain_);
+ source_evaluator_ = std::make_unique<FieldEvaluator>(*source_context_, domain_num);
source_evaluator_->add(src_field_);
source_evaluator_->evaluate();
source_data_ = &source_evaluator_->get_evaluated(0);
@@ -449,7 +449,7 @@ class NearestInterpolatedTransferFunction : public fn::MultiFunction {
class NearestTransferFunction : public fn::MultiFunction {
GeometrySet source_;
GField src_field_;
- AttributeDomain domain_;
+ eAttrDomain domain_;
fn::MFSignature signature_;
@@ -466,7 +466,7 @@ class NearestTransferFunction : public fn::MultiFunction {
const GVArray *point_data_;
public:
- NearestTransferFunction(GeometrySet geometry, GField src_field, AttributeDomain domain)
+ NearestTransferFunction(GeometrySet geometry, GField src_field, eAttrDomain domain)
: source_(std::move(geometry)), src_field_(std::move(src_field)), domain_(domain)
{
source_.ensure_owns_direct_data();
@@ -578,9 +578,9 @@ class NearestTransferFunction : public fn::MultiFunction {
{
if (use_mesh_) {
const MeshComponent &mesh = *source_.get_component_for_read<MeshComponent>();
- const int domain_size = mesh.attribute_domain_size(domain_);
+ const int domain_num = mesh.attribute_domain_num(domain_);
mesh_context_.emplace(GeometryComponentFieldContext(mesh, domain_));
- mesh_evaluator_ = std::make_unique<FieldEvaluator>(*mesh_context_, domain_size);
+ mesh_evaluator_ = std::make_unique<FieldEvaluator>(*mesh_context_, domain_num);
mesh_evaluator_->add(src_field_);
mesh_evaluator_->evaluate();
mesh_data_ = &mesh_evaluator_->get_evaluated(0);
@@ -588,9 +588,9 @@ class NearestTransferFunction : public fn::MultiFunction {
if (use_points_) {
const PointCloudComponent &points = *source_.get_component_for_read<PointCloudComponent>();
- const int domain_size = points.attribute_domain_size(domain_);
+ const int domain_num = points.attribute_domain_num(domain_);
point_context_.emplace(GeometryComponentFieldContext(points, domain_));
- point_evaluator_ = std::make_unique<FieldEvaluator>(*point_context_, domain_size);
+ point_evaluator_ = std::make_unique<FieldEvaluator>(*point_context_, domain_num);
point_evaluator_->add(src_field_);
point_evaluator_->evaluate();
point_data_ = &point_evaluator_->get_evaluated(0);
@@ -599,7 +599,7 @@ class NearestTransferFunction : public fn::MultiFunction {
};
static const GeometryComponent *find_source_component(const GeometrySet &geometry,
- const AttributeDomain domain)
+ const eAttrDomain domain)
{
/* Choose the other component based on a consistent order, rather than some more complicated
* heuristic. This is the same order visible in the spreadsheet and used in the ray-cast node. */
@@ -624,7 +624,7 @@ static const GeometryComponent *find_source_component(const GeometrySet &geometr
class IndexTransferFunction : public fn::MultiFunction {
GeometrySet src_geometry_;
GField src_field_;
- AttributeDomain domain_;
+ eAttrDomain domain_;
fn::MFSignature signature_;
@@ -633,7 +633,7 @@ class IndexTransferFunction : public fn::MultiFunction {
const GVArray *src_data_ = nullptr;
public:
- IndexTransferFunction(GeometrySet geometry, GField src_field, const AttributeDomain domain)
+ IndexTransferFunction(GeometrySet geometry, GField src_field, const eAttrDomain domain)
: src_geometry_(std::move(geometry)), src_field_(std::move(src_field)), domain_(domain)
{
src_geometry_.ensure_owns_direct_data();
@@ -658,9 +658,9 @@ class IndexTransferFunction : public fn::MultiFunction {
if (component == nullptr) {
return;
}
- const int domain_size = component->attribute_domain_size(domain_);
+ const int domain_num = component->attribute_domain_num(domain_);
geometry_context_.emplace(GeometryComponentFieldContext(*component, domain_));
- evaluator_ = std::make_unique<FieldEvaluator>(*geometry_context_, domain_size);
+ evaluator_ = std::make_unique<FieldEvaluator>(*geometry_context_, domain_num);
evaluator_->add(src_field_);
evaluator_->evaluate();
src_data_ = &evaluator_->get_evaluated(0);
@@ -684,7 +684,7 @@ class IndexTransferFunction : public fn::MultiFunction {
}
};
-static GField get_input_attribute_field(GeoNodeExecParams &params, const CustomDataType data_type)
+static GField get_input_attribute_field(GeoNodeExecParams &params, const eCustomDataType data_type)
{
switch (data_type) {
case CD_PROP_FLOAT:
@@ -737,8 +737,8 @@ static void node_geo_exec(GeoNodeExecParams params)
const NodeGeometryTransferAttribute &storage = node_storage(params.node());
const GeometryNodeAttributeTransferMode mapping = (GeometryNodeAttributeTransferMode)
storage.mode;
- const CustomDataType data_type = static_cast<CustomDataType>(storage.data_type);
- const AttributeDomain domain = static_cast<AttributeDomain>(storage.domain);
+ const eCustomDataType data_type = static_cast<eCustomDataType>(storage.data_type);
+ const eAttrDomain domain = static_cast<eAttrDomain>(storage.domain);
GField field = get_input_attribute_field(params, data_type);
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 a5ca1cba28f..258c1ac3fba 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_translate_instances.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_translate_instances.cc
@@ -19,7 +19,7 @@ static void translate_instances(GeoNodeExecParams &params, InstancesComponent &i
{
GeometryComponentFieldContext field_context{instances_component, ATTR_DOMAIN_INSTANCE};
- fn::FieldEvaluator evaluator{field_context, instances_component.instances_amount()};
+ fn::FieldEvaluator evaluator{field_context, instances_component.instances_num()};
evaluator.set_selection(params.extract_input<Field<bool>>("Selection"));
evaluator.add(params.extract_input<Field<float3>>("Translation"));
evaluator.add(params.extract_input<Field<bool>>("Local Space"));
diff --git a/source/blender/nodes/geometry/nodes/node_geo_triangulate.cc b/source/blender/nodes/geometry/nodes/node_geo_triangulate.cc
index 992470e8279..e47dc22da04 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_triangulate.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_triangulate.cc
@@ -83,9 +83,9 @@ static void node_geo_exec(GeoNodeExecParams params)
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);
+ const int domain_num = component.attribute_domain_num(ATTR_DOMAIN_FACE);
GeometryComponentFieldContext context{component, ATTR_DOMAIN_FACE};
- FieldEvaluator evaluator{context, domain_size};
+ FieldEvaluator evaluator{context, domain_num};
evaluator.add(selection_field);
evaluator.evaluate();
const IndexMask selection = evaluator.get_evaluated_as_mask(0);
diff --git a/source/blender/nodes/geometry/nodes/node_geo_viewer.cc b/source/blender/nodes/geometry/nodes/node_geo_viewer.cc
index 8e9d7b0e46d..6979693e215 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_viewer.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_viewer.cc
@@ -39,7 +39,7 @@ static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
uiItemR(layout, ptr, "data_type", 0, "", ICON_NONE);
}
-static eNodeSocketDatatype custom_data_type_to_socket_type(const CustomDataType type)
+static eNodeSocketDatatype custom_data_type_to_socket_type(const eCustomDataType type)
{
switch (type) {
case CD_PROP_FLOAT:
@@ -61,7 +61,7 @@ static eNodeSocketDatatype custom_data_type_to_socket_type(const CustomDataType
static void node_update(bNodeTree *ntree, bNode *node)
{
const NodeGeometryViewer &storage = node_storage(*node);
- const CustomDataType data_type = static_cast<CustomDataType>(storage.data_type);
+ const eCustomDataType data_type = static_cast<eCustomDataType>(storage.data_type);
const eNodeSocketDatatype socket_type = custom_data_type_to_socket_type(data_type);
LISTBASE_FOREACH (bNodeSocket *, socket, &node->inputs) {
@@ -82,7 +82,7 @@ static void node_gather_link_searches(GatherLinkSearchOpParams &params)
ED_spreadsheet_context_paths_set_geometry_node(bmain, snode, &viewer_node);
};
- const std::optional<CustomDataType> type = node_socket_to_custom_data_type(
+ const std::optional<eCustomDataType> type = node_socket_to_custom_data_type(
params.other_socket());
if (params.in_out() == SOCK_OUT) {
/* The viewer node only has inputs. */
diff --git a/source/blender/nodes/geometry/nodes/node_geo_volume_cube.cc b/source/blender/nodes/geometry/nodes/node_geo_volume_cube.cc
new file mode 100644
index 00000000000..d7e9e38ea0d
--- /dev/null
+++ b/source/blender/nodes/geometry/nodes/node_geo_volume_cube.cc
@@ -0,0 +1,197 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+
+#ifdef WITH_OPENVDB
+# include <openvdb/openvdb.h>
+# include <openvdb/tools/Dense.h>
+# include <openvdb/tools/LevelSetUtil.h>
+# include <openvdb/tools/ParticlesToLevelSet.h>
+#endif
+
+#include "node_geometry_util.hh"
+
+#include "DNA_mesh_types.h"
+
+#include "BLI_task.hh"
+
+#include "BKE_geometry_set.hh"
+#include "BKE_lib_id.h"
+#include "BKE_mesh.h"
+#include "BKE_volume.h"
+
+namespace blender::nodes::node_geo_volume_cube_cc {
+
+static void node_declare(NodeDeclarationBuilder &b)
+{
+ b.add_input<decl::Float>(N_("Density"))
+ .description(N_("Volume density per voxel"))
+ .supports_field()
+ .default_value(1.0f);
+ b.add_input<decl::Float>(N_("Background"))
+ .description(N_("Value for voxels outside of the cube"));
+
+ b.add_input<decl::Vector>(N_("Min"))
+ .description(N_("Minimum boundary of volume"))
+ .default_value(float3(-1.0f));
+ b.add_input<decl::Vector>(N_("Max"))
+ .description(N_("Maximum boundary of volume"))
+ .default_value(float3(1.0f));
+
+ b.add_input<decl::Int>(N_("Resolution X"))
+ .description(N_("Number of voxels in the X axis"))
+ .default_value(32)
+ .min(2);
+ b.add_input<decl::Int>(N_("Resolution Y"))
+ .description(N_("Number of voxels in the Y axis"))
+ .default_value(32)
+ .min(2);
+ b.add_input<decl::Int>(N_("Resolution Z"))
+ .description(N_("Number of voxels in the Z axis"))
+ .default_value(32)
+ .min(2);
+
+ b.add_output<decl::Geometry>(N_("Volume"));
+}
+
+static float map(const float x,
+ const float in_min,
+ const float in_max,
+ const float out_min,
+ const float out_max)
+{
+ return (x - in_min) * (out_max - out_min) / (in_max - in_min) + out_min;
+}
+
+class Grid3DFieldContext : public FieldContext {
+ private:
+ int3 resolution_;
+ float3 bounds_min_;
+ float3 bounds_max_;
+
+ public:
+ Grid3DFieldContext(const int3 resolution, const float3 bounds_min, const float3 bounds_max)
+ : resolution_(resolution), bounds_min_(bounds_min), bounds_max_(bounds_max)
+ {
+ }
+
+ int64_t points_num() const
+ {
+ return static_cast<int64_t>(resolution_.x) * static_cast<int64_t>(resolution_.y) *
+ static_cast<int64_t>(resolution_.z);
+ }
+
+ GVArray get_varray_for_input(const FieldInput &field_input,
+ const IndexMask UNUSED(mask),
+ ResourceScope &UNUSED(scope)) const
+ {
+ const bke::AttributeFieldInput *attribute_field_input =
+ dynamic_cast<const bke::AttributeFieldInput *>(&field_input);
+ if (attribute_field_input == nullptr) {
+ return {};
+ }
+ if (attribute_field_input->attribute_name() != "position") {
+ return {};
+ }
+
+ Array<float3> positions(this->points_num());
+
+ threading::parallel_for(IndexRange(resolution_.x), 1, [&](const IndexRange x_range) {
+ /* Start indexing at current X slice. */
+ int64_t index = x_range.start() * resolution_.y * resolution_.z;
+ for (const int64_t x_i : x_range) {
+ const float x = map(x_i, 0.0f, resolution_.x - 1, bounds_min_.x, bounds_max_.x);
+ for (const int64_t y_i : IndexRange(resolution_.y)) {
+ const float y = map(y_i, 0.0f, resolution_.y - 1, bounds_min_.y, bounds_max_.y);
+ for (const int64_t z_i : IndexRange(resolution_.z)) {
+ const float z = map(z_i, 0.0f, resolution_.z - 1, bounds_min_.z, bounds_max_.z);
+ positions[index] = float3(x, y, z);
+ index++;
+ }
+ }
+ }
+ });
+ return VArray<float3>::ForContainer(std::move(positions));
+ }
+};
+
+#ifdef WITH_OPENVDB
+static void node_geo_exec(GeoNodeExecParams params)
+{
+ const float3 bounds_min = params.extract_input<float3>("Min");
+ const float3 bounds_max = params.extract_input<float3>("Max");
+
+ const int3 resolution = int3(params.extract_input<int>("Resolution X"),
+ params.extract_input<int>("Resolution Y"),
+ params.extract_input<int>("Resolution Z"));
+
+ if (resolution.x < 2 || resolution.y < 2 || resolution.z < 2) {
+ params.error_message_add(NodeWarningType::Error, TIP_("Resolution must be greater than 1"));
+ params.set_default_remaining_outputs();
+ return;
+ }
+
+ if (bounds_min.x == bounds_max.x || bounds_min.y == bounds_max.y ||
+ bounds_min.z == bounds_max.z) {
+ params.error_message_add(NodeWarningType::Error,
+ TIP_("Bounding box volume must be greater than 0"));
+ params.set_default_remaining_outputs();
+ return;
+ }
+
+ Field<float> input_field = params.extract_input<Field<float>>("Density");
+
+ /* Evaluate input field on a 3D grid. */
+ Grid3DFieldContext context(resolution, bounds_min, bounds_max);
+ FieldEvaluator evaluator(context, context.points_num());
+ Array<float> densities(context.points_num());
+ evaluator.add_with_destination(std::move(input_field), densities.as_mutable_span());
+ evaluator.evaluate();
+
+ /* Store resulting values in openvdb grid. */
+ const float background = params.extract_input<float>("Background");
+ openvdb::FloatGrid::Ptr grid = openvdb::FloatGrid::create(background);
+ grid->setGridClass(openvdb::GRID_FOG_VOLUME);
+
+ openvdb::tools::Dense<float, openvdb::tools::LayoutZYX> dense_grid{
+ openvdb::math::CoordBBox({0, 0, 0}, {resolution.x - 1, resolution.y - 1, resolution.z - 1}),
+ densities.data()};
+ openvdb::tools::copyFromDense(dense_grid, *grid, 0.0f);
+
+ grid->transform().preTranslate(openvdb::math::Vec3<float>(-0.5f));
+ const float3 scale_fac = (bounds_max - bounds_min) / float3(resolution - 1);
+ grid->transform().postScale(openvdb::math::Vec3<float>(scale_fac.x, scale_fac.y, scale_fac.z));
+ grid->transform().postTranslate(
+ openvdb::math::Vec3<float>(bounds_min.x, bounds_min.y, bounds_min.z));
+
+ Volume *volume = (Volume *)BKE_id_new_nomain(ID_VO, nullptr);
+ BKE_volume_init_grids(volume);
+
+ BKE_volume_grid_add_vdb(*volume, "density", std::move(grid));
+
+ GeometrySet r_geometry_set;
+ r_geometry_set.replace_volume(volume);
+ params.set_output("Volume", r_geometry_set);
+}
+
+#else
+static void node_geo_exec(GeoNodeExecParams params)
+{
+ params.error_message_add(NodeWarningType::Error,
+ TIP_("Disabled, Blender was compiled without OpenVDB"));
+ params.set_default_remaining_outputs();
+}
+#endif /* WITH_OPENVDB */
+
+} // namespace blender::nodes::node_geo_volume_cube_cc
+
+void register_node_type_geo_volume_cube()
+{
+ namespace file_ns = blender::nodes::node_geo_volume_cube_cc;
+
+ static bNodeType ntype;
+
+ geo_node_type_base(&ntype, GEO_NODE_VOLUME_CUBE, "Volume 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_volume_to_mesh.cc b/source/blender/nodes/geometry/nodes/node_geo_volume_to_mesh.cc
index e5827c24320..e1d1c67b8c8 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
@@ -41,7 +41,9 @@ static void node_declare(NodeDeclarationBuilder &b)
.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_("Threshold"))
+ .default_value(0.1f)
+ .description(N_("Values larger than the threshold are inside the generated mesh"));
b.add_input<decl::Float>(N_("Adaptivity")).min(0.0f).max(1.0f).subtype(PROP_FACTOR);
b.add_output<decl::Geometry>(N_("Mesh"));
}
@@ -151,6 +153,16 @@ static Mesh *create_mesh_from_volume(GeometrySet &geometry_set, GeoNodeExecParam
}
const bke::VolumeToMeshResolution resolution = get_resolution_param(params);
+
+ if (resolution.mode == VOLUME_TO_MESH_RESOLUTION_MODE_VOXEL_SIZE &&
+ resolution.settings.voxel_size <= 0.0f) {
+ return nullptr;
+ }
+ if (resolution.mode == VOLUME_TO_MESH_RESOLUTION_MODE_VOXEL_AMOUNT &&
+ resolution.settings.voxel_amount <= 0) {
+ return nullptr;
+ }
+
const Main *bmain = DEG_get_bmain(params.depsgraph());
BKE_volume_load(volume, bmain);
diff --git a/source/blender/nodes/intern/geometry_nodes_eval_log.cc b/source/blender/nodes/intern/geometry_nodes_eval_log.cc
index 378bac894e8..85dfdf03b82 100644
--- a/source/blender/nodes/intern/geometry_nodes_eval_log.cc
+++ b/source/blender/nodes/intern/geometry_nodes_eval_log.cc
@@ -241,27 +241,27 @@ GeometryValueLog::GeometryValueLog(const GeometrySet &geometry_set, bool log_ful
case GEO_COMPONENT_TYPE_MESH: {
const MeshComponent &mesh_component = *(const MeshComponent *)component;
MeshInfo &info = this->mesh_info.emplace();
- info.tot_verts = mesh_component.attribute_domain_size(ATTR_DOMAIN_POINT);
- info.tot_edges = mesh_component.attribute_domain_size(ATTR_DOMAIN_EDGE);
- info.tot_faces = mesh_component.attribute_domain_size(ATTR_DOMAIN_FACE);
+ info.verts_num = mesh_component.attribute_domain_num(ATTR_DOMAIN_POINT);
+ info.edges_num = mesh_component.attribute_domain_num(ATTR_DOMAIN_EDGE);
+ info.faces_num = mesh_component.attribute_domain_num(ATTR_DOMAIN_FACE);
break;
}
case GEO_COMPONENT_TYPE_CURVE: {
const CurveComponent &curve_component = *(const CurveComponent *)component;
CurveInfo &info = this->curve_info.emplace();
- info.tot_splines = curve_component.attribute_domain_size(ATTR_DOMAIN_CURVE);
+ info.splines_num = curve_component.attribute_domain_num(ATTR_DOMAIN_CURVE);
break;
}
case GEO_COMPONENT_TYPE_POINT_CLOUD: {
const PointCloudComponent &pointcloud_component = *(const PointCloudComponent *)component;
PointCloudInfo &info = this->pointcloud_info.emplace();
- info.tot_points = pointcloud_component.attribute_domain_size(ATTR_DOMAIN_POINT);
+ info.points_num = pointcloud_component.attribute_domain_num(ATTR_DOMAIN_POINT);
break;
}
case GEO_COMPONENT_TYPE_INSTANCES: {
const InstancesComponent &instances_component = *(const InstancesComponent *)component;
InstancesInfo &info = this->instances_info.emplace();
- info.tot_instances = instances_component.instances_amount();
+ info.instances_num = instances_component.instances_num();
break;
}
case GEO_COMPONENT_TYPE_VOLUME: {
@@ -495,7 +495,7 @@ void LocalGeoLogger::log_execution_time(DNode node, std::chrono::microseconds ex
void LocalGeoLogger::log_used_named_attribute(DNode node,
std::string attribute_name,
- NamedAttributeUsage usage)
+ eNamedAttrUsage usage)
{
used_named_attributes_.append({node, {std::move(attribute_name), usage}});
}
diff --git a/source/blender/nodes/intern/node_common.cc b/source/blender/nodes/intern/node_common.cc
index abbfe4b823d..b7c5f9570e4 100644
--- a/source/blender/nodes/intern/node_common.cc
+++ b/source/blender/nodes/intern/node_common.cc
@@ -156,7 +156,8 @@ static void group_verify_socket_list(bNodeTree &node_tree,
bNode &node,
const ListBase &interface_sockets,
ListBase &verify_lb,
- const eNodeSocketInOut in_out)
+ const eNodeSocketInOut in_out,
+ const bool ensure_extend_socket_exists)
{
ListBase old_sockets = verify_lb;
BLI_listbase_clear(&verify_lb);
@@ -177,6 +178,17 @@ static void group_verify_socket_list(bNodeTree &node_tree,
}
}
+ if (ensure_extend_socket_exists) {
+ bNodeSocket *last_socket = static_cast<bNodeSocket *>(old_sockets.last);
+ if (last_socket != nullptr && STREQ(last_socket->identifier, "__extend__")) {
+ BLI_remlink(&old_sockets, last_socket);
+ BLI_addtail(&verify_lb, last_socket);
+ }
+ else {
+ nodeAddSocket(&node_tree, &node, in_out, "NodeSocketVirtual", "__extend__", "");
+ }
+ }
+
/* Remove leftover sockets that didn't match the node group's interface. */
LISTBASE_FOREACH_MUTABLE (bNodeSocket *, unused_socket, &old_sockets) {
nodeRemoveSocket(&node_tree, &node, unused_socket);
@@ -195,8 +207,8 @@ void node_group_update(struct bNodeTree *ntree, struct bNode *node)
}
else {
bNodeTree *ngroup = (bNodeTree *)node->id;
- group_verify_socket_list(*ntree, *node, ngroup->inputs, node->inputs, SOCK_IN);
- group_verify_socket_list(*ntree, *node, ngroup->outputs, node->outputs, SOCK_OUT);
+ group_verify_socket_list(*ntree, *node, ngroup->inputs, node->inputs, SOCK_IN, false);
+ group_verify_socket_list(*ntree, *node, ngroup->outputs, node->outputs, SOCK_OUT, false);
}
}
@@ -484,15 +496,7 @@ void node_group_input_update(bNodeTree *ntree, bNode *node)
}
BLI_freelistN(&tmplinks);
-
- /* check inputs and outputs, and remove or insert them */
- {
- /* value_in_out inverted for interface nodes to get correct socket value_property */
- group_verify_socket_list(*ntree, *node, ntree->inputs, node->outputs, SOCK_OUT);
-
- /* add virtual extension socket */
- nodeAddSocket(ntree, node, SOCK_OUT, "NodeSocketVirtual", "__extend__", "");
- }
+ group_verify_socket_list(*ntree, *node, ntree->inputs, node->outputs, SOCK_OUT, true);
}
void register_node_type_group_input()
@@ -582,15 +586,7 @@ void node_group_output_update(bNodeTree *ntree, bNode *node)
}
BLI_freelistN(&tmplinks);
-
- /* check inputs and outputs, and remove or insert them */
- {
- /* value_in_out inverted for interface nodes to get correct socket value_property */
- group_verify_socket_list(*ntree, *node, ntree->outputs, node->inputs, SOCK_IN);
-
- /* add virtual extension socket */
- nodeAddSocket(ntree, node, SOCK_IN, "NodeSocketVirtual", "__extend__", "");
- }
+ group_verify_socket_list(*ntree, *node, ntree->outputs, node->inputs, SOCK_IN, true);
}
void register_node_type_group_output()
diff --git a/source/blender/nodes/intern/node_geometry_exec.cc b/source/blender/nodes/intern/node_geometry_exec.cc
index cea3084a418..56e9c9f0496 100644
--- a/source/blender/nodes/intern/node_geometry_exec.cc
+++ b/source/blender/nodes/intern/node_geometry_exec.cc
@@ -24,7 +24,7 @@ void GeoNodeExecParams::error_message_add(const NodeWarningType type, std::strin
}
void GeoNodeExecParams::used_named_attribute(std::string attribute_name,
- const NamedAttributeUsage usage)
+ const eNamedAttrUsage usage)
{
if (provider_->logger == nullptr) {
return;
@@ -37,7 +37,7 @@ void GeoNodeExecParams::check_input_geometry_set(StringRef identifier,
const GeometrySet &geometry_set) const
{
const SocketDeclaration &decl =
- *provider_->dnode->input_by_identifier(identifier).bsocket()->declaration;
+ *provider_->dnode->input_by_identifier(identifier).bsocket()->runtime->declaration;
const decl::Geometry *geo_decl = dynamic_cast<const decl::Geometry *>(&decl);
if (geo_decl == nullptr) {
return;
@@ -110,137 +110,6 @@ const bNodeSocket *GeoNodeExecParams::find_available_socket(const StringRef name
return nullptr;
}
-GVArray GeoNodeExecParams::get_input_attribute(const StringRef name,
- const GeometryComponent &component,
- const AttributeDomain domain,
- const CustomDataType type,
- const void *default_value) const
-{
- const bNodeSocket *found_socket = this->find_available_socket(name);
- BLI_assert(found_socket != nullptr); /* There should always be available socket for the name. */
- const CPPType *cpp_type = bke::custom_data_type_to_cpp_type(type);
- const int64_t domain_size = component.attribute_domain_size(domain);
-
- if (default_value == nullptr) {
- default_value = cpp_type->default_value();
- }
-
- if (found_socket == nullptr) {
- return GVArray::ForSingle(*cpp_type, domain_size, default_value);
- }
-
- if (found_socket->type == SOCK_STRING) {
- const std::string name = this->get_input<std::string>(found_socket->identifier);
- /* Try getting the attribute without the default value. */
- GVArray attribute = component.attribute_try_get_for_read(name, domain, type);
- if (attribute) {
- return attribute;
- }
-
- /* If the attribute doesn't exist, use the default value and output an error message
- * (except when the field is empty, to avoid spamming error messages, and not when
- * the domain is empty and we don't expect an attribute anyway). */
- if (!name.empty() && component.attribute_domain_size(domain) != 0) {
- this->error_message_add(NodeWarningType::Error,
- TIP_("No attribute with name \"") + name + "\"");
- }
- return GVArray::ForSingle(*cpp_type, domain_size, default_value);
- }
- const bke::DataTypeConversions &conversions = bke::get_implicit_type_conversions();
- if (found_socket->type == SOCK_FLOAT) {
- const float value = this->get_input<float>(found_socket->identifier);
- BUFFER_FOR_CPP_TYPE_VALUE(*cpp_type, buffer);
- conversions.convert_to_uninitialized(CPPType::get<float>(), *cpp_type, &value, buffer);
- return GVArray::ForSingle(*cpp_type, domain_size, buffer);
- }
- if (found_socket->type == SOCK_INT) {
- const int value = this->get_input<int>(found_socket->identifier);
- BUFFER_FOR_CPP_TYPE_VALUE(*cpp_type, buffer);
- conversions.convert_to_uninitialized(CPPType::get<int>(), *cpp_type, &value, buffer);
- return GVArray::ForSingle(*cpp_type, domain_size, buffer);
- }
- if (found_socket->type == SOCK_VECTOR) {
- const float3 value = this->get_input<float3>(found_socket->identifier);
- BUFFER_FOR_CPP_TYPE_VALUE(*cpp_type, buffer);
- conversions.convert_to_uninitialized(CPPType::get<float3>(), *cpp_type, &value, buffer);
- return GVArray::ForSingle(*cpp_type, domain_size, buffer);
- }
- if (found_socket->type == SOCK_RGBA) {
- const ColorGeometry4f value = this->get_input<ColorGeometry4f>(found_socket->identifier);
- BUFFER_FOR_CPP_TYPE_VALUE(*cpp_type, buffer);
- conversions.convert_to_uninitialized(
- CPPType::get<ColorGeometry4f>(), *cpp_type, &value, buffer);
- return GVArray::ForSingle(*cpp_type, domain_size, buffer);
- }
- BLI_assert(false);
- return GVArray::ForSingle(*cpp_type, domain_size, default_value);
-}
-
-CustomDataType GeoNodeExecParams::get_input_attribute_data_type(
- const StringRef name,
- const GeometryComponent &component,
- const CustomDataType default_type) const
-{
- const bNodeSocket *found_socket = this->find_available_socket(name);
- BLI_assert(found_socket != nullptr); /* There should always be available socket for the name. */
- if (found_socket == nullptr) {
- return default_type;
- }
-
- if (found_socket->type == SOCK_STRING) {
- const std::string name = this->get_input<std::string>(found_socket->identifier);
- std::optional<AttributeMetaData> info = component.attribute_get_meta_data(name);
- if (info) {
- return info->data_type;
- }
- return default_type;
- }
- if (found_socket->type == SOCK_FLOAT) {
- return CD_PROP_FLOAT;
- }
- if (found_socket->type == SOCK_VECTOR) {
- return CD_PROP_FLOAT3;
- }
- if (found_socket->type == SOCK_RGBA) {
- return CD_PROP_COLOR;
- }
- if (found_socket->type == SOCK_BOOLEAN) {
- return CD_PROP_BOOL;
- }
-
- BLI_assert(false);
- return default_type;
-}
-
-AttributeDomain GeoNodeExecParams::get_highest_priority_input_domain(
- Span<std::string> names,
- const GeometryComponent &component,
- const AttributeDomain default_domain) const
-{
- Vector<AttributeDomain, 8> input_domains;
- for (const std::string &name : names) {
- const bNodeSocket *found_socket = this->find_available_socket(name);
- BLI_assert(found_socket != nullptr); /* A socket should be available socket for the name. */
- if (found_socket == nullptr) {
- continue;
- }
-
- if (found_socket->type == SOCK_STRING) {
- const std::string name = this->get_input<std::string>(found_socket->identifier);
- std::optional<AttributeMetaData> info = component.attribute_get_meta_data(name);
- if (info) {
- input_domains.append(info->domain);
- }
- }
- }
-
- if (input_domains.size() > 0) {
- return bke::attribute_domain_highest_priority(input_domains);
- }
-
- return default_domain;
-}
-
std::string GeoNodeExecParams::attribute_producer_name() const
{
return provider_->dnode->label_or_name() + TIP_(" node");
diff --git a/source/blender/nodes/intern/node_socket.cc b/source/blender/nodes/intern/node_socket.cc
index 0ab446d8b0c..098f766589d 100644
--- a/source/blender/nodes/intern/node_socket.cc
+++ b/source/blender/nodes/intern/node_socket.cc
@@ -19,6 +19,7 @@
#include "BKE_geometry_set.hh"
#include "BKE_lib_id.h"
#include "BKE_node.h"
+#include "BKE_node_runtime.hh"
#include "DNA_collection_types.h"
#include "DNA_material_types.h"
@@ -261,8 +262,8 @@ void node_verify_sockets(bNodeTree *ntree, bNode *node, bool do_id_user)
}
if (ntype->declare != nullptr) {
nodeDeclarationEnsureOnOutdatedNode(ntree, node);
- if (!node->declaration->matches(*node)) {
- refresh_node(*ntree, *node, *node->declaration, do_id_user);
+ if (!node->runtime->declaration->matches(*node)) {
+ refresh_node(*ntree, *node, *node->runtime->declaration, do_id_user);
}
nodeSocketDeclarationsUpdate(node);
return;
diff --git a/source/blender/nodes/intern/node_socket_declarations.cc b/source/blender/nodes/intern/node_socket_declarations.cc
index 06925761bc7..b9fb75f30c7 100644
--- a/source/blender/nodes/intern/node_socket_declarations.cc
+++ b/source/blender/nodes/intern/node_socket_declarations.cc
@@ -4,6 +4,7 @@
#include "NOD_socket_declarations_geometry.hh"
#include "BKE_node.h"
+#include "BKE_node_runtime.hh"
#include "BLI_math_vector.h"
@@ -33,14 +34,14 @@ static bool sockets_can_connect(const SocketDeclaration &socket_decl,
return false;
}
- if (other_socket.declaration) {
+ if (other_socket.runtime->declaration) {
if (socket_decl.in_out() == SOCK_IN) {
- if (!field_types_are_compatible(socket_decl, *other_socket.declaration)) {
+ if (!field_types_are_compatible(socket_decl, *other_socket.runtime->declaration)) {
return false;
}
}
else {
- if (!field_types_are_compatible(*other_socket.declaration, socket_decl)) {
+ if (!field_types_are_compatible(*other_socket.runtime->declaration, socket_decl)) {
return false;
}
}
diff --git a/source/blender/nodes/shader/node_shader_tree.cc b/source/blender/nodes/shader/node_shader_tree.cc
index c5f40a46ca3..24558e4b32b 100644
--- a/source/blender/nodes/shader/node_shader_tree.cc
+++ b/source/blender/nodes/shader/node_shader_tree.cc
@@ -587,10 +587,11 @@ static bNode *ntree_shader_copy_branch(bNodeTree *ntree,
}
}
}
- /* Recreate links between copied nodes. */
+ /* Recreate links between copied nodes AND incoming links to the copied nodes. */
LISTBASE_FOREACH (bNodeLink *, link, &ntree->links) {
- if (link->fromnode->tmp_flag >= 0 && link->tonode->tmp_flag >= 0) {
- bNode *fromnode = nodes_copy[link->fromnode->tmp_flag];
+ if (link->tonode->tmp_flag >= 0) {
+ bool from_node_copied = link->fromnode->tmp_flag >= 0;
+ bNode *fromnode = from_node_copied ? nodes_copy[link->fromnode->tmp_flag] : link->fromnode;
bNode *tonode = nodes_copy[link->tonode->tmp_flag];
bNodeSocket *fromsock = ntree_shader_node_find_output(fromnode, link->fromsock->identifier);
bNodeSocket *tosock = ntree_shader_node_find_input(tonode, link->tosock->identifier);
@@ -1006,6 +1007,7 @@ static void ntree_shader_pruned_unused(bNodeTree *ntree, bNode *output_node)
LISTBASE_FOREACH (bNode *, node, &ntree->nodes) {
if (node->type == SH_NODE_OUTPUT_AOV) {
+ node->tmp_flag = 1;
nodeChainIterBackwards(ntree, node, ntree_branch_node_tag, nullptr, 0);
}
}
diff --git a/source/blender/nodes/shader/node_shader_util.cc b/source/blender/nodes/shader/node_shader_util.cc
index c47b69e6b69..059d7800fc5 100644
--- a/source/blender/nodes/shader/node_shader_util.cc
+++ b/source/blender/nodes/shader/node_shader_util.cc
@@ -329,7 +329,7 @@ void node_shader_gpu_tex_mapping(GPUMaterial *mat,
void get_XYZ_to_RGB_for_gpu(XYZ_to_RGB *data)
{
- const float *xyz_to_rgb = IMB_colormanagement_get_xyz_to_rgb();
+ const float *xyz_to_rgb = IMB_colormanagement_get_xyz_to_scene_linear();
data->r[0] = xyz_to_rgb[0];
data->r[1] = xyz_to_rgb[3];
data->r[2] = xyz_to_rgb[6];
diff --git a/source/blender/nodes/shader/nodes/node_shader_blackbody.cc b/source/blender/nodes/shader/nodes/node_shader_blackbody.cc
index 62e631efb57..9f382e5a3bb 100644
--- a/source/blender/nodes/shader/nodes/node_shader_blackbody.cc
+++ b/source/blender/nodes/shader/nodes/node_shader_blackbody.cc
@@ -3,6 +3,8 @@
#include "node_shader_util.hh"
+#include "IMB_colormanagement.h"
+
namespace blender::nodes::node_shader_blackbody_cc {
static void node_declare(NodeDeclarationBuilder &b)
@@ -20,7 +22,7 @@ static int node_shader_gpu_blackbody(GPUMaterial *mat,
const int size = CM_TABLE + 1;
float *data = static_cast<float *>(MEM_mallocN(sizeof(float) * size * 4, "blackbody texture"));
- blackbody_temperature_to_rgb_table(data, size, 965.0f, 12000.0f);
+ IMB_colormanagement_blackbody_temperature_to_rgb_table(data, size, 800.0f, 12000.0f);
float layer;
GPUNodeLink *ramp_texture = GPU_color_band(mat, size, data, &layer);
diff --git a/source/blender/nodes/shader/nodes/node_shader_curves.cc b/source/blender/nodes/shader/nodes/node_shader_curves.cc
index b1db0248d9f..eb47059063d 100644
--- a/source/blender/nodes/shader/nodes/node_shader_curves.cc
+++ b/source/blender/nodes/shader/nodes/node_shader_curves.cc
@@ -28,48 +28,34 @@ static int gpu_shader_curve_vec(GPUMaterial *mat,
GPUNodeStack *in,
GPUNodeStack *out)
{
- float *array, layer;
- int size;
-
- CurveMapping *cumap = (CurveMapping *)node->storage;
-
- BKE_curvemapping_init(cumap);
- BKE_curvemapping_table_RGBA(cumap, &array, &size);
- GPUNodeLink *tex = GPU_color_band(mat, size, array, &layer);
-
- float ext_xyz[3][4];
- float range_xyz[3];
-
- for (int a = 0; a < 3; a++) {
- const CurveMap *cm = &cumap->cm[a];
- ext_xyz[a][0] = cm->mintable;
- ext_xyz[a][2] = cm->maxtable;
- range_xyz[a] = 1.0f / max_ff(1e-8f, cm->maxtable - cm->mintable);
- /* Compute extrapolation gradients. */
- if ((cumap->flag & CUMA_EXTEND_EXTRAPOLATE) != 0) {
- ext_xyz[a][1] = (cm->ext_in[0] != 0.0f) ? (cm->ext_in[1] / (cm->ext_in[0] * range_xyz[a])) :
- 1e8f;
- ext_xyz[a][3] = (cm->ext_out[0] != 0.0f) ?
- (cm->ext_out[1] / (cm->ext_out[0] * range_xyz[a])) :
- 1e8f;
- }
- else {
- ext_xyz[a][1] = 0.0f;
- ext_xyz[a][3] = 0.0f;
- }
- }
+ CurveMapping *curve_mapping = (CurveMapping *)node->storage;
+
+ BKE_curvemapping_init(curve_mapping);
+ float *band_values;
+ int band_size;
+ BKE_curvemapping_table_RGBA(curve_mapping, &band_values, &band_size);
+ float band_layer;
+ GPUNodeLink *band_texture = GPU_color_band(mat, band_size, band_values, &band_layer);
+
+ float start_slopes[CM_TOT];
+ float end_slopes[CM_TOT];
+ BKE_curvemapping_compute_slopes(curve_mapping, start_slopes, end_slopes);
+ float range_minimums[CM_TOT];
+ BKE_curvemapping_get_range_minimums(curve_mapping, range_minimums);
+ float range_dividers[CM_TOT];
+ BKE_curvemapping_compute_range_dividers(curve_mapping, range_dividers);
return GPU_stack_link(mat,
node,
- "curves_vec",
+ "curves_vector_mixed",
in,
out,
- tex,
- GPU_constant(&layer),
- GPU_uniform(range_xyz),
- GPU_uniform(ext_xyz[0]),
- GPU_uniform(ext_xyz[1]),
- GPU_uniform(ext_xyz[2]));
+ band_texture,
+ GPU_constant(&band_layer),
+ GPU_uniform(range_minimums),
+ GPU_uniform(range_dividers),
+ GPU_uniform(start_slopes),
+ GPU_uniform(end_slopes));
}
class CurveVecFunction : public fn::MultiFunction {
@@ -157,72 +143,59 @@ static int gpu_shader_curve_rgb(GPUMaterial *mat,
GPUNodeStack *in,
GPUNodeStack *out)
{
- float *array, layer;
- int size;
- bool use_opti = true;
-
- CurveMapping *cumap = (CurveMapping *)node->storage;
-
- BKE_curvemapping_init(cumap);
- BKE_curvemapping_table_RGBA(cumap, &array, &size);
- GPUNodeLink *tex = GPU_color_band(mat, size, array, &layer);
-
- float ext_rgba[4][4];
- float range_rgba[4];
-
- for (int a = 0; a < CM_TOT; a++) {
- const CurveMap *cm = &cumap->cm[a];
- ext_rgba[a][0] = cm->mintable;
- ext_rgba[a][2] = cm->maxtable;
- range_rgba[a] = 1.0f / max_ff(1e-8f, cm->maxtable - cm->mintable);
- /* Compute extrapolation gradients. */
- if ((cumap->flag & CUMA_EXTEND_EXTRAPOLATE) != 0) {
- ext_rgba[a][1] = (cm->ext_in[0] != 0.0f) ?
- (cm->ext_in[1] / (cm->ext_in[0] * range_rgba[a])) :
- 1e8f;
- ext_rgba[a][3] = (cm->ext_out[0] != 0.0f) ?
- (cm->ext_out[1] / (cm->ext_out[0] * range_rgba[a])) :
- 1e8f;
- }
- else {
- ext_rgba[a][1] = 0.0f;
- ext_rgba[a][3] = 0.0f;
- }
-
- /* Check if rgb comps are just linear. */
- if (a < 3) {
- if (range_rgba[a] != 1.0f || ext_rgba[a][1] != 1.0f || ext_rgba[a][2] != 1.0f ||
- cm->totpoint != 2 || cm->curve[0].x != 0.0f || cm->curve[0].y != 0.0f ||
- cm->curve[1].x != 1.0f || cm->curve[1].y != 1.0f) {
- use_opti = false;
- }
- }
- }
-
- if (use_opti) {
+ CurveMapping *curve_mapping = (CurveMapping *)node->storage;
+
+ BKE_curvemapping_init(curve_mapping);
+ float *band_values;
+ int band_size;
+ BKE_curvemapping_table_RGBA(curve_mapping, &band_values, &band_size);
+ float band_layer;
+ GPUNodeLink *band_texture = GPU_color_band(mat, band_size, band_values, &band_layer);
+
+ float start_slopes[CM_TOT];
+ float end_slopes[CM_TOT];
+ BKE_curvemapping_compute_slopes(curve_mapping, start_slopes, end_slopes);
+ float range_minimums[CM_TOT];
+ BKE_curvemapping_get_range_minimums(curve_mapping, range_minimums);
+ float range_dividers[CM_TOT];
+ BKE_curvemapping_compute_range_dividers(curve_mapping, range_dividers);
+
+ /* Shader nodes don't do white balancing. */
+ float black_level[4] = {0.0f, 0.0f, 0.0f, 1.0f};
+ float white_level[4] = {1.0f, 1.0f, 1.0f, 1.0f};
+
+ /* If the RGB curves do nothing, use a function that skips RGB computations. */
+ if (BKE_curvemapping_is_map_identity(curve_mapping, 0) &&
+ BKE_curvemapping_is_map_identity(curve_mapping, 1) &&
+ BKE_curvemapping_is_map_identity(curve_mapping, 2)) {
return GPU_stack_link(mat,
node,
- "curves_rgb_opti",
+ "curves_combined_only",
in,
out,
- tex,
- GPU_constant(&layer),
- GPU_uniform(range_rgba),
- GPU_uniform(ext_rgba[3]));
+ GPU_constant(black_level),
+ GPU_constant(white_level),
+ band_texture,
+ GPU_constant(&band_layer),
+ GPU_uniform(&range_minimums[3]),
+ GPU_uniform(&range_dividers[3]),
+ GPU_uniform(&start_slopes[3]),
+ GPU_uniform(&end_slopes[3]));
}
return GPU_stack_link(mat,
node,
- "curves_rgb",
+ "curves_combined_rgb",
in,
out,
- tex,
- GPU_constant(&layer),
- GPU_uniform(range_rgba),
- GPU_uniform(ext_rgba[0]),
- GPU_uniform(ext_rgba[1]),
- GPU_uniform(ext_rgba[2]),
- GPU_uniform(ext_rgba[3]));
+ GPU_constant(black_level),
+ GPU_constant(white_level),
+ band_texture,
+ GPU_constant(&band_layer),
+ GPU_uniform(range_minimums),
+ GPU_uniform(range_dividers),
+ GPU_uniform(start_slopes),
+ GPU_uniform(end_slopes));
}
class CurveRGBFunction : public fn::MultiFunction {
@@ -316,40 +289,34 @@ static int gpu_shader_curve_float(GPUMaterial *mat,
GPUNodeStack *in,
GPUNodeStack *out)
{
- float *array, layer;
- int size;
-
- CurveMapping *cumap = (CurveMapping *)node->storage;
+ CurveMapping *curve_mapping = (CurveMapping *)node->storage;
+
+ BKE_curvemapping_init(curve_mapping);
+ float *band_values;
+ int band_size;
+ BKE_curvemapping_table_RGBA(curve_mapping, &band_values, &band_size);
+ float band_layer;
+ GPUNodeLink *band_texture = GPU_color_band(mat, band_size, band_values, &band_layer);
+
+ float start_slopes[CM_TOT];
+ float end_slopes[CM_TOT];
+ BKE_curvemapping_compute_slopes(curve_mapping, start_slopes, end_slopes);
+ float range_minimums[CM_TOT];
+ BKE_curvemapping_get_range_minimums(curve_mapping, range_minimums);
+ float range_dividers[CM_TOT];
+ BKE_curvemapping_compute_range_dividers(curve_mapping, range_dividers);
- BKE_curvemapping_init(cumap);
- BKE_curvemapping_table_F(cumap, &array, &size);
- GPUNodeLink *tex = GPU_color_band(mat, size, array, &layer);
-
- float ext_xyz[4];
- float range_x;
-
- const CurveMap *cm = &cumap->cm[0];
- ext_xyz[0] = cm->mintable;
- ext_xyz[2] = cm->maxtable;
- range_x = 1.0f / max_ff(1e-8f, cm->maxtable - cm->mintable);
- /* Compute extrapolation gradients. */
- if ((cumap->flag & CUMA_EXTEND_EXTRAPOLATE) != 0) {
- ext_xyz[1] = (cm->ext_in[0] != 0.0f) ? (cm->ext_in[1] / (cm->ext_in[0] * range_x)) : 1e8f;
- ext_xyz[3] = (cm->ext_out[0] != 0.0f) ? (cm->ext_out[1] / (cm->ext_out[0] * range_x)) : 1e8f;
- }
- else {
- ext_xyz[1] = 0.0f;
- ext_xyz[3] = 0.0f;
- }
return GPU_stack_link(mat,
node,
- "curve_float",
+ "curves_float_mixed",
in,
out,
- tex,
- GPU_constant(&layer),
- GPU_uniform(&range_x),
- GPU_uniform(ext_xyz));
+ band_texture,
+ GPU_constant(&band_layer),
+ GPU_uniform(range_minimums),
+ GPU_uniform(range_dividers),
+ GPU_uniform(start_slopes),
+ GPU_uniform(end_slopes));
}
class CurveFloatFunction : public fn::MultiFunction {
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 a487e07bd5a..5fc69987c67 100644
--- a/source/blender/nodes/shader/nodes/node_shader_map_range.cc
+++ b/source/blender/nodes/shader/nodes/node_shader_map_range.cc
@@ -53,7 +53,7 @@ static void node_shader_buts_map_range(uiLayout *layout, bContext *UNUSED(C), Po
static int node_shader_map_range_ui_class(const bNode *node)
{
const NodeMapRange &storage = node_storage(*node);
- const CustomDataType data_type = static_cast<CustomDataType>(storage.data_type);
+ const eCustomDataType data_type = static_cast<eCustomDataType>(storage.data_type);
if (data_type == CD_PROP_FLOAT3) {
return NODE_CLASS_OP_VECTOR;
}
@@ -63,7 +63,7 @@ static int node_shader_map_range_ui_class(const bNode *node)
static void node_shader_update_map_range(bNodeTree *ntree, bNode *node)
{
const NodeMapRange &storage = node_storage(*node);
- const CustomDataType data_type = static_cast<CustomDataType>(storage.data_type);
+ const eCustomDataType data_type = static_cast<eCustomDataType>(storage.data_type);
const int type = (data_type == CD_PROP_FLOAT) ? SOCK_FLOAT : SOCK_VECTOR;
Array<bool> new_input_availability(BLI_listbase_count(&node->inputs));
@@ -108,7 +108,7 @@ static void node_shader_init_map_range(bNodeTree *UNUSED(ntree), bNode *node)
class SocketSearchOp {
public:
std::string socket_name;
- CustomDataType data_type;
+ eCustomDataType data_type;
int interpolation_type = NODE_MAP_RANGE_LINEAR;
void operator()(LinkSearchOpParams &params)
@@ -120,7 +120,7 @@ class SocketSearchOp {
}
};
-static std::optional<CustomDataType> node_type_from_other_socket(const bNodeSocket &socket)
+static std::optional<eCustomDataType> node_type_from_other_socket(const bNodeSocket &socket)
{
switch (socket.type) {
case SOCK_FLOAT:
@@ -137,7 +137,7 @@ static std::optional<CustomDataType> node_type_from_other_socket(const bNodeSock
static void node_map_range_gather_link_searches(GatherLinkSearchOpParams &params)
{
- const std::optional<CustomDataType> type = node_type_from_other_socket(params.other_socket());
+ const std::optional<eCustomDataType> type = node_type_from_other_socket(params.other_socket());
if (!type) {
return;
}
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 94a6febe92e..d4413036555 100644
--- a/source/blender/nodes/shader/nodes/node_shader_sepcomb_xyz.cc
+++ b/source/blender/nodes/shader/nodes/node_shader_sepcomb_xyz.cc
@@ -48,16 +48,36 @@ class MF_SeparateXYZ : public fn::MultiFunction {
void call(IndexMask mask, fn::MFParams params, fn::MFContext UNUSED(context)) const override
{
const VArray<float3> &vectors = params.readonly_single_input<float3>(0, "XYZ");
- MutableSpan<float> xs = params.uninitialized_single_output<float>(1, "X");
- MutableSpan<float> ys = params.uninitialized_single_output<float>(2, "Y");
- MutableSpan<float> zs = params.uninitialized_single_output<float>(3, "Z");
-
- for (int64_t i : mask) {
- float3 xyz = vectors[i];
- xs[i] = xyz.x;
- ys[i] = xyz.y;
- zs[i] = xyz.z;
+ MutableSpan<float> xs = params.uninitialized_single_output_if_required<float>(1, "X");
+ MutableSpan<float> ys = params.uninitialized_single_output_if_required<float>(2, "Y");
+ MutableSpan<float> zs = params.uninitialized_single_output_if_required<float>(3, "Z");
+
+ std::array<MutableSpan<float>, 3> outputs = {xs, ys, zs};
+ Vector<int> used_outputs;
+ if (!xs.is_empty()) {
+ used_outputs.append(0);
}
+ if (!ys.is_empty()) {
+ used_outputs.append(1);
+ }
+ if (!zs.is_empty()) {
+ used_outputs.append(2);
+ }
+
+ devirtualize_varray(vectors, [&](auto vectors) {
+ mask.to_best_mask_type([&](auto mask) {
+ const int used_outputs_num = used_outputs.size();
+ const int *used_outputs_data = used_outputs.data();
+
+ for (const int64_t i : mask) {
+ const float3 &vector = vectors[i];
+ for (const int out_i : IndexRange(used_outputs_num)) {
+ const int coordinate = used_outputs_data[out_i];
+ outputs[coordinate][i] = vector[coordinate];
+ }
+ }
+ });
+ });
}
};
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 06c238fead0..c9588949761 100644
--- a/source/blender/nodes/shader/nodes/node_shader_tex_image.cc
+++ b/source/blender/nodes/shader/nodes/node_shader_tex_image.cc
@@ -74,7 +74,7 @@ static int node_shader_gpu_tex_image(GPUMaterial *mat,
const char *gpu_node_name = use_cubic ? "node_tex_tile_cubic" : "node_tex_tile_linear";
GPUNodeLink *gpu_image = GPU_image_tiled(mat, ima, iuser, sampler_state);
GPUNodeLink *gpu_image_tile_mapping = GPU_image_tiled_mapping(mat, ima, iuser);
- /* UDIM tiles needs a samper2DArray and sampler1DArray for tile mapping. */
+ /* UDIM tiles needs a `sampler2DArray` and `sampler1DArray` for tile mapping. */
GPU_stack_link(mat, node, gpu_node_name, in, out, gpu_image, gpu_image_tile_mapping);
}
else {
diff --git a/source/blender/nodes/shader/nodes/node_shader_uvmap.cc b/source/blender/nodes/shader/nodes/node_shader_uvmap.cc
index 91d89952da7..53228f0a314 100644
--- a/source/blender/nodes/shader/nodes/node_shader_uvmap.cc
+++ b/source/blender/nodes/shader/nodes/node_shader_uvmap.cc
@@ -46,7 +46,7 @@ static int node_shader_gpu_uvmap(GPUMaterial *mat,
NodeShaderUVMap *attr = static_cast<NodeShaderUVMap *>(node->storage);
/* NOTE: using CD_AUTO_FROM_NAME instead of CD_MTFACE as geometry nodes may overwrite data which
- * will also change the CustomDataType. This will also make EEVEE and Cycles consistent. See
+ * will also change the eCustomDataType. This will also make EEVEE and Cycles consistent. See
* T93179. */
GPUNodeLink *mtface = GPU_attribute(mat, CD_AUTO_FROM_NAME, attr->uv_map);
diff --git a/source/blender/nodes/shader/nodes/node_shader_vertex_color.cc b/source/blender/nodes/shader/nodes/node_shader_vertex_color.cc
index a2a9aa9ad91..830f02d8df1 100644
--- a/source/blender/nodes/shader/nodes/node_shader_vertex_color.cc
+++ b/source/blender/nodes/shader/nodes/node_shader_vertex_color.cc
@@ -42,10 +42,20 @@ static int node_shader_gpu_vertex_color(GPUMaterial *mat,
GPUNodeStack *out)
{
NodeShaderVertexColor *vertexColor = (NodeShaderVertexColor *)node->storage;
- /* NOTE: using CD_AUTO_FROM_NAME instead of CD_MCOL or CD_PROP_COLOR as geometry nodes may
- * overwrite data which will also change the CustomDataType. This will also make EEVEE and Cycles
+ /* NOTE: using CD_AUTO_FROM_NAME instead of CD_MCOL or CD_PROP_COLOR for named attributes
+ * as geometry nodes may overwrite data which will also change the eCustomDataType.
+ * This will also make EEVEE and Cycles
* consistent. See T93179. */
- GPUNodeLink *vertexColorLink = GPU_attribute(mat, CD_AUTO_FROM_NAME, vertexColor->layer_name);
+
+ GPUNodeLink *vertexColorLink;
+
+ if (vertexColor->layer_name[0]) {
+ vertexColorLink = GPU_attribute(mat, CD_AUTO_FROM_NAME, vertexColor->layer_name);
+ }
+ else { /* Fall back on active render color attribute. */
+ vertexColorLink = GPU_attribute(mat, CD_MCOL, vertexColor->layer_name);
+ }
+
return GPU_stack_link(mat, node, "node_vertex_color", in, out, vertexColorLink);
}
diff --git a/source/blender/nodes/shader/nodes/node_shader_volume_principled.cc b/source/blender/nodes/shader/nodes/node_shader_volume_principled.cc
index 07e700e550a..4c4122a905f 100644
--- a/source/blender/nodes/shader/nodes/node_shader_volume_principled.cc
+++ b/source/blender/nodes/shader/nodes/node_shader_volume_principled.cc
@@ -3,6 +3,8 @@
#include "node_shader_util.hh"
+#include "IMB_colormanagement.h"
+
namespace blender::nodes::node_shader_volume_principled_cc {
static void node_declare(NodeDeclarationBuilder &b)
@@ -109,7 +111,7 @@ static int node_shader_gpu_volume_principled(GPUMaterial *mat,
float *data, layer;
if (use_blackbody) {
data = (float *)MEM_mallocN(sizeof(float) * size * 4, "blackbody texture");
- blackbody_temperature_to_rgb_table(data, size, 965.0f, 12000.0f);
+ IMB_colormanagement_blackbody_temperature_to_rgb_table(data, size, 800.0f, 12000.0f);
}
else {
data = (float *)MEM_callocN(sizeof(float) * size * 4, "blackbody black");
diff --git a/source/blender/nodes/shader/nodes/node_shader_wavelength.cc b/source/blender/nodes/shader/nodes/node_shader_wavelength.cc
index 522928a30fa..34fa639dd07 100644
--- a/source/blender/nodes/shader/nodes/node_shader_wavelength.cc
+++ b/source/blender/nodes/shader/nodes/node_shader_wavelength.cc
@@ -3,6 +3,8 @@
#include "node_shader_util.hh"
+#include "IMB_colormanagement.h"
+
namespace blender::nodes::node_shader_wavelength_cc {
static void node_declare(NodeDeclarationBuilder &b)
@@ -20,22 +22,11 @@ static int node_shader_gpu_wavelength(GPUMaterial *mat,
const int size = CM_TABLE + 1;
float *data = static_cast<float *>(MEM_mallocN(sizeof(float) * size * 4, "cie_xyz texture"));
- wavelength_to_xyz_table(data, size);
+ IMB_colormanagement_wavelength_to_rgb_table(data, size);
float layer;
GPUNodeLink *ramp_texture = GPU_color_band(mat, size, data, &layer);
- XYZ_to_RGB xyz_to_rgb;
- get_XYZ_to_RGB_for_gpu(&xyz_to_rgb);
- return GPU_stack_link(mat,
- node,
- "node_wavelength",
- in,
- out,
- ramp_texture,
- GPU_constant(&layer),
- GPU_uniform(xyz_to_rgb.r),
- GPU_uniform(xyz_to_rgb.g),
- GPU_uniform(xyz_to_rgb.b));
+ return GPU_stack_link(mat, node, "node_wavelength", in, out, ramp_texture, GPU_constant(&layer));
}
} // namespace blender::nodes::node_shader_wavelength_cc
diff --git a/source/blender/nodes/texture/node_texture_tree.c b/source/blender/nodes/texture/node_texture_tree.c
index 903e293a962..03dc61af9a2 100644
--- a/source/blender/nodes/texture/node_texture_tree.c
+++ b/source/blender/nodes/texture/node_texture_tree.c
@@ -324,7 +324,6 @@ int ntreeTexExecTree(bNodeTree *ntree,
MTex *mtex)
{
TexCallData data;
- float *nor = target->nor;
int retval = TEX_INT;
bNodeThreadStack *nts = NULL;
bNodeTreeExec *exec = ntree->execdata;
@@ -356,14 +355,7 @@ int ntreeTexExecTree(bNodeTree *ntree,
ntreeExecThreadNodes(exec, nts, &data, thread);
ntreeReleaseThreadStack(nts);
- if (target->nor) {
- retval |= TEX_NOR;
- }
retval |= TEX_RGB;
- /* confusing stuff; the texture output node sets this to NULL to indicate no normal socket was
- * set however, the texture code checks this for other reasons
- * (namely, a normal is required for material). */
- target->nor = nor;
return retval;
}
diff --git a/source/blender/nodes/texture/node_texture_util.c b/source/blender/nodes/texture/node_texture_util.c
index 76208104a8c..248114f242a 100644
--- a/source/blender/nodes/texture/node_texture_util.c
+++ b/source/blender/nodes/texture/node_texture_util.c
@@ -49,7 +49,7 @@ static void tex_call_delegate(TexDelegate *dg, float *out, TexParams *params, sh
}
}
-static void tex_input(float *out, int sz, bNodeStack *in, TexParams *params, short thread)
+static void tex_input(float *out, int num, bNodeStack *in, TexParams *params, short thread)
{
TexDelegate *dg = in->data;
if (dg) {
@@ -59,7 +59,7 @@ static void tex_input(float *out, int sz, bNodeStack *in, TexParams *params, sho
in->vec[1] = in->vec[2] = in->vec[0];
}
}
- memcpy(out, in->vec, sz * sizeof(float));
+ memcpy(out, in->vec, num * sizeof(float));
}
void tex_input_vec(float *out, bNodeStack *in, TexParams *params, short thread)
diff --git a/source/blender/nodes/texture/nodes/node_texture_output.c b/source/blender/nodes/texture/nodes/node_texture_output.c
index cf5e32cb486..b300ba9ef77 100644
--- a/source/blender/nodes/texture/nodes/node_texture_output.c
+++ b/source/blender/nodes/texture/nodes/node_texture_output.c
@@ -13,7 +13,6 @@
/* **************** COMPOSITE ******************** */
static bNodeSocketTemplate inputs[] = {
{SOCK_RGBA, N_("Color"), 0.0f, 0.0f, 0.0f, 1.0f},
- {SOCK_VECTOR, N_("Normal"), 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 1.0f, PROP_DIRECTION},
{-1, ""},
};
@@ -32,12 +31,7 @@ static void exec(void *data,
TexParams params;
params_from_cdata(&params, cdata);
- if (in[1] && in[1]->hasinput && !in[0]->hasinput) {
- tex_input_rgba(target->trgba, in[1], &params, cdata->thread);
- }
- else {
- tex_input_rgba(target->trgba, in[0], &params, cdata->thread);
- }
+ tex_input_rgba(target->trgba, in[0], &params, cdata->thread);
}
else {
/* 0 means don't care, so just use first */
@@ -49,15 +43,6 @@ static void exec(void *data,
target->tin = (target->trgba[0] + target->trgba[1] + target->trgba[2]) / 3.0f;
target->talpha = true;
-
- if (target->nor) {
- if (in[1] && in[1]->hasinput) {
- tex_input_vec(target->nor, in[1], &params, cdata->thread);
- }
- else {
- target->nor = NULL;
- }
- }
}
}
}
diff --git a/source/blender/nodes/texture/nodes/node_texture_proc.c b/source/blender/nodes/texture/nodes/node_texture_proc.c
index fd7e6fdfc7f..d925c9f3554 100644
--- a/source/blender/nodes/texture/nodes/node_texture_proc.c
+++ b/source/blender/nodes/texture/nodes/node_texture_proc.c
@@ -14,10 +14,8 @@
* In this file: wrappers to use procedural textures as nodes
*/
-static bNodeSocketTemplate outputs_both[] = {
- {SOCK_RGBA, N_("Color"), 1.0f, 0.0f, 0.0f, 1.0f},
- {SOCK_VECTOR, N_("Normal"), 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 1.0f, PROP_DIRECTION},
- {-1, ""}};
+static bNodeSocketTemplate outputs_both[] = {{SOCK_RGBA, N_("Color"), 1.0f, 0.0f, 0.0f, 1.0f},
+ {-1, ""}};
static bNodeSocketTemplate outputs_color_only[] = {{SOCK_RGBA, N_("Color")}, {-1, ""}};
/* Inputs common to all, #defined because nodes will need their own inputs too */
@@ -34,27 +32,15 @@ static void do_proc(float *result,
TexParams *p,
const float col1[4],
const float col2[4],
- char is_normal,
Tex *tex,
const short thread)
{
TexResult texres;
int textype;
- if (is_normal) {
- texres.nor = result;
- }
- else {
- texres.nor = NULL;
- }
-
textype = multitex_nodes(
tex, p->co, p->dxt, p->dyt, p->osatex, &texres, thread, 0, p->mtex, NULL);
- if (is_normal) {
- return;
- }
-
if (textype & TEX_RGB) {
copy_v4_v4(result, texres.trgba);
}
@@ -66,13 +52,8 @@ static void do_proc(float *result,
typedef void (*MapFn)(Tex *tex, bNodeStack **in, TexParams *p, const short thread);
-static void texfn(float *result,
- TexParams *p,
- bNode *node,
- bNodeStack **in,
- char is_normal,
- MapFn map_inputs,
- short thread)
+static void texfn(
+ float *result, TexParams *p, bNode *node, bNodeStack **in, MapFn map_inputs, short thread)
{
Tex tex = *((Tex *)(node->storage));
float col1[4], col2[4];
@@ -81,7 +62,7 @@ static void texfn(float *result,
map_inputs(&tex, in, p, thread);
- do_proc(result, p, col1, col2, is_normal, &tex, thread);
+ do_proc(result, p, col1, col2, &tex, thread);
}
static int count_outputs(bNode *node)
@@ -106,12 +87,7 @@ static int count_outputs(bNode *node)
static void name##_colorfn( \
float *result, TexParams *p, bNode *node, bNodeStack **in, short thread) \
{ \
- texfn(result, p, node, in, 0, &name##_map_inputs, thread); \
- } \
- static void name##_normalfn( \
- float *result, TexParams *p, bNode *node, bNodeStack **in, short thread) \
- { \
- texfn(result, p, node, in, 1, &name##_map_inputs, thread); \
+ texfn(result, p, node, in, &name##_map_inputs, thread); \
} \
static void name##_exec(void *data, \
int UNUSED(thread), \
@@ -124,9 +100,6 @@ static int count_outputs(bNode *node)
if (outs >= 1) { \
tex_output(node, execdata, in, out[0], &name##_colorfn, data); \
} \
- if (outs >= 2) { \
- tex_output(node, execdata, in, out[1], &name##_normalfn, data); \
- } \
}
/* --- VORONOI -- */
diff --git a/source/blender/nodes/texture/nodes/node_texture_texture.c b/source/blender/nodes/texture/nodes/node_texture_texture.c
index 2d2b4e06665..79cd8bbb1df 100644
--- a/source/blender/nodes/texture/nodes/node_texture_texture.c
+++ b/source/blender/nodes/texture/nodes/node_texture_texture.c
@@ -45,13 +45,11 @@ static void colorfn(float *out, TexParams *p, bNode *node, bNodeStack **in, shor
else if (nodetex) {
TexResult texres;
int textype;
- float nor[] = {0, 0, 0};
float col1[4], col2[4];
tex_input_rgba(col1, in[0], p, thread);
tex_input_rgba(col2, in[1], p, thread);
- texres.nor = nor;
textype = multitex_nodes(nodetex, co, dxt, dyt, p->osatex, &texres, thread, 0, p->mtex, NULL);
if (textype & TEX_RGB) {
diff --git a/source/blender/python/bmesh/bmesh_py_types.c b/source/blender/python/bmesh/bmesh_py_types.c
index baa2b0deb71..972a782d650 100644
--- a/source/blender/python/bmesh/bmesh_py_types.c
+++ b/source/blender/python/bmesh/bmesh_py_types.c
@@ -1259,10 +1259,16 @@ static PyObject *bpy_bmesh_select_flush(BPy_BMesh *self, PyObject *value)
Py_RETURN_NONE;
}
-PyDoc_STRVAR(bpy_bmesh_normal_update_doc,
- ".. method:: normal_update()\n"
- "\n"
- " Update mesh normals.\n");
+PyDoc_STRVAR(
+ bpy_bmesh_normal_update_doc,
+ ".. method:: normal_update()\n"
+ "\n"
+ " Update normals of mesh faces and verts.\n"
+ "\n"
+ " .. note::\n"
+ "\n"
+ " The normal of any vertex where :attr:`is_wire` is True will be a zero vector.\n");
+
static PyObject *bpy_bmesh_normal_update(BPy_BMesh *self)
{
BPY_BM_CHECK_OBJ(self);
@@ -1611,7 +1617,12 @@ static PyObject *bpy_bmvert_calc_shell_factor(BPy_BMVert *self)
PyDoc_STRVAR(bpy_bmvert_normal_update_doc,
".. method:: normal_update()\n"
"\n"
- " Update vertex normal.\n");
+ " Update vertex normal.\n"
+ " This does not update the normals of adjoining faces.\n"
+ "\n"
+ " .. note::\n"
+ "\n"
+ " The vertex normal will be a zero vector if vertex :attr:`is_wire` is True.\n");
static PyObject *bpy_bmvert_normal_update(BPy_BMVert *self)
{
BPY_BM_CHECK_OBJ(self);
@@ -1773,10 +1784,15 @@ static PyObject *bpy_bmedge_other_vert(BPy_BMEdge *self, BPy_BMVert *value)
Py_RETURN_NONE;
}
-PyDoc_STRVAR(bpy_bmedge_normal_update_doc,
- ".. method:: normal_update()\n"
- "\n"
- " Update edges vertex normals.\n");
+PyDoc_STRVAR(
+ bpy_bmedge_normal_update_doc,
+ ".. method:: normal_update()\n"
+ "\n"
+ " Update normals of all connected faces and the edge verts.\n"
+ "\n"
+ " .. note::\n"
+ "\n"
+ " The normal of edge vertex will be a zero vector if vertex :attr:`is_wire` is True.\n");
static PyObject *bpy_bmedge_normal_update(BPy_BMEdge *self)
{
BPY_BM_CHECK_OBJ(self);
@@ -2012,7 +2028,8 @@ static PyObject *bpy_bmface_calc_center_bounds(BPy_BMFace *self)
PyDoc_STRVAR(bpy_bmface_normal_update_doc,
".. method:: normal_update()\n"
"\n"
- " Update face's normal.\n");
+ " Update face normal based on the positions of the face verts.\n"
+ " This does not update the normals of face verts.\n");
static PyObject *bpy_bmface_normal_update(BPy_BMFace *self)
{
BPY_BM_CHECK_OBJ(self);
diff --git a/source/blender/python/generic/blf_py_api.c b/source/blender/python/generic/blf_py_api.c
index 9e45105d105..060b7758ea9 100644
--- a/source/blender/python/generic/blf_py_api.c
+++ b/source/blender/python/generic/blf_py_api.c
@@ -50,7 +50,7 @@ static PyObject *py_blf_position(PyObject *UNUSED(self), PyObject *args)
PyDoc_STRVAR(py_blf_size_doc,
".. function:: size(fontid, size, dpi)\n"
"\n"
- " Set the size and dpi for drawing text.\n"
+ " Set the size and DPI for drawing text.\n"
"\n"
" :arg fontid: The id of the typeface as returned by :func:`blf.load`, for default "
"font use 0.\n"
diff --git a/source/blender/python/generic/idprop_py_api.c b/source/blender/python/generic/idprop_py_api.c
index 2fbb6b8ee05..3f880da2f56 100644
--- a/source/blender/python/generic/idprop_py_api.c
+++ b/source/blender/python/generic/idprop_py_api.c
@@ -1279,9 +1279,8 @@ static PyObject *BPy_IDGroup_pop(BPy_IDProperty *self, PyObject *args)
pyform = BPy_IDGroup_MapDataToPy(idprop);
if (pyform == NULL) {
- /* ok something bad happened with the #PyObject,
- * so don't remove the prop from the group. if `pyform is
- * NULL, then it already should have raised an exception. */
+ /* Ok something bad happened with the #PyObject, so don't remove the prop from the group.
+ * if `pyform` is NULL, then it already should have raised an exception. */
return NULL;
}
diff --git a/source/blender/python/generic/imbuf_py_api.c b/source/blender/python/generic/imbuf_py_api.c
index ef11d1ab32d..e6d90c46866 100644
--- a/source/blender/python/generic/imbuf_py_api.c
+++ b/source/blender/python/generic/imbuf_py_api.c
@@ -559,7 +559,11 @@ static PyMethodDef IMB_methods[] = {
{NULL, NULL, 0, NULL},
};
-PyDoc_STRVAR(IMB_doc, "This module provides access to Blender's image manipulation API.");
+PyDoc_STRVAR(IMB_doc,
+ "This module provides access to Blender's image manipulation API.\n"
+ "\n"
+ "It provides access to image buffers outside of Blender's\n"
+ ":class:`bpy.types.Image` data-block context.\n");
static struct PyModuleDef IMB_module_def = {
PyModuleDef_HEAD_INIT,
"imbuf", /* m_name */
@@ -596,7 +600,13 @@ PyObject *BPyInit_imbuf(void)
* for docs and the ability to use with built-ins such as `isinstance`, `issubclass`.
* \{ */
-PyDoc_STRVAR(IMB_types_doc, "This module provides access to image buffer types.");
+PyDoc_STRVAR(IMB_types_doc,
+ "This module provides access to image buffer types.\n"
+ "\n"
+ ".. note::\n"
+ "\n"
+ " Image buffer is also the structure used by :class:`bpy.types.Image`\n"
+ " ID type to store and manipulate image data at runtime.\n");
static struct PyModuleDef IMB_types_module_def = {
PyModuleDef_HEAD_INIT,
diff --git a/source/blender/python/gpu/gpu_py_api.c b/source/blender/python/gpu/gpu_py_api.c
index d45fdc21130..a2075566f31 100644
--- a/source/blender/python/gpu/gpu_py_api.c
+++ b/source/blender/python/gpu/gpu_py_api.c
@@ -14,8 +14,6 @@
#include "BLI_utildefines.h"
-#include "../generic/python_utildefines.h"
-
#include "gpu_py_capabilities.h"
#include "gpu_py_matrix.h"
#include "gpu_py_platform.h"
@@ -23,7 +21,7 @@
#include "gpu_py_state.h"
#include "gpu_py_types.h"
-#include "gpu_py_api.h" /* own include */
+#include "gpu_py_api.h" /* Own include. */
/* -------------------------------------------------------------------- */
/** \name GPU Module
diff --git a/source/blender/python/gpu/gpu_py_batch.c b/source/blender/python/gpu/gpu_py_batch.c
index 02bcf80aa5d..533e5154d83 100644
--- a/source/blender/python/gpu/gpu_py_batch.c
+++ b/source/blender/python/gpu/gpu_py_batch.c
@@ -13,14 +13,10 @@
#include <Python.h>
-#include "MEM_guardedalloc.h"
-
#include "BLI_utildefines.h"
#include "GPU_batch.h"
-#include "../mathutils/mathutils.h"
-
#include "../generic/py_capi_utils.h"
#include "gpu_py.h"
diff --git a/source/blender/python/gpu/gpu_py_element.c b/source/blender/python/gpu/gpu_py_element.c
index 04975fcef96..d52a97c0c84 100644
--- a/source/blender/python/gpu/gpu_py_element.c
+++ b/source/blender/python/gpu/gpu_py_element.c
@@ -16,7 +16,6 @@
#include "MEM_guardedalloc.h"
#include "../generic/py_capi_utils.h"
-#include "../generic/python_utildefines.h"
#include "gpu_py.h"
#include "gpu_py_element.h" /* own include */
@@ -91,15 +90,11 @@ static PyObject *pygpu_IndexBuf__tp_new(PyTypeObject *UNUSED(type), PyObject *ar
/* Use `INT_MAX` instead of the actual number of vertices. */
GPU_indexbuf_init(&builder, prim_type.value_found, index_len, INT_MAX);
-#if 0
uint *buf = pybuffer.buf;
for (uint i = index_len; i--; buf++) {
GPU_indexbuf_add_generic_vert(&builder, *buf);
}
-#else
- memcpy(builder.data, pybuffer.buf, index_len * sizeof(*builder.data));
- builder.index_len = index_len;
-#endif
+
PyBuffer_Release(&pybuffer);
}
else {
diff --git a/source/blender/python/gpu/gpu_py_offscreen.c b/source/blender/python/gpu/gpu_py_offscreen.c
index b50f536da8a..621c6647cb9 100644
--- a/source/blender/python/gpu/gpu_py_offscreen.c
+++ b/source/blender/python/gpu/gpu_py_offscreen.c
@@ -13,8 +13,6 @@
#include <Python.h>
-#include "MEM_guardedalloc.h"
-
#include "BLI_string.h"
#include "BLI_utildefines.h"
@@ -31,7 +29,6 @@
#include "GPU_texture.h"
#include "GPU_viewport.h"
-#include "ED_view3d.h"
#include "ED_view3d_offscreen.h"
#include "../mathutils/mathutils.h"
diff --git a/source/blender/python/gpu/gpu_py_platform.c b/source/blender/python/gpu/gpu_py_platform.c
index 6c5a5bdaaf8..656024ae22c 100644
--- a/source/blender/python/gpu/gpu_py_platform.c
+++ b/source/blender/python/gpu/gpu_py_platform.c
@@ -13,7 +13,7 @@
#include "GPU_platform.h"
-#include "gpu_py_platform.h" /* own include */
+#include "gpu_py_platform.h" /* Own include. */
/* -------------------------------------------------------------------- */
/** \name Functions
diff --git a/source/blender/python/gpu/gpu_py_select.c b/source/blender/python/gpu/gpu_py_select.c
index 8e5c172f90c..8869ea38e32 100644
--- a/source/blender/python/gpu/gpu_py_select.c
+++ b/source/blender/python/gpu/gpu_py_select.c
@@ -20,7 +20,7 @@
#include "GPU_select.h"
-#include "gpu_py_select.h" /* own include */
+#include "gpu_py_select.h" /* Own include. */
/* -------------------------------------------------------------------- */
/** \name Methods
diff --git a/source/blender/python/gpu/gpu_py_shader.c b/source/blender/python/gpu/gpu_py_shader.c
index 77333c6dfea..101b9f8e4c6 100644
--- a/source/blender/python/gpu/gpu_py_shader.c
+++ b/source/blender/python/gpu/gpu_py_shader.c
@@ -16,7 +16,6 @@
#include "GPU_uniform_buffer.h"
#include "../generic/py_capi_utils.h"
-#include "../generic/python_utildefines.h"
#include "../mathutils/mathutils.h"
#include "gpu_py.h"
@@ -46,6 +45,9 @@
"``3D_FLAT_COLOR``\n" \
" :Attributes: vec3 pos, vec4 color\n" \
" :Uniforms: none\n" \
+ "``3D_IMAGE``\n" \
+ " :Attributes: vec3 pos, vec2 texCoord\n" \
+ " :Uniforms: sampler2D image\n" \
"``3D_SMOOTH_COLOR``\n" \
" :Attributes: vec3 pos, vec4 color\n" \
" :Uniforms: none\n" \
@@ -68,6 +70,7 @@ static const struct PyC_StringEnumItems pygpu_shader_builtin_items[] = {
{GPU_SHADER_2D_SMOOTH_COLOR, "2D_SMOOTH_COLOR"},
{GPU_SHADER_2D_UNIFORM_COLOR, "2D_UNIFORM_COLOR"},
{GPU_SHADER_3D_FLAT_COLOR, "3D_FLAT_COLOR"},
+ {GPU_SHADER_3D_IMAGE, "3D_IMAGE"},
{GPU_SHADER_3D_SMOOTH_COLOR, "3D_SMOOTH_COLOR"},
{GPU_SHADER_3D_UNIFORM_COLOR, "3D_UNIFORM_COLOR"},
{GPU_SHADER_3D_POLYLINE_FLAT_COLOR, "3D_POLYLINE_FLAT_COLOR"},
@@ -748,28 +751,27 @@ static PyObject *pygpu_shader_unbind(BPyGPUShader *UNUSED(self))
Py_RETURN_NONE;
}
-PyDoc_STRVAR(pygpu_shader_from_builtin_doc,
- ".. function:: from_builtin(shader_name, config='DEFAULT')\n"
- "\n"
- " Shaders that are embedded in the blender internal code:\n"
- "" PYDOC_BUILTIN_SHADER_DESCRIPTION
- "\n"
- " They all read the uniform ``mat4 ModelViewProjectionMatrix``,\n"
- " which can be edited by the :mod:`gpu.matrix` module.\n"
- "\n"
- " You can also choose a shader configuration that uses clip_planes by setting the "
- "``CLIPPED`` value to the config parameter. Note that in this case you also need to "
- "manually set the value of ``mat4 ModelMatrix``.\n"
- "\n"
- " :param shader_name: One of the builtin shader names.\n"
- " :type shader_name: str\n"
- " :param config: One of these types of shader configuration:\n"
- "\n"
- " - ``DEFAULT``\n"
- " - ``CLIPPED``\n"
- " :type config: str\n"
- " :return: Shader object corresponding to the given name.\n"
- " :rtype: :class:`bpy.types.GPUShader`\n");
+PyDoc_STRVAR(
+ pygpu_shader_from_builtin_doc,
+ ".. function:: from_builtin(shader_name, config='DEFAULT')\n"
+ "\n"
+ " Shaders that are embedded in the blender internal code (see :ref:`built-in-shaders`).\n"
+ " They all read the uniform ``mat4 ModelViewProjectionMatrix``,\n"
+ " which can be edited by the :mod:`gpu.matrix` module.\n"
+ "\n"
+ " You can also choose a shader configuration that uses clip_planes by setting the "
+ "``CLIPPED`` value to the config parameter. Note that in this case you also need to "
+ "manually set the value of ``mat4 ModelMatrix``.\n"
+ "\n"
+ " :param shader_name: One of the builtin shader names.\n"
+ " :type shader_name: str\n"
+ " :param config: One of these types of shader configuration:\n"
+ "\n"
+ " - ``DEFAULT``\n"
+ " - ``CLIPPED``\n"
+ " :type config: str\n"
+ " :return: Shader object corresponding to the given name.\n"
+ " :rtype: :class:`bpy.types.GPUShader`\n");
static PyObject *pygpu_shader_from_builtin(PyObject *UNUSED(self), PyObject *args, PyObject *kwds)
{
BPYGPU_IS_INIT_OR_ERROR_OBJ;
@@ -850,6 +852,8 @@ static struct PyMethodDef pygpu_shader_module__tp_methods[] = {
PyDoc_STRVAR(pygpu_shader_module__tp_doc,
"This module provides access to GPUShader internal functions.\n"
"\n"
+ ".. _built-in-shaders:\n"
+ "\n"
".. rubric:: Built-in shaders\n"
"\n"
"All built-in shaders have the ``mat4 ModelViewProjectionMatrix`` uniform.\n"
diff --git a/source/blender/python/gpu/gpu_py_shader_create_info.cc b/source/blender/python/gpu/gpu_py_shader_create_info.cc
index 3b043c605fa..e00d01174f4 100644
--- a/source/blender/python/gpu/gpu_py_shader_create_info.cc
+++ b/source/blender/python/gpu/gpu_py_shader_create_info.cc
@@ -15,7 +15,6 @@
#include "intern/gpu_shader_create_info.hh"
#include "../generic/py_capi_utils.h"
-#include "../generic/python_utildefines.h"
#include "gpu_py_shader.h" /* own include */
diff --git a/source/blender/python/gpu/gpu_py_types.c b/source/blender/python/gpu/gpu_py_types.c
index 65201df4a9e..eccbebbd8dd 100644
--- a/source/blender/python/gpu/gpu_py_types.c
+++ b/source/blender/python/gpu/gpu_py_types.c
@@ -10,7 +10,6 @@
#include <Python.h>
#include "../generic/py_capi_utils.h"
-#include "../generic/python_utildefines.h"
#include "gpu_py_types.h" /* own include */
diff --git a/source/blender/python/gpu/gpu_py_uniformbuffer.c b/source/blender/python/gpu/gpu_py_uniformbuffer.c
index f8f88d61cf6..dcf9ab76470 100644
--- a/source/blender/python/gpu/gpu_py_uniformbuffer.c
+++ b/source/blender/python/gpu/gpu_py_uniformbuffer.c
@@ -14,13 +14,11 @@
#include "BLI_string.h"
#include "GPU_context.h"
-#include "GPU_texture.h"
#include "GPU_uniform_buffer.h"
#include "../generic/py_capi_utils.h"
#include "gpu_py.h"
-#include "gpu_py_buffer.h"
#include "gpu_py_uniformbuffer.h" /* own include */
diff --git a/source/blender/python/gpu/gpu_py_vertex_format.c b/source/blender/python/gpu/gpu_py_vertex_format.c
index 3e6695419c0..40a0e5d1e9f 100644
--- a/source/blender/python/gpu/gpu_py_vertex_format.c
+++ b/source/blender/python/gpu/gpu_py_vertex_format.c
@@ -9,10 +9,6 @@
#include <Python.h>
-#include "BLI_math.h"
-
-#include "MEM_guardedalloc.h"
-
#include "../generic/py_capi_utils.h"
#include "../generic/python_utildefines.h"
diff --git a/source/blender/python/intern/CMakeLists.txt b/source/blender/python/intern/CMakeLists.txt
index e4e198ab812..71138134370 100644
--- a/source/blender/python/intern/CMakeLists.txt
+++ b/source/blender/python/intern/CMakeLists.txt
@@ -143,10 +143,13 @@ if(WITH_PYTHON_SAFETY)
add_definitions(-DWITH_PYTHON_SAFETY)
endif()
-
-
if(WITH_AUDASPACE)
+ # It's possible to build with AUDASPACE (for file IO) but without the `aud` Python API,
+ # when building without NUMPY so define both `WITH_AUDASPACE` & `DWITH_AUDASPACE_PY`.
add_definitions(-DWITH_AUDASPACE)
+ if(WITH_PYTHON_NUMPY)
+ add_definitions(-DWITH_AUDASPACE_PY)
+ endif()
endif()
if(WITH_BULLET)
@@ -229,7 +232,7 @@ if(WITH_IMAGE_TIFF)
endif()
if(WITH_WEBP)
- add_definitions(-DWITH_WEBP)
+ add_definitions(-DWITH_WEBP)
endif()
if(WITH_INPUT_NDOF)
@@ -307,6 +310,18 @@ if(WITH_OPENCOLLADA)
add_definitions(-DWITH_COLLADA)
endif()
+if(WITH_IO_WAVEFRONT_OBJ)
+ add_definitions(-DWITH_IO_WAVEFRONT_OBJ)
+endif()
+
+if(WITH_IO_STL)
+ add_definitions(-DWITH_IO_STL)
+endif()
+
+if(WITH_IO_GPENCIL)
+ add_definitions(-DWITH_IO_GPENCIL)
+endif()
+
if(WITH_ALEMBIC)
add_definitions(-DWITH_ALEMBIC)
endif()
diff --git a/source/blender/python/intern/bpy.c b/source/blender/python/intern/bpy.c
index 748a501ef76..2e97ae0fc1d 100644
--- a/source/blender/python/intern/bpy.c
+++ b/source/blender/python/intern/bpy.c
@@ -23,6 +23,7 @@
#include "BKE_global.h" /* XXX, G_MAIN only */
#include "RNA_access.h"
+#include "RNA_enum_types.h"
#include "RNA_prototypes.h"
#include "RNA_types.h"
@@ -400,6 +401,97 @@ static PyObject *bpy_unescape_identifier(PyObject *UNUSED(self), PyObject *value
return value_unescape;
}
+/**
+ * \note only exposed for generating documentation, see: `doc/python_api/sphinx_doc_gen.py`.
+ */
+PyDoc_STRVAR(
+ bpy_context_members_doc,
+ ".. function:: context_members()\n"
+ "\n"
+ " :return: A dict where the key is the context and the value is a tuple of it's members.\n"
+ " :rtype: dict\n");
+static PyObject *bpy_context_members(PyObject *UNUSED(self))
+{
+ extern const char *buttons_context_dir[];
+ extern const char *clip_context_dir[];
+ extern const char *file_context_dir[];
+ extern const char *image_context_dir[];
+ extern const char *node_context_dir[];
+ extern const char *screen_context_dir[];
+ extern const char *sequencer_context_dir[];
+ extern const char *text_context_dir[];
+ extern const char *view3d_context_dir[];
+
+ struct {
+ const char *name;
+ const char **dir;
+ } context_members_all[] = {
+ {"buttons", buttons_context_dir},
+ {"clip", clip_context_dir},
+ {"file", file_context_dir},
+ {"image", image_context_dir},
+ {"node", node_context_dir},
+ {"screen", screen_context_dir},
+ {"sequencer", sequencer_context_dir},
+ {"text", text_context_dir},
+ {"view3d", view3d_context_dir},
+ };
+
+ PyObject *result = _PyDict_NewPresized(ARRAY_SIZE(context_members_all));
+ for (int context_index = 0; context_index < ARRAY_SIZE(context_members_all); context_index++) {
+ const char *name = context_members_all[context_index].name;
+ const char **dir = context_members_all[context_index].dir;
+ int i;
+ for (i = 0; dir[i]; i++) {
+ /* Pass. */
+ }
+ PyObject *members = PyTuple_New(i);
+ for (i = 0; dir[i]; i++) {
+ PyTuple_SET_ITEM(members, i, PyUnicode_FromString(dir[i]));
+ }
+ PyDict_SetItemString(result, name, members);
+ Py_DECREF(members);
+ }
+ BLI_assert(PyDict_GET_SIZE(result) == ARRAY_SIZE(context_members_all));
+
+ return result;
+}
+
+/**
+ * \note only exposed for generating documentation, see: `doc/python_api/sphinx_doc_gen.py`.
+ */
+PyDoc_STRVAR(bpy_rna_enum_items_static_doc,
+ ".. function:: rna_enum_items_static()\n"
+ "\n"
+ " :return: A dict where the key the name of the enum, the value is a tuple of "
+ ":class:`bpy.types.EnumPropertyItem`.\n"
+ " :rtype: dict of \n");
+static PyObject *bpy_rna_enum_items_static(PyObject *UNUSED(self))
+{
+#define DEF_ENUM(id) {STRINGIFY(id), id},
+ struct {
+ const char *id;
+ const EnumPropertyItem *items;
+ } enum_info[] = {
+#include "RNA_enum_items.h"
+ };
+ PyObject *result = _PyDict_NewPresized(ARRAY_SIZE(enum_info));
+ for (int i = 0; i < ARRAY_SIZE(enum_info); i++) {
+ /* Include all items (including headings & separators), can be shown in documentation. */
+ const EnumPropertyItem *items = enum_info[i].items;
+ const int items_count = RNA_enum_items_count(items);
+ PyObject *value = PyTuple_New(items_count);
+ for (int item_index = 0; item_index < items_count; item_index++) {
+ PointerRNA ptr;
+ RNA_pointer_create(NULL, &RNA_EnumPropertyItem, (void *)&items[item_index], &ptr);
+ PyTuple_SET_ITEM(value, item_index, pyrna_struct_CreatePyObject(&ptr));
+ }
+ PyDict_SetItemString(result, enum_info[i].id, value);
+ Py_DECREF(value);
+ }
+ return result;
+}
+
static PyMethodDef meth_bpy_script_paths = {
"script_paths",
(PyCFunction)bpy_script_paths,
@@ -448,6 +540,18 @@ static PyMethodDef meth_bpy_unescape_identifier = {
METH_O,
bpy_unescape_identifier_doc,
};
+static PyMethodDef meth_bpy_context_members = {
+ "context_members",
+ (PyCFunction)bpy_context_members,
+ METH_NOARGS,
+ bpy_context_members_doc,
+};
+static PyMethodDef meth_bpy_rna_enum_items_static = {
+ "rna_enum_items_static",
+ (PyCFunction)bpy_rna_enum_items_static,
+ METH_NOARGS,
+ bpy_rna_enum_items_static_doc,
+};
static PyObject *bpy_import_test(const char *modname)
{
@@ -551,6 +655,12 @@ void BPy_init_modules(struct bContext *C)
(PyObject *)PyCFunction_New(&meth_bpy_unescape_identifier, NULL));
PyModule_AddObject(
mod, meth_bpy_flip_name.ml_name, (PyObject *)PyCFunction_New(&meth_bpy_flip_name, NULL));
+ PyModule_AddObject(mod,
+ meth_bpy_context_members.ml_name,
+ (PyObject *)PyCFunction_New(&meth_bpy_context_members, NULL));
+ PyModule_AddObject(mod,
+ meth_bpy_rna_enum_items_static.ml_name,
+ (PyObject *)PyCFunction_New(&meth_bpy_rna_enum_items_static, NULL));
/* register funcs (bpy_rna.c) */
PyModule_AddObject(mod,
diff --git a/source/blender/python/intern/bpy_app.c b/source/blender/python/intern/bpy_app.c
index 621cc79a8db..939473ceaa0 100644
--- a/source/blender/python/intern/bpy_app.c
+++ b/source/blender/python/intern/bpy_app.c
@@ -36,15 +36,19 @@
#include "BKE_appdir.h"
#include "BKE_blender_version.h"
#include "BKE_global.h"
+#include "BKE_main.h"
#include "DNA_ID.h"
#include "UI_interface_icons.h"
+#include "RNA_enum_types.h" /* For `rna_enum_wm_job_type_items`. */
+
/* for notifiers */
#include "WM_api.h"
#include "WM_types.h"
+#include "../generic/py_capi_rna.h"
#include "../generic/py_capi_utils.h"
#include "../generic/python_utildefines.h"
@@ -450,6 +454,44 @@ static PyGetSetDef bpy_app_getsets[] = {
{NULL, NULL, NULL, NULL, NULL},
};
+PyDoc_STRVAR(bpy_app_is_job_running_doc,
+ ".. staticmethod:: is_job_running(job_type)\n"
+ "\n"
+ " Check whether a job of the given type is running.\n"
+ "\n"
+ " :arg job_type: job type in :ref:`rna_enum_wm_job_type_items`.\n"
+ " :type job_type: str\n"
+ " :return: Whether a job of the given type is currently running.\n"
+ " :rtype: bool.\n");
+static PyObject *bpy_app_is_job_running(PyObject *UNUSED(self), PyObject *args, PyObject *kwds)
+{
+ struct BPy_EnumProperty_Parse job_type_enum = {
+ .items = rna_enum_wm_job_type_items,
+ .value = 0,
+ };
+ static const char *_keywords[] = {"job_type", NULL};
+ static _PyArg_Parser _parser = {
+ "O&" /* `job_type` */
+ ":is_job_running",
+ _keywords,
+ 0,
+ };
+ if (!_PyArg_ParseTupleAndKeywordsFast(
+ args, kwds, &_parser, pyrna_enum_value_parse_string, &job_type_enum)) {
+ return NULL;
+ }
+ wmWindowManager *wm = G_MAIN->wm.first;
+ return PyBool_FromLong(WM_jobs_has_running_type(wm, job_type_enum.value));
+}
+
+static struct PyMethodDef bpy_app_methods[] = {
+ {"is_job_running",
+ (PyCFunction)bpy_app_is_job_running,
+ METH_VARARGS | METH_KEYWORDS | METH_STATIC,
+ bpy_app_is_job_running_doc},
+ {NULL, NULL, 0, NULL},
+};
+
static void py_struct_seq_getset_init(void)
{
/* tricky dynamic members, not to py-spec! */
@@ -459,6 +501,17 @@ static void py_struct_seq_getset_init(void)
Py_DECREF(item);
}
}
+
+static void py_struct_seq_method_init(void)
+{
+ for (PyMethodDef *method = bpy_app_methods; method->ml_name; method++) {
+ BLI_assert_msg(method->ml_flags & METH_STATIC, "Only static methods make sense for 'bpy.app'");
+ PyObject *item = PyCFunction_New(method, NULL);
+ PyDict_SetItemString(BlenderAppType.tp_dict, method->ml_name, item);
+ Py_DECREF(item);
+ }
+}
+
/* end dynamic bpy.app */
PyObject *BPY_app_struct(void)
@@ -477,6 +530,7 @@ PyObject *BPY_app_struct(void)
/* kindof a hack ontop of PyStructSequence */
py_struct_seq_getset_init();
+ py_struct_seq_method_init();
return ret;
}
diff --git a/source/blender/python/intern/bpy_app_build_options.c b/source/blender/python/intern/bpy_app_build_options.c
index beb78753406..fe5111c37f2 100644
--- a/source/blender/python/intern/bpy_app_build_options.c
+++ b/source/blender/python/intern/bpy_app_build_options.c
@@ -43,6 +43,9 @@ static PyStructSequence_Field app_builtopts_info_fields[] = {
{"mod_oceansim", NULL},
{"mod_remesh", NULL},
{"collada", NULL},
+ {"io_wavefront_obj", NULL},
+ {"io_stl", NULL},
+ {"io_gpencil", NULL},
{"opencolorio", NULL},
{"openmp", NULL},
{"openvdb", NULL},
@@ -251,6 +254,24 @@ static PyObject *make_builtopts_info(void)
SetObjIncref(Py_False);
#endif
+#ifdef WITH_IO_WAVEFRONT_OBJ
+ SetObjIncref(Py_True);
+#else
+ SetObjIncref(Py_False);
+#endif
+
+#ifdef WITH_IO_STL
+ SetObjIncref(Py_True);
+#else
+ SetObjIncref(Py_False);
+#endif
+
+#ifdef WITH_IO_GPENCIL
+ SetObjIncref(Py_True);
+#else
+ SetObjIncref(Py_False);
+#endif
+
#ifdef WITH_OCIO
SetObjIncref(Py_True);
#else
diff --git a/source/blender/python/intern/bpy_app_handlers.c b/source/blender/python/intern/bpy_app_handlers.c
index bf427d9639a..641727927ec 100644
--- a/source/blender/python/intern/bpy_app_handlers.c
+++ b/source/blender/python/intern/bpy_app_handlers.c
@@ -66,6 +66,12 @@ static PyStructSequence_Field app_cb_info_fields[] = {
{"xr_session_start_pre", "on starting an xr session (before)"},
{"annotation_pre", "on drawing an annotation (before)"},
{"annotation_post", "on drawing an annotation (after)"},
+ {"object_bake_pre", "before starting a bake job"},
+ {"object_bake_complete", "on completing a bake job; will be called in the main thread"},
+ {"object_bake_cancel", "on canceling a bake job; will be called in the main thread"},
+ {"composite_pre", "on a compositing background job (before)"},
+ {"composite_post", "on a compositing background job (after)"},
+ {"composite_cancel", "on a compositing background job (cancel)"},
/* sets the permanent tag */
#define APP_CB_OTHER_FIELDS 1
diff --git a/source/blender/python/intern/bpy_interface.c b/source/blender/python/intern/bpy_interface.c
index e05cfb771c1..0ab8b4385e5 100644
--- a/source/blender/python/intern/bpy_interface.c
+++ b/source/blender/python/intern/bpy_interface.c
@@ -238,7 +238,7 @@ void BPY_context_set(bContext *C)
extern PyObject *Manta_initPython(void);
#endif
-#ifdef WITH_AUDASPACE
+#ifdef WITH_AUDASPACE_PY
/* defined in AUD_C-API.cpp */
extern PyObject *AUD_initPython(void);
#endif
@@ -272,7 +272,7 @@ static struct _inittab bpy_internal_modules[] = {
#ifdef WITH_FLUID
{"manta", Manta_initPython},
#endif
-#ifdef WITH_AUDASPACE
+#ifdef WITH_AUDASPACE_PY
{"aud", AUD_initPython},
#endif
#ifdef WITH_CYCLES
@@ -312,6 +312,14 @@ void BPY_python_start(bContext *C, int argc, const char **argv)
PyPreConfig preconfig;
PyStatus status;
+ /* To narrow down reports where the systems Python is inexplicably used, see: T98131. */
+ CLOG_INFO(
+ BPY_LOG_INTERFACE,
+ 2,
+ "Initializing %s support for the systems Python environment such as 'PYTHONPATH' and "
+ "the user-site directory.",
+ py_use_system_env ? "*with*" : "*without*");
+
if (py_use_system_env) {
PyPreConfig_InitPythonConfig(&preconfig);
}
@@ -579,9 +587,9 @@ void BPY_python_backtrace(FILE *fp)
PyFrameObject *frame = tstate->frame;
do {
const int line = PyCode_Addr2Line(frame->f_code, frame->f_lasti);
- const char *filename = PyUnicode_AsUTF8(frame->f_code->co_filename);
+ const char *filepath = PyUnicode_AsUTF8(frame->f_code->co_filename);
const char *funcname = PyUnicode_AsUTF8(frame->f_code->co_name);
- fprintf(fp, " File \"%s\", line %d in %s\n", filename, line, funcname);
+ fprintf(fp, " File \"%s\", line %d in %s\n", filepath, line, funcname);
} while ((frame = frame->f_back));
}
}
@@ -770,16 +778,16 @@ static void bpy_module_delay_init(PyObject *bpy_proxy)
const char *argv[2];
/* updating the module dict below will lose the reference to __file__ */
- PyObject *filename_obj = PyModule_GetFilenameObject(bpy_proxy);
+ PyObject *filepath_obj = PyModule_GetFilenameObject(bpy_proxy);
- const char *filename_rel = PyUnicode_AsUTF8(filename_obj); /* can be relative */
- char filename_abs[1024];
+ const char *filepath_rel = PyUnicode_AsUTF8(filepath_obj); /* can be relative */
+ char filepath_abs[1024];
- BLI_strncpy(filename_abs, filename_rel, sizeof(filename_abs));
- BLI_path_abs_from_cwd(filename_abs, sizeof(filename_abs));
- Py_DECREF(filename_obj);
+ BLI_strncpy(filepath_abs, filepath_rel, sizeof(filepath_abs));
+ BLI_path_abs_from_cwd(filepath_abs, sizeof(filepath_abs));
+ Py_DECREF(filepath_obj);
- argv[0] = filename_abs;
+ argv[0] = filepath_abs;
argv[1] = NULL;
// printf("module found %s\n", argv[0]);
@@ -810,16 +818,16 @@ PyMODINIT_FUNC PyInit_bpy(void)
PyObject *bpy_proxy = PyModule_Create(&bpy_proxy_def);
/* Problem:
- * 1) this init function is expected to have a private member defined - 'md_def'
+ * 1) this init function is expected to have a private member defined - `md_def`
* but this is only set for C defined modules (not py packages)
* so we can't return 'bpy_package_py' as is.
*
* 2) there is a 'bpy' C module for python to load which is basically all of blender,
- * and there is scripts/bpy/__init__.py,
+ * and there is `scripts/bpy/__init__.py`,
* we may end up having to rename this module so there is no naming conflict here eg:
* 'from blender import bpy'
*
- * 3) we don't know the filename at this point, workaround by assigning a dummy value
+ * 3) we don't know the filepath at this point, workaround by assigning a dummy value
* which calls back when its freed so the real loading can take place.
*/
diff --git a/source/blender/python/intern/bpy_library_load.c b/source/blender/python/intern/bpy_library_load.c
index e0e5dd869ba..9754599eeed 100644
--- a/source/blender/python/intern/bpy_library_load.c
+++ b/source/blender/python/intern/bpy_library_load.c
@@ -182,7 +182,7 @@ static PyObject *bpy_lib_load(BPy_PropertyRNA *self, PyObject *args, PyObject *k
Main *bmain_base = CTX_data_main(BPY_context_get());
Main *bmain = self->ptr.data; /* Typically #G_MAIN */
BPy_Library *ret;
- const char *filename = NULL;
+ const char *filepath = NULL;
bool is_rel = false, is_link = false, use_assets_only = false;
static const char *_keywords[] = {"filepath", "link", "relative", "assets_only", NULL};
@@ -200,7 +200,7 @@ static PyObject *bpy_lib_load(BPy_PropertyRNA *self, PyObject *args, PyObject *k
if (!_PyArg_ParseTupleAndKeywordsFast(args,
kw,
&_parser,
- &filename,
+ &filepath,
PyC_ParseBool,
&is_link,
PyC_ParseBool,
@@ -212,8 +212,8 @@ static PyObject *bpy_lib_load(BPy_PropertyRNA *self, PyObject *args, PyObject *k
ret = PyObject_New(BPy_Library, &bpy_lib_Type);
- BLI_strncpy(ret->relpath, filename, sizeof(ret->relpath));
- BLI_strncpy(ret->abspath, filename, sizeof(ret->abspath));
+ BLI_strncpy(ret->relpath, filepath, sizeof(ret->relpath));
+ BLI_strncpy(ret->abspath, filepath, sizeof(ret->abspath));
BLI_path_abs(ret->abspath, BKE_main_blendfile_path(bmain));
ret->bmain = bmain;
diff --git a/source/blender/python/intern/bpy_props.c b/source/blender/python/intern/bpy_props.c
index a6aa1f46b0c..3f2154189e8 100644
--- a/source/blender/python/intern/bpy_props.c
+++ b/source/blender/python/intern/bpy_props.c
@@ -45,150 +45,32 @@
/** \name Shared Enums & Doc-Strings
* \{ */
-static const EnumPropertyItem property_flag_items[] = {
- {PROP_HIDDEN, "HIDDEN", 0, "Hidden", ""},
- {PROP_SKIP_SAVE, "SKIP_SAVE", 0, "Skip Save", ""},
- {PROP_ANIMATABLE, "ANIMATABLE", 0, "Animatable", ""},
- {PROP_LIB_EXCEPTION, "LIBRARY_EDITABLE", 0, "Library Editable", ""},
- {PROP_PROPORTIONAL, "PROPORTIONAL", 0, "Adjust values proportionally to eachother", ""},
- {PROP_TEXTEDIT_UPDATE,
- "TEXTEDIT_UPDATE",
- 0,
- "Update on every keystroke in textedit 'mode'",
- ""},
- {0, NULL, 0, NULL, NULL},
-};
-
#define BPY_PROPDEF_OPTIONS_DOC \
- " :arg options: Enumerator in ['HIDDEN', 'SKIP_SAVE', 'ANIMATABLE', 'LIBRARY_EDITABLE', " \
- "'PROPORTIONAL'," \
- "'TEXTEDIT_UPDATE'].\n" \
+ " :arg options: Enumerator in :ref:`rna_enum_property_flag_items`.\n" \
" :type options: set\n"
-static const EnumPropertyItem property_flag_enum_items[] = {
- {PROP_HIDDEN, "HIDDEN", 0, "Hidden", ""},
- {PROP_SKIP_SAVE, "SKIP_SAVE", 0, "Skip Save", ""},
- {PROP_ANIMATABLE, "ANIMATABLE", 0, "Animatable", ""},
- {PROP_LIB_EXCEPTION, "LIBRARY_EDITABLE", 0, "Library Editable", ""},
- {PROP_ENUM_FLAG, "ENUM_FLAG", 0, "Enum Flag", ""},
- {0, NULL, 0, NULL, NULL},
-};
-
#define BPY_PROPDEF_OPTIONS_ENUM_DOC \
- " :arg options: Enumerator in ['HIDDEN', 'SKIP_SAVE', 'ANIMATABLE', 'ENUM_FLAG', " \
- "'LIBRARY_EDITABLE'].\n" \
+ " :arg options: Enumerator in :ref:`rna_enum_property_flag_enum_items`.\n" \
" :type options: set\n"
-static const EnumPropertyItem property_flag_override_items[] = {
- {PROPOVERRIDE_OVERRIDABLE_LIBRARY,
- "LIBRARY_OVERRIDABLE",
- 0,
- "Library Overridable",
- "Make that property editable in library overrides of linked data-blocks"},
- {0, NULL, 0, NULL, NULL},
-};
-
#define BPY_PROPDEF_OPTIONS_OVERRIDE_DOC \
- " :arg override: Enumerator in ['LIBRARY_OVERRIDABLE'].\n" \
+ " :arg override: Enumerator in :ref:`rna_enum_property_override_flag_items`.\n" \
" :type override: set\n"
-static const EnumPropertyItem property_flag_override_collection_items[] = {
- {PROPOVERRIDE_OVERRIDABLE_LIBRARY,
- "LIBRARY_OVERRIDABLE",
- 0,
- "Library Overridable",
- "Make that property editable in library overrides of linked data-blocks"},
- {PROPOVERRIDE_NO_PROP_NAME,
- "NO_PROPERTY_NAME",
- 0,
- "No Name",
- "Do not use the names of the items, only their indices in the collection"},
- {PROPOVERRIDE_LIBRARY_INSERTION,
- "USE_INSERTION",
- 0,
- "Use Insertion",
- "Allow users to add new items in that collection in library overrides"},
- {0, NULL, 0, NULL, NULL},
-};
-
#define BPY_PROPDEF_OPTIONS_OVERRIDE_COLLECTION_DOC \
- " :arg override: Enumerator in ['LIBRARY_OVERRIDABLE', 'NO_PROPERTY_NAME', " \
- "'USE_INSERTION'].\n" \
+ " :arg override: Enumerator in :ref:`rna_enum_property_override_flag_collection_items`.\n" \
" :type override: set\n"
-/* subtypes */
-/* Keep in sync with RNA_types.h PropertySubType and rna_rna.c's rna_enum_property_subtype_items */
-static const EnumPropertyItem property_subtype_string_items[] = {
- {PROP_FILEPATH, "FILE_PATH", 0, "File Path", ""},
- {PROP_DIRPATH, "DIR_PATH", 0, "Directory Path", ""},
- {PROP_FILENAME, "FILE_NAME", 0, "Filename", ""},
- {PROP_BYTESTRING, "BYTE_STRING", 0, "Byte String", ""},
- {PROP_PASSWORD, "PASSWORD", 0, "Password", "A string that is displayed hidden ('********')"},
-
- {PROP_NONE, "NONE", 0, "None", ""},
- {0, NULL, 0, NULL, NULL},
-};
-
#define BPY_PROPDEF_SUBTYPE_STRING_DOC \
- " :arg subtype: Enumerator in ['FILE_PATH', 'DIR_PATH', 'FILE_NAME', 'BYTE_STRING', " \
- "'PASSWORD', 'NONE'].\n" \
+ " :arg subtype: Enumerator in :ref:`rna_enum_property_subtype_string_items`.\n" \
" :type subtype: string\n"
-static const EnumPropertyItem property_subtype_number_items[] = {
- {PROP_PIXEL, "PIXEL", 0, "Pixel", ""},
- {PROP_UNSIGNED, "UNSIGNED", 0, "Unsigned", ""},
- {PROP_PERCENTAGE, "PERCENTAGE", 0, "Percentage", ""},
- {PROP_FACTOR, "FACTOR", 0, "Factor", ""},
- {PROP_ANGLE, "ANGLE", 0, "Angle", ""},
- {PROP_TIME,
- "TIME",
- 0,
- "Time (Scene Relative)",
- "Time specified in frames, converted to seconds based on scene frame rate"},
- {PROP_TIME_ABSOLUTE,
- "TIME_ABSOLUTE",
- 0,
- "Time (Absolute)",
- "Time specified in seconds, independent of the scene"},
- {PROP_DISTANCE, "DISTANCE", 0, "Distance", ""},
- {PROP_DISTANCE_CAMERA, "DISTANCE_CAMERA", 0, "Camera Distance", ""},
- {PROP_POWER, "POWER", 0, "Power", ""},
- {PROP_TEMPERATURE, "TEMPERATURE", 0, "Temperature", ""},
-
- {PROP_NONE, "NONE", 0, "None", ""},
- {0, NULL, 0, NULL, NULL},
-};
-
#define BPY_PROPDEF_SUBTYPE_NUMBER_DOC \
- " :arg subtype: Enumerator in ['PIXEL', 'UNSIGNED', 'PERCENTAGE', 'FACTOR', 'ANGLE', " \
- "'TIME', 'DISTANCE', 'DISTANCE_CAMERA', 'POWER', 'TEMPERATURE', 'NONE'].\n" \
+ " :arg subtype: Enumerator in :ref:`rna_enum_property_subtype_number_items`.\n" \
" :type subtype: string\n"
-static const EnumPropertyItem property_subtype_array_items[] = {
- {PROP_COLOR, "COLOR", 0, "Color", ""},
- {PROP_TRANSLATION, "TRANSLATION", 0, "Translation", ""},
- {PROP_DIRECTION, "DIRECTION", 0, "Direction", ""},
- {PROP_VELOCITY, "VELOCITY", 0, "Velocity", ""},
- {PROP_ACCELERATION, "ACCELERATION", 0, "Acceleration", ""},
- {PROP_MATRIX, "MATRIX", 0, "Matrix", ""},
- {PROP_EULER, "EULER", 0, "Euler", ""},
- {PROP_QUATERNION, "QUATERNION", 0, "Quaternion", ""},
- {PROP_AXISANGLE, "AXISANGLE", 0, "Axis Angle", ""},
- {PROP_XYZ, "XYZ", 0, "XYZ", ""},
- {PROP_XYZ_LENGTH, "XYZ_LENGTH", 0, "XYZ Length", ""},
- {PROP_COLOR_GAMMA, "COLOR_GAMMA", 0, "Color Gamma", ""},
- {PROP_COORDS, "COORDINATES", 0, "Vector Coordinates", ""},
- {PROP_LAYER, "LAYER", 0, "Layer", ""},
- {PROP_LAYER_MEMBER, "LAYER_MEMBER", 0, "Layer Member", ""},
-
- {PROP_NONE, "NONE", 0, "None", ""},
- {0, NULL, 0, NULL, NULL},
-};
-
-#define BPY_PROPDEF_SUBTYPE_ARRAY_DOC \
- " :arg subtype: Enumerator in ['COLOR', 'TRANSLATION', 'DIRECTION', " \
- "'VELOCITY', 'ACCELERATION', 'MATRIX', 'EULER', 'QUATERNION', 'AXISANGLE', " \
- "'XYZ', 'XYZ_LENGTH', 'COLOR_GAMMA', 'COORDINATES', 'LAYER', 'LAYER_MEMBER', 'NONE'].\n" \
+#define BPY_PROPDEF_SUBTYPE_NUMBER_ARRAY_DOC \
+ " :arg subtype: Enumerator in :ref:`rna_enum_property_subtype_number_array_items`.\n" \
" :type subtype: string\n"
/** \} */
@@ -257,6 +139,11 @@ struct BPyPropStore {
/** Wrap: #RNA_def_property_poll_runtime */
PyObject *poll_fn;
} pointer_data;
+ /** #PROP_STRING type. */
+ struct {
+ /** Wrap: #RNA_def_property_string_search_func_runtime */
+ PyObject *search_fn;
+ } string_data;
};
} py_data;
};
@@ -1672,6 +1559,163 @@ static void bpy_prop_string_set_fn(struct PointerRNA *ptr,
}
}
+static bool bpy_prop_string_visit_fn_call(PyObject *py_func,
+ PyObject *item,
+ StringPropertySearchVisitFunc visit_fn,
+ void *visit_user_data)
+{
+ const char *text;
+ const char *info = NULL;
+
+ if (PyTuple_CheckExact(item)) {
+ /* Positional only. */
+ static const char *_keywords[] = {
+ "",
+ "",
+ NULL,
+ };
+ static _PyArg_Parser _parser = {
+ "s" /* `text` */
+ "s" /* `info` */
+ ":search",
+ _keywords,
+ 0,
+ };
+ if (!_PyArg_ParseTupleAndKeywordsFast(item, NULL, &_parser, &text, &info)) {
+ PyC_Err_PrintWithFunc(py_func);
+ return false;
+ }
+ }
+ else {
+ text = PyUnicode_AsUTF8(item);
+ if (UNLIKELY(text == NULL)) {
+ PyErr_Clear();
+ PyErr_Format(PyExc_TypeError,
+ "expected sequence of strings or tuple pairs of strings, not %.200s",
+ Py_TYPE(item)->tp_name);
+ PyC_Err_PrintWithFunc(py_func);
+ return false;
+ }
+ }
+
+ StringPropertySearchVisitParams visit_params = {NULL};
+ visit_params.text = text;
+ visit_params.info = info;
+ visit_fn(visit_user_data, &visit_params);
+ return true;
+}
+
+static void bpy_prop_string_visit_for_search_fn(const struct bContext *C,
+ struct PointerRNA *ptr,
+ struct PropertyRNA *prop,
+ const char *edit_text,
+ StringPropertySearchVisitFunc visit_fn,
+ void *visit_user_data)
+{
+ struct BPyPropStore *prop_store = RNA_property_py_data_get(prop);
+ PyObject *py_func;
+ PyObject *args;
+ PyObject *self;
+ PyObject *ret;
+ PyGILState_STATE gilstate;
+ PyObject *py_edit_text;
+
+ BLI_assert(prop_store != NULL);
+
+ if (C) {
+ bpy_context_set((struct bContext *)C, &gilstate);
+ }
+ else {
+ gilstate = PyGILState_Ensure();
+ }
+
+ py_func = prop_store->py_data.string_data.search_fn;
+
+ args = PyTuple_New(3);
+ self = pyrna_struct_as_instance(ptr);
+ PyTuple_SET_ITEM(args, 0, self);
+
+ Py_INCREF(bpy_context_module);
+ PyTuple_SET_ITEM(args, 1, (PyObject *)bpy_context_module);
+
+ py_edit_text = PyUnicode_FromString(edit_text);
+ PyTuple_SET_ITEM(args, 2, py_edit_text);
+
+ ret = PyObject_CallObject(py_func, args);
+
+ Py_DECREF(args);
+
+ if (ret == NULL) {
+ PyC_Err_PrintWithFunc(py_func);
+ }
+ else {
+ if (PyIter_Check(ret)) {
+ /* Iterators / generator types. */
+ PyObject *it;
+ PyObject *(*iternext)(PyObject *);
+ it = PyObject_GetIter(ret);
+ if (it == NULL) {
+ PyC_Err_PrintWithFunc(py_func);
+ }
+ else {
+ iternext = *Py_TYPE(it)->tp_iternext;
+ for (;;) {
+ PyObject *py_text = iternext(it);
+ if (py_text == NULL) {
+ break;
+ }
+ const bool ok = bpy_prop_string_visit_fn_call(
+ py_func, py_text, visit_fn, visit_user_data);
+ Py_DECREF(py_text);
+ if (!ok) {
+ break;
+ }
+ }
+ Py_DECREF(it);
+ if (PyErr_Occurred()) {
+ if (PyErr_ExceptionMatches(PyExc_StopIteration)) {
+ PyErr_Clear();
+ }
+ else {
+ PyC_Err_PrintWithFunc(py_func);
+ }
+ }
+ }
+ }
+ else {
+ /* Sequence (typically list/tuple). */
+ PyObject *ret_fast = PySequence_Fast(
+ ret,
+ "StringProperty(...): "
+ "return value from search callback was not a sequence, iterator or generator");
+ if (ret_fast == NULL) {
+ PyC_Err_PrintWithFunc(py_func);
+ }
+ else {
+ const Py_ssize_t ret_num = PySequence_Fast_GET_SIZE(ret_fast);
+ PyObject **ret_fast_items = PySequence_Fast_ITEMS(ret_fast);
+ for (Py_ssize_t i = 0; i < ret_num; i++) {
+ const bool ok = bpy_prop_string_visit_fn_call(
+ py_func, ret_fast_items[i], visit_fn, visit_user_data);
+ if (!ok) {
+ break;
+ }
+ }
+ Py_DECREF(ret_fast);
+ }
+ }
+
+ Py_DECREF(ret);
+ }
+
+ if (C) {
+ bpy_context_clear((struct bContext *)C, &gilstate);
+ }
+ else {
+ PyGILState_Release(gilstate);
+ }
+}
+
/** \} */
/* -------------------------------------------------------------------- */
@@ -2352,11 +2396,14 @@ static void bpy_prop_callback_assign_float_array(struct PropertyRNA *prop,
static void bpy_prop_callback_assign_string(struct PropertyRNA *prop,
PyObject *get_fn,
- PyObject *set_fn)
+ PyObject *set_fn,
+ PyObject *search_fn,
+ const eStringPropertySearchFlag search_flag)
{
StringPropertyGetFunc rna_get_fn = NULL;
StringPropertyLengthFunc rna_length_fn = NULL;
StringPropertySetFunc rna_set_fn = NULL;
+ StringPropertySearchFunc rna_search_fn = NULL;
if (get_fn && get_fn != Py_None) {
struct BPyPropStore *prop_store = bpy_prop_py_data_ensure(prop);
@@ -2372,8 +2419,17 @@ static void bpy_prop_callback_assign_string(struct PropertyRNA *prop,
rna_set_fn = bpy_prop_string_set_fn;
ASSIGN_PYOBJECT_INCREF(prop_store->py_data.set_fn, set_fn);
}
+ if (search_fn) {
+ struct BPyPropStore *prop_store = bpy_prop_py_data_ensure(prop);
+
+ rna_search_fn = bpy_prop_string_visit_for_search_fn;
+ ASSIGN_PYOBJECT_INCREF(prop_store->py_data.string_data.search_fn, search_fn);
+ }
RNA_def_property_string_funcs_runtime(prop, rna_get_fn, rna_length_fn, rna_set_fn);
+ if (rna_search_fn) {
+ RNA_def_property_string_search_func_runtime(prop, rna_search_fn, search_flag);
+ }
}
static void bpy_prop_callback_assign_enum(struct PropertyRNA *prop,
@@ -2565,8 +2621,7 @@ static int bpy_prop_arg_parse_tag_defines(PyObject *o, void *p)
" :type description: string\n"
#define BPY_PROPDEF_UNIT_DOC \
- " :arg unit: Enumerator in ['NONE', 'LENGTH', 'AREA', 'VOLUME', 'ROTATION', 'TIME', " \
- "'VELOCITY', 'ACCELERATION', 'MASS', 'CAMERA', 'POWER'].\n" \
+ " :arg unit: Enumerator in :ref:`rna_enum_property_unit_items`.\n" \
" :type unit: string\n"
#define BPY_PROPDEF_NUM_MIN_DOC \
@@ -2628,6 +2683,24 @@ static int bpy_prop_arg_parse_tag_defines(PyObject *o, void *p)
" This function must take 2 values (self, value) and return None.\n" \
" :type set: function\n"
+#define BPY_PROPDEF_SEARCH_DOC \
+ " :arg search: Function to be called to show candidates for this string (shown in the UI).\n" \
+ " This function must take 3 values (self, context, edit_text)\n" \
+ " and return a sequence, iterator or generator where each item must be:\n" \
+ "\n" \
+ " - A single string (representing a candidate to display).\n" \
+ " - A tuple-pair of strings, where the first is a candidate and the second\n" \
+ " is additional information about the candidate.\n" \
+ " :type search: function\n" \
+ " :arg search_options: Set of strings in:\n" \
+ "\n" \
+ " - 'SORT' sorts the resulting items.\n" \
+ " - 'SUGGESTION' lets the user enter values not found in search candidates.\n" \
+ " **WARNING** disabling this flag causes the search callback to run on redraw,\n" \
+ " so only disable this flag if it's not likely to cause performance issues.\n" \
+ "\n" \
+ " :type search_options: set\n"
+
#define BPY_PROPDEF_POINTER_TYPE_DOC \
" :arg type: A subclass of :class:`bpy.types.PropertyGroup` or :class:`bpy.types.ID`.\n" \
" :type type: class\n"
@@ -2697,18 +2770,18 @@ static PyObject *BPy_BoolProperty(PyObject *self, PyObject *args, PyObject *kw)
bool default_value = false;
PropertyRNA *prop;
struct BPy_EnumProperty_Parse options_enum = {
- .items = property_flag_items,
+ .items = rna_enum_property_flag_items,
.value = 0,
};
struct BPy_EnumProperty_Parse override_enum = {
- .items = property_flag_override_items,
+ .items = rna_enum_property_override_flag_items,
.value = 0,
};
struct BPy_EnumProperty_Parse_WithSRNA tags_enum = {
.srna = srna,
};
struct BPy_EnumProperty_Parse subtype_enum = {
- .items = property_subtype_number_items,
+ .items = rna_enum_property_subtype_number_items,
.value = PROP_NONE,
};
@@ -2822,7 +2895,7 @@ PyDoc_STRVAR(
"\n" BPY_PROPDEF_NAME_DOC BPY_PROPDEF_DESC_DOC
" :arg default: sequence of booleans the length of *size*.\n"
" :type default: sequence\n" BPY_PROPDEF_OPTIONS_DOC BPY_PROPDEF_OPTIONS_OVERRIDE_DOC
- BPY_PROPDEF_TAGS_DOC BPY_PROPDEF_SUBTYPE_ARRAY_DOC BPY_PROPDEF_VECSIZE_DOC
+ BPY_PROPDEF_TAGS_DOC BPY_PROPDEF_SUBTYPE_NUMBER_ARRAY_DOC BPY_PROPDEF_VECSIZE_DOC
BPY_PROPDEF_UPDATE_DOC BPY_PROPDEF_GET_DOC BPY_PROPDEF_SET_DOC);
static PyObject *BPy_BoolVectorProperty(PyObject *self, PyObject *args, PyObject *kw)
{
@@ -2845,18 +2918,18 @@ static PyObject *BPy_BoolVectorProperty(PyObject *self, PyObject *args, PyObject
PropertyRNA *prop;
PyObject *default_py = NULL;
struct BPy_EnumProperty_Parse options_enum = {
- .items = property_flag_items,
+ .items = rna_enum_property_flag_items,
.value = 0,
};
struct BPy_EnumProperty_Parse override_enum = {
- .items = property_flag_override_items,
+ .items = rna_enum_property_override_flag_items,
.value = 0,
};
struct BPy_EnumProperty_Parse_WithSRNA tags_enum = {
.srna = srna,
};
struct BPy_EnumProperty_Parse subtype_enum = {
- .items = property_subtype_array_items,
+ .items = rna_enum_property_subtype_number_array_items,
.value = PROP_NONE,
};
PyObject *update_fn = NULL;
@@ -3021,18 +3094,18 @@ static PyObject *BPy_IntProperty(PyObject *self, PyObject *args, PyObject *kw)
PropertyRNA *prop;
struct BPy_EnumProperty_Parse options_enum = {
- .items = property_flag_items,
+ .items = rna_enum_property_flag_items,
.value = 0,
};
struct BPy_EnumProperty_Parse override_enum = {
- .items = property_flag_override_items,
+ .items = rna_enum_property_override_flag_items,
.value = 0,
};
struct BPy_EnumProperty_Parse_WithSRNA tags_enum = {
.srna = srna,
};
struct BPy_EnumProperty_Parse subtype_enum = {
- .items = property_subtype_number_items,
+ .items = rna_enum_property_subtype_number_items,
.value = PROP_NONE,
};
PyObject *update_fn = NULL;
@@ -3168,8 +3241,8 @@ PyDoc_STRVAR(BPy_IntVectorProperty_doc,
" :type soft_min: int\n" BPY_PROPDEF_NUM_SOFTMAX_DOC
" :type soft_max: int\n" BPY_PROPDEF_INT_STEP_DOC BPY_PROPDEF_OPTIONS_DOC
BPY_PROPDEF_OPTIONS_OVERRIDE_DOC BPY_PROPDEF_TAGS_DOC
- BPY_PROPDEF_SUBTYPE_ARRAY_DOC BPY_PROPDEF_VECSIZE_DOC BPY_PROPDEF_UPDATE_DOC
- BPY_PROPDEF_GET_DOC BPY_PROPDEF_SET_DOC);
+ BPY_PROPDEF_SUBTYPE_NUMBER_ARRAY_DOC BPY_PROPDEF_VECSIZE_DOC
+ BPY_PROPDEF_UPDATE_DOC BPY_PROPDEF_GET_DOC BPY_PROPDEF_SET_DOC);
static PyObject *BPy_IntVectorProperty(PyObject *self, PyObject *args, PyObject *kw)
{
StructRNA *srna;
@@ -3194,18 +3267,18 @@ static PyObject *BPy_IntVectorProperty(PyObject *self, PyObject *args, PyObject
PyObject *default_py = NULL;
struct BPy_EnumProperty_Parse options_enum = {
- .items = property_flag_items,
+ .items = rna_enum_property_flag_items,
.value = 0,
};
struct BPy_EnumProperty_Parse override_enum = {
- .items = property_flag_override_items,
+ .items = rna_enum_property_override_flag_items,
.value = 0,
};
struct BPy_EnumProperty_Parse_WithSRNA tags_enum = {
.srna = srna,
};
struct BPy_EnumProperty_Parse subtype_enum = {
- .items = property_subtype_array_items,
+ .items = rna_enum_property_subtype_number_array_items,
.value = PROP_NONE,
};
PyObject *update_fn = NULL;
@@ -3391,18 +3464,18 @@ static PyObject *BPy_FloatProperty(PyObject *self, PyObject *args, PyObject *kw)
PropertyRNA *prop;
struct BPy_EnumProperty_Parse options_enum = {
- .items = property_flag_items,
+ .items = rna_enum_property_flag_items,
.value = 0,
};
struct BPy_EnumProperty_Parse override_enum = {
- .items = property_flag_override_items,
+ .items = rna_enum_property_override_flag_items,
.value = 0,
};
struct BPy_EnumProperty_Parse_WithSRNA tags_enum = {
.srna = srna,
};
struct BPy_EnumProperty_Parse subtype_enum = {
- .items = property_subtype_number_items,
+ .items = rna_enum_property_subtype_number_items,
.value = PROP_NONE,
};
struct BPy_EnumProperty_Parse unit_enum = {
@@ -3536,8 +3609,9 @@ PyDoc_STRVAR(BPy_FloatVectorProperty_doc,
" :type soft_min: float\n" BPY_PROPDEF_NUM_SOFTMAX_DOC
" :type soft_max: float\n" BPY_PROPDEF_OPTIONS_DOC BPY_PROPDEF_OPTIONS_OVERRIDE_DOC
BPY_PROPDEF_TAGS_DOC BPY_PROPDEF_FLOAT_STEP_DOC BPY_PROPDEF_FLOAT_PREC_DOC
- BPY_PROPDEF_SUBTYPE_ARRAY_DOC BPY_PROPDEF_UNIT_DOC BPY_PROPDEF_VECSIZE_DOC
- BPY_PROPDEF_UPDATE_DOC BPY_PROPDEF_GET_DOC BPY_PROPDEF_SET_DOC);
+ BPY_PROPDEF_SUBTYPE_NUMBER_ARRAY_DOC BPY_PROPDEF_UNIT_DOC
+ BPY_PROPDEF_VECSIZE_DOC BPY_PROPDEF_UPDATE_DOC BPY_PROPDEF_GET_DOC
+ BPY_PROPDEF_SET_DOC);
static PyObject *BPy_FloatVectorProperty(PyObject *self, PyObject *args, PyObject *kw)
{
StructRNA *srna;
@@ -3563,18 +3637,18 @@ static PyObject *BPy_FloatVectorProperty(PyObject *self, PyObject *args, PyObjec
PyObject *default_py = NULL;
struct BPy_EnumProperty_Parse options_enum = {
- .items = property_flag_items,
+ .items = rna_enum_property_flag_items,
.value = 0,
};
struct BPy_EnumProperty_Parse override_enum = {
- .items = property_flag_override_items,
+ .items = rna_enum_property_override_flag_items,
.value = 0,
};
struct BPy_EnumProperty_Parse_WithSRNA tags_enum = {
.srna = srna,
};
struct BPy_EnumProperty_Parse subtype_enum = {
- .items = property_subtype_array_items,
+ .items = rna_enum_property_subtype_number_array_items,
.value = PROP_NONE,
};
struct BPy_EnumProperty_Parse unit_enum = {
@@ -3721,7 +3795,9 @@ PyDoc_STRVAR(BPy_StringProperty_doc,
"subtype='NONE', "
"update=None, "
"get=None, "
- "set=None)\n"
+ "set=None, "
+ "search=None, "
+ "search_options={'SUGGESTION'})\n"
"\n"
" Returns a new string property definition.\n"
"\n" BPY_PROPDEF_NAME_DOC BPY_PROPDEF_DESC_DOC
@@ -3730,7 +3806,7 @@ PyDoc_STRVAR(BPy_StringProperty_doc,
" :arg maxlen: maximum length of the string.\n"
" :type maxlen: int\n" BPY_PROPDEF_OPTIONS_DOC BPY_PROPDEF_OPTIONS_OVERRIDE_DOC
BPY_PROPDEF_TAGS_DOC BPY_PROPDEF_SUBTYPE_STRING_DOC BPY_PROPDEF_UPDATE_DOC
- BPY_PROPDEF_GET_DOC BPY_PROPDEF_SET_DOC);
+ BPY_PROPDEF_GET_DOC BPY_PROPDEF_SET_DOC BPY_PROPDEF_SEARCH_DOC);
static PyObject *BPy_StringProperty(PyObject *self, PyObject *args, PyObject *kw)
{
StructRNA *srna;
@@ -3750,23 +3826,28 @@ static PyObject *BPy_StringProperty(PyObject *self, PyObject *args, PyObject *kw
PropertyRNA *prop;
struct BPy_EnumProperty_Parse options_enum = {
- .items = property_flag_items,
+ .items = rna_enum_property_flag_items,
.value = 0,
};
struct BPy_EnumProperty_Parse override_enum = {
- .items = property_flag_override_items,
+ .items = rna_enum_property_override_flag_items,
.value = 0,
};
struct BPy_EnumProperty_Parse_WithSRNA tags_enum = {
.srna = srna,
};
struct BPy_EnumProperty_Parse subtype_enum = {
- .items = property_subtype_string_items,
+ .items = rna_enum_property_subtype_string_items,
.value = PROP_NONE,
};
PyObject *update_fn = NULL;
PyObject *get_fn = NULL;
PyObject *set_fn = NULL;
+ PyObject *search_fn = NULL;
+ static struct BPy_EnumProperty_Parse search_options_enum = {
+ .items = rna_enum_property_string_search_flag_items,
+ .value = PROP_STRING_SEARCH_SUGGESTION,
+ };
static const char *_keywords[] = {
"attr",
@@ -3781,6 +3862,8 @@ static PyObject *BPy_StringProperty(PyObject *self, PyObject *args, PyObject *kw
"update",
"get",
"set",
+ "search",
+ "search_options",
NULL,
};
static _PyArg_Parser _parser = {
@@ -3797,6 +3880,8 @@ static PyObject *BPy_StringProperty(PyObject *self, PyObject *args, PyObject *kw
"O" /* `update` */
"O" /* `get` */
"O" /* `set` */
+ "O" /* `search` */
+ "O&" /* `search_options` */
":StringProperty",
_keywords,
0,
@@ -3820,7 +3905,10 @@ static PyObject *BPy_StringProperty(PyObject *self, PyObject *args, PyObject *kw
&subtype_enum,
&update_fn,
&get_fn,
- &set_fn)) {
+ &set_fn,
+ &search_fn,
+ pyrna_enum_bitfield_parse_set,
+ &search_options_enum)) {
return NULL;
}
@@ -3833,6 +3921,9 @@ static PyObject *BPy_StringProperty(PyObject *self, PyObject *args, PyObject *kw
if (bpy_prop_callback_check(set_fn, "set", 2) == -1) {
return NULL;
}
+ if (bpy_prop_callback_check(search_fn, "search", 3) == -1) {
+ return NULL;
+ }
if (id_data.prop_free_handle != NULL) {
RNA_def_property_free_identifier_deferred_finish(srna, id_data.prop_free_handle);
@@ -3858,7 +3949,7 @@ static PyObject *BPy_StringProperty(PyObject *self, PyObject *args, PyObject *kw
bpy_prop_assign_flag_override(prop, override_enum.value);
}
bpy_prop_callback_assign_update(prop, update_fn);
- bpy_prop_callback_assign_string(prop, get_fn, set_fn);
+ bpy_prop_callback_assign_string(prop, get_fn, set_fn, search_fn, search_options_enum.value);
RNA_def_property_duplicate_pointers(srna, prop);
Py_RETURN_NONE;
@@ -3941,11 +4032,11 @@ static PyObject *BPy_EnumProperty(PyObject *self, PyObject *args, PyObject *kw)
PropertyRNA *prop;
struct BPy_EnumProperty_Parse options_enum = {
- .items = property_flag_enum_items,
+ .items = rna_enum_property_flag_enum_items,
.value = 0,
};
struct BPy_EnumProperty_Parse override_enum = {
- .items = property_flag_override_items,
+ .items = rna_enum_property_override_flag_items,
.value = 0,
};
struct BPy_EnumProperty_Parse_WithSRNA tags_enum = {
@@ -4164,11 +4255,11 @@ PyObject *BPy_PointerProperty(PyObject *self, PyObject *args, PyObject *kw)
PyObject *type = Py_None;
struct BPy_EnumProperty_Parse options_enum = {
- .items = property_flag_items,
+ .items = rna_enum_property_flag_items,
.value = 0,
};
struct BPy_EnumProperty_Parse override_enum = {
- .items = property_flag_override_items,
+ .items = rna_enum_property_override_flag_items,
.value = 0,
};
struct BPy_EnumProperty_Parse_WithSRNA tags_enum = {
@@ -4301,11 +4392,11 @@ PyObject *BPy_CollectionProperty(PyObject *self, PyObject *args, PyObject *kw)
PyObject *type = Py_None;
struct BPy_EnumProperty_Parse options_enum = {
- .items = property_flag_items,
+ .items = rna_enum_property_flag_items,
.value = 0,
};
struct BPy_EnumProperty_Parse override_enum = {
- .items = property_flag_override_collection_items,
+ .items = rna_enum_property_override_flag_collection_items,
.value = 0,
};
struct BPy_EnumProperty_Parse_WithSRNA tags_enum = {
diff --git a/source/blender/python/intern/bpy_rna.c b/source/blender/python/intern/bpy_rna.c
index 2276e5e97a8..14be9ceda94 100644
--- a/source/blender/python/intern/bpy_rna.c
+++ b/source/blender/python/intern/bpy_rna.c
@@ -8886,7 +8886,7 @@ static PyObject *pyrna_register_class(PyObject *UNUSED(self), PyObject *py_class
return NULL;
}
- /* Warning: gets parent classes srna, only for the register function. */
+ /* WARNING: gets parent classes srna, only for the register function. */
srna = pyrna_struct_as_srna(py_class, true, "register_class(...):");
if (srna == NULL) {
return NULL;
diff --git a/source/blender/python/intern/bpy_rna_text.h b/source/blender/python/intern/bpy_rna_text.h
index b3854b96886..6d8ed208bc3 100644
--- a/source/blender/python/intern/bpy_rna_text.h
+++ b/source/blender/python/intern/bpy_rna_text.h
@@ -15,4 +15,4 @@ extern PyMethodDef BPY_rna_region_from_string_method_def;
#ifdef __cplusplus
}
-#endif \ No newline at end of file
+#endif
diff --git a/source/blender/python/intern/bpy_rna_types_capi.c b/source/blender/python/intern/bpy_rna_types_capi.c
index d58adb66b37..c3a07847aff 100644
--- a/source/blender/python/intern/bpy_rna_types_capi.c
+++ b/source/blender/python/intern/bpy_rna_types_capi.c
@@ -107,6 +107,7 @@ static struct PyMethodDef pyrna_text_methods[] = {
* and creating the buffer, causing writes past the allocated length.
* \{ */
+PyDoc_STRVAR(pyrna_WindowManager_clipboard_doc, "Clipboard text storage.\n\n:type: string");
static PyObject *pyrna_WindowManager_clipboard_get(PyObject *UNUSED(self), void *UNUSED(flag))
{
int text_len = 0;
@@ -154,7 +155,7 @@ static struct PyGetSetDef pyrna_windowmanager_getset[] = {
{"clipboard",
pyrna_WindowManager_clipboard_get,
pyrna_WindowManager_clipboard_set,
- NULL,
+ pyrna_WindowManager_clipboard_doc,
NULL},
{NULL, NULL, NULL, NULL, NULL} /* Sentinel */
};
diff --git a/source/blender/python/intern/bpy_traceback.c b/source/blender/python/intern/bpy_traceback.c
index 45977ba400c..cb93843a6de 100644
--- a/source/blender/python/intern/bpy_traceback.c
+++ b/source/blender/python/intern/bpy_traceback.c
@@ -165,7 +165,7 @@ finally:
bool python_script_error_jump(
const char *filepath, int *r_lineno, int *r_offset, int *r_lineno_end, int *r_offset_end)
{
- /* WARNING(@campbellbarton): The normalized exception is restored (loosing line number info).
+ /* WARNING(@campbellbarton): The normalized exception is restored (losing line number info).
* Ideally this would leave the exception state as it found it, but that needs to be done
* carefully with regards to reference counting, see: T97731. */
diff --git a/source/blender/python/intern/bpy_utils_units.c b/source/blender/python/intern/bpy_utils_units.c
index 3e0698caa50..1e5856a3285 100644
--- a/source/blender/python/intern/bpy_utils_units.c
+++ b/source/blender/python/intern/bpy_utils_units.c
@@ -35,7 +35,7 @@ static const char *bpyunits_usystem_items[] = {
NULL,
};
-static const char *bpyunits_ucategorie_items[] = {
+static const char *bpyunits_ucategories_items[] = {
"NONE",
"LENGTH",
"AREA",
@@ -43,20 +43,26 @@ static const char *bpyunits_ucategorie_items[] = {
"MASS",
"ROTATION",
"TIME",
+ "TIME_ABSOLUTE",
"VELOCITY",
"ACCELERATION",
"CAMERA",
"POWER",
+ "TEMPERATURE",
NULL,
};
+BLI_STATIC_ASSERT(
+ ARRAY_SIZE(bpyunits_ucategories_items) == B_UNIT_TYPE_TOT + 1,
+ "`bpyunits_ucategories_items` should match `B_UNIT_` enum items in `BKE_units.h`")
+
/**
* These fields are just empty placeholders, actual values get set in initializations functions.
* This allows us to avoid many handwriting, and above all,
* to keep all systems/categories definition stuff in `BKE_unit.h`.
*/
static PyStructSequence_Field bpyunits_systems_fields[ARRAY_SIZE(bpyunits_usystem_items)];
-static PyStructSequence_Field bpyunits_categories_fields[ARRAY_SIZE(bpyunits_ucategorie_items)];
+static PyStructSequence_Field bpyunits_categories_fields[ARRAY_SIZE(bpyunits_ucategories_items)];
static PyStructSequence_Desc bpyunits_systems_desc = {
"bpy.utils.units.systems", /* name */
@@ -114,7 +120,7 @@ static bool bpyunits_validate(const char *usys_str, const char *ucat_str, int *r
return false;
}
- *r_ucat = BLI_str_index_in_array(ucat_str, bpyunits_ucategorie_items);
+ *r_ucat = BLI_str_index_in_array(ucat_str, bpyunits_ucategories_items);
if (*r_ucat < 0) {
PyErr_Format(PyExc_ValueError, "Unknown unit category specified: %.200s.", ucat_str);
return false;
@@ -356,7 +362,7 @@ PyObject *BPY_utils_units(void)
/* bpy.utils.units.categories */
item = py_structseq_from_strings(
- &BPyUnitsCategoriesType, &bpyunits_categories_desc, bpyunits_ucategorie_items);
+ &BPyUnitsCategoriesType, &bpyunits_categories_desc, bpyunits_ucategories_items);
PyModule_AddObject(submodule, "categories", item); /* steals ref */
return submodule;
diff --git a/source/blender/python/mathutils/CMakeLists.txt b/source/blender/python/mathutils/CMakeLists.txt
index 1be9b568626..f355d03cadc 100644
--- a/source/blender/python/mathutils/CMakeLists.txt
+++ b/source/blender/python/mathutils/CMakeLists.txt
@@ -6,6 +6,7 @@ set(INC
../../blenlib
../../bmesh
../../depsgraph
+ ../../imbuf
../../makesdna
../../../../intern/guardedalloc
)
@@ -42,6 +43,7 @@ set(SRC
set(LIB
bf_blenlib
+ bf_imbuf
bf_python_ext
${PYTHON_LINKFLAGS}
diff --git a/source/blender/python/mathutils/mathutils_Color.c b/source/blender/python/mathutils/mathutils_Color.c
index 8b126639f10..88e8d880360 100644
--- a/source/blender/python/mathutils/mathutils_Color.c
+++ b/source/blender/python/mathutils/mathutils_Color.c
@@ -14,14 +14,48 @@
#include "../generic/py_capi_utils.h"
#include "../generic/python_utildefines.h"
+#include "IMB_colormanagement.h"
+
#ifndef MATH_STANDALONE
# include "BLI_dynstr.h"
#endif
#define COLOR_SIZE 3
-/* ----------------------------------mathutils.Color() ------------------- */
-/* makes a new color for you to play with */
+/* -------------------------------------------------------------------- */
+/** \name Utilities
+ * \{ */
+
+/**
+ * \note #BaseMath_ReadCallback must be called beforehand.
+ */
+static PyObject *Color_to_tuple_ex(ColorObject *self, int ndigits)
+{
+ PyObject *ret;
+ int i;
+
+ ret = PyTuple_New(COLOR_SIZE);
+
+ if (ndigits >= 0) {
+ for (i = 0; i < COLOR_SIZE; i++) {
+ PyTuple_SET_ITEM(ret, i, PyFloat_FromDouble(double_round((double)self->col[i], ndigits)));
+ }
+ }
+ else {
+ for (i = 0; i < COLOR_SIZE; i++) {
+ PyTuple_SET_ITEM(ret, i, PyFloat_FromDouble(self->col[i]));
+ }
+ }
+
+ return ret;
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Color Type: `__new__` / `mathutils.Color()`
+ * \{ */
+
static PyObject *Color_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
{
float col[3] = {0.0f, 0.0f, 0.0f};
@@ -52,30 +86,130 @@ static PyObject *Color_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
return Color_CreatePyObject(col, type);
}
-/* -----------------------------METHODS---------------------------- */
+/** \} */
-/* NOTE: BaseMath_ReadCallback must be called beforehand. */
-static PyObject *Color_ToTupleExt(ColorObject *self, int ndigits)
+/* -------------------------------------------------------------------- */
+/** \name Color Methods: Color Space Conversion
+ * \{ */
+
+PyDoc_STRVAR(Color_from_scene_linear_to_srgb_doc,
+ ".. function:: from_scene_linear_to_srgb()\n"
+ "\n"
+ " Convert from scene linear to sRGB color space.\n"
+ "\n"
+ " :return: A color in sRGB color space.\n"
+ " :rtype: :class:`Color`\n");
+static PyObject *Color_from_scene_linear_to_srgb(ColorObject *self)
{
- PyObject *ret;
- int i;
+ float col[3];
+ IMB_colormanagement_scene_linear_to_srgb_v3(col, self->col);
+ return Color_CreatePyObject(col, Py_TYPE(self));
+}
- ret = PyTuple_New(COLOR_SIZE);
+PyDoc_STRVAR(Color_from_srgb_to_scene_linear_doc,
+ ".. function:: from_srgb_to_scene_linear()\n"
+ "\n"
+ " Convert from sRGB to scene linear color space.\n"
+ "\n"
+ " :return: A color in scene linear color space.\n"
+ " :rtype: :class:`Color`\n");
+static PyObject *Color_from_srgb_to_scene_linear(ColorObject *self)
+{
+ float col[3];
+ IMB_colormanagement_srgb_to_scene_linear_v3(col, self->col);
+ return Color_CreatePyObject(col, Py_TYPE(self));
+}
- if (ndigits >= 0) {
- for (i = 0; i < COLOR_SIZE; i++) {
- PyTuple_SET_ITEM(ret, i, PyFloat_FromDouble(double_round((double)self->col[i], ndigits)));
- }
- }
- else {
- for (i = 0; i < COLOR_SIZE; i++) {
- PyTuple_SET_ITEM(ret, i, PyFloat_FromDouble(self->col[i]));
- }
- }
+PyDoc_STRVAR(Color_from_scene_linear_to_xyz_d65_doc,
+ ".. function:: from_scene_linear_to_xyz_d65()\n"
+ "\n"
+ " Convert from scene linear to CIE XYZ (Illuminant D65) color space.\n"
+ "\n"
+ " :return: A color in XYZ color space.\n"
+ " :rtype: :class:`Color`\n");
+static PyObject *Color_from_scene_linear_to_xyz_d65(ColorObject *self)
+{
+ float col[3];
+ IMB_colormanagement_scene_linear_to_xyz(col, self->col);
+ return Color_CreatePyObject(col, Py_TYPE(self));
+}
- return ret;
+PyDoc_STRVAR(Color_from_xyz_d65_to_scene_linear_doc,
+ ".. function:: from_xyz_d65_to_scene_linear()\n"
+ "\n"
+ " Convert from CIE XYZ (Illuminant D65) to scene linear color space.\n"
+ "\n"
+ " :return: A color in scene linear color space.\n"
+ " :rtype: :class:`Color`\n");
+static PyObject *Color_from_xyz_d65_to_scene_linear(ColorObject *self)
+{
+ float col[3];
+ IMB_colormanagement_xyz_to_scene_linear(col, self->col);
+ return Color_CreatePyObject(col, Py_TYPE(self));
+}
+
+PyDoc_STRVAR(Color_from_scene_linear_to_aces_doc,
+ ".. function:: from_scene_linear_to_aces()\n"
+ "\n"
+ " Convert from scene linear to ACES2065-1 linear color space.\n"
+ "\n"
+ " :return: A color in ACES2065-1 linear color space.\n"
+ " :rtype: :class:`Color`\n");
+static PyObject *Color_from_scene_linear_to_aces(ColorObject *self)
+{
+ float col[3];
+ IMB_colormanagement_scene_linear_to_aces(col, self->col);
+ return Color_CreatePyObject(col, Py_TYPE(self));
+}
+
+PyDoc_STRVAR(Color_from_aces_to_scene_linear_doc,
+ ".. function:: from_aces_to_scene_linear()\n"
+ "\n"
+ " Convert from ACES2065-1 linear to scene linear color space.\n"
+ "\n"
+ " :return: A color in scene linear color space.\n"
+ " :rtype: :class:`Color`\n");
+static PyObject *Color_from_aces_to_scene_linear(ColorObject *self)
+{
+ float col[3];
+ IMB_colormanagement_aces_to_scene_linear(col, self->col);
+ return Color_CreatePyObject(col, Py_TYPE(self));
}
+PyDoc_STRVAR(Color_from_scene_linear_to_rec709_linear_doc,
+ ".. function:: from_scene_linear_to_rec709_linear()\n"
+ "\n"
+ " Convert from scene linear to Rec.709 linear color space.\n"
+ "\n"
+ " :return: A color in Rec.709 linear color space.\n"
+ " :rtype: :class:`Color`\n");
+static PyObject *Color_from_scene_linear_to_rec709_linear(ColorObject *self)
+{
+ float col[3];
+ IMB_colormanagement_scene_linear_to_rec709(col, self->col);
+ return Color_CreatePyObject(col, Py_TYPE(self));
+}
+
+PyDoc_STRVAR(Color_from_rec709_linear_to_scene_linear_doc,
+ ".. function:: from_rec709_linear_to_scene_linear()\n"
+ "\n"
+ " Convert from Rec.709 linear color space to scene linear color space.\n"
+ "\n"
+ " :return: A color in scene linear color space.\n"
+ " :rtype: :class:`Color`\n");
+static PyObject *Color_from_rec709_linear_to_scene_linear(ColorObject *self)
+{
+ float col[3];
+ IMB_colormanagement_rec709_to_scene_linear(col, self->col);
+ return Color_CreatePyObject(col, Py_TYPE(self));
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Color Methods: Color Copy/Deep-Copy
+ * \{ */
+
PyDoc_STRVAR(Color_copy_doc,
".. function:: copy()\n"
"\n"
@@ -102,8 +236,11 @@ static PyObject *Color_deepcopy(ColorObject *self, PyObject *args)
return Color_copy(self);
}
-/* ----------------------------print object (internal)-------------- */
-/* print the object to screen */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Color Type: `__repr__` & `__str__`
+ * \{ */
static PyObject *Color_repr(ColorObject *self)
{
@@ -113,7 +250,7 @@ static PyObject *Color_repr(ColorObject *self)
return NULL;
}
- tuple = Color_ToTupleExt(self, -1);
+ tuple = Color_to_tuple_ex(self, -1);
ret = PyUnicode_FromFormat("Color(%R)", tuple);
@@ -139,8 +276,12 @@ static PyObject *Color_str(ColorObject *self)
}
#endif
-/* ------------------------tp_richcmpr */
-/* returns -1 exception, 0 false, 1 true */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Color Type: Rich Compare
+ * \{ */
+
static PyObject *Color_richcmpr(PyObject *a, PyObject *b, int op)
{
PyObject *res;
@@ -179,6 +320,12 @@ static PyObject *Color_richcmpr(PyObject *a, PyObject *b, int op)
return Py_INCREF_RET(res);
}
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Color Type: Hash (`__hash__`)
+ * \{ */
+
static Py_hash_t Color_hash(ColorObject *self)
{
if (BaseMath_ReadCallback(self) == -1) {
@@ -192,15 +339,19 @@ static Py_hash_t Color_hash(ColorObject *self)
return mathutils_array_hash(self->col, COLOR_SIZE);
}
-/* ---------------------SEQUENCE PROTOCOLS------------------------ */
-/* ----------------------------len(object)------------------------ */
-/* sequence length */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Color Type: Sequence & Mapping Protocols Implementation
+ * \{ */
+
+/** Sequence length: `len(object)`. */
static int Color_len(ColorObject *UNUSED(self))
{
return COLOR_SIZE;
}
-/* ----------------------------object[]--------------------------- */
-/* sequence accessor (get) */
+
+/** Sequence accessor (get): `x = object[i]`. */
static PyObject *Color_item(ColorObject *self, int i)
{
if (i < 0) {
@@ -220,8 +371,8 @@ static PyObject *Color_item(ColorObject *self, int i)
return PyFloat_FromDouble(self->col[i]);
}
-/* ----------------------------object[]------------------------- */
-/* sequence accessor (set) */
+
+/** Sequence accessor (set): `object[i] = x`. */
static int Color_ass_item(ColorObject *self, int i, PyObject *value)
{
float f;
@@ -257,8 +408,8 @@ static int Color_ass_item(ColorObject *self, int i, PyObject *value)
return 0;
}
-/* ----------------------------object[z:y]------------------------ */
-/* sequence slice (get) */
+
+/** Sequence slice accessor (get): `x = object[i:j]`. */
static PyObject *Color_slice(ColorObject *self, int begin, int end)
{
PyObject *tuple;
@@ -282,8 +433,8 @@ static PyObject *Color_slice(ColorObject *self, int begin, int end)
return tuple;
}
-/* ----------------------------object[z:y]------------------------ */
-/* sequence slice (set) */
+
+/** Sequence slice accessor (set): `object[i:j] = x`. */
static int Color_ass_slice(ColorObject *self, int begin, int end, PyObject *seq)
{
int i, size;
@@ -320,6 +471,7 @@ static int Color_ass_slice(ColorObject *self, int begin, int end, PyObject *seq)
return 0;
}
+/** Sequence generic subscript (get): `x = object[...]`. */
static PyObject *Color_subscript(ColorObject *self, PyObject *item)
{
if (PyIndex_Check(item)) {
@@ -356,6 +508,7 @@ static PyObject *Color_subscript(ColorObject *self, PyObject *item)
return NULL;
}
+/** Sequence generic subscript (set): `object[...] = x`. */
static int Color_ass_subscript(ColorObject *self, PyObject *item, PyObject *value)
{
if (PyIndex_Check(item)) {
@@ -388,29 +541,13 @@ static int Color_ass_subscript(ColorObject *self, PyObject *item, PyObject *valu
return -1;
}
-/* -----------------PROTCOL DECLARATIONS-------------------------- */
-static PySequenceMethods Color_SeqMethods = {
- (lenfunc)Color_len, /* sq_length */
- (binaryfunc)NULL, /* sq_concat */
- (ssizeargfunc)NULL, /* sq_repeat */
- (ssizeargfunc)Color_item, /* sq_item */
- NULL, /* sq_slice, deprecated */
- (ssizeobjargproc)Color_ass_item, /* sq_ass_item */
- NULL, /* sq_ass_slice, deprecated */
- (objobjproc)NULL, /* sq_contains */
- (binaryfunc)NULL, /* sq_inplace_concat */
- (ssizeargfunc)NULL, /* sq_inplace_repeat */
-};
-
-static PyMappingMethods Color_AsMapping = {
- (lenfunc)Color_len,
- (binaryfunc)Color_subscript,
- (objobjargproc)Color_ass_subscript,
-};
+/** \} */
-/* numeric */
+/* -------------------------------------------------------------------- */
+/** \name Color Type: Numeric Protocol Implementation
+ * \{ */
-/* addition: obj + obj */
+/** Addition: `object + object`. */
static PyObject *Color_add(PyObject *v1, PyObject *v2)
{
ColorObject *color1 = NULL, *color2 = NULL;
@@ -436,7 +573,7 @@ static PyObject *Color_add(PyObject *v1, PyObject *v2)
return Color_CreatePyObject(col, Py_TYPE(v1));
}
-/* addition in-place: obj += obj */
+/** Addition in-place: `object += object`. */
static PyObject *Color_iadd(PyObject *v1, PyObject *v2)
{
ColorObject *color1 = NULL, *color2 = NULL;
@@ -463,7 +600,7 @@ static PyObject *Color_iadd(PyObject *v1, PyObject *v2)
return v1;
}
-/* subtraction: obj - obj */
+/** Subtraction: `object - object`. */
static PyObject *Color_sub(PyObject *v1, PyObject *v2)
{
ColorObject *color1 = NULL, *color2 = NULL;
@@ -489,7 +626,7 @@ static PyObject *Color_sub(PyObject *v1, PyObject *v2)
return Color_CreatePyObject(col, Py_TYPE(v1));
}
-/* subtraction in-place: obj -= obj */
+/** Subtraction in-place: `object -= object`. */
static PyObject *Color_isub(PyObject *v1, PyObject *v2)
{
ColorObject *color1 = NULL, *color2 = NULL;
@@ -523,6 +660,7 @@ static PyObject *color_mul_float(ColorObject *color, const float scalar)
return Color_CreatePyObject(tcol, Py_TYPE(color));
}
+/** Multiplication: `object * object`. */
static PyObject *Color_mul(PyObject *v1, PyObject *v2)
{
ColorObject *color1 = NULL, *color2 = NULL;
@@ -567,6 +705,7 @@ static PyObject *Color_mul(PyObject *v1, PyObject *v2)
return NULL;
}
+/** Division: `object / object`. */
static PyObject *Color_div(PyObject *v1, PyObject *v2)
{
ColorObject *color1 = NULL;
@@ -600,7 +739,7 @@ static PyObject *Color_div(PyObject *v1, PyObject *v2)
return NULL;
}
-/* multiplication in-place: obj *= obj */
+/** Multiplication in-place: `object *= object`. */
static PyObject *Color_imul(PyObject *v1, PyObject *v2)
{
ColorObject *color = (ColorObject *)v1;
@@ -628,7 +767,7 @@ static PyObject *Color_imul(PyObject *v1, PyObject *v2)
return v1;
}
-/* multiplication in-place: obj *= obj */
+/** Division in-place: `object *= object`. */
static PyObject *Color_idiv(PyObject *v1, PyObject *v2)
{
ColorObject *color = (ColorObject *)v1;
@@ -661,8 +800,7 @@ static PyObject *Color_idiv(PyObject *v1, PyObject *v2)
return v1;
}
-/* -obj
- * returns the negative of this object */
+/** Negative (returns the negative of this object): `-object`. */
static PyObject *Color_neg(ColorObject *self)
{
float tcol[COLOR_SIZE];
@@ -675,6 +813,31 @@ static PyObject *Color_neg(ColorObject *self)
return Color_CreatePyObject(tcol, Py_TYPE(self));
}
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Color Type: Protocol Declarations
+ * \{ */
+
+static PySequenceMethods Color_SeqMethods = {
+ (lenfunc)Color_len, /*sq_length*/
+ (binaryfunc)NULL, /*sq_concat*/
+ (ssizeargfunc)NULL, /*sq_repeat*/
+ (ssizeargfunc)Color_item, /*sq_item*/
+ NULL, /*sq_slice(DEPRECATED)*/
+ (ssizeobjargproc)Color_ass_item, /*sq_ass_item*/
+ NULL, /*sq_ass_slice(DEPRECATED)*/
+ (objobjproc)NULL, /*sq_contains*/
+ (binaryfunc)NULL, /*sq_inplace_concat*/
+ (ssizeargfunc)NULL, /*sq_inplace_repeat*/
+};
+
+static PyMappingMethods Color_AsMapping = {
+ (lenfunc)Color_len,
+ (binaryfunc)Color_subscript,
+ (objobjargproc)Color_ass_subscript,
+};
+
static PyNumberMethods Color_NumMethods = {
(binaryfunc)Color_add, /*nb_add*/
(binaryfunc)Color_sub, /*nb_subtract*/
@@ -695,24 +858,31 @@ static PyNumberMethods Color_NumMethods = {
NULL, /*nb_int*/
NULL, /*nb_reserved*/
NULL, /*nb_float*/
- Color_iadd, /* nb_inplace_add */
- Color_isub, /* nb_inplace_subtract */
- Color_imul, /* nb_inplace_multiply */
- NULL, /* nb_inplace_remainder */
- NULL, /* nb_inplace_power */
- NULL, /* nb_inplace_lshift */
- NULL, /* nb_inplace_rshift */
- NULL, /* nb_inplace_and */
- NULL, /* nb_inplace_xor */
- NULL, /* nb_inplace_or */
- NULL, /* nb_floor_divide */
- Color_div, /* nb_true_divide */
- NULL, /* nb_inplace_floor_divide */
- Color_idiv, /* nb_inplace_true_divide */
- NULL, /* nb_index */
+ Color_iadd, /*nb_inplace_add*/
+ Color_isub, /*nb_inplace_subtract*/
+ Color_imul, /*nb_inplace_multiply*/
+ NULL, /*nb_inplace_remainder*/
+ NULL, /*nb_inplace_power*/
+ NULL, /*nb_inplace_lshift*/
+ NULL, /*nb_inplace_rshift*/
+ NULL, /*nb_inplace_and*/
+ NULL, /*nb_inplace_xor*/
+ NULL, /*nb_inplace_or*/
+ NULL, /*nb_floor_divide*/
+ Color_div, /*nb_true_divide*/
+ NULL, /*nb_inplace_floor_divide*/
+ Color_idiv, /*nb_inplace_true_divide*/
+ NULL, /*nb_index*/
};
-/* color channel, vector.r/g/b */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Color Type: Get/Set Item Implementation
+ * \{ */
+
+/* Color channel (RGB): `color.r/g/b`. */
+
PyDoc_STRVAR(Color_channel_r_doc, "Red color channel.\n\n:type: float");
PyDoc_STRVAR(Color_channel_g_doc, "Green color channel.\n\n:type: float");
PyDoc_STRVAR(Color_channel_b_doc, "Blue color channel.\n\n:type: float");
@@ -727,7 +897,8 @@ static int Color_channel_set(ColorObject *self, PyObject *value, void *type)
return Color_ass_item(self, POINTER_AS_INT(type), value);
}
-/* color channel (HSV), color.h/s/v */
+/* Color channel (HSV): `color.h/s/v`. */
+
PyDoc_STRVAR(Color_channel_hsv_h_doc, "HSV Hue component in [0, 1].\n\n:type: float");
PyDoc_STRVAR(Color_channel_hsv_s_doc, "HSV Saturation component in [0, 1].\n\n:type: float");
PyDoc_STRVAR(Color_channel_hsv_v_doc, "HSV Value component in [0, 1].\n\n:type: float");
@@ -775,8 +946,8 @@ static int Color_channel_hsv_set(ColorObject *self, PyObject *value, void *type)
return 0;
}
-/* color channel (HSV), color.h/s/v */
PyDoc_STRVAR(Color_hsv_doc, "HSV Values in [0, 1].\n\n:type: float triplet");
+/** Color channel HSV (get): `x = color.hsv`. */
static PyObject *Color_hsv_get(ColorObject *self, void *UNUSED(closure))
{
float hsv[3];
@@ -794,6 +965,7 @@ static PyObject *Color_hsv_get(ColorObject *self, void *UNUSED(closure))
return ret;
}
+/** Color channel HSV (set): `color.hsv = x`. */
static int Color_hsv_set(ColorObject *self, PyObject *value, void *UNUSED(closure))
{
float hsv[3];
@@ -816,9 +988,12 @@ static int Color_hsv_set(ColorObject *self, PyObject *value, void *UNUSED(closur
return 0;
}
-/*****************************************************************************/
-/* Python attributes get/set structure: */
-/*****************************************************************************/
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Color Type: Get/Set Item Definitions
+ * \{ */
+
static PyGetSetDef Color_getseters[] = {
{"r", (getter)Color_channel_get, (setter)Color_channel_set, Color_channel_r_doc, (void *)0},
{"g", (getter)Color_channel_get, (setter)Color_channel_set, Color_channel_g_doc, (void *)1},
@@ -861,7 +1036,12 @@ static PyGetSetDef Color_getseters[] = {
{NULL, NULL, NULL, NULL, NULL} /* Sentinel */
};
-/* -----------------------METHOD DEFINITIONS ---------------------- */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Color Type: Method Definitions
+ * \{ */
+
static struct PyMethodDef Color_methods[] = {
{"copy", (PyCFunction)Color_copy, METH_NOARGS, Color_copy_doc},
{"__copy__", (PyCFunction)Color_copy, METH_NOARGS, Color_copy_doc},
@@ -869,17 +1049,61 @@ static struct PyMethodDef Color_methods[] = {
/* base-math methods */
{"freeze", (PyCFunction)BaseMathObject_freeze, METH_NOARGS, BaseMathObject_freeze_doc},
+
+ /* Color-space methods. */
+ {"from_scene_linear_to_srgb",
+ (PyCFunction)Color_from_scene_linear_to_srgb,
+ METH_NOARGS,
+ Color_from_scene_linear_to_srgb_doc},
+ {"from_srgb_to_scene_linear",
+ (PyCFunction)Color_from_srgb_to_scene_linear,
+ METH_NOARGS,
+ Color_from_srgb_to_scene_linear_doc},
+ {"from_scene_linear_to_xyz_d65",
+ (PyCFunction)Color_from_scene_linear_to_xyz_d65,
+ METH_NOARGS,
+ Color_from_scene_linear_to_xyz_d65_doc},
+ {"from_xyz_d65_to_scene_linear",
+ (PyCFunction)Color_from_xyz_d65_to_scene_linear,
+ METH_NOARGS,
+ Color_from_xyz_d65_to_scene_linear_doc},
+ {"from_scene_linear_to_aces",
+ (PyCFunction)Color_from_scene_linear_to_aces,
+ METH_NOARGS,
+ Color_from_scene_linear_to_aces_doc},
+ {"from_aces_to_scene_linear",
+ (PyCFunction)Color_from_aces_to_scene_linear,
+ METH_NOARGS,
+ Color_from_aces_to_scene_linear_doc},
+ {"from_scene_linear_to_rec709_linear",
+ (PyCFunction)Color_from_scene_linear_to_rec709_linear,
+ METH_NOARGS,
+ Color_from_scene_linear_to_rec709_linear_doc},
+ {"from_rec709_linear_to_scene_linear",
+ (PyCFunction)Color_from_rec709_linear_to_scene_linear,
+ METH_NOARGS,
+ Color_from_rec709_linear_to_scene_linear_doc},
{NULL, NULL, 0, NULL},
};
-/* ------------------PY_OBECT DEFINITION-------------------------- */
-PyDoc_STRVAR(color_doc,
- ".. class:: Color(rgb)\n"
- "\n"
- " This object gives access to Colors in Blender.\n"
- "\n"
- " :param rgb: (r, g, b) color values\n"
- " :type rgb: 3d vector\n");
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Color Type: Python Object Definition
+ * \{ */
+
+PyDoc_STRVAR(
+ color_doc,
+ ".. class:: Color(rgb)\n"
+ "\n"
+ " This object gives access to Colors in Blender.\n"
+ "\n"
+ " Most colors returned by Blender APIs are in scene linear color space, as defined by "
+ " the OpenColorIO configuration. The notable exception is user interface theming colors, "
+ " which are in sRGB color space.\n"
+ "\n"
+ " :param rgb: (r, g, b) color values\n"
+ " :type rgb: 3d vector\n");
PyTypeObject color_Type = {
PyVarObject_HEAD_INIT(NULL, 0) "Color", /* tp_name */
sizeof(ColorObject), /* tp_basicsize */
@@ -932,6 +1156,12 @@ PyTypeObject color_Type = {
NULL, /* tp_del */
};
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Color Type: C/API Constructors
+ * \{ */
+
PyObject *Color_CreatePyObject(const float col[3], PyTypeObject *base_type)
{
ColorObject *self;
@@ -1001,3 +1231,5 @@ PyObject *Color_CreatePyObject_cb(PyObject *cb_user, uchar cb_type, uchar cb_sub
return (PyObject *)self;
}
+
+/** \} */
diff --git a/source/blender/python/mathutils/mathutils_Color.h b/source/blender/python/mathutils/mathutils_Color.h
index 11a936b7bc8..b4fd2eeaa81 100644
--- a/source/blender/python/mathutils/mathutils_Color.h
+++ b/source/blender/python/mathutils/mathutils_Color.h
@@ -19,7 +19,8 @@ typedef struct {
* be stored in py_data) or be a wrapper for data allocated through
* Blender (stored in blend_data). This is an either/or struct not both. */
-/* prototypes */
+/* Prototypes. */
+
PyObject *Color_CreatePyObject(const float col[3],
PyTypeObject *base_type) ATTR_WARN_UNUSED_RESULT;
PyObject *Color_CreatePyObject_wrap(float col[3], PyTypeObject *base_type) ATTR_WARN_UNUSED_RESULT
diff --git a/source/blender/python/mathutils/mathutils_Euler.c b/source/blender/python/mathutils/mathutils_Euler.c
index 909c19e8cd2..f49868dfba7 100644
--- a/source/blender/python/mathutils/mathutils_Euler.c
+++ b/source/blender/python/mathutils/mathutils_Euler.c
@@ -19,45 +19,11 @@
#define EULER_SIZE 3
-/* ----------------------------------mathutils.Euler() ------------------- */
-/* makes a new euler for you to play with */
-static PyObject *Euler_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
-{
- PyObject *seq = NULL;
- const char *order_str = NULL;
-
- float eul[EULER_SIZE] = {0.0f, 0.0f, 0.0f};
- short order = EULER_ORDER_XYZ;
-
- if (kwds && PyDict_Size(kwds)) {
- PyErr_SetString(PyExc_TypeError,
- "mathutils.Euler(): "
- "takes no keyword args");
- return NULL;
- }
-
- if (!PyArg_ParseTuple(args, "|Os:mathutils.Euler", &seq, &order_str)) {
- return NULL;
- }
-
- switch (PyTuple_GET_SIZE(args)) {
- case 0:
- break;
- case 2:
- if ((order = euler_order_from_string(order_str, "mathutils.Euler()")) == -1) {
- return NULL;
- }
- ATTR_FALLTHROUGH;
- case 1:
- if (mathutils_array_parse(eul, EULER_SIZE, EULER_SIZE, seq, "mathutils.Euler()") == -1) {
- return NULL;
- }
- break;
- }
- return Euler_CreatePyObject(eul, order, type);
-}
+/* -------------------------------------------------------------------- */
+/** \name Utilities
+ * \{ */
-/* internal use, assume read callback is done */
+/** Internal use, assume read callback is done. */
static const char *euler_order_str(EulerObject *self)
{
static const char order[][4] = {"XYZ", "XZY", "YXZ", "YZX", "ZXY", "ZYX"};
@@ -96,8 +62,10 @@ short euler_order_from_string(const char *str, const char *error_prefix)
return -1;
}
-/* NOTE: BaseMath_ReadCallback must be called beforehand. */
-static PyObject *Euler_ToTupleExt(EulerObject *self, int ndigits)
+/**
+ * \note #BaseMath_ReadCallback must be called beforehand.
+ */
+static PyObject *Euler_to_tuple_ex(EulerObject *self, int ndigits)
{
PyObject *ret;
int i;
@@ -118,8 +86,53 @@ static PyObject *Euler_ToTupleExt(EulerObject *self, int ndigits)
return ret;
}
-/* -----------------------------METHODS----------------------------
- * return a quaternion representation of the euler */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Euler Type: `__new__` / `mathutils.Euler()`
+ * \{ */
+
+static PyObject *Euler_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
+{
+ PyObject *seq = NULL;
+ const char *order_str = NULL;
+
+ float eul[EULER_SIZE] = {0.0f, 0.0f, 0.0f};
+ short order = EULER_ORDER_XYZ;
+
+ if (kwds && PyDict_Size(kwds)) {
+ PyErr_SetString(PyExc_TypeError,
+ "mathutils.Euler(): "
+ "takes no keyword args");
+ return NULL;
+ }
+
+ if (!PyArg_ParseTuple(args, "|Os:mathutils.Euler", &seq, &order_str)) {
+ return NULL;
+ }
+
+ switch (PyTuple_GET_SIZE(args)) {
+ case 0:
+ break;
+ case 2:
+ if ((order = euler_order_from_string(order_str, "mathutils.Euler()")) == -1) {
+ return NULL;
+ }
+ ATTR_FALLTHROUGH;
+ case 1:
+ if (mathutils_array_parse(eul, EULER_SIZE, EULER_SIZE, seq, "mathutils.Euler()") == -1) {
+ return NULL;
+ }
+ break;
+ }
+ return Euler_CreatePyObject(eul, order, type);
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Euler Methods
+ * \{ */
PyDoc_STRVAR(Euler_to_quaternion_doc,
".. method:: to_quaternion()\n"
@@ -141,7 +154,6 @@ static PyObject *Euler_to_quaternion(EulerObject *self)
return Quaternion_CreatePyObject(quat, NULL);
}
-/* return a matrix representation of the euler */
PyDoc_STRVAR(Euler_to_matrix_doc,
".. method:: to_matrix()\n"
"\n"
@@ -279,9 +291,6 @@ static PyObject *Euler_make_compatible(EulerObject *self, PyObject *value)
Py_RETURN_NONE;
}
-/* ----------------------------Euler.rotate()-----------------------
- * return a copy of the euler */
-
PyDoc_STRVAR(Euler_copy_doc,
".. function:: copy()\n"
"\n"
@@ -308,8 +317,11 @@ static PyObject *Euler_deepcopy(EulerObject *self, PyObject *args)
return Euler_copy(self);
}
-/* ----------------------------print object (internal)--------------
- * print the object to screen */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Euler Type: `__repr__` & `__str__`
+ * \{ */
static PyObject *Euler_repr(EulerObject *self)
{
@@ -319,7 +331,7 @@ static PyObject *Euler_repr(EulerObject *self)
return NULL;
}
- tuple = Euler_ToTupleExt(self, -1);
+ tuple = Euler_to_tuple_ex(self, -1);
ret = PyUnicode_FromFormat("Euler(%R, '%s')", tuple, euler_order_str(self));
@@ -349,6 +361,12 @@ static PyObject *Euler_str(EulerObject *self)
}
#endif
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Euler Type: Rich Compare
+ * \{ */
+
static PyObject *Euler_richcmpr(PyObject *a, PyObject *b, int op)
{
PyObject *res;
@@ -390,6 +408,12 @@ static PyObject *Euler_richcmpr(PyObject *a, PyObject *b, int op)
return Py_INCREF_RET(res);
}
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Euler Type: Hash (`__hash__`)
+ * \{ */
+
static Py_hash_t Euler_hash(EulerObject *self)
{
if (BaseMath_ReadCallback(self) == -1) {
@@ -403,15 +427,19 @@ static Py_hash_t Euler_hash(EulerObject *self)
return mathutils_array_hash(self->eul, EULER_SIZE);
}
-/* ---------------------SEQUENCE PROTOCOLS------------------------ */
-/* ----------------------------len(object)------------------------ */
-/* sequence length */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Euler Type: Sequence Protocol
+ * \{ */
+
+/** Sequence length: `len(object)`. */
static int Euler_len(EulerObject *UNUSED(self))
{
return EULER_SIZE;
}
-/* ----------------------------object[]--------------------------- */
-/* sequence accessor (get) */
+
+/** Sequence accessor (get): `x = object[i]`. */
static PyObject *Euler_item(EulerObject *self, int i)
{
if (i < 0) {
@@ -431,8 +459,8 @@ static PyObject *Euler_item(EulerObject *self, int i)
return PyFloat_FromDouble(self->eul[i]);
}
-/* ----------------------------object[]------------------------- */
-/* sequence accessor (set) */
+
+/** Sequence accessor (set): `object[i] = x`. */
static int Euler_ass_item(EulerObject *self, int i, PyObject *value)
{
float f;
@@ -468,8 +496,8 @@ static int Euler_ass_item(EulerObject *self, int i, PyObject *value)
return 0;
}
-/* ----------------------------object[z:y]------------------------ */
-/* sequence slice (get) */
+
+/** Sequence slice accessor (get): `x = object[i:j]`. */
static PyObject *Euler_slice(EulerObject *self, int begin, int end)
{
PyObject *tuple;
@@ -493,8 +521,8 @@ static PyObject *Euler_slice(EulerObject *self, int begin, int end)
return tuple;
}
-/* ----------------------------object[z:y]------------------------ */
-/* sequence slice (set) */
+
+/** Sequence slice accessor (set): `object[i:j] = x`. */
static int Euler_ass_slice(EulerObject *self, int begin, int end, PyObject *seq)
{
int i, size;
@@ -531,6 +559,7 @@ static int Euler_ass_slice(EulerObject *self, int begin, int end, PyObject *seq)
return 0;
}
+/** Sequence generic subscript (get): `x = object[...]`. */
static PyObject *Euler_subscript(EulerObject *self, PyObject *item)
{
if (PyIndex_Check(item)) {
@@ -567,6 +596,7 @@ static PyObject *Euler_subscript(EulerObject *self, PyObject *item)
return NULL;
}
+/** Sequence generic subscript (set): `object[...] = x`. */
static int Euler_ass_subscript(EulerObject *self, PyObject *item, PyObject *value)
{
if (PyIndex_Check(item)) {
@@ -599,18 +629,23 @@ static int Euler_ass_subscript(EulerObject *self, PyObject *item, PyObject *valu
return -1;
}
-/* -----------------PROTCOL DECLARATIONS-------------------------- */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Euler Type: Sequence & Mapping Protocol Declarations
+ * \{ */
+
static PySequenceMethods Euler_SeqMethods = {
- (lenfunc)Euler_len, /* sq_length */
- (binaryfunc)NULL, /* sq_concat */
- (ssizeargfunc)NULL, /* sq_repeat */
- (ssizeargfunc)Euler_item, /* sq_item */
- (ssizessizeargfunc)NULL, /* sq_slice (deprecated) */
- (ssizeobjargproc)Euler_ass_item, /* sq_ass_item */
- (ssizessizeobjargproc)NULL, /* sq_ass_slice (deprecated) */
- (objobjproc)NULL, /* sq_contains */
- (binaryfunc)NULL, /* sq_inplace_concat */
- (ssizeargfunc)NULL, /* sq_inplace_repeat */
+ (lenfunc)Euler_len, /*sq_length*/
+ (binaryfunc)NULL, /*sq_concat*/
+ (ssizeargfunc)NULL, /*sq_repeat*/
+ (ssizeargfunc)Euler_item, /*sq_item*/
+ (ssizessizeargfunc)NULL, /*sq_slice(DEPRECATED)*/
+ (ssizeobjargproc)Euler_ass_item, /*sq_ass_item*/
+ (ssizessizeobjargproc)NULL, /*sq_ass_slice(DEPRECATED)*/
+ (objobjproc)NULL, /*sq_contains*/
+ (binaryfunc)NULL, /*sq_inplace_concat*/
+ (ssizeargfunc)NULL, /*sq_inplace_repeat*/
};
static PyMappingMethods Euler_AsMapping = {
@@ -619,7 +654,13 @@ static PyMappingMethods Euler_AsMapping = {
(objobjargproc)Euler_ass_subscript,
};
-/* euler axis, euler.x/y/z */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Euler Type: Get/Set Item Implementation
+ * \{ */
+
+/* Euler axis: `euler.x/y/z`. */
PyDoc_STRVAR(Euler_axis_doc, "Euler axis angle in radians.\n\n:type: float");
static PyObject *Euler_axis_get(EulerObject *self, void *type)
@@ -632,7 +673,7 @@ static int Euler_axis_set(EulerObject *self, PyObject *value, void *type)
return Euler_ass_item(self, POINTER_AS_INT(type), value);
}
-/* rotation order */
+/* Euler rotation order: `euler.order`. */
PyDoc_STRVAR(
Euler_order_doc,
@@ -666,9 +707,12 @@ static int Euler_order_set(EulerObject *self, PyObject *value, void *UNUSED(clos
return 0;
}
-/*****************************************************************************/
-/* Python attributes get/set structure: */
-/*****************************************************************************/
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Euler Type: Get/Set Item Definitions
+ * \{ */
+
static PyGetSetDef Euler_getseters[] = {
{"x", (getter)Euler_axis_get, (setter)Euler_axis_set, Euler_axis_doc, (void *)0},
{"y", (getter)Euler_axis_get, (setter)Euler_axis_set, Euler_axis_doc, (void *)1},
@@ -694,7 +738,12 @@ static PyGetSetDef Euler_getseters[] = {
{NULL, NULL, NULL, NULL, NULL} /* Sentinel */
};
-/* -----------------------METHOD DEFINITIONS ---------------------- */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Euler Type: Method Definitions
+ * \{ */
+
static struct PyMethodDef Euler_methods[] = {
{"zero", (PyCFunction)Euler_zero, METH_NOARGS, Euler_zero_doc},
{"to_matrix", (PyCFunction)Euler_to_matrix, METH_NOARGS, Euler_to_matrix_doc},
@@ -711,7 +760,12 @@ static struct PyMethodDef Euler_methods[] = {
{NULL, NULL, 0, NULL},
};
-/* ------------------PY_OBECT DEFINITION-------------------------- */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Euler Type: Python Object Definition
+ * \{ */
+
PyDoc_STRVAR(
euler_doc,
".. class:: Euler(angles, order='XYZ')\n"
@@ -776,6 +830,12 @@ PyTypeObject euler_Type = {
NULL, /* tp_del */
};
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Euler Type: C/API Constructors
+ * \{ */
+
PyObject *Euler_CreatePyObject(const float eul[3], const short order, PyTypeObject *base_type)
{
EulerObject *self;
@@ -849,3 +909,5 @@ PyObject *Euler_CreatePyObject_cb(PyObject *cb_user,
return (PyObject *)self;
}
+
+/** \} */
diff --git a/source/blender/python/mathutils/mathutils_Euler.h b/source/blender/python/mathutils/mathutils_Euler.h
index 4438ee380af..ca2ca26c90a 100644
--- a/source/blender/python/mathutils/mathutils_Euler.h
+++ b/source/blender/python/mathutils/mathutils_Euler.h
@@ -22,6 +22,7 @@ typedef struct {
* blender (stored in blend_data). This is an either/or struct not both */
/* prototypes */
+
PyObject *Euler_CreatePyObject(const float eul[3],
short order,
PyTypeObject *base_type) ATTR_WARN_UNUSED_RESULT;
diff --git a/source/blender/python/mathutils/mathutils_Matrix.c b/source/blender/python/mathutils/mathutils_Matrix.c
index 76b5424711f..8cd7a5c7d87 100644
--- a/source/blender/python/mathutils/mathutils_Matrix.c
+++ b/source/blender/python/mathutils/mathutils_Matrix.c
@@ -32,6 +32,10 @@ static PyObject *matrix__apply_to_copy(PyObject *(*matrix_func)(MatrixObject *),
MatrixObject *self);
static PyObject *MatrixAccess_CreatePyObject(MatrixObject *matrix, const eMatrixAccess_t type);
+/* -------------------------------------------------------------------- */
+/** \name Utilities
+ * \{ */
+
static int matrix_row_vector_check(MatrixObject *mat, VectorObject *vec, int row)
{
if ((vec->vec_num != mat->col_num) || (row >= mat->row_num)) {
@@ -56,9 +60,242 @@ static int matrix_col_vector_check(MatrixObject *mat, VectorObject *vec, int col
return 1;
}
-/* ----------------------------------------------------------------------------
- * matrix row callbacks
- * this is so you can do matrix[i][j] = val OR matrix.row[i][j] = val */
+/** When a matrix is 4x4 size but initialized as a 3x3, re-assign values for 4x4. */
+static void matrix_3x3_as_4x4(float mat[16])
+{
+ mat[10] = mat[8];
+ mat[9] = mat[7];
+ mat[8] = mat[6];
+ mat[7] = 0.0f;
+ mat[6] = mat[5];
+ mat[5] = mat[4];
+ mat[4] = mat[3];
+ mat[3] = 0.0f;
+}
+
+void matrix_as_3x3(float mat[3][3], MatrixObject *self)
+{
+ copy_v3_v3(mat[0], MATRIX_COL_PTR(self, 0));
+ copy_v3_v3(mat[1], MATRIX_COL_PTR(self, 1));
+ copy_v3_v3(mat[2], MATRIX_COL_PTR(self, 2));
+}
+
+static void matrix_copy(MatrixObject *mat_dst, const MatrixObject *mat_src)
+{
+ BLI_assert((mat_dst->col_num == mat_src->col_num) && (mat_dst->row_num == mat_src->row_num));
+ BLI_assert(mat_dst != mat_src);
+
+ memcpy(mat_dst->matrix, mat_src->matrix, sizeof(float) * (mat_dst->col_num * mat_dst->row_num));
+}
+
+static void matrix_unit_internal(MatrixObject *self)
+{
+ const int mat_size = sizeof(float) * (self->col_num * self->row_num);
+ memset(self->matrix, 0x0, mat_size);
+ const int col_row_max = min_ii(self->col_num, self->row_num);
+ const int row_num = self->row_num;
+ for (int col = 0; col < col_row_max; col++) {
+ self->matrix[(col * row_num) + col] = 1.0f;
+ }
+}
+
+/** Transposes memory layout, row/columns don't have to match. */
+static void matrix_transpose_internal(float mat_dst_fl[], const MatrixObject *mat_src)
+{
+ ushort col, row;
+ uint i = 0;
+
+ for (row = 0; row < mat_src->row_num; row++) {
+ for (col = 0; col < mat_src->col_num; col++) {
+ mat_dst_fl[i++] = MATRIX_ITEM(mat_src, row, col);
+ }
+ }
+}
+
+/** Assumes `rowsize == colsize` is checked and the read callback has run. */
+static float matrix_determinant_internal(const MatrixObject *self)
+{
+ if (self->col_num == 2) {
+ return determinant_m2(MATRIX_ITEM(self, 0, 0),
+ MATRIX_ITEM(self, 0, 1),
+ MATRIX_ITEM(self, 1, 0),
+ MATRIX_ITEM(self, 1, 1));
+ }
+ if (self->col_num == 3) {
+ return determinant_m3(MATRIX_ITEM(self, 0, 0),
+ MATRIX_ITEM(self, 0, 1),
+ MATRIX_ITEM(self, 0, 2),
+ MATRIX_ITEM(self, 1, 0),
+ MATRIX_ITEM(self, 1, 1),
+ MATRIX_ITEM(self, 1, 2),
+ MATRIX_ITEM(self, 2, 0),
+ MATRIX_ITEM(self, 2, 1),
+ MATRIX_ITEM(self, 2, 2));
+ }
+
+ return determinant_m4((const float(*)[4])self->matrix);
+}
+
+static void adjoint_matrix_n(float *mat_dst, const float *mat_src, const ushort dim)
+{
+ /* calculate the classical adjoint */
+ switch (dim) {
+ case 2: {
+ adjoint_m2_m2((float(*)[2])mat_dst, (const float(*)[2])mat_src);
+ break;
+ }
+ case 3: {
+ adjoint_m3_m3((float(*)[3])mat_dst, (const float(*)[3])mat_src);
+ break;
+ }
+ case 4: {
+ adjoint_m4_m4((float(*)[4])mat_dst, (const float(*)[4])mat_src);
+ break;
+ }
+ default:
+ BLI_assert_unreachable();
+ break;
+ }
+}
+
+static void matrix_invert_with_det_n_internal(float *mat_dst,
+ const float *mat_src,
+ const float det,
+ const ushort dim)
+{
+ float mat[MATRIX_MAX_DIM * MATRIX_MAX_DIM];
+ ushort i, j, k;
+
+ BLI_assert(det != 0.0f);
+
+ adjoint_matrix_n(mat, mat_src, dim);
+
+ /* divide by determinant & set values */
+ k = 0;
+ for (i = 0; i < dim; i++) { /* col_num */
+ for (j = 0; j < dim; j++) { /* row_num */
+ mat_dst[MATRIX_ITEM_INDEX_NUMROW(dim, j, i)] = mat[k++] / det;
+ }
+ }
+}
+
+/**
+ * \param r_mat: can be from `self->matrix` or not.
+ */
+static bool matrix_invert_internal(const MatrixObject *self, float *r_mat)
+{
+ float det;
+ BLI_assert(self->col_num == self->row_num);
+ det = matrix_determinant_internal(self);
+
+ if (det != 0.0f) {
+ matrix_invert_with_det_n_internal(r_mat, self->matrix, det, self->col_num);
+ return true;
+ }
+
+ return false;
+}
+
+/**
+ * Similar to `matrix_invert_internal` but should never error.
+ * \param r_mat: can be from `self->matrix` or not.
+ */
+static void matrix_invert_safe_internal(const MatrixObject *self, float *r_mat)
+{
+ float det;
+ float *in_mat = self->matrix;
+ BLI_assert(self->col_num == self->row_num);
+ det = matrix_determinant_internal(self);
+
+ if (det == 0.0f) {
+ const float eps = PSEUDOINVERSE_EPSILON;
+
+ /* We will copy self->matrix into r_mat (if needed),
+ * and modify it in place to add diagonal epsilon. */
+ in_mat = r_mat;
+
+ switch (self->col_num) {
+ case 2: {
+ float(*mat)[2] = (float(*)[2])in_mat;
+
+ if (in_mat != self->matrix) {
+ copy_m2_m2(mat, (const float(*)[2])self->matrix);
+ }
+ mat[0][0] += eps;
+ mat[1][1] += eps;
+
+ if (UNLIKELY((det = determinant_m2(mat[0][0], mat[0][1], mat[1][0], mat[1][1])) == 0.0f)) {
+ unit_m2(mat);
+ det = 1.0f;
+ }
+ break;
+ }
+ case 3: {
+ float(*mat)[3] = (float(*)[3])in_mat;
+
+ if (in_mat != self->matrix) {
+ copy_m3_m3(mat, (const float(*)[3])self->matrix);
+ }
+ mat[0][0] += eps;
+ mat[1][1] += eps;
+ mat[2][2] += eps;
+
+ if (UNLIKELY((det = determinant_m3_array(mat)) == 0.0f)) {
+ unit_m3(mat);
+ det = 1.0f;
+ }
+ break;
+ }
+ case 4: {
+ float(*mat)[4] = (float(*)[4])in_mat;
+
+ if (in_mat != self->matrix) {
+ copy_m4_m4(mat, (const float(*)[4])self->matrix);
+ }
+ mat[0][0] += eps;
+ mat[1][1] += eps;
+ mat[2][2] += eps;
+ mat[3][3] += eps;
+
+ if (UNLIKELY(det = determinant_m4(mat)) == 0.0f) {
+ unit_m4(mat);
+ det = 1.0f;
+ }
+ break;
+ }
+ default:
+ BLI_assert_unreachable();
+ }
+ }
+
+ matrix_invert_with_det_n_internal(r_mat, in_mat, det, self->col_num);
+}
+
+static PyObject *matrix__apply_to_copy(PyObject *(*matrix_func)(MatrixObject *),
+ MatrixObject *self)
+{
+ PyObject *ret = Matrix_copy(self);
+ if (ret) {
+ PyObject *ret_dummy = matrix_func((MatrixObject *)ret);
+ if (ret_dummy) {
+ Py_DECREF(ret_dummy);
+ return ret;
+ }
+ /* error */
+ Py_DECREF(ret);
+ return NULL;
+ }
+
+ /* copy may fail if the read callback errors out */
+ return NULL;
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Matrix Row Callbacks
+ * This is so you can do `matrix[i][j] = val` or `matrix.row[i][j] = val`.
+ * \{ */
uchar mathutils_matrix_row_cb_index = -1;
@@ -147,9 +384,12 @@ Mathutils_Callback mathutils_matrix_row_cb = {
mathutils_matrix_row_set_index,
};
-/* ----------------------------------------------------------------------------
- * matrix row callbacks
- * this is so you can do matrix.col[i][j] = val */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Matrix Column Callbacks
+ * This is so you can do `matrix.col[i][j] = val`.
+ * \{ */
uchar mathutils_matrix_col_cb_index = -1;
@@ -246,10 +486,14 @@ Mathutils_Callback mathutils_matrix_col_cb = {
mathutils_matrix_col_set_index,
};
-/* ----------------------------------------------------------------------------
- * matrix row callbacks
- * this is so you can do matrix.translation = val
- * NOTE: this is _exactly like matrix.col except the 4th component is always omitted. */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Matrix Translation Callbacks
+ * This is so you can do `matrix.translation = val`.
+ *
+ * \note this is _exactly like matrix.col except the 4th component is always omitted.
+ * \{ */
uchar mathutils_matrix_translation_cb_index = -1;
@@ -326,11 +570,12 @@ Mathutils_Callback mathutils_matrix_translation_cb = {
mathutils_matrix_translation_set_index,
};
-/* matrix column callbacks, this is so you can do `matrix.translation = Vector()`. */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Matrix Type: `__new__` / `mathutils.Matrix()`
+ * \{ */
-/* ----------------------------------mathutils.Matrix() ----------------- */
-/* mat is a 1D array of floats - row[0][0], row[0][1], row[1][0], etc. */
-/* create a new matrix type */
static PyObject *Matrix_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
{
if (kwds && PyDict_Size(kwds)) {
@@ -379,41 +624,13 @@ static PyObject *Matrix_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
return NULL;
}
-static PyObject *matrix__apply_to_copy(PyObject *(*matrix_func)(MatrixObject *),
- MatrixObject *self)
-{
- PyObject *ret = Matrix_copy(self);
- if (ret) {
- PyObject *ret_dummy = matrix_func((MatrixObject *)ret);
- if (ret_dummy) {
- Py_DECREF(ret_dummy);
- return ret;
- }
- /* error */
- Py_DECREF(ret);
- return NULL;
- }
-
- /* copy may fail if the read callback errors out */
- return NULL;
-}
-
-/* when a matrix is 4x4 size but initialized as a 3x3, re-assign values for 4x4 */
-static void matrix_3x3_as_4x4(float mat[16])
-{
- mat[10] = mat[8];
- mat[9] = mat[7];
- mat[8] = mat[6];
- mat[7] = 0.0f;
- mat[6] = mat[5];
- mat[5] = mat[4];
- mat[4] = mat[3];
- mat[3] = 0.0f;
-}
+/** \} */
-/*-----------------------CLASS-METHODS----------------------------*/
+/* -------------------------------------------------------------------- */
+/** \name Matrix Class Methods
+ * \{ */
-/* mat is a 1D array of floats - row[0][0], row[0][1], row[1][0], etc. */
+/** Identity constructor: `mathutils.Matrix.Identity()`. */
PyDoc_STRVAR(C_Matrix_Identity_doc,
".. classmethod:: Identity(size)\n"
"\n"
@@ -441,6 +658,7 @@ static PyObject *C_Matrix_Identity(PyObject *cls, PyObject *args)
return Matrix_CreatePyObject(NULL, matSize, matSize, (PyTypeObject *)cls);
}
+/** Rotation constructor: `mathutils.Matrix.Rotation()`. */
PyDoc_STRVAR(C_Matrix_Rotation_doc,
".. classmethod:: Rotation(angle, size, axis)\n"
"\n"
@@ -460,25 +678,8 @@ static PyObject *C_Matrix_Rotation(PyObject *cls, PyObject *args)
PyObject *vec = NULL;
const char *axis = NULL;
int matSize;
- double angle; /* use double because of precision problems at high values */
- float mat[16] = {
- 0.0f,
- 0.0f,
- 0.0f,
- 0.0f,
- 0.0f,
- 0.0f,
- 0.0f,
- 0.0f,
- 0.0f,
- 0.0f,
- 0.0f,
- 0.0f,
- 0.0f,
- 0.0f,
- 0.0f,
- 1.0f,
- };
+ double angle; /* Use double because of precision problems at high values. */
+ float mat[16] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1};
if (!PyArg_ParseTuple(args, "di|O:Matrix.Rotation", &angle, &matSize, &vec)) {
return NULL;
@@ -545,6 +746,7 @@ static PyObject *C_Matrix_Rotation(PyObject *cls, PyObject *args)
return Matrix_CreatePyObject(mat, matSize, matSize, (PyTypeObject *)cls);
}
+/** Translation constructor: `mathutils.Matrix.Translation()`. */
PyDoc_STRVAR(C_Matrix_Translation_doc,
".. classmethod:: Translation(vector)\n"
"\n"
@@ -567,7 +769,7 @@ static PyObject *C_Matrix_Translation(PyObject *cls, PyObject *value)
return Matrix_CreatePyObject(&mat[0][0], 4, 4, (PyTypeObject *)cls);
}
-/* ----------------------------------mathutils.Matrix.Diagonal() ------------- */
+
PyDoc_STRVAR(C_Matrix_Diagonal_doc,
".. classmethod:: Diagonal(vector)\n"
"\n"
@@ -577,6 +779,7 @@ PyDoc_STRVAR(C_Matrix_Diagonal_doc,
" :type vector: :class:`Vector`\n"
" :return: A diagonal matrix.\n"
" :rtype: :class:`Matrix`\n");
+/** Diagonal constructor: `mathutils.Matrix.Diagonal()`. */
static PyObject *C_Matrix_Diagonal(PyObject *cls, PyObject *value)
{
float mat[16] = {0.0f};
@@ -595,8 +798,8 @@ static PyObject *C_Matrix_Diagonal(PyObject *cls, PyObject *value)
return Matrix_CreatePyObject(mat, size, size, (PyTypeObject *)cls);
}
-/* ----------------------------------mathutils.Matrix.Scale() ------------- */
-/* mat is a 1D array of floats - row[0][0], row[0][1], row[1][0], etc. */
+
+/** Scale constructor: `mathutils.Matrix.Scale()`. */
PyDoc_STRVAR(C_Matrix_Scale_doc,
".. classmethod:: Scale(factor, size, axis)\n"
"\n"
@@ -617,24 +820,7 @@ static PyObject *C_Matrix_Scale(PyObject *cls, PyObject *args)
float tvec[3];
float factor;
int matSize;
- float mat[16] = {
- 0.0f,
- 0.0f,
- 0.0f,
- 0.0f,
- 0.0f,
- 0.0f,
- 0.0f,
- 0.0f,
- 0.0f,
- 0.0f,
- 0.0f,
- 0.0f,
- 0.0f,
- 0.0f,
- 0.0f,
- 1.0f,
- };
+ float mat[16] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1};
if (!PyArg_ParseTuple(args, "fi|O:Matrix.Scale", &factor, &matSize, &vec)) {
return NULL;
@@ -700,8 +886,7 @@ static PyObject *C_Matrix_Scale(PyObject *cls, PyObject *args)
/* pass to matrix creation */
return Matrix_CreatePyObject(mat, matSize, matSize, (PyTypeObject *)cls);
}
-/* ----------------------------------mathutils.Matrix.OrthoProjection() --- */
-/* mat is a 1D array of floats - row[0][0], row[0][1], row[1][0], etc. */
+/** Orthographic projection constructor: `mathutils.Matrix.OrthoProjection()`. */
PyDoc_STRVAR(C_Matrix_OrthoProjection_doc,
".. classmethod:: OrthoProjection(axis, size)\n"
"\n"
@@ -721,24 +906,7 @@ static PyObject *C_Matrix_OrthoProjection(PyObject *cls, PyObject *args)
int matSize, x;
float norm = 0.0f;
- float mat[16] = {
- 0.0f,
- 0.0f,
- 0.0f,
- 0.0f,
- 0.0f,
- 0.0f,
- 0.0f,
- 0.0f,
- 0.0f,
- 0.0f,
- 0.0f,
- 0.0f,
- 0.0f,
- 0.0f,
- 0.0f,
- 1.0f,
- };
+ float mat[16] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1};
if (!PyArg_ParseTuple(args, "Oi:Matrix.OrthoProjection", &axis, &matSize)) {
return NULL;
@@ -837,6 +1005,7 @@ static PyObject *C_Matrix_OrthoProjection(PyObject *cls, PyObject *args)
return Matrix_CreatePyObject(mat, matSize, matSize, (PyTypeObject *)cls);
}
+/** Shear constructor: `mathutils.Matrix.Shear()`. */
PyDoc_STRVAR(C_Matrix_Shear_doc,
".. classmethod:: Shear(plane, size, factor)\n"
"\n"
@@ -857,24 +1026,7 @@ static PyObject *C_Matrix_Shear(PyObject *cls, PyObject *args)
int matSize;
const char *plane;
PyObject *fac;
- float mat[16] = {
- 0.0f,
- 0.0f,
- 0.0f,
- 0.0f,
- 0.0f,
- 0.0f,
- 0.0f,
- 0.0f,
- 0.0f,
- 0.0f,
- 0.0f,
- 0.0f,
- 0.0f,
- 0.0f,
- 0.0f,
- 1.0f,
- };
+ float mat[16] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1};
if (!PyArg_ParseTuple(args, "siO:Matrix.Shear", &plane, &matSize, &fac)) {
return NULL;
@@ -1051,205 +1203,12 @@ static PyObject *C_Matrix_LocRotScale(PyObject *cls, PyObject *args)
return Matrix_CreatePyObject(&mat[0][0], 4, 4, (PyTypeObject *)cls);
}
-void matrix_as_3x3(float mat[3][3], MatrixObject *self)
-{
- copy_v3_v3(mat[0], MATRIX_COL_PTR(self, 0));
- copy_v3_v3(mat[1], MATRIX_COL_PTR(self, 1));
- copy_v3_v3(mat[2], MATRIX_COL_PTR(self, 2));
-}
-
-static void matrix_copy(MatrixObject *mat_dst, const MatrixObject *mat_src)
-{
- BLI_assert((mat_dst->col_num == mat_src->col_num) && (mat_dst->row_num == mat_src->row_num));
- BLI_assert(mat_dst != mat_src);
+/** \} */
- memcpy(mat_dst->matrix, mat_src->matrix, sizeof(float) * (mat_dst->col_num * mat_dst->row_num));
-}
+/* -------------------------------------------------------------------- */
+/** \name Matrix Methods: To Quaternion
+ * \{ */
-static void matrix_unit_internal(MatrixObject *self)
-{
- const int mat_size = sizeof(float) * (self->col_num * self->row_num);
- memset(self->matrix, 0x0, mat_size);
- const int col_row_max = min_ii(self->col_num, self->row_num);
- const int row_num = self->row_num;
- for (int col = 0; col < col_row_max; col++) {
- self->matrix[(col * row_num) + col] = 1.0f;
- }
-}
-
-/* transposes memory layout, rol/col's don't have to match */
-static void matrix_transpose_internal(float mat_dst_fl[], const MatrixObject *mat_src)
-{
- ushort col, row;
- uint i = 0;
-
- for (row = 0; row < mat_src->row_num; row++) {
- for (col = 0; col < mat_src->col_num; col++) {
- mat_dst_fl[i++] = MATRIX_ITEM(mat_src, row, col);
- }
- }
-}
-
-/* assumes rowsize == colsize is checked and the read callback has run */
-static float matrix_determinant_internal(const MatrixObject *self)
-{
- if (self->col_num == 2) {
- return determinant_m2(MATRIX_ITEM(self, 0, 0),
- MATRIX_ITEM(self, 0, 1),
- MATRIX_ITEM(self, 1, 0),
- MATRIX_ITEM(self, 1, 1));
- }
- if (self->col_num == 3) {
- return determinant_m3(MATRIX_ITEM(self, 0, 0),
- MATRIX_ITEM(self, 0, 1),
- MATRIX_ITEM(self, 0, 2),
- MATRIX_ITEM(self, 1, 0),
- MATRIX_ITEM(self, 1, 1),
- MATRIX_ITEM(self, 1, 2),
- MATRIX_ITEM(self, 2, 0),
- MATRIX_ITEM(self, 2, 1),
- MATRIX_ITEM(self, 2, 2));
- }
-
- return determinant_m4((const float(*)[4])self->matrix);
-}
-
-static void adjoint_matrix_n(float *mat_dst, const float *mat_src, const ushort dim)
-{
- /* calculate the classical adjoint */
- switch (dim) {
- case 2: {
- adjoint_m2_m2((float(*)[2])mat_dst, (const float(*)[2])mat_src);
- break;
- }
- case 3: {
- adjoint_m3_m3((float(*)[3])mat_dst, (const float(*)[3])mat_src);
- break;
- }
- case 4: {
- adjoint_m4_m4((float(*)[4])mat_dst, (const float(*)[4])mat_src);
- break;
- }
- default:
- BLI_assert_unreachable();
- break;
- }
-}
-
-static void matrix_invert_with_det_n_internal(float *mat_dst,
- const float *mat_src,
- const float det,
- const ushort dim)
-{
- float mat[MATRIX_MAX_DIM * MATRIX_MAX_DIM];
- ushort i, j, k;
-
- BLI_assert(det != 0.0f);
-
- adjoint_matrix_n(mat, mat_src, dim);
-
- /* divide by determinant & set values */
- k = 0;
- for (i = 0; i < dim; i++) { /* col_num */
- for (j = 0; j < dim; j++) { /* row_num */
- mat_dst[MATRIX_ITEM_INDEX_NUMROW(dim, j, i)] = mat[k++] / det;
- }
- }
-}
-
-/**
- * \param r_mat: can be from `self->matrix` or not.
- */
-static bool matrix_invert_internal(const MatrixObject *self, float *r_mat)
-{
- float det;
- BLI_assert(self->col_num == self->row_num);
- det = matrix_determinant_internal(self);
-
- if (det != 0.0f) {
- matrix_invert_with_det_n_internal(r_mat, self->matrix, det, self->col_num);
- return true;
- }
-
- return false;
-}
-
-/**
- * Similar to `matrix_invert_internal` but should never error.
- * \param r_mat: can be from `self->matrix` or not.
- */
-static void matrix_invert_safe_internal(const MatrixObject *self, float *r_mat)
-{
- float det;
- float *in_mat = self->matrix;
- BLI_assert(self->col_num == self->row_num);
- det = matrix_determinant_internal(self);
-
- if (det == 0.0f) {
- const float eps = PSEUDOINVERSE_EPSILON;
-
- /* We will copy self->matrix into r_mat (if needed),
- * and modify it in place to add diagonal epsilon. */
- in_mat = r_mat;
-
- switch (self->col_num) {
- case 2: {
- float(*mat)[2] = (float(*)[2])in_mat;
-
- if (in_mat != self->matrix) {
- copy_m2_m2(mat, (const float(*)[2])self->matrix);
- }
- mat[0][0] += eps;
- mat[1][1] += eps;
-
- if (UNLIKELY((det = determinant_m2(mat[0][0], mat[0][1], mat[1][0], mat[1][1])) == 0.0f)) {
- unit_m2(mat);
- det = 1.0f;
- }
- break;
- }
- case 3: {
- float(*mat)[3] = (float(*)[3])in_mat;
-
- if (in_mat != self->matrix) {
- copy_m3_m3(mat, (const float(*)[3])self->matrix);
- }
- mat[0][0] += eps;
- mat[1][1] += eps;
- mat[2][2] += eps;
-
- if (UNLIKELY((det = determinant_m3_array(mat)) == 0.0f)) {
- unit_m3(mat);
- det = 1.0f;
- }
- break;
- }
- case 4: {
- float(*mat)[4] = (float(*)[4])in_mat;
-
- if (in_mat != self->matrix) {
- copy_m4_m4(mat, (const float(*)[4])self->matrix);
- }
- mat[0][0] += eps;
- mat[1][1] += eps;
- mat[2][2] += eps;
- mat[3][3] += eps;
-
- if (UNLIKELY(det = determinant_m4(mat)) == 0.0f) {
- unit_m4(mat);
- det = 1.0f;
- }
- break;
- }
- default:
- BLI_assert_unreachable();
- }
- }
-
- matrix_invert_with_det_n_internal(r_mat, in_mat, det, self->col_num);
-}
-
-/*-----------------------------METHODS----------------------------*/
PyDoc_STRVAR(Matrix_to_quaternion_doc,
".. method:: to_quaternion()\n"
"\n"
@@ -1282,7 +1241,12 @@ static PyObject *Matrix_to_quaternion(MatrixObject *self)
return Quaternion_CreatePyObject(quat, NULL);
}
-/*---------------------------matrix.toEuler() --------------------*/
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Matrix Methods: To Euler
+ * \{ */
+
PyDoc_STRVAR(Matrix_to_euler_doc,
".. method:: to_euler(order, euler_compat)\n"
"\n"
@@ -1367,6 +1331,12 @@ static PyObject *Matrix_to_euler(MatrixObject *self, PyObject *args)
return Euler_CreatePyObject(eul, order, NULL);
}
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Matrix Methods: Resize
+ * \{ */
+
PyDoc_STRVAR(Matrix_resize_4x4_doc,
".. method:: resize_4x4()\n"
"\n"
@@ -1411,6 +1381,12 @@ static PyObject *Matrix_resize_4x4(MatrixObject *self)
Py_RETURN_NONE;
}
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Matrix Methods: To NxN
+ * \{ */
+
static PyObject *Matrix_to_NxN(MatrixObject *self, const int col_num, const int row_num)
{
const int mat_size = sizeof(float) * (col_num * row_num);
@@ -1480,6 +1456,12 @@ static PyObject *Matrix_to_4x4(MatrixObject *self)
return Matrix_to_NxN(self, 4, 4);
}
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Matrix Methods: To Translation/Scale
+ * \{ */
+
PyDoc_STRVAR(Matrix_to_translation_doc,
".. method:: to_translation()\n"
"\n"
@@ -1539,9 +1521,13 @@ static PyObject *Matrix_to_scale(MatrixObject *self)
return Vector_CreatePyObject(size, 3, NULL);
}
-/*---------------------------matrix.invert() ---------------------*/
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Matrix Methods: Invert
+ * \{ */
-/* re-usable checks for invert */
+/** Re-usable checks for invert. */
static bool matrix_invert_is_compat(const MatrixObject *self)
{
if (self->col_num != self->row_num) {
@@ -1763,7 +1749,12 @@ static PyObject *Matrix_inverted_safe(MatrixObject *self)
return Matrix_copy_notest(self, mat);
}
-/*---------------------------matrix.adjugate() ---------------------*/
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Matrix Methods: Adjugate
+ * \{ */
+
PyDoc_STRVAR(
Matrix_adjugate_doc,
".. method:: adjugate()\n"
@@ -1852,7 +1843,12 @@ static PyObject *Matrix_rotate(MatrixObject *self, PyObject *value)
Py_RETURN_NONE;
}
-/*---------------------------matrix.decompose() ---------------------*/
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Matrix Methods: Decompose
+ * \{ */
+
PyDoc_STRVAR(Matrix_decompose_doc,
".. method:: decompose()\n"
"\n"
@@ -1890,6 +1886,12 @@ static PyObject *Matrix_decompose(MatrixObject *self)
return ret;
}
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Matrix Methods: Linear Interpolate (lerp)
+ * \{ */
+
PyDoc_STRVAR(Matrix_lerp_doc,
".. function:: lerp(other, factor)\n"
"\n"
@@ -1947,7 +1949,6 @@ static PyObject *Matrix_lerp(MatrixObject *self, PyObject *args)
return Matrix_CreatePyObject(mat, self->col_num, self->row_num, Py_TYPE(self));
}
-/*---------------------------matrix.determinant() ----------------*/
PyDoc_STRVAR(
Matrix_determinant_doc,
".. method:: determinant()\n"
@@ -1973,7 +1974,13 @@ static PyObject *Matrix_determinant(MatrixObject *self)
return PyFloat_FromDouble((double)matrix_determinant_internal(self));
}
-/*---------------------------matrix.transpose() ------------------*/
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Matrix Methods: Transpose
+ * \{ */
+
PyDoc_STRVAR(
Matrix_transpose_doc,
".. method:: transpose()\n"
@@ -2022,7 +2029,12 @@ static PyObject *Matrix_transposed(MatrixObject *self)
return matrix__apply_to_copy(Matrix_transpose, self);
}
-/*---------------------------matrix.normalize() ------------------*/
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Matrix Methods: Normalize
+ * \{ */
+
PyDoc_STRVAR(Matrix_normalize_doc,
".. method:: normalize()\n"
"\n"
@@ -2068,7 +2080,12 @@ static PyObject *Matrix_normalized(MatrixObject *self)
return matrix__apply_to_copy(Matrix_normalize, self);
}
-/*---------------------------matrix.zero() -----------------------*/
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Matrix Methods: Zero
+ * \{ */
+
PyDoc_STRVAR(Matrix_zero_doc,
".. method:: zero()\n"
"\n"
@@ -2089,7 +2106,13 @@ static PyObject *Matrix_zero(MatrixObject *self)
Py_RETURN_NONE;
}
-/*---------------------------matrix.identity(() ------------------*/
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Matrix Methods: Set Identity
+ * \{ */
+
static void matrix_identity_internal(MatrixObject *self)
{
BLI_assert((self->col_num == self->row_num) && (self->row_num <= 4));
@@ -2137,8 +2160,13 @@ static PyObject *Matrix_identity(MatrixObject *self)
Py_RETURN_NONE;
}
-/*---------------------------Matrix.copy() ------------------*/
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Matrix Methods: Copy
+ * \{ */
+/** Copy `Matrix.copy()` */
static PyObject *Matrix_copy_notest(MatrixObject *self, const float *matrix)
{
return Matrix_CreatePyObject((const float *)matrix, self->col_num, self->row_num, Py_TYPE(self));
@@ -2159,6 +2187,8 @@ static PyObject *Matrix_copy(MatrixObject *self)
return Matrix_copy_notest(self, self->matrix);
}
+
+/** Deep-copy `Matrix.deepcopy()` */
static PyObject *Matrix_deepcopy(MatrixObject *self, PyObject *args)
{
if (!PyC_CheckArgs_DeepCopy(args)) {
@@ -2167,8 +2197,12 @@ static PyObject *Matrix_deepcopy(MatrixObject *self, PyObject *args)
return Matrix_copy(self);
}
-/*----------------------------print object (internal)-------------*/
-/* print the object to screen */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Matrix Type: `__repr__` & `__str__`
+ * \{ */
+
static PyObject *Matrix_repr(MatrixObject *self)
{
int col, row;
@@ -2257,6 +2291,12 @@ static PyObject *Matrix_str(MatrixObject *self)
}
#endif
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Matrix Type: Rich Compare
+ * \{ */
+
static PyObject *Matrix_richcmpr(PyObject *a, PyObject *b, int op)
{
PyObject *res;
@@ -2298,6 +2338,12 @@ static PyObject *Matrix_richcmpr(PyObject *a, PyObject *b, int op)
return Py_INCREF_RET(res);
}
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Matrix Type: Hash (`__hash__`)
+ * \{ */
+
static Py_hash_t Matrix_hash(MatrixObject *self)
{
float mat[MATRIX_MAX_DIM * MATRIX_MAX_DIM];
@@ -2315,16 +2361,22 @@ static Py_hash_t Matrix_hash(MatrixObject *self)
return mathutils_array_hash(mat, self->row_num * self->col_num);
}
-/*---------------------SEQUENCE PROTOCOLS------------------------
- * ----------------------------len(object)------------------------
- * sequence length */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Matrix Type: Sequence & Mapping Protocol Implementation
+ * \{ */
+
+/** Sequence length: `len(object)`. */
static int Matrix_len(MatrixObject *self)
{
return self->row_num;
}
-/*----------------------------object[]---------------------------
- * sequence accessor (get)
- * the wrapped vector gives direct access to the matrix data */
+
+/**
+ * Sequence accessor (get): `x = object[i]`.
+ * \note the wrapped vector gives direct access to the matrix data.
+ */
static PyObject *Matrix_item_row(MatrixObject *self, int row)
{
if (BaseMath_ReadCallback_ForWrite(self) == -1) {
@@ -2340,7 +2392,10 @@ static PyObject *Matrix_item_row(MatrixObject *self, int row)
return Vector_CreatePyObject_cb(
(PyObject *)self, self->col_num, mathutils_matrix_row_cb_index, row);
}
-/* same but column access */
+/**
+ * Sequence accessor (get): `x = object.col[i]`.
+ * \note the wrapped vector gives direct access to the matrix data.
+ */
static PyObject *Matrix_item_col(MatrixObject *self, int col)
{
if (BaseMath_ReadCallback_ForWrite(self) == -1) {
@@ -2357,9 +2412,7 @@ static PyObject *Matrix_item_col(MatrixObject *self, int col)
(PyObject *)self, self->row_num, mathutils_matrix_col_cb_index, col);
}
-/*----------------------------object[]-------------------------
- * sequence accessor (set) */
-
+/** Sequence accessor (set): `object[i] = x`. */
static int Matrix_ass_item_row(MatrixObject *self, int row, PyObject *value)
{
int col;
@@ -2386,6 +2439,8 @@ static int Matrix_ass_item_row(MatrixObject *self, int row, PyObject *value)
(void)BaseMath_WriteCallback(self);
return 0;
}
+
+/** Sequence accessor (set): `object.col[i] = x`. */
static int Matrix_ass_item_col(MatrixObject *self, int col, PyObject *value)
{
int row;
@@ -2413,8 +2468,7 @@ static int Matrix_ass_item_col(MatrixObject *self, int col, PyObject *value)
return 0;
}
-/*----------------------------object[z:y]------------------------
- * Sequence slice (get). */
+/** Sequence slice accessor (get): `x = object[i:j]`. */
static PyObject *Matrix_slice(MatrixObject *self, int begin, int end)
{
@@ -2439,8 +2493,8 @@ static PyObject *Matrix_slice(MatrixObject *self, int begin, int end)
return tuple;
}
-/*----------------------------object[z:y]------------------------
- * Sequence slice (set). */
+
+/** Sequence slice accessor (set): `object[i:j] = x`. */
static int Matrix_ass_slice(MatrixObject *self, int begin, int end, PyObject *value)
{
PyObject *value_fast;
@@ -2500,8 +2554,84 @@ static int Matrix_ass_slice(MatrixObject *self, int begin, int end, PyObject *va
(void)BaseMath_WriteCallback(self);
return 0;
}
-/*------------------------NUMERIC PROTOCOLS----------------------
- *------------------------obj + obj------------------------------*/
+
+/** Sequence generic subscript (get): `x = object[...]`. */
+static PyObject *Matrix_subscript(MatrixObject *self, PyObject *item)
+{
+ if (PyIndex_Check(item)) {
+ Py_ssize_t i;
+ i = PyNumber_AsSsize_t(item, PyExc_IndexError);
+ if (i == -1 && PyErr_Occurred()) {
+ return NULL;
+ }
+ if (i < 0) {
+ i += self->row_num;
+ }
+ return Matrix_item_row(self, i);
+ }
+ if (PySlice_Check(item)) {
+ Py_ssize_t start, stop, step, slicelength;
+
+ if (PySlice_GetIndicesEx(item, self->row_num, &start, &stop, &step, &slicelength) < 0) {
+ return NULL;
+ }
+
+ if (slicelength <= 0) {
+ return PyTuple_New(0);
+ }
+ if (step == 1) {
+ return Matrix_slice(self, start, stop);
+ }
+
+ PyErr_SetString(PyExc_IndexError, "slice steps not supported with matrices");
+ return NULL;
+ }
+
+ PyErr_Format(
+ PyExc_TypeError, "matrix indices must be integers, not %.200s", Py_TYPE(item)->tp_name);
+ return NULL;
+}
+
+/** Sequence generic subscript (set): `object[...] = x`. */
+static int Matrix_ass_subscript(MatrixObject *self, PyObject *item, PyObject *value)
+{
+ if (PyIndex_Check(item)) {
+ Py_ssize_t i = PyNumber_AsSsize_t(item, PyExc_IndexError);
+ if (i == -1 && PyErr_Occurred()) {
+ return -1;
+ }
+ if (i < 0) {
+ i += self->row_num;
+ }
+ return Matrix_ass_item_row(self, i, value);
+ }
+ if (PySlice_Check(item)) {
+ Py_ssize_t start, stop, step, slicelength;
+
+ if (PySlice_GetIndicesEx(item, self->row_num, &start, &stop, &step, &slicelength) < 0) {
+ return -1;
+ }
+
+ if (step == 1) {
+ return Matrix_ass_slice(self, start, stop, value);
+ }
+
+ PyErr_SetString(PyExc_IndexError, "slice steps not supported with matrices");
+ return -1;
+ }
+
+ PyErr_Format(
+ PyExc_TypeError, "matrix indices must be integers, not %.200s", Py_TYPE(item)->tp_name);
+ return -1;
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Matrix Type: Numeric Protocol Implementation
+ * \{ */
+
+/** Addition: `object + object`. */
static PyObject *Matrix_add(PyObject *m1, PyObject *m2)
{
float mat[MATRIX_MAX_DIM * MATRIX_MAX_DIM];
@@ -2534,8 +2664,8 @@ static PyObject *Matrix_add(PyObject *m1, PyObject *m2)
return Matrix_CreatePyObject(mat, mat1->col_num, mat1->row_num, Py_TYPE(mat1));
}
-/*------------------------obj - obj------------------------------
- * subtraction */
+
+/** Subtraction: `object - object`. */
static PyObject *Matrix_sub(PyObject *m1, PyObject *m2)
{
float mat[MATRIX_MAX_DIM * MATRIX_MAX_DIM];
@@ -2568,8 +2698,8 @@ static PyObject *Matrix_sub(PyObject *m1, PyObject *m2)
return Matrix_CreatePyObject(mat, mat1->col_num, mat1->row_num, Py_TYPE(mat1));
}
-/*------------------------obj * obj------------------------------
- * element-wise multiplication */
+
+/** Multiplication (element-wise): `object * object`. */
static PyObject *matrix_mul_float(MatrixObject *mat, const float scalar)
{
float tmat[MATRIX_MAX_DIM * MATRIX_MAX_DIM];
@@ -2631,8 +2761,8 @@ static PyObject *Matrix_mul(PyObject *m1, PyObject *m2)
Py_TYPE(m2)->tp_name);
return NULL;
}
-/*------------------------obj *= obj------------------------------
- * In place element-wise multiplication */
+
+/** Multiplication in-place (element-wise): `object *= object`. */
static PyObject *Matrix_imul(PyObject *m1, PyObject *m2)
{
float scalar;
@@ -2680,8 +2810,8 @@ static PyObject *Matrix_imul(PyObject *m1, PyObject *m2)
Py_INCREF(m1);
return m1;
}
-/*------------------------obj @ obj------------------------------
- * matrix multiplication */
+
+/** Multiplication (matrix multiply): `object @ object`. */
static PyObject *Matrix_matmul(PyObject *m1, PyObject *m2)
{
int vec_num;
@@ -2756,8 +2886,8 @@ static PyObject *Matrix_matmul(PyObject *m1, PyObject *m2)
Py_TYPE(m2)->tp_name);
return NULL;
}
-/*------------------------obj @= obj------------------------------
- * In place matrix multiplication */
+
+/** Multiplication in-place (matrix multiply): `object @= object`. */
static PyObject *Matrix_imatmul(PyObject *m1, PyObject *m2)
{
MatrixObject *mat1 = NULL, *mat2 = NULL;
@@ -2816,87 +2946,24 @@ static PyObject *Matrix_imatmul(PyObject *m1, PyObject *m2)
return m1;
}
-/*-----------------PROTOCOL DECLARATIONS--------------------------*/
-static PySequenceMethods Matrix_SeqMethods = {
- (lenfunc)Matrix_len, /* sq_length */
- (binaryfunc)NULL, /* sq_concat */
- (ssizeargfunc)NULL, /* sq_repeat */
- (ssizeargfunc)Matrix_item_row, /* sq_item */
- (ssizessizeargfunc)NULL, /* sq_slice, deprecated */
- (ssizeobjargproc)Matrix_ass_item_row, /* sq_ass_item */
- (ssizessizeobjargproc)NULL, /* sq_ass_slice, deprecated */
- (objobjproc)NULL, /* sq_contains */
- (binaryfunc)NULL, /* sq_inplace_concat */
- (ssizeargfunc)NULL, /* sq_inplace_repeat */
-};
-
-static PyObject *Matrix_subscript(MatrixObject *self, PyObject *item)
-{
- if (PyIndex_Check(item)) {
- Py_ssize_t i;
- i = PyNumber_AsSsize_t(item, PyExc_IndexError);
- if (i == -1 && PyErr_Occurred()) {
- return NULL;
- }
- if (i < 0) {
- i += self->row_num;
- }
- return Matrix_item_row(self, i);
- }
- if (PySlice_Check(item)) {
- Py_ssize_t start, stop, step, slicelength;
-
- if (PySlice_GetIndicesEx(item, self->row_num, &start, &stop, &step, &slicelength) < 0) {
- return NULL;
- }
-
- if (slicelength <= 0) {
- return PyTuple_New(0);
- }
- if (step == 1) {
- return Matrix_slice(self, start, stop);
- }
-
- PyErr_SetString(PyExc_IndexError, "slice steps not supported with matrices");
- return NULL;
- }
-
- PyErr_Format(
- PyExc_TypeError, "matrix indices must be integers, not %.200s", Py_TYPE(item)->tp_name);
- return NULL;
-}
-
-static int Matrix_ass_subscript(MatrixObject *self, PyObject *item, PyObject *value)
-{
- if (PyIndex_Check(item)) {
- Py_ssize_t i = PyNumber_AsSsize_t(item, PyExc_IndexError);
- if (i == -1 && PyErr_Occurred()) {
- return -1;
- }
- if (i < 0) {
- i += self->row_num;
- }
- return Matrix_ass_item_row(self, i, value);
- }
- if (PySlice_Check(item)) {
- Py_ssize_t start, stop, step, slicelength;
+/** \} */
- if (PySlice_GetIndicesEx(item, self->row_num, &start, &stop, &step, &slicelength) < 0) {
- return -1;
- }
+/* -------------------------------------------------------------------- */
+/** \name Matrix Type: Protocol Declarations
+ * \{ */
- if (step == 1) {
- return Matrix_ass_slice(self, start, stop, value);
- }
-
- PyErr_SetString(PyExc_IndexError, "slice steps not supported with matrices");
- return -1;
- }
-
- PyErr_Format(
- PyExc_TypeError, "matrix indices must be integers, not %.200s", Py_TYPE(item)->tp_name);
- return -1;
-}
+static PySequenceMethods Matrix_SeqMethods = {
+ (lenfunc)Matrix_len, /*sq_length*/
+ (binaryfunc)NULL, /*sq_concat*/
+ (ssizeargfunc)NULL, /*sq_repeat*/
+ (ssizeargfunc)Matrix_item_row, /*sq_item*/
+ (ssizessizeargfunc)NULL, /*sq_slice(DEPRECATED)*/
+ (ssizeobjargproc)Matrix_ass_item_row, /*sq_ass_item*/
+ (ssizessizeobjargproc)NULL, /*sq_ass_slice(DEPRECATED)*/
+ (objobjproc)NULL, /*sq_contains*/
+ (binaryfunc)NULL, /*sq_inplace_concat*/
+ (ssizeargfunc)NULL, /*sq_inplace_repeat*/
+};
static PyMappingMethods Matrix_AsMapping = {
(lenfunc)Matrix_len,
@@ -2924,25 +2991,31 @@ static PyNumberMethods Matrix_NumMethods = {
NULL, /*nb_int*/
NULL, /*nb_reserved*/
NULL, /*nb_float*/
- NULL, /* nb_inplace_add */
- NULL, /* nb_inplace_subtract */
- (binaryfunc)Matrix_imul, /* nb_inplace_multiply */
- NULL, /* nb_inplace_remainder */
- NULL, /* nb_inplace_power */
- NULL, /* nb_inplace_lshift */
- NULL, /* nb_inplace_rshift */
- NULL, /* nb_inplace_and */
- NULL, /* nb_inplace_xor */
- NULL, /* nb_inplace_or */
- NULL, /* nb_floor_divide */
- NULL, /* nb_true_divide */
- NULL, /* nb_inplace_floor_divide */
- NULL, /* nb_inplace_true_divide */
- NULL, /* nb_index */
- (binaryfunc)Matrix_matmul, /* nb_matrix_multiply */
- (binaryfunc)Matrix_imatmul, /* nb_inplace_matrix_multiply */
+ NULL, /*nb_inplace_add*/
+ NULL, /*nb_inplace_subtract*/
+ (binaryfunc)Matrix_imul, /*nb_inplace_multiply*/
+ NULL, /*nb_inplace_remainder*/
+ NULL, /*nb_inplace_power*/
+ NULL, /*nb_inplace_lshift*/
+ NULL, /*nb_inplace_rshift*/
+ NULL, /*nb_inplace_and*/
+ NULL, /*nb_inplace_xor*/
+ NULL, /*nb_inplace_or*/
+ NULL, /*nb_floor_divide*/
+ NULL, /*nb_true_divide*/
+ NULL, /*nb_inplace_floor_divide*/
+ NULL, /*nb_inplace_true_divide*/
+ NULL, /*nb_index*/
+ (binaryfunc)Matrix_matmul, /*nb_matrix_multiply*/
+ (binaryfunc)Matrix_imatmul, /*nb_inplace_matrix_multiply*/
};
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Matrix Type: Get/Set Item Implementation
+ * \{ */
+
PyDoc_STRVAR(Matrix_translation_doc, "The translation component of the matrix.\n\n:type: Vector");
static PyObject *Matrix_translation_get(MatrixObject *self, void *UNUSED(closure))
{
@@ -3099,9 +3172,12 @@ static PyObject *Matrix_is_orthogonal_axis_vectors_get(MatrixObject *self, void
return NULL;
}
-/*****************************************************************************/
-/* Python attributes get/set structure: */
-/*****************************************************************************/
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Matrix Type: Get/Set Item Definitions
+ * \{ */
+
static PyGetSetDef Matrix_getseters[] = {
{"median_scale", (getter)Matrix_median_scale_get, (setter)NULL, Matrix_median_scale_doc, NULL},
{"translation",
@@ -3141,7 +3217,12 @@ static PyGetSetDef Matrix_getseters[] = {
{NULL, NULL, NULL, NULL, NULL} /* Sentinel */
};
-/*-----------------------METHOD DEFINITIONS ----------------------*/
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Matrix Type: Method Definitions
+ * \{ */
+
static struct PyMethodDef Matrix_methods[] = {
/* Derived values. */
{"determinant", (PyCFunction)Matrix_determinant, METH_NOARGS, Matrix_determinant_doc},
@@ -3205,7 +3286,12 @@ static struct PyMethodDef Matrix_methods[] = {
{NULL, NULL, 0, NULL},
};
-/*------------------PY_OBECT DEFINITION--------------------------*/
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Matrix Type: Python Object Definition
+ * \{ */
+
PyDoc_STRVAR(
matrix_doc,
".. class:: Matrix([rows])\n"
@@ -3268,6 +3354,12 @@ PyTypeObject matrix_Type = {
NULL, /*tp_del*/
};
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Matrix Type: C/API Constructors
+ * \{ */
+
PyObject *Matrix_CreatePyObject(const float *mat,
const ushort col_num,
const ushort row_num,
@@ -3380,6 +3472,12 @@ PyObject *Matrix_CreatePyObject_alloc(float *mat,
return (PyObject *)self;
}
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Matrix Type: C/API Parse Utilities
+ * \{ */
+
/**
* Use with PyArg_ParseTuple's "O&" formatting.
*/
@@ -3460,8 +3558,11 @@ int Matrix_Parse4x4(PyObject *o, void *p)
return 1;
}
-/* ----------------------------------------------------------------------------
- * special type for alternate access */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Matrix-Access Type: Struct & Internal Functions
+ * \{ */
typedef struct {
PyObject_HEAD /* Required Python macro. */
@@ -3491,7 +3592,11 @@ static void MatrixAccess_dealloc(MatrixAccessObject *self)
Py_TYPE(self)->tp_free(self);
}
-/* sequence access */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Matrix-Access Type: Sequence Protocol
+ * \{ */
static int MatrixAccess_len(MatrixAccessObject *self)
{
@@ -3609,13 +3714,13 @@ static int MatrixAccess_ass_subscript(MatrixAccessObject *self, PyObject *item,
static PyObject *MatrixAccess_iter(MatrixAccessObject *self)
{
- /* Try get values from a collection */
+ /* Try get values from a collection. */
PyObject *ret;
PyObject *iter = NULL;
ret = MatrixAccess_slice(self, 0, MATRIX_MAX_DIM);
- /* we know this is a tuple so no need to PyIter_Check
- * otherwise it could be NULL (unlikely) if conversion failed */
+ /* We know this is a tuple so no need to #PyIter_Check
+ * otherwise it could be NULL (unlikely) if conversion failed. */
if (ret) {
iter = PyObject_GetIter(ret);
Py_DECREF(ret);
@@ -3630,6 +3735,12 @@ static PyMappingMethods MatrixAccess_AsMapping = {
(objobjargproc)MatrixAccess_ass_subscript,
};
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Matrix-Access Type: Python Object Definition
+ * \{ */
+
PyTypeObject matrix_access_Type = {
PyVarObject_HEAD_INIT(NULL, 0) "MatrixAccess", /*tp_name*/
sizeof(MatrixAccessObject), /*tp_basicsize*/
@@ -3658,6 +3769,12 @@ PyTypeObject matrix_access_Type = {
(getiterfunc)MatrixAccess_iter, /* getiterfunc tp_iter; */
};
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Matrix-Access Type: C/API Constructor
+ * \{ */
+
static PyObject *MatrixAccess_CreatePyObject(MatrixObject *matrix, const eMatrixAccess_t type)
{
MatrixAccessObject *matrix_access = (MatrixAccessObject *)PyObject_GC_New(MatrixObject,
@@ -3671,5 +3788,4 @@ static PyObject *MatrixAccess_CreatePyObject(MatrixObject *matrix, const eMatrix
return (PyObject *)matrix_access;
}
-/* end special access
- * -------------------------------------------------------------------------- */
+/** \} */
diff --git a/source/blender/python/mathutils/mathutils_Matrix.h b/source/blender/python/mathutils/mathutils_Matrix.h
index bc596ce6ac8..c8c207c13f3 100644
--- a/source/blender/python/mathutils/mathutils_Matrix.h
+++ b/source/blender/python/mathutils/mathutils_Matrix.h
@@ -45,7 +45,8 @@ typedef struct {
* be stored in py_data) or be a wrapper for data allocated through
* blender (stored in blend_data). This is an either/or struct not both */
-/* prototypes */
+/* Prototypes. */
+
PyObject *Matrix_CreatePyObject(const float *mat,
ushort col_num,
ushort row_num,
@@ -70,6 +71,7 @@ PyObject *Matrix_CreatePyObject_alloc(float *mat,
PyTypeObject *base_type) ATTR_WARN_UNUSED_RESULT;
/* PyArg_ParseTuple's "O&" formatting helpers. */
+
int Matrix_ParseAny(PyObject *o, void *p);
int Matrix_Parse2x2(PyObject *o, void *p);
int Matrix_Parse3x3(PyObject *o, void *p);
diff --git a/source/blender/python/mathutils/mathutils_Quaternion.c b/source/blender/python/mathutils/mathutils_Quaternion.c
index 7b51154f0d0..6994a313237 100644
--- a/source/blender/python/mathutils/mathutils_Quaternion.c
+++ b/source/blender/python/mathutils/mathutils_Quaternion.c
@@ -26,9 +26,49 @@ static void quat__axis_angle_sanitize(float axis[3], float *angle);
static PyObject *Quaternion_copy(QuaternionObject *self);
static PyObject *Quaternion_deepcopy(QuaternionObject *self, PyObject *args);
-/* -----------------------------METHODS------------------------------ */
+/* -------------------------------------------------------------------- */
+/** \name Utilities
+ * \{ */
-/* NOTE: BaseMath_ReadCallback must be called beforehand. */
+static PyObject *quat__apply_to_copy(PyObject *(*quat_func)(QuaternionObject *),
+ QuaternionObject *self)
+{
+ PyObject *ret = Quaternion_copy(self);
+ PyObject *ret_dummy = quat_func((QuaternionObject *)ret);
+ if (ret_dummy) {
+ Py_DECREF(ret_dummy);
+ return ret;
+ }
+ /* error */
+ Py_DECREF(ret);
+ return NULL;
+}
+
+/** Axis vector suffers from precision errors, use this function to ensure. */
+static void quat__axis_angle_sanitize(float axis[3], float *angle)
+{
+ if (axis) {
+ if (is_zero_v3(axis) || !isfinite(axis[0]) || !isfinite(axis[1]) || !isfinite(axis[2])) {
+ axis[0] = 1.0f;
+ axis[1] = 0.0f;
+ axis[2] = 0.0f;
+ }
+ else if (EXPP_FloatsAreEqual(axis[0], 0.0f, 10) && EXPP_FloatsAreEqual(axis[1], 0.0f, 10) &&
+ EXPP_FloatsAreEqual(axis[2], 0.0f, 10)) {
+ axis[0] = 1.0f;
+ }
+ }
+
+ if (angle) {
+ if (!isfinite(*angle)) {
+ *angle = 0.0f;
+ }
+ }
+}
+
+/**
+ * \note #BaseMath_ReadCallback must be called beforehand.
+ */
static PyObject *Quaternion_to_tuple_ext(QuaternionObject *self, int ndigits)
{
PyObject *ret;
@@ -50,6 +90,72 @@ static PyObject *Quaternion_to_tuple_ext(QuaternionObject *self, int ndigits)
return ret;
}
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Quaternion Type: `__new__` / `mathutils.Quaternion()`
+ * \{ */
+
+static PyObject *Quaternion_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
+{
+ PyObject *seq = NULL;
+ double angle = 0.0f;
+ float quat[QUAT_SIZE];
+ unit_qt(quat);
+
+ if (kwds && PyDict_Size(kwds)) {
+ PyErr_SetString(PyExc_TypeError,
+ "mathutils.Quaternion(): "
+ "takes no keyword args");
+ return NULL;
+ }
+
+ if (!PyArg_ParseTuple(args, "|Od:mathutils.Quaternion", &seq, &angle)) {
+ return NULL;
+ }
+
+ switch (PyTuple_GET_SIZE(args)) {
+ case 0:
+ break;
+ case 1: {
+ int size;
+
+ if ((size = mathutils_array_parse(quat, 3, QUAT_SIZE, seq, "mathutils.Quaternion()")) ==
+ -1) {
+ return NULL;
+ }
+
+ if (size == 4) {
+ /* 4d: Quaternion (common case) */
+ }
+ else {
+ /* 3d: Interpret as exponential map */
+ BLI_assert(size == 3);
+ expmap_to_quat(quat, quat);
+ }
+
+ break;
+ }
+ case 2: {
+ float axis[3];
+ if (mathutils_array_parse(axis, 3, 3, seq, "mathutils.Quaternion()") == -1) {
+ return NULL;
+ }
+ angle = angle_wrap_rad(angle); /* clamp because of precision issues */
+ axis_angle_to_quat(quat, axis, angle);
+ break;
+ /* PyArg_ParseTuple assures no more than 2 */
+ }
+ }
+ return Quaternion_CreatePyObject(quat, type);
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Quaternion Methods: To Euler
+ * \{ */
+
PyDoc_STRVAR(Quaternion_to_euler_doc,
".. method:: to_euler(order, euler_compat)\n"
"\n"
@@ -114,6 +220,12 @@ static PyObject *Quaternion_to_euler(QuaternionObject *self, PyObject *args)
return Euler_CreatePyObject(eul, order, NULL);
}
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Quaternion Methods: To Matrix
+ * \{ */
+
PyDoc_STRVAR(Quaternion_to_matrix_doc,
".. method:: to_matrix()\n"
"\n"
@@ -133,6 +245,12 @@ static PyObject *Quaternion_to_matrix(QuaternionObject *self)
return Matrix_CreatePyObject(mat, 3, 3, NULL);
}
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Quaternion Methods: To Axis/Angle
+ * \{ */
+
PyDoc_STRVAR(Quaternion_to_axis_angle_doc,
".. method:: to_axis_angle()\n"
"\n"
@@ -163,6 +281,12 @@ static PyObject *Quaternion_to_axis_angle(QuaternionObject *self)
return ret;
}
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Quaternion Methods: To Swing/Twist
+ * \{ */
+
PyDoc_STRVAR(Quaternion_to_swing_twist_doc,
".. method:: to_swing_twist(axis)\n"
"\n"
@@ -207,6 +331,12 @@ static PyObject *Quaternion_to_swing_twist(QuaternionObject *self, PyObject *axi
return ret;
}
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Quaternion Methods: To Exponential Map
+ * \{ */
+
PyDoc_STRVAR(
Quaternion_to_exponential_map_doc,
".. method:: to_exponential_map()\n"
@@ -232,6 +362,12 @@ static PyObject *Quaternion_to_exponential_map(QuaternionObject *self)
return Vector_CreatePyObject(expmap, 3, NULL);
}
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Quaternion Methods: Cross Product
+ * \{ */
+
PyDoc_STRVAR(Quaternion_cross_doc,
".. method:: cross(other)\n"
"\n"
@@ -259,6 +395,12 @@ static PyObject *Quaternion_cross(QuaternionObject *self, PyObject *value)
return Quaternion_CreatePyObject(quat, Py_TYPE(self));
}
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Quaternion Methods: Dot Product
+ * \{ */
+
PyDoc_STRVAR(Quaternion_dot_doc,
".. method:: dot(other)\n"
"\n"
@@ -285,6 +427,12 @@ static PyObject *Quaternion_dot(QuaternionObject *self, PyObject *value)
return PyFloat_FromDouble(dot_qtqt(self->quat, tquat));
}
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Quaternion Methods: Rotation Difference
+ * \{ */
+
PyDoc_STRVAR(Quaternion_rotation_difference_doc,
".. function:: rotation_difference(other)\n"
"\n"
@@ -315,6 +463,12 @@ static PyObject *Quaternion_rotation_difference(QuaternionObject *self, PyObject
return Quaternion_CreatePyObject(quat, Py_TYPE(self));
}
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Quaternion Methods: Spherical Interpolation (slerp)
+ * \{ */
+
PyDoc_STRVAR(Quaternion_slerp_doc,
".. function:: slerp(other, factor)\n"
"\n"
@@ -360,6 +514,12 @@ static PyObject *Quaternion_slerp(QuaternionObject *self, PyObject *args)
return Quaternion_CreatePyObject(quat, Py_TYPE(self));
}
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Quaternion Methods: Rotate
+ * \{ */
+
PyDoc_STRVAR(Quaternion_rotate_doc,
".. method:: rotate(other)\n"
"\n"
@@ -423,9 +583,15 @@ static PyObject *Quaternion_make_compatible(QuaternionObject *self, PyObject *va
Py_RETURN_NONE;
}
-/* ----------------------------Quaternion.normalize()---------------- */
-/* Normalize the quaternion. This may change the angle as well as the
- * rotation axis, as all of (w, x, y, z) are scaled. */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Quaternion Methods: Normalize
+ *
+ * Normalize the quaternion. This may change the angle as well as the
+ * rotation axis, as all of (w, x, y, z) are scaled.
+ * \{ */
+
PyDoc_STRVAR(Quaternion_normalize_doc,
".. function:: normalize()\n"
"\n"
@@ -453,6 +619,15 @@ static PyObject *Quaternion_normalized(QuaternionObject *self)
return quat__apply_to_copy(Quaternion_normalize, self);
}
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Quaternion Methods: Invert
+ *
+ * Normalize the quaternion. This may change the angle as well as the
+ * rotation axis, as all of (w, x, y, z) are scaled.
+ * \{ */
+
PyDoc_STRVAR(Quaternion_invert_doc,
".. function:: invert()\n"
"\n"
@@ -480,6 +655,12 @@ static PyObject *Quaternion_inverted(QuaternionObject *self)
return quat__apply_to_copy(Quaternion_invert, self);
}
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Quaternion Methods: Set Identity
+ * \{ */
+
PyDoc_STRVAR(Quaternion_identity_doc,
".. function:: identity()\n"
"\n"
@@ -498,6 +679,12 @@ static PyObject *Quaternion_identity(QuaternionObject *self)
Py_RETURN_NONE;
}
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Quaternion Methods: Negate
+ * \{ */
+
PyDoc_STRVAR(Quaternion_negate_doc,
".. function:: negate()\n"
"\n"
@@ -516,6 +703,12 @@ static PyObject *Quaternion_negate(QuaternionObject *self)
Py_RETURN_NONE;
}
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Quaternion Methods: Conjugate
+ * \{ */
+
PyDoc_STRVAR(Quaternion_conjugate_doc,
".. function:: conjugate()\n"
"\n"
@@ -543,6 +736,12 @@ static PyObject *Quaternion_conjugated(QuaternionObject *self)
return quat__apply_to_copy(Quaternion_conjugate, self);
}
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Quaternion Methods: Copy/Deep-Copy
+ * \{ */
+
PyDoc_STRVAR(Quaternion_copy_doc,
".. function:: copy()\n"
"\n"
@@ -569,7 +768,12 @@ static PyObject *Quaternion_deepcopy(QuaternionObject *self, PyObject *args)
return Quaternion_copy(self);
}
-/* print the object to screen */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Quaternion Type: `__repr__` & `__str__`
+ * \{ */
+
static PyObject *Quaternion_repr(QuaternionObject *self)
{
PyObject *ret, *tuple;
@@ -608,6 +812,12 @@ static PyObject *Quaternion_str(QuaternionObject *self)
}
#endif
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Quaternion Type: Rich Compare
+ * \{ */
+
static PyObject *Quaternion_richcmpr(PyObject *a, PyObject *b, int op)
{
PyObject *res;
@@ -646,6 +856,12 @@ static PyObject *Quaternion_richcmpr(PyObject *a, PyObject *b, int op)
return Py_INCREF_RET(res);
}
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Quaternion Type: Hash (`__hash__`)
+ * \{ */
+
static Py_hash_t Quaternion_hash(QuaternionObject *self)
{
if (BaseMath_ReadCallback(self) == -1) {
@@ -659,15 +875,19 @@ static Py_hash_t Quaternion_hash(QuaternionObject *self)
return mathutils_array_hash(self->quat, QUAT_SIZE);
}
-/* ---------------------SEQUENCE PROTOCOLS------------------------ */
-/* ----------------------------len(object)------------------------ */
-/* sequence length */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Quaternion Type: Sequence & Mapping Protocols Implementation
+ * \{ */
+
+/** Sequence length: `len(object)`. */
static int Quaternion_len(QuaternionObject *UNUSED(self))
{
return QUAT_SIZE;
}
-/* ----------------------------object[]--------------------------- */
-/* sequence accessor (get) */
+
+/** Sequence accessor (get): `x = object[i]`. */
static PyObject *Quaternion_item(QuaternionObject *self, int i)
{
if (i < 0) {
@@ -687,8 +907,8 @@ static PyObject *Quaternion_item(QuaternionObject *self, int i)
return PyFloat_FromDouble(self->quat[i]);
}
-/* ----------------------------object[]------------------------- */
-/* sequence accessor (set) */
+
+/** Sequence accessor (set): `object[i] = x`. */
static int Quaternion_ass_item(QuaternionObject *self, int i, PyObject *ob)
{
float f;
@@ -724,8 +944,8 @@ static int Quaternion_ass_item(QuaternionObject *self, int i, PyObject *ob)
return 0;
}
-/* ----------------------------object[z:y]------------------------ */
-/* sequence slice (get) */
+
+/** Sequence slice accessor (get): `x = object[i:j]`. */
static PyObject *Quaternion_slice(QuaternionObject *self, int begin, int end)
{
PyObject *tuple;
@@ -749,8 +969,8 @@ static PyObject *Quaternion_slice(QuaternionObject *self, int begin, int end)
return tuple;
}
-/* ----------------------------object[z:y]------------------------ */
-/* sequence slice (set) */
+
+/** Sequence slice accessor (set): `object[i:j] = x`. */
static int Quaternion_ass_slice(QuaternionObject *self, int begin, int end, PyObject *seq)
{
int i, size;
@@ -779,7 +999,7 @@ static int Quaternion_ass_slice(QuaternionObject *self, int begin, int end, PyOb
return -1;
}
- /* parsed well - now set in vector */
+ /* Parsed well, now set in vector. */
for (i = 0; i < size; i++) {
self->quat[begin + i] = quat[i];
}
@@ -788,6 +1008,7 @@ static int Quaternion_ass_slice(QuaternionObject *self, int begin, int end, PyOb
return 0;
}
+/** Sequence generic subscript (get): `x = object[...]`. */
static PyObject *Quaternion_subscript(QuaternionObject *self, PyObject *item)
{
if (PyIndex_Check(item)) {
@@ -824,6 +1045,7 @@ static PyObject *Quaternion_subscript(QuaternionObject *self, PyObject *item)
return NULL;
}
+/** Sequence generic subscript (set): `object[...] = x`. */
static int Quaternion_ass_subscript(QuaternionObject *self, PyObject *item, PyObject *value)
{
if (PyIndex_Check(item)) {
@@ -856,9 +1078,13 @@ static int Quaternion_ass_subscript(QuaternionObject *self, PyObject *item, PyOb
return -1;
}
-/* ------------------------NUMERIC PROTOCOLS---------------------- */
-/* ------------------------obj + obj------------------------------ */
-/* addition */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Quaternion Type: Numeric Protocol Implementation
+ * \{ */
+
+/** Addition: `object + object`. */
static PyObject *Quaternion_add(PyObject *q1, PyObject *q2)
{
float quat[QUAT_SIZE];
@@ -882,8 +1108,8 @@ static PyObject *Quaternion_add(PyObject *q1, PyObject *q2)
add_qt_qtqt(quat, quat1->quat, quat2->quat, 1.0f);
return Quaternion_CreatePyObject(quat, Py_TYPE(q1));
}
-/* ------------------------obj - obj------------------------------ */
-/* subtraction */
+
+/** Subtraction: `object - object`. */
static PyObject *Quaternion_sub(PyObject *q1, PyObject *q2)
{
int x;
@@ -921,8 +1147,7 @@ static PyObject *quat_mul_float(QuaternionObject *quat, const float scalar)
return Quaternion_CreatePyObject(tquat, Py_TYPE(quat));
}
-/*------------------------obj * obj------------------------------
- * multiplication */
+/** Multiplication (element-wise or scalar): `object * object`. */
static PyObject *Quaternion_mul(PyObject *q1, PyObject *q2)
{
float scalar;
@@ -965,8 +1190,8 @@ static PyObject *Quaternion_mul(PyObject *q1, PyObject *q2)
Py_TYPE(q2)->tp_name);
return NULL;
}
-/*------------------------obj *= obj------------------------------
- * in-place multiplication */
+
+/** Multiplication in-place (element-wise or scalar): `object *= object`. */
static PyObject *Quaternion_imul(PyObject *q1, PyObject *q2)
{
float scalar;
@@ -1005,8 +1230,8 @@ static PyObject *Quaternion_imul(PyObject *q1, PyObject *q2)
Py_INCREF(q1);
return q1;
}
-/*------------------------obj @ obj------------------------------
- * quaternion multiplication */
+
+/** Multiplication (quaternion multiply): `object @ object`. */
static PyObject *Quaternion_matmul(PyObject *q1, PyObject *q2)
{
float quat[QUAT_SIZE];
@@ -1060,8 +1285,8 @@ static PyObject *Quaternion_matmul(PyObject *q1, PyObject *q2)
Py_TYPE(q2)->tp_name);
return NULL;
}
-/*------------------------obj @= obj------------------------------
- * in-place quaternion multiplication */
+
+/** Multiplication in-place (quaternion multiply): `object @= object`. */
static PyObject *Quaternion_imatmul(PyObject *q1, PyObject *q2)
{
float quat[QUAT_SIZE];
@@ -1098,8 +1323,7 @@ static PyObject *Quaternion_imatmul(PyObject *q1, PyObject *q2)
return q1;
}
-/* -obj
- * Returns the negative of this object. */
+/** Negative (returns the negative of this object): `-object`. */
static PyObject *Quaternion_neg(QuaternionObject *self)
{
float tquat[QUAT_SIZE];
@@ -1112,18 +1336,23 @@ static PyObject *Quaternion_neg(QuaternionObject *self)
return Quaternion_CreatePyObject(tquat, Py_TYPE(self));
}
-/* -----------------PROTOCOL DECLARATIONS-------------------------- */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Quaternion Type: Protocol Declarations
+ * \{ */
+
static PySequenceMethods Quaternion_SeqMethods = {
- (lenfunc)Quaternion_len, /* sq_length */
- (binaryfunc)NULL, /* sq_concat */
- (ssizeargfunc)NULL, /* sq_repeat */
- (ssizeargfunc)Quaternion_item, /* sq_item */
- (ssizessizeargfunc)NULL, /* sq_slice, deprecated */
- (ssizeobjargproc)Quaternion_ass_item, /* sq_ass_item */
- (ssizessizeobjargproc)NULL, /* sq_ass_slice, deprecated */
- (objobjproc)NULL, /* sq_contains */
- (binaryfunc)NULL, /* sq_inplace_concat */
- (ssizeargfunc)NULL, /* sq_inplace_repeat */
+ (lenfunc)Quaternion_len, /*sq_length*/
+ (binaryfunc)NULL, /*sq_concat*/
+ (ssizeargfunc)NULL, /*sq_repeat*/
+ (ssizeargfunc)Quaternion_item, /*sq_item*/
+ (ssizessizeargfunc)NULL, /*sq_slice(deprecated)*/
+ (ssizeobjargproc)Quaternion_ass_item, /*sq_ass_item*/
+ (ssizessizeobjargproc)NULL, /*sq_ass_slice(deprecated)*/
+ (objobjproc)NULL, /*sq_contains*/
+ (binaryfunc)NULL, /*sq_inplace_concat*/
+ (ssizeargfunc)NULL, /*sq_inplace_repeat*/
};
static PyMappingMethods Quaternion_AsMapping = {
@@ -1152,25 +1381,31 @@ static PyNumberMethods Quaternion_NumMethods = {
NULL, /*nb_int*/
NULL, /*nb_reserved*/
NULL, /*nb_float*/
- NULL, /* nb_inplace_add */
- NULL, /* nb_inplace_subtract */
- (binaryfunc)Quaternion_imul, /* nb_inplace_multiply */
- NULL, /* nb_inplace_remainder */
- NULL, /* nb_inplace_power */
- NULL, /* nb_inplace_lshift */
- NULL, /* nb_inplace_rshift */
- NULL, /* nb_inplace_and */
- NULL, /* nb_inplace_xor */
- NULL, /* nb_inplace_or */
- NULL, /* nb_floor_divide */
- NULL, /* nb_true_divide */
- NULL, /* nb_inplace_floor_divide */
- NULL, /* nb_inplace_true_divide */
- NULL, /* nb_index */
- (binaryfunc)Quaternion_matmul, /* nb_matrix_multiply */
- (binaryfunc)Quaternion_imatmul, /* nb_inplace_matrix_multiply */
+ NULL, /*nb_inplace_add*/
+ NULL, /*nb_inplace_subtract*/
+ (binaryfunc)Quaternion_imul, /*nb_inplace_multiply*/
+ NULL, /*nb_inplace_remainder*/
+ NULL, /*nb_inplace_power*/
+ NULL, /*nb_inplace_lshift*/
+ NULL, /*nb_inplace_rshift*/
+ NULL, /*nb_inplace_and*/
+ NULL, /*nb_inplace_xor*/
+ NULL, /*nb_inplace_or*/
+ NULL, /*nb_floor_divide*/
+ NULL, /*nb_true_divide*/
+ NULL, /*nb_inplace_floor_divide*/
+ NULL, /*nb_inplace_true_divide*/
+ NULL, /*nb_index*/
+ (binaryfunc)Quaternion_matmul, /*nb_matrix_multiply*/
+ (binaryfunc)Quaternion_imatmul, /*nb_inplace_matrix_multiply*/
};
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Quaternion Type: Get/Set Item Implementation
+ * \{ */
+
PyDoc_STRVAR(Quaternion_axis_doc, "Quaternion axis value.\n\n:type: float");
static PyObject *Quaternion_axis_get(QuaternionObject *self, void *type)
{
@@ -1300,98 +1535,69 @@ static int Quaternion_axis_vector_set(QuaternionObject *self,
return 0;
}
-/* ----------------------------------mathutils.Quaternion() -------------- */
-static PyObject *Quaternion_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
-{
- PyObject *seq = NULL;
- double angle = 0.0f;
- float quat[QUAT_SIZE];
- unit_qt(quat);
-
- if (kwds && PyDict_Size(kwds)) {
- PyErr_SetString(PyExc_TypeError,
- "mathutils.Quaternion(): "
- "takes no keyword args");
- return NULL;
- }
-
- if (!PyArg_ParseTuple(args, "|Od:mathutils.Quaternion", &seq, &angle)) {
- return NULL;
- }
-
- switch (PyTuple_GET_SIZE(args)) {
- case 0:
- break;
- case 1: {
- int size;
-
- if ((size = mathutils_array_parse(quat, 3, QUAT_SIZE, seq, "mathutils.Quaternion()")) ==
- -1) {
- return NULL;
- }
+/** \} */
- if (size == 4) {
- /* 4d: Quaternion (common case) */
- }
- else {
- /* 3d: Interpret as exponential map */
- BLI_assert(size == 3);
- expmap_to_quat(quat, quat);
- }
-
- break;
- }
- case 2: {
- float axis[3];
- if (mathutils_array_parse(axis, 3, 3, seq, "mathutils.Quaternion()") == -1) {
- return NULL;
- }
- angle = angle_wrap_rad(angle); /* clamp because of precision issues */
- axis_angle_to_quat(quat, axis, angle);
- break;
- /* PyArg_ParseTuple assures no more than 2 */
- }
- }
- return Quaternion_CreatePyObject(quat, type);
-}
+/* -------------------------------------------------------------------- */
+/** \name Quaternion Type: Get/Set Item Definitions
+ * \{ */
-static PyObject *quat__apply_to_copy(PyObject *(*quat_func)(QuaternionObject *),
- QuaternionObject *self)
-{
- PyObject *ret = Quaternion_copy(self);
- PyObject *ret_dummy = quat_func((QuaternionObject *)ret);
- if (ret_dummy) {
- Py_DECREF(ret_dummy);
- return ret;
- }
- /* error */
- Py_DECREF(ret);
- return NULL;
-}
+static PyGetSetDef Quaternion_getseters[] = {
+ {"w",
+ (getter)Quaternion_axis_get,
+ (setter)Quaternion_axis_set,
+ Quaternion_axis_doc,
+ (void *)0},
+ {"x",
+ (getter)Quaternion_axis_get,
+ (setter)Quaternion_axis_set,
+ Quaternion_axis_doc,
+ (void *)1},
+ {"y",
+ (getter)Quaternion_axis_get,
+ (setter)Quaternion_axis_set,
+ Quaternion_axis_doc,
+ (void *)2},
+ {"z",
+ (getter)Quaternion_axis_get,
+ (setter)Quaternion_axis_set,
+ Quaternion_axis_doc,
+ (void *)3},
+ {"magnitude", (getter)Quaternion_magnitude_get, (setter)NULL, Quaternion_magnitude_doc, NULL},
+ {"angle",
+ (getter)Quaternion_angle_get,
+ (setter)Quaternion_angle_set,
+ Quaternion_angle_doc,
+ NULL},
+ {"axis",
+ (getter)Quaternion_axis_vector_get,
+ (setter)Quaternion_axis_vector_set,
+ Quaternion_axis_vector_doc,
+ NULL},
+ {"is_wrapped",
+ (getter)BaseMathObject_is_wrapped_get,
+ (setter)NULL,
+ BaseMathObject_is_wrapped_doc,
+ NULL},
+ {"is_frozen",
+ (getter)BaseMathObject_is_frozen_get,
+ (setter)NULL,
+ BaseMathObject_is_frozen_doc,
+ NULL},
+ {"is_valid",
+ (getter)BaseMathObject_is_valid_get,
+ (setter)NULL,
+ BaseMathObject_is_valid_doc,
+ NULL},
+ {"owner", (getter)BaseMathObject_owner_get, (setter)NULL, BaseMathObject_owner_doc, NULL},
+ {NULL, NULL, NULL, NULL, NULL} /* Sentinel */
+};
-/* axis vector suffers from precision errors, use this function to ensure */
-static void quat__axis_angle_sanitize(float axis[3], float *angle)
-{
- if (axis) {
- if (is_zero_v3(axis) || !isfinite(axis[0]) || !isfinite(axis[1]) || !isfinite(axis[2])) {
- axis[0] = 1.0f;
- axis[1] = 0.0f;
- axis[2] = 0.0f;
- }
- else if (EXPP_FloatsAreEqual(axis[0], 0.0f, 10) && EXPP_FloatsAreEqual(axis[1], 0.0f, 10) &&
- EXPP_FloatsAreEqual(axis[2], 0.0f, 10)) {
- axis[0] = 1.0f;
- }
- }
+/** \} */
- if (angle) {
- if (!isfinite(*angle)) {
- *angle = 0.0f;
- }
- }
-}
+/* -------------------------------------------------------------------- */
+/** \name Quaternion Type: Method Definitions
+ * \{ */
-/* -----------------------METHOD DEFINITIONS ---------------------- */
static struct PyMethodDef Quaternion_methods[] = {
/* In place only. */
{"identity", (PyCFunction)Quaternion_identity, METH_NOARGS, Quaternion_identity_doc},
@@ -1446,61 +1652,12 @@ static struct PyMethodDef Quaternion_methods[] = {
{NULL, NULL, 0, NULL},
};
-/*****************************************************************************/
-/* Python attributes get/set structure: */
-/*****************************************************************************/
-static PyGetSetDef Quaternion_getseters[] = {
- {"w",
- (getter)Quaternion_axis_get,
- (setter)Quaternion_axis_set,
- Quaternion_axis_doc,
- (void *)0},
- {"x",
- (getter)Quaternion_axis_get,
- (setter)Quaternion_axis_set,
- Quaternion_axis_doc,
- (void *)1},
- {"y",
- (getter)Quaternion_axis_get,
- (setter)Quaternion_axis_set,
- Quaternion_axis_doc,
- (void *)2},
- {"z",
- (getter)Quaternion_axis_get,
- (setter)Quaternion_axis_set,
- Quaternion_axis_doc,
- (void *)3},
- {"magnitude", (getter)Quaternion_magnitude_get, (setter)NULL, Quaternion_magnitude_doc, NULL},
- {"angle",
- (getter)Quaternion_angle_get,
- (setter)Quaternion_angle_set,
- Quaternion_angle_doc,
- NULL},
- {"axis",
- (getter)Quaternion_axis_vector_get,
- (setter)Quaternion_axis_vector_set,
- Quaternion_axis_vector_doc,
- NULL},
- {"is_wrapped",
- (getter)BaseMathObject_is_wrapped_get,
- (setter)NULL,
- BaseMathObject_is_wrapped_doc,
- NULL},
- {"is_frozen",
- (getter)BaseMathObject_is_frozen_get,
- (setter)NULL,
- BaseMathObject_is_frozen_doc,
- NULL},
- {"is_valid",
- (getter)BaseMathObject_is_valid_get,
- (setter)NULL,
- BaseMathObject_is_valid_doc,
- NULL},
- {"owner", (getter)BaseMathObject_owner_get, (setter)NULL, BaseMathObject_owner_doc, NULL},
- {NULL, NULL, NULL, NULL, NULL} /* Sentinel */
-};
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Quaternion Type: Python Object Definition
+ * \{ */
-/* ------------------PY_OBECT DEFINITION-------------------------- */
PyDoc_STRVAR(quaternion_doc,
".. class:: Quaternion([seq, [angle]])\n"
"\n"
@@ -1577,6 +1734,12 @@ PyTypeObject quaternion_Type = {
NULL, /* tp_del */
};
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Quaternion Type: C/API Constructors
+ * \{ */
+
PyObject *Quaternion_CreatePyObject(const float quat[4], PyTypeObject *base_type)
{
QuaternionObject *self;
@@ -1643,3 +1806,5 @@ PyObject *Quaternion_CreatePyObject_cb(PyObject *cb_user, uchar cb_type, uchar c
return (PyObject *)self;
}
+
+/** \} */
diff --git a/source/blender/python/mathutils/mathutils_Quaternion.h b/source/blender/python/mathutils/mathutils_Quaternion.h
index 96e3d2e0055..c45b0a98a7b 100644
--- a/source/blender/python/mathutils/mathutils_Quaternion.h
+++ b/source/blender/python/mathutils/mathutils_Quaternion.h
@@ -20,7 +20,8 @@ typedef struct {
* be stored in py_data) or be a wrapper for data allocated through
* blender (stored in blend_data). This is an either/or struct not both */
-/* prototypes */
+/* Prototypes. */
+
PyObject *Quaternion_CreatePyObject(const float quat[4],
PyTypeObject *base_type) ATTR_WARN_UNUSED_RESULT;
PyObject *Quaternion_CreatePyObject_wrap(float quat[4],
diff --git a/source/blender/python/mathutils/mathutils_Vector.c b/source/blender/python/mathutils/mathutils_Vector.c
index ffeb121b3d1..0c9cbd6ccfa 100644
--- a/source/blender/python/mathutils/mathutils_Vector.c
+++ b/source/blender/python/mathutils/mathutils_Vector.c
@@ -24,19 +24,108 @@
*/
#define MAX_DIMENSIONS 4
-/* Swizzle axes get packed into a single value that is used as a closure. Each
+/**
+ * Swizzle axes get packed into a single value that is used as a closure. Each
* axis uses SWIZZLE_BITS_PER_AXIS bits. The first bit (SWIZZLE_VALID_AXIS) is
- * used as a sentinel: if it is unset, the axis is not valid. */
+ * used as a sentinel: if it is unset, the axis is not valid.
+ */
#define SWIZZLE_BITS_PER_AXIS 3
#define SWIZZLE_VALID_AXIS 0x4
#define SWIZZLE_AXIS 0x3
static PyObject *Vector_copy(VectorObject *self);
static PyObject *Vector_deepcopy(VectorObject *self, PyObject *args);
-static PyObject *Vector_to_tuple_ex(VectorObject *self, int ndigits);
+
+/* -------------------------------------------------------------------- */
+/** \name Utilities
+ * \{ */
+
+/**
+ * Row vector multiplication - (Vector * Matrix)
+ * <pre>
+ * [x][y][z] * [1][4][7]
+ * [2][5][8]
+ * [3][6][9]
+ * </pre>
+ * \note vector/matrix multiplication is not commutative.
+ */
static int row_vector_multiplication(float r_vec[MAX_DIMENSIONS],
VectorObject *vec,
- MatrixObject *mat);
+ MatrixObject *mat)
+{
+ float vec_cpy[MAX_DIMENSIONS];
+ int row, col, z = 0, vec_num = vec->vec_num;
+
+ if (mat->row_num != vec_num) {
+ if (mat->row_num == 4 && vec_num == 3) {
+ vec_cpy[3] = 1.0f;
+ }
+ else {
+ PyErr_SetString(PyExc_ValueError,
+ "vector * matrix: matrix column size "
+ "and the vector size must be the same");
+ return -1;
+ }
+ }
+
+ if (BaseMath_ReadCallback(vec) == -1 || BaseMath_ReadCallback(mat) == -1) {
+ return -1;
+ }
+
+ memcpy(vec_cpy, vec->vec, vec_num * sizeof(float));
+
+ r_vec[3] = 1.0f;
+ /* Multiplication. */
+ for (col = 0; col < mat->col_num; col++) {
+ double dot = 0.0;
+ for (row = 0; row < mat->row_num; row++) {
+ dot += (double)(MATRIX_ITEM(mat, row, col) * vec_cpy[row]);
+ }
+ r_vec[z++] = (float)dot;
+ }
+ return 0;
+}
+
+static PyObject *vec__apply_to_copy(PyObject *(*vec_func)(VectorObject *), VectorObject *self)
+{
+ PyObject *ret = Vector_copy(self);
+ PyObject *ret_dummy = vec_func((VectorObject *)ret);
+ if (ret_dummy) {
+ Py_DECREF(ret_dummy);
+ return (PyObject *)ret;
+ }
+ /* error */
+ Py_DECREF(ret);
+ return NULL;
+}
+
+/** \note #BaseMath_ReadCallback must be called beforehand. */
+static PyObject *Vector_to_tuple_ex(VectorObject *self, int ndigits)
+{
+ PyObject *ret;
+ int i;
+
+ ret = PyTuple_New(self->vec_num);
+
+ if (ndigits >= 0) {
+ for (i = 0; i < self->vec_num; i++) {
+ PyTuple_SET_ITEM(ret, i, PyFloat_FromDouble(double_round((double)self->vec[i], ndigits)));
+ }
+ }
+ else {
+ for (i = 0; i < self->vec_num; i++) {
+ PyTuple_SET_ITEM(ret, i, PyFloat_FromDouble(self->vec[i]));
+ }
+ }
+
+ return ret;
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Vector Type: `__new__` / `mathutils.Vector()`
+ * \{ */
/**
* Supports 2D, 3D, and 4D vector objects both int and float values
@@ -82,20 +171,12 @@ static PyObject *Vector_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
return Vector_CreatePyObject_alloc(vec, vec_num, type);
}
-static PyObject *vec__apply_to_copy(PyObject *(*vec_func)(VectorObject *), VectorObject *self)
-{
- PyObject *ret = Vector_copy(self);
- PyObject *ret_dummy = vec_func((VectorObject *)ret);
- if (ret_dummy) {
- Py_DECREF(ret_dummy);
- return (PyObject *)ret;
- }
- /* error */
- Py_DECREF(ret);
- return NULL;
-}
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Vector Class Methods
+ * \{ */
-/*-----------------------CLASS-METHODS----------------------------*/
PyDoc_STRVAR(C_Vector_Fill_doc,
".. classmethod:: Fill(size, fill=0.0)\n"
"\n"
@@ -311,7 +392,12 @@ static PyObject *C_Vector_Repeat(PyObject *cls, PyObject *args)
return Vector_CreatePyObject_alloc(vec, vec_num, (PyTypeObject *)cls);
}
-/*-----------------------------METHODS---------------------------- */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Vector Methods: Zero
+ * \{ */
+
PyDoc_STRVAR(Vector_zero_doc,
".. method:: zero()\n"
"\n"
@@ -331,6 +417,12 @@ static PyObject *Vector_zero(VectorObject *self)
Py_RETURN_NONE;
}
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Vector Methods: Normalize
+ * \{ */
+
PyDoc_STRVAR(Vector_normalize_doc,
".. method:: normalize()\n"
"\n"
@@ -364,6 +456,12 @@ static PyObject *Vector_normalized(VectorObject *self)
return vec__apply_to_copy(Vector_normalize, self);
}
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Vector Methods: Resize
+ * \{ */
+
PyDoc_STRVAR(Vector_resize_doc,
".. method:: resize(size=3)\n"
"\n"
@@ -553,6 +651,13 @@ static PyObject *Vector_resize_4d(VectorObject *self)
self->vec_num = 4;
Py_RETURN_NONE;
}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Vector Methods: To N-dimensions
+ * \{ */
+
PyDoc_STRVAR(Vector_to_2d_doc,
".. method:: to_2d()\n"
"\n"
@@ -605,6 +710,12 @@ static PyObject *Vector_to_4d(VectorObject *self)
return Vector_CreatePyObject(tvec, 4, Py_TYPE(self));
}
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Vector Methods: To Tuple
+ * \{ */
+
PyDoc_STRVAR(Vector_to_tuple_doc,
".. method:: to_tuple(precision=-1)\n"
"\n"
@@ -614,28 +725,6 @@ PyDoc_STRVAR(Vector_to_tuple_doc,
" :type precision: int\n"
" :return: the values of the vector rounded by *precision*\n"
" :rtype: tuple\n");
-/* NOTE: BaseMath_ReadCallback must be called beforehand. */
-static PyObject *Vector_to_tuple_ex(VectorObject *self, int ndigits)
-{
- PyObject *ret;
- int i;
-
- ret = PyTuple_New(self->vec_num);
-
- if (ndigits >= 0) {
- for (i = 0; i < self->vec_num; i++) {
- PyTuple_SET_ITEM(ret, i, PyFloat_FromDouble(double_round((double)self->vec[i], ndigits)));
- }
- }
- else {
- for (i = 0; i < self->vec_num; i++) {
- PyTuple_SET_ITEM(ret, i, PyFloat_FromDouble(self->vec[i]));
- }
- }
-
- return ret;
-}
-
static PyObject *Vector_to_tuple(VectorObject *self, PyObject *args)
{
int ndigits = 0;
@@ -662,6 +751,12 @@ static PyObject *Vector_to_tuple(VectorObject *self, PyObject *args)
return Vector_to_tuple_ex(self, ndigits);
}
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Vector Methods: To Track Quaternion
+ * \{ */
+
PyDoc_STRVAR(Vector_to_track_quat_doc,
".. method:: to_track_quat(track, up)\n"
"\n"
@@ -781,6 +876,12 @@ static PyObject *Vector_to_track_quat(VectorObject *self, PyObject *args)
return Quaternion_CreatePyObject(quat, NULL);
}
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Vector Methods: Orthogonal
+ * \{ */
+
PyDoc_STRVAR(
Vector_orthogonal_doc,
".. method:: orthogonal()\n"
@@ -816,12 +917,15 @@ static PyObject *Vector_orthogonal(VectorObject *self)
return Vector_CreatePyObject(vec, self->vec_num, Py_TYPE(self));
}
-/**
- * Vector.reflect(mirror): return a reflected vector on the mirror normal.
- * <pre>
- * vec - ((2 * dot(vec, mirror)) * mirror)
- * </pre>
- */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Vector Methods: Reflect
+ *
+ * `Vector.reflect(mirror)`: return a reflected vector on the mirror normal:
+ * `vec - ((2 * dot(vec, mirror)) * mirror)`.
+ * \{ */
+
PyDoc_STRVAR(Vector_reflect_doc,
".. method:: reflect(mirror)\n"
"\n"
@@ -866,6 +970,12 @@ static PyObject *Vector_reflect(VectorObject *self, PyObject *value)
return Vector_CreatePyObject(reflect, self->vec_num, Py_TYPE(self));
}
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Vector Methods: Cross Product
+ * \{ */
+
PyDoc_STRVAR(Vector_cross_doc,
".. method:: cross(other)\n"
"\n"
@@ -908,6 +1018,12 @@ static PyObject *Vector_cross(VectorObject *self, PyObject *value)
return ret;
}
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Vector Methods: Dot Product
+ * \{ */
+
PyDoc_STRVAR(Vector_dot_doc,
".. method:: dot(other)\n"
"\n"
@@ -936,6 +1052,12 @@ static PyObject *Vector_dot(VectorObject *self, PyObject *value)
return ret;
}
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Vector Methods: Angle
+ * \{ */
+
PyDoc_STRVAR(
Vector_angle_doc,
".. function:: angle(other, fallback=None)\n"
@@ -1001,6 +1123,12 @@ static PyObject *Vector_angle(VectorObject *self, PyObject *args)
return PyFloat_FromDouble(saacos(dot / (sqrt(dot_self) * sqrt(dot_other))));
}
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Vector Methods: Angle Signed
+ * \{ */
+
PyDoc_STRVAR(
Vector_angle_signed_doc,
".. function:: angle_signed(other, fallback)\n"
@@ -1055,6 +1183,12 @@ static PyObject *Vector_angle_signed(VectorObject *self, PyObject *args)
return PyFloat_FromDouble(angle_signed_v2v2(self->vec, tvec));
}
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Vector Methods: Rotation Difference
+ * \{ */
+
PyDoc_STRVAR(Vector_rotation_difference_doc,
".. function:: rotation_difference(other)\n"
"\n"
@@ -1096,6 +1230,12 @@ static PyObject *Vector_rotation_difference(VectorObject *self, PyObject *value)
return Quaternion_CreatePyObject(quat, NULL);
}
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Vector Methods: Project
+ * \{ */
+
PyDoc_STRVAR(Vector_project_doc,
".. function:: project(other)\n"
"\n"
@@ -1134,6 +1274,12 @@ static PyObject *Vector_project(VectorObject *self, PyObject *value)
return Vector_CreatePyObject_alloc(tvec, vec_num, Py_TYPE(self));
}
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Vector Methods: Linear Interpolation
+ * \{ */
+
PyDoc_STRVAR(Vector_lerp_doc,
".. function:: lerp(other, factor)\n"
"\n"
@@ -1170,6 +1316,12 @@ static PyObject *Vector_lerp(VectorObject *self, PyObject *args)
return Vector_CreatePyObject_alloc(tvec, vec_num, Py_TYPE(self));
}
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Vector Methods: Spherical Interpolation
+ * \{ */
+
PyDoc_STRVAR(Vector_slerp_doc,
".. function:: slerp(other, factor, fallback=None)\n"
"\n"
@@ -1256,6 +1408,12 @@ static PyObject *Vector_slerp(VectorObject *self, PyObject *args)
return Vector_CreatePyObject(ret_vec, vec_num, Py_TYPE(self));
}
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Vector Methods: Rotate
+ * \{ */
+
PyDoc_STRVAR(
Vector_rotate_doc,
".. function:: rotate(other)\n"
@@ -1297,6 +1455,34 @@ static PyObject *Vector_rotate(VectorObject *self, PyObject *value)
Py_RETURN_NONE;
}
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Vector Methods: Negate
+ * \{ */
+
+PyDoc_STRVAR(Vector_negate_doc,
+ ".. method:: negate()\n"
+ "\n"
+ " Set all values to their negative.\n");
+static PyObject *Vector_negate(VectorObject *self)
+{
+ if (BaseMath_ReadCallback(self) == -1) {
+ return NULL;
+ }
+
+ negate_vn(self->vec, self->vec_num);
+
+ (void)BaseMath_WriteCallback(self); /* already checked for error */
+ Py_RETURN_NONE;
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Vector Methods: Copy/Deep-Copy
+ * \{ */
+
PyDoc_STRVAR(Vector_copy_doc,
".. function:: copy()\n"
"\n"
@@ -1323,6 +1509,12 @@ static PyObject *Vector_deepcopy(VectorObject *self, PyObject *args)
return Vector_copy(self);
}
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Vector Type: `__repr__` & `__str__`
+ * \{ */
+
static PyObject *Vector_repr(VectorObject *self)
{
PyObject *ret, *tuple;
@@ -1362,13 +1554,124 @@ static PyObject *Vector_str(VectorObject *self)
}
#endif
-/* Sequence Protocol */
-/* sequence length len(vector) */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Vector Type: Rich Compare
+ * \{ */
+
+static PyObject *Vector_richcmpr(PyObject *objectA, PyObject *objectB, int comparison_type)
+{
+ VectorObject *vecA = NULL, *vecB = NULL;
+ int result = 0;
+ const double epsilon = 0.000001f;
+ double lenA, lenB;
+
+ if (!VectorObject_Check(objectA) || !VectorObject_Check(objectB)) {
+ if (comparison_type == Py_NE) {
+ Py_RETURN_TRUE;
+ }
+
+ Py_RETURN_FALSE;
+ }
+ vecA = (VectorObject *)objectA;
+ vecB = (VectorObject *)objectB;
+
+ if (BaseMath_ReadCallback(vecA) == -1 || BaseMath_ReadCallback(vecB) == -1) {
+ return NULL;
+ }
+
+ if (vecA->vec_num != vecB->vec_num) {
+ if (comparison_type == Py_NE) {
+ Py_RETURN_TRUE;
+ }
+
+ Py_RETURN_FALSE;
+ }
+
+ switch (comparison_type) {
+ case Py_LT:
+ lenA = len_squared_vn(vecA->vec, vecA->vec_num);
+ lenB = len_squared_vn(vecB->vec, vecB->vec_num);
+ if (lenA < lenB) {
+ result = 1;
+ }
+ break;
+ case Py_LE:
+ lenA = len_squared_vn(vecA->vec, vecA->vec_num);
+ lenB = len_squared_vn(vecB->vec, vecB->vec_num);
+ if (lenA < lenB) {
+ result = 1;
+ }
+ else {
+ result = (((lenA + epsilon) > lenB) && ((lenA - epsilon) < lenB));
+ }
+ break;
+ case Py_EQ:
+ result = EXPP_VectorsAreEqual(vecA->vec, vecB->vec, vecA->vec_num, 1);
+ break;
+ case Py_NE:
+ result = !EXPP_VectorsAreEqual(vecA->vec, vecB->vec, vecA->vec_num, 1);
+ break;
+ case Py_GT:
+ lenA = len_squared_vn(vecA->vec, vecA->vec_num);
+ lenB = len_squared_vn(vecB->vec, vecB->vec_num);
+ if (lenA > lenB) {
+ result = 1;
+ }
+ break;
+ case Py_GE:
+ lenA = len_squared_vn(vecA->vec, vecA->vec_num);
+ lenB = len_squared_vn(vecB->vec, vecB->vec_num);
+ if (lenA > lenB) {
+ result = 1;
+ }
+ else {
+ result = (((lenA + epsilon) > lenB) && ((lenA - epsilon) < lenB));
+ }
+ break;
+ default:
+ printf("The result of the comparison could not be evaluated");
+ break;
+ }
+ if (result == 1) {
+ Py_RETURN_TRUE;
+ }
+
+ Py_RETURN_FALSE;
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Vector Type: Hash (`__hash__`)
+ * \{ */
+
+static Py_hash_t Vector_hash(VectorObject *self)
+{
+ if (BaseMath_ReadCallback(self) == -1) {
+ return -1;
+ }
+
+ if (BaseMathObject_Prepare_ForHash(self) == -1) {
+ return -1;
+ }
+
+ return mathutils_array_hash(self->vec, self->vec_num);
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Vector Type: Sequence & Mapping Protocols Implementation
+ * \{ */
+
+/** Sequence length: `len(object)`. */
static int Vector_len(VectorObject *self)
{
return self->vec_num;
}
-/* sequence accessor (get): vector[index] */
+
static PyObject *vector_item_internal(VectorObject *self, int i, const bool is_attr)
{
if (i < 0) {
@@ -1395,11 +1698,12 @@ static PyObject *vector_item_internal(VectorObject *self, int i, const bool is_a
return PyFloat_FromDouble(self->vec[i]);
}
+/** Sequence accessor (get): `x = object[i]`. */
static PyObject *Vector_item(VectorObject *self, int i)
{
return vector_item_internal(self, i, false);
}
-/* sequence accessor (set): vector[index] = value */
+
static int vector_ass_item_internal(VectorObject *self, int i, PyObject *value, const bool is_attr)
{
float scalar;
@@ -1442,12 +1746,13 @@ static int vector_ass_item_internal(VectorObject *self, int i, PyObject *value,
return 0;
}
+/** Sequence accessor (set): `object[i] = x`. */
static int Vector_ass_item(VectorObject *self, int i, PyObject *value)
{
return vector_ass_item_internal(self, i, value, false);
}
-/* sequence slice (get): vector[a:b] */
+/** Sequence slice accessor (get): `x = object[i:j]`. */
static PyObject *Vector_slice(VectorObject *self, int begin, int end)
{
PyObject *tuple;
@@ -1471,7 +1776,8 @@ static PyObject *Vector_slice(VectorObject *self, int begin, int end)
return tuple;
}
-/* sequence slice (set): vector[a:b] = value */
+
+/** Sequence slice accessor (set): `object[i:j] = x`. */
static int Vector_ass_slice(VectorObject *self, int begin, int end, PyObject *seq)
{
int vec_num = 0;
@@ -1509,8 +1815,83 @@ static int Vector_ass_slice(VectorObject *self, int begin, int end, PyObject *se
return 0;
}
-/* Numeric Protocols */
-/* addition: obj + obj */
+/** Sequence generic subscript (get): `x = object[...]`. */
+static PyObject *Vector_subscript(VectorObject *self, PyObject *item)
+{
+ if (PyIndex_Check(item)) {
+ Py_ssize_t i;
+ i = PyNumber_AsSsize_t(item, PyExc_IndexError);
+ if (i == -1 && PyErr_Occurred()) {
+ return NULL;
+ }
+ if (i < 0) {
+ i += self->vec_num;
+ }
+ return Vector_item(self, i);
+ }
+ if (PySlice_Check(item)) {
+ Py_ssize_t start, stop, step, slicelength;
+
+ if (PySlice_GetIndicesEx(item, self->vec_num, &start, &stop, &step, &slicelength) < 0) {
+ return NULL;
+ }
+
+ if (slicelength <= 0) {
+ return PyTuple_New(0);
+ }
+ if (step == 1) {
+ return Vector_slice(self, start, stop);
+ }
+
+ PyErr_SetString(PyExc_IndexError, "slice steps not supported with vectors");
+ return NULL;
+ }
+
+ PyErr_Format(
+ PyExc_TypeError, "vector indices must be integers, not %.200s", Py_TYPE(item)->tp_name);
+ return NULL;
+}
+
+/** Sequence generic subscript (set): `object[...] = x`. */
+static int Vector_ass_subscript(VectorObject *self, PyObject *item, PyObject *value)
+{
+ if (PyIndex_Check(item)) {
+ Py_ssize_t i = PyNumber_AsSsize_t(item, PyExc_IndexError);
+ if (i == -1 && PyErr_Occurred()) {
+ return -1;
+ }
+ if (i < 0) {
+ i += self->vec_num;
+ }
+ return Vector_ass_item(self, i, value);
+ }
+ if (PySlice_Check(item)) {
+ Py_ssize_t start, stop, step, slicelength;
+
+ if (PySlice_GetIndicesEx(item, self->vec_num, &start, &stop, &step, &slicelength) < 0) {
+ return -1;
+ }
+
+ if (step == 1) {
+ return Vector_ass_slice(self, start, stop, value);
+ }
+
+ PyErr_SetString(PyExc_IndexError, "slice steps not supported with vectors");
+ return -1;
+ }
+
+ PyErr_Format(
+ PyExc_TypeError, "vector indices must be integers, not %.200s", Py_TYPE(item)->tp_name);
+ return -1;
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Vector Type: Numeric Protocol Implementation
+ * \{ */
+
+/** Addition: `object + object`. */
static PyObject *Vector_add(PyObject *v1, PyObject *v2)
{
VectorObject *vec1 = NULL, *vec2 = NULL;
@@ -1552,7 +1933,7 @@ static PyObject *Vector_add(PyObject *v1, PyObject *v2)
return Vector_CreatePyObject_alloc(vec, vec1->vec_num, Py_TYPE(v1));
}
-/* addition in-place: obj += obj */
+/** Addition in-place: `object += object`. */
static PyObject *Vector_iadd(PyObject *v1, PyObject *v2)
{
VectorObject *vec1 = NULL, *vec2 = NULL;
@@ -1586,7 +1967,7 @@ static PyObject *Vector_iadd(PyObject *v1, PyObject *v2)
return v1;
}
-/* subtraction: obj - obj */
+/** Subtraction: `object - object`. */
static PyObject *Vector_sub(PyObject *v1, PyObject *v2)
{
VectorObject *vec1 = NULL, *vec2 = NULL;
@@ -1627,7 +2008,7 @@ static PyObject *Vector_sub(PyObject *v1, PyObject *v2)
return Vector_CreatePyObject_alloc(vec, vec1->vec_num, Py_TYPE(v1));
}
-/* subtraction in-place: obj -= obj */
+/** Subtraction in-place: `object -= object`. */
static PyObject *Vector_isub(PyObject *v1, PyObject *v2)
{
VectorObject *vec1 = NULL, *vec2 = NULL;
@@ -1661,8 +2042,7 @@ static PyObject *Vector_isub(PyObject *v1, PyObject *v2)
return v1;
}
-/*------------------------obj * obj------------------------------
- * multiplication */
+/* Multiply internal implementation `object * object`, `object *= object`. */
int column_vector_multiplication(float r_vec[MAX_DIMENSIONS], VectorObject *vec, MatrixObject *mat)
{
@@ -1725,6 +2105,7 @@ static PyObject *vector_mul_vec(VectorObject *vec1, VectorObject *vec2)
return Vector_CreatePyObject_alloc(tvec, vec1->vec_num, Py_TYPE(vec1));
}
+/** Multiplication (element-wise or scalar): `object * object`. */
static PyObject *Vector_mul(PyObject *v1, PyObject *v2)
{
VectorObject *vec1 = NULL, *vec2 = NULL;
@@ -1776,7 +2157,7 @@ static PyObject *Vector_mul(PyObject *v1, PyObject *v2)
return NULL;
}
-/* multiplication in-place: obj *= obj */
+/** Multiplication in-place (element-wise or scalar): `object *= object`. */
static PyObject *Vector_imul(PyObject *v1, PyObject *v2)
{
VectorObject *vec1 = NULL, *vec2 = NULL;
@@ -1830,6 +2211,7 @@ static PyObject *Vector_imul(PyObject *v1, PyObject *v2)
return v1;
}
+/** Multiplication (matrix multiply): `object @ object`. */
static PyObject *Vector_matmul(PyObject *v1, PyObject *v2)
{
VectorObject *vec1 = NULL, *vec2 = NULL;
@@ -1893,6 +2275,7 @@ static PyObject *Vector_matmul(PyObject *v1, PyObject *v2)
return NULL;
}
+/** Multiplication in-place (matrix multiply): `object @= object`. */
static PyObject *Vector_imatmul(PyObject *v1, PyObject *v2)
{
PyErr_Format(PyExc_TypeError,
@@ -1903,7 +2286,7 @@ static PyObject *Vector_imatmul(PyObject *v1, PyObject *v2)
return NULL;
}
-/* divide: obj / obj */
+/** Division: `object / object`. */
static PyObject *Vector_div(PyObject *v1, PyObject *v2)
{
float *vec = NULL, scalar;
@@ -1950,7 +2333,7 @@ static PyObject *Vector_div(PyObject *v1, PyObject *v2)
return Vector_CreatePyObject_alloc(vec, vec1->vec_num, Py_TYPE(v1));
}
-/* divide in-place: obj /= obj */
+/** Division in-place: `object /= object`. */
static PyObject *Vector_idiv(PyObject *v1, PyObject *v2)
{
float scalar;
@@ -1983,8 +2366,7 @@ static PyObject *Vector_idiv(PyObject *v1, PyObject *v2)
return v1;
}
-/* -obj
- * Returns the negative of this object. */
+/** Negative (returns the negative of this object): `-object`. */
static PyObject *Vector_neg(VectorObject *self)
{
float *tvec;
@@ -1998,184 +2380,25 @@ static PyObject *Vector_neg(VectorObject *self)
return Vector_CreatePyObject_alloc(tvec, self->vec_num, Py_TYPE(self));
}
-/*------------------------tp_richcmpr
- * returns -1 exception, 0 false, 1 true */
-static PyObject *Vector_richcmpr(PyObject *objectA, PyObject *objectB, int comparison_type)
-{
- VectorObject *vecA = NULL, *vecB = NULL;
- int result = 0;
- const double epsilon = 0.000001f;
- double lenA, lenB;
-
- if (!VectorObject_Check(objectA) || !VectorObject_Check(objectB)) {
- if (comparison_type == Py_NE) {
- Py_RETURN_TRUE;
- }
-
- Py_RETURN_FALSE;
- }
- vecA = (VectorObject *)objectA;
- vecB = (VectorObject *)objectB;
-
- if (BaseMath_ReadCallback(vecA) == -1 || BaseMath_ReadCallback(vecB) == -1) {
- return NULL;
- }
+/** \} */
- if (vecA->vec_num != vecB->vec_num) {
- if (comparison_type == Py_NE) {
- Py_RETURN_TRUE;
- }
-
- Py_RETURN_FALSE;
- }
-
- switch (comparison_type) {
- case Py_LT:
- lenA = len_squared_vn(vecA->vec, vecA->vec_num);
- lenB = len_squared_vn(vecB->vec, vecB->vec_num);
- if (lenA < lenB) {
- result = 1;
- }
- break;
- case Py_LE:
- lenA = len_squared_vn(vecA->vec, vecA->vec_num);
- lenB = len_squared_vn(vecB->vec, vecB->vec_num);
- if (lenA < lenB) {
- result = 1;
- }
- else {
- result = (((lenA + epsilon) > lenB) && ((lenA - epsilon) < lenB));
- }
- break;
- case Py_EQ:
- result = EXPP_VectorsAreEqual(vecA->vec, vecB->vec, vecA->vec_num, 1);
- break;
- case Py_NE:
- result = !EXPP_VectorsAreEqual(vecA->vec, vecB->vec, vecA->vec_num, 1);
- break;
- case Py_GT:
- lenA = len_squared_vn(vecA->vec, vecA->vec_num);
- lenB = len_squared_vn(vecB->vec, vecB->vec_num);
- if (lenA > lenB) {
- result = 1;
- }
- break;
- case Py_GE:
- lenA = len_squared_vn(vecA->vec, vecA->vec_num);
- lenB = len_squared_vn(vecB->vec, vecB->vec_num);
- if (lenA > lenB) {
- result = 1;
- }
- else {
- result = (((lenA + epsilon) > lenB) && ((lenA - epsilon) < lenB));
- }
- break;
- default:
- printf("The result of the comparison could not be evaluated");
- break;
- }
- if (result == 1) {
- Py_RETURN_TRUE;
- }
-
- Py_RETURN_FALSE;
-}
-
-static Py_hash_t Vector_hash(VectorObject *self)
-{
- if (BaseMath_ReadCallback(self) == -1) {
- return -1;
- }
+/* -------------------------------------------------------------------- */
+/** \name Vector Type: Protocol Declarations
+ * \{ */
- if (BaseMathObject_Prepare_ForHash(self) == -1) {
- return -1;
- }
-
- return mathutils_array_hash(self->vec, self->vec_num);
-}
-
-/*-----------------PROTCOL DECLARATIONS--------------------------*/
static PySequenceMethods Vector_SeqMethods = {
- (lenfunc)Vector_len, /* sq_length */
- (binaryfunc)NULL, /* sq_concat */
- (ssizeargfunc)NULL, /* sq_repeat */
- (ssizeargfunc)Vector_item, /* sq_item */
- NULL, /* py3 deprecated slice func */
- (ssizeobjargproc)Vector_ass_item, /* sq_ass_item */
- NULL, /* py3 deprecated slice assign func */
- (objobjproc)NULL, /* sq_contains */
- (binaryfunc)NULL, /* sq_inplace_concat */
- (ssizeargfunc)NULL, /* sq_inplace_repeat */
+ (lenfunc)Vector_len, /*sq_length*/
+ (binaryfunc)NULL, /*sq_concat*/
+ (ssizeargfunc)NULL, /*sq_repeat*/
+ (ssizeargfunc)Vector_item, /*sq_item*/
+ NULL, /*sq_slice(DEPRECATED)*/
+ (ssizeobjargproc)Vector_ass_item, /*sq_ass_item*/
+ NULL, /*sq_ass_slice(DEPRECATED)*/
+ (objobjproc)NULL, /*sq_contains*/
+ (binaryfunc)NULL, /*sq_inplace_concat */
+ (ssizeargfunc)NULL, /*sq_inplace_repeat */
};
-static PyObject *Vector_subscript(VectorObject *self, PyObject *item)
-{
- if (PyIndex_Check(item)) {
- Py_ssize_t i;
- i = PyNumber_AsSsize_t(item, PyExc_IndexError);
- if (i == -1 && PyErr_Occurred()) {
- return NULL;
- }
- if (i < 0) {
- i += self->vec_num;
- }
- return Vector_item(self, i);
- }
- if (PySlice_Check(item)) {
- Py_ssize_t start, stop, step, slicelength;
-
- if (PySlice_GetIndicesEx(item, self->vec_num, &start, &stop, &step, &slicelength) < 0) {
- return NULL;
- }
-
- if (slicelength <= 0) {
- return PyTuple_New(0);
- }
- if (step == 1) {
- return Vector_slice(self, start, stop);
- }
-
- PyErr_SetString(PyExc_IndexError, "slice steps not supported with vectors");
- return NULL;
- }
-
- PyErr_Format(
- PyExc_TypeError, "vector indices must be integers, not %.200s", Py_TYPE(item)->tp_name);
- return NULL;
-}
-
-static int Vector_ass_subscript(VectorObject *self, PyObject *item, PyObject *value)
-{
- if (PyIndex_Check(item)) {
- Py_ssize_t i = PyNumber_AsSsize_t(item, PyExc_IndexError);
- if (i == -1 && PyErr_Occurred()) {
- return -1;
- }
- if (i < 0) {
- i += self->vec_num;
- }
- return Vector_ass_item(self, i, value);
- }
- if (PySlice_Check(item)) {
- Py_ssize_t start, stop, step, slicelength;
-
- if (PySlice_GetIndicesEx(item, self->vec_num, &start, &stop, &step, &slicelength) < 0) {
- return -1;
- }
-
- if (step == 1) {
- return Vector_ass_slice(self, start, stop, value);
- }
-
- PyErr_SetString(PyExc_IndexError, "slice steps not supported with vectors");
- return -1;
- }
-
- PyErr_Format(
- PyExc_TypeError, "vector indices must be integers, not %.200s", Py_TYPE(item)->tp_name);
- return -1;
-}
-
static PyMappingMethods Vector_AsMapping = {
(lenfunc)Vector_len,
(binaryfunc)Vector_subscript,
@@ -2202,28 +2425,32 @@ static PyNumberMethods Vector_NumMethods = {
NULL, /*nb_int*/
NULL, /*nb_reserved*/
NULL, /*nb_float*/
- Vector_iadd, /* nb_inplace_add */
- Vector_isub, /* nb_inplace_subtract */
- Vector_imul, /* nb_inplace_multiply */
- NULL, /* nb_inplace_remainder */
- NULL, /* nb_inplace_power */
- NULL, /* nb_inplace_lshift */
- NULL, /* nb_inplace_rshift */
- NULL, /* nb_inplace_and */
- NULL, /* nb_inplace_xor */
- NULL, /* nb_inplace_or */
- NULL, /* nb_floor_divide */
- Vector_div, /* nb_true_divide */
- NULL, /* nb_inplace_floor_divide */
- Vector_idiv, /* nb_inplace_true_divide */
- NULL, /* nb_index */
- (binaryfunc)Vector_matmul, /* nb_matrix_multiply */
- (binaryfunc)Vector_imatmul, /* nb_inplace_matrix_multiply */
+ Vector_iadd, /*nb_inplace_add*/
+ Vector_isub, /*nb_inplace_subtract*/
+ Vector_imul, /*nb_inplace_multiply*/
+ NULL, /*nb_inplace_remainder*/
+ NULL, /*nb_inplace_power*/
+ NULL, /*nb_inplace_lshift*/
+ NULL, /*nb_inplace_rshift*/
+ NULL, /*nb_inplace_and*/
+ NULL, /*nb_inplace_xor*/
+ NULL, /*nb_inplace_or*/
+ NULL, /*nb_floor_divide*/
+ Vector_div, /*nb_true_divide*/
+ NULL, /*nb_inplace_floor_divide*/
+ Vector_idiv, /*nb_inplace_true_divide*/
+ NULL, /*nb_index*/
+ (binaryfunc)Vector_matmul, /*nb_matrix_multiply*/
+ (binaryfunc)Vector_imatmul, /*nb_inplace_matrix_multiply*/
};
-/*------------------PY_OBECT DEFINITION--------------------------*/
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Vector Type: Get/Set Item Implementation
+ * \{ */
-/* vector axis, vector.x/y/z/w */
+/* Vector axis: `vector.x/y/z/w`. */
PyDoc_STRVAR(Vector_axis_x_doc, "Vector X axis.\n\n:type: float");
PyDoc_STRVAR(Vector_axis_y_doc, "Vector Y axis.\n\n:type: float");
@@ -2240,7 +2467,7 @@ static int Vector_axis_set(VectorObject *self, PyObject *value, void *type)
return vector_ass_item_internal(self, POINTER_AS_INT(type), value, true);
}
-/* vector.length */
+/* `Vector.length`. */
PyDoc_STRVAR(Vector_length_doc, "Vector Length.\n\n:type: float");
static PyObject *Vector_length_get(VectorObject *self, void *UNUSED(closure))
@@ -2296,7 +2523,7 @@ static int Vector_length_set(VectorObject *self, PyObject *value)
return 0;
}
-/* vector.length_squared */
+/* `Vector.length_squared`. */
PyDoc_STRVAR(Vector_length_squared_doc, "Vector length squared (v.dot(v)).\n\n:type: float");
static PyObject *Vector_length_squared_get(VectorObject *self, void *UNUSED(closure))
{
@@ -2503,9 +2730,12 @@ static int Vector_swizzle_set(VectorObject *self, PyObject *value, void *closure
#define SWIZZLE3(a, b, c) POINTER_FROM_INT(_SWIZZLE3(a, b, c))
#define SWIZZLE4(a, b, c, d) POINTER_FROM_INT(_SWIZZLE4(a, b, c, d))
-/*****************************************************************************/
-/* Python attributes get/set structure: */
-/*****************************************************************************/
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Vector Type: Get/Set Item Definitions
+ * \{ */
+
static PyGetSetDef Vector_getseters[] = {
{"x", (getter)Vector_axis_get, (setter)Vector_axis_set, Vector_axis_x_doc, (void *)0},
{"y", (getter)Vector_axis_get, (setter)Vector_axis_set, Vector_axis_y_doc, (void *)1},
@@ -2886,68 +3116,11 @@ static PyGetSetDef Vector_getseters[] = {
{NULL, NULL, NULL, NULL, NULL} /* Sentinel */
};
-/**
- * Row vector multiplication - (Vector * Matrix)
- * <pre>
- * [x][y][z] * [1][4][7]
- * [2][5][8]
- * [3][6][9]
- * </pre>
- * \note vector/matrix multiplication is not commutative.
- */
-static int row_vector_multiplication(float r_vec[MAX_DIMENSIONS],
- VectorObject *vec,
- MatrixObject *mat)
-{
- float vec_cpy[MAX_DIMENSIONS];
- int row, col, z = 0, vec_num = vec->vec_num;
-
- if (mat->row_num != vec_num) {
- if (mat->row_num == 4 && vec_num == 3) {
- vec_cpy[3] = 1.0f;
- }
- else {
- PyErr_SetString(PyExc_ValueError,
- "vector * matrix: matrix column size "
- "and the vector size must be the same");
- return -1;
- }
- }
-
- if (BaseMath_ReadCallback(vec) == -1 || BaseMath_ReadCallback(mat) == -1) {
- return -1;
- }
-
- memcpy(vec_cpy, vec->vec, vec_num * sizeof(float));
-
- r_vec[3] = 1.0f;
- /* Multiplication. */
- for (col = 0; col < mat->col_num; col++) {
- double dot = 0.0;
- for (row = 0; row < mat->row_num; row++) {
- dot += (double)(MATRIX_ITEM(mat, row, col) * vec_cpy[row]);
- }
- r_vec[z++] = (float)dot;
- }
- return 0;
-}
-
-/*----------------------------Vector.negate() -------------------- */
-PyDoc_STRVAR(Vector_negate_doc,
- ".. method:: negate()\n"
- "\n"
- " Set all values to their negative.\n");
-static PyObject *Vector_negate(VectorObject *self)
-{
- if (BaseMath_ReadCallback(self) == -1) {
- return NULL;
- }
-
- negate_vn(self->vec, self->vec_num);
+/** \} */
- (void)BaseMath_WriteCallback(self); /* already checked for error */
- Py_RETURN_NONE;
-}
+/* -------------------------------------------------------------------- */
+/** \name Vector Type: Method Definitions
+ * \{ */
static struct PyMethodDef Vector_methods[] = {
/* Class Methods */
@@ -3000,11 +3173,15 @@ static struct PyMethodDef Vector_methods[] = {
{NULL, NULL, 0, NULL},
};
-/**
- * NOTE: #Py_TPFLAGS_CHECKTYPES allows us to avoid casting all types to Vector when coercing
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Vector Type: Python Object Definition
+ *
+ * \note #Py_TPFLAGS_CHECKTYPES allows us to avoid casting all types to Vector when coercing
* but this means for eg that (vec * mat) and (mat * vec)
* both get sent to Vector_mul and it needs to sort out the order
- */
+ * \{ */
PyDoc_STRVAR(vector_doc,
".. class:: Vector(seq)\n"
@@ -3098,6 +3275,12 @@ PyTypeObject vector_Type = {
NULL,
};
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Vector Type: C/API Constructors
+ * \{ */
+
PyObject *Vector_CreatePyObject(const float *vec, const int vec_num, PyTypeObject *base_type)
{
VectorObject *self;
@@ -3190,3 +3373,5 @@ PyObject *Vector_CreatePyObject_alloc(float *vec, const int vec_num, PyTypeObjec
return (PyObject *)self;
}
+
+/** \} */
diff --git a/source/blender/python/mathutils/mathutils_Vector.h b/source/blender/python/mathutils/mathutils_Vector.h
index 3bc4e9d6b6f..7006ece6bf0 100644
--- a/source/blender/python/mathutils/mathutils_Vector.h
+++ b/source/blender/python/mathutils/mathutils_Vector.h
@@ -18,7 +18,8 @@ typedef struct {
int vec_num;
} VectorObject;
-/*prototypes*/
+/* Prototypes. */
+
PyObject *Vector_CreatePyObject(const float *vec,
int vec_num,
PyTypeObject *base_type) ATTR_WARN_UNUSED_RESULT;
diff --git a/source/blender/python/rna_dump.py b/source/blender/python/rna_dump.py
index 61df784336c..b4e23547c62 100644
--- a/source/blender/python/rna_dump.py
+++ b/source/blender/python/rna_dump.py
@@ -1,7 +1,5 @@
# SPDX-License-Identifier: GPL-2.0-or-later
-# <pep8 compliant>
-
if 1:
# Print once every 1000
GEN_PATH = True
diff --git a/source/blender/render/RE_pipeline.h b/source/blender/render/RE_pipeline.h
index 0a8668221ad..548e38d3ef3 100644
--- a/source/blender/render/RE_pipeline.h
+++ b/source/blender/render/RE_pipeline.h
@@ -74,10 +74,12 @@ typedef struct RenderPass {
int pad;
} RenderPass;
-/* a renderlayer is a full image, but with all passes and samples */
-/* size of the rects is defined in RenderResult */
-/* after render, the Combined pass is in combined,
- * for renderlayers read from files it is a real pass */
+/**
+ * - A render-layer is a full image, but with all passes and samples.
+ * - The size of the rects is defined in #RenderResult.
+ * - After render, the Combined pass is in combined,
+ * for render-layers read from files it is a real pass.
+ */
typedef struct RenderLayer {
struct RenderLayer *next, *prev;
@@ -247,15 +249,15 @@ void RE_render_result_full_channel_name(char *fullname,
const char *passname,
const char *viewname,
const char *chan_id,
- const int channel);
+ int channel);
struct ImBuf *RE_render_result_rect_to_ibuf(struct RenderResult *rr,
const struct ImageFormatData *imf,
const float dither,
- const int view_id);
+ int view_id);
void RE_render_result_rect_from_ibuf(struct RenderResult *rr,
const struct ImBuf *ibuf,
- const int view_id);
+ int view_id);
struct RenderLayer *RE_GetRenderLayer(struct RenderResult *rr, const char *name);
float *RE_RenderLayerGetPass(struct RenderLayer *rl, const char *name, const char *viewname);
diff --git a/source/blender/render/RE_texture.h b/source/blender/render/RE_texture.h
index be50eacd7bf..a4e30c917d5 100644
--- a/source/blender/render/RE_texture.h
+++ b/source/blender/render/RE_texture.h
@@ -44,8 +44,6 @@ bool RE_texture_evaluate(const struct MTex *mtex,
* \param fact: Texture strength.
* \param facg: Button strength value.
*/
-void texture_rgb_blend(
- float in[3], const float tex[3], const float out[3], float fact, float facg, int blendtype);
float texture_value_blend(float tex, float out, float fact, float facg, int blendtype);
void RE_texture_rng_init(void);
@@ -89,7 +87,6 @@ typedef struct TexResult {
float trgba[4];
/* Is actually a boolean: When true -> use alpha, false -> set alpha to 1.0. */
int talpha;
- float *nor;
} TexResult;
/* This one uses nodes. */
diff --git a/source/blender/render/RE_texture_margin.h b/source/blender/render/RE_texture_margin.h
index 0c91abeaddd..023615cea87 100644
--- a/source/blender/render/RE_texture_margin.h
+++ b/source/blender/render/RE_texture_margin.h
@@ -27,16 +27,13 @@ struct Mesh;
*/
void RE_generate_texturemargin_adjacentfaces(struct ImBuf *ibuf,
char *mask,
- const int margin,
+ int margin,
struct Mesh const *me,
char const *uv_layer,
const float uv_offset[2]);
-void RE_generate_texturemargin_adjacentfaces_dm(struct ImBuf *ibuf,
- char *mask,
- const int margin,
- struct DerivedMesh *dm,
- const float uv_offset[2]);
+void RE_generate_texturemargin_adjacentfaces_dm(
+ struct ImBuf *ibuf, char *mask, int margin, struct DerivedMesh *dm, const float uv_offset[2]);
#ifdef __cplusplus
}
diff --git a/source/blender/render/intern/bake.c b/source/blender/render/intern/bake.c
index 5953c0f0f8f..9ffe2879779 100644
--- a/source/blender/render/intern/bake.c
+++ b/source/blender/render/intern/bake.c
@@ -96,7 +96,7 @@ typedef struct TriTessFace {
const MVert *mverts[3];
const float *vert_normals[3];
const TSpace *tspace[3];
- float *loop_normal[3];
+ const float *loop_normal[3];
float normal[3]; /* for flat faces */
bool is_smooth;
} TriTessFace;
@@ -330,10 +330,10 @@ static bool cast_ray_highpoly(BVHTreeFromMesh *treeData,
{
int i;
int hit_mesh = -1;
- float hit_distance = max_ray_distance;
- if (hit_distance == 0.0f) {
+ float hit_distance_squared = max_ray_distance * max_ray_distance;
+ if (hit_distance_squared == 0.0f) {
/* No ray distance set, use maximum. */
- hit_distance = FLT_MAX;
+ hit_distance_squared = FLT_MAX;
}
BVHTreeRayHit *hits;
@@ -365,16 +365,14 @@ static bool cast_ray_highpoly(BVHTreeFromMesh *treeData,
}
if (hits[i].index != -1) {
- float distance;
- float hit_world[3];
-
/* distance comparison in world space */
+ float hit_world[3];
mul_v3_m4v3(hit_world, highpoly[i].obmat, hits[i].co);
- distance = len_squared_v3v3(hit_world, co);
+ float distance_squared = len_squared_v3v3(hit_world, co);
- if (distance < hit_distance) {
+ if (distance_squared < hit_distance_squared) {
hit_mesh = i;
- hit_distance = distance;
+ hit_distance_squared = distance_squared;
}
}
}
@@ -453,9 +451,6 @@ static bool cast_ray_highpoly(BVHTreeFromMesh *treeData,
static TriTessFace *mesh_calc_tri_tessface(Mesh *me, bool tangent, Mesh *me_eval)
{
int i;
- MVert *mvert;
- TSpace *tspace = NULL;
- float(*loop_normals)[3] = NULL;
const int tottri = poly_to_tri_count(me->totpoly, me->totloop);
MLoopTri *looptri;
@@ -465,7 +460,7 @@ static TriTessFace *mesh_calc_tri_tessface(Mesh *me, bool tangent, Mesh *me_eval
unsigned int mpoly_prev = UINT_MAX;
float no[3];
- mvert = CustomData_get_layer(&me->vdata, CD_MVERT);
+ const MVert *mvert = CustomData_get_layer(&me->vdata, CD_MVERT);
looptri = MEM_mallocN(sizeof(*looptri) * tottri, __func__);
triangles = MEM_callocN(sizeof(TriTessFace) * tottri, __func__);
@@ -482,6 +477,8 @@ static TriTessFace *mesh_calc_tri_tessface(Mesh *me, bool tangent, Mesh *me_eval
BKE_mesh_recalc_looptri(me->mloop, me->mpoly, me->mvert, me->totloop, me->totpoly, looptri);
}
+ const TSpace *tspace = NULL;
+ const float(*loop_normals)[3] = NULL;
if (tangent) {
BKE_mesh_ensure_normals_for_display(me_eval);
BKE_mesh_calc_normals_split(me_eval);
diff --git a/source/blender/render/intern/multires_bake.c b/source/blender/render/intern/multires_bake.c
index f93397eedab..e3229e20595 100644
--- a/source/blender/render/intern/multires_bake.c
+++ b/source/blender/render/intern/multires_bake.c
@@ -10,6 +10,7 @@
#include "MEM_guardedalloc.h"
#include "DNA_mesh_types.h"
+#include "DNA_meshdata_types.h"
#include "DNA_object_types.h"
#include "DNA_scene_types.h"
@@ -464,140 +465,141 @@ static void do_multires_bake(MultiresBakeRender *bkr,
const MLoopTri *mlooptri = dm->getLoopTriArray(dm);
const int lvl = bkr->lvl;
int tot_tri = dm->getNumLoopTri(dm);
+ if (tot_tri < 1) {
+ return;
+ }
- if (tot_tri > 0) {
- MultiresBakeThread *handles;
- MultiresBakeQueue queue;
-
- MVert *mvert = dm->getVertArray(dm);
- MPoly *mpoly = dm->getPolyArray(dm);
- MLoop *mloop = dm->getLoopArray(dm);
- MLoopUV *mloopuv = dm->getLoopDataArray(dm, CD_MLOOPUV);
- float *pvtangent = NULL;
-
- ListBase threads;
- int i, tot_thread = bkr->threads > 0 ? bkr->threads : BLI_system_thread_count();
-
- void *bake_data = NULL;
-
- Mesh *temp_mesh = BKE_mesh_new_nomain(
- dm->getNumVerts(dm), dm->getNumEdges(dm), 0, dm->getNumLoops(dm), dm->getNumPolys(dm));
- memcpy(temp_mesh->mvert, dm->getVertArray(dm), temp_mesh->totvert * sizeof(*temp_mesh->mvert));
- memcpy(temp_mesh->medge, dm->getEdgeArray(dm), temp_mesh->totedge * sizeof(*temp_mesh->medge));
- memcpy(temp_mesh->mpoly, dm->getPolyArray(dm), temp_mesh->totpoly * sizeof(*temp_mesh->mpoly));
- memcpy(temp_mesh->mloop, dm->getLoopArray(dm), temp_mesh->totloop * sizeof(*temp_mesh->mloop));
- const float(*vert_normals)[3] = BKE_mesh_vertex_normals_ensure(temp_mesh);
- const float(*poly_normals)[3] = BKE_mesh_poly_normals_ensure(temp_mesh);
-
- if (require_tangent) {
- if (CustomData_get_layer_index(&dm->loopData, CD_TANGENT) == -1) {
- BKE_mesh_calc_loop_tangent_ex(
- dm->getVertArray(dm),
- dm->getPolyArray(dm),
- dm->getNumPolys(dm),
- dm->getLoopArray(dm),
- dm->getLoopTriArray(dm),
- dm->getNumLoopTri(dm),
- &dm->loopData,
- true,
- NULL,
- 0,
- vert_normals,
- poly_normals,
- (const float(*)[3])dm->getLoopDataArray(dm, CD_NORMAL),
- (const float(*)[3])dm->getVertDataArray(dm, CD_ORCO), /* may be nullptr */
- /* result */
- &dm->loopData,
- dm->getNumLoops(dm),
- &dm->tangent_mask);
- }
-
- pvtangent = DM_get_loop_data_layer(dm, CD_TANGENT);
+ MultiresBakeThread *handles;
+ MultiresBakeQueue queue;
+
+ MVert *mvert = dm->getVertArray(dm);
+ MPoly *mpoly = dm->getPolyArray(dm);
+ MLoop *mloop = dm->getLoopArray(dm);
+ MLoopUV *mloopuv = dm->getLoopDataArray(dm, CD_MLOOPUV);
+ float *pvtangent = NULL;
+
+ ListBase threads;
+ int i, tot_thread = bkr->threads > 0 ? bkr->threads : BLI_system_thread_count();
+
+ void *bake_data = NULL;
+
+ Mesh *temp_mesh = BKE_mesh_new_nomain(
+ dm->getNumVerts(dm), dm->getNumEdges(dm), 0, dm->getNumLoops(dm), dm->getNumPolys(dm));
+ memcpy(temp_mesh->mvert, dm->getVertArray(dm), temp_mesh->totvert * sizeof(*temp_mesh->mvert));
+ memcpy(temp_mesh->medge, dm->getEdgeArray(dm), temp_mesh->totedge * sizeof(*temp_mesh->medge));
+ memcpy(temp_mesh->mpoly, dm->getPolyArray(dm), temp_mesh->totpoly * sizeof(*temp_mesh->mpoly));
+ memcpy(temp_mesh->mloop, dm->getLoopArray(dm), temp_mesh->totloop * sizeof(*temp_mesh->mloop));
+ const float(*vert_normals)[3] = BKE_mesh_vertex_normals_ensure(temp_mesh);
+ const float(*poly_normals)[3] = BKE_mesh_poly_normals_ensure(temp_mesh);
+
+ if (require_tangent) {
+ if (CustomData_get_layer_index(&dm->loopData, CD_TANGENT) == -1) {
+ BKE_mesh_calc_loop_tangent_ex(
+ dm->getVertArray(dm),
+ dm->getPolyArray(dm),
+ dm->getNumPolys(dm),
+ dm->getLoopArray(dm),
+ dm->getLoopTriArray(dm),
+ dm->getNumLoopTri(dm),
+ &dm->loopData,
+ true,
+ NULL,
+ 0,
+ vert_normals,
+ poly_normals,
+ (const float(*)[3])dm->getLoopDataArray(dm, CD_NORMAL),
+ (const float(*)[3])dm->getVertDataArray(dm, CD_ORCO), /* may be nullptr */
+ /* result */
+ &dm->loopData,
+ dm->getNumLoops(dm),
+ &dm->tangent_mask);
}
- /* all threads shares the same custom bake data */
- if (initBakeData) {
- bake_data = initBakeData(bkr, ibuf);
- }
+ pvtangent = DM_get_loop_data_layer(dm, CD_TANGENT);
+ }
- if (tot_thread > 1) {
- BLI_threadpool_init(&threads, do_multires_bake_thread, tot_thread);
- }
+ /* all threads shares the same custom bake data */
+ if (initBakeData) {
+ bake_data = initBakeData(bkr, ibuf);
+ }
- handles = MEM_callocN(tot_thread * sizeof(MultiresBakeThread), "do_multires_bake handles");
-
- init_ccgdm_arrays(bkr->hires_dm);
-
- /* faces queue */
- queue.cur_tri = 0;
- queue.tot_tri = tot_tri;
- BLI_spin_init(&queue.spin);
-
- /* fill in threads handles */
- for (i = 0; i < tot_thread; i++) {
- MultiresBakeThread *handle = &handles[i];
-
- handle->bkr = bkr;
- handle->image = ima;
- handle->queue = &queue;
-
- handle->data.mpoly = mpoly;
- handle->data.mvert = mvert;
- handle->data.vert_normals = vert_normals;
- handle->data.mloopuv = mloopuv;
- BKE_image_get_tile_uv(ima, tile->tile_number, handle->data.uv_offset);
- handle->data.mlooptri = mlooptri;
- handle->data.mloop = mloop;
- handle->data.pvtangent = pvtangent;
- handle->data.precomputed_normals = poly_normals; /* don't strictly need this */
- handle->data.w = ibuf->x;
- handle->data.h = ibuf->y;
- handle->data.lores_dm = dm;
- handle->data.hires_dm = bkr->hires_dm;
- handle->data.lvl = lvl;
- handle->data.pass_data = passKnownData;
- handle->data.thread_data = handle;
- handle->data.bake_data = bake_data;
- handle->data.ibuf = ibuf;
-
- handle->height_min = FLT_MAX;
- handle->height_max = -FLT_MAX;
-
- init_bake_rast(&handle->bake_rast, ibuf, &handle->data, flush_pixel, bkr->do_update);
-
- if (tot_thread > 1) {
- BLI_threadpool_insert(&threads, handle);
- }
- }
+ if (tot_thread > 1) {
+ BLI_threadpool_init(&threads, do_multires_bake_thread, tot_thread);
+ }
+
+ handles = MEM_callocN(tot_thread * sizeof(MultiresBakeThread), "do_multires_bake handles");
+
+ init_ccgdm_arrays(bkr->hires_dm);
+
+ /* faces queue */
+ queue.cur_tri = 0;
+ queue.tot_tri = tot_tri;
+ BLI_spin_init(&queue.spin);
+
+ /* fill in threads handles */
+ for (i = 0; i < tot_thread; i++) {
+ MultiresBakeThread *handle = &handles[i];
+
+ handle->bkr = bkr;
+ handle->image = ima;
+ handle->queue = &queue;
+
+ handle->data.mpoly = mpoly;
+ handle->data.mvert = mvert;
+ handle->data.vert_normals = vert_normals;
+ handle->data.mloopuv = mloopuv;
+ BKE_image_get_tile_uv(ima, tile->tile_number, handle->data.uv_offset);
+ handle->data.mlooptri = mlooptri;
+ handle->data.mloop = mloop;
+ handle->data.pvtangent = pvtangent;
+ handle->data.precomputed_normals = poly_normals; /* don't strictly need this */
+ handle->data.w = ibuf->x;
+ handle->data.h = ibuf->y;
+ handle->data.lores_dm = dm;
+ handle->data.hires_dm = bkr->hires_dm;
+ handle->data.lvl = lvl;
+ handle->data.pass_data = passKnownData;
+ handle->data.thread_data = handle;
+ handle->data.bake_data = bake_data;
+ handle->data.ibuf = ibuf;
+
+ handle->height_min = FLT_MAX;
+ handle->height_max = -FLT_MAX;
+
+ init_bake_rast(&handle->bake_rast, ibuf, &handle->data, flush_pixel, bkr->do_update);
- /* run threads */
if (tot_thread > 1) {
- BLI_threadpool_end(&threads);
+ BLI_threadpool_insert(&threads, handle);
}
- else {
- do_multires_bake_thread(&handles[0]);
- }
-
- /* construct bake result */
- result->height_min = handles[0].height_min;
- result->height_max = handles[0].height_max;
+ }
- for (i = 1; i < tot_thread; i++) {
- result->height_min = min_ff(result->height_min, handles[i].height_min);
- result->height_max = max_ff(result->height_max, handles[i].height_max);
- }
+ /* run threads */
+ if (tot_thread > 1) {
+ BLI_threadpool_end(&threads);
+ }
+ else {
+ do_multires_bake_thread(&handles[0]);
+ }
- BLI_spin_end(&queue.spin);
+ /* construct bake result */
+ result->height_min = handles[0].height_min;
+ result->height_max = handles[0].height_max;
- /* finalize baking */
- if (freeBakeData) {
- freeBakeData(bake_data);
- }
+ for (i = 1; i < tot_thread; i++) {
+ result->height_min = min_ff(result->height_min, handles[i].height_min);
+ result->height_max = max_ff(result->height_max, handles[i].height_max);
+ }
- MEM_freeN(handles);
+ BLI_spin_end(&queue.spin);
- BKE_id_free(NULL, temp_mesh);
+ /* finalize baking */
+ if (freeBakeData) {
+ freeBakeData(bake_data);
}
+
+ MEM_freeN(handles);
+
+ BKE_id_free(NULL, temp_mesh);
}
/* mode = 0: interpolate normals,
diff --git a/source/blender/render/intern/pipeline.c b/source/blender/render/intern/pipeline.c
index 6c06cd663fa..075f1ece647 100644
--- a/source/blender/render/intern/pipeline.c
+++ b/source/blender/render/intern/pipeline.c
@@ -87,8 +87,6 @@
# include "FRS_freestyle.h"
#endif
-#include "DEG_depsgraph.h"
-
/* internal */
#include "pipeline.h"
#include "render_result.h"
@@ -983,7 +981,7 @@ static void render_result_uncrop(Render *re)
render_result_free(re->result);
re->result = rres;
- /* weak... the display callback wants an active renderlayer pointer... */
+ /* Weak, the display callback wants an active render-layer pointer. */
re->result->renlay = render_get_active_layer(re, re->result);
BLI_rw_mutex_unlock(&re->resultmutex);
@@ -1315,8 +1313,8 @@ static void do_render_sequencer(Render *re)
true,
&context);
- /* the renderresult gets destroyed during the rendering, so we first collect all ibufs
- * and then we populate the final renderesult */
+ /* The render-result gets destroyed during the rendering, so we first collect all ibufs
+ * and then we populate the final render-result. */
for (view_id = 0; view_id < tot_views; view_id++) {
context.view_id = view_id;
diff --git a/source/blender/render/intern/render_result.c b/source/blender/render/intern/render_result.c
index 9f4aa642773..9992d1a507f 100644
--- a/source/blender/render/intern/render_result.c
+++ b/source/blender/render/intern/render_result.c
@@ -825,7 +825,7 @@ void render_result_merge(RenderResult *rr, RenderResult *rrpart)
if (rpass->rect == NULL || rpassp->rect == NULL) {
continue;
}
- /* Renderresult have all passes, renderpart only the active view's passes. */
+ /* Render-result have all passes, render-part only the active view's passes. */
if (!STREQ(rpassp->fullname, rpass->fullname)) {
continue;
}
diff --git a/source/blender/render/intern/render_result.h b/source/blender/render/intern/render_result.h
index 30f49775562..c84e0a04018 100644
--- a/source/blender/render/intern/render_result.h
+++ b/source/blender/render/intern/render_result.h
@@ -44,7 +44,7 @@ struct RenderResult *render_result_new(struct Render *re,
void render_result_passes_allocated_ensure(struct RenderResult *rr);
/**
- * From imbuf, if a handle was returned and
+ * From `imbuf`, if a handle was returned and
* it's not a single-layer multi-view we convert this to render result.
*/
struct RenderResult *render_result_new_from_exr(
diff --git a/source/blender/render/intern/texture_image.c b/source/blender/render/intern/texture_image.c
index 69c24a18f36..7da9e7c3d58 100644
--- a/source/blender/render/intern/texture_image.c
+++ b/source/blender/render/intern/texture_image.c
@@ -88,14 +88,13 @@ int imagewrap(Tex *tex,
struct ImagePool *pool,
const bool skip_load_image)
{
- float fx, fy, val1, val2, val3;
+ float fx, fy;
int x, y, retval;
int xi, yi; /* original values */
texres->tin = texres->trgba[3] = texres->trgba[0] = texres->trgba[1] = texres->trgba[2] = 0.0f;
- /* we need to set retval OK, otherwise texture code generates normals itself... */
- retval = texres->nor ? (TEX_RGB | TEX_NOR) : TEX_RGB;
+ retval = TEX_RGB;
/* quick tests */
if (ima == NULL) {
@@ -256,47 +255,6 @@ int imagewrap(Tex *tex,
ibuf_get_color(texres->trgba, ibuf, x, y);
}
- if (texres->nor) {
- if (tex->imaflag & TEX_NORMALMAP) {
- /* Normal from color:
- * The invert of the red channel is to make
- * the normal map compliant with the outside world.
- * It needs to be done because in Blender
- * the normal used in the renderer points inward. It is generated
- * this way in calc_vertexnormals(). Should this ever change
- * this negate must be removed. */
- texres->nor[0] = -2.0f * (texres->trgba[0] - 0.5f);
- texres->nor[1] = 2.0f * (texres->trgba[1] - 0.5f);
- texres->nor[2] = 2.0f * (texres->trgba[2] - 0.5f);
- }
- else {
- /* bump: take three samples */
- val1 = texres->trgba[0] + texres->trgba[1] + texres->trgba[2];
-
- if (x < ibuf->x - 1) {
- float col[4];
- ibuf_get_color(col, ibuf, x + 1, y);
- val2 = (col[0] + col[1] + col[2]);
- }
- else {
- val2 = val1;
- }
-
- if (y < ibuf->y - 1) {
- float col[4];
- ibuf_get_color(col, ibuf, x, y + 1);
- val3 = (col[0] + col[1] + col[2]);
- }
- else {
- val3 = val1;
- }
-
- /* do not mix up x and y here! */
- texres->nor[0] = (val1 - val2);
- texres->nor[1] = (val1 - val3);
- }
- }
-
if (texres->talpha) {
texres->tin = texres->trgba[3];
}
@@ -989,7 +947,7 @@ static int imagewraposa_aniso(Tex *tex,
{
TexResult texr;
float fx, fy, minx, maxx, miny, maxy;
- float maxd, val1, val2, val3;
+ float maxd;
int curmap, retval, intpol, extflag = 0;
afdata_t AFD;
@@ -1008,8 +966,7 @@ static int imagewraposa_aniso(Tex *tex,
texres->tin = texres->trgba[3] = texres->trgba[0] = texres->trgba[1] = texres->trgba[2] = 0.0f;
- /* we need to set retval OK, otherwise texture code generates normals itself... */
- retval = texres->nor ? (TEX_RGB | TEX_NOR) : TEX_RGB;
+ retval = TEX_RGB;
/* quick tests */
if (ibuf == NULL && ima == NULL) {
@@ -1040,7 +997,7 @@ static int imagewraposa_aniso(Tex *tex,
if (ima) {
if ((tex->imaflag & TEX_USEALPHA) && (ima->alpha_mode != IMA_ALPHA_IGNORE)) {
if ((tex->imaflag & TEX_CALCALPHA) == 0) {
- texres->talpha = 1;
+ texres->talpha = true;
}
}
}
@@ -1215,7 +1172,7 @@ static int imagewraposa_aniso(Tex *tex,
AFD.intpol = intpol;
AFD.extflag = extflag;
- /* brecht: added stupid clamping here, large dx/dy can give very large
+ /* NOTE(@brecht): added stupid clamping here, large dx/dy can give very large
* filter sizes which take ages to render, it may be better to do this
* more intelligently later in the code .. probably it's not noticeable */
if (AFD.dxt[0] * AFD.dxt[0] + AFD.dxt[1] * AFD.dxt[1] > 2.0f * 2.0f) {
@@ -1301,48 +1258,17 @@ static int imagewraposa_aniso(Tex *tex,
}
/* filter functions take care of interpolation themselves, no need to modify dxt/dyt here */
-
- if (texres->nor && ((tex->imaflag & TEX_NORMALMAP) == 0)) {
- /* color & normal */
- filterfunc(texres, curibuf, fx, fy, &AFD);
- val1 = texres->trgba[0] + texres->trgba[1] + texres->trgba[2];
- filterfunc(&texr, curibuf, fx + dxt[0], fy + dxt[1], &AFD);
- val2 = texr.trgba[0] + texr.trgba[1] + texr.trgba[2];
- filterfunc(&texr, curibuf, fx + dyt[0], fy + dyt[1], &AFD);
- val3 = texr.trgba[0] + texr.trgba[1] + texr.trgba[2];
- /* don't switch x or y! */
- texres->nor[0] = val1 - val2;
- texres->nor[1] = val1 - val3;
- if (previbuf != curibuf) { /* interpolate */
- filterfunc(&texr, previbuf, fx, fy, &AFD);
- /* rgb */
- texres->trgba[0] += levf * (texr.trgba[0] - texres->trgba[0]);
- texres->trgba[1] += levf * (texr.trgba[1] - texres->trgba[1]);
- texres->trgba[2] += levf * (texr.trgba[2] - texres->trgba[2]);
- texres->trgba[3] += levf * (texr.trgba[3] - texres->trgba[3]);
- /* normal */
- val1 += levf * ((texr.trgba[0] + texr.trgba[1] + texr.trgba[2]) - val1);
- filterfunc(&texr, previbuf, fx + dxt[0], fy + dxt[1], &AFD);
- val2 += levf * ((texr.trgba[0] + texr.trgba[1] + texr.trgba[2]) - val2);
- filterfunc(&texr, previbuf, fx + dyt[0], fy + dyt[1], &AFD);
- val3 += levf * ((texr.trgba[0] + texr.trgba[1] + texr.trgba[2]) - val3);
- texres->nor[0] = val1 - val2; /* vals have been interpolated above! */
- texres->nor[1] = val1 - val3;
- }
+ filterfunc(texres, curibuf, fx, fy, &AFD);
+ if (previbuf != curibuf) { /* interpolate */
+ filterfunc(&texr, previbuf, fx, fy, &AFD);
+ texres->trgba[0] += levf * (texr.trgba[0] - texres->trgba[0]);
+ texres->trgba[1] += levf * (texr.trgba[1] - texres->trgba[1]);
+ texres->trgba[2] += levf * (texr.trgba[2] - texres->trgba[2]);
+ texres->trgba[3] += levf * (texr.trgba[3] - texres->trgba[3]);
}
- else { /* color */
- filterfunc(texres, curibuf, fx, fy, &AFD);
- if (previbuf != curibuf) { /* interpolate */
- filterfunc(&texr, previbuf, fx, fy, &AFD);
- texres->trgba[0] += levf * (texr.trgba[0] - texres->trgba[0]);
- texres->trgba[1] += levf * (texr.trgba[1] - texres->trgba[1]);
- texres->trgba[2] += levf * (texr.trgba[2] - texres->trgba[2]);
- texres->trgba[3] += levf * (texr.trgba[3] - texres->trgba[3]);
- }
- if (tex->texfilter != TXF_EWA) {
- alpha_clip_aniso(ibuf, fx - minx, fy - miny, fx + minx, fy + miny, extflag, texres);
- }
+ if (tex->texfilter != TXF_EWA) {
+ alpha_clip_aniso(ibuf, fx - minx, fy - miny, fx + minx, fy + miny, extflag, texres);
}
}
else { /* no mipmap */
@@ -1372,23 +1298,9 @@ static int imagewraposa_aniso(Tex *tex,
AFD.dusc = 1.0f / ff;
AFD.dvsc = ff / (float)ibuf->y;
}
- if (texres->nor && ((tex->imaflag & TEX_NORMALMAP) == 0)) {
- /* color & normal */
- filterfunc(texres, ibuf, fx, fy, &AFD);
- val1 = texres->trgba[0] + texres->trgba[1] + texres->trgba[2];
- filterfunc(&texr, ibuf, fx + dxt[0], fy + dxt[1], &AFD);
- val2 = texr.trgba[0] + texr.trgba[1] + texr.trgba[2];
- filterfunc(&texr, ibuf, fx + dyt[0], fy + dyt[1], &AFD);
- val3 = texr.trgba[0] + texr.trgba[1] + texr.trgba[2];
- /* don't switch x or y! */
- texres->nor[0] = val1 - val2;
- texres->nor[1] = val1 - val3;
- }
- else {
- filterfunc(texres, ibuf, fx, fy, &AFD);
- if (tex->texfilter != TXF_EWA) {
- alpha_clip_aniso(ibuf, fx - minx, fy - miny, fx + minx, fy + miny, extflag, texres);
- }
+ filterfunc(texres, ibuf, fx, fy, &AFD);
+ if (tex->texfilter != TXF_EWA) {
+ alpha_clip_aniso(ibuf, fx - minx, fy - miny, fx + minx, fy + miny, extflag, texres);
}
}
@@ -1403,18 +1315,6 @@ static int imagewraposa_aniso(Tex *tex,
texres->trgba[3] = 1.0f - texres->trgba[3];
}
- if (texres->nor && (tex->imaflag & TEX_NORMALMAP)) { /* normal from color */
- /* The invert of the red channel is to make
- * the normal map compliant with the outside world.
- * It needs to be done because in Blender
- * the normal used in the renderer points inward. It is generated
- * this way in calc_vertexnormals(). Should this ever change
- * this negate must be removed. */
- texres->nor[0] = -2.0f * (texres->trgba[0] - 0.5f);
- texres->nor[1] = 2.0f * (texres->trgba[1] - 0.5f);
- texres->nor[2] = 2.0f * (texres->trgba[2] - 0.5f);
- }
-
/* de-premul, this is being pre-multiplied in shade_input_do_shade()
* TXF: this currently does not (yet?) work properly, destroys edge AA in clip/checker mode,
* so for now commented out also disabled in imagewraposa()
@@ -1451,7 +1351,7 @@ int imagewraposa(Tex *tex,
{
TexResult texr;
float fx, fy, minx, maxx, miny, maxy, dx, dy, dxt[2], dyt[2];
- float maxd, pixsize, val1, val2, val3;
+ float maxd, pixsize;
int curmap, retval, imaprepeat, imapextend;
/* TXF: since dxt/dyt might be modified here and since they might be needed after imagewraposa()
@@ -1466,8 +1366,7 @@ int imagewraposa(Tex *tex,
texres->tin = texres->trgba[3] = texres->trgba[0] = texres->trgba[1] = texres->trgba[2] = 0.0f;
- /* we need to set retval OK, otherwise texture code generates normals itself... */
- retval = texres->nor ? (TEX_RGB | TEX_NOR) : TEX_RGB;
+ retval = TEX_RGB;
/* quick tests */
if (ibuf == NULL && ima == NULL) {
@@ -1762,118 +1661,30 @@ int imagewraposa(Tex *tex,
}
}
- if (texres->nor && (tex->imaflag & TEX_NORMALMAP) == 0) {
- /* a bit extra filter */
- // minx*= 1.35f;
- // miny*= 1.35f;
-
- boxsample(
- curibuf, fx - minx, fy - miny, fx + minx, fy + miny, texres, imaprepeat, imapextend);
- val1 = texres->trgba[0] + texres->trgba[1] + texres->trgba[2];
- boxsample(curibuf,
- fx - minx + dxt[0],
- fy - miny + dxt[1],
- fx + minx + dxt[0],
- fy + miny + dxt[1],
- &texr,
- imaprepeat,
- imapextend);
- val2 = texr.trgba[0] + texr.trgba[1] + texr.trgba[2];
- boxsample(curibuf,
- fx - minx + dyt[0],
- fy - miny + dyt[1],
- fx + minx + dyt[0],
- fy + miny + dyt[1],
- &texr,
- imaprepeat,
- imapextend);
- val3 = texr.trgba[0] + texr.trgba[1] + texr.trgba[2];
-
- /* don't switch x or y! */
- texres->nor[0] = (val1 - val2);
- texres->nor[1] = (val1 - val3);
-
- if (previbuf != curibuf) { /* interpolate */
-
- boxsample(
- previbuf, fx - minx, fy - miny, fx + minx, fy + miny, &texr, imaprepeat, imapextend);
-
- /* calc rgb */
- dx = 2.0f * (pixsize - maxd) / pixsize;
- if (dx >= 1.0f) {
- texres->trgba[3] = texr.trgba[3];
- texres->trgba[2] = texr.trgba[2];
- texres->trgba[1] = texr.trgba[1];
- texres->trgba[0] = texr.trgba[0];
- }
- else {
- dy = 1.0f - dx;
- texres->trgba[2] = dy * texres->trgba[2] + dx * texr.trgba[2];
- texres->trgba[1] = dy * texres->trgba[1] + dx * texr.trgba[1];
- texres->trgba[0] = dy * texres->trgba[0] + dx * texr.trgba[0];
- texres->trgba[3] = dy * texres->trgba[3] + dx * texr.trgba[3];
- }
-
- val1 = dy * val1 + dx * (texr.trgba[0] + texr.trgba[1] + texr.trgba[2]);
- boxsample(previbuf,
- fx - minx + dxt[0],
- fy - miny + dxt[1],
- fx + minx + dxt[0],
- fy + miny + dxt[1],
- &texr,
- imaprepeat,
- imapextend);
- val2 = dy * val2 + dx * (texr.trgba[0] + texr.trgba[1] + texr.trgba[2]);
- boxsample(previbuf,
- fx - minx + dyt[0],
- fy - miny + dyt[1],
- fx + minx + dyt[0],
- fy + miny + dyt[1],
- &texr,
- imaprepeat,
- imapextend);
- val3 = dy * val3 + dx * (texr.trgba[0] + texr.trgba[1] + texr.trgba[2]);
-
- texres->nor[0] = (val1 - val2); /* vals have been interpolated above! */
- texres->nor[1] = (val1 - val3);
-
- if (dx < 1.0f) {
- dy = 1.0f - dx;
- texres->trgba[2] = dy * texres->trgba[2] + dx * texr.trgba[2];
- texres->trgba[1] = dy * texres->trgba[1] + dx * texr.trgba[1];
- texres->trgba[0] = dy * texres->trgba[0] + dx * texr.trgba[0];
- texres->trgba[3] = dy * texres->trgba[3] + dx * texr.trgba[3];
- }
- }
- texres->nor[0] *= bumpscale;
- texres->nor[1] *= bumpscale;
- }
- else {
- maxx = fx + minx;
- minx = fx - minx;
- maxy = fy + miny;
- miny = fy - miny;
+ maxx = fx + minx;
+ minx = fx - minx;
+ maxy = fy + miny;
+ miny = fy - miny;
- boxsample(curibuf, minx, miny, maxx, maxy, texres, imaprepeat, imapextend);
+ boxsample(curibuf, minx, miny, maxx, maxy, texres, imaprepeat, imapextend);
- if (previbuf != curibuf) { /* interpolate */
- boxsample(previbuf, minx, miny, maxx, maxy, &texr, imaprepeat, imapextend);
+ if (previbuf != curibuf) { /* interpolate */
+ boxsample(previbuf, minx, miny, maxx, maxy, &texr, imaprepeat, imapextend);
- fx = 2.0f * (pixsize - maxd) / pixsize;
+ fx = 2.0f * (pixsize - maxd) / pixsize;
- if (fx >= 1.0f) {
- texres->trgba[3] = texr.trgba[3];
- texres->trgba[2] = texr.trgba[2];
- texres->trgba[1] = texr.trgba[1];
- texres->trgba[0] = texr.trgba[0];
- }
- else {
- fy = 1.0f - fx;
- texres->trgba[2] = fy * texres->trgba[2] + fx * texr.trgba[2];
- texres->trgba[1] = fy * texres->trgba[1] + fx * texr.trgba[1];
- texres->trgba[0] = fy * texres->trgba[0] + fx * texr.trgba[0];
- texres->trgba[3] = fy * texres->trgba[3] + fx * texr.trgba[3];
- }
+ if (fx >= 1.0f) {
+ texres->trgba[3] = texr.trgba[3];
+ texres->trgba[2] = texr.trgba[2];
+ texres->trgba[1] = texr.trgba[1];
+ texres->trgba[0] = texr.trgba[0];
+ }
+ else {
+ fy = 1.0f - fx;
+ texres->trgba[2] = fy * texres->trgba[2] + fx * texr.trgba[2];
+ texres->trgba[1] = fy * texres->trgba[1] + fx * texr.trgba[1];
+ texres->trgba[0] = fy * texres->trgba[0] + fx * texr.trgba[0];
+ texres->trgba[3] = fy * texres->trgba[3] + fx * texr.trgba[3];
}
}
}
@@ -1889,35 +1700,7 @@ int imagewraposa(Tex *tex,
}
}
- if (texres->nor && (tex->imaflag & TEX_NORMALMAP) == 0) {
- boxsample(ibuf, fx - minx, fy - miny, fx + minx, fy + miny, texres, imaprepeat, imapextend);
- val1 = texres->trgba[0] + texres->trgba[1] + texres->trgba[2];
- boxsample(ibuf,
- fx - minx + dxt[0],
- fy - miny + dxt[1],
- fx + minx + dxt[0],
- fy + miny + dxt[1],
- &texr,
- imaprepeat,
- imapextend);
- val2 = texr.trgba[0] + texr.trgba[1] + texr.trgba[2];
- boxsample(ibuf,
- fx - minx + dyt[0],
- fy - miny + dyt[1],
- fx + minx + dyt[0],
- fy + miny + dyt[1],
- &texr,
- imaprepeat,
- imapextend);
- val3 = texr.trgba[0] + texr.trgba[1] + texr.trgba[2];
-
- /* don't switch x or y! */
- texres->nor[0] = (val1 - val2);
- texres->nor[1] = (val1 - val3);
- }
- else {
- boxsample(ibuf, fx - minx, fy - miny, fx + minx, fy + miny, texres, imaprepeat, imapextend);
- }
+ boxsample(ibuf, fx - minx, fy - miny, fx + minx, fy + miny, texres, imaprepeat, imapextend);
}
if (tex->imaflag & TEX_CALCALPHA) {
@@ -1932,17 +1715,6 @@ int imagewraposa(Tex *tex,
texres->trgba[3] = 1.0f - texres->trgba[3];
}
- if (texres->nor && (tex->imaflag & TEX_NORMALMAP)) {
- /* Normal from color:
- * The invert of the red channel is to make the normal map compliant with the outside world.
- * It needs to be done because in Blender the normal used in the renderer points inward.
- * It is generated this way in #calc_vertexnormals().
- * Should this ever change this negate must be removed. */
- texres->nor[0] = -2.0f * (texres->trgba[0] - 0.5f);
- texres->nor[1] = 2.0f * (texres->trgba[1] - 0.5f);
- texres->nor[2] = 2.0f * (texres->trgba[2] - 0.5f);
- }
-
/* de-premul, this is being pre-multiplied in shade_input_do_shade() */
/* do not de-premul for generated alpha, it is already in straight */
if (texres->trgba[3] != 1.0f && texres->trgba[3] > 1e-4f && !(tex->imaflag & TEX_CALCALPHA)) {
diff --git a/source/blender/render/intern/texture_margin.cc b/source/blender/render/intern/texture_margin.cc
index 2d68148a86a..37ef9213615 100644
--- a/source/blender/render/intern/texture_margin.cc
+++ b/source/blender/render/intern/texture_margin.cc
@@ -12,6 +12,7 @@
#include "BLI_vector.hh"
#include "BKE_DerivedMesh.h"
+#include "BKE_customdata.h"
#include "BKE_mesh.h"
#include "DNA_mesh_types.h"
@@ -492,11 +493,11 @@ static void generate_margin(ImBuf *ibuf,
MPoly *mpoly;
MLoop *mloop;
- MLoopUV const *mloopuv;
+ const MLoopUV *mloopuv;
int totpoly, totloop, totedge;
int tottri;
- MLoopTri const *looptri;
+ const MLoopTri *looptri;
MLoopTri *looptri_mem = nullptr;
if (me) {
@@ -508,11 +509,11 @@ static void generate_margin(ImBuf *ibuf,
mloop = me->mloop;
if ((uv_layer == nullptr) || (uv_layer[0] == '\0')) {
- mloopuv = static_cast<MLoopUV const *>(CustomData_get_layer(&me->ldata, CD_MLOOPUV));
+ mloopuv = static_cast<const MLoopUV *>(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 *>(
+ mloopuv = static_cast<const MLoopUV *>(
CustomData_get_layer_n(&me->ldata, CD_MLOOPUV, uv_id));
}
diff --git a/source/blender/render/intern/texture_pointdensity.c b/source/blender/render/intern/texture_pointdensity.c
index 8ba3bac7cad..6e0bae700dc 100644
--- a/source/blender/render/intern/texture_pointdensity.c
+++ b/source/blender/render/intern/texture_pointdensity.c
@@ -271,7 +271,6 @@ static void pointdensity_cache_vertex_color(PointDensity *pd,
{
const MLoop *mloop = mesh->mloop;
const int totloop = mesh->totloop;
- const MLoopCol *mcol;
char layername[MAX_CUSTOMDATA_LAYER_NAME];
int i;
@@ -282,7 +281,7 @@ static void pointdensity_cache_vertex_color(PointDensity *pd,
}
CustomData_validate_layer_name(
&mesh->ldata, CD_PROP_BYTE_COLOR, pd->vertex_attribute_name, layername);
- mcol = CustomData_get_layer_named(&mesh->ldata, CD_PROP_BYTE_COLOR, layername);
+ const MLoopCol *mcol = CustomData_get_layer_named(&mesh->ldata, CD_PROP_BYTE_COLOR, layername);
if (!mcol) {
return;
}
@@ -323,13 +322,12 @@ static void pointdensity_cache_vertex_weight(PointDensity *pd,
float *data_color)
{
const int totvert = mesh->totvert;
- const MDeformVert *mdef, *dv;
int mdef_index;
int i;
BLI_assert(data_color);
- mdef = CustomData_get_layer(&mesh->vdata, CD_MDEFORMVERT);
+ const MDeformVert *mdef = CustomData_get_layer(&mesh->vdata, CD_MDEFORMVERT);
if (!mdef) {
return;
}
@@ -341,6 +339,7 @@ static void pointdensity_cache_vertex_weight(PointDensity *pd,
return;
}
+ const MDeformVert *dv;
for (i = 0, dv = mdef; i < totvert; i++, dv++, data_color += 3) {
MDeformWeight *dw;
int j;
diff --git a/source/blender/render/intern/texture_procedural.c b/source/blender/render/intern/texture_procedural.c
index 73dbcfdfeab..37605236738 100644
--- a/source/blender/render/intern/texture_procedural.c
+++ b/source/blender/render/intern/texture_procedural.c
@@ -61,34 +61,6 @@ void RE_texture_rng_exit(void)
/* ------------------------------------------------------------------------- */
-/* This allows color-banded textures to control normals as well. */
-static void tex_normal_derivate(const Tex *tex, TexResult *texres)
-{
- if (tex->flag & TEX_COLORBAND) {
- float col[4];
- if (BKE_colorband_evaluate(tex->coba, texres->tin, col)) {
- float fac0, fac1, fac2, fac3;
-
- fac0 = (col[0] + col[1] + col[2]);
- BKE_colorband_evaluate(tex->coba, texres->nor[0], col);
- fac1 = (col[0] + col[1] + col[2]);
- BKE_colorband_evaluate(tex->coba, texres->nor[1], col);
- fac2 = (col[0] + col[1] + col[2]);
- BKE_colorband_evaluate(tex->coba, texres->nor[2], col);
- fac3 = (col[0] + col[1] + col[2]);
-
- texres->nor[0] = (fac0 - fac1) / 3.0f;
- texres->nor[1] = (fac0 - fac2) / 3.0f;
- texres->nor[2] = (fac0 - fac3) / 3.0f;
-
- return;
- }
- }
- texres->nor[0] = texres->tin - texres->nor[0];
- texres->nor[1] = texres->tin - texres->nor[1];
- texres->nor[2] = texres->tin - texres->nor[2];
-}
-
static int blend(const Tex *tex, const float texvec[3], TexResult *texres)
{
float x, y, t;
@@ -165,37 +137,7 @@ static int clouds(const Tex *tex, const float texvec[3], TexResult *texres)
(tex->noisetype != TEX_NOISESOFT),
tex->noisebasis);
- if (texres->nor != NULL) {
- /* calculate bumpnormal */
- texres->nor[0] = BLI_noise_generic_turbulence(tex->noisesize,
- texvec[0] + tex->nabla,
- texvec[1],
- texvec[2],
- tex->noisedepth,
- (tex->noisetype != TEX_NOISESOFT),
- tex->noisebasis);
- texres->nor[1] = BLI_noise_generic_turbulence(tex->noisesize,
- texvec[0],
- texvec[1] + tex->nabla,
- texvec[2],
- tex->noisedepth,
- (tex->noisetype != TEX_NOISESOFT),
- tex->noisebasis);
- texres->nor[2] = BLI_noise_generic_turbulence(tex->noisesize,
- texvec[0],
- texvec[1],
- texvec[2] + tex->nabla,
- tex->noisedepth,
- (tex->noisetype != TEX_NOISESOFT),
- tex->noisebasis);
-
- tex_normal_derivate(tex, texres);
- rv |= TEX_NOR;
- }
-
if (tex->stype == TEX_COLOR) {
- /* in this case, int. value should really be computed from color,
- * and bumpnormal from that, would be too slow, looks ok as is */
texres->trgba[0] = texres->tin;
texres->trgba[1] = BLI_noise_generic_turbulence(tex->noisesize,
texvec[1],
@@ -298,15 +240,6 @@ static int wood(const Tex *tex, const float texvec[3], TexResult *texres)
int rv = TEX_INT;
texres->tin = wood_int(tex, texvec[0], texvec[1], texvec[2]);
- if (texres->nor != NULL) {
- /* calculate bumpnormal */
- texres->nor[0] = wood_int(tex, texvec[0] + tex->nabla, texvec[1], texvec[2]);
- texres->nor[1] = wood_int(tex, texvec[0], texvec[1] + tex->nabla, texvec[2]);
- texres->nor[2] = wood_int(tex, texvec[0], texvec[1], texvec[2] + tex->nabla);
-
- tex_normal_derivate(tex, texres);
- rv |= TEX_NOR;
- }
BRICONT;
@@ -358,17 +291,6 @@ static int marble(const Tex *tex, const float texvec[3], TexResult *texres)
texres->tin = marble_int(tex, texvec[0], texvec[1], texvec[2]);
- if (texres->nor != NULL) {
- /* calculate bumpnormal */
- texres->nor[0] = marble_int(tex, texvec[0] + tex->nabla, texvec[1], texvec[2]);
- texres->nor[1] = marble_int(tex, texvec[0], texvec[1] + tex->nabla, texvec[2]);
- texres->nor[2] = marble_int(tex, texvec[0], texvec[1], texvec[2] + tex->nabla);
-
- tex_normal_derivate(tex, texres);
-
- rv |= TEX_NOR;
- }
-
BRICONT;
return rv;
@@ -454,7 +376,7 @@ static int magic(const Tex *tex, const float texvec[3], TexResult *texres)
/* newnoise: stucci also modified to use different noisebasis */
static int stucci(const Tex *tex, const float texvec[3], TexResult *texres)
{
- float nor[3], b2, ofs;
+ float b2, ofs;
int retval = TEX_INT;
b2 = BLI_noise_generic_noise(tex->noisesize,
@@ -469,40 +391,13 @@ static int stucci(const Tex *tex, const float texvec[3], TexResult *texres)
if (tex->stype) {
ofs *= (b2 * b2);
}
- nor[0] = BLI_noise_generic_noise(tex->noisesize,
- texvec[0] + ofs,
- texvec[1],
- texvec[2],
- (tex->noisetype != TEX_NOISESOFT),
- tex->noisebasis);
- nor[1] = BLI_noise_generic_noise(tex->noisesize,
- texvec[0],
- texvec[1] + ofs,
- texvec[2],
- (tex->noisetype != TEX_NOISESOFT),
- tex->noisebasis);
- nor[2] = BLI_noise_generic_noise(tex->noisesize,
- texvec[0],
- texvec[1],
- texvec[2] + ofs,
- (tex->noisetype != TEX_NOISESOFT),
- tex->noisebasis);
-
- texres->tin = nor[2];
-
- if (texres->nor) {
-
- copy_v3_v3(texres->nor, nor);
- tex_normal_derivate(tex, texres);
-
- if (tex->stype == TEX_WALLOUT) {
- texres->nor[0] = -texres->nor[0];
- texres->nor[1] = -texres->nor[1];
- texres->nor[2] = -texres->nor[2];
- }
- retval |= TEX_NOR;
- }
+ texres->tin = BLI_noise_generic_noise(tex->noisesize,
+ texvec[0],
+ texvec[1],
+ texvec[2] + ofs,
+ (tex->noisetype != TEX_NOISESOFT),
+ tex->noisebasis);
if (tex->stype == TEX_WALLOUT) {
texres->tin = 1.0f - texres->tin;
@@ -538,36 +433,6 @@ static int mg_mFractalOrfBmTex(const Tex *tex, const float texvec[3], TexResult
tex->mg_octaves,
tex->noisebasis);
- if (texres->nor != NULL) {
- float ofs = tex->nabla / tex->noisesize; /* also scaling of texvec */
-
- /* calculate bumpnormal */
- texres->nor[0] = tex->ns_outscale * mgravefunc(texvec[0] + ofs,
- texvec[1],
- texvec[2],
- tex->mg_H,
- tex->mg_lacunarity,
- tex->mg_octaves,
- tex->noisebasis);
- texres->nor[1] = tex->ns_outscale * mgravefunc(texvec[0],
- texvec[1] + ofs,
- texvec[2],
- tex->mg_H,
- tex->mg_lacunarity,
- tex->mg_octaves,
- tex->noisebasis);
- texres->nor[2] = tex->ns_outscale * mgravefunc(texvec[0],
- texvec[1],
- texvec[2] + ofs,
- tex->mg_H,
- tex->mg_lacunarity,
- tex->mg_octaves,
- tex->noisebasis);
-
- tex_normal_derivate(tex, texres);
- rv |= TEX_NOR;
- }
-
BRICONT;
return rv;
@@ -595,42 +460,6 @@ static int mg_ridgedOrHybridMFTex(const Tex *tex, const float texvec[3], TexResu
tex->mg_gain,
tex->noisebasis);
- if (texres->nor != NULL) {
- float ofs = tex->nabla / tex->noisesize; /* also scaling of texvec */
-
- /* calculate bumpnormal */
- texres->nor[0] = tex->ns_outscale * mgravefunc(texvec[0] + ofs,
- texvec[1],
- texvec[2],
- tex->mg_H,
- tex->mg_lacunarity,
- tex->mg_octaves,
- tex->mg_offset,
- tex->mg_gain,
- tex->noisebasis);
- texres->nor[1] = tex->ns_outscale * mgravefunc(texvec[0],
- texvec[1] + ofs,
- texvec[2],
- tex->mg_H,
- tex->mg_lacunarity,
- tex->mg_octaves,
- tex->mg_offset,
- tex->mg_gain,
- tex->noisebasis);
- texres->nor[2] = tex->ns_outscale * mgravefunc(texvec[0],
- texvec[1],
- texvec[2] + ofs,
- tex->mg_H,
- tex->mg_lacunarity,
- tex->mg_octaves,
- tex->mg_offset,
- tex->mg_gain,
- tex->noisebasis);
-
- tex_normal_derivate(tex, texres);
- rv |= TEX_NOR;
- }
-
BRICONT;
return rv;
@@ -649,39 +478,6 @@ static int mg_HTerrainTex(const Tex *tex, const float texvec[3], TexResult *texr
tex->mg_offset,
tex->noisebasis);
- if (texres->nor != NULL) {
- float ofs = tex->nabla / tex->noisesize; /* also scaling of texvec */
-
- /* calculate bumpnormal */
- texres->nor[0] = tex->ns_outscale * BLI_noise_mg_hetero_terrain(texvec[0] + ofs,
- texvec[1],
- texvec[2],
- tex->mg_H,
- tex->mg_lacunarity,
- tex->mg_octaves,
- tex->mg_offset,
- tex->noisebasis);
- texres->nor[1] = tex->ns_outscale * BLI_noise_mg_hetero_terrain(texvec[0],
- texvec[1] + ofs,
- texvec[2],
- tex->mg_H,
- tex->mg_lacunarity,
- tex->mg_octaves,
- tex->mg_offset,
- tex->noisebasis);
- texres->nor[2] = tex->ns_outscale * BLI_noise_mg_hetero_terrain(texvec[0],
- texvec[1],
- texvec[2] + ofs,
- tex->mg_H,
- tex->mg_lacunarity,
- tex->mg_octaves,
- tex->mg_offset,
- tex->noisebasis);
-
- tex_normal_derivate(tex, texres);
- rv |= TEX_NOR;
- }
-
BRICONT;
return rv;
@@ -694,33 +490,6 @@ static int mg_distNoiseTex(const Tex *tex, const float texvec[3], TexResult *tex
texres->tin = BLI_noise_mg_variable_lacunarity(
texvec[0], texvec[1], texvec[2], tex->dist_amount, tex->noisebasis, tex->noisebasis2);
- if (texres->nor != NULL) {
- float ofs = tex->nabla / tex->noisesize; /* also scaling of texvec */
-
- /* calculate bumpnormal */
- texres->nor[0] = BLI_noise_mg_variable_lacunarity(texvec[0] + ofs,
- texvec[1],
- texvec[2],
- tex->dist_amount,
- tex->noisebasis,
- tex->noisebasis2);
- texres->nor[1] = BLI_noise_mg_variable_lacunarity(texvec[0],
- texvec[1] + ofs,
- texvec[2],
- tex->dist_amount,
- tex->noisebasis,
- tex->noisebasis2);
- texres->nor[2] = BLI_noise_mg_variable_lacunarity(texvec[0],
- texvec[1],
- texvec[2] + ofs,
- tex->dist_amount,
- tex->noisebasis,
- tex->noisebasis2);
-
- tex_normal_derivate(tex, texres);
- rv |= TEX_NOR;
- }
-
BRICONT;
return rv;
@@ -788,21 +557,6 @@ static int voronoiTex(const Tex *tex, const float texvec[3], TexResult *texres)
}
}
- if (texres->nor != NULL) {
- float ofs = tex->nabla / tex->noisesize; /* also scaling of texvec */
-
- /* calculate bumpnormal */
- BLI_noise_voronoi(texvec[0] + ofs, texvec[1], texvec[2], da, pa, tex->vn_mexp, tex->vn_distm);
- texres->nor[0] = sc * fabsf(dot_v4v4(&tex->vn_w1, da));
- BLI_noise_voronoi(texvec[0], texvec[1] + ofs, texvec[2], da, pa, tex->vn_mexp, tex->vn_distm);
- texres->nor[1] = sc * fabsf(dot_v4v4(&tex->vn_w1, da));
- BLI_noise_voronoi(texvec[0], texvec[1], texvec[2] + ofs, da, pa, tex->vn_mexp, tex->vn_distm);
- texres->nor[2] = sc * fabsf(dot_v4v4(&tex->vn_w1, da));
-
- tex_normal_derivate(tex, texres);
- rv |= TEX_NOR;
- }
-
if (tex->vn_coltype) {
BRICONTRGB;
texres->trgba[3] = 1.0;
@@ -1148,7 +902,7 @@ static int multitex(Tex *tex,
const bool use_nodes)
{
float tmpvec[3];
- int retval = 0; /* return value, int:0, col:1, nor:2, everything:3 */
+ int retval = 0; /* return value, TEX_INT or TEX_RGB. */
texres->talpha = false; /* is set when image texture returns alpha (considered premul) */
@@ -1208,9 +962,8 @@ static int multitex(Tex *tex,
case TEX_MUSGRAVE:
/* newnoise: musgrave types */
- /* ton: added this, for Blender convention reason.
- * artificer: added the use of tmpvec to avoid scaling texvec
- */
+ /* NOTE(@ton): added this, for Blender convention reason.
+ * NOTE(@artificer): added the use of tmpvec to avoid scaling texvec. */
copy_v3_v3(tmpvec, texvec);
mul_v3_fl(tmpvec, 1.0f / tex->noisesize);
@@ -1230,18 +983,16 @@ static int multitex(Tex *tex,
break;
/* newnoise: voronoi type */
case TEX_VORONOI:
- /* ton: added this, for Blender convention reason.
- * artificer: added the use of tmpvec to avoid scaling texvec
- */
+ /* NOTE(@ton): added this, for Blender convention reason.
+ * NOTE(@artificer): added the use of tmpvec to avoid scaling texvec. */
copy_v3_v3(tmpvec, texvec);
mul_v3_fl(tmpvec, 1.0f / tex->noisesize);
retval = voronoiTex(tex, tmpvec, texres);
break;
case TEX_DISTNOISE:
- /* ton: added this, for Blender convention reason.
- * artificer: added the use of tmpvec to avoid scaling texvec
- */
+ /* NOTE(@ton): added this, for Blender convention reason.
+ * NOTE(@artificer): added the use of tmpvec to avoid scaling texvec. */
copy_v3_v3(tmpvec, texvec);
mul_v3_fl(tmpvec, 1.0f / tex->noisesize);
@@ -1286,14 +1037,14 @@ static int multitex_nodes_intern(Tex *tex,
}
if (tex->type == TEX_IMAGE) {
- int rgbnor;
+ int retval;
if (mtex) {
float texvec_l[3];
copy_v3_v3(texvec_l, texvec);
/* we have mtex, use it for 2d mapping images only */
do_2d_mapping(mtex, texvec_l, NULL, dxt, dyt);
- rgbnor = multitex(tex,
+ retval = multitex(tex,
texvec_l,
dxt,
dyt,
@@ -1310,7 +1061,7 @@ static int multitex_nodes_intern(Tex *tex,
ImBuf *ibuf = BKE_image_pool_acquire_ibuf(tex->ima, &tex->iuser, pool);
/* don't linearize float buffers, assumed to be linear */
- if (ibuf != NULL && ibuf->rect_float == NULL && (rgbnor & TEX_RGB) && scene_color_manage) {
+ if (ibuf != NULL && ibuf->rect_float == NULL && (retval & TEX_RGB) && scene_color_manage) {
IMB_colormanagement_colorspace_to_scene_linear_v3(texres->trgba, ibuf->rect_colorspace);
}
@@ -1338,7 +1089,7 @@ static int multitex_nodes_intern(Tex *tex,
}
do_2d_mapping(&localmtex, texvec_l, NULL, dxt_l, dyt_l);
- rgbnor = multitex(tex,
+ retval = multitex(tex,
texvec_l,
dxt_l,
dyt_l,
@@ -1355,7 +1106,7 @@ static int multitex_nodes_intern(Tex *tex,
ImBuf *ibuf = BKE_image_pool_acquire_ibuf(tex->ima, &tex->iuser, pool);
/* don't linearize float buffers, assumed to be linear */
- if (ibuf != NULL && ibuf->rect_float == NULL && (rgbnor & TEX_RGB) && scene_color_manage) {
+ if (ibuf != NULL && ibuf->rect_float == NULL && (retval & TEX_RGB) && scene_color_manage) {
IMB_colormanagement_colorspace_to_scene_linear_v3(texres->trgba, ibuf->rect_colorspace);
}
@@ -1363,7 +1114,7 @@ static int multitex_nodes_intern(Tex *tex,
}
}
- return rgbnor;
+ return retval;
}
return multitex(tex,
@@ -1459,145 +1210,6 @@ int multitex_ext_safe(Tex *tex,
/* ------------------------------------------------------------------------- */
-void texture_rgb_blend(
- float in[3], const float tex[3], const float out[3], float fact, float facg, int blendtype)
-{
- float facm;
-
- switch (blendtype) {
- case MTEX_BLEND:
- fact *= facg;
- facm = 1.0f - fact;
-
- in[0] = (fact * tex[0] + facm * out[0]);
- in[1] = (fact * tex[1] + facm * out[1]);
- in[2] = (fact * tex[2] + facm * out[2]);
- break;
-
- case MTEX_MUL:
- fact *= facg;
- facm = 1.0f - fact;
- in[0] = (facm + fact * tex[0]) * out[0];
- in[1] = (facm + fact * tex[1]) * out[1];
- in[2] = (facm + fact * tex[2]) * out[2];
- break;
-
- case MTEX_SCREEN:
- fact *= facg;
- facm = 1.0f - fact;
- in[0] = 1.0f - (facm + fact * (1.0f - tex[0])) * (1.0f - out[0]);
- in[1] = 1.0f - (facm + fact * (1.0f - tex[1])) * (1.0f - out[1]);
- in[2] = 1.0f - (facm + fact * (1.0f - tex[2])) * (1.0f - out[2]);
- break;
-
- case MTEX_OVERLAY:
- fact *= facg;
- facm = 1.0f - fact;
-
- if (out[0] < 0.5f) {
- in[0] = out[0] * (facm + 2.0f * fact * tex[0]);
- }
- else {
- in[0] = 1.0f - (facm + 2.0f * fact * (1.0f - tex[0])) * (1.0f - out[0]);
- }
- if (out[1] < 0.5f) {
- in[1] = out[1] * (facm + 2.0f * fact * tex[1]);
- }
- else {
- in[1] = 1.0f - (facm + 2.0f * fact * (1.0f - tex[1])) * (1.0f - out[1]);
- }
- if (out[2] < 0.5f) {
- in[2] = out[2] * (facm + 2.0f * fact * tex[2]);
- }
- else {
- in[2] = 1.0f - (facm + 2.0f * fact * (1.0f - tex[2])) * (1.0f - out[2]);
- }
- break;
-
- case MTEX_SUB:
- fact = -fact;
- ATTR_FALLTHROUGH;
- case MTEX_ADD:
- fact *= facg;
- in[0] = (fact * tex[0] + out[0]);
- in[1] = (fact * tex[1] + out[1]);
- in[2] = (fact * tex[2] + out[2]);
- break;
-
- case MTEX_DIV:
- fact *= facg;
- facm = 1.0f - fact;
-
- if (tex[0] != 0.0f) {
- in[0] = facm * out[0] + fact * out[0] / tex[0];
- }
- if (tex[1] != 0.0f) {
- in[1] = facm * out[1] + fact * out[1] / tex[1];
- }
- if (tex[2] != 0.0f) {
- in[2] = facm * out[2] + fact * out[2] / tex[2];
- }
-
- break;
-
- case MTEX_DIFF:
- fact *= facg;
- facm = 1.0f - fact;
- in[0] = facm * out[0] + fact * fabsf(tex[0] - out[0]);
- in[1] = facm * out[1] + fact * fabsf(tex[1] - out[1]);
- in[2] = facm * out[2] + fact * fabsf(tex[2] - out[2]);
- break;
-
- case MTEX_DARK:
- fact *= facg;
- facm = 1.0f - fact;
-
- in[0] = min_ff(out[0], tex[0]) * fact + out[0] * facm;
- in[1] = min_ff(out[1], tex[1]) * fact + out[1] * facm;
- in[2] = min_ff(out[2], tex[2]) * fact + out[2] * facm;
- break;
-
- case MTEX_LIGHT:
- fact *= facg;
-
- in[0] = max_ff(fact * tex[0], out[0]);
- in[1] = max_ff(fact * tex[1], out[1]);
- in[2] = max_ff(fact * tex[2], out[2]);
- break;
-
- case MTEX_BLEND_HUE:
- fact *= facg;
- copy_v3_v3(in, out);
- ramp_blend(MA_RAMP_HUE, in, fact, tex);
- break;
- case MTEX_BLEND_SAT:
- fact *= facg;
- copy_v3_v3(in, out);
- ramp_blend(MA_RAMP_SAT, in, fact, tex);
- break;
- case MTEX_BLEND_VAL:
- fact *= facg;
- copy_v3_v3(in, out);
- ramp_blend(MA_RAMP_VAL, in, fact, tex);
- break;
- case MTEX_BLEND_COLOR:
- fact *= facg;
- copy_v3_v3(in, out);
- ramp_blend(MA_RAMP_COLOR, in, fact, tex);
- break;
- case MTEX_SOFT_LIGHT:
- fact *= facg;
- copy_v3_v3(in, out);
- ramp_blend(MA_RAMP_SOFT, in, fact, tex);
- break;
- case MTEX_LIN_LIGHT:
- fact *= facg;
- copy_v3_v3(in, out);
- ramp_blend(MA_RAMP_LINEAR, in, fact, tex);
- break;
- }
-}
-
float texture_value_blend(float tex, float out, float fact, float facg, int blendtype)
{
float in = 0.0, facm, col, scf;
@@ -1706,7 +1318,6 @@ bool RE_texture_evaluate(const MTex *mtex,
if (tex == NULL) {
return 0;
}
- texr.nor = NULL;
/* placement */
if (mtex->projx) {
diff --git a/source/blender/sequencer/SEQ_add.h b/source/blender/sequencer/SEQ_add.h
index c195165a792..dea5151598c 100644
--- a/source/blender/sequencer/SEQ_add.h
+++ b/source/blender/sequencer/SEQ_add.h
@@ -183,9 +183,6 @@ void SEQ_add_image_load_file(struct Sequence *seq, size_t strip_frame, char *fil
* \param seq: image strip to be changed
*/
void SEQ_add_image_init_alpha_mode(struct Sequence *seq);
-/**
- * \note caller should run `SEQ_time_update_sequence(scene, seq)` after..
- */
void SEQ_add_reload_new_file(struct Main *bmain,
struct Scene *scene,
struct Sequence *seq,
diff --git a/source/blender/sequencer/SEQ_channels.h b/source/blender/sequencer/SEQ_channels.h
index dcfdb933940..197ad5e55de 100644
--- a/source/blender/sequencer/SEQ_channels.h
+++ b/source/blender/sequencer/SEQ_channels.h
@@ -24,8 +24,8 @@ void SEQ_channels_duplicate(struct ListBase *channels_dst, struct ListBase *chan
void SEQ_channels_free(struct ListBase *channels);
struct SeqTimelineChannel *SEQ_channel_get_by_index(const struct ListBase *channels,
- const int channel_index);
-char *SEQ_channel_name_get(struct ListBase *channels, const int channel_index);
+ int channel_index);
+char *SEQ_channel_name_get(struct ListBase *channels, int channel_index);
bool SEQ_channel_is_locked(const struct SeqTimelineChannel *channel);
bool SEQ_channel_is_muted(const struct SeqTimelineChannel *channel);
int SEQ_channel_index_get(const struct SeqTimelineChannel *channel);
diff --git a/source/blender/sequencer/SEQ_iterator.h b/source/blender/sequencer/SEQ_iterator.h
index 8cb20d41ba2..1f94574513c 100644
--- a/source/blender/sequencer/SEQ_iterator.h
+++ b/source/blender/sequencer/SEQ_iterator.h
@@ -131,6 +131,9 @@ bool SEQ_collection_remove_strip(struct Sequence *seq, SeqCollection *collection
* \param collection: collection to be freed
*/
void SEQ_collection_free(SeqCollection *collection);
+/** Quiet compiler warning for free function. */
+#define SEQ_collection_free_void_p ((GHashValFreeFP)SEQ_collection_free)
+
/**
* Move strips from collection_src to collection_dst. Source collection will be freed.
*
diff --git a/source/blender/sequencer/SEQ_sequencer.h b/source/blender/sequencer/SEQ_sequencer.h
index 8ded6d99a8d..70cba58007f 100644
--- a/source/blender/sequencer/SEQ_sequencer.h
+++ b/source/blender/sequencer/SEQ_sequencer.h
@@ -143,7 +143,8 @@ typedef enum eSequenceLookupTag {
*
* \return pointer to Sequence
*/
-struct Sequence *SEQ_sequence_lookup_by_name(const struct Scene *scene, const char *key);
+struct Sequence *SEQ_sequence_lookup_seq_by_name(const struct Scene *scene, const char *key);
+
/**
* Free lookup hash data.
*
diff --git a/source/blender/sequencer/SEQ_time.h b/source/blender/sequencer/SEQ_time.h
index b4adc950d6b..eab10f2e852 100644
--- a/source/blender/sequencer/SEQ_time.h
+++ b/source/blender/sequencer/SEQ_time.h
@@ -47,8 +47,6 @@ int SEQ_time_find_next_prev_edit(struct Scene *scene,
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);
/**
* Test if strip intersects with timeline frame.
* \note This checks if strip would be rendered at this frame. For rendering it is assumed, that
@@ -59,7 +57,15 @@ void SEQ_time_update_recursive(struct Scene *scene, struct Sequence *changed_seq
* \return true if strip intersects with 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);
+bool SEQ_time_has_still_frames(const struct Sequence *seq);
+bool SEQ_time_has_left_still_frames(const struct Sequence *seq);
+bool SEQ_time_has_right_still_frames(const struct Sequence *seq);
+
+int SEQ_time_left_handle_frame_get(const struct Sequence *seq);
+int SEQ_time_right_handle_frame_get(const struct Sequence *seq);
+void SEQ_time_left_handle_frame_set(const struct Scene *scene, struct Sequence *seq, int val);
+void SEQ_time_right_handle_frame_set(const struct Scene *scene, struct Sequence *seq, int val);
+void SEQ_time_update_meta_strip_range(const 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 ea90a3ed372..31a7399f844 100644
--- a/source/blender/sequencer/SEQ_transform.h
+++ b/source/blender/sequencer/SEQ_transform.h
@@ -17,22 +17,21 @@ struct Scene;
struct SeqCollection;
struct Sequence;
-int SEQ_transform_get_left_handle_frame(struct Sequence *seq);
-int SEQ_transform_get_right_handle_frame(struct Sequence *seq);
-void SEQ_transform_set_left_handle_frame(struct Sequence *seq, int val);
-void SEQ_transform_set_right_handle_frame(struct Sequence *seq, int val);
/**
* Use to impose limits when dragging/extending - so impossible situations don't happen.
* Can't use the #SEQ_LEFTSEL and #SEQ_LEFTSEL directly because the strip may be in a meta-strip.
*/
-void SEQ_transform_handle_xlimits(struct Sequence *seq, int leftflag, int rightflag);
+void SEQ_transform_handle_xlimits(const struct Scene *scene,
+ struct Sequence *seq,
+ int leftflag,
+ int rightflag);
bool SEQ_transform_sequence_can_be_translated(struct Sequence *seq);
/**
* Used so we can do a quick check for single image seq
* since they work a bit differently to normal image seq's (during transform).
*/
bool SEQ_transform_single_image_check(struct Sequence *seq);
-void SEQ_transform_fix_single_image_seq_offsets(struct Sequence *seq);
+void SEQ_transform_fix_single_image_seq_offsets(const struct Scene *scene, struct Sequence *seq);
bool SEQ_transform_test_overlap(struct ListBase *seqbasep, struct Sequence *test);
bool SEQ_transform_test_overlap_seq_seq(struct Sequence *seq1, struct Sequence *seq2);
void SEQ_transform_translate_sequence(struct Scene *scene, struct Sequence *seq, int delta);
@@ -47,6 +46,7 @@ bool SEQ_transform_seqbase_shuffle(struct ListBase *seqbasep,
struct Sequence *test,
struct Scene *evil_scene);
bool SEQ_transform_seqbase_shuffle_time(struct SeqCollection *strips_to_shuffle,
+ struct SeqCollection *time_dependent_strips,
struct ListBase *seqbasep,
struct Scene *evil_scene,
struct ListBase *markers,
@@ -55,6 +55,7 @@ bool SEQ_transform_seqbase_shuffle_time(struct SeqCollection *strips_to_shuffle,
void SEQ_transform_handle_overlap(struct Scene *scene,
struct ListBase *seqbasep,
struct SeqCollection *transformed_strips,
+ struct SeqCollection *time_dependent_strips,
bool use_sync_markers);
/**
* Check if the selected seq's reference unselected seq's.
diff --git a/source/blender/sequencer/SEQ_utils.h b/source/blender/sequencer/SEQ_utils.h
index ec33bca87a3..24ca7559166 100644
--- a/source/blender/sequencer/SEQ_utils.h
+++ b/source/blender/sequencer/SEQ_utils.h
@@ -20,24 +20,18 @@ struct SeqRenderData;
struct Sequence;
struct StripElem;
-/**
- * Sort strips in provided seqbase. Effect strips are trailing the list and they are sorted by
- * channel position as well.
- * This is important for SEQ_time_update_sequence to work properly
- *
- * \param seqbase: ListBase with strips
- */
-void SEQ_sort(struct ListBase *seqbase);
void SEQ_sequence_base_unique_name_recursive(struct Scene *scene,
struct ListBase *seqbasep,
struct Sequence *seq);
const char *SEQ_sequence_give_name(struct Sequence *seq);
-struct ListBase *SEQ_get_seqbase_from_sequence(struct Sequence *seq, int *r_offset);
+struct ListBase *SEQ_get_seqbase_from_sequence(struct Sequence *seq,
+ struct ListBase **channels,
+ int *r_offset);
const struct Sequence *SEQ_get_topmost_sequence(const struct Scene *scene, int frame);
/**
* In cases where we don't know the sequence's listbase.
*/
-struct ListBase *SEQ_get_seqbase_by_seq(struct ListBase *seqbase, struct Sequence *seq);
+struct ListBase *SEQ_get_seqbase_by_seq(const struct Scene *scene, struct Sequence *seq);
/**
* Only use as last resort when the StripElem is available but no the Sequence.
* (needed for RNA)
diff --git a/source/blender/sequencer/intern/disk_cache.c b/source/blender/sequencer/intern/disk_cache.c
index 0fdaef61b65..cc34066c432 100644
--- a/source/blender/sequencer/intern/disk_cache.c
+++ b/source/blender/sequencer/intern/disk_cache.c
@@ -37,6 +37,7 @@
#include "SEQ_relations.h"
#include "SEQ_render.h"
#include "SEQ_sequencer.h"
+#include "SEQ_time.h"
#include "disk_cache.h"
#include "image_cache.h"
@@ -344,15 +345,15 @@ static void seq_disk_cache_create_version_file(char *path)
static void seq_disk_cache_handle_versioning(SeqDiskCache *disk_cache)
{
- char path[FILE_MAX];
+ char filepath[FILE_MAX];
char path_version_file[FILE_MAX];
int version = 0;
- seq_disk_cache_get_project_dir(disk_cache, path, sizeof(path));
- BLI_strncpy(path_version_file, path, sizeof(path_version_file));
+ seq_disk_cache_get_project_dir(disk_cache, filepath, sizeof(filepath));
+ BLI_strncpy(path_version_file, filepath, sizeof(path_version_file));
BLI_path_append(path_version_file, sizeof(path_version_file), "cache_version");
- if (BLI_exists(path) && BLI_is_dir(path)) {
+ if (BLI_exists(filepath) && BLI_is_dir(filepath)) {
FILE *file = BLI_fopen(path_version_file, "r");
if (file) {
@@ -364,7 +365,7 @@ static void seq_disk_cache_handle_versioning(SeqDiskCache *disk_cache)
}
if (version != DCACHE_CURRENT_VERSION) {
- BLI_delete(path, false, true);
+ BLI_delete(filepath, false, true);
seq_disk_cache_create_version_file(path_version_file);
}
}
@@ -411,8 +412,8 @@ void seq_disk_cache_invalidate(SeqDiskCache *disk_cache,
BLI_mutex_lock(&disk_cache->read_write_mutex);
- start = seq_changed->startdisp - DCACHE_IMAGES_PER_FILE;
- end = seq_changed->enddisp;
+ start = SEQ_time_left_handle_frame_get(seq_changed) - DCACHE_IMAGES_PER_FILE;
+ end = SEQ_time_right_handle_frame_get(seq_changed);
seq_disk_cache_delete_invalid_files(disk_cache, scene, seq, invalidate_types, start, end);
@@ -548,22 +549,22 @@ bool seq_disk_cache_write_file(SeqDiskCache *disk_cache, SeqCacheKey *key, ImBuf
{
BLI_mutex_lock(&disk_cache->read_write_mutex);
- char path[FILE_MAX];
+ char filepath[FILE_MAX];
- seq_disk_cache_get_file_path(disk_cache, key, path, sizeof(path));
- BLI_make_existing_file(path);
+ seq_disk_cache_get_file_path(disk_cache, key, filepath, sizeof(filepath));
+ BLI_make_existing_file(filepath);
- FILE *file = BLI_fopen(path, "rb+");
+ FILE *file = BLI_fopen(filepath, "rb+");
if (!file) {
- file = BLI_fopen(path, "wb+");
+ file = BLI_fopen(filepath, "wb+");
if (!file) {
BLI_mutex_unlock(&disk_cache->read_write_mutex);
return false;
}
- seq_disk_cache_add_file_to_list(disk_cache, path);
+ seq_disk_cache_add_file_to_list(disk_cache, filepath);
}
- DiskCacheFile *cache_file = seq_disk_cache_get_file_entry_by_path(disk_cache, path);
+ DiskCacheFile *cache_file = seq_disk_cache_get_file_entry_by_path(disk_cache, filepath);
DiskCacheHeader header;
memset(&header, 0, sizeof(header));
/* #BLI_make_existing_file() above may create an empty file. This is fine, don't attempt reading
@@ -585,7 +586,7 @@ bool seq_disk_cache_write_file(SeqDiskCache *disk_cache, SeqCacheKey *key, ImBuf
*/
header.entry[entry_index].size_compressed = bytes_written;
seq_disk_cache_write_header(file, &header);
- seq_disk_cache_update_file(disk_cache, path);
+ seq_disk_cache_update_file(disk_cache, filepath);
fclose(file);
BLI_mutex_unlock(&disk_cache->read_write_mutex);
@@ -600,13 +601,13 @@ ImBuf *seq_disk_cache_read_file(SeqDiskCache *disk_cache, SeqCacheKey *key)
{
BLI_mutex_lock(&disk_cache->read_write_mutex);
- char path[FILE_MAX];
+ char filepath[FILE_MAX];
DiskCacheHeader header;
- seq_disk_cache_get_file_path(disk_cache, key, path, sizeof(path));
- BLI_make_existing_file(path);
+ seq_disk_cache_get_file_path(disk_cache, key, filepath, sizeof(filepath));
+ BLI_make_existing_file(filepath);
- FILE *file = BLI_fopen(path, "rb");
+ FILE *file = BLI_fopen(filepath, "rb");
if (!file) {
BLI_mutex_unlock(&disk_cache->read_write_mutex);
return NULL;
@@ -656,8 +657,8 @@ ImBuf *seq_disk_cache_read_file(SeqDiskCache *disk_cache, SeqCacheKey *key)
BLI_mutex_unlock(&disk_cache->read_write_mutex);
return NULL;
}
- BLI_file_touch(path);
- seq_disk_cache_update_file(disk_cache, path);
+ BLI_file_touch(filepath);
+ seq_disk_cache_update_file(disk_cache, filepath);
fclose(file);
BLI_mutex_unlock(&disk_cache->read_write_mutex);
diff --git a/source/blender/sequencer/intern/effects.c b/source/blender/sequencer/intern/effects.c
index d9d21ee3b05..0e5e56908b0 100644
--- a/source/blender/sequencer/intern/effects.c
+++ b/source/blender/sequencer/intern/effects.c
@@ -49,6 +49,7 @@
#include "SEQ_proxy.h"
#include "SEQ_relations.h"
#include "SEQ_render.h"
+#include "SEQ_time.h"
#include "SEQ_utils.h"
#include "BLF_api.h"
@@ -2431,7 +2432,7 @@ static ImBuf *do_multicam(const SeqRenderData *context,
if (!ed) {
return NULL;
}
- ListBase *seqbasep = SEQ_get_seqbase_by_seq(&ed->seqbase, seq);
+ ListBase *seqbasep = SEQ_get_seqbase_by_seq(context->scene, seq);
ListBase *channels = SEQ_get_channels_by_seq(&ed->seqbase, &ed->channels, seq);
if (!seqbasep) {
return NULL;
@@ -2467,13 +2468,15 @@ static ImBuf *do_adjustment_impl(const SeqRenderData *context, Sequence *seq, fl
ed = context->scene->ed;
- ListBase *seqbasep = SEQ_get_seqbase_by_seq(&ed->seqbase, seq);
+ ListBase *seqbasep = SEQ_get_seqbase_by_seq(context->scene, seq);
ListBase *channels = SEQ_get_channels_by_seq(&ed->seqbase, &ed->channels, seq);
/* Clamp timeline_frame to strip range so it behaves as if it had "still frame" offset (last
* frame is static after end of strip). This is how most strips behave. This way transition
* effects that doesn't overlap or speed effect can't fail rendering outside of strip range. */
- timeline_frame = clamp_i(timeline_frame, seq->startdisp, seq->enddisp - 1);
+ timeline_frame = clamp_i(timeline_frame,
+ SEQ_time_left_handle_frame_get(seq),
+ SEQ_time_right_handle_frame_get(seq) - 1);
if (seq->machine > 1) {
i = seq_render_give_ibuf_seqbase(
@@ -2583,7 +2586,7 @@ static int early_out_speed(Sequence *UNUSED(seq), float UNUSED(fac))
static int seq_effect_speed_get_strip_content_length(const Sequence *seq)
{
if ((seq->type & SEQ_TYPE_EFFECT) != 0 && SEQ_effect_get_num_inputs(seq->type) == 0) {
- return seq->enddisp - seq->startdisp;
+ return SEQ_time_right_handle_frame_get(seq) - SEQ_time_left_handle_frame_get(seq);
}
return seq->len;
@@ -2610,13 +2613,14 @@ void seq_effect_speed_rebuild_map(Scene *scene, Sequence *seq)
MEM_freeN(v->frameMap);
}
- const int effect_strip_length = seq->enddisp - seq->startdisp;
+ const int effect_strip_length = SEQ_time_right_handle_frame_get(seq) -
+ SEQ_time_left_handle_frame_get(seq);
v->frameMap = MEM_mallocN(sizeof(float) * effect_strip_length, __func__);
v->frameMap[0] = 0.0f;
float target_frame = 0;
for (int frame_index = 1; frame_index < effect_strip_length; frame_index++) {
- target_frame += evaluate_fcurve(fcu, seq->startdisp + frame_index);
+ target_frame += evaluate_fcurve(fcu, SEQ_time_left_handle_frame_get(seq) + frame_index);
CLAMP(target_frame, 0, seq->seq1->len);
v->frameMap[frame_index] = target_frame;
}
@@ -2652,7 +2656,8 @@ float seq_speed_effect_target_frame_get(Scene *scene,
/* Only right handle controls effect speed! */
const float target_content_length = seq_effect_speed_get_strip_content_length(source) -
source->startofs;
- const float speed_effetct_length = seq_speed->enddisp - seq_speed->startdisp;
+ const float speed_effetct_length = SEQ_time_right_handle_frame_get(seq_speed) -
+ SEQ_time_left_handle_frame_get(seq_speed);
const float ratio = frame_index / speed_effetct_length;
target_frame = target_content_length * ratio;
break;
@@ -3509,7 +3514,7 @@ static void get_default_fac_noop(Sequence *UNUSED(seq), float UNUSED(timeline_fr
static void get_default_fac_fade(Sequence *seq, float timeline_frame, float *fac)
{
- *fac = (float)(timeline_frame - seq->startdisp);
+ *fac = (float)(timeline_frame - SEQ_time_left_handle_frame_get(seq));
*fac /= seq->len;
}
diff --git a/source/blender/sequencer/intern/image_cache.c b/source/blender/sequencer/intern/image_cache.c
index e1ff0ff64b3..47306dbbc6c 100644
--- a/source/blender/sequencer/intern/image_cache.c
+++ b/source/blender/sequencer/intern/image_cache.c
@@ -36,6 +36,7 @@
#include "SEQ_prefetch.h"
#include "SEQ_relations.h"
#include "SEQ_sequencer.h"
+#include "SEQ_time.h"
#include "disk_cache.h"
#include "image_cache.h"
@@ -558,8 +559,9 @@ void seq_cache_free_temp_cache(Scene *scene, short id, int timeline_frame)
/* Use frame_index here to avoid freeing raw images if they are used for multiple frames. */
float frame_index = seq_cache_timeline_frame_to_frame_index(
key->seq, timeline_frame, key->type);
- if (frame_index != key->frame_index || timeline_frame > key->seq->enddisp ||
- timeline_frame < key->seq->startdisp) {
+ if (frame_index != key->frame_index ||
+ timeline_frame > SEQ_time_right_handle_frame_get(key->seq) ||
+ timeline_frame < SEQ_time_left_handle_frame_get(key->seq)) {
BLI_ghash_remove(cache->hash, key, seq_cache_keyfree, seq_cache_valfree);
}
}
@@ -634,17 +636,12 @@ void seq_cache_cleanup_sequence(Scene *scene,
seq_cache_lock(scene);
- int range_start = seq_changed->startdisp;
- int range_end = seq_changed->enddisp;
+ int range_start = SEQ_time_left_handle_frame_get(seq_changed);
+ int range_end = SEQ_time_right_handle_frame_get(seq_changed);
if (!force_seq_changed_range) {
- if (seq->startdisp > range_start) {
- range_start = seq->startdisp;
- }
-
- if (seq->enddisp < range_end) {
- range_end = seq->enddisp;
- }
+ range_start = max_ii(range_start, SEQ_time_left_handle_frame_get(seq));
+ range_end = min_ii(range_end, SEQ_time_right_handle_frame_get(seq));
}
int invalidate_composite = invalidate_types & SEQ_CACHE_STORE_FINAL_OUT;
@@ -668,8 +665,8 @@ void seq_cache_cleanup_sequence(Scene *scene,
}
if (key->type & invalidate_source && key->seq == seq &&
- key->timeline_frame >= seq_changed->startdisp &&
- key->timeline_frame <= seq_changed->enddisp) {
+ key->timeline_frame >= SEQ_time_left_handle_frame_get(seq_changed) &&
+ key->timeline_frame <= SEQ_time_right_handle_frame_get(seq_changed)) {
if (key->link_next || key->link_prev) {
seq_cache_relink_keys(key->link_next, key->link_prev);
}
@@ -700,11 +697,12 @@ void seq_cache_thumbnail_cleanup(Scene *scene, rctf *view_area_safe)
SeqCacheKey *key = BLI_ghashIterator_getKey(&gh_iter);
BLI_ghashIterator_step(&gh_iter);
- const int frame_index = key->timeline_frame - key->seq->startdisp;
+ const int frame_index = key->timeline_frame - SEQ_time_left_handle_frame_get(key->seq);
const int frame_step = SEQ_render_thumbnails_guaranteed_set_frame_step_get(key->seq);
const int relative_base_frame = round_fl_to_int((frame_index / (float)frame_step)) *
frame_step;
- const int nearest_guaranted_absolute_frame = relative_base_frame + key->seq->startdisp;
+ const int nearest_guaranted_absolute_frame = relative_base_frame +
+ SEQ_time_left_handle_frame_get(key->seq);
if (nearest_guaranted_absolute_frame == key->timeline_frame) {
continue;
diff --git a/source/blender/sequencer/intern/proxy.c b/source/blender/sequencer/intern/proxy.c
index 91b69bfe01f..464580f5bed 100644
--- a/source/blender/sequencer/intern/proxy.c
+++ b/source/blender/sequencer/intern/proxy.c
@@ -43,6 +43,7 @@
#include "SEQ_relations.h"
#include "SEQ_render.h"
#include "SEQ_sequencer.h"
+#include "SEQ_time.h"
#include "multiview.h"
#include "proxy.h"
@@ -523,8 +524,8 @@ void SEQ_proxy_rebuild(SeqIndexBuildContext *context,
SeqRenderState state;
seq_render_state_init(&state);
- for (timeline_frame = seq->startdisp + seq->startstill;
- timeline_frame < seq->enddisp - seq->endstill;
+ for (timeline_frame = SEQ_time_left_handle_frame_get(seq);
+ timeline_frame < SEQ_time_right_handle_frame_get(seq);
timeline_frame++) {
if (context->size_flags & IMB_PROXY_25) {
seq_proxy_build_frame(&render_context, &state, seq, timeline_frame, 25, overwrite);
@@ -539,8 +540,8 @@ void SEQ_proxy_rebuild(SeqIndexBuildContext *context,
seq_proxy_build_frame(&render_context, &state, seq, timeline_frame, 100, overwrite);
}
- *progress = (float)(timeline_frame - seq->startdisp - seq->startstill) /
- (seq->enddisp - seq->endstill - seq->startdisp - seq->startstill);
+ *progress = (float)(timeline_frame - SEQ_time_left_handle_frame_get(seq)) /
+ (SEQ_time_right_handle_frame_get(seq) - SEQ_time_left_handle_frame_get(seq));
*do_update = true;
if (*stop || G.is_break) {
diff --git a/source/blender/sequencer/intern/render.c b/source/blender/sequencer/intern/render.c
index 8d8a13be09e..e7a1bbeb9d0 100644
--- a/source/blender/sequencer/intern/render.c
+++ b/source/blender/sequencer/intern/render.c
@@ -1586,10 +1586,10 @@ static ImBuf *do_render_strip_seqbase(const SeqRenderData *context,
{
ImBuf *ibuf = NULL;
ListBase *seqbase = NULL;
- ListBase *channels = &seq->channels;
+ ListBase *channels = NULL;
int offset;
- seqbase = SEQ_get_seqbase_from_sequence(seq, &offset);
+ seqbase = SEQ_get_seqbase_from_sequence(seq, &channels, &offset);
if (seqbase && !BLI_listbase_is_empty(seqbase)) {
@@ -1994,11 +1994,12 @@ ImBuf *SEQ_render_give_ibuf_direct(const SeqRenderData *context,
float SEQ_render_thumbnail_first_frame_get(Sequence *seq, float frame_step, rctf *view_area)
{
- int first_drawable_frame = max_iii(seq->startdisp, seq->start, view_area->xmin);
+ int first_drawable_frame = max_iii(
+ SEQ_time_left_handle_frame_get(seq), seq->start, view_area->xmin);
/* First frame should correspond to handle position. */
- if (first_drawable_frame == seq->startdisp) {
- return seq->startdisp;
+ if (first_drawable_frame == SEQ_time_left_handle_frame_get(seq)) {
+ return SEQ_time_left_handle_frame_get(seq);
}
float aligned_frame_offset = (int)((first_drawable_frame - seq->start) / frame_step) *
@@ -2011,7 +2012,7 @@ float SEQ_render_thumbnail_next_frame_get(Sequence *seq, float last_frame, float
float next_frame = last_frame + frame_step;
/* If handle position was displayed, align next frame with `seq->start`. */
- if (last_frame == seq->startdisp) {
+ if (last_frame == SEQ_time_left_handle_frame_get(seq)) {
next_frame = seq->start + ((int)((last_frame - seq->start) / frame_step) + 1) * frame_step;
}
@@ -2088,7 +2089,9 @@ void SEQ_render_thumbnails(const SeqRenderData *context,
/* Adding the hold offset value (seq->anim_startofs) to the start frame. Position of image not
* affected, but frame loaded affected. */
- float upper_thumb_bound = (seq->endstill) ? (seq->start + seq->len) : seq->enddisp;
+ float upper_thumb_bound = SEQ_time_has_right_still_frames(seq) ?
+ (seq->start + seq->len) :
+ SEQ_time_right_handle_frame_get(seq);
upper_thumb_bound = (upper_thumb_bound > view_area->xmax) ? view_area->xmax + frame_step :
upper_thumb_bound;
@@ -2121,7 +2124,9 @@ void SEQ_render_thumbnails(const SeqRenderData *context,
int SEQ_render_thumbnails_guaranteed_set_frame_step_get(const Sequence *seq)
{
- const int content_len = (seq->enddisp - seq->startdisp - seq->startstill - seq->endstill);
+ const int content_start = max_ii(SEQ_time_left_handle_frame_get(seq), seq->start);
+ const int content_end = min_ii(SEQ_time_right_handle_frame_get(seq), seq->start + seq->len);
+ const int content_len = content_end - content_start;
/* Arbitrary, but due to performance reasons should be as low as possible. */
const int thumbnails_base_set_count = min_ii(content_len / 100, 30);
@@ -2140,10 +2145,10 @@ void SEQ_render_thumbnails_base_set(const SeqRenderData *context,
SeqRenderState state;
seq_render_state_init(&state);
- int timeline_frame = seq->startdisp;
+ int timeline_frame = SEQ_time_left_handle_frame_get(seq);
const int frame_step = SEQ_render_thumbnails_guaranteed_set_frame_step_get(seq);
- while (timeline_frame < seq->enddisp && !*stop) {
+ while (timeline_frame < SEQ_time_right_handle_frame_get(seq) && !*stop) {
ImBuf *ibuf = seq_cache_get(
context, seq_orig, roundf(timeline_frame), SEQ_CACHE_STORE_THUMBNAIL);
if (ibuf) {
diff --git a/source/blender/sequencer/intern/sequence_lookup.c b/source/blender/sequencer/intern/sequence_lookup.c
index 2a2626d8abf..8d18e381171 100644
--- a/source/blender/sequencer/intern/sequence_lookup.c
+++ b/source/blender/sequencer/intern/sequence_lookup.c
@@ -6,6 +6,7 @@
*/
#include "SEQ_sequencer.h"
+#include "sequencer.h"
#include "DNA_listBase.h"
#include "DNA_scene_types.h"
@@ -14,6 +15,7 @@
#include "SEQ_iterator.h"
#include "BLI_ghash.h"
+#include "BLI_listbase.h"
#include "BLI_string.h"
#include "BLI_sys_types.h"
#include "BLI_threads.h"
@@ -24,24 +26,66 @@
static ThreadMutex lookup_lock = BLI_MUTEX_INITIALIZER;
typedef struct SequenceLookup {
- GHash *by_name;
+ GHash *seq_by_name;
+ GHash *meta_by_seq;
+ GHash *effects_by_seq;
eSequenceLookupTag tag;
} SequenceLookup;
static void seq_sequence_lookup_init(struct SequenceLookup *lookup)
{
- lookup->by_name = BLI_ghash_str_new(__func__);
+ lookup->seq_by_name = BLI_ghash_str_new(__func__);
+ lookup->meta_by_seq = BLI_ghash_ptr_new(__func__);
+ lookup->effects_by_seq = BLI_ghash_ptr_new(__func__);
lookup->tag |= SEQ_LOOKUP_TAG_INVALID;
}
-static void seq_sequence_lookup_build(const struct Scene *scene, struct SequenceLookup *lookup)
+static void seq_sequence_lookup_append_effect(Sequence *input,
+ Sequence *effect,
+ struct SequenceLookup *lookup)
+{
+ if (input == NULL) {
+ return;
+ }
+
+ SeqCollection *effects = BLI_ghash_lookup(lookup->effects_by_seq, input);
+ if (effects == NULL) {
+ effects = SEQ_collection_create(__func__);
+ BLI_ghash_insert(lookup->effects_by_seq, input, effects);
+ }
+
+ SEQ_collection_append_strip(effect, effects);
+}
+
+static void seq_sequence_lookup_build_effect(Sequence *seq, struct SequenceLookup *lookup)
{
- SeqCollection *all_strips = SEQ_query_all_strips_recursive(&scene->ed->seqbase);
- Sequence *seq;
- SEQ_ITERATOR_FOREACH (seq, all_strips) {
- BLI_ghash_insert(lookup->by_name, seq->name + 2, seq);
+ if ((seq->type & SEQ_TYPE_EFFECT) == 0) {
+ return;
}
- SEQ_collection_free(all_strips);
+
+ seq_sequence_lookup_append_effect(seq->seq1, seq, lookup);
+ seq_sequence_lookup_append_effect(seq->seq2, seq, lookup);
+}
+
+static void seq_sequence_lookup_build_from_seqbase(Sequence *parent_meta,
+ const ListBase *seqbase,
+ struct SequenceLookup *lookup)
+{
+ LISTBASE_FOREACH (Sequence *, seq, seqbase) {
+ BLI_ghash_insert(lookup->seq_by_name, seq->name + 2, seq);
+ BLI_ghash_insert(lookup->meta_by_seq, seq, parent_meta);
+ seq_sequence_lookup_build_effect(seq, lookup);
+
+ if (seq->type == SEQ_TYPE_META) {
+ seq_sequence_lookup_build_from_seqbase(seq, &seq->seqbase, lookup);
+ }
+ }
+}
+
+static void seq_sequence_lookup_build(const struct Scene *scene, struct SequenceLookup *lookup)
+{
+ Editing *ed = SEQ_editing_get(scene);
+ seq_sequence_lookup_build_from_seqbase(NULL, &ed->seqbase, lookup);
lookup->tag &= ~SEQ_LOOKUP_TAG_INVALID;
}
@@ -58,8 +102,12 @@ static void seq_sequence_lookup_free(struct SequenceLookup **lookup)
return;
}
- BLI_ghash_free((*lookup)->by_name, NULL, NULL);
- (*lookup)->by_name = NULL;
+ BLI_ghash_free((*lookup)->seq_by_name, NULL, NULL);
+ BLI_ghash_free((*lookup)->meta_by_seq, NULL, NULL);
+ BLI_ghash_free((*lookup)->effects_by_seq, NULL, SEQ_collection_free_void_p);
+ (*lookup)->seq_by_name = NULL;
+ (*lookup)->meta_by_seq = NULL;
+ (*lookup)->effects_by_seq = NULL;
MEM_freeN(*lookup);
*lookup = NULL;
}
@@ -98,17 +146,39 @@ void SEQ_sequence_lookup_free(const Scene *scene)
BLI_mutex_unlock(&lookup_lock);
}
-Sequence *SEQ_sequence_lookup_by_name(const Scene *scene, const char *key)
+Sequence *SEQ_sequence_lookup_seq_by_name(const Scene *scene, const char *key)
+{
+ BLI_assert(scene->ed);
+ BLI_mutex_lock(&lookup_lock);
+ seq_sequence_lookup_update_if_needed(scene, &scene->ed->runtime.sequence_lookup);
+ SequenceLookup *lookup = scene->ed->runtime.sequence_lookup;
+ Sequence *seq = BLI_ghash_lookup(lookup->seq_by_name, key);
+ BLI_mutex_unlock(&lookup_lock);
+ return seq;
+}
+
+Sequence *seq_sequence_lookup_meta_by_seq(const Scene *scene, const Sequence *key)
{
BLI_assert(scene->ed);
BLI_mutex_lock(&lookup_lock);
seq_sequence_lookup_update_if_needed(scene, &scene->ed->runtime.sequence_lookup);
SequenceLookup *lookup = scene->ed->runtime.sequence_lookup;
- Sequence *seq = BLI_ghash_lookup(lookup->by_name, key);
+ Sequence *seq = BLI_ghash_lookup(lookup->meta_by_seq, key);
BLI_mutex_unlock(&lookup_lock);
return seq;
}
+SeqCollection *seq_sequence_lookup_effects_by_seq(const Scene *scene, const Sequence *key)
+{
+ BLI_assert(scene->ed);
+ BLI_mutex_lock(&lookup_lock);
+ seq_sequence_lookup_update_if_needed(scene, &scene->ed->runtime.sequence_lookup);
+ SequenceLookup *lookup = scene->ed->runtime.sequence_lookup;
+ SeqCollection *effects = BLI_ghash_lookup(lookup->effects_by_seq, key);
+ BLI_mutex_unlock(&lookup_lock);
+ return effects;
+}
+
void SEQ_sequence_lookup_tag(const Scene *scene, eSequenceLookupTag tag)
{
if (!scene->ed) {
diff --git a/source/blender/sequencer/intern/sequencer.c b/source/blender/sequencer/intern/sequencer.c
index faa527786fd..ad57412034a 100644
--- a/source/blender/sequencer/intern/sequencer.c
+++ b/source/blender/sequencer/intern/sequencer.c
@@ -129,7 +129,13 @@ 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;
+
+ if (seq->type == SEQ_TYPE_ADJUSTMENT) {
+ seq->blend_mode = SEQ_TYPE_CROSS;
+ }
+ else {
+ seq->blend_mode = SEQ_TYPE_ALPHAOVER;
+ }
seq->strip = seq_strip_alloc(type);
seq->stereo3d_format = MEM_callocN(sizeof(Stereo3dFormat), "Sequence Stereo Format");
diff --git a/source/blender/sequencer/intern/sequencer.h b/source/blender/sequencer/intern/sequencer.h
index 9f5bdf672c0..5e78c8c6f96 100644
--- a/source/blender/sequencer/intern/sequencer.h
+++ b/source/blender/sequencer/intern/sequencer.h
@@ -14,13 +14,37 @@ extern "C" {
struct Scene;
struct Sequence;
struct StripProxy;
+struct SeqCollection;
/**
* 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, bool do_id_user);
struct StripProxy *seq_strip_proxy_alloc(void);
-
+/**
+ * Find meta strip, that contains strip `key`.
+ * If lookup hash doesn't exist, it will be created. If hash is tagged as invalid, it will be
+ * rebuilt.
+ *
+ * \param scene: scene that owns lookup hash
+ * \param key: pointer to Sequence inside of meta strip
+ *
+ * \return pointer to meta strip
+ */
+struct Sequence *seq_sequence_lookup_meta_by_seq(const struct Scene *scene,
+ const struct Sequence *key);
+/**
+ * Find effect strips, that use strip `seq` as one of inputs.
+ * If lookup hash doesn't exist, it will be created. If hash is tagged as invalid, it will be
+ * rebuilt.
+ *
+ * \param scene: scene that owns lookup hash
+ * \param key: pointer to Sequence inside of meta strip
+ *
+ * \return collection of effect strips
+ */
+struct SeqCollection *seq_sequence_lookup_effects_by_seq(const struct Scene *scene,
+ const struct Sequence *key);
#ifdef __cplusplus
}
#endif
diff --git a/source/blender/sequencer/intern/sound.c b/source/blender/sequencer/intern/sound.c
index 8076c600560..50c8b76a9a0 100644
--- a/source/blender/sequencer/intern/sound.c
+++ b/source/blender/sequencer/intern/sound.c
@@ -35,7 +35,6 @@ static bool sequencer_refresh_sound_length_recursive(Main *bmain, Scene *scene,
for (seq = seqbase->first; seq; seq = seq->next) {
if (seq->type == SEQ_TYPE_META) {
if (sequencer_refresh_sound_length_recursive(bmain, scene, &seq->seqbase)) {
- SEQ_time_update_sequence(scene, seqbase, seq);
changed = true;
}
}
@@ -55,7 +54,6 @@ static bool sequencer_refresh_sound_length_recursive(Main *bmain, Scene *scene,
seq->endofs *= fac;
seq->start += (old - seq->startofs); /* So that visual/"real" start frame does not change! */
- SEQ_time_update_sequence(scene, seqbase, seq);
changed = true;
}
}
@@ -99,8 +97,12 @@ void SEQ_sound_update_bounds(Scene *scene, Sequence *seq)
/* We have to take into account start frame of the sequence's scene! */
int startofs = seq->startofs + seq->anim_startofs + seq->scene->r.sfra;
- BKE_sound_move_scene_sound(
- scene, seq->scene_sound, seq->startdisp, seq->enddisp, startofs, 0.0);
+ BKE_sound_move_scene_sound(scene,
+ seq->scene_sound,
+ SEQ_time_left_handle_frame_get(seq),
+ SEQ_time_right_handle_frame_get(seq),
+ startofs,
+ 0.0);
}
}
else {
diff --git a/source/blender/sequencer/intern/strip_add.c b/source/blender/sequencer/intern/strip_add.c
index f8e26a56692..4f0b2e38f56 100644
--- a/source/blender/sequencer/intern/strip_add.c
+++ b/source/blender/sequencer/intern/strip_add.c
@@ -51,6 +51,8 @@
#include "multiview.h"
#include "proxy.h"
+#include "sequencer.h"
+#include "strip_time.h"
#include "utils.h"
void SEQ_add_load_data_init(SeqLoadData *load_data,
@@ -70,12 +72,12 @@ void SEQ_add_load_data_init(SeqLoadData *load_data,
load_data->channel = channel;
}
-static void seq_add_generic_update(Scene *scene, ListBase *seqbase, Sequence *seq)
+static void seq_add_generic_update(Scene *scene, Sequence *seq)
{
SEQ_sequence_base_unique_name_recursive(scene, &scene->ed->seqbase, seq);
- SEQ_time_update_sequence(scene, seqbase, seq);
- SEQ_sort(seqbase);
SEQ_relations_invalidate_cache_composite(scene, seq);
+ SEQ_sequence_lookup_tag(scene, SEQ_LOOKUP_TAG_INVALID);
+ SEQ_time_update_meta_strip_range(scene, seq_sequence_lookup_meta_by_seq(scene, seq));
}
static void seq_add_set_name(Scene *scene, Sequence *seq, SeqLoadData *load_data)
@@ -128,7 +130,7 @@ Sequence *SEQ_add_scene_strip(Scene *scene, ListBase *seqbase, struct SeqLoadDat
seq->len = load_data->scene->r.efra - load_data->scene->r.sfra + 1;
id_us_ensure_real((ID *)load_data->scene);
seq_add_set_name(scene, seq, load_data);
- seq_add_generic_update(scene, seqbase, seq);
+ seq_add_generic_update(scene, seq);
return seq;
}
@@ -140,7 +142,7 @@ Sequence *SEQ_add_movieclip_strip(Scene *scene, ListBase *seqbase, struct SeqLoa
seq->len = BKE_movieclip_get_duration(load_data->clip);
id_us_ensure_real((ID *)load_data->clip);
seq_add_set_name(scene, seq, load_data);
- seq_add_generic_update(scene, seqbase, seq);
+ seq_add_generic_update(scene, seq);
return seq;
}
@@ -152,7 +154,7 @@ Sequence *SEQ_add_mask_strip(Scene *scene, ListBase *seqbase, struct SeqLoadData
seq->len = BKE_mask_get_duration(load_data->mask);
id_us_ensure_real((ID *)load_data->mask);
seq_add_set_name(scene, seq, load_data);
- seq_add_generic_update(scene, seqbase, seq);
+ seq_add_generic_update(scene, seq);
return seq;
}
@@ -174,11 +176,12 @@ Sequence *SEQ_add_effect_strip(Scene *scene, ListBase *seqbase, struct SeqLoadDa
if (!load_data->effect.seq1) {
seq->len = 1; /* Effect is generator, set non zero length. */
- SEQ_transform_set_right_handle_frame(seq, load_data->effect.end_frame);
+ SEQ_time_right_handle_frame_set(scene, seq, load_data->effect.end_frame);
}
seq_add_set_name(scene, seq, load_data);
- seq_add_generic_update(scene, seqbase, seq);
+ seq_add_generic_update(scene, seq);
+ seq_time_effect_range_set(seq);
return seq;
}
@@ -264,7 +267,7 @@ Sequence *SEQ_add_image_strip(Main *bmain, Scene *scene, ListBase *seqbase, SeqL
BLI_strncpy(scene->ed->act_imagedir, seq->strip->dir, sizeof(scene->ed->act_imagedir));
seq_add_set_view_transform(scene, seq, load_data);
seq_add_set_name(scene, seq, load_data);
- seq_add_generic_update(scene, seqbase, seq);
+ seq_add_generic_update(scene, seq);
return seq;
}
@@ -335,7 +338,7 @@ Sequence *SEQ_add_sound_strip(Main *bmain, Scene *scene, ListBase *seqbase, SeqL
/* Set Last active directory. */
BLI_strncpy(scene->ed->act_sounddir, strip->dir, FILE_MAXDIR);
seq_add_set_name(scene, seq, load_data);
- seq_add_generic_update(scene, seqbase, seq);
+ seq_add_generic_update(scene, seq);
return seq;
}
@@ -362,7 +365,6 @@ Sequence *SEQ_add_meta_strip(Scene *scene, ListBase *seqbase, SeqLoadData *load_
/* Set frames start and length. */
seqm->start = load_data->start_frame;
seqm->len = 1;
- SEQ_time_update_sequence(scene, seqbase, seqm);
return seqm;
}
@@ -484,7 +486,7 @@ Sequence *SEQ_add_movie_strip(Main *bmain, Scene *scene, ListBase *seqbase, SeqL
seq_add_set_view_transform(scene, seq, load_data);
seq_add_set_name(scene, seq, load_data);
- seq_add_generic_update(scene, seqbase, seq);
+ seq_add_generic_update(scene, seq);
MEM_freeN(anim_arr);
return seq;
@@ -509,11 +511,8 @@ void SEQ_add_reload_new_file(Main *bmain, Scene *scene, Sequence *seq, const boo
if (lock_range) {
/* keep so we don't have to move the actual start and end points (only the data) */
- Editing *ed = SEQ_editing_get(scene);
- ListBase *seqbase = SEQ_get_seqbase_by_seq(&ed->seqbase, seq);
- SEQ_time_update_sequence(scene, seqbase, seq);
- prev_startdisp = seq->startdisp;
- prev_enddisp = seq->enddisp;
+ prev_startdisp = SEQ_time_left_handle_frame_get(seq);
+ prev_enddisp = SEQ_time_right_handle_frame_get(seq);
}
switch (seq->type) {
@@ -656,13 +655,11 @@ void SEQ_add_reload_new_file(Main *bmain, Scene *scene, Sequence *seq, const boo
free_proxy_seq(seq);
if (lock_range) {
- SEQ_transform_set_left_handle_frame(seq, prev_startdisp);
- SEQ_transform_set_right_handle_frame(seq, prev_enddisp);
- SEQ_transform_fix_single_image_seq_offsets(seq);
+ SEQ_time_left_handle_frame_set(scene, seq, prev_startdisp);
+ SEQ_time_right_handle_frame_set(scene, seq, prev_enddisp);
+ SEQ_transform_fix_single_image_seq_offsets(scene, seq);
}
- ListBase *seqbase = SEQ_active_seqbase_get(SEQ_editing_get(scene));
- SEQ_time_update_sequence(scene, seqbase, seq);
SEQ_relations_invalidate_cache_raw(scene, seq);
}
diff --git a/source/blender/sequencer/intern/strip_edit.c b/source/blender/sequencer/intern/strip_edit.c
index 6c7bb71cb75..bd439e3c9f8 100644
--- a/source/blender/sequencer/intern/strip_edit.c
+++ b/source/blender/sequencer/intern/strip_edit.c
@@ -83,11 +83,9 @@ int SEQ_edit_sequence_swap(Sequence *seq_a, Sequence *seq_b, const char **error_
SWAP(int, seq_a->start, seq_b->start);
SWAP(int, seq_a->startofs, seq_b->startofs);
SWAP(int, seq_a->endofs, seq_b->endofs);
- SWAP(int, seq_a->startstill, seq_b->startstill);
- SWAP(int, seq_a->endstill, seq_b->endstill);
SWAP(int, seq_a->machine, seq_b->machine);
- SWAP(int, seq_a->startdisp, seq_b->startdisp);
- SWAP(int, seq_a->enddisp, seq_b->enddisp);
+ seq_time_effect_range_set(seq_a);
+ seq_time_effect_range_set(seq_b);
return 1;
}
@@ -232,7 +230,7 @@ bool SEQ_edit_move_strip_to_meta(Scene *scene,
{
/* Find the appropriate seqbase */
Editing *ed = SEQ_editing_get(scene);
- ListBase *seqbase = SEQ_get_seqbase_by_seq(&ed->seqbase, src_seq);
+ ListBase *seqbase = SEQ_get_seqbase_by_seq(scene, src_seq);
if (dst_seqm->type != SEQ_TYPE_META) {
*error_str = N_("Can not move strip to non-meta strip");
@@ -274,87 +272,81 @@ bool SEQ_edit_move_strip_to_meta(Scene *scene,
return true;
}
-static void seq_split_set_left_hold_offset(Sequence *seq, int timeline_frame)
+static void seq_split_set_left_hold_offset(const Scene *scene, Sequence *seq, int timeline_frame)
{
/* Adjust within range of extended stillframes before strip. */
if (timeline_frame < seq->start) {
- seq->start = timeline_frame - 1;
- seq->anim_endofs += seq->len - 1;
- seq->startstill = timeline_frame - seq->startdisp - 1;
- seq->endstill = 0;
+ SEQ_time_left_handle_frame_set(scene, seq, timeline_frame);
}
/* Adjust within range of strip contents. */
else if ((timeline_frame >= seq->start) && (timeline_frame <= (seq->start + seq->len))) {
- seq->endofs = 0;
- seq->endstill = 0;
- seq->anim_endofs += (seq->start + seq->len) - timeline_frame;
+ seq->anim_startofs += timeline_frame - seq->start;
+ seq->start = timeline_frame;
+ seq->startofs = 0;
}
/* Adjust within range of extended stillframes after strip. */
else if ((seq->start + seq->len) < timeline_frame) {
- seq->endstill = timeline_frame - seq->start - seq->len;
+ const int right_handle_backup = SEQ_time_right_handle_frame_get(seq);
+ seq->start += timeline_frame - seq->start;
+ seq->anim_startofs += seq->len - 1;
+ seq->len = 1;
+ SEQ_time_left_handle_frame_set(scene, seq, timeline_frame);
+ SEQ_time_right_handle_frame_set(scene, seq, right_handle_backup);
}
}
-static void seq_split_set_right_hold_offset(Sequence *seq, int timeline_frame)
+static void seq_split_set_right_hold_offset(const Scene *scene, Sequence *seq, int timeline_frame)
{
/* Adjust within range of extended stillframes before strip. */
if (timeline_frame < seq->start) {
- seq->startstill = seq->start - timeline_frame;
+ const int left_handle_backup = SEQ_time_left_handle_frame_get(seq);
+ seq->start = timeline_frame - 1;
+ SEQ_time_left_handle_frame_set(scene, seq, left_handle_backup);
+ SEQ_time_right_handle_frame_set(scene, seq, timeline_frame);
}
/* Adjust within range of strip contents. */
else if ((timeline_frame >= seq->start) && (timeline_frame <= (seq->start + seq->len))) {
- seq->anim_startofs += timeline_frame - seq->start;
- seq->start = timeline_frame;
- seq->startstill = 0;
- seq->startofs = 0;
+ seq->anim_endofs += seq->start + seq->len - timeline_frame;
+ seq->endofs = 0;
}
/* Adjust within range of extended stillframes after strip. */
else if ((seq->start + seq->len) < timeline_frame) {
- seq->start = timeline_frame;
- seq->startofs = 0;
- seq->anim_startofs += seq->len - 1;
- seq->endstill = seq->enddisp - timeline_frame - 1;
- seq->startstill = 0;
+ SEQ_time_right_handle_frame_set(scene, seq, timeline_frame);
}
}
-static void seq_split_set_right_offset(Sequence *seq, int timeline_frame)
+static void seq_split_set_right_offset(const Scene *scene, Sequence *seq, int timeline_frame)
{
/* Adjust within range of extended stillframes before strip. */
if (timeline_frame < seq->start) {
+ const int content_offset = seq->start - timeline_frame + 1;
seq->start = timeline_frame - 1;
- seq->startstill = timeline_frame - seq->startdisp - 1;
- seq->endofs = seq->len - 1;
- }
- /* Adjust within range of extended stillframes after strip. */
- else if ((seq->start + seq->len) < timeline_frame) {
- seq->endstill -= seq->enddisp - timeline_frame;
+ seq->startofs += content_offset;
}
- SEQ_transform_set_right_handle_frame(seq, timeline_frame);
+
+ SEQ_time_right_handle_frame_set(scene, seq, timeline_frame);
}
-static void seq_split_set_left_offset(Sequence *seq, int timeline_frame)
+static void seq_split_set_left_offset(const Scene *scene, Sequence *seq, int timeline_frame)
{
- /* Adjust within range of extended stillframes before strip. */
- if (timeline_frame < seq->start) {
- seq->startstill = seq->start - timeline_frame;
- }
/* Adjust within range of extended stillframes after strip. */
- if ((seq->start + seq->len) < timeline_frame) {
- seq->start = timeline_frame - seq->len + 1;
- seq->endstill = seq->enddisp - timeline_frame - 1;
+ if (timeline_frame > seq->start + seq->len) {
+ const int content_offset = timeline_frame - (seq->start + seq->len) + 1;
+ seq->start += content_offset;
+ seq->endofs += content_offset;
}
- SEQ_transform_set_left_handle_frame(seq, timeline_frame);
+
+ SEQ_time_left_handle_frame_set(scene, seq, timeline_frame);
}
static bool seq_edit_split_effect_intersect_check(const Sequence *seq, const int timeline_frame)
{
- return timeline_frame > seq->startdisp && timeline_frame < seq->enddisp;
+ return timeline_frame > SEQ_time_left_handle_frame_get(seq) &&
+ timeline_frame < SEQ_time_right_handle_frame_get(seq);
}
static void seq_edit_split_handle_strip_offsets(Main *bmain,
Scene *scene,
- ListBase *seqbase,
Sequence *left_seq,
Sequence *right_seq,
const int timeline_frame,
@@ -363,27 +355,25 @@ static void seq_edit_split_handle_strip_offsets(Main *bmain,
if (seq_edit_split_effect_intersect_check(right_seq, timeline_frame)) {
switch (method) {
case SEQ_SPLIT_SOFT:
- seq_split_set_left_offset(right_seq, timeline_frame);
+ seq_split_set_left_offset(scene, right_seq, timeline_frame);
break;
case SEQ_SPLIT_HARD:
- seq_split_set_left_hold_offset(right_seq, timeline_frame);
+ seq_split_set_left_hold_offset(scene, right_seq, timeline_frame);
SEQ_add_reload_new_file(bmain, scene, right_seq, false);
break;
}
- SEQ_time_update_sequence(scene, seqbase, right_seq);
}
if (seq_edit_split_effect_intersect_check(left_seq, timeline_frame)) {
switch (method) {
case SEQ_SPLIT_SOFT:
- seq_split_set_right_offset(left_seq, timeline_frame);
+ seq_split_set_right_offset(scene, left_seq, timeline_frame);
break;
case SEQ_SPLIT_HARD:
- seq_split_set_right_hold_offset(left_seq, timeline_frame);
+ seq_split_set_right_hold_offset(scene, left_seq, timeline_frame);
SEQ_add_reload_new_file(bmain, scene, left_seq, false);
break;
}
- SEQ_time_update_sequence(scene, seqbase, left_seq);
}
}
@@ -476,10 +466,6 @@ Sequence *SEQ_edit_strip_split(Main *bmain,
SEQ_collection_free(collection);
- /* Sort list, so that no strip can depend on next strip in list.
- * This is important for SEQ_time_update_sequence functionality. */
- SEQ_sort(&left_strips);
-
/* Duplicate ListBase. */
ListBase right_strips = {NULL, NULL};
SEQ_sequence_base_dupli_recursive(scene, scene, &right_strips, &left_strips, SEQ_DUPE_ALL, 0);
@@ -488,18 +474,23 @@ Sequence *SEQ_edit_strip_split(Main *bmain,
Sequence *right_seq = right_strips.first;
Sequence *return_seq = NULL;
- /* 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. */
+ /* Move strips from detached `ListBase`, otherwise they can't be flagged for removal. */
BLI_movelisttolist(seqbase, &left_strips);
BLI_movelisttolist(seqbase, &right_strips);
+ /* Rename duplicated strips. This has to be done immediately after adding
+ * strips to seqbase, for lookup cache to work correctly. */
+ Sequence *seq_rename = right_seq;
+ for (; seq_rename; seq_rename = seq_rename->next) {
+ SEQ_ensure_unique_name(seq_rename, scene);
+ }
+
/* Split strips. */
while (left_seq && right_seq) {
- if (left_seq->startdisp >= timeline_frame) {
+ if (SEQ_time_left_handle_frame_get(left_seq) >= timeline_frame) {
SEQ_edit_flag_for_removal(scene, seqbase, left_seq);
}
- if (right_seq->enddisp <= timeline_frame) {
+ else if (SEQ_time_right_handle_frame_get(right_seq) <= timeline_frame) {
SEQ_edit_flag_for_removal(scene, seqbase, right_seq);
}
else if (return_seq == NULL) {
@@ -507,20 +498,12 @@ Sequence *SEQ_edit_strip_split(Main *bmain,
return_seq = right_seq;
}
- seq_edit_split_handle_strip_offsets(
- bmain, scene, seqbase, left_seq, right_seq, timeline_frame, method);
+ seq_edit_split_handle_strip_offsets(bmain, scene, left_seq, right_seq, timeline_frame, method);
left_seq = left_seq->next;
right_seq = right_seq->next;
}
SEQ_edit_remove_flagged_sequences(scene, seqbase);
-
- /* Rename duplicated strips. */
- Sequence *seq_rename = return_seq;
- for (; seq_rename; seq_rename = seq_rename->next) {
- SEQ_ensure_unique_name(seq_rename, scene);
- }
-
SEQ_animation_restore_original(scene, &fcurves_original_backup);
return return_seq;
diff --git a/source/blender/sequencer/intern/strip_relations.c b/source/blender/sequencer/intern/strip_relations.c
index 1899cc99263..4acf2763ce5 100644
--- a/source/blender/sequencer/intern/strip_relations.c
+++ b/source/blender/sequencer/intern/strip_relations.c
@@ -47,7 +47,8 @@ static bool seq_relations_check_depend(Sequence *seq, Sequence *cur)
}
/* sequences are not intersecting in time, assume no dependency exists between them */
- if (cur->enddisp < seq->startdisp || cur->startdisp > seq->enddisp) {
+ if (SEQ_time_right_handle_frame_get(cur) < SEQ_time_left_handle_frame_get(seq) ||
+ SEQ_time_left_handle_frame_get(cur) > SEQ_time_right_handle_frame_get(seq)) {
return false;
}
@@ -290,8 +291,8 @@ static void sequencer_all_free_anim_ibufs(Editing *ed,
}
else {
/* Limit frame range to meta strip. */
- meta_range[0] = max_ii(frame_range[0], seq->startdisp);
- meta_range[1] = min_ii(frame_range[1], seq->enddisp);
+ meta_range[0] = max_ii(frame_range[0], SEQ_time_left_handle_frame_get(seq));
+ meta_range[1] = min_ii(frame_range[1], SEQ_time_right_handle_frame_get(seq));
}
sequencer_all_free_anim_ibufs(ed, &seq->seqbase, timeline_frame, meta_range);
@@ -345,7 +346,7 @@ bool SEQ_relations_check_scene_recursion(Scene *scene, ReportList *reports)
RPT_WARNING,
"Recursion detected in video sequencer. Strip %s at frame %d will not be rendered",
recursive_seq->name + 2,
- recursive_seq->startdisp);
+ SEQ_time_left_handle_frame_get(recursive_seq));
LISTBASE_FOREACH (Sequence *, seq, &ed->seqbase) {
if (seq->type != SEQ_TYPE_SCENE && sequencer_seq_generates_image(seq)) {
diff --git a/source/blender/sequencer/intern/strip_time.c b/source/blender/sequencer/intern/strip_time.c
index a5341dbc528..4d6efb1639b 100644
--- a/source/blender/sequencer/intern/strip_time.c
+++ b/source/blender/sequencer/intern/strip_time.c
@@ -27,6 +27,7 @@
#include "SEQ_time.h"
#include "SEQ_transform.h"
+#include "sequencer.h"
#include "strip_time.h"
#include "utils.h"
@@ -37,7 +38,7 @@ float seq_give_frame_index(Sequence *seq, float timeline_frame)
int end = seq->start + seq->len - 1;
if (seq->type & SEQ_TYPE_EFFECT) {
- end = seq->enddisp;
+ end = SEQ_time_right_handle_frame_get(seq);
}
if (end < sta) {
@@ -89,7 +90,7 @@ static int metaseq_end(Sequence *metaseq)
return metaseq->start + metaseq->len - metaseq->endofs;
}
-static void seq_update_sound_bounds_recursive_impl(Scene *scene,
+static void seq_update_sound_bounds_recursive_impl(const Scene *scene,
Sequence *metaseq,
int start,
int end)
@@ -131,40 +132,31 @@ static void seq_update_sound_bounds_recursive_impl(Scene *scene,
}
}
-void seq_update_sound_bounds_recursive(Scene *scene, Sequence *metaseq)
+void seq_update_sound_bounds_recursive(const Scene *scene, Sequence *metaseq)
{
seq_update_sound_bounds_recursive_impl(
scene, metaseq, metaseq_start(metaseq), metaseq_end(metaseq));
}
-static void seq_time_update_sequence_bounds(Scene *scene, Sequence *seq)
+/* Update meta strip content start and end, update sound playback range. */
+void SEQ_time_update_meta_strip_range(const Scene *scene, Sequence *seq_meta)
{
- if (seq->startofs && seq->startstill) {
- seq->startstill = 0;
- }
- if (seq->endofs && seq->endstill) {
- seq->endstill = 0;
+ if (seq_meta == NULL) {
+ return;
}
- seq->startdisp = seq->start + seq->startofs - seq->startstill;
- seq->enddisp = seq->start + seq->len - seq->endofs + seq->endstill;
-
- if (seq->type == SEQ_TYPE_META) {
- seq_update_sound_bounds_recursive(scene, seq);
- }
-}
-
-static void seq_time_update_meta_strip(Scene *scene, Sequence *seq_meta)
-{
if (BLI_listbase_is_empty(&seq_meta->seqbase)) {
return;
}
+ const int strip_start = SEQ_time_left_handle_frame_get(seq_meta);
+ const int strip_end = SEQ_time_right_handle_frame_get(seq_meta);
+
int min = MAXFRAME * 2;
int max = -MAXFRAME * 2;
LISTBASE_FOREACH (Sequence *, seq, &seq_meta->seqbase) {
- min = min_ii(seq->startdisp, min);
- max = max_ii(seq->enddisp, max);
+ min = min_ii(SEQ_time_left_handle_frame_get(seq), min);
+ max = max_ii(SEQ_time_right_handle_frame_get(seq), max);
}
seq_meta->start = min + seq_meta->anim_startofs;
@@ -173,144 +165,58 @@ static void seq_time_update_meta_strip(Scene *scene, Sequence *seq_meta)
seq_meta->len -= seq_meta->anim_endofs;
seq_update_sound_bounds_recursive(scene, 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. */
- SEQ_transform_set_left_handle_frame(seq_meta, seq_meta->startdisp);
- SEQ_transform_set_right_handle_frame(seq_meta, seq_meta->enddisp);
+ SEQ_time_left_handle_frame_set(scene, seq_meta, strip_start);
+ SEQ_time_right_handle_frame_set(scene, seq_meta, strip_end);
}
-void SEQ_time_update_sequence(Scene *scene, ListBase *seqbase, Sequence *seq)
+void seq_time_effect_range_set(Sequence *seq)
{
- Sequence *seqm;
-
- /* Check all meta-strips recursively. */
- seqm = seq->seqbase.first;
- while (seqm) {
- if (seqm->seqbase.first) {
- SEQ_time_update_sequence(scene, &seqm->seqbase, seqm);
- }
- seqm = seqm->next;
+ if (seq->seq1 == NULL && seq->seq2 == NULL) {
+ return;
}
- /* effects and meta: automatic start and end */
- if (seq->type & SEQ_TYPE_EFFECT) {
- if (seq->seq1) {
- seq->startofs = seq->endofs = seq->startstill = seq->endstill = 0;
- if (seq->seq3) {
- seq->start = seq->startdisp = max_iii(
- seq->seq1->startdisp, seq->seq2->startdisp, seq->seq3->startdisp);
- seq->enddisp = min_iii(seq->seq1->enddisp, seq->seq2->enddisp, seq->seq3->enddisp);
- }
- else if (seq->seq2) {
- seq->start = seq->startdisp = max_ii(seq->seq1->startdisp, seq->seq2->startdisp);
- seq->enddisp = min_ii(seq->seq1->enddisp, seq->seq2->enddisp);
- }
- else {
- seq->start = seq->startdisp = seq->seq1->startdisp;
- seq->enddisp = seq->seq1->enddisp;
- }
- /* we can't help if strips don't overlap, it won't give useful results.
- * but at least ensure 'len' is never negative which causes bad bugs elsewhere. */
- if (seq->enddisp < seq->startdisp) {
- /* simple start/end swap */
- seq->start = seq->enddisp;
- seq->enddisp = seq->startdisp;
- seq->startdisp = seq->start;
- seq->flag |= SEQ_INVALID_EFFECT;
- }
- else {
- seq->flag &= ~SEQ_INVALID_EFFECT;
- }
-
- seq->len = seq->enddisp - seq->startdisp;
- }
- else {
- seq_time_update_sequence_bounds(scene, seq);
- }
+ if (seq->seq1 && seq->seq2) { /* 2 - input effect. */
+ seq->startdisp = max_ii(SEQ_time_left_handle_frame_get(seq->seq1),
+ SEQ_time_left_handle_frame_get(seq->seq2));
+ seq->enddisp = min_ii(SEQ_time_right_handle_frame_get(seq->seq1),
+ SEQ_time_right_handle_frame_get(seq->seq2));
}
- else if (seq->type == SEQ_TYPE_META) {
- seq_time_update_meta_strip(scene, seq);
+ else if (seq->seq1) { /* Single input effect. */
+ seq->startdisp = SEQ_time_right_handle_frame_get(seq->seq1);
+ seq->enddisp = SEQ_time_left_handle_frame_get(seq->seq1);
}
- else {
- seq_time_update_sequence_bounds(scene, seq);
+ else if (seq->seq2) { /* Strip may be missing one of inputs. */
+ seq->startdisp = SEQ_time_right_handle_frame_get(seq->seq2);
+ seq->enddisp = SEQ_time_left_handle_frame_get(seq->seq2);
}
- Editing *ed = SEQ_editing_get(scene);
-
- /* Strip is inside meta strip */
- if (seqbase != &ed->seqbase) {
- Sequence *meta = SEQ_get_meta_by_seqbase(&ed->seqbase, seqbase);
- SEQ_time_update_meta_strip_range(scene, meta);
+ if (seq->startdisp > seq->enddisp) {
+ SWAP(int, seq->startdisp, seq->enddisp);
}
- seq_time_update_sequence_bounds(scene, seq);
+ /* Values unusable for effects, these should be always 0. */
+ seq->startofs = seq->endofs = seq->anim_startofs = seq->anim_endofs = 0;
}
-static bool update_changed_seq_recurs(Scene *scene, Sequence *seq, Sequence *changed_seq)
+/* Update strip startdisp and enddisp (n-input effects have no len to calculate these). */
+void seq_time_update_effects_strip_range(const Scene *scene, SeqCollection *effects)
{
- Sequence *subseq;
- bool do_update = false;
-
- /* recurse downwards to see if this seq depends on the changed seq */
-
- if (seq == NULL) {
- return false;
- }
-
- if (seq == changed_seq) {
- do_update = true;
- }
-
- for (subseq = seq->seqbase.first; subseq; subseq = subseq->next) {
- if (update_changed_seq_recurs(scene, subseq, changed_seq)) {
- do_update = true;
- }
- }
-
- if (seq->seq1) {
- if (update_changed_seq_recurs(scene, seq->seq1, changed_seq)) {
- do_update = true;
- }
- }
- if (seq->seq2 && (seq->seq2 != seq->seq1)) {
- if (update_changed_seq_recurs(scene, seq->seq2, changed_seq)) {
- do_update = true;
- }
- }
- if (seq->seq3 && (seq->seq3 != seq->seq1) && (seq->seq3 != seq->seq2)) {
- if (update_changed_seq_recurs(scene, seq->seq3, changed_seq)) {
- do_update = true;
- }
- }
-
- if (do_update) {
- ListBase *seqbase = SEQ_active_seqbase_get(SEQ_editing_get(scene));
- SEQ_time_update_sequence(scene, seqbase, seq);
+ if (effects == NULL) {
+ return;
}
- return do_update;
-}
-
-void SEQ_time_update_recursive(Scene *scene, Sequence *changed_seq)
-{
- Editing *ed = SEQ_editing_get(scene);
Sequence *seq;
-
- if (ed == NULL) {
- return;
+ /* First pass: Update length of immediate effects. */
+ SEQ_ITERATOR_FOREACH (seq, effects) {
+ seq_time_effect_range_set(seq);
}
- for (seq = ed->seqbase.first; seq; seq = seq->next) {
- update_changed_seq_recurs(scene, seq, changed_seq);
+ /* Second pass: Recursive call to update effects in chain and in order, so they inherit length
+ * correctly. */
+ SEQ_ITERATOR_FOREACH (seq, effects) {
+ seq_time_update_effects_strip_range(scene, seq_sequence_lookup_effects_by_seq(scene, seq));
}
}
@@ -349,12 +255,14 @@ int SEQ_time_find_next_prev_edit(Scene *scene,
}
if (do_center) {
- seq_frames[0] = (seq->startdisp + seq->enddisp) / 2;
+ seq_frames[0] = (SEQ_time_left_handle_frame_get(seq) +
+ SEQ_time_right_handle_frame_get(seq)) /
+ 2;
seq_frames_tot = 1;
}
else {
- seq_frames[0] = seq->startdisp;
- seq_frames[1] = seq->enddisp;
+ seq_frames[0] = SEQ_time_left_handle_frame_get(seq);
+ seq_frames[1] = SEQ_time_right_handle_frame_get(seq);
seq_frames_tot = 2;
}
@@ -438,11 +346,11 @@ void SEQ_timeline_expand_boundbox(const ListBase *seqbase, rctf *rect)
}
LISTBASE_FOREACH (Sequence *, seq, seqbase) {
- if (rect->xmin > seq->startdisp - 1) {
- rect->xmin = seq->startdisp - 1;
+ if (rect->xmin > SEQ_time_left_handle_frame_get(seq) - 1) {
+ rect->xmin = SEQ_time_left_handle_frame_get(seq) - 1;
}
- if (rect->xmax < seq->enddisp + 1) {
- rect->xmax = seq->enddisp + 1;
+ if (rect->xmax < SEQ_time_right_handle_frame_get(seq) + 1) {
+ rect->xmax = SEQ_time_right_handle_frame_get(seq) + 1;
}
if (rect->ymax < seq->machine) {
rect->ymax = seq->machine;
@@ -514,5 +422,55 @@ void seq_time_gap_info_get(const Scene *scene,
bool SEQ_time_strip_intersects_frame(const Sequence *seq, const int timeline_frame)
{
- return (seq->startdisp <= timeline_frame) && (seq->enddisp > timeline_frame);
+ return (SEQ_time_left_handle_frame_get(seq) <= timeline_frame) &&
+ (SEQ_time_right_handle_frame_get(seq) > timeline_frame);
+}
+
+bool SEQ_time_has_left_still_frames(const Sequence *seq)
+{
+ return seq->startofs < 0;
+}
+
+bool SEQ_time_has_right_still_frames(const Sequence *seq)
+{
+ return seq->endofs < 0;
+}
+
+bool SEQ_time_has_still_frames(const Sequence *seq)
+{
+ return SEQ_time_has_right_still_frames(seq) || SEQ_time_has_left_still_frames(seq);
+}
+
+int SEQ_time_left_handle_frame_get(const Sequence *seq)
+{
+ if (seq->seq1 || seq->seq2) {
+ return seq->startdisp;
+ }
+
+ return seq->start + seq->startofs;
+}
+
+int SEQ_time_right_handle_frame_get(const Sequence *seq)
+{
+ if (seq->seq1 || seq->seq2) {
+ return seq->enddisp;
+ }
+
+ return seq->start + seq->len - seq->endofs;
+}
+
+void SEQ_time_left_handle_frame_set(const Scene *scene, Sequence *seq, int val)
+{
+ seq->startofs = val - seq->start;
+ seq->startdisp = val; /* Only to make files usable in older versions. */
+ SEQ_time_update_meta_strip_range(scene, seq_sequence_lookup_meta_by_seq(scene, seq));
+ seq_time_update_effects_strip_range(scene, seq_sequence_lookup_effects_by_seq(scene, seq));
+}
+
+void SEQ_time_right_handle_frame_set(const Scene *scene, Sequence *seq, int val)
+{
+ seq->endofs = seq->start + seq->len - val;
+ seq->enddisp = val; /* Only to make files usable in older versions. */
+ SEQ_time_update_meta_strip_range(scene, seq_sequence_lookup_meta_by_seq(scene, seq));
+ seq_time_update_effects_strip_range(scene, seq_sequence_lookup_effects_by_seq(scene, seq));
}
diff --git a/source/blender/sequencer/intern/strip_time.h b/source/blender/sequencer/intern/strip_time.h
index c96a016e646..7a75aeac1a6 100644
--- a/source/blender/sequencer/intern/strip_time.h
+++ b/source/blender/sequencer/intern/strip_time.h
@@ -14,9 +14,10 @@ extern "C" {
struct ListBase;
struct Scene;
struct Sequence;
+struct SeqCollection;
float seq_give_frame_index(struct Sequence *seq, float timeline_frame);
-void seq_update_sound_bounds_recursive(struct Scene *scene, struct Sequence *metaseq);
+void seq_update_sound_bounds_recursive(const struct Scene *scene, struct Sequence *metaseq);
/* Describes gap between strips in timeline. */
typedef struct GapInfo {
@@ -37,6 +38,8 @@ void seq_time_gap_info_get(const struct Scene *scene,
struct ListBase *seqbase,
int initial_frame,
struct GapInfo *r_gap_info);
+void seq_time_effect_range_set(Sequence *seq);
+void seq_time_update_effects_strip_range(const struct Scene *scene, struct SeqCollection *effects);
#ifdef __cplusplus
}
diff --git a/source/blender/sequencer/intern/strip_transform.c b/source/blender/sequencer/intern/strip_transform.c
index 2c9ab0a3335..19caf12ff2a 100644
--- a/source/blender/sequencer/intern/strip_transform.c
+++ b/source/blender/sequencer/intern/strip_transform.c
@@ -13,11 +13,13 @@
#include "BLI_listbase.h"
#include "BLI_math.h"
+#include "BKE_main.h"
#include "BKE_scene.h"
#include "BKE_sound.h"
#include "SEQ_animation.h"
#include "SEQ_channels.h"
+#include "SEQ_edit.h"
#include "SEQ_effects.h"
#include "SEQ_iterator.h"
#include "SEQ_relations.h"
@@ -25,6 +27,9 @@
#include "SEQ_time.h"
#include "SEQ_transform.h"
+#include "sequencer.h"
+#include "strip_time.h"
+
#include "CLG_log.h"
static CLG_LogRef LOG = {"seq.strip_transform"};
@@ -38,39 +43,6 @@ static int seq_tx_get_end(Sequence *seq)
return seq->start + seq->len;
}
-int SEQ_transform_get_left_handle_frame(Sequence *seq)
-{
- return (seq->start - seq->startstill) + seq->startofs;
-}
-int SEQ_transform_get_right_handle_frame(Sequence *seq)
-{
- return ((seq->start + seq->len) + seq->endstill) - seq->endofs;
-}
-
-void SEQ_transform_set_left_handle_frame(Sequence *seq, int val)
-{
- if (val < (seq)->start) {
- seq->startstill = abs(val - (seq)->start);
- seq->startofs = 0;
- }
- else {
- seq->startofs = abs(val - (seq)->start);
- seq->startstill = 0;
- }
-}
-
-void SEQ_transform_set_right_handle_frame(Sequence *seq, int val)
-{
- if (val > (seq)->start + (seq)->len) {
- seq->endstill = abs(val - (seq->start + (seq)->len));
- seq->endofs = 0;
- }
- else {
- seq->endofs = abs(val - ((seq)->start + (seq)->len));
- seq->endstill = 0;
- }
-}
-
bool SEQ_transform_single_image_check(Sequence *seq)
{
return ((seq->len == 1) &&
@@ -119,16 +91,16 @@ bool SEQ_transform_seqbase_isolated_sel_check(ListBase *seqbase)
return true;
}
-void SEQ_transform_handle_xlimits(Sequence *seq, int leftflag, int rightflag)
+void SEQ_transform_handle_xlimits(const Scene *scene, Sequence *seq, int leftflag, int rightflag)
{
if (leftflag) {
- if (SEQ_transform_get_left_handle_frame(seq) >= SEQ_transform_get_right_handle_frame(seq)) {
- SEQ_transform_set_left_handle_frame(seq, SEQ_transform_get_right_handle_frame(seq) - 1);
+ if (SEQ_time_left_handle_frame_get(seq) >= SEQ_time_right_handle_frame_get(seq)) {
+ SEQ_time_left_handle_frame_set(scene, seq, SEQ_time_right_handle_frame_get(seq) - 1);
}
if (SEQ_transform_single_image_check(seq) == 0) {
- if (SEQ_transform_get_left_handle_frame(seq) >= seq_tx_get_end(seq)) {
- SEQ_transform_set_left_handle_frame(seq, seq_tx_get_end(seq) - 1);
+ if (SEQ_time_left_handle_frame_get(seq) >= seq_tx_get_end(seq)) {
+ SEQ_time_left_handle_frame_set(scene, seq, seq_tx_get_end(seq) - 1);
}
/* TODO: This doesn't work at the moment. */
@@ -144,25 +116,25 @@ void SEQ_transform_handle_xlimits(Sequence *seq, int leftflag, int rightflag)
}
if (rightflag) {
- if (SEQ_transform_get_right_handle_frame(seq) <= SEQ_transform_get_left_handle_frame(seq)) {
- SEQ_transform_set_right_handle_frame(seq, SEQ_transform_get_left_handle_frame(seq) + 1);
+ if (SEQ_time_right_handle_frame_get(seq) <= SEQ_time_left_handle_frame_get(seq)) {
+ SEQ_time_right_handle_frame_set(scene, seq, SEQ_time_left_handle_frame_get(seq) + 1);
}
if (SEQ_transform_single_image_check(seq) == 0) {
- if (SEQ_transform_get_right_handle_frame(seq) <= seq_tx_get_start(seq)) {
- SEQ_transform_set_right_handle_frame(seq, seq_tx_get_start(seq) + 1);
+ if (SEQ_time_right_handle_frame_get(seq) <= seq_tx_get_start(seq)) {
+ SEQ_time_right_handle_frame_set(scene, seq, seq_tx_get_start(seq) + 1);
}
}
}
/* sounds cannot be extended past their endpoints */
if (seq->type == SEQ_TYPE_SOUND_RAM) {
- seq->startstill = 0;
- seq->endstill = 0;
+ CLAMP(seq->startofs, 0, MAXFRAME);
+ CLAMP(seq->endofs, 0, MAXFRAME);
}
}
-void SEQ_transform_fix_single_image_seq_offsets(Sequence *seq)
+void SEQ_transform_fix_single_image_seq_offsets(const Scene *scene, Sequence *seq)
{
int left, start, offset;
if (!SEQ_transform_single_image_check(seq)) {
@@ -171,12 +143,12 @@ void SEQ_transform_fix_single_image_seq_offsets(Sequence *seq)
/* make sure the image is always at the start since there is only one,
* adjusting its start should be ok */
- left = SEQ_transform_get_left_handle_frame(seq);
+ left = SEQ_time_left_handle_frame_get(seq);
start = seq->start;
if (start != left) {
offset = left - start;
- SEQ_transform_set_left_handle_frame(seq, SEQ_transform_get_left_handle_frame(seq) - offset);
- SEQ_transform_set_right_handle_frame(seq, SEQ_transform_get_right_handle_frame(seq) - offset);
+ SEQ_time_left_handle_frame_set(scene, seq, SEQ_time_left_handle_frame_get(seq) - offset);
+ SEQ_time_right_handle_frame_set(scene, seq, SEQ_time_right_handle_frame_get(seq) - offset);
seq->start += offset;
}
}
@@ -189,7 +161,8 @@ bool SEQ_transform_sequence_can_be_translated(Sequence *seq)
bool SEQ_transform_test_overlap_seq_seq(Sequence *seq1, Sequence *seq2)
{
return (seq1 != seq2 && seq1->machine == seq2->machine &&
- ((seq1->enddisp <= seq2->startdisp) || (seq1->startdisp >= seq2->enddisp)) == 0);
+ ((SEQ_time_right_handle_frame_get(seq1) <= SEQ_time_left_handle_frame_get(seq2)) ||
+ (SEQ_time_left_handle_frame_get(seq1) >= SEQ_time_right_handle_frame_get(seq2))) == 0);
}
bool SEQ_transform_test_overlap(ListBase *seqbasep, Sequence *test)
@@ -213,9 +186,6 @@ void SEQ_transform_translate_sequence(Scene *evil_scene, Sequence *seq, int delt
return;
}
- SEQ_offset_animdata(evil_scene, seq, delta);
- seq->start += delta;
-
/* Meta strips requires special handling: their content is to be translated, and then frame range
* of the meta is to be updated for the updated content. */
if (seq->type == SEQ_TYPE_META) {
@@ -223,16 +193,21 @@ void SEQ_transform_translate_sequence(Scene *evil_scene, Sequence *seq, int delt
for (seq_child = seq->seqbase.first; seq_child; seq_child = seq_child->next) {
SEQ_transform_translate_sequence(evil_scene, seq_child, delta);
}
- /* Ensure that meta bounds are updated, but this function prevents resets seq->start and
- * start/end point in timeline. */
- SEQ_time_update_meta_strip_range(evil_scene, seq);
/* Move meta start/end points. */
- SEQ_transform_set_left_handle_frame(seq, seq->startdisp + delta);
- SEQ_transform_set_right_handle_frame(seq, seq->enddisp + delta);
+ SEQ_time_left_handle_frame_set(evil_scene, seq, SEQ_time_left_handle_frame_get(seq) + delta);
+ SEQ_time_right_handle_frame_set(evil_scene, seq, SEQ_time_right_handle_frame_get(seq) + delta);
+ }
+ else { /* All other strip types. */
+ seq->start += delta;
+ /* Only to make files usable in older versions. */
+ seq->startdisp = SEQ_time_left_handle_frame_get(seq);
+ seq->enddisp = SEQ_time_right_handle_frame_get(seq);
}
- ListBase *seqbase = SEQ_active_seqbase_get(SEQ_editing_get(evil_scene));
- SEQ_time_update_sequence(evil_scene, seqbase, seq);
+ SEQ_offset_animdata(evil_scene, seq, delta);
+ SEQ_time_update_meta_strip_range(evil_scene, seq_sequence_lookup_meta_by_seq(evil_scene, seq));
+ seq_time_update_effects_strip_range(evil_scene,
+ seq_sequence_lookup_effects_by_seq(evil_scene, seq));
}
bool SEQ_transform_seqbase_shuffle_ex(ListBase *seqbasep,
@@ -244,16 +219,12 @@ bool SEQ_transform_seqbase_shuffle_ex(ListBase *seqbasep,
BLI_assert(ELEM(channel_delta, -1, 1));
test->machine += channel_delta;
- SEQ_time_update_sequence(evil_scene, seqbasep, test);
while (SEQ_transform_test_overlap(seqbasep, test)) {
if ((channel_delta > 0) ? (test->machine >= MAXSEQ) : (test->machine < 1)) {
break;
}
test->machine += channel_delta;
-
- /* XXX: I don't think this is needed since were only moving vertically, Campbell. */
- SEQ_time_update_sequence(evil_scene, seqbasep, test);
}
if (!SEQ_valid_strip_channel(test)) {
@@ -261,19 +232,18 @@ bool SEQ_transform_seqbase_shuffle_ex(ListBase *seqbasep,
* nicer to move it to the end */
Sequence *seq;
- int new_frame = test->enddisp;
+ int new_frame = SEQ_time_right_handle_frame_get(test);
for (seq = seqbasep->first; seq; seq = seq->next) {
if (seq->machine == orig_machine) {
- new_frame = max_ii(new_frame, seq->enddisp);
+ new_frame = max_ii(new_frame, SEQ_time_right_handle_frame_get(seq));
}
}
test->machine = orig_machine;
- new_frame = new_frame + (test->start - test->startdisp); /* adjust by the startdisp */
+ new_frame = new_frame +
+ (test->start - SEQ_time_left_handle_frame_get(test)); /* adjust by the startdisp */
SEQ_transform_translate_sequence(evil_scene, test, new_frame - test->start);
-
- SEQ_time_update_sequence(evil_scene, seqbasep, test);
return false;
}
@@ -285,71 +255,68 @@ bool SEQ_transform_seqbase_shuffle(ListBase *seqbasep, Sequence *test, Scene *ev
return SEQ_transform_seqbase_shuffle_ex(seqbasep, test, evil_scene, 1);
}
-static int shuffle_seq_time_offset_test(SeqCollection *strips_to_shuffle,
- ListBase *seqbasep,
- char dir)
+static bool shuffle_seq_test_overlap(const Sequence *seq1, const Sequence *seq2, const int offset)
{
- int offset = 0;
- Sequence *seq;
-
- SEQ_ITERATOR_FOREACH (seq, strips_to_shuffle) {
- LISTBASE_FOREACH (Sequence *, seq_other, seqbasep) {
- if (!SEQ_transform_test_overlap_seq_seq(seq, seq_other)) {
- continue;
- }
- if (SEQ_relation_is_effect_of_strip(seq_other, seq)) {
- continue;
- }
- if (UNLIKELY(SEQ_collection_has_strip(seq_other, strips_to_shuffle))) {
- CLOG_WARN(&LOG,
- "Strip overlaps with itself or another strip, that is to be shuffled. "
- "This should never happen.");
- continue;
- }
- if (dir == 'L') {
- offset = min_ii(offset, seq_other->startdisp - seq->enddisp);
- }
- else {
- offset = max_ii(offset, seq_other->enddisp - seq->startdisp);
- }
- }
- }
- return offset;
+ return (
+ seq1 != seq2 && seq1->machine == seq2->machine &&
+ ((SEQ_time_right_handle_frame_get(seq1) + offset <= SEQ_time_left_handle_frame_get(seq2)) ||
+ (SEQ_time_left_handle_frame_get(seq1) + offset >= SEQ_time_right_handle_frame_get(seq2))) ==
+ 0);
}
-static int shuffle_seq_time_offset(SeqCollection *strips_to_shuffle,
- ListBase *seqbasep,
- Scene *scene,
- char dir)
+static int shuffle_seq_time_offset_get(SeqCollection *strips_to_shuffle,
+ ListBase *seqbasep,
+ char dir)
{
- int ofs = 0;
- int tot_ofs = 0;
+ int offset = 0;
Sequence *seq;
- while ((ofs = shuffle_seq_time_offset_test(strips_to_shuffle, seqbasep, dir))) {
+ bool all_conflicts_resolved = false;
+
+ while (!all_conflicts_resolved) {
+ all_conflicts_resolved = true;
SEQ_ITERATOR_FOREACH (seq, strips_to_shuffle) {
- /* seq_test_overlap only tests display values */
- seq->startdisp += ofs;
- seq->enddisp += ofs;
- }
+ LISTBASE_FOREACH (Sequence *, seq_other, seqbasep) {
+ if (!shuffle_seq_test_overlap(seq, seq_other, offset)) {
+ continue;
+ }
+ if (SEQ_relation_is_effect_of_strip(seq_other, seq)) {
+ continue;
+ }
+ if (UNLIKELY(SEQ_collection_has_strip(seq_other, strips_to_shuffle))) {
+ CLOG_WARN(&LOG,
+ "Strip overlaps with itself or another strip, that is to be shuffled. "
+ "This should never happen.");
+ continue;
+ }
- tot_ofs += ofs;
- }
+ all_conflicts_resolved = false;
- SEQ_ITERATOR_FOREACH (seq, strips_to_shuffle) {
- SEQ_time_update_sequence(scene, seqbasep, seq); /* corrects dummy startdisp/enddisp values */
+ if (dir == 'L') {
+ offset = min_ii(offset,
+ SEQ_time_left_handle_frame_get(seq_other) -
+ SEQ_time_right_handle_frame_get(seq));
+ }
+ else {
+ offset = max_ii(offset,
+ SEQ_time_right_handle_frame_get(seq_other) -
+ SEQ_time_left_handle_frame_get(seq));
+ }
+ }
+ }
}
- return tot_ofs;
+ return offset;
}
bool SEQ_transform_seqbase_shuffle_time(SeqCollection *strips_to_shuffle,
+ SeqCollection *time_dependent_strips,
ListBase *seqbasep,
Scene *evil_scene,
ListBase *markers,
const bool use_sync_markers)
{
- int offset_l = shuffle_seq_time_offset(strips_to_shuffle, seqbasep, evil_scene, 'L');
- int offset_r = shuffle_seq_time_offset(strips_to_shuffle, seqbasep, evil_scene, 'R');
+ int offset_l = shuffle_seq_time_offset_get(strips_to_shuffle, seqbasep, 'L');
+ int offset_r = shuffle_seq_time_offset_get(strips_to_shuffle, seqbasep, 'R');
int offset = (-offset_l < offset_r) ? offset_l : offset_r;
if (offset) {
@@ -359,6 +326,12 @@ bool SEQ_transform_seqbase_shuffle_time(SeqCollection *strips_to_shuffle,
seq->flag &= ~SEQ_OVERLAP;
}
+ if (time_dependent_strips != NULL) {
+ SEQ_ITERATOR_FOREACH (seq, time_dependent_strips) {
+ SEQ_offset_animdata(evil_scene, seq, offset);
+ }
+ }
+
if (use_sync_markers && !(evil_scene->toolsettings->lock_markers) && (markers != NULL)) {
TimeMarker *marker;
/* affect selected markers - it's unlikely that we will want to affect all in this way? */
@@ -373,15 +346,304 @@ bool SEQ_transform_seqbase_shuffle_time(SeqCollection *strips_to_shuffle,
return offset ? false : true;
}
+static SeqCollection *extract_standalone_strips(SeqCollection *transformed_strips)
+{
+ SeqCollection *collection = SEQ_collection_create(__func__);
+ Sequence *seq;
+ SEQ_ITERATOR_FOREACH (seq, transformed_strips) {
+ if ((seq->type & SEQ_TYPE_EFFECT) == 0 || seq->seq1 == NULL) {
+ SEQ_collection_append_strip(seq, collection);
+ }
+ }
+ return collection;
+}
+
+/* Query strips positioned after left edge of transformed strips bound-box. */
+static SeqCollection *query_right_side_strips(ListBase *seqbase,
+ SeqCollection *transformed_strips,
+ SeqCollection *time_dependent_strips)
+{
+ int minframe = MAXFRAME;
+ {
+ Sequence *seq;
+ SEQ_ITERATOR_FOREACH (seq, transformed_strips) {
+ minframe = min_ii(minframe, SEQ_time_left_handle_frame_get(seq));
+ }
+ }
+
+ SeqCollection *collection = SEQ_collection_create(__func__);
+ LISTBASE_FOREACH (Sequence *, seq, seqbase) {
+ if (SEQ_collection_has_strip(seq, time_dependent_strips)) {
+ continue;
+ }
+ if (SEQ_collection_has_strip(seq, transformed_strips)) {
+ continue;
+ }
+
+ if ((seq->flag & SELECT) == 0 && SEQ_time_left_handle_frame_get(seq) >= minframe) {
+ SEQ_collection_append_strip(seq, collection);
+ }
+ }
+ return collection;
+}
+
+/* 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(Scene *scene,
+ ListBase *seqbasep,
+ SeqCollection *transformed_strips,
+ SeqCollection *time_dependent_strips,
+ bool use_sync_markers)
+{
+ ListBase *markers = &scene->markers;
+
+ SeqCollection *right_side_strips = query_right_side_strips(
+ seqbasep, transformed_strips, time_dependent_strips);
+
+ /* Temporarily move right side strips beyond timeline boundary. */
+ Sequence *seq;
+ SEQ_ITERATOR_FOREACH (seq, right_side_strips) {
+ seq->machine += MAXSEQ * 2;
+ }
+
+ /* Shuffle transformed standalone strips. This is because transformed strips can overlap with
+ * strips on left side. */
+ SeqCollection *standalone_strips = extract_standalone_strips(transformed_strips);
+ SEQ_transform_seqbase_shuffle_time(
+ standalone_strips, time_dependent_strips, seqbasep, scene, markers, use_sync_markers);
+ SEQ_collection_free(standalone_strips);
+
+ /* Move temporarily moved strips back to their original place and tag for shuffling. */
+ SEQ_ITERATOR_FOREACH (seq, right_side_strips) {
+ seq->machine -= MAXSEQ * 2;
+ }
+ /* Shuffle again to displace strips on right side. Final effect shuffling is done in
+ * SEQ_transform_handle_overlap. */
+ SEQ_transform_seqbase_shuffle_time(
+ right_side_strips, NULL, seqbasep, scene, markers, use_sync_markers);
+ SEQ_collection_free(right_side_strips);
+}
+
+static SeqCollection *query_overwrite_targets(ListBase *seqbasep,
+ SeqCollection *transformed_strips)
+{
+ SeqCollection *collection = SEQ_query_unselected_strips(seqbasep);
+
+ Sequence *seq, *seq_transformed;
+ SEQ_ITERATOR_FOREACH (seq, collection) {
+ bool does_overlap = false;
+
+ SEQ_ITERATOR_FOREACH (seq_transformed, transformed_strips) {
+ /* Effects of transformed strips can be unselected. These must not be included. */
+ if (seq == seq_transformed) {
+ SEQ_collection_remove_strip(seq, collection);
+ }
+ if (SEQ_transform_test_overlap_seq_seq(seq, seq_transformed)) {
+ does_overlap = true;
+ }
+ }
+
+ if (!does_overlap) {
+ SEQ_collection_remove_strip(seq, collection);
+ }
+ }
+
+ return collection;
+}
+
+typedef enum eOvelapDescrition {
+ /* No overlap. */
+ STRIP_OVERLAP_NONE,
+ /* Overlapping strip covers overlapped completely. */
+ STRIP_OVERLAP_IS_FULL,
+ /* Overlapping strip is inside overlapped. */
+ STRIP_OVERLAP_IS_INSIDE,
+ /* Partial overlap between 2 strips. */
+ STRIP_OVERLAP_LEFT_SIDE,
+ STRIP_OVERLAP_RIGHT_SIDE,
+} eOvelapDescrition;
+
+static eOvelapDescrition overlap_description_get(const Sequence *transformed,
+ const Sequence *target)
+{
+ if (SEQ_time_left_handle_frame_get(transformed) <= SEQ_time_left_handle_frame_get(target) &&
+ SEQ_time_right_handle_frame_get(transformed) >= SEQ_time_right_handle_frame_get(target)) {
+ return STRIP_OVERLAP_IS_FULL;
+ }
+ if (SEQ_time_left_handle_frame_get(transformed) > SEQ_time_left_handle_frame_get(target) &&
+ SEQ_time_right_handle_frame_get(transformed) < SEQ_time_right_handle_frame_get(target)) {
+ return STRIP_OVERLAP_IS_INSIDE;
+ }
+ if (SEQ_time_left_handle_frame_get(transformed) <= SEQ_time_left_handle_frame_get(target) &&
+ SEQ_time_left_handle_frame_get(target) <= SEQ_time_right_handle_frame_get(transformed)) {
+ return STRIP_OVERLAP_LEFT_SIDE;
+ }
+ if (SEQ_time_left_handle_frame_get(transformed) <= SEQ_time_right_handle_frame_get(target) &&
+ SEQ_time_right_handle_frame_get(target) <= SEQ_time_right_handle_frame_get(transformed)) {
+ return STRIP_OVERLAP_RIGHT_SIDE;
+ }
+ return STRIP_OVERLAP_NONE;
+}
+
+/* Split strip in 3 parts, remove middle part and fit transformed inside. */
+static void seq_transform_handle_overwrite_split(Scene *scene,
+ ListBase *seqbasep,
+ const Sequence *transformed,
+ Sequence *target)
+{
+ /* Because we are doing a soft split, bmain is not used in SEQ_edit_strip_split, so we can pass
+ * NULL here. */
+ Main *bmain = NULL;
+
+ Sequence *split_strip = SEQ_edit_strip_split(bmain,
+ scene,
+ seqbasep,
+ target,
+ SEQ_time_left_handle_frame_get(transformed),
+ SEQ_SPLIT_SOFT,
+ NULL);
+ SEQ_edit_strip_split(bmain,
+ scene,
+ seqbasep,
+ split_strip,
+ SEQ_time_right_handle_frame_get(transformed),
+ SEQ_SPLIT_SOFT,
+ NULL);
+ SEQ_edit_flag_for_removal(scene, seqbasep, split_strip);
+ SEQ_edit_remove_flagged_sequences(scene, seqbasep);
+}
+
+/* Trim strips by adjusting handle position.
+ * This is bit more complicated in case overlap happens on effect. */
+static void seq_transform_handle_overwrite_trim(Scene *scene,
+ ListBase *seqbasep,
+ const Sequence *transformed,
+ Sequence *target,
+ const eOvelapDescrition overlap)
+{
+ SeqCollection *targets = SEQ_query_by_reference(target, seqbasep, SEQ_query_strip_effect_chain);
+
+ /* Expand collection by adding all target's children, effects and their children. */
+ if ((target->type & SEQ_TYPE_EFFECT) != 0) {
+ SEQ_collection_expand(seqbasep, targets, SEQ_query_strip_effect_chain);
+ }
+
+ /* Trim all non effects, that have influence on effect length which is overlapping. */
+ Sequence *seq;
+ SEQ_ITERATOR_FOREACH (seq, targets) {
+ if ((seq->type & SEQ_TYPE_EFFECT) != 0 && SEQ_effect_get_num_inputs(seq->type) > 0) {
+ continue;
+ }
+ if (overlap == STRIP_OVERLAP_LEFT_SIDE) {
+ SEQ_time_left_handle_frame_set(scene, seq, SEQ_time_right_handle_frame_get(transformed));
+ }
+ else {
+ BLI_assert(overlap == STRIP_OVERLAP_RIGHT_SIDE);
+ SEQ_time_right_handle_frame_set(scene, seq, SEQ_time_left_handle_frame_get(transformed));
+ }
+ }
+ SEQ_collection_free(targets);
+}
+
+static void seq_transform_handle_overwrite(Scene *scene,
+ ListBase *seqbasep,
+ SeqCollection *transformed_strips)
+{
+ SeqCollection *targets = query_overwrite_targets(seqbasep, transformed_strips);
+ SeqCollection *strips_to_delete = SEQ_collection_create(__func__);
+
+ Sequence *target;
+ Sequence *transformed;
+ SEQ_ITERATOR_FOREACH (target, targets) {
+ SEQ_ITERATOR_FOREACH (transformed, transformed_strips) {
+ if (transformed->machine != target->machine) {
+ continue;
+ }
+
+ const eOvelapDescrition overlap = overlap_description_get(transformed, target);
+
+ if (overlap == STRIP_OVERLAP_IS_FULL) {
+ SEQ_collection_append_strip(target, strips_to_delete);
+ }
+ else if (overlap == STRIP_OVERLAP_IS_INSIDE) {
+ seq_transform_handle_overwrite_split(scene, seqbasep, transformed, target);
+ }
+ else if (ELEM(overlap, STRIP_OVERLAP_LEFT_SIDE, STRIP_OVERLAP_RIGHT_SIDE)) {
+ seq_transform_handle_overwrite_trim(scene, seqbasep, transformed, target, overlap);
+ }
+ }
+ }
+
+ SEQ_collection_free(targets);
+
+ /* Remove covered strips. This must be done in separate loop, because `SEQ_edit_strip_split()`
+ * also uses `SEQ_edit_remove_flagged_sequences()`. See T91096. */
+ if (SEQ_collection_len(strips_to_delete) > 0) {
+ Sequence *seq;
+ SEQ_ITERATOR_FOREACH (seq, strips_to_delete) {
+ SEQ_edit_flag_for_removal(scene, seqbasep, seq);
+ }
+ SEQ_edit_remove_flagged_sequences(scene, seqbasep);
+ }
+ SEQ_collection_free(strips_to_delete);
+}
+
+static void seq_transform_handle_overlap_shuffle(Scene *scene,
+ ListBase *seqbasep,
+ SeqCollection *transformed_strips,
+ SeqCollection *time_dependent_strips,
+ bool use_sync_markers)
+{
+ ListBase *markers = &scene->markers;
+
+ /* Shuffle non strips with no effects attached. */
+ SeqCollection *standalone_strips = extract_standalone_strips(transformed_strips);
+ SEQ_transform_seqbase_shuffle_time(
+ standalone_strips, time_dependent_strips, seqbasep, scene, markers, use_sync_markers);
+ SEQ_collection_free(standalone_strips);
+}
+
+void SEQ_transform_handle_overlap(Scene *scene,
+ ListBase *seqbasep,
+ SeqCollection *transformed_strips,
+ SeqCollection *time_dependent_strips,
+ bool use_sync_markers)
+{
+ const eSeqOverlapMode overlap_mode = SEQ_tool_settings_overlap_mode_get(scene);
+
+ switch (overlap_mode) {
+ case SEQ_OVERLAP_EXPAND:
+ seq_transform_handle_expand_to_fit(
+ scene, seqbasep, transformed_strips, time_dependent_strips, use_sync_markers);
+ break;
+ case SEQ_OVERLAP_OVERWRITE:
+ seq_transform_handle_overwrite(scene, seqbasep, transformed_strips);
+ break;
+ case SEQ_OVERLAP_SHUFFLE:
+ seq_transform_handle_overlap_shuffle(
+ scene, seqbasep, transformed_strips, time_dependent_strips, use_sync_markers);
+ break;
+ }
+
+ /* If any effects still overlap, we need to move them up.
+ * In some cases other strips can be overlapping still, see T90646. */
+ Sequence *seq;
+ SEQ_ITERATOR_FOREACH (seq, transformed_strips) {
+ if (SEQ_transform_test_overlap(seqbasep, seq)) {
+ SEQ_transform_seqbase_shuffle(seqbasep, seq, scene);
+ }
+ seq->flag &= ~SEQ_OVERLAP;
+ }
+}
+
void SEQ_transform_offset_after_frame(Scene *scene,
ListBase *seqbase,
const int delta,
const int timeline_frame)
{
LISTBASE_FOREACH (Sequence *, seq, seqbase) {
- if (seq->startdisp >= timeline_frame) {
+ if (SEQ_time_left_handle_frame_get(seq) >= timeline_frame) {
SEQ_transform_translate_sequence(scene, seq, delta);
- SEQ_time_update_sequence(scene, seqbase, seq);
SEQ_relations_invalidate_cache_preprocessed(scene, seq);
}
}
diff --git a/source/blender/sequencer/intern/utils.c b/source/blender/sequencer/intern/utils.c
index da422c4228f..3cfe63e284f 100644
--- a/source/blender/sequencer/intern/utils.c
+++ b/source/blender/sequencer/intern/utils.c
@@ -39,55 +39,9 @@
#include "multiview.h"
#include "proxy.h"
+#include "sequencer.h"
#include "utils.h"
-void SEQ_sort(ListBase *seqbase)
-{
- if (seqbase == NULL) {
- return;
- }
-
- /* all strips together per kind, and in order of y location ("machine") */
- ListBase inputbase, effbase;
- Sequence *seq, *seqt;
-
- BLI_listbase_clear(&inputbase);
- BLI_listbase_clear(&effbase);
-
- while ((seq = BLI_pophead(seqbase))) {
-
- if (seq->type & SEQ_TYPE_EFFECT) {
- seqt = effbase.first;
- while (seqt) {
- if (seqt->machine >= seq->machine) {
- BLI_insertlinkbefore(&effbase, seqt, seq);
- break;
- }
- seqt = seqt->next;
- }
- if (seqt == NULL) {
- BLI_addtail(&effbase, seq);
- }
- }
- else {
- seqt = inputbase.first;
- while (seqt) {
- if (seqt->machine >= seq->machine) {
- BLI_insertlinkbefore(&inputbase, seqt, seq);
- break;
- }
- seqt = seqt->next;
- }
- if (seqt == NULL) {
- BLI_addtail(&inputbase, seq);
- }
- }
- }
-
- BLI_movelisttolist(seqbase, &inputbase);
- BLI_movelisttolist(seqbase, &effbase);
-}
-
typedef struct SeqUniqueInfo {
Sequence *seq;
char name_src[SEQ_NAME_MAXSTR];
@@ -225,13 +179,14 @@ const char *SEQ_sequence_give_name(Sequence *seq)
return name;
}
-ListBase *SEQ_get_seqbase_from_sequence(Sequence *seq, int *r_offset)
+ListBase *SEQ_get_seqbase_from_sequence(Sequence *seq, ListBase **r_channels, int *r_offset)
{
ListBase *seqbase = NULL;
switch (seq->type) {
case SEQ_TYPE_META: {
seqbase = &seq->seqbase;
+ *r_channels = &seq->channels;
*r_offset = seq->start;
break;
}
@@ -240,6 +195,7 @@ ListBase *SEQ_get_seqbase_from_sequence(Sequence *seq, int *r_offset)
Editing *ed = SEQ_editing_get(seq->scene);
if (ed) {
seqbase = &ed->seqbase;
+ *r_channels = &ed->channels;
*r_offset = seq->scene->r.sfra;
}
}
@@ -261,7 +217,7 @@ void seq_open_anim_file(Scene *scene, Sequence *seq, bool openfile)
const bool is_multiview = (seq->flag & SEQ_USE_VIEWS) != 0 &&
(scene->r.scemode & R_MULTIVIEW) != 0;
- if ((seq->anims.first != NULL) && (((StripAnim *)seq->anims.first)->anim != NULL)) {
+ if ((seq->anims.first != NULL) && (((StripAnim *)seq->anims.first)->anim != NULL) && !openfile) {
return;
}
@@ -412,20 +368,18 @@ const Sequence *SEQ_get_topmost_sequence(const Scene *scene, int frame)
return best_seq;
}
-ListBase *SEQ_get_seqbase_by_seq(ListBase *seqbase, Sequence *seq)
+ListBase *SEQ_get_seqbase_by_seq(const Scene *scene, Sequence *seq)
{
- Sequence *iseq;
- ListBase *lb = NULL;
+ Editing *ed = SEQ_editing_get(scene);
+ ListBase *main_seqbase = &ed->seqbase;
+ Sequence *seq_meta = seq_sequence_lookup_meta_by_seq(scene, seq);
- for (iseq = seqbase->first; iseq; iseq = iseq->next) {
- if (seq == iseq) {
- return seqbase;
- }
- if (iseq->seqbase.first && (lb = SEQ_get_seqbase_by_seq(&iseq->seqbase, seq))) {
- return lb;
- }
+ if (seq_meta != NULL) {
+ return &seq_meta->seqbase;
+ }
+ if (BLI_findindex(main_seqbase, seq) >= 0) {
+ return main_seqbase;
}
-
return NULL;
}
diff --git a/source/blender/simulation/intern/SIM_mass_spring.cpp b/source/blender/simulation/intern/SIM_mass_spring.cpp
index 46597f80d75..f5a6427a6a4 100644
--- a/source/blender/simulation/intern/SIM_mass_spring.cpp
+++ b/source/blender/simulation/intern/SIM_mass_spring.cpp
@@ -268,9 +268,8 @@ static void cloth_setup_constraints(ClothModifierData *clmd)
/**
* Computes where the cloth would be if it were subject to perfectly stiff edges
- * (edge distance constraints) in a lagrangian solver. then add forces to help
- * guide the implicit solver to that state. this function is called after
- * collisions.
+ * (edge distance constraints) in a lagrangian solver. Then add forces to help
+ * guide the implicit solver to that state. This function is called after collisions.
*/
static int UNUSED_FUNCTION(cloth_calc_helper_forces)(Object *UNUSED(ob),
ClothModifierData *clmd,
diff --git a/source/blender/windowmanager/CMakeLists.txt b/source/blender/windowmanager/CMakeLists.txt
index 73a5f1e6f8d..4c553d0edfe 100644
--- a/source/blender/windowmanager/CMakeLists.txt
+++ b/source/blender/windowmanager/CMakeLists.txt
@@ -39,7 +39,7 @@ set(SRC
intern/wm_dragdrop.c
intern/wm_draw.c
intern/wm_event_query.c
- intern/wm_event_system.c
+ intern/wm_event_system.cc
intern/wm_files.c
intern/wm_files_link.c
intern/wm_gesture.c
diff --git a/source/blender/windowmanager/WM_api.h b/source/blender/windowmanager/WM_api.h
index 525301d4393..60cded3b869 100644
--- a/source/blender/windowmanager/WM_api.h
+++ b/source/blender/windowmanager/WM_api.h
@@ -388,6 +388,12 @@ struct wmEventHandler_UI *WM_event_add_ui_handler(const struct bContext *C,
wmUIHandlerRemoveFunc remove_fn,
void *user_data,
char flag);
+
+/**
+ * Return the first modal operator of type \a ot or NULL.
+ */
+wmOperator *WM_operator_find_modal_by_type(wmWindow *win, const wmOperatorType *ot);
+
/**
* \param postpone: Enable for `win->modalhandlers`,
* this is in a running for () loop in wm_handlers_do().
@@ -732,6 +738,7 @@ void WM_operator_last_properties_ensure(struct wmOperatorType *ot, struct Pointe
wmOperator *WM_operator_last_redo(const struct bContext *C);
/**
* Use for drag & drop a path or name with operators invoke() function.
+ * Returns null if no operator property is set to identify the file or ID to use.
*/
ID *WM_operator_drop_load_path(struct bContext *C, struct wmOperator *op, short idcode);
@@ -770,6 +777,41 @@ void WM_operator_properties_filesel(struct wmOperatorType *ot,
eFileSel_Flag flag,
short display,
short sort);
+
+/**
+ * Tries to pass \a id to an operator via either a "session_uuid" or a "name" property defined in
+ * the properties of \a ptr. The former is preferred, since it works properly with linking and
+ * library overrides (which may both result in multiple IDs with the same name and type).
+ *
+ * Also see #WM_operator_properties_id_lookup() and
+ * #WM_operator_properties_id_lookup_from_name_or_session_uuid()
+ */
+void WM_operator_properties_id_lookup_set_from_id(PointerRNA *ptr, const ID *id);
+/**
+ * Tries to find an ID in \a bmain. There needs to be either a "session_uuid" int or "name" string
+ * property defined and set. The former has priority. See #WM_operator_properties_id_lookup() for a
+ * helper to add the properties.
+ */
+struct ID *WM_operator_properties_id_lookup_from_name_or_session_uuid(struct Main *bmain,
+ PointerRNA *ptr,
+ enum ID_Type type);
+/**
+ * Check if either the "session_uuid" or "name" property is set inside \a ptr. If this is the case
+ * the ID can be looked up by #WM_operator_properties_id_lookup_from_name_or_session_uuid().
+ */
+bool WM_operator_properties_id_lookup_is_set(PointerRNA *ptr);
+/**
+ * Adds "name" and "session_uuid" properties so the caller can tell the operator which ID to act
+ * on. See #WM_operator_properties_id_lookup_from_name_or_session_uuid(). Both properties will be
+ * hidden in the UI and not be saved over consecutive operator calls.
+ *
+ * \note New operators should probably use "session_uuid" only (set \a add_name_prop to #false),
+ * since this works properly with linked data and/or library overrides (in both cases, multiple IDs
+ * with the same name and type may be present). The "name" property is only kept to not break
+ * compatibility with old scripts using some previously existing operators.
+ */
+void WM_operator_properties_id_lookup(wmOperatorType *ot, const bool add_name_prop);
+
/**
* Disable using cursor position,
* use when view operators are initialized from buttons.
@@ -895,12 +937,14 @@ char *WM_prop_pystring_assign(struct bContext *C,
int index);
/**
* Convert: `some.op` -> `SOME_OT_op` or leave as-is.
+ * \return the length of `dst`.
*/
-void WM_operator_bl_idname(char *to, const char *from);
+size_t WM_operator_bl_idname(char *dst, const char *src) ATTR_NONNULL(1, 2);
/**
* Convert: `SOME_OT_op` -> `some.op` or leave as-is.
+ * \return the length of `dst`.
*/
-void WM_operator_py_idname(char *to, const char *from);
+size_t WM_operator_py_idname(char *dst, const char *src) ATTR_NONNULL(1, 2);
/**
* Sanity check to ensure #WM_operator_bl_idname won't fail.
* \returns true when there are no problems with \a idname, otherwise report an error.
@@ -937,6 +981,14 @@ bool WM_operatortype_remove(const char *idname);
* Remove memory of all previously executed tools.
*/
void WM_operatortype_last_properties_clear_all(void);
+
+void WM_operatortype_idname_visit_for_search(const struct bContext *C,
+ PointerRNA *ptr,
+ PropertyRNA *prop,
+ const char *edit_text,
+ StringPropertySearchVisitFunc visit_fn,
+ void *visit_user_data);
+
/**
* Tag all operator-properties of \a ot defined after calling this, until
* the next #WM_operatortype_props_advanced_end call (if available), with
@@ -1040,6 +1092,13 @@ void WM_menutype_freelink(struct MenuType *mt);
void WM_menutype_free(void);
bool WM_menutype_poll(struct bContext *C, struct MenuType *mt);
+void WM_menutype_idname_visit_for_search(const struct bContext *C,
+ struct PointerRNA *ptr,
+ struct PropertyRNA *prop,
+ const char *edit_text,
+ StringPropertySearchVisitFunc visit_fn,
+ void *visit_user_data);
+
/* wm_panel_type.c */
/**
@@ -1051,6 +1110,13 @@ struct PanelType *WM_paneltype_find(const char *idname, bool quiet);
bool WM_paneltype_add(struct PanelType *pt);
void WM_paneltype_remove(struct PanelType *pt);
+void WM_paneltype_idname_visit_for_search(const struct bContext *C,
+ struct PointerRNA *ptr,
+ struct PropertyRNA *prop,
+ const char *edit_text,
+ StringPropertySearchVisitFunc visit_fn,
+ void *visit_user_data);
+
/* wm_gesture_ops.c */
int WM_gesture_box_invoke(struct bContext *C, struct wmOperator *op, const struct wmEvent *event);
@@ -1196,7 +1262,7 @@ struct ID *WM_drag_get_local_ID_from_event(const struct wmEvent *event, short id
bool WM_drag_is_ID_type(const struct wmDrag *drag, int idcode);
/**
- * \note: Does not store \a asset in any way, so it's fine to pass a temporary.
+ * \note Does not store \a asset in any way, so it's fine to pass a temporary.
*/
wmDragAsset *WM_drag_create_asset_data(const struct AssetHandle *asset,
struct AssetMetaData *metadata,
@@ -1228,7 +1294,7 @@ void WM_drag_free_imported_drag_ID(struct Main *bmain,
struct wmDragAssetCatalog *WM_drag_get_asset_catalog_data(const struct wmDrag *drag);
/**
- * \note: Does not store \a asset in any way, so it's fine to pass a temporary.
+ * \note Does not store \a asset in any way, so it's fine to pass a temporary.
*/
void WM_drag_add_asset_list_item(wmDrag *drag,
const struct bContext *C,
@@ -1341,6 +1407,14 @@ void WM_jobs_callbacks(struct wmJob *,
void (*update)(void *),
void (*endjob)(void *));
+void WM_jobs_callbacks_ex(wmJob *wm_job,
+ wm_jobs_start_callback startjob,
+ void (*initjob)(void *),
+ void (*update)(void *),
+ void (*endjob)(void *),
+ void (*completed)(void *),
+ void (*canceled)(void *));
+
/**
* If job running, the same owner gave it a new job.
* if different owner starts existing startjob, it suspends itself
@@ -1367,6 +1441,7 @@ void WM_jobs_kill_all_except(struct wmWindowManager *wm, const void *owner);
void WM_jobs_kill_type(struct wmWindowManager *wm, const void *owner, int job_type);
bool WM_jobs_has_running(const struct wmWindowManager *wm);
+bool WM_jobs_has_running_type(const struct wmWindowManager *wm, int job_type);
void WM_job_main_thread_lock_acquire(struct wmJob *job);
void WM_job_main_thread_lock_release(struct wmJob *job);
@@ -1641,7 +1716,7 @@ void WM_xr_action_binding_destroy(wmXrData *xr,
/**
* If action_set_name is NULL, then all action sets will be treated as active.
*/
-bool WM_xr_active_action_set_set(wmXrData *xr, const char *action_set_name);
+bool WM_xr_active_action_set_set(wmXrData *xr, const char *action_set_name, bool delayed);
bool WM_xr_controller_pose_actions_set(wmXrData *xr,
const char *action_set_name,
diff --git a/source/blender/windowmanager/WM_toolsystem.h b/source/blender/windowmanager/WM_toolsystem.h
index a9e1495d9bf..96094e9e7ef 100644
--- a/source/blender/windowmanager/WM_toolsystem.h
+++ b/source/blender/windowmanager/WM_toolsystem.h
@@ -28,6 +28,11 @@ struct wmOperatorType;
#define WM_TOOLSYSTEM_SPACE_MASK \
((1 << SPACE_IMAGE) | (1 << SPACE_NODE) | (1 << SPACE_VIEW3D) | (1 << SPACE_SEQ))
+/**
+ * Space-types that define their own "mode" (as returned by #WM_toolsystem_mode_from_spacetype).
+ */
+#define WM_TOOLSYSTEM_SPACE_MASK_MODE_FROM_SPACE ((1 << SPACE_IMAGE) | (1 << SPACE_SEQ))
+
/* Values that define a category of active tool. */
typedef struct bToolKey {
int space_type;
diff --git a/source/blender/windowmanager/WM_types.h b/source/blender/windowmanager/WM_types.h
index 3ee5c85c031..aebd62ee91b 100644
--- a/source/blender/windowmanager/WM_types.h
+++ b/source/blender/windowmanager/WM_types.h
@@ -616,6 +616,7 @@ typedef enum eWM_EventFlag {
*/
WM_EVENT_FORCE_DRAG_THRESHOLD = (1 << 2),
} eWM_EventFlag;
+ENUM_OPERATORS(eWM_EventFlag, WM_EVENT_FORCE_DRAG_THRESHOLD);
typedef struct wmTabletData {
/** 0=EVT_TABLET_NONE, 1=EVT_TABLET_STYLUS, 2=EVT_TABLET_ERASER. */
@@ -812,6 +813,10 @@ typedef struct wmXrActionData {
char action_set[64];
/** Action name. */
char action[64];
+ /** User path. E.g. "/user/hand/left" */
+ char user_path[64];
+ /** Other user path, for bimanual actions. E.g. "/user/hand/right" */
+ char user_path_other[64];
/** Type. */
eXrActionType type;
/** State. Set appropriately based on type. */
diff --git a/source/blender/windowmanager/gizmo/WM_gizmo_api.h b/source/blender/windowmanager/gizmo/WM_gizmo_api.h
index 80d29bb8c40..663c8a0baed 100644
--- a/source/blender/windowmanager/gizmo/WM_gizmo_api.h
+++ b/source/blender/windowmanager/gizmo/WM_gizmo_api.h
@@ -388,6 +388,8 @@ void WM_gizmomap_message_subscribe(const struct bContext *C,
struct ARegion *region,
struct wmMsgBus *mbus);
bool WM_gizmomap_is_any_selected(const struct wmGizmoMap *gzmap);
+struct wmGizmo *WM_gizmomap_get_modal(const struct wmGizmoMap *gzmap);
+
/**
* \note We could use a callback to define bounds, for now just use matrix location.
*/
diff --git a/source/blender/windowmanager/gizmo/intern/wm_gizmo_map.c b/source/blender/windowmanager/gizmo/intern/wm_gizmo_map.c
index a61d73b9f0b..f5974a2176b 100644
--- a/source/blender/windowmanager/gizmo/intern/wm_gizmo_map.c
+++ b/source/blender/windowmanager/gizmo/intern/wm_gizmo_map.c
@@ -229,6 +229,11 @@ bool WM_gizmomap_is_any_selected(const wmGizmoMap *gzmap)
return gzmap->gzmap_context.select.len != 0;
}
+wmGizmo *WM_gizmomap_get_modal(const wmGizmoMap *gzmap)
+{
+ return gzmap->gzmap_context.modal;
+}
+
bool WM_gizmomap_minmax(const wmGizmoMap *gzmap,
bool UNUSED(use_hidden),
bool use_select,
@@ -492,7 +497,8 @@ void WM_gizmomap_draw(wmGizmoMap *gzmap,
static void gizmo_draw_select_3d_loop(const bContext *C,
wmGizmo **visible_gizmos,
- const int visible_gizmos_len)
+ const int visible_gizmos_len,
+ bool *r_use_select_bias)
{
/* TODO(campbell): this depends on depth buffer being written to,
@@ -528,6 +534,10 @@ 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);
@@ -545,10 +555,7 @@ 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 bool use_depth_test,
- const bool has_3d_select_bias,
- int *r_hits)
+ const int hotspot)
{
const wmWindowManager *wm = CTX_wm_manager(C);
ScrArea *area = CTX_wm_area(C);
@@ -562,76 +569,30 @@ static int gizmo_find_intersected_3d_intern(wmGizmo **visible_gizmos,
BLI_rcti_init_pt_radius(&rect, co, hotspot);
- /* 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,
- * pick the nearest 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 eGPUSelectMode 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);
-
- /* When switching between modes and the mouse pointer is over a gizmo, the highlight test is
- * performed before the viewport is fully initialized (region->draw_buffer = NULL).
- * When this is the case we should not use depth testing. */
- GPUViewport *gpu_viewport = WM_draw_region_get_viewport(region);
- if (use_depth_test && gpu_viewport == NULL) {
- return -1;
- }
+ ED_view3d_draw_setup_view(
+ wm, CTX_wm_window(C), depsgraph, CTX_data_scene(C), region, v3d, NULL, NULL, &rect);
- 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) */
+ bool use_select_bias = false;
- ED_view3d_draw_setup_view(
- wm, CTX_wm_window(C), depsgraph, CTX_data_scene(C), region, v3d, NULL, NULL, &rect);
+ /* 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);
- /* 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) {
- GPUTexture *depth_tx = GPU_viewport_depth_texture(gpu_viewport);
- GPU_framebuffer_ensure_config(&depth_read_fb,
- {
- GPU_ATTACHMENT_TEXTURE(depth_tx),
- GPU_ATTACHMENT_NONE,
- });
- GPU_framebuffer_bind(depth_read_fb);
- }
-
- 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);
- }
-
- ED_view3d_draw_setup_view(
- wm, CTX_wm_window(C), depsgraph, CTX_data_scene(C), region, v3d, NULL, NULL, NULL);
+ 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();
}
- /* When selection bias is needed, this function will run again with `use_depth_test` enabled. */
- int hit_found = -1;
+ ED_view3d_draw_setup_view(
+ wm, CTX_wm_window(C), depsgraph, CTX_data_scene(C), region, v3d, NULL, NULL, NULL);
- if (has_3d_select_bias && use_depth_test && (hits > 1)) {
+ if (use_select_bias && (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);
@@ -643,6 +604,7 @@ static int gizmo_find_intersected_3d_intern(wmGizmo **visible_gizmos,
GPU_matrix_unproject_3fv(co_screen, rv3d->viewinv, rv3d->winmat, viewport, co_3d_origin);
GPUSelectResult *buf_iter = buffer;
+ int hit_found = -1;
float dot_best = FLT_MAX;
for (int i = 0; i < hits; i++, buf_iter++) {
@@ -662,16 +624,11 @@ static int gizmo_find_intersected_3d_intern(wmGizmo **visible_gizmos,
hit_found = buf_iter->id;
}
}
- }
- else {
- const GPUSelectResult *hit_near = GPU_select_buffer_near(buffer, hits);
- if (hit_near) {
- hit_found = hit_near->id;
- }
+ return hit_found;
}
- *r_hits = hits;
- return hit_found;
+ const GPUSelectResult *hit_near = GPU_select_buffer_near(buffer, hits);
+ return hit_near ? hit_near->id : -1;
}
/**
@@ -694,7 +651,6 @@ 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];
@@ -710,9 +666,6 @@ 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;
- }
}
}
}
@@ -721,86 +674,39 @@ static wmGizmo *gizmo_find_intersected_3d(bContext *C,
* 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 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[] = {
- 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;
+ /* The depth buffer is needed for for gizmos to obscure each other. */
+ GPUViewport *viewport = WM_draw_region_get_viewport(CTX_wm_region(C));
- bool use_depth_test = false;
- bool use_depth_cache = false;
-
- /* Workaround for MS-Windows & NVidia failing to detect any gizmo undo the cursor unless the
- * depth test is enabled, see: T97124.
- * NOTE(@campbellbarton): Ideally the exact cause of this could be tracked down,
- * disable as I don't have a system to test this configuration. */
- if (GPU_type_matches(GPU_DEVICE_NVIDIA | GPU_DEVICE_SOFTWARE, GPU_OS_WIN, GPU_DRIVER_ANY)) {
- use_depth_test = true;
+ /* When switching between modes and the mouse pointer is over a gizmo, the highlight test is
+ * performed before the viewport is fully initialized (region->draw_buffer = NULL).
+ * When this is the case we should not use depth testing. */
+ if (viewport == NULL) {
+ return NULL;
}
+ GPUTexture *depth_tx = GPU_viewport_depth_texture(viewport);
+ GPUFrameBuffer *depth_read_fb = NULL;
+ GPU_framebuffer_ensure_config(&depth_read_fb,
+ {
+ GPU_ATTACHMENT_TEXTURE(depth_tx),
+ GPU_ATTACHMENT_NONE,
+ });
+ GPU_framebuffer_bind(depth_read_fb);
+ const int hotspot_radii[] = {
+ 3 * U.pixelsize,
+ /* This runs on mouse move, careful doing too many tests! */
+ 10 * U.pixelsize,
+ };
for (int i = 0; i < ARRAY_SIZE(hotspot_radii); i++) {
-
- 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) {
+ hit = gizmo_find_intersected_3d_intern(
+ visible_gizmos, visible_gizmos_len_trim, C, co, hotspot_radii[i]);
+ if (hit != -1) {
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();
- }
+ GPU_framebuffer_restore();
+ GPU_framebuffer_free(depth_read_fb);
if (hit != -1) {
const int select_id = hit >> 8;
diff --git a/source/blender/windowmanager/gizmo/intern/wm_gizmo_target_props.c b/source/blender/windowmanager/gizmo/intern/wm_gizmo_target_props.c
index af083630623..1c257424297 100644
--- a/source/blender/windowmanager/gizmo/intern/wm_gizmo_target_props.c
+++ b/source/blender/windowmanager/gizmo/intern/wm_gizmo_target_props.c
@@ -345,7 +345,7 @@ void WM_gizmo_target_property_anim_autokey(bContext *C,
Scene *scene = CTX_data_scene(C);
const float cfra = (float)CFRA;
const int index = gz_prop->index == -1 ? 0 : gz_prop->index;
- ED_autokeyframe_property(C, scene, &gz_prop->ptr, gz_prop->prop, index, cfra);
+ ED_autokeyframe_property(C, scene, &gz_prop->ptr, gz_prop->prop, index, cfra, false);
}
}
diff --git a/source/blender/windowmanager/intern/wm_cursors.c b/source/blender/windowmanager/intern/wm_cursors.c
index b7066178abd..fc992ef069d 100644
--- a/source/blender/windowmanager/intern/wm_cursors.c
+++ b/source/blender/windowmanager/intern/wm_cursors.c
@@ -383,7 +383,7 @@ void WM_cursor_time(wmWindow *win, int nr)
/**
* Because defining a cursor mixes declarations and executable code
* each cursor needs its own scoping block or it would be split up
- * over several hundred lines of code. To enforce/document this better
+ * over several hundred lines of code. To enforce/document this better
* I define 2 pretty brain-dead macros so it's obvious what the extra "[]"
* are for */
diff --git a/source/blender/windowmanager/intern/wm_dragdrop.c b/source/blender/windowmanager/intern/wm_dragdrop.c
index a98ded82a92..09ef4e15012 100644
--- a/source/blender/windowmanager/intern/wm_dragdrop.c
+++ b/source/blender/windowmanager/intern/wm_dragdrop.c
@@ -683,15 +683,10 @@ void WM_drag_free_imported_drag_ID(struct Main *bmain, wmDrag *drag, wmDropBox *
return;
}
- /* Get name from property, not asset data - it may have changed after importing to ensure
- * uniqueness (name is assumed to be set from the imported ID name). */
- char name[MAX_ID_NAME - 2];
- RNA_string_get(drop->ptr, "name", name);
- if (!name[0]) {
- return;
- }
-
- ID *id = BKE_libblock_find_name(bmain, asset_drag->id_type, name);
+ /* Try to find the imported ID. For this to work either a "session_uuid" or "name" property must
+ * have been defined (see #WM_operator_properties_id_lookup()). */
+ ID *id = WM_operator_properties_id_lookup_from_name_or_session_uuid(
+ bmain, drop->ptr, asset_drag->id_type);
if (id != NULL) {
/* Do not delete the dragged ID if it has any user, otherwise if it is a 're-used' ID it will
* cause T95636. Note that we need first to add the user that we want to remove in
@@ -832,7 +827,7 @@ static void wm_drag_draw_icon(bContext *UNUSED(C),
x = xy[0] - (wm_drag_imbuf_icon_width_get(drag) / 2);
y = xy[1] - (wm_drag_imbuf_icon_height_get(drag) / 2);
- float col[4] = {1.0f, 1.0f, 1.0f, 0.65f}; /* this blends texture */
+ const float col[4] = {1.0f, 1.0f, 1.0f, 0.65f}; /* this blends texture */
IMMDrawPixelsTexState state = immDrawPixelsTexSetup(GPU_SHADER_2D_IMAGE_COLOR);
immDrawPixelsTexTiled_scaling(&state,
x,
diff --git a/source/blender/windowmanager/intern/wm_draw.c b/source/blender/windowmanager/intern/wm_draw.c
index 02da798495b..aaa28b1fd85 100644
--- a/source/blender/windowmanager/intern/wm_draw.c
+++ b/source/blender/windowmanager/intern/wm_draw.c
@@ -41,6 +41,7 @@
#include "GPU_debug.h"
#include "GPU_framebuffer.h"
#include "GPU_immediate.h"
+#include "GPU_matrix.h"
#include "GPU_state.h"
#include "GPU_texture.h"
#include "GPU_viewport.h"
@@ -119,6 +120,216 @@ static void wm_paintcursor_draw(bContext *C, ScrArea *area, ARegion *region)
/** \} */
/* -------------------------------------------------------------------- */
+/** \name Draw Software Cursor
+ *
+ * Draw the cursor instead of relying on the graphical environment.
+ * Needed when setting the cursor position (warping) isn't supported (GHOST/WAYLAND).
+ * \{ */
+
+/**
+ * Track the state of the last drawn cursor.
+ */
+static struct {
+ int8_t enabled;
+ int winid;
+ int xy[2];
+} g_software_cursor = {
+ .enabled = -1,
+ .winid = -1,
+};
+
+/** Reuse the result from #GHOST_GetCursorGrabState. */
+struct GrabState {
+ GHOST_TGrabCursorMode mode;
+ GHOST_TAxisFlag wrap_axis;
+ int bounds[4];
+};
+
+static bool wm_software_cursor_needed(void)
+{
+ if (UNLIKELY(g_software_cursor.enabled == -1)) {
+ g_software_cursor.enabled = !GHOST_SupportsCursorWarp();
+ }
+ return g_software_cursor.enabled;
+}
+
+static bool wm_software_cursor_needed_for_window(const wmWindow *win, struct GrabState *grab_state)
+{
+ BLI_assert(wm_software_cursor_needed());
+ if (GHOST_GetCursorVisibility(win->ghostwin)) {
+ /* NOTE: The value in `win->grabcursor` can't be used as it
+ * doesn't always match GHOST's value in the case of tablet events. */
+ bool use_software_cursor;
+ GHOST_GetCursorGrabState(win->ghostwin,
+ &grab_state->mode,
+ &grab_state->wrap_axis,
+ grab_state->bounds,
+ &use_software_cursor);
+ if (use_software_cursor) {
+ return true;
+ }
+ }
+ return false;
+}
+
+static bool wm_software_cursor_motion_test(const wmWindow *win)
+{
+ return (g_software_cursor.winid != win->winid) ||
+ (g_software_cursor.xy[0] != win->eventstate->xy[0]) ||
+ (g_software_cursor.xy[1] != win->eventstate->xy[1]);
+}
+
+static void wm_software_cursor_motion_update(const wmWindow *win)
+{
+
+ g_software_cursor.winid = win->winid;
+ g_software_cursor.xy[0] = win->eventstate->xy[0];
+ g_software_cursor.xy[1] = win->eventstate->xy[1];
+}
+
+static void wm_software_cursor_motion_clear(void)
+{
+ g_software_cursor.winid = -1;
+ g_software_cursor.xy[0] = -1;
+ g_software_cursor.xy[1] = -1;
+}
+
+static void wm_software_cursor_draw_bitmap(const int event_xy[2],
+ const GHOST_CursorBitmapRef *bitmap)
+{
+ GPU_blend(GPU_BLEND_ALPHA);
+
+ float gl_matrix[4][4];
+ GPUTexture *texture = GPU_texture_create_2d(
+ "softeare_cursor", bitmap->data_size[0], bitmap->data_size[1], 1, GPU_RGBA8, NULL);
+ GPU_texture_update(texture, GPU_DATA_UBYTE, bitmap->data);
+ GPU_texture_filter_mode(texture, false);
+
+ GPU_matrix_push();
+
+ const int scale = (int)U.pixelsize;
+
+ unit_m4(gl_matrix);
+
+ gl_matrix[3][0] = event_xy[0] - (bitmap->hot_spot[0] * scale);
+ gl_matrix[3][1] = event_xy[1] - ((bitmap->data_size[1] - bitmap->hot_spot[1]) * scale);
+
+ gl_matrix[0][0] = bitmap->data_size[0] * scale;
+ gl_matrix[1][1] = bitmap->data_size[1] * scale;
+
+ GPU_matrix_mul(gl_matrix);
+
+ GPUVertFormat *imm_format = immVertexFormat();
+ uint pos = GPU_vertformat_attr_add(imm_format, "pos", GPU_COMP_F32, 3, GPU_FETCH_FLOAT);
+ uint texCoord = GPU_vertformat_attr_add(
+ imm_format, "texCoord", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
+
+ /* Use 3D image for correct display of planar tracked images. */
+ immBindBuiltinProgram(GPU_SHADER_3D_IMAGE_MODULATE_ALPHA);
+
+ immBindTexture("image", texture);
+ immUniform1f("alpha", 1.0f);
+
+ immBegin(GPU_PRIM_TRI_FAN, 4);
+
+ immAttr2f(texCoord, 0.0f, 1.0f);
+ immVertex3f(pos, 0.0f, 0.0f, 0.0f);
+
+ immAttr2f(texCoord, 1.0f, 1.0f);
+ immVertex3f(pos, 1.0f, 0.0f, 0.0f);
+
+ immAttr2f(texCoord, 1.0f, 0.0f);
+ immVertex3f(pos, 1.0f, 1.0f, 0.0f);
+
+ immAttr2f(texCoord, 0.0f, 0.0f);
+ immVertex3f(pos, 0.0f, 1.0f, 0.0f);
+
+ immEnd();
+
+ immUnbindProgram();
+
+ GPU_matrix_pop();
+ GPU_texture_unbind(texture);
+ GPU_texture_free(texture);
+
+ GPU_blend(GPU_BLEND_NONE);
+}
+
+static void wm_software_cursor_draw_crosshair(const int event_xy[2])
+{
+ /* Draw a primitive cross-hair cursor.
+ * NOTE: the `win->cursor` could be used for drawing although it's complicated as some cursors
+ * are set by the operating-system, where the pixel information isn't easily available. */
+ const float unit = max_ff(U.dpi_fac, 1.0f);
+ uint pos = GPU_vertformat_attr_add(
+ immVertexFormat(), "pos", GPU_COMP_I32, 2, GPU_FETCH_INT_TO_FLOAT);
+ immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
+
+ immUniformColor4f(1, 1, 1, 1);
+ {
+ const int ofs_line = (8 * unit);
+ const int ofs_size = (2 * unit);
+ immRecti(pos,
+ event_xy[0] - ofs_line,
+ event_xy[1] - ofs_size,
+ event_xy[0] + ofs_line,
+ event_xy[1] + ofs_size);
+ immRecti(pos,
+ event_xy[0] - ofs_size,
+ event_xy[1] - ofs_line,
+ event_xy[0] + ofs_size,
+ event_xy[1] + ofs_line);
+ }
+ immUniformColor4f(0, 0, 0, 1);
+ {
+ const int ofs_line = (7 * unit);
+ const int ofs_size = (1 * unit);
+ immRecti(pos,
+ event_xy[0] - ofs_line,
+ event_xy[1] - ofs_size,
+ event_xy[0] + ofs_line,
+ event_xy[1] + ofs_size);
+ immRecti(pos,
+ event_xy[0] - ofs_size,
+ event_xy[1] - ofs_line,
+ event_xy[0] + ofs_size,
+ event_xy[1] + ofs_line);
+ }
+ immUnbindProgram();
+}
+
+static void wm_software_cursor_draw(wmWindow *win, const struct GrabState *grab_state)
+{
+ int event_xy[2] = {UNPACK2(win->eventstate->xy)};
+
+ if (grab_state->wrap_axis & GHOST_kAxisX) {
+ const int min = grab_state->bounds[0];
+ const int max = grab_state->bounds[2];
+ if (min != max) {
+ event_xy[0] = mod_i(event_xy[0] - min, max - min) + min;
+ }
+ }
+ if (grab_state->wrap_axis & GHOST_kGrabAxisY) {
+ const int height = WM_window_pixels_y(win);
+ const int min = height - grab_state->bounds[1];
+ const int max = height - grab_state->bounds[3];
+ if (min != max) {
+ event_xy[1] = mod_i(event_xy[1] - max, min - max) + max;
+ }
+ }
+
+ GHOST_CursorBitmapRef bitmap = {0};
+ if (GHOST_GetCursorBitmap(win->ghostwin, &bitmap) == GHOST_kSuccess) {
+ wm_software_cursor_draw_bitmap(event_xy, &bitmap);
+ }
+ else {
+ wm_software_cursor_draw_crosshair(event_xy);
+ }
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
/** \name Post Draw Region on display handlers
* \{ */
@@ -467,7 +678,7 @@ static bool wm_draw_region_bind(bContext *C, ARegion *region, int view)
}
if (region->draw_buffer->viewport) {
- if (G.is_rendering && C != NULL) {
+ if (G.is_rendering && C != NULL && U.experimental.use_draw_manager_acquire_lock) {
Scene *scene = CTX_data_scene(C);
RenderEngineType *render_engine_type = RE_engines_find(scene->r.engine);
if (RE_engine_is_opengl(render_engine_type)) {
@@ -862,6 +1073,7 @@ static void wm_draw_window_onscreen(bContext *C, wmWindow *win, int view)
/* always draw, not only when screen tagged */
if (win->gesture.first) {
wm_gesture_draw(win);
+ wmWindowViewport(win);
}
/* Needs pixel coords in screen. */
@@ -870,6 +1082,17 @@ static void wm_draw_window_onscreen(bContext *C, wmWindow *win, int view)
wmWindowViewport(win);
}
+ if (wm_software_cursor_needed()) {
+ struct GrabState grab_state;
+ if (wm_software_cursor_needed_for_window(win, &grab_state)) {
+ wm_software_cursor_draw(win, &grab_state);
+ wm_software_cursor_motion_update(win);
+ }
+ else {
+ wm_software_cursor_motion_clear();
+ }
+ }
+
GPU_debug_group_end();
}
@@ -1020,6 +1243,22 @@ static bool wm_draw_update_test_window(Main *bmain, bContext *C, wmWindow *win)
return true;
}
+ if (wm_software_cursor_needed()) {
+ struct GrabState grab_state;
+ if (wm_software_cursor_needed_for_window(win, &grab_state)) {
+ if (wm_software_cursor_motion_test(win)) {
+ return true;
+ }
+ }
+ else {
+ /* Detect the edge case when the previous draw used the software cursor but this one doesn't,
+ * it's important to redraw otherwise the software cursor will remain displayed. */
+ if (g_software_cursor.winid != -1) {
+ return true;
+ }
+ }
+ }
+
#ifndef WITH_XR_OPENXR
UNUSED_VARS(wm);
#endif
diff --git a/source/blender/windowmanager/intern/wm_event_query.c b/source/blender/windowmanager/intern/wm_event_query.c
index 503dae53122..b732bc91569 100644
--- a/source/blender/windowmanager/intern/wm_event_query.c
+++ b/source/blender/windowmanager/intern/wm_event_query.c
@@ -199,6 +199,13 @@ bool WM_event_type_mask_test(const int event_type, const enum eEventType_Mask ma
}
}
+ /* NDOF */
+ if (mask & EVT_TYPE_MASK_NDOF) {
+ if (ISNDOF(event_type)) {
+ return true;
+ }
+ }
+
/* Action Zone. */
if (mask & EVT_TYPE_MASK_ACTIONZONE) {
if (IS_EVENT_ACTIONZONE(event_type)) {
diff --git a/source/blender/windowmanager/intern/wm_event_system.c b/source/blender/windowmanager/intern/wm_event_system.cc
index 1c3f7ed3e7a..d3ae4177e4d 100644
--- a/source/blender/windowmanager/intern/wm_event_system.c
+++ b/source/blender/windowmanager/intern/wm_event_system.cc
@@ -9,9 +9,9 @@
* Also some operator reports utility functions.
*/
-#include <math.h>
-#include <stdlib.h>
-#include <string.h>
+#include <cmath>
+#include <cstdlib>
+#include <cstring>
#include "DNA_listBase.h"
#include "DNA_scene_types.h"
@@ -101,6 +101,12 @@ static int wm_operator_call_internal(bContext *C,
static bool wm_operator_check_locked_interface(bContext *C, wmOperatorType *ot);
static wmEvent *wm_event_add_mousemove_to_head(wmWindow *win);
+static void wm_operator_free_for_fileselect(wmOperator *file_operator);
+
+static void wm_event_state_update_and_click_set_ex(wmEvent *event,
+ wmEvent *event_state,
+ const bool is_keyboard,
+ const bool check_double_click);
/* -------------------------------------------------------------------- */
/** \name Event Management
@@ -110,11 +116,11 @@ wmEvent *wm_event_add_ex(wmWindow *win,
const wmEvent *event_to_add,
const wmEvent *event_to_add_after)
{
- wmEvent *event = MEM_mallocN(sizeof(wmEvent), "wmEvent");
+ wmEvent *event = MEM_new<wmEvent>(__func__);
*event = *event_to_add;
- if (event_to_add_after == NULL) {
+ if (event_to_add_after == nullptr) {
BLI_addtail(&win->event_queue, event);
}
else {
@@ -127,14 +133,14 @@ wmEvent *wm_event_add_ex(wmWindow *win,
wmEvent *wm_event_add(wmWindow *win, const wmEvent *event_to_add)
{
- return wm_event_add_ex(win, event_to_add, NULL);
+ return wm_event_add_ex(win, event_to_add, nullptr);
}
wmEvent *WM_event_add_simulate(wmWindow *win, const wmEvent *event_to_add)
{
if ((G.f & G_FLAG_EVENT_SIMULATE) == 0) {
BLI_assert_unreachable();
- return NULL;
+ return nullptr;
}
wmEvent *event = wm_event_add(win, event_to_add);
@@ -147,17 +153,7 @@ wmEvent *WM_event_add_simulate(wmWindow *win, const wmEvent *event_to_add)
copy_v2_v2_int(event->prev_xy, win->eventstate->xy);
}
else if (ISKEYBOARD_OR_BUTTON(event->type)) {
- win->eventstate->prev_val = event->prev_val = win->eventstate->val;
- win->eventstate->prev_type = event->prev_type = win->eventstate->type;
-
- win->eventstate->val = event->val;
- win->eventstate->type = event->type;
-
- if (event->val == KM_PRESS) {
- if ((event->flag & WM_EVENT_IS_REPEAT) == 0) {
- copy_v2_v2_int(win->eventstate->prev_press_xy, event->xy);
- }
- }
+ wm_event_state_update_and_click_set_ex(event, win->eventstate, ISKEYBOARD(event->type), false);
}
return event;
}
@@ -170,7 +166,7 @@ static void wm_event_custom_free(wmEvent *event)
/* NOTE: pointer to #ListBase struct elsewhere. */
if (event->custom == EVT_DATA_DRAGDROP) {
- ListBase *lb = event->customdata;
+ ListBase *lb = static_cast<ListBase *>(event->customdata);
WM_drag_free_list(lb);
}
else {
@@ -181,7 +177,7 @@ static void wm_event_custom_free(wmEvent *event)
static void wm_event_custom_clear(wmEvent *event)
{
event->custom = 0;
- event->customdata = NULL;
+ event->customdata = nullptr;
event->customdata_free = false;
}
@@ -213,7 +209,7 @@ static void wm_event_free_last_handled(wmWindow *win, wmEvent *event)
* As this function should be interchangeable with #wm_event_free. */
#ifndef NDEBUG
{
- wmEvent *event_copy = MEM_dupallocN(event);
+ wmEvent *event_copy = static_cast<wmEvent *>(MEM_dupallocN(event));
MEM_freeN(event);
event = event_copy;
}
@@ -231,8 +227,8 @@ static void wm_event_free_last_handled(wmWindow *win, wmEvent *event)
static void wm_event_free_last(wmWindow *win)
{
- wmEvent *event = BLI_poptail(&win->event_queue);
- if (event != NULL) {
+ wmEvent *event = static_cast<wmEvent *>(BLI_poptail(&win->event_queue));
+ if (event != nullptr) {
wm_event_free(event);
}
}
@@ -240,7 +236,7 @@ static void wm_event_free_last(wmWindow *win)
void wm_event_free_all(wmWindow *win)
{
wmEvent *event;
- while ((event = BLI_pophead(&win->event_queue))) {
+ while ((event = static_cast<wmEvent *>(BLI_pophead(&win->event_queue)))) {
wm_event_free(event);
}
}
@@ -274,7 +270,7 @@ void WM_event_add_notifier_ex(wmWindowManager *wm, const wmWindow *win, uint typ
return;
}
- wmNotifier *note = MEM_callocN(sizeof(wmNotifier), "notifier");
+ wmNotifier *note = MEM_cnew<wmNotifier>(__func__);
BLI_addtail(&wm->notifier_queue, note);
@@ -297,13 +293,13 @@ void WM_event_add_notifier(const bContext *C, uint type, void *reference)
void WM_main_add_notifier(unsigned int type, void *reference)
{
Main *bmain = G_MAIN;
- wmWindowManager *wm = bmain->wm.first;
+ wmWindowManager *wm = static_cast<wmWindowManager *>(bmain->wm.first);
if (!wm || wm_test_duplicate_notifier(wm, type, reference)) {
return;
}
- wmNotifier *note = MEM_callocN(sizeof(wmNotifier), "notifier");
+ wmNotifier *note = MEM_cnew<wmNotifier>(__func__);
BLI_addtail(&wm->notifier_queue, note);
@@ -318,7 +314,7 @@ void WM_main_add_notifier(unsigned int type, void *reference)
void WM_main_remove_notifier_reference(const void *reference)
{
Main *bmain = G_MAIN;
- wmWindowManager *wm = bmain->wm.first;
+ wmWindowManager *wm = static_cast<wmWindowManager *>(bmain->wm.first);
if (wm) {
LISTBASE_FOREACH_MUTABLE (wmNotifier *, note, &wm->notifier_queue) {
@@ -345,8 +341,8 @@ static void wm_main_remap_assetlist(ID *old_id, ID *new_id, void *UNUSED(user_da
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) {
+ wmMsgBus *mbus = static_cast<wmMsgBus *>(user_data);
+ if (new_id != nullptr) {
WM_msg_id_update(mbus, old_id, new_id);
}
else {
@@ -354,7 +350,7 @@ static void wm_main_remap_msgbus_notify(ID *old_id, ID *new_id, void *user_data)
}
}
-void WM_main_remap_editor_id_reference(const struct IDRemapper *mappings)
+void WM_main_remap_editor_id_reference(const IDRemapper *mappings)
{
Main *bmain = G_MAIN;
@@ -366,9 +362,9 @@ void WM_main_remap_editor_id_reference(const struct IDRemapper *mappings)
}
}
- BKE_id_remapper_iter(mappings, wm_main_remap_assetlist, NULL);
+ BKE_id_remapper_iter(mappings, wm_main_remap_assetlist, nullptr);
- wmWindowManager *wm = bmain->wm.first;
+ wmWindowManager *wm = static_cast<wmWindowManager *>(bmain->wm.first);
if (wm && wm->message_bus) {
BKE_id_remapper_iter(mappings, wm_main_remap_msgbus_notify, wm->message_bus);
}
@@ -376,7 +372,7 @@ void WM_main_remap_editor_id_reference(const struct IDRemapper *mappings)
static void wm_notifier_clear(wmNotifier *note)
{
- /* NULL the entire notifier, only leaving (`next`, `prev`) members intact. */
+ /* nullptr the entire notifier, only leaving (`next`, `prev`) members intact. */
memset(((char *)note) + sizeof(Link), 0, sizeof(*note) - sizeof(Link));
}
@@ -439,22 +435,22 @@ void wm_event_do_refresh_wm_and_depsgraph(bContext *C)
wm_event_do_depsgraph(C, false);
- CTX_wm_window_set(C, NULL);
+ CTX_wm_window_set(C, nullptr);
}
static void wm_event_execute_timers(bContext *C)
{
wmWindowManager *wm = CTX_wm_manager(C);
- if (UNLIKELY(wm == NULL)) {
+ if (UNLIKELY(wm == nullptr)) {
return;
}
/* Set the first window as context, so that there is some minimal context. This avoids crashes
* when calling code that assumes that there is always a window in the context (which many
* operators do). */
- CTX_wm_window_set(C, wm->windows.first);
+ CTX_wm_window_set(C, static_cast<wmWindow *>(wm->windows.first));
BLI_timer_execute();
- CTX_wm_window_set(C, NULL);
+ CTX_wm_window_set(C, nullptr);
}
void wm_event_do_notifiers(bContext *C)
@@ -463,7 +459,7 @@ void wm_event_do_notifiers(bContext *C)
wm_event_execute_timers(C);
wmWindowManager *wm = CTX_wm_manager(C);
- if (wm == NULL) {
+ if (wm == nullptr) {
return;
}
@@ -493,7 +489,7 @@ void wm_event_do_notifiers(bContext *C)
if (note->window == win) {
if (note->category == NC_SCREEN) {
if (note->data == ND_WORKSPACE_SET) {
- WorkSpace *ref_ws = note->reference;
+ WorkSpace *ref_ws = static_cast<WorkSpace *>(note->reference);
UI_popup_handlers_remove_all(C, &win->modalhandlers);
@@ -503,7 +499,7 @@ void wm_event_do_notifiers(bContext *C)
}
}
else if (note->data == ND_WORKSPACE_DELETE) {
- WorkSpace *workspace = note->reference;
+ WorkSpace *workspace = static_cast<WorkSpace *>(note->reference);
ED_workspace_delete(
workspace, CTX_data_main(C), C, wm); /* XXX: hum, think this over! */
@@ -512,7 +508,8 @@ void wm_event_do_notifiers(bContext *C)
}
}
else if (note->data == ND_LAYOUTBROWSE) {
- bScreen *ref_screen = BKE_workspace_layout_screen_get(note->reference);
+ bScreen *ref_screen = BKE_workspace_layout_screen_get(
+ static_cast<WorkSpaceLayout *>(note->reference));
/* Free popup handlers only T35434. */
UI_popup_handlers_remove_all(C, &win->modalhandlers);
@@ -524,7 +521,7 @@ void wm_event_do_notifiers(bContext *C)
}
else if (note->data == ND_LAYOUTDELETE) {
WorkSpace *workspace = WM_window_get_active_workspace(win);
- WorkSpaceLayout *layout = note->reference;
+ WorkSpaceLayout *layout = static_cast<WorkSpaceLayout *>(note->reference);
ED_workspace_layout_delete(workspace, layout, C); /* XXX: hum, think this over! */
if (G.debug & G_DEBUG_EVENTS) {
@@ -534,7 +531,8 @@ void wm_event_do_notifiers(bContext *C)
}
}
- if (note->window == win || (note->window == NULL && (ELEM(note->reference, NULL, scene)))) {
+ if (note->window == win ||
+ (note->window == nullptr && (ELEM(note->reference, nullptr, scene)))) {
if (note->category == NC_SCENE) {
if (note->data == ND_FRAME) {
do_anim = true;
@@ -550,7 +548,7 @@ void wm_event_do_notifiers(bContext *C)
/* Only do once since adding notifiers is slow when there are many. */
ViewLayer *view_layer = CTX_data_view_layer(C);
ED_info_stats_clear(wm, view_layer);
- WM_event_add_notifier(C, NC_SPACE | ND_SPACE_INFO, NULL);
+ WM_event_add_notifier(C, NC_SPACE | ND_SPACE_INFO, nullptr);
}
if (do_anim) {
@@ -568,7 +566,7 @@ void wm_event_do_notifiers(bContext *C)
/* The notifiers are sent without context, to keep it clean. */
wmNotifier *note;
- while ((note = BLI_pophead(&wm->notifier_queue))) {
+ while ((note = static_cast<wmNotifier *>(BLI_pophead(&wm->notifier_queue)))) {
LISTBASE_FOREACH (wmWindow *, win, &wm->windows) {
Scene *scene = WM_window_get_active_scene(win);
bScreen *screen = WM_window_get_active_screen(win);
@@ -595,13 +593,13 @@ void wm_event_do_notifiers(bContext *C)
ED_screen_do_listen(C, note);
LISTBASE_FOREACH (ARegion *, region, &screen->regionbase) {
- wmRegionListenerParams region_params = {
- .window = win,
- .area = NULL,
- .region = region,
- .scene = scene,
- .notifier = note,
- };
+ wmRegionListenerParams region_params{};
+ region_params.window = win;
+ region_params.area = nullptr;
+ region_params.region = region;
+ region_params.scene = scene;
+ region_params.notifier = note;
+
ED_region_do_listen(&region_params);
}
@@ -613,21 +611,19 @@ void wm_event_do_notifiers(bContext *C)
continue;
}
}
- wmSpaceTypeListenerParams area_params = {
- .window = win,
- .area = area,
- .notifier = note,
- .scene = scene,
- };
+ wmSpaceTypeListenerParams area_params{};
+ area_params.window = win;
+ area_params.area = area;
+ area_params.notifier = note;
+ area_params.scene = scene;
ED_area_do_listen(&area_params);
LISTBASE_FOREACH (ARegion *, region, &area->regionbase) {
- wmRegionListenerParams region_params = {
- .window = win,
- .area = area,
- .region = region,
- .scene = scene,
- .notifier = note,
- };
+ wmRegionListenerParams region_params{};
+ region_params.window = win;
+ region_params.area = area;
+ region_params.region = region;
+ region_params.scene = scene;
+ region_params.notifier = note;
ED_region_do_listen(&region_params);
}
}
@@ -644,7 +640,7 @@ void wm_event_do_notifiers(bContext *C)
CTX_wm_window_set(C, win);
WM_msgbus_handle(wm->message_bus, C);
}
- CTX_wm_window_set(C, NULL);
+ CTX_wm_window_set(C, nullptr);
}
wm_event_do_refresh_wm_and_depsgraph(C);
@@ -654,7 +650,7 @@ void wm_event_do_notifiers(bContext *C)
wmWindow *win = wm->winactive;
CTX_wm_window_set(C, win);
WM_window_cursor_keymap_status_refresh(C, win);
- CTX_wm_window_set(C, NULL);
+ CTX_wm_window_set(C, nullptr);
}
/* Auto-run warning. */
@@ -672,7 +668,7 @@ static int wm_event_always_pass(const wmEvent *event)
* don't cause non-passing handler return values, and thus actually pass.
*
* Can't be executed if the handler just loaded a file (typically identified by `CTX_wm_window(C)`
- * returning `NULL`), because the event will have been freed then.
+ * returning `nullptr`), because the event will have been freed then.
*/
BLI_INLINE void wm_event_handler_return_value_check(const wmEvent *event, const int action)
{
@@ -743,9 +739,9 @@ static int wm_handler_ui_call(bContext *C,
}
else {
/* This special cases is for areas and regions that get removed. */
- CTX_wm_area_set(C, NULL);
- CTX_wm_region_set(C, NULL);
- CTX_wm_menu_set(C, NULL);
+ CTX_wm_area_set(C, nullptr);
+ CTX_wm_region_set(C, nullptr);
+ CTX_wm_menu_set(C, nullptr);
}
if (retval == WM_UI_HANDLER_BREAK) {
@@ -772,12 +768,12 @@ void wm_event_handler_ui_cancel_ex(bContext *C,
LISTBASE_FOREACH_MUTABLE (wmEventHandler *, handler_base, &region->handlers) {
if (handler_base->type == WM_HANDLER_TYPE_UI) {
wmEventHandler_UI *handler = (wmEventHandler_UI *)handler_base;
- BLI_assert(handler->handle_fn != NULL);
+ BLI_assert(handler->handle_fn != nullptr);
wmEvent event;
wm_event_init_from_window(win, &event);
event.type = EVT_BUT_CANCEL;
event.val = reactivate_button ? 0 : 1;
- event.flag = 0;
+ event.flag = (eWM_EventFlag)0;
handler->handle_fn(C, &event, handler->user_data);
}
}
@@ -800,24 +796,24 @@ static void wm_event_handler_ui_cancel(bContext *C)
void WM_report_banner_show(void)
{
- wmWindowManager *wm = G_MAIN->wm.first;
+ wmWindowManager *wm = static_cast<wmWindowManager *>(G_MAIN->wm.first);
ReportList *wm_reports = &wm->reports;
/* After adding reports to the global list, reset the report timer. */
- WM_event_remove_timer(wm, NULL, wm_reports->reporttimer);
+ WM_event_remove_timer(wm, nullptr, wm_reports->reporttimer);
/* Records time since last report was added. */
wm_reports->reporttimer = WM_event_add_timer(wm, wm->winactive, TIMERREPORT, 0.05);
- ReportTimerInfo *rti = MEM_callocN(sizeof(ReportTimerInfo), "ReportTimerInfo");
+ ReportTimerInfo *rti = MEM_cnew<ReportTimerInfo>(__func__);
wm_reports->reporttimer->customdata = rti;
}
void WM_report_banners_cancel(Main *bmain)
{
- wmWindowManager *wm = bmain->wm.first;
+ wmWindowManager *wm = static_cast<wmWindowManager *>(bmain->wm.first);
BKE_reports_clear(&wm->reports);
- WM_event_remove_timer(wm, NULL, wm->reports.reporttimer);
+ WM_event_remove_timer(wm, nullptr, wm->reports.reporttimer);
}
#ifdef WITH_INPUT_NDOF
@@ -831,7 +827,7 @@ static void wm_add_reports(ReportList *reports)
{
/* If the caller owns them, handle this. */
if (reports->list.first && (reports->flag & RPT_OP_HOLD) == 0) {
- wmWindowManager *wm = G_MAIN->wm.first;
+ wmWindowManager *wm = static_cast<wmWindowManager *>(G_MAIN->wm.first);
/* Add reports to the global list, otherwise they are not seen. */
BLI_movelisttolist(&wm->reports.list, &reports->list);
@@ -877,7 +873,7 @@ bool WM_operator_poll(bContext *C, wmOperatorType *ot)
{
LISTBASE_FOREACH (wmOperatorTypeMacro *, macro, &ot->macro) {
- wmOperatorType *ot_macro = WM_operatortype_find(macro->idname, 0);
+ wmOperatorType *ot_macro = WM_operatortype_find(macro->idname, false);
if (!WM_operator_poll(C, ot_macro)) {
return false;
@@ -898,15 +894,16 @@ bool WM_operator_poll(bContext *C, wmOperatorType *ot)
bool WM_operator_poll_context(bContext *C, wmOperatorType *ot, short context)
{
/* Sets up the new context and calls #wm_operator_invoke() with poll_only. */
- return wm_operator_call_internal(C, ot, NULL, NULL, context, true, NULL);
+ return wm_operator_call_internal(
+ C, ot, nullptr, nullptr, static_cast<wmOperatorCallContext>(context), true, nullptr);
}
bool WM_operator_check_ui_empty(wmOperatorType *ot)
{
- if (ot->macro.first != NULL) {
+ if (ot->macro.first != nullptr) {
/* For macros, check all have exec() we can call. */
LISTBASE_FOREACH (wmOperatorTypeMacro *, macro, &ot->macro) {
- wmOperatorType *otm = WM_operatortype_find(macro->idname, 0);
+ wmOperatorType *otm = WM_operatortype_find(macro->idname, false);
if (otm && !WM_operator_check_ui_empty(otm)) {
return false;
}
@@ -955,8 +952,8 @@ static void wm_operator_reports(bContext *C, wmOperator *op, int retval, bool ca
ScrArea *area_prev = CTX_wm_area(C);
ARegion *region_prev = CTX_wm_region(C);
- if (win_prev == NULL) {
- CTX_wm_window_set(C, CTX_wm_manager(C)->windows.first);
+ if (win_prev == nullptr) {
+ CTX_wm_window_set(C, static_cast<wmWindow *>(CTX_wm_manager(C)->windows.first));
}
UI_popup_menu_reports(C, op->reports);
@@ -986,7 +983,7 @@ static void wm_operator_reports(bContext *C, wmOperator *op, int retval, bool ca
/* Refresh Info Editor with reports immediately, even if op returned #OPERATOR_CANCELLED. */
if ((retval & OPERATOR_CANCELLED) && !BLI_listbase_is_empty(&op->reports->list)) {
- WM_event_add_notifier(C, NC_SPACE | ND_SPACE_INFO_REPORT, NULL);
+ WM_event_add_notifier(C, NC_SPACE | ND_SPACE_INFO_REPORT, nullptr);
}
/* If the caller owns them, handle this. */
wm_add_reports(op->reports);
@@ -1012,7 +1009,7 @@ static void wm_operator_finished(bContext *C, wmOperator *op, const bool repeat,
CLEAR,
} hud_status = NOP;
- op->customdata = NULL;
+ op->customdata = nullptr;
if (store) {
WM_operator_last_properties_store(op);
@@ -1068,7 +1065,7 @@ static void wm_operator_finished(bContext *C, wmOperator *op, const bool repeat,
}
}
else if (hud_status == CLEAR) {
- ED_area_type_hud_clear(wm, NULL);
+ ED_area_type_hud_clear(wm, nullptr);
}
else {
BLI_assert_unreachable();
@@ -1086,7 +1083,7 @@ static int wm_operator_exec(bContext *C, wmOperator *op, const bool repeat, cons
CTX_wm_operator_poll_msg_clear(C);
- if (op == NULL || op->type == NULL) {
+ if (op == nullptr || op->type == nullptr) {
return retval;
}
@@ -1134,7 +1131,7 @@ static int wm_operator_exec_notest(bContext *C, wmOperator *op)
{
int retval = OPERATOR_CANCELLED;
- if (op == NULL || op->type == NULL || op->type->exec == NULL) {
+ if (op == nullptr || op->type == nullptr || op->type->exec == nullptr) {
return retval;
}
@@ -1177,14 +1174,14 @@ int WM_operator_repeat_last(bContext *C, wmOperator *op)
}
bool WM_operator_repeat_check(const bContext *UNUSED(C), wmOperator *op)
{
- if (op->type->exec != NULL) {
+ if (op->type->exec != nullptr) {
return true;
}
if (op->opm) {
/* For macros, check all have exec() we can call. */
LISTBASE_FOREACH (wmOperatorTypeMacro *, macro, &op->opm->type->macro) {
- wmOperatorType *otm = WM_operatortype_find(macro->idname, 0);
- if (otm && otm->exec == NULL) {
+ wmOperatorType *otm = WM_operatortype_find(macro->idname, false);
+ if (otm && otm->exec == nullptr) {
return false;
}
}
@@ -1198,9 +1195,9 @@ bool WM_operator_is_repeat(const bContext *C, const wmOperator *op)
{
/* May be in the operators list or not. */
wmOperator *op_prev;
- if (op->prev == NULL && op->next == NULL) {
+ if (op->prev == nullptr && op->next == nullptr) {
wmWindowManager *wm = CTX_wm_manager(C);
- op_prev = wm->operators.last;
+ op_prev = static_cast<wmOperator *>(wm->operators.last);
}
else {
op_prev = op->prev;
@@ -1214,16 +1211,16 @@ static wmOperator *wm_operator_create(wmWindowManager *wm,
ReportList *reports)
{
/* Operator-type names are static still. pass to allocation name for debugging. */
- wmOperator *op = MEM_callocN(sizeof(wmOperator), ot->idname);
+ wmOperator *op = MEM_cnew<wmOperator>(ot->idname);
/* Adding new operator could be function, only happens here now. */
op->type = ot;
BLI_strncpy(op->idname, ot->idname, OP_MAX_TYPENAME);
/* Initialize properties, either copy or create. */
- op->ptr = MEM_callocN(sizeof(PointerRNA), "wmOperatorPtrRNA");
+ op->ptr = MEM_cnew<PointerRNA>("wmOperatorPtrRNA");
if (properties && properties->data) {
- op->properties = IDP_CopyProperty(properties->data);
+ op->properties = IDP_CopyProperty(static_cast<const IDProperty *>(properties->data));
}
else {
IDPropertyTemplate val = {0};
@@ -1236,36 +1233,36 @@ static wmOperator *wm_operator_create(wmWindowManager *wm,
op->reports = reports; /* Must be initialized already. */
}
else {
- op->reports = MEM_mallocN(sizeof(ReportList), "wmOperatorReportList");
+ op->reports = MEM_cnew<ReportList>("wmOperatorReportList");
BKE_reports_init(op->reports, RPT_STORE | RPT_FREE);
}
/* Recursive filling of operator macro list. */
if (ot->macro.first) {
- static wmOperator *motherop = NULL;
+ static wmOperator *motherop = nullptr;
int root = 0;
/* Ensure all ops are in execution order in 1 list. */
- if (motherop == NULL) {
+ if (motherop == nullptr) {
motherop = op;
root = 1;
}
/* If properties exist, it will contain everything needed. */
if (properties) {
- wmOperatorTypeMacro *otmacro = ot->macro.first;
+ wmOperatorTypeMacro *otmacro = static_cast<wmOperatorTypeMacro *>(ot->macro.first);
RNA_STRUCT_BEGIN (properties, prop) {
- if (otmacro == NULL) {
+ if (otmacro == nullptr) {
break;
}
/* Skip invalid properties. */
if (STREQ(RNA_property_identifier(prop), otmacro->idname)) {
- wmOperatorType *otm = WM_operatortype_find(otmacro->idname, 0);
+ wmOperatorType *otm = WM_operatortype_find(otmacro->idname, false);
PointerRNA someptr = RNA_property_pointer_get(properties, prop);
- wmOperator *opm = wm_operator_create(wm, otm, &someptr, NULL);
+ wmOperator *opm = wm_operator_create(wm, otm, &someptr, nullptr);
IDP_ReplaceGroupInGroup(opm->properties, otmacro->properties);
@@ -1279,8 +1276,8 @@ static wmOperator *wm_operator_create(wmWindowManager *wm,
}
else {
LISTBASE_FOREACH (wmOperatorTypeMacro *, macro, &ot->macro) {
- wmOperatorType *otm = WM_operatortype_find(macro->idname, 0);
- wmOperator *opm = wm_operator_create(wm, otm, macro->ptr, NULL);
+ wmOperatorType *otm = WM_operatortype_find(macro->idname, false);
+ wmOperator *opm = wm_operator_create(wm, otm, macro->ptr, nullptr);
BLI_addtail(&motherop->macro, opm);
opm->opm = motherop; /* Pointer to mom, for modal(). */
@@ -1288,11 +1285,11 @@ static wmOperator *wm_operator_create(wmWindowManager *wm,
}
if (root) {
- motherop = NULL;
+ motherop = nullptr;
}
}
- WM_operator_properties_sanitize(op->ptr, 0);
+ WM_operator_properties_sanitize(op->ptr, false);
return op;
}
@@ -1306,12 +1303,12 @@ static void wm_region_tag_draw_on_gizmo_delay_refresh_for_tweak(wmWindow *win)
bScreen *screen = WM_window_get_active_screen(win);
/* Unlikely but not impossible as this runs after events have been handled. */
- if (UNLIKELY(screen == NULL)) {
+ if (UNLIKELY(screen == nullptr)) {
return;
}
ED_screen_areas_iter (win, screen, area) {
LISTBASE_FOREACH (ARegion *, region, &area->regionbase) {
- if (region->gizmo_map != NULL) {
+ if (region->gizmo_map != nullptr) {
if (WM_gizmomap_tag_delay_refresh_for_tweak_check(region->gizmo_map)) {
ED_region_tag_redraw(region);
}
@@ -1336,7 +1333,7 @@ static void wm_region_mouse_co(bContext *C, wmEvent *event)
}
/**
- * Also used for exec when 'event' is NULL.
+ * Also used for exec when 'event' is nullptr.
*/
static int wm_operator_invoke(bContext *C,
wmOperatorType *ot,
@@ -1357,12 +1354,12 @@ static int wm_operator_invoke(bContext *C,
if (WM_operator_poll(C, ot)) {
wmWindowManager *wm = CTX_wm_manager(C);
- /* If `reports == NULL`, they'll be initialized. */
+ /* If `reports == nullptr`, they'll be initialized. */
wmOperator *op = wm_operator_create(wm, ot, properties, reports);
const bool is_nested_call = (wm->op_undo_depth != 0);
- if (event != NULL) {
+ if (event != nullptr) {
op->flag |= OP_IS_INVOKE;
}
@@ -1371,7 +1368,7 @@ static int wm_operator_invoke(bContext *C,
WM_operator_last_properties_init(op);
}
- if ((event == NULL) || (event->type != MOUSEMOVE)) {
+ if ((event == nullptr) || (event->type != MOUSEMOVE)) {
CLOG_INFO(WM_LOG_HANDLERS,
2,
"handle evt %d win %p op %s",
@@ -1382,7 +1379,7 @@ static int wm_operator_invoke(bContext *C,
if (op->type->invoke && event) {
/* Temporarily write into `mval` (not technically `const` correct) but this is restored. */
- int mval_prev[2] = {UNPACK2(event->mval)};
+ const int mval_prev[2] = {UNPACK2(event->mval)};
wm_region_mouse_co(C, (wmEvent *)event);
if (op->type->flag & OPTYPE_UNDO) {
@@ -1419,7 +1416,7 @@ static int wm_operator_invoke(bContext *C,
* them currently Python only uses this. */
if (!(retval & OPERATOR_HANDLED) && (retval & (OPERATOR_FINISHED | OPERATOR_CANCELLED))) {
/* Only show the report if the report list was not given in the function. */
- wm_operator_reports(C, op, retval, (reports != NULL));
+ wm_operator_reports(C, op, retval, (reports != nullptr));
}
if (retval & OPERATOR_HANDLED) {
@@ -1455,7 +1452,7 @@ static int wm_operator_invoke(bContext *C,
}
if (wrap) {
- const rcti *winrect = NULL;
+ const rcti *winrect = nullptr;
ARegion *region = CTX_wm_region(C);
ScrArea *area = CTX_wm_area(C);
@@ -1518,7 +1515,7 @@ static int wm_operator_call_internal(bContext *C,
if (ot) {
wmWindow *window = CTX_wm_window(C);
- if (event == NULL) {
+ if (event == nullptr) {
switch (context) {
case WM_OP_INVOKE_DEFAULT:
case WM_OP_INVOKE_REGION_WIN:
@@ -1527,7 +1524,7 @@ static int wm_operator_call_internal(bContext *C,
case WM_OP_INVOKE_AREA:
case WM_OP_INVOKE_SCREEN:
/* Window is needed for invoke and cancel operators. */
- if (window == NULL) {
+ if (window == nullptr) {
if (poll_only) {
CTX_wm_operator_poll_msg_set(C, "Missing 'window' in context");
}
@@ -1538,7 +1535,7 @@ static int wm_operator_call_internal(bContext *C,
}
break;
default:
- event = NULL;
+ event = nullptr;
break;
}
}
@@ -1550,7 +1547,7 @@ static int wm_operator_call_internal(bContext *C,
case WM_OP_EXEC_REGION_CHANNELS:
case WM_OP_EXEC_AREA:
case WM_OP_EXEC_SCREEN:
- event = NULL;
+ event = nullptr;
default:
break;
}
@@ -1608,7 +1605,7 @@ static int wm_operator_call_internal(bContext *C,
/* Remove region from context. */
ARegion *region = CTX_wm_region(C);
- CTX_wm_region_set(C, NULL);
+ CTX_wm_region_set(C, nullptr);
retval = wm_operator_invoke(C, ot, event, properties, reports, poll_only, true);
CTX_wm_region_set(C, region);
@@ -1620,8 +1617,8 @@ static int wm_operator_call_internal(bContext *C,
ARegion *region = CTX_wm_region(C);
ScrArea *area = CTX_wm_area(C);
- CTX_wm_region_set(C, NULL);
- CTX_wm_area_set(C, NULL);
+ CTX_wm_region_set(C, nullptr);
+ CTX_wm_area_set(C, nullptr);
retval = wm_operator_invoke(C, ot, event, properties, reports, poll_only, true);
CTX_wm_area_set(C, area);
CTX_wm_region_set(C, region);
@@ -1644,7 +1641,7 @@ int WM_operator_name_call_ptr(bContext *C,
const wmEvent *event)
{
BLI_assert(ot == WM_operatortype_find(ot->idname, true));
- return wm_operator_call_internal(C, ot, properties, NULL, context, false, event);
+ return wm_operator_call_internal(C, ot, properties, nullptr, context, false, event);
}
int WM_operator_name_call(bContext *C,
const char *opstring,
@@ -1652,7 +1649,7 @@ int WM_operator_name_call(bContext *C,
PointerRNA *properties,
const wmEvent *event)
{
- wmOperatorType *ot = WM_operatortype_find(opstring, 0);
+ wmOperatorType *ot = WM_operatortype_find(opstring, false);
if (ot) {
return WM_operator_name_call_ptr(C, ot, context, properties, event);
}
@@ -1662,7 +1659,7 @@ int WM_operator_name_call(bContext *C,
bool WM_operator_name_poll(bContext *C, const char *opstring)
{
- wmOperatorType *ot = WM_operatortype_find(opstring, 0);
+ wmOperatorType *ot = WM_operatortype_find(opstring, false);
if (!ot) {
return false;
}
@@ -1670,15 +1667,16 @@ bool WM_operator_name_poll(bContext *C, const char *opstring)
return WM_operator_poll(C, ot);
}
-int WM_operator_name_call_with_properties(struct bContext *C,
+int WM_operator_name_call_with_properties(bContext *C,
const char *opstring,
wmOperatorCallContext context,
- struct IDProperty *properties,
+ IDProperty *properties,
const wmEvent *event)
{
PointerRNA props_ptr;
wmOperatorType *ot = WM_operatortype_find(opstring, false);
- RNA_pointer_create(G_MAIN->wm.first, ot->srna, properties, &props_ptr);
+ RNA_pointer_create(
+ &static_cast<wmWindowManager *>(G_MAIN->wm.first)->id, ot->srna, properties, &props_ptr);
return WM_operator_name_call_ptr(C, ot, context, &props_ptr, event);
}
@@ -1688,7 +1686,7 @@ void WM_menu_name_call(bContext *C, const char *menu_name, short context)
PointerRNA ptr;
WM_operator_properties_create_ptr(&ptr, ot);
RNA_string_set(&ptr, "name", menu_name);
- WM_operator_name_call_ptr(C, ot, context, &ptr, NULL);
+ WM_operator_name_call_ptr(C, ot, static_cast<wmOperatorCallContext>(context), &ptr, nullptr);
WM_operator_properties_free(&ptr);
}
@@ -1707,7 +1705,7 @@ int WM_operator_call_py(bContext *C,
wm->op_undo_depth++;
}
- retval = wm_operator_call_internal(C, ot, properties, reports, context, false, NULL);
+ retval = wm_operator_call_internal(C, ot, properties, reports, context, false, nullptr);
if (!is_undo && wm && (wm == CTX_wm_manager(C))) {
wm->op_undo_depth--;
@@ -1726,18 +1724,18 @@ int WM_operator_call_py(bContext *C,
* See: #OPTYPE_DEPENDS_ON_CURSOR doc-string for more information.
* \{ */
-typedef struct uiOperatorWaitForInput {
+struct uiOperatorWaitForInput {
ScrArea *area;
wmOperatorCallParams optype_params;
bContextStore *context;
-} uiOperatorWaitForInput;
+};
static void ui_handler_wait_for_input_remove(bContext *C, void *userdata)
{
- uiOperatorWaitForInput *opwait = userdata;
+ uiOperatorWaitForInput *opwait = static_cast<uiOperatorWaitForInput *>(userdata);
if (opwait->optype_params.opptr) {
if (opwait->optype_params.opptr->data) {
- IDP_FreeProperty(opwait->optype_params.opptr->data);
+ IDP_FreeProperty(static_cast<IDProperty *>(opwait->optype_params.opptr->data));
}
MEM_freeN(opwait->optype_params.opptr);
}
@@ -1745,11 +1743,11 @@ static void ui_handler_wait_for_input_remove(bContext *C, void *userdata)
CTX_store_free(opwait->context);
}
- if (opwait->area != NULL) {
- ED_area_status_text(opwait->area, NULL);
+ if (opwait->area != nullptr) {
+ ED_area_status_text(opwait->area, nullptr);
}
else {
- ED_workspace_status_text(C, NULL);
+ ED_workspace_status_text(C, nullptr);
}
MEM_freeN(opwait);
@@ -1757,7 +1755,7 @@ static void ui_handler_wait_for_input_remove(bContext *C, void *userdata)
static int ui_handler_wait_for_input(bContext *C, const wmEvent *event, void *userdata)
{
- uiOperatorWaitForInput *opwait = userdata;
+ uiOperatorWaitForInput *opwait = static_cast<uiOperatorWaitForInput *>(userdata);
enum { CONTINUE = 0, EXECUTE, CANCEL } state = CONTINUE;
state = CONTINUE;
@@ -1802,7 +1800,7 @@ static int ui_handler_wait_for_input(bContext *C, const wmEvent *event, void *us
opwait->optype_params.opcontext,
opwait->optype_params.opptr,
event);
- CTX_store_set(C, NULL);
+ CTX_store_set(C, nullptr);
}
WM_event_remove_ui_handler(&win->modalhandlers,
@@ -1829,8 +1827,8 @@ void WM_operator_name_call_ptr_with_depends_on_cursor(bContext *C,
int flag = ot->flag;
LISTBASE_FOREACH (wmOperatorTypeMacro *, macro, &ot->macro) {
- wmOperatorType *otm = WM_operatortype_find(macro->idname, 0);
- if (otm != NULL) {
+ wmOperatorType *otm = WM_operatortype_find(macro->idname, false);
+ if (otm != nullptr) {
flag |= otm->flag;
}
}
@@ -1844,7 +1842,7 @@ void WM_operator_name_call_ptr_with_depends_on_cursor(bContext *C,
/* The operator context is applied when the operator is called,
* the check for the area needs to be explicitly limited here.
* Useful so it's possible to screen-shot an area without drawing into it's header. */
- ScrArea *area = WM_OP_CONTEXT_HAS_AREA(opcontext) ? CTX_wm_area(C) : NULL;
+ ScrArea *area = WM_OP_CONTEXT_HAS_AREA(opcontext) ? CTX_wm_area(C) : nullptr;
{
char header_text[UI_MAX_DRAW_STR];
@@ -1852,7 +1850,7 @@ void WM_operator_name_call_ptr_with_depends_on_cursor(bContext *C,
"%s %s",
IFACE_("Input pending "),
(drawstr && drawstr[0]) ? drawstr : CTX_IFACE_(ot->translation_context, ot->name));
- if (area != NULL) {
+ if (area != nullptr) {
ED_area_status_text(area, header_text);
}
else {
@@ -1862,7 +1860,7 @@ void WM_operator_name_call_ptr_with_depends_on_cursor(bContext *C,
WM_cursor_modal_set(win, ot->cursor_pending);
- uiOperatorWaitForInput *opwait = MEM_callocN(sizeof(*opwait), __func__);
+ uiOperatorWaitForInput *opwait = MEM_cnew<uiOperatorWaitForInput>(__func__);
opwait->optype_params.optype = ot;
opwait->optype_params.opcontext = opcontext;
opwait->optype_params.opptr = properties;
@@ -1870,10 +1868,11 @@ void WM_operator_name_call_ptr_with_depends_on_cursor(bContext *C,
opwait->area = area;
if (properties) {
- opwait->optype_params.opptr = MEM_mallocN(sizeof(*opwait->optype_params.opptr), __func__);
+ opwait->optype_params.opptr = MEM_cnew<PointerRNA>(__func__);
*opwait->optype_params.opptr = *properties;
- if (properties->data != NULL) {
- opwait->optype_params.opptr->data = IDP_CopyProperty(properties->data);
+ if (properties->data != nullptr) {
+ opwait->optype_params.opptr->data = IDP_CopyProperty(
+ static_cast<IDProperty *>(properties->data));
}
}
@@ -1904,8 +1903,15 @@ void wm_event_free_handler(wmEventHandler *handler)
MEM_freeN(handler);
}
-/* Only set context when area/region is part of screen. */
-static void wm_handler_op_context(bContext *C, wmEventHandler_Op *handler, const wmEvent *event)
+/**
+ * Check if the handler's area and/or region are actually part of the screen, and return them if
+ * so.
+ */
+static void wm_handler_op_context_get_if_valid(bContext *C,
+ wmEventHandler_Op *handler,
+ const wmEvent *event,
+ ScrArea **r_area,
+ ARegion **r_region)
{
wmWindow *win = handler->context.win ? handler->context.win : CTX_wm_window(C);
/* It's probably fine to always use #WM_window_get_active_screen() to get the screen. But this
@@ -1913,15 +1919,18 @@ static void wm_handler_op_context(bContext *C, wmEventHandler_Op *handler, const
* possible. */
bScreen *screen = handler->context.win ? WM_window_get_active_screen(win) : CTX_wm_screen(C);
- if (screen == NULL || handler->op == NULL) {
+ *r_area = nullptr;
+ *r_region = nullptr;
+
+ if (screen == nullptr || handler->op == nullptr) {
return;
}
- if (handler->context.area == NULL) {
- CTX_wm_area_set(C, NULL);
+ if (handler->context.area == nullptr) {
+ /* Pass */
}
else {
- ScrArea *area = NULL;
+ ScrArea *area = nullptr;
ED_screen_areas_iter (win, screen, area_iter) {
if (area_iter == handler->context.area) {
@@ -1930,10 +1939,10 @@ static void wm_handler_op_context(bContext *C, wmEventHandler_Op *handler, const
}
}
- if (area == NULL) {
+ if (area == nullptr) {
/* When changing screen layouts with running modal handlers (like render display), this
* is not an error to print. */
- if (handler->op == NULL) {
+ if (handler->op == nullptr) {
CLOG_ERROR(WM_LOG_HANDLERS,
"internal error: handler (%s) has invalid area",
handler->op->type->idname);
@@ -1941,8 +1950,8 @@ static void wm_handler_op_context(bContext *C, wmEventHandler_Op *handler, const
}
else {
ARegion *region;
- wmOperator *op = handler->op ? (handler->op->opm ? handler->op->opm : handler->op) : NULL;
- CTX_wm_area_set(C, area);
+ wmOperator *op = handler->op ? (handler->op->opm ? handler->op->opm : handler->op) : nullptr;
+ *r_area = area;
if (op && (op->flag & OP_IS_MODAL_CURSOR_REGION)) {
region = BKE_area_find_region_xy(area, handler->context.region_type, event->xy);
@@ -1951,33 +1960,39 @@ static void wm_handler_op_context(bContext *C, wmEventHandler_Op *handler, const
}
}
else {
- region = NULL;
+ region = nullptr;
}
- if (region == NULL) {
- LISTBASE_FOREACH (ARegion *, region_iter, &area->regionbase) {
- region = region_iter;
- if (region == handler->context.region) {
- break;
- }
+ if ((region == nullptr) && handler->context.region) {
+ if (BLI_findindex(&area->regionbase, handler->context.region) != -1) {
+ region = handler->context.region;
}
}
/* No warning print here, after full-area and back regions are remade. */
if (region) {
- CTX_wm_region_set(C, region);
+ *r_region = region;
}
}
}
}
+static void wm_handler_op_context(bContext *C, wmEventHandler_Op *handler, const wmEvent *event)
+{
+ ScrArea *area = nullptr;
+ ARegion *region = nullptr;
+ wm_handler_op_context_get_if_valid(C, handler, event, &area, &region);
+ CTX_wm_area_set(C, area);
+ CTX_wm_region_set(C, region);
+}
+
void WM_event_remove_handlers(bContext *C, ListBase *handlers)
{
wmWindowManager *wm = CTX_wm_manager(C);
/* C is zero on freeing database, modal handlers then already were freed. */
wmEventHandler *handler_base;
- while ((handler_base = BLI_pophead(handlers))) {
+ while ((handler_base = static_cast<wmEventHandler *>(BLI_pophead(handlers)))) {
BLI_assert(handler_base->type != 0);
if (handler_base->type == WM_HANDLER_TYPE_OP) {
wmEventHandler_Op *handler = (wmEventHandler_Op *)handler_base;
@@ -2016,8 +2031,14 @@ void WM_event_remove_handlers(bContext *C, ListBase *handlers)
CTX_wm_region_set(C, region);
}
- WM_cursor_grab_disable(win, NULL);
- WM_operator_free(handler->op);
+ WM_cursor_grab_disable(win, nullptr);
+
+ if (handler->is_fileselect) {
+ wm_operator_free_for_fileselect(handler->op);
+ }
+ else {
+ WM_operator_free(handler->op);
+ }
}
}
else if (handler_base->type == WM_HANDLER_TYPE_UI) {
@@ -2114,25 +2135,26 @@ static bool wm_eventmatch(const wmEvent *winevent, const wmKeyMapItem *kmi)
/* Account for rare case of when these keys are used as the 'type' not as modifiers. */
if (kmi->shift != KM_ANY) {
const bool shift = (winevent->modifier & KM_SHIFT) != 0;
- if ((shift != kmi->shift) && !ELEM(winevent->type, EVT_LEFTSHIFTKEY, EVT_RIGHTSHIFTKEY)) {
+ if ((shift != (bool)kmi->shift) &&
+ !ELEM(winevent->type, EVT_LEFTSHIFTKEY, EVT_RIGHTSHIFTKEY)) {
return false;
}
}
if (kmi->ctrl != KM_ANY) {
const bool ctrl = (winevent->modifier & KM_CTRL) != 0;
- if (ctrl != kmi->ctrl && !ELEM(winevent->type, EVT_LEFTCTRLKEY, EVT_RIGHTCTRLKEY)) {
+ if (ctrl != (bool)kmi->ctrl && !ELEM(winevent->type, EVT_LEFTCTRLKEY, EVT_RIGHTCTRLKEY)) {
return false;
}
}
if (kmi->alt != KM_ANY) {
const bool alt = (winevent->modifier & KM_ALT) != 0;
- if (alt != kmi->alt && !ELEM(winevent->type, EVT_LEFTALTKEY, EVT_RIGHTALTKEY)) {
+ if (alt != (bool)kmi->alt && !ELEM(winevent->type, EVT_LEFTALTKEY, EVT_RIGHTALTKEY)) {
return false;
}
}
if (kmi->oskey != KM_ANY) {
const bool oskey = (winevent->modifier & KM_OSKEY) != 0;
- if ((oskey != kmi->oskey) && (winevent->type != EVT_OSKEY)) {
+ if ((oskey != (bool)kmi->oskey) && (winevent->type != EVT_OSKEY)) {
return false;
}
}
@@ -2157,12 +2179,12 @@ static wmKeyMapItem *wm_eventmatch_modal_keymap_items(const wmKeyMap *keymap,
/* Should already be handled by #wm_user_modal_keymap_set_items. */
BLI_assert(kmi->propvalue_str[0] == '\0');
if (wm_eventmatch(event, kmi)) {
- if ((keymap->poll_modal_item == NULL) || (keymap->poll_modal_item(op, kmi->propvalue))) {
+ if ((keymap->poll_modal_item == nullptr) || (keymap->poll_modal_item(op, kmi->propvalue))) {
return kmi;
}
}
}
- return NULL;
+ return nullptr;
}
struct wmEvent_ModalMapStore {
@@ -2185,7 +2207,7 @@ struct wmEvent_ModalMapStore {
static void wm_event_modalkeymap_begin(const bContext *C,
wmOperator *op,
wmEvent *event,
- struct wmEvent_ModalMapStore *event_backup)
+ wmEvent_ModalMapStore *event_backup)
{
BLI_assert(event->type != EVT_MODAL_MAP);
@@ -2198,9 +2220,9 @@ static void wm_event_modalkeymap_begin(const bContext *C,
if (op->type->modalkeymap) {
wmKeyMap *keymap = WM_keymap_active(CTX_wm_manager(C), op->type->modalkeymap);
- wmKeyMapItem *kmi = NULL;
+ wmKeyMapItem *kmi = nullptr;
- const wmEvent *event_match = NULL;
+ const wmEvent *event_match = nullptr;
wmEvent event_no_dbl_click;
if ((kmi = wm_eventmatch_modal_keymap_items(keymap, op, event))) {
@@ -2214,7 +2236,7 @@ static void wm_event_modalkeymap_begin(const bContext *C,
}
}
- if (event_match != NULL) {
+ if (event_match != nullptr) {
event_backup->prev_type = event->prev_type;
event_backup->prev_val = event->prev_val;
@@ -2249,8 +2271,7 @@ static void wm_event_modalkeymap_begin(const bContext *C,
* better restore event type for checking of #KM_CLICK for example.
* Modal maps could use different method (ton).
*/
-static void wm_event_modalkeymap_end(wmEvent *event,
- const struct wmEvent_ModalMapStore *event_backup)
+static void wm_event_modalkeymap_end(wmEvent *event, const wmEvent_ModalMapStore *event_backup)
{
if (event->type == EVT_MODAL_MAP) {
event->type = event->prev_type;
@@ -2279,7 +2300,7 @@ static int wm_handler_operator_call(bContext *C,
/* Derived, modal or blocking operator. */
if ((handler_base->type == WM_HANDLER_TYPE_OP) &&
- (((wmEventHandler_Op *)handler_base)->op != NULL)) {
+ (((wmEventHandler_Op *)handler_base)->op != nullptr)) {
wmEventHandler_Op *handler = (wmEventHandler_Op *)handler_base;
wmOperator *op = handler->op;
wmOperatorType *ot = op->type;
@@ -2298,7 +2319,7 @@ static int wm_handler_operator_call(bContext *C,
wm_handler_op_context(C, handler, event);
wm_region_mouse_co(C, event);
- struct wmEvent_ModalMapStore event_backup;
+ wmEvent_ModalMapStore event_backup;
wm_event_modalkeymap_begin(C, op, event, &event_backup);
if (ot->flag & OPTYPE_UNDO) {
@@ -2334,14 +2355,14 @@ static int wm_handler_operator_call(bContext *C,
}
}
- /* Important to run 'wm_operator_finished' before NULL-ing the context members. */
+ /* Important to run 'wm_operator_finished' before nullptr-ing the context members. */
if (retval & OPERATOR_FINISHED) {
wm_operator_finished(C, op, false, true);
- handler->op = NULL;
+ handler->op = nullptr;
}
else if (retval & (OPERATOR_CANCELLED | OPERATOR_FINISHED)) {
WM_operator_free(op);
- handler->op = NULL;
+ handler->op = nullptr;
}
/* Putting back screen context, `reval` can pass through after modal failures! */
@@ -2351,8 +2372,8 @@ static int wm_handler_operator_call(bContext *C,
}
else {
/* This special cases is for areas and regions that get removed. */
- CTX_wm_area_set(C, NULL);
- CTX_wm_region_set(C, NULL);
+ CTX_wm_area_set(C, nullptr);
+ CTX_wm_region_set(C, nullptr);
}
/* Update gizmos during modal handlers. */
@@ -2360,7 +2381,7 @@ static int wm_handler_operator_call(bContext *C,
/* Remove modal handler, operator itself should have been canceled and freed. */
if (retval & (OPERATOR_CANCELLED | OPERATOR_FINISHED)) {
- WM_cursor_grab_disable(CTX_wm_window(C), NULL);
+ WM_cursor_grab_disable(CTX_wm_window(C), nullptr);
BLI_remlink(handlers, handler);
wm_event_free_handler(&handler->head);
@@ -2375,13 +2396,13 @@ static int wm_handler_operator_call(bContext *C,
}
}
else {
- wmOperatorType *ot = WM_operatortype_find(kmi_idname, 0);
+ wmOperatorType *ot = WM_operatortype_find(kmi_idname, false);
if (ot && wm_operator_check_locked_interface(C, ot)) {
bool use_last_properties = true;
- PointerRNA tool_properties = {0};
+ PointerRNA tool_properties = {nullptr};
- bToolRef *keymap_tool = NULL;
+ bToolRef *keymap_tool = nullptr;
if (handler_base->type == WM_HANDLER_TYPE_KEYMAP) {
keymap_tool = ((wmEventHandler_Keymap *)handler_base)->keymap_tool;
}
@@ -2393,7 +2414,7 @@ static int wm_handler_operator_call(bContext *C,
}
}
- const bool is_tool = (keymap_tool != NULL);
+ const bool is_tool = (keymap_tool != nullptr);
const bool use_tool_properties = is_tool;
if (use_tool_properties) {
@@ -2403,7 +2424,7 @@ static int wm_handler_operator_call(bContext *C,
use_last_properties = false;
}
- retval = wm_operator_invoke(C, ot, event, properties, NULL, false, use_last_properties);
+ retval = wm_operator_invoke(C, ot, event, properties, nullptr, false, use_last_properties);
if (use_tool_properties) {
WM_operator_properties_free(&tool_properties);
@@ -2416,10 +2437,10 @@ static int wm_handler_operator_call(bContext *C,
if (tref_rt->gizmo_group[0]) {
const char *idname = tref_rt->gizmo_group;
wmGizmoGroupType *gzgt = WM_gizmogrouptype_find(idname, false);
- if (gzgt != NULL) {
+ if (gzgt != nullptr) {
if ((gzgt->flag & WM_GIZMOGROUPTYPE_TOOL_INIT) != 0) {
ARegion *region = CTX_wm_region(C);
- if (region != NULL) {
+ if (region != nullptr) {
wmGizmoMapType *gzmap_type = WM_gizmomaptype_ensure(&gzgt->gzmap_params);
WM_gizmo_group_type_ensure_ptr_ex(gzgt, gzmap_type);
wmGizmoGroup *gzgroup = WM_gizmomaptype_group_init_runtime_with_region(
@@ -2454,6 +2475,22 @@ static int wm_handler_operator_call(bContext *C,
return WM_HANDLER_BREAK;
}
+static void wm_operator_free_for_fileselect(wmOperator *file_operator)
+{
+ LISTBASE_FOREACH (bScreen *, screen, &G_MAIN->screens) {
+ LISTBASE_FOREACH (ScrArea *, area, &screen->areabase) {
+ if (area->spacetype == SPACE_FILE) {
+ SpaceFile *sfile = static_cast<SpaceFile *>(area->spacedata.first);
+ if (sfile->op == file_operator) {
+ sfile->op = nullptr;
+ }
+ }
+ }
+ }
+
+ WM_operator_free(file_operator);
+}
+
/**
* File-select handlers are only in the window queue,
* so it's safe to switch screens or area types.
@@ -2507,6 +2544,9 @@ static int wm_handler_fileselect_do(bContext *C,
case EVT_FILESELECT_CANCEL:
case EVT_FILESELECT_EXTERNAL_CANCEL: {
wmWindow *ctx_win = CTX_wm_window(C);
+ wmEvent *eventstate = ctx_win->eventstate;
+ /* The root window of the operation as determined in #WM_event_add_fileselect(). */
+ wmWindow *root_win = handler->context.win;
/* Remove link now, for load file case before removing. */
BLI_remlink(handlers, handler);
@@ -2514,16 +2554,16 @@ static int wm_handler_fileselect_do(bContext *C,
if (val == EVT_FILESELECT_EXTERNAL_CANCEL) {
/* The window might have been freed already. */
if (BLI_findindex(&wm->windows, handler->context.win) == -1) {
- handler->context.win = NULL;
+ handler->context.win = nullptr;
}
}
else {
ScrArea *ctx_area = CTX_wm_area(C);
- wmWindow *temp_win = NULL;
+ wmWindow *temp_win = nullptr;
LISTBASE_FOREACH (wmWindow *, win, &wm->windows) {
bScreen *screen = WM_window_get_active_screen(win);
- ScrArea *file_area = screen->areabase.first;
+ ScrArea *file_area = static_cast<ScrArea *>(screen->areabase.first);
if ((file_area->spacetype != SPACE_FILE) || !WM_window_is_temp_screen(win)) {
continue;
@@ -2539,24 +2579,21 @@ static int wm_handler_fileselect_do(bContext *C,
int win_size[2];
bool is_maximized;
ED_fileselect_window_params_get(win, win_size, &is_maximized);
- ED_fileselect_params_to_userdef(file_area->spacedata.first, win_size, is_maximized);
+ ED_fileselect_params_to_userdef(
+ static_cast<SpaceFile *>(file_area->spacedata.first), win_size, is_maximized);
if (BLI_listbase_is_single(&file_area->spacedata)) {
- BLI_assert(ctx_win != win);
+ BLI_assert(root_win != win);
wm_window_close(C, wm, win);
- CTX_wm_window_set(C, ctx_win); /* #wm_window_close() NULLs. */
+ CTX_wm_window_set(C, root_win); /* #wm_window_close() nullptrs. */
/* Some operators expect a drawable context (for #EVT_FILESELECT_EXEC). */
- wm_window_make_drawable(wm, ctx_win);
+ wm_window_make_drawable(wm, root_win);
/* Ensure correct cursor position, otherwise, popups may close immediately after
* opening (#UI_BLOCK_MOVEMOUSE_QUIT). */
- wm_cursor_position_get(
- ctx_win, &ctx_win->eventstate->xy[0], &ctx_win->eventstate->xy[1]);
- wm->winactive = ctx_win; /* Reports use this... */
- if (handler->context.win == win) {
- handler->context.win = NULL;
- }
+ wm_cursor_position_get(root_win, &eventstate->xy[0], &eventstate->xy[1]);
+ wm->winactive = root_win; /* Reports use this... */
}
else if (file_area->full) {
ED_screen_full_prevspace(C, file_area);
@@ -2570,12 +2607,19 @@ static int wm_handler_fileselect_do(bContext *C,
}
if (!temp_win && ctx_area->full) {
- ED_fileselect_params_to_userdef(ctx_area->spacedata.first, NULL, false);
+ ED_fileselect_params_to_userdef(
+ static_cast<SpaceFile *>(ctx_area->spacedata.first), nullptr, false);
ED_screen_full_prevspace(C, ctx_area);
}
}
- wm_handler_op_context(C, handler, ctx_win->eventstate);
+ CTX_wm_window_set(C, root_win);
+ wm_handler_op_context(C, handler, eventstate);
+ /* At this point context is supposed to match the root context determined by
+ * #WM_event_add_fileselect(). */
+ BLI_assert(!CTX_wm_area(C) || (CTX_wm_area(C) == handler->context.area));
+ BLI_assert(!CTX_wm_region(C) || (CTX_wm_region(C) == handler->context.region));
+
ScrArea *handler_area = CTX_wm_area(C);
/* Make sure new context area is ready, the operator callback may operate on it. */
if (handler_area) {
@@ -2617,8 +2661,8 @@ static int wm_handler_fileselect_do(bContext *C,
ScrArea *area_prev = CTX_wm_area(C);
ARegion *region_prev = CTX_wm_region(C);
- if (win_prev == NULL) {
- CTX_wm_window_set(C, CTX_wm_manager(C)->windows.first);
+ if (win_prev == nullptr) {
+ CTX_wm_window_set(C, static_cast<wmWindow *>(CTX_wm_manager(C)->windows.first));
}
BKE_report_print_level_set(handler->op->reports, RPT_WARNING);
@@ -2644,7 +2688,7 @@ static int wm_handler_fileselect_do(bContext *C,
}
if (retval & (OPERATOR_CANCELLED | OPERATOR_FINISHED)) {
- WM_operator_free(handler->op);
+ wm_operator_free_for_fileselect(handler->op);
}
}
else {
@@ -2659,11 +2703,10 @@ static int wm_handler_fileselect_do(bContext *C,
wm->op_undo_depth--;
}
}
-
- WM_operator_free(handler->op);
+ wm_operator_free_for_fileselect(handler->op);
}
- CTX_wm_area_set(C, NULL);
+ CTX_wm_area_set(C, nullptr);
wm_event_free_handler(&handler->head);
@@ -2725,18 +2768,18 @@ static const char *keymap_handler_log_kmi_op_str(bContext *C,
size_t buf_maxlen)
{
/* The key-map item properties can further help distinguish this item from others. */
- char *kmi_props = NULL;
- if (kmi->properties != NULL) {
- wmOperatorType *ot = WM_operatortype_find(kmi->idname, 0);
+ char *kmi_props = nullptr;
+ if (kmi->properties != nullptr) {
+ wmOperatorType *ot = WM_operatortype_find(kmi->idname, false);
if (ot) {
kmi_props = RNA_pointer_as_string_keywords(C, kmi->ptr, false, false, true, 512);
}
else { /* Fallback. */
- kmi_props = IDP_reprN(kmi->properties, NULL);
+ kmi_props = IDP_reprN(kmi->properties, nullptr);
}
}
BLI_snprintf(buf, buf_maxlen, "%s(%s)", kmi->idname, kmi_props ? kmi_props : "");
- if (kmi_props != NULL) {
+ if (kmi_props != nullptr) {
MEM_freeN(kmi_props);
}
return buf;
@@ -2758,8 +2801,8 @@ static int wm_handlers_do_keymap_with_keymap_handler(
{
int action = WM_HANDLER_CONTINUE;
- if (keymap == NULL) {
- /* Only callback is allowed to have NULL key-maps. */
+ if (keymap == nullptr) {
+ /* Only callback is allowed to have nullptr key-maps. */
BLI_assert(handler->dynamic.keymap_fn);
}
else {
@@ -2771,7 +2814,7 @@ static int wm_handlers_do_keymap_with_keymap_handler(
LISTBASE_FOREACH (wmKeyMapItem *, kmi, &keymap->items) {
if (wm_eventmatch(event, kmi)) {
- struct wmEventHandler_KeymapPost keymap_post = handler->post;
+ wmEventHandler_KeymapPost keymap_post = handler->post;
action |= wm_handler_operator_call(
C, handlers, &handler->head, event, kmi->ptr, kmi->idname);
@@ -2788,7 +2831,7 @@ static int wm_handlers_do_keymap_with_keymap_handler(
if (action & WM_HANDLER_BREAK) {
/* Not always_pass here, it denotes removed handler_base. */
- if (keymap_post.post_fn != NULL) {
+ if (keymap_post.post_fn != nullptr) {
keymap_post.post_fn(keymap, kmi, keymap_post.user_data);
}
break;
@@ -2834,7 +2877,7 @@ static int wm_handlers_do_keymap_with_gizmo_handler(
action |= wm_handler_operator_call(
C, handlers, &handler->head, event, kmi->ptr, kmi->idname);
- CTX_wm_gizmo_group_set(C, NULL);
+ CTX_wm_gizmo_group_set(C, nullptr);
if (action & WM_HANDLER_BREAK) {
if (G.debug & (G_DEBUG_EVENTS | G_DEBUG_HANDLERS)) {
@@ -2884,7 +2927,7 @@ static int wm_handlers_do_gizmo_handler(bContext *C,
ScrArea *area = CTX_wm_area(C);
ARegion *region = CTX_wm_region(C);
wmGizmoMap *gzmap = handler->gizmo_map;
- BLI_assert(gzmap != NULL);
+ BLI_assert(gzmap != nullptr);
wmGizmo *gz = wm_gizmomap_highlight_get(gzmap);
/* Needed so UI blocks over gizmos don't let events fall through to the gizmos,
@@ -2892,25 +2935,25 @@ static int wm_handlers_do_gizmo_handler(bContext *C,
* note we still allow for starting the gizmo drag outside, then travel 'inside' the node. */
if (region->type->clip_gizmo_events_by_ui) {
if (UI_region_block_find_mouse_over(region, event->xy, true)) {
- if (gz != NULL && event->type != EVT_GIZMO_UPDATE) {
+ if (gz != nullptr && event->type != EVT_GIZMO_UPDATE) {
if (restore_highlight_unless_activated == false) {
WM_tooltip_clear(C, CTX_wm_window(C));
- wm_gizmomap_highlight_set(gzmap, C, NULL, 0);
+ wm_gizmomap_highlight_set(gzmap, C, nullptr, 0);
}
}
return action;
}
}
- struct {
+ struct PrevGizmoData {
wmGizmo *gz_modal;
wmGizmo *gz;
int part;
- } prev = {
- .gz_modal = wm_gizmomap_modal_get(gzmap),
- .gz = gz,
- .part = gz ? gz->highlight_part : 0,
};
+ PrevGizmoData prev{};
+ prev.gz_modal = wm_gizmomap_modal_get(gzmap);
+ prev.gz = gz;
+ prev.part = gz ? gz->highlight_part : 0;
if (region->gizmo_map != handler->gizmo_map) {
WM_gizmomap_tag_refresh(handler->gizmo_map);
@@ -2923,7 +2966,7 @@ static int wm_handlers_do_gizmo_handler(bContext *C,
bool handle_keymap = false;
/* Handle gizmo highlighting. */
- if ((prev.gz_modal == NULL) &&
+ if ((prev.gz_modal == nullptr) &&
((event->type == MOUSEMOVE) || is_event_modifier || is_event_drag)) {
handle_highlight = true;
if (is_event_modifier || is_event_drag) {
@@ -2954,7 +2997,7 @@ static int wm_handlers_do_gizmo_handler(bContext *C,
}
if (wm_gizmomap_highlight_set(gzmap, C, gz, part)) {
- if (gz != NULL) {
+ if (gz != nullptr) {
if ((U.flag & USER_TOOLTIPS) && (gz->flag & WM_GIZMO_NO_TOOLTIP) == 0) {
WM_tooltip_timer_init(C, CTX_wm_window(C), area, region, WM_gizmomap_tooltip_init);
}
@@ -2967,7 +3010,7 @@ static int wm_handlers_do_gizmo_handler(bContext *C,
if (handle_keymap) {
/* Handle highlight gizmo. */
- if ((gz != NULL) && (gz->flag & WM_GIZMO_HIDDEN_KEYMAP) == 0) {
+ if ((gz != nullptr) && (gz->flag & WM_GIZMO_HIDDEN_KEYMAP) == 0) {
bool keymap_poll = false;
wmGizmoGroup *gzgroup = gz->parent_gzgroup;
wmKeyMap *keymap = WM_keymap_active(wm, gz->keymap ? gz->keymap : gzgroup->type->keymap);
@@ -2988,7 +3031,7 @@ static int wm_handlers_do_gizmo_handler(bContext *C,
if ((kmi->flag & KMI_INACTIVE) == 0) {
if (wm_eventmatch(&event_test_click, kmi) ||
wm_eventmatch(&event_test_click_drag, kmi)) {
- wmOperatorType *ot = WM_operatortype_find(kmi->idname, 0);
+ wmOperatorType *ot = WM_operatortype_find(kmi->idname, false);
if (WM_operator_poll_context(C, ot, WM_OP_INVOKE_DEFAULT)) {
is_event_handle_all = true;
break;
@@ -3002,7 +3045,7 @@ static int wm_handlers_do_gizmo_handler(bContext *C,
}
/* Don't use from now on. */
- gz = NULL;
+ gz = nullptr;
/* Fallback to selected gizmo (when un-handled). */
if ((action & WM_HANDLER_BREAK) == 0) {
@@ -3012,7 +3055,7 @@ static int wm_handlers_do_gizmo_handler(bContext *C,
if (wm_gizmogroup_is_any_selected(gzgroup)) {
wmKeyMap *keymap = WM_keymap_active(wm, gzgroup->type->keymap);
action |= wm_handlers_do_keymap_with_gizmo_handler(
- C, event, handlers, handler, gzgroup, keymap, do_debug_handler, NULL);
+ C, event, handlers, handler, gzgroup, keymap, do_debug_handler, nullptr);
if (action & WM_HANDLER_BREAK) {
break;
}
@@ -3061,7 +3104,7 @@ static int wm_handlers_do_intern(bContext *C, wmWindow *win, wmEvent *event, Lis
wmWindowManager *wm = CTX_wm_manager(C);
int action = WM_HANDLER_CONTINUE;
- if (handlers == NULL) {
+ if (handlers == nullptr) {
wm_event_handler_return_value_check(event, action);
return action;
}
@@ -3072,7 +3115,8 @@ static int wm_handlers_do_intern(bContext *C, wmWindow *win, wmEvent *event, Lis
* by the event that's called, for eg:
*
* Calling a python script which changes the area.type, see T32232. */
- for (wmEventHandler *handler_base = handlers->first, *handler_base_next;
+ for (wmEventHandler *handler_base = static_cast<wmEventHandler *>(handlers->first),
+ *handler_base_next;
handler_base && handlers->first;
handler_base = handler_base_next) {
handler_base_next = handler_base->next;
@@ -3081,7 +3125,7 @@ static int wm_handlers_do_intern(bContext *C, wmWindow *win, wmEvent *event, Lis
if (handler_base->flag & WM_HANDLER_DO_FREE) {
/* Pass. */
}
- else if (handler_base->poll == NULL || handler_base->poll(CTX_wm_region(C), event)) {
+ else if (handler_base->poll == nullptr || handler_base->poll(CTX_wm_region(C), event)) {
/* In advance to avoid access to freed event on window close. */
const int always_pass = wm_event_always_pass(event);
@@ -3110,14 +3154,14 @@ static int wm_handlers_do_intern(bContext *C, wmWindow *win, wmEvent *event, Lis
* are kept when a modal operators starts (annoying but otherwise harmless). */
if (action & WM_HANDLER_BREAK) {
/* Window may be gone after file read. */
- if (CTX_wm_window(C) != NULL) {
+ if (CTX_wm_window(C) != nullptr) {
WM_tooltip_clear(C, CTX_wm_window(C));
}
}
}
else if (handler_base->type == WM_HANDLER_TYPE_UI) {
wmEventHandler_UI *handler = (wmEventHandler_UI *)handler_base;
- BLI_assert(handler->handle_fn != NULL);
+ BLI_assert(handler->handle_fn != nullptr);
if (!wm->is_interface_locked) {
action |= wm_handler_ui_call(C, handler, event, always_pass);
}
@@ -3135,13 +3179,13 @@ static int wm_handlers_do_intern(bContext *C, wmWindow *win, wmEvent *event, Lis
/* Pass single matched #wmDrag onto the operator. */
BLI_remlink(lb, drag);
- ListBase single_lb = {0};
+ ListBase single_lb = {nullptr};
BLI_addtail(&single_lb, drag);
event->customdata = &single_lb;
const wmOperatorCallContext opcontext = wm_drop_operator_context_get(drop);
int op_retval = wm_operator_call_internal(
- C, drop->ot, drop->ptr, NULL, opcontext, false, event);
+ C, drop->ot, drop->ptr, nullptr, opcontext, false, event);
OPERATOR_RETVAL_CHECK(op_retval);
if ((op_retval & OPERATOR_CANCELLED) && drop->cancel) {
@@ -3159,7 +3203,7 @@ static int wm_handlers_do_intern(bContext *C, wmWindow *win, wmEvent *event, Lis
wm_drop_end(C, drag, drop);
/* XXX file-read case. */
- if (CTX_wm_window(C) == NULL) {
+ if (CTX_wm_window(C) == nullptr) {
return action;
}
@@ -3186,7 +3230,7 @@ static int wm_handlers_do_intern(bContext *C, wmWindow *win, wmEvent *event, Lis
}
}
else {
- action |= wm_handler_operator_call(C, handlers, handler_base, event, NULL, NULL);
+ action |= wm_handler_operator_call(C, handlers, handler_base, event, nullptr, nullptr);
}
}
else {
@@ -3206,7 +3250,7 @@ static int wm_handlers_do_intern(bContext *C, wmWindow *win, wmEvent *event, Lis
/* File-read case, if the wm is freed then the handler's
* will have been too so the code below need not run. */
- if (CTX_wm_window(C) == NULL) {
+ if (CTX_wm_window(C) == nullptr) {
return action;
}
@@ -3227,7 +3271,7 @@ static int wm_handlers_do_intern(bContext *C, wmWindow *win, wmEvent *event, Lis
}
/* Do some extra sanity checking before returning the action. */
- if (CTX_wm_window(C) != NULL) {
+ if (CTX_wm_window(C) != nullptr) {
wm_event_handler_return_value_check(event, action);
}
return action;
@@ -3240,9 +3284,9 @@ static int wm_handlers_do(bContext *C, wmEvent *event, ListBase *handlers)
{
int action = wm_handlers_do_intern(C, CTX_wm_window(C), event, handlers);
- /* Will be NULL in the file read case. */
+ /* Will be nullptr in the file read case. */
wmWindow *win = CTX_wm_window(C);
- if (win == NULL) {
+ if (win == nullptr) {
return action;
}
@@ -3336,7 +3380,7 @@ static int wm_handlers_do(bContext *C, wmEvent *event, ListBase *handlers)
if (event->val == KM_RELEASE) {
if (event->prev_val == KM_PRESS) {
- if (win->event_queue_check_click == true) {
+ if (win->event_queue_check_click) {
if (WM_event_drag_test(event, event->prev_press_xy)) {
win->event_queue_check_click = false;
if (win->event_queue_check_drag) {
@@ -3349,7 +3393,7 @@ static int wm_handlers_do(bContext *C, wmEvent *event, ListBase *handlers)
else {
/* Position is where the actual click happens, for more
* accurate selecting in case the mouse drifts a little. */
- int xy[2] = {UNPACK2(event->xy)};
+ const int xy[2] = {UNPACK2(event->xy)};
copy_v2_v2_int(event->xy, event->prev_press_xy);
event->val = KM_CLICK;
@@ -3436,7 +3480,7 @@ static ScrArea *area_event_inside(bContext *C, const int xy[2])
}
}
}
- return NULL;
+ return nullptr;
}
static ARegion *region_event_inside(bContext *C, const int xy[2])
@@ -3451,14 +3495,14 @@ static ARegion *region_event_inside(bContext *C, const int xy[2])
}
}
}
- return NULL;
+ return nullptr;
}
static void wm_paintcursor_tag(bContext *C, wmPaintCursor *pc, ARegion *region)
{
if (region) {
for (; pc; pc = pc->next) {
- if (pc->poll == NULL || pc->poll(C)) {
+ if (pc->poll == nullptr || pc->poll(C)) {
wmWindow *win = CTX_wm_window(C);
WM_paint_cursor_tag_redraw(win, region);
}
@@ -3479,17 +3523,18 @@ static void wm_paintcursor_test(bContext *C, const wmEvent *event)
ARegion *region = CTX_wm_region(C);
if (region) {
- wm_paintcursor_tag(C, wm->paintcursors.first, region);
+ wm_paintcursor_tag(C, static_cast<wmPaintCursor *>(wm->paintcursors.first), region);
}
/* If previous position was not in current region, we have to set a temp new context. */
- if (region == NULL || !BLI_rcti_isect_pt_v(&region->winrct, event->prev_xy)) {
+ if (region == nullptr || !BLI_rcti_isect_pt_v(&region->winrct, event->prev_xy)) {
ScrArea *area = CTX_wm_area(C);
CTX_wm_area_set(C, area_event_inside(C, event->prev_xy));
CTX_wm_region_set(C, region_event_inside(C, event->prev_xy));
- wm_paintcursor_tag(C, wm->paintcursors.first, CTX_wm_region(C));
+ wm_paintcursor_tag(
+ C, static_cast<wmPaintCursor *>(wm->paintcursors.first), CTX_wm_region(C));
CTX_wm_area_set(C, area);
CTX_wm_region_set(C, region);
@@ -3606,27 +3651,29 @@ static void wm_event_handle_xrevent(bContext *C,
int action = wm_handlers_do(C, event, &win->modalhandlers);
if ((action & WM_HANDLER_BREAK) == 0) {
- wmXrActionData *actiondata = event->customdata;
+ wmXrActionData *actiondata = static_cast<wmXrActionData *>(event->customdata);
if (actiondata->ot->modal && event->val == KM_RELEASE) {
/* Don't execute modal operators on release. */
}
else {
- PointerRNA properties = {.type = actiondata->ot->srna, .data = actiondata->op_properties};
+ PointerRNA properties{};
+ properties.type = actiondata->ot->srna;
+ properties.data = actiondata->op_properties;
if (actiondata->ot->invoke) {
/* Invoke operator, either executing operator or transferring responsibility to window
* modal handlers. */
wm_operator_invoke(C,
actiondata->ot,
event,
- actiondata->op_properties ? &properties : NULL,
- NULL,
+ actiondata->op_properties ? &properties : nullptr,
+ nullptr,
false,
false);
}
else {
/* Execute operator. */
wmOperator *op = wm_operator_create(
- wm, actiondata->ot, actiondata->op_properties ? &properties : NULL, NULL);
+ wm, actiondata->ot, actiondata->op_properties ? &properties : nullptr, nullptr);
if ((WM_operator_call(C, op) & OPERATOR_HANDLED) == 0) {
WM_operator_free(op);
}
@@ -3634,8 +3681,8 @@ static void wm_event_handle_xrevent(bContext *C,
}
}
- CTX_wm_region_set(C, NULL);
- CTX_wm_area_set(C, NULL);
+ CTX_wm_region_set(C, nullptr);
+ CTX_wm_area_set(C, nullptr);
}
#endif /* WITH_XR_OPENXR */
@@ -3705,16 +3752,16 @@ void wm_event_do_handlers(bContext *C)
BLI_assert(WM_window_get_active_screen(win));
BLI_assert(WM_window_get_active_workspace(win));
- if (screen == NULL) {
+ if (screen == nullptr) {
wm_event_free_all(win);
}
else {
Scene *scene = WM_window_get_active_scene(win);
ViewLayer *view_layer = WM_window_get_active_view_layer(win);
Depsgraph *depsgraph = BKE_scene_get_depsgraph(scene, view_layer);
- Scene *scene_eval = (depsgraph != NULL) ? DEG_get_evaluated_scene(depsgraph) : NULL;
+ Scene *scene_eval = (depsgraph != nullptr) ? DEG_get_evaluated_scene(depsgraph) : nullptr;
- if (scene_eval != NULL) {
+ if (scene_eval != nullptr) {
const int is_playing_sound = BKE_sound_scene_playing(scene_eval);
if (scene_eval->id.recalc & ID_RECALC_FRAME_CHANGE) {
@@ -3724,7 +3771,7 @@ void wm_event_do_handlers(bContext *C)
else if (is_playing_sound != -1) {
bool is_playing_screen;
- is_playing_screen = (ED_screen_animation_playing(wm) != NULL);
+ is_playing_screen = (ED_screen_animation_playing(wm) != nullptr);
if (((is_playing_sound == 1) && (is_playing_screen == 0)) ||
((is_playing_sound == 0) && (is_playing_screen == 1))) {
@@ -3750,7 +3797,7 @@ void wm_event_do_handlers(bContext *C)
if (ncfra != scene->r.cfra) {
scene->r.cfra = ncfra;
ED_update_for_newframe(CTX_data_main(C), depsgraph);
- WM_event_add_notifier(C, NC_WINDOW, NULL);
+ WM_event_add_notifier(C, NC_WINDOW, nullptr);
}
}
}
@@ -3759,7 +3806,7 @@ void wm_event_do_handlers(bContext *C)
}
wmEvent *event;
- while ((event = win->event_queue.first)) {
+ while ((event = static_cast<wmEvent *>(win->event_queue.first))) {
int action = WM_HANDLER_CONTINUE;
/* Force handling drag if a key is pressed even if the drag threshold has not been met.
@@ -3831,7 +3878,7 @@ void wm_event_do_handlers(bContext *C)
action |= wm_handlers_do(C, event, &win->modalhandlers);
/* File-read case. */
- if (CTX_wm_window(C) == NULL) {
+ if (CTX_wm_window(C) == nullptr) {
wm_event_free_and_remove_from_queue_if_valid(event);
return;
}
@@ -3867,7 +3914,7 @@ void wm_event_do_handlers(bContext *C)
ED_screen_areas_iter (win, screen, area) {
/* After restoring a screen from SCREENMAXIMIZED we have to wait
* with the screen handling till the region coordinates are updated. */
- if (screen->skip_handling == true) {
+ if (screen->skip_handling) {
/* Restore for the next iteration of wm_event_do_handlers. */
screen->skip_handling = false;
break;
@@ -3885,18 +3932,18 @@ void wm_event_do_handlers(bContext *C)
action |= wm_event_do_handlers_area_regions(C, event, area);
/* File-read case (Python), T29489. */
- if (CTX_wm_window(C) == NULL) {
+ if (CTX_wm_window(C) == nullptr) {
wm_event_free_and_remove_from_queue_if_valid(event);
return;
}
- CTX_wm_region_set(C, NULL);
+ CTX_wm_region_set(C, nullptr);
if ((action & WM_HANDLER_BREAK) == 0) {
wm_region_mouse_co(C, event); /* Only invalidates `event->mval` in this case. */
action |= wm_handlers_do(C, event, &area->handlers);
}
- CTX_wm_area_set(C, NULL);
+ CTX_wm_area_set(C, nullptr);
/* NOTE: do not escape on #WM_HANDLER_BREAK,
* mouse-move needs handled for previous area. */
@@ -3913,7 +3960,7 @@ void wm_event_do_handlers(bContext *C)
action |= wm_handlers_do(C, event, &win->handlers);
/* File-read case. */
- if (CTX_wm_window(C) == NULL) {
+ if (CTX_wm_window(C) == nullptr) {
wm_event_free_and_remove_from_queue_if_valid(event);
return;
}
@@ -3954,12 +4001,12 @@ void wm_event_do_handlers(bContext *C)
tevent.val = KM_NOTHING;
tevent.prev_xy[0] = tevent.xy[0];
tevent.prev_xy[1] = tevent.xy[1];
- tevent.flag = 0;
+ tevent.flag = (eWM_EventFlag)0;
wm_event_add(win, &tevent);
win->addmousemove = 0;
}
- CTX_wm_window_set(C, NULL);
+ CTX_wm_window_set(C, nullptr);
}
/* Update key configuration after handling events. */
@@ -3981,58 +4028,123 @@ void WM_event_fileselect_event(wmWindowManager *wm, void *ophandle, int eventval
event.type = EVT_FILESELECT;
event.val = eventval;
+ event.flag = (eWM_EventFlag)0;
event.customdata = ophandle; /* Only as void pointer type check. */
wm_event_add(win, &event);
}
}
+/**
+ * From the context window, try to find a window that is appropriate for use as root window of a
+ * modal File Browser (modal means: there is a #SpaceFile.op to execute). The root window will
+ * become the parent of the File Browser and provides a context to execute the file operator in,
+ * even after closing the File Browser.
+ *
+ * An appropriate window is either of the following:
+ * * A parent window that does not yet contain a modal File Browser. This is determined using
+ * #ED_fileselect_handler_area_find_any_with_op().
+ * * A parent window containing a modal File Browser, but in a maximized/fullscreen state. Users
+ * shouldn't be able to put a temporary screen like the modal File Browser into
+ * maximized/fullscreen state themselves. So this setup indicates that the File Browser was
+ * opened using #USER_TEMP_SPACE_DISPLAY_FULLSCREEN.
+ *
+ * If no appropriate parent window can be found from the context window, return the first
+ * registered window (which can be assumed to be a regular window, e.g. no modal File Browser; this
+ * is asserted).
+ */
+static wmWindow *wm_event_find_fileselect_root_window_from_context(const bContext *C)
+{
+ wmWindow *ctx_win = CTX_wm_window(C);
+
+ for (wmWindow *ctx_win_or_parent = ctx_win; ctx_win_or_parent;
+ ctx_win_or_parent = ctx_win_or_parent->parent) {
+ ScrArea *file_area = ED_fileselect_handler_area_find_any_with_op(ctx_win_or_parent);
+
+ if (!file_area) {
+ return ctx_win_or_parent;
+ }
+
+ if (file_area->full) {
+ return ctx_win_or_parent;
+ }
+ }
+
+ /* Fallback to the first window. */
+ const wmWindowManager *wm = CTX_wm_manager(C);
+ BLI_assert(!ED_fileselect_handler_area_find_any_with_op(
+ static_cast<const wmWindow *>(wm->windows.first)));
+ return static_cast<wmWindow *>(wm->windows.first);
+}
+
/* Operator is supposed to have a filled "path" property. */
/* Optional property: file-type (XXX enum?) */
void WM_event_add_fileselect(bContext *C, wmOperator *op)
{
wmWindowManager *wm = CTX_wm_manager(C);
- wmWindow *win = CTX_wm_window(C);
- const bool is_temp_screen = WM_window_is_temp_screen(win);
+ wmWindow *ctx_win = CTX_wm_window(C);
+
+ /* The following vars define the root context. That is essentially the "parent" context of the
+ * File Browser operation, to be restored for eventually executing the file operation. */
+ wmWindow *root_win = wm_event_find_fileselect_root_window_from_context(C);
+ /* Determined later. */
+ ScrArea *root_area = nullptr;
+ ARegion *root_region = nullptr;
/* Close any popups, like when opening a file browser from the splash. */
- UI_popup_handlers_remove_all(C, &win->modalhandlers);
+ UI_popup_handlers_remove_all(C, &root_win->modalhandlers);
- if (!is_temp_screen) {
- /* Only allow 1 file selector open per window. */
- LISTBASE_FOREACH_MUTABLE (wmEventHandler *, handler_base, &win->modalhandlers) {
- if (handler_base->type == WM_HANDLER_TYPE_OP) {
- wmEventHandler_Op *handler = (wmEventHandler_Op *)handler_base;
- if (handler->is_fileselect == false) {
- continue;
- }
+ /* Setting the context window unsets the context area & screen. Avoid doing that, so operators
+ * calling the file browser can operate in the context the browser was opened in. */
+ if (ctx_win != root_win) {
+ CTX_wm_window_set(C, root_win);
+ }
- ScrArea *file_area = ED_fileselect_handler_area_find(win, handler->op);
+ /* The root window may already have a File Browser open. Cancel it if so, only 1 should be open
+ * per window. The root context of this operation is also used for the new operation. */
+ LISTBASE_FOREACH_MUTABLE (wmEventHandler *, handler_base, &root_win->modalhandlers) {
+ if (handler_base->type == WM_HANDLER_TYPE_OP) {
+ wmEventHandler_Op *handler = (wmEventHandler_Op *)handler_base;
+ if (handler->is_fileselect == false) {
+ continue;
+ }
- if (file_area) {
- CTX_wm_area_set(C, file_area);
- wm_handler_fileselect_do(C, &win->modalhandlers, handler, EVT_FILESELECT_CANCEL);
- }
- /* If not found we stop the handler without changing the screen. */
- else {
- wm_handler_fileselect_do(
- C, &win->modalhandlers, handler, EVT_FILESELECT_EXTERNAL_CANCEL);
- }
+ wm_handler_op_context_get_if_valid(
+ C, handler, ctx_win->eventstate, &root_area, &root_region);
+
+ ScrArea *file_area = ED_fileselect_handler_area_find(root_win, handler->op);
+
+ if (file_area) {
+ CTX_wm_area_set(C, file_area);
+ wm_handler_fileselect_do(C, &root_win->modalhandlers, handler, EVT_FILESELECT_CANCEL);
+ }
+ /* If not found we stop the handler without changing the screen. */
+ else {
+ wm_handler_fileselect_do(
+ C, &root_win->modalhandlers, handler, EVT_FILESELECT_EXTERNAL_CANCEL);
}
}
}
- wmEventHandler_Op *handler = MEM_callocN(sizeof(*handler), __func__);
+ BLI_assert(root_win != nullptr);
+ /* When not reusing the root context from a previous file browsing operation, use the current
+ * area & region, if they are inside the root window. */
+ if (!root_area && ctx_win == root_win) {
+ root_area = CTX_wm_area(C);
+ root_region = CTX_wm_region(C);
+ }
+
+ wmEventHandler_Op *handler = MEM_cnew<wmEventHandler_Op>(__func__);
handler->head.type = WM_HANDLER_TYPE_OP;
handler->is_fileselect = true;
handler->op = op;
- handler->context.win = CTX_wm_window(C);
- handler->context.area = CTX_wm_area(C);
- handler->context.region = CTX_wm_region(C);
+ handler->context.win = root_win;
+ handler->context.area = root_area;
+ handler->context.region = root_region;
- BLI_addhead(&win->modalhandlers, handler);
+ BLI_addhead(&root_win->modalhandlers, handler);
/* Check props once before invoking if check is available
* ensures initial properties are valid. */
@@ -4041,6 +4153,10 @@ void WM_event_add_fileselect(bContext *C, wmOperator *op)
}
WM_event_fileselect_event(wm, op, EVT_FILESELECT_FULL_OPEN);
+
+ if (ctx_win != root_win) {
+ CTX_wm_window_set(C, ctx_win);
+ }
}
/** \} */
@@ -4059,7 +4175,7 @@ static void WM_event_set_handler_flag(wmEventHandler *handler, int flag)
wmEventHandler_Op *WM_event_add_modal_handler(bContext *C, wmOperator *op)
{
- wmEventHandler_Op *handler = MEM_callocN(sizeof(*handler), __func__);
+ wmEventHandler_Op *handler = MEM_cnew<wmEventHandler_Op>(__func__);
handler->head.type = WM_HANDLER_TYPE_OP;
wmWindow *win = CTX_wm_window(C);
@@ -4113,7 +4229,7 @@ void WM_event_modal_handler_region_replace(wmWindow *win,
* it needs to keep old region stored in handler, so don't change it. */
if ((handler->context.region == old_region) && (handler->is_fileselect == false)) {
handler->context.region = new_region;
- handler->context.region_type = new_region ? new_region->regiontype : RGN_TYPE_WINDOW;
+ handler->context.region_type = new_region ? new_region->regiontype : (int)RGN_TYPE_WINDOW;
}
}
}
@@ -4122,8 +4238,8 @@ void WM_event_modal_handler_region_replace(wmWindow *win,
wmEventHandler_Keymap *WM_event_add_keymap_handler(ListBase *handlers, wmKeyMap *keymap)
{
if (!keymap) {
- CLOG_WARN(WM_LOG_HANDLERS, "called with NULL key-map");
- return NULL;
+ CLOG_WARN(WM_LOG_HANDLERS, "called with nullptr key-map");
+ return nullptr;
}
/* Only allow same key-map once. */
@@ -4136,7 +4252,7 @@ wmEventHandler_Keymap *WM_event_add_keymap_handler(ListBase *handlers, wmKeyMap
}
}
- wmEventHandler_Keymap *handler = MEM_callocN(sizeof(*handler), __func__);
+ wmEventHandler_Keymap *handler = MEM_cnew<wmEventHandler_Keymap>(__func__);
handler->head.type = WM_HANDLER_TYPE_KEYMAP;
BLI_addtail(handlers, handler);
handler->keymap = keymap;
@@ -4168,16 +4284,16 @@ static void wm_event_get_keymap_from_toolsystem_ex(wmWindowManager *wm,
const char *keymap_id_list[ARRAY_SIZE(km_result->keymaps)];
int keymap_id_list_len = 0;
- /* NOTE(@campbellbarton): If `win` is NULL, this function may not behave as expected.
+ /* NOTE(@campbellbarton): If `win` is nullptr, this function may not behave as expected.
* Assert since this should not happen in practice.
* If it does, the window could be looked up in `wm` using the `area`.
- * Keep NULL checks in run-time code since any crashes here are difficult to redo. */
- BLI_assert_msg(win != NULL, "The window should always be set for tool interactions!");
- const Scene *scene = win ? win->scene : NULL;
+ * Keep nullptr checks in run-time code since any crashes here are difficult to redo. */
+ BLI_assert_msg(win != nullptr, "The window should always be set for tool interactions!");
+ const Scene *scene = win ? win->scene : nullptr;
- ScrArea *area = handler->dynamic.user_data;
- handler->keymap_tool = NULL;
- bToolRef_Runtime *tref_rt = area->runtime.tool ? area->runtime.tool->runtime : NULL;
+ ScrArea *area = static_cast<ScrArea *>(handler->dynamic.user_data);
+ handler->keymap_tool = nullptr;
+ bToolRef_Runtime *tref_rt = area->runtime.tool ? area->runtime.tool->runtime : nullptr;
if (tref_rt && tref_rt->keymap[0]) {
keymap_id_list[keymap_id_list_len++] = tref_rt->keymap;
@@ -4196,18 +4312,18 @@ static void wm_event_get_keymap_from_toolsystem_ex(wmWindowManager *wm,
}
if (with_gizmos && (tref_rt->gizmo_group[0] != '\0')) {
- wmGizmoMap *gzmap = NULL;
- wmGizmoGroup *gzgroup = NULL;
+ wmGizmoMap *gzmap = nullptr;
+ wmGizmoGroup *gzgroup = nullptr;
LISTBASE_FOREACH (ARegion *, region, &area->regionbase) {
- if (region->gizmo_map != NULL) {
+ if (region->gizmo_map != nullptr) {
gzmap = region->gizmo_map;
gzgroup = WM_gizmomap_group_find(gzmap, tref_rt->gizmo_group);
- if (gzgroup != NULL) {
+ if (gzgroup != nullptr) {
break;
}
}
}
- if (gzgroup != NULL) {
+ if (gzgroup != nullptr) {
if (gzgroup->type->flag & WM_GIZMOGROUPTYPE_TOOL_FALLBACK_KEYMAP) {
/* If all are hidden, don't override. */
is_gizmo_visible = true;
@@ -4238,7 +4354,7 @@ static void wm_event_get_keymap_from_toolsystem_ex(wmWindowManager *wm,
wmKeyMap *km = WM_keymap_list_find_spaceid_or_empty(
&wm->userconf->keymaps, keymap_id, area->spacetype, RGN_TYPE_WINDOW);
/* We shouldn't use key-maps from unrelated spaces. */
- if (km == NULL) {
+ if (km == nullptr) {
printf("Key-map: '%s' not found for tool '%s'\n", keymap_id, area->runtime.tool->idname);
continue;
}
@@ -4263,12 +4379,12 @@ void WM_event_get_keymap_from_toolsystem(wmWindowManager *wm,
wm_event_get_keymap_from_toolsystem_ex(wm, win, handler, km_result, false);
}
-struct wmEventHandler_Keymap *WM_event_add_keymap_handler_dynamic(
+wmEventHandler_Keymap *WM_event_add_keymap_handler_dynamic(
ListBase *handlers, wmEventHandler_KeymapDynamicFn *keymap_fn, void *user_data)
{
if (!keymap_fn) {
- CLOG_WARN(WM_LOG_HANDLERS, "called with NULL keymap_fn");
- return NULL;
+ CLOG_WARN(WM_LOG_HANDLERS, "called with nullptr keymap_fn");
+ return nullptr;
}
/* Only allow same key-map once. */
@@ -4283,7 +4399,7 @@ struct wmEventHandler_Keymap *WM_event_add_keymap_handler_dynamic(
}
}
- wmEventHandler_Keymap *handler = MEM_callocN(sizeof(*handler), __func__);
+ wmEventHandler_Keymap *handler = MEM_cnew<wmEventHandler_Keymap>(__func__);
handler->head.type = WM_HANDLER_TYPE_KEYMAP;
BLI_addtail(handlers, handler);
handler->dynamic.keymap_fn = keymap_fn;
@@ -4298,7 +4414,7 @@ wmEventHandler_Keymap *WM_event_add_keymap_handler_priority(ListBase *handlers,
{
WM_event_remove_keymap_handler(handlers, keymap);
- wmEventHandler_Keymap *handler = MEM_callocN(sizeof(*handler), "event key-map handler");
+ wmEventHandler_Keymap *handler = MEM_cnew<wmEventHandler_Keymap>("event key-map handler");
handler->head.type = WM_HANDLER_TYPE_KEYMAP;
BLI_addhead(handlers, handler);
@@ -4330,8 +4446,8 @@ wmEventHandler_Keymap *WM_event_add_keymap_handler_poll(ListBase *handlers,
EventHandlerPoll poll)
{
wmEventHandler_Keymap *handler = WM_event_add_keymap_handler(handlers, keymap);
- if (handler == NULL) {
- return NULL;
+ if (handler == nullptr) {
+ return nullptr;
}
handler->head.poll = poll;
@@ -4374,7 +4490,7 @@ wmEventHandler_UI *WM_event_add_ui_handler(const bContext *C,
void *user_data,
const char flag)
{
- wmEventHandler_UI *handler = MEM_callocN(sizeof(*handler), __func__);
+ wmEventHandler_UI *handler = MEM_cnew<wmEventHandler_UI>(__func__);
handler->head.type = WM_HANDLER_TYPE_UI;
handler->handle_fn = handle_fn;
handler->remove_fn = remove_fn;
@@ -4385,9 +4501,9 @@ wmEventHandler_UI *WM_event_add_ui_handler(const bContext *C,
handler->context.menu = CTX_wm_menu(C);
}
else {
- handler->context.area = NULL;
- handler->context.region = NULL;
- handler->context.menu = NULL;
+ handler->context.area = nullptr;
+ handler->context.region = nullptr;
+ handler->context.menu = nullptr;
}
BLI_assert((flag & WM_HANDLER_DO_FREE) == 0);
@@ -4452,7 +4568,7 @@ wmEventHandler_Dropbox *WM_event_add_dropbox_handler(ListBase *handlers, ListBas
}
}
- wmEventHandler_Dropbox *handler = MEM_callocN(sizeof(*handler), __func__);
+ wmEventHandler_Dropbox *handler = MEM_cnew<wmEventHandler_Dropbox>(__func__);
handler->head.type = WM_HANDLER_TYPE_DROPBOX;
/* Dropbox stored static, no free or copy. */
@@ -4477,6 +4593,20 @@ void WM_event_remove_area_handler(ListBase *handlers, void *area)
}
}
+wmOperator *WM_operator_find_modal_by_type(wmWindow *win, const wmOperatorType *ot)
+{
+ LISTBASE_FOREACH (wmEventHandler *, handler_base, &win->modalhandlers) {
+ if (handler_base->type != WM_HANDLER_TYPE_OP) {
+ continue;
+ }
+ wmEventHandler_Op *handler = (wmEventHandler_Op *)handler_base;
+ if (handler->op && handler->op->type == ot) {
+ return handler->op;
+ }
+ }
+ return nullptr;
+}
+
#if 0
static void WM_event_remove_handler(ListBase *handlers, wmEventHandler *handler)
{
@@ -4747,22 +4877,25 @@ static void wm_eventemulation(wmEvent *event, bool test_only)
}
}
-static const wmTabletData wm_event_tablet_data_default = {
- .active = EVT_TABLET_NONE,
- .pressure = 1.0f,
- .x_tilt = 0.0f,
- .y_tilt = 0.0f,
- .is_motion_absolute = false,
-};
+constexpr wmTabletData wm_event_tablet_data_default()
+{
+ wmTabletData tablet_data{};
+ tablet_data.active = EVT_TABLET_NONE;
+ tablet_data.pressure = 1.0f;
+ tablet_data.x_tilt = 0.0f;
+ tablet_data.y_tilt = 0.0f;
+ tablet_data.is_motion_absolute = false;
+ return tablet_data;
+}
void WM_event_tablet_data_default_set(wmTabletData *tablet_data)
{
- *tablet_data = wm_event_tablet_data_default;
+ *tablet_data = wm_event_tablet_data_default();
}
void wm_tablet_data_from_ghost(const GHOST_TabletData *tablet_data, wmTabletData *wmtab)
{
- if ((tablet_data != NULL) && tablet_data->Active != GHOST_kTabletModeNone) {
+ if ((tablet_data != nullptr) && tablet_data->Active != GHOST_kTabletModeNone) {
wmtab->active = (int)tablet_data->Active;
wmtab->pressure = wm_pressure_curve(tablet_data->Pressure);
wmtab->x_tilt = tablet_data->Xtilt;
@@ -4772,7 +4905,7 @@ void wm_tablet_data_from_ghost(const GHOST_TabletData *tablet_data, wmTabletData
// printf("%s: using tablet %.5f\n", __func__, wmtab->pressure);
}
else {
- *wmtab = wm_event_tablet_data_default;
+ *wmtab = wm_event_tablet_data_default();
// printf("%s: not using tablet\n", __func__);
}
}
@@ -4781,7 +4914,7 @@ void wm_tablet_data_from_ghost(const GHOST_TabletData *tablet_data, wmTabletData
/* Adds custom-data to event. */
static void attach_ndof_data(wmEvent *event, const GHOST_TEventNDOFMotionData *ghost)
{
- wmNDOFMotionData *data = MEM_mallocN(sizeof(wmNDOFMotionData), "Custom-data NDOF");
+ wmNDOFMotionData *data = MEM_cnew<wmNDOFMotionData>("Custom-data NDOF");
const float ts = U.ndof_sensitivity;
const float rs = U.ndof_orbit_sensitivity;
@@ -4809,33 +4942,38 @@ static void attach_ndof_data(wmEvent *event, const GHOST_TEventNDOFMotionData *g
/* Imperfect but probably usable... draw/enable drags to other windows. */
static wmWindow *wm_event_cursor_other_windows(wmWindowManager *wm, wmWindow *win, wmEvent *event)
{
- int mval[2] = {event->xy[0], event->xy[1]};
+ /* If GHOST doesn't support window positioning, don't use this feature at all. */
+ const static int8_t supports_window_position = GHOST_SupportsWindowPosition();
+ if (!supports_window_position) {
+ return nullptr;
+ }
if (wm->windows.first == wm->windows.last) {
- return NULL;
+ return nullptr;
}
/* In order to use window size and mouse position (pixels), we have to use a WM function. */
/* Check if outside, include top window bar. */
- if (mval[0] < 0 || mval[1] < 0 || mval[0] > WM_window_pixels_x(win) ||
- mval[1] > WM_window_pixels_y(win) + 30) {
+ int event_xy[2] = {UNPACK2(event->xy)};
+ if (event_xy[0] < 0 || event_xy[1] < 0 || event_xy[0] > WM_window_pixels_x(win) ||
+ event_xy[1] > WM_window_pixels_y(win) + 30) {
/* Let's skip windows having modal handlers now. */
/* Potential XXX ugly... I wouldn't have added a `modalhandlers` list
* (introduced in rev 23331, ton). */
LISTBASE_FOREACH (wmEventHandler *, handler, &win->modalhandlers) {
if (ELEM(handler->type, WM_HANDLER_TYPE_UI, WM_HANDLER_TYPE_OP)) {
- return NULL;
+ return nullptr;
}
}
- wmWindow *win_other = WM_window_find_under_cursor(win, mval, mval);
+ wmWindow *win_other = WM_window_find_under_cursor(win, event_xy, event_xy);
if (win_other && win_other != win) {
- copy_v2_v2_int(event->xy, mval);
+ copy_v2_v2_int(event->xy, event_xy);
return win_other;
}
}
- return NULL;
+ return nullptr;
}
static bool wm_event_is_double_click(const wmEvent *event)
@@ -4876,18 +5014,18 @@ static void wm_event_prev_click_set(wmEvent *event_state)
static wmEvent *wm_event_add_mousemove(wmWindow *win, const wmEvent *event)
{
- wmEvent *event_last = win->event_queue.last;
+ wmEvent *event_last = static_cast<wmEvent *>(win->event_queue.last);
/* Some painting operators want accurate mouse events, they can
* handle in between mouse move moves, others can happily ignore
* them for better performance. */
if (event_last && event_last->type == MOUSEMOVE) {
event_last->type = INBETWEEN_MOUSEMOVE;
- event_last->flag = 0;
+ event_last->flag = (eWM_EventFlag)0;
}
wmEvent *event_new = wm_event_add(win, event);
- if (event_last == NULL) {
+ if (event_last == nullptr) {
event_last = win->eventstate;
}
@@ -4906,7 +5044,7 @@ static wmEvent *wm_event_add_mousemove_to_head(wmWindow *win)
if (event_last) {
tevent = *event_last;
- tevent.flag = 0;
+ tevent.flag = (eWM_EventFlag)0;
tevent.ascii = '\0';
tevent.utf8_buf[0] = '\0';
@@ -4932,7 +5070,7 @@ static wmEvent *wm_event_add_trackpad(wmWindow *win, const wmEvent *event, int d
{
/* Ignore in between track-pad events for performance, we only need high accuracy
* for painting with mouse moves, for navigation using the accumulated value is ok. */
- wmEvent *event_last = win->event_queue.last;
+ wmEvent *event_last = static_cast<wmEvent *>(win->event_queue.last);
if (event_last && event_last->type == event->type) {
deltax += event_last->xy[0] - event_last->prev_xy[0];
deltay += event_last->xy[1] - event_last->prev_xy[1];
@@ -4950,10 +5088,14 @@ static wmEvent *wm_event_add_trackpad(wmWindow *win, const wmEvent *event, int d
/**
* Update the event-state for any kind of event that supports #KM_PRESS / #KM_RELEASE.
+ *
+ * \param check_double_click: Optionally skip checking for double-click events.
+ * Needed for event simulation where the time of click events is not so predictable.
*/
-static void wm_event_state_update_and_click_set(const GHOST_TEventType type,
- wmEvent *event,
- wmEvent *event_state)
+static void wm_event_state_update_and_click_set_ex(wmEvent *event,
+ wmEvent *event_state,
+ const bool is_keyboard,
+ const bool check_double_click)
{
BLI_assert(ISKEYBOARD_OR_BUTTON(event->type));
BLI_assert(ELEM(event->val, KM_PRESS, KM_RELEASE));
@@ -4969,7 +5111,7 @@ static void wm_event_state_update_and_click_set(const GHOST_TEventType type,
/* It's important only to write into the `event_state` modifier for keyboard
* events because emulate MMB clears one of the modifiers in `event->modifier`,
* making the second press not behave as if the modifier is pressed, see T96279. */
- if (ELEM(type, GHOST_kEventKeyDown, GHOST_kEventKeyUp)) {
+ if (is_keyboard) {
event_state->modifier = event->modifier;
}
event_state->flag = (event->flag & event_state_flag_mask);
@@ -4977,7 +5119,7 @@ static void wm_event_state_update_and_click_set(const GHOST_TEventType type,
* since the `event_state` and the `event` are not kept in sync. */
/* Double click test. */
- if (wm_event_is_double_click(event)) {
+ if (check_double_click && wm_event_is_double_click(event)) {
CLOG_INFO(WM_LOG_HANDLERS, 1, "DBL_CLICK: detected");
event->val = KM_DBL_CLICK;
}
@@ -4988,6 +5130,15 @@ static void wm_event_state_update_and_click_set(const GHOST_TEventType type,
}
}
+static void wm_event_state_update_and_click_set(wmEvent *event,
+ wmEvent *event_state,
+ const GHOST_TEventType type)
+{
+ const bool is_keyboard = ELEM(type, GHOST_kEventKeyDown, GHOST_kEventKeyUp);
+ const bool check_double_click = true;
+ wm_event_state_update_and_click_set_ex(event, event_state, is_keyboard, check_double_click);
+}
+
void wm_event_add_ghostevent(wmWindowManager *wm, wmWindow *win, int type, void *customdata)
{
if (UNLIKELY(G.f & G_FLAG_EVENT_SIMULATE)) {
@@ -5008,7 +5159,7 @@ void wm_event_add_ghostevent(wmWindowManager *wm, wmWindow *win, int type, void
/* Initialize and copy state (only mouse x y and modifiers). */
event = *event_state;
- event.flag = 0;
+ event.flag = (eWM_EventFlag)0;
/**
* Always support accessing the last key press/release. This is set from `win->eventstate`,
@@ -5045,7 +5196,7 @@ void wm_event_add_ghostevent(wmWindowManager *wm, wmWindow *win, int type, void
switch (type) {
/* Mouse move, also to inactive window (X11 does this). */
case GHOST_kEventCursorMove: {
- GHOST_TEventCursorData *cd = customdata;
+ GHOST_TEventCursorData *cd = static_cast<GHOST_TEventCursorData *>(customdata);
copy_v2_v2_int(event.xy, &cd->x);
wm_stereo3d_mouse_offset_apply(win, event.xy);
@@ -5082,7 +5233,7 @@ void wm_event_add_ghostevent(wmWindowManager *wm, wmWindow *win, int type, void
break;
}
case GHOST_kEventTrackpad: {
- GHOST_TEventTrackpadData *pd = customdata;
+ GHOST_TEventTrackpadData *pd = static_cast<GHOST_TEventTrackpadData *>(customdata);
switch (pd->subtype) {
case GHOST_kTrackpadEventMagnify:
event.type = MOUSEZOOM;
@@ -5116,7 +5267,7 @@ void wm_event_add_ghostevent(wmWindowManager *wm, wmWindow *win, int type, void
/* Mouse button. */
case GHOST_kEventButtonDown:
case GHOST_kEventButtonUp: {
- GHOST_TEventButtonData *bd = customdata;
+ GHOST_TEventButtonData *bd = static_cast<GHOST_TEventButtonData *>(customdata);
/* Get value and type from Ghost. */
event.val = (type == GHOST_kEventButtonDown) ? KM_PRESS : KM_RELEASE;
@@ -5147,7 +5298,7 @@ void wm_event_add_ghostevent(wmWindowManager *wm, wmWindow *win, int type, void
wm_tablet_data_from_ghost(&bd->tablet, &event.tablet);
wm_eventemulation(&event, false);
- wm_event_state_update_and_click_set(type, &event, event_state);
+ wm_event_state_update_and_click_set(&event, event_state, (GHOST_TEventType)type);
/* Add to other window if event is there (not to both!). */
wmWindow *win_other = wm_event_cursor_other_windows(wm, win, &event);
@@ -5175,14 +5326,14 @@ void wm_event_add_ghostevent(wmWindowManager *wm, wmWindow *win, int type, void
/* Keyboard. */
case GHOST_kEventKeyDown:
case GHOST_kEventKeyUp: {
- GHOST_TEventKeyData *kd = customdata;
+ GHOST_TEventKeyData *kd = static_cast<GHOST_TEventKeyData *>(customdata);
event.type = convert_key(kd->key);
if (UNLIKELY(event.type == EVENT_NONE)) {
break;
}
event.ascii = kd->ascii;
- /* Might be not NULL terminated. */
+ /* Might be not nullptr terminated. */
memcpy(event.utf8_buf, kd->utf8_buf, sizeof(event.utf8_buf));
if (kd->is_repeat) {
event.flag |= WM_EVENT_IS_REPEAT;
@@ -5271,7 +5422,7 @@ void wm_event_add_ghostevent(wmWindowManager *wm, wmWindow *win, int type, void
}
/* It's important `event.modifier` has been initialized first. */
- wm_event_state_update_and_click_set(type, &event, event_state);
+ wm_event_state_update_and_click_set(&event, event_state, (GHOST_TEventType)type);
/* If test_break set, it catches this. Do not set with modifier presses.
* Exclude modifiers because MS-Windows uses these to bring up the task manager.
@@ -5290,7 +5441,7 @@ void wm_event_add_ghostevent(wmWindowManager *wm, wmWindow *win, int type, void
}
case GHOST_kEventWheel: {
- GHOST_TEventWheelData *wheelData = customdata;
+ GHOST_TEventWheelData *wheelData = static_cast<GHOST_TEventWheelData *>(customdata);
if (wheelData->z > 0) {
event.type = WHEELUPMOUSE;
@@ -5319,7 +5470,7 @@ void wm_event_add_ghostevent(wmWindowManager *wm, wmWindow *win, int type, void
case GHOST_kEventNDOFMotion: {
event.type = NDOF_MOTION;
event.val = KM_NOTHING;
- attach_ndof_data(&event, customdata);
+ attach_ndof_data(&event, static_cast<const GHOST_TEventNDOFMotionData *>(customdata));
wm_event_add(win, &event);
CLOG_INFO(WM_LOG_HANDLERS, 1, "sending NDOF_MOTION, prev = %d %d", event.xy[0], event.xy[1]);
@@ -5327,7 +5478,7 @@ void wm_event_add_ghostevent(wmWindowManager *wm, wmWindow *win, int type, void
}
case GHOST_kEventNDOFButton: {
- GHOST_TEventNDOFButtonData *e = customdata;
+ GHOST_TEventNDOFButtonData *e = static_cast<GHOST_TEventNDOFButtonData *>(customdata);
event.type = NDOF_BUTTON_NONE + e->button;
@@ -5343,9 +5494,9 @@ void wm_event_add_ghostevent(wmWindowManager *wm, wmWindow *win, int type, void
}
event.custom = 0;
- event.customdata = NULL;
+ event.customdata = nullptr;
- wm_event_state_update_and_click_set(type, &event, event_state);
+ wm_event_state_update_and_click_set(&event, event_state, (GHOST_TEventType)type);
wm_event_add(win, &event);
@@ -5367,7 +5518,7 @@ void wm_event_add_ghostevent(wmWindowManager *wm, wmWindow *win, int type, void
#ifdef WITH_INPUT_IME
case GHOST_kEventImeCompositionStart: {
event.val = KM_PRESS;
- win->ime_data = customdata;
+ win->ime_data = static_cast<wmIMEData *>(customdata);
win->ime_data->is_ime_composing = true;
event.type = WM_IME_COMPOSITE_START;
wm_event_add(win, &event);
@@ -5401,14 +5552,13 @@ void wm_event_add_xrevent(wmWindow *win, wmXrActionData *actiondata, short val)
{
BLI_assert(ELEM(val, KM_PRESS, KM_RELEASE));
- wmEvent event = {
- .type = EVT_XR_ACTION,
- .val = val,
- .flag = 0,
- .custom = EVT_DATA_XR,
- .customdata = actiondata,
- .customdata_free = true,
- };
+ wmEvent event{};
+ event.type = EVT_XR_ACTION;
+ event.val = val;
+ event.flag = (eWM_EventFlag)0;
+ event.custom = EVT_DATA_XR;
+ event.customdata = actiondata;
+ event.customdata_free = true;
wm_event_add(win, &event);
}
@@ -5469,15 +5619,15 @@ void WM_event_get_keymaps_from_handler(wmWindowManager *wm,
wmEventHandler_Keymap *handler,
wmEventHandler_KeymapResult *km_result)
{
- if (handler->dynamic.keymap_fn != NULL) {
+ if (handler->dynamic.keymap_fn != nullptr) {
handler->dynamic.keymap_fn(wm, win, handler, km_result);
- BLI_assert(handler->keymap == NULL);
+ BLI_assert(handler->keymap == nullptr);
}
else {
memset(km_result, 0x0, sizeof(*km_result));
wmKeyMap *keymap = WM_keymap_active(wm, handler->keymap);
- BLI_assert(keymap != NULL);
- if (keymap != NULL) {
+ BLI_assert(keymap != nullptr);
+ if (keymap != nullptr) {
km_result->keymaps[km_result->keymaps_len++] = keymap;
}
}
@@ -5487,13 +5637,13 @@ wmKeyMapItem *WM_event_match_keymap_item(bContext *C, wmKeyMap *keymap, const wm
{
LISTBASE_FOREACH (wmKeyMapItem *, kmi, &keymap->items) {
if (wm_eventmatch(event, kmi)) {
- wmOperatorType *ot = WM_operatortype_find(kmi->idname, 0);
+ wmOperatorType *ot = WM_operatortype_find(kmi->idname, false);
if (WM_operator_poll_context(C, ot, WM_OP_INVOKE_DEFAULT)) {
return kmi;
}
}
}
- return NULL;
+ return nullptr;
}
wmKeyMapItem *WM_event_match_keymap_item_from_handlers(
@@ -5504,7 +5654,7 @@ wmKeyMapItem *WM_event_match_keymap_item_from_handlers(
if (handler_base->flag & WM_HANDLER_DO_FREE) {
/* Pass. */
}
- else if (handler_base->poll == NULL || handler_base->poll(CTX_wm_region(C), event)) {
+ else if (handler_base->poll == nullptr || handler_base->poll(CTX_wm_region(C), event)) {
if (handler_base->type == WM_HANDLER_TYPE_KEYMAP) {
wmEventHandler_Keymap *handler = (wmEventHandler_Keymap *)handler_base;
wmEventHandler_KeymapResult km_result;
@@ -5513,7 +5663,7 @@ wmKeyMapItem *WM_event_match_keymap_item_from_handlers(
wmKeyMap *keymap = km_result.keymaps[km_index];
if (WM_keymap_poll(C, keymap)) {
wmKeyMapItem *kmi = WM_event_match_keymap_item(C, keymap, event);
- if (kmi != NULL) {
+ if (kmi != nullptr) {
return kmi;
}
}
@@ -5521,7 +5671,7 @@ wmKeyMapItem *WM_event_match_keymap_item_from_handlers(
}
}
}
- return NULL;
+ return nullptr;
}
/** \} */
@@ -5551,10 +5701,10 @@ struct CursorKeymapInfo {
*/
char text[3][2][128];
wmEvent state_event;
- struct CursorKeymapInfo_State state;
+ CursorKeymapInfo_State state;
};
-static void wm_event_cursor_store(struct CursorKeymapInfo_State *state,
+static void wm_event_cursor_store(CursorKeymapInfo_State *state,
const wmEvent *event,
short space_type,
short region_type,
@@ -5563,29 +5713,29 @@ static void wm_event_cursor_store(struct CursorKeymapInfo_State *state,
state->modifier = event->modifier;
state->space_type = space_type;
state->region_type = region_type;
- state->tref = tref ? *tref : (bToolRef){0};
+ state->tref = tref ? *tref : bToolRef{};
}
const char *WM_window_cursor_keymap_status_get(const wmWindow *win,
int button_index,
int type_index)
{
- if (win->cursor_keymap_status != NULL) {
- struct CursorKeymapInfo *cd = win->cursor_keymap_status;
+ if (win->cursor_keymap_status != nullptr) {
+ CursorKeymapInfo *cd = static_cast<CursorKeymapInfo *>(win->cursor_keymap_status);
const char *msg = cd->text[button_index][type_index];
if (*msg) {
return msg;
}
}
- return NULL;
+ return nullptr;
}
ScrArea *WM_window_status_area_find(wmWindow *win, bScreen *screen)
{
if (screen->state == SCREENFULL) {
- return NULL;
+ return nullptr;
}
- ScrArea *area_statusbar = NULL;
+ ScrArea *area_statusbar = nullptr;
LISTBASE_FOREACH (ScrArea *, area, &win->global_areas.areabase) {
if (area->spacetype == SPACE_STATUSBAR) {
area_statusbar = area;
@@ -5599,7 +5749,7 @@ void WM_window_status_area_tag_redraw(wmWindow *win)
{
bScreen *screen = WM_window_get_active_screen(win);
ScrArea *area = WM_window_status_area_find(win, screen);
- if (area != NULL) {
+ if (area != nullptr) {
ED_area_tag_redraw(area);
}
}
@@ -5608,16 +5758,16 @@ void WM_window_cursor_keymap_status_refresh(bContext *C, wmWindow *win)
{
bScreen *screen = WM_window_get_active_screen(win);
ScrArea *area_statusbar = WM_window_status_area_find(win, screen);
- if (area_statusbar == NULL) {
+ if (area_statusbar == nullptr) {
MEM_SAFE_FREE(win->cursor_keymap_status);
return;
}
- struct CursorKeymapInfo *cd;
- if (UNLIKELY(win->cursor_keymap_status == NULL)) {
- win->cursor_keymap_status = MEM_callocN(sizeof(struct CursorKeymapInfo), __func__);
+ CursorKeymapInfo *cd;
+ if (UNLIKELY(win->cursor_keymap_status == nullptr)) {
+ win->cursor_keymap_status = MEM_callocN(sizeof(CursorKeymapInfo), __func__);
}
- cd = win->cursor_keymap_status;
+ cd = static_cast<CursorKeymapInfo *>(win->cursor_keymap_status);
/* Detect unchanged state (early exit). */
if (memcmp(&cd->state_event, win->eventstate, sizeof(wmEvent)) == 0) {
@@ -5626,23 +5776,23 @@ void WM_window_cursor_keymap_status_refresh(bContext *C, wmWindow *win)
/* Now perform more comprehensive check,
* still keep this fast since it happens on mouse-move. */
- struct CursorKeymapInfo cd_prev = *((struct CursorKeymapInfo *)win->cursor_keymap_status);
+ CursorKeymapInfo cd_prev = *((CursorKeymapInfo *)win->cursor_keymap_status);
cd->state_event = *win->eventstate;
/* Find active region and associated area. */
ARegion *region = screen->active_region;
- if (region == NULL) {
+ if (region == nullptr) {
return;
}
- ScrArea *area = NULL;
+ ScrArea *area = nullptr;
ED_screen_areas_iter (win, screen, area_iter) {
if (BLI_findindex(&area_iter->regionbase, region) != -1) {
area = area_iter;
break;
}
}
- if (area == NULL) {
+ if (area == nullptr) {
return;
}
@@ -5665,15 +5815,14 @@ void WM_window_cursor_keymap_status_refresh(bContext *C, wmWindow *win)
/* Detect changes to the state. */
{
- bToolRef *tref = NULL;
+ bToolRef *tref = nullptr;
if ((region->regiontype == RGN_TYPE_WINDOW) &&
((1 << area->spacetype) & WM_TOOLSYSTEM_SPACE_MASK)) {
ViewLayer *view_layer = WM_window_get_active_view_layer(win);
WorkSpace *workspace = WM_window_get_active_workspace(win);
- const bToolKey tkey = {
- .space_type = area->spacetype,
- .mode = WM_toolsystem_mode_from_spacetype(view_layer, area, area->spacetype),
- };
+ bToolKey tkey{};
+ tkey.space_type = area->spacetype;
+ tkey.mode = WM_toolsystem_mode_from_spacetype(view_layer, area, area->spacetype);
tref = WM_toolsystem_ref_find(workspace, &tkey);
}
wm_event_cursor_store(&cd->state, win->eventstate, area->spacetype, region->regiontype, tref);
@@ -5727,8 +5876,9 @@ void WM_window_cursor_keymap_status_refresh(bContext *C, wmWindow *win)
wmEvent test_event = *win->eventstate;
test_event.type = event_data[data_index].event_type;
test_event.val = event_data[data_index].event_value;
+ test_event.flag = (eWM_EventFlag)0;
wm_eventemulation(&test_event, true);
- wmKeyMapItem *kmi = NULL;
+ wmKeyMapItem *kmi = nullptr;
for (int handler_index = 0; handler_index < ARRAY_SIZE(handlers); handler_index++) {
kmi = WM_event_match_keymap_item_from_handlers(
C, wm, win, handlers[handler_index], &test_event);
@@ -5737,7 +5887,7 @@ void WM_window_cursor_keymap_status_refresh(bContext *C, wmWindow *win)
}
}
if (kmi) {
- wmOperatorType *ot = WM_operatortype_find(kmi->idname, 0);
+ wmOperatorType *ot = WM_operatortype_find(kmi->idname, false);
const char *name = (ot) ? WM_operatortype_name(ot, kmi->ptr) : kmi->idname;
STRNCPY(cd->text[button_index][type_index], name);
}
@@ -5747,7 +5897,7 @@ void WM_window_cursor_keymap_status_refresh(bContext *C, wmWindow *win)
ED_area_tag_redraw(area_statusbar);
}
- CTX_wm_window_set(C, NULL);
+ CTX_wm_window_set(C, nullptr);
}
/** \} */
@@ -5759,12 +5909,12 @@ void WM_window_cursor_keymap_status_refresh(bContext *C, wmWindow *win)
bool WM_window_modal_keymap_status_draw(bContext *C, wmWindow *win, uiLayout *layout)
{
wmWindowManager *wm = CTX_wm_manager(C);
- wmKeyMap *keymap = NULL;
- wmOperator *op = NULL;
+ wmKeyMap *keymap = nullptr;
+ wmOperator *op = nullptr;
LISTBASE_FOREACH (wmEventHandler *, handler_base, &win->modalhandlers) {
if (handler_base->type == WM_HANDLER_TYPE_OP) {
wmEventHandler_Op *handler = (wmEventHandler_Op *)handler_base;
- if (handler->op != NULL) {
+ if (handler->op != nullptr) {
/* 'handler->keymap' could be checked too, seems not to be used. */
wmKeyMap *keymap_test = WM_keymap_active(wm, handler->op->type->modalkeymap);
if (keymap_test && keymap_test->modal_items) {
@@ -5775,17 +5925,17 @@ bool WM_window_modal_keymap_status_draw(bContext *C, wmWindow *win, uiLayout *la
}
}
}
- if (keymap == NULL || keymap->modal_items == NULL) {
+ if (keymap == nullptr || keymap->modal_items == nullptr) {
return false;
}
- const EnumPropertyItem *items = keymap->modal_items;
+ const EnumPropertyItem *items = static_cast<const EnumPropertyItem *>(keymap->modal_items);
uiLayout *row = uiLayoutRow(layout, true);
for (int i = 0; items[i].identifier; i++) {
if (!items[i].identifier[0]) {
continue;
}
- if ((keymap->poll_modal_item != NULL) &&
+ if ((keymap->poll_modal_item != nullptr) &&
(keymap->poll_modal_item(op, items[i].value) == false)) {
continue;
}
@@ -5793,14 +5943,14 @@ bool WM_window_modal_keymap_status_draw(bContext *C, wmWindow *win, uiLayout *la
bool show_text = true;
{
- /* Warning: O(n^2). */
- wmKeyMapItem *kmi = NULL;
- for (kmi = keymap->items.first; kmi; kmi = kmi->next) {
+ /* WARNING: O(n^2). */
+ wmKeyMapItem *kmi = nullptr;
+ for (kmi = static_cast<wmKeyMapItem *>(keymap->items.first); kmi; kmi = kmi->next) {
if (kmi->propvalue == items[i].value) {
break;
}
}
- if (kmi != NULL) {
+ if (kmi != nullptr) {
if (kmi->val == KM_RELEASE) {
/* Assume release events just disable something which was toggled on. */
continue;
diff --git a/source/blender/windowmanager/intern/wm_files.c b/source/blender/windowmanager/intern/wm_files.c
index bee7e71df54..a170fa9902b 100644
--- a/source/blender/windowmanager/intern/wm_files.c
+++ b/source/blender/windowmanager/intern/wm_files.c
@@ -846,8 +846,13 @@ static void file_read_reports_finalize(BlendFileReadReport *bf_reports)
bf_reports->count.missing_obproxies);
}
else {
- BLI_assert(bf_reports->count.missing_obdata == 0);
- BLI_assert(bf_reports->count.missing_obproxies == 0);
+ if (bf_reports->count.missing_obdata != 0 || bf_reports->count.missing_obproxies != 0) {
+ CLOG_ERROR(&LOG,
+ "%d local ObjectData and %d local Object proxies are reported to be missing, "
+ "this should never happen",
+ bf_reports->count.missing_obdata,
+ bf_reports->count.missing_obproxies);
+ }
}
if (bf_reports->resynced_lib_overrides_libraries_count != 0) {
@@ -1091,7 +1096,7 @@ void wm_homefile_read_ex(bContext *C,
const bool reset_app_template = ((!app_template && U.app_template[0]) ||
(app_template && !STREQ(app_template, U.app_template)));
- /* options exclude eachother */
+ /* Options exclude each other. */
BLI_assert((use_factory_settings && filepath_startup_override) == 0);
if ((G.f & G_FLAG_SCRIPT_OVERRIDE_PREF) == 0) {
diff --git a/source/blender/windowmanager/intern/wm_files_link.c b/source/blender/windowmanager/intern/wm_files_link.c
index b41ffb4cfc2..f2c41dada48 100644
--- a/source/blender/windowmanager/intern/wm_files_link.c
+++ b/source/blender/windowmanager/intern/wm_files_link.c
@@ -438,7 +438,7 @@ void WM_OT_link(wmOperatorType *ot)
ot->exec = wm_link_append_exec;
ot->poll = wm_link_append_poll;
- ot->flag |= OPTYPE_UNDO;
+ ot->flag = OPTYPE_UNDO;
WM_operator_properties_filesel(ot,
FILE_TYPE_FOLDER | FILE_TYPE_BLENDER | FILE_TYPE_BLENDERLIB,
@@ -462,7 +462,7 @@ void WM_OT_append(wmOperatorType *ot)
ot->exec = wm_link_append_exec;
ot->poll = wm_link_append_poll;
- ot->flag |= OPTYPE_UNDO;
+ ot->flag = OPTYPE_UNDO;
WM_operator_properties_filesel(ot,
FILE_TYPE_FOLDER | FILE_TYPE_BLENDER | FILE_TYPE_BLENDERLIB,
@@ -803,7 +803,7 @@ void WM_OT_lib_relocate(wmOperatorType *ot)
ot->invoke = wm_lib_relocate_invoke;
ot->exec = wm_lib_relocate_exec;
- ot->flag |= OPTYPE_UNDO;
+ ot->flag = OPTYPE_UNDO;
prop = RNA_def_string(ot->srna, "library", NULL, MAX_NAME, "Library", "Library to relocate");
RNA_def_property_flag(prop, PROP_HIDDEN);
@@ -833,7 +833,7 @@ void WM_OT_lib_reload(wmOperatorType *ot)
ot->exec = wm_lib_reload_exec;
- ot->flag |= OPTYPE_UNDO;
+ ot->flag = OPTYPE_UNDO;
prop = RNA_def_string(ot->srna, "library", NULL, MAX_NAME, "Library", "Library to reload");
RNA_def_property_flag(prop, PROP_HIDDEN);
diff --git a/source/blender/windowmanager/intern/wm_gesture_ops.c b/source/blender/windowmanager/intern/wm_gesture_ops.c
index 1fdc8bbe2c8..e3892933905 100644
--- a/source/blender/windowmanager/intern/wm_gesture_ops.c
+++ b/source/blender/windowmanager/intern/wm_gesture_ops.c
@@ -819,6 +819,7 @@ int WM_gesture_straightline_modal(bContext *C, wmOperator *op, const wmEvent *ev
/* Toggle flipping on/off. */
gesture->use_flip = !gesture->use_flip;
gesture_straightline_apply(C, op);
+ wm_gesture_tag_redraw(win);
break;
}
case GESTURE_MODAL_SELECT: {
@@ -897,6 +898,7 @@ int WM_gesture_straightline_oneshot_modal(bContext *C, wmOperator *op, const wmE
case GESTURE_MODAL_FLIP: {
/* Toggle flip on/off. */
gesture->use_flip = !gesture->use_flip;
+ wm_gesture_tag_redraw(win);
break;
}
case GESTURE_MODAL_SELECT:
diff --git a/source/blender/windowmanager/intern/wm_init_exit.c b/source/blender/windowmanager/intern/wm_init_exit.c
index 8d6741dcfb6..f77aad24719 100644
--- a/source/blender/windowmanager/intern/wm_init_exit.c
+++ b/source/blender/windowmanager/intern/wm_init_exit.c
@@ -59,6 +59,7 @@
#include "BKE_mask.h" /* free mask clipboard */
#include "BKE_material.h" /* BKE_material_copybuf_clear */
#include "BKE_studiolight.h"
+#include "BKE_subdiv.h"
#include "BKE_tracking.h" /* free tracking clipboard */
#include "RE_engine.h"
@@ -114,9 +115,6 @@
#include "GPU_init_exit.h"
#include "GPU_material.h"
-#include "BKE_sound.h"
-#include "BKE_subdiv.h"
-
#include "COM_compositor.h"
#include "DEG_depsgraph.h"
@@ -340,10 +338,10 @@ void WM_init(bContext *C, int argc, const char **argv)
if (!G.background) {
if (wm_start_with_console) {
- setConsoleWindowState(GHOST_kConsoleWindowStateShow);
+ GHOST_setConsoleWindowState(GHOST_kConsoleWindowStateShow);
}
else {
- setConsoleWindowState(GHOST_kConsoleWindowStateHideForNonConsoleLaunch);
+ GHOST_setConsoleWindowState(GHOST_kConsoleWindowStateHideForNonConsoleLaunch);
}
}
@@ -382,7 +380,7 @@ static void free_openrecent(void)
}
#ifdef WIN32
-/* Read console events until there is a key event. Also returns on any error. */
+/* Read console events until there is a key event. Also returns on any error. */
static void wait_for_console_key(void)
{
HANDLE hConsoleInput = GetStdHandle(STD_INPUT_HANDLE);
diff --git a/source/blender/windowmanager/intern/wm_jobs.c b/source/blender/windowmanager/intern/wm_jobs.c
index b44cf9e48b8..d5c4d07e9ed 100644
--- a/source/blender/windowmanager/intern/wm_jobs.c
+++ b/source/blender/windowmanager/intern/wm_jobs.c
@@ -87,6 +87,16 @@ struct wmJob {
* Executed in main thread.
*/
void (*endjob)(void *);
+ /**
+ * Called when job is stopped normally, i.e. by simply completing the startjob function.
+ * Executed in main thread.
+ */
+ void (*completed)(void *);
+ /**
+ * Called when job is stopped abnormally, i.e. when stop=true but ready=false.
+ * Executed in main thread.
+ */
+ void (*canceled)(void *);
/** Running jobs each have own timer */
double timestep;
@@ -344,10 +354,23 @@ void WM_jobs_callbacks(wmJob *wm_job,
void (*update)(void *),
void (*endjob)(void *))
{
+ WM_jobs_callbacks_ex(wm_job, startjob, initjob, update, endjob, NULL, NULL);
+}
+
+void WM_jobs_callbacks_ex(wmJob *wm_job,
+ wm_jobs_start_callback startjob,
+ void (*initjob)(void *),
+ void (*update)(void *),
+ void (*endjob)(void *),
+ void (*completed)(void *),
+ void (*canceled)(void *))
+{
wm_job->startjob = startjob;
wm_job->initjob = initjob;
wm_job->update = update;
wm_job->endjob = endjob;
+ wm_job->completed = completed;
+ wm_job->canceled = canceled;
}
static void *do_job_thread(void *job_v)
@@ -465,6 +488,24 @@ void WM_jobs_start(wmWindowManager *wm, wmJob *wm_job)
}
}
+static void wm_job_end(wmJob *wm_job)
+{
+ BLI_assert_msg(BLI_thread_is_main(), "wm_job_end should only be called from the main thread");
+ if (wm_job->endjob) {
+ wm_job->endjob(wm_job->run_customdata);
+ }
+
+ /* Do the final callback based on whether the job was run to completion or not.
+ * Not all jobs have the same way of signaling cancellation (i.e. rendering stops when
+ * `G.is_break == true`, but doesn't set any wm_job properties to cancel the WM job). */
+ const bool was_canceled = wm_job->stop || G.is_break;
+ void (*final_callback)(void *) = (wm_job->ready && !was_canceled) ? wm_job->completed :
+ wm_job->canceled;
+ if (final_callback) {
+ final_callback(wm_job->run_customdata);
+ }
+}
+
static void wm_job_free(wmWindowManager *wm, wmJob *wm_job)
{
BLI_remlink(&wm->jobs, wm_job);
@@ -485,10 +526,7 @@ static void wm_jobs_kill_job(wmWindowManager *wm, wmJob *wm_job)
WM_job_main_thread_lock_release(wm_job);
BLI_threadpool_end(&wm_job->threads);
WM_job_main_thread_lock_acquire(wm_job);
-
- if (wm_job->endjob) {
- wm_job->endjob(wm_job->run_customdata);
- }
+ wm_job_end(wm_job);
}
if (wm_job->wt) {
@@ -600,9 +638,7 @@ void wm_jobs_timer(wmWindowManager *wm, wmTimer *wt)
}
if (wm_job->ready) {
- if (wm_job->endjob) {
- wm_job->endjob(wm_job->run_customdata);
- }
+ wm_job_end(wm_job);
/* free own data */
wm_job->run_free(wm_job->run_customdata);
@@ -670,3 +706,13 @@ bool WM_jobs_has_running(const wmWindowManager *wm)
return false;
}
+
+bool WM_jobs_has_running_type(const struct wmWindowManager *wm, int job_type)
+{
+ LISTBASE_FOREACH (wmJob *, wm_job, &wm->jobs) {
+ if (wm_job->running && wm_job->job_type == job_type) {
+ return true;
+ }
+ }
+ return false;
+}
diff --git a/source/blender/windowmanager/intern/wm_keymap.c b/source/blender/windowmanager/intern/wm_keymap.c
index 1fa5e64093f..acacbd77f9e 100644
--- a/source/blender/windowmanager/intern/wm_keymap.c
+++ b/source/blender/windowmanager/intern/wm_keymap.c
@@ -445,7 +445,10 @@ bool WM_keymap_poll(bContext *C, wmKeyMap *keymap)
* When developing a customized Blender though you may want empty keymaps. */
if (!U.app_template[0] &&
/* Fallback key-maps may be intentionally empty, don't flood the output. */
- !BLI_str_endswith(keymap->idname, " (fallback)")) {
+ !BLI_str_endswith(keymap->idname, " (fallback)") &&
+ /* This is an exception which may be empty.
+ * Longer term we might want a flag to indicate an empty key-map is intended. */
+ !STREQ(keymap->idname, "Node Tool: Tweak")) {
CLOG_WARN(WM_LOG_KEYMAPS, "empty keymap '%s'", keymap->idname);
}
}
diff --git a/source/blender/windowmanager/intern/wm_keymap_utils.c b/source/blender/windowmanager/intern/wm_keymap_utils.c
index 5a35570296a..0817b10f86e 100644
--- a/source/blender/windowmanager/intern/wm_keymap_utils.c
+++ b/source/blender/windowmanager/intern/wm_keymap_utils.c
@@ -270,6 +270,12 @@ wmKeyMap *WM_keymap_guess_opname(const bContext *C, const char *opname)
break;
}
}
+ else if (STRPREFIX(opname, "CURVES_OT")) {
+ km = WM_keymap_find_all(wm, "Curves", 0, 0);
+ }
+ else if (STRPREFIX(opname, "SCULPT_CURVES_OT")) {
+ km = WM_keymap_find_all(wm, "Sculpt Curves", 0, 0);
+ }
else if (STRPREFIX(opname, "MBALL_OT")) {
km = WM_keymap_find_all(wm, "Metaball", 0, 0);
diff --git a/source/blender/windowmanager/intern/wm_menu_type.c b/source/blender/windowmanager/intern/wm_menu_type.c
index 9e50ebb1ce5..b4cf5a79cfa 100644
--- a/source/blender/windowmanager/intern/wm_menu_type.c
+++ b/source/blender/windowmanager/intern/wm_menu_type.c
@@ -99,3 +99,21 @@ bool WM_menutype_poll(bContext *C, MenuType *mt)
}
return true;
}
+
+void WM_menutype_idname_visit_for_search(const bContext *UNUSED(C),
+ PointerRNA *UNUSED(ptr),
+ PropertyRNA *UNUSED(prop),
+ const char *UNUSED(edit_text),
+ StringPropertySearchVisitFunc visit_fn,
+ void *visit_user_data)
+{
+ GHashIterator gh_iter;
+ GHASH_ITER (gh_iter, menutypes_hash) {
+ MenuType *mt = BLI_ghashIterator_getValue(&gh_iter);
+
+ StringPropertySearchVisitParams visit_params = {NULL};
+ visit_params.text = mt->idname;
+ visit_params.info = mt->label;
+ visit_fn(visit_user_data, &visit_params);
+ }
+}
diff --git a/source/blender/windowmanager/intern/wm_operator_props.c b/source/blender/windowmanager/intern/wm_operator_props.c
index 6e44246f3ef..71c948dfbb9 100644
--- a/source/blender/windowmanager/intern/wm_operator_props.c
+++ b/source/blender/windowmanager/intern/wm_operator_props.c
@@ -8,8 +8,12 @@
* (`WM_operator_properties_*` functions).
*/
+#include "DNA_ID_enums.h"
#include "DNA_space_types.h"
+#include "BKE_lib_id.h"
+#include "BKE_main.h"
+
#include "BLI_math_base.h"
#include "BLI_rect.h"
@@ -222,6 +226,74 @@ void WM_operator_properties_filesel(wmOperatorType *ot,
RNA_def_property_flag(prop, PROP_HIDDEN | PROP_SKIP_SAVE);
}
+void WM_operator_properties_id_lookup_set_from_id(PointerRNA *ptr, const ID *id)
+{
+ PropertyRNA *prop_session_uuid = RNA_struct_find_property(ptr, "session_uuid");
+ PropertyRNA *prop_name = RNA_struct_find_property(ptr, "name");
+
+ if (prop_session_uuid) {
+ RNA_int_set(ptr, "session_uuid", (int)id->session_uuid);
+ }
+ else if (prop_name) {
+ RNA_string_set(ptr, "name", id->name + 2);
+ }
+ else {
+ BLI_assert_unreachable();
+ }
+}
+
+ID *WM_operator_properties_id_lookup_from_name_or_session_uuid(Main *bmain,
+ PointerRNA *ptr,
+ const ID_Type type)
+{
+ PropertyRNA *prop_session_uuid = RNA_struct_find_property(ptr, "session_uuid");
+ if (prop_session_uuid && RNA_property_is_set(ptr, prop_session_uuid)) {
+ const uint32_t session_uuid = (uint32_t)RNA_property_int_get(ptr, prop_session_uuid);
+ return BKE_libblock_find_session_uuid(bmain, type, session_uuid);
+ }
+
+ PropertyRNA *prop_name = RNA_struct_find_property(ptr, "name");
+ if (prop_name && RNA_property_is_set(ptr, prop_name)) {
+ char name[MAX_ID_NAME - 2];
+ RNA_property_string_get(ptr, prop_name, name);
+ return BKE_libblock_find_name(bmain, type, name);
+ }
+
+ return NULL;
+}
+
+bool WM_operator_properties_id_lookup_is_set(PointerRNA *ptr)
+{
+ return RNA_struct_property_is_set(ptr, "session_uuid") ||
+ RNA_struct_property_is_set(ptr, "name");
+}
+
+void WM_operator_properties_id_lookup(wmOperatorType *ot, const bool add_name_prop)
+{
+ PropertyRNA *prop;
+
+ if (add_name_prop) {
+ prop = RNA_def_string(ot->srna,
+ "name",
+ NULL,
+ MAX_ID_NAME - 2,
+ "Name",
+ "Name of the data-block to use by the operator");
+ RNA_def_property_flag(prop, (PropertyFlag)(PROP_SKIP_SAVE | PROP_HIDDEN));
+ }
+
+ prop = RNA_def_int(ot->srna,
+ "session_uuid",
+ 0,
+ INT32_MIN,
+ INT32_MAX,
+ "Session UUID",
+ "Session UUID of the data-block to use by the operator",
+ INT32_MIN,
+ INT32_MAX);
+ RNA_def_property_flag(prop, (PropertyFlag)(PROP_SKIP_SAVE | PROP_HIDDEN));
+}
+
static void wm_operator_properties_select_action_ex(wmOperatorType *ot,
int default_action,
const EnumPropertyItem *select_actions,
diff --git a/source/blender/windowmanager/intern/wm_operator_type.c b/source/blender/windowmanager/intern/wm_operator_type.c
index 8aa8469f0bc..d1c27504628 100644
--- a/source/blender/windowmanager/intern/wm_operator_type.c
+++ b/source/blender/windowmanager/intern/wm_operator_type.c
@@ -246,6 +246,27 @@ void WM_operatortype_last_properties_clear_all(void)
}
}
+void WM_operatortype_idname_visit_for_search(const bContext *UNUSED(C),
+ PointerRNA *UNUSED(ptr),
+ PropertyRNA *UNUSED(prop),
+ const char *UNUSED(edit_text),
+ StringPropertySearchVisitFunc visit_fn,
+ void *visit_user_data)
+{
+ GHashIterator gh_iter;
+ GHASH_ITER (gh_iter, global_ops_hash) {
+ wmOperatorType *ot = BLI_ghashIterator_getValue(&gh_iter);
+
+ char idname_py[OP_MAX_TYPENAME];
+ WM_operator_py_idname(idname_py, ot->idname);
+
+ StringPropertySearchVisitParams visit_params = {NULL};
+ visit_params.text = idname_py;
+ visit_params.info = ot->name;
+ visit_fn(visit_user_data, &visit_params);
+ }
+}
+
/** \} */
/* -------------------------------------------------------------------- */
diff --git a/source/blender/windowmanager/intern/wm_operators.c b/source/blender/windowmanager/intern/wm_operators.c
index b8107a49a4c..33c69a23558 100644
--- a/source/blender/windowmanager/intern/wm_operators.c
+++ b/source/blender/windowmanager/intern/wm_operators.c
@@ -106,47 +106,38 @@
/** \name Operator API
* \{ */
-void WM_operator_py_idname(char *to, const char *from)
+size_t WM_operator_py_idname(char *dst, const char *src)
{
- const char *sep = strstr(from, "_OT_");
+ const char *sep = strstr(src, "_OT_");
if (sep) {
- int ofs = (sep - from);
+ int ofs = (sep - src);
/* NOTE: we use ascii `tolower` instead of system `tolower`, because the
* latter depends on the locale, and can lead to `idname` mismatch. */
- memcpy(to, from, sizeof(char) * ofs);
- BLI_str_tolower_ascii(to, ofs);
+ memcpy(dst, src, sizeof(char) * ofs);
+ BLI_str_tolower_ascii(dst, ofs);
- to[ofs] = '.';
- BLI_strncpy(to + (ofs + 1), sep + 4, OP_MAX_TYPENAME - (ofs + 1));
- }
- else {
- /* should not happen but support just in case */
- BLI_strncpy(to, from, OP_MAX_TYPENAME);
+ dst[ofs] = '.';
+ return BLI_strncpy_rlen(dst + (ofs + 1), sep + 4, OP_MAX_TYPENAME - (ofs + 1)) + (ofs + 1);
}
+ /* Should not happen but support just in case. */
+ return BLI_strncpy_rlen(dst, src, OP_MAX_TYPENAME);
}
-void WM_operator_bl_idname(char *to, const char *from)
+size_t WM_operator_bl_idname(char *dst, const char *src)
{
- if (from) {
- const char *sep = strchr(from, '.');
-
- int from_len;
- if (sep && (from_len = strlen(from)) < OP_MAX_TYPENAME - 3) {
- const int ofs = (sep - from);
- memcpy(to, from, sizeof(char) * ofs);
- BLI_str_toupper_ascii(to, ofs);
- memcpy(to + ofs, "_OT_", 4);
- memcpy(to + (ofs + 4), sep + 1, (from_len - ofs));
- }
- else {
- /* should not happen but support just in case */
- BLI_strncpy(to, from, OP_MAX_TYPENAME);
- }
- }
- else {
- to[0] = 0;
+ const char *sep = strchr(src, '.');
+ int from_len;
+ if (sep && (from_len = strlen(src)) < OP_MAX_TYPENAME - 3) {
+ const int ofs = (sep - src);
+ memcpy(dst, src, sizeof(char) * ofs);
+ BLI_str_toupper_ascii(dst, ofs);
+ memcpy(dst + ofs, "_OT_", 4);
+ memcpy(dst + (ofs + 4), sep + 1, (from_len - ofs));
+ return (from_len - ofs) - 1;
}
+ /* Should not happen but support just in case. */
+ return BLI_strncpy_rlen(dst, src, OP_MAX_TYPENAME);
}
bool WM_operator_py_idname_ok_or_report(ReportList *reports,
@@ -1275,6 +1266,7 @@ ID *WM_operator_drop_load_path(struct bContext *C, wmOperator *op, const short i
{
Main *bmain = CTX_data_main(C);
ID *id = NULL;
+
/* check input variables */
if (RNA_struct_property_is_set(op->ptr, "filepath")) {
const bool is_relative_path = RNA_boolean_get(op->ptr, "relative_path");
@@ -1312,19 +1304,33 @@ ID *WM_operator_drop_load_path(struct bContext *C, wmOperator *op, const short i
}
}
}
+
+ return id;
}
- else if (RNA_struct_property_is_set(op->ptr, "name")) {
- char name[MAX_ID_NAME - 2];
- RNA_string_get(op->ptr, "name", name);
- id = BKE_libblock_find_name(bmain, idcode, name);
- if (!id) {
+
+ if (!WM_operator_properties_id_lookup_is_set(op->ptr)) {
+ return NULL;
+ }
+
+ /* Lookup an already existing ID. */
+ id = WM_operator_properties_id_lookup_from_name_or_session_uuid(bmain, op->ptr, idcode);
+
+ if (!id) {
+ /* Print error with the name if the name is available. */
+
+ if (RNA_struct_property_is_set(op->ptr, "name")) {
+ char name[MAX_ID_NAME - 2];
+ RNA_string_get(op->ptr, "name", name);
BKE_reportf(
op->reports, RPT_ERROR, "%s '%s' not found", BKE_idtype_idcode_to_name(idcode), name);
return NULL;
}
- id_us_plus(id);
+
+ BKE_reportf(op->reports, RPT_ERROR, "%s not found", BKE_idtype_idcode_to_name(idcode));
+ return NULL;
}
+ id_us_plus(id);
return id;
}
@@ -1868,7 +1874,14 @@ static void WM_OT_call_menu(wmOperatorType *ot)
ot->flag = OPTYPE_INTERNAL;
- RNA_def_string(ot->srna, "name", NULL, BKE_ST_MAXNAME, "Name", "Name of the menu");
+ PropertyRNA *prop;
+
+ prop = RNA_def_string(ot->srna, "name", NULL, BKE_ST_MAXNAME, "Name", "Name of the menu");
+ RNA_def_property_string_search_func_runtime(
+ prop,
+ WM_menutype_idname_visit_for_search,
+ /* Only a suggestion as menu items may be referenced from add-ons that have been disabled. */
+ (PROP_STRING_SEARCH_SORT | PROP_STRING_SEARCH_SUGGESTION));
}
static int wm_call_pie_menu_invoke(bContext *C, wmOperator *op, const wmEvent *event)
@@ -1900,7 +1913,14 @@ static void WM_OT_call_menu_pie(wmOperatorType *ot)
ot->flag = OPTYPE_INTERNAL;
- RNA_def_string(ot->srna, "name", NULL, BKE_ST_MAXNAME, "Name", "Name of the pie menu");
+ PropertyRNA *prop;
+
+ prop = RNA_def_string(ot->srna, "name", NULL, BKE_ST_MAXNAME, "Name", "Name of the pie menu");
+ RNA_def_property_string_search_func_runtime(
+ prop,
+ WM_menutype_idname_visit_for_search,
+ /* Only a suggestion as menu items may be referenced from add-ons that have been disabled. */
+ (PROP_STRING_SEARCH_SORT | PROP_STRING_SEARCH_SUGGESTION));
}
static int wm_call_panel_exec(bContext *C, wmOperator *op)
@@ -1936,6 +1956,11 @@ static void WM_OT_call_panel(wmOperatorType *ot)
PropertyRNA *prop;
prop = RNA_def_string(ot->srna, "name", NULL, BKE_ST_MAXNAME, "Name", "Name of the menu");
+ RNA_def_property_string_search_func_runtime(
+ prop,
+ WM_paneltype_idname_visit_for_search,
+ /* Only a suggestion as menu items may be referenced from add-ons that have been disabled. */
+ (PROP_STRING_SEARCH_SORT | PROP_STRING_SEARCH_SUGGESTION));
RNA_def_property_flag(prop, PROP_SKIP_SAVE);
prop = RNA_def_boolean(ot->srna, "keep_open", true, "Keep Open", "");
RNA_def_property_flag(prop, PROP_SKIP_SAVE);
@@ -2047,7 +2072,7 @@ static void WM_OT_quit_blender(wmOperatorType *ot)
static int wm_console_toggle_exec(bContext *UNUSED(C), wmOperator *UNUSED(op))
{
- setConsoleWindowState(GHOST_kConsoleWindowStateToggle);
+ GHOST_setConsoleWindowState(GHOST_kConsoleWindowStateToggle);
return OPERATOR_FINISHED;
}
@@ -3877,7 +3902,7 @@ static void gesture_box_modal_keymap(wmKeyConfig *keyconf)
WM_modalkeymap_assign(keymap, "VIEW3D_OT_clip_border");
WM_modalkeymap_assign(keymap, "VIEW3D_OT_render_border");
WM_modalkeymap_assign(keymap, "VIEW3D_OT_select_box");
- /* XXX TODO: zoom border should perhaps map rightmouse to zoom out instead of in+cancel */
+ /* XXX TODO: zoom border should perhaps map right-mouse to zoom out instead of in+cancel. */
WM_modalkeymap_assign(keymap, "VIEW3D_OT_zoom_border");
WM_modalkeymap_assign(keymap, "IMAGE_OT_render_border");
WM_modalkeymap_assign(keymap, "IMAGE_OT_view_zoom_border");
diff --git a/source/blender/windowmanager/intern/wm_panel_type.c b/source/blender/windowmanager/intern/wm_panel_type.c
index bfcc86c38e7..860b53c1071 100644
--- a/source/blender/windowmanager/intern/wm_panel_type.c
+++ b/source/blender/windowmanager/intern/wm_panel_type.c
@@ -65,3 +65,21 @@ void WM_paneltype_clear(void)
{
BLI_ghash_free(g_paneltypes_hash, NULL, NULL);
}
+
+void WM_paneltype_idname_visit_for_search(const bContext *UNUSED(C),
+ PointerRNA *UNUSED(ptr),
+ PropertyRNA *UNUSED(prop),
+ const char *UNUSED(edit_text),
+ StringPropertySearchVisitFunc visit_fn,
+ void *visit_user_data)
+{
+ GHashIterator gh_iter;
+ GHASH_ITER (gh_iter, g_paneltypes_hash) {
+ PanelType *pt = BLI_ghashIterator_getValue(&gh_iter);
+
+ StringPropertySearchVisitParams visit_params = {NULL};
+ visit_params.text = pt->idname;
+ visit_params.info = pt->label;
+ visit_fn(visit_user_data, &visit_params);
+ }
+}
diff --git a/source/blender/windowmanager/intern/wm_playanim.c b/source/blender/windowmanager/intern/wm_playanim.c
index 95879829d42..9c97b05f79b 100644
--- a/source/blender/windowmanager/intern/wm_playanim.c
+++ b/source/blender/windowmanager/intern/wm_playanim.c
@@ -33,6 +33,7 @@
#include "BLI_path_util.h"
#include "BLI_rect.h"
#include "BLI_string.h"
+#include "BLI_system.h"
#include "BLI_utildefines.h"
#include "IMB_colormanagement.h"
@@ -211,7 +212,7 @@ static void playanim_gl_matrix(void)
/* implementation */
static void playanim_event_qual_update(void)
{
- int val;
+ bool val;
/* Shift */
GHOST_GetModifierKeyState(g_WS.ghost_system, GHOST_kModifierKeyLeftShift, &val);
@@ -673,7 +674,7 @@ static void build_pict_list_ex(
*
* If set, all reads and writes on the resulting file descriptor will
* be performed directly to or from the user program buffer, provided
- * appropriate size and alignment restrictions are met. Refer to the
+ * appropriate size and alignment restrictions are met. Refer to the
* F_SETFL and F_DIOINFO commands in the fcntl(2) manual entry for
* information about how to determine the alignment constraints.
* O_DIRECT is a Silicon Graphics extension and is only supported on
@@ -870,7 +871,7 @@ static void change_frame(PlayState *ps)
ps->need_frame_update = false;
}
-static int ghost_event_proc(GHOST_EventHandle evt, GHOST_TUserDataPtr ps_void)
+static bool ghost_event_proc(GHOST_EventHandle evt, GHOST_TUserDataPtr ps_void)
{
PlayState *ps = (PlayState *)ps_void;
const GHOST_TEventType type = GHOST_GetEventType(evt);
@@ -901,7 +902,7 @@ static int ghost_event_proc(GHOST_EventHandle evt, GHOST_TUserDataPtr ps_void)
default:
break;
}
- return 1;
+ return true;
}
if (ps->wait2 && ps->stopped == false) {
@@ -1334,7 +1335,7 @@ static int ghost_event_proc(GHOST_EventHandle evt, GHOST_TUserDataPtr ps_void)
break;
}
- return 1;
+ return true;
}
static void playanim_window_open(const char *title, int posx, int posy, int sizex, int sizey)
@@ -1536,6 +1537,8 @@ static char *wm_main_playanim_intern(int argc, const char **argv)
GHOST_EventConsumerHandle consumer = GHOST_CreateEventConsumer(ghost_event_proc, &ps);
+ GHOST_SetBacktraceHandler((GHOST_TBacktraceFn)BLI_system_backtrace);
+
g_WS.ghost_system = GHOST_CreateSystem();
GHOST_AddEventConsumer(g_WS.ghost_system, consumer);
@@ -1552,6 +1555,7 @@ static char *wm_main_playanim_intern(int argc, const char **argv)
/* initialize the font */
BLF_init();
+ BLF_load_font_stack();
ps.fontid = BLF_load_mono_default(false);
BLF_size(ps.fontid, 11.0f, 72);
diff --git a/source/blender/windowmanager/intern/wm_toolsystem.c b/source/blender/windowmanager/intern/wm_toolsystem.c
index 8c7cf86d050..984a8ef41d0 100644
--- a/source/blender/windowmanager/intern/wm_toolsystem.c
+++ b/source/blender/windowmanager/intern/wm_toolsystem.c
@@ -636,7 +636,8 @@ bToolRef *WM_toolsystem_ref_set_by_id_ex(
/* Some contexts use the current space type (image editor for e.g.),
* ensure this is set correctly or there is no area. */
#ifndef NDEBUG
- {
+ /* Exclude this check for some space types where the space type isn't used. */
+ if ((1 << tkey->space_type) & WM_TOOLSYSTEM_SPACE_MASK_MODE_FROM_SPACE) {
ScrArea *area = CTX_wm_area(C);
BLI_assert(area == NULL || area->spacetype == tkey->space_type);
}
diff --git a/source/blender/windowmanager/intern/wm_uilist_type.c b/source/blender/windowmanager/intern/wm_uilist_type.c
index 88eacf9013b..6dd64b89eb6 100644
--- a/source/blender/windowmanager/intern/wm_uilist_type.c
+++ b/source/blender/windowmanager/intern/wm_uilist_type.c
@@ -20,7 +20,6 @@
#include "UI_interface.h"
#include "BLI_ghash.h"
-#include "BLI_listbase.h"
#include "BLI_string.h"
#include "BLI_utildefines.h"
diff --git a/source/blender/windowmanager/intern/wm_window.c b/source/blender/windowmanager/intern/wm_window.c
index 382a37e09e5..91ec45da6d4 100644
--- a/source/blender/windowmanager/intern/wm_window.c
+++ b/source/blender/windowmanager/intern/wm_window.c
@@ -23,6 +23,7 @@
#include "BLI_blenlib.h"
#include "BLI_math.h"
+#include "BLI_system.h"
#include "BLI_utildefines.h"
#include "BLT_translation.h"
@@ -578,6 +579,9 @@ static void wm_window_ghostwindow_add(wmWindowManager *wm,
wm_window_swap_buffers(win);
+ /* Clear double buffer to avoids flickering of new windows on certain drivers. (See T97600) */
+ GPU_clear_color(0.55f, 0.55f, 0.55f, 1.0f);
+
// GHOST_SetWindowState(ghostwin, GHOST_kWindowStateModified);
}
else {
@@ -979,7 +983,7 @@ static int query_qual(modifierKeyType qual)
break;
}
- int val = 0;
+ bool val = false;
GHOST_GetModifierKeyState(g_system, left, &val);
if (!val) {
GHOST_GetModifierKeyState(g_system, right, &val);
@@ -1049,7 +1053,7 @@ void wm_window_reset_drawable(void)
*
* Mouse coordinate conversion happens here.
*/
-static int ghost_event_proc(GHOST_EventHandle evt, GHOST_TUserDataPtr C_void_ptr)
+static bool ghost_event_proc(GHOST_EventHandle evt, GHOST_TUserDataPtr C_void_ptr)
{
bContext *C = C_void_ptr;
wmWindowManager *wm = CTX_wm_manager(C);
@@ -1087,17 +1091,17 @@ static int ghost_event_proc(GHOST_EventHandle evt, GHOST_TUserDataPtr C_void_ptr
* but it should return if WM didn't initialize yet.
* Can happen on file read (especially full size window). */
if ((wm->initialized & WM_WINDOW_IS_INIT) == 0) {
- return 1;
+ return true;
}
if (!ghostwin) {
/* XXX: should be checked, why are we getting an event here, and what is it? */
puts("<!> event has no window");
- return 1;
+ return true;
}
if (!GHOST_ValidWindow(g_system, ghostwin)) {
/* XXX: should be checked, why are we getting an event here, and what is it? */
puts("<!> event has invalid window");
- return 1;
+ return true;
}
wmWindow *win = GHOST_GetWindowUserData(ghostwin);
@@ -1440,7 +1444,7 @@ static int ghost_event_proc(GHOST_EventHandle evt, GHOST_TUserDataPtr C_void_ptr
}
}
}
- return 1;
+ return true;
}
/**
@@ -1540,6 +1544,8 @@ void wm_ghost_init(bContext *C)
consumer = GHOST_CreateEventConsumer(ghost_event_proc, C);
}
+ GHOST_SetBacktraceHandler((GHOST_TBacktraceFn)BLI_system_backtrace);
+
g_system = GHOST_CreateSystem();
GHOST_Debug debug = {0};
@@ -1866,11 +1872,10 @@ wmWindow *WM_window_find_under_cursor(wmWindow *win, const int mval[2], int r_mv
return NULL;
}
- wmWindow *r_win = GHOST_GetWindowUserData(ghostwin);
- wm_cursor_position_from_ghost(r_win, &tmp[0], &tmp[1]);
+ wmWindow *win_other = GHOST_GetWindowUserData(ghostwin);
+ wm_cursor_position_from_ghost(win_other, &tmp[0], &tmp[1]);
copy_v2_v2_int(r_mval, tmp);
-
- return r_win;
+ return win_other;
}
void WM_window_pixel_sample_read(const wmWindowManager *wm,
diff --git a/source/blender/windowmanager/xr/intern/wm_xr_action.c b/source/blender/windowmanager/xr/intern/wm_xr_action.c
index 6750e7a7d77..a83415c98af 100644
--- a/source/blender/windowmanager/xr/intern/wm_xr_action.c
+++ b/source/blender/windowmanager/xr/intern/wm_xr_action.c
@@ -391,13 +391,20 @@ void WM_xr_action_binding_destroy(wmXrData *xr,
xr->runtime->context, action_set_name, 1, &action_name, &profile_path);
}
-bool WM_xr_active_action_set_set(wmXrData *xr, const char *action_set_name)
+bool WM_xr_active_action_set_set(wmXrData *xr, const char *action_set_name, bool delayed)
{
wmXrActionSet *action_set = action_set_find(xr, action_set_name);
if (!action_set) {
return false;
}
+ if (delayed) {
+ /* Save name to activate action set later, before next actions sync
+ * (see #wm_xr_session_actions_update()). */
+ strcpy(xr->runtime->session_state.active_action_set_next, action_set_name);
+ return true;
+ }
+
{
/* Clear any active modal/haptic actions. */
wmXrActionSet *active_action_set = xr->runtime->session_state.active_action_set;
diff --git a/source/blender/windowmanager/xr/intern/wm_xr_intern.h b/source/blender/windowmanager/xr/intern/wm_xr_intern.h
index 3fc1f362541..bb24514457d 100644
--- a/source/blender/windowmanager/xr/intern/wm_xr_intern.h
+++ b/source/blender/windowmanager/xr/intern/wm_xr_intern.h
@@ -54,9 +54,11 @@ typedef struct wmXrSessionState {
ListBase controllers; /* #wmXrController */
/** The currently active action set that will be updated on calls to
- * wm_xr_session_actions_update(). If NULL, all action sets will be treated as active and
+ * #wm_xr_session_actions_update(). If NULL, all action sets will be treated as active and
* updated. */
struct wmXrActionSet *active_action_set;
+ /* Name of the action set (if any) to activate before the next actions sync. */
+ char active_action_set_next[64]; /* MAX_NAME */
} wmXrSessionState;
typedef struct wmXrRuntimeData {
diff --git a/source/blender/windowmanager/xr/intern/wm_xr_operators.c b/source/blender/windowmanager/xr/intern/wm_xr_operators.c
index 3c090423c41..3f0c72a4a05 100644
--- a/source/blender/windowmanager/xr/intern/wm_xr_operators.c
+++ b/source/blender/windowmanager/xr/intern/wm_xr_operators.c
@@ -731,8 +731,9 @@ static void wm_xr_raycast(Scene *scene,
sctx,
depsgraph,
NULL,
- &(const struct SnapObjectParams){
- .snap_select = (selectable_only ? SNAP_SELECTABLE : SNAP_ALL)},
+ &(const struct SnapObjectParams){.snap_target_select = (selectable_only ?
+ SCE_SNAP_TARGET_ONLY_SELECTABLE :
+ SCE_SNAP_TARGET_ALL)},
origin,
direction,
ray_dist,
diff --git a/source/blender/windowmanager/xr/intern/wm_xr_session.c b/source/blender/windowmanager/xr/intern/wm_xr_session.c
index 0a76fd0a25f..a4d2a65830f 100644
--- a/source/blender/windowmanager/xr/intern/wm_xr_session.c
+++ b/source/blender/windowmanager/xr/intern/wm_xr_session.c
@@ -1025,6 +1025,10 @@ static wmXrActionData *wm_xr_session_event_create(const char *action_set_name,
wmXrActionData *data = MEM_callocN(sizeof(wmXrActionData), __func__);
strcpy(data->action_set, action_set_name);
strcpy(data->action, action->name);
+ strcpy(data->user_path, action->subaction_paths[subaction_idx]);
+ if (bimanual) {
+ strcpy(data->user_path_other, action->subaction_paths[subaction_idx_other]);
+ }
data->type = action->type;
switch (action->type) {
@@ -1171,7 +1175,6 @@ void wm_xr_session_actions_update(wmWindowManager *wm)
XrSessionSettings *settings = &xr->session_settings;
GHOST_XrContextHandle xr_context = xr->runtime->context;
wmXrSessionState *state = &xr->runtime->session_state;
- wmXrActionSet *active_action_set = state->active_action_set;
if (state->is_navigation_dirty) {
memcpy(&state->nav_pose_prev, &state->nav_pose, sizeof(state->nav_pose_prev));
@@ -1188,6 +1191,13 @@ void wm_xr_session_actions_update(wmWindowManager *wm)
&state->viewer_pose, settings->base_scale * state->nav_scale, state->viewer_viewmat);
}
+ /* Set active action set if requested previously. */
+ if (state->active_action_set_next[0]) {
+ WM_xr_active_action_set_set(xr, state->active_action_set_next, false);
+ state->active_action_set_next[0] = '\0';
+ }
+ wmXrActionSet *active_action_set = state->active_action_set;
+
const bool synced = GHOST_XrSyncActions(xr_context,
active_action_set ? active_action_set->name : NULL);
if (!synced) {