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

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
path: root/source
diff options
context:
space:
mode:
Diffstat (limited to 'source')
-rw-r--r--source/CMakeLists.txt5
-rw-r--r--source/blender/CMakeLists.txt36
-rw-r--r--source/blender/blenfont/intern/blf_font.c2
-rw-r--r--source/blender/blenfont/intern/blf_internal_types.h7
-rw-r--r--source/blender/blenkernel/BKE_DerivedMesh.h17
-rw-r--r--source/blender/blenkernel/BKE_attribute.h3
-rw-r--r--source/blender/blenkernel/BKE_blender_version.h6
-rw-r--r--source/blender/blenkernel/BKE_bvhutils.h21
-rw-r--r--source/blender/blenkernel/BKE_camera.h10
-rw-r--r--source/blender/blenkernel/BKE_colortools.h30
-rw-r--r--source/blender/blenkernel/BKE_constraint.h2
-rw-r--r--source/blender/blenkernel/BKE_curves.hh63
-rw-r--r--source/blender/blenkernel/BKE_curves_utils.hh26
-rw-r--r--source/blender/blenkernel/BKE_customdata.h44
-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.h2
-rw-r--r--source/blender/blenkernel/BKE_geometry_fields.hh10
-rw-r--r--source/blender/blenkernel/BKE_geometry_set.hh29
-rw-r--r--source/blender/blenkernel/BKE_global.h1
-rw-r--r--source/blender/blenkernel/BKE_icons.h9
-rw-r--r--source/blender/blenkernel/BKE_image.h12
-rw-r--r--source/blender/blenkernel/BKE_image_format.h2
-rw-r--r--source/blender/blenkernel/BKE_image_save.h16
-rw-r--r--source/blender/blenkernel/BKE_lib_override.h10
-rw-r--r--source/blender/blenkernel/BKE_lib_principle_properties.h2
-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_tangent.h2
-rw-r--r--source/blender/blenkernel/BKE_modifier.h11
-rw-r--r--source/blender/blenkernel/BKE_multires.h2
-rw-r--r--source/blender/blenkernel/BKE_node.h36
-rw-r--r--source/blender/blenkernel/BKE_node_runtime.hh89
-rw-r--r--source/blender/blenkernel/BKE_paint.h3
-rw-r--r--source/blender/blenkernel/BKE_particle.h2
-rw-r--r--source/blender/blenkernel/BKE_pbvh_pixels.hh27
-rw-r--r--source/blender/blenkernel/BKE_shrinkwrap.h2
-rw-r--r--source/blender/blenkernel/BKE_sound.h2
-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.h2
-rw-r--r--source/blender/blenkernel/BKE_subsurf.h21
-rw-r--r--source/blender/blenkernel/BKE_tracking.h153
-rw-r--r--source/blender/blenkernel/CMakeLists.txt7
-rw-r--r--source/blender/blenkernel/intern/DerivedMesh.cc15
-rw-r--r--source/blender/blenkernel/intern/anim_sys.c2
-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)102
-rw-r--r--source/blender/blenkernel/intern/attribute_access.cc106
-rw-r--r--source/blender/blenkernel/intern/attribute_access_intern.hh16
-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.c6
-rw-r--r--source/blender/blenkernel/intern/brush.c1
-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/colortools.c74
-rw-r--r--source/blender/blenkernel/intern/crazyspace.c2
-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.cc48
-rw-r--r--source/blender/blenkernel/intern/curve_poly.cc4
-rw-r--r--source/blender/blenkernel/intern/curve_to_mesh_convert.cc19
-rw-r--r--source/blender/blenkernel/intern/curves.cc76
-rw-r--r--source/blender/blenkernel/intern/curves_geometry.cc152
-rw-r--r--source/blender/blenkernel/intern/curves_utils.cc38
-rw-r--r--source/blender/blenkernel/intern/customdata.cc173
-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.c5
-rw-r--r--source/blender/blenkernel/intern/editmesh.c1
-rw-r--r--source/blender/blenkernel/intern/fcurve.c99
-rw-r--r--source/blender/blenkernel/intern/fluid.c26
-rw-r--r--source/blender/blenkernel/intern/geometry_component_curve.cc28
-rw-r--r--source/blender/blenkernel/intern/geometry_component_curves.cc77
-rw-r--r--source/blender/blenkernel/intern/geometry_component_instances.cc14
-rw-r--r--source/blender/blenkernel/intern/geometry_component_mesh.cc12
-rw-r--r--source/blender/blenkernel/intern/geometry_component_pointcloud.cc2
-rw-r--r--source/blender/blenkernel/intern/geometry_set.cc2
-rw-r--r--source/blender/blenkernel/intern/gpencil.c2
-rw-r--r--source/blender/blenkernel/intern/icons.cc75
-rw-r--r--source/blender/blenkernel/intern/idprop.c2
-rw-r--r--source/blender/blenkernel/intern/idprop_utils.c2
-rw-r--r--source/blender/blenkernel/intern/image.cc201
-rw-r--r--source/blender/blenkernel/intern/image_format.cc5
-rw-r--r--source/blender/blenkernel/intern/image_gpu.cc185
-rw-r--r--source/blender/blenkernel/intern/image_save.cc250
-rw-r--r--source/blender/blenkernel/intern/lib_id.c10
-rw-r--r--source/blender/blenkernel/intern/lib_override.c73
-rw-r--r--source/blender/blenkernel/intern/lib_override_proxy_conversion.c2
-rw-r--r--source/blender/blenkernel/intern/lib_remap.c5
-rw-r--r--source/blender/blenkernel/intern/main.c6
-rw-r--r--source/blender/blenkernel/intern/material.c8
-rw-r--r--source/blender/blenkernel/intern/mesh.cc67
-rw-r--r--source/blender/blenkernel/intern/mesh_convert.cc29
-rw-r--r--source/blender/blenkernel/intern/mesh_evaluate.cc86
-rw-r--r--source/blender/blenkernel/intern/mesh_remesh_voxel.cc2
-rw-r--r--source/blender/blenkernel/intern/mesh_tangent.c29
-rw-r--r--source/blender/blenkernel/intern/mesh_tessellate.c16
-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_util.c2
-rw-r--r--source/blender/blenkernel/intern/node.cc65
-rw-r--r--source/blender/blenkernel/intern/node_tree_update.cc94
-rw-r--r--source/blender/blenkernel/intern/object.cc4
-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.c9
-rw-r--r--source/blender/blenkernel/intern/particle.c41
-rw-r--r--source/blender/blenkernel/intern/particle_distribute.c15
-rw-r--r--source/blender/blenkernel/intern/particle_system.c5
-rw-r--r--source/blender/blenkernel/intern/pbvh_intern.h15
-rw-r--r--source/blender/blenkernel/intern/pbvh_pixels.cc13
-rw-r--r--source/blender/blenkernel/intern/pointcache.c14
-rw-r--r--source/blender/blenkernel/intern/pointcloud.cc20
-rw-r--r--source/blender/blenkernel/intern/sound.c9
-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_converter_mesh.c20
-rw-r--r--source/blender/blenkernel/intern/subdiv_eval.c12
-rw-r--r--source/blender/blenkernel/intern/subsurf_ccg.c145
-rw-r--r--source/blender/blenkernel/intern/tracking.c223
-rw-r--r--source/blender/blenkernel/intern/tracking_plane_tracker.c6
-rw-r--r--source/blender/blenkernel/intern/unit.c2
-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_bitmap.h2
-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_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_rotation.h1
-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.h2
-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_vector.hh4
-rw-r--r--source/blender/blenlib/BLI_vector_set.hh4
-rw-r--r--source/blender/blenlib/BLI_virtual_array.hh4
-rw-r--r--source/blender/blenlib/CMakeLists.txt6
-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/fileops.c86
-rw-r--r--source/blender/blenlib/intern/hash_md5.c2
-rw-r--r--source/blender/blenlib/intern/listbase.c10
-rw-r--r--source/blender/blenlib/intern/math_color.c4
-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/scanfill.c2
-rw-r--r--source/blender/blenlib/intern/string.c2
-rw-r--r--source/blender/blenlib/intern/string_cursor_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_float3x3_test.cc119
-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.c21
-rw-r--r--source/blender/blenloader/intern/undofile.c10
-rw-r--r--source/blender/blenloader/intern/versioning_280.c2
-rw-r--r--source/blender/blenloader/intern/versioning_290.c11
-rw-r--r--source/blender/blenloader/intern/versioning_300.c294
-rw-r--r--source/blender/blenloader/intern/writefile.c34
-rw-r--r--source/blender/bmesh/bmesh_class.h16
-rw-r--r--source/blender/bmesh/intern/bmesh_core.c2
-rw-r--r--source/blender/bmesh/intern/bmesh_mesh_convert.cc3
-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/tools/bmesh_bevel.c2
-rw-r--r--source/blender/compositor/CMakeLists.txt4
-rw-r--r--source/blender/compositor/intern/COM_Converter.cc24
-rw-r--r--source/blender/compositor/intern/COM_Debug.cc8
-rw-r--r--source/blender/compositor/nodes/COM_CombineColorNode.cc59
-rw-r--r--source/blender/compositor/nodes/COM_CombineColorNode.h39
-rw-r--r--source/blender/compositor/nodes/COM_CombineColorNodeLegacy.cc78
-rw-r--r--source/blender/compositor/nodes/COM_CombineColorNodeLegacy.h56
-rw-r--r--source/blender/compositor/nodes/COM_SeparateColorNode.cc59
-rw-r--r--source/blender/compositor/nodes/COM_SeparateColorNode.h39
-rw-r--r--source/blender/compositor/nodes/COM_SeparateColorNodeLegacy.cc110
-rw-r--r--source/blender/compositor/nodes/COM_SeparateColorNodeLegacy.h56
-rw-r--r--source/blender/compositor/operations/COM_ConvertOperation.cc62
-rw-r--r--source/blender/compositor/operations/COM_ConvertOperation.h20
-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/depsgraph/CMakeLists.txt2
-rw-r--r--source/blender/depsgraph/DEG_depsgraph_query.h2
-rw-r--r--source/blender/depsgraph/intern/builder/deg_builder_nodes.cc4
-rw-r--r--source/blender/depsgraph/intern/builder/deg_builder_relations.cc83
-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.txt16
-rw-r--r--source/blender/draw/DRW_select_buffer.h8
-rw-r--r--source/blender/draw/engines/eevee/eevee_cryptomatte.c2
-rw-r--r--source/blender/draw/engines/eevee/eevee_lightcache.c14
-rw-r--r--source/blender/draw/engines/eevee/eevee_lookdev.c2
-rw-r--r--source/blender/draw/engines/eevee/eevee_private.h4
-rw-r--r--source/blender/draw/engines/eevee/eevee_shaders_extra.cc4
-rw-r--r--source/blender/draw/engines/eevee/shaders/closure_type_lib.glsl2
-rw-r--r--source/blender/draw/engines/eevee/shaders/shadow_vert.glsl24
-rw-r--r--source/blender/draw/engines/eevee/shaders/surface_lib.glsl2
-rw-r--r--source/blender/draw/engines/eevee/shaders/surface_vert.glsl24
-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.glsl2
-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.hh8
-rw-r--r--source/blender/draw/engines/eevee_next/eevee_engine.cc35
-rw-r--r--source/blender/draw/engines/eevee_next/eevee_instance.cc33
-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.hh51
-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.cc19
-rw-r--r--source/blender/draw/engines/eevee_next/eevee_shader.hh6
-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.hh3
-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.cc38
-rw-r--r--source/blender/draw/engines/eevee_next/eevee_view.hh12
-rw-r--r--source/blender/draw/engines/eevee_next/eevee_world.cc12
-rw-r--r--source/blender/draw/engines/eevee_next/eevee_world.hh2
-rw-r--r--source/blender/draw/engines/eevee_next/shaders/eevee_attributes_lib.glsl25
-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.glsl14
-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_surf_depth_frag.glsl13
-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.hh8
-rw-r--r--source/blender/draw/engines/eevee_next/shaders/infos/eevee_velocity_info.hh55
-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/overlay/overlay_edit_uv.c2
-rw-r--r--source/blender/draw/engines/overlay/overlay_gpencil.c8
-rw-r--r--source/blender/draw/engines/overlay/shaders/infos/extra_info.hh2
-rw-r--r--source/blender/draw/engines/overlay/shaders/infos/volume_info.hh2
-rw-r--r--source/blender/draw/engines/overlay/shaders/infos/wireframe_info.hh2
-rw-r--r--source/blender/draw/engines/overlay/shaders/outline_detect_frag.glsl2
-rw-r--r--source/blender/draw/engines/select/shaders/infos/select_id_info.hh2
-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_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.h13
-rw-r--r--source/blender/draw/intern/draw_attributes.cc112
-rw-r--r--source/blender/draw/intern/draw_attributes.h60
-rw-r--r--source/blender/draw/intern/draw_cache.c3
-rw-r--r--source/blender/draw/intern/draw_cache_extract.h15
-rw-r--r--source/blender/draw/intern/draw_cache_extract_mesh.cc8
-rw-r--r--source/blender/draw/intern/draw_cache_impl.h1
-rw-r--r--source/blender/draw/intern/draw_cache_impl_curve.cc2
-rw-r--r--source/blender/draw/intern/draw_cache_impl_curves.cc299
-rw-r--r--source/blender/draw/intern/draw_cache_impl_mesh.c157
-rw-r--r--source/blender/draw/intern/draw_cache_impl_particles.c54
-rw-r--r--source/blender/draw/intern/draw_cache_impl_subdivision.cc59
-rw-r--r--source/blender/draw/intern/draw_common.h6
-rw-r--r--source/blender/draw/intern/draw_curves.cc220
-rw-r--r--source/blender/draw/intern/draw_curves_private.h29
-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.c18
-rw-r--r--source/blender/draw/intern/draw_manager.h6
-rw-r--r--source/blender/draw/intern/draw_manager_data.c40
-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.h8
-rw-r--r--source/blender/draw/intern/mesh_extractors/extract_mesh.h2
-rw-r--r--source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_attributes.cc7
-rw-r--r--source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_edituv_stretch_angle.cc6
-rw-r--r--source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_fdots_uv.cc4
-rw-r--r--source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_orco.cc71
-rw-r--r--source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_pos_nor.cc20
-rw-r--r--source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_sculpt_data.cc10
-rw-r--r--source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_select_idx.cc2
-rw-r--r--source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_tan.cc5
-rw-r--r--source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_uv.cc3
-rw-r--r--source/blender/draw/intern/shaders/common_globals_lib.glsl2
-rw-r--r--source/blender/draw/intern/shaders/common_hair_lib.glsl4
-rw-r--r--source/blender/draw/intern/shaders/common_subdiv_patch_evaluation_comp.glsl56
-rw-r--r--source/blender/draw/intern/shaders/draw_object_infos_info.hh4
-rw-r--r--source/blender/editors/animation/anim_channels_defines.c5
-rw-r--r--source/blender/editors/animation/anim_channels_edit.c5
-rw-r--r--source/blender/editors/animation/anim_markers.c4
-rw-r--r--source/blender/editors/animation/anim_ops.c5
-rw-r--r--source/blender/editors/animation/keyframes_draw.c38
-rw-r--r--source/blender/editors/animation/keyframing.c4
-rw-r--r--source/blender/editors/animation/keyingsets.c66
-rw-r--r--source/blender/editors/armature/armature_edit.c7
-rw-r--r--source/blender/editors/armature/armature_skinning.c1
-rw-r--r--source/blender/editors/curve/CMakeLists.txt2
-rw-r--r--source/blender/editors/curves/CMakeLists.txt4
-rw-r--r--source/blender/editors/curves/intern/curves_add.cc2
-rw-r--r--source/blender/editors/curves/intern/curves_ops.cc140
-rw-r--r--source/blender/editors/datafiles/CMakeLists.txt3
-rw-r--r--source/blender/editors/geometry/geometry_attributes.cc14
-rw-r--r--source/blender/editors/gizmo_library/gizmo_draw_utils.c2
-rw-r--r--source/blender/editors/gizmo_library/gizmo_types/button2d_gizmo.c2
-rw-r--r--source/blender/editors/gizmo_library/gizmo_types/dial3d_gizmo.c2
-rw-r--r--source/blender/editors/gizmo_library/gizmo_types/move3d_gizmo.c2
-rw-r--r--source/blender/editors/gpencil/gpencil_interpolate.c17
-rw-r--r--source/blender/editors/gpencil/gpencil_sculpt_paint.c166
-rw-r--r--source/blender/editors/gpencil/gpencil_utils.c5
-rw-r--r--source/blender/editors/include/ED_anim_api.h2
-rw-r--r--source/blender/editors/include/ED_keyframing.h13
-rw-r--r--source/blender/editors/include/ED_mesh.h16
-rw-r--r--source/blender/editors/include/ED_object.h12
-rw-r--r--source/blender/editors/include/ED_scene.h5
-rw-r--r--source/blender/editors/include/ED_screen.h4
-rw-r--r--source/blender/editors/include/ED_uvedit.h12
-rw-r--r--source/blender/editors/include/ED_view3d.h29
-rw-r--r--source/blender/editors/include/UI_icons.h2
-rw-r--r--source/blender/editors/include/UI_interface.h37
-rw-r--r--source/blender/editors/include/UI_interface_icons.h2
-rw-r--r--source/blender/editors/interface/interface.cc73
-rw-r--r--source/blender/editors/interface/interface_handlers.c225
-rw-r--r--source/blender/editors/interface/interface_intern.h20
-rw-r--r--source/blender/editors/interface/interface_layout.c55
-rw-r--r--source/blender/editors/interface/interface_ops.c18
-rw-r--r--source/blender/editors/interface/interface_region_search.cc37
-rw-r--r--source/blender/editors/interface/interface_style.cc2
-rw-r--r--source/blender/editors/interface/interface_templates.c20
-rw-r--r--source/blender/editors/interface/interface_utils.cc166
-rw-r--r--source/blender/editors/interface/interface_widgets.c461
-rw-r--r--source/blender/editors/interface/view2d.cc21
-rw-r--r--source/blender/editors/interface/view2d_gizmo_navigate.cc7
-rw-r--r--source/blender/editors/io/io_alembic.c3
-rw-r--r--source/blender/editors/io/io_cache.c18
-rw-r--r--source/blender/editors/io/io_obj.c8
-rw-r--r--source/blender/editors/io/io_usd.c17
-rw-r--r--source/blender/editors/mask/mask_add.c4
-rw-r--r--source/blender/editors/mask/mask_query.c4
-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)170
-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_knife.c370
-rw-r--r--source/blender/editors/mesh/editmesh_select_similar.c8
-rw-r--r--source/blender/editors/mesh/editmesh_utils.c2
-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.h10
-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.cc131
-rw-r--r--source/blender/editors/object/object_bake_api.c8
-rw-r--r--source/blender/editors/object/object_constraint.c4
-rw-r--r--source/blender/editors/object/object_data_transfer.c11
-rw-r--r--source/blender/editors/object/object_edit.c24
-rw-r--r--source/blender/editors/object/object_modes.c7
-rw-r--r--source/blender/editors/object/object_modifier.cc33
-rw-r--r--source/blender/editors/object/object_relations.c139
-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/screen_edit.c2
-rw-r--r--source/blender/editors/screen/screen_ops.c4
-rw-r--r--source/blender/editors/sculpt_paint/CMakeLists.txt2
-rw-r--r--source/blender/editors/sculpt_paint/curves_sculpt_add.cc237
-rw-r--r--source/blender/editors/sculpt_paint/curves_sculpt_brush.cc (renamed from source/blender/editors/sculpt_paint/curves_sculpt_3d_brush.cc)96
-rw-r--r--source/blender/editors/sculpt_paint/curves_sculpt_comb.cc109
-rw-r--r--source/blender/editors/sculpt_paint/curves_sculpt_delete.cc213
-rw-r--r--source/blender/editors/sculpt_paint/curves_sculpt_grow_shrink.cc251
-rw-r--r--source/blender/editors/sculpt_paint/curves_sculpt_intern.hh33
-rw-r--r--source/blender/editors/sculpt_paint/curves_sculpt_ops.cc51
-rw-r--r--source/blender/editors/sculpt_paint/curves_sculpt_snake_hook.cc107
-rw-r--r--source/blender/editors/sculpt_paint/paint_image_proj.c201
-rw-r--r--source/blender/editors/sculpt_paint/paint_vertex.cc8
-rw-r--r--source/blender/editors/sculpt_paint/sculpt.c43
-rw-r--r--source/blender/editors/sculpt_paint/sculpt_face_set.c35
-rw-r--r--source/blender/editors/sculpt_paint/sculpt_intern.h6
-rw-r--r--source/blender/editors/sculpt_paint/sculpt_ops.c21
-rw-r--r--source/blender/editors/sculpt_paint/sculpt_paint_image.cc86
-rw-r--r--source/blender/editors/sculpt_paint/sculpt_undo.c2
-rw-r--r--source/blender/editors/space_clip/clip_buttons.c6
-rw-r--r--source/blender/editors/space_clip/clip_intern.h6
-rw-r--r--source/blender/editors/space_clip/space_clip.c167
-rw-r--r--source/blender/editors/space_clip/tracking_ops.c367
-rw-r--r--source/blender/editors/space_clip/tracking_select.c83
-rw-r--r--source/blender/editors/space_file/filelist.c20
-rw-r--r--source/blender/editors/space_file/fsmenu.c8
-rw-r--r--source/blender/editors/space_file/fsmenu.h4
-rw-r--r--source/blender/editors/space_image/image_ops.c369
-rw-r--r--source/blender/editors/space_image/image_undo.c2
-rw-r--r--source/blender/editors/space_image/space_image.c2
-rw-r--r--source/blender/editors/space_nla/nla_buttons.c1
-rw-r--r--source/blender/editors/space_nla/nla_channels.c116
-rw-r--r--source/blender/editors/space_node/drawnode.cc45
-rw-r--r--source/blender/editors/space_node/node_add.cc104
-rw-r--r--source/blender/editors/space_node/node_context_path.cc4
-rw-r--r--source/blender/editors/space_node/node_draw.cc20
-rw-r--r--source/blender/editors/space_node/node_edit.cc179
-rw-r--r--source/blender/editors/space_node/node_intern.hh16
-rw-r--r--source/blender/editors/space_node/node_relationships.cc2
-rw-r--r--source/blender/editors/space_node/node_select.cc2
-rw-r--r--source/blender/editors/space_node/space_node.cc14
-rw-r--r--source/blender/editors/space_outliner/CMakeLists.txt5
-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.cc559
-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.cc46
-rw-r--r--source/blender/editors/space_outliner/outliner_tools.cc491
-rw-r--r--source/blender/editors/space_outliner/outliner_tree.cc7
-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.cc3
-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.cc5
-rw-r--r--source/blender/editors/space_outliner/tree/tree_element.cc40
-rw-r--r--source/blender/editors/space_outliner/tree/tree_element.hh17
-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.cc24
-rw-r--r--source/blender/editors/space_outliner/tree/tree_element_overrides.hh4
-rw-r--r--source/blender/editors/space_outliner/tree/tree_iterator.cc58
-rw-r--r--source/blender/editors/space_outliner/tree/tree_iterator.hh35
-rw-r--r--source/blender/editors/space_sequencer/CMakeLists.txt4
-rw-r--r--source/blender/editors/space_sequencer/sequencer_add.c127
-rw-r--r--source/blender/editors/space_sequencer/sequencer_channels_draw.c4
-rw-r--r--source/blender/editors/space_sequencer/sequencer_draw.c17
-rw-r--r--source/blender/editors/space_sequencer/sequencer_edit.c196
-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_thumbnails.c4
-rw-r--r--source/blender/editors/space_sequencer/sequencer_view.c2
-rw-r--r--source/blender/editors/space_spreadsheet/space_spreadsheet.cc2
-rw-r--r--source/blender/editors/space_spreadsheet/spreadsheet_data_source_geometry.cc22
-rw-r--r--source/blender/editors/space_spreadsheet/spreadsheet_dataset_draw.cc4
-rw-r--r--source/blender/editors/space_spreadsheet/spreadsheet_ops.cc8
-rw-r--r--source/blender/editors/space_spreadsheet/spreadsheet_row_filter.cc2
-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/view3d_cursor_snap.c1
-rw-r--r--source/blender/editors/space_view3d/view3d_edit.c29
-rw-r--r--source/blender/editors/space_view3d/view3d_gizmo_tool_generic.c2
-rw-r--r--source/blender/editors/space_view3d/view3d_project.c10
-rw-r--r--source/blender/editors/space_view3d/view3d_select.c1
-rw-r--r--source/blender/editors/space_view3d/view3d_utils.c2
-rw-r--r--source/blender/editors/transform/transform.c2
-rw-r--r--source/blender/editors/transform/transform_convert.c87
-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_sequencer.c18
-rw-r--r--source/blender/editors/transform/transform_convert_sequencer_image.c17
-rw-r--r--source/blender/editors/transform/transform_convert_tracking.c10
-rw-r--r--source/blender/editors/transform/transform_snap.c58
-rw-r--r--source/blender/editors/util/ed_util.c13
-rw-r--r--source/blender/editors/util/ed_util_ops.cc10
-rw-r--r--source/blender/editors/uvedit/uvedit_select.c33
-rw-r--r--source/blender/editors/uvedit/uvedit_unwrap_ops.c19
-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.hh4
-rw-r--r--source/blender/geometry/CMakeLists.txt4
-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_uv_parametrizer.h4
-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.cc18
-rw-r--r--source/blender/geometry/intern/resample_curves.cc474
-rw-r--r--source/blender/geometry/intern/uv_parametrizer.c143
-rw-r--r--source/blender/gpencil_modifiers/CMakeLists.txt16
-rw-r--r--source/blender/gpencil_modifiers/intern/MOD_gpencildash.c2
-rw-r--r--source/blender/gpencil_modifiers/intern/MOD_gpencillineart.c26
-rw-r--r--source/blender/gpencil_modifiers/intern/MOD_gpencilnoise.c17
-rw-r--r--source/blender/gpencil_modifiers/intern/MOD_gpenciltime.c24
-rw-r--r--source/blender/gpencil_modifiers/intern/lineart/MOD_lineart.h63
-rw-r--r--source/blender/gpencil_modifiers/intern/lineart/lineart_chain.c141
-rw-r--r--source/blender/gpencil_modifiers/intern/lineart/lineart_cpp_bridge.cc25
-rw-r--r--source/blender/gpencil_modifiers/intern/lineart/lineart_cpu.c1298
-rw-r--r--source/blender/gpencil_modifiers/intern/lineart/lineart_intern.h58
-rw-r--r--source/blender/gpu/CMakeLists.txt25
-rw-r--r--source/blender/gpu/GPU_capabilities.h2
-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_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.h4
-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_capabilities.cc5
-rw-r--r--source/blender/gpu/intern/gpu_debug.cc6
-rw-r--r--source/blender/gpu/intern/gpu_immediate.cc2
-rw-r--r--source/blender/gpu/intern/gpu_material.c2
-rw-r--r--source/blender/gpu/intern/gpu_material_library.h2
-rw-r--r--source/blender/gpu/intern/gpu_shader_builtin.c5
-rw-r--r--source/blender/gpu/intern/gpu_shader_dependency.cc16
-rw-r--r--source/blender/gpu/intern/gpu_storage_buffer.cc7
-rw-r--r--source/blender/gpu/intern/gpu_storage_buffer_private.hh1
-rw-r--r--source/blender/gpu/intern/gpu_vertex_buffer.cc15
-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/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_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.mm675
-rw-r--r--source/blender/gpu/metal/mtl_texture.hh49
-rw-r--r--source/blender/gpu/metal/mtl_texture.mm8
-rw-r--r--source/blender/gpu/opengl/gl_debug.cc20
-rw-r--r--source/blender/gpu/opengl/gl_shader.cc4
-rw-r--r--source/blender/gpu/opengl/gl_storage_buffer.cc24
-rw-r--r--source/blender/gpu/opengl/gl_storage_buffer.hh1
-rw-r--r--source/blender/gpu/opengl/gl_texture.hh2
-rw-r--r--source/blender/gpu/opengl/gl_vertex_array.cc4
-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)50
-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_geometry.glsl93
-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_uniform_color_info.hh2
-rw-r--r--source/blender/gpu/shaders/material/gpu_shader_material_combine_color.glsl16
-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_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_hair_info.glsl2
-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_noise.glsl2
-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_rgb_curves.glsl73
-rw-r--r--source/blender/gpu/shaders/material/gpu_shader_material_separate_color.glsl28
-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/tests/gpu_shader_builtin_test.cc1
-rw-r--r--source/blender/imbuf/IMB_imbuf.h18
-rw-r--r--source/blender/imbuf/IMB_imbuf_types.h2
-rw-r--r--source/blender/imbuf/IMB_thumbs.h10
-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.c6
-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.c211
-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.c16
-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.c117
-rw-r--r--source/blender/imbuf/intern/openexr/openexr_api.cpp185
-rw-r--r--source/blender/imbuf/intern/openexr/openexr_api.h7
-rw-r--r--source/blender/imbuf/intern/readimage.c67
-rw-r--r--source/blender/imbuf/intern/thumbs.c71
-rw-r--r--source/blender/imbuf/intern/thumbs_font.c4
-rw-r--r--source/blender/imbuf/intern/util.c11
-rw-r--r--source/blender/imbuf/intern/util_gpu.c6
-rw-r--r--source/blender/imbuf/intern/writeimage.c37
-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.cc30
-rw-r--r--source/blender/io/alembic/intern/abc_reader_mesh.cc11
-rw-r--r--source/blender/io/collada/AnimationImporter.h2
-rw-r--r--source/blender/io/collada/GeometryExporter.cpp7
-rw-r--r--source/blender/io/collada/MeshImporter.h6
-rw-r--r--source/blender/io/common/CMakeLists.txt4
-rw-r--r--source/blender/io/common/IO_abstract_hierarchy_iterator.h4
-rw-r--r--source/blender/io/common/IO_string_utils.hh69
-rw-r--r--source/blender/io/common/intern/abstract_hierarchy_iterator.cc4
-rw-r--r--source/blender/io/common/intern/abstract_hierarchy_iterator_test.cc5
-rw-r--r--source/blender/io/common/intern/string_utils.cc99
-rw-r--r--source/blender/io/usd/CMakeLists.txt13
-rw-r--r--source/blender/io/usd/intern/usd_capi_export.cc14
-rw-r--r--source/blender/io/usd/intern/usd_capi_import.cc20
-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_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.cc10
-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/usd.h4
-rw-r--r--source/blender/io/wavefront_obj/CMakeLists.txt5
-rw-r--r--source/blender/io/wavefront_obj/IO_wavefront_obj.h6
-rw-r--r--source/blender/io/wavefront_obj/exporter/obj_export_file_writer.cc2
-rw-r--r--source/blender/io/wavefront_obj/exporter/obj_export_io.hh2
-rw-r--r--source/blender/io/wavefront_obj/importer/obj_import_file_reader.cc301
-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_mtl.cc3
-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_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.cc2
-rw-r--r--source/blender/makesdna/DNA_anim_types.h6
-rw-r--r--source/blender/makesdna/DNA_brush_enums.h7
-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_curves_types.h25
-rw-r--r--source/blender/makesdna/DNA_customdata_types.h2
-rw-r--r--source/blender/makesdna/DNA_gpencil_modifier_defaults.h3
-rw-r--r--source/blender/makesdna/DNA_gpencil_modifier_types.h9
-rw-r--r--source/blender/makesdna/DNA_gpencil_types.h6
-rw-r--r--source/blender/makesdna/DNA_image_types.h36
-rw-r--r--source/blender/makesdna/DNA_layer_types.h2
-rw-r--r--source/blender/makesdna/DNA_lineart_types.h17
-rw-r--r--source/blender/makesdna/DNA_modifier_defaults.h3
-rw-r--r--source/blender/makesdna/DNA_modifier_types.h10
-rw-r--r--source/blender/makesdna/DNA_node_types.h107
-rw-r--r--source/blender/makesdna/DNA_object_types.h3
-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_types.h14
-rw-r--r--source/blender/makesdna/DNA_userdef_types.h5
-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/intern/CMakeLists.txt50
-rw-r--r--source/blender/makesdna/intern/dna_rename_defs.h4
-rw-r--r--source/blender/makesdna/intern/makesdna.c192
-rw-r--r--source/blender/makesrna/RNA_access.h83
-rw-r--r--source/blender/makesrna/RNA_define.h6
-rw-r--r--source/blender/makesrna/RNA_enum_items.h12
-rw-r--r--source/blender/makesrna/RNA_types.h70
-rw-r--r--source/blender/makesrna/intern/makesrna.c38
-rw-r--r--source/blender/makesrna/intern/rna_ID.c14
-rw-r--r--source/blender/makesrna/intern/rna_access.c173
-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.c20
-rw-r--r--source/blender/makesrna/intern/rna_boid.c12
-rw-r--r--source/blender/makesrna/intern/rna_brush.c54
-rw-r--r--source/blender/makesrna/intern/rna_camera.c72
-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.c33
-rw-r--r--source/blender/makesrna/intern/rna_curve.c27
-rw-r--r--source/blender/makesrna/intern/rna_curves.c62
-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.c40
-rw-r--r--source/blender/makesrna/intern/rna_image.c16
-rw-r--r--source/blender/makesrna/intern/rna_image_api.c83
-rw-r--r--source/blender/makesrna/intern/rna_internal.h6
-rw-r--r--source/blender/makesrna/intern/rna_internal_types.h14
-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.c6
-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.c152
-rw-r--r--source/blender/makesrna/intern/rna_meta.c6
-rw-r--r--source/blender/makesrna/intern/rna_modifier.c23
-rw-r--r--source/blender/makesrna/intern/rna_nla.c88
-rw-r--r--source/blender/makesrna/intern/rna_nodetree.c254
-rw-r--r--source/blender/makesrna/intern/rna_object.c25
-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.c6
-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.c55
-rw-r--r--source/blender/makesrna/intern/rna_sculpt_paint.c32
-rw-r--r--source/blender/makesrna/intern/rna_sequencer.c95
-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.c57
-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_userdef.c26
-rw-r--r--source/blender/makesrna/intern/rna_volume.c19
-rw-r--r--source/blender/makesrna/intern/rna_wm.c41
-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_bevel.c5
-rw-r--r--source/blender/modifiers/intern/MOD_correctivesmooth.c21
-rw-r--r--source/blender/modifiers/intern/MOD_displace.c4
-rw-r--r--source/blender/modifiers/intern/MOD_explode.c7
-rw-r--r--source/blender/modifiers/intern/MOD_hook.c4
-rw-r--r--source/blender/modifiers/intern/MOD_laplaciandeform.c21
-rw-r--r--source/blender/modifiers/intern/MOD_mask.cc13
-rw-r--r--source/blender/modifiers/intern/MOD_meshdeform.c45
-rw-r--r--source/blender/modifiers/intern/MOD_meshsequencecache.cc47
-rw-r--r--source/blender/modifiers/intern/MOD_nodes.cc20
-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)86
-rw-r--r--source/blender/modifiers/intern/MOD_screw.c126
-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_surfacedeform.c112
-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.c4
-rw-r--r--source/blender/modifiers/intern/MOD_weighted_normal.c12
-rw-r--r--source/blender/modifiers/intern/MOD_weightvg_util.c6
-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_composite.h2
-rw-r--r--source/blender/nodes/NOD_function.h2
-rw-r--r--source/blender/nodes/NOD_geometry_nodes_eval_log.hh8
-rw-r--r--source/blender/nodes/NOD_node_tree_ref.hh3
-rw-r--r--source/blender/nodes/NOD_shader.h2
-rw-r--r--source/blender/nodes/NOD_static_types.h44
-rw-r--r--source/blender/nodes/NOD_texture.h2
-rw-r--r--source/blender/nodes/composite/CMakeLists.txt1
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_sepcomb_color.cc139
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_sepcomb_hsva.cc4
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_sepcomb_rgba.cc4
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_sepcomb_ycca.cc4
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_sepcomb_yuva.cc4
-rw-r--r--source/blender/nodes/function/CMakeLists.txt2
-rw-r--r--source/blender/nodes/function/nodes/node_fn_combine_color.cc108
-rw-r--r--source/blender/nodes/function/nodes/node_fn_separate_color.cc205
-rw-r--r--source/blender/nodes/geometry/node_geometry_tree.cc2
-rw-r--r--source/blender/nodes/geometry/node_geometry_util.hh12
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_accumulate_field.cc14
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_attribute_capture.cc60
-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.cc8
-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_fillet.cc86
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_curve_resample.cc600
-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.cc18
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_curve_spline_type.cc75
-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.cc35
-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.cc10
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_distribute_points_on_faces.cc6
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_duplicate_elements.cc36
-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.cc2
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_field_at_index.cc2
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_flip_faces.cc6
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_input_mesh_island.cc3
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_input_spline_length.cc73
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_instance_on_points.cc12
-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.cc10
-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.cc46
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_points_to_vertices.cc6
-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.cc4
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_rotate_instances.cc4
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_scale_instances.cc2
-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.cc6
-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.cc6
-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.cc10
-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.cc98
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_transfer_attribute.cc18
-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/intern/geometry_nodes_eval_log.cc12
-rw-r--r--source/blender/nodes/intern/node_geometry_exec.cc20
-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/intern/node_util.c33
-rw-r--r--source/blender/nodes/intern/node_util.h1
-rw-r--r--source/blender/nodes/shader/CMakeLists.txt1
-rw-r--r--source/blender/nodes/shader/node_shader_tree.cc2
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_curves.cc211
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_sepcomb_color.cc162
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_sepcomb_hsv.cc4
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_sepcomb_rgb.cc4
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_tex_image.cc2
-rw-r--r--source/blender/nodes/texture/CMakeLists.txt2
-rw-r--r--source/blender/nodes/texture/node_texture_util.c4
-rw-r--r--source/blender/nodes/texture/nodes/node_texture_combine_color.c76
-rw-r--r--source/blender/nodes/texture/nodes/node_texture_compose.c2
-rw-r--r--source/blender/nodes/texture/nodes/node_texture_decompose.c2
-rw-r--r--source/blender/nodes/texture/nodes/node_texture_separate_color.c102
-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/gpu/CMakeLists.txt2
-rw-r--r--source/blender/python/gpu/gpu_py_shader.c49
-rw-r--r--source/blender/python/intern/CMakeLists.txt7
-rw-r--r--source/blender/python/intern/bpy.c110
-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/mathutils/mathutils_Color.c263
-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/render/intern/bake.c9
-rw-r--r--source/blender/render/intern/multires_bake.c242
-rw-r--r--source/blender/render/intern/pipeline.c2
-rw-r--r--source/blender/render/intern/texture_image.c2
-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.c15
-rw-r--r--source/blender/sequencer/SEQ_time.h7
-rw-r--r--source/blender/sequencer/SEQ_transform.h4
-rw-r--r--source/blender/sequencer/intern/disk_cache.c38
-rw-r--r--source/blender/sequencer/intern/proxy.c7
-rw-r--r--source/blender/sequencer/intern/render.c7
-rw-r--r--source/blender/sequencer/intern/sequencer.c8
-rw-r--r--source/blender/sequencer/intern/strip_add.c6
-rw-r--r--source/blender/sequencer/intern/strip_edit.c62
-rw-r--r--source/blender/sequencer/intern/strip_time.c51
-rw-r--r--source/blender/sequencer/intern/strip_transform.c63
-rw-r--r--source/blender/simulation/intern/SIM_mass_spring.cpp5
-rw-r--r--source/blender/windowmanager/WM_api.h41
-rw-r--r--source/blender/windowmanager/WM_types.h9
-rw-r--r--source/blender/windowmanager/intern/wm_event_system.c4
-rw-r--r--source/blender/windowmanager/intern/wm_files.c9
-rw-r--r--source/blender/windowmanager/intern/wm_gesture_ops.c2
-rw-r--r--source/blender/windowmanager/intern/wm_init_exit.c4
-rw-r--r--source/blender/windowmanager/intern/wm_menu_type.c18
-rw-r--r--source/blender/windowmanager/intern/wm_operator_props.c17
-rw-r--r--source/blender/windowmanager/intern/wm_operator_type.c21
-rw-r--r--source/blender/windowmanager/intern/wm_operators.c97
-rw-r--r--source/blender/windowmanager/intern/wm_panel_type.c18
-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_session.c12
909 files changed, 23693 insertions, 13481 deletions
diff --git a/source/CMakeLists.txt b/source/CMakeLists.txt
index ffc4d37f622..d0592e9a405 100644
--- a/source/CMakeLists.txt
+++ b/source/CMakeLists.txt
@@ -15,8 +15,9 @@ if(WITH_CLANG_TIDY AND NOT MSVC)
endif()
find_package(ClangTidy REQUIRED)
- set(CMAKE_C_CLANG_TIDY ${CLANG_TIDY_EXECUTABLE})
- set(CMAKE_CXX_CLANG_TIDY ${CLANG_TIDY_EXECUTABLE})
+ set(CMAKE_C_CLANG_TIDY
+ ${CLANG_TIDY_EXECUTABLE};--extra-arg=-Wno-error=unknown-warning-option)
+ set(CMAKE_CXX_CLANG_TIDY ${CLANG_TIDY_EXECUTABLE};--extra-arg=-Wno-error=unknown-warning-option)
endif()
add_subdirectory(blender)
diff --git a/source/blender/CMakeLists.txt b/source/blender/CMakeLists.txt
index deff45d0350..efa2be9e48c 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_curves_defaults.h
+ ${CMAKE_CURRENT_SOURCE_DIR}/makesdna/DNA_curve_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_lightprobe_defaults.h
+ ${CMAKE_CURRENT_SOURCE_DIR}/makesdna/DNA_light_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/intern/blf_font.c b/source/blender/blenfont/intern/blf_font.c
index f93cb8b2d64..a170f27d247 100644
--- a/source/blender/blenfont/intern/blf_font.c
+++ b/source/blender/blenfont/intern/blf_font.c
@@ -1374,7 +1374,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_internal_types.h b/source/blender/blenfont/intern/blf_internal_types.h
index 62bce36dda0..9dfcb1a4ad6 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;
@@ -264,7 +264,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 +276,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..59f0c86684d 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" {
@@ -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..cc50076e964 100644
--- a/source/blender/blenkernel/BKE_attribute.h
+++ b/source/blender/blenkernel/BKE_attribute.h
@@ -30,9 +30,8 @@ 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 */
-
- ATTR_DOMAIN_NUM
} AttributeDomain;
+#define ATTR_DOMAIN_NUM 6
typedef enum AttributeDomainMask {
ATTR_DOMAIN_MASK_POINT = (1 << 0),
diff --git a/source/blender/blenkernel/BKE_blender_version.h b/source/blender/blenkernel/BKE_blender_version.h
index 15fdc73adeb..ab13a2e85d0 100644
--- a/source/blender/blenkernel/BKE_blender_version.h
+++ b/source/blender/blenkernel/BKE_blender_version.h
@@ -17,15 +17,15 @@ extern "C" {
*/
/* Blender major and minor version. */
-#define BLENDER_VERSION 302
+#define BLENDER_VERSION 303
/* Blender patch version for bugfix releases. */
#define BLENDER_VERSION_PATCH 0
/** Blender release cycle stage: alpha/beta/rc/release. */
-#define BLENDER_VERSION_CYCLE beta
+#define BLENDER_VERSION_CYCLE alpha
/* Blender file format version. */
#define BLENDER_FILE_VERSION BLENDER_VERSION
-#define BLENDER_FILE_SUBVERSION 14
+#define BLENDER_FILE_SUBVERSION 0
/* 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_camera.h b/source/blender/blenkernel/BKE_camera.h
index 57dc1e288dc..b7aa1c09e04 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_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..ce1f4c2b98c 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.
diff --git a/source/blender/blenkernel/BKE_curves.hh b/source/blender/blenkernel/BKE_curves.hh
index 1e96c0e4c41..cc056dab248 100644
--- a/source/blender/blenkernel/BKE_curves.hh
+++ b/source/blender/blenkernel/BKE_curves.hh
@@ -48,6 +48,13 @@ struct BasisCache {
* In other words, the index of the first control point that influences this evaluated point.
*/
Vector<int> start_indices;
+
+ /**
+ * 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.
+ */
+ bool invalid = false;
};
} // namespace curves::nurbs
@@ -120,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);
@@ -174,11 +181,18 @@ class CurvesGeometry : public ::CurvesGeometry {
/** Update the cached count of curves of each type, necessary after #curve_types_for_write. */
void update_curve_types();
- bool has_curve_with_type(const CurveType type) const;
+ bool has_curve_with_type(CurveType type) 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. */
const std::array<int, CURVE_TYPES_NUM> &curve_type_counts() const;
+ /**
+ * All of the curve indices for curves with a specific type.
+ */
+ IndexMask indices_for_curve_type(CurveType type, Vector<int64_t> &r_indices) const;
+ IndexMask indices_for_curve_type(CurveType type,
+ IndexMask selection,
+ Vector<int64_t> &r_indices) const;
Span<float3> positions() const;
MutableSpan<float3> positions_for_write();
@@ -276,11 +290,6 @@ class CurvesGeometry : public ::CurvesGeometry {
bool bounds_min_max(float3 &min, float3 &max) const;
private:
- /**
- * All of the curve indices for curves with a specific type.
- */
- IndexMask indices_for_curve_type(CurveType type, Vector<int64_t> &r_indices) const;
-
/* --------------------------------------------------------------------
* Evaluation.
*/
@@ -409,7 +418,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;
@@ -444,7 +453,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);
@@ -474,10 +483,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
@@ -576,11 +586,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);
@@ -597,7 +607,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
@@ -607,7 +617,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);
/**
@@ -615,7 +625,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
@@ -635,7 +645,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,
@@ -662,6 +672,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.
@@ -676,11 +687,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,7 +721,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];
@@ -720,7 +731,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()];
@@ -742,7 +753,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};
@@ -760,7 +771,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, points.is_empty() ? 0 : 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,
@@ -775,8 +786,10 @@ 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);
- /* Check for curves that have no evaluated segments. */
- return lengths.is_empty() ? 0.0f : lengths.last();
+ 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..62b060093e9
--- /dev/null
+++ b/source/blender/blenkernel/BKE_curves_utils.hh
@@ -0,0 +1,26 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+
+#pragma once
+
+#include "BKE_curves.hh"
+
+/** \file
+ * \ingroup bke
+ * \brief Low-level operations for curves.
+ */
+
+namespace blender::bke::curves {
+
+/**
+ * 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);
+
+} // namespace blender::bke::curves
diff --git a/source/blender/blenkernel/BKE_customdata.h b/source/blender/blenkernel/BKE_customdata.h
index f05dfb164cf..64c49830dc5 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"
@@ -700,39 +704,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);
+ ID *id);
+
+#endif
+
void CustomData_blend_read(struct BlendDataReader *reader, struct CustomData *data, int count);
#ifndef NDEBUG
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..78d80ce200e 100644
--- a/source/blender/blenkernel/BKE_fcurve.h
+++ b/source/blender/blenkernel/BKE_fcurve.h
@@ -293,7 +293,7 @@ struct FCurve *BKE_fcurve_find_by_rna(struct PointerRNA *ptr,
* temp hack needed for complex paths like texture ones.
*/
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 36b382feb5f..9c86ab262ef 100644
--- a/source/blender/blenkernel/BKE_geometry_fields.hh
+++ b/source/blender/blenkernel/BKE_geometry_fields.hh
@@ -162,4 +162,14 @@ class AnonymousAttributeFieldInput : public GeometryFieldInput {
bool is_equal_to(const fn::FieldNode &other) const override;
};
+class CurveLengthFieldInput final : public GeometryFieldInput {
+ public:
+ CurveLengthFieldInput();
+ GVArray get_varray_for_context(const GeometryComponent &component,
+ AttributeDomain domain,
+ IndexMask mask) const final;
+ uint64_t hash() const override;
+ bool is_equal_to(const fn::FieldNode &other) const override;
+};
+
} // namespace blender::bke
diff --git a/source/blender/blenkernel/BKE_geometry_set.hh b/source/blender/blenkernel/BKE_geometry_set.hh
index dfd9fccebbd..c58420efceb 100644
--- a/source/blender/blenkernel/BKE_geometry_set.hh
+++ b/source/blender/blenkernel/BKE_geometry_set.hh
@@ -98,7 +98,7 @@ class GeometryComponent {
/**
* 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(AttributeDomain domain) const;
/**
* Return true if the attribute name corresponds to a built-in attribute with a hardcoded domain
@@ -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(AttributeDomain domain) const final;
bool is_empty() 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(AttributeDomain 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(AttributeDomain domain) const final;
bool is_empty() const final;
@@ -682,8 +682,9 @@ class CurveComponentLegacy : public GeometryComponent {
};
/**
- * 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(AttributeDomain domain) const final;
bool is_empty() 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(AttributeDomain 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_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 0417f335d11..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);
@@ -392,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);
@@ -459,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_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_override.h b/source/blender/blenkernel/BKE_lib_override.h
index dfb2b900b10..38de4bebdbd 100644
--- a/source/blender/blenkernel/BKE_lib_override.h
+++ b/source/blender/blenkernel/BKE_lib_override.h
@@ -116,6 +116,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 +125,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 +157,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 +168,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.
*/
diff --git a/source/blender/blenkernel/BKE_lib_principle_properties.h b/source/blender/blenkernel/BKE_lib_principle_properties.h
index 10d0d33a0c4..42177204efb 100644
--- a/source/blender/blenkernel/BKE_lib_principle_properties.h
+++ b/source/blender/blenkernel/BKE_lib_principle_properties.h
@@ -40,7 +40,7 @@ struct ReportList;
struct IDPrincipleProperties *BKE_lib_principleprop_init(struct ID *id);
#if 0
/**
- * Shallow or deep copy of a whole princple properties from \a src_id to \a dst_id.
+ * Shallow or deep copy of a whole principle properties from \a src_id to \a dst_id.
*/
void BKE_lib_principleprop_copy(struct ID *dst_id, const struct ID *src_id, bool do_full_copy);
#endif
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_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 881e86ccc54..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,
@@ -113,7 +114,7 @@ typedef enum ModifierApplyFlag {
/** Render time. */
MOD_APPLY_RENDER = 1 << 0,
/** Result of evaluation will be cached, so modifier might
- * want to cache data for quick updates (used by subsurf) */
+ * want to cache data for quick updates (used by subdivision-surface) */
MOD_APPLY_USECACHE = 1 << 1,
/** Modifier evaluated for undeformed texture coordinates */
MOD_APPLY_ORCO = 1 << 2,
@@ -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 c9228db9ecc..1ff10d06b00 100644
--- a/source/blender/blenkernel/BKE_node.h
+++ b/source/blender/blenkernel/BKE_node.h
@@ -1090,8 +1090,8 @@ void BKE_nodetree_remove_layer_n(struct bNodeTree *ntree, struct Scene *scene, i
#define SH_NODE_SQUEEZE 117
//#define SH_NODE_MATERIAL_EXT 118
#define SH_NODE_INVERT 119
-#define SH_NODE_SEPRGB 120
-#define SH_NODE_COMBRGB 121
+#define SH_NODE_SEPRGB_LEGACY 120
+#define SH_NODE_COMBRGB_LEGACY 121
#define SH_NODE_HUE_SAT 122
#define SH_NODE_OUTPUT_MATERIAL 124
@@ -1147,8 +1147,8 @@ void BKE_nodetree_remove_layer_n(struct bNodeTree *ntree, struct Scene *scene, i
#define SH_NODE_WAVELENGTH 180
#define SH_NODE_BLACKBODY 181
#define SH_NODE_VECT_TRANSFORM 182
-#define SH_NODE_SEPHSV 183
-#define SH_NODE_COMBHSV 184
+#define SH_NODE_SEPHSV_LEGACY 183
+#define SH_NODE_COMBHSV_LEGACY 184
#define SH_NODE_BSDF_HAIR 185
// #define SH_NODE_LAMP 186
#define SH_NODE_UVMAP 187
@@ -1175,6 +1175,8 @@ void BKE_nodetree_remove_layer_n(struct bNodeTree *ntree, struct Scene *scene, i
#define SH_NODE_VECTOR_ROTATE 708
#define SH_NODE_CURVE_FLOAT 709
#define SH_NODE_POINT_INFO 710
+#define SH_NODE_COMBINE_COLOR 711
+#define SH_NODE_SEPARATE_COLOR 712
/** \} */
@@ -1202,8 +1204,8 @@ void BKE_nodetree_remove_layer_n(struct bNodeTree *ntree, struct Scene *scene, i
#define CMP_NODE_MAP_VALUE 213
#define CMP_NODE_TIME 214
#define CMP_NODE_VECBLUR 215
-#define CMP_NODE_SEPRGBA 216
-#define CMP_NODE_SEPHSVA 217
+#define CMP_NODE_SEPRGBA_LEGACY 216
+#define CMP_NODE_SEPHSVA_LEGACY 217
#define CMP_NODE_SETALPHA 218
#define CMP_NODE_HUE_SAT 219
#define CMP_NODE_IMAGE 220
@@ -1213,14 +1215,14 @@ void BKE_nodetree_remove_layer_n(struct bNodeTree *ntree, struct Scene *scene, i
#define CMP_NODE_TEXTURE 224
#define CMP_NODE_TRANSLATE 225
#define CMP_NODE_ZCOMBINE 226
-#define CMP_NODE_COMBRGBA 227
+#define CMP_NODE_COMBRGBA_LEGACY 227
#define CMP_NODE_DILATEERODE 228
#define CMP_NODE_ROTATE 229
#define CMP_NODE_SCALE 230
-#define CMP_NODE_SEPYCCA 231
-#define CMP_NODE_COMBYCCA 232
-#define CMP_NODE_SEPYUVA 233
-#define CMP_NODE_COMBYUVA 234
+#define CMP_NODE_SEPYCCA_LEGACY 231
+#define CMP_NODE_COMBYCCA_LEGACY 232
+#define CMP_NODE_SEPYUVA_LEGACY 233
+#define CMP_NODE_COMBYUVA_LEGACY 234
#define CMP_NODE_DIFF_MATTE 235
#define CMP_NODE_COLOR_SPILL 236
#define CMP_NODE_CHROMA_MATTE 237
@@ -1232,7 +1234,7 @@ void BKE_nodetree_remove_layer_n(struct bNodeTree *ntree, struct Scene *scene, i
#define CMP_NODE_ID_MASK 243
#define CMP_NODE_DEFOCUS 244
#define CMP_NODE_DISPLACE 245
-#define CMP_NODE_COMBHSVA 246
+#define CMP_NODE_COMBHSVA_LEGACY 246
#define CMP_NODE_MATH 247
#define CMP_NODE_LUMA_MATTE 248
#define CMP_NODE_BRIGHTCONTRAST 249
@@ -1289,6 +1291,8 @@ void BKE_nodetree_remove_layer_n(struct bNodeTree *ntree, struct Scene *scene, i
#define CMP_NODE_SCENE_TIME 329
#define CMP_NODE_SEPARATE_XYZ 330
#define CMP_NODE_COMBINE_XYZ 331
+#define CMP_NODE_COMBINE_COLOR 332
+#define CMP_NODE_SEPARATE_COLOR 333
/* channel toggles */
#define CMP_CHAN_RGB 1
@@ -1354,11 +1358,13 @@ struct TexResult;
#define TEX_NODE_TRANSLATE 416
#define TEX_NODE_COORD 417
#define TEX_NODE_DISTANCE 418
-#define TEX_NODE_COMPOSE 419
-#define TEX_NODE_DECOMPOSE 420
+#define TEX_NODE_COMPOSE_LEGACY 419
+#define TEX_NODE_DECOMPOSE_LEGACY 420
#define TEX_NODE_VALTONOR 421
#define TEX_NODE_SCALE 422
#define TEX_NODE_AT 423
+#define TEX_NODE_COMBINE_COLOR 424
+#define TEX_NODE_SEPARATE_COLOR 425
/* 501-599 reserved. Use like this: TEX_NODE_PROC + TEX_CLOUDS, etc */
#define TEX_NODE_PROC 500
@@ -1511,6 +1517,8 @@ struct TexResult;
#define FN_NODE_REPLACE_STRING 1218
#define FN_NODE_INPUT_BOOL 1219
#define FN_NODE_INPUT_INT 1220
+#define FN_NODE_SEPARATE_COLOR 1221
+#define FN_NODE_COMBINE_COLOR 1222
/** \} */
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 0e976f04dd1..c39ab22ce3a 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);
@@ -733,7 +734,7 @@ enum {
/* paint_vertex.cc */
/**
- * Fills the object's active color atribute layer with the fill color.
+ * Fills the object's active color attribute layer with the fill color.
*
* \param[in] ob: The object.
* \param[in] fill_color: The fill color.
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_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_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..edb301f06bf 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;
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 7673f18317a..cb0f2ac7e32 100644
--- a/source/blender/blenkernel/BKE_subdiv_eval.h
+++ b/source/blender/blenkernel/BKE_subdiv_eval.h
@@ -62,7 +62,7 @@ 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). */
+/* 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,
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/CMakeLists.txt b/source/blender/blenkernel/CMakeLists.txt
index a57d4d0a2bf..0b5f252b0d6 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
@@ -242,8 +243,8 @@ set(SRC
intern/particle_child.c
intern/particle_distribute.c
intern/particle_system.c
- intern/pbvh.cc
intern/pbvh.c
+ intern/pbvh.cc
intern/pbvh_bmesh.c
intern/pbvh_pixels.cc
intern/pointcache.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
diff --git a/source/blender/blenkernel/intern/DerivedMesh.cc b/source/blender/blenkernel/intern/DerivedMesh.cc
index 6b43fe57e93..5cf0ca6e062 100644
--- a/source/blender/blenkernel/intern/DerivedMesh.cc
+++ b/source/blender/blenkernel/intern/DerivedMesh.cc
@@ -423,21 +423,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) {
diff --git a/source/blender/blenkernel/intern/anim_sys.c b/source/blender/blenkernel/intern/anim_sys.c
index b886722676b..94b85e42f96 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.
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..0007fea62cb 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,6 +18,7 @@
#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"
@@ -30,10 +31,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 +52,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 +78,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:
@@ -90,7 +93,7 @@ static CustomData *attribute_customdata_find(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)) {
@@ -98,14 +101,14 @@ static CustomData *attribute_customdata_find(ID *id, CustomDataLayer *layer)
}
}
- return NULL;
+ return nullptr;
}
-bool BKE_id_attributes_supported(struct ID *id)
+bool BKE_id_attributes_supported(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;
}
@@ -124,7 +127,7 @@ bool BKE_id_attribute_rename(ID *id,
}
CustomData *customdata = attribute_customdata_find(id, layer);
- if (customdata == NULL) {
+ if (customdata == nullptr) {
BKE_report(reports, RPT_ERROR, "Attribute is not part of this geometry");
return false;
}
@@ -134,9 +137,9 @@ bool BKE_id_attribute_rename(ID *id,
return true;
}
-typedef struct AttrUniqueData {
+struct AttrUniqueData {
ID *id;
-} AttrUniqueData;
+};
static bool unique_name_cb(void *arg, const char *name)
{
@@ -145,7 +148,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,11 +168,12 @@ 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(
@@ -179,9 +183,9 @@ CustomDataLayer *BKE_id_attribute_new(
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,24 +195,24 @@ 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)
@@ -232,7 +236,7 @@ bool BKE_id_attribute_remove(ID *id, CustomDataLayer *layer, ReportList *reports
case ID_ME: {
Mesh *me = (Mesh *)id;
BMEditMesh *em = me->edit_mesh;
- if (em != NULL) {
+ if (em != nullptr) {
BM_data_layer_free(em->bm, customdata, layer->type);
}
else {
@@ -260,8 +264,8 @@ CustomDataLayer *BKE_id_attribute_find(const ID *id,
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,7 +275,7 @@ CustomDataLayer *BKE_id_attribute_find(const ID *id,
}
}
- return NULL;
+ return nullptr;
}
int BKE_id_attributes_length(const ID *id, AttributeDomainMask domain_mask, CustomDataMask mask)
@@ -281,7 +285,7 @@ int BKE_id_attributes_length(const ID *id, AttributeDomainMask domain_mask, Cust
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)) {
@@ -297,16 +301,16 @@ AttributeDomain BKE_id_attribute_domain(const ID *id, const CustomDataLayer *lay
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<AttributeDomain>(domain);
}
}
BLI_assert_msg(0, "Custom data layer not found in geometry");
- return ATTR_DOMAIN_NUM;
+ return static_cast<AttributeDomain>(ATTR_DOMAIN_POINT);
}
int BKE_id_attribute_data_length(ID *id, CustomDataLayer *layer)
@@ -317,7 +321,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 +332,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)) {
@@ -366,7 +370,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 +385,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 +395,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 +425,7 @@ int *BKE_id_attributes_active_index_p(ID *id)
return &((Curves *)id)->attributes_active_index;
}
default:
- return NULL;
+ return nullptr;
}
}
@@ -430,9 +434,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,7 +448,7 @@ CustomData *BKE_id_attributes_iterator_next_domain(ID *id, CustomDataLayer *laye
}
}
- return NULL;
+ return nullptr;
}
CustomDataLayer *BKE_id_attribute_from_index(ID *id,
@@ -456,7 +460,7 @@ CustomDataLayer *BKE_id_attribute_from_index(ID *id,
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,7 +481,7 @@ CustomDataLayer *BKE_id_attribute_from_index(ID *id,
}
}
- return NULL;
+ return nullptr;
}
/** Get list of domain types but with ATTR_DOMAIN_FACE and
@@ -485,15 +489,15 @@ CustomDataLayer *BKE_id_attribute_from_index(ID *id,
*/
static void get_domains_types(AttributeDomain 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<AttributeDomain>(i);
}
/* Swap corner and face. */
SWAP(AttributeDomain, 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)
@@ -544,7 +548,7 @@ CustomDataLayer *BKE_id_attribute_subset_active_get(const ID *id,
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;
@@ -632,13 +636,13 @@ 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 +665,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..e86bac21084 100644
--- a/source/blender/blenkernel/intern/attribute_access.cc
+++ b/source/blender/blenkernel/intern/attribute_access.cc
@@ -184,16 +184,16 @@ 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 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 +204,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;
@@ -221,35 +221,35 @@ static void *add_generic_custom_data_layer(CustomData &custom_data,
const CustomDataType 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 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 +260,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 +303,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 +317,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 +333,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 +353,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 +366,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 +381,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 +401,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 +409,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 +417,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,7 +446,7 @@ 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;
@@ -455,7 +455,7 @@ ReadAttributeLookup CustomDataAttributeProvider::try_get_for_read(
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 +468,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);
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 +497,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) &&
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;
}
}
@@ -531,9 +530,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;
}
@@ -567,8 +566,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 +584,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 +611,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);
}
@@ -702,9 +701,9 @@ GVArray CustomDataAttributes::get_for_read(const AttributeIDRef &attribute_id,
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) {
@@ -822,7 +821,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 AttributeDomain UNUSED(domain)) const
{
return 0;
}
@@ -1157,8 +1156,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 {
@@ -1267,10 +1266,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 +1300,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 +1309,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 +1332,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,10 +1341,10 @@ 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);
}
@@ -1429,7 +1427,7 @@ GVArray IDAttributeFieldInput::get_varray_for_context(const GeometryComponent &c
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;
}
diff --git a/source/blender/blenkernel/intern/attribute_access_intern.hh b/source/blender/blenkernel/intern/attribute_access_intern.hh
index 8c021ed0e21..f0f47cb7a11 100644
--- a/source/blender/blenkernel/intern/attribute_access_intern.hh
+++ b/source/blender/blenkernel/intern/attribute_access_intern.hh
@@ -172,8 +172,8 @@ 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);
+ using AsReadAttribute = GVArray (*)(const void *data, int domain_num);
+ using AsWriteAttribute = GVMutableArray (*)(void *data, int domain_num);
const AttributeDomain domain_;
const CustomDataType attribute_type_;
const CustomDataType stored_type_;
@@ -207,14 +207,14 @@ class NamedLegacyCustomDataProvider final : public DynamicAttributesProvider {
void foreach_domain(const FunctionRef<void(AttributeDomain)> 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,8 +226,8 @@ 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_;
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 62196ea63bd..ebf48acde0f 100644
--- a/source/blender/blenkernel/intern/blendfile_link_append.c
+++ b/source/blender/blenkernel/intern/blendfile_link_append.c
@@ -400,7 +400,7 @@ typedef struct LooseDataInstantiateContext {
static bool object_in_any_scene(Main *bmain, Object *ob)
{
LISTBASE_FOREACH (Scene *, sce, &bmain->scenes) {
- /* #BKE_scene_has_object checks bases cache of the scenes' viewlayer, not actual content of
+ /* #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;
@@ -1114,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) {
@@ -1537,7 +1537,7 @@ void BKE_blendfile_library_relocate(BlendfileLinkAppendContext *lapp_context,
}
if (GS(old_id->name) == ID_KE) {
- /* Shape Keys are handled as part of their owning obdata (see below). This implies thar
+ /* Shape Keys are handled as part of their owning obdata (see below). This implies that
* there is no way to know when the old pointer gets invalid, so just clear it immediately.
*/
item->userdata = NULL;
diff --git a/source/blender/blenkernel/intern/brush.c b/source/blender/blenkernel/intern/brush.c
index 3f243d04965..083d5af063a 100644
--- a/source/blender/blenkernel/intern/brush.c
+++ b/source/blender/blenkernel/intern/brush.c
@@ -1559,6 +1559,7 @@ void BKE_brush_init_curves_sculpt_settings(Brush *brush)
}
BrushCurvesSculptSettings *settings = brush->curves_sculpt_settings;
settings->add_amount = 1;
+ settings->points_per_curve = 8;
settings->minimum_length = 0.01f;
settings->curve_length = 0.3f;
}
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/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/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_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 0114c0b45f4..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)) {
- return 0;
+ 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]);
@@ -232,8 +232,12 @@ void interpolate_to_evaluated(const BasisCache &basis_cache,
const GSpan src,
GMutableSpan dst)
{
- BLI_assert(dst.size() == basis_cache.start_indices.size());
+ if (basis_cache.invalid) {
+ dst.copy_from(src);
+ return;
+ }
+ BLI_assert(dst.size() == basis_cache.start_indices.size());
attribute_math::convert_to_static_type(src.type(), [&](auto dummy) {
using T = decltype(dummy);
if constexpr (!std::is_void_v<attribute_math::DefaultMixer<T>>) {
diff --git a/source/blender/blenkernel/intern/curve_poly.cc b/source/blender/blenkernel/intern/curve_poly.cc
index 2a546e81825..7ab92068d81 100644
--- a/source/blender/blenkernel/intern/curve_poly.cc
+++ b/source/blender/blenkernel/intern/curve_poly.cc
@@ -159,7 +159,7 @@ void calculate_normals_minimum(const Span<float3> tangents,
normals.first() = math::normalize(float3(first_tangent.y, -first_tangent.x, 0.0f));
}
- /* Forward normal with minimum twist along the entire spline. */
+ /* Forward normal with minimum twist along the entire curve. */
for (const int i : IndexRange(1, normals.size() - 1)) {
normals[i] = calculate_next_normal(normals[i - 1], tangents[i - 1], tangents[i]);
}
@@ -169,7 +169,7 @@ void calculate_normals_minimum(const Span<float3> tangents,
}
/* Compute how much the first normal deviates from the normal that has been forwarded along the
- * entire cyclic spline. */
+ * entire cyclic curve. */
const float3 uncorrected_last_normal = calculate_next_normal(
normals.last(), tangents.last(), tangents.first());
float correction_angle = angle_signed_on_axis_v3v3_v3(
diff --git a/source/blender/blenkernel/intern/curve_to_mesh_convert.cc b/source/blender/blenkernel/intern/curve_to_mesh_convert.cc
index ef921797698..0cd324cfe2c 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;
@@ -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),
diff --git a/source/blender/blenkernel/intern/curves.cc b/source/blender/blenkernel/intern/curves.cc
index 1df1492bac1..ab9dd702630 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,12 +80,12 @@ 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));
@@ -121,12 +123,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 +135,23 @@ 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_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 +161,11 @@ 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);
curves->geometry.runtime = MEM_new<blender::bke::CurvesGeometryRuntime>(__func__);
@@ -247,7 +239,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 +248,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);
}
@@ -364,19 +357,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 7a09b87490b..0fd58a52f81 100644
--- a/source/blender/blenkernel/intern/curves_geometry.cc
+++ b/source/blender/blenkernel/intern/curves_geometry.cc
@@ -46,10 +46,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 +57,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 +74,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 +94,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 +110,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 +130,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 +145,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,7 +158,7 @@ CurvesGeometry::~CurvesGeometry()
/** \name Accessors
* \{ */
-static int domain_size(const CurvesGeometry &curves, const AttributeDomain domain)
+static int domain_num(const CurvesGeometry &curves, const AttributeDomain domain)
{
return domain == ATTR_DOMAIN_POINT ? curves.points_num() : curves.curves_num();
}
@@ -178,15 +180,15 @@ static VArray<T> get_varray_attribute(const CurvesGeometry &curves,
const StringRefNull name,
const T default_value)
{
- const int size = domain_size(curves, domain);
+ const int num = domain_num(curves, domain);
const CustomDataType 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>
@@ -194,7 +196,7 @@ static Span<T> get_span_attribute(const CurvesGeometry &curves,
const AttributeDomain 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>());
@@ -202,7 +204,7 @@ static Span<T> get_span_attribute(const CurvesGeometry &curves,
if (data == nullptr) {
return {};
}
- return {data, size};
+ return {data, num};
}
template<typename T>
@@ -211,19 +213,19 @@ static MutableSpan<T> get_mutable_attribute(CurvesGeometry &curves,
const StringRefNull name,
const T default_value = T())
{
- const int size = domain_size(curves, domain);
+ const int num = domain_num(curves, domain);
const CustomDataType 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;
@@ -250,6 +252,10 @@ void CurvesGeometry::fill_curve_types(const CurveType type)
void CurvesGeometry::fill_curve_types(const IndexMask selection, const CurveType type)
{
+ if (selection.size() == this->curves_num()) {
+ this->fill_curve_types(type);
+ return;
+ }
/* A potential performance optimization is only counting the changed indices. */
this->curve_types_for_write().fill_indices(selection, type);
this->update_curve_types();
@@ -295,22 +301,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
@@ -438,12 +444,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;
}
@@ -466,7 +472,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();
@@ -478,11 +484,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;
@@ -527,19 +533,23 @@ Span<int> CurvesGeometry::evaluated_offsets() const
IndexMask CurvesGeometry::indices_for_curve_type(const CurveType type,
Vector<int64_t> &r_indices) const
{
+ return this->indices_for_curve_type(type, this->curves_range(), r_indices);
+}
- VArray<int8_t> types = this->curve_types();
+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;
+ }
+ const VArray<int8_t> types = this->curve_types();
if (types.is_single()) {
- if (types.get_internal_single() == type) {
- return IndexMask(types.size());
- }
- return {};
+ return types.get_internal_single() == type ? IndexMask(this->curves_num()) : IndexMask(0);
}
Span<int8_t> types_span = types.get_internal_span();
return index_mask_ops::find_indices_based_on_predicate(
- IndexMask(types.size()), 1024, r_indices, [&](const int index) {
- return types_span[index] == type;
- });
+ selection, 1024, r_indices, [&](const int index) { return types_span[index] == type; });
}
void CurvesGeometry::ensure_nurbs_basis_cache() const
@@ -577,8 +587,13 @@ void CurvesGeometry::ensure_nurbs_basis_cache() const
const bool is_cyclic = cyclic[curve_index];
const KnotsMode mode = KnotsMode(knots_modes[curve_index]);
- const int knots_size = curves::nurbs::knots_size(points.size(), order, is_cyclic);
- Array<float> knots(knots_size);
+ if (!curves::nurbs::check_valid_num_and_order(points.size(), order, is_cyclic, mode)) {
+ basis_caches[curve_index].invalid = true;
+ continue;
+ }
+
+ 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(),
@@ -696,9 +711,6 @@ Span<float3> CurvesGeometry::evaluated_tangents() const
threading::parallel_for(this->curves_range(), 128, [&](IndexRange curves_range) {
for (const int curve_index : curves_range) {
const IndexRange evaluated_points = this->evaluated_points_for_curve(curve_index);
- if (UNLIKELY(evaluated_points.is_empty())) {
- continue;
- }
curves::poly::calculate_tangents(evaluated_positions.slice(evaluated_points),
cyclic[curve_index],
tangents.slice(evaluated_points));
@@ -773,9 +785,6 @@ Span<float3> CurvesGeometry::evaluated_normals() const
for (const int curve_index : curves_range) {
const IndexRange evaluated_points = this->evaluated_points_for_curve(curve_index);
- if (UNLIKELY(evaluated_points.is_empty())) {
- continue;
- }
switch (normal_mode[curve_index]) {
case NORMAL_MODE_Z_UP:
curves::poly::calculate_normals_z_up(evaluated_tangents.slice(evaluated_points),
@@ -905,8 +914,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();
@@ -916,9 +925,6 @@ void CurvesGeometry::ensure_evaluated_lengths() const
for (const int curve_index : curves_range) {
const bool cyclic = curves_cyclic[curve_index];
const IndexRange evaluated_points = this->evaluated_points_for_curve(curve_index);
- if (UNLIKELY(evaluated_points.is_empty())) {
- continue;
- }
const IndexRange lengths_range = this->lengths_range_for_curve(curve_index, cyclic);
length_parameterize::accumulate_lengths(evaluated_positions.slice(evaluated_points),
cyclic,
@@ -938,13 +944,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();
@@ -1196,6 +1202,8 @@ static CurvesGeometry copy_with_removed_curves(const CurvesGeometry &curves,
}
});
+ new_curves.update_curve_types();
+
return new_curves;
}
diff --git a/source/blender/blenkernel/intern/curves_utils.cc b/source/blender/blenkernel/intern/curves_utils.cc
new file mode 100644
index 00000000000..78c2382b62f
--- /dev/null
+++ b/source/blender/blenkernel/intern/curves_utils.cc
@@ -0,0 +1,38 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+
+/** \file
+ * \ingroup bke
+ */
+
+#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;
+}
+
+} // namespace blender::bke::curves
diff --git a/source/blender/blenkernel/intern/customdata.cc b/source/blender/blenkernel/intern/customdata.cc
index 62351a31042..da5c8389be2 100644
--- a/source/blender/blenkernel/intern/customdata.cc
+++ b/source/blender/blenkernel/intern/customdata.cc
@@ -25,6 +25,7 @@
#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_utils.h"
#include "BLI_utildefines.h"
@@ -54,6 +55,9 @@
/* only for customdata_data_transfer_interp_normal_normals */
#include "data_transfer_intern.h"
+using blender::Span;
+using blender::Vector;
+
/* number of layers to add when growing a CustomData object */
#define CUSTOMDATA_GROW 5
@@ -2575,36 +2579,48 @@ 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;
}
}
}
@@ -3646,7 +3662,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;
}
@@ -4337,45 +4353,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)
@@ -5137,12 +5127,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 +5146,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,7 +5164,7 @@ 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,
ID *id)
@@ -5182,55 +5174,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);
+ }
}
}
}
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..48f2d66c1cd 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;
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/fcurve.c b/source/blender/blenkernel/intern/fcurve.c
index 34357c3e454..952d5df299c 100644
--- a/source/blender/blenkernel/intern/fcurve.c
+++ b/source/blender/blenkernel/intern/fcurve.c
@@ -351,8 +351,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,
@@ -361,7 +361,6 @@ FCurve *BKE_fcurve_find_by_rna_context_ui(bContext *C,
bool *r_special)
{
FCurve *fcu = NULL;
- PointerRNA tptr = *ptr;
*r_driven = false;
*r_special = false;
@@ -388,79 +387,51 @@ FCurve *BKE_fcurve_find_by_rna_context_ui(bContext *C,
}
/* 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;
- }
+ if (!prop || !ptr->owner_id || !RNA_property_animateable(ptr, prop)) {
+ return fcu;
+ }
- /* 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);
+ AnimData *adt = BKE_animdata_from_id(ptr->owner_id);
+ if (adt == NULL) {
+ return fcu;
+ }
- if (fcu && r_action) {
- *r_action = adt->action;
- }
- }
+ const bool has_action_fcurves = adt->action != NULL &&
+ !BLI_listbase_is_empty(&adt->action->curves);
+ const bool has_drivers = !BLI_listbase_is_empty(&adt->drivers);
- /* If not animated, check if driven. */
- if (!fcu && (adt->drivers.first)) {
- fcu = BKE_fcurve_find(&adt->drivers, path, rnaindex);
+ /* XXX This function call can become a performance bottleneck. */
+ char *path = RNA_path_from_ID_to_property(ptr, prop);
- if (fcu) {
- if (r_animdata) {
- *r_animdata = adt;
- }
- *r_driven = true;
- }
- }
+ /* Standard F-Curve - Animation (Action) or Drivers. */
+ /* Animation takes priority over drivers. */
+ /* XXX: The logic here is duplicated with a function up above. */
+ if (has_action_fcurves) {
+ fcu = BKE_fcurve_find(&adt->action->curves, path, rnaindex);
- if (fcu && r_action) {
- if (r_animdata) {
- *r_animdata = adt;
- }
+ if (fcu) {
+ if (r_action) {
*r_action = adt->action;
- break;
}
+ if (r_animdata) {
+ *r_animdata = adt;
+ }
+ }
+ }
- 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;
- }
+ /* If not animated, check if driven. */
+ if (fcu == NULL && has_drivers) {
+ fcu = BKE_fcurve_find(&adt->drivers, path, rnaindex);
+
+ if (fcu) {
+ if (r_animdata) {
+ *r_animdata = adt;
}
+ *r_driven = true;
}
- MEM_SAFE_FREE(path);
}
+ MEM_SAFE_FREE(path);
return fcu;
}
diff --git a/source/blender/blenkernel/intern/fluid.c b/source/blender/blenkernel/intern/fluid.c
index 5de13fbdbed..06d32d5bfd4 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)
@@ -2008,7 +2008,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 +2074,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 +2086,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 +2094,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..a28afc8ddca 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 AttributeDomain 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];
@@ -415,7 +415,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 +495,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 +541,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];
@@ -589,13 +589,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 {};
@@ -1168,7 +1168,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;
}
};
diff --git a/source/blender/blenkernel/intern/geometry_component_curves.cc b/source/blender/blenkernel/intern/geometry_component_curves.cc
index bc9bba3ee2f..9b023d12a7d 100644
--- a/source/blender/blenkernel/intern/geometry_component_curves.cc
+++ b/source/blender/blenkernel/intern/geometry_component_curves.cc
@@ -135,12 +135,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();
@@ -237,26 +237,89 @@ VArray<float3> curve_normals_varray(const CurveComponent &component, const Attri
return nullptr;
}
-} // namespace blender::bke
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Curve Length Field Input
+ * \{ */
+
+static VArray<float> construct_curve_length_gvarray(const CurveComponent &component,
+ const AttributeDomain domain)
+{
+ if (!component.has_curves()) {
+ return {};
+ }
+ const Curves &curves_id = *component.get_for_read();
+ const bke::CurvesGeometry &curves = bke::CurvesGeometry::wrap(curves_id.geometry);
+
+ curves.ensure_evaluated_lengths();
+
+ VArray<bool> cyclic = curves.cyclic();
+ VArray<float> lengths = VArray<float>::ForFunc(
+ curves.curves_num(), [&curves, cyclic = std::move(cyclic)](int64_t index) {
+ return curves.evaluated_length_total_for_curve(index, cyclic[index]);
+ });
+
+ if (domain == ATTR_DOMAIN_CURVE) {
+ return lengths;
+ }
+
+ if (domain == ATTR_DOMAIN_POINT) {
+ return component.attribute_try_adapt_domain<float>(
+ std::move(lengths), ATTR_DOMAIN_CURVE, ATTR_DOMAIN_POINT);
+ }
+
+ return {};
+}
+
+CurveLengthFieldInput::CurveLengthFieldInput()
+ : GeometryFieldInput(CPPType::get<float>(), "Spline Length node")
+{
+ category_ = Category::Generated;
+}
+
+GVArray CurveLengthFieldInput::get_varray_for_context(const GeometryComponent &component,
+ const AttributeDomain domain,
+ IndexMask UNUSED(mask)) const
+{
+ if (component.type() == GEO_COMPONENT_TYPE_CURVE) {
+ const CurveComponent &curve_component = static_cast<const CurveComponent &>(component);
+ return construct_curve_length_gvarray(curve_component, domain);
+ }
+ return {};
+}
+
+uint64_t CurveLengthFieldInput::hash() const
+{
+ /* Some random constant hash. */
+ return 3549623580;
+}
+
+bool CurveLengthFieldInput::is_equal_to(const fn::FieldNode &other) const
+{
+ return dynamic_cast<const CurveLengthFieldInput *>(&other) != nullptr;
+}
/** \} */
+} // namespace blender::bke
+
/* -------------------------------------------------------------------- */
/** \name Attribute Access Helper Functions
* \{ */
-int CurveComponent::attribute_domain_size(const AttributeDomain domain) const
+int CurveComponent::attribute_domain_num(const AttributeDomain 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;
}
diff --git a/source/blender/blenkernel/intern/geometry_component_instances.cc b/source/blender/blenkernel/intern/geometry_component_instances.cc
index 0dc6f486d28..e56a7ca4dd8 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 AttributeDomain 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..5ac9a03f43c 100644
--- a/source/blender/blenkernel/intern/geometry_component_mesh.cc
+++ b/source/blender/blenkernel/intern/geometry_component_mesh.cc
@@ -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 AttributeDomain domain) const
{
if (mesh_ == nullptr) {
return 0;
@@ -839,20 +839,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)
@@ -1160,7 +1160,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..6de123c7cb9 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 AttributeDomain 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..40e36ced199 100644
--- a/source/blender/blenkernel/intern/geometry_set.cc
+++ b/source/blender/blenkernel/intern/geometry_set.cc
@@ -272,7 +272,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
diff --git a/source/blender/blenkernel/intern/gpencil.c b/source/blender/blenkernel/intern/gpencil.c
index 699f8b356bd..f86e947910b 100644
--- a/source/blender/blenkernel/intern/gpencil.c
+++ b/source/blender/blenkernel/intern/gpencil.c
@@ -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/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..e99230ef523 100644
--- a/source/blender/blenkernel/intern/idprop.c
+++ b/source/blender/blenkernel/intern/idprop.c
@@ -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 4bf25c24235..06a5d877882 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);
}
}
@@ -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;
}
}
}
@@ -2951,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));
@@ -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);
@@ -3931,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 {
@@ -4001,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));
}
@@ -5108,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..bed79a318e8 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]);
}
@@ -845,7 +757,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 +772,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 +806,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 +855,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 5361f234a63..6bfdaf9b522 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)
@@ -105,12 +309,17 @@ static void image_save_post(ReportList *reports,
BLI_path_rel(ima->filepath, relbase); /* only after saving */
}
- ColorManagedColorspaceSettings old_colorspace_settings;
- BKE_color_managed_colorspace_settings_copy(&old_colorspace_settings, &ima->colorspace_settings);
- IMB_colormanagement_colorspace_from_ibuf_ftype(&ima->colorspace_settings, ibuf);
- if (!BKE_color_managed_colorspace_settings_equals(&old_colorspace_settings,
- &ima->colorspace_settings)) {
- *r_colorspace_changed = true;
+ /* 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);
+
+ 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 */
@@ -787,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..528681d196e 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
}
diff --git a/source/blender/blenkernel/intern/lib_override.c b/source/blender/blenkernel/intern/lib_override.c
index 768ac4f606f..50c9514e810 100644
--- a/source/blender/blenkernel/intern/lib_override.c
+++ b/source/blender/blenkernel/intern/lib_override.c
@@ -72,6 +72,21 @@ 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)
{
@@ -383,7 +398,8 @@ 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));
/* If we do not have any hierarchy root given, then the root reference must be tagged for
@@ -449,6 +465,9 @@ bool BKE_lib_override_library_create_from_tag(Main *bmain,
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;
@@ -978,7 +997,8 @@ 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,
@@ -1002,12 +1022,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,
+ NULL,
+ 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,
+ NULL,
+ id_hierarchy_root_reference,
+ false,
+ do_fully_editable);
}
return success;
@@ -1165,7 +1195,8 @@ 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;
@@ -1175,8 +1206,12 @@ bool BKE_lib_override_library_create(Main *bmain,
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;
@@ -1219,12 +1254,11 @@ 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;
}
if (!ID_IS_OVERRIDE_LIBRARY(id)) {
- BLI_assert(0);
+ BLI_assert_unreachable();
return NULL;
}
@@ -1666,7 +1700,13 @@ 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,
+ NULL,
+ id_root_reference,
+ id_root->override_library->hierarchy_root,
+ NULL,
+ true,
+ false);
if (!success) {
BLI_ghash_free(linkedref_to_old_override, NULL, NULL);
@@ -1704,6 +1744,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));
@@ -2088,9 +2130,7 @@ 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);
- if (id_root->override_library == NULL) {
- BLI_assert(0);
- }
+ BLI_assert(id_root->override_library != NULL);
LinkNodePair **id_resync_roots_p;
if (!BLI_ghash_ensure_p(id_roots, id_root, (void ***)&id_resync_roots_p)) {
@@ -2344,7 +2384,6 @@ static int lib_override_sort_libraries_func(LibraryIDLinkCallbackData *cb_data)
id_owner->lib->filepath,
id->name,
id->lib->filepath);
- BLI_assert(0);
return IDWALK_RET_NOP;
}
@@ -3429,6 +3468,8 @@ 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);
diff --git a/source/blender/blenkernel/intern/lib_override_proxy_conversion.c b/source/blender/blenkernel/intern/lib_override_proxy_conversion.c
index 7fa9ba5dca9..88f6fbb0ead 100644
--- a/source/blender/blenkernel/intern/lib_override_proxy_conversion.c
+++ b/source/blender/blenkernel/intern/lib_override_proxy_conversion.c
@@ -83,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..2600a40153c 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++;
}
@@ -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/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..e5b875cadf9 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;
}
diff --git a/source/blender/blenkernel/intern/mesh.cc b/source/blender/blenkernel/intern/mesh.cc
index 628f59ae449..0becea62810 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);
@@ -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_convert.cc b/source/blender/blenkernel/intern/mesh_convert.cc
index 0d34c8ad6b1..cc4a995b1b1 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"
@@ -943,24 +944,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;
@@ -968,12 +954,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;
@@ -1392,7 +1376,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) {
@@ -1409,7 +1393,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_remesh_voxel.cc b/source/blender/blenkernel/intern/mesh_remesh_voxel.cc
index 02c9f61957d..c960a7f35f1 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);
}
diff --git a/source/blender/blenkernel/intern/mesh_tangent.c b/source/blender/blenkernel/intern/mesh_tangent.c
index f2e46c3bd92..c0b2b33c47c 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) {
@@ -173,7 +172,7 @@ void BKE_mesh_calc_loop_tangent_single(Mesh *mesh,
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/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_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/node.cc b/source/blender/blenkernel/intern/node.cc
index e9c8b438284..cf50e8a3b43 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,9 +676,7 @@ void ntreeBlendReadData(BlendDataReader *reader, bNodeTree *ntree)
ntree->progress = nullptr;
ntree->execdata = nullptr;
- ntree->runtime_flag = 0;
-
- 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);
@@ -680,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);
@@ -1117,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);
@@ -1166,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,
@@ -1512,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);
@@ -1917,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)
@@ -2122,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));
@@ -2159,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);
}
@@ -2191,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) {
@@ -2251,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;
@@ -2668,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;
}
@@ -2969,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) {
@@ -3063,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)
@@ -3289,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 */
@@ -3676,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;
}
@@ -4503,6 +4516,8 @@ static void registerCompositNodes()
register_node_type_cmp_premulkey();
register_node_type_cmp_separate_xyz();
register_node_type_cmp_combine_xyz();
+ register_node_type_cmp_separate_color();
+ register_node_type_cmp_combine_color();
register_node_type_cmp_diff_matte();
register_node_type_cmp_distance_matte();
@@ -4575,6 +4590,8 @@ static void registerShaderNodes()
register_node_type_sh_vect_transform();
register_node_type_sh_squeeze();
register_node_type_sh_invert();
+ register_node_type_sh_sepcolor();
+ register_node_type_sh_combcolor();
register_node_type_sh_seprgb();
register_node_type_sh_combrgb();
register_node_type_sh_sephsv();
@@ -4661,6 +4678,8 @@ static void registerTextureNodes()
register_node_type_tex_distance();
register_node_type_tex_compose();
register_node_type_tex_decompose();
+ register_node_type_tex_combine_color();
+ register_node_type_tex_separate_color();
register_node_type_tex_output();
register_node_type_tex_viewer();
@@ -4822,6 +4841,7 @@ static void registerFunctionNodes()
{
register_node_type_fn_align_euler_to_vector();
register_node_type_fn_boolean_math();
+ register_node_type_fn_combine_color();
register_node_type_fn_compare();
register_node_type_fn_float_to_int();
register_node_type_fn_input_bool();
@@ -4833,6 +4853,7 @@ static void registerFunctionNodes()
register_node_type_fn_random_value();
register_node_type_fn_replace_string();
register_node_type_fn_rotate_euler();
+ register_node_type_fn_separate_color();
register_node_type_fn_slice_string();
register_node_type_fn_string_length();
register_node_type_fn_value_to_string();
diff --git a/source/blender/blenkernel/intern/node_tree_update.cc b/source/blender/blenkernel/intern/node_tree_update.cc
index 68e4cccba00..019ab114b83 100644
--- a/source/blender/blenkernel/intern/node_tree_update.cc
+++ b/source/blender/blenkernel/intern/node_tree_update.cc
@@ -15,6 +15,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 "MOD_nodes.h"
@@ -48,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 {
@@ -172,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;
@@ -551,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),
@@ -567,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;
}
@@ -799,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);
}
}
@@ -817,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);
@@ -830,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)) {
@@ -1002,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;
}
@@ -1057,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;
}
}
}
@@ -1077,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()) {
@@ -1101,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;
}
@@ -1232,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)
@@ -1250,7 +1252,7 @@ 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);
@@ -1259,7 +1261,7 @@ class NodeTreeMainUpdater {
void propagate_runtime_flags(const NodeTreeRef &tree_ref)
{
bNodeTree &ntree = *tree_ref.btree();
- ntree.runtime_flag = 0;
+ ntree.runtime->runtime_flag = 0;
if (ntree.type != NTREE_SHADER) {
return;
}
@@ -1268,7 +1270,7 @@ class NodeTreeMainUpdater {
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_flag |= group->runtime_flag;
+ ntree.runtime->runtime_flag |= group->runtime->runtime_flag;
}
}
/* Check if the tree itself has an animated image. */
@@ -1276,7 +1278,7 @@ class NodeTreeMainUpdater {
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_flag |= NTREE_RUNTIME_FLAG_HAS_IMAGE_ANIMATION;
+ ntree.runtime->runtime_flag |= NTREE_RUNTIME_FLAG_HAS_IMAGE_ANIMATION;
break;
}
}
@@ -1288,7 +1290,7 @@ class NodeTreeMainUpdater {
"ShaderNodeOutputAOV"}) {
const Span<const NodeRef *> nodes = tree_ref.nodes_by_type(idname);
if (!nodes.is_empty()) {
- ntree.runtime_flag |= NTREE_RUNTIME_FLAG_HAS_MATERIAL_OUTPUT;
+ ntree.runtime->runtime_flag |= NTREE_RUNTIME_FLAG_HAS_MATERIAL_OUTPUT;
break;
}
}
@@ -1323,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
@@ -1352,7 +1354,7 @@ class NodeTreeMainUpdater {
}
}
- if (btree.changed_flag & NTREE_CHANGED_ANY) {
+ if (btree.runtime->changed_flag & NTREE_CHANGED_ANY) {
return true;
}
@@ -1361,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;
}
@@ -1404,7 +1406,7 @@ class NodeTreeMainUpdater {
if (bnode.type == NODE_GROUP) {
const bNodeTree *node_group = reinterpret_cast<const bNodeTree *>(bnode.id);
if (node_group != nullptr &&
- node_group->runtime_flag & NTREE_RUNTIME_FLAG_HAS_MATERIAL_OUTPUT) {
+ node_group->runtime->runtime_flag & NTREE_RUNTIME_FLAG_HAS_MATERIAL_OUTPUT) {
return true;
}
}
@@ -1540,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;
@@ -1591,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 2a25d73ed87..55b9951c52d 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);
@@ -2114,7 +2114,7 @@ static const char *get_obdata_defname(int type)
case OB_SPEAKER:
return DATA_("Speaker");
case OB_CURVES:
- return DATA_("HairCurves");
+ return DATA_("Curves");
case OB_POINTCLOUD:
return DATA_("PointCloud");
case OB_VOLUME:
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..cff7eb20b05 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;
}
@@ -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;
}
diff --git a/source/blender/blenkernel/intern/particle.c b/source/blender/blenkernel/intern/particle.c
index b935f2afaaa..a5f7f73af70 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(
@@ -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..4be48efb2b5 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);
@@ -1219,7 +1219,7 @@ static int psys_thread_context_init_distribute(ParticleThreadContext *ctx,
/* For hair, sort by 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..a7ab1536b1f 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;
diff --git a/source/blender/blenkernel/intern/pbvh_intern.h b/source/blender/blenkernel/intern/pbvh_intern.h
index c7c8fbe8bce..a86663a9c74 100644
--- a/source/blender/blenkernel/intern/pbvh_intern.h
+++ b/source/blender/blenkernel/intern/pbvh_intern.h
@@ -10,6 +10,11 @@
extern "C" {
#endif
+struct MLoop;
+struct MLoopTri;
+struct MPoly;
+struct MVert;
+
/* Axis-aligned bounding box */
typedef struct {
float bmin[3], bmax[3];
@@ -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;
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..2467ca16670 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) {
diff --git a/source/blender/blenkernel/intern/pointcloud.cc b/source/blender/blenkernel/intern/pointcloud.cc
index 3ee46fc4f15..9720c61e3b9 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)
diff --git a/source/blender/blenkernel/intern/sound.c b/source/blender/blenkernel/intern/sound.c
index 864a4f3281b..de5589cf5dc 100644
--- a/source/blender/blenkernel/intern/sound.c
+++ b/source/blender/blenkernel/intern/sound.c
@@ -264,6 +264,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);
@@ -1202,6 +1210,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;
}
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..04a274d0215 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_converter_mesh.c b/source/blender/blenkernel/intern/subdiv_converter_mesh.c
index 1c5078df1f3..12a5f00a68b 100644
--- a/source/blender/blenkernel/intern/subdiv_converter_mesh.c
+++ b/source/blender/blenkernel/intern/subdiv_converter_mesh.c
@@ -295,16 +295,16 @@ static void init_functions(OpenSubdiv_Converter *converter)
static void initialize_manifold_index_array(const BLI_bitmap *used_map,
const int num_elements,
- int **indices_r,
- int **indices_reverse_r,
- int *num_manifold_elements_r)
+ int **r_indices,
+ int **r_indices_reverse,
+ int *r_num_manifold_elements)
{
int *indices = NULL;
- if (indices_r != NULL) {
+ if (r_indices != NULL) {
indices = MEM_malloc_arrayN(num_elements, sizeof(int), "manifold indices");
}
int *indices_reverse = NULL;
- if (indices_reverse_r != NULL) {
+ if (r_indices_reverse != NULL) {
indices_reverse = MEM_malloc_arrayN(num_elements, sizeof(int), "manifold indices reverse");
}
int offset = 0;
@@ -324,13 +324,13 @@ static void initialize_manifold_index_array(const BLI_bitmap *used_map,
offset++;
}
}
- if (indices_r != NULL) {
- *indices_r = indices;
+ if (r_indices != NULL) {
+ *r_indices = indices;
}
- if (indices_reverse_r != NULL) {
- *indices_reverse_r = indices_reverse;
+ if (r_indices_reverse != NULL) {
+ *r_indices_reverse = indices_reverse;
}
- *num_manifold_elements_r = num_elements - offset;
+ *r_num_manifold_elements = num_elements - offset;
}
static void initialize_manifold_indices(ConverterStorage *storage)
diff --git a/source/blender/blenkernel/intern/subdiv_eval.c b/source/blender/blenkernel/intern/subdiv_eval.c
index b8f6dc322c5..1996273b681 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,7 +42,9 @@ 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,
@@ -269,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])
diff --git a/source/blender/blenkernel/intern/subsurf_ccg.c b/source/blender/blenkernel/intern/subsurf_ccg.c
index 5e7a0fc116b..ba2df362b92 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)
{
@@ -1336,8 +1247,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 +1287,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 +1330,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 +1504,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 +1579,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 +1595,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 +1607,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 +2067,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/tracking.c b/source/blender/blenkernel/intern/tracking.c
index 348d6a91eb8..f9d3a44e5cb 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)
@@ -435,7 +437,9 @@ void BKE_tracking_get_projection_matrix(MovieTracking *tracking,
}
}
-/*********************** clipboard *************************/
+/* --------------------------------------------------------------------
+ * Clipboard.
+ */
void BKE_tracking_clipboard_free(void)
{
@@ -496,7 +500,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 +727,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;
-
- 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++;
- }
+ 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 (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 +1291,9 @@ void BKE_tracking_tracks_deselect_all(ListBase *tracksbase)
}
}
-/*********************** Marker *************************/
+/* --------------------------------------------------------------------
+ * Marker.
+ */
MovieTrackingMarker *BKE_tracking_marker_insert(MovieTrackingTrack *track,
MovieTrackingMarker *marker)
@@ -1350,60 +1367,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 +1600,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 +1807,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 +1987,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 +2134,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 +2292,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 +2607,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 +2853,9 @@ void BKE_tracking_disable_channels(
}
}
-/*********************** Dopesheet functions *************************/
+/* --------------------------------------------------------------------
+ * Dopesheet functions.
+ */
/* ** Channels sort comparators ** */
diff --git a/source/blender/blenkernel/intern/tracking_plane_tracker.c b/source/blender/blenkernel/intern/tracking_plane_tracker.c
index 5e60f6f59a9..c4379ea61bc 100644
--- a/source/blender/blenkernel/intern/tracking_plane_tracker.c
+++ b/source/blender/blenkernel/intern/tracking_plane_tracker.c
@@ -21,12 +21,12 @@
typedef double Vec2[2];
static int point_markers_correspondences_on_both_image(
- MovieTrackingPlaneTrack *plane_track, int frame1, int frame2, Vec2 **x1_r, Vec2 **x2_r)
+ MovieTrackingPlaneTrack *plane_track, int frame1, int frame2, Vec2 **r_x1, Vec2 **r_x2)
{
Vec2 *x1, *x2;
- *x1_r = x1 = MEM_mallocN(sizeof(*x1) * plane_track->point_tracksnr, "point correspondences x1");
- *x2_r = x2 = MEM_mallocN(sizeof(*x1) * plane_track->point_tracksnr, "point correspondences x2");
+ *r_x1 = x1 = MEM_mallocN(sizeof(*x1) * plane_track->point_tracksnr, "point correspondences x1");
+ *r_x2 = x2 = MEM_mallocN(sizeof(*x1) * plane_track->point_tracksnr, "point correspondences x2");
int correspondence_index = 0;
for (int i = 0; i < plane_track->point_tracksnr; i++) {
diff --git a/source/blender/blenkernel/intern/unit.c b/source/blender/blenkernel/intern/unit.c
index 02134623a31..30e02e5411b 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. */
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_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_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_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_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_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 0344622e81d..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.
*
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_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..6efd1d6d769 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
diff --git a/source/blender/blenlib/CMakeLists.txt b/source/blender/blenlib/CMakeLists.txt
index e0f28522d6c..109230ebfa7 100644
--- a/source/blender/blenlib/CMakeLists.txt
+++ b/source/blender/blenlib/CMakeLists.txt
@@ -79,8 +79,8 @@ set(SRC
intern/kdtree_3d.c
intern/kdtree_4d.c
intern/lasso_2d.c
- intern/listbase.c
intern/length_parameterize.cc
+ intern/listbase.c
intern/math_base.c
intern/math_base_inline.c
intern/math_base_safe_inline.c
@@ -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
@@ -274,8 +275,8 @@ set(SRC
BLI_multi_value_map.hh
BLI_noise.h
BLI_noise.hh
- BLI_path_util.h
BLI_parameter_pack_utils.hh
+ BLI_path_util.h
BLI_polyfill_2d.h
BLI_polyfill_2d_beautify.h
BLI_probing_strategies.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
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/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/hash_md5.c b/source/blender/blenlib/intern/hash_md5.c
index cc59662b6de..9da8c0a0941 100644
--- a/source/blender/blenlib/intern/hash_md5.c
+++ b/source/blender/blenlib/intern/hash_md5.c
@@ -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];
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_color.c b/source/blender/blenlib/intern/math_color.c
index 0955f5d1b5a..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;
@@ -238,7 +238,7 @@ void rgb_to_hsl(float r, float g, float b, float *r_h, float *r_s, float *r_l)
{
const float cmax = max_fff(r, g, b);
const float cmin = min_fff(r, g, b);
- float h, s, l = min_ff(1.0, (cmax + cmin) / 2.0f);
+ float h, s, l = min_ff(1.0f, (cmax + cmin) / 2.0f);
if (cmax == cmin) {
h = s = 0.0f; /* achromatic */
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/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 8387eb5f4f9..976b9a5cd02 100644
--- a/source/blender/blenlib/intern/string.c
+++ b/source/blender/blenlib/intern/string.c
@@ -1155,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/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_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_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 27890a908ab..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));
}
}
}
@@ -2068,7 +2067,7 @@ static void direct_link_id_embedded_id(BlendDataReader *reader,
static int direct_link_id_restore_recalc_exceptions(const ID *id_current)
{
/* Exception for armature objects, where the pose has direct points to the
- * armature databolock. */
+ * armature data-block. */
if (GS(id_current->name) == ID_OB && ((Object *)id_current)->pose) {
return ID_RECALC_GEOMETRY;
}
@@ -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..eeec55a7b06 100644
--- a/source/blender/blenloader/intern/versioning_280.c
+++ b/source/blender/blenloader/intern/versioning_280.c
@@ -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..585ada3b2d8 100644
--- a/source/blender/blenloader/intern/versioning_290.c
+++ b/source/blender/blenloader/intern/versioning_290.c
@@ -360,8 +360,8 @@ static void seq_update_meta_disp_range(Editing *ed)
}
/* 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_time_left_handle_frame_set(ms->parseq, ms->disp_range[0]);
+ SEQ_time_right_handle_frame_set(ms->parseq, ms->disp_range[1]);
SEQ_transform_fix_single_image_seq_offsets(ms->parseq);
/* Recalculate effects using meta strip. */
@@ -1666,13 +1666,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 e6a214452fe..83d325e9c40 100644
--- a/source/blender/blenloader/intern/versioning_300.c
+++ b/source/blender/blenloader/intern/versioning_300.c
@@ -63,7 +63,7 @@
#include "RNA_prototypes.h"
#include "BLO_readfile.h"
-#include "MEM_guardedalloc.h"
+
#include "readfile.h"
#include "SEQ_channels.h"
@@ -71,8 +71,6 @@
#include "SEQ_sequencer.h"
#include "SEQ_time.h"
-#include "RNA_access.h"
-
#include "versioning_common.h"
static CLG_LogRef LOG = {"blo.readfile.doversion"};
@@ -1217,6 +1215,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.
@@ -2735,6 +2742,13 @@ void blo_do_versions_300(FileData *fd, Library *UNUSED(lib), Main *bmain)
}
}
FOREACH_NODETREE_END;
+
+ LISTBASE_FOREACH (bNodeTree *, ntree, &bmain->nodetrees) {
+ if (ntree->type == NTREE_GEOMETRY) {
+ version_node_input_socket_name(
+ ntree, GEO_NODE_SUBDIVISION_SURFACE, "Crease", "Edge Crease");
+ }
+ }
}
if (!MAIN_VERSION_ATLEAST(bmain, 302, 13)) {
@@ -2772,5 +2786,279 @@ void blo_do_versions_300(FileData *fd, Library *UNUSED(lib), Main *bmain)
*/
{
/* Keep this block, even when empty. */
+
+ /* Replace legacy combine/separate color nodes */
+ 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");
+
+ 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;
+ }
+ }
+ }
+ }
+ }
+ 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;
+ }
+ }
+
+ /* 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;
+ }
+ }
+ }
+
+ /* 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);
+ }
+ }
}
}
diff --git a/source/blender/blenloader/intern/writefile.c b/source/blender/blenloader/intern/writefile.c
index 22db54d7609..65c42545a77 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\n", 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\n",
+ 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);
}
@@ -1415,7 +1423,7 @@ 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;
}
@@ -1490,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>\n", struct_name);
return;
}
BLO_write_struct_array_by_id(writer, struct_id, array_size, data_ptr);
@@ -1538,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>\n", struct_name);
return;
}
BLO_write_struct_list_by_id(writer, struct_id, list);
diff --git a/source/blender/bmesh/bmesh_class.h b/source/blender/bmesh/bmesh_class.h
index 0246850123a..9d5737a5b71 100644
--- a/source/blender/bmesh/bmesh_class.h
+++ b/source/blender/bmesh/bmesh_class.h
@@ -265,8 +265,20 @@ typedef struct BMFace {
* (the length of #BMFace.l_first circular linked list).
*/
int len;
- float no[3]; /* face normal */
- short mat_nr; /* material index */
+ /**
+ * Face normal, see #BM_face_calc_normal.
+ */
+ float no[3];
+ /**
+ * Material index, typically >= 0 and < #Mesh.totcol although this isn't enforced
+ * Python for e.g. can set this to any positive value since scripts may create
+ * mesh data first and setup material slots later.
+ *
+ * When using to index into a material array it's range should be checked first,
+ * values exceeding the range should be ignored or treated as zero
+ * (if a material slot needs to be used - when drawing for e.g.)
+ */
+ short mat_nr;
// short _pad[3];
} BMFace;
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_mesh_convert.cc b/source/blender/bmesh/intern/bmesh_mesh_convert.cc
index 40f1d7c496d..bb1fe749e6b 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);
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/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/CMakeLists.txt b/source/blender/compositor/CMakeLists.txt
index 66f813e02b2..55e349423bb 100644
--- a/source/blender/compositor/CMakeLists.txt
+++ b/source/blender/compositor/CMakeLists.txt
@@ -259,12 +259,16 @@ set(SRC
# converter nodes
nodes/COM_CombineColorNode.cc
nodes/COM_CombineColorNode.h
+ nodes/COM_CombineColorNodeLegacy.cc
+ nodes/COM_CombineColorNodeLegacy.h
nodes/COM_CombineXYZNode.cc
nodes/COM_CombineXYZNode.h
nodes/COM_IDMaskNode.cc
nodes/COM_IDMaskNode.h
nodes/COM_SeparateColorNode.cc
nodes/COM_SeparateColorNode.h
+ nodes/COM_SeparateColorNodeLegacy.cc
+ nodes/COM_SeparateColorNodeLegacy.h
nodes/COM_SeparateXYZNode.cc
nodes/COM_SeparateXYZNode.h
diff --git a/source/blender/compositor/intern/COM_Converter.cc b/source/blender/compositor/intern/COM_Converter.cc
index 13d412a338b..6d7341376e9 100644
--- a/source/blender/compositor/intern/COM_Converter.cc
+++ b/source/blender/compositor/intern/COM_Converter.cc
@@ -29,6 +29,7 @@
#include "COM_ColorSpillNode.h"
#include "COM_ColorToBWNode.h"
#include "COM_CombineColorNode.h"
+#include "COM_CombineColorNodeLegacy.h"
#include "COM_CombineXYZNode.h"
#include "COM_CompositorNode.h"
#include "COM_ConvertAlphaNode.h"
@@ -82,6 +83,7 @@
#include "COM_ScaleOperation.h"
#include "COM_SceneTimeNode.h"
#include "COM_SeparateColorNode.h"
+#include "COM_SeparateColorNodeLegacy.h"
#include "COM_SeparateXYZNode.h"
#include "COM_SetAlphaNode.h"
#include "COM_SetValueOperation.h"
@@ -169,28 +171,34 @@ Node *COM_convert_bnode(bNode *b_node)
case CMP_NODE_BRIGHTCONTRAST:
node = new BrightnessNode(b_node);
break;
- case CMP_NODE_SEPRGBA:
+ case CMP_NODE_SEPARATE_COLOR:
+ node = new SeparateColorNode(b_node);
+ break;
+ case CMP_NODE_COMBINE_COLOR:
+ node = new CombineColorNode(b_node);
+ break;
+ case CMP_NODE_SEPRGBA_LEGACY:
node = new SeparateRGBANode(b_node);
break;
- case CMP_NODE_COMBRGBA:
+ case CMP_NODE_COMBRGBA_LEGACY:
node = new CombineRGBANode(b_node);
break;
- case CMP_NODE_SEPHSVA:
+ case CMP_NODE_SEPHSVA_LEGACY:
node = new SeparateHSVANode(b_node);
break;
- case CMP_NODE_COMBHSVA:
+ case CMP_NODE_COMBHSVA_LEGACY:
node = new CombineHSVANode(b_node);
break;
- case CMP_NODE_SEPYUVA:
+ case CMP_NODE_SEPYUVA_LEGACY:
node = new SeparateYUVANode(b_node);
break;
- case CMP_NODE_COMBYUVA:
+ case CMP_NODE_COMBYUVA_LEGACY:
node = new CombineYUVANode(b_node);
break;
- case CMP_NODE_SEPYCCA:
+ case CMP_NODE_SEPYCCA_LEGACY:
node = new SeparateYCCANode(b_node);
break;
- case CMP_NODE_COMBYCCA:
+ case CMP_NODE_COMBYCCA_LEGACY:
node = new CombineYCCANode(b_node);
break;
case CMP_NODE_ALPHAOVER:
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/nodes/COM_CombineColorNode.cc b/source/blender/compositor/nodes/COM_CombineColorNode.cc
index 0c8748fd2d6..ca2c59478fd 100644
--- a/source/blender/compositor/nodes/COM_CombineColorNode.cc
+++ b/source/blender/compositor/nodes/COM_CombineColorNode.cc
@@ -12,7 +12,7 @@ CombineColorNode::CombineColorNode(bNode *editor_node) : Node(editor_node)
}
void CombineColorNode::convert_to_operations(NodeConverter &converter,
- const CompositorContext &context) const
+ const CompositorContext &UNUSED(context)) const
{
NodeInput *input_rsocket = this->get_input_socket(0);
NodeInput *input_gsocket = this->get_input_socket(1);
@@ -40,7 +40,39 @@ void CombineColorNode::convert_to_operations(NodeConverter &converter,
converter.map_input_socket(input_bsocket, operation->get_input_socket(2));
converter.map_input_socket(input_asocket, operation->get_input_socket(3));
- NodeOperation *color_conv = get_color_converter(context);
+ bNode *editor_node = this->get_bnode();
+ NodeCMPCombSepColor *storage = (NodeCMPCombSepColor *)editor_node->storage;
+
+ NodeOperation *color_conv = nullptr;
+ switch (storage->mode) {
+ case CMP_NODE_COMBSEP_COLOR_RGB: {
+ /* Pass */
+ break;
+ }
+ case CMP_NODE_COMBSEP_COLOR_HSV: {
+ color_conv = new ConvertHSVToRGBOperation();
+ break;
+ }
+ case CMP_NODE_COMBSEP_COLOR_HSL: {
+ color_conv = new ConvertHSLToRGBOperation();
+ break;
+ }
+ case CMP_NODE_COMBSEP_COLOR_YCC: {
+ ConvertYCCToRGBOperation *operation = new ConvertYCCToRGBOperation();
+ operation->set_mode(storage->ycc_mode);
+ color_conv = operation;
+ break;
+ }
+ case CMP_NODE_COMBSEP_COLOR_YUV: {
+ color_conv = new ConvertYUVToRGBOperation();
+ break;
+ }
+ default: {
+ BLI_assert_unreachable();
+ break;
+ }
+ }
+
if (color_conv) {
converter.add_operation(color_conv);
@@ -52,27 +84,4 @@ void CombineColorNode::convert_to_operations(NodeConverter &converter,
}
}
-NodeOperation *CombineRGBANode::get_color_converter(const CompositorContext & /*context*/) const
-{
- return nullptr; /* no conversion needed */
-}
-
-NodeOperation *CombineHSVANode::get_color_converter(const CompositorContext & /*context*/) const
-{
- return new ConvertHSVToRGBOperation();
-}
-
-NodeOperation *CombineYCCANode::get_color_converter(const CompositorContext & /*context*/) const
-{
- ConvertYCCToRGBOperation *operation = new ConvertYCCToRGBOperation();
- bNode *editor_node = this->get_bnode();
- operation->set_mode(editor_node->custom1);
- return operation;
-}
-
-NodeOperation *CombineYUVANode::get_color_converter(const CompositorContext & /*context*/) const
-{
- return new ConvertYUVToRGBOperation();
-}
-
} // namespace blender::compositor
diff --git a/source/blender/compositor/nodes/COM_CombineColorNode.h b/source/blender/compositor/nodes/COM_CombineColorNode.h
index 2bead24cb02..7576cc9eb2d 100644
--- a/source/blender/compositor/nodes/COM_CombineColorNode.h
+++ b/source/blender/compositor/nodes/COM_CombineColorNode.h
@@ -12,45 +12,6 @@ class CombineColorNode : public Node {
CombineColorNode(bNode *editor_node);
void convert_to_operations(NodeConverter &converter,
const CompositorContext &context) const override;
-
- protected:
- virtual NodeOperation *get_color_converter(const CompositorContext &context) const = 0;
-};
-
-class CombineRGBANode : public CombineColorNode {
- public:
- CombineRGBANode(bNode *editor_node) : CombineColorNode(editor_node)
- {
- }
-
- NodeOperation *get_color_converter(const CompositorContext &context) const override;
-};
-
-class CombineHSVANode : public CombineColorNode {
- public:
- CombineHSVANode(bNode *editor_node) : CombineColorNode(editor_node)
- {
- }
-
- NodeOperation *get_color_converter(const CompositorContext &context) const override;
-};
-
-class CombineYCCANode : public CombineColorNode {
- public:
- CombineYCCANode(bNode *editor_node) : CombineColorNode(editor_node)
- {
- }
-
- NodeOperation *get_color_converter(const CompositorContext &context) const override;
-};
-
-class CombineYUVANode : public CombineColorNode {
- public:
- CombineYUVANode(bNode *editor_node) : CombineColorNode(editor_node)
- {
- }
-
- NodeOperation *get_color_converter(const CompositorContext &context) const override;
};
} // namespace blender::compositor
diff --git a/source/blender/compositor/nodes/COM_CombineColorNodeLegacy.cc b/source/blender/compositor/nodes/COM_CombineColorNodeLegacy.cc
new file mode 100644
index 00000000000..d5ba379bfc2
--- /dev/null
+++ b/source/blender/compositor/nodes/COM_CombineColorNodeLegacy.cc
@@ -0,0 +1,78 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later
+ * Copyright 2011 Blender Foundation. */
+
+#include "COM_CombineColorNodeLegacy.h"
+
+#include "COM_ConvertOperation.h"
+
+namespace blender::compositor {
+
+CombineColorNodeLegacy::CombineColorNodeLegacy(bNode *editor_node) : Node(editor_node)
+{
+}
+
+void CombineColorNodeLegacy::convert_to_operations(NodeConverter &converter,
+ const CompositorContext &context) const
+{
+ NodeInput *input_rsocket = this->get_input_socket(0);
+ NodeInput *input_gsocket = this->get_input_socket(1);
+ NodeInput *input_bsocket = this->get_input_socket(2);
+ NodeInput *input_asocket = this->get_input_socket(3);
+ NodeOutput *output_socket = this->get_output_socket(0);
+
+ CombineChannelsOperation *operation = new CombineChannelsOperation();
+ if (input_rsocket->is_linked()) {
+ operation->set_canvas_input_index(0);
+ }
+ else if (input_gsocket->is_linked()) {
+ operation->set_canvas_input_index(1);
+ }
+ else if (input_bsocket->is_linked()) {
+ operation->set_canvas_input_index(2);
+ }
+ else {
+ operation->set_canvas_input_index(3);
+ }
+ converter.add_operation(operation);
+
+ converter.map_input_socket(input_rsocket, operation->get_input_socket(0));
+ converter.map_input_socket(input_gsocket, operation->get_input_socket(1));
+ converter.map_input_socket(input_bsocket, operation->get_input_socket(2));
+ converter.map_input_socket(input_asocket, operation->get_input_socket(3));
+
+ NodeOperation *color_conv = get_color_converter(context);
+ if (color_conv) {
+ converter.add_operation(color_conv);
+
+ converter.add_link(operation->get_output_socket(), color_conv->get_input_socket(0));
+ converter.map_output_socket(output_socket, color_conv->get_output_socket());
+ }
+ else {
+ converter.map_output_socket(output_socket, operation->get_output_socket());
+ }
+}
+
+NodeOperation *CombineRGBANode::get_color_converter(const CompositorContext & /*context*/) const
+{
+ return nullptr; /* no conversion needed */
+}
+
+NodeOperation *CombineHSVANode::get_color_converter(const CompositorContext & /*context*/) const
+{
+ return new ConvertHSVToRGBOperation();
+}
+
+NodeOperation *CombineYCCANode::get_color_converter(const CompositorContext & /*context*/) const
+{
+ ConvertYCCToRGBOperation *operation = new ConvertYCCToRGBOperation();
+ bNode *editor_node = this->get_bnode();
+ operation->set_mode(editor_node->custom1);
+ return operation;
+}
+
+NodeOperation *CombineYUVANode::get_color_converter(const CompositorContext & /*context*/) const
+{
+ return new ConvertYUVToRGBOperation();
+}
+
+} // namespace blender::compositor
diff --git a/source/blender/compositor/nodes/COM_CombineColorNodeLegacy.h b/source/blender/compositor/nodes/COM_CombineColorNodeLegacy.h
new file mode 100644
index 00000000000..edc66c8932f
--- /dev/null
+++ b/source/blender/compositor/nodes/COM_CombineColorNodeLegacy.h
@@ -0,0 +1,56 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later
+ * Copyright 2011 Blender Foundation. */
+
+#pragma once
+
+#include "COM_Node.h"
+
+namespace blender::compositor {
+
+class CombineColorNodeLegacy : public Node {
+ public:
+ CombineColorNodeLegacy(bNode *editor_node);
+ void convert_to_operations(NodeConverter &converter,
+ const CompositorContext &context) const override;
+
+ protected:
+ virtual NodeOperation *get_color_converter(const CompositorContext &context) const = 0;
+};
+
+class CombineRGBANode : public CombineColorNodeLegacy {
+ public:
+ CombineRGBANode(bNode *editor_node) : CombineColorNodeLegacy(editor_node)
+ {
+ }
+
+ NodeOperation *get_color_converter(const CompositorContext &context) const override;
+};
+
+class CombineHSVANode : public CombineColorNodeLegacy {
+ public:
+ CombineHSVANode(bNode *editor_node) : CombineColorNodeLegacy(editor_node)
+ {
+ }
+
+ NodeOperation *get_color_converter(const CompositorContext &context) const override;
+};
+
+class CombineYCCANode : public CombineColorNodeLegacy {
+ public:
+ CombineYCCANode(bNode *editor_node) : CombineColorNodeLegacy(editor_node)
+ {
+ }
+
+ NodeOperation *get_color_converter(const CompositorContext &context) const override;
+};
+
+class CombineYUVANode : public CombineColorNodeLegacy {
+ public:
+ CombineYUVANode(bNode *editor_node) : CombineColorNodeLegacy(editor_node)
+ {
+ }
+
+ NodeOperation *get_color_converter(const CompositorContext &context) const override;
+};
+
+} // namespace blender::compositor
diff --git a/source/blender/compositor/nodes/COM_SeparateColorNode.cc b/source/blender/compositor/nodes/COM_SeparateColorNode.cc
index 221d80e67f2..a956c02ed42 100644
--- a/source/blender/compositor/nodes/COM_SeparateColorNode.cc
+++ b/source/blender/compositor/nodes/COM_SeparateColorNode.cc
@@ -12,7 +12,7 @@ SeparateColorNode::SeparateColorNode(bNode *editor_node) : Node(editor_node)
}
void SeparateColorNode::convert_to_operations(NodeConverter &converter,
- const CompositorContext &context) const
+ const CompositorContext &UNUSED(context)) const
{
NodeInput *image_socket = this->get_input_socket(0);
NodeOutput *output_rsocket = this->get_output_socket(0);
@@ -20,7 +20,39 @@ void SeparateColorNode::convert_to_operations(NodeConverter &converter,
NodeOutput *output_bsocket = this->get_output_socket(2);
NodeOutput *output_asocket = this->get_output_socket(3);
- NodeOperation *color_conv = get_color_converter(context);
+ bNode *editor_node = this->get_bnode();
+ NodeCMPCombSepColor *storage = (NodeCMPCombSepColor *)editor_node->storage;
+
+ NodeOperation *color_conv = nullptr;
+ switch (storage->mode) {
+ case CMP_NODE_COMBSEP_COLOR_RGB: {
+ /* Pass */
+ break;
+ }
+ case CMP_NODE_COMBSEP_COLOR_HSV: {
+ color_conv = new ConvertRGBToHSVOperation();
+ break;
+ }
+ case CMP_NODE_COMBSEP_COLOR_HSL: {
+ color_conv = new ConvertRGBToHSLOperation();
+ break;
+ }
+ case CMP_NODE_COMBSEP_COLOR_YCC: {
+ ConvertRGBToYCCOperation *operation = new ConvertRGBToYCCOperation();
+ operation->set_mode(storage->ycc_mode);
+ color_conv = operation;
+ break;
+ }
+ case CMP_NODE_COMBSEP_COLOR_YUV: {
+ color_conv = new ConvertRGBToYUVOperation();
+ break;
+ }
+ default: {
+ BLI_assert_unreachable();
+ break;
+ }
+ }
+
if (color_conv) {
converter.add_operation(color_conv);
@@ -84,27 +116,4 @@ void SeparateColorNode::convert_to_operations(NodeConverter &converter,
}
}
-NodeOperation *SeparateRGBANode::get_color_converter(const CompositorContext & /*context*/) const
-{
- return nullptr; /* no conversion needed */
-}
-
-NodeOperation *SeparateHSVANode::get_color_converter(const CompositorContext & /*context*/) const
-{
- return new ConvertRGBToHSVOperation();
-}
-
-NodeOperation *SeparateYCCANode::get_color_converter(const CompositorContext & /*context*/) const
-{
- ConvertRGBToYCCOperation *operation = new ConvertRGBToYCCOperation();
- bNode *editor_node = this->get_bnode();
- operation->set_mode(editor_node->custom1);
- return operation;
-}
-
-NodeOperation *SeparateYUVANode::get_color_converter(const CompositorContext & /*context*/) const
-{
- return new ConvertRGBToYUVOperation();
-}
-
} // namespace blender::compositor
diff --git a/source/blender/compositor/nodes/COM_SeparateColorNode.h b/source/blender/compositor/nodes/COM_SeparateColorNode.h
index 78ab0959f43..6adb2d0bb22 100644
--- a/source/blender/compositor/nodes/COM_SeparateColorNode.h
+++ b/source/blender/compositor/nodes/COM_SeparateColorNode.h
@@ -12,45 +12,6 @@ class SeparateColorNode : public Node {
SeparateColorNode(bNode *editor_node);
void convert_to_operations(NodeConverter &converter,
const CompositorContext &context) const override;
-
- protected:
- virtual NodeOperation *get_color_converter(const CompositorContext &context) const = 0;
-};
-
-class SeparateRGBANode : public SeparateColorNode {
- public:
- SeparateRGBANode(bNode *editor_node) : SeparateColorNode(editor_node)
- {
- }
-
- NodeOperation *get_color_converter(const CompositorContext &context) const override;
-};
-
-class SeparateHSVANode : public SeparateColorNode {
- public:
- SeparateHSVANode(bNode *editor_node) : SeparateColorNode(editor_node)
- {
- }
-
- NodeOperation *get_color_converter(const CompositorContext &context) const override;
-};
-
-class SeparateYCCANode : public SeparateColorNode {
- public:
- SeparateYCCANode(bNode *editor_node) : SeparateColorNode(editor_node)
- {
- }
-
- NodeOperation *get_color_converter(const CompositorContext &context) const override;
-};
-
-class SeparateYUVANode : public SeparateColorNode {
- public:
- SeparateYUVANode(bNode *editor_node) : SeparateColorNode(editor_node)
- {
- }
-
- NodeOperation *get_color_converter(const CompositorContext &context) const override;
};
} // namespace blender::compositor
diff --git a/source/blender/compositor/nodes/COM_SeparateColorNodeLegacy.cc b/source/blender/compositor/nodes/COM_SeparateColorNodeLegacy.cc
new file mode 100644
index 00000000000..c3728bc152f
--- /dev/null
+++ b/source/blender/compositor/nodes/COM_SeparateColorNodeLegacy.cc
@@ -0,0 +1,110 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later
+ * Copyright 2011 Blender Foundation. */
+
+#include "COM_SeparateColorNodeLegacy.h"
+
+#include "COM_ConvertOperation.h"
+
+namespace blender::compositor {
+
+SeparateColorNodeLegacy::SeparateColorNodeLegacy(bNode *editor_node) : Node(editor_node)
+{
+}
+
+void SeparateColorNodeLegacy::convert_to_operations(NodeConverter &converter,
+ const CompositorContext &context) const
+{
+ NodeInput *image_socket = this->get_input_socket(0);
+ NodeOutput *output_rsocket = this->get_output_socket(0);
+ NodeOutput *output_gsocket = this->get_output_socket(1);
+ NodeOutput *output_bsocket = this->get_output_socket(2);
+ NodeOutput *output_asocket = this->get_output_socket(3);
+
+ NodeOperation *color_conv = get_color_converter(context);
+ if (color_conv) {
+ converter.add_operation(color_conv);
+
+ converter.map_input_socket(image_socket, color_conv->get_input_socket(0));
+ }
+
+ {
+ SeparateChannelOperation *operation = new SeparateChannelOperation();
+ operation->set_channel(0);
+ converter.add_operation(operation);
+
+ if (color_conv) {
+ converter.add_link(color_conv->get_output_socket(), operation->get_input_socket(0));
+ }
+ else {
+ converter.map_input_socket(image_socket, operation->get_input_socket(0));
+ }
+ converter.map_output_socket(output_rsocket, operation->get_output_socket(0));
+ }
+
+ {
+ SeparateChannelOperation *operation = new SeparateChannelOperation();
+ operation->set_channel(1);
+ converter.add_operation(operation);
+
+ if (color_conv) {
+ converter.add_link(color_conv->get_output_socket(), operation->get_input_socket(0));
+ }
+ else {
+ converter.map_input_socket(image_socket, operation->get_input_socket(0));
+ }
+ converter.map_output_socket(output_gsocket, operation->get_output_socket(0));
+ }
+
+ {
+ SeparateChannelOperation *operation = new SeparateChannelOperation();
+ operation->set_channel(2);
+ converter.add_operation(operation);
+
+ if (color_conv) {
+ converter.add_link(color_conv->get_output_socket(), operation->get_input_socket(0));
+ }
+ else {
+ converter.map_input_socket(image_socket, operation->get_input_socket(0));
+ }
+ converter.map_output_socket(output_bsocket, operation->get_output_socket(0));
+ }
+
+ {
+ SeparateChannelOperation *operation = new SeparateChannelOperation();
+ operation->set_channel(3);
+ converter.add_operation(operation);
+
+ if (color_conv) {
+ converter.add_link(color_conv->get_output_socket(), operation->get_input_socket(0));
+ }
+ else {
+ converter.map_input_socket(image_socket, operation->get_input_socket(0));
+ }
+ converter.map_output_socket(output_asocket, operation->get_output_socket(0));
+ }
+}
+
+NodeOperation *SeparateRGBANode::get_color_converter(const CompositorContext & /*context*/) const
+{
+ return nullptr; /* no conversion needed */
+}
+
+NodeOperation *SeparateHSVANode::get_color_converter(const CompositorContext & /*context*/) const
+{
+ return new ConvertRGBToHSVOperation();
+}
+
+NodeOperation *SeparateYCCANode::get_color_converter(const CompositorContext & /*context*/) const
+{
+ ConvertRGBToYCCOperation *operation = new ConvertRGBToYCCOperation();
+ bNode *editor_node = this->get_bnode();
+ operation->set_mode(editor_node->custom1);
+ return operation;
+}
+
+NodeOperation *SeparateYUVANode::get_color_converter(const CompositorContext & /*context*/) const
+{
+ return new ConvertRGBToYUVOperation();
+}
+
+} // namespace blender::compositor
diff --git a/source/blender/compositor/nodes/COM_SeparateColorNodeLegacy.h b/source/blender/compositor/nodes/COM_SeparateColorNodeLegacy.h
new file mode 100644
index 00000000000..10b33039c86
--- /dev/null
+++ b/source/blender/compositor/nodes/COM_SeparateColorNodeLegacy.h
@@ -0,0 +1,56 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later
+ * Copyright 2011 Blender Foundation. */
+
+#pragma once
+
+#include "COM_Node.h"
+
+namespace blender::compositor {
+
+class SeparateColorNodeLegacy : public Node {
+ public:
+ SeparateColorNodeLegacy(bNode *editor_node);
+ void convert_to_operations(NodeConverter &converter,
+ const CompositorContext &context) const override;
+
+ protected:
+ virtual NodeOperation *get_color_converter(const CompositorContext &context) const = 0;
+};
+
+class SeparateRGBANode : public SeparateColorNodeLegacy {
+ public:
+ SeparateRGBANode(bNode *editor_node) : SeparateColorNodeLegacy(editor_node)
+ {
+ }
+
+ NodeOperation *get_color_converter(const CompositorContext &context) const override;
+};
+
+class SeparateHSVANode : public SeparateColorNodeLegacy {
+ public:
+ SeparateHSVANode(bNode *editor_node) : SeparateColorNodeLegacy(editor_node)
+ {
+ }
+
+ NodeOperation *get_color_converter(const CompositorContext &context) const override;
+};
+
+class SeparateYCCANode : public SeparateColorNodeLegacy {
+ public:
+ SeparateYCCANode(bNode *editor_node) : SeparateColorNodeLegacy(editor_node)
+ {
+ }
+
+ NodeOperation *get_color_converter(const CompositorContext &context) const override;
+};
+
+class SeparateYUVANode : public SeparateColorNodeLegacy {
+ public:
+ SeparateYUVANode(bNode *editor_node) : SeparateColorNodeLegacy(editor_node)
+ {
+ }
+
+ NodeOperation *get_color_converter(const CompositorContext &context) const override;
+};
+
+} // namespace blender::compositor
diff --git a/source/blender/compositor/operations/COM_ConvertOperation.cc b/source/blender/compositor/operations/COM_ConvertOperation.cc
index 7579abf792a..24c0c577ac7 100644
--- a/source/blender/compositor/operations/COM_ConvertOperation.cc
+++ b/source/blender/compositor/operations/COM_ConvertOperation.cc
@@ -464,6 +464,68 @@ void ConvertHSVToRGBOperation::update_memory_buffer_partial(BuffersIterator<floa
}
}
+/* ******** RGB to HSL ******** */
+
+ConvertRGBToHSLOperation::ConvertRGBToHSLOperation() : ConvertBaseOperation()
+{
+ this->add_input_socket(DataType::Color);
+ this->add_output_socket(DataType::Color);
+}
+
+void ConvertRGBToHSLOperation::execute_pixel_sampled(float output[4],
+ float x,
+ float y,
+ PixelSampler sampler)
+{
+ float input_color[4];
+ input_operation_->read_sampled(input_color, x, y, sampler);
+ rgb_to_hsl_v(input_color, output);
+ output[3] = input_color[3];
+}
+
+void ConvertRGBToHSLOperation::update_memory_buffer_partial(BuffersIterator<float> &it)
+{
+ for (; !it.is_end(); ++it) {
+ const float *in = it.in(0);
+ rgb_to_hsl_v(in, it.out);
+ it.out[3] = in[3];
+ }
+}
+
+/* ******** HSL to RGB ******** */
+
+ConvertHSLToRGBOperation::ConvertHSLToRGBOperation() : ConvertBaseOperation()
+{
+ this->add_input_socket(DataType::Color);
+ this->add_output_socket(DataType::Color);
+}
+
+void ConvertHSLToRGBOperation::execute_pixel_sampled(float output[4],
+ float x,
+ float y,
+ PixelSampler sampler)
+{
+ float input_color[4];
+ input_operation_->read_sampled(input_color, x, y, sampler);
+ hsl_to_rgb_v(input_color, output);
+ output[0] = max_ff(output[0], 0.0f);
+ output[1] = max_ff(output[1], 0.0f);
+ output[2] = max_ff(output[2], 0.0f);
+ output[3] = input_color[3];
+}
+
+void ConvertHSLToRGBOperation::update_memory_buffer_partial(BuffersIterator<float> &it)
+{
+ for (; !it.is_end(); ++it) {
+ const float *in = it.in(0);
+ hsl_to_rgb_v(in, it.out);
+ it.out[0] = max_ff(it.out[0], 0.0f);
+ it.out[1] = max_ff(it.out[1], 0.0f);
+ it.out[2] = max_ff(it.out[2], 0.0f);
+ it.out[3] = in[3];
+ }
+}
+
/* ******** Premul to Straight ******** */
ConvertPremulToStraightOperation::ConvertPremulToStraightOperation() : ConvertBaseOperation()
diff --git a/source/blender/compositor/operations/COM_ConvertOperation.h b/source/blender/compositor/operations/COM_ConvertOperation.h
index e1904d61d46..16d1e2e6bb5 100644
--- a/source/blender/compositor/operations/COM_ConvertOperation.h
+++ b/source/blender/compositor/operations/COM_ConvertOperation.h
@@ -172,6 +172,26 @@ class ConvertHSVToRGBOperation : public ConvertBaseOperation {
void update_memory_buffer_partial(BuffersIterator<float> &it) override;
};
+class ConvertRGBToHSLOperation : public ConvertBaseOperation {
+ public:
+ ConvertRGBToHSLOperation();
+
+ void execute_pixel_sampled(float output[4], float x, float y, PixelSampler sampler) override;
+
+ protected:
+ void update_memory_buffer_partial(BuffersIterator<float> &it) override;
+};
+
+class ConvertHSLToRGBOperation : public ConvertBaseOperation {
+ public:
+ ConvertHSLToRGBOperation();
+
+ void execute_pixel_sampled(float output[4], float x, float y, PixelSampler sampler) override;
+
+ protected:
+ void update_memory_buffer_partial(BuffersIterator<float> &it) override;
+};
+
class ConvertPremulToStraightOperation : public ConvertBaseOperation {
public:
ConvertPremulToStraightOperation();
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/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_nodes.cc b/source/blender/depsgraph/intern/builder/deg_builder_nodes.cc
index c6fc3cd5d0b..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"
@@ -1083,7 +1084,8 @@ void DepsgraphNodeBuilder::build_animation_images(ID *id)
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_flag & NTREE_RUNTIME_FLAG_HAS_IMAGE_ANIMATION) {
+ if (ntree != nullptr &&
+ ntree->runtime->runtime_flag & NTREE_RUNTIME_FLAG_HAS_IMAGE_ANIMATION) {
has_image_animation = true;
}
}
diff --git a/source/blender/depsgraph/intern/builder/deg_builder_relations.cc b/source/blender/depsgraph/intern/builder/deg_builder_relations.cc
index 3eeab23823c..ae159373efd 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;
@@ -1133,6 +1141,9 @@ void DepsgraphRelationBuilder::build_constraints(ID *id,
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,
@@ -1449,7 +1460,8 @@ void DepsgraphRelationBuilder::build_animation_images(ID *id)
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_flag & NTREE_RUNTIME_FLAG_HAS_IMAGE_ANIMATION) {
+ if (ntree != nullptr &&
+ ntree->runtime->runtime_flag & NTREE_RUNTIME_FLAG_HAS_IMAGE_ANIMATION) {
has_image_animation = true;
}
}
@@ -1500,6 +1512,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;
@@ -1787,6 +1802,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);
@@ -2012,6 +2030,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);
@@ -2070,6 +2091,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);
@@ -2131,6 +2155,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);
@@ -2251,6 +2277,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);
@@ -2369,6 +2398,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);
@@ -2388,6 +2420,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);
@@ -2405,6 +2440,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);
@@ -2469,6 +2507,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);
@@ -2574,6 +2615,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);
@@ -2610,6 +2654,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);
@@ -2651,6 +2698,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);
}
@@ -2660,6 +2710,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);
@@ -2689,6 +2742,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. */
@@ -2727,6 +2783,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);
@@ -2739,6 +2797,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);
@@ -2750,6 +2811,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);
@@ -2760,6 +2824,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);
@@ -2776,6 +2843,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);
@@ -2786,6 +2856,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);
@@ -2850,6 +2923,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. */
@@ -2893,6 +2969,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 1ff7585165b..3381dbadbab 100644
--- a/source/blender/draw/CMakeLists.txt
+++ b/source/blender/draw/CMakeLists.txt
@@ -69,6 +69,7 @@ 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
@@ -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,6 +134,7 @@ 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
@@ -140,6 +142,7 @@ set(SRC
engines/eevee_next/eevee_shader.cc
engines/eevee_next/eevee_sync.cc
engines/eevee_next/eevee_view.cc
+ engines/eevee_next/eevee_velocity.cc
engines/eevee_next/eevee_world.cc
engines/workbench/workbench_data.c
engines/workbench/workbench_effect_antialiasing.c
@@ -196,6 +199,7 @@ 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_impl.h
@@ -352,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
@@ -362,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
@@ -422,8 +432,8 @@ set(GLSL_SRC
intern/shaders/common_subdiv_vbo_lnor_comp.glsl
intern/shaders/common_subdiv_vbo_sculpt_data_comp.glsl
- intern/draw_shader_shared.h
intern/draw_common_shader_shared.h
+ intern/draw_shader_shared.h
engines/gpencil/shaders/gpencil_frag.glsl
engines/gpencil/shaders/gpencil_vert.glsl
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/eevee/eevee_cryptomatte.c b/source/blender/draw/engines/eevee/eevee_cryptomatte.c
index b17efe4b68d..33063e14c03 100644
--- a/source/blender/draw/engines/eevee/eevee_cryptomatte.c
+++ b/source/blender/draw/engines/eevee/eevee_cryptomatte.c
@@ -68,7 +68,7 @@ BLI_INLINE int eevee_cryptomatte_layers_count(const ViewLayer *view_layer)
}
/* The number of render result passes are needed to store a single cryptomatte layer. Per
- * renderpass 2 cryptomatte samples can be stored. */
+ * render-pass 2 cryptomatte samples can be stored. */
BLI_INLINE int eevee_cryptomatte_passes_per_layer(const ViewLayer *view_layer)
{
const int num_cryptomatte_levels = view_layer->cryptomatte_levels;
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 43d0b050cc8..a4bd789438d 100644
--- a/source/blender/draw/engines/eevee/eevee_lookdev.c
+++ b/source/blender/draw/engines/eevee/eevee_lookdev.c
@@ -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_private.h b/source/blender/draw/engines/eevee/eevee_private.h
index b03a4fa70b4..0a7c8e185c4 100644
--- a/source/blender/draw/engines/eevee/eevee_private.h
+++ b/source/blender/draw/engines/eevee/eevee_private.h
@@ -301,7 +301,7 @@ typedef struct EEVEE_PassList {
struct DRWPass *maxz_copydepth_ps;
struct DRWPass *maxz_copydepth_layer_ps;
- /* Renderpass Accumulation. */
+ /* Render-pass Accumulation. */
struct DRWPass *material_accum_ps;
struct DRWPass *background_accum_ps;
struct DRWPass *cryptomatte_ps;
@@ -1069,7 +1069,7 @@ typedef struct EEVEE_PrivateData {
GPUTexture *renderpass_col_input;
GPUTexture *renderpass_light_input;
GPUTexture *renderpass_transmittance_input;
- /* Renderpass ubo reference used by material pass. */
+ /* Render-pass UBO reference used by material pass. */
struct GPUUniformBuf *renderpass_ubo;
/** For rendering shadows. */
struct DRWView *cube_views[6];
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_type_lib.glsl b/source/blender/draw/engines/eevee/shaders/closure_type_lib.glsl
index 21d347942ca..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
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 81f73979723..8e1bafe8d92 100644
--- a/source/blender/draw/engines/eevee/shaders/surface_lib.glsl
+++ b/source/blender/draw/engines/eevee/shaders/surface_lib.glsl
@@ -201,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 04f38978076..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
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 ce863bdf660..186f438b03b 100644
--- a/source/blender/draw/engines/eevee/shaders/volumetric_vert.glsl
+++ b/source/blender/draw/engines/eevee/shaders/volumetric_vert.glsl
@@ -76,4 +76,4 @@ vec3 coordinate_reflect(vec3 P, vec3 N)
vec3 coordinate_incoming(vec3 P)
{
return vec3(0.0);
-} \ No newline at end of file
+}
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 35eb33671db..7141928a20d 100644
--- a/source/blender/draw/engines/eevee_next/eevee_defines.hh
+++ b/source/blender/draw/engines/eevee_next/eevee_defines.hh
@@ -11,9 +11,11 @@
#pragma once
-/* 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
- * threadgroup which maximum size is 1024. */
+/**
+ 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.
+ */
#define CULLING_BATCH_SIZE 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 922f6c9e1ae..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"
@@ -21,9 +23,9 @@
namespace blender::eevee {
/* -------------------------------------------------------------------- */
-/** \name Init
+/** \name Initialization
*
- * Init funcions need to be called once at the start of a frame.
+ * Initialization functions need to be called once at the start of a frame.
* Active camera, render extent and enabled render passes are immutable until next init.
* This takes care of resizing output buffers and view in case a parameter changed.
* IMPORTANT: xxx.init() functions are NOT meant to acquire and allocate DRW resources.
@@ -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 56f9b077f7a..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,
@@ -104,7 +106,7 @@ static inline eMaterialGeometry to_material_geometry(const Object *ob)
}
}
-/** Unique key to identify each material in the hashmap. */
+/** Unique key to identify each material in the hash-map. */
struct MaterialKey {
Material *mat;
uint64_t options;
@@ -169,7 +171,7 @@ struct ShaderKey {
/** \} */
/* -------------------------------------------------------------------- */
-/** \name Default Material Nodetree
+/** \name Default Material Node-Tree
*
* In order to support materials without nodetree we reuse and configure a standalone nodetree that
* we pass for shader generation. The GPUMaterial is still stored inside the Material even if
@@ -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,
@@ -254,4 +267,4 @@ class MaterialModule {
/** \} */
-} // namespace blender::eevee \ No newline at end of file
+} // namespace blender::eevee
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 086c5f9f358..09aa97e49e9 100644
--- a/source/blender/draw/engines/eevee_next/eevee_shader.cc
+++ b/source/blender/draw/engines/eevee_next/eevee_shader.cc
@@ -25,7 +25,7 @@ ShaderModule *ShaderModule::g_shader_module = nullptr;
ShaderModule *ShaderModule::module_get()
{
if (g_shader_module == nullptr) {
- /* TODO(fclem) threadsafety. */
+ /* TODO(@fclem) thread-safety. */
g_shader_module = new ShaderModule();
}
return g_shader_module;
@@ -34,7 +34,7 @@ ShaderModule *ShaderModule::module_get()
void ShaderModule::module_free()
{
if (g_shader_module != nullptr) {
- /* TODO(fclem) threadsafety. */
+ /* TODO(@fclem) thread-safety. */
delete g_shader_module;
g_shader_module = nullptr;
}
@@ -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 "";
@@ -148,7 +150,7 @@ void ShaderModule::material_create_info_ammend(GPUMaterial *gpumat, GPUCodegenOu
/** Noop. */
break;
case MAT_GEOM_CURVES:
- /** Hair attributes comme from sampler buffer. Transfer attributes to sampler. */
+ /** Hair attributes come from sampler buffer. Transfer attributes to sampler. */
for (auto &input : info.vertex_inputs_) {
if (input.name == "orco") {
/** NOTE: Orco is generated from strand position for now. */
@@ -159,18 +161,19 @@ void ShaderModule::material_create_info_ammend(GPUMaterial *gpumat, GPUCodegenOu
}
}
info.vertex_inputs_.clear();
+ info.additional_info("draw_curves_infos");
break;
case MAT_GEOM_WORLD:
/**
* Only orco layer is supported by world and it is procedurally generated. These are here to
- * make the attribs_load function calls valids.
+ * make the attribs_load function calls valid.
*/
ATTR_FALLTHROUGH;
case MAT_GEOM_GPENCIL:
/**
* Only one uv and one color attribute layer are supported by gpencil objects and they are
* already declared in another createInfo. These are here to make the attribs_load
- * function calls valids.
+ * function calls valid.
*/
for (auto &input : info.vertex_inputs_) {
global_vars << input.type << " " << input.name << ";\n";
@@ -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 ba7c97b3b6a..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,
};
/**
@@ -36,7 +38,7 @@ class ShaderModule {
private:
std::array<GPUShader *, MAX_SHADER_TYPE> shaders_;
- /** Shared shader module accross all engine instances. */
+ /** Shared shader module across all engine instances. */
static ShaderModule *g_shader_module;
public:
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 2225ccac43a..1261c855a82 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,7 +28,101 @@ using draw::TextureFromPool;
#define UBO_MIN_MAX_SUPPORTED_SIZE 1 << 14
/* -------------------------------------------------------------------- */
-/** \name Raytracing
+/** \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 {
@@ -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 51e0f86fe5c..bd8147a2882 100644
--- a/source/blender/draw/engines/eevee_next/eevee_sync.hh
+++ b/source/blender/draw/engines/eevee_next/eevee_sync.hh
@@ -27,7 +27,8 @@ class Instance;
/* -------------------------------------------------------------------- */
/** \name ObjectKey
*
- * Unique key to identify each object in the hashmap.
+ * 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..9f8dce43910
--- /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..1bfd9f8c18f
--- /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 &ob_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 df45200c712..e21342c5ef6 100644
--- a/source/blender/draw/engines/eevee_next/eevee_view.cc
+++ b/source/blender/draw/engines/eevee_next/eevee_view.cc
@@ -9,7 +9,7 @@
* - The entire main view.
* - A fragment of the main view (for panoramic projections).
* - A shadow map view.
- * - A lightprobe view (either planar, cubemap, irradiance grid).
+ * - A light-probe view (either planar, cube-map, irradiance grid).
*
* A pass is a container for scene data. It is view agnostic but has specific logic depending on
* its type. Passes are shared between views.
@@ -40,7 +40,7 @@ void ShadingView::sync(int2 render_extent_)
int64_t render_pixel_count = render_extent_.x * (int64_t)render_extent_.y;
/* Divide pixel count between the 6 views. Rendering to a square target. */
extent_[0] = extent_[1] = ceilf(sqrtf(1 + (render_pixel_count / 6)));
- /* TODO(fclem) Clip unused views heres. */
+ /* TODO(@fclem): Clip unused views here. */
is_enabled_ = true;
}
else {
@@ -60,8 +60,8 @@ void ShadingView::sync(int2 render_extent_)
const float(*viewmat_p)[4] = viewmat.ptr(), (*winmat_p)[4] = winmat.ptr();
#if 0
if (false /* inst_.camera.is_panoramic() */) {
- /* TODO(fclem) Overscans. */
- /* For now a mandatory 5% overscan for DoF. */
+ /* TODO(@fclem) Over-scans. */
+ /* For now a mandatory 5% over-scan for DoF. */
float side = data.clip_near * 1.05f;
float near = data.clip_near;
float far = data.clip_far;
@@ -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)
@@ -205,4 +215,4 @@ void ShadingView::update_view()
/** \} */
-} // namespace blender::eevee \ No newline at end of file
+} // namespace blender::eevee
diff --git a/source/blender/draw/engines/eevee_next/eevee_view.hh b/source/blender/draw/engines/eevee_next/eevee_view.hh
index ab7b5722de1..95ec1760c63 100644
--- a/source/blender/draw/engines/eevee_next/eevee_view.hh
+++ b/source/blender/draw/engines/eevee_next/eevee_view.hh
@@ -8,7 +8,7 @@
* A view is either:
* - The entire main view.
* - A portion of the main view (for panoramic projections).
- * - A lightprobe view (either planar, cubemap, irradiance grid).
+ * - A light-probe view (either planar, cube-map, irradiance grid).
*
* A pass is a container for scene data. It is view agnostic but has specific logic depending on
* its type. Passes are shared between views.
@@ -21,6 +21,7 @@
#include "eevee_camera.hh"
#include "eevee_pipeline.hh"
#include "eevee_shader.hh"
+#include "eevee_velocity.hh"
namespace blender::eevee {
@@ -43,13 +44,14 @@ class ShadingView {
/** 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(){};
@@ -154,4 +156,4 @@ class MainView {
/** \} */
-} // namespace blender::eevee \ No newline at end of file
+} // namespace blender::eevee
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/eevee_world.hh b/source/blender/draw/engines/eevee_next/eevee_world.hh
index 56554051eea..05177928436 100644
--- a/source/blender/draw/engines/eevee_next/eevee_world.hh
+++ b/source/blender/draw/engines/eevee_next/eevee_world.hh
@@ -18,7 +18,7 @@ namespace blender::eevee {
class Instance;
/* -------------------------------------------------------------------- */
-/** \name Default World Nodetree
+/** \name Default World Node-Tree
*
* In order to support worlds without nodetree we reuse and configure a standalone nodetree that
* we pass for shader generation. The GPUMaterial is still stored inside the World even if
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 3c5acf62e30..1b113e529b6 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,22 @@ 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) {
+ id = hair_get_base_id();
+ }
+
+ g_curves_attr_id += 1;
+ return id;
+}
+
vec4 attr_load_tangent(samplerBuffer cd_buf)
{
/* Not supported for the moment. */
@@ -137,19 +154,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;
}
/** \} */
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 708bd153e84..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()
{
@@ -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_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_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 4d6895bcde0..49250b5741e 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,19 @@ 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");
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")
@@ -66,7 +70,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)
@@ -95,7 +99,7 @@ GPU_SHADER_CREATE_INFO(eevee_surf_forward)
.fragment_source("eevee_surf_forward_frag.glsl")
// .additional_info("eevee_sampling_data",
// "eevee_lightprobe_data",
- /* Optionnally added depending on the material. */
+ /* Optionally added depending on the material. */
// "eevee_raytrace_data",
// "eevee_transmittance_data",
// "eevee_utility_texture",
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/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/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_gpencil.c b/source/blender/draw/engines/overlay/overlay_gpencil.c
index 5c5226bfe65..9531b0dd983 100644
--- a/source/blender/draw/engines/overlay/overlay_gpencil.c
+++ b/source/blender/draw/engines/overlay/overlay_gpencil.c
@@ -124,7 +124,7 @@ void OVERLAY_edit_gpencil_cache_init(OVERLAY_Data *vedata)
}
}
- /* Handles and curve point for Curve Edit submode. */
+ /* Handles and curve point for Curve Edit sub-mode. */
if (GPENCIL_CURVE_EDIT_SESSIONS_ON(gpd)) {
DRWState state = DRW_STATE_WRITE_COLOR;
DRW_PASS_CREATE(psl->edit_gpencil_curve_ps, state | pd->clipping_state);
@@ -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/shaders/infos/extra_info.hh b/source/blender/draw/engines/overlay/shaders/infos/extra_info.hh
index a765d881682..b9b1b73dbd4 100644
--- a/source/blender/draw/engines/overlay/shaders/infos/extra_info.hh
+++ b/source/blender/draw/engines/overlay/shaders/infos/extra_info.hh
@@ -284,7 +284,7 @@ GPU_SHADER_INTERFACE_INFO(overlay_particle_iface, "").flat(Type::VEC4, "finalCol
GPU_SHADER_CREATE_INFO(overlay_particle)
.sampler(0, ImageType::FLOAT_1D, "weightTex")
- .push_constant(Type::VEC4, "color") /* Drawsize packed in alpha */
+ .push_constant(Type::VEC4, "color") /* Draw-size packed in alpha. */
.vertex_in(0, Type::VEC3, "part_pos")
.vertex_in(1, Type::VEC4, "part_rot")
.vertex_in(2, Type::FLOAT, "part_val")
diff --git a/source/blender/draw/engines/overlay/shaders/infos/volume_info.hh b/source/blender/draw/engines/overlay/shaders/infos/volume_info.hh
index 713c8c2dc4b..5853e974eeb 100644
--- a/source/blender/draw/engines/overlay/shaders/infos/volume_info.hh
+++ b/source/blender/draw/engines/overlay/shaders/infos/volume_info.hh
@@ -48,7 +48,7 @@ GPU_SHADER_CREATE_INFO(overlay_volume_velocity_needle)
/** \} */
/* -------------------------------------------------------------------- */
-/** \name Volume Gridlines
+/** \name Volume Grid-Lines
* \{ */
GPU_SHADER_INTERFACE_INFO(overlay_volume_gridlines_iface, "").flat(Type::VEC4, "finalColor");
diff --git a/source/blender/draw/engines/overlay/shaders/infos/wireframe_info.hh b/source/blender/draw/engines/overlay/shaders/infos/wireframe_info.hh
index 43367121d6a..16b59f6bb7d 100644
--- a/source/blender/draw/engines/overlay/shaders/infos/wireframe_info.hh
+++ b/source/blender/draw/engines/overlay/shaders/infos/wireframe_info.hh
@@ -21,7 +21,7 @@ GPU_SHADER_CREATE_INFO(overlay_wireframe)
.sampler(0, ImageType::DEPTH_2D, "depthTex")
.vertex_in(0, Type::VEC3, "pos")
.vertex_in(1, Type::VEC3, "nor")
- .vertex_in(2, Type::FLOAT, "wd") /* wiredata */
+ .vertex_in(2, Type::FLOAT, "wd") /* wire-data. */
.vertex_out(overlay_wireframe_iface)
.vertex_source("wireframe_vert.glsl")
.fragment_source("wireframe_frag.glsl")
diff --git a/source/blender/draw/engines/overlay/shaders/outline_detect_frag.glsl b/source/blender/draw/engines/overlay/shaders/outline_detect_frag.glsl
index bea54ff8cf5..472a589f441 100644
--- a/source/blender/draw/engines/overlay/shaders/outline_detect_frag.glsl
+++ b/source/blender/draw/engines/overlay/shaders/outline_detect_frag.glsl
@@ -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/select/shaders/infos/select_id_info.hh b/source/blender/draw/engines/select/shaders/infos/select_id_info.hh
index ad0de61ffc3..e3166582197 100644
--- a/source/blender/draw/engines/select/shaders/infos/select_id_info.hh
+++ b/source/blender/draw/engines/select/shaders/infos/select_id_info.hh
@@ -3,7 +3,7 @@
#include "gpu_shader_create_info.hh"
/* -------------------------------------------------------------------- */
-/** \name Select ID fo Edit Mesh selection
+/** \name Select ID for Edit Mesh Selection
* \{ */
GPU_SHADER_INTERFACE_INFO(select_id_iface, "").flat(Type::INT, "id");
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_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..07105757b2c 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. */
diff --git a/source/blender/draw/intern/draw_attributes.cc b/source/blender/draw/intern/draw_attributes.cc
new file mode 100644
index 00000000000..714f1dbb3d1
--- /dev/null
+++ b/source/blender/draw/intern/draw_attributes.cc
@@ -0,0 +1,112 @@
+/* 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,
+ CustomDataType type,
+ int layer,
+ AttributeDomain domain)
+{
+ if (attrs->num_requests >= GPU_MAX_ATTR) {
+ return nullptr;
+ }
+
+ DRW_AttributeRequest *req = &attrs->requests[attrs->num_requests];
+ req->cd_type = type;
+ req->layer_index = layer;
+ 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,
+ 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;
+}
diff --git a/source/blender/draw/intern/draw_attributes.h b/source/blender/draw/intern/draw_attributes.h
new file mode 100644
index 00000000000..192ffa43337
--- /dev/null
+++ b/source/blender/draw/intern/draw_attributes.h
@@ -0,0 +1,60 @@
+/* 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 {
+ CustomDataType cd_type;
+ int layer_index;
+ AttributeDomain 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,
+ CustomDataType type,
+ int layer,
+ AttributeDomain domain);
+
+bool drw_custom_data_match_attribute(const CustomData *custom_data,
+ const char *name,
+ int *r_layer_index,
+ int *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..fb074cc728e 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;
diff --git a/source/blender/draw/intern/draw_cache_extract.h b/source/blender/draw/intern/draw_cache_extract.h
index cb6006e303a..ce3ad9923da 100644
--- a/source/blender/draw/intern/draw_cache_extract.h
+++ b/source/blender/draw/intern/draw_cache_extract.h
@@ -20,6 +20,8 @@ struct TaskGraph;
#include "GPU_index_buffer.h"
#include "GPU_vertex_buffer.h"
+#include "draw_attributes.h"
+
/* Vertex Group Selection and display options */
typedef struct DRW_MeshWeightState {
int defgroup_active;
@@ -67,17 +69,6 @@ typedef enum eMRIterType {
} 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 {
MR_DATA_NONE = 0,
MR_DATA_POLY_NOR = 1 << 1,
@@ -294,7 +285,7 @@ typedef struct MeshBatchCache {
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;
diff --git a/source/blender/draw/intern/draw_cache_extract_mesh.cc b/source/blender/draw/intern/draw_cache_extract_mesh.cc
index ec544d8e786..3d44d3d1b3f 100644
--- a/source/blender/draw/intern/draw_cache_extract_mesh.cc
+++ b/source/blender/draw/intern/draw_cache_extract_mesh.cc
@@ -793,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]);
@@ -843,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);
diff --git a/source/blender/draw/intern/draw_cache_impl.h b/source/blender/draw/intern/draw_cache_impl.h
index f877c94208f..0755d5967d5 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);
/** \} */
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..f9cf0021fcd 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;
/* ---------------------------------------------------------------------- */
@@ -49,6 +54,10 @@ struct CurvesBatchCache {
/* To determine if cache is invalid. */
bool is_dirty;
+
+ /** Needed when updating material data (e.g. attributes) as the same curves might be used for
+ * multiple objects with different materials. */
+ ThreadMutex render_mutex;
};
static bool curves_batch_cache_valid(const Curves &curves)
@@ -63,6 +72,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 +82,23 @@ static void curves_batch_cache_init(Curves &curves)
cache->is_dirty = false;
}
+static void curves_discard_attributes(CurvesEvalCache &curves_cache)
+{
+ for (int i = 0; i < GPU_MAX_ATTR; i++) {
+ GPU_VERTBUF_DISCARD_SAFE(curves_cache.proc_attributes_buf[i]);
+ DRW_TEXTURE_FREE_SAFE(curves_cache.proc_attributes_tex[i]);
+ }
+
+ for (int i = 0; i < MAX_HAIR_SUBDIV; i++) {
+ for (int j = 0; j < GPU_MAX_ATTR; j++) {
+ 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. */
@@ -92,6 +119,8 @@ static void curves_batch_cache_clear_data(CurvesEvalCache &curves_cache)
GPU_BATCH_DISCARD_SAFE(curves_cache.final[i].proc_hairs[j]);
}
}
+
+ curves_discard_attributes(curves_cache);
}
static void curves_batch_cache_clear(Curves &curves)
@@ -138,55 +167,89 @@ void DRW_curves_batch_cache_dirty_tag(Curves *curves, int mode)
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 (int i = 0; i < MAX_HAIR_SUBDIV; i++) {
+ 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 +262,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 +300,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 +452,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 +498,88 @@ 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 type = gpu_attr->type;
+ int layer = -1;
+ AttributeDomain domain;
+
+ if (drw_custom_data_match_attribute(cd_curve, name, &layer, &type)) {
+ domain = ATTR_DOMAIN_CURVE;
+ }
+ else if (drw_custom_data_match_attribute(cd_point, name, &layer, &type)) {
+ domain = ATTR_DOMAIN_POINT;
+ }
+ else {
+ continue;
+ }
+
+ switch (type) {
+ default:
+ break;
+ case CD_PROP_BOOL:
+ case CD_PROP_INT8:
+ case CD_PROP_INT32:
+ case CD_PROP_FLOAT:
+ case CD_PROP_FLOAT2:
+ case CD_PROP_FLOAT3:
+ case CD_PROP_COLOR: {
+ if (layer != -1) {
+ DRW_AttributeRequest *req = drw_attributes_add_request(
+ &attrs_needed, (CustomDataType)type, layer, domain);
+ if (req) {
+ BLI_strncpy(req->attribute_name, name, sizeof(req->attribute_name));
+ }
+ }
+ break;
+ }
+ }
+ }
+
+ CurvesEvalFinalCache &final_cache = cache.curves_cache.final[subdiv];
+
+ const bool attr_overlap = drw_attributes_overlap(&final_cache.attr_used, &attrs_needed);
+ if (attr_overlap == false) {
+ /* Some new attributes have been added, free all and start over. */
+ for (int i = 0; i < GPU_MAX_ATTR; i++) {
+ 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 (int i = 0; i < final_cache.attr_used.num_requests; i++) {
+ 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 +617,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;
}
diff --git a/source/blender/draw/intern/draw_cache_impl_mesh.c b/source/blender/draw/intern/draw_cache_impl_mesh.c
index dac4b7488be..a6ab2176d16 100644
--- a/source/blender/draw/intern/draw_cache_impl_mesh.c
+++ b/source/blender/draw/intern/draw_cache_impl_mesh.c
@@ -281,91 +281,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) {
@@ -475,36 +390,6 @@ 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,
@@ -531,7 +416,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 +429,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 +441,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);
@@ -636,16 +521,16 @@ 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 {
@@ -701,7 +586,7 @@ 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.
*/
@@ -718,7 +603,7 @@ static DRW_MeshCDMask mesh_cd_calc_used_gpu_layers(const Object *object,
}
if (layer != -1 && domain != ATTR_DOMAIN_NUM) {
- drw_mesh_attributes_add_request(attributes, type, layer, domain);
+ drw_attributes_add_request(attributes, type, layer, domain);
}
break;
}
@@ -729,7 +614,7 @@ static DRW_MeshCDMask mesh_cd_calc_used_gpu_layers(const Object *object,
case CD_PROP_FLOAT:
case CD_PROP_FLOAT2: {
if (layer != -1 && domain != ATTR_DOMAIN_NUM) {
- drw_mesh_attributes_add_request(attributes, type, layer, domain);
+ drw_attributes_add_request(attributes, type, layer, domain);
}
break;
}
@@ -1317,8 +1202,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);
@@ -1326,7 +1211,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;
}
@@ -1596,7 +1481,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;
}
@@ -1605,12 +1490,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]);
@@ -1721,7 +1606,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) {
@@ -1741,7 +1626,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]);
}
@@ -1756,13 +1641,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) {
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 3a5593fa2a5..a0c7e064e00 100644
--- a/source/blender/draw/intern/draw_cache_impl_subdivision.cc
+++ b/source/blender/draw/intern/draw_cache_impl_subdivision.cc
@@ -70,6 +70,7 @@ enum {
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,
@@ -109,7 +110,8 @@ 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_WITH_NORMALS: {
+ 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:
@@ -168,6 +170,9 @@ static const char *get_shader_name(int shader_type)
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";
}
@@ -218,6 +223,12 @@ static GPUShader *get_patch_evaluation_shader(int shader_type)
"#define FDOTS_EVALUATION\n"
"#define FOTS_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"
@@ -248,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) {
@@ -731,6 +743,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;
+ }
+ }
+}
+
/** \} */
/* -------------------------------------------------------------------- */
@@ -766,8 +795,8 @@ struct DRWCacheBuildingContext {
/* 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;
+ const int *v_origindex;
+ const int *e_origindex;
};
static bool draw_subdiv_topology_info_cb(const SubdivForeachContext *foreach_context,
@@ -1257,7 +1286,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. */
@@ -1272,6 +1303,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());
@@ -1287,7 +1326,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;
@@ -1300,6 +1340,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);
@@ -1316,6 +1360,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,
@@ -1971,6 +2016,8 @@ static bool draw_subdiv_create_requested_buffers(const Scene *scene,
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:
diff --git a/source/blender/draw/intern/draw_common.h b/source/blender/draw/intern/draw_common.h
index 779ac43178c..b6b0c94f4bf 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);
diff --git a/source/blender/draw/intern/draw_curves.cc b/source/blender/draw/intern/draw_curves.cc
index 88118361115..39d4845994f 100644
--- a/source/blender/draw/intern/draw_curves.cc
+++ b/source/blender/draw/intern/draw_curves.cc
@@ -10,6 +10,7 @@
#include "BLI_string_utils.h"
#include "BLI_utildefines.h"
+#include "DNA_curves_types.h"
#include "DNA_customdata_types.h"
#include "GPU_batch.h"
@@ -20,9 +21,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 +66,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 +126,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 +275,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,7 +320,7 @@ 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;
@@ -218,6 +329,43 @@ DRWShadingGroup *DRW_shgroup_curves_create_sub(Object *object,
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..ed4dd50dfbe 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
@@ -35,6 +40,23 @@ typedef struct CurvesEvalFinalCache {
/* Points per curve, at least 2. */
int strands_res;
+
+ /* Attributes currently being or about to be drawn. */
+ DRW_Attributes attr_used;
+
+ /* Attributes which were used at some point. This is used for garbage collection, to remove
+ * attributes which are not used in shaders anymore due to user edits. */
+ DRW_Attributes attr_used_over_time;
+
+ /* Last time, in seconds, 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. */
@@ -56,6 +78,11 @@ typedef struct CurvesEvalCache {
CurvesEvalFinalCache final[MAX_HAIR_SUBDIV];
+ /* For point attributes, which need subdivision, these are the input data.
+ * For spline attributes, which need not 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;
@@ -70,6 +97,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_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 4bbcf6eaf42..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);
@@ -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..f0960c5324b 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,
@@ -1905,8 +1928,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 +2081,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 2689159d259..15c770a51c4 100644
--- a/source/blender/draw/intern/draw_subdivision.h
+++ b/source/blender/draw/intern/draw_subdivision.h
@@ -160,8 +160,8 @@ typedef struct DRWSubdivCache {
/* Contains the start loop index and the smooth flag for each coarse polygon. */
struct GPUVertBuf *extra_coarse_face_data;
- /* Computed for ibo.points, one value per subdivided vertex, mapping coarse vertices ->
- * subdivided loop */
+ /* Computed for `ibo.points`, one value per subdivided vertex,
+ * mapping coarse vertices -> subdivided loop. */
int *point_indices;
/* Material offsets. */
@@ -235,7 +235,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,
diff --git a/source/blender/draw/intern/mesh_extractors/extract_mesh.h b/source/blender/draw/intern/mesh_extractors/extract_mesh.h
index d55386dfd7d..b88cd9e77d2 100644
--- a/source/blender/draw/intern/mesh_extractors/extract_mesh.h
+++ b/source/blender/draw/intern/mesh_extractors/extract_mesh.h
@@ -67,7 +67,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;
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 497cde9aaf2..d595abc6dd3 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,6 +14,7 @@
#include "BKE_attribute.h"
+#include "draw_attributes.h"
#include "draw_subdivision.h"
#include "extract_mesh.h"
@@ -180,7 +181,7 @@ 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>;
@@ -284,7 +285,7 @@ static void extract_attr_init(const MeshRenderData *mr,
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);
@@ -337,7 +338,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;
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..fb4b95885fc 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
@@ -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;
@@ -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);
}
}
@@ -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
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..e7a3cb03903 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
@@ -17,7 +17,7 @@ namespace blender::draw {
struct MeshExtract_FdotUV_Data {
float (*vbo_data)[2];
- MLoopUV *uv_data;
+ const MLoopUV *uv_data;
int cd_ofs;
};
@@ -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);
}
}
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..94674a54f12 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
@@ -7,8 +7,6 @@
#include "extract_mesh.h"
-#include "draw_subdivision.h"
-
namespace blender::draw {
/* ---------------------------------------------------------------------- */
@@ -17,7 +15,7 @@ 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,
@@ -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;
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..f80b33e28f2 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
@@ -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),
+ struct 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<float(*)[3]>(
CustomData_get_layer(&coarse_mesh->ldata, CD_NORMAL));
BLI_assert(lnors != nullptr);
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..5658ed85c8b 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
@@ -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);
@@ -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);
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 2a4a6a186be..f4c54b2f881 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
@@ -188,7 +188,7 @@ static void extract_vert_idx_init_subdiv(const DRWSubdivCache *subdiv_cache,
{
GPUVertBuf *vbo = static_cast<GPUVertBuf *>(buf);
const DRWSubdivLooseGeom &loose_geom = subdiv_cache->loose_geom;
- /* Each element points to an element in the ibo.points. */
+ /* Each element points to an element in the `ibo.points`. */
draw_subdiv_init_origindex_buffer(
vbo,
(int32_t *)GPU_vertbuf_get_data(subdiv_cache->verts_orig_index),
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..91cd675d32f 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
@@ -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;
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..2808a0a3a71 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
@@ -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));
}
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_hair_lib.glsl b/source/blender/draw/intern/shaders/common_hair_lib.glsl
index ff52b483d77..dfa2f307800 100644
--- a/source/blender/draw/intern/shaders/common_hair_lib.glsl
+++ b/source/blender/draw/intern/shaders/common_hair_lib.glsl
@@ -212,8 +212,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_subdiv_patch_evaluation_comp.glsl b/source/blender/draw/intern/shaders/common_subdiv_patch_evaluation_comp.glsl
index e842a73b8b3..0ffb216fc6f 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
@@ -91,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)
@@ -110,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];
@@ -292,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
/* ------------------------------------------------------------------------------
@@ -422,6 +468,16 @@ void main()
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/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 7bb1d652bf1..c2d517588b2 100644
--- a/source/blender/editors/animation/anim_channels_defines.c
+++ b/source/blender/editors/animation/anim_channels_defines.c
@@ -4020,6 +4020,8 @@ static bool acf_nlaaction_setting_valid(bAnimContext *UNUSED(ac),
else {
return false;
}
+ case ACHANNEL_SETTING_SELECT: /* selected */
+ return true;
/* unsupported */
default:
@@ -4040,6 +4042,9 @@ static int acf_nlaaction_setting_flag(bAnimContext *UNUSED(ac),
*neg = true; /* XXX */
return ADT_NLA_EDIT_NOMAP;
+ case ACHANNEL_SETTING_SELECT: /* selected */
+ return ADT_UI_SELECTED;
+
default: /* unsupported */
return 0;
}
diff --git a/source/blender/editors/animation/anim_channels_edit.c b/source/blender/editors/animation/anim_channels_edit.c
index 31d90c8bfec..f148bb5b77d 100644
--- a/source/blender/editors/animation/anim_channels_edit.c
+++ b/source/blender/editors/animation/anim_channels_edit.c
@@ -125,6 +125,7 @@ void ANIM_set_active_channel(bAnimContext *ac,
case ANIMTYPE_DSHAIR:
case ANIMTYPE_DSPOINTCLOUD:
case ANIMTYPE_DSVOLUME:
+ case ANIMTYPE_NLAACTION:
case ANIMTYPE_DSSIMULATION: {
/* need to verify that this data is valid for now */
if (ale->adt) {
@@ -182,6 +183,7 @@ void ANIM_set_active_channel(bAnimContext *ac,
case ANIMTYPE_DSHAIR:
case ANIMTYPE_DSPOINTCLOUD:
case ANIMTYPE_DSVOLUME:
+ case ANIMTYPE_NLAACTION:
case ANIMTYPE_DSSIMULATION: {
/* need to verify that this data is valid for now */
if (ale && ale->adt) {
@@ -199,7 +201,6 @@ void ANIM_set_active_channel(bAnimContext *ac,
/* unhandled currently, but may be interesting */
case ANIMTYPE_MASKLAYER:
case ANIMTYPE_SHAPEKEY:
- case ANIMTYPE_NLAACTION:
break;
/* other types */
@@ -312,6 +313,7 @@ static eAnimChannels_SetFlag anim_channels_selection_flag_for_toggle(const ListB
case ANIMTYPE_DSHAIR:
case ANIMTYPE_DSPOINTCLOUD:
case ANIMTYPE_DSVOLUME:
+ case ANIMTYPE_NLAACTION:
case ANIMTYPE_DSSIMULATION: {
if ((ale->adt) && (ale->adt->flag & ADT_UI_SELECTED)) {
return ACHANNEL_SETFLAG_CLEAR;
@@ -420,6 +422,7 @@ static void anim_channels_select_set(bAnimContext *ac,
case ANIMTYPE_DSHAIR:
case ANIMTYPE_DSPOINTCLOUD:
case ANIMTYPE_DSVOLUME:
+ case ANIMTYPE_NLAACTION:
case ANIMTYPE_DSSIMULATION: {
/* need to verify that this data is valid for now */
if (ale->adt) {
diff --git a/source/blender/editors/animation/anim_markers.c b/source/blender/editors/animation/anim_markers.c
index 1a3ab100768..8519b2061f2 100644
--- a/source/blender/editors/animation/anim_markers.c
+++ b/source/blender/editors/animation/anim_markers.c
@@ -543,6 +543,9 @@ void ED_markers_draw(const bContext *C, int flag)
View2D *v2d = UI_view2d_fromcontext(C);
int cfra = CTX_data_scene(C)->r.cfra;
+ const float line_width = GPU_line_width_get();
+ GPU_line_width(1.0f);
+
rctf markers_region_rect;
get_marker_region_rect(v2d, &markers_region_rect);
@@ -575,6 +578,7 @@ void ED_markers_draw(const bContext *C, int flag)
}
}
+ GPU_line_width(line_width);
GPU_matrix_pop();
}
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/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/keyframing.c b/source/blender/editors/animation/keyframing.c
index 14a3b958ea6..941125b9ad5 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;
}
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_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_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/curve/CMakeLists.txt b/source/blender/editors/curve/CMakeLists.txt
index b21ae305dbe..791e28de694 100644
--- a/source/blender/editors/curve/CMakeLists.txt
+++ b/source/blender/editors/curve/CMakeLists.txt
@@ -23,9 +23,9 @@ set(SRC
editcurve.c
editcurve_add.c
editcurve_paint.c
+ editcurve_pen.c
editcurve_query.c
editcurve_select.c
- editcurve_pen.c
editcurve_undo.c
editfont.c
editfont_undo.c
diff --git a/source/blender/editors/curves/CMakeLists.txt b/source/blender/editors/curves/CMakeLists.txt
index 1731d224b3e..a5d8390e7f2 100644
--- a/source/blender/editors/curves/CMakeLists.txt
+++ b/source/blender/editors/curves/CMakeLists.txt
@@ -11,6 +11,9 @@ set(INC
../../makesrna
../../windowmanager
../../../../intern/guardedalloc
+
+ # RNA_prototypes.h
+ ${CMAKE_BINARY_DIR}/source/blender/makesrna
)
set(SRC
@@ -24,3 +27,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..5588f7440a8 100644
--- a/source/blender/editors/curves/intern/curves_ops.cc
+++ b/source/blender/editors/curves/intern/curves_ops.cc
@@ -20,6 +20,7 @@
#include "BKE_layer.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 +33,11 @@
#include "DNA_scene_types.h"
#include "DEG_depsgraph.h"
+#include "DEG_depsgraph_query.h"
#include "RNA_access.h"
#include "RNA_define.h"
+#include "RNA_prototypes.h"
/**
* The code below uses a suffix naming convention to indicate the coordinate space:
@@ -192,7 +195,7 @@ static void try_convert_single_object(Object &curves_ob,
/* Prepare utility data structure to map hair roots to mfaces. */
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()) {
@@ -315,6 +318,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 {
@@ -514,5 +651,6 @@ 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);
}
diff --git a/source/blender/editors/datafiles/CMakeLists.txt b/source/blender/editors/datafiles/CMakeLists.txt
index 9e7e00d5656..59370b53995 100644
--- a/source/blender/editors/datafiles/CMakeLists.txt
+++ b/source/blender/editors/datafiles/CMakeLists.txt
@@ -777,12 +777,15 @@ set_property(GLOBAL PROPERTY ICON_GEOM_NAMES
ops.curves.sculpt_cut
ops.curves.sculpt_delete
ops.curves.sculpt_grow_shrink
+ ops.curves.sculpt_pinch
+ ops.curves.sculpt_puff
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
diff --git a/source/blender/editors/geometry/geometry_attributes.cc b/source/blender/editors/geometry/geometry_attributes.cc
index 05f9e19da71..ed16b8a903a 100644
--- a/source/blender/editors/geometry/geometry_attributes.cc
+++ b/source/blender/editors/geometry/geometry_attributes.cc
@@ -385,24 +385,16 @@ void GEOMETRY_OT_color_attribute_add(wmOperatorType *ot)
ot->srna, "name", "Color", MAX_NAME, "Name", "Name of new color attribute");
RNA_def_property_flag(prop, PROP_SKIP_SAVE);
- static EnumPropertyItem domains[3] = {{ATTR_DOMAIN_POINT, "POINT", 0, "Vertex", ""},
- {ATTR_DOMAIN_CORNER, "CORNER", 0, "Face Corner", ""},
- {0, nullptr, 0, nullptr, nullptr}};
-
- static EnumPropertyItem types[3] = {{CD_PROP_COLOR, "COLOR", 0, "Color", ""},
- {CD_PROP_BYTE_COLOR, "BYTE_COLOR", 0, "Byte Color", ""},
- {0, nullptr, 0, nullptr, nullptr}};
-
prop = RNA_def_enum(ot->srna,
"domain",
- domains,
+ rna_enum_color_attribute_domain_items,
ATTR_DOMAIN_POINT,
"Domain",
"Type of element that attribute is stored on");
prop = RNA_def_enum(ot->srna,
"data_type",
- types,
+ rna_enum_color_attribute_type_items,
CD_PROP_COLOR,
"Data Type",
"Type of data stored in attribute");
@@ -410,7 +402,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);
}
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/button2d_gizmo.c b/source/blender/editors/gizmo_library/gizmo_types/button2d_gizmo.c
index b326d6d1859..a0e30c7518a 100644
--- a/source/blender/editors/gizmo_library/gizmo_types/button2d_gizmo.c
+++ b/source/blender/editors/gizmo_library/gizmo_types/button2d_gizmo.c
@@ -74,7 +74,7 @@ static void button2d_geom_draw_backdrop(const wmGizmo *gz,
GPU_viewport_size_get_f(viewport);
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. */
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..1d9fc35eda8 100644
--- a/source/blender/editors/gizmo_library/gizmo_types/dial3d_gizmo.c
+++ b/source/blender/editors/gizmo_library/gizmo_types/dial3d_gizmo.c
@@ -96,7 +96,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) {
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..46fede8f6be 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 :
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 3cdf364e4b2..01ac02a9a1d 100644
--- a/source/blender/editors/gpencil/gpencil_sculpt_paint.c
+++ b/source/blender/editors/gpencil/gpencil_sculpt_paint.c
@@ -146,6 +146,10 @@ typedef struct tGP_BrushEditData {
float inv_mat[4][4];
RNG *rng;
+ /* Auto-masking strokes. */
+ struct GHash *automasking_strokes;
+ bool automasking_ready;
+
} tGP_BrushEditData;
/* Callback for performing some brush operation on a single point */
@@ -1182,9 +1186,18 @@ static bool gpencil_sculpt_brush_init(bContext *C, wmOperator *op)
gso->region = CTX_wm_region(C);
Paint *paint = &ts->gp_sculptpaint->paint;
- gso->brush = paint->brush;
+ Brush *brush = paint->brush;
+ gso->brush = brush;
BKE_curvemapping_init(gso->brush->curve);
+ if (brush->gpencil_settings->sculpt_mode_flag &
+ (GP_SCULPT_FLAGMODE_AUTOMASK_STROKE | GP_SCULPT_FLAGMODE_AUTOMASK_LAYER |
+ GP_SCULPT_FLAGMODE_AUTOMASK_MATERIAL)) {
+ gso->automasking_strokes = BLI_ghash_ptr_new(__func__);
+ }
+ else {
+ gso->automasking_strokes = NULL;
+ }
/* save mask */
gso->mask = ts->gpencil_selectmode_sculpt;
@@ -1285,6 +1298,10 @@ static void gpencil_sculpt_brush_exit(bContext *C, wmOperator *op)
BLI_rng_free(gso->rng);
}
+ if (gso->automasking_strokes != NULL) {
+ BLI_ghash_free(gso->automasking_strokes, NULL, NULL);
+ }
+
/* Disable headerprints. */
ED_workspace_status_text(C, NULL);
@@ -1570,11 +1587,15 @@ static bool gpencil_sculpt_brush_do_frame(bContext *C,
bool redo_geom = false;
Object *ob = gso->object;
bGPdata *gpd = ob->data;
- char tool = gso->brush->gpencil_sculpt_tool;
+ const char tool = gso->brush->gpencil_sculpt_tool;
GP_SpaceConversion *gsc = &gso->gsc;
Brush *brush = gso->brush;
const int radius = (brush->flag & GP_BRUSH_USE_PRESSURE) ? gso->brush->size * gso->pressure :
gso->brush->size;
+ const bool is_automasking = (brush->gpencil_settings->sculpt_mode_flag &
+ (GP_SCULPT_FLAGMODE_AUTOMASK_STROKE |
+ GP_SCULPT_FLAGMODE_AUTOMASK_LAYER |
+ GP_SCULPT_FLAGMODE_AUTOMASK_MATERIAL)) != 0;
/* Calc bound box matrix. */
float bound_mat[4][4];
BKE_gpencil_layer_transform_matrix_get(gso->depsgraph, gso->object, gpl, bound_mat);
@@ -1589,6 +1610,13 @@ static bool gpencil_sculpt_brush_do_frame(bContext *C,
continue;
}
+ {
+ bGPDstroke *gps_active = (gps->runtime.gps_orig) ? gps->runtime.gps_orig : gps;
+ if ((is_automasking) && (!BLI_ghash_haskey(gso->automasking_strokes, gps_active))) {
+ continue;
+ }
+ }
+
/* Check if the stroke collide with brush. */
if (!ED_gpencil_stroke_check_collision(gsc, gps, gso->mval, radius, bound_mat)) {
continue;
@@ -1699,6 +1727,132 @@ static bool gpencil_sculpt_brush_do_frame(bContext *C,
return changed;
}
+/* Get list of Auto-Masking strokes. */
+static bool get_automasking_strokes_list(tGP_BrushEditData *gso)
+{
+ bGPdata *gpd = gso->gpd;
+ GP_SpaceConversion *gsc = &gso->gsc;
+ Brush *brush = gso->brush;
+ Object *ob = gso->object;
+ Material *mat_active = BKE_gpencil_material(ob, ob->actcol);
+ const bool is_multiedit = (bool)GPENCIL_MULTIEDIT_SESSIONS_ON(gpd);
+ const bool is_masking_stroke = (brush->gpencil_settings->sculpt_mode_flag &
+ GP_SCULPT_FLAGMODE_AUTOMASK_STROKE) != 0;
+ const bool is_masking_layer = (brush->gpencil_settings->sculpt_mode_flag &
+ GP_SCULPT_FLAGMODE_AUTOMASK_LAYER) != 0;
+ const bool is_masking_material = (brush->gpencil_settings->sculpt_mode_flag &
+ GP_SCULPT_FLAGMODE_AUTOMASK_MATERIAL) != 0;
+ int mval_i[2];
+ round_v2i_v2fl(mval_i, gso->mval);
+
+ /* Define a fix number of pixel as cursor radius. */
+ const int radius = 10;
+ bGPDlayer *gpl_active = BKE_gpencil_layer_active_get(gpd);
+
+ LISTBASE_FOREACH (bGPDlayer *, gpl, &gpd->layers) {
+ /* Only editable and visible layers are considered. */
+ if (!BKE_gpencil_layer_is_editable(gpl) || (gpl->actframe == NULL)) {
+ continue;
+ }
+ /* Calculate bound box matrix. */
+ float bound_mat[4][4];
+ BKE_gpencil_layer_transform_matrix_get(gso->depsgraph, gso->object, gpl, bound_mat);
+
+ bGPDframe *init_gpf = (is_multiedit) ? gpl->frames.first : gpl->actframe;
+ for (bGPDframe *gpf = init_gpf; gpf; gpf = gpf->next) {
+ LISTBASE_FOREACH (bGPDstroke *, gps, &gpf->strokes) {
+ if (gps->totpoints == 0) {
+ continue;
+ }
+ /* Check if the color is editable. */
+ if (ED_gpencil_stroke_material_editable(gso->object, gpl, gps) == false) {
+ continue;
+ }
+
+ /* Layer Auto-Masking. */
+ if ((is_masking_layer) && (gpl == gpl_active)) {
+ BLI_ghash_insert(gso->automasking_strokes, gps, gps);
+ continue;
+ }
+ /* Material Auto-Masking. */
+ if (is_masking_material) {
+ Material *mat = BKE_object_material_get(ob, gps->mat_nr + 1);
+ if (mat == mat_active) {
+ BLI_ghash_insert(gso->automasking_strokes, gps, gps);
+ continue;
+ }
+ }
+
+ /* If Stroke Auto-Masking is not enabled, nothing else to do. */
+ if (!is_masking_stroke) {
+ continue;
+ }
+
+ /* Check if the stroke collide with brush. */
+ if (!ED_gpencil_stroke_check_collision(gsc, gps, gso->mval, radius, bound_mat)) {
+ continue;
+ }
+
+ bGPDspoint *pt1, *pt2;
+ int pc1[2] = {0};
+ int pc2[2] = {0};
+ bGPDspoint npt;
+
+ if (gps->totpoints == 1) {
+ gpencil_point_to_parent_space(gps->points, bound_mat, &npt);
+ gpencil_point_to_xy(gsc, gps, &npt, &pc1[0], &pc1[1]);
+
+ /* Only check if point is inside. */
+ if (len_v2v2_int(mval_i, pc1) <= radius) {
+ BLI_ghash_insert(gso->automasking_strokes, gps, gps);
+ }
+ }
+ else {
+ /* Loop over the points in the stroke, checking for intersections
+ * - an intersection means that we touched the stroke.
+ */
+ for (int i = 0; (i + 1) < gps->totpoints; i++) {
+ /* Get points to work with. */
+ pt1 = gps->points + i;
+ pt2 = gps->points + i + 1;
+
+ /* Check first point. */
+ gpencil_point_to_parent_space(pt1, bound_mat, &npt);
+ gpencil_point_to_xy(gsc, gps, &npt, &pc1[0], &pc1[1]);
+ if (len_v2v2_int(mval_i, pc1) <= radius) {
+ BLI_ghash_insert(gso->automasking_strokes, gps, gps);
+ i = gps->totpoints;
+ continue;
+ }
+
+ /* Check second point. */
+ gpencil_point_to_parent_space(pt2, bound_mat, &npt);
+ gpencil_point_to_xy(gsc, gps, &npt, &pc2[0], &pc2[1]);
+ if (len_v2v2_int(mval_i, pc2) <= radius) {
+ BLI_ghash_insert(gso->automasking_strokes, gps, gps);
+ i = gps->totpoints;
+ continue;
+ }
+
+ /* Check segment. */
+ if (gpencil_stroke_inside_circle(gso->mval, radius, pc1[0], pc1[1], pc2[0], pc2[1])) {
+ BLI_ghash_insert(gso->automasking_strokes, gps, gps);
+ i = gps->totpoints;
+ continue;
+ }
+ }
+ }
+ }
+ /* If not multi-edit, exit loop. */
+ if (!is_multiedit) {
+ break;
+ }
+ }
+ }
+
+ return true;
+}
+
/* Perform two-pass brushes which modify the existing strokes */
static bool gpencil_sculpt_brush_apply_standard(bContext *C, tGP_BrushEditData *gso)
{
@@ -1840,6 +1994,14 @@ static void gpencil_sculpt_brush_apply(bContext *C, wmOperator *op, PointerRNA *
gso->brush_rect.xmax = mouse[0] + radius;
gso->brush_rect.ymax = mouse[1] + radius;
+ /* Get list of Auto-Masking strokes. */
+ if ((!gso->automasking_ready) &&
+ (brush->gpencil_settings->sculpt_mode_flag &
+ (GP_SCULPT_FLAGMODE_AUTOMASK_STROKE | GP_SCULPT_FLAGMODE_AUTOMASK_LAYER |
+ GP_SCULPT_FLAGMODE_AUTOMASK_MATERIAL))) {
+ gso->automasking_ready = get_automasking_strokes_list(gso);
+ }
+
/* Apply brush */
char tool = gso->brush->gpencil_sculpt_tool;
if (tool == GPSCULPT_TOOL_CLONE) {
diff --git a/source/blender/editors/gpencil/gpencil_utils.c b/source/blender/editors/gpencil/gpencil_utils.c
index 2dc12125f40..23c385c1213 100644
--- a/source/blender/editors/gpencil/gpencil_utils.c
+++ b/source/blender/editors/gpencil/gpencil_utils.c
@@ -3077,6 +3077,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/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_keyframing.h b/source/blender/editors/include/ED_keyframing.h
index 6a730225da9..8c0147612fb 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.
*/
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 0078c1087a0..39c7ad3556c 100644
--- a/source/blender/editors/include/ED_object.h
+++ b/source/blender/editors/include/ED_object.h
@@ -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..aa62a6209e4 100644
--- a/source/blender/editors/include/ED_screen.h
+++ b/source/blender/editors/include/ED_screen.h
@@ -596,7 +596,7 @@ 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 +666,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_uvedit.h b/source/blender/editors/include/ED_uvedit.h
index 06134f1d7b5..80a75da27f8 100644
--- a/source/blender/editors/include/ED_uvedit.h
+++ b/source/blender/editors/include/ED_uvedit.h
@@ -24,6 +24,7 @@ struct Object;
struct Scene;
struct SpaceImage;
struct ToolSettings;
+struct View2D;
struct ViewLayer;
struct bContext;
struct bNode;
@@ -242,15 +243,12 @@ void uvedit_deselect_flush(const struct Scene *scene, struct BMEditMesh *em);
*/
void uvedit_select_flush(const struct Scene *scene, struct BMEditMesh *em);
-bool ED_uvedit_nearest_uv(const struct Scene *scene,
- struct Object *obedit,
- const float co[2],
- float *dist_sq,
- float r_uv[2]);
-bool ED_uvedit_nearest_uv_multi(const struct Scene *scene,
+bool ED_uvedit_nearest_uv_multi(const struct View2D *v2d,
+ const struct Scene *scene,
struct Object **objects,
uint objects_len,
- const float co[2],
+ const int mval[2],
+ const bool ignore_selected,
float *dist_sq,
float r_uv[2]);
diff --git a/source/blender/editors/include/ED_view3d.h b/source/blender/editors/include/ED_view3d.h
index 51fd8e6c533..8695e03a57f 100644
--- a/source/blender/editors/include/ED_view3d.h
+++ b/source/blender/editors/include/ED_view3d.h
@@ -7,6 +7,8 @@
#pragma once
+#include "BLI_utildefines.h"
+
#ifdef __cplusplus
extern "C" {
#endif
@@ -256,6 +258,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)
@@ -443,14 +446,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 +703,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 +736,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,
@@ -952,6 +955,22 @@ float ED_view3d_select_dist_px(void);
void ED_view3d_viewcontext_init(struct bContext *C,
struct ViewContext *vc,
struct Depsgraph *depsgraph);
+
+/**
+ * Re-initialize `vc` with `obact` as if it's active object (with some differences).
+ *
+ * This is often used when operating on multiple objects in modes (edit, pose mode etc)
+ * where the `vc` is passed in as an argument which then references it's object data.
+ *
+ * \note members #ViewContext.obedit & #ViewContext.em are only initialized if they're already set,
+ * by #ED_view3d_viewcontext_init in most cases.
+ * This is necessary because the active object defines the current object-mode.
+ * When iterating over objects in object-mode it doesn't make sense to perform
+ * an edit-mode action on an object that happens to contain edit-mode data.
+ * In some cases these values are cleared allowing the owner of `vc` to explicitly
+ * disable edit-mode operation (to force object selection in edit-mode for e.g.).
+ * So object-mode specific values should remain cleared when initialized with another object.
+ */
void ED_view3d_viewcontext_init_object(struct ViewContext *vc, struct Object *obact);
/**
* Use this call when executing an operator,
diff --git a/source/blender/editors/include/UI_icons.h b/source/blender/editors/include/UI_icons.h
index d1a6501408c..ea1095b26ff 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)
diff --git a/source/blender/editors/include/UI_interface.h b/source/blender/editors/include/UI_interface.h
index 1b61e87b140..a9a9c98cab8 100644
--- a/source/blender/editors/include/UI_interface.h
+++ b/source/blender/editors/include/UI_interface.h
@@ -202,7 +202,7 @@ enum {
UI_BUT_INACTIVE = 1 << 18,
UI_BUT_LAST_ACTIVE = 1 << 19,
UI_BUT_UNDO = 1 << 20,
- UI_BUT_IMMEDIATE = 1 << 21,
+ /* UNUSED = 1 << 21, */
UI_BUT_NO_UTF8 = 1 << 22,
/** For popups, pressing return activates this button, overriding the highlighted button.
@@ -221,7 +221,7 @@ enum {
UI_BUT_HAS_SEP_CHAR = 1 << 27,
/** Don't run updates while dragging (needed in rare cases). */
UI_BUT_UPDATE_DELAY = 1 << 28,
- /** When widget is in textedit mode, update value on each char stroke */
+ /** When widget is in text-edit mode, update value on each char stroke. */
UI_BUT_TEXTEDIT_UPDATE = 1 << 29,
/** Show 'x' icon to clear/unlink value of text or search button. */
UI_BUT_VALUE_CLEAR = 1 << 30,
@@ -454,7 +454,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.
@@ -1539,31 +1538,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 +1648,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);
/**
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/interface/interface.cc b/source/blender/editors/interface/interface.cc
index 480044118f1..d6719f0aa9f 100644
--- a/source/blender/editors/interface/interface.cc
+++ b/source/blender/editors/interface/interface.cc
@@ -3849,21 +3849,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 ");
}
@@ -3989,6 +3990,10 @@ 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;
default:
alloc_size = sizeof(uiBut);
alloc_str = "uiBut";
@@ -6280,64 +6285,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_handlers.c b/source/blender/editors/interface/interface_handlers.c
index 3e3b30a2c1e..a7dfff2edb4 100644
--- a/source/blender/editors/interface/interface_handlers.c
+++ b/source/blender/editors/interface/interface_handlers.c
@@ -542,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));
}
@@ -660,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)
@@ -900,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)
@@ -967,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);
}
}
@@ -1631,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);
@@ -4507,10 +4516,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;
}
@@ -4531,20 +4544,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);
@@ -8498,14 +8507,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);
diff --git a/source/blender/editors/interface/interface_intern.h b/source/blender/editors/interface/interface_intern.h
index 1c79d3218fb..1b245ba9e6f 100644
--- a/source/blender/editors/interface/interface_intern.h
+++ b/source/blender/editors/interface/interface_intern.h
@@ -229,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 */
@@ -381,6 +380,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.
*/
@@ -1212,24 +1218,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
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 f14c6ad9924..c066ced21cb 100644
--- a/source/blender/editors/interface/interface_ops.c
+++ b/source/blender/editors/interface/interface_ops.c
@@ -2142,11 +2142,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 +2181,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_region_search.cc b/source/blender/editors/interface/interface_region_search.cc
index bc497e2647c..64de31dfe6a 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++;
@@ -556,7 +556,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 +568,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 +590,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 +600,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 +615,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 +633,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 +646,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 +678,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 +848,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 +914,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 +937,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_style.cc b/source/blender/editors/interface/interface_style.cc
index 0156a943015..291ede05730 100644
--- a/source/blender/editors/interface/interface_style.cc
+++ b/source/blender/editors/interface/interface_style.cc
@@ -376,7 +376,7 @@ 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;
}
diff --git a/source/blender/editors/interface/interface_templates.c b/source/blender/editors/interface/interface_templates.c
index c6e5deb314e..a02e8a3ac49 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;
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_widgets.c b/source/blender/editors/interface/interface_widgets.c
index 98ecf91adbc..3777ff31b26 100644
--- a/source/blender/editors/interface/interface_widgets.c
+++ b/source/blender/editors/interface/interface_widgets.c
@@ -107,22 +107,22 @@ typedef enum {
UI_WTYPE_TREEROW,
} 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 +256,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 +1300,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 +1378,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);
@@ -2446,7 +2460,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 +2487,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 +2495,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 +2540,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 +2557,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 +2572,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 +2613,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 +2632,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 +2652,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 +2666,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 +2674,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 +2689,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 +2708,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 +2723,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 +2797,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 +2805,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 +3331,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 +3357,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 +3370,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 +3390,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 +3409,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 +3428,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 +3436,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 +3474,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 +3496,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 +3506,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 +3550,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 +3577,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 +3633,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 +3673,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 +3686,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,8 +3694,12 @@ 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);
@@ -3701,7 +3709,7 @@ static void widget_treerow(
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 +3745,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 +3764,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 +3772,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 +3840,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 +3852,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 +3862,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 +3891,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 +3954,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 +3962,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 +3991,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 +4013,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 +4022,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 +4038,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 +4072,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 +4096,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 +4118,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 +4144,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 +4161,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 +4192,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 +4209,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 +4231,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 +4255,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 +4281,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 +4311,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 +4333,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 +4488,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 +4544,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 */
@@ -4921,62 +4967,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 +5051,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 +5152,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 +5341,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 +5369,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 +5389,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 +5488,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 +5578,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/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/interface/view2d_gizmo_navigate.cc b/source/blender/editors/interface/view2d_gizmo_navigate.cc
index 01729e35246..fae28833e4f 100644
--- a/source/blender/editors/interface/view2d_gizmo_navigate.cc
+++ b/source/blender/editors/interface/view2d_gizmo_navigate.cc
@@ -130,6 +130,13 @@ static bool WIDGETGROUP_navigate_poll(const bContext *C, wmGizmoGroupType *UNUSE
}
break;
}
+ case SPACE_IMAGE: {
+ const SpaceImage *sima = static_cast<const SpaceImage *>(area->spacedata.first);
+ if (sima->gizmo_flag & (SI_GIZMO_HIDE | SI_GIZMO_HIDE_NAVIGATE)) {
+ return false;
+ }
+ break;
+ }
}
return true;
}
diff --git a/source/blender/editors/io/io_alembic.c b/source/blender/editors/io/io_alembic.c
index fd454083653..87923d9fdf8 100644
--- a/source/blender/editors/io/io_alembic.c
+++ b/source/blender/editors/io/io_alembic.c
@@ -282,6 +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;
WM_operator_properties_filesel(ot,
FILE_TYPE_FOLDER | FILE_TYPE_ALEMBIC,
@@ -475,7 +476,7 @@ void WM_OT_alembic_export(wmOperatorType *ot)
/* This dummy prop is used to check whether we need to init the start and
* end frame values to that of the scene's, otherwise they are reset at
* every change, draw update. */
- RNA_def_boolean(ot->srna, "init_scene_frame_range", false, "", "");
+ RNA_def_boolean(ot->srna, "init_scene_frame_range", true, "", "");
}
/* ************************************************************************** */
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_obj.c b/source/blender/editors/io/io_obj.c
index 886586ff236..f1cd7607771 100644
--- a/source/blender/editors/io/io_obj.c
+++ b/source/blender/editors/io/io_obj.c
@@ -16,6 +16,8 @@
#include "BLT_translation.h"
+#include "ED_outliner.h"
+
#include "MEM_guardedalloc.h"
#include "RNA_access.h"
@@ -410,6 +412,12 @@ static int wm_obj_import_exec(bContext *C, wmOperator *op)
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;
}
diff --git a/source/blender/editors/io/io_usd.c b/source/blender/editors/io/io_usd.c
index ca9c2de63a4..609230eefea 100644
--- a/source/blender/editors/io/io_usd.c
+++ b/source/blender/editors/io/io_usd.c
@@ -118,7 +118,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 +133,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,9 +181,9 @@ 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);
@@ -297,10 +297,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 ====== */
diff --git a/source/blender/editors/mask/mask_add.c b/source/blender/editors/mask/mask_add.c
index 0b9261eac4f..d10c420e28c 100644
--- a/source/blender/editors/mask/mask_add.c
+++ b/source/blender/editors/mask/mask_add.c
@@ -230,7 +230,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;
@@ -593,7 +593,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);
diff --git a/source/blender/editors/mask/mask_query.c b/source/blender/editors/mask/mask_query.c
index afe457a8502..89524a7b9e2 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;
}
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..cb5d48d1023 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);
@@ -175,9 +162,6 @@ void paintface_reveal(bContext *C, Object *ob, const bool select)
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_knife.c b/source/blender/editors/mesh/editmesh_knife.c
index 01276d7640d..5b3487b0a33 100644
--- a/source/blender/editors/mesh/editmesh_knife.c
+++ b/source/blender/editors/mesh/editmesh_knife.c
@@ -198,7 +198,7 @@ typedef struct KnifeObjectInfo {
* 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:
+ * and the loops in `em->looptris` no longer refer to the original triangles, see: T97153.
*/
const int (*tri_indices)[3];
@@ -377,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)
@@ -440,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)
@@ -1226,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;
@@ -1283,8 +1284,10 @@ static void knife_bvh_init(KnifeTool_OpData *kcd)
if (!test_fn_ret) {
continue;
}
- knife_bm_tri_cagecos_get_worldspace(kcd, b, i, cos);
- 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;
@@ -1307,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;
@@ -1315,60 +1322,49 @@ 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;
}
+ }
- 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,
- 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) {
+ hit->dist = dist;
+ hit->index = index;
- copy_v3_v3(hit->no, ltri[0]->f->no);
+ copy_v3_v3(hit->no, ltri[0]->f->no);
- madd_v3_v3v3fl(hit->co, ray->origin, ray->direction, dist);
+ madd_v3_v3v3fl(hit->co, ray->origin, ray->direction, dist);
- kcd->bvh.looptris = em->looptris;
- copy_v2_v2(kcd->bvh.uv, uv);
- kcd->bvh.base_index = b;
- }
+ kcd->bvh.looptris = em->looptris;
+ copy_v2_v2(kcd->bvh.uv, uv);
+ kcd->bvh.base_index = b;
}
}
@@ -1978,29 +1974,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;
}
}
}
@@ -2272,11 +2269,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;
}
}
@@ -2588,7 +2586,7 @@ 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];
@@ -2596,22 +2594,22 @@ static bool knife_ray_intersect_face(KnifeTool_OpData *kcd,
break;
}
- knife_bm_tri_cagecos_get_worldspace(kcd, base_index, tri_i, lv);
+ 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) {
@@ -5028,17 +5026,19 @@ void EDBM_mesh_knife(ViewContext *vc, LinkNode *polys, bool use_tag, bool cut_th
/* 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);
}
}
}
@@ -5048,43 +5048,45 @@ void EDBM_mesh_knife(ViewContext *vc, LinkNode *polys, bool use_tag, bool cut_th
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);
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_utils.c b/source/blender/editors/mesh/editmesh_utils.c
index c3d5f33705c..c7c7e5cf2f8 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"
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 5abbfc2cb14..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;
@@ -300,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);
@@ -313,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 20b9844ac89..422aaa03120 100644
--- a/source/blender/editors/object/object_add.cc
+++ b/source/blender/editors/object/object_add.cc
@@ -1265,9 +1265,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);
}
@@ -1729,8 +1729,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);
@@ -1762,16 +1761,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);
}
@@ -1868,20 +1858,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",
@@ -1913,18 +1894,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;
}
@@ -1967,7 +1942,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);
@@ -2109,6 +2084,22 @@ static int object_curves_empty_hair_add_exec(bContext *C, wmOperator *op)
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";
@@ -2116,7 +2107,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;
@@ -2755,9 +2746,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) {
@@ -3058,6 +3072,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;
@@ -3473,6 +3531,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,
diff --git a/source/blender/editors/object/object_bake_api.c b/source/blender/editors/object/object_bake_api.c
index a7379d7e492..114b2ce8102 100644
--- a/source/blender/editors/object/object_bake_api.c
+++ b/source/blender/editors/object/object_bake_api.c
@@ -446,9 +446,9 @@ 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 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);
+ const MLoopCol *mloopcol = CustomData_get_layer(&me->ldata, CD_PROP_BYTE_COLOR);
if (mloopcol == NULL && !mcol_valid) {
BKE_reportf(reports,
RPT_ERROR,
@@ -943,9 +943,9 @@ static bool bake_targets_init_vertex_colors(BakeTargets *targets, Object *ob, Re
}
Mesh *me = ob->data;
- MPropCol *mcol = CustomData_get_layer(&me->vdata, CD_PROP_COLOR);
+ const 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);
+ const 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");
return false;
diff --git a/source/blender/editors/object/object_constraint.c b/source/blender/editors/object/object_constraint.c
index 2e878770347..d982d86fe77 100644
--- a/source/blender/editors/object/object_constraint.c
+++ b/source/blender/editors/object/object_constraint.c
@@ -1715,7 +1715,7 @@ static int constraint_copy_to_selected_exec(bContext *C, wmOperator *op)
Object *prev_ob = NULL;
- /* Copy all constraints from active posebone to all selected posebones. */
+ /* Copy all constraints from active pose-bone to all selected pose-bones. */
CTX_DATA_BEGIN_WITH_ID (C, bPoseChannel *, chan, selected_pose_bones, Object *, ob) {
/* If we're not handling the object we're copying from, copy all constraints over. */
if (pchan == chan) {
@@ -2115,7 +2115,7 @@ static int pose_constraint_copy_exec(bContext *C, wmOperator *op)
Object *prev_ob = NULL;
- /* copy all constraints from active posebone to all selected posebones */
+ /* Copy all constraints from active pose-bone to all selected pose-bones. */
CTX_DATA_BEGIN_WITH_ID (C, bPoseChannel *, chan, selected_pose_bones, Object *, ob) {
/* if we're not handling the object we're copying from, copy all constraints over */
if (pchan != chan) {
diff --git a/source/blender/editors/object/object_data_transfer.c b/source/blender/editors/object/object_data_transfer.c
index dfe858e5bd9..b9a4c79ac03 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",
diff --git a/source/blender/editors/object/object_edit.c b/source/blender/editors/object/object_edit.c
index c0637f4ac04..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"
@@ -1467,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;
@@ -1514,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;
}
@@ -1583,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)");
}
/** \} */
diff --git a/source/blender/editors/object/object_modes.c b/source/blender/editors/object/object_modes.c
index cc6aa34d39d..fdf2cae026d 100644
--- a/source/blender/editors/object/object_modes.c
+++ b/source/blender/editors/object/object_modes.c
@@ -143,7 +143,12 @@ bool ED_object_mode_compat_test(const Object *ob, eObjectMode mode)
}
break;
case OB_CURVES:
- if (mode & (OB_MODE_EDIT | OB_MODE_SCULPT_CURVES)) {
+ if (U.experimental.use_new_curves_tools) {
+ if (mode & OB_MODE_EDIT) {
+ return true;
+ }
+ }
+ if (mode & OB_MODE_SCULPT_CURVES) {
return true;
}
break;
diff --git a/source/blender/editors/object/object_modifier.cc b/source/blender/editors/object/object_modifier.cc
index 963e92942bb..45c751f2c40 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;
@@ -1608,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)
@@ -1618,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);
@@ -1646,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";
@@ -1657,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");
}
/** \} */
diff --git a/source/blender/editors/object/object_relations.c b/source/blender/editors/object/object_relations.c
index 111f3b6bf92..6cfd322b2e2 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",
@@ -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 &&
@@ -2359,7 +2320,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,25 +2343,34 @@ 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. */
@@ -2411,6 +2384,37 @@ static int make_override_library_exec(bContext *C, wmOperator *op)
return success ? OPERATOR_FINISHED : OPERATOR_CANCELLED;
}
+/* 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)) {
+ return make_override_library_exec(C, op);
+ }
+
+ 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 bool make_override_library_poll(bContext *C)
{
Object *obact = CTX_data_active_object(C);
@@ -2480,6 +2484,13 @@ void OBJECT_OT_make_override_library(wmOperatorType *ot)
RNA_def_enum_funcs(prop, make_override_collections_of_linked_object_itemf);
RNA_def_property_flag(prop, PROP_ENUM_NO_TRANSLATE);
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);
}
/** \} */
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/screen_edit.c b/source/blender/editors/screen/screen_edit.c
index d5385181055..43c19670a41 100644
--- a/source/blender/editors/screen/screen_edit.c
+++ b/source/blender/editors/screen/screen_edit.c
@@ -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..a922e5aaaee 100644
--- a/source/blender/editors/screen/screen_ops.c
+++ b/source/blender/editors/screen/screen_ops.c
@@ -685,10 +685,10 @@ bool ED_operator_mask(bContext *C)
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));
}
/** \} */
diff --git a/source/blender/editors/sculpt_paint/CMakeLists.txt b/source/blender/editors/sculpt_paint/CMakeLists.txt
index 08eed52f440..d3bf28798c4 100644
--- a/source/blender/editors/sculpt_paint/CMakeLists.txt
+++ b/source/blender/editors/sculpt_paint/CMakeLists.txt
@@ -27,8 +27,8 @@ set(INC
)
set(SRC
- curves_sculpt_3d_brush.cc
curves_sculpt_add.cc
+ curves_sculpt_brush.cc
curves_sculpt_comb.cc
curves_sculpt_delete.cc
curves_sculpt_grow_shrink.cc
diff --git a/source/blender/editors/sculpt_paint/curves_sculpt_add.cc b/source/blender/editors/sculpt_paint/curves_sculpt_add.cc
index 0d399419ad8..d7f4b71d2d0 100644
--- a/source/blender/editors/sculpt_paint/curves_sculpt_add.cc
+++ b/source/blender/editors/sculpt_paint/curves_sculpt_add.cc
@@ -18,9 +18,11 @@
#include "BKE_bvhutils.h"
#include "BKE_context.h"
#include "BKE_curves.hh"
+#include "BKE_curves_utils.hh"
#include "BKE_mesh.h"
#include "BKE_mesh_runtime.h"
#include "BKE_paint.h"
+#include "BKE_report.h"
#include "BKE_spline.hh"
#include "DNA_brush_enums.h"
@@ -35,6 +37,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.
@@ -62,7 +66,7 @@ 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,
@@ -81,11 +85,12 @@ static void initialize_straight_curve_positions(const float3 &p1,
*/
struct AddOperationExecutor {
AddOperation *self_ = nullptr;
- Depsgraph *depsgraph_ = nullptr;
- Scene *scene_ = nullptr;
- Object *object_ = nullptr;
+ const Depsgraph *depsgraph_ = nullptr;
+ const Scene *scene_ = nullptr;
ARegion *region_ = nullptr;
- View3D *v3d_ = nullptr;
+ const View3D *v3d_ = nullptr;
+
+ Object *object_ = nullptr;
Curves *curves_id_ = nullptr;
CurvesGeometry *curves_ = nullptr;
@@ -94,9 +99,9 @@ struct AddOperationExecutor {
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;
float brush_radius_re_;
float2 brush_pos_re_;
@@ -104,10 +109,11 @@ struct AddOperationExecutor {
bool use_front_face_;
bool interpolate_length_;
bool interpolate_shape_;
+ bool interpolate_point_count_;
bool use_interpolation_;
float new_curve_length_;
int add_amount_;
- int points_per_curve_ = 8;
+ int constant_points_per_curve_;
/** Various matrices to convert between coordinate spaces. */
float4x4 curves_to_world_mat_;
@@ -128,14 +134,23 @@ struct AddOperationExecutor {
Vector<int> looptri_indices;
};
- void execute(AddOperation &self, bContext *C, const StrokeExtension &stroke_extension)
+ 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 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);
+ depsgraph_ = CTX_data_depsgraph_pointer(&C);
+ scene_ = CTX_data_scene(&C);
+ object_ = CTX_data_active_object(&C);
+ region_ = CTX_wm_region(&C);
+ v3d_ = CTX_wm_view3d(&C);
curves_id_ = static_cast<Curves *>(object_->data);
curves_ = &CurvesGeometry::wrap(curves_id_->geometry);
@@ -162,18 +177,21 @@ struct AddOperationExecutor {
surface_->totloop};
curves_sculpt_ = scene_->toolsettings->curves_sculpt;
- brush_ = BKE_paint_brush(&curves_sculpt_->paint);
+ 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(*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);
+ constant_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_;
+ interpolate_point_count_ = brush_settings_->flag &
+ BRUSH_CURVES_SCULPT_FLAG_INTERPOLATE_POINT_COUNT;
+ use_interpolation_ = interpolate_length_ || interpolate_shape_ || interpolate_point_count_;
new_curve_length_ = brush_settings_->curve_length;
tot_old_curves_ = curves_->curves_num();
@@ -183,7 +201,9 @@ struct AddOperationExecutor {
return;
}
- RandomNumberGenerator rng{(uint32_t)(PIL_check_seconds_timer() * 1000000.0f)};
+ const double time = PIL_check_seconds_timer() * 1000000.0;
+ /* Use a pointer cast to avoid overflow warnings. */
+ RandomNumberGenerator rng{*(uint32_t *)(&time)};
BKE_bvhtree_from_mesh_get(&surface_bvh_, surface_, BVHTREE_FROM_LOOPTRI, 2);
BLI_SCOPED_DEFER([&]() { free_bvhtree_from_mesh(&surface_bvh_); });
@@ -194,13 +214,13 @@ struct AddOperationExecutor {
/* Sample points on the surface using one of multiple strategies. */
AddedPoints added_points;
if (add_amount_ == 1) {
- this->sample_in_center(added_points);
+ this->sample_in_center_with_symmetry(added_points);
}
else if (falloff_shape == PAINT_FALLOFF_SHAPE_TUBE) {
- this->sample_projected(rng, added_points);
+ this->sample_projected_with_symmetry(rng, added_points);
}
else if (falloff_shape == PAINT_FALLOFF_SHAPE_SPHERE) {
- this->sample_spherical(rng, added_points);
+ this->sample_spherical_with_symmetry(rng, added_points);
}
else {
BLI_assert_unreachable();
@@ -211,20 +231,31 @@ struct AddOperationExecutor {
return;
}
+ Array<NeighborsVector> neighbors_per_curve;
if (use_interpolation_) {
this->ensure_curve_roots_kdtree();
+ neighbors_per_curve = this->find_curve_neighbors(added_points);
}
+ /* Resize to add the new curves, building the offsets in the array owned by the curves. */
const int tot_added_curves = added_points.bary_coords.size();
- const int tot_added_points = tot_added_curves * points_per_curve_;
+ curves_->resize(curves_->points_num(), curves_->curves_num() + tot_added_curves);
+ if (interpolate_point_count_) {
+ this->initialize_curve_offsets_with_interpolation(neighbors_per_curve);
+ }
+ else {
+ this->initialize_curve_offsets_without_interpolation(constant_points_per_curve_);
+ }
+
+ /* Resize to add the correct point count calculated as part of building the offsets. */
+ curves_->resize(curves_->offsets().last(), curves_->curves_num());
- curves_->resize(curves_->points_num() + tot_added_points,
- curves_->curves_num() + tot_added_curves);
+ this->initialize_attributes(added_points, neighbors_per_curve);
- threading::parallel_invoke([&]() { this->initialize_curve_offsets(tot_added_curves); },
- [&]() { this->initialize_attributes(added_points); });
+ curves_->update_curve_types();
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(region_);
}
@@ -241,13 +272,27 @@ struct AddOperationExecutor {
/**
* Sample a single point exactly at the mouse position.
*/
- void sample_in_center(AddedPoints &r_added_points)
+ void sample_in_center_with_symmetry(AddedPoints &r_added_points)
{
float3 ray_start_wo, ray_end_wo;
ED_view3d_win_to_segment_clipped(
depsgraph_, region_, v3d_, brush_pos_re_, ray_start_wo, ray_end_wo, true);
const float3 ray_start_su = world_to_surface_mat_ * ray_start_wo;
const float3 ray_end_su = world_to_surface_mat_ * ray_end_wo;
+
+ const 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);
+ }
+ }
+
+ void sample_in_center(AddedPoints &r_added_points,
+ const float3 &ray_start_su,
+ const float3 &ray_end_su)
+ {
const float3 ray_direction_su = math::normalize(ray_end_su - ray_start_su);
BVHTreeRayHit ray_hit;
@@ -280,11 +325,23 @@ struct AddOperationExecutor {
/**
* Sample points by shooting rays within the brush radius in the 3D view.
*/
- void sample_projected(RandomNumberGenerator &rng, AddedPoints &r_added_points)
+ void sample_projected_with_symmetry(RandomNumberGenerator &rng, AddedPoints &r_added_points)
{
+ const Vector<float4x4> symmetry_brush_transforms = get_symmetry_brush_transforms(
+ eCurvesSymmetryType(curves_id_->symmetry));
+ for (const float4x4 &brush_transform : symmetry_brush_transforms) {
+ this->sample_projected(rng, r_added_points, brush_transform);
+ }
+ }
+
+ void sample_projected(RandomNumberGenerator &rng,
+ AddedPoints &r_added_points,
+ 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);
int current_iteration = 0;
- while (r_added_points.bary_coords.size() < add_amount_) {
+ while (r_added_points.bary_coords.size() < old_amount + add_amount_) {
if (current_iteration++ >= max_iterations) {
break;
}
@@ -296,8 +353,8 @@ struct AddOperationExecutor {
float3 ray_start_wo, ray_end_wo;
ED_view3d_win_to_segment_clipped(
depsgraph_, region_, v3d_, pos_re, ray_start_wo, ray_end_wo, true);
- const float3 ray_start_su = world_to_surface_mat_ * ray_start_wo;
- const float3 ray_end_su = world_to_surface_mat_ * ray_end_wo;
+ const float3 ray_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;
@@ -339,7 +396,7 @@ struct AddOperationExecutor {
/**
* Sample points in a 3D sphere around the surface position that the mouse hovers over.
*/
- void sample_spherical(RandomNumberGenerator &rng, AddedPoints &r_added_points)
+ 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;
@@ -347,7 +404,6 @@ struct AddOperationExecutor {
depsgraph_, region_, v3d_, brush_pos_re_, brush_ray_start_wo, brush_ray_end_wo, true);
const float3 brush_ray_start_su = world_to_surface_mat_ * brush_ray_start_wo;
const float3 brush_ray_end_su = world_to_surface_mat_ * brush_ray_end_wo;
- const float3 brush_ray_direction_su = math::normalize(brush_ray_end_su - brush_ray_start_su);
/* Find ray that starts on the boundary of the brush. That is used to compute the brush radius
* in 3D. */
@@ -362,6 +418,27 @@ struct AddOperationExecutor {
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 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);
+ }
+ }
+
+ 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_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;
@@ -426,7 +503,8 @@ struct AddOperationExecutor {
const int max_iterations = 5;
int current_iteration = 0;
- while (r_added_points.bary_coords.size() < add_amount_) {
+ const int old_amount = r_added_points.bary_coords.size();
+ while (r_added_points.bary_coords.size() < old_amount + add_amount_) {
if (current_iteration++ >= max_iterations) {
break;
}
@@ -506,8 +584,8 @@ struct AddOperationExecutor {
}
/* Remove samples when there are too many. */
- while (r_added_points.bary_coords.size() > add_amount_) {
- const int index_to_remove = rng.get_int32(r_added_points.bary_coords.size());
+ while (r_added_points.bary_coords.size() > old_amount + add_amount_) {
+ const int index_to_remove = rng.get_int32(add_amount_) + old_amount;
r_added_points.bary_coords.remove_and_reorder(index_to_remove);
r_added_points.looptri_indices.remove_and_reorder(index_to_remove);
r_added_points.positions_cu.remove_and_reorder(index_to_remove);
@@ -527,33 +605,42 @@ struct AddOperationExecutor {
}
}
- void initialize_curve_offsets(const int tot_added_curves)
+ void initialize_curve_offsets_with_interpolation(const Span<NeighborsVector> neighbors_per_curve)
{
- 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_;
+ MutableSpan<int> new_offsets = curves_->offsets_for_write().drop_front(tot_old_curves_);
+
+ attribute_math::DefaultMixer<int> mixer{new_offsets};
+ threading::parallel_for(neighbors_per_curve.index_range(), 1024, [&](IndexRange curves_range) {
+ for (const int i : curves_range) {
+ if (neighbors_per_curve[i].is_empty()) {
+ mixer.mix_in(i, constant_points_per_curve_, 1.0f);
+ }
+ else {
+ for (const NeighborInfo &neighbor : neighbors_per_curve[i]) {
+ const int neighbor_points_num = curves_->points_for_curve(neighbor.index).size();
+ mixer.mix_in(i, neighbor_points_num, neighbor.weight);
+ }
+ }
}
});
- }
+ mixer.finalize();
- 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>;
+ bke::curves::accumulate_counts_to_offsets(new_offsets, tot_old_points_);
+ }
- void initialize_attributes(const AddedPoints &added_points)
+ void initialize_curve_offsets_without_interpolation(const int points_per_curve)
{
- Array<NeighborsVector> neighbors_per_curve;
- if (use_interpolation_) {
- neighbors_per_curve = this->find_curve_neighbors(added_points);
+ MutableSpan<int> new_offsets = curves_->offsets_for_write().drop_front(tot_old_curves_);
+ int offset = tot_old_points_;
+ for (const int i : new_offsets.index_range()) {
+ new_offsets[i] = offset;
+ offset += points_per_curve;
}
+ }
+ void initialize_attributes(const AddedPoints &added_points,
+ const Span<NeighborsVector> neighbors_per_curve)
+ {
Array<float> new_lengths_cu(added_points.bary_coords.size());
if (interpolate_length_) {
this->interpolate_lengths(neighbors_per_curve, new_lengths_cu);
@@ -613,10 +700,9 @@ struct AddOperationExecutor {
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];
+ for (const int segment_i : neighbor_points.drop_back(1)) {
+ const float3 &p1 = positions_cu[segment_i];
+ const float3 &p2 = positions_cu[segment_i + 1];
neighbor_length += math::distance(p1, p2);
}
length_sum += neighbor.weight * neighbor_length;
@@ -682,15 +768,14 @@ struct AddOperationExecutor {
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 IndexRange points = curves_->points_for_curve(tot_old_curves_ + i);
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_));
+ initialize_straight_curve_positions(root_cu, tip_cu, positions_cu.slice(points));
}
});
}
@@ -711,23 +796,22 @@ struct AddOperationExecutor {
added_points.bary_coords.index_range(), 256, [&](const IndexRange range) {
for (const int i : range) {
const Span<NeighborInfo> neighbors = neighbors_per_curve[i];
+ const IndexRange points = curves_->points_for_curve(tot_old_curves_ + 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_));
+ initialize_straight_curve_positions(root_cu, tip_cu, positions_cu.slice(points));
continue;
}
- positions_cu.slice(first_point_i, points_per_curve_).fill(root_cu);
+ positions_cu.slice(points).fill(root_cu);
for (const NeighborInfo &neighbor : neighbors) {
const int neighbor_curve_i = neighbor.index;
@@ -761,8 +845,8 @@ struct AddOperationExecutor {
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 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;
@@ -772,7 +856,7 @@ struct AddOperationExecutor {
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;
+ positions_cu[points[j]] += neighbor.weight * rotated_relative_coord;
}
}
}
@@ -780,14 +864,23 @@ struct AddOperationExecutor {
}
};
-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;
executor.execute(*this, C, stroke_extension);
}
-std::unique_ptr<CurvesSculptStrokeOperation> new_add_operation()
+std::unique_ptr<CurvesSculptStrokeOperation> new_add_operation(const bContext &C,
+ ReportList *reports)
{
+ const Object &ob_active = *CTX_data_active_object(&C);
+ BLI_assert(ob_active.type == OB_CURVES);
+ 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 {};
+ }
+
return std::make_unique<AddOperation>();
}
diff --git a/source/blender/editors/sculpt_paint/curves_sculpt_3d_brush.cc b/source/blender/editors/sculpt_paint/curves_sculpt_brush.cc
index 945bb09c0c6..92ce6ba3153 100644
--- a/source/blender/editors/sculpt_paint/curves_sculpt_3d_brush.cc
+++ b/source/blender/editors/sculpt_paint/curves_sculpt_brush.cc
@@ -41,9 +41,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 +94,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);
@@ -116,8 +135,11 @@ static std::optional<float3> find_curves_brush_position(const CurvesGeometry &cu
const float distance_sq_re = math::distance_squared(brush_pos_re, closest_re);
+ float3 brush_position_cu;
+ closest_to_line_segment_v3(brush_position_cu, closest_cu, ray_start_cu, ray_end_cu);
+
BrushPositionCandidate candidate;
- candidate.position_cu = closest_cu;
+ candidate.position_cu = brush_position_cu;
candidate.depth_sq_cu = depth_sq_cu;
candidate.distance_sq_re = distance_sq_re;
@@ -138,23 +160,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) {
@@ -202,8 +222,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. */
@@ -213,9 +233,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,
@@ -229,4 +249,32 @@ std::optional<CurvesBrush3D> sample_curves_3d_brush(bContext &C,
return brush_3d;
}
+Vector<float4x4> get_symmetry_brush_transforms(const eCurvesSymmetryType symmetry)
+{
+ Vector<float4x4> matrices;
+
+ auto symmetry_to_factors = [&](const eCurvesSymmetryType type) -> Span<float> {
+ if (symmetry & type) {
+ static std::array<float, 2> values = {1.0f, -1.0f};
+ return values;
+ }
+ static std::array<float, 1> values = {1.0f};
+ return values;
+ };
+
+ for (const float x : symmetry_to_factors(CURVES_SYMMETRY_X)) {
+ for (const float y : symmetry_to_factors(CURVES_SYMMETRY_Y)) {
+ for (const float z : symmetry_to_factors(CURVES_SYMMETRY_Z)) {
+ float4x4 matrix = float4x4::identity();
+ matrix.values[0][0] = x;
+ matrix.values[1][1] = y;
+ matrix.values[2][2] = z;
+ matrices.append(matrix);
+ }
+ }
+ }
+
+ return matrices;
+}
+
} // 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 232d632aa3f..1fcab2290e8 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,21 +78,21 @@ class CombOperation : public CurvesSculptStrokeOperation {
*/
struct CombOperationExecutor {
CombOperation *self_ = nullptr;
- bContext *C_ = nullptr;
- Depsgraph *depsgraph_ = nullptr;
- Scene *scene_ = nullptr;
- Object *object_ = nullptr;
+ const Depsgraph *depsgraph_ = nullptr;
+ const Scene *scene_ = nullptr;
ARegion *region_ = nullptr;
- View3D *v3d_ = nullptr;
- RegionView3D *rv3d_ = nullptr;
+ const View3D *v3d_ = nullptr;
+ const RegionView3D *rv3d_ = nullptr;
- 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;
@@ -110,24 +112,24 @@ struct CombOperationExecutor {
BVHTreeFromMesh surface_bvh_;
- 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);
+ 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_);
+ brush_ = BKE_paint_brush_for_read(&curves_sculpt_->paint);
+ brush_radius_base_re_ = BKE_brush_size_get(scene_, brush_);
+ brush_radius_factor_ = brush_radius_factor(*brush_, stroke_extension);
+ brush_strength_ = brush_strength_get(*scene_, *brush_, stroke_extension);
curves_to_world_mat_ = object_->obmat;
world_to_curves_mat_ = curves_to_world_mat_.inverted();
@@ -173,10 +175,10 @@ struct CombOperationExecutor {
EnumerableThreadSpecific<Vector<int>> changed_curves;
if (falloff_shape_ == PAINT_FALLOFF_SHAPE_TUBE) {
- this->comb_projected(changed_curves);
+ this->comb_projected_with_symmetry(changed_curves);
}
else if (falloff_shape_ == PAINT_FALLOFF_SHAPE_SPHERE) {
- this->comb_spherical(changed_curves);
+ this->comb_spherical_with_symmetry(changed_curves);
}
else {
BLI_assert_unreachable();
@@ -186,20 +188,34 @@ struct CombOperationExecutor {
curves_->tag_positions_changed();
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(region_);
}
/**
* Do combing in screen space.
*/
- void comb_projected(EnumerableThreadSpecific<Vector<int>> &r_changed_curves)
+ void comb_projected_with_symmetry(EnumerableThreadSpecific<Vector<int>> &r_changed_curves)
{
+ const Vector<float4x4> symmetry_brush_transforms = get_symmetry_brush_transforms(
+ eCurvesSymmetryType(curves_id_->symmetry));
+ for (const float4x4 &brush_transform : symmetry_brush_transforms) {
+ this->comb_projected(r_changed_curves, brush_transform);
+ }
+ }
+
+ void comb_projected(EnumerableThreadSpecific<Vector<int>> &r_changed_curves,
+ const float4x4 &brush_transform)
+ {
+ const float4x4 brush_transform_inv = brush_transform.inverted();
+
MutableSpan<float3> positions_cu = curves_->positions_for_write();
float4x4 projection;
ED_view3d_ob_project_mat_get(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) {
Vector<int> &local_changed_curves = r_changed_curves.local();
@@ -207,7 +223,7 @@ struct CombOperationExecutor {
bool curve_changed = false;
const IndexRange points = curves_->points_for_curve(curve_i);
for (const int point_i : points.drop_front(1)) {
- const float3 old_pos_cu = positions_cu[point_i];
+ const float3 old_pos_cu = brush_transform_inv * positions_cu[point_i];
/* Find the position of the point in screen space. */
float2 old_pos_re;
@@ -223,7 +239,7 @@ 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;
@@ -232,7 +248,8 @@ struct CombOperationExecutor {
float3 new_position_wo;
ED_view3d_win_to_3d(
v3d_, region_, curves_to_world_mat_ * old_pos_cu, new_position_re, new_position_wo);
- const float3 new_position_cu = world_to_curves_mat_ * new_position_wo;
+ const float3 new_position_cu = brush_transform *
+ (world_to_curves_mat_ * new_position_wo);
positions_cu[point_i] = new_position_cu;
curve_changed = true;
@@ -247,10 +264,8 @@ struct CombOperationExecutor {
/**
* Do combing in 3D space.
*/
- void comb_spherical(EnumerableThreadSpecific<Vector<int>> &r_changed_curves)
+ void comb_spherical_with_symmetry(EnumerableThreadSpecific<Vector<int>> &r_changed_curves)
{
- MutableSpan<float3> positions_cu = curves_->positions_for_write();
-
float4x4 projection;
ED_view3d_ob_project_mat_get(rv3d_, object_, projection.values);
@@ -268,10 +283,26 @@ struct CombOperationExecutor {
const float3 brush_start_cu = world_to_curves_mat_ * brush_start_wo;
const float3 brush_end_cu = world_to_curves_mat_ * brush_end_wo;
- const float3 brush_diff_cu = brush_end_cu - brush_start_cu;
+ const float brush_radius_cu = self_->brush_3d_.radius_cu * brush_radius_factor_;
+
+ const Vector<float4x4> symmetry_brush_transforms = get_symmetry_brush_transforms(
+ eCurvesSymmetryType(curves_id_->symmetry));
+ for (const float4x4 &brush_transform : symmetry_brush_transforms) {
+ this->comb_spherical(r_changed_curves,
+ brush_transform * brush_start_cu,
+ brush_transform * brush_end_cu,
+ brush_radius_cu);
+ }
+ }
- const float brush_radius_cu = self_->brush_3d_.radius_cu;
+ void comb_spherical(EnumerableThreadSpecific<Vector<int>> &r_changed_curves,
+ const float3 &brush_start_cu,
+ const float3 &brush_end_cu,
+ const float brush_radius_cu)
+ {
+ MutableSpan<float3> positions_cu = curves_->positions_for_write();
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) {
Vector<int> &local_changed_curves = r_changed_curves.local();
@@ -314,7 +345,7 @@ 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_);
+ *depsgraph_, *region_, *v3d_, *rv3d_, *object_, brush_pos_re_, brush_radius_base_re_);
if (brush_3d.has_value()) {
self_->brush_3d_ = *brush_3d;
}
@@ -353,11 +384,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;
}
}
@@ -366,7 +397,7 @@ 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;
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 2841a19d677..323e99df099 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,62 +50,56 @@ 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;
+ const Depsgraph *depsgraph_ = nullptr;
+ const Scene *scene_ = nullptr;
ARegion *region_ = nullptr;
- View3D *v3d_ = nullptr;
- RegionView3D *rv3d_ = nullptr;
+ const View3D *v3d_ = nullptr;
+ const RegionView3D *rv3d_ = nullptr;
+ Object *object_ = nullptr;
Curves *curves_id_ = nullptr;
CurvesGeometry *curves_ = nullptr;
- 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_;
float2 brush_pos_re_;
- float2 brush_pos_prev_re_;
float4x4 curves_to_world_mat_;
float4x4 world_to_curves_mat_;
- void execute(DeleteOperation &self, bContext *C, const StrokeExtension &stroke_extension)
+ void execute(DeleteOperation &self, const bContext &C, const StrokeExtension &stroke_extension)
{
- BLI_SCOPED_DEFER([&]() { self.brush_pos_prev_re_ = stroke_extension.mouse_position; });
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);
+ 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_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_);
+ brush_ = BKE_paint_brush_for_read(&curves_sculpt_->paint);
+ brush_radius_base_re_ = BKE_brush_size_get(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();
@@ -117,115 +113,152 @@ struct DeleteOperationExecutor {
}
}
+ Array<bool> curves_to_delete(curves_->curves_num(), false);
if (falloff_shape == PAINT_FALLOFF_SHAPE_TUBE) {
- this->delete_projected();
+ this->delete_projected_with_symmetry(curves_to_delete);
}
else if (falloff_shape == PAINT_FALLOFF_SHAPE_SPHERE) {
- this->delete_spherical();
+ this->delete_spherical_with_symmetry(curves_to_delete);
}
else {
BLI_assert_unreachable();
}
+ Vector<int64_t> indices;
+ const IndexMask mask = index_mask_ops::find_indices_based_on_predicate(
+ curves_->curves_range(), 4096, indices, [&](const int curve_i) {
+ return curves_to_delete[curve_i];
+ });
+
+ curves_->remove_curves(mask);
+
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(region_);
}
- void delete_projected()
+ void delete_projected_with_symmetry(MutableSpan<bool> curves_to_delete)
{
+ 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(brush_transform, curves_to_delete);
+ }
+ }
+
+ 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);
Span<float3> positions_cu = curves_->positions();
- /* Find indices of curves that have to be removed. */
- Vector<int64_t> indices;
- const IndexMask curves_to_remove = index_mask_ops::find_indices_based_on_predicate(
- curves_->curves_range(), 512, indices, [&](const int curve_i) {
- const IndexRange point_range = curves_->points_for_curve(curve_i);
- for (const int segment_i : IndexRange(point_range.size() - 1)) {
- const float3 pos1_cu = positions_cu[point_range[segment_i]];
- const float3 pos2_cu = positions_cu[point_range[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);
-
- const float dist = dist_seg_seg_v2(
- pos1_re, pos2_re, brush_pos_prev_re_, brush_pos_re_);
- if (dist <= brush_radius_re_) {
- return true;
- }
- }
- return false;
- });
+ 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(), 512, [&](IndexRange curve_range) {
+ for (const int curve_i : curve_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(region_, pos_cu, pos_re, projection.values);
- curves_->remove_curves(curves_to_remove);
+ 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);
+
+ 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;
+ }
+ }
+ }
+ });
}
- void delete_spherical()
+ void delete_spherical_with_symmetry(MutableSpan<bool> curves_to_delete)
{
- Span<float3> positions_cu = curves_->positions();
-
float4x4 projection;
ED_view3d_ob_project_mat_get(rv3d_, object_, projection.values);
- float3 brush_start_wo, brush_end_wo;
- ED_view3d_win_to_3d(v3d_,
- region_,
- curves_to_world_mat_ * self_->brush_3d_.position_cu,
- brush_pos_prev_re_,
- brush_start_wo);
+ float3 brush_wo;
ED_view3d_win_to_3d(v3d_,
region_,
curves_to_world_mat_ * self_->brush_3d_.position_cu,
brush_pos_re_,
- brush_end_wo);
- const float3 brush_start_cu = world_to_curves_mat_ * brush_start_wo;
- const float3 brush_end_cu = world_to_curves_mat_ * brush_end_wo;
+ brush_wo);
+ const float3 brush_cu = world_to_curves_mat_ * 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(brush_transform * brush_cu, curves_to_delete);
+ }
+ }
- const float brush_radius_cu = self_->brush_3d_.radius_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 * brush_radius_factor_;
const float brush_radius_sq_cu = pow2f(brush_radius_cu);
- Vector<int64_t> indices;
- const IndexMask curves_to_remove = index_mask_ops::find_indices_based_on_predicate(
- curves_->curves_range(), 512, indices, [&](const int curve_i) {
- const IndexRange 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) {
- continue;
- }
- return true;
+ threading::parallel_for(curves_->curves_range(), 512, [&](IndexRange curve_range) {
+ for (const int curve_i : curve_range) {
+ const IndexRange points = curves_->points_for_curve(curve_i);
+
+ 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;
}
- return false;
- });
+ 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];
- curves_->remove_curves(curves_to_remove);
+ 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;
+ break;
+ }
+ }
+ });
}
void initialize_spherical_brush_reference_point()
{
std::optional<CurvesBrush3D> brush_3d = sample_curves_3d_brush(
- *C_, *object_, brush_pos_re_, brush_radius_re_);
+ *depsgraph_, *region_, *v3d_, *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;
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 6228a643a76..25eb8041f4c 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)
{
}
@@ -203,10 +203,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 +261,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,20 +270,21 @@ class CurvesEffectOperation : public CurvesSculptStrokeOperation {
*/
struct CurvesEffectOperationExecutor {
CurvesEffectOperation *self_ = nullptr;
- Depsgraph *depsgraph_ = nullptr;
- Scene *scene_ = nullptr;
- Object *object_ = nullptr;
+ const Depsgraph *depsgraph_ = nullptr;
+ const Scene *scene_ = nullptr;
ARegion *region_ = nullptr;
- View3D *v3d_ = nullptr;
- RegionView3D *rv3d_ = nullptr;
+ const View3D *v3d_ = nullptr;
+ const RegionView3D *rv3d_ = nullptr;
+ Object *object_ = nullptr;
Curves *curves_id_ = nullptr;
CurvesGeometry *curves_ = nullptr;
- Brush *brush_ = nullptr;
- float brush_radius_re_;
- float brush_radius_sq_re_;
+ const Brush *brush_ = nullptr;
+ float brush_radius_base_re_;
+ float brush_radius_factor_;
float brush_strength_;
+
eBrushFalloffShape falloff_shape_;
float4x4 curves_to_world_mat_;
@@ -297,17 +298,19 @@ struct CurvesEffectOperationExecutor {
Vector<float> move_distances_cu;
};
- void execute(CurvesEffectOperation &self, bContext *C, const StrokeExtension &stroke_extension)
+ 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);
+ 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_id_ = static_cast<Curves *>(object_->data);
curves_ = &CurvesGeometry::wrap(curves_id_->geometry);
@@ -315,11 +318,14 @@ 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_);
+ const CurvesSculpt &curves_sculpt = *scene_->toolsettings->curves_sculpt;
+ brush_ = BKE_paint_brush_for_read(&curves_sculpt.paint);
+ brush_strength_ = brush_strength_get(*scene_, *brush_, stroke_extension);
+
+ brush_radius_base_re_ = BKE_brush_size_get(scene_, brush_);
+ brush_radius_factor_ = brush_radius_factor(*brush_, stroke_extension);
+ brush_strength_ = brush_strength_get(*scene_, *brush_, stroke_extension);
+
falloff_shape_ = eBrushFalloffShape(brush_->falloff_shape);
curves_to_world_mat_ = object_->obmat;
@@ -331,7 +337,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_)) {
+ *depsgraph_,
+ *region_,
+ *v3d_,
+ *rv3d_,
+ *object_,
+ stroke_extension.mouse_position,
+ brush_radius_base_re_)) {
self.brush_3d_ = *brush_3d;
}
}
@@ -356,6 +368,7 @@ struct CurvesEffectOperationExecutor {
curves_->tag_positions_changed();
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(region_);
}
@@ -367,62 +380,75 @@ struct CurvesEffectOperationExecutor {
float4x4 projection;
ED_view3d_ob_project_mat_get(rv3d_, object_, projection.values);
+ const Vector<float4x4> symmetry_brush_transforms = get_symmetry_brush_transforms(
+ eCurvesSymmetryType(curves_id_->symmetry));
+ Vector<float4x4> symmetry_brush_transforms_inv;
+ for (const float4x4 brush_transform : symmetry_brush_transforms) {
+ 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;
- 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];
-
- float2 p1_re, p2_re;
- ED_view3d_project_float_v2_m4(region_, p1_cu, p1_re, projection.values);
- ED_view3d_project_float_v2_m4(region_, p2_cu, p2_re, projection.values);
-
- float2 closest_on_brush_re;
- float2 closest_on_segment_re;
- float lambda_on_brush;
- float lambda_on_segment;
- const float dist_to_brush_sq_re = closest_seg_seg_v2(closest_on_brush_re,
- closest_on_segment_re,
- &lambda_on_brush,
- &lambda_on_segment,
- brush_pos_start_re_,
- brush_pos_end_re_,
- p1_re,
- p2_re);
-
- if (dist_to_brush_sq_re > brush_radius_sq_re_) {
- continue;
+ for (const float4x4 &brush_transform_inv : symmetry_brush_transforms_inv) {
+ 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);
+
+ float2 closest_on_brush_re;
+ float2 closest_on_segment_re;
+ float lambda_on_brush;
+ float lambda_on_segment;
+ const float dist_to_brush_sq_re = closest_seg_seg_v2(closest_on_brush_re,
+ closest_on_segment_re,
+ &lambda_on_brush,
+ &lambda_on_segment,
+ brush_pos_start_re_,
+ brush_pos_end_re_,
+ p1_re,
+ p2_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;
+
+ 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,
+ brush_pos_start_re_,
+ brush_start_pos_wo);
+ ED_view3d_win_to_3d(v3d_,
+ region_,
+ curves_to_world_mat_ * 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 float move_distance_cu = weight *
+ math::distance(brush_start_pos_cu, brush_end_pos_cu);
+ max_move_distance_cu = std::max(max_move_distance_cu, move_distance_cu);
}
-
- 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;
-
- 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,
- brush_pos_start_re_,
- brush_start_pos_wo);
- ED_view3d_win_to_3d(v3d_,
- region_,
- curves_to_world_mat_ * 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 float move_distance_cu = weight *
- math::distance(brush_start_pos_cu, brush_end_pos_cu);
- max_move_distance_cu = std::max(max_move_distance_cu, move_distance_cu);
}
if (max_move_distance_cu > 0.0f) {
local_influences.curve_indices.append(curve_i);
@@ -452,41 +478,50 @@ struct CurvesEffectOperationExecutor {
const float3 brush_pos_end_cu = world_to_curves_mat_ * 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(
+ eCurvesSymmetryType(curves_id_->symmetry));
+
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;
- 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];
-
- float3 closest_on_segment_cu;
- float3 closest_on_brush_cu;
- isect_seg_seg_v3(p1_cu,
- p2_cu,
- brush_pos_start_cu,
- brush_pos_end_cu,
- closest_on_segment_cu,
- closest_on_brush_cu);
-
- const float dist_to_brush_sq_cu = math::distance_squared(closest_on_segment_cu,
- closest_on_brush_cu);
- if (dist_to_brush_sq_cu > brush_radius_sq_cu) {
- continue;
+ 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 : 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;
+ isect_seg_seg_v3(p1_cu,
+ p2_cu,
+ brush_pos_start_transformed_cu,
+ brush_pos_end_transformed_cu,
+ closest_on_segment_cu,
+ closest_on_brush_cu);
+
+ const float dist_to_brush_sq_cu = math::distance_squared(closest_on_segment_cu,
+ closest_on_brush_cu);
+ if (dist_to_brush_sq_cu > brush_radius_sq_cu) {
+ continue;
+ }
+
+ 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 move_distance_cu = weight * brush_pos_diff_length_cu;
+ max_move_distance_cu = std::max(max_move_distance_cu, move_distance_cu);
}
-
- 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 move_distance_cu = weight * brush_pos_diff_length_cu;
- max_move_distance_cu = std::max(max_move_distance_cu, move_distance_cu);
}
if (max_move_distance_cu > 0.0f) {
local_influences.curve_indices.append(curve_i);
@@ -497,7 +532,7 @@ struct CurvesEffectOperationExecutor {
}
};
-void CurvesEffectOperation::on_stroke_extended(bContext *C,
+void CurvesEffectOperation::on_stroke_extended(const bContext &C,
const StrokeExtension &stroke_extension)
{
CurvesEffectOperationExecutor executor;
@@ -505,10 +540,10 @@ void CurvesEffectOperation::on_stroke_extended(bContext *C,
}
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 03413221907..842de234761 100644
--- a/source/blender/editors/sculpt_paint/curves_sculpt_intern.hh
+++ b/source/blender/editors/sculpt_paint/curves_sculpt_intern.hh
@@ -13,7 +13,11 @@
struct ARegion;
struct RegionView3D;
+struct Depsgraph;
+struct View3D;
struct Object;
+struct Brush;
+struct Scene;
namespace blender::ed::sculpt_paint {
@@ -22,23 +26,35 @@ 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();
+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);
struct CurvesBrush3D {
float3 position_cu;
@@ -48,9 +64,14 @@ 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);
} // 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 992ac77803a..15d0f73592d 100644
--- a/source/blender/editors/sculpt_paint/curves_sculpt_ops.cc
+++ b/source/blender/editors/sculpt_paint/curves_sculpt_ops.cc
@@ -74,12 +74,42 @@ using blender::bke::CurvesGeometry;
/** \name * SCULPT_CURVES_OT_brush_stroke
* \{ */
-static std::unique_ptr<CurvesSculptStrokeOperation> start_brush_operation(bContext *C,
- wmOperator *op)
+float brush_radius_factor(const Brush &brush, const StrokeExtension &stroke_extension)
{
- const BrushStrokeMode mode = static_cast<BrushStrokeMode>(RNA_enum_get(op->ptr, "mode"));
+ 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);
+}
- Scene &scene = *CTX_data_scene(C);
+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);
switch (brush.curves_sculpt_tool) {
@@ -90,7 +120,7 @@ static std::unique_ptr<CurvesSculptStrokeOperation> start_brush_operation(bConte
case CURVES_SCULPT_TOOL_SNAKE_HOOK:
return new_snake_hook_operation();
case CURVES_SCULPT_TOOL_ADD:
- return new_add_operation();
+ return new_add_operation(C, op.reports);
case CURVES_SCULPT_TOOL_GROW_SHRINK:
return new_grow_shrink_operation(mode, C);
}
@@ -128,17 +158,18 @@ 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;
- op_data->operation = start_brush_operation(C, op);
+ op_data->operation = start_brush_operation(*C, *op);
}
else {
stroke_extension.is_first = false;
}
if (op_data->operation) {
- op_data->operation->on_stroke_extended(C, stroke_extension);
+ op_data->operation->on_stroke_extended(*C, stroke_extension);
}
}
@@ -149,6 +180,12 @@ 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);
+ if (brush == nullptr) {
+ return OPERATOR_CANCELLED;
+ }
+
SculptCurvesBrushStrokeData *op_data = MEM_new<SculptCurvesBrushStrokeData>(__func__);
op_data->stroke = paint_stroke_new(C,
op,
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 6d930d35f04..bcdeaaeabf2 100644
--- a/source/blender/editors/sculpt_paint/curves_sculpt_snake_hook.cc
+++ b/source/blender/editors/sculpt_paint/curves_sculpt_snake_hook.cc
@@ -37,6 +37,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 +63,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,19 +72,21 @@ class SnakeHookOperation : public CurvesSculptStrokeOperation {
*/
struct SnakeHookOperatorExecutor {
SnakeHookOperation *self_ = nullptr;
- bContext *C_ = nullptr;
- Scene *scene_ = nullptr;
- Object *object_ = nullptr;
+ const Depsgraph *depsgraph_ = nullptr;
+ const Scene *scene_ = nullptr;
ARegion *region_ = nullptr;
- View3D *v3d_ = nullptr;
- RegionView3D *rv3d_ = nullptr;
+ const View3D *v3d_ = nullptr;
+ const RegionView3D *rv3d_ = nullptr;
- 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;
@@ -93,22 +97,28 @@ struct SnakeHookOperatorExecutor {
float2 brush_pos_re_;
float2 brush_pos_diff_re_;
- void execute(SnakeHookOperation &self, bContext *C, const StrokeExtension &stroke_extension)
+ 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);
+ depsgraph_ = CTX_data_depsgraph_pointer(&C);
+ scene_ = CTX_data_scene(&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_);
+ brush_ = BKE_paint_brush_for_read(&curves_sculpt_->paint);
+
+ brush_radius_base_re_ = BKE_brush_size_get(scene_, brush_);
+ brush_radius_factor_ = brush_radius_factor(*brush_, stroke_extension);
+ brush_strength_ = brush_strength_get(*scene_, *brush_, stroke_extension);
+
falloff_shape_ = static_cast<eBrushFalloffShape>(brush_->falloff_shape);
curves_to_world_mat_ = object_->obmat;
@@ -127,7 +137,7 @@ struct SnakeHookOperatorExecutor {
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_);
+ *depsgraph_, *region_, *v3d_, *rv3d_, *object_, brush_pos_re_, brush_radius_base_re_);
if (brush_3d.has_value()) {
self_->brush_3d_ = *brush_3d;
}
@@ -136,10 +146,10 @@ struct SnakeHookOperatorExecutor {
}
if (falloff_shape_ == PAINT_FALLOFF_SHAPE_SPHERE) {
- this->spherical_snake_hook();
+ this->spherical_snake_hook_with_symmetry();
}
else if (falloff_shape_ == PAINT_FALLOFF_SHAPE_TUBE) {
- this->projected_snake_hook();
+ this->projected_snake_hook_with_symmetry();
}
else {
BLI_assert_unreachable();
@@ -147,49 +157,63 @@ struct SnakeHookOperatorExecutor {
curves_->tag_positions_changed();
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(region_);
}
- void projected_snake_hook()
+ void projected_snake_hook_with_symmetry()
{
+ const Vector<float4x4> symmetry_brush_transforms = get_symmetry_brush_transforms(
+ eCurvesSymmetryType(curves_id_->symmetry));
+ for (const float4x4 &brush_transform : symmetry_brush_transforms) {
+ this->projected_snake_hook(brush_transform);
+ }
+ }
+
+ void projected_snake_hook(const float4x4 &brush_transform)
+ {
+ const float4x4 brush_transform_inv = brush_transform.inverted();
+
MutableSpan<float3> positions_cu = curves_->positions_for_write();
float4x4 projection;
ED_view3d_ob_project_mat_get(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) {
const IndexRange points = curves_->points_for_curve(curve_i);
const int last_point_i = points.last();
- const float3 old_pos_cu = positions_cu[last_point_i];
+ 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);
- 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_);
+ brush_, std::sqrt(distance_to_brush_sq_re), brush_radius_re);
const float weight = brush_strength_ * radius_falloff;
const float2 new_position_re = old_pos_re + brush_pos_diff_re_ * weight;
float3 new_position_wo;
ED_view3d_win_to_3d(
v3d_, region_, curves_to_world_mat_ * old_pos_cu, new_position_re, new_position_wo);
- const float3 new_position_cu = world_to_curves_mat_ * new_position_wo;
+ 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);
}
});
}
- void spherical_snake_hook()
+ void spherical_snake_hook_with_symmetry()
{
- MutableSpan<float3> positions_cu = curves_->positions_for_write();
-
float4x4 projection;
ED_view3d_ob_project_mat_get(rv3d_, object_, projection.values);
@@ -206,9 +230,23 @@ struct SnakeHookOperatorExecutor {
brush_end_wo);
const float3 brush_start_cu = world_to_curves_mat_ * brush_start_wo;
const float3 brush_end_cu = world_to_curves_mat_ * brush_end_wo;
- const float3 brush_diff_cu = brush_end_cu - brush_start_cu;
- const float brush_radius_cu = self_->brush_3d_.radius_cu;
+ const float brush_radius_cu = self_->brush_3d_.radius_cu * brush_radius_factor_;
+
+ const Vector<float4x4> symmetry_brush_transforms = get_symmetry_brush_transforms(
+ eCurvesSymmetryType(curves_id_->symmetry));
+ for (const float4x4 &brush_transform : symmetry_brush_transforms) {
+ this->spherical_snake_hook(
+ brush_transform * brush_start_cu, brush_transform * brush_end_cu, brush_radius_cu);
+ }
+ }
+
+ void spherical_snake_hook(const float3 &brush_start_cu,
+ const float3 &brush_end_cu,
+ const float brush_radius_cu)
+ {
+ MutableSpan<float3> positions_cu = curves_->positions_for_write();
+ const float3 brush_diff_cu = brush_end_cu - brush_start_cu;
const float brush_radius_sq_cu = pow2f(brush_radius_cu);
threading::parallel_for(curves_->curves_range(), 256, [&](const IndexRange curves_range) {
@@ -269,7 +307,8 @@ struct SnakeHookOperatorExecutor {
}
};
-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;
executor.execute(*this, C, stroke_extension);
diff --git a/source/blender/editors/sculpt_paint/paint_image_proj.c b/source/blender/editors/sculpt_paint/paint_image_proj.c
index e442cd53639..b7ec427349f 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,14 +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 "NOD_shader.h"
+#include "RNA_types.h"
#include "IMB_colormanagement.h"
@@ -4070,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) {
@@ -6472,6 +6484,38 @@ static Image *proj_paint_image_create(wmOperator *op, Main *bmain, bool is_data)
return ima;
}
+static CustomDataLayer *proj_paint_color_attribute_create(wmOperator *op, Object *ob)
+{
+ char name[MAX_NAME] = "";
+ float color[4] = {0.0f, 0.0f, 0.0f, 1.0f};
+ AttributeDomain domain = ATTR_DOMAIN_POINT;
+ CustomDataType type = CD_PROP_COLOR;
+
+ if (op) {
+ RNA_string_get(op->ptr, "name", name);
+ RNA_float_get_array(op->ptr, "color", color);
+ domain = (AttributeDomain)RNA_enum_get(op->ptr, "domain");
+ type = (CustomDataType)RNA_enum_get(op->ptr, "data_type");
+ }
+
+ ID *id = (ID *)ob->data;
+ CustomDataLayer *layer = BKE_id_attribute_new(id, name, type, domain, op->reports);
+
+ if (!layer) {
+ return NULL;
+ }
+
+ BKE_id_attributes_active_color_set(id, layer);
+
+ if (!BKE_id_attributes_render_color_get(id)) {
+ BKE_id_attributes_render_color_set(id, layer);
+ }
+
+ 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.
*
@@ -6539,6 +6583,7 @@ 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;
@@ -6551,7 +6596,7 @@ static bool proj_paint_add_slot(bContext *C, wmOperator *op)
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) {
@@ -6561,17 +6606,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");
@@ -6634,6 +6698,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);
@@ -6695,6 +6764,44 @@ static int texture_paint_add_texture_paint_slot_invoke(bContext *C,
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)
@@ -6702,40 +6809,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_vertex.cc b/source/blender/editors/sculpt_paint/paint_vertex.cc
index f13c34e2030..fb1c8ceaa1a 100644
--- a/source/blender/editors/sculpt_paint/paint_vertex.cc
+++ b/source/blender/editors/sculpt_paint/paint_vertex.cc
@@ -4144,13 +4144,7 @@ static bool vertex_color_set(Object *ob, ColorPaint4f paintcol_in, Color *color_
}
/**
- * Fills the object's active color atribute layer with the fill color.
- *
- * \param[in] ob: The object.
- * \param[in] fill_color: The fill color.
- * \param[in] only_selected: Limit the fill to selected faces or vertices.
- *
- * \return #true if successful.
+ * See doc-string for #BKE_object_attributes_active_color_fill.
*/
static bool paint_object_attributes_active_color_fill_ex(Object *ob,
ColorPaint4f fill_color,
diff --git a/source/blender/editors/sculpt_paint/sculpt.c b/source/blender/editors/sculpt_paint/sculpt.c
index 34647cd9bf6..2c6c4c82676 100644
--- a/source/blender/editors/sculpt_paint/sculpt.c
+++ b/source/blender/editors/sculpt_paint/sculpt.c
@@ -3261,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);
}
@@ -3315,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);
@@ -5289,6 +5291,7 @@ static bool sculpt_stroke_test_start(bContext *C, struct wmOperator *op, const f
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). */
@@ -5306,7 +5309,15 @@ static bool sculpt_stroke_test_start(bContext *C, struct wmOperator *op, const f
SculptCursorGeometryInfo sgi;
SCULPT_cursor_geometry_info_update(C, &sgi, mouse, 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;
}
@@ -5433,7 +5444,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);
diff --git a/source/blender/editors/sculpt_paint/sculpt_face_set.c b/source/blender/editors/sculpt_paint/sculpt_face_set.c
index 7171c241534..d03c5ecab4d 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);
}
}
}
diff --git a/source/blender/editors/sculpt_paint/sculpt_intern.h b/source/blender/editors/sculpt_paint/sculpt_intern.h
index f9633c91087..5fa115ed629 100644
--- a/source/blender/editors/sculpt_paint/sculpt_intern.h
+++ b/source/blender/editors/sculpt_paint/sculpt_intern.h
@@ -1652,11 +1652,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_ops.c b/source/blender/editors/sculpt_paint/sculpt_ops.c
index 8df1cc458d3..dc620f0ee93 100644
--- a/source/blender/editors/sculpt_paint/sculpt_ops.c
+++ b/source/blender/editors/sculpt_paint/sculpt_ops.c
@@ -637,16 +637,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 +711,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 +720,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);
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_undo.c b/source/blender/editors/sculpt_paint/sculpt_undo.c
index 5867dc558de..1fee20444e7 100644
--- a/source/blender/editors/sculpt_paint/sculpt_undo.c
+++ b/source/blender/editors/sculpt_paint/sculpt_undo.c
@@ -1265,7 +1265,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];
}
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_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/space_clip.c b/source/blender/editors/space_clip/space_clip.c
index 91fef23019c..5f52e1a3071 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);
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 ad604fe59bc..bbfbbd2cc58 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);
@@ -375,51 +409,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);
diff --git a/source/blender/editors/space_file/filelist.c b/source/blender/editors/space_file/filelist.c
index 59ecef7d4c6..cfbbc1a1b45 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) {
diff --git a/source/blender/editors/space_file/fsmenu.c b/source/blender/editors/space_file/fsmenu.c
index 65354591034..10cde239987 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;
}
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_image/image_ops.c b/source/blender/editors/space_image/image_ops.c
index 68d342e2143..bd1cb3a345e 100644
--- a/source/blender/editors/space_image/image_ops.c
+++ b/source/blender/editors/space_image/image_ops.c
@@ -1680,184 +1680,28 @@ 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)
+static void image_save_options_from_op(Main *bmain, ImageSaveOptions *opts, wmOperator *op)
{
- 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)
-{
- 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"));
+ opts->do_newpath = true;
+}
+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 +1716,54 @@ 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;
+ }
+
+ 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 +1773,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, &isd->opts, op);
+ BKE_image_save_options_update(&isd->opts, isd->image);
- image_save_options_from_op(bmain, &opts, op, imf);
- opts.do_newpath = true;
+ save_image_op(bmain, isd->image, isd->iuser, op, &isd->opts);
- save_image_op(bmain, image, iuser, op, &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 +1849,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 +1861,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 +1915,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 +1994,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 +2171,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 +2202,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 +2259,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;
}
@@ -3040,9 +2902,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 +2971,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 +3004,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;
}
diff --git a/source/blender/editors/space_image/image_undo.c b/source/blender/editors/space_image/image_undo.c
index c3a48abcae1..1fd9fde084b 100644
--- a/source/blender/editors/space_image/image_undo.c
+++ b/source/blender/editors/space_image/image_undo.c
@@ -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..63f919a1713 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;
diff --git a/source/blender/editors/space_nla/nla_buttons.c b/source/blender/editors/space_nla/nla_buttons.c
index 5e4389279eb..f89bfd2a36a 100644
--- a/source/blender/editors/space_nla/nla_buttons.c
+++ b/source/blender/editors/space_nla/nla_buttons.c
@@ -107,6 +107,7 @@ bool nla_panel_context(const bContext *C,
found = 1;
break;
}
+ case ANIMTYPE_NLAACTION:
case ANIMTYPE_SCENE: /* Top-Level Widgets doubling up as datablocks */
case ANIMTYPE_OBJECT:
case ANIMTYPE_DSMAT: /* Datablock AnimData Expanders */
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_node/drawnode.cc b/source/blender/editors/space_node/drawnode.cc
index 958a9fdfc60..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"
@@ -213,6 +214,11 @@ static void node_buts_math(uiLayout *layout, bContext *UNUSED(C), PointerRNA *pt
uiItemR(layout, ptr, "use_clamp", DEFAULT_FLAGS, nullptr, ICON_NONE);
}
+static void node_buts_combsep_color(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
+{
+ uiItemR(layout, ptr, "mode", DEFAULT_FLAGS, "", ICON_NONE);
+}
+
NodeResizeDirection node_get_resize_direction(const bNode *node, const int x, const int y)
{
if (node->type == NODE_FRAME) {
@@ -480,6 +486,10 @@ static void node_shader_set_butfunc(bNodeType *ntype)
case SH_NODE_MATH:
ntype->draw_buttons = node_buts_math;
break;
+ case SH_NODE_COMBINE_COLOR:
+ case SH_NODE_SEPARATE_COLOR:
+ ntype->draw_buttons = node_buts_combsep_color;
+ break;
case SH_NODE_TEX_IMAGE:
ntype->draw_buttons = node_shader_buts_tex_image;
ntype->draw_buttons_ex = node_shader_buts_tex_image_ex;
@@ -589,6 +599,19 @@ static void node_composit_buts_ycc(uiLayout *layout, bContext *UNUSED(C), Pointe
uiItemR(layout, ptr, "mode", DEFAULT_FLAGS, "", ICON_NONE);
}
+static void node_composit_buts_combsep_color(uiLayout *layout,
+ bContext *UNUSED(C),
+ PointerRNA *ptr)
+{
+ bNode *node = (bNode *)ptr->data;
+ NodeCMPCombSepColor *storage = (NodeCMPCombSepColor *)node->storage;
+
+ uiItemR(layout, ptr, "mode", DEFAULT_FLAGS, "", ICON_NONE);
+ if (storage->mode == CMP_NODE_COMBSEP_COLOR_YCC) {
+ uiItemR(layout, ptr, "ycc_mode", DEFAULT_FLAGS, "", ICON_NONE);
+ }
+}
+
static void node_composit_backdrop_viewer(
SpaceNode *snode, ImBuf *backdrop, bNode *node, int x, int y)
{
@@ -821,8 +844,12 @@ static void node_composit_set_butfunc(bNodeType *ntype)
case CMP_NODE_HUECORRECT:
ntype->draw_buttons = node_composit_buts_huecorrect;
break;
- case CMP_NODE_COMBYCCA:
- case CMP_NODE_SEPYCCA:
+ case CMP_NODE_COMBINE_COLOR:
+ case CMP_NODE_SEPARATE_COLOR:
+ ntype->draw_buttons = node_composit_buts_combsep_color;
+ break;
+ case CMP_NODE_COMBYCCA_LEGACY:
+ case CMP_NODE_SEPYCCA_LEGACY:
ntype->draw_buttons = node_composit_buts_ycc;
break;
case CMP_NODE_MASK_BOX:
@@ -975,6 +1002,11 @@ static void node_texture_buts_output(uiLayout *layout, bContext *UNUSED(C), Poin
uiItemR(layout, ptr, "filepath", DEFAULT_FLAGS, "", ICON_NONE);
}
+static void node_texture_buts_combsep_color(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
+{
+ uiItemR(layout, ptr, "mode", DEFAULT_FLAGS, "", ICON_NONE);
+}
+
/* only once called */
static void node_texture_set_butfunc(bNodeType *ntype)
{
@@ -1020,6 +1052,11 @@ static void node_texture_set_butfunc(bNodeType *ntype)
case TEX_NODE_OUTPUT:
ntype->draw_buttons = node_texture_buts_output;
break;
+
+ case TEX_NODE_COMBINE_COLOR:
+ case TEX_NODE_SEPARATE_COLOR:
+ ntype->draw_buttons = node_texture_buts_combsep_color;
+ break;
}
}
}
@@ -1235,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 80c5a186021..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;
}
@@ -423,7 +421,7 @@ void NODE_OT_add_group(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");
+ WM_operator_properties_id_lookup(ot, true);
}
/** \} */
@@ -432,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;
}
@@ -508,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";
@@ -523,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);
}
/** \} */
@@ -542,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;
}
@@ -619,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";
@@ -634,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);
}
/** \} */
@@ -767,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);
}
/** \} */
@@ -776,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);
@@ -801,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;
}
@@ -827,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";
@@ -841,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 738d482bea3..e0ff4212a94 100644
--- a/source/blender/editors/space_node/node_draw.cc
+++ b/source/blender/editors/space_node/node_draw.cc
@@ -895,9 +895,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 +908,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 +918,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 +928,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;
}
@@ -982,8 +982,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 +996,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());
diff --git a/source/blender/editors/space_node/node_edit.cc b/source/blender/editors/space_node/node_edit.cc
index 2d7972e2291..ab80a44d636 100644
--- a/source/blender/editors/space_node/node_edit.cc
+++ b/source/blender/editors/space_node/node_edit.cc
@@ -66,7 +66,9 @@ namespace blender::ed::space_node {
#define USE_ESC_COMPO
-/* ***************** composite job manager ********************** */
+/* -------------------------------------------------------------------- */
+/** \name Composite Job Manager
+ * \{ */
enum {
COM_RECALC_COMPOSITE = 1,
@@ -291,8 +293,14 @@ static void compo_startjob(void *cjv,
ntree->progress = nullptr;
}
+/** \} */
+
} // 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;
@@ -336,9 +344,13 @@ void ED_node_composite_job(const bContext *C, struct bNodeTree *nodetree, Scene
WM_jobs_start(CTX_wm_manager(C), wm_job);
}
+/** \} */
+
namespace blender::ed::space_node {
-/* ***************************************** */
+/* -------------------------------------------------------------------- */
+/** \name Composite Poll & Utility Functions
+ * \{ */
bool composite_node_active(bContext *C)
{
@@ -388,8 +400,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 +801,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 +883,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 +900,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 +1107,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 +1245,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 +1275,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 +1464,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 +1567,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 +1767,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 +1807,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 +1846,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 +1894,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 +1934,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 +1988,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 +2038,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 +2114,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 +2163,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 +2245,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 +2373,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 +2447,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 +2497,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 +2601,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 +2679,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 +2828,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 +2954,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 +3002,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 +3051,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_intern.hh b/source/blender/editors/space_node/node_intern.hh
index 6d7348bfffc..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,13 +76,17 @@ struct SpaceNode_Runtime {
/** Mouse position for drawing socket-less links and adding nodes. */
float2 cursor;
- /* Indicates that the compositing tree in the space needs to be re-evaluated using the
+ /**
+ * Indicates that the compositing tree in the space needs to be re-evaluated using the
* auto-compositing pipeline.
- * Takes priority over the regular compsiting. */
+ * 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. */
+ /**
+ * 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. */
@@ -100,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)
diff --git a/source/blender/editors/space_node/node_relationships.cc b/source/blender/editors/space_node/node_relationships.cc
index c757fb46407..5796a712205 100644
--- a/source/blender/editors/space_node/node_relationships.cc
+++ b/source/blender/editors/space_node/node_relationships.cc
@@ -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 005dbc1eb10..9d73156edab 100644
--- a/source/blender/editors/space_node/node_select.cc
+++ b/source/blender/editors/space_node/node_select.cc
@@ -716,7 +716,7 @@ void NODE_OT_select(wmOperatorType *ot)
prop = RNA_def_int_vector(ot->srna,
"location",
2,
- NULL,
+ nullptr,
INT_MIN,
INT_MAX,
"Location",
diff --git a/source/blender/editors/space_node/space_node.cc b/source/blender/editors/space_node/space_node.cc
index 296cd1ff133..15afd024766 100644
--- a/source/blender/editors/space_node/space_node.cc
+++ b/source/blender/editors/space_node/space_node.cc
@@ -327,8 +327,9 @@ static bool any_node_uses_id(const bNodeTree *ntree, const ID *id)
/**
* Tag the space to recalculate the compositing tree using auto-compositing pipeline.
*
- * Will check the space to be using a compsiting tree, and check whether auto-compositing
- * is enabled. If the checks do not pass then the function has no affect. */
+ * 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)) {
@@ -347,7 +348,8 @@ static void node_area_tag_recalc_auto_compositing(SpaceNode *snode, ScrArea *are
* 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. */
+ * 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)) {
@@ -670,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)
@@ -685,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]) {
@@ -824,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 fae0e4be2a8..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
@@ -38,8 +39,8 @@ set(SRC
tree/tree_display_data.cc
tree/tree_display_libraries.cc
tree/tree_display_orphaned.cc
- tree/tree_display_override_library_properties.cc
tree/tree_display_override_library_hierarchies.cc
+ tree/tree_display_override_library_properties.cc
tree/tree_display_scenes.cc
tree/tree_display_sequencer.cc
tree/tree_display_view_layer.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 36e21cf51a5..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,
@@ -1817,7 +1818,7 @@ static void outliner_draw_overrides_rna_buts(uiBlock *block,
te->ys + pad_y,
item_max_width,
item_height,
- NULL,
+ nullptr,
0.0f,
0.0f,
0.0f,
@@ -1919,91 +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: {
- TreeElementOverridesProperty &te_override_prop =
- *tree_element_cast<TreeElementOverridesProperty>(te);
- if (!te_override_prop.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;
@@ -2024,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,
@@ -2184,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;
}
@@ -2257,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;
+ }
+
+ /* 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);
}
- 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);
+ 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 :
@@ -2319,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,
@@ -2329,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);
}
- }
+ });
}
/** \} */
@@ -2524,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:
@@ -3226,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,
@@ -3489,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;
}
}
@@ -3648,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;
@@ -3719,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,
@@ -3753,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);
}
@@ -3955,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);
@@ -3991,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) {
@@ -4031,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..bd6d3d89706 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 */
@@ -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);
diff --git a/source/blender/editors/space_outliner/outliner_tools.cc b/source/blender/editors/space_outliner/outliner_tools.cc
index 5da64177e51..bfb4c7251a8 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"};
@@ -231,43 +232,51 @@ static void unlink_material_fn(bContext *UNUSED(C),
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 +413,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 +425,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 +496,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 +759,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 +957,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 +1598,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 +1731,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) {
@@ -1964,6 +1975,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 +2008,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 +2021,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 +2067,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 +2106,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 +2183,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 +2193,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 +2235,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 +2253,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 +2284,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 +2292,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 +2317,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 +2338,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 +2362,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 +2392,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 +2401,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 +2411,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 +2464,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 +2501,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 +2557,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 +2568,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 +2623,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 +2713,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 +2730,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 +2796,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 +2842,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 +2885,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 +2907,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 +2922,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..e6098631a68 100644
--- a/source/blender/editors/space_outliner/outliner_tree.cc
+++ b/source/blender/editors/space_outliner/outliner_tree.cc
@@ -919,10 +919,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 +1682,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 79eec632c90..405f1dd73f4 100644
--- a/source/blender/editors/space_outliner/tree/tree_display_libraries.cc
+++ b/source/blender/editors/space_outliner/tree/tree_display_libraries.cc
@@ -141,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_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..80b3365766a 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};
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..0dcd75d340d 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).
*
@@ -96,13 +104,4 @@ struct TreeElement *outliner_add_element(SpaceOutliner *space_outliner,
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 3a039da86c2..53e7b88c923 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);
@@ -93,4 +106,15 @@ TreeElementOverridesProperty::TreeElementOverridesProperty(TreeElement &legacy_t
legacy_te.name = override_data.override_property.rna_path;
}
+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 b42e1c37a0f..1db46d9af1d 100644
--- a/source/blender/editors/space_outliner/tree/tree_element_overrides.hh
+++ b/source/blender/editors/space_outliner/tree/tree_element_overrides.hh
@@ -34,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 {
@@ -46,6 +48,8 @@ class TreeElementOverridesProperty final : public AbstractTreeElement {
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..85ff9e6437e
--- /dev/null
+++ b/source/blender/editors/space_outliner/tree/tree_iterator.cc
@@ -0,0 +1,58 @@
+/* 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 bool is_open = TSELEM_OPEN(element->store_elem, &space_outliner);
+ const ListBase subtree = element->subtree;
+
+ visitor(element);
+ /* Don't access element from now on, it may be freed. */
+
+ if (is_open) {
+ 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..e3b3c90eaad
--- /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.
+ */
+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/CMakeLists.txt b/source/blender/editors/space_sequencer/CMakeLists.txt
index b5355efec7a..44f919ca361 100644
--- a/source/blender/editors/space_sequencer/CMakeLists.txt
+++ b/source/blender/editors/space_sequencer/CMakeLists.txt
@@ -25,10 +25,10 @@ set(INC
set(SRC
sequencer_add.c
sequencer_buttons.c
- sequencer_drag_drop.c
- sequencer_draw.c
sequencer_channels_draw.c
sequencer_channels_edit.c
+ sequencer_drag_drop.c
+ sequencer_draw.c
sequencer_edit.c
sequencer_modifier.c
sequencer_ops.c
diff --git a/source/blender/editors/space_sequencer/sequencer_add.c b/source/blender/editors/space_sequencer/sequencer_add.c
index 469169cf4cc..10c6e828e96 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"
@@ -469,6 +471,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);
@@ -672,8 +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_right_handle_frame_set(seq_sound, SEQ_time_right_handle_frame_get(seq_movie));
+ SEQ_time_left_handle_frame_set(seq_sound, SEQ_time_left_handle_frame_get(seq_movie));
SEQ_time_update_sequence(scene, seqbase, seq_sound);
}
@@ -1179,7 +1300,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_right_handle_frame_set(seq, load_data.image.end_frame);
SEQ_time_update_sequence(scene, SEQ_active_seqbase_get(ed), 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_draw.c b/source/blender/editors/space_sequencer/sequencer_draw.c
index a561de1ef64..02e77732e02 100644
--- a/source/blender/editors/space_sequencer/sequencer_draw.c
+++ b/source/blender/editors/space_sequencer/sequencer_draw.c
@@ -1098,26 +1098,23 @@ 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) {
+ if (SEQ_time_has_left_still_frames(seq)) {
const float content_start = min_ff(seq->enddisp, seq->start);
immRectf(pos, seq->startdisp, y1, content_start, y2);
}
- if (seq->endstill) {
+ if (SEQ_time_has_right_still_frames(seq)) {
const float content_end = max_ff(seq->startdisp, seq->start + seq->len);
immRectf(pos, content_end, y1, seq->enddisp, y2);
}
@@ -1336,9 +1333,9 @@ 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->startdisp;
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->enddisp;
y2 = seq->machine + SEQ_STRIP_OFSTOP;
/* Limit body to strip bounds. Meta strip can end up with content outside of strip range. */
diff --git a/source/blender/editors/space_sequencer/sequencer_edit.c b/source/blender/editors/space_sequencer/sequencer_edit.c
index 0305ad279a0..08f98dfb161 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,7 +77,6 @@
typedef struct TransSeq {
int start, machine;
- int startstill, endstill;
int startdisp, enddisp;
int startofs, endofs;
int anim_startofs, anim_endofs;
@@ -357,15 +357,14 @@ 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(seq, snap_frame);
}
else { /* SEQ_RIGHTSEL */
- SEQ_transform_set_right_handle_frame(seq, snap_frame);
+ SEQ_time_right_handle_frame_set(seq, snap_frame);
}
SEQ_transform_handle_xlimits(seq, seq->flag & SEQ_LEFTSEL, seq->flag & SEQ_RIGHTSEL);
SEQ_transform_fix_single_image_seq_offsets(seq);
@@ -478,8 +477,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;
@@ -493,8 +490,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;
@@ -595,11 +590,8 @@ 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];
@@ -613,33 +605,13 @@ static bool sequencer_slip_recursively(Scene *scene, SlipData *data, int offset)
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;
- }
+ seq->endofs = endframe - seq->enddisp;
+ seq->startofs = seq->startdisp - seq->start;
}
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.
@@ -651,13 +623,11 @@ static bool sequencer_slip_recursively(Scene *scene, SlipData *data, int offset)
SEQ_time_update_sequence(scene, seqbase, seq);
}
}
- 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. */
@@ -687,7 +657,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 +678,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 +728,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 +760,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;
}
@@ -875,9 +839,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;
@@ -1719,11 +1682,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 +1714,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 +1759,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,7 +1784,7 @@ 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;
}
}
@@ -1869,8 +1858,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 +1870,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;
@@ -2596,7 +2585,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.
@@ -3040,6 +3029,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 +3113,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) {
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_thumbnails.c b/source/blender/editors/space_sequencer/sequencer_thumbnails.c
index 43c5e004040..eab17d876f3 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"
@@ -443,7 +444,8 @@ 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->enddisp;
if (seq->type == SEQ_TYPE_IMAGE) {
upper_thumb_bound = seq->enddisp;
}
diff --git a/source/blender/editors/space_sequencer/sequencer_view.c b/source/blender/editors/space_sequencer/sequencer_view.c
index b3dbc3c72d1..93641375d42 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"
diff --git a/source/blender/editors/space_spreadsheet/space_spreadsheet.cc b/source/blender/editors/space_spreadsheet/space_spreadsheet.cc
index b3d6c395e89..a498e5e99cf 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"
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..7f696efabf7 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;
}
@@ -110,8 +110,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 +129,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 +137,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 +210,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 +256,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>(
@@ -524,17 +524,17 @@ static void add_fields_as_extra_columns(SpaceSpreadsheet *sspreadsheet,
std::make_unique<GeometryComponentCacheKey>(component));
const AttributeDomain domain = (AttributeDomain)sspreadsheet->attribute_domain;
- const int domain_size = component.attribute_domain_size(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;
diff --git a/source/blender/editors/space_spreadsheet/spreadsheet_dataset_draw.cc b/source/blender/editors/space_spreadsheet/spreadsheet_dataset_draw.cc
index c4b5228758c..724d0783707 100644
--- a/source/blender/editors/space_spreadsheet/spreadsheet_dataset_draw.cc
+++ b/source/blender/editors/space_spreadsheet/spreadsheet_dataset_draw.cc
@@ -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..d76bbbf3be6 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"
diff --git a/source/blender/editors/space_spreadsheet/spreadsheet_row_filter.cc b/source/blender/editors/space_spreadsheet/spreadsheet_row_filter.cc
index 3ae4536b652..91ce5c2f6ec 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"
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/view3d_cursor_snap.c b/source/blender/editors/space_view3d/view3d_cursor_snap.c
index 96a193cc10d..1e54afe46f0 100644
--- a/source/blender/editors/space_view3d/view3d_cursor_snap.c
+++ b/source/blender/editors/space_view3d/view3d_cursor_snap.c
@@ -12,7 +12,6 @@
#include "BLI_listbase.h"
#include "BLI_rect.h"
-#include "DNA_scene_types.h"
#include "MEM_guardedalloc.h"
diff --git a/source/blender/editors/space_view3d/view3d_edit.c b/source/blender/editors/space_view3d/view3d_edit.c
index e52ff062302..a65e9a8d506 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);
}
/** \} */
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_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 d99063a9b26..efe89621e7b 100644
--- a/source/blender/editors/space_view3d/view3d_select.c
+++ b/source/blender/editors/space_view3d/view3d_select.c
@@ -126,6 +126,7 @@ void ED_view3d_viewcontext_init(bContext *C, ViewContext *vc, Depsgraph *depsgra
void ED_view3d_viewcontext_init_object(ViewContext *vc, Object *obact)
{
vc->obact = obact;
+ /* See public doc-string for rationale on checking the existing values first. */
if (vc->obedit) {
BLI_assert(BKE_object_is_in_editmode(obact));
vc->obedit = obact;
diff --git a/source/blender/editors/space_view3d/view3d_utils.c b/source/blender/editors/space_view3d/view3d_utils.c
index 51f50633468..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,
diff --git a/source/blender/editors/transform/transform.c b/source/blender/editors/transform/transform.c
index 7ae041f2b2f..a7e2f616c9e 100644
--- a/source/blender/editors/transform/transform.c
+++ b/source/blender/editors/transform/transform.c
@@ -1174,7 +1174,7 @@ int transformEvent(TransInfo *t, const wmEvent *event)
stopConstraint(t);
initSelectConstraint(t);
- /* In this case we might just want to remove the contraint,
+ /* 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;
diff --git a/source/blender/editors/transform/transform_convert.c b/source/blender/editors/transform/transform_convert.c
index dbe67bd0d66..018468dcd03 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]) {
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_sequencer.c b/source/blender/editors/transform/transform_convert_sequencer.c
index 5964af7ed4b..3735ff0727c 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;
}
@@ -489,11 +489,11 @@ static void seq_transform_handle_overwrite_trim(Scene *scene,
continue;
}
if (overlap == STRIP_OVERLAP_LEFT_SIDE) {
- SEQ_transform_set_left_handle_frame(seq, transformed->enddisp);
+ SEQ_time_left_handle_frame_set(seq, transformed->enddisp);
}
else {
BLI_assert(overlap == STRIP_OVERLAP_RIGHT_SIDE);
- SEQ_transform_set_right_handle_frame(seq, transformed->startdisp);
+ SEQ_time_right_handle_frame_set(seq, transformed->startdisp);
}
SEQ_time_update_sequence(scene, seqbasep, seq);
@@ -915,7 +915,7 @@ static void flushTransSeq(TransInfo *t)
}
case SEQ_LEFTSEL: { /* No vertical transform. */
int old_startdisp = seq->startdisp;
- SEQ_transform_set_left_handle_frame(seq, new_frame);
+ SEQ_time_left_handle_frame_set(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);
@@ -926,7 +926,7 @@ static void flushTransSeq(TransInfo *t)
}
case SEQ_RIGHTSEL: { /* No vertical transform. */
int old_enddisp = seq->enddisp;
- SEQ_transform_set_right_handle_frame(seq, new_frame);
+ SEQ_time_right_handle_frame_set(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);
diff --git a/source/blender/editors/transform/transform_convert_sequencer_image.c b/source/blender/editors/transform/transform_convert_sequencer_image.c
index cbc2cab0a7a..deae51a1149 100644
--- a/source/blender/editors/transform/transform_convert_sequencer_image.c
+++ b/source/blender/editors/transform/transform_convert_sequencer_image.c
@@ -197,11 +197,7 @@ 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];
}
SEQ_relations_invalidate_cache_preprocessed(t->scene, seq);
}
@@ -209,9 +205,6 @@ void recalcData_sequencer_image(TransInfo *t)
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;
@@ -225,8 +218,14 @@ void special_aftertrans_update__sequencer_image(bContext *UNUSED(C), TransInfo *
TransDataSeq *tdseq = td->extra;
Sequence *seq = tdseq->seq;
StripTransform *transform = seq->strip->transform;
- Scene *scene = t->scene;
+ if (t->state == TRANS_CANCEL) {
+ if (t->mode == TFM_ROTATION) {
+ transform->rotation = tdseq->orig_rotation;
+ }
+ continue;
+ }
+ Scene *scene = t->scene;
RNA_pointer_create(&scene->id, &RNA_SequenceTransform, transform, &ptr);
if (t->mode == TFM_ROTATION) {
diff --git a/source/blender/editors/transform/transform_convert_tracking.c b/source/blender/editors/transform/transform_convert_tracking.c
index bf9f929dd65..d447cd71a40 100644
--- a/source/blender/editors/transform/transform_convert_tracking.c
+++ b/source/blender/editors/transform/transform_convert_tracking.c
@@ -713,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_snap.c b/source/blender/editors/transform/transform_snap.c
index afad4df2c88..769fd28c57b 100644
--- a/source/blender/editors/transform/transform_snap.c
+++ b/source/blender/editors/transform/transform_snap.c
@@ -15,6 +15,7 @@
#include "BLI_math.h"
#include "GPU_immediate.h"
+#include "GPU_matrix.h"
#include "GPU_state.h"
#include "BKE_context.h"
@@ -25,6 +26,7 @@
#include "RNA_access.h"
+#include "WM_api.h"
#include "WM_types.h"
#include "ED_gizmo_library.h"
@@ -173,20 +175,20 @@ void drawSnapping(const struct bContext *C, TransInfo *t)
return;
}
- UI_GetThemeColor3ubv(TH_TRANSFORM, col);
- col[3] = 128;
-
- UI_GetThemeColor3ubv(TH_SELECT, selectedCol);
- selectedCol[3] = 128;
-
- UI_GetThemeColor3ubv(TH_ACTIVE, activeCol);
- activeCol[3] = 192;
-
if (t->spacetype == SPACE_VIEW3D) {
bool draw_target = (t->tsnap.status & TARGET_INIT) &&
(t->tsnap.mode & SCE_SNAP_MODE_EDGE_PERPENDICULAR);
if (draw_target || validSnap(t)) {
+ UI_GetThemeColor3ubv(TH_TRANSFORM, col);
+ col[3] = 128;
+
+ UI_GetThemeColor3ubv(TH_SELECT, selectedCol);
+ selectedCol[3] = 128;
+
+ UI_GetThemeColor3ubv(TH_ACTIVE, activeCol);
+ activeCol[3] = 192;
+
const float *loc_cur = NULL;
const float *loc_prev = NULL;
const float *normal = NULL;
@@ -240,8 +242,26 @@ void drawSnapping(const struct bContext *C, TransInfo *t)
}
else if (t->spacetype == SPACE_IMAGE) {
if (validSnap(t)) {
- /* This will not draw, and I'm nor sure why - campbell */
- /* TODO: see 2.7x for non-working code */
+ uint pos = GPU_vertformat_attr_add(
+ immVertexFormat(), "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
+
+ float x, y;
+ const float snap_point[2] = {
+ t->tsnap.snapPoint[0] / t->aspect[0],
+ t->tsnap.snapPoint[1] / t->aspect[1],
+ };
+ UI_view2d_view_to_region_fl(&t->region->v2d, UNPACK2(snap_point), &x, &y);
+ float radius = 2.5f * UI_GetThemeValuef(TH_VERTEX_SIZE) * U.pixelsize;
+
+ GPU_matrix_push_projection();
+ wmOrtho2_region_pixelspace(t->region);
+
+ immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
+ immUniformColor3ub(255, 255, 255);
+ imm_draw_circle_wire_2d(pos, x, y, radius, 8);
+ immUnbindProgram();
+
+ GPU_matrix_pop_projection();
}
}
else if (t->spacetype == SPACE_NODE) {
@@ -990,17 +1010,19 @@ static void snap_calc_uv_fn(TransInfo *t, float *UNUSED(vec))
{
BLI_assert(t->spacetype == SPACE_IMAGE);
if (t->tsnap.mode & SCE_SNAP_MODE_VERTEX) {
- float co[2];
-
- UI_view2d_region_to_view(&t->region->v2d, t->mval[0], t->mval[1], &co[0], &co[1]);
-
uint objects_len = 0;
Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data_with_uvs(
t->view_layer, NULL, &objects_len);
- float dist_sq = FLT_MAX;
- if (ED_uvedit_nearest_uv_multi(
- t->scene, objects, objects_len, co, &dist_sq, t->tsnap.snapPoint)) {
+ float dist_sq = square_f((float)SNAP_MIN_DISTANCE);
+ if (ED_uvedit_nearest_uv_multi(&t->region->v2d,
+ t->scene,
+ objects,
+ objects_len,
+ t->mval,
+ t->tsnap.modeSelect == SNAP_NOT_SELECTED,
+ &dist_sq,
+ t->tsnap.snapPoint)) {
t->tsnap.snapPoint[0] *= t->aspect[0];
t->tsnap.snapPoint[1] *= t->aspect[1];
diff --git a/source/blender/editors/util/ed_util.c b/source/blender/editors/util/ed_util.c
index e7b3bce700e..3cfe6bd61a4 100644
--- a/source/blender/editors/util/ed_util.c
+++ b/source/blender/editors/util/ed_util.c
@@ -41,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"
@@ -187,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/uvedit/uvedit_select.c b/source/blender/editors/uvedit/uvedit_select.c
index 6405d2df66a..ead017a91bf 100644
--- a/source/blender/editors/uvedit/uvedit_select.c
+++ b/source/blender/editors/uvedit/uvedit_select.c
@@ -1022,8 +1022,13 @@ bool uv_find_nearest_vert_multi(Scene *scene,
return found;
}
-bool ED_uvedit_nearest_uv(
- const Scene *scene, Object *obedit, const float co[2], float *dist_sq, float r_uv[2])
+static bool uvedit_nearest_uv(const Scene *scene,
+ Object *obedit,
+ const float co[2],
+ const float scale[2],
+ const bool ignore_selected,
+ float *dist_sq,
+ float r_uv[2])
{
BMEditMesh *em = BKE_editmesh_from_object(obedit);
BMIter iter;
@@ -1038,8 +1043,14 @@ bool ED_uvedit_nearest_uv(
BMLoop *l_iter, *l_first;
l_iter = l_first = BM_FACE_FIRST_LOOP(efa);
do {
+ if (ignore_selected && uvedit_uv_select_test(scene, l_iter, cd_loop_uv_offset)) {
+ continue;
+ }
+
const float *uv = ((const MLoopUV *)BM_ELEM_CD_GET_VOID_P(l_iter, cd_loop_uv_offset))->uv;
- const float dist_test = len_squared_v2v2(co, uv);
+ float co_tmp[2];
+ mul_v2_v2v2(co_tmp, scale, uv);
+ const float dist_test = len_squared_v2v2(co, co_tmp);
if (dist_best > dist_test) {
dist_best = dist_test;
uv_best = uv;
@@ -1055,17 +1066,27 @@ bool ED_uvedit_nearest_uv(
return false;
}
-bool ED_uvedit_nearest_uv_multi(const Scene *scene,
+bool ED_uvedit_nearest_uv_multi(const View2D *v2d,
+ const Scene *scene,
Object **objects,
const uint objects_len,
- const float co[2],
+ const int mval[2],
+ const bool ignore_selected,
float *dist_sq,
float r_uv[2])
{
bool found = false;
+
+ float scale[2], offset[2];
+ UI_view2d_scale_get(v2d, &scale[0], &scale[1]);
+ UI_view2d_view_to_region_fl(v2d, 0.0f, 0.0f, &offset[0], &offset[1]);
+
+ float co[2];
+ sub_v2_v2v2(co, (float[2]){UNPACK2(mval)}, offset);
+
for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
Object *obedit = objects[ob_index];
- if (ED_uvedit_nearest_uv(scene, obedit, co, dist_sq, r_uv)) {
+ if (uvedit_nearest_uv(scene, obedit, co, scale, ignore_selected, dist_sq, r_uv)) {
found = true;
}
}
diff --git a/source/blender/editors/uvedit/uvedit_unwrap_ops.c b/source/blender/editors/uvedit/uvedit_unwrap_ops.c
index c0ea753ed51..84dca352c9f 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. */
@@ -339,7 +339,6 @@ static ParamHandle *construct_param_handle(const Scene *scene,
const UnwrapOptions *options,
UnwrapResultInfo *result_info)
{
- ParamHandle *handle;
BMFace *efa;
BMLoop *l;
BMEdge *eed;
@@ -348,7 +347,7 @@ static ParamHandle *construct_param_handle(const Scene *scene,
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;
@@ -417,14 +416,13 @@ 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;
int i;
- handle = GEO_uv_parametrizer_construct_begin();
+ ParamHandle *handle = GEO_uv_parametrizer_construct_begin();
if (options->correct_aspect) {
Object *ob = objects[0];
@@ -539,7 +537,6 @@ static ParamHandle *construct_param_handle_subsurfed(const Scene *scene,
const UnwrapOptions *options,
UnwrapResultInfo *result_info)
{
- ParamHandle *handle;
/* index pointers */
MPoly *mpoly;
MLoop *mloop;
@@ -571,7 +568,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;
@@ -1023,8 +1020,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);
@@ -1043,8 +1039,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);
@@ -3038,7 +3033,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..46051a58e8b 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)
diff --git a/source/blender/geometry/CMakeLists.txt b/source/blender/geometry/CMakeLists.txt
index 8716d6c8f67..010c327d482 100644
--- a/source/blender/geometry/CMakeLists.txt
+++ b/source/blender/geometry/CMakeLists.txt
@@ -16,15 +16,19 @@ set(INC
set(SRC
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/uv_parametrizer.c
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_uv_parametrizer.h
)
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_uv_parametrizer.h b/source/blender/geometry/GEO_uv_parametrizer.h
index a5194883cf2..624b0695aa3 100644
--- a/source/blender/geometry/GEO_uv_parametrizer.h
+++ b/source/blender/geometry/GEO_uv_parametrizer.h
@@ -12,8 +12,8 @@
extern "C" {
#endif
-typedef void ParamHandle; /* handle to a set of charts */
-typedef intptr_t ParamKey; /* (hash) key for identifying verts and faces */
+typedef struct ParamHandle ParamHandle; /* Handle to an array of charts. */
+typedef intptr_t ParamKey; /* Key (hash) for identifying verts and faces. */
typedef enum ParamBool {
PARAM_TRUE = 1,
PARAM_FALSE = 0,
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..ae07e817c67 100644
--- a/source/blender/geometry/intern/realize_instances.cc
+++ b/source/blender/geometry/intern/realize_instances.cc
@@ -374,7 +374,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 +548,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 +556,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;
}
@@ -1052,7 +1052,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);
}
}
@@ -1215,13 +1215,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);
diff --git a/source/blender/geometry/intern/resample_curves.cc b/source/blender/geometry/intern/resample_curves.cc
new file mode 100644
index 00000000000..7895225a189
--- /dev/null
+++ b/source/blender/geometry/intern/resample_curves.cc
@@ -0,0 +1,474 @@
+/* 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 CustomDataType 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();
+}
+
+/**
+ * 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>());
+ });
+}
+
+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()) {
+ 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 (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()) {
+ 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 (bke::OutputAttribute &attribute : attributes.dst_attributes) {
+ attribute.save();
+ }
+
+ return dst_curves_id;
+}
+
+} // namespace blender::geometry
diff --git a/source/blender/geometry/intern/uv_parametrizer.c b/source/blender/geometry/intern/uv_parametrizer.c
index e25fff0d6b8..ad4b051a6c2 100644
--- a/source/blender/geometry/intern/uv_parametrizer.c
+++ b/source/blender/geometry/intern/uv_parametrizer.c
@@ -59,7 +59,6 @@ typedef struct PHash {
struct PChart;
struct PEdge;
struct PFace;
-struct PHandle;
struct PVert;
/* Simplices */
@@ -171,7 +170,7 @@ typedef struct PChart {
} u;
uchar flag;
- struct PHandle *handle;
+ ParamHandle *handle;
} PChart;
enum PChartFlag {
@@ -185,7 +184,7 @@ enum PHandleState {
PHANDLE_STATE_STRETCH,
};
-typedef struct PHandle {
+typedef struct ParamHandle {
enum PHandleState state;
MemArena *arena;
MemArena *polyfill_arena;
@@ -204,7 +203,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.
@@ -637,7 +636,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 +678,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 +690,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 +741,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 +764,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 +788,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 +807,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, 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);
@@ -833,7 +831,7 @@ static int p_face_exists(ParamHandle *phandle, ParamKey *pvkeys, int i1, int i2,
return P_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;
@@ -881,7 +879,10 @@ static PBool p_edge_implicit_seam(PEdge *e, PEdge *ep)
return P_FALSE;
}
-static PBool p_edge_has_pair(PHandle *handle, PEdge *e, PBool topology_from_uvs, PEdge **r_pair)
+static PBool p_edge_has_pair(ParamHandle *handle,
+ PEdge *e,
+ PBool topology_from_uvs,
+ PEdge **r_pair)
{
PHashKey key;
PEdge *pe;
@@ -930,7 +931,7 @@ static PBool p_edge_has_pair(PHandle *handle, PEdge *e, PBool topology_from_uvs,
return (*r_pair != NULL);
}
-static PBool p_edge_connect_pair(PHandle *handle,
+static PBool p_edge_connect_pair(ParamHandle *handle,
PEdge *e,
PBool topology_from_uvs,
PEdge ***stack)
@@ -954,7 +955,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, PBool topology_from_uvs)
{
PEdge **stackbase = MEM_mallocN(sizeof(*stackbase) * phash_size(handle->hash_faces),
"Pstackbase");
@@ -1061,7 +1062,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 +1101,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,7 +1133,7 @@ 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],
@@ -1219,7 +1220,7 @@ 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 PBool p_quad_split_direction(ParamHandle *handle, float **co, PHashKey *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
@@ -3212,7 +3213,7 @@ static void p_chart_lscm_begin(PChart *chart, PBool live, PBool abf)
}
}
-static PBool p_chart_lscm_solve(PHandle *handle, PChart *chart)
+static PBool 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;
@@ -4361,7 +4362,7 @@ static void p_smooth(PChart *chart)
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 +4376,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));
@@ -4426,9 +4424,8 @@ static void p_add_ngon(ParamHandle *handle,
ParamBool *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);
@@ -4478,7 +4475,7 @@ static void p_add_ngon(ParamHandle *handle,
BLI_memarena_clear(arena);
}
-void GEO_uv_parametrizer_face_add(ParamHandle *handle,
+void GEO_uv_parametrizer_face_add(ParamHandle *phandle,
ParamKey key,
int nverts,
ParamKey *vkeys,
@@ -4487,15 +4484,13 @@ void GEO_uv_parametrizer_face_add(ParamHandle *handle,
ParamBool *pin,
ParamBool *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 +4509,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,12 +4521,11 @@ void GEO_uv_parametrizer_edge_set_seam(ParamHandle *handle, ParamKey *vkeys)
}
}
-void GEO_uv_parametrizer_construct_end(ParamHandle *handle,
+void GEO_uv_parametrizer_construct_end(ParamHandle *phandle,
ParamBool fill,
ParamBool topology_from_uvs,
int *count_fail)
{
- PHandle *phandle = (PHandle *)handle;
PChart *chart = phandle->construction_chart;
int i, j, nboundaries = 0;
PEdge *outer;
@@ -4572,7 +4565,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 +4574,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, ParamBool live, ParamBool abf)
{
- PHandle *phandle = (PHandle *)handle;
PFace *f;
int i;
@@ -4598,9 +4590,8 @@ void GEO_uv_parametrizer_lscm_begin(ParamHandle *handle, ParamBool live, ParamBo
}
}
-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;
@@ -4638,9 +4629,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 +4645,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 +4674,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 +4693,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,9 +4702,8 @@ void GEO_uv_parametrizer_stretch_end(ParamHandle *handle)
phandle->rng = NULL;
}
-void GEO_uv_parametrizer_smooth_area(ParamHandle *handle)
+void GEO_uv_parametrizer_smooth_area(ParamHandle *phandle)
{
- PHandle *phandle = (PHandle *)handle;
int i;
param_assert(phandle->state == PHANDLE_STATE_CONSTRUCTED);
@@ -4738,13 +4721,11 @@ void GEO_uv_parametrizer_smooth_area(ParamHandle *handle)
}
/* 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 +4751,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 +4760,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 +4800,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 +4817,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 +4826,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 +4908,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 +4919,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 +4940,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 6108629183c..69fc26c99e9 100644
--- a/source/blender/gpencil_modifiers/CMakeLists.txt
+++ b/source/blender/gpencil_modifiers/CMakeLists.txt
@@ -65,14 +65,30 @@ set(SRC
# Lineart code
intern/lineart/lineart_chain.c
+ intern/lineart/lineart_cpp_bridge.cc
intern/lineart/lineart_cpu.c
intern/lineart/lineart_ops.c
intern/lineart/lineart_util.c
intern/lineart/MOD_lineart.h
intern/lineart/lineart_intern.h
+)
+
+if(WITH_TBB)
+add_definitions(-DWITH_TBB)
+if(WIN32)
+ # TBB includes Windows.h which will define min/max macros
+ # that will collide with the stl versions.
+ add_definitions(-DNOMINMAX)
+endif()
+list(APPEND INC_SYS
+ ${TBB_INCLUDE_DIRS}
+)
+list(APPEND LIB
+ ${TBB_LIBRARIES}
)
+endif()
set(LIB
)
diff --git a/source/blender/gpencil_modifiers/intern/MOD_gpencildash.c b/source/blender/gpencil_modifiers/intern/MOD_gpencildash.c
index e57b9df03f5..f023b00480c 100644
--- a/source/blender/gpencil_modifiers/intern/MOD_gpencildash.c
+++ b/source/blender/gpencil_modifiers/intern/MOD_gpencildash.c
@@ -12,8 +12,6 @@
#include "BLI_math.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_gpencillineart.c b/source/blender/gpencil_modifiers/intern/MOD_gpencillineart.c
index 1058f861be3..a07ef2eb195 100644
--- a/source/blender/gpencil_modifiers/intern/MOD_gpencillineart.c
+++ b/source/blender/gpencil_modifiers/intern/MOD_gpencillineart.c
@@ -218,9 +218,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 +248,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");
@@ -387,7 +392,6 @@ static void options_panel_draw(const bContext *UNUSED(C), Panel *panel)
uiLayout *col = uiLayoutColumn(layout, true);
- uiItemR(col, ptr, "use_remove_doubles", 0, NULL, ICON_NONE);
uiItemR(col, ptr, "use_edge_overlap", 0, IFACE_("Overlapping Edges As Contour"), ICON_NONE);
uiItemR(col, ptr, "use_object_instances", 0, NULL, ICON_NONE);
uiItemR(col, ptr, "use_clip_plane_boundaries", 0, NULL, ICON_NONE);
diff --git a/source/blender/gpencil_modifiers/intern/MOD_gpencilnoise.c b/source/blender/gpencil_modifiers/intern/MOD_gpencilnoise.c
index fcf1e28c6da..259e62a249c 100644
--- a/source/blender/gpencil_modifiers/intern/MOD_gpencilnoise.c
+++ b/source/blender/gpencil_modifiers/intern/MOD_gpencilnoise.c
@@ -122,6 +122,8 @@ static void deformStroke(GpencilModifierData *md,
const int def_nr = BKE_object_defgroup_name_index(ob, mmd->vgname);
const bool invert_group = (mmd->flag & GP_NOISE_INVERT_VGROUP) != 0;
const bool use_curve = (mmd->flag & GP_NOISE_CUSTOM_CURVE) != 0 && mmd->curve_intensity;
+ const int cfra = (int)DEG_get_ctime(depsgraph);
+ const bool is_keyframe = (mmd->noise_mode == GP_NOISE_RANDOM_KEYFRAME);
if (!is_stroke_affected_by_modifier(ob,
mmd->layername,
@@ -148,7 +150,13 @@ static void deformStroke(GpencilModifierData *md,
seed += BLI_hash_string(md->name);
if (mmd->flag & GP_NOISE_USE_RANDOM) {
- seed += ((int)DEG_get_ctime(depsgraph)) / mmd->step;
+ if (!is_keyframe) {
+ seed += cfra / mmd->step;
+ }
+ else {
+ /* If change every keyframe, use the last keyframe. */
+ seed += gpf->framenum;
+ }
}
/* Sanitize as it can create out of bound reads. */
@@ -302,7 +310,12 @@ static void random_panel_draw(const bContext *UNUSED(C), Panel *panel)
uiLayoutSetActive(layout, RNA_boolean_get(ptr, "use_random"));
- uiItemR(layout, ptr, "step", 0, NULL, ICON_NONE);
+ uiItemR(layout, ptr, "random_mode", 0, NULL, ICON_NONE);
+
+ const int mode = RNA_enum_get(ptr, "random_mode");
+ if (mode != GP_NOISE_RANDOM_KEYFRAME) {
+ uiItemR(layout, ptr, "step", 0, NULL, ICON_NONE);
+ }
}
static void mask_panel_draw(const bContext *UNUSED(C), Panel *panel)
diff --git a/source/blender/gpencil_modifiers/intern/MOD_gpenciltime.c b/source/blender/gpencil_modifiers/intern/MOD_gpenciltime.c
index c576cfbe525..414231fcae5 100644
--- a/source/blender/gpencil_modifiers/intern/MOD_gpenciltime.c
+++ b/source/blender/gpencil_modifiers/intern/MOD_gpenciltime.c
@@ -122,6 +122,30 @@ static int remapTime(struct GpencilModifierData *md,
nfra = (efra + 1 - (cfra + offset - 1) % (efra - sfra + 1)) - 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;
+ }
+ }
+ 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 nfra;
}
diff --git a/source/blender/gpencil_modifiers/intern/lineart/MOD_lineart.h b/source/blender/gpencil_modifiers/intern/lineart/MOD_lineart.h
index 5d952991cf7..ad3e1b5d7f2 100644
--- a/source/blender/gpencil_modifiers/intern/lineart/MOD_lineart.h
+++ b/source/blender/gpencil_modifiers/intern/lineart/MOD_lineart.h
@@ -122,17 +122,13 @@ 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;
/** Also for line type determination on chaining. */
- unsigned char flags;
+ uint16_t flags;
unsigned char intersection_mask;
/**
@@ -158,6 +154,8 @@ typedef struct LineartEdgeChain {
/** Chain now only contains one type of segments */
int type;
+ /** Will only connect chains that has the same loop id. */
+ int loop_id;
unsigned char material_mask_bits;
unsigned char intersection_mask;
@@ -171,7 +169,7 @@ typedef struct LineartEdgeChainItem {
/** For restoring position to 3d space. */
float gpos[3];
float normal[3];
- unsigned char line_type;
+ uint16_t line_type;
char occlusion;
unsigned char material_mask_bits;
unsigned char intersection_mask;
@@ -189,6 +187,12 @@ typedef struct LineartChainRegisterEntry {
char is_left;
} LineartChainRegisterEntry;
+typedef struct LineartAdjacentEdge {
+ unsigned int v1;
+ unsigned int v2;
+ unsigned int e;
+} LineartAdjacentEdge;
+
enum eLineArtTileRecursiveLimit {
/* If tile gets this small, it's already much smaller than a pixel. No need to continue
* splitting. */
@@ -200,6 +204,12 @@ enum eLineArtTileRecursiveLimit {
#define LRT_TILE_SPLITTING_TRIANGLE_LIMIT 100
#define LRT_TILE_EDGE_COUNT_INITIAL 32
+typedef struct LineartPendingEdges {
+ LineartEdge **array;
+ int max;
+ int next;
+} LineartPendingEdges;
+
typedef struct LineartRenderBuffer {
struct LineartRenderBuffer *prev, *next;
@@ -244,15 +254,9 @@ typedef struct LineartRenderBuffer {
int triangle_size;
- /* 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;
+ /* Note: Data inside #pending_edges are allocated with MEM_xxx call instead of in pool. */
+ struct LineartPendingEdges pending_edges;
+ int scheduled_count;
ListBase chains;
@@ -358,14 +362,11 @@ typedef struct LineartRenderTaskInfo {
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
+ * LineartRenderbuffer::pending_edges, assigned by the occlusion scheduler.
+ */
+ struct LineartPendingEdges pending_edges;
} LineartRenderTaskInfo;
@@ -383,20 +384,14 @@ 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 Depsgraph *dg;
+ int thread_id;
/* LinkNode styled list */
LineartObjectInfo *pending;
/* Used to spread the load across several threads. This can not overflow. */
@@ -481,7 +476,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.
*/
diff --git a/source/blender/gpencil_modifiers/intern/lineart/lineart_chain.c b/source/blender/gpencil_modifiers/intern/lineart/lineart_chain.c
index b666eb677eb..226b8f532b5 100644
--- a/source/blender/gpencil_modifiers/intern/lineart/lineart_chain.c
+++ b/source/blender/gpencil_modifiers/intern/lineart/lineart_chain.c
@@ -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;
@@ -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;
}
@@ -282,7 +282,7 @@ 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;
}
@@ -295,7 +295,7 @@ 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]);
}
@@ -336,7 +336,7 @@ 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;
}
@@ -349,7 +349,7 @@ 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]);
@@ -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) {
@@ -428,7 +428,7 @@ 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;
}
@@ -441,7 +441,7 @@ 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]);
}
@@ -617,9 +617,14 @@ void MOD_lineart_chain_split_for_fixed_occlusion(LineartRenderBuffer *rb)
rb->chains.last = rb->chains.first = NULL;
+ int loop_id = 0;
while ((ec = BLI_pophead(&swap)) != NULL) {
ec->next = ec->prev = NULL;
BLI_addtail(&rb->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;
@@ -651,6 +656,7 @@ void MOD_lineart_chain_split_for_fixed_occlusion(LineartRenderBuffer *rb)
new_ec = lineart_chain_create(rb);
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;
@@ -743,6 +749,7 @@ static LineartChainRegisterEntry *lineart_chain_get_closest_cre(LineartRenderBuf
int occlusion,
unsigned char material_mask_bits,
unsigned char isec_mask,
+ int loop_id,
float dist,
float *result_new_len,
LineartBoundingArea *caller_ba)
@@ -791,7 +798,11 @@ 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) {
+ /* 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) {
@@ -815,6 +826,7 @@ static LineartChainRegisterEntry *lineart_chain_get_closest_cre(LineartRenderBuf
occlusion, \
material_mask_bits, \
isec_mask, \
+ loop_id, \
dist, \
&adjacent_new_len, \
ba); \
@@ -844,7 +856,7 @@ void MOD_lineart_chain_connect(LineartRenderBuffer *rb)
LineartChainRegisterEntry *closest_cre_l, *closest_cre_r, *closest_cre;
float dist = rb->chaining_image_threshold;
float dist_l, dist_r;
- int occlusion, reverse_main;
+ int occlusion, reverse_main, loop_id;
unsigned char material_mask_bits, isec_mask;
ListBase swap = {0};
@@ -863,6 +875,7 @@ void MOD_lineart_chain_connect(LineartRenderBuffer *rb)
continue;
}
BLI_addtail(&rb->chains, ec);
+ loop_id = ec->loop_id;
if (ec->type == LRT_EDGE_FLAG_LOOSE && (!rb->use_loose_edge_chain)) {
continue;
@@ -876,10 +889,28 @@ void MOD_lineart_chain_connect(LineartRenderBuffer *rb)
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);
+ closest_cre_l = lineart_chain_get_closest_cre(rb,
+ 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(rb,
+ 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;
@@ -971,27 +1002,67 @@ void MOD_lineart_chain_clear_picked_flag(LineartCache *lc)
void MOD_lineart_smooth_chains(LineartRenderBuffer *rb, 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;
+ /* 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);
}
}
}
@@ -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;
}
diff --git a/source/blender/gpencil_modifiers/intern/lineart/lineart_cpp_bridge.cc b/source/blender/gpencil_modifiers/intern/lineart/lineart_cpp_bridge.cc
new file mode 100644
index 00000000000..5e741ccbd55
--- /dev/null
+++ b/source/blender/gpencil_modifiers/intern/lineart/lineart_cpp_bridge.cc
@@ -0,0 +1,25 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+
+/** \file
+ * \ingroup modifiers
+ */
+
+#include "BLI_sort.hh"
+#include "BLI_vector.hh"
+#include "MOD_lineart.h"
+#include "lineart_intern.h"
+
+static bool cmp_adjacent_items(const LineartAdjacentEdge &p1, const LineartAdjacentEdge &p2)
+{
+ int a = p1.v1 - p2.v1;
+ int b = p1.v2 - p2.v2;
+ /* parallel_sort() requires cmp() to return true when the first element needs to appear before
+ * the second element in the sorted array, false otherwise (strict weak ordering), see
+ * https://en.cppreference.com/w/cpp/named_req/Compare. */
+ return a < 0 ? true : (a == 0 ? b < 0 : false);
+}
+
+void lineart_sort_adjacent_items(LineartAdjacentEdge *ai, int length)
+{
+ 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 24e11f6be3b..016b70cedb0 100644
--- a/source/blender/gpencil_modifiers/intern/lineart/lineart_cpu.c
+++ b/source/blender/gpencil_modifiers/intern/lineart/lineart_cpu.c
@@ -8,6 +8,7 @@
#include "MOD_gpencil_lineart.h"
#include "MOD_lineart.h"
+#include "BLI_edgehash.h"
#include "BLI_linklist.h"
#include "BLI_listbase.h"
#include "BLI_math.h"
@@ -20,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"
@@ -28,6 +30,8 @@
#include "BKE_lib_id.h"
#include "BKE_material.h"
#include "BKE_mesh.h"
+#include "BKE_mesh_mapping.h"
+#include "BKE_mesh_runtime.h"
#include "BKE_object.h"
#include "BKE_pointcache.h"
#include "BKE_scene.h"
@@ -93,7 +97,7 @@ 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 LineartCache *lineart_init_cache(void);
@@ -408,38 +412,26 @@ static void lineart_occlusion_single_line(LineartRenderBuffer *rb, LineartEdge *
static int lineart_occlusion_make_task_info(LineartRenderBuffer *rb, LineartRenderTaskInfo *rti)
{
- LineartEdge *data;
- int i;
int res = 0;
+ int starting_index;
BLI_spin_lock(&rb->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);
-
-#undef LRT_ASSIGN_OCCLUSION_TASK
+ starting_index = rb->scheduled_count;
+ rb->scheduled_count += LRT_THREAD_EDGE_COUNT;
BLI_spin_unlock(&rb->lock_task);
+ if (starting_index >= rb->pending_edges.next) {
+ res = 0;
+ }
+ else {
+ rti->pending_edges.array = &rb->pending_edges.array[starting_index];
+ int remaining = rb->pending_edges.next - starting_index;
+ rti->pending_edges.max = MIN2(remaining, LRT_THREAD_EDGE_COUNT);
+ res = 1;
+ }
+
return res;
}
@@ -449,28 +441,8 @@ static void lineart_occlusion_worker(TaskPool *__restrict UNUSED(pool), LineartR
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) {
+ for (int i = 0; i < rti->pending_edges.max; i++) {
+ eip = rti->pending_edges.array[i];
lineart_occlusion_single_line(rb, eip, rti->thread_id);
}
}
@@ -488,15 +460,6 @@ static void lineart_main_occlusion_begin(LineartRenderBuffer *rb)
"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++) {
@@ -753,13 +716,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;
}
}
@@ -789,8 +751,7 @@ static void lineart_triangle_cull_single(LineartRenderBuffer *rb,
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;
@@ -813,13 +774,9 @@ static void lineart_triangle_cull_single(LineartRenderBuffer *rb,
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)); \
BLI_addtail(&e->segments, es);
@@ -828,15 +785,17 @@ static void lineart_triangle_cull_single(LineartRenderBuffer *rb,
old_e = ta->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(&rb->pending_edges, e); \
}
#define RELINK_EDGE(e_num, new_tri) \
@@ -849,15 +808,15 @@ static void lineart_triangle_cull_single(LineartRenderBuffer *rb,
#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); \
+ lineart_discard_duplicated_edges(ta->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); \
+ lineart_discard_duplicated_edges(ta->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); \
+ lineart_discard_duplicated_edges(ta->e[2]); \
}
switch (in0 + in1 + in2) {
@@ -922,7 +881,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(&rb->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
@@ -971,7 +930,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(&rb->pending_edges, e);
}
e->v1 = &vt[0];
e->v2 = &vt[1];
@@ -1012,7 +971,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(&rb->pending_edges, e);
}
e->v1 = &vt[1];
e->v2 = &vt[0];
@@ -1087,7 +1046,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(&rb->pending_edges, e);
}
e->v1 = &vt[1];
e->v2 = &vt[0];
@@ -1139,10 +1098,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(&rb->pending_edges, e);
}
e->v1 = &vt[1];
e->v2 = &vt[0];
+
e->t1 = tri1;
e->object_ref = ob;
@@ -1187,10 +1147,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(&rb->pending_edges, e);
}
e->v1 = &vt[1];
e->v2 = &vt[0];
+
e->t1 = tri1;
e->object_ref = ob;
@@ -1426,17 +1387,45 @@ static void lineart_main_discard_out_of_frame_edges(LineartRenderBuffer *rb)
}
}
-/**
- * Transform a single vert to it's viewing position.
- */
-static void lineart_vert_transform(
- BMVert *v, int index, LineartVert *RvBuf, double (*mv_mat)[4], double (*mvp_mat)[4])
+typedef struct LineartEdgeNeighbor {
+ int e;
+ uint16_t flags;
+ int v1, v2;
+} LineartEdgeNeighbor;
+
+typedef struct VertData {
+ MVert *mvert;
+ LineartVert *v_arr;
+ double (*model_view)[4];
+ double (*model_view_proj)[4];
+} VertData;
+
+static void lineart_mvert_transform_task(void *__restrict userdata,
+ const int i,
+ const TaskParallelTLS *__restrict UNUSED(tls))
{
+ VertData *vert_task_data = (VertData *)userdata;
+ MVert *m_v = &vert_task_data->mvert[i];
double co[4];
- LineartVert *vt = &RvBuf[index];
- copy_v3db_v3fl(co, v->co);
- mul_v3_m4v3_db(vt->gloc, mv_mat, co);
- mul_v4_m4v3_db(vt->fbcoord, mvp_mat, co);
+ LineartVert *v = &vert_task_data->v_arr[i];
+ copy_v3db_v3fl(co, m_v->co);
+ mul_v3_m4v3_db(v->gloc, vert_task_data->model_view, co);
+ mul_v4_m4v3_db(v->fbcoord, vert_task_data->model_view_proj, co);
+ v->index = i;
+}
+
+#define LRT_EDGE_FLAG_TYPE_MAX_BITS 6
+
+static int lineart_edge_type_duplication_count(char eflag)
+{
+ int count = 0;
+ /* See eLineartEdgeFlag for details. */
+ for (int i = 0; i < LRT_EDGE_FLAG_TYPE_MAX_BITS; i++) {
+ if (eflag & (1 << i)) {
+ count++;
+ }
+ }
+ return count;
}
/**
@@ -1452,88 +1441,123 @@ static LineartTriangle *lineart_triangle_from_index(LineartRenderBuffer *rb,
return (LineartTriangle *)b;
}
-static uint16_t lineart_identify_feature_line(LineartRenderBuffer *rb,
- BMEdge *e,
- LineartTriangle *rt_array,
- LineartVert *rv_array,
- float crease_threshold,
- bool use_auto_smooth,
- bool use_freestyle_edge,
- bool use_freestyle_face,
- BMesh *bm_if_freestyle)
+typedef struct EdgeFeatData {
+ LineartRenderBuffer *rb;
+ Mesh *me;
+ const MLoopTri *mlooptri;
+ LineartTriangle *tri_array;
+ LineartVert *v_array;
+ float crease_threshold;
+ bool use_auto_smooth;
+ bool use_freestyle_face;
+ int freestyle_face_index;
+ bool use_freestyle_edge;
+ int freestyle_edge_index;
+ LineartEdgeNeighbor *edge_nabr;
+} EdgeFeatData;
+
+typedef struct EdgeFeatReduceData {
+ int feat_edges;
+} EdgeFeatReduceData;
+
+static void feat_data_sum_reduce(const void *__restrict UNUSED(userdata),
+ void *__restrict chunk_join,
+ void *__restrict chunk)
{
- BMLoop *ll, *lr = NULL;
+ EdgeFeatReduceData *feat_chunk_join = (EdgeFeatReduceData *)chunk_join;
+ EdgeFeatReduceData *feat_chunk = (EdgeFeatReduceData *)chunk;
+ feat_chunk_join->feat_edges += feat_chunk->feat_edges;
+}
- ll = e->l;
- if (ll) {
- lr = e->l->radial_next;
- }
+static void lineart_identify_mlooptri_feature_edges(void *__restrict userdata,
+ const int i,
+ const TaskParallelTLS *__restrict tls)
+{
+ EdgeFeatData *e_feat_data = (EdgeFeatData *)userdata;
+ EdgeFeatReduceData *reduce_data = (EdgeFeatReduceData *)tls->userdata_chunk;
+ Mesh *me = e_feat_data->me;
+ LineartEdgeNeighbor *edge_nabr = e_feat_data->edge_nabr;
+ const MLoopTri *mlooptri = e_feat_data->mlooptri;
+
+ uint16_t edge_flag_result = 0;
- if (!ll && !lr) {
- return LRT_EDGE_FLAG_LOOSE;
+ /* Because the edge neighbor array contains loop edge pairs, we only need to process the first
+ * edge in the pair. Otherwise we would add the same edge that the loops represent twice. */
+ if (i < edge_nabr[i].e) {
+ return;
}
- FreestyleEdge *fel, *fer;
bool face_mark_filtered = false;
- uint16_t edge_flag_result = 0;
+ bool enable_face_mark = (e_feat_data->use_freestyle_face && e_feat_data->rb->filter_face_mark);
bool only_contour = false;
-
- if (use_freestyle_face && rb->filter_face_mark) {
- fel = CustomData_bmesh_get(&bm_if_freestyle->pdata, ll->f->head.data, CD_FREESTYLE_FACE);
- if (ll != lr && lr) {
- fer = CustomData_bmesh_get(&bm_if_freestyle->pdata, lr->f->head.data, CD_FREESTYLE_FACE);
+ if (enable_face_mark) {
+ FreestyleFace *ff1, *ff2;
+ int index = e_feat_data->freestyle_face_index;
+ if (index > -1) {
+ ff1 = &((FreestyleFace *)me->pdata.layers[index].data)[mlooptri[i / 3].poly];
+ }
+ if (edge_nabr[i].e > -1) {
+ ff2 = &((FreestyleFace *)me->pdata.layers[index].data)[mlooptri[edge_nabr[i].e / 3].poly];
}
else {
- /* Handles mesh boundary case */
- fer = fel;
+ /* Handle mesh boundary cases: We want mesh boundaries to respect
+ * `filter_face_mark_boundaries` option the same way as face mark boundaries, and the code
+ * path is simper when it's assuming both ff1 and ff2 not NULL. */
+ ff2 = ff1;
}
- if (rb->filter_face_mark_boundaries ^ rb->filter_face_mark_invert) {
- if ((fel->flag & FREESTYLE_FACE_MARK) || (fer->flag & FREESTYLE_FACE_MARK)) {
+ if (e_feat_data->rb->filter_face_mark_boundaries ^ e_feat_data->rb->filter_face_mark_invert) {
+ if ((ff1->flag & FREESTYLE_FACE_MARK) || (ff2->flag & FREESTYLE_FACE_MARK)) {
face_mark_filtered = true;
}
}
else {
- if ((fel->flag & FREESTYLE_FACE_MARK) && (fer->flag & FREESTYLE_FACE_MARK) && (fer != fel)) {
+ if ((ff1->flag & FREESTYLE_FACE_MARK) && (ff2->flag & FREESTYLE_FACE_MARK) && (ff2 != ff1)) {
face_mark_filtered = true;
}
}
- if (rb->filter_face_mark_invert) {
+ if (e_feat_data->rb->filter_face_mark_invert) {
face_mark_filtered = !face_mark_filtered;
}
if (!face_mark_filtered) {
- if (rb->filter_face_mark_keep_contour) {
+ edge_nabr[i].flags = LRT_EDGE_FLAG_INHIBIT;
+ if (e_feat_data->rb->filter_face_mark_keep_contour) {
only_contour = true;
}
- else {
- return 0;
- }
}
}
+ if (enable_face_mark && !face_mark_filtered && !only_contour) {
+ return;
+ }
+
/* Mesh boundary */
- if (!lr || ll == lr) {
- return (edge_flag_result | LRT_EDGE_FLAG_CONTOUR);
+ if (edge_nabr[i].e == -1) {
+ edge_nabr[i].flags = LRT_EDGE_FLAG_CONTOUR;
+ reduce_data->feat_edges += 1;
+ return;
}
LineartTriangle *tri1, *tri2;
- LineartVert *l;
+ LineartVert *vert;
+ LineartRenderBuffer *rb = e_feat_data->rb;
+
+ 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, rt_array, BM_elem_index_get(ll->f));
- tri2 = lineart_triangle_from_index(rb, rt_array, BM_elem_index_get(lr->f));
+ tri1 = lineart_triangle_from_index(rb, e_feat_data->tri_array, f1);
+ tri2 = lineart_triangle_from_index(rb, e_feat_data->tri_array, f2);
- l = &rv_array[BM_elem_index_get(e->v1)];
+ vert = &e_feat_data->v_array[edge_nabr[i].v1];
- double vv[3];
- double *view_vector = vv;
+ double view_vector_persp[3];
+ double *view_vector = view_vector_persp;
double dot_1 = 0, dot_2 = 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, l->gloc);
+ sub_v3_v3v3_db(view_vector, rb->camera_pos, vert->gloc);
}
else {
view_vector = rb->view_vector;
@@ -1542,11 +1566,10 @@ static uint16_t lineart_identify_feature_line(LineartRenderBuffer *rb,
dot_1 = dot_v3v3_db(view_vector, tri1->gn);
dot_2 = dot_v3v3_db(view_vector, tri2->gn);
- if (rb->use_contour && (result = dot_1 * dot_2) <= 0 && (dot_1 + dot_2)) {
+ if ((result = dot_1 * dot_2) <= 0 && (dot_1 + dot_2)) {
edge_flag_result |= LRT_EDGE_FLAG_CONTOUR;
}
- /* Because the ray points towards the camera, so back-face is when dot value being negative. */
if (rb->use_back_face_culling) {
if (dot_1 < 0) {
tri1->flags |= LRT_CULL_DISCARD;
@@ -1564,127 +1587,182 @@ static uint16_t lineart_identify_feature_line(LineartRenderBuffer *rb,
}
}
}
- else {
- view_vector = rb->view_vector;
- }
- if ((result = dot_1 * dot_2) <= 0 && (fabs(dot_1) + fabs(dot_2))) {
- edge_flag_result |= LRT_EDGE_FLAG_CONTOUR;
- }
+ if (!only_contour) {
- /* For when face mark filtering decided that we discard the face but keep_contour option is on.
- * so we still have correct full contour around the object. */
- if (only_contour) {
- return edge_flag_result;
- }
+ if (rb->use_crease) {
+ bool do_crease = true;
+ if (!rb->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;
+ }
+ if (do_crease && (dot_v3v3_db(tri1->gn, tri2->gn) < e_feat_data->crease_threshold)) {
+ edge_flag_result |= LRT_EDGE_FLAG_CREASE;
+ }
+ }
- /* Do not show lines other than contour on back face (because contour has one adjacent face that
- * isn't a back face).
- * TODO(Yiming): Do we need separate option for this? */
- if (rb->use_back_face_culling ||
- ((tri1->flags & tri2->flags) & LRT_TRIANGLE_MAT_BACK_FACE_CULLING)) {
- if (dot_1 < 0 && dot_2 < 0) {
- return edge_flag_result;
+ int mat1 = me->mpoly[mlooptri[f1].poly].mat_nr;
+ int mat2 = me->mpoly[mlooptri[f2].poly].mat_nr;
+
+ if (rb->use_material && mat1 != mat2) {
+ edge_flag_result |= LRT_EDGE_FLAG_MATERIAL;
+ }
+ }
+ else { /* only_contour */
+ if (!edge_flag_result) { /* Other edge types inhibited */
+ return;
}
}
- if (rb->use_crease) {
- if (rb->sharp_as_crease && !BM_elem_flag_test(e, BM_ELEM_SMOOTH)) {
+ int real_edges[3];
+ BKE_mesh_looptri_get_real_edges(me, &mlooptri[i / 3], real_edges);
+
+ 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)) {
edge_flag_result |= LRT_EDGE_FLAG_CREASE;
}
- else {
- bool do_crease = true;
- if (!rb->force_crease && !use_auto_smooth &&
- (BM_elem_flag_test(ll->f, BM_ELEM_SMOOTH) && BM_elem_flag_test(lr->f, BM_ELEM_SMOOTH))) {
- do_crease = false;
- }
- if (do_crease && (dot_v3v3_db(tri1->gn, tri2->gn) < crease_threshold)) {
- edge_flag_result |= LRT_EDGE_FLAG_CREASE;
+
+ if (rb->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]];
+ if (fe->flag & FREESTYLE_EDGE_MARK) {
+ edge_flag_result |= LRT_EDGE_FLAG_EDGE_MARK;
}
}
}
- if (rb->use_material && (ll->f->mat_nr != lr->f->mat_nr)) {
- edge_flag_result |= LRT_EDGE_FLAG_MATERIAL;
+
+ edge_nabr[i].flags = edge_flag_result;
+
+ if (edge_flag_result) {
+ /* 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 ?
+ lineart_edge_type_duplication_count(edge_flag_result) :
+ 1;
}
- if (use_freestyle_edge && rb->use_edge_marks) {
- FreestyleEdge *fe;
- fe = CustomData_bmesh_get(&bm_if_freestyle->edata, e->head.data, CD_FREESTYLE_EDGE);
- if (fe->flag & FREESTYLE_EDGE_MARK) {
- edge_flag_result |= LRT_EDGE_FLAG_EDGE_MARK;
- }
+}
+
+typedef struct LooseEdgeData {
+ int loose_count;
+ int loose_max;
+ MEdge **loose_array;
+ Mesh *me;
+} LooseEdgeData;
+
+static void lineart_loose_data_reallocate(LooseEdgeData *loose_data, int count)
+{
+ MEdge **new_arr = MEM_callocN(sizeof(MEdge *) * count, "loose edge array");
+ if (loose_data->loose_array) {
+ memcpy(new_arr, loose_data->loose_array, sizeof(MEdge *) * loose_data->loose_max);
+ MEM_freeN(loose_data->loose_array);
}
- return edge_flag_result;
+ loose_data->loose_max = count;
+ loose_data->loose_array = new_arr;
}
-static void lineart_add_edge_to_list(LineartRenderBuffer *rb, LineartEdge *e)
+static void lineart_join_loose_edge_arr(LooseEdgeData *loose_data, LooseEdgeData *to_be_joined)
{
- 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 (!to_be_joined->loose_array) {
+ return;
+ }
+ int new_count = loose_data->loose_count + to_be_joined->loose_count;
+ if (new_count >= loose_data->loose_max) {
+ lineart_loose_data_reallocate(loose_data, new_count);
+ }
+ memcpy(&loose_data->loose_array[loose_data->loose_count],
+ to_be_joined->loose_array,
+ sizeof(MEdge *) * to_be_joined->loose_count);
+ loose_data->loose_count += to_be_joined->loose_count;
+ MEM_freeN(to_be_joined->loose_array);
+}
+
+static void lineart_add_loose_edge(LooseEdgeData *loose_data, MEdge *e)
+{
+ if (loose_data->loose_count >= loose_data->loose_max) {
+ int min_amount = MAX2(100, loose_data->loose_count * 2);
+ lineart_loose_data_reallocate(loose_data, min_amount);
}
+ loose_data->loose_array[loose_data->loose_count] = e;
+ loose_data->loose_count++;
}
-static void lineart_add_edge_to_list_thread(LineartObjectInfo *obi, LineartEdge *e)
+static void lineart_identify_loose_edges(void *__restrict UNUSED(userdata),
+ const int i,
+ const TaskParallelTLS *__restrict tls)
{
+ LooseEdgeData *loose_data = (LooseEdgeData *)tls->userdata_chunk;
+ Mesh *me = loose_data->me;
-#define LRT_ASSIGN_EDGE(name) \
- lineart_prepend_edge_direct(&obi->name.first, e); \
- if (!obi->name.last) { \
- obi->name.last = e; \
+ if (me->medge[i].flag & ME_LOOSEEDGE) {
+ lineart_add_loose_edge(loose_data, &me->medge[i]);
}
- 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;
+}
+
+static void loose_data_sum_reduce(const void *__restrict UNUSED(userdata),
+ void *__restrict chunk_join,
+ void *__restrict chunk)
+{
+ LooseEdgeData *final = (LooseEdgeData *)chunk_join;
+ LooseEdgeData *loose_chunk = (LooseEdgeData *)chunk;
+ lineart_join_loose_edge_arr(final, loose_chunk);
+}
+
+static void lineart_add_edge_to_array(LineartPendingEdges *pe, LineartEdge *e)
+{
+ 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_array_thread(LineartObjectInfo *obi, LineartEdge *e)
+{
+ lineart_add_edge_to_array(&obi->pending_edges, e);
+}
+
+/* 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,
@@ -1702,298 +1780,416 @@ static void lineart_triangle_adjacent_assign(LineartTriangle *tri,
}
}
-static int lineart_edge_type_duplication_count(char eflag)
+typedef struct TriData {
+ LineartObjectInfo *ob_info;
+ const MLoopTri *mlooptri;
+ LineartVert *vert_arr;
+ LineartTriangle *tri_arr;
+ int lineart_triangle_size;
+ LineartTriangleAdjacent *tri_adj;
+} TriData;
+
+static void lineart_load_tri_task(void *__restrict userdata,
+ const int i,
+ const TaskParallelTLS *__restrict UNUSED(tls))
{
- int count = 0;
- /* See eLineartEdgeFlag for details. */
- for (int i = 0; i < 6; i++) {
- if (eflag & (1 << i)) {
- count++;
- }
- }
- return count;
+ TriData *tri_task_data = (TriData *)userdata;
+ Mesh *me = tri_task_data->ob_info->original_me;
+ LineartObjectInfo *ob_info = tri_task_data->ob_info;
+ const MLoopTri *mlooptri = &tri_task_data->mlooptri[i];
+ LineartVert *vert_arr = tri_task_data->vert_arr;
+ LineartTriangle *tri = tri_task_data->tri_arr;
+
+ tri = (LineartTriangle *)(((uchar *)tri) + tri_task_data->lineart_triangle_size * i);
+
+ int v1 = me->mloop[mlooptri->tri[0]].v;
+ int v2 = me->mloop[mlooptri->tri[1]].v;
+ int v3 = me->mloop[mlooptri->tri[2]].v;
+
+ tri->v[0] = &vert_arr[v1];
+ tri->v[1] = &vert_arr[v2];
+ tri->v[2] = &vert_arr[v3];
+
+ /* Material mask bits and occlusion effectiveness assignment. */
+ Material *mat = BKE_object_material_get(ob_info->original_ob,
+ me->mpoly[mlooptri->poly].mat_nr + 1);
+ tri->material_mask_bits |= ((mat && (mat->lineart.flags & LRT_MATERIAL_MASK_ENABLED)) ?
+ mat->lineart.material_mask_bits :
+ 0);
+ tri->mat_occlusion |= (mat ? mat->lineart.mat_occlusion : 1);
+ tri->flags |= (mat && (mat->blend_flag & MA_BL_CULL_BACKFACE)) ?
+ LRT_TRIANGLE_MAT_BACK_FACE_CULLING :
+ 0;
+
+ tri->intersection_mask = ob_info->override_intersection_mask;
+
+ double gn[3];
+ float no[3];
+ normal_tri_v3(no, me->mvert[v1].co, me->mvert[v2].co, me->mvert[v3].co);
+ copy_v3db_v3fl(gn, no);
+ mul_v3_mat3_m4v3_db(tri->gn, ob_info->normal, gn);
+ normalize_v3_db(tri->gn);
+
+ if (ob_info->usage == OBJECT_LRT_INTERSECTION_ONLY) {
+ tri->flags |= LRT_TRIANGLE_INTERSECTION_ONLY;
+ }
+ else if (ob_info->usage == OBJECT_LRT_NO_INTERSECTION ||
+ ob_info->usage == OBJECT_LRT_OCCLUSION_ONLY) {
+ tri->flags |= LRT_TRIANGLE_NO_INTERSECTION;
+ }
+
+ /* Re-use this field to refer to adjacent info, will be cleared after culling stage. */
+ tri->intersecting_verts = (void *)&tri_task_data->tri_adj[i];
}
-static void lineart_geometry_object_load(LineartObjectInfo *obi, LineartRenderBuffer *rb)
+typedef struct EdgeNeighborData {
+ LineartEdgeNeighbor *edge_nabr;
+ LineartAdjacentEdge *adj_e;
+ MLoopTri *mlooptri;
+ MLoop *mloop;
+} EdgeNeighborData;
+
+static void lineart_edge_neighbor_init_task(void *__restrict userdata,
+ const int i,
+ const TaskParallelTLS *__restrict UNUSED(tls))
{
- BMesh *bm;
- BMVert *v;
- BMFace *f;
- BMEdge *e;
- BMLoop *loop;
- LineartEdge *la_e;
- LineartEdgeSegment *la_s;
- LineartTriangle *tri;
- LineartTriangleAdjacent *orta;
- double(*model_view_proj)[4] = obi->model_view_proj, (*model_view)[4] = obi->model_view,
- (*normal)[4] = obi->normal;
- LineartElementLinkNode *eln;
- LineartVert *orv;
- LineartEdge *o_la_e;
- LineartEdgeSegment *o_la_s;
- LineartTriangle *ort;
- Object *orig_ob;
- bool can_find_freestyle_edge = false;
- bool can_find_freestyle_face = false;
- int i;
- float use_crease = 0;
+ EdgeNeighborData *en_data = (EdgeNeighborData *)userdata;
+ LineartAdjacentEdge *adj_e = &en_data->adj_e[i];
+ MLoopTri *looptri = &en_data->mlooptri[i / 3];
+ LineartEdgeNeighbor *edge_nabr = &en_data->edge_nabr[i];
+ MLoop *mloop = en_data->mloop;
+
+ adj_e->e = i;
+ 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);
+ }
+ edge_nabr->e = -1;
+
+ edge_nabr->v1 = adj_e->v1;
+ edge_nabr->v2 = adj_e->v2;
+ edge_nabr->flags = 0;
+}
- int usage = obi->usage;
+static LineartEdgeNeighbor *lineart_build_edge_neighbor(Mesh *me, int total_edges)
+{
+ /* Because the mesh is triangulated, so `me->totedge` should be reliable? */
+ LineartAdjacentEdge *adj_e = MEM_mallocN(sizeof(LineartAdjacentEdge) * total_edges,
+ "LineartAdjacentEdge arr");
+ LineartEdgeNeighbor *edge_nabr = MEM_mallocN(sizeof(LineartEdgeNeighbor) * total_edges,
+ "LineartEdgeNeighbor arr");
- if (obi->original_me->edit_mesh) {
- /* Do not use edit_mesh directly because we will modify it, so create a copy. */
- bm = BM_mesh_copy(obi->original_me->edit_mesh->bm);
- }
- else {
- const BMAllocTemplate allocsize = BMALLOC_TEMPLATE_FROM_ME(((Mesh *)(obi->original_me)));
- bm = BM_mesh_create(&allocsize,
- &((struct BMeshCreateParams){
- .use_toolflags = true,
- }));
- BM_mesh_bm_from_me(bm,
- obi->original_me,
- &((struct BMeshFromMeshParams){
- .calc_face_normal = true,
- .calc_vert_normal = true,
- }));
- }
+ MLoopTri *mlooptri = me->runtime.looptris.array;
- if (obi->free_use_mesh) {
- BKE_id_free(NULL, obi->original_me);
- }
+ TaskParallelSettings en_settings;
+ BLI_parallel_range_settings_defaults(&en_settings);
+ /* Set the minimum amount of edges a thread has to process. */
+ en_settings.min_iter_per_thread = 50000;
+
+ EdgeNeighborData en_data;
+ en_data.adj_e = adj_e;
+ en_data.edge_nabr = edge_nabr;
+ en_data.mlooptri = mlooptri;
+ en_data.mloop = me->mloop;
+
+ BLI_task_parallel_range(0, total_edges, &en_data, lineart_edge_neighbor_init_task, &en_settings);
- if (rb->remove_doubles) {
- BMEditMesh *em = BKE_editmesh_create(bm);
- BMOperator findop, weldop;
+ lineart_sort_adjacent_items(adj_e, total_edges);
- /* See bmesh_opdefines.c and bmesh_operators.c for op names and argument formatting. */
- BMO_op_initf(bm, &findop, BMO_FLAG_DEFAULTS, "find_doubles verts=%av dist=%f", 0.0001);
+ for (int i = 0; i < total_edges - 1; i++) {
+ if (adj_e[i].v1 == adj_e[i + 1].v1 && adj_e[i].v2 == adj_e[i + 1].v2) {
+ edge_nabr[adj_e[i].e].e = adj_e[i + 1].e;
+ edge_nabr[adj_e[i + 1].e].e = adj_e[i].e;
+ }
+ }
- BMO_op_exec(bm, &findop);
+ MEM_freeN(adj_e);
- /* Weld the vertices. */
- BMO_op_init(bm, &weldop, BMO_FLAG_DEFAULTS, "weld_verts");
- BMO_slot_copy(&findop, slots_out, "targetmap.out", &weldop, slots_in, "targetmap");
- BMO_op_exec(bm, &weldop);
+ return edge_nabr;
+}
- BMO_op_finish(bm, &findop);
- BMO_op_finish(bm, &weldop);
+static void lineart_geometry_object_load(LineartObjectInfo *ob_info, LineartRenderBuffer *re_buf)
+{
+ LineartElementLinkNode *elem_link_node;
+ LineartVert *la_v_arr;
+ LineartEdge *la_edge_arr;
+ LineartEdgeSegment *la_seg_arr;
+ LineartTriangle *la_tri_arr;
- MEM_freeN(em);
+ Mesh *me = ob_info->original_me;
+
+ if (!me->totedge) {
+ return;
}
- BM_mesh_elem_hflag_disable_all(bm, BM_FACE | BM_EDGE, BM_ELEM_TAG, false);
- BM_mesh_triangulate(
- bm, MOD_TRIANGULATE_QUAD_BEAUTY, MOD_TRIANGULATE_NGON_BEAUTY, 4, false, NULL, NULL, NULL);
- BM_mesh_normals_update(bm);
- BM_mesh_elem_table_ensure(bm, BM_VERT | BM_EDGE | BM_FACE);
- BM_mesh_elem_index_ensure(bm, BM_VERT | BM_EDGE | BM_FACE);
+ /* Triangulate. */
+ const MLoopTri *mlooptri = BKE_mesh_runtime_looptri_ensure(me);
+ const int tot_tri = BKE_mesh_runtime_looptri_len(me);
- if (CustomData_has_layer(&bm->edata, CD_FREESTYLE_EDGE)) {
- can_find_freestyle_edge = 1;
+ /* Check if we should look for custom data tags like Freestyle edges or faces. */
+ bool can_find_freestyle_edge = false;
+ int layer_index = CustomData_get_active_layer_index(&me->edata, CD_FREESTYLE_EDGE);
+ if (layer_index != -1) {
+ can_find_freestyle_edge = true;
}
- if (CustomData_has_layer(&bm->pdata, CD_FREESTYLE_FACE)) {
+
+ bool can_find_freestyle_face = false;
+ layer_index = CustomData_get_active_layer_index(&me->pdata, CD_FREESTYLE_FACE);
+ if (layer_index != -1) {
can_find_freestyle_face = true;
}
/* 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. */
- orv = lineart_mem_acquire_thread(&rb->render_data_pool, sizeof(LineartVert) * bm->totvert);
- ort = lineart_mem_acquire_thread(&rb->render_data_pool, bm->totface * rb->triangle_size);
+ la_v_arr = lineart_mem_acquire_thread(&re_buf->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);
- orig_ob = obi->original_ob;
+ Object *orig_ob = ob_info->original_ob;
- BLI_spin_lock(&rb->lock_task);
- eln = lineart_list_append_pointer_pool_sized_thread(
- &rb->vertex_buffer_pointers, &rb->render_data_pool, orv, sizeof(LineartElementLinkNode));
- BLI_spin_unlock(&rb->lock_task);
+ 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);
- eln->element_count = bm->totvert;
- eln->object_ref = orig_ob;
- obi->v_eln = eln;
+ elem_link_node->element_count = me->totvert;
+ elem_link_node->object_ref = orig_ob;
+ ob_info->v_eln = elem_link_node;
bool use_auto_smooth = false;
+ float crease_angle = 0;
if (orig_ob->lineart.flags & OBJECT_LRT_OWN_CREASE) {
- use_crease = cosf(M_PI - orig_ob->lineart.crease_threshold);
+ crease_angle = cosf(M_PI - orig_ob->lineart.crease_threshold);
}
- else if (obi->original_me->flag & ME_AUTOSMOOTH) {
- use_crease = cosf(obi->original_me->smoothresh);
+ else if (ob_info->original_me->flag & ME_AUTOSMOOTH) {
+ crease_angle = cosf(ob_info->original_me->smoothresh);
use_auto_smooth = true;
}
else {
- use_crease = rb->crease_threshold;
+ crease_angle = re_buf->crease_threshold;
}
/* FIXME(Yiming): Hack for getting clean 3D text, the seam that extruded text object creates
* erroneous detection on creases. Future configuration should allow options. */
if (orig_ob->type == OB_FONT) {
- eln->flags |= LRT_ELEMENT_BORDER_ONLY;
+ elem_link_node->flags |= LRT_ELEMENT_BORDER_ONLY;
}
- BLI_spin_lock(&rb->lock_task);
- eln = lineart_list_append_pointer_pool_sized_thread(
- &rb->triangle_buffer_pointers, &rb->render_data_pool, ort, sizeof(LineartElementLinkNode));
- BLI_spin_unlock(&rb->lock_task);
+ 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);
+
+ int usage = ob_info->usage;
- eln->element_count = bm->totface;
- eln->object_ref = orig_ob;
- eln->flags |= (usage == OBJECT_LRT_NO_INTERSECTION ? LRT_ELEMENT_NO_INTERSECTION : 0);
+ elem_link_node->element_count = tot_tri;
+ elem_link_node->object_ref = orig_ob;
+ elem_link_node->flags |= (usage == OBJECT_LRT_NO_INTERSECTION ? LRT_ELEMENT_NO_INTERSECTION : 0);
/* Note this memory is not from pool, will be deleted after culling. */
- orta = MEM_callocN(sizeof(LineartTriangleAdjacent) * bm->totface, "LineartTriangleAdjacent");
+ LineartTriangleAdjacent *tri_adj = MEM_callocN(sizeof(LineartTriangleAdjacent) * tot_tri,
+ "LineartTriangleAdjacent");
/* Link is minimal so we use pool anyway. */
- BLI_spin_lock(&rb->lock_task);
+ BLI_spin_lock(&re_buf->lock_task);
lineart_list_append_pointer_pool_thread(
- &rb->triangle_adjacent_pointers, &rb->render_data_pool, orta);
- BLI_spin_unlock(&rb->lock_task);
-
- for (i = 0; i < bm->totvert; i++) {
- v = BM_vert_at_index(bm, i);
- lineart_vert_transform(v, i, orv, model_view, model_view_proj);
- orv[i].index = 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 = bm->totvert;
-
- tri = ort;
- for (i = 0; i < bm->totface; i++) {
- f = BM_face_at_index(bm, i);
-
- loop = f->l_first;
- tri->v[0] = &orv[BM_elem_index_get(loop->v)];
- loop = loop->next;
- tri->v[1] = &orv[BM_elem_index_get(loop->v)];
- loop = loop->next;
- tri->v[2] = &orv[BM_elem_index_get(loop->v)];
-
- /* Material mask bits and occlusion effectiveness assignment. */
- Material *mat = BKE_object_material_get(orig_ob, f->mat_nr + 1);
- tri->material_mask_bits |= ((mat && (mat->lineart.flags & LRT_MATERIAL_MASK_ENABLED)) ?
- mat->lineart.material_mask_bits :
- 0);
- tri->mat_occlusion |= (mat ? mat->lineart.mat_occlusion : 1);
- tri->flags |= (mat && (mat->blend_flag & MA_BL_CULL_BACKFACE)) ?
- LRT_TRIANGLE_MAT_BACK_FACE_CULLING :
- 0;
-
- tri->intersection_mask = obi->override_intersection_mask;
-
- double gn[3];
- copy_v3db_v3fl(gn, f->no);
- mul_v3_mat3_m4v3_db(tri->gn, normal, gn);
- normalize_v3_db(tri->gn);
-
- if (usage == OBJECT_LRT_INTERSECTION_ONLY) {
- tri->flags |= LRT_TRIANGLE_INTERSECTION_ONLY;
- }
- else if (ELEM(usage, OBJECT_LRT_NO_INTERSECTION, OBJECT_LRT_OCCLUSION_ONLY)) {
- tri->flags |= LRT_TRIANGLE_NO_INTERSECTION;
- }
-
- /* Re-use this field to refer to adjacent info, will be cleared after culling stage. */
- tri->intersecting_verts = (void *)&orta[i];
-
- tri = (LineartTriangle *)(((uchar *)tri) + rb->triangle_size);
- }
-
- /* Use BM_ELEM_TAG in f->head.hflag to store needed faces in the first iteration. */
-
- int allocate_la_e = 0;
- for (i = 0; i < bm->totedge; i++) {
- e = BM_edge_at_index(bm, i);
-
- /* Because e->head.hflag is char, so line type flags should not exceed positive 7 bits. */
- uint16_t eflag = lineart_identify_feature_line(rb,
- e,
- ort,
- orv,
- use_crease,
- use_auto_smooth,
- can_find_freestyle_edge,
- can_find_freestyle_face,
- bm);
- if (eflag) {
- /* Only allocate for feature lines (instead of all lines) to save memory.
- * If allow duplicated edges, one edge gets added multiple times if it has multiple types.
- */
- allocate_la_e += rb->allow_duplicated_types ? lineart_edge_type_duplication_count(eflag) : 1;
+ &re_buf->triangle_adjacent_pointers, &re_buf->render_data_pool, tri_adj);
+ BLI_spin_unlock(&re_buf->lock_task);
+
+ /* Convert all vertices to lineart verts. */
+ TaskParallelSettings vert_settings;
+ BLI_parallel_range_settings_defaults(&vert_settings);
+ /* Set the minimum amount of verts a thread has to process. */
+ vert_settings.min_iter_per_thread = 4000;
+
+ VertData vert_data;
+ vert_data.mvert = me->mvert;
+ vert_data.v_arr = la_v_arr;
+ vert_data.model_view = ob_info->model_view;
+ vert_data.model_view_proj = ob_info->model_view_proj;
+
+ BLI_task_parallel_range(
+ 0, me->totvert, &vert_data, lineart_mvert_transform_task, &vert_settings);
+
+ /* Convert all mesh triangles into lineart triangles.
+ * Also create an edge map to get connectivity between edges and triangles. */
+ TaskParallelSettings tri_settings;
+ BLI_parallel_range_settings_defaults(&tri_settings);
+ /* Set the minimum amount of triangles a thread has to process. */
+ tri_settings.min_iter_per_thread = 4000;
+
+ TriData tri_data;
+ tri_data.ob_info = ob_info;
+ 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.tri_adj = tri_adj;
+
+ unsigned int total_edges = tot_tri * 3;
+
+ BLI_task_parallel_range(0, tot_tri, &tri_data, lineart_load_tri_task, &tri_settings);
+
+ /* Check for contour lines in the mesh.
+ * IE check if the triangle edges lies in area where the triangles go from front facing to back
+ * facing.
+ */
+ EdgeFeatReduceData edge_reduce = {0};
+ TaskParallelSettings edge_feat_settings;
+ BLI_parallel_range_settings_defaults(&edge_feat_settings);
+ /* Set the minimum amount of edges a thread has to process. */
+ edge_feat_settings.min_iter_per_thread = 4000;
+ edge_feat_settings.userdata_chunk = &edge_reduce;
+ edge_feat_settings.userdata_chunk_size = sizeof(EdgeFeatReduceData);
+ edge_feat_settings.func_reduce = feat_data_sum_reduce;
+
+ EdgeFeatData edge_feat_data = {0};
+ edge_feat_data.rb = re_buf;
+ edge_feat_data.me = me;
+ edge_feat_data.mlooptri = mlooptri;
+ edge_feat_data.edge_nabr = lineart_build_edge_neighbor(me, total_edges);
+ edge_feat_data.tri_array = la_tri_arr;
+ edge_feat_data.v_array = la_v_arr;
+ edge_feat_data.crease_threshold = crease_angle;
+ edge_feat_data.use_auto_smooth = use_auto_smooth;
+ edge_feat_data.use_freestyle_face = can_find_freestyle_face;
+ edge_feat_data.use_freestyle_edge = can_find_freestyle_edge;
+ if (edge_feat_data.use_freestyle_face) {
+ edge_feat_data.freestyle_face_index = CustomData_get_layer_index(&me->pdata,
+ CD_FREESTYLE_FACE);
+ }
+ if (edge_feat_data.use_freestyle_edge) {
+ edge_feat_data.freestyle_edge_index = CustomData_get_layer_index(&me->edata,
+ CD_FREESTYLE_EDGE);
+ }
+
+ BLI_task_parallel_range(0,
+ total_edges,
+ &edge_feat_data,
+ lineart_identify_mlooptri_feature_edges,
+ &edge_feat_settings);
+
+ LooseEdgeData loose_data = {0};
+ if (re_buf->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;
+ BLI_parallel_range_settings_defaults(&edge_loose_settings);
+ edge_loose_settings.min_iter_per_thread = 4000;
+ edge_loose_settings.func_reduce = loose_data_sum_reduce;
+ edge_loose_settings.userdata_chunk = &loose_data;
+ edge_loose_settings.userdata_chunk_size = sizeof(LooseEdgeData);
+ loose_data.me = me;
+ BLI_task_parallel_range(
+ 0, me->totedge, &loose_data, lineart_identify_loose_edges, &edge_loose_settings);
+ }
+
+ int allocate_la_e = edge_reduce.feat_edges + loose_data.loose_count;
+
+ la_edge_arr = lineart_mem_acquire_thread(&re_buf->render_data_pool,
+ sizeof(LineartEdge) * allocate_la_e);
+ la_seg_arr = lineart_mem_acquire_thread(&re_buf->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);
+ elem_link_node->element_count = allocate_la_e;
+ elem_link_node->object_ref = orig_ob;
+
+ // Start of the edge/seg arr
+ LineartEdge *la_edge;
+ LineartEdgeSegment *la_seg;
+ la_edge = la_edge_arr;
+ la_seg = la_seg_arr;
+
+ for (int i = 0; i < total_edges; i++) {
+ LineartEdgeNeighbor *edge_nabr = &edge_feat_data.edge_nabr[i];
+
+ if (i < edge_nabr->e) {
+ continue;
}
- /* Here we just use bm's flag for when loading actual lines, then we don't need to call
- * lineart_identify_feature_line() again, e->head.hflag deleted after loading anyway. Always
- * set the flag, so hflag stays 0 for lines that are not feature lines. */
- e->head.hflag = eflag;
- }
-
- o_la_e = lineart_mem_acquire_thread(&rb->render_data_pool, sizeof(LineartEdge) * allocate_la_e);
- o_la_s = lineart_mem_acquire_thread(&rb->render_data_pool,
- sizeof(LineartEdgeSegment) * allocate_la_e);
- BLI_spin_lock(&rb->lock_task);
- eln = lineart_list_append_pointer_pool_sized_thread(
- &rb->line_buffer_pointers, &rb->render_data_pool, o_la_e, sizeof(LineartElementLinkNode));
- BLI_spin_unlock(&rb->lock_task);
- eln->element_count = allocate_la_e;
- eln->object_ref = orig_ob;
-
- la_e = o_la_e;
- la_s = o_la_s;
- for (i = 0; i < bm->totedge; i++) {
- e = BM_edge_at_index(bm, i);
/* Not a feature line, so we skip. */
- if (!e->head.hflag) {
+ if (edge_nabr->flags == 0) {
continue;
}
- bool edge_added = false;
+ LineartEdge *edge_added = NULL;
/* See eLineartEdgeFlag for details. */
- for (int flag_bit = 0; flag_bit < 6; flag_bit++) {
+ for (int flag_bit = 0; flag_bit < LRT_EDGE_FLAG_TYPE_MAX_BITS; flag_bit++) {
char use_type = 1 << flag_bit;
- if (!(use_type & e->head.hflag)) {
+ if (!(use_type & edge_nabr->flags)) {
continue;
}
- la_e->v1 = &orv[BM_elem_index_get(e->v1)];
- la_e->v2 = &orv[BM_elem_index_get(e->v2)];
- la_e->v1_obindex = la_e->v1->index;
- la_e->v2_obindex = la_e->v2->index;
- if (e->l) {
- int findex = BM_elem_index_get(e->l->f);
- la_e->t1 = lineart_triangle_from_index(rb, ort, findex);
+ la_edge->v1 = &la_v_arr[edge_nabr->v1];
+ la_edge->v2 = &la_v_arr[edge_nabr->v2];
+ int findex = i / 3;
+ la_edge->t1 = lineart_triangle_from_index(re_buf, 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);
if (!edge_added) {
- lineart_triangle_adjacent_assign(la_e->t1, &orta[findex], la_e);
- }
- if (e->l->radial_next && e->l->radial_next != e->l) {
- findex = BM_elem_index_get(e->l->radial_next->f);
- la_e->t2 = lineart_triangle_from_index(rb, ort, findex);
- if (!edge_added) {
- lineart_triangle_adjacent_assign(la_e->t2, &orta[findex], la_e);
- }
+ lineart_triangle_adjacent_assign(la_edge->t2, &tri_adj[findex], la_edge);
}
}
- la_e->flags = use_type;
- la_e->object_ref = orig_ob;
- BLI_addtail(&la_e->segments, la_s);
- if (ELEM(usage, OBJECT_LRT_INHERIT, OBJECT_LRT_INCLUDE, OBJECT_LRT_NO_INTERSECTION)) {
- lineart_add_edge_to_list_thread(obi, la_e);
+ la_edge->flags = use_type;
+ 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_array_thread(ob_info, la_edge);
}
- edge_added = true;
+ if (edge_added) {
+ edge_added->flags |= LRT_EDGE_FLAG_NEXT_IS_DUPLICATION;
+ }
+
+ edge_added = la_edge;
- la_e++;
- la_s++;
+ la_edge++;
+ la_seg++;
- if (!rb->allow_duplicated_types) {
+ if (!re_buf->allow_duplicated_types) {
break;
}
}
}
- /* always free bm as it's a copy from before threading */
- BM_mesh_free(bm);
+ if (loose_data.loose_array) {
+ 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->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_array_thread(ob_info, la_edge);
+ }
+ la_edge++;
+ la_seg++;
+ }
+ MEM_freeN(loose_data.loose_array);
+ }
+
+ MEM_freeN(edge_feat_data.edge_nabr);
+
+ if (ob_info->free_use_mesh) {
+ BKE_id_free(NULL, me);
+ }
}
static void lineart_object_load_worker(TaskPool *__restrict UNUSED(pool),
@@ -2001,6 +2197,9 @@ static void lineart_object_load_worker(TaskPool *__restrict UNUSED(pool),
{
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);
+ }
}
}
@@ -2085,6 +2284,7 @@ static void lineart_geometry_load_assign_thread(LineartObjectLoadTaskInfo *olti_
use_olti = &olti_list[i];
}
}
+
use_olti->total_faces += this_face_count;
obi->next = use_olti->pending;
use_olti->pending = obi;
@@ -2093,18 +2293,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];
@@ -2130,6 +2333,69 @@ static bool lineart_geometry_check_visible(double (*model_view_proj)[4],
return true;
}
+static void lineart_object_load_single_instance(LineartRenderBuffer *rb,
+ 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(&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) {
+ 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, rb->view_projection, use_mat);
+ mul_m4db_m4db_m4fl_uniq(obi->model_view, rb->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, rb->shift_x, rb->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,
@@ -2178,14 +2444,6 @@ static void lineart_main_load_geometries(
BLI_listbase_clear(&rb->triangle_buffer_pointers);
BLI_listbase_clear(&rb->vertex_buffer_pointers);
- int flags = DEG_ITER_OBJECT_FLAG_LINKED_DIRECTLY | DEG_ITER_OBJECT_FLAG_LINKED_VIA_SET |
- DEG_ITER_OBJECT_FLAG_VISIBLE;
-
- /* Instance duplicated & particles. */
- if (allow_duplicates) {
- 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.
@@ -2193,75 +2451,43 @@ static void lineart_main_load_geometries(
LineartObjectLoadTaskInfo *olti = lineart_mem_acquire(
&rb->render_data_pool, sizeof(LineartObjectLoadTaskInfo) * thread_count);
- bool is_render = DEG_get_mode(depsgraph) == DAG_EVAL_RENDER;
+ eEvaluationMode eval_mode = DEG_get_mode(depsgraph);
+ bool is_render = eval_mode == DAG_EVAL_RENDER;
- 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;
+ FOREACH_SCENE_OBJECT_BEGIN (scene, ob) {
+ Object *eval_ob = DEG_get_evaluated_object(depsgraph, ob);
- if (obi->usage == OBJECT_LRT_EXCLUDE) {
+ if (!eval_ob) {
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);
-
- if (!ELEM(use_ob->type, OB_MESH, OB_MBALL, OB_CURVES_LEGACY, OB_SURF, OB_FONT)) {
- 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);
+ if (BKE_object_visibility(eval_ob, eval_mode) & OB_VISIBLE_SELF) {
+ lineart_object_load_single_instance(
+ rb, depsgraph, scene, eval_ob, eval_ob, eval_ob->obmat, is_render, olti, thread_count);
}
- 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;
+ if (allow_duplicates) {
+ ListBase *dupli = object_duplilist(depsgraph, scene, eval_ob);
+ LISTBASE_FOREACH (DupliObject *, dob, dupli) {
+ if (BKE_object_visibility(eval_ob, eval_mode) &
+ (OB_VISIBLE_PARTICLES | OB_VISIBLE_INSTANCES)) {
+ Object *ob_ref = (dob->type & OB_DUPLIPARTS) ? eval_ob : dob->ob;
+ lineart_object_load_single_instance(
+ rb, depsgraph, scene, dob->ob, ob_ref, dob->mat, is_render, olti, thread_count);
+ }
}
- 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) {
- continue;
- }
-
- if (ob->type != OB_MESH) {
- obi->free_use_mesh = true;
+ free_object_duplilist(dupli);
}
-
- /* 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;
+ FOREACH_SCENE_OBJECT_END;
TaskPool *tp = BLI_task_pool_create(NULL, TASK_PRIORITY_HIGH);
+ if (G.debug_value == 4000) {
+ printf("thread count: %d\n", thread_count);
+ }
for (int i = 0; i < thread_count; i++) {
olti[i].rb = rb;
- olti[i].dg = depsgraph;
+ olti[i].thread_id = i;
BLI_task_pool_push(tp, (TaskRunFunction)lineart_object_load_worker, &olti[i], 0, NULL);
}
BLI_task_pool_work_and_wait(tp);
@@ -2271,6 +2497,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(&rb->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) {
@@ -2281,8 +2518,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(&rb->pending_edges, obi);
}
}
@@ -2987,7 +3229,7 @@ static LineartEdge *lineart_triangle_intersect(LineartRenderBuffer *rb,
result->flags = LRT_EDGE_FLAG_INTERSECTION;
result->intersection_mask = (tri->intersection_mask | testing->intersection_mask);
- lineart_prepend_edge_direct(&rb->intersection.first, result);
+ lineart_add_edge_to_array(&rb->pending_edges, result);
return result;
}
@@ -3003,7 +3245,7 @@ static void lineart_triangle_intersect_in_bounding_area(LineartRenderBuffer *rb,
double *G0 = tri->v[0]->gloc, *G1 = tri->v[1]->gloc, *G2 = tri->v[2]->gloc;
- /* If this is not the smallest subdivision bounding area. */
+ /* 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]);
@@ -3075,13 +3317,6 @@ static void lineart_destroy_render_data(LineartRenderBuffer *rb)
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(&rb->chains);
BLI_listbase_clear(&rb->wasted_cuts);
@@ -3093,6 +3328,10 @@ static void lineart_destroy_render_data(LineartRenderBuffer *rb)
BLI_spin_end(&rb->lock_cuts);
BLI_spin_end(&rb->render_data_pool.lock_mem);
+ if (rb->pending_edges.array) {
+ MEM_freeN(rb->pending_edges.array);
+ }
+
lineart_mem_destroy(&rb->render_data_pool);
}
@@ -3187,7 +3426,6 @@ static LineartRenderBuffer *lineart_create_render_buffer(Scene *scene,
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->remove_doubles = (lmd->calculation_flags & LRT_REMOVE_DOUBLES) != 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;
diff --git a/source/blender/gpencil_modifiers/intern/lineart/lineart_intern.h b/source/blender/gpencil_modifiers/intern/lineart/lineart_intern.h
index 508061d5d98..1a197c8b4b7 100644
--- a/source/blender/gpencil_modifiers/intern/lineart/lineart_intern.h
+++ b/source/blender/gpencil_modifiers/intern/lineart/lineart_intern.h
@@ -67,49 +67,11 @@ int lineart_count_intersection_segment_count(struct LineartRenderBuffer *rb);
void lineart_count_and_print_render_buffer_memory(struct LineartRenderBuffer *rb);
#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 < rb->pending_edges.next; i++) { \
+ e = rb->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 \
@@ -121,3 +83,13 @@ void lineart_count_and_print_render_buffer_memory(struct LineartRenderBuffer *rb
/* Initial bounding area row/column count, setting 4 is the simplest way algorithm could function
* efficiently. */
#define LRT_BA_ROWS 4
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+void lineart_sort_adjacent_items(LineartAdjacentEdge *ai, int length);
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/source/blender/gpu/CMakeLists.txt b/source/blender/gpu/CMakeLists.txt
index 6d84f71d92f..e78c86ae196 100644
--- a/source/blender/gpu/CMakeLists.txt
+++ b/source/blender/gpu/CMakeLists.txt
@@ -85,6 +85,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 +190,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 +199,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 +304,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 +324,7 @@ 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
shaders/material/gpu_shader_material_combine_xyz.glsl
@@ -324,7 +332,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
@@ -333,7 +340,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
@@ -342,9 +348,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
@@ -357,8 +360,8 @@ 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
shaders/material/gpu_shader_material_separate_rgb.glsl
shaders/material/gpu_shader_material_separate_xyz.glsl
@@ -381,10 +384,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
@@ -441,6 +444,7 @@ 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
@@ -494,6 +498,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_capabilities.h b/source/blender/gpu/GPU_capabilities.h
index 061b850619f..7fe467de402 100644
--- a/source/blender/gpu/GPU_capabilities.h
+++ b/source/blender/gpu/GPU_capabilities.h
@@ -35,7 +35,7 @@ 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);
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_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..b045d908438 100644
--- a/source/blender/gpu/GPU_texture.h
+++ b/source/blender/gpu/GPU_texture.h
@@ -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_capabilities.cc b/source/blender/gpu/intern/gpu_capabilities.cc
index 4ec215c2d3b..eb69a1d2635 100644
--- a/source/blender/gpu/intern/gpu_capabilities.cc
+++ b/source/blender/gpu/intern/gpu_capabilities.cc
@@ -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);
}
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_immediate.cc b/source/blender/gpu/intern/gpu_immediate.cc
index 7dc1c739750..69467e5b28a 100644
--- a/source/blender/gpu/intern/gpu_immediate.cc
+++ b/source/blender/gpu/intern/gpu_immediate.cc
@@ -490,7 +490,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_material.c b/source/blender/gpu/intern/gpu_material.c
index 7ec6ee5183a..23028f58059 100644
--- a/source/blender/gpu/intern/gpu_material.c
+++ b/source/blender/gpu/intern/gpu_material.c
@@ -626,7 +626,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;
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_shader_builtin.c b/source/blender/gpu/intern/gpu_shader_builtin.c
index 1100272b712..b92fae4a89b 100644
--- a/source/blender/gpu/intern/gpu_shader_builtin.c
+++ b/source/blender/gpu/intern/gpu_shader_builtin.c
@@ -150,6 +150,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",
diff --git a/source/blender/gpu/intern/gpu_shader_dependency.cc b/source/blender/gpu/intern/gpu_shader_dependency.cc
index f69c56b5f3f..842914f5bed 100644
--- a/source/blender/gpu/intern/gpu_shader_dependency.cc
+++ b/source/blender/gpu/intern/gpu_shader_dependency.cc
@@ -593,7 +593,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");
}
};
@@ -668,14 +670,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_storage_buffer.cc b/source/blender/gpu/intern/gpu_storage_buffer.cc
index 806acad90fe..68020ec66f4 100644
--- a/source/blender/gpu/intern/gpu_storage_buffer.cc
+++ b/source/blender/gpu/intern/gpu_storage_buffer.cc
@@ -19,6 +19,7 @@
#include "GPU_storage_buffer.h"
#include "gpu_storage_buffer_private.hh"
+#include "gpu_vertex_buffer_private.hh"
/* -------------------------------------------------------------------- */
/** \name Creation & Deletion
@@ -103,4 +104,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_vertex_buffer.cc b/source/blender/gpu/intern/gpu_vertex_buffer.cc
index 2974547c858..f47970d48d1 100644
--- a/source/blender/gpu/intern/gpu_vertex_buffer.cc
+++ b/source/blender/gpu/intern/gpu_vertex_buffer.cc
@@ -199,7 +199,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 +208,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 +235,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 +256,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 +328,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/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_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..5f52bc55f72
--- /dev/null
+++ b/source/blender/gpu/metal/mtl_state.mm
@@ -0,0 +1,675 @@
+/** \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. */
+/*void MTLStateManager::issue_barrier(eGPUBarrier barrier_bits,
+ eGPUStageBarrierBits before_stages,
+ eGPUStageBarrierBits after_stages) */
+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 e013bb5321a..b820256ec36 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;
@@ -242,7 +219,7 @@ class MTLTexture : public Texture {
id<MTLBuffer> vert_buffer_mtl_;
int vert_buffer_offset_;
- /* Core parameters and subresources. */
+ /* Core parameters and sub-resources. */
eGPUTextureUsage gpu_image_usage_flags_;
/* Whether the texture's properties or state has changed (e.g. mipmap range), and re-baking of
diff --git a/source/blender/gpu/metal/mtl_texture.mm b/source/blender/gpu/metal/mtl_texture.mm
index df3efdd12e7..ca19d1f9e4b 100644
--- a/source/blender/gpu/metal/mtl_texture.mm
+++ b/source/blender/gpu/metal/mtl_texture.mm
@@ -563,7 +563,7 @@ void gpu::MTLTexture::update_sub(
return;
}
- /* Check Format writeability. */
+ /* Check Format write-ability. */
if (mtl_format_get_writeable_view_format(destination_format) == MTLPixelFormatInvalid) {
MTL_LOG_ERROR(
"[Error]: Updating texture -- destination MTLPixelFormat '%d' does not support write "
@@ -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.
@@ -1769,8 +1769,8 @@ void gpu::MTLTexture::ensure_baked()
/* CUBE TEXTURES */
case GPU_TEXTURE_CUBE:
case GPU_TEXTURE_CUBE_ARRAY: {
- /* Note: For a cubemap 'Texture::d_' refers to total number of faces, not just array slices
- */
+ /* NOTE: For a cube-map 'Texture::d_' refers to total number of faces,
+ * not just array slices. */
BLI_assert(this->w_ > 0 && this->h_ > 0);
this->texture_descriptor_ = [[MTLTextureDescriptor alloc] init];
this->texture_descriptor_.pixelFormat = mtl_format;
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_shader.cc b/source/blender/gpu/opengl/gl_shader.cc
index 957bc8b24be..5a28b8b7318 100644
--- a/source/blender/gpu/opengl/gl_shader.cc
+++ b/source/blender/gpu/opengl/gl_shader.cc
@@ -876,7 +876,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 +889,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_storage_buffer.cc b/source/blender/gpu/opengl/gl_storage_buffer.cc
index 109bb65fcb7..b30674fe5fa 100644
--- a/source/blender/gpu/opengl/gl_storage_buffer.cc
+++ b/source/blender/gpu/opengl/gl_storage_buffer.cc
@@ -144,6 +144,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.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_vertex_array.cc b/source/blender/gpu/opengl/gl_vertex_array.cc
index 04f60f10d41..cfcf77fe705 100644
--- a/source/blender/gpu/opengl/gl_vertex_array.cc
+++ b/source/blender/gpu/opengl/gl_vertex_array.cc
@@ -39,8 +39,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 a5c3a990d90..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
@@ -90,6 +90,56 @@ void hsv_to_rgb(vec4 hsv, out vec4 outcol)
outcol = vec4(rgb, hsv.w);
}
+void rgb_to_hsl(vec4 rgb, out vec4 outcol)
+{
+ float cmax, cmin, h, s, l;
+
+ cmax = max(rgb[0], max(rgb[1], rgb[2]));
+ cmin = min(rgb[0], min(rgb[1], rgb[2]));
+ l = min(1.0, (cmax + cmin) / 2.0);
+
+ if (cmax == cmin) {
+ h = s = 0.0; /* achromatic */
+ }
+ else {
+ float cdelta = cmax - cmin;
+ s = l > 0.5 ? cdelta / (2.0 - cmax - cmin) : cdelta / (cmax + cmin);
+ if (cmax == rgb[0]) {
+ h = (rgb[1] - rgb[2]) / cdelta + (rgb[1] < rgb[2] ? 6.0 : 0.0);
+ }
+ else if (cmax == rgb[1]) {
+ h = (rgb[2] - rgb[0]) / cdelta + 2.0;
+ }
+ else {
+ h = (rgb[0] - rgb[1]) / cdelta + 4.0;
+ }
+ }
+ h /= 6.0;
+
+ outcol = vec4(h, s, l, rgb.w);
+}
+
+void hsl_to_rgb(vec4 hsl, out vec4 outcol)
+{
+ float nr, ng, nb, chroma, h, s, l;
+
+ h = hsl[0];
+ s = hsl[1];
+ l = hsl[2];
+
+ nr = abs(h * 6.0 - 3.0) - 1.0;
+ ng = 2.0 - abs(h * 6.0 - 2.0);
+ nb = 2.0 - abs(h * 6.0 - 4.0);
+
+ nr = clamp(nr, 0.0, 1.0);
+ nb = clamp(nb, 0.0, 1.0);
+ ng = clamp(ng, 0.0, 1.0);
+
+ chroma = (1.0 - abs(2.0 * l - 1.0)) * s;
+
+ outcol = vec4((nr - 0.5) * chroma + l, (ng - 0.5) * chroma + l, (nb - 0.5) * chroma + l, hsl.w);
+}
+
void color_alpha_clear(vec4 color, out vec4 result)
{
result = vec4(color.rgb, 1.0);
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_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/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_uniform_color_info.hh b/source/blender/gpu/shaders/infos/gpu_shader_3D_uniform_color_info.hh
index 369fe3ac293..ae7edeb16e2 100644
--- a/source/blender/gpu/shaders/infos/gpu_shader_3D_uniform_color_info.hh
+++ b/source/blender/gpu/shaders/infos/gpu_shader_3D_uniform_color_info.hh
@@ -28,7 +28,7 @@ GPU_SHADER_CREATE_INFO(gpu_shader_3D_clipped_uniform_color)
.fragment_out(0, Type::VEC4, "fragColor")
.push_constant(Type::MAT4, "ModelViewProjectionMatrix")
.push_constant(Type::VEC4, "color")
- /* TODO(fclem): Put thoses two to one UBO. */
+ /* TODO(@fclem): Put those two to one UBO. */
.push_constant(Type::MAT4, "ModelMatrix")
.push_constant(Type::VEC4, "ClipPlane")
.vertex_source("gpu_shader_3D_clipped_uniform_color_vert.glsl")
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
new file mode 100644
index 00000000000..e68d0d98484
--- /dev/null
+++ b/source/blender/gpu/shaders/material/gpu_shader_material_combine_color.glsl
@@ -0,0 +1,16 @@
+#pragma BLENDER_REQUIRE(gpu_shader_common_color_utils.glsl)
+
+void combine_color_rgb(float r, float g, float b, out vec4 col)
+{
+ col = vec4(r, g, b, 1.0);
+}
+
+void combine_color_hsv(float h, float s, float v, out vec4 col)
+{
+ hsv_to_rgb(vec4(h, s, v, 1.0), col);
+}
+
+void combine_color_hsl(float h, float s, float l, out vec4 col)
+{
+ hsl_to_rgb(vec4(h, s, l, 1.0), 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_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_hair_info.glsl b/source/blender/gpu/shaders/material/gpu_shader_material_hair_info.glsl
index 2d5114c3bad..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,4 +1,4 @@
-#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,
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_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_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_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
new file mode 100644
index 00000000000..2dd51029cef
--- /dev/null
+++ b/source/blender/gpu/shaders/material/gpu_shader_material_separate_color.glsl
@@ -0,0 +1,28 @@
+#pragma BLENDER_REQUIRE(gpu_shader_common_color_utils.glsl)
+
+void separate_color_rgb(vec4 col, out float r, out float g, out float b)
+{
+ r = col.r;
+ g = col.g;
+ b = col.b;
+}
+
+void separate_color_hsv(vec4 col, out float r, out float g, out float b)
+{
+ vec4 hsv;
+
+ rgb_to_hsv(col, hsv);
+ r = hsv[0];
+ g = hsv[1];
+ b = hsv[2];
+}
+
+void separate_color_hsl(vec4 col, out float r, out float g, out float b)
+{
+ vec4 hsl;
+
+ rgb_to_hsl(col, hsl);
+ r = hsl[0];
+ g = hsl[1];
+ b = hsl[2];
+}
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/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/IMB_imbuf.h b/source/blender/imbuf/IMB_imbuf.h
index 0390df06052..20c414bb1ad 100644
--- a/source/blender/imbuf/IMB_imbuf.h
+++ b/source/blender/imbuf/IMB_imbuf.h
@@ -109,6 +109,14 @@ struct ImBuf *IMB_loadiffname(const char *filepath, int flags, char colorspace[I
/**
*
+ * \attention Defined in readimage.c
+ */
+struct ImBuf *IMB_thumb_load_image(const char *filepath,
+ const size_t max_thumb_size,
+ char colorspace[IM_MAX_SPACE]);
+
+/**
+ *
* \attention Defined in allocimbuf.c
*/
void IMB_freeImBuf(struct ImBuf *ibuf);
@@ -522,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);
/**
*
@@ -546,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);
@@ -935,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..16cf0e2125e 100644
--- a/source/blender/imbuf/IMB_imbuf_types.h
+++ b/source/blender/imbuf/IMB_imbuf_types.h
@@ -47,7 +47,7 @@ typedef struct DDSData {
* 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. */
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_filetype.h b/source/blender/imbuf/intern/IMB_filetype.h
index 31f8b3a9505..67d1aefeacb 100644
--- a/source/blender/imbuf/intern/IMB_filetype.h
+++ b/source/blender/imbuf/intern/IMB_filetype.h
@@ -36,6 +36,17 @@ typedef struct ImFileType {
char colorspace[IM_MAX_SPACE]);
/** Load an image from a file. */
struct ImBuf *(*load_filepath)(const char *filepath, int flags, char colorspace[IM_MAX_SPACE]);
+ /**
+ * Load/Create a thumbnail image from a filepath. `max_thumb_size` is maximum size of either
+ * dimension, so can return less on either or both. Should, if possible and performant, return
+ * 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,
+ char colorspace[IM_MAX_SPACE],
+ size_t *r_width,
+ size_t *r_height);
/** Save to a file (or memory if #IB_mem is set in `flags` and the format supports it). */
bool (*save)(struct ImBuf *ibuf, const char *filepath, int flags);
void (*load_tile)(struct ImBuf *ibuf,
@@ -143,6 +154,12 @@ struct ImBuf *imb_load_jpeg(const unsigned char *buffer,
size_t size,
int flags,
char colorspace[IM_MAX_SPACE]);
+struct ImBuf *imb_thumbnail_jpeg(const char *filepath,
+ const int flags,
+ const size_t max_thumb_size,
+ char colorspace[IM_MAX_SPACE],
+ size_t *r_width,
+ size_t *r_height);
/** \} */
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..6448d6cd76a 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,
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 670394e1a1a..d4c9e78a299 100644
--- a/source/blender/imbuf/intern/colormanagement.c
+++ b/source/blender/imbuf/intern/colormanagement.c
@@ -2451,68 +2451,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);
-
- 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 to a file format that needs a linear float buffer. */
+ const bool linear_float_output = BKE_imtype_requires_linear_float(image_format->imtype);
- if (ibuf->rect && (ibuf->mall & IB_rect) == 0) {
- ibuf->rect = MEM_dupallocN(ibuf->rect);
- ibuf->mall |= IB_rect;
- }
+ /* 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_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);
@@ -2526,67 +2535,93 @@ 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;
-
- IMB_colormanagement_transform(colormanaged_ibuf->rect_float,
- colormanaged_ibuf->x,
- colormanaged_ibuf->y,
- colormanaged_ibuf->channels,
- from_colorspace,
- to_colorspace,
- false);
- }
- }
+ /* This conversion always goes to scene linear. */
+ from_colorspace = global_role_scene_linear;
+ }
- if (colormanaged_ibuf != ibuf) {
- IMB_metadata_copy(colormanaged_ibuf, ibuf);
+ 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);
+ }
+ }
+ }
}
return colormanaged_ibuf;
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 548bc9e120c..92fa980cd7f 100644
--- a/source/blender/imbuf/intern/filetype.c
+++ b/source/blender/imbuf/intern/filetype.c
@@ -33,6 +33,7 @@ const ImFileType IMB_FILE_TYPES[] = {
.is_a = imb_is_a_jpeg,
.load = imb_load_jpeg,
.load_filepath = NULL,
+ .load_filepath_thumbnail = imb_thumbnail_jpeg,
.save = imb_savejpeg,
.load_tile = NULL,
.flag = 0,
@@ -45,6 +46,7 @@ const ImFileType IMB_FILE_TYPES[] = {
.is_a = imb_is_a_png,
.load = imb_loadpng,
.load_filepath = NULL,
+ .load_filepath_thumbnail = NULL,
.save = imb_savepng,
.load_tile = NULL,
.flag = 0,
@@ -57,6 +59,7 @@ const ImFileType IMB_FILE_TYPES[] = {
.is_a = imb_is_a_bmp,
.load = imb_bmp_decode,
.load_filepath = NULL,
+ .load_filepath_thumbnail = NULL,
.save = imb_savebmp,
.load_tile = NULL,
.flag = 0,
@@ -69,6 +72,7 @@ const ImFileType IMB_FILE_TYPES[] = {
.is_a = imb_is_a_targa,
.load = imb_loadtarga,
.load_filepath = NULL,
+ .load_filepath_thumbnail = NULL,
.save = imb_savetarga,
.load_tile = NULL,
.flag = 0,
@@ -81,6 +85,7 @@ const ImFileType IMB_FILE_TYPES[] = {
.is_a = imb_is_a_iris,
.load = imb_loadiris,
.load_filepath = NULL,
+ .load_filepath_thumbnail = NULL,
.save = imb_saveiris,
.load_tile = NULL,
.flag = 0,
@@ -94,6 +99,7 @@ const ImFileType IMB_FILE_TYPES[] = {
.is_a = imb_is_a_dpx,
.load = imb_load_dpx,
.load_filepath = NULL,
+ .load_filepath_thumbnail = NULL,
.save = imb_save_dpx,
.load_tile = NULL,
.flag = IM_FTYPE_FLOAT,
@@ -106,6 +112,7 @@ const ImFileType IMB_FILE_TYPES[] = {
.is_a = imb_is_a_cineon,
.load = imb_load_cineon,
.load_filepath = NULL,
+ .load_filepath_thumbnail = NULL,
.save = imb_save_cineon,
.load_tile = NULL,
.flag = IM_FTYPE_FLOAT,
@@ -120,6 +127,7 @@ const ImFileType IMB_FILE_TYPES[] = {
.is_a = imb_is_a_tiff,
.load = imb_loadtiff,
.load_filepath = NULL,
+ .load_filepath_thumbnail = NULL,
.save = imb_savetiff,
.load_tile = imb_loadtiletiff,
.flag = 0,
@@ -134,6 +142,7 @@ const ImFileType IMB_FILE_TYPES[] = {
.is_a = imb_is_a_hdr,
.load = imb_loadhdr,
.load_filepath = NULL,
+ .load_filepath_thumbnail = NULL,
.save = imb_savehdr,
.load_tile = NULL,
.flag = IM_FTYPE_FLOAT,
@@ -148,6 +157,7 @@ const ImFileType IMB_FILE_TYPES[] = {
.is_a = imb_is_a_openexr,
.load = imb_load_openexr,
.load_filepath = NULL,
+ .load_filepath_thumbnail = imb_load_filepath_thumbnail_openexr,
.save = imb_save_openexr,
.load_tile = NULL,
.flag = IM_FTYPE_FLOAT,
@@ -162,6 +172,7 @@ const ImFileType IMB_FILE_TYPES[] = {
.is_a = imb_is_a_jp2,
.load = imb_load_jp2,
.load_filepath = NULL,
+ .load_filepath_thumbnail = NULL,
.save = imb_save_jp2,
.load_tile = NULL,
.flag = IM_FTYPE_FLOAT,
@@ -176,6 +187,7 @@ const ImFileType IMB_FILE_TYPES[] = {
.is_a = imb_is_a_dds,
.load = imb_load_dds,
.load_filepath = NULL,
+ .load_filepath_thumbnail = NULL,
.save = NULL,
.load_tile = NULL,
.flag = 0,
@@ -190,6 +202,7 @@ const ImFileType IMB_FILE_TYPES[] = {
.is_a = imb_is_a_photoshop,
.load = NULL,
.load_filepath = imb_load_photoshop,
+ .load_filepath_thumbnail = NULL,
.save = NULL,
.load_tile = NULL,
.flag = IM_FTYPE_FLOAT,
@@ -204,6 +217,7 @@ const ImFileType IMB_FILE_TYPES[] = {
.is_a = imb_is_a_webp,
.load = imb_loadwebp,
.load_filepath = NULL,
+ .load_filepath_thumbnail = NULL,
.save = imb_savewebp,
.load_tile = NULL,
.flag = 0,
@@ -211,7 +225,7 @@ const ImFileType IMB_FILE_TYPES[] = {
.default_save_role = COLOR_ROLE_DEFAULT_BYTE,
},
#endif
- {NULL, NULL, NULL, NULL, NULL, NULL, NULL, 0, 0},
+ {NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, 0, 0, 0},
};
const ImFileType *IMB_FILE_TYPES_LAST = &IMB_FILE_TYPES[ARRAY_SIZE(IMB_FILE_TYPES) - 1];
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 6fb1fb52153..cffa61977f7 100644
--- a/source/blender/imbuf/intern/jpeg.c
+++ b/source/blender/imbuf/intern/jpeg.c
@@ -39,7 +39,11 @@ static void skip_input_data(j_decompress_ptr cinfo, long num_bytes);
static void term_source(j_decompress_ptr cinfo);
static void memory_source(j_decompress_ptr cinfo, const unsigned char *buffer, size_t size);
static boolean handle_app1(j_decompress_ptr cinfo);
-static ImBuf *ibJpegImageFromCinfo(struct jpeg_decompress_struct *cinfo, int flags);
+static ImBuf *ibJpegImageFromCinfo(struct jpeg_decompress_struct *cinfo,
+ int flags,
+ int max_size,
+ size_t *r_width,
+ size_t *r_height);
static const uchar jpeg_default_quality = 75;
static uchar ibuf_quality;
@@ -246,7 +250,11 @@ static boolean handle_app1(j_decompress_ptr cinfo)
return true;
}
-static ImBuf *ibJpegImageFromCinfo(struct jpeg_decompress_struct *cinfo, int flags)
+static ImBuf *ibJpegImageFromCinfo(struct jpeg_decompress_struct *cinfo,
+ int flags,
+ int max_size,
+ size_t *r_width,
+ size_t *r_height)
{
JSAMPARRAY row_pointer;
JSAMPLE *buffer = NULL;
@@ -264,16 +272,34 @@ static ImBuf *ibJpegImageFromCinfo(struct jpeg_decompress_struct *cinfo, int fla
jpeg_save_markers(cinfo, JPEG_COM, 0xffff);
if (jpeg_read_header(cinfo, false) == JPEG_HEADER_OK) {
- x = cinfo->image_width;
- y = cinfo->image_height;
depth = cinfo->num_components;
if (cinfo->jpeg_color_space == JCS_YCCK) {
cinfo->out_color_space = JCS_CMYK;
}
+ if (r_width) {
+ *r_width = cinfo->image_width;
+ }
+ if (r_height) {
+ *r_height = cinfo->image_height;
+ }
+
+ 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. */
+ 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)));
+ cinfo->dct_method = JDCT_FASTEST;
+ cinfo->dither_mode = JDITHER_ORDERED;
+ }
+
jpeg_start_decompress(cinfo);
+ x = cinfo->output_width;
+ y = cinfo->output_height;
+
if (flags & IB_test) {
jpeg_abort_decompress(cinfo);
ibuf = IMB_allocImBuf(x, y, 8 * depth, 0);
@@ -449,11 +475,92 @@ ImBuf *imb_load_jpeg(const unsigned char *buffer,
jpeg_create_decompress(cinfo);
memory_source(cinfo, buffer, size);
- ibuf = ibJpegImageFromCinfo(cinfo, flags);
+ ibuf = ibJpegImageFromCinfo(cinfo, flags, -1, NULL, NULL);
+
+ return ibuf;
+}
+
+/* Defines for JPEG Header markers and segment size. */
+#define JPEG_MARKER_MSB (0xFF)
+#define JPEG_MARKER_SOI (0xD8)
+#define JPEG_MARKER_APP1 (0xE1)
+#define JPEG_APP1_MAX (1 << 16)
+
+struct ImBuf *imb_thumbnail_jpeg(const char *filepath,
+ const int flags,
+ const size_t max_thumb_size,
+ char colorspace[IM_MAX_SPACE],
+ size_t *r_width,
+ size_t *r_height)
+{
+ struct jpeg_decompress_struct _cinfo, *cinfo = &_cinfo;
+ struct my_error_mgr jerr;
+ FILE *infile = NULL;
+
+ colorspace_set_default_role(colorspace, IM_MAX_SPACE, COLOR_ROLE_DEFAULT_BYTE);
+
+ cinfo->err = jpeg_std_error(&jerr.pub);
+ jerr.pub.error_exit = jpeg_error;
+
+ /* Establish the setjmp return context for my_error_exit to use. */
+ if (setjmp(jerr.setjmp_buffer)) {
+ /* If we get here, the JPEG code has signaled an error.
+ * We need to clean up the JPEG object, close the input file, and return.
+ */
+ jpeg_destroy_decompress(cinfo);
+ return NULL;
+ }
+
+ if ((infile = BLI_fopen(filepath, "rb")) == NULL) {
+ fprintf(stderr, "can't open %s\n", filepath);
+ return NULL;
+ }
+
+ /* If file contains an embedded thumbnail, let's return that instead. */
+
+ 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). */
+ unsigned int i = JPEG_APP1_MAX;
+ /* 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--)
+ ;
+ if (i > 0 && !feof(infile)) {
+ /* We found a JPEG thumbnail inside this image. */
+ ImBuf *ibuf = NULL;
+ uchar *buffer = MEM_callocN(JPEG_APP1_MAX, "thumbbuffer");
+ /* Just put SOI directly in buffer rather than seeking back 2 bytes. */
+ buffer[0] = JPEG_MARKER_MSB;
+ buffer[1] = JPEG_MARKER_SOI;
+ if (fread(buffer + 2, JPEG_APP1_MAX - 2, 1, infile) == 1) {
+ ibuf = imb_load_jpeg(buffer, JPEG_APP1_MAX, flags, colorspace);
+ }
+ MEM_SAFE_FREE(buffer);
+ if (ibuf) {
+ fclose(infile);
+ return ibuf;
+ }
+ }
+ }
+
+ /* No embedded thumbnail found, so let's create a new one. */
+
+ fseek(infile, 0, SEEK_SET);
+ jpeg_create_decompress(cinfo);
+
+ jpeg_stdio_src(cinfo, infile);
+ ImBuf *ibuf = ibJpegImageFromCinfo(cinfo, flags, max_thumb_size, r_width, r_height);
+ fclose(infile);
return ibuf;
}
+#undef JPEG_MARKER_MSB
+#undef JPEG_MARKER_SOI
+#undef JPEG_MARKER_APP1
+#undef JPEG_APP1_MAX
+
static void write_jpeg(struct jpeg_compress_struct *cinfo, struct ImBuf *ibuf)
{
JSAMPLE *buffer = NULL;
diff --git a/source/blender/imbuf/intern/openexr/openexr_api.cpp b/source/blender/imbuf/intern/openexr/openexr_api.cpp
index 66ee3cf2c26..54ef5438c23 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 == NULL) {
+ throw IEX_NAMESPACE::InputExc("BLI_mmap_open failed");
+ }
+ close(file);
+ _exrbuf = (unsigned char *)BLI_mmap_get_pointer(_mmap_file);
+ }
+
+ ~IMMapStream()
+ {
+ 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 {
@@ -2099,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 {
+
+ /* 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(), NULL, 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;
+ }
+ }
- setGlobalThreadCount(num_threads);
+ 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..a62c87428b6 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,
+ const int flags,
+ const 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 df41c0ca757..4b433836767 100644
--- a/source/blender/imbuf/intern/readimage.c
+++ b/source/blender/imbuf/intern/readimage.c
@@ -22,6 +22,8 @@
#include "IMB_filetype.h"
#include "IMB_imbuf.h"
#include "IMB_imbuf_types.h"
+#include "IMB_metadata.h"
+#include "IMB_thumbs.h"
#include "imbuf.h"
#include "IMB_colormanagement.h"
@@ -187,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])
@@ -234,6 +236,61 @@ ImBuf *IMB_loadiffname(const char *filepath, int flags, char colorspace[IM_MAX_S
return ibuf;
}
+struct ImBuf *IMB_thumb_load_image(const char *filepath,
+ size_t max_thumb_size,
+ char colorspace[IM_MAX_SPACE])
+{
+ const ImFileType *type = IMB_file_type_from_ftype(IMB_ispic_type(filepath));
+ if (type == NULL) {
+ return NULL;
+ }
+
+ ImBuf *ibuf = NULL;
+ int flags = IB_rect | IB_metadata;
+ /* Size of the original image. */
+ size_t width = 0;
+ size_t height = 0;
+
+ char effective_colorspace[IM_MAX_SPACE] = "";
+ if (colorspace) {
+ BLI_strncpy(effective_colorspace, colorspace, sizeof(effective_colorspace));
+ }
+
+ if (type->load_filepath_thumbnail) {
+ ibuf = type->load_filepath_thumbnail(
+ filepath, flags, max_thumb_size, colorspace, &width, &height);
+ }
+ else {
+ /* Skip images of other types if over 100MB. */
+ const size_t file_size = BLI_file_size(filepath);
+ if (file_size != -1 && file_size > THUMB_SIZE_MAX) {
+ return NULL;
+ }
+ ibuf = IMB_loadiffname(filepath, flags, colorspace);
+ if (ibuf) {
+ width = ibuf->x;
+ height = ibuf->y;
+ }
+ }
+
+ if (ibuf) {
+ imb_handle_alpha(ibuf, flags, colorspace, effective_colorspace);
+
+ if (width > 0 && height > 0) {
+ /* Save dimensions of original image into the thumbnail metadata. */
+ char cwidth[40];
+ char cheight[40];
+ SNPRINTF(cwidth, "%zu", width);
+ SNPRINTF(cheight, "%zu", height);
+ IMB_metadata_ensure(&ibuf->metadata);
+ IMB_metadata_set_field(ibuf->metadata, "Thumb::Image::Width", cwidth);
+ IMB_metadata_set_field(ibuf->metadata, "Thumb::Image::Height", cheight);
+ }
+ }
+
+ return ibuf;
+}
+
ImBuf *IMB_testiffname(const char *filepath, int flags)
{
ImBuf *ibuf;
diff --git a/source/blender/imbuf/intern/thumbs.c b/source/blender/imbuf/intern/thumbs.c
index 37734ebacb2..f2c9c82fa66 100644
--- a/source/blender/imbuf/intern/thumbs.c
+++ b/source/blender/imbuf/intern/thumbs.c
@@ -318,12 +318,8 @@ static ImBuf *thumb_create_ex(const char *file_path,
char tpath[FILE_MAX];
char tdir[FILE_MAX];
char temp[FILE_MAX];
- char mtime[40] = "0"; /* in case we can't stat the file */
- char cwidth[40] = "0"; /* in case images have no data */
- char cheight[40] = "0";
+ char mtime[40] = "0"; /* in case we can't stat the file */
short tsize = 128;
- short ex, ey;
- float scaledx, scaledy;
BLI_stat_t info;
switch (size) {
@@ -340,15 +336,6 @@ static ImBuf *thumb_create_ex(const char *file_path,
return NULL; /* unknown size */
}
- /* exception, skip images over 100mb */
- if (source == THB_SOURCE_IMAGE) {
- const size_t file_size = BLI_file_size(file_path);
- if (file_size != -1 && file_size > THUMB_SIZE_MAX) {
- // printf("file too big: %d, skipping %s\n", (int)size, file_path);
- return NULL;
- }
- }
-
if (get_thumb_dir(tdir, size)) {
BLI_snprintf(tpath, FILE_MAX, "%s%s", tdir, thumb);
// thumb[8] = '\0'; /* shorten for tempname, not needed anymore */
@@ -368,7 +355,7 @@ static ImBuf *thumb_create_ex(const char *file_path,
if (img == NULL) {
switch (source) {
case THB_SOURCE_IMAGE:
- img = IMB_loadiffname(file_path, IB_rect | IB_metadata, NULL);
+ img = IMB_thumb_load_image(file_path, tsize, NULL);
break;
case THB_SOURCE_BLEND:
img = IMB_thumb_load_blend(file_path, blen_group, blen_id);
@@ -385,8 +372,6 @@ static ImBuf *thumb_create_ex(const char *file_path,
if (BLI_stat(file_path, &info) != -1) {
BLI_snprintf(mtime, sizeof(mtime), "%ld", (long int)info.st_mtime);
}
- BLI_snprintf(cwidth, sizeof(cwidth), "%d", img->x);
- BLI_snprintf(cheight, sizeof(cheight), "%d", img->y);
}
}
else if (THB_SOURCE_MOVIE == source) {
@@ -411,28 +396,20 @@ static ImBuf *thumb_create_ex(const char *file_path,
return NULL;
}
- if (img->x > img->y) {
- scaledx = (float)tsize;
- scaledy = ((float)img->y / (float)img->x) * tsize;
- }
- else {
- scaledy = (float)tsize;
- scaledx = ((float)img->x / (float)img->y) * tsize;
- }
- /* Scaling down must never assign zero width/height, see: T89868. */
- ex = MAX2(1, (short)scaledx);
- ey = MAX2(1, (short)scaledy);
-
- /* save some time by only scaling byte buf */
- if (img->rect_float) {
- if (img->rect == NULL) {
- IMB_rect_from_float(img);
+ if (img->x > tsize || img->y > tsize) {
+ float scale = MIN2((float)tsize / (float)img->x, (float)tsize / (float)img->y);
+ /* Scaling down must never assign zero width/height, see: T89868. */
+ short ex = MAX2(1, (short)(img->x * scale));
+ short ey = MAX2(1, (short)(img->y * scale));
+ /* Save some time by only scaling byte buf */
+ if (img->rect_float) {
+ if (img->rect == NULL) {
+ IMB_rect_from_float(img);
+ }
+ imb_freerectfloatImBuf(img);
}
-
- imb_freerectfloatImBuf(img);
+ IMB_scaleImBuf(img, ex, ey);
}
-
- IMB_scaleImBuf(img, ex, ey);
}
BLI_snprintf(desc, sizeof(desc), "Thumbnail for %s", uri);
IMB_metadata_ensure(&img->metadata);
@@ -443,10 +420,6 @@ static ImBuf *thumb_create_ex(const char *file_path,
if (use_hash) {
IMB_metadata_set_field(img->metadata, "X-Blender::Hash", hash);
}
- if (ELEM(source, THB_SOURCE_IMAGE, THB_SOURCE_BLEND, THB_SOURCE_FONT)) {
- IMB_metadata_set_field(img->metadata, "Thumb::Image::Width", cwidth);
- IMB_metadata_set_field(img->metadata, "Thumb::Image::Height", cheight);
- }
img->ftype = IMB_FTYPE_PNG;
img->planes = 32;
@@ -493,27 +466,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)) {
@@ -523,16 +496,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)) {
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/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 8da9eb9ccf7..8e004938a89 100644
--- a/source/blender/imbuf/intern/util_gpu.c
+++ b/source/blender/imbuf/intern/util_gpu.c
@@ -197,12 +197,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
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/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..633611cf1a6 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;
@@ -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 8c62484028d..219bba285a7 100644
--- a/source/blender/io/alembic/intern/abc_reader_mesh.cc
+++ b/source/blender/io/alembic/intern/abc_reader_mesh.cc
@@ -377,25 +377,22 @@ 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;
/* 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;
}
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/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..85f960abfe6 100644
--- a/source/blender/io/collada/MeshImporter.h
+++ b/source/blender/io/collada/MeshImporter.h
@@ -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/common/CMakeLists.txt b/source/blender/io/common/CMakeLists.txt
index b5766b44025..e80bd850825 100644
--- a/source/blender/io/common/CMakeLists.txt
+++ b/source/blender/io/common/CMakeLists.txt
@@ -8,7 +8,6 @@ set(INC
../../depsgraph
../../makesdna
../../../../intern/guardedalloc
- ../../../../extern/fast_float
)
set(INC_SYS
@@ -20,13 +19,11 @@ set(SRC
intern/dupli_persistent_id.cc
intern/object_identifier.cc
intern/path_util.cc
- intern/string_utils.cc
IO_abstract_hierarchy_iterator.h
IO_dupli_persistent_id.hh
IO_path_util.hh
IO_path_util_types.h
- IO_string_utils.hh
IO_types.h
intern/dupli_parent_finder.hh
)
@@ -45,7 +42,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..3371501db95 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;
@@ -204,12 +205,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_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..82bb1c57833 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})
{
}
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/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/usd/CMakeLists.txt b/source/blender/io/usd/CMakeLists.txt
index 594dbe5ddd1..1205ae74e6f 100644
--- a/source/blender/io/usd/CMakeLists.txt
+++ b/source/blender/io/usd/CMakeLists.txt
@@ -70,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
@@ -96,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
@@ -121,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..29b256125f0 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;
}
@@ -356,7 +356,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 +499,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_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 dd795e4f922..857896b9330 100644
--- a/source/blender/io/usd/intern/usd_writer_material.cc
+++ b/source/blender/io/usd/intern/usd_writer_material.cc
@@ -575,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 {
@@ -593,7 +593,7 @@ static std::string get_tex_image_asset_path(bNode *node,
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();
@@ -605,11 +605,7 @@ 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;
}
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/usd.h b/source/blender/io/usd/usd.h
index e63cd0a4e04..2e4dcb0da94 100644
--- a/source/blender/io/usd/usd.h
+++ b/source/blender/io/usd/usd.h
@@ -28,7 +28,7 @@ struct USDExportParams {
bool generate_preview_surface;
bool export_textures;
bool overwrite_textures;
- bool relative_texture_paths;
+ bool relative_paths;
};
struct USDImportParams {
@@ -83,7 +83,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 67cec000778..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,8 +72,10 @@ 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
+
tests/obj_exporter_tests.hh
)
diff --git a/source/blender/io/wavefront_obj/IO_wavefront_obj.h b/source/blender/io/wavefront_obj/IO_wavefront_obj.h
index f7bf678310f..bebad06d37f 100644
--- a/source/blender/io/wavefront_obj/IO_wavefront_obj.h
+++ b/source/blender/io/wavefront_obj/IO_wavefront_obj.h
@@ -92,12 +92,14 @@ struct OBJImportParams {
};
/**
- * 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 b027df73b1e..11d1bafdafe 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
@@ -385,7 +385,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 =
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..f0263989bfc 100644
--- a/source/blender/io/wavefront_obj/exporter/obj_export_io.hh
+++ b/source/blender/io/wavefront_obj/exporter/obj_export_io.hh
@@ -236,7 +236,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/importer/obj_import_file_reader.cc b/source/blender/io/wavefront_obj/importer/obj_import_file_reader.cc
index d14401224ed..c7990028312 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
@@ -8,9 +8,8 @@
#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"
namespace blender::io::obj {
@@ -67,40 +66,43 @@ 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);
+ parse_floats(p, end, 0.0f, vert, 3);
r_global_vertices.vertices.append(vert);
geom->vertex_count_++;
}
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);
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 +111,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,
@@ -128,24 +131,24 @@ static void geom_add_polygon(Geometry *geom,
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);
+ if (p < end && *p == '/') {
+ ++p;
+ p = parse_int(p, end, INT32_MAX, corner.vertex_normal_index, false);
got_normal = corner.uv_vert_index != INT32_MAX;
}
}
@@ -186,7 +189,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 +204,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 +222,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 +248,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 +276,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 +285,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 +318,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 whitespace; don't use isspace() for performance reasons.
- */
- if (line[keyword_len] > ' ') {
+ /* Treat any ASCII control character as white-space;
+ * don't use `isspace()` for performance reasons. */
+ if (p[keyword_len] > ' ') {
return false;
}
- line = line.drop_prefix(keyword_len + 1);
+ p += keyword_len + 1;
return true;
}
@@ -400,27 +406,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 +436,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 +461,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 +474,32 @@ 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());
}
/* 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 +513,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 +557,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 +602,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 +624,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 +686,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_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_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/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..d7f4ce3d773 100644
--- a/source/blender/io/wavefront_obj/tests/obj_importer_tests.cc
+++ b/source/blender/io/wavefront_obj/tests/obj_importer_tests.cc
@@ -333,7 +333,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,
diff --git a/source/blender/makesdna/DNA_anim_types.h b/source/blender/makesdna/DNA_anim_types.h
index 99737aa3b67..c1dfab8a041 100644
--- a/source/blender/makesdna/DNA_anim_types.h
+++ b/source/blender/makesdna/DNA_anim_types.h
@@ -304,7 +304,7 @@ typedef struct DriverTarget {
char *rna_path;
/**
- * Name of the posebone to use
+ * Name of the pose-bone to use
* (for vars where DTAR_FLAG_STRUCT_REF is used) - `MAX_ID_NAME - 2`.
*/
char pchan_name[64];
@@ -918,9 +918,9 @@ typedef struct KS_Path {
/** Index that path affects. */
int array_index;
- /** (eInsertKeyFlags) settings to supply insertkey() with. */
+ /** (#eInsertKeyFlags) settings to supply insert-key() with. */
short keyingflag;
- /** (eInsertKeyFlags) for each flag set, the relevant keyingflag bit overrides the default. */
+ /** (#eInsertKeyFlags) for each flag set, the relevant keying-flag bit overrides the default. */
short keyingoverride;
} KS_Path;
diff --git a/source/blender/makesdna/DNA_brush_enums.h b/source/blender/makesdna/DNA_brush_enums.h
index 3e7a4431bf5..f409d1c0442 100644
--- a/source/blender/makesdna/DNA_brush_enums.h
+++ b/source/blender/makesdna/DNA_brush_enums.h
@@ -305,6 +305,12 @@ typedef enum eGP_Sculpt_Mode_Flag {
GP_SCULPT_FLAGMODE_APPLY_THICKNESS = (1 << 2),
/* apply brush to uv data */
GP_SCULPT_FLAGMODE_APPLY_UV = (1 << 3),
+ /* Stroke Auto-Masking for sculpt. */
+ GP_SCULPT_FLAGMODE_AUTOMASK_STROKE = (1 << 4),
+ /* Layer Auto-Masking for sculpt. */
+ GP_SCULPT_FLAGMODE_AUTOMASK_LAYER = (1 << 5),
+ /* Material Auto-Masking for sculpt. */
+ GP_SCULPT_FLAGMODE_AUTOMASK_MATERIAL = (1 << 6),
} eGP_Sculpt_Mode_Flag;
typedef enum eAutomasking_flag {
@@ -612,6 +618,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 7d230b7d7a3..24e77ecf87f 100644
--- a/source/blender/makesdna/DNA_brush_types.h
+++ b/source/blender/makesdna/DNA_brush_types.h
@@ -140,6 +140,8 @@ typedef struct BrushGpencilSettings {
typedef struct BrushCurvesSculptSettings {
/** Number of curves added by the add brush. */
int add_amount;
+ /** Number of control points in new curves added by the add brush. */
+ int points_per_curve;
/* eBrushCurvesSculptFlag. */
uint32_t flag;
/** When shrinking curves, they shouldn't become shorter than this length. */
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_curves_types.h b/source/blender/makesdna/DNA_curves_types.h
index bb53dbafdc8..2388f04cc39 100644
--- a/source/blender/makesdna/DNA_curves_types.h
+++ b/source/blender/makesdna/DNA_curves_types.h
@@ -9,6 +9,8 @@
#include "DNA_ID.h"
#include "DNA_customdata_types.h"
+#include "BLI_utildefines.h"
+
#ifdef __cplusplus
extern "C" {
#endif
@@ -87,6 +89,9 @@ typedef struct CurvesGeometry {
* this array is allocated with a length one larger than the number of curves. This is allowed
* to be null when there are no curves.
*
+ * Every curve offset must be at least one larger than the previous.
+ * In other words, every curve must have at least one point.
+ *
* \note This is *not* stored in #CustomData because its size is one larger than #curve_data.
*/
int *curve_offsets;
@@ -105,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.
@@ -130,7 +135,13 @@ typedef struct Curves {
/* Materials. */
struct Material **mat;
short totcol;
- short _pad2[3];
+
+ /**
+ * User-defined symmetry flag (#eCurvesSymmetryType) that causes editing operations to maintain
+ * symmetrical geometry.
+ */
+ char symmetry;
+ char _pad2[5];
/**
* Used as base mesh when curves represent e.g. hair or fur. This surface is used in edit modes.
@@ -150,6 +161,14 @@ enum {
HA_DS_EXPAND = (1 << 0),
};
+/** #Curves.symmetry */
+typedef enum eCurvesSymmetryType {
+ CURVES_SYMMETRY_X = 1 << 0,
+ CURVES_SYMMETRY_Y = 1 << 1,
+ CURVES_SYMMETRY_Z = 1 << 2,
+} eCurvesSymmetryType;
+ENUM_OPERATORS(eCurvesSymmetryType, CURVES_SYMMETRY_Z)
+
/* Only one material supported currently. */
#define CURVES_MATERIAL_NR 1
diff --git a/source/blender/makesdna/DNA_customdata_types.h b/source/blender/makesdna/DNA_customdata_types.h
index ef937fb139b..fe06e97946c 100644
--- a/source/blender/makesdna/DNA_customdata_types.h
+++ b/source/blender/makesdna/DNA_customdata_types.h
@@ -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 b0e7342c9cb..c20fb180fcd 100644
--- a/source/blender/makesdna/DNA_gpencil_modifier_types.h
+++ b/source/blender/makesdna/DNA_gpencil_modifier_types.h
@@ -102,7 +102,8 @@ typedef struct NoiseGpencilModifierData {
/** Noise Frequency scaling */
float noise_scale;
float noise_offset;
- char _pad[4];
+ short noise_mode;
+ char _pad[2];
/** How many frames before recalculate randoms. */
int step;
/** Custom index for passes. */
@@ -127,6 +128,11 @@ typedef enum eNoiseGpencil_Flag {
GP_NOISE_INVERT_MATERIAL = (1 << 11),
} eNoiseGpencil_Flag;
+typedef enum eNoiseRandomGpencil_Mode {
+ GP_NOISE_RANDOM_STEP = 0,
+ GP_NOISE_RANDOM_KEYFRAME = 1,
+} eNoiseRandomGpencil_Mode;
+
typedef struct SubdivGpencilModifierData {
GpencilModifierData modifier;
/** Material for filtering. */
@@ -223,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 {
diff --git a/source/blender/makesdna/DNA_gpencil_types.h b/source/blender/makesdna/DNA_gpencil_types.h
index 4a1b639122a..a83262d7639 100644
--- a/source/blender/makesdna/DNA_gpencil_types.h
+++ b/source/blender/makesdna/DNA_gpencil_types.h
@@ -245,7 +245,7 @@ typedef struct bGPDstroke_Runtime {
/** Vertex offset in the VBO where this stroke starts. */
int stroke_start;
- /** Triangle offset in the ibo where this fill starts. */
+ /** Triangle offset in the IBO where this fill starts. */
int fill_start;
/** Curve Handles offset in the IBO where this handle starts. */
int curve_start;
@@ -814,10 +814,10 @@ typedef enum eGPdata_Flag {
/* Vertex Paint Mode - Toggle paint mode */
GP_DATA_STROKE_VERTEXMODE = (1 << 18),
- /* Autolock not active layers */
+ /* Auto-lock not active layers. */
GP_DATA_AUTOLOCK_LAYERS = (1 << 20),
- /* Enable Bezier Editing Curve (a submode of Edit mode). */
+ /* Enable Bezier Editing Curve (a sub-mode of Edit mode). */
GP_DATA_CURVE_EDIT_MODE = (1 << 21),
/* Use adaptive curve resolution */
GP_DATA_CURVE_ADAPTIVE_RESOLUTION = (1 << 22),
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_layer_types.h b/source/blender/makesdna/DNA_layer_types.h
index d5f7e25bb80..4ee5f34fcde 100644
--- a/source/blender/makesdna/DNA_layer_types.h
+++ b/source/blender/makesdna/DNA_layer_types.h
@@ -125,7 +125,7 @@ typedef struct ViewLayerAOV {
int type;
} ViewLayerAOV;
-/* Lightgroup Renderpass definition. */
+/** Light-group Render-pass definition. */
typedef struct ViewLayerLightgroup {
struct ViewLayerLightgroup *next, *prev;
diff --git a/source/blender/makesdna/DNA_lineart_types.h b/source/blender/makesdna/DNA_lineart_types.h
index 2e446427cc3..5b3a23000d7 100644
--- a/source/blender/makesdna/DNA_lineart_types.h
+++ b/source/blender/makesdna/DNA_lineart_types.h
@@ -21,7 +21,7 @@ typedef enum eLineartMainFlags {
LRT_ALLOW_DUPLI_OBJECTS = (1 << 2),
LRT_ALLOW_OVERLAPPING_EDGES = (1 << 3),
LRT_ALLOW_CLIPPING_BOUNDARIES = (1 << 4),
- LRT_REMOVE_DOUBLES = (1 << 5),
+ /* LRT_REMOVE_DOUBLES = (1 << 5), Deprecated */
LRT_LOOSE_AS_CONTOUR = (1 << 6),
LRT_GPENCIL_INVERT_SOURCE_VGROUP = (1 << 7),
LRT_GPENCIL_MATCH_OUTPUT_VGROUP = (1 << 8),
@@ -47,9 +47,18 @@ typedef enum eLineartEdgeFlag {
LRT_EDGE_FLAG_MATERIAL = (1 << 3),
LRT_EDGE_FLAG_INTERSECTION = (1 << 4),
LRT_EDGE_FLAG_LOOSE = (1 << 5),
- LRT_EDGE_FLAG_CHAIN_PICKED = (1 << 6),
- LRT_EDGE_FLAG_CLIPPED = (1 << 7),
- /** Limited to 8 bits, DON'T ADD ANYMORE until improvements on the data structure. */
+ /* 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. */
+ 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_modifier_defaults.h b/source/blender/makesdna/DNA_modifier_defaults.h
index 77730ce254c..92a65a50bd4 100644
--- a/source/blender/makesdna/DNA_modifier_defaults.h
+++ b/source/blender/makesdna/DNA_modifier_defaults.h
@@ -632,7 +632,8 @@
.falloff = 4.0f, \
.mesh_verts_num = 0, \
.bind_verts_num = 0, \
- .polys_num = 0, \
+ .target_verts_num = 0, \
+ .target_polys_num = 0, \
.flags = 0, \
.mat = _DNA_DEFAULT_UNIT_M4, \
.strength = 1.0f, \
diff --git a/source/blender/makesdna/DNA_modifier_types.h b/source/blender/makesdna/DNA_modifier_types.h
index 73c4eeaaab3..6e3ce7e98a8 100644
--- a/source/blender/makesdna/DNA_modifier_types.h
+++ b/source/blender/makesdna/DNA_modifier_types.h
@@ -2222,13 +2222,19 @@ typedef struct SurfaceDeformModifierData {
struct Object *target;
/** Vertex bind data. */
SDefVert *verts;
+ void *_pad1;
float falloff;
- unsigned int mesh_verts_num, bind_verts_num, polys_num;
+ /* Number of of vertices on the deformed mesh upon the bind process. */
+ unsigned int mesh_verts_num;
+ /* Number of vertices in the `verts` array of this modifier. */
+ unsigned int bind_verts_num;
+ /* Number of vertices and polygons on the target mesh upon bind process. */
+ unsigned int target_verts_num, target_polys_num;
int flags;
float mat[4][4];
float strength;
char defgrp_name[64];
- void *_pad1;
+ int _pad2;
} SurfaceDeformModifierData;
/** Surface Deform modifier flags. */
diff --git a/source/blender/makesdna/DNA_node_types.h b/source/blender/makesdna/DNA_node_types.h
index e7e8ab3dd61..a0738883bf3 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 {
@@ -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,31 +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;
/**
- * Used to cache run-time information of the node tree.
- * #eNodeTreeRuntimeFlag.
- */
- uint8_t runtime_flag;
-
- char _pad1[3];
-
- /**
* 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). */
@@ -552,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.
*
@@ -579,6 +533,8 @@ typedef struct bNodeTree {
/** Image representing what the node group does. */
struct PreviewImage *preview;
+
+ bNodeTreeRuntimeHandle *runtime;
} bNodeTree;
/** #NodeTree.type, index */
@@ -868,6 +824,12 @@ typedef struct NodeVertexCol {
char name[64];
} NodeVertexCol;
+typedef struct NodeCMPCombSepColor {
+ /* CMPNodeCombSepColorMode */
+ uint8_t mode;
+ uint8_t ycc_mode;
+} NodeCMPCombSepColor;
+
/** Defocus blur node. */
typedef struct NodeDefocus {
char bktype, _pad0, preview, gamco;
@@ -1498,6 +1460,11 @@ typedef struct NodeFunctionCompare {
char _pad[1];
} NodeFunctionCompare;
+typedef struct NodeCombSepColor {
+ /* NodeCombSepColorMode */
+ int8_t mode;
+} NodeCombSepColor;
+
/* script node mode */
#define NODE_SCRIPT_INTERNAL 0
#define NODE_SCRIPT_EXTERNAL 1
@@ -1890,6 +1857,16 @@ typedef enum CMPNodeDenoisePrefilter {
CMP_NODE_DENOISE_PREFILTER_ACCURATE = 2
} CMPNodeDenoisePrefilter;
+/* Color combine/separate modes */
+
+typedef enum CMPNodeCombSepColorMode {
+ CMP_NODE_COMBSEP_COLOR_RGB = 0,
+ CMP_NODE_COMBSEP_COLOR_HSV = 1,
+ CMP_NODE_COMBSEP_COLOR_HSL = 2,
+ CMP_NODE_COMBSEP_COLOR_YCC = 3,
+ CMP_NODE_COMBSEP_COLOR_YUV = 4,
+} CMPNodeCombSepColorMode;
+
#define CMP_NODE_PLANETRACKDEFORM_MBLUR_SAMPLES_MAX 64
/* Point Density shader node */
@@ -2148,6 +2125,12 @@ typedef enum GeometryNodeScaleElementsMode {
GEO_NODE_SCALE_ELEMENTS_SINGLE_AXIS = 1,
} GeometryNodeScaleElementsMode;
+typedef enum NodeCombSepColorMode {
+ NODE_COMBSEP_COLOR_RGB = 0,
+ NODE_COMBSEP_COLOR_HSV = 1,
+ NODE_COMBSEP_COLOR_HSL = 2,
+} NodeCombSepColorMode;
+
#ifdef __cplusplus
}
#endif
diff --git a/source/blender/makesdna/DNA_object_types.h b/source/blender/makesdna/DNA_object_types.h
index 9ea1e3a9e8d..f257833efe8 100644
--- a/source/blender/makesdna/DNA_object_types.h
+++ b/source/blender/makesdna/DNA_object_types.h
@@ -535,7 +535,8 @@ enum {
/** Matches #OB_TYPE_SUPPORT_EDITMODE. */
#define OB_DATA_SUPPORT_EDITMODE(_type) \
- (ELEM(_type, ID_ME, ID_CU_LEGACY, ID_MB, ID_LT, ID_AR, ID_CV))
+ (ELEM(_type, ID_ME, ID_CU_LEGACY, ID_MB, ID_LT, ID_AR) || \
+ (U.experimental.use_new_curves_tools && (_type) == ID_CV))
/* is this ID type used as object data */
#define OB_DATA_SUPPORT_ID(_id_type) \
diff --git a/source/blender/makesdna/DNA_sequence_types.h b/source/blender/makesdna/DNA_sequence_types.h
index d28550b5456..a54fd838bbe 100644
--- a/source/blender/makesdna/DNA_sequence_types.h
+++ b/source/blender/makesdna/DNA_sequence_types.h
@@ -161,7 +161,7 @@ typedef struct Sequence {
* Frames that use the first frame before data begins,
* frames that use the last frame after data ends.
*/
- int startstill, endstill;
+ int startstill DNA_DEPRECATED, endstill DNA_DEPRECATED;
/** Machine: the strip channel */
int machine;
int _pad3;
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_types.h b/source/blender/makesdna/DNA_space_types.h
index c1e96bcfaf3..85649a31ea4 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
@@ -1223,7 +1223,8 @@ typedef struct SpaceImage {
char dt_uvstretch;
char around;
- char _pad1[4];
+ char gizmo_flag;
+ char _pad1[3];
int flag;
@@ -1321,6 +1322,13 @@ typedef enum eSpaceImageOverlay_Flag {
SI_OVERLAY_SHOW_GRID_BACKGROUND = (1 << 1),
} eSpaceImageOverlay_Flag;
+/** #SpaceImage.gizmo_flag */
+enum {
+ /** All gizmos. */
+ SI_GIZMO_HIDE = (1 << 0),
+ SI_GIZMO_HIDE_NAVIGATE = (1 << 1),
+};
+
/** Keep in sync with `STEPS_LEN` in `grid_frag.glsl`. */
#define SI_GRID_STEPS_LEN 8
@@ -1332,7 +1340,7 @@ typedef enum eSpaceImageOverlay_Flag {
typedef struct SpaceText_Runtime {
- /** Actual line height, scaled by dpi. */
+ /** Actual line height, scaled by DPI. */
int lheight_px;
/** Runtime computed, character width. */
diff --git a/source/blender/makesdna/DNA_userdef_types.h b/source/blender/makesdna/DNA_userdef_types.h
index 21abb632b94..275a89ec680 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;
@@ -643,6 +643,8 @@ typedef struct UserDef_Experimental {
/* The following options are automatically sanitized (set to 0)
* when the release cycle is not alpha. */
char use_new_curves_type;
+ /** Only available when #use_new_curves_type is enabled. */
+ char use_new_curves_tools;
char use_new_point_cloud_type;
char use_full_frame_compositor;
char use_sculpt_tools_tilt;
@@ -651,7 +653,6 @@ typedef struct UserDef_Experimental {
char enable_eevee_next;
char use_sculpt_texture_paint;
char use_draw_manager_acquire_lock;
- char _pad0[1];
/** `makesdna` does not allow empty structs. */
} UserDef_Experimental;
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/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 86649357433..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)
@@ -106,7 +108,7 @@ DNA_STRUCT_RENAME_ELEM(SDefBind, numverts, verts_num)
DNA_STRUCT_RENAME_ELEM(SDefVert, numbinds, binds_num)
DNA_STRUCT_RENAME_ELEM(SpaceSeq, overlay_type, overlay_frame_type)
DNA_STRUCT_RENAME_ELEM(SurfaceDeformModifierData, num_mesh_verts, mesh_verts_num)
-DNA_STRUCT_RENAME_ELEM(SurfaceDeformModifierData, numpoly, polys_num)
+DNA_STRUCT_RENAME_ELEM(SurfaceDeformModifierData, numpoly, target_polys_num)
DNA_STRUCT_RENAME_ELEM(SurfaceDeformModifierData, numverts, bind_verts_num)
DNA_STRUCT_RENAME_ELEM(SurfaceModifierData, numverts, verts_num)
DNA_STRUCT_RENAME_ELEM(Text, name, filepath)
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..e855395482e 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,7 +485,7 @@ 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
@@ -486,7 +503,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 +515,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 +542,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 +555,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 +576,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 +595,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 +643,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 +669,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 +682,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 74f8e2487a4..8c42bbe2ee6 100644
--- a/source/blender/makesrna/RNA_enum_items.h
+++ b/source/blender/makesrna/RNA_enum_items.h
@@ -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)
@@ -150,7 +150,15 @@ DEF_ENUM(rna_enum_wm_report_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)
@@ -198,8 +206,10 @@ DEF_ENUM(rna_enum_context_mode_items)
DEF_ENUM(rna_enum_preference_section_items)
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_color_attribute_domain_items)
DEF_ENUM(rna_enum_attribute_domain_without_corner_items)
DEF_ENUM(rna_enum_attribute_domain_with_auto_items)
DEF_ENUM(rna_enum_geometry_component_type_items)
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/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 b0488bbfa7a..b5cf8abaac6 100644
--- a/source/blender/makesrna/intern/rna_ID.c
+++ b/source/blender/makesrna/intern/rna_ID.c
@@ -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);
diff --git a/source/blender/makesrna/intern/rna_access.c b/source/blender/makesrna/intern/rna_access.c
index 8f7660d4015..75579107465 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;
@@ -5724,7 +5761,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);
@@ -5753,7 +5790,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,
@@ -5772,7 +5809,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)
@@ -5828,13 +5865,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);
@@ -5843,7 +5884,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)
{
@@ -5916,7 +5957,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;
@@ -5945,7 +5986,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;
@@ -5992,7 +6033,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);
}
@@ -6723,23 +6764,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;
}
@@ -6749,29 +6794,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 d49bac15242..36706c82366 100644
--- a/source/blender/makesrna/intern/rna_attribute.c
+++ b/source/blender/makesrna/intern/rna_attribute.c
@@ -40,12 +40,21 @@ const EnumPropertyItem rna_enum_attribute_type_items[] = {
{0, NULL, 0, NULL, NULL},
};
+const EnumPropertyItem rna_enum_color_attribute_type_items[] = {
+ {CD_PROP_COLOR, "FLOAT_COLOR", 0, "Color", "RGBA color 32-bit floating-point values"},
+ {CD_PROP_BYTE_COLOR,
+ "BYTE_COLOR",
+ 0,
+ "Byte Color",
+ "RGBA color with 8-bit positive integer values"},
+ {0, NULL, 0, NULL, NULL}};
+
const EnumPropertyItem rna_enum_attribute_type_with_auto_items[] = {
{CD_AUTO_FROM_NAME, "AUTO", 0, "Auto", ""},
{CD_PROP_FLOAT, "FLOAT", 0, "Float", "Floating-point value"},
{CD_PROP_INT32, "INT", 0, "Integer", "32-bit integer"},
{CD_PROP_FLOAT3, "FLOAT_VECTOR", 0, "Vector", "3D vector with floating-point values"},
- {CD_PROP_COLOR, "FLOAT_COLOR", 0, "Color", "RGBA color 32-bit floating-point values"},
+ {CD_PROP_COLOR, "FLOAT_COLOR", 0, "Color", "RGBA color with 32-bit floating-point values"},
{CD_PROP_BYTE_COLOR,
"BYTE_COLOR",
0,
@@ -92,6 +101,11 @@ const EnumPropertyItem rna_enum_attribute_domain_with_auto_items[] = {
{0, NULL, 0, NULL, NULL},
};
+const EnumPropertyItem rna_enum_color_attribute_domain_items[] = {
+ {ATTR_DOMAIN_POINT, "POINT", 0, "Vertex", ""},
+ {ATTR_DOMAIN_CORNER, "CORNER", 0, "Face Corner", ""},
+ {0, NULL, 0, NULL, NULL}};
+
#ifdef RNA_RUNTIME
# include "BLI_math.h"
@@ -104,9 +118,9 @@ const EnumPropertyItem rna_enum_attribute_domain_with_auto_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);
}
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 848779c49f7..2735a00ee75 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", ""},
@@ -934,7 +934,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");
}
@@ -1844,6 +1844,26 @@ static void rna_def_gpencil_options(BlenderRNA *brna)
RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
RNA_def_property_update(prop, NC_SCENE | ND_TOOLSETTINGS, NULL);
+ prop = RNA_def_property(srna, "use_automasking_stroke", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(
+ prop, NULL, "sculpt_mode_flag", GP_SCULPT_FLAGMODE_AUTOMASK_STROKE);
+ RNA_def_property_ui_text(prop, "Auto-Masking Strokes", "Mask strokes below brush cursor");
+ RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
+ RNA_def_property_update(prop, NC_SCENE | ND_TOOLSETTINGS, NULL);
+
+ prop = RNA_def_property(srna, "use_automasking_layer", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "sculpt_mode_flag", GP_SCULPT_FLAGMODE_AUTOMASK_LAYER);
+ RNA_def_property_ui_text(prop, "Auto-Masking Layer", "Mask strokes using active layer");
+ RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
+ RNA_def_property_update(prop, NC_SCENE | ND_TOOLSETTINGS, NULL);
+
+ prop = RNA_def_property(srna, "use_automasking_material", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(
+ prop, NULL, "sculpt_mode_flag", GP_SCULPT_FLAGMODE_AUTOMASK_MATERIAL);
+ RNA_def_property_ui_text(prop, "Auto-Masking Material", "Mask strokes using active material");
+ RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
+ RNA_def_property_update(prop, NC_SCENE | ND_TOOLSETTINGS, NULL);
+
/* Material */
prop = RNA_def_property(srna, "material", PROP_POINTER, PROP_NONE);
RNA_def_property_struct_type(prop, "Material");
@@ -1931,7 +1951,12 @@ 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);
+ RNA_def_property_ui_text(
+ prop, "Points per Curve", "Number of control points in a newly added curve");
prop = RNA_def_property(srna, "scale_uniform", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flag", BRUSH_CURVES_SCULPT_FLAG_SCALE_UNIFORM);
@@ -1950,6 +1975,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(
@@ -1970,7 +2002,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,
@@ -1983,7 +2015,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,
@@ -1992,7 +2024,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",
@@ -2019,7 +2051,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,
@@ -2031,7 +2063,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",
@@ -2040,7 +2072,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..dcf0647392e 100644
--- a/source/blender/makesrna/intern/rna_camera.c
+++ b/source/blender/makesrna/intern/rna_camera.c
@@ -111,13 +111,70 @@ 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;
+}
+
+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 +236,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);
@@ -736,6 +804,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..24f226eb6e6 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;
@@ -691,11 +694,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 +1626,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 +1647,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 +1785,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 7a1a368551f..7cf34db4cf4 100644
--- a/source/blender/makesrna/intern/rna_curves.c
+++ b/source/blender/makesrna/intern/rna_curves.c
@@ -30,7 +30,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 +38,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 +47,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 +94,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 +143,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 +240,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 +248,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 +257,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,6 +292,22 @@ 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);
+ /* 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_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_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_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 be2ac6b12be..c3d5819caa3 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},
};
@@ -232,6 +234,11 @@ static const EnumPropertyItem gpencil_envelope_mode_items[] = {
"Add fill segments to create the envelope. Don't keep the original stroke"},
{0, NULL, 0, NULL, NULL},
};
+static const EnumPropertyItem modifier_noise_random_mode_items[] = {
+ {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
#ifdef RNA_RUNTIME
@@ -335,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));
@@ -746,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);
@@ -924,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);
@@ -959,6 +965,12 @@ static void rna_def_modifier_gpencilnoise(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "Inverse Pass", "Inverse filter");
RNA_def_property_update(prop, 0, "rna_GpencilModifier_update");
+ 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", "Where to perform randomization");
+ RNA_def_property_update(prop, 0, "rna_GpencilModifier_update");
+
RNA_define_lib_overridable(false);
}
@@ -3259,12 +3271,6 @@ static void rna_def_modifier_gpencillineart(BlenderRNA *brna)
RNA_def_property_range(prop, 0.0f, 30.0f);
RNA_def_property_update(prop, NC_SCENE, "rna_GpencilModifier_update");
- prop = RNA_def_property(srna, "use_remove_doubles", PROP_BOOLEAN, PROP_NONE);
- RNA_def_property_boolean_sdna(prop, NULL, "calculation_flags", LRT_REMOVE_DOUBLES);
- RNA_def_property_ui_text(
- prop, "Remove Doubles", "Remove doubles from the source geometry before generating stokes");
- RNA_def_property_update(prop, NC_SCENE, "rna_GpencilModifier_update");
-
prop = RNA_def_property(srna, "use_loose_as_contour", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "calculation_flags", LRT_LOOSE_AS_CONTOUR);
RNA_def_property_ui_text(prop, "Loose As Contour", "Loose edges will have contour type");
diff --git a/source/blender/makesrna/intern/rna_image.c b/source/blender/makesrna/intern/rna_image.c
index bd3b03add95..269ebe1581f 100644
--- a/source/blender/makesrna/intern/rna_image.c
+++ b/source/blender/makesrna/intern/rna_image.c
@@ -175,7 +175,7 @@ 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; */
@@ -397,7 +397,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 +446,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;
@@ -737,6 +737,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);
}
diff --git a/source/blender/makesrna/intern/rna_image_api.c b/source/blender/makesrna/intern/rna_image_api.c
index 29f639fbe65..46bb0df5c11 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");
- }
- 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);
+ 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);
}
-
- 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' */
+ Scene *scene = CTX_data_scene(C);
+ ImageSaveOptions opts;
- if (IMB_saveiff(ibuf, filepath, ibuf->flags)) {
- image->type = IMA_TYPE_IMAGE;
-
- if (image->source == IMA_SRC_GENERATED) {
- image->source = IMA_SRC_FILE;
- }
-
- 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 {
@@ -234,7 +197,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);
}
diff --git a/source/blender/makesrna/intern/rna_internal.h b/source/blender/makesrna/intern/rna_internal.h
index bf4eec433c4..058c63f640a 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,8 @@ 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);
/* 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..4f88959b5ba 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;
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..8c9c66bffcf 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));
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 ec0a182e338..da4be3cd0da 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,9 +1089,10 @@ 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. */
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);
}
}
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..4c410782326 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);
}
@@ -6991,7 +6994,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_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 eaf2142495e..841c250df4c 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},
};
@@ -489,6 +489,13 @@ static const EnumPropertyItem rna_node_geometry_curve_handle_side_items[] = {
{GEO_NODE_CURVE_HANDLE_RIGHT, "RIGHT", ICON_NONE, "Right", "Use the right handles"},
{0, NULL, 0, NULL, NULL}};
+static const EnumPropertyItem rna_node_combsep_color_items[] = {
+ {NODE_COMBSEP_COLOR_RGB, "RGB", ICON_NONE, "RGB", "Use RGB color processing"},
+ {NODE_COMBSEP_COLOR_HSV, "HSV", ICON_NONE, "HSV", "Use HSV color processing"},
+ {NODE_COMBSEP_COLOR_HSL, "HSL", ICON_NONE, "HSL", "Use HSL color processing"},
+ {0, NULL, 0, NULL, NULL},
+};
+
#ifndef RNA_RUNTIME
static const EnumPropertyItem node_sampler_type_items[] = {
{0, "NEAREST", 0, "Nearest", ""},
@@ -1591,16 +1598,16 @@ 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;
@@ -2749,7 +2756,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;
@@ -3063,10 +3070,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);
@@ -4516,9 +4523,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},
};
@@ -4537,46 +4544,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},
};
@@ -4616,7 +4658,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},
};
@@ -5050,6 +5097,18 @@ static void def_fn_input_string(StructRNA *srna)
RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update");
}
+static void def_fn_combsep_color(StructRNA *srna)
+{
+ PropertyRNA *prop;
+
+ RNA_def_struct_sdna_from(srna, "NodeCombSepColor", "storage");
+
+ prop = RNA_def_property(srna, "mode", PROP_ENUM, PROP_NONE);
+ RNA_def_property_enum_items(prop, rna_node_combsep_color_items);
+ RNA_def_property_ui_text(prop, "Mode", "Mode of color processing");
+ RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_socket_update");
+}
+
/* -- Shader Nodes ---------------------------------------------------------- */
static void def_sh_output(StructRNA *srna)
@@ -5401,6 +5460,17 @@ static void def_sh_tex_image(StructRNA *srna)
RNA_def_property_update(prop, 0, "rna_Node_update");
}
+static void def_tex_combsep_color(StructRNA *srna)
+{
+ PropertyRNA *prop;
+
+ prop = RNA_def_property(srna, "mode", PROP_ENUM, PROP_NONE);
+ RNA_def_property_enum_sdna(prop, NULL, "custom1");
+ RNA_def_property_enum_items(prop, rna_node_combsep_color_items);
+ RNA_def_property_ui_text(prop, "Mode", "Mode of color processing");
+ RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_socket_update");
+}
+
static void def_geo_image_texture(StructRNA *srna)
{
static const EnumPropertyItem fn_tex_prop_interpolation_items[] = {
@@ -5487,8 +5557,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");
}
@@ -5551,11 +5620,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},
};
@@ -5567,13 +5653,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");
}
@@ -5622,19 +5708,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");
}
@@ -5710,8 +5798,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");
}
@@ -5953,7 +6040,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");
}
@@ -5964,7 +6051,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");
}
@@ -5975,7 +6062,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);
@@ -5993,7 +6080,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");
}
@@ -6004,7 +6091,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");
}
@@ -6015,7 +6102,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");
}
@@ -6037,7 +6124,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");
}
@@ -6308,6 +6395,25 @@ static void def_sh_output_aov(StructRNA *srna)
RNA_def_struct_sdna_from(srna, "bNode", NULL);
}
+static void def_sh_combsep_color(StructRNA *srna)
+{
+ static const EnumPropertyItem type_items[] = {
+ {NODE_COMBSEP_COLOR_RGB, "RGB", ICON_NONE, "RGB", "Use RGB color processing"},
+ {NODE_COMBSEP_COLOR_HSV, "HSV", ICON_NONE, "HSV", "Use HSV color processing"},
+ {NODE_COMBSEP_COLOR_HSL, "HSL", ICON_NONE, "HSL", "Use HSL color processing"},
+ {0, NULL, 0, NULL, NULL},
+ };
+
+ PropertyRNA *prop;
+
+ RNA_def_struct_sdna_from(srna, "NodeCombSepColor", "storage");
+
+ prop = RNA_def_property(srna, "mode", PROP_ENUM, PROP_NONE);
+ RNA_def_property_enum_items(prop, type_items);
+ RNA_def_property_ui_text(prop, "Mode", "Mode of color processing");
+ RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_socket_update");
+}
+
static void def_sh_script(StructRNA *srna)
{
PropertyRNA *prop;
@@ -8071,6 +8177,32 @@ static void def_cmp_ycc(StructRNA *srna)
RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update");
}
+static void def_cmp_combsep_color(StructRNA *srna)
+{
+ static const EnumPropertyItem mode_items[] = {
+ {CMP_NODE_COMBSEP_COLOR_RGB, "RGB", ICON_NONE, "RGB", "Use RGB color processing"},
+ {CMP_NODE_COMBSEP_COLOR_HSV, "HSV", ICON_NONE, "HSV", "Use HSV color processing"},
+ {CMP_NODE_COMBSEP_COLOR_HSL, "HSL", ICON_NONE, "HSL", "Use HSL color processing"},
+ {CMP_NODE_COMBSEP_COLOR_YCC, "YCC", ICON_NONE, "YCbCr", "Use YCbCr color processing"},
+ {CMP_NODE_COMBSEP_COLOR_YUV, "YUV", ICON_NONE, "YUV", "Use YUV color processing"},
+ {0, NULL, 0, NULL, NULL},
+ };
+
+ PropertyRNA *prop;
+
+ RNA_def_struct_sdna_from(srna, "NodeCMPCombSepColor", "storage");
+
+ prop = RNA_def_property(srna, "mode", PROP_ENUM, PROP_NONE);
+ RNA_def_property_enum_items(prop, mode_items);
+ RNA_def_property_ui_text(prop, "Mode", "Mode of color processing");
+ RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_socket_update");
+
+ prop = RNA_def_property(srna, "ycc_mode", PROP_ENUM, PROP_NONE);
+ RNA_def_property_enum_items(prop, node_ycc_items);
+ RNA_def_property_ui_text(prop, "Color Space", "Color space used for YCbCrA processing");
+ RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update");
+}
+
static void def_cmp_movieclip(StructRNA *srna)
{
PropertyRNA *prop;
@@ -12294,7 +12426,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 98fc6633f78..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");
}
@@ -2484,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..4108baca2fa 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));
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..72ad695cd03 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, "COORDS", 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 eachother", ""},
+ {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..9b8e94db081 100644
--- a/source/blender/makesrna/intern/rna_scene.c
+++ b/source/blender/makesrna/intern/rna_scene.c
@@ -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,
@@ -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,12 +2702,12 @@ 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");
}
diff --git a/source/blender/makesrna/intern/rna_sculpt_paint.c b/source/blender/makesrna/intern/rna_sculpt_paint.c
index 017e8bde7a1..ab5e4c2f0d5 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");
}
diff --git a/source/blender/makesrna/intern/rna_sequencer.c b/source/blender/makesrna/intern/rna_sequencer.c
index 51f62b62c8e..8acc31cd71a 100644
--- a/source/blender/makesrna/intern/rna_sequencer.c
+++ b/source/blender/makesrna/intern/rna_sequencer.c
@@ -341,7 +341,7 @@ 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_time_left_handle_frame_set(seq, value);
SEQ_transform_fix_single_image_seq_offsets(seq);
do_sequence_frame_change_update(scene, seq);
SEQ_relations_invalidate_cache_composite(scene, seq);
@@ -352,7 +352,7 @@ 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_time_right_handle_frame_set(seq, value);
SEQ_transform_fix_single_image_seq_offsets(seq);
do_sequence_frame_change_update(scene, seq);
SEQ_relations_invalidate_cache_composite(scene, seq);
@@ -376,24 +376,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 +437,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(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 +445,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))
@@ -522,13 +504,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 +556,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 +700,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)
@@ -1057,14 +1034,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 +1178,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];
@@ -1419,7 +1396,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 +1779,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 +2014,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 +3164,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_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..2714b4157fd 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 */
+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 fb3fa69139a..af43133c979 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},
@@ -1565,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");
}
@@ -1575,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");
}
@@ -1587,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");
}
@@ -2024,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;
@@ -2426,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");
}
@@ -2442,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");
}
@@ -2635,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");
}
@@ -3338,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,
@@ -5461,6 +5461,17 @@ static void rna_def_space_image(BlenderRNA *brna)
RNA_def_property_clear_flag(prop, PROP_EDITABLE);
RNA_def_property_ui_text(prop, "Show Mask Editor", "Show Mask editing related properties");
+ /* Gizmo Toggles. */
+ prop = RNA_def_property(srna, "show_gizmo", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_negative_sdna(prop, NULL, "gizmo_flag", SI_GIZMO_HIDE);
+ RNA_def_property_ui_text(prop, "Show Gizmo", "Show gizmos of all types");
+ RNA_def_property_update(prop, NC_SPACE | ND_SPACE_IMAGE, NULL);
+
+ prop = RNA_def_property(srna, "show_gizmo_navigate", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_negative_sdna(prop, NULL, "gizmo_flag", SI_GIZMO_HIDE_NAVIGATE);
+ RNA_def_property_ui_text(prop, "Navigate Gizmo", "Viewport navigation gizmo");
+ RNA_def_property_update(prop, NC_SPACE | ND_SPACE_IMAGE, NULL);
+
/* Overlays */
prop = RNA_def_property(srna, "overlay", PROP_POINTER, PROP_NONE);
RNA_def_property_flag(prop, PROP_NEVER_NULL);
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_userdef.c b/source/blender/makesrna/intern/rna_userdef.c
index 6f57e2755ee..43e8879fc17 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},
};
@@ -1101,6 +1101,16 @@ int rna_show_statusbar_vram_editable(struct PointerRNA *UNUSED(ptr), const char
return GPU_mem_stats_supported() ? PROP_EDITABLE : 0;
}
+static int rna_userdef_experimental_use_new_curve_tools_editable(struct PointerRNA *UNUSED(ptr),
+ const char **r_info)
+{
+ if (U.experimental.use_new_curves_type) {
+ return PROP_EDITABLE;
+ }
+ *r_info = "Only available when new curves type is enabled";
+ return 0;
+}
+
#else
# define USERDEF_TAG_DIRTY_PROPERTY_UPDATE_ENABLE \
@@ -6394,6 +6404,12 @@ static void rna_def_userdef_experimental(BlenderRNA *brna)
RNA_def_property_boolean_sdna(prop, NULL, "use_new_curves_type", 1);
RNA_def_property_ui_text(prop, "New Curves Type", "Enable the new curves data type in the UI");
+ prop = RNA_def_property(srna, "use_new_curves_tools", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "use_new_curves_tools", 1);
+ RNA_def_property_editable_func(prop, "rna_userdef_experimental_use_new_curve_tools_editable");
+ RNA_def_property_ui_text(
+ prop, "New Curves Tools", "Enable additional features for the new curves data block");
+
prop = RNA_def_property(srna, "use_cycles_debug", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "use_cycles_debug", 1);
RNA_def_property_ui_text(prop, "Cycles Debug", "Enable Cycles debugging options for developers");
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 b09a9ab0733..1dc2cbe9e69 100644
--- a/source/blender/makesrna/intern/rna_wm.c
+++ b/source/blender/makesrna/intern/rna_wm.c
@@ -36,16 +36,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", ""},
@@ -135,22 +135,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 +177,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 +188,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 +268,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 +285,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"},
@@ -896,8 +896,10 @@ 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 */
+/**
+ * Assumes value to be an enum from rna_enum_event_type_items.
+ * Function makes sure keymodifiers are only valid keys, ESC keeps it unaltered.
+ */
static void rna_wmKeyMapItem_keymodifier_set(PointerRNA *ptr, int value)
{
wmKeyMapItem *kmi = ptr->data;
@@ -1155,9 +1157,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)
@@ -2599,6 +2599,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_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_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_correctivesmooth.c b/source/blender/modifiers/intern/MOD_correctivesmooth.c
index 52162eaacc5..8b6c306dae8 100644
--- a/source/blender/modifiers/intern/MOD_correctivesmooth.c
+++ b/source/blender/modifiers/intern/MOD_correctivesmooth.c
@@ -798,12 +798,25 @@ 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;
+
+ if (ID_IS_OVERRIDE_LIBRARY(id_owner)) {
+ 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..149cf0c0cbb 100644
--- a/source/blender/modifiers/intern/MOD_displace.c
+++ b/source/blender/modifiers/intern/MOD_displace.c
@@ -310,13 +310,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_explode.c b/source/blender/modifiers/intern/MOD_explode.c
index 9e2bb79138e..d76a750f7e8 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++) {
@@ -911,7 +911,6 @@ static Mesh *explodeMesh(ExplodeModifierData *emd,
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;
@@ -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..06ded1c4488 100644
--- a/source/blender/modifiers/intern/MOD_laplaciandeform.c
+++ b/source/blender/modifiers/intern/MOD_laplaciandeform.c
@@ -843,11 +843,26 @@ 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;
+
+ if (ID_IS_OVERRIDE_LIBRARY(id_owner)) {
+ 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 c2e9e5ebe7d..0cff85d30ec 100644
--- a/source/blender/modifiers/intern/MOD_meshdeform.c
+++ b/source/blender/modifiers/intern/MOD_meshdeform.c
@@ -581,26 +581,49 @@ 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;
+ MeshDeformModifierData mmd = *(const MeshDeformModifierData *)md;
+
+ if (ID_IS_OVERRIDE_LIBRARY(id_owner)) {
+ 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;
+ }
+ }
- BLO_write_struct_array(writer, MDefInfluence, mmd->influences_num, mmd->bindinfluences);
+ 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);
+ if (mmd.verts_num > 0) {
+ BLO_write_int32_array(writer, mmd.verts_num + 1, mmd.bindoffsets);
}
else {
- BLI_assert(mmd->bindoffsets == NULL);
+ 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);
+ 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)
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..e0105e4962d 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"
@@ -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;
}
@@ -985,17 +987,16 @@ static Vector<OutputAttributeToStore> compute_attributes_to_store(
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);
}
@@ -1730,9 +1731,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 +1803,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..c6a606360e3 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;
@@ -315,23 +315,23 @@ ModifierTypeInfo modifierType_ParticleSystem = {
/* 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 08925e8aeb1..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);
@@ -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,11 +1126,11 @@ static Mesh *modifyMesh(ModifierData *md, const ModifierEvalContext *ctx, Mesh *
MEM_freeN(vert_loop_map);
}
- if ((ltmd->flag & MOD_SCREW_NORMAL_CALC)) {
+ if (do_normal_create) {
BKE_mesh_vertex_normals_clear_dirty(result);
}
- if ((ltmd->flag & MOD_SCREW_MERGE) && (screw_ofs == 0.0f)) {
+ if (do_remove_doubles) {
result = mesh_remove_doubles_on_axis(result,
mvert_new,
totvert,
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_surfacedeform.c b/source/blender/modifiers/intern/MOD_surfacedeform.c
index a80918b8d2b..9b0012e3890 100644
--- a/source/blender/modifiers/intern/MOD_surfacedeform.c
+++ b/source/blender/modifiers/intern/MOD_surfacedeform.c
@@ -1166,8 +1166,8 @@ static bool surfacedeformBind(Object *ob,
SurfaceDeformModifierData *smd_eval,
float (*vertexCos)[3],
uint verts_num,
- uint tpolys_num,
- uint tverts_num,
+ uint target_polys_num,
+ uint target_verts_num,
Mesh *target,
Mesh *mesh)
{
@@ -1182,7 +1182,7 @@ static bool surfacedeformBind(Object *ob,
SDefAdjacency *adj_array;
SDefEdgePolys *edge_polys;
- vert_edges = MEM_calloc_arrayN(tverts_num, sizeof(*vert_edges), "SDefVertEdgeMap");
+ vert_edges = MEM_calloc_arrayN(target_verts_num, sizeof(*vert_edges), "SDefVertEdgeMap");
if (vert_edges == NULL) {
BKE_modifier_set_error(ob, (ModifierData *)smd_eval, "Out of memory");
return false;
@@ -1220,7 +1220,7 @@ static bool surfacedeformBind(Object *ob,
}
adj_result = buildAdjacencyMap(
- mpoly, medge, mloop, tpolys_num, tedges_num, vert_edges, adj_array, edge_polys);
+ mpoly, medge, mloop, target_polys_num, tedges_num, vert_edges, adj_array, edge_polys);
if (adj_result == MOD_SDEF_BIND_RESULT_NONMANY_ERR) {
BKE_modifier_set_error(
@@ -1233,7 +1233,8 @@ static bool surfacedeformBind(Object *ob,
}
smd_orig->mesh_verts_num = verts_num;
- smd_orig->polys_num = tpolys_num;
+ smd_orig->target_verts_num = target_verts_num;
+ smd_orig->target_polys_num = target_polys_num;
int defgrp_index;
MDeformVert *dvert;
@@ -1249,7 +1250,8 @@ static bool surfacedeformBind(Object *ob,
.medge = medge,
.mloop = mloop,
.looptri = BKE_mesh_runtime_looptri_ensure(target),
- .targetCos = MEM_malloc_arrayN(tverts_num, sizeof(float[3]), "SDefTargetBindVertArray"),
+ .targetCos = MEM_malloc_arrayN(
+ target_verts_num, sizeof(float[3]), "SDefTargetBindVertArray"),
.bind_verts = smd_orig->verts,
.vertexCos = vertexCos,
.falloff = smd_orig->falloff,
@@ -1268,7 +1270,7 @@ static bool surfacedeformBind(Object *ob,
invert_m4_m4(data.imat, smd_orig->mat);
- for (int i = 0; i < tverts_num; i++) {
+ for (int i = 0; i < target_verts_num; i++) {
mul_v3_m4v3(data.targetCos[i], smd_orig->mat, mvert[i].co);
}
@@ -1431,7 +1433,7 @@ static void surfacedeformModifier_do(ModifierData *md,
{
SurfaceDeformModifierData *smd = (SurfaceDeformModifierData *)md;
Mesh *target;
- uint tverts_num, tpolys_num;
+ uint target_verts_num, target_polys_num;
/* Exit function if bind flag is not set (free bind data if any). */
if (!(smd->flags & MOD_SDEF_BIND)) {
@@ -1453,8 +1455,8 @@ static void surfacedeformModifier_do(ModifierData *md,
return;
}
- tverts_num = BKE_mesh_wrapper_vert_len(target);
- tpolys_num = BKE_mesh_wrapper_poly_len(target);
+ target_verts_num = BKE_mesh_wrapper_vert_len(target);
+ target_polys_num = BKE_mesh_wrapper_poly_len(target);
/* If not bound, execute bind. */
if (smd->verts == NULL) {
@@ -1473,25 +1475,62 @@ static void surfacedeformModifier_do(ModifierData *md,
/* Avoid converting edit-mesh data, binding is an exception. */
BKE_mesh_wrapper_ensure_mdata(target);
- if (!surfacedeformBind(
- ob, smd_orig, smd, vertexCos, verts_num, tpolys_num, tverts_num, target, mesh)) {
+ if (!surfacedeformBind(ob,
+ smd_orig,
+ smd,
+ vertexCos,
+ verts_num,
+ target_polys_num,
+ target_verts_num,
+ target,
+ mesh)) {
smd->flags &= ~MOD_SDEF_BIND;
}
/* Early abort, this is binding 'call', no need to perform whole evaluation. */
return;
}
- /* Poly count checks */
+ /* Geometry count on the deforming mesh. */
if (smd->mesh_verts_num != verts_num) {
BKE_modifier_set_error(
ob, md, "Vertices changed from %u to %u", smd->mesh_verts_num, verts_num);
return;
}
- if (smd->polys_num != tpolys_num) {
+
+ /* Geometry count on the target mesh. */
+ if (smd->target_polys_num != target_polys_num && smd->target_verts_num == 0) {
+ /* Change in the number of polygons does not really imply change in the vertex count, but
+ * this is how the modifier worked before the vertex count was known. Follow the legacy
+ * logic without requirement to re-bind the mesh. */
BKE_modifier_set_error(
- ob, md, "Target polygons changed from %u to %u", smd->polys_num, tpolys_num);
+ ob, md, "Target polygons changed from %u to %u", smd->target_polys_num, target_polys_num);
return;
}
+ if (smd->target_verts_num != 0 && smd->target_verts_num != target_verts_num) {
+ if (smd->target_verts_num > target_verts_num) {
+ /* Number of vertices on the target did reduce. There is no usable recovery from this. */
+ BKE_modifier_set_error(ob,
+ md,
+ "Target vertices changed from %u to %u",
+ smd->target_verts_num,
+ target_verts_num);
+ return;
+ }
+
+ /* Assume the increase in the vertex count means that the "new" vertices in the target mesh are
+ * added after the original ones. This covers typical case when target was at the subdivision
+ * level 0 and then subdivision was increased (i.e. for the render purposes). */
+
+ BKE_modifier_set_error(ob,
+ md,
+ "Target vertices changed from %u to %u, continuing anyway",
+ smd->target_verts_num,
+ target_verts_num);
+
+ /* In theory we only need the `smd->verts_num` vertices in the `targetCos` for evaluation, but
+ * it is not currently possible to request a subset of coordinates: the API expects that the
+ * caller needs coordinates of all vertices and asserts for it. */
+ }
/* Early out if modifier would not affect input at all - still *after* the sanity checks
* (and potential binding) above. */
@@ -1507,7 +1546,7 @@ static void surfacedeformModifier_do(ModifierData *md,
/* Actual vertex location update starts here */
SDefDeformData data = {
.bind_verts = smd->verts,
- .targetCos = MEM_malloc_arrayN(tverts_num, sizeof(float[3]), "SDefTargetVertArray"),
+ .targetCos = MEM_malloc_arrayN(target_verts_num, sizeof(float[3]), "SDefTargetVertArray"),
.vertexCos = vertexCos,
.dvert = dvert,
.defgrp_index = defgrp_index,
@@ -1516,7 +1555,8 @@ static void surfacedeformModifier_do(ModifierData *md,
};
if (data.targetCos != NULL) {
- BKE_mesh_wrapper_vert_coords_copy_with_mat4(target, data.targetCos, tverts_num, smd->mat);
+ BKE_mesh_wrapper_vert_coords_copy_with_mat4(
+ target, data.targetCos, target_verts_num, smd->mat);
TaskParallelSettings settings;
BLI_parallel_range_settings_defaults(&settings);
@@ -1629,27 +1669,41 @@ 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;
+
+ if (ID_IS_OVERRIDE_LIBRARY(id_owner)) {
+ 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 79972d1911d..402d7b2c99e 100644
--- a/source/blender/modifiers/intern/MOD_warp.c
+++ b/source/blender/modifiers/intern/MOD_warp.c
@@ -489,10 +489,12 @@ 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 *wmd = (const WarpModifierData *)md;
+ BLO_write_struct(writer, WarpModifierData, wmd);
+
if (wmd->curfalloff) {
BKE_curvemapping_blend_write(writer, wmd->curfalloff);
}
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..65393370268 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;
@@ -206,8 +206,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 +213,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_composite.h b/source/blender/nodes/NOD_composite.h
index 3d3450d9252..5d782674f16 100644
--- a/source/blender/nodes/NOD_composite.h
+++ b/source/blender/nodes/NOD_composite.h
@@ -126,6 +126,8 @@ void register_node_type_cmp_planetrackdeform(void);
void register_node_type_cmp_cornerpin(void);
void register_node_type_cmp_separate_xyz(void);
void register_node_type_cmp_combine_xyz(void);
+void register_node_type_cmp_separate_color(void);
+void register_node_type_cmp_combine_color(void);
void node_cmp_rlayers_outputs(struct bNodeTree *ntree, struct bNode *node);
void node_cmp_rlayers_register_pass(struct bNodeTree *ntree,
diff --git a/source/blender/nodes/NOD_function.h b/source/blender/nodes/NOD_function.h
index cde4b67e120..ad96fba1929 100644
--- a/source/blender/nodes/NOD_function.h
+++ b/source/blender/nodes/NOD_function.h
@@ -8,6 +8,7 @@ extern "C" {
void register_node_type_fn_align_euler_to_vector(void);
void register_node_type_fn_boolean_math(void);
+void register_node_type_fn_combine_color(void);
void register_node_type_fn_compare(void);
void register_node_type_fn_float_to_int(void);
void register_node_type_fn_input_bool(void);
@@ -19,6 +20,7 @@ void register_node_type_fn_input_vector(void);
void register_node_type_fn_random_value(void);
void register_node_type_fn_replace_string(void);
void register_node_type_fn_rotate_euler(void);
+void register_node_type_fn_separate_color(void);
void register_node_type_fn_slice_string(void);
void register_node_type_fn_string_length(void);
void register_node_type_fn_value_to_string(void);
diff --git a/source/blender/nodes/NOD_geometry_nodes_eval_log.hh b/source/blender/nodes/NOD_geometry_nodes_eval_log.hh
index 43792a2d90a..2917861f084 100644
--- a/source/blender/nodes/NOD_geometry_nodes_eval_log.hh
+++ b/source/blender/nodes/NOD_geometry_nodes_eval_log.hh
@@ -104,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;
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_shader.h b/source/blender/nodes/NOD_shader.h
index 4996f12e27d..1d1310360b8 100644
--- a/source/blender/nodes/NOD_shader.h
+++ b/source/blender/nodes/NOD_shader.h
@@ -43,6 +43,8 @@ void register_node_type_sh_vect_math(void);
void register_node_type_sh_squeeze(void);
void register_node_type_sh_dynamic(void);
void register_node_type_sh_invert(void);
+void register_node_type_sh_sepcolor(void);
+void register_node_type_sh_combcolor(void);
void register_node_type_sh_seprgb(void);
void register_node_type_sh_combrgb(void);
void register_node_type_sh_sephsv(void);
diff --git a/source/blender/nodes/NOD_static_types.h b/source/blender/nodes/NOD_static_types.h
index 5818fa631e7..e0a4d241b3b 100644
--- a/source/blender/nodes/NOD_static_types.h
+++ b/source/blender/nodes/NOD_static_types.h
@@ -42,9 +42,9 @@ DefNode(ShaderNode, SH_NODE_MATH, def_math, "MATH",
DefNode(ShaderNode, SH_NODE_VECTOR_MATH, def_vector_math, "VECT_MATH", VectorMath, "Vector Math", "" )
DefNode(ShaderNode, SH_NODE_SQUEEZE, 0, "SQUEEZE", Squeeze, "Squeeze Value", "" )
DefNode(ShaderNode, SH_NODE_INVERT, 0, "INVERT", Invert, "Invert", "" )
-DefNode(ShaderNode, SH_NODE_SEPRGB, 0, "SEPRGB", SeparateRGB, "Separate RGB", "" )
-DefNode(ShaderNode, SH_NODE_COMBRGB, 0, "COMBRGB", CombineRGB, "Combine RGB", "" )
-DefNode(ShaderNode, SH_NODE_HUE_SAT, 0, "HUE_SAT", HueSaturation, "Hue/Saturation", "" )
+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 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", "" )
@@ -106,8 +106,8 @@ DefNode(ShaderNode, SH_NODE_TEX_POINTDENSITY, def_sh_tex_pointdensity,"TEX
DefNode(ShaderNode, SH_NODE_TEX_COORD, def_sh_tex_coord, "TEX_COORD", TexCoord, "Texture Coordinate","" )
DefNode(ShaderNode, SH_NODE_VECTOR_ROTATE, def_sh_vector_rotate, "VECTOR_ROTATE", VectorRotate, "Vector Rotate", "" )
DefNode(ShaderNode, SH_NODE_VECT_TRANSFORM, def_sh_vect_transform, "VECT_TRANSFORM", VectorTransform, "Vector Transform", "" )
-DefNode(ShaderNode, SH_NODE_SEPHSV, 0, "SEPHSV", SeparateHSV, "Separate HSV", "" )
-DefNode(ShaderNode, SH_NODE_COMBHSV, 0, "COMBHSV", CombineHSV, "Combine HSV", "" )
+DefNode(ShaderNode, SH_NODE_SEPHSV_LEGACY, 0, "SEPHSV", SeparateHSV, "Separate HSV", "" )
+DefNode(ShaderNode, SH_NODE_COMBHSV_LEGACY, 0, "COMBHSV", CombineHSV, "Combine HSV", "" )
DefNode(ShaderNode, SH_NODE_UVMAP, def_sh_uvmap, "UVMAP", UVMap, "UV Map", "" )
DefNode(ShaderNode, SH_NODE_VERTEX_COLOR, def_sh_vertex_color, "VERTEX_COLOR", VertexColor, "Color Attribute", "" )
DefNode(ShaderNode, SH_NODE_UVALONGSTROKE, def_sh_uvalongstroke, "UVALONGSTROKE", UVAlongStroke, "UV Along Stroke", "" )
@@ -120,6 +120,8 @@ DefNode(ShaderNode, SH_NODE_TEX_IES, def_sh_tex_ies, "TEX
DefNode(ShaderNode, SH_NODE_TEX_WHITE_NOISE, def_sh_tex_white_noise, "TEX_WHITE_NOISE", TexWhiteNoise, "White Noise", "" )
DefNode(ShaderNode, SH_NODE_OUTPUT_AOV, def_sh_output_aov, "OUTPUT_AOV", OutputAOV, "AOV Output", "" )
DefNode(ShaderNode, SH_NODE_CURVE_FLOAT, def_float_curve, "CURVE_FLOAT", FloatCurve, "Float Curve", "" )
+DefNode(ShaderNode, SH_NODE_COMBINE_COLOR, def_sh_combsep_color, "COMBINE_COLOR", CombineColor, "Combine Color", "" )
+DefNode(ShaderNode, SH_NODE_SEPARATE_COLOR, def_sh_combsep_color, "SEPARATE_COLOR", SeparateColor, "Separate Color", "" )
DefNode(CompositorNode, CMP_NODE_VIEWER, def_cmp_viewer, "VIEWER", Viewer, "Viewer", "" )
DefNode(CompositorNode, CMP_NODE_RGB, 0, "RGB", RGB, "RGB", "" )
@@ -137,8 +139,8 @@ DefNode(CompositorNode, CMP_NODE_MAP_VALUE, def_cmp_map_value, "MAP_VA
DefNode(CompositorNode, CMP_NODE_MAP_RANGE, def_cmp_map_range, "MAP_RANGE", MapRange, "Map Range", "" )
DefNode(CompositorNode, CMP_NODE_TIME, def_time, "TIME", Time, "Time Curve", "" )
DefNode(CompositorNode, CMP_NODE_VECBLUR, def_cmp_vector_blur, "VECBLUR", VecBlur, "Vector Blur", "" )
-DefNode(CompositorNode, CMP_NODE_SEPRGBA, 0, "SEPRGBA", SepRGBA, "Separate RGBA", "" )
-DefNode(CompositorNode, CMP_NODE_SEPHSVA, 0, "SEPHSVA", SepHSVA, "Separate HSVA", "" )
+DefNode(CompositorNode, CMP_NODE_SEPRGBA_LEGACY, 0, "SEPRGBA", SepRGBA, "Separate RGBA", "" )
+DefNode(CompositorNode, CMP_NODE_SEPHSVA_LEGACY, 0, "SEPHSVA", SepHSVA, "Separate HSVA", "" )
DefNode(CompositorNode, CMP_NODE_SETALPHA, def_cmp_set_alpha, "SETALPHA", SetAlpha, "Set Alpha", "" )
DefNode(CompositorNode, CMP_NODE_HUE_SAT, 0, "HUE_SAT", HueSat, "Hue Saturation Value","" )
DefNode(CompositorNode, CMP_NODE_IMAGE, def_cmp_image, "IMAGE", Image, "Image", "" )
@@ -149,16 +151,16 @@ DefNode(CompositorNode, CMP_NODE_OUTPUT_FILE, 0, "OUTPUT
DefNode(CompositorNode, CMP_NODE_TEXTURE, def_texture, "TEXTURE", Texture, "Texture", "" )
DefNode(CompositorNode, CMP_NODE_TRANSLATE, def_cmp_translate, "TRANSLATE", Translate, "Translate", "" )
DefNode(CompositorNode, CMP_NODE_ZCOMBINE, def_cmp_zcombine, "ZCOMBINE", Zcombine, "Z Combine", "" )
-DefNode(CompositorNode, CMP_NODE_COMBRGBA, 0, "COMBRGBA", CombRGBA, "Combine RGBA", "" )
+DefNode(CompositorNode, CMP_NODE_COMBRGBA_LEGACY,0, "COMBRGBA", CombRGBA, "Combine RGBA", "" )
DefNode(CompositorNode, CMP_NODE_DILATEERODE, def_cmp_dilate_erode, "DILATEERODE", DilateErode, "Dilate/Erode", "" )
DefNode(CompositorNode, CMP_NODE_INPAINT, def_cmp_inpaint, "INPAINT", Inpaint, "Inpaint", "" )
DefNode(CompositorNode, CMP_NODE_DESPECKLE, def_cmp_despeckle, "DESPECKLE", Despeckle, "Despeckle", "" )
DefNode(CompositorNode, CMP_NODE_ROTATE, def_cmp_rotate, "ROTATE", Rotate, "Rotate", "" )
DefNode(CompositorNode, CMP_NODE_SCALE, def_cmp_scale, "SCALE", Scale, "Scale", "" )
-DefNode(CompositorNode, CMP_NODE_SEPYCCA, def_cmp_ycc, "SEPYCCA", SepYCCA, "Separate YCbCrA", "" )
-DefNode(CompositorNode, CMP_NODE_COMBYCCA, def_cmp_ycc, "COMBYCCA", CombYCCA, "Combine YCbCrA", "" )
-DefNode(CompositorNode, CMP_NODE_SEPYUVA, 0, "SEPYUVA", SepYUVA, "Separate YUVA", "" )
-DefNode(CompositorNode, CMP_NODE_COMBYUVA, 0, "COMBYUVA", CombYUVA, "Combine YUVA", "" )
+DefNode(CompositorNode, CMP_NODE_SEPYCCA_LEGACY, def_cmp_ycc, "SEPYCCA", SepYCCA, "Separate YCbCrA", "" )
+DefNode(CompositorNode, CMP_NODE_COMBYCCA_LEGACY,def_cmp_ycc, "COMBYCCA", CombYCCA, "Combine YCbCrA", "" )
+DefNode(CompositorNode, CMP_NODE_SEPYUVA_LEGACY, 0, "SEPYUVA", SepYUVA, "Separate YUVA", "" )
+DefNode(CompositorNode, CMP_NODE_COMBYUVA_LEGACY,0, "COMBYUVA", CombYUVA, "Combine YUVA", "" )
DefNode(CompositorNode, CMP_NODE_DIFF_MATTE, def_cmp_diff_matte, "DIFF_MATTE", DiffMatte, "Difference Key", "" )
DefNode(CompositorNode, CMP_NODE_COLOR_SPILL, def_cmp_color_spill, "COLOR_SPILL", ColorSpill, "Color Spill", "" )
DefNode(CompositorNode, CMP_NODE_CHROMA_MATTE, def_cmp_chroma_matte, "CHROMA_MATTE", ChromaMatte, "Chroma Key", "" )
@@ -170,7 +172,7 @@ DefNode(CompositorNode, CMP_NODE_ID_MASK, def_cmp_id_mask, "ID_MAS
DefNode(CompositorNode, CMP_NODE_DOUBLEEDGEMASK, def_cmp_double_edge_mask,"DOUBLEEDGEMASK", DoubleEdgeMask, "Double Edge Mask", "" )
DefNode(CompositorNode, CMP_NODE_DEFOCUS, def_cmp_defocus, "DEFOCUS", Defocus, "Defocus", "" )
DefNode(CompositorNode, CMP_NODE_DISPLACE, 0, "DISPLACE", Displace, "Displace", "" )
-DefNode(CompositorNode, CMP_NODE_COMBHSVA, 0, "COMBHSVA", CombHSVA, "Combine HSVA", "" )
+DefNode(CompositorNode, CMP_NODE_COMBHSVA_LEGACY,0, "COMBHSVA", CombHSVA, "Combine HSVA", "" )
DefNode(CompositorNode, CMP_NODE_MATH, def_math, "MATH", Math, "Math", "" )
DefNode(CompositorNode, CMP_NODE_LUMA_MATTE, def_cmp_luma_matte, "LUMA_MATTE", LumaMatte, "Luminance Key", "" )
DefNode(CompositorNode, CMP_NODE_BRIGHTCONTRAST, def_cmp_brightcontrast, "BRIGHTCONTRAST", BrightContrast, "Bright/Contrast", "" )
@@ -214,10 +216,12 @@ DefNode(CompositorNode, CMP_NODE_DENOISE, def_cmp_denoise, "DENOIS
DefNode(CompositorNode, CMP_NODE_EXPOSURE, 0, "EXPOSURE", Exposure, "Exposure", "" )
DefNode(CompositorNode, CMP_NODE_ANTIALIASING, def_cmp_antialiasing, "ANTIALIASING", AntiAliasing, "Anti-Aliasing", "" )
DefNode(CompositorNode, CMP_NODE_POSTERIZE, 0, "POSTERIZE", Posterize, "Posterize", "" )
-DefNode(CompositorNode, CMP_NODE_CONVERT_COLOR_SPACE,def_cmp_convert_color_space, "CONVERT_COLORSPACE", ConvertColorSpace, "Color Space","" )
-DefNode(CompositorNode, CMP_NODE_SCENE_TIME, 0, "SCENE_TIME", SceneTime, "Scene Time", "" )
+DefNode(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", "" )
+DefNode(CompositorNode, CMP_NODE_SEPARATE_COLOR, def_cmp_combsep_color, "SEPARATE_COLOR", SeparateColor, "Separate Color", "" )
+DefNode(CompositorNode, CMP_NODE_COMBINE_COLOR, def_cmp_combsep_color, "COMBINE_COLOR", CombineColor, "Combine Color", "" )
DefNode(TextureNode, TEX_NODE_OUTPUT, def_tex_output, "OUTPUT", Output, "Output", "" )
DefNode(TextureNode, TEX_NODE_CHECKER, 0, "CHECKER", Checker, "Checker", "" )
@@ -230,18 +234,20 @@ 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", "" )
DefNode(TextureNode, TEX_NODE_TRANSLATE, 0, "TRANSLATE", Translate, "Translate", "" )
DefNode(TextureNode, TEX_NODE_COORD, 0, "COORD", Coordinates, "Coordinates", "" )
DefNode(TextureNode, TEX_NODE_DISTANCE, 0, "DISTANCE", Distance, "Distance", "" )
-DefNode(TextureNode, TEX_NODE_COMPOSE, 0, "COMPOSE", Compose, "Combine RGBA", "" )
-DefNode(TextureNode, TEX_NODE_DECOMPOSE, 0, "DECOMPOSE", Decompose, "Separate RGBA", "" )
+DefNode(TextureNode, TEX_NODE_COMPOSE_LEGACY, 0, "COMPOSE", Compose, "Combine RGBA", "" )
+DefNode(TextureNode, TEX_NODE_DECOMPOSE_LEGACY,0, "DECOMPOSE", Decompose, "Separate RGBA", "" )
DefNode(TextureNode, TEX_NODE_VALTONOR, 0, "VALTONOR", ValToNor, "Value to Normal", "" )
DefNode(TextureNode, TEX_NODE_SCALE, 0, "SCALE", Scale, "Scale", "" )
DefNode(TextureNode, TEX_NODE_AT, 0, "AT", At, "At", "" )
+DefNode(TextureNode, TEX_NODE_COMBINE_COLOR, def_tex_combsep_color, "COMBINE_COLOR", CombineColor, "Combine Color", "" )
+DefNode(TextureNode, TEX_NODE_SEPARATE_COLOR, def_tex_combsep_color, "SEPARATE_COLOR", SeparateColor, "Separate Color", "" )
/* procedural textures */
DefNode(TextureNode, TEX_NODE_PROC+TEX_VORONOI, 0, "TEX_VORONOI", TexVoronoi, "Voronoi", "" )
DefNode(TextureNode, TEX_NODE_PROC+TEX_BLEND, 0, "TEX_BLEND", TexBlend, "Blend", "" )
@@ -256,6 +262,7 @@ DefNode(TextureNode, TEX_NODE_PROC+TEX_DISTNOISE, 0, "TEX_DI
DefNode(FunctionNode, FN_NODE_ALIGN_EULER_TO_VECTOR, def_fn_align_euler_to_vector, "ALIGN_EULER_TO_VECTOR", AlignEulerToVector, "Align Euler To Vector", "")
DefNode(FunctionNode, FN_NODE_BOOLEAN_MATH, def_boolean_math, "BOOLEAN_MATH", BooleanMath, "Boolean Math", "")
+DefNode(FunctionNode, FN_NODE_COMBINE_COLOR, def_fn_combsep_color, "COMBINE_COLOR", CombineColor, "Combine Color", "")
DefNode(FunctionNode, FN_NODE_COMPARE, def_compare, "COMPARE", Compare, "Compare", "")
DefNode(FunctionNode, FN_NODE_FLOAT_TO_INT, def_float_to_int, "FLOAT_TO_INT", FloatToInt, "Float to Integer", "")
DefNode(FunctionNode, FN_NODE_INPUT_BOOL, def_fn_input_bool, "INPUT_BOOL", InputBool, "Boolean", "")
@@ -267,6 +274,7 @@ DefNode(FunctionNode, FN_NODE_INPUT_VECTOR, def_fn_input_vector, "INPUT_VECTOR",
DefNode(FunctionNode, FN_NODE_RANDOM_VALUE, def_fn_random_value, "RANDOM_VALUE", RandomValue, "Random Value", "")
DefNode(FunctionNode, FN_NODE_REPLACE_STRING, 0, "REPLACE_STRING", ReplaceString, "Replace String", "")
DefNode(FunctionNode, FN_NODE_ROTATE_EULER, def_fn_rotate_euler, "ROTATE_EULER", RotateEuler, "Rotate Euler", "")
+DefNode(FunctionNode, FN_NODE_SEPARATE_COLOR, def_fn_combsep_color, "SEPARATE_COLOR", SeparateColor, "Separate Color", "")
DefNode(FunctionNode, FN_NODE_SLICE_STRING, 0, "SLICE_STRING", SliceString, "Slice String", "")
DefNode(FunctionNode, FN_NODE_STRING_LENGTH, 0, "STRING_LENGTH", StringLength, "String Length", "")
DefNode(FunctionNode, FN_NODE_VALUE_TO_STRING, 0, "VALUE_TO_STRING", ValueToString, "Value to String", "")
diff --git a/source/blender/nodes/NOD_texture.h b/source/blender/nodes/NOD_texture.h
index 0f07b17f165..9a2dc705c0d 100644
--- a/source/blender/nodes/NOD_texture.h
+++ b/source/blender/nodes/NOD_texture.h
@@ -46,6 +46,8 @@ void register_node_type_tex_at(void);
void register_node_type_tex_compose(void);
void register_node_type_tex_decompose(void);
+void register_node_type_tex_combine_color(void);
+void register_node_type_tex_separate_color(void);
void register_node_type_tex_proc_voronoi(void);
void register_node_type_tex_proc_blend(void);
diff --git a/source/blender/nodes/composite/CMakeLists.txt b/source/blender/nodes/composite/CMakeLists.txt
index 57f76f20ac6..c0100d77889 100644
--- a/source/blender/nodes/composite/CMakeLists.txt
+++ b/source/blender/nodes/composite/CMakeLists.txt
@@ -91,6 +91,7 @@ set(SRC
nodes/node_composite_rotate.cc
nodes/node_composite_scale.cc
nodes/node_composite_scene_time.cc
+ nodes/node_composite_sepcomb_color.cc
nodes/node_composite_sepcomb_hsva.cc
nodes/node_composite_sepcomb_rgba.cc
nodes/node_composite_sepcomb_xyz.cc
diff --git a/source/blender/nodes/composite/nodes/node_composite_sepcomb_color.cc b/source/blender/nodes/composite/nodes/node_composite_sepcomb_color.cc
new file mode 100644
index 00000000000..b253656a628
--- /dev/null
+++ b/source/blender/nodes/composite/nodes/node_composite_sepcomb_color.cc
@@ -0,0 +1,139 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+
+#include "node_composite_util.hh"
+
+static void node_cmp_combsep_color_init(bNodeTree *UNUSED(ntree), bNode *node)
+{
+ NodeCMPCombSepColor *data = MEM_cnew<NodeCMPCombSepColor>(__func__);
+ data->mode = CMP_NODE_COMBSEP_COLOR_RGB;
+ data->ycc_mode = BLI_YCC_ITU_BT709;
+ node->storage = data;
+}
+
+static void node_cmp_combsep_color_label(const ListBase *sockets, CMPNodeCombSepColorMode mode)
+{
+ bNodeSocket *sock1 = (bNodeSocket *)sockets->first;
+ bNodeSocket *sock2 = sock1->next;
+ bNodeSocket *sock3 = sock2->next;
+
+ node_sock_label_clear(sock1);
+ node_sock_label_clear(sock2);
+ node_sock_label_clear(sock3);
+
+ switch (mode) {
+ case CMP_NODE_COMBSEP_COLOR_RGB:
+ node_sock_label(sock1, "Red");
+ node_sock_label(sock2, "Green");
+ node_sock_label(sock3, "Blue");
+ break;
+ case CMP_NODE_COMBSEP_COLOR_HSV:
+ node_sock_label(sock1, "Hue");
+ node_sock_label(sock2, "Saturation");
+ node_sock_label(sock3, "Value");
+ break;
+ case CMP_NODE_COMBSEP_COLOR_HSL:
+ node_sock_label(sock1, "Hue");
+ node_sock_label(sock2, "Saturation");
+ node_sock_label(sock3, "Lightness");
+ break;
+ case CMP_NODE_COMBSEP_COLOR_YCC:
+ node_sock_label(sock1, "Y");
+ node_sock_label(sock2, "Cb");
+ node_sock_label(sock3, "Cr");
+ break;
+ case CMP_NODE_COMBSEP_COLOR_YUV:
+ node_sock_label(sock1, "Y");
+ node_sock_label(sock2, "U");
+ node_sock_label(sock3, "V");
+ break;
+ default:
+ BLI_assert_unreachable();
+ break;
+ }
+}
+
+/* **************** SEPARATE COLOR ******************** */
+
+namespace blender::nodes::node_composite_separate_color_cc {
+
+static void cmp_node_separate_color_declare(NodeDeclarationBuilder &b)
+{
+ b.add_input<decl::Color>(N_("Image")).default_value({1.0f, 1.0f, 1.0f, 1.0f});
+ b.add_output<decl::Float>(N_("Red"));
+ b.add_output<decl::Float>(N_("Green"));
+ b.add_output<decl::Float>(N_("Blue"));
+ b.add_output<decl::Float>(N_("Alpha"));
+}
+
+static void cmp_node_separate_color_update(bNodeTree *UNUSED(ntree), bNode *node)
+{
+ const NodeCMPCombSepColor *storage = (NodeCMPCombSepColor *)node->storage;
+ node_cmp_combsep_color_label(&node->outputs, (CMPNodeCombSepColorMode)storage->mode);
+}
+
+} // namespace blender::nodes::node_composite_separate_color_cc
+
+void register_node_type_cmp_separate_color()
+{
+ namespace file_ns = blender::nodes::node_composite_separate_color_cc;
+
+ static bNodeType ntype;
+
+ cmp_node_type_base(&ntype, CMP_NODE_SEPARATE_COLOR, "Separate Color", NODE_CLASS_CONVERTER);
+ ntype.declare = file_ns::cmp_node_separate_color_declare;
+ node_type_init(&ntype, node_cmp_combsep_color_init);
+ node_type_storage(
+ &ntype, "NodeCMPCombSepColor", node_free_standard_storage, node_copy_standard_storage);
+ node_type_update(&ntype, file_ns::cmp_node_separate_color_update);
+
+ nodeRegisterType(&ntype);
+}
+
+/* **************** COMBINE COLOR ******************** */
+
+namespace blender::nodes::node_composite_combine_color_cc {
+
+static void cmp_node_combine_color_declare(NodeDeclarationBuilder &b)
+{
+ b.add_input<decl::Float>(N_("Red")).default_value(0.0f).min(0.0f).max(1.0f).subtype(PROP_FACTOR);
+ b.add_input<decl::Float>(N_("Green"))
+ .default_value(0.0f)
+ .min(0.0f)
+ .max(1.0f)
+ .subtype(PROP_FACTOR);
+ b.add_input<decl::Float>(N_("Blue"))
+ .default_value(0.0f)
+ .min(0.0f)
+ .max(1.0f)
+ .subtype(PROP_FACTOR);
+ b.add_input<decl::Float>(N_("Alpha"))
+ .default_value(1.0f)
+ .min(0.0f)
+ .max(1.0f)
+ .subtype(PROP_FACTOR);
+ b.add_output<decl::Color>(N_("Image"));
+}
+
+static void cmp_node_combine_color_update(bNodeTree *UNUSED(ntree), bNode *node)
+{
+ const NodeCMPCombSepColor *storage = (NodeCMPCombSepColor *)node->storage;
+ node_cmp_combsep_color_label(&node->inputs, (CMPNodeCombSepColorMode)storage->mode);
+}
+
+} // namespace blender::nodes::node_composite_combine_color_cc
+
+void register_node_type_cmp_combine_color()
+{
+ namespace file_ns = blender::nodes::node_composite_combine_color_cc;
+
+ static bNodeType ntype;
+
+ cmp_node_type_base(&ntype, CMP_NODE_COMBINE_COLOR, "Combine Color", NODE_CLASS_CONVERTER);
+ ntype.declare = file_ns::cmp_node_combine_color_declare;
+ node_type_init(&ntype, node_cmp_combsep_color_init);
+ node_type_storage(
+ &ntype, "NodeCMPCombSepColor", node_free_standard_storage, node_copy_standard_storage);
+ node_type_update(&ntype, file_ns::cmp_node_combine_color_update);
+
+ nodeRegisterType(&ntype);
+}
diff --git a/source/blender/nodes/composite/nodes/node_composite_sepcomb_hsva.cc b/source/blender/nodes/composite/nodes/node_composite_sepcomb_hsva.cc
index 349c27d876d..a0d2485ea5a 100644
--- a/source/blender/nodes/composite/nodes/node_composite_sepcomb_hsva.cc
+++ b/source/blender/nodes/composite/nodes/node_composite_sepcomb_hsva.cc
@@ -28,7 +28,7 @@ void register_node_type_cmp_sephsva()
static bNodeType ntype;
- cmp_node_type_base(&ntype, CMP_NODE_SEPHSVA, "Separate HSVA", NODE_CLASS_CONVERTER);
+ cmp_node_type_base(&ntype, CMP_NODE_SEPHSVA_LEGACY, "Separate HSVA", NODE_CLASS_CONVERTER);
ntype.declare = file_ns::cmp_node_sephsva_declare;
nodeRegisterType(&ntype);
}
@@ -54,7 +54,7 @@ void register_node_type_cmp_combhsva()
static bNodeType ntype;
- cmp_node_type_base(&ntype, CMP_NODE_COMBHSVA, "Combine HSVA", NODE_CLASS_CONVERTER);
+ cmp_node_type_base(&ntype, CMP_NODE_COMBHSVA_LEGACY, "Combine HSVA", NODE_CLASS_CONVERTER);
ntype.declare = file_ns::cmp_node_combhsva_declare;
nodeRegisterType(&ntype);
diff --git a/source/blender/nodes/composite/nodes/node_composite_sepcomb_rgba.cc b/source/blender/nodes/composite/nodes/node_composite_sepcomb_rgba.cc
index c46603be847..ae46681b0f4 100644
--- a/source/blender/nodes/composite/nodes/node_composite_sepcomb_rgba.cc
+++ b/source/blender/nodes/composite/nodes/node_composite_sepcomb_rgba.cc
@@ -27,7 +27,7 @@ void register_node_type_cmp_seprgba()
static bNodeType ntype;
- cmp_node_type_base(&ntype, CMP_NODE_SEPRGBA, "Separate RGBA", NODE_CLASS_CONVERTER);
+ cmp_node_type_base(&ntype, CMP_NODE_SEPRGBA_LEGACY, "Separate RGBA", NODE_CLASS_CONVERTER);
ntype.declare = file_ns::cmp_node_seprgba_declare;
nodeRegisterType(&ntype);
@@ -54,7 +54,7 @@ void register_node_type_cmp_combrgba()
static bNodeType ntype;
- cmp_node_type_base(&ntype, CMP_NODE_COMBRGBA, "Combine RGBA", NODE_CLASS_CONVERTER);
+ cmp_node_type_base(&ntype, CMP_NODE_COMBRGBA_LEGACY, "Combine RGBA", NODE_CLASS_CONVERTER);
ntype.declare = file_ns::cmp_node_combrgba_declare;
nodeRegisterType(&ntype);
diff --git a/source/blender/nodes/composite/nodes/node_composite_sepcomb_ycca.cc b/source/blender/nodes/composite/nodes/node_composite_sepcomb_ycca.cc
index 9b5c153fddf..a3c40b61e64 100644
--- a/source/blender/nodes/composite/nodes/node_composite_sepcomb_ycca.cc
+++ b/source/blender/nodes/composite/nodes/node_composite_sepcomb_ycca.cc
@@ -33,7 +33,7 @@ void register_node_type_cmp_sepycca()
static bNodeType ntype;
- cmp_node_type_base(&ntype, CMP_NODE_SEPYCCA, "Separate YCbCrA", NODE_CLASS_CONVERTER);
+ cmp_node_type_base(&ntype, CMP_NODE_SEPYCCA_LEGACY, "Separate YCbCrA", NODE_CLASS_CONVERTER);
ntype.declare = file_ns::cmp_node_sepycca_declare;
node_type_init(&ntype, file_ns::node_composit_init_mode_sepycca);
@@ -66,7 +66,7 @@ void register_node_type_cmp_combycca()
static bNodeType ntype;
- cmp_node_type_base(&ntype, CMP_NODE_COMBYCCA, "Combine YCbCrA", NODE_CLASS_CONVERTER);
+ cmp_node_type_base(&ntype, CMP_NODE_COMBYCCA_LEGACY, "Combine YCbCrA", NODE_CLASS_CONVERTER);
ntype.declare = file_ns::cmp_node_combycca_declare;
node_type_init(&ntype, file_ns::node_composit_init_mode_combycca);
diff --git a/source/blender/nodes/composite/nodes/node_composite_sepcomb_yuva.cc b/source/blender/nodes/composite/nodes/node_composite_sepcomb_yuva.cc
index e458c9cfb7e..7fdece5904d 100644
--- a/source/blender/nodes/composite/nodes/node_composite_sepcomb_yuva.cc
+++ b/source/blender/nodes/composite/nodes/node_composite_sepcomb_yuva.cc
@@ -28,7 +28,7 @@ void register_node_type_cmp_sepyuva()
static bNodeType ntype;
- cmp_node_type_base(&ntype, CMP_NODE_SEPYUVA, "Separate YUVA", NODE_CLASS_CONVERTER);
+ cmp_node_type_base(&ntype, CMP_NODE_SEPYUVA_LEGACY, "Separate YUVA", NODE_CLASS_CONVERTER);
ntype.declare = file_ns::cmp_node_sepyuva_declare;
nodeRegisterType(&ntype);
@@ -55,7 +55,7 @@ void register_node_type_cmp_combyuva()
static bNodeType ntype;
- cmp_node_type_base(&ntype, CMP_NODE_COMBYUVA, "Combine YUVA", NODE_CLASS_CONVERTER);
+ cmp_node_type_base(&ntype, CMP_NODE_COMBYUVA_LEGACY, "Combine YUVA", NODE_CLASS_CONVERTER);
ntype.declare = file_ns::cmp_node_combyuva_declare;
nodeRegisterType(&ntype);
diff --git a/source/blender/nodes/function/CMakeLists.txt b/source/blender/nodes/function/CMakeLists.txt
index 6ccc4c7bf5c..d03f1cb63ff 100644
--- a/source/blender/nodes/function/CMakeLists.txt
+++ b/source/blender/nodes/function/CMakeLists.txt
@@ -20,6 +20,7 @@ set(INC
set(SRC
nodes/node_fn_align_euler_to_vector.cc
nodes/node_fn_boolean_math.cc
+ nodes/node_fn_combine_color.cc
nodes/node_fn_compare.cc
nodes/node_fn_float_to_int.cc
nodes/node_fn_input_bool.cc
@@ -31,6 +32,7 @@ set(SRC
nodes/node_fn_random_value.cc
nodes/node_fn_replace_string.cc
nodes/node_fn_rotate_euler.cc
+ nodes/node_fn_separate_color.cc
nodes/node_fn_slice_string.cc
nodes/node_fn_string_length.cc
nodes/node_fn_value_to_string.cc
diff --git a/source/blender/nodes/function/nodes/node_fn_combine_color.cc b/source/blender/nodes/function/nodes/node_fn_combine_color.cc
new file mode 100644
index 00000000000..c5fd3ce38a1
--- /dev/null
+++ b/source/blender/nodes/function/nodes/node_fn_combine_color.cc
@@ -0,0 +1,108 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+
+#include "node_function_util.hh"
+
+#include "UI_interface.h"
+#include "UI_resources.h"
+
+namespace blender::nodes {
+
+NODE_STORAGE_FUNCS(NodeCombSepColor)
+
+static void fn_node_combine_color_declare(NodeDeclarationBuilder &b)
+{
+ b.is_function_node();
+ b.add_input<decl::Float>(N_("Red")).default_value(0.0f).min(0.0f).max(1.0f).subtype(PROP_FACTOR);
+ b.add_input<decl::Float>(N_("Green"))
+ .default_value(0.0f)
+ .min(0.0f)
+ .max(1.0f)
+ .subtype(PROP_FACTOR);
+ b.add_input<decl::Float>(N_("Blue"))
+ .default_value(0.0f)
+ .min(0.0f)
+ .max(1.0f)
+ .subtype(PROP_FACTOR);
+ b.add_input<decl::Float>(N_("Alpha"))
+ .default_value(1.0f)
+ .min(0.0f)
+ .max(1.0f)
+ .subtype(PROP_FACTOR);
+ b.add_output<decl::Color>(N_("Color"));
+};
+
+static void fn_node_combine_color_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
+{
+ uiItemR(layout, ptr, "mode", 0, "", ICON_NONE);
+}
+
+static void fn_node_combine_color_update(bNodeTree *UNUSED(ntree), bNode *node)
+{
+ const NodeCombSepColor &storage = node_storage(*node);
+ node_combsep_color_label(&node->inputs, (NodeCombSepColorMode)storage.mode);
+}
+
+static void fn_node_combine_color_init(bNodeTree *UNUSED(tree), bNode *node)
+{
+ NodeCombSepColor *data = MEM_cnew<NodeCombSepColor>(__func__);
+ data->mode = NODE_COMBSEP_COLOR_RGB;
+ node->storage = data;
+}
+
+static const fn::MultiFunction *get_multi_function(bNode &bnode)
+{
+ const NodeCombSepColor &storage = node_storage(bnode);
+
+ static fn::CustomMF_SI_SI_SI_SI_SO<float, float, float, float, ColorGeometry4f> rgba_fn{
+ "RGB", [](float r, float g, float b, float a) { return ColorGeometry4f(r, g, b, a); }};
+ static fn::CustomMF_SI_SI_SI_SI_SO<float, float, float, float, ColorGeometry4f> hsva_fn{
+ "HSV", [](float h, float s, float v, float a) {
+ ColorGeometry4f r_color;
+ hsv_to_rgb(h, s, v, &r_color.r, &r_color.g, &r_color.b);
+ r_color.a = a;
+ return r_color;
+ }};
+ static fn::CustomMF_SI_SI_SI_SI_SO<float, float, float, float, ColorGeometry4f> hsla_fn{
+ "HSL", [](float h, float s, float l, float a) {
+ ColorGeometry4f color;
+ hsl_to_rgb(h, s, l, &color.r, &color.g, &color.b);
+ color.a = a;
+ return color;
+ }};
+
+ switch (storage.mode) {
+ case NODE_COMBSEP_COLOR_RGB:
+ return &rgba_fn;
+ case NODE_COMBSEP_COLOR_HSV:
+ return &hsva_fn;
+ case NODE_COMBSEP_COLOR_HSL:
+ return &hsla_fn;
+ }
+
+ BLI_assert_unreachable();
+ return nullptr;
+}
+
+static void fn_node_combine_color_build_multi_function(NodeMultiFunctionBuilder &builder)
+{
+ const fn::MultiFunction *fn = get_multi_function(builder.node());
+ builder.set_matching_fn(fn);
+}
+
+} // namespace blender::nodes
+
+void register_node_type_fn_combine_color(void)
+{
+ static bNodeType ntype;
+
+ fn_node_type_base(&ntype, FN_NODE_COMBINE_COLOR, "Combine Color", NODE_CLASS_CONVERTER);
+ ntype.declare = blender::nodes::fn_node_combine_color_declare;
+ node_type_update(&ntype, blender::nodes::fn_node_combine_color_update);
+ node_type_init(&ntype, blender::nodes::fn_node_combine_color_init);
+ node_type_storage(
+ &ntype, "NodeCombSepColor", node_free_standard_storage, node_copy_standard_storage);
+ ntype.build_multi_function = blender::nodes::fn_node_combine_color_build_multi_function;
+ ntype.draw_buttons = blender::nodes::fn_node_combine_color_layout;
+
+ nodeRegisterType(&ntype);
+}
diff --git a/source/blender/nodes/function/nodes/node_fn_separate_color.cc b/source/blender/nodes/function/nodes/node_fn_separate_color.cc
new file mode 100644
index 00000000000..1701dfdc6fa
--- /dev/null
+++ b/source/blender/nodes/function/nodes/node_fn_separate_color.cc
@@ -0,0 +1,205 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+
+#include "node_function_util.hh"
+
+#include "UI_interface.h"
+#include "UI_resources.h"
+
+namespace blender::nodes {
+
+NODE_STORAGE_FUNCS(NodeCombSepColor)
+
+static void fn_node_separate_color_declare(NodeDeclarationBuilder &b)
+{
+ b.is_function_node();
+ b.add_input<decl::Color>(N_("Color")).default_value({1.0f, 1.0f, 1.0f, 1.0f});
+ b.add_output<decl::Float>(N_("Red"));
+ b.add_output<decl::Float>(N_("Green"));
+ b.add_output<decl::Float>(N_("Blue"));
+ b.add_output<decl::Float>(N_("Alpha"));
+};
+
+static void fn_node_separate_color_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
+{
+ uiItemR(layout, ptr, "mode", 0, "", ICON_NONE);
+}
+
+static void fn_node_separate_color_update(bNodeTree *UNUSED(ntree), bNode *node)
+{
+ const NodeCombSepColor &storage = node_storage(*node);
+ node_combsep_color_label(&node->outputs, (NodeCombSepColorMode)storage.mode);
+}
+
+static void fn_node_separate_color_init(bNodeTree *UNUSED(tree), bNode *node)
+{
+ NodeCombSepColor *data = MEM_cnew<NodeCombSepColor>(__func__);
+ data->mode = NODE_COMBSEP_COLOR_RGB;
+ node->storage = data;
+}
+
+class SeparateRGBAFunction : public fn::MultiFunction {
+ public:
+ SeparateRGBAFunction()
+ {
+ static fn::MFSignature signature = create_signature();
+ this->set_signature(&signature);
+ }
+
+ static fn::MFSignature create_signature()
+ {
+ fn::MFSignatureBuilder signature{"Separate Color"};
+ signature.single_input<ColorGeometry4f>("Color");
+ signature.single_output<float>("Red");
+ signature.single_output<float>("Green");
+ signature.single_output<float>("Blue");
+ signature.single_output<float>("Alpha");
+ return signature.build();
+ }
+
+ void call(IndexMask mask, fn::MFParams params, fn::MFContext UNUSED(context)) const override
+ {
+ const VArray<ColorGeometry4f> &colors = params.readonly_single_input<ColorGeometry4f>(0,
+ "Color");
+ MutableSpan<float> red = params.uninitialized_single_output<float>(1, "Red");
+ MutableSpan<float> green = params.uninitialized_single_output<float>(2, "Green");
+ MutableSpan<float> blue = params.uninitialized_single_output<float>(3, "Blue");
+ MutableSpan<float> alpha = params.uninitialized_single_output_if_required<float>(4, "Alpha");
+
+ for (int64_t i : mask) {
+ red[i] = colors[i].r;
+ green[i] = colors[i].g;
+ blue[i] = colors[i].b;
+ }
+
+ if (!alpha.is_empty()) {
+ for (int64_t i : mask) {
+ alpha[i] = colors[i].a;
+ }
+ }
+ }
+};
+
+class SeparateHSVAFunction : public fn::MultiFunction {
+ public:
+ SeparateHSVAFunction()
+ {
+ static fn::MFSignature signature = create_signature();
+ this->set_signature(&signature);
+ }
+
+ static fn::MFSignature create_signature()
+ {
+ fn::MFSignatureBuilder signature{"Separate Color"};
+ signature.single_input<ColorGeometry4f>("Color");
+ signature.single_output<float>("Hue");
+ signature.single_output<float>("Saturation");
+ signature.single_output<float>("Value");
+ signature.single_output<float>("Alpha");
+ return signature.build();
+ }
+
+ void call(IndexMask mask, fn::MFParams params, fn::MFContext UNUSED(context)) const override
+ {
+ const VArray<ColorGeometry4f> &colors = params.readonly_single_input<ColorGeometry4f>(0,
+ "Color");
+ MutableSpan<float> hue = params.uninitialized_single_output<float>(1, "Hue");
+ MutableSpan<float> saturation = params.uninitialized_single_output<float>(2, "Saturation");
+ MutableSpan<float> value = params.uninitialized_single_output<float>(3, "Value");
+ MutableSpan<float> alpha = params.uninitialized_single_output_if_required<float>(4, "Alpha");
+
+ for (int64_t i : mask) {
+ rgb_to_hsv(colors[i].r, colors[i].g, colors[i].b, &hue[i], &saturation[i], &value[i]);
+ }
+
+ if (!alpha.is_empty()) {
+ for (int64_t i : mask) {
+ alpha[i] = colors[i].a;
+ }
+ }
+ }
+};
+
+class SeparateHSLAFunction : public fn::MultiFunction {
+ public:
+ SeparateHSLAFunction()
+ {
+ static fn::MFSignature signature = create_signature();
+ this->set_signature(&signature);
+ }
+
+ static fn::MFSignature create_signature()
+ {
+ fn::MFSignatureBuilder signature{"Separate Color"};
+ signature.single_input<ColorGeometry4f>("Color");
+ signature.single_output<float>("Hue");
+ signature.single_output<float>("Saturation");
+ signature.single_output<float>("Lightness");
+ signature.single_output<float>("Alpha");
+ return signature.build();
+ }
+
+ void call(IndexMask mask, fn::MFParams params, fn::MFContext UNUSED(context)) const override
+ {
+ const VArray<ColorGeometry4f> &colors = params.readonly_single_input<ColorGeometry4f>(0,
+ "Color");
+ MutableSpan<float> hue = params.uninitialized_single_output<float>(1, "Hue");
+ MutableSpan<float> saturation = params.uninitialized_single_output<float>(2, "Saturation");
+ MutableSpan<float> lightness = params.uninitialized_single_output<float>(3, "Lightness");
+ MutableSpan<float> alpha = params.uninitialized_single_output_if_required<float>(4, "Alpha");
+
+ for (int64_t i : mask) {
+ rgb_to_hsl(colors[i].r, colors[i].g, colors[i].b, &hue[i], &saturation[i], &lightness[i]);
+ }
+
+ if (!alpha.is_empty()) {
+ for (int64_t i : mask) {
+ alpha[i] = colors[i].a;
+ }
+ }
+ }
+};
+
+static void fn_node_separate_color_build_multi_function(NodeMultiFunctionBuilder &builder)
+{
+ const NodeCombSepColor &storage = node_storage(builder.node());
+
+ switch (storage.mode) {
+ case NODE_COMBSEP_COLOR_RGB: {
+ static SeparateRGBAFunction fn;
+ builder.set_matching_fn(fn);
+ break;
+ }
+ case NODE_COMBSEP_COLOR_HSV: {
+ static SeparateHSVAFunction fn;
+ builder.set_matching_fn(fn);
+ break;
+ }
+ case NODE_COMBSEP_COLOR_HSL: {
+ static SeparateHSLAFunction fn;
+ builder.set_matching_fn(fn);
+ break;
+ }
+ default: {
+ BLI_assert_unreachable();
+ break;
+ }
+ }
+}
+
+} // namespace blender::nodes
+
+void register_node_type_fn_separate_color(void)
+{
+ static bNodeType ntype;
+
+ fn_node_type_base(&ntype, FN_NODE_SEPARATE_COLOR, "Separate Color", NODE_CLASS_CONVERTER);
+ ntype.declare = blender::nodes::fn_node_separate_color_declare;
+ node_type_update(&ntype, blender::nodes::fn_node_separate_color_update);
+ node_type_init(&ntype, blender::nodes::fn_node_separate_color_init);
+ node_type_storage(
+ &ntype, "NodeCombSepColor", node_free_standard_storage, node_copy_standard_storage);
+ ntype.build_multi_function = blender::nodes::fn_node_separate_color_build_multi_function;
+ ntype.draw_buttons = blender::nodes::fn_node_separate_color_layout;
+
+ nodeRegisterType(&ntype);
+}
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.hh b/source/blender/nodes/geometry/node_geometry_util.hh
index 7af3159bbf8..8f20da66c3b 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`.
*/
@@ -81,14 +79,4 @@ void separate_geometry(GeometrySet &geometry_set,
std::optional<CustomDataType> node_data_type_to_custom_data_type(eNodeSocketDatatype type);
std::optional<CustomDataType> node_socket_to_custom_data_type(const bNodeSocket &socket);
-class SplineLengthFieldInput final : public GeometryFieldInput {
- public:
- SplineLengthFieldInput();
- GVArray get_varray_for_context(const GeometryComponent &component,
- AttributeDomain domain,
- IndexMask mask) const final;
- uint64_t hash() const override;
- bool is_equal_to(const fn::FieldNode &other) const override;
-};
-
} // 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..b29831ceeb6 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_accumulate_field.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_accumulate_field.cc
@@ -217,16 +217,16 @@ template<typename T> class AccumulateFieldInput final : public GeometryFieldInpu
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();
@@ -303,9 +303,9 @@ template<typename T> class TotalFieldInput final : public GeometryFieldInput {
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]);
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..16967d32673 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_attribute_capture.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_attribute_capture.cc
@@ -112,8 +112,8 @@ static void try_capture_field_on_geometry(GeometryComponent &component,
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());
OutputAttribute output_attribute = component.attribute_try_get_for_output_only(
@@ -126,30 +126,66 @@ static void try_capture_field_on_geometry(GeometryComponent &component,
output_attribute.save();
}
+static StringRefNull identifier_suffix(CustomDataType 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 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..c7f65a68d60 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_attribute_statistic.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_attribute_statistic.cc
@@ -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_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_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_resample.cc b/source/blender/nodes/geometry/nodes/node_geo_curve_resample.cc
index e0348f27e51..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,556 +51,6 @@ static void node_update(bNodeTree *ntree, bNode *node)
nodeSetSocketAvailability(ntree, length_socket, mode == GEO_NODE_CURVE_RESAMPLE_LENGTH);
}
-/** Returns the number of evaluated points in each curve. Used to deselect curves with none. */
-class EvaluatedCountFieldInput final : public GeometryFieldInput {
- public:
- EvaluatedCountFieldInput() : GeometryFieldInput(CPPType::get<int>(), "Evaluated Point Count")
- {
- category_ = Category::Generated;
- }
-
- GVArray get_varray_for_context(const GeometryComponent &component,
- const AttributeDomain domain,
- IndexMask UNUSED(mask)) const final
- {
- if (component.type() == GEO_COMPONENT_TYPE_CURVE && domain == ATTR_DOMAIN_CURVE &&
- !component.is_empty()) {
- const CurveComponent &curve_component = static_cast<const CurveComponent &>(component);
- const Curves &curves_id = *curve_component.get_for_read();
- const bke::CurvesGeometry &curves = bke::CurvesGeometry::wrap(curves_id.geometry);
- curves.ensure_evaluated_offsets();
- return VArray<int>::ForFunc(curves.curves_num(), [&](const int64_t index) -> int {
- return curves.evaluated_points_for_curve(index).size();
- });
- }
- return {};
- }
-
- uint64_t hash() const override
- {
- /* Some random constant hash. */
- return 234905872379865;
- }
-
- bool is_equal_to(const fn::FieldNode &other) const override
- {
- return dynamic_cast<const EvaluatedCountFieldInput *>(&other) != nullptr;
- }
-};
-
-/**
- * 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.
- *
- * \warning Curves with no evaluated points must not be selected.
- */
-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<SplineLengthFieldInput>()),
- params.extract_input<Field<float>>("Length")}));
-
- return Field<int>(std::move(get_count_op));
- }
-
- BLI_assert_unreachable();
- return {};
-}
-
-/**
- * Create a selection field that removes curves without any evaluated points (invalid NURBS curves)
- * from the original selection provided to the node. This is here to simplify the sampling actual
- * resampling code.
- */
-static Field<bool> get_selection_field(GeoNodeExecParams params)
-{
- static fn::CustomMF_SI_SI_SO<bool, int, bool> get_selection_fn(
- "Create Curve Selection",
- [](const bool orig_selection, const int evaluated_points_num) {
- return orig_selection && evaluated_points_num > 1;
- },
- fn::CustomMF_presets::AllSpanOrSingle());
-
- auto selection_op = std::make_shared<FieldOperation>(
- FieldOperation(get_selection_fn,
- {params.extract_input<Field<bool>>("Selection"),
- Field<int>(std::make_shared<EvaluatedCountFieldInput>())}));
-
- return Field<bool>(std::move(selection_op));
-}
-
static void node_geo_exec(GeoNodeExecParams params)
{
GeometrySet geometry_set = params.extract_input<GeometrySet>("Curve");
@@ -613,35 +58,38 @@ static void node_geo_exec(GeoNodeExecParams params)
const NodeGeometryCurveResample &storage = node_storage(params.node());
const GeometryNodeCurveResampleMode mode = (GeometryNodeCurveResampleMode)storage.mode;
- const Field<bool> selection = get_selection_field(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 5d97720a4f8..ae36248b573 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];
}
break;
}
@@ -144,9 +144,9 @@ static VArray<float> construct_curve_parameter_varray(const bke::CurvesGeometry
return {};
}
-static VArray<float> construct_curve_length_varray(const bke::CurvesGeometry &curves,
- const IndexMask UNUSED(mask),
- const AttributeDomain domain)
+static VArray<float> construct_curve_length_parameter_varray(const bke::CurvesGeometry &curves,
+ const IndexMask UNUSED(mask),
+ const AttributeDomain domain)
{
curves.ensure_evaluated_lengths();
@@ -217,9 +217,9 @@ class CurveParameterFieldInput final : public GeometryFieldInput {
}
};
-class CurveLengthFieldInput final : public GeometryFieldInput {
+class CurveLengthParameterFieldInput final : public GeometryFieldInput {
public:
- CurveLengthFieldInput() : GeometryFieldInput(CPPType::get<float>(), "Curve Length node")
+ CurveLengthParameterFieldInput() : GeometryFieldInput(CPPType::get<float>(), "Curve Length node")
{
category_ = Category::Generated;
}
@@ -233,7 +233,7 @@ class CurveLengthFieldInput final : public GeometryFieldInput {
if (curve_component.has_curves()) {
const Curves &curves_id = *curve_component.get_for_read();
const bke::CurvesGeometry &curves = bke::CurvesGeometry::wrap(curves_id.geometry);
- return construct_curve_length_varray(curves, mask, domain);
+ return construct_curve_length_parameter_varray(curves, mask, domain);
}
}
return {};
@@ -247,7 +247,7 @@ class CurveLengthFieldInput final : public GeometryFieldInput {
bool is_equal_to(const fn::FieldNode &other) const override
{
- return dynamic_cast<const CurveLengthFieldInput *>(&other) != nullptr;
+ return dynamic_cast<const CurveLengthParameterFieldInput *>(&other) != nullptr;
}
};
@@ -288,7 +288,7 @@ class IndexOnSplineFieldInput final : public GeometryFieldInput {
static void node_geo_exec(GeoNodeExecParams params)
{
Field<float> parameter_field{std::make_shared<CurveParameterFieldInput>()};
- Field<float> length_field{std::make_shared<CurveLengthFieldInput>()};
+ Field<float> length_field{std::make_shared<CurveLengthParameterFieldInput>()};
Field<int> index_on_spline_field{std::make_shared<IndexOnSplineFieldInput>()};
params.set_output("Factor", std::move(parameter_field));
params.set_output("Length", std::move(length_field));
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 4118448b237..500804e41f0 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
@@ -33,52 +33,49 @@ static void node_init(bNodeTree *UNUSED(tree), bNode *node)
node->storage = data;
}
-template<class T>
-static void scale_input_assign(const Span<T> input,
+template<typename T>
+static void scale_input_assign(const Span<T> src,
const int scale,
const int offset,
- const MutableSpan<T> r_output)
+ MutableSpan<T> dst)
{
- for (const int i : IndexRange(r_output.size())) {
- r_output[i] = input[i * scale + offset];
+ for (const int i : dst.index_range()) {
+ dst[i] = src[i * scale + offset];
}
}
-template<class T>
-static void scale_output_assign(const Span<T> input,
+template<typename T>
+static void scale_output_assign(const Span<T> src,
const int scale,
const int offset,
- const MutableSpan<T> &r_output)
+ MutableSpan<T> dst)
{
- for (const int i : IndexRange(input.size())) {
- r_output[i * scale + offset] = input[i];
+ for (const int i : src.index_range()) {
+ dst[i * scale + offset] = src[i];
}
}
-template<class T>
-static void nurbs_to_bezier_assign(const Span<T> input,
- const MutableSpan<T> r_output,
- const KnotsMode knotsMode)
+template<typename T>
+static void nurbs_to_bezier_assign(const Span<T> src,
+ const MutableSpan<T> dst,
+ const KnotsMode knots_mode)
{
- const int input_size = input.size();
- const int output_size = r_output.size();
-
- switch (knotsMode) {
+ switch (knots_mode) {
case NURBS_KNOT_MODE_BEZIER:
- scale_input_assign<T>(input, 3, 1, r_output);
+ scale_input_assign<T>(src, 3, 1, dst);
break;
case NURBS_KNOT_MODE_NORMAL:
- for (const int i : IndexRange(output_size)) {
- r_output[i] = input[(i + 1) % input_size];
+ 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 : IndexRange(1, output_size - 2)) {
- r_output[i] = input[i + 1];
+ for (const int i : dst.index_range().drop_back(1).drop_front(1)) {
+ dst[i] = src[i + 1];
}
- r_output.first() = input.first();
- r_output.last() = input.last();
+ dst.first() = src.first();
+ dst.last() = src.last();
break;
}
}
@@ -110,20 +107,20 @@ static void copy_attributes(const Spline &input_spline, Spline &output_spline, C
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)) {
+ for (const int i : IndexRange(nurbs_positions_num)) {
if (i % 3 == 1) {
continue;
}
handle_positions.append(nurbs_positions[i]);
}
- if (nurbs_positions_size % 3 == 1) {
+ if (nurbs_positions_num % 3 == 1) {
handle_positions.pop_last();
}
- else if (nurbs_positions_size % 3 == 2) {
- const int last_index = nurbs_positions_size - 1;
+ 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]);
}
}
@@ -137,11 +134,11 @@ 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;
+ 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)) {
const int divisor = is_periodic ?
3 :
std::min(3, (int)(-std::abs(i - mid_offset) + mid_offset + 1.0f));
@@ -154,7 +151,7 @@ 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] +
@@ -357,7 +354,7 @@ static SplinePtr convert_to_nurbs(const Spline &input)
static void node_geo_exec(GeoNodeExecParams params)
{
const NodeGeometryCurveSplineType &storage = node_storage(params.node());
- const GeometryNodeSplineType output_type = (const GeometryNodeSplineType)storage.spline_type;
+ const GeometryNodeSplineType dst_type = (const GeometryNodeSplineType)storage.spline_type;
GeometrySet geometry_set = params.extract_input<GeometrySet>("Curve");
Field<bool> selection_field = params.extract_input<Field<bool>>("Selection");
@@ -371,11 +368,11 @@ static void node_geo_exec(GeoNodeExecParams params)
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);
+ const int domain_num = curve_component->attribute_domain_num(ATTR_DOMAIN_CURVE);
Span<SplinePtr> src_splines = curve->splines();
- 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 VArray<bool> &selection = selection_evaluator.get_evaluated<bool>(0);
@@ -386,7 +383,7 @@ static void node_geo_exec(GeoNodeExecParams params)
threading::parallel_for(src_splines.index_range(), 512, [&](IndexRange range) {
for (const int i : range) {
if (selection[i]) {
- switch (output_type) {
+ switch (dst_type) {
case GEO_NODE_SPLINE_TYPE_POLY:
new_curve->splines()[i] = convert_to_poly_spline(*src_splines[i]);
break;
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..73b2c400e90 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,7 +120,7 @@ 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,
@@ -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..99edc4d298c 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_delete_geometry.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_delete_geometry.cc
@@ -470,7 +470,7 @@ static void separate_curve_selection(GeometrySet &geometry_set,
GeometryComponentFieldContext field_context{src_component, selection_domain};
fn::FieldEvaluator selection_evaluator{field_context,
- src_component.attribute_domain_size(selection_domain)};
+ src_component.attribute_domain_num(selection_domain)};
selection_evaluator.add(selection_field);
selection_evaluator.evaluate();
const VArray_Span<bool> &selection = selection_evaluator.get_evaluated<bool>(0);
@@ -493,7 +493,7 @@ static void separate_point_cloud_selection(GeometrySet &geometry_set,
GeometryComponentFieldContext field_context{src_points, ATTR_DOMAIN_POINT};
fn::FieldEvaluator selection_evaluator{field_context,
- src_points.attribute_domain_size(ATTR_DOMAIN_POINT)};
+ src_points.attribute_domain_num(ATTR_DOMAIN_POINT)};
selection_evaluator.add(selection_field);
selection_evaluator.evaluate();
const VArray_Span<bool> &selection = selection_evaluator.get_evaluated<bool>(0);
@@ -526,8 +526,8 @@ static void separate_instance_selection(GeometrySet &geometry_set,
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};
+ const int domain_num = instances.attribute_domain_num(ATTR_DOMAIN_INSTANCE);
+ fn::FieldEvaluator evaluator{field_context, domain_num};
evaluator.add(selection_field);
evaluator.evaluate();
const VArray_Span<bool> &selection = evaluator.get_evaluated<bool>(0);
@@ -1238,7 +1238,7 @@ static void separate_mesh_selection(GeometrySet &geometry_set,
GeometryComponentFieldContext field_context{src_component, selection_domain};
fn::FieldEvaluator selection_evaluator{field_context,
- src_component.attribute_domain_size(selection_domain)};
+ src_component.attribute_domain_num(selection_domain)};
selection_evaluator.add(selection_field);
selection_evaluator.evaluate();
const VArray_Span<bool> &selection = selection_evaluator.get_evaluated<bool>(0);
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..c242cfd5cf3 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
@@ -398,11 +398,11 @@ static Array<float> calc_full_density_factors_with_selection(const MeshComponent
{
const AttributeDomain 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_duplicate_elements.cc b/source/blender/nodes/geometry/nodes/node_geo_duplicate_elements.cc
index 75987ec2317..ac057ad078b 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_duplicate_elements.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_duplicate_elements.cc
@@ -354,19 +354,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();
@@ -382,7 +382,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);
@@ -810,23 +810,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);
@@ -943,10 +943,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();
@@ -1029,7 +1029,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();
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..1f16e8d55bd 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_extrude_mesh.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_extrude_mesh.cc
@@ -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,
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..bf956f3b83d 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
@@ -91,7 +91,7 @@ class FieldAtIndex final : public GeometryFieldInput {
{
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);
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_mesh_island.cc b/source/blender/nodes/geometry/nodes/node_geo_input_mesh_island.cc
index d39291a2a7e..8e3a9b6769d 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
@@ -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_spline_length.cc b/source/blender/nodes/geometry/nodes/node_geo_input_spline_length.cc
index 6c24f86b63b..84d773ff8eb 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
@@ -4,71 +4,6 @@
#include "BKE_curves.hh"
-namespace blender::nodes {
-
-/* --------------------------------------------------------------------
- * Spline Length
- */
-
-static VArray<float> construct_spline_length_gvarray(const CurveComponent &component,
- const AttributeDomain domain)
-{
- if (!component.has_curves()) {
- return {};
- }
- const Curves &curves_id = *component.get_for_read();
- const bke::CurvesGeometry &curves = bke::CurvesGeometry::wrap(curves_id.geometry);
-
- curves.ensure_evaluated_lengths();
-
- VArray<bool> cyclic = curves.cyclic();
- VArray<float> lengths = VArray<float>::ForFunc(
- curves.curves_num(), [&curves, cyclic = std::move(cyclic)](int64_t index) {
- return curves.evaluated_length_total_for_curve(index, cyclic[index]);
- });
-
- if (domain == ATTR_DOMAIN_CURVE) {
- return lengths;
- }
-
- if (domain == ATTR_DOMAIN_POINT) {
- return component.attribute_try_adapt_domain<float>(
- std::move(lengths), ATTR_DOMAIN_CURVE, ATTR_DOMAIN_POINT);
- }
-
- return {};
-}
-
-SplineLengthFieldInput::SplineLengthFieldInput()
- : GeometryFieldInput(CPPType::get<float>(), "Spline Length node")
-{
- category_ = Category::Generated;
-}
-
-GVArray SplineLengthFieldInput::get_varray_for_context(const GeometryComponent &component,
- const AttributeDomain domain,
- IndexMask UNUSED(mask)) const
-{
- if (component.type() == GEO_COMPONENT_TYPE_CURVE) {
- const CurveComponent &curve_component = static_cast<const CurveComponent &>(component);
- return construct_spline_length_gvarray(curve_component, domain);
- }
- return {};
-}
-
-uint64_t SplineLengthFieldInput::hash() const
-{
- /* Some random constant hash. */
- return 3549623580;
-}
-
-bool SplineLengthFieldInput::is_equal_to(const fn::FieldNode &other) const
-{
- return dynamic_cast<const SplineLengthFieldInput *>(&other) != nullptr;
-}
-
-} // namespace blender::nodes
-
namespace blender::nodes::node_geo_input_spline_length_cc {
static void node_declare(NodeDeclarationBuilder &b)
@@ -81,8 +16,8 @@ static void node_declare(NodeDeclarationBuilder &b)
* Spline Count
*/
-static VArray<int> construct_spline_count_gvarray(const CurveComponent &component,
- const AttributeDomain domain)
+static VArray<int> construct_curve_point_count_gvarray(const CurveComponent &component,
+ const AttributeDomain domain)
{
if (!component.has_curves()) {
return {};
@@ -117,7 +52,7 @@ class SplineCountFieldInput final : public GeometryFieldInput {
{
if (component.type() == GEO_COMPONENT_TYPE_CURVE) {
const CurveComponent &curve_component = static_cast<const CurveComponent &>(component);
- return construct_spline_count_gvarray(curve_component, domain);
+ return construct_curve_point_count_gvarray(curve_component, domain);
}
return {};
}
@@ -136,7 +71,7 @@ class SplineCountFieldInput final : public GeometryFieldInput {
static void node_geo_exec(GeoNodeExecParams params)
{
- Field<float> spline_length_field{std::make_shared<SplineLengthFieldInput>()};
+ Field<float> spline_length_field{std::make_shared<bke::CurveLengthFieldInput>()};
Field<int> spline_count_field{std::make_shared<SplineCountFieldInput>()};
params.set_output("Length", std::move(spline_length_field));
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..12582f9e9c6 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
@@ -50,7 +50,7 @@ static void add_instances_from_component(
const Map<AttributeIDRef, AttributeKind> &attributes_to_propagate)
{
const AttributeDomain domain = ATTR_DOMAIN_POINT;
- const int domain_size = src_component.attribute_domain_size(domain);
+ 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..2067086c298 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_join_geometry.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_join_geometry.cc
@@ -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_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 1a0cc53cb6c..6b23b685549 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
@@ -1,5 +1,7 @@
/* SPDX-License-Identifier: GPL-2.0-or-later */
+#include "BLI_task.hh"
+
#include "DNA_pointcloud_types.h"
#include "BKE_attribute_math.hh"
@@ -41,14 +43,15 @@ static void node_init(bNodeTree *UNUSED(tree), bNode *node)
node->storage = data;
}
-template<typename T>
-static void copy_attribute_to_points(const VArray<T> &src,
- const IndexMask mask,
- MutableSpan<T> dst)
+static void materialize_compressed_to_uninitialized_threaded(const GVArray &src,
+ const IndexMask mask,
+ GMutableSpan dst)
{
- for (const int i : mask.index_range()) {
- dst[i] = src[mask[i]];
- }
+ BLI_assert(src.type() == dst.type());
+ BLI_assert(mask.size() == dst.size());
+ threading::parallel_for(mask.index_range(), 4096, [&](IndexRange range) {
+ src.materialize_compressed_to_uninitialized(mask.slice(range), dst.slice(range).data());
+ });
}
static void geometry_set_mesh_to_points(GeometrySet &geometry_set,
@@ -63,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
@@ -79,16 +82,21 @@ static void geometry_set_mesh_to_points(GeometrySet &geometry_set,
const IndexMask selection = evaluator.get_evaluated_selection_as_mask();
PointCloud *pointcloud = BKE_pointcloud_new_nomain(selection.size());
- uninitialized_fill_n(pointcloud->radius, pointcloud->totpoint, 0.05f);
geometry_set.replace_pointcloud(pointcloud);
PointCloudComponent &point_component =
geometry_set.get_component_for_write<PointCloudComponent>();
- copy_attribute_to_points(evaluator.get_evaluated<float3>(0),
- selection,
- {(float3 *)pointcloud->co, pointcloud->totpoint});
- copy_attribute_to_points(
- evaluator.get_evaluated<float>(1), selection, {pointcloud->radius, pointcloud->totpoint});
+ OutputAttribute position = point_component.attribute_try_get_for_output_only(
+ "position", ATTR_DOMAIN_POINT, CD_PROP_FLOAT3);
+ materialize_compressed_to_uninitialized_threaded(
+ evaluator.get_evaluated(0), selection, position.as_span());
+ position.save();
+
+ OutputAttribute radius = point_component.attribute_try_get_for_output_only(
+ "radius", ATTR_DOMAIN_POINT, CD_PROP_FLOAT);
+ materialize_compressed_to_uninitialized_threaded(
+ evaluator.get_evaluated(1), selection, radius.as_span());
+ radius.save();
Map<AttributeIDRef, AttributeKind> attributes;
geometry_set.gather_attributes_for_propagation(
@@ -102,11 +110,7 @@ static void geometry_set_mesh_to_points(GeometrySet &geometry_set,
OutputAttribute dst = point_component.attribute_try_get_for_output_only(
attribute_id, ATTR_DOMAIN_POINT, data_type);
if (dst && src) {
- attribute_math::convert_to_static_type(data_type, [&](auto dummy) {
- using T = decltype(dummy);
- VArray<T> src_typed = src.typed<T>();
- copy_attribute_to_points(src_typed, selection, dst.as_span().typed<T>());
- });
+ materialize_compressed_to_uninitialized_threaded(src, selection, dst.as_span());
dst.save();
}
}
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..577b001fd06 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);
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..0c30d50076f 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_raycast.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_raycast.cc
@@ -312,8 +312,8 @@ 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);
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_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_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..ec95f9a89f5 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_set_id.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_set_id.cc
@@ -20,12 +20,12 @@ static void set_id_in_component(GeometryComponent &component,
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..caf33108716 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_set_position.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_set_position.cc
@@ -143,12 +143,12 @@ static void set_position_in_component(GeometryComponent &component,
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..3b348dd0136 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
@@ -88,8 +88,8 @@ static void try_capture_field_on_geometry(GeometryComponent &component,
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);
@@ -97,10 +97,10 @@ static void try_capture_field_on_geometry(GeometryComponent &component,
/* 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 {
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 4832feac5bd..9eda5bb34ff 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_subdivision_surface.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_subdivision_surface.cc
@@ -1,5 +1,7 @@
/* SPDX-License-Identifier: GPL-2.0-or-later */
+#include "BLI_task.hh"
+
#include "DNA_mesh_types.h"
#include "DNA_meshdata_types.h"
#include "DNA_modifier_types.h"
@@ -21,7 +23,13 @@ static void node_declare(NodeDeclarationBuilder &b)
{
b.add_input<decl::Geometry>(N_("Mesh")).supported_type(GEO_COMPONENT_TYPE_MESH);
b.add_input<decl::Int>(N_("Level")).default_value(1).min(0).max(6);
- b.add_input<decl::Float>(N_("Crease"))
+ b.add_input<decl::Float>(N_("Edge Crease"))
+ .default_value(0.0f)
+ .min(0.0f)
+ .max(1.0f)
+ .supports_field()
+ .subtype(PROP_FACTOR);
+ b.add_input<decl::Float>(N_("Vertex Crease"))
.default_value(0.0f)
.min(0.0f)
.max(1.0f)
@@ -44,6 +52,45 @@ static void node_init(bNodeTree *UNUSED(ntree), bNode *node)
node->storage = data;
}
+#ifdef WITH_OPENSUBDIV
+static void materialize_and_clamp_creases(const VArray<float> &crease_varray,
+ MutableSpan<float> creases)
+{
+ threading::parallel_for(creases.index_range(), 1024, [&](IndexRange range) {
+ crease_varray.materialize(range, creases);
+ for (const int i : range) {
+ creases[i] = std::clamp(creases[i], 0.0f, 1.0f);
+ }
+ });
+}
+
+static void write_vertex_creases(Mesh &mesh, const VArray<float> &crease_varray)
+{
+ float *crease;
+ if (CustomData_has_layer(&mesh.vdata, CD_CREASE)) {
+ crease = static_cast<float *>(CustomData_get_layer(&mesh.vdata, CD_CREASE));
+ }
+ else {
+ crease = static_cast<float *>(
+ CustomData_add_layer(&mesh.vdata, CD_CREASE, CD_DEFAULT, nullptr, mesh.totvert));
+ }
+ materialize_and_clamp_creases(crease_varray, {crease, mesh.totvert});
+}
+
+static void write_edge_creases(MeshComponent &mesh, const VArray<float> &crease_varray)
+{
+ OutputAttribute_Typed<float> attribute = mesh.attribute_try_get_for_output_only<float>(
+ "crease", ATTR_DOMAIN_EDGE);
+ materialize_and_clamp_creases(crease_varray, attribute.as_span());
+ attribute.save();
+}
+
+static bool varray_is_nonzero(const VArray<float> &varray)
+{
+ return !(varray.is_single() && varray.get_internal_single() == 0.0f);
+}
+#endif
+
static void node_geo_exec(GeoNodeExecParams params)
{
GeometrySet geometry_set = params.extract_input<GeometrySet>("Mesh");
@@ -51,7 +98,8 @@ static void node_geo_exec(GeoNodeExecParams params)
params.error_message_add(NodeWarningType::Error,
TIP_("Disabled, Blender was compiled without OpenSubdiv"));
#else
- Field<float> crease_field = params.extract_input<Field<float>>("Crease");
+ Field<float> edge_crease_field = params.extract_input<Field<float>>("Edge Crease");
+ Field<float> vertex_crease_field = params.extract_input<Field<float>>("Vertex Crease");
const NodeGeometrySubdivisionSurface &storage = node_storage(params.node());
const int uv_smooth = storage.uv_smooth;
@@ -69,27 +117,31 @@ static void node_geo_exec(GeoNodeExecParams params)
return;
}
- MeshComponent &mesh_component = geometry_set.get_component_for_write<MeshComponent>();
- AttributeDomain domain = ATTR_DOMAIN_EDGE;
- GeometryComponentFieldContext field_context{mesh_component, domain};
- const int domain_size = mesh_component.attribute_domain_size(domain);
-
- if (domain_size == 0) {
+ const MeshComponent &mesh_component = *geometry_set.get_component_for_read<MeshComponent>();
+ 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;
}
- FieldEvaluator evaluator(field_context, domain_size);
- evaluator.add(crease_field);
- evaluator.evaluate();
- const VArray<float> &creases = evaluator.get_evaluated<float>(0);
+ GeometryComponentFieldContext point_context{mesh_component, ATTR_DOMAIN_POINT};
+ FieldEvaluator point_evaluator(point_context, verts_num);
+ point_evaluator.add(vertex_crease_field);
+ point_evaluator.evaluate();
+ const VArray<float> vertex_creases = point_evaluator.get_evaluated<float>(0);
+
+ GeometryComponentFieldContext edge_context{mesh_component, ATTR_DOMAIN_EDGE};
+ FieldEvaluator edge_evaluator(edge_context, edges_num);
+ edge_evaluator.add(edge_crease_field);
+ edge_evaluator.evaluate();
+ const VArray<float> edge_creases = edge_evaluator.get_evaluated<float>(0);
+
+ const bool use_creases = varray_is_nonzero(vertex_creases) || varray_is_nonzero(edge_creases);
- OutputAttribute_Typed<float> crease = mesh_component.attribute_try_get_for_output_only<float>(
- "crease", domain);
- MutableSpan<float> crease_span = crease.as_span();
- for (auto i : creases.index_range()) {
- crease_span[i] = std::clamp(creases[i], 0.0f, 1.0f);
+ if (use_creases) {
+ write_vertex_creases(*geometry_set.get_mesh_for_write(), vertex_creases);
+ write_edge_creases(geometry_set.get_component_for_write<MeshComponent>(), edge_creases);
}
- crease.save();
/* Initialize mesh settings. */
SubdivToMeshSettings mesh_settings;
@@ -100,7 +152,7 @@ static void node_geo_exec(GeoNodeExecParams params)
SubdivSettings subdiv_settings;
subdiv_settings.is_simple = false;
subdiv_settings.is_adaptive = false;
- subdiv_settings.use_creases = !(creases.is_single() && creases.get_internal_single() == 0.0f);
+ subdiv_settings.use_creases = use_creases;
subdiv_settings.level = subdiv_level;
subdiv_settings.vtx_boundary_interpolation =
@@ -108,19 +160,19 @@ static void node_geo_exec(GeoNodeExecParams params)
subdiv_settings.fvar_linear_interpolation = BKE_subdiv_fvar_interpolation_from_uv_smooth(
uv_smooth);
- Mesh *mesh_in = mesh_component.get_for_write();
+ const Mesh &mesh_in = *geometry_set.get_mesh_for_read();
/* Apply subdivision to mesh. */
- Subdiv *subdiv = BKE_subdiv_update_from_mesh(nullptr, &subdiv_settings, mesh_in);
+ Subdiv *subdiv = BKE_subdiv_update_from_mesh(nullptr, &subdiv_settings, &mesh_in);
/* In case of bad topology, skip to input mesh. */
if (subdiv == nullptr) {
return;
}
- Mesh *mesh_out = BKE_subdiv_to_mesh(subdiv, &mesh_settings, mesh_in);
+ Mesh *mesh_out = BKE_subdiv_to_mesh(subdiv, &mesh_settings, &mesh_in);
- mesh_component.replace(mesh_out);
+ geometry_set.replace_mesh(mesh_out);
BKE_subdiv_free(subdiv);
});
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..dca214660c8 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_transfer_attribute.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_transfer_attribute.cc
@@ -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;
}
/**
@@ -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);
@@ -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);
@@ -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);
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/intern/geometry_nodes_eval_log.cc b/source/blender/nodes/intern/geometry_nodes_eval_log.cc
index 378bac894e8..9a316190720 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: {
diff --git a/source/blender/nodes/intern/node_geometry_exec.cc b/source/blender/nodes/intern/node_geometry_exec.cc
index cea3084a418..9aee3ddcce7 100644
--- a/source/blender/nodes/intern/node_geometry_exec.cc
+++ b/source/blender/nodes/intern/node_geometry_exec.cc
@@ -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;
@@ -119,14 +119,14 @@ GVArray GeoNodeExecParams::get_input_attribute(const StringRef name,
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);
+ const int64_t domain_num = component.attribute_domain_num(domain);
if (default_value == nullptr) {
default_value = cpp_type->default_value();
}
if (found_socket == nullptr) {
- return GVArray::ForSingle(*cpp_type, domain_size, default_value);
+ return GVArray::ForSingle(*cpp_type, domain_num, default_value);
}
if (found_socket->type == SOCK_STRING) {
@@ -140,40 +140,40 @@ GVArray GeoNodeExecParams::get_input_attribute(const StringRef name,
/* 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) {
+ if (!name.empty() && component.attribute_domain_num(domain) != 0) {
this->error_message_add(NodeWarningType::Error,
TIP_("No attribute with name \"") + name + "\"");
}
- return GVArray::ForSingle(*cpp_type, domain_size, default_value);
+ return GVArray::ForSingle(*cpp_type, domain_num, 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);
+ return GVArray::ForSingle(*cpp_type, domain_num, 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);
+ return GVArray::ForSingle(*cpp_type, domain_num, 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);
+ return GVArray::ForSingle(*cpp_type, domain_num, 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);
+ return GVArray::ForSingle(*cpp_type, domain_num, buffer);
}
BLI_assert(false);
- return GVArray::ForSingle(*cpp_type, domain_size, default_value);
+ return GVArray::ForSingle(*cpp_type, domain_num, default_value);
}
CustomDataType GeoNodeExecParams::get_input_attribute_data_type(
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/intern/node_util.c b/source/blender/nodes/intern/node_util.c
index 5d2e1663ae3..e8be093c606 100644
--- a/source/blender/nodes/intern/node_util.c
+++ b/source/blender/nodes/intern/node_util.c
@@ -226,6 +226,39 @@ void node_filter_label(const bNodeTree *UNUSED(ntree), const bNode *node, char *
BLI_strncpy(label, IFACE_(name), maxlen);
}
+void node_combsep_color_label(const ListBase *sockets, NodeCombSepColorMode mode)
+{
+ bNodeSocket *sock1 = (bNodeSocket *)sockets->first;
+ bNodeSocket *sock2 = sock1->next;
+ bNodeSocket *sock3 = sock2->next;
+
+ node_sock_label_clear(sock1);
+ node_sock_label_clear(sock2);
+ node_sock_label_clear(sock3);
+
+ switch (mode) {
+ case NODE_COMBSEP_COLOR_RGB:
+ node_sock_label(sock1, "Red");
+ node_sock_label(sock2, "Green");
+ node_sock_label(sock3, "Blue");
+ break;
+ case NODE_COMBSEP_COLOR_HSL:
+ node_sock_label(sock1, "Hue");
+ node_sock_label(sock2, "Saturation");
+ node_sock_label(sock3, "Lightness");
+ break;
+ case NODE_COMBSEP_COLOR_HSV:
+ node_sock_label(sock1, "Hue");
+ node_sock_label(sock2, "Saturation");
+ node_sock_label(sock3, "Value");
+ break;
+ default: {
+ BLI_assert_unreachable();
+ break;
+ }
+ }
+}
+
/** \} */
/* -------------------------------------------------------------------- */
diff --git a/source/blender/nodes/intern/node_util.h b/source/blender/nodes/intern/node_util.h
index de03a176c0c..0a2a7a70091 100644
--- a/source/blender/nodes/intern/node_util.h
+++ b/source/blender/nodes/intern/node_util.h
@@ -65,6 +65,7 @@ void node_filter_label(const struct bNodeTree *ntree,
const struct bNode *node,
char *label,
int maxlen);
+void node_combsep_color_label(const ListBase *sockets, NodeCombSepColorMode mode);
/*** Link Handling */
diff --git a/source/blender/nodes/shader/CMakeLists.txt b/source/blender/nodes/shader/CMakeLists.txt
index 9b4ea0e0db6..3e90f185168 100644
--- a/source/blender/nodes/shader/CMakeLists.txt
+++ b/source/blender/nodes/shader/CMakeLists.txt
@@ -82,6 +82,7 @@ set(SRC
nodes/node_shader_rgb.cc
nodes/node_shader_rgb_to_bw.cc
nodes/node_shader_script.cc
+ nodes/node_shader_sepcomb_color.cc
nodes/node_shader_sepcomb_hsv.cc
nodes/node_shader_sepcomb_rgb.cc
nodes/node_shader_sepcomb_xyz.cc
diff --git a/source/blender/nodes/shader/node_shader_tree.cc b/source/blender/nodes/shader/node_shader_tree.cc
index ec97637ccd2..f107ec73c60 100644
--- a/source/blender/nodes/shader/node_shader_tree.cc
+++ b/source/blender/nodes/shader/node_shader_tree.cc
@@ -587,7 +587,7 @@ static bNode *ntree_shader_copy_branch(bNodeTree *ntree,
}
}
}
- /* Recreate links between copied nodes AND incomming links to the copied nodes. */
+ /* Recreate links between copied nodes AND incoming links to the copied nodes. */
LISTBASE_FOREACH (bNodeLink *, link, &ntree->links) {
if (link->tonode->tmp_flag >= 0) {
bool from_node_copied = link->fromnode->tmp_flag >= 0;
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_sepcomb_color.cc b/source/blender/nodes/shader/nodes/node_shader_sepcomb_color.cc
new file mode 100644
index 00000000000..8e378ebabce
--- /dev/null
+++ b/source/blender/nodes/shader/nodes/node_shader_sepcomb_color.cc
@@ -0,0 +1,162 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later
+ * Copyright 2022 Blender Foundation. All rights reserved. */
+
+/** \file
+ * \ingroup shdnodes
+ */
+
+#include "node_shader_util.hh"
+
+#include "UI_interface.h"
+#include "UI_resources.h"
+
+static void node_combsep_color_init(bNodeTree *UNUSED(tree), bNode *node)
+{
+ NodeCombSepColor *data = MEM_cnew<NodeCombSepColor>(__func__);
+ data->mode = NODE_COMBSEP_COLOR_RGB;
+ node->storage = data;
+}
+
+/* **************** SEPARATE COLOR ******************** */
+
+namespace blender::nodes::node_shader_separate_color_cc {
+
+NODE_STORAGE_FUNCS(NodeCombSepColor)
+
+static void sh_node_sepcolor_declare(NodeDeclarationBuilder &b)
+{
+ b.add_input<decl::Color>(N_("Color")).default_value({0.8f, 0.8f, 0.8f, 1.0f});
+ b.add_output<decl::Float>(N_("Red"));
+ b.add_output<decl::Float>(N_("Green"));
+ b.add_output<decl::Float>(N_("Blue"));
+}
+
+static void node_sepcolor_update(bNodeTree *UNUSED(ntree), bNode *node)
+{
+ const NodeCombSepColor &storage = node_storage(*node);
+ node_combsep_color_label(&node->outputs, (NodeCombSepColorMode)storage.mode);
+}
+
+static const char *gpu_shader_get_name(int mode)
+{
+ switch (mode) {
+ case NODE_COMBSEP_COLOR_RGB:
+ return "separate_color_rgb";
+ case NODE_COMBSEP_COLOR_HSV:
+ return "separate_color_hsv";
+ case NODE_COMBSEP_COLOR_HSL:
+ return "separate_color_hsl";
+ }
+
+ return nullptr;
+}
+
+static int gpu_shader_sepcolor(GPUMaterial *mat,
+ bNode *node,
+ bNodeExecData *UNUSED(execdata),
+ GPUNodeStack *in,
+ GPUNodeStack *out)
+{
+ const NodeCombSepColor &storage = node_storage(*node);
+ const char *name = gpu_shader_get_name(storage.mode);
+ if (name != nullptr) {
+ return GPU_stack_link(mat, node, name, in, out);
+ }
+
+ return 0;
+}
+
+} // namespace blender::nodes::node_shader_separate_color_cc
+
+void register_node_type_sh_sepcolor()
+{
+ namespace file_ns = blender::nodes::node_shader_separate_color_cc;
+
+ static bNodeType ntype;
+
+ sh_node_type_base(&ntype, SH_NODE_SEPARATE_COLOR, "Separate Color", NODE_CLASS_CONVERTER);
+ ntype.declare = file_ns::sh_node_sepcolor_declare;
+ node_type_update(&ntype, file_ns::node_sepcolor_update);
+ node_type_init(&ntype, node_combsep_color_init);
+ node_type_storage(
+ &ntype, "NodeCombSepColor", node_free_standard_storage, node_copy_standard_storage);
+ node_type_gpu(&ntype, file_ns::gpu_shader_sepcolor);
+
+ nodeRegisterType(&ntype);
+}
+
+/* **************** COMBINE COLOR ******************** */
+
+namespace blender::nodes::node_shader_combine_color_cc {
+
+NODE_STORAGE_FUNCS(NodeCombSepColor)
+
+static void sh_node_combcolor_declare(NodeDeclarationBuilder &b)
+{
+ b.add_input<decl::Float>(N_("Red")).default_value(0.0f).min(0.0f).max(1.0f).subtype(PROP_FACTOR);
+ b.add_input<decl::Float>(N_("Green"))
+ .default_value(0.0f)
+ .min(0.0f)
+ .max(1.0f)
+ .subtype(PROP_FACTOR);
+ b.add_input<decl::Float>(N_("Blue"))
+ .default_value(0.0f)
+ .min(0.0f)
+ .max(1.0f)
+ .subtype(PROP_FACTOR);
+ b.add_output<decl::Color>(N_("Color"));
+}
+
+static void node_combcolor_update(bNodeTree *UNUSED(ntree), bNode *node)
+{
+ const NodeCombSepColor &storage = node_storage(*node);
+ node_combsep_color_label(&node->inputs, (NodeCombSepColorMode)storage.mode);
+}
+
+static const char *gpu_shader_get_name(int mode)
+{
+ switch (mode) {
+ case NODE_COMBSEP_COLOR_RGB:
+ return "combine_color_rgb";
+ case NODE_COMBSEP_COLOR_HSV:
+ return "combine_color_hsv";
+ case NODE_COMBSEP_COLOR_HSL:
+ return "combine_color_hsl";
+ }
+
+ return nullptr;
+}
+
+static int gpu_shader_combcolor(GPUMaterial *mat,
+ bNode *node,
+ bNodeExecData *UNUSED(execdata),
+ GPUNodeStack *in,
+ GPUNodeStack *out)
+{
+ const NodeCombSepColor &storage = node_storage(*node);
+ const char *name = gpu_shader_get_name(storage.mode);
+ if (name != nullptr) {
+ return GPU_stack_link(mat, node, name, in, out);
+ }
+
+ return 0;
+}
+
+} // namespace blender::nodes::node_shader_combine_color_cc
+
+void register_node_type_sh_combcolor()
+{
+ namespace file_ns = blender::nodes::node_shader_combine_color_cc;
+
+ static bNodeType ntype;
+
+ sh_node_type_base(&ntype, SH_NODE_COMBINE_COLOR, "Combine Color", NODE_CLASS_CONVERTER);
+ ntype.declare = file_ns::sh_node_combcolor_declare;
+ node_type_update(&ntype, file_ns::node_combcolor_update);
+ node_type_init(&ntype, node_combsep_color_init);
+ node_type_storage(
+ &ntype, "NodeCombSepColor", node_free_standard_storage, node_copy_standard_storage);
+ node_type_gpu(&ntype, file_ns::gpu_shader_combcolor);
+
+ nodeRegisterType(&ntype);
+}
diff --git a/source/blender/nodes/shader/nodes/node_shader_sepcomb_hsv.cc b/source/blender/nodes/shader/nodes/node_shader_sepcomb_hsv.cc
index 129c8cf4b97..6dfabe48292 100644
--- a/source/blender/nodes/shader/nodes/node_shader_sepcomb_hsv.cc
+++ b/source/blender/nodes/shader/nodes/node_shader_sepcomb_hsv.cc
@@ -36,7 +36,7 @@ void register_node_type_sh_sephsv()
static bNodeType ntype;
- sh_node_type_base(&ntype, SH_NODE_SEPHSV, "Separate HSV", NODE_CLASS_CONVERTER);
+ sh_node_type_base(&ntype, SH_NODE_SEPHSV_LEGACY, "Separate HSV", NODE_CLASS_CONVERTER);
ntype.declare = file_ns::node_declare_sephsv;
node_type_gpu(&ntype, file_ns::gpu_shader_sephsv);
@@ -72,7 +72,7 @@ void register_node_type_sh_combhsv()
static bNodeType ntype;
- sh_node_type_base(&ntype, SH_NODE_COMBHSV, "Combine HSV", NODE_CLASS_CONVERTER);
+ sh_node_type_base(&ntype, SH_NODE_COMBHSV_LEGACY, "Combine HSV", NODE_CLASS_CONVERTER);
ntype.declare = file_ns::node_declare_combhsv;
node_type_gpu(&ntype, file_ns::gpu_shader_combhsv);
diff --git a/source/blender/nodes/shader/nodes/node_shader_sepcomb_rgb.cc b/source/blender/nodes/shader/nodes/node_shader_sepcomb_rgb.cc
index 657f591a50c..28b55047633 100644
--- a/source/blender/nodes/shader/nodes/node_shader_sepcomb_rgb.cc
+++ b/source/blender/nodes/shader/nodes/node_shader_sepcomb_rgb.cc
@@ -76,7 +76,7 @@ void register_node_type_sh_seprgb()
static bNodeType ntype;
- sh_fn_node_type_base(&ntype, SH_NODE_SEPRGB, "Separate RGB", NODE_CLASS_CONVERTER);
+ sh_fn_node_type_base(&ntype, SH_NODE_SEPRGB_LEGACY, "Separate RGB", NODE_CLASS_CONVERTER);
ntype.declare = file_ns::sh_node_seprgb_declare;
node_type_gpu(&ntype, file_ns::gpu_shader_seprgb);
ntype.build_multi_function = file_ns::sh_node_seprgb_build_multi_function;
@@ -119,7 +119,7 @@ void register_node_type_sh_combrgb()
static bNodeType ntype;
- sh_fn_node_type_base(&ntype, SH_NODE_COMBRGB, "Combine RGB", NODE_CLASS_CONVERTER);
+ sh_fn_node_type_base(&ntype, SH_NODE_COMBRGB_LEGACY, "Combine RGB", NODE_CLASS_CONVERTER);
ntype.declare = file_ns::sh_node_combrgb_declare;
node_type_gpu(&ntype, file_ns::gpu_shader_combrgb);
ntype.build_multi_function = file_ns::sh_node_combrgb_build_multi_function;
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/texture/CMakeLists.txt b/source/blender/nodes/texture/CMakeLists.txt
index 7706f118507..5bed54ebfd7 100644
--- a/source/blender/nodes/texture/CMakeLists.txt
+++ b/source/blender/nodes/texture/CMakeLists.txt
@@ -24,6 +24,7 @@ set(SRC
nodes/node_texture_at.c
nodes/node_texture_bricks.c
nodes/node_texture_checker.c
+ nodes/node_texture_combine_color.c
nodes/node_texture_common.c
nodes/node_texture_compose.c
nodes/node_texture_coord.c
@@ -39,6 +40,7 @@ set(SRC
nodes/node_texture_proc.c
nodes/node_texture_rotate.c
nodes/node_texture_scale.c
+ nodes/node_texture_separate_color.c
nodes/node_texture_texture.c
nodes/node_texture_translate.c
nodes/node_texture_valToNor.c
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_combine_color.c b/source/blender/nodes/texture/nodes/node_texture_combine_color.c
new file mode 100644
index 00000000000..459553bc950
--- /dev/null
+++ b/source/blender/nodes/texture/nodes/node_texture_combine_color.c
@@ -0,0 +1,76 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later
+ * Copyright 2022 Blender Foundation. All rights reserved. */
+
+/** \file
+ * \ingroup texnodes
+ */
+
+#include "BLI_listbase.h"
+#include "NOD_texture.h"
+#include "node_texture_util.h"
+
+static bNodeSocketTemplate inputs[] = {
+ {SOCK_FLOAT, N_("Red"), 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, PROP_FACTOR},
+ {SOCK_FLOAT, N_("Green"), 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, PROP_FACTOR},
+ {SOCK_FLOAT, N_("Blue"), 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, PROP_FACTOR},
+ {SOCK_FLOAT, N_("Alpha"), 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, PROP_FACTOR},
+ {-1, ""},
+};
+static bNodeSocketTemplate outputs[] = {
+ {SOCK_RGBA, N_("Color")},
+ {-1, ""},
+};
+
+static void colorfn(float *out, TexParams *p, bNode *node, bNodeStack **in, short thread)
+{
+ int i;
+ for (i = 0; i < 4; i++) {
+ out[i] = tex_input_value(in[i], p, thread);
+ }
+ /* Apply color space if required. */
+ switch (node->custom1) {
+ case NODE_COMBSEP_COLOR_RGB: {
+ /* Pass */
+ break;
+ }
+ case NODE_COMBSEP_COLOR_HSV: {
+ hsv_to_rgb_v(out, out);
+ break;
+ }
+ case NODE_COMBSEP_COLOR_HSL: {
+ hsl_to_rgb_v(out, out);
+ break;
+ }
+ default: {
+ BLI_assert_unreachable();
+ break;
+ }
+ }
+}
+
+static void update(bNodeTree *UNUSED(ntree), bNode *node)
+{
+ node_combsep_color_label(&node->inputs, (NodeCombSepColorMode)node->custom1);
+}
+
+static void exec(void *data,
+ int UNUSED(thread),
+ bNode *node,
+ bNodeExecData *execdata,
+ bNodeStack **in,
+ bNodeStack **out)
+{
+ tex_output(node, execdata, in, out[0], &colorfn, data);
+}
+
+void register_node_type_tex_combine_color(void)
+{
+ static bNodeType ntype;
+
+ tex_node_type_base(&ntype, TEX_NODE_COMBINE_COLOR, "Combine Color", NODE_CLASS_OP_COLOR);
+ node_type_socket_templates(&ntype, inputs, outputs);
+ node_type_exec(&ntype, NULL, NULL, exec);
+ node_type_update(&ntype, update);
+
+ nodeRegisterType(&ntype);
+}
diff --git a/source/blender/nodes/texture/nodes/node_texture_compose.c b/source/blender/nodes/texture/nodes/node_texture_compose.c
index e341b65ac97..ef14062c72d 100644
--- a/source/blender/nodes/texture/nodes/node_texture_compose.c
+++ b/source/blender/nodes/texture/nodes/node_texture_compose.c
@@ -42,7 +42,7 @@ void register_node_type_tex_compose(void)
{
static bNodeType ntype;
- tex_node_type_base(&ntype, TEX_NODE_COMPOSE, "Combine RGBA", NODE_CLASS_OP_COLOR);
+ tex_node_type_base(&ntype, TEX_NODE_COMPOSE_LEGACY, "Combine RGBA", NODE_CLASS_OP_COLOR);
node_type_socket_templates(&ntype, inputs, outputs);
node_type_exec(&ntype, NULL, NULL, exec);
diff --git a/source/blender/nodes/texture/nodes/node_texture_decompose.c b/source/blender/nodes/texture/nodes/node_texture_decompose.c
index 21c3944e255..2d42fa4602e 100644
--- a/source/blender/nodes/texture/nodes/node_texture_decompose.c
+++ b/source/blender/nodes/texture/nodes/node_texture_decompose.c
@@ -62,7 +62,7 @@ void register_node_type_tex_decompose(void)
{
static bNodeType ntype;
- tex_node_type_base(&ntype, TEX_NODE_DECOMPOSE, "Separate RGBA", NODE_CLASS_OP_COLOR);
+ tex_node_type_base(&ntype, TEX_NODE_DECOMPOSE_LEGACY, "Separate RGBA", NODE_CLASS_OP_COLOR);
node_type_socket_templates(&ntype, inputs, outputs);
node_type_exec(&ntype, NULL, NULL, exec);
diff --git a/source/blender/nodes/texture/nodes/node_texture_separate_color.c b/source/blender/nodes/texture/nodes/node_texture_separate_color.c
new file mode 100644
index 00000000000..a482a3f3421
--- /dev/null
+++ b/source/blender/nodes/texture/nodes/node_texture_separate_color.c
@@ -0,0 +1,102 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later
+ * Copyright 2022 Blender Foundation. All rights reserved. */
+
+/** \file
+ * \ingroup texnodes
+ */
+
+#include "BLI_listbase.h"
+#include "NOD_texture.h"
+#include "node_texture_util.h"
+#include <math.h>
+
+static bNodeSocketTemplate inputs[] = {
+ {SOCK_RGBA, N_("Color"), 0.0f, 0.0f, 0.0f, 1.0f},
+ {-1, ""},
+};
+static bNodeSocketTemplate outputs[] = {
+ {SOCK_FLOAT, N_("Red")},
+ {SOCK_FLOAT, N_("Green")},
+ {SOCK_FLOAT, N_("Blue")},
+ {SOCK_FLOAT, N_("Alpha")},
+ {-1, ""},
+};
+
+static void apply_color_space(float *out, NodeCombSepColorMode type)
+{
+ switch (type) {
+ case NODE_COMBSEP_COLOR_RGB: {
+ /* Pass */
+ break;
+ }
+ case NODE_COMBSEP_COLOR_HSV: {
+ rgb_to_hsv_v(out, out);
+ break;
+ }
+ case NODE_COMBSEP_COLOR_HSL: {
+ rgb_to_hsl_v(out, out);
+ break;
+ }
+ default: {
+ BLI_assert_unreachable();
+ break;
+ }
+ }
+}
+
+static void valuefn_r(float *out, TexParams *p, bNode *node, bNodeStack **in, short thread)
+{
+ tex_input_rgba(out, in[0], p, thread);
+ apply_color_space(out, (NodeCombSepColorMode)node->custom1);
+ *out = out[0];
+}
+
+static void valuefn_g(float *out, TexParams *p, bNode *node, bNodeStack **in, short thread)
+{
+ tex_input_rgba(out, in[0], p, thread);
+ apply_color_space(out, (NodeCombSepColorMode)node->custom1);
+ *out = out[1];
+}
+
+static void valuefn_b(float *out, TexParams *p, bNode *node, bNodeStack **in, short thread)
+{
+ tex_input_rgba(out, in[0], p, thread);
+ apply_color_space(out, (NodeCombSepColorMode)node->custom1);
+ *out = out[2];
+}
+
+static void valuefn_a(float *out, TexParams *p, bNode *UNUSED(node), bNodeStack **in, short thread)
+{
+ tex_input_rgba(out, in[0], p, thread);
+ *out = out[3];
+}
+
+static void update(bNodeTree *UNUSED(ntree), bNode *node)
+{
+ node_combsep_color_label(&node->outputs, (NodeCombSepColorMode)node->custom1);
+}
+
+static void exec(void *data,
+ int UNUSED(thread),
+ bNode *node,
+ bNodeExecData *execdata,
+ bNodeStack **in,
+ bNodeStack **out)
+{
+ tex_output(node, execdata, in, out[0], &valuefn_r, data);
+ tex_output(node, execdata, in, out[1], &valuefn_g, data);
+ tex_output(node, execdata, in, out[2], &valuefn_b, data);
+ tex_output(node, execdata, in, out[3], &valuefn_a, data);
+}
+
+void register_node_type_tex_separate_color(void)
+{
+ static bNodeType ntype;
+
+ tex_node_type_base(&ntype, TEX_NODE_SEPARATE_COLOR, "Separate Color", NODE_CLASS_OP_COLOR);
+ node_type_socket_templates(&ntype, inputs, outputs);
+ node_type_exec(&ntype, NULL, NULL, exec);
+ node_type_update(&ntype, update);
+
+ nodeRegisterType(&ntype);
+}
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/gpu/CMakeLists.txt b/source/blender/python/gpu/CMakeLists.txt
index e726cb7883d..8ccb29beb13 100644
--- a/source/blender/python/gpu/CMakeLists.txt
+++ b/source/blender/python/gpu/CMakeLists.txt
@@ -29,8 +29,8 @@ set(SRC
gpu_py_offscreen.c
gpu_py_platform.c
gpu_py_select.c
- gpu_py_shader_create_info.cc
gpu_py_shader.c
+ gpu_py_shader_create_info.cc
gpu_py_state.c
gpu_py_texture.c
gpu_py_types.c
diff --git a/source/blender/python/gpu/gpu_py_shader.c b/source/blender/python/gpu/gpu_py_shader.c
index 77333c6dfea..d7369731a98 100644
--- a/source/blender/python/gpu/gpu_py_shader.c
+++ b/source/blender/python/gpu/gpu_py_shader.c
@@ -46,6 +46,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 +71,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 +752,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 +853,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/intern/CMakeLists.txt b/source/blender/python/intern/CMakeLists.txt
index e4e198ab812..959fbc7ee98 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)
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_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/mathutils/mathutils_Color.c b/source/blender/python/mathutils/mathutils_Color.c
index 0fcde229907..88e8d880360 100644
--- a/source/blender/python/mathutils/mathutils_Color.c
+++ b/source/blender/python/mathutils/mathutils_Color.c
@@ -22,8 +22,40 @@
#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};
@@ -54,29 +86,11 @@ 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)
-{
- 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 Methods: Color Space Conversion
+ * \{ */
PyDoc_STRVAR(Color_from_scene_linear_to_srgb_doc,
".. function:: from_scene_linear_to_srgb()\n"
@@ -190,7 +204,11 @@ static PyObject *Color_from_rec709_linear_to_scene_linear(ColorObject *self)
return Color_CreatePyObject(col, Py_TYPE(self));
}
-/* ---------------------------- Colorspace conversion -------------- */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Color Methods: Color Copy/Deep-Copy
+ * \{ */
PyDoc_STRVAR(Color_copy_doc,
".. function:: copy()\n"
@@ -218,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)
{
@@ -229,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);
@@ -255,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;
@@ -295,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) {
@@ -308,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) {
@@ -336,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;
@@ -373,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;
@@ -398,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;
@@ -436,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)) {
@@ -472,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)) {
@@ -504,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;
@@ -552,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;
@@ -579,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;
@@ -605,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;
@@ -639,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;
@@ -683,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;
@@ -716,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;
@@ -744,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;
@@ -777,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];
@@ -791,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*/
@@ -811,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");
@@ -843,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");
@@ -891,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];
@@ -910,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];
@@ -932,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},
@@ -977,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},
@@ -986,7 +1050,7 @@ static struct PyMethodDef Color_methods[] = {
/* base-math methods */
{"freeze", (PyCFunction)BaseMathObject_freeze, METH_NOARGS, BaseMathObject_freeze_doc},
- /* Colorspace methods. */
+ /* Color-space methods. */
{"from_scene_linear_to_srgb",
(PyCFunction)Color_from_scene_linear_to_srgb,
METH_NOARGS,
@@ -1022,7 +1086,12 @@ static struct PyMethodDef Color_methods[] = {
{NULL, NULL, 0, NULL},
};
-/* ------------------PY_OBECT DEFINITION-------------------------- */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Color Type: Python Object Definition
+ * \{ */
+
PyDoc_STRVAR(
color_doc,
".. class:: Color(rgb)\n"
@@ -1087,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;
@@ -1156,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/render/intern/bake.c b/source/blender/render/intern/bake.c
index bf876163013..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;
@@ -451,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;
@@ -463,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__);
@@ -480,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..43497fb8318 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"
diff --git a/source/blender/render/intern/texture_image.c b/source/blender/render/intern/texture_image.c
index 69c24a18f36..3b1eb293a3a 100644
--- a/source/blender/render/intern/texture_image.c
+++ b/source/blender/render/intern/texture_image.c
@@ -1215,7 +1215,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) {
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..ce58993b7cf 100644
--- a/source/blender/render/intern/texture_procedural.c
+++ b/source/blender/render/intern/texture_procedural.c
@@ -1208,9 +1208,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 +1229,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);
diff --git a/source/blender/sequencer/SEQ_time.h b/source/blender/sequencer/SEQ_time.h
index b4adc950d6b..1da6efb1d04 100644
--- a/source/blender/sequencer/SEQ_time.h
+++ b/source/blender/sequencer/SEQ_time.h
@@ -60,6 +60,13 @@ void SEQ_time_update_recursive(struct Scene *scene, struct Sequence *changed_seq
*/
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(struct Sequence *seq);
+int SEQ_time_right_handle_frame_get(struct Sequence *seq);
+void SEQ_time_left_handle_frame_set(struct Sequence *seq, int val);
+void SEQ_time_right_handle_frame_set(struct Sequence *seq, int val);
#ifdef __cplusplus
}
diff --git a/source/blender/sequencer/SEQ_transform.h b/source/blender/sequencer/SEQ_transform.h
index ea90a3ed372..bd4258bfdb1 100644
--- a/source/blender/sequencer/SEQ_transform.h
+++ b/source/blender/sequencer/SEQ_transform.h
@@ -17,10 +17,6 @@ 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.
diff --git a/source/blender/sequencer/intern/disk_cache.c b/source/blender/sequencer/intern/disk_cache.c
index 0fdaef61b65..f8e8fc32a5d 100644
--- a/source/blender/sequencer/intern/disk_cache.c
+++ b/source/blender/sequencer/intern/disk_cache.c
@@ -344,15 +344,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 +364,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);
}
}
@@ -548,22 +548,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 +585,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 +600,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 +656,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/proxy.c b/source/blender/sequencer/intern/proxy.c
index 91b69bfe01f..59b4c6de1ef 100644
--- a/source/blender/sequencer/intern/proxy.c
+++ b/source/blender/sequencer/intern/proxy.c
@@ -523,9 +523,7 @@ 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;
- timeline_frame++) {
+ for (timeline_frame = seq->startdisp; timeline_frame < seq->enddisp; timeline_frame++) {
if (context->size_flags & IMB_PROXY_25) {
seq_proxy_build_frame(&render_context, &state, seq, timeline_frame, 25, overwrite);
}
@@ -539,8 +537,7 @@ 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->startdisp) / (seq->enddisp - seq->startdisp);
*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 1b9e89a35d5..b0898be3765 100644
--- a/source/blender/sequencer/intern/render.c
+++ b/source/blender/sequencer/intern/render.c
@@ -2088,7 +2088,8 @@ 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->enddisp;
upper_thumb_bound = (upper_thumb_bound > view_area->xmax) ? view_area->xmax + frame_step :
upper_thumb_bound;
@@ -2121,7 +2122,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->startdisp, seq->start);
+ const int content_end = min_ii(seq->enddisp, 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);
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/strip_add.c b/source/blender/sequencer/intern/strip_add.c
index f8e26a56692..77b0fc946d9 100644
--- a/source/blender/sequencer/intern/strip_add.c
+++ b/source/blender/sequencer/intern/strip_add.c
@@ -174,7 +174,7 @@ 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(seq, load_data->effect.end_frame);
}
seq_add_set_name(scene, seq, load_data);
@@ -656,8 +656,8 @@ 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_time_left_handle_frame_set(seq, prev_startdisp);
+ SEQ_time_right_handle_frame_set(seq, prev_enddisp);
SEQ_transform_fix_single_image_seq_offsets(seq);
}
diff --git a/source/blender/sequencer/intern/strip_edit.c b/source/blender/sequencer/intern/strip_edit.c
index 6c7bb71cb75..96bfce8f740 100644
--- a/source/blender/sequencer/intern/strip_edit.c
+++ b/source/blender/sequencer/intern/strip_edit.c
@@ -83,8 +83,6 @@ 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);
@@ -278,20 +276,22 @@ static void seq_split_set_left_hold_offset(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(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(seq, timeline_frame);
+ SEQ_time_right_handle_frame_set(seq, right_handle_backup);
}
}
@@ -299,22 +299,19 @@ static void seq_split_set_right_hold_offset(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(seq, left_handle_backup);
+ SEQ_time_right_handle_frame_set(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(seq, timeline_frame);
}
}
@@ -322,29 +319,24 @@ static void seq_split_set_right_offset(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(seq, timeline_frame);
}
static void seq_split_set_left_offset(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(seq, timeline_frame);
}
static bool seq_edit_split_effect_intersect_check(const Sequence *seq, const int timeline_frame)
diff --git a/source/blender/sequencer/intern/strip_time.c b/source/blender/sequencer/intern/strip_time.c
index a5341dbc528..e4f7a5e87e8 100644
--- a/source/blender/sequencer/intern/strip_time.c
+++ b/source/blender/sequencer/intern/strip_time.c
@@ -139,15 +139,8 @@ void seq_update_sound_bounds_recursive(Scene *scene, Sequence *metaseq)
static void seq_time_update_sequence_bounds(Scene *scene, Sequence *seq)
{
- if (seq->startofs && seq->startstill) {
- seq->startstill = 0;
- }
- if (seq->endofs && seq->endstill) {
- seq->endstill = 0;
- }
-
- seq->startdisp = seq->start + seq->startofs - seq->startstill;
- seq->enddisp = seq->start + seq->len - seq->endofs + seq->endstill;
+ seq->startdisp = seq->start + seq->startofs;
+ seq->enddisp = seq->start + seq->len - seq->endofs;
if (seq->type == SEQ_TYPE_META) {
seq_update_sound_bounds_recursive(scene, seq);
@@ -184,8 +177,8 @@ void SEQ_time_update_meta_strip_range(Scene *scene, Sequence *seq_meta)
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(seq_meta, seq_meta->startdisp);
+ SEQ_time_right_handle_frame_set(seq_meta, seq_meta->enddisp);
}
void SEQ_time_update_sequence(Scene *scene, ListBase *seqbase, Sequence *seq)
@@ -204,7 +197,7 @@ void SEQ_time_update_sequence(Scene *scene, ListBase *seqbase, Sequence *seq)
/* 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;
+ seq->startofs = seq->endofs = 0;
if (seq->seq3) {
seq->start = seq->startdisp = max_iii(
seq->seq1->startdisp, seq->seq2->startdisp, seq->seq3->startdisp);
@@ -516,3 +509,37 @@ bool SEQ_time_strip_intersects_frame(const Sequence *seq, const int timeline_fra
{
return (seq->startdisp <= timeline_frame) && (seq->enddisp > 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(Sequence *seq)
+{
+ return seq->start + seq->startofs;
+}
+int SEQ_time_right_handle_frame_get(Sequence *seq)
+{
+ return seq->start + seq->len - seq->endofs;
+}
+
+void SEQ_time_left_handle_frame_set(Sequence *seq, int val)
+{
+ seq->startofs = val - seq->start;
+}
+
+void SEQ_time_right_handle_frame_set(Sequence *seq, int val)
+{
+ seq->endofs = seq->start + seq->len - val;
+}
diff --git a/source/blender/sequencer/intern/strip_transform.c b/source/blender/sequencer/intern/strip_transform.c
index 2c9ab0a3335..8ff577240d6 100644
--- a/source/blender/sequencer/intern/strip_transform.c
+++ b/source/blender/sequencer/intern/strip_transform.c
@@ -38,39 +38,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) &&
@@ -122,13 +89,13 @@ bool SEQ_transform_seqbase_isolated_sel_check(ListBase *seqbase)
void SEQ_transform_handle_xlimits(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(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(seq, seq_tx_get_end(seq) - 1);
}
/* TODO: This doesn't work at the moment. */
@@ -144,21 +111,21 @@ 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(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(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);
}
}
@@ -171,12 +138,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(seq, SEQ_time_left_handle_frame_get(seq) - offset);
+ SEQ_time_right_handle_frame_set(seq, SEQ_time_right_handle_frame_get(seq) - offset);
seq->start += offset;
}
}
@@ -227,8 +194,8 @@ void SEQ_transform_translate_sequence(Scene *evil_scene, Sequence *seq, int delt
* 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(seq, seq->startdisp + delta);
+ SEQ_time_right_handle_frame_set(seq, seq->enddisp + delta);
}
ListBase *seqbase = SEQ_active_seqbase_get(SEQ_editing_get(evil_scene));
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/WM_api.h b/source/blender/windowmanager/WM_api.h
index b87fa896e69..890872a06bc 100644
--- a/source/blender/windowmanager/WM_api.h
+++ b/source/blender/windowmanager/WM_api.h
@@ -781,7 +781,7 @@ void WM_operator_properties_filesel(struct wmOperatorType *ot,
*/
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 "name" string or "session_uuid" int
+ * 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.
*/
@@ -789,6 +789,11 @@ struct ID *WM_operator_properties_id_lookup_from_name_or_session_uuid(struct Mai
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.
@@ -925,12 +930,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.
@@ -967,6 +974,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
@@ -1070,6 +1085,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 */
/**
@@ -1081,6 +1103,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);
@@ -1226,7 +1255,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,
@@ -1258,7 +1287,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,
@@ -1671,7 +1700,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_types.h b/source/blender/windowmanager/WM_types.h
index a9b8d91ca03..9e9f195c430 100644
--- a/source/blender/windowmanager/WM_types.h
+++ b/source/blender/windowmanager/WM_types.h
@@ -812,6 +812,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. */
@@ -1193,8 +1197,9 @@ typedef struct wmDropBox {
struct wmDrag *drag,
const int xy[2]);
- /** Called with the draw buffer (#GPUViewport) set up for drawing into the region's view.
- * \note Only setups the drawing buffer for drawing in view, not the GPU transform matricies.
+ /**
+ * Called with the draw buffer (#GPUViewport) set up for drawing into the region's view.
+ * \note Only setups the drawing buffer for drawing in view, not the GPU transform matrices.
* The callback has to do that itself, with for example #UI_view2d_view_ortho.
* \param xy: Cursor location in window coordinates (#wmEvent.xy compatible).
*/
diff --git a/source/blender/windowmanager/intern/wm_event_system.c b/source/blender/windowmanager/intern/wm_event_system.c
index c806472103d..3ff3117dafe 100644
--- a/source/blender/windowmanager/intern/wm_event_system.c
+++ b/source/blender/windowmanager/intern/wm_event_system.c
@@ -4019,6 +4019,7 @@ void WM_event_fileselect_event(wmWindowManager *wm, void *ophandle, int eventval
event.type = EVT_FILESELECT;
event.val = eventval;
+ event.flag = 0;
event.customdata = ophandle; /* Only as void pointer type check. */
wm_event_add(win, &event);
@@ -5845,6 +5846,7 @@ 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 = 0;
wm_eventemulation(&test_event, true);
wmKeyMapItem *kmi = NULL;
for (int handler_index = 0; handler_index < ARRAY_SIZE(handlers); handler_index++) {
@@ -5911,7 +5913,7 @@ bool WM_window_modal_keymap_status_draw(bContext *C, wmWindow *win, uiLayout *la
bool show_text = true;
{
- /* Warning: O(n^2). */
+ /* WARNING: O(n^2). */
wmKeyMapItem *kmi = NULL;
for (kmi = keymap->items.first; kmi; kmi = kmi->next) {
if (kmi->propvalue == items[i].value) {
diff --git a/source/blender/windowmanager/intern/wm_files.c b/source/blender/windowmanager/intern/wm_files.c
index bee7e71df54..9578f82d3d4 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) {
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..dbce360cb61 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"
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 3476a16b02a..71c948dfbb9 100644
--- a/source/blender/windowmanager/intern/wm_operator_props.c
+++ b/source/blender/windowmanager/intern/wm_operator_props.c
@@ -246,23 +246,28 @@ ID *WM_operator_properties_id_lookup_from_name_or_session_uuid(Main *bmain,
PointerRNA *ptr,
const ID_Type type)
{
- PropertyRNA *prop_name = RNA_struct_find_property(ptr, "name");
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);
}
- 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);
- }
-
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;
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..307d3282659 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,29 @@ 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) {
+
+ /* 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 +1870,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 +1909,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 +1952,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);
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/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_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) {