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:
authorOmar Emara <mail@OmarEmara.dev>2022-05-12 16:08:18 +0300
committerOmar Emara <mail@OmarEmara.dev>2022-05-12 16:08:18 +0300
commit1328d9a575d28a2756594f01a6ef162e1c5afb8e (patch)
tree4452b9409c2bcf1d6ab057847226429f8dbb4ef0 /source
parent2e8e7bd7b9632122e5d8e83b1ac0690522433c15 (diff)
parent31202ea628d2da2a5a2e6494d12bf32b7886f4cf (diff)
Merge branch 'master' into temp-viewport-compositor-merge
Diffstat (limited to 'source')
-rw-r--r--source/CMakeLists.txt5
-rw-r--r--source/blender/blenkernel/BKE_curves.hh31
-rw-r--r--source/blender/blenkernel/BKE_curves_utils.hh26
-rw-r--r--source/blender/blenkernel/BKE_geometry_set.hh16
-rw-r--r--source/blender/blenkernel/BKE_image.h2
-rw-r--r--source/blender/blenkernel/BKE_mesh.h1
-rw-r--r--source/blender/blenkernel/BKE_modifier.h1
-rw-r--r--source/blender/blenkernel/BKE_spline.hh24
-rw-r--r--source/blender/blenkernel/BKE_unit.h2
-rw-r--r--source/blender/blenkernel/CMakeLists.txt2
-rw-r--r--source/blender/blenkernel/intern/anonymous_attribute.cc2
-rw-r--r--source/blender/blenkernel/intern/asset_catalog_test.cc2
-rw-r--r--source/blender/blenkernel/intern/attribute.c4
-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/curve_catmull_rom.cc8
-rw-r--r--source/blender/blenkernel/intern/curve_eval.cc6
-rw-r--r--source/blender/blenkernel/intern/curve_nurbs.cc40
-rw-r--r--source/blender/blenkernel/intern/curve_to_mesh_convert.cc19
-rw-r--r--source/blender/blenkernel/intern/curves.cc27
-rw-r--r--source/blender/blenkernel/intern/curves_geometry.cc114
-rw-r--r--source/blender/blenkernel/intern/curves_utils.cc38
-rw-r--r--source/blender/blenkernel/intern/geometry_component_curve.cc28
-rw-r--r--source/blender/blenkernel/intern/geometry_component_curves.cc2
-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/image.cc123
-rw-r--r--source/blender/blenkernel/intern/lib_override.c23
-rw-r--r--source/blender/blenkernel/intern/main.c6
-rw-r--r--source/blender/blenkernel/intern/mesh.cc13
-rw-r--r--source/blender/blenkernel/intern/packedFile.c24
-rw-r--r--source/blender/blenkernel/intern/pbvh_pixels.cc2
-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_modifier.c2
-rw-r--r--source/blender/blenlib/BLI_fileops.h2
-rw-r--r--source/blender/blenlib/BLI_length_parameterize.hh2
-rw-r--r--source/blender/blenlib/BLI_math_rotation.h1
-rw-r--r--source/blender/blenlib/BLI_string.h10
-rw-r--r--source/blender/blenlib/BLI_task.hh18
-rw-r--r--source/blender/blenlib/intern/BLI_filelist.c4
-rw-r--r--source/blender/blenlib/intern/string.c20
-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/intern/readfile.c16
-rw-r--r--source/blender/blenloader/intern/versioning_300.c11
-rw-r--r--source/blender/compositor/operations/COM_FastGaussianBlurOperation.cc10
-rw-r--r--source/blender/draw/engines/eevee/eevee_lightcache.c12
-rw-r--r--source/blender/draw/engines/eevee/eevee_lookdev.c4
-rw-r--r--source/blender/draw/engines/eevee/eevee_materials.c27
-rw-r--r--source/blender/draw/engines/eevee/eevee_private.h1
-rw-r--r--source/blender/draw/engines/eevee/shaders/closure_eval_surface_lib.glsl9
-rw-r--r--source/blender/draw/engines/eevee/shaders/closure_eval_volume_lib.glsl4
-rw-r--r--source/blender/draw/engines/eevee/shaders/closure_type_lib.glsl6
-rw-r--r--source/blender/draw/engines/eevee/shaders/prepass_frag.glsl15
-rw-r--r--source/blender/draw/engines/eevee/shaders/surface_lib.glsl8
-rw-r--r--source/blender/draw/engines/eevee/shaders/volumetric_vert.glsl20
-rw-r--r--source/blender/draw/engines/eevee_next/shaders/eevee_attributes_lib.glsl2
-rw-r--r--source/blender/draw/engines/eevee_next/shaders/eevee_geom_curves_vert.glsl2
-rw-r--r--source/blender/draw/engines/eevee_next/shaders/eevee_nodetree_lib.glsl1
-rw-r--r--source/blender/draw/engines/eevee_next/shaders/eevee_surf_lib.glsl7
-rw-r--r--source/blender/draw/engines/eevee_next/shaders/infos/eevee_material_info.hh1
-rw-r--r--source/blender/draw/engines/gpencil/gpencil_render.c12
-rw-r--r--source/blender/draw/engines/image/image_instance_data.hh6
-rw-r--r--source/blender/draw/engines/image/image_texture_info.hh2
-rw-r--r--source/blender/draw/engines/overlay/overlay_gpencil.c6
-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_render.h4
-rw-r--r--source/blender/draw/intern/draw_cache_extract.h1
-rw-r--r--source/blender/draw/intern/draw_cache_extract_mesh.cc5
-rw-r--r--source/blender/draw/intern/draw_cache_impl_curve.cc2
-rw-r--r--source/blender/draw/intern/draw_cache_impl_curves.cc73
-rw-r--r--source/blender/draw/intern/draw_cache_impl_mesh.c16
-rw-r--r--source/blender/draw/intern/draw_cache_impl_subdivision.cc3
-rw-r--r--source/blender/draw/intern/draw_curves.cc2
-rw-r--r--source/blender/draw/intern/draw_manager.c4
-rw-r--r--source/blender/draw/intern/draw_manager.h2
-rw-r--r--source/blender/draw/intern/draw_manager_data.c12
-rw-r--r--source/blender/draw/intern/draw_subdivision.h1
-rw-r--r--source/blender/draw/intern/draw_view_data.cc17
-rw-r--r--source/blender/editors/animation/keyframes_draw.c38
-rw-r--r--source/blender/editors/curves/intern/curves_add.cc2
-rw-r--r--source/blender/editors/include/ED_fileselect.h8
-rw-r--r--source/blender/editors/include/ED_uvedit.h4
-rw-r--r--source/blender/editors/include/UI_icons.h2
-rw-r--r--source/blender/editors/include/UI_interface.h60
-rw-r--r--source/blender/editors/interface/interface.cc12
-rw-r--r--source/blender/editors/interface/interface_anim.c4
-rw-r--r--source/blender/editors/interface/interface_intern.h16
-rw-r--r--source/blender/editors/interface/interface_layout.c2
-rw-r--r--source/blender/editors/interface/interface_query.cc4
-rw-r--r--source/blender/editors/interface/interface_region_search.cc12
-rw-r--r--source/blender/editors/interface/interface_template_search_menu.cc2
-rw-r--r--source/blender/editors/interface/interface_utils.cc2
-rw-r--r--source/blender/editors/interface/interface_widgets.c133
-rw-r--r--source/blender/editors/interface/view2d.cc4
-rw-r--r--source/blender/editors/io/CMakeLists.txt1
-rw-r--r--source/blender/editors/io/io_obj.c40
-rw-r--r--source/blender/editors/io/io_usd.c15
-rw-r--r--source/blender/editors/mesh/editmesh_knife.c155
-rw-r--r--source/blender/editors/object/object_add.cc86
-rw-r--r--source/blender/editors/object/object_edit.c24
-rw-r--r--source/blender/editors/object/object_relations.c2
-rw-r--r--source/blender/editors/sculpt_paint/curves_sculpt_add.cc104
-rw-r--r--source/blender/editors/sculpt_paint/paint_image_proj.c203
-rw-r--r--source/blender/editors/sculpt_paint/sculpt.c2
-rw-r--r--source/blender/editors/sculpt_paint/sculpt_filter_color.c8
-rw-r--r--source/blender/editors/sculpt_paint/sculpt_ops.c4
-rw-r--r--source/blender/editors/sound/sound_ops.c3
-rw-r--r--source/blender/editors/space_file/filelist.c3
-rw-r--r--source/blender/editors/space_file/filesel.c18
-rw-r--r--source/blender/editors/space_image/image_ops.c27
-rw-r--r--source/blender/editors/space_nla/nla_channels.c116
-rw-r--r--source/blender/editors/space_node/node_context_path.cc2
-rw-r--r--source/blender/editors/space_node/node_draw.cc12
-rw-r--r--source/blender/editors/space_node/node_edit.cc179
-rw-r--r--source/blender/editors/space_node/node_select.cc170
-rw-r--r--source/blender/editors/space_outliner/outliner_draw.cc24
-rw-r--r--source/blender/editors/space_outliner/outliner_edit.cc193
-rw-r--r--source/blender/editors/space_outliner/outliner_intern.hh8
-rw-r--r--source/blender/editors/space_outliner/outliner_ops.cc1
-rw-r--r--source/blender/editors/space_outliner/outliner_tools.cc37
-rw-r--r--source/blender/editors/space_outliner/tree/tree_element_overrides.cc7
-rw-r--r--source/blender/editors/space_outliner/tree/tree_element_overrides.hh5
-rw-r--r--source/blender/editors/space_sequencer/sequencer_add.c2
-rw-r--r--source/blender/editors/space_spreadsheet/spreadsheet_data_source_geometry.cc20
-rw-r--r--source/blender/editors/space_spreadsheet/spreadsheet_dataset_draw.cc4
-rw-r--r--source/blender/editors/transform/transform_convert.c87
-rw-r--r--source/blender/editors/transform/transform_snap.c2
-rw-r--r--source/blender/editors/transform/transform_snap_object.cc15
-rw-r--r--source/blender/editors/uvedit/uvedit_unwrap_ops.c160
-rw-r--r--source/blender/freestyle/intern/geometry/SweepLine.h2
-rw-r--r--source/blender/geometry/CMakeLists.txt4
-rw-r--r--source/blender/geometry/GEO_mesh_primitive_cuboid.hh18
-rw-r--r--source/blender/geometry/GEO_resample_curves.hh39
-rw-r--r--source/blender/geometry/intern/mesh_primitive_cuboid.cc423
-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/gpencil_modifiers/CMakeLists.txt1
-rw-r--r--source/blender/gpencil_modifiers/intern/lineart/lineart_cpu.c31
-rw-r--r--source/blender/gpu/CMakeLists.txt1
-rw-r--r--source/blender/gpu/GPU_capabilities.h2
-rw-r--r--source/blender/gpu/GPU_shader.h10
-rw-r--r--source/blender/gpu/GPU_texture.h2
-rw-r--r--source/blender/gpu/GPU_vertex_format.h2
-rw-r--r--source/blender/gpu/intern/gpu_capabilities.cc10
-rw-r--r--source/blender/gpu/intern/gpu_capabilities_private.hh2
-rw-r--r--source/blender/gpu/intern/gpu_codegen.cc36
-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_index_buffer.cc1
-rw-r--r--source/blender/gpu/intern/gpu_index_buffer_private.hh7
-rw-r--r--source/blender/gpu/intern/gpu_material.c2
-rw-r--r--source/blender/gpu/intern/gpu_node_graph.c2
-rw-r--r--source/blender/gpu/intern/gpu_shader_builtin.c15
-rw-r--r--source/blender/gpu/intern/gpu_shader_dependency.cc44
-rw-r--r--source/blender/gpu/intern/gpu_vertex_buffer.cc10
-rw-r--r--source/blender/gpu/intern/gpu_vertex_format.cc22
-rw-r--r--source/blender/gpu/intern/gpu_viewport.c28
-rw-r--r--source/blender/gpu/opengl/gl_backend.cc8
-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/shaders/gpu_shader_codegen_lib.glsl4
-rw-r--r--source/blender/gpu/shaders/gpu_shader_image_overlays_stereo_merge_frag.glsl12
-rw-r--r--source/blender/gpu/shaders/infos/gpu_shader_2D_image_overlays_stereo_merge_info.hh4
-rw-r--r--source/blender/gpu/shaders/infos/gpu_shader_3D_depth_only_info.hh3
-rw-r--r--source/blender/gpu/shaders/infos/gpu_shader_3D_flat_color_info.hh3
-rw-r--r--source/blender/gpu/shaders/infos/gpu_shader_3D_image_info.hh20
-rw-r--r--source/blender/gpu/shaders/infos/gpu_shader_3D_point_info.hh3
-rw-r--r--source/blender/gpu/shaders/infos/gpu_shader_3D_smooth_color_info.hh3
-rw-r--r--source/blender/gpu/shaders/material/gpu_shader_material_add_shader.glsl2
-rw-r--r--source/blender/gpu/shaders/material/gpu_shader_material_eevee_specular.glsl6
-rw-r--r--source/blender/gpu/shaders/material/gpu_shader_material_geometry.glsl2
-rw-r--r--source/blender/gpu/shaders/material/gpu_shader_material_hair.glsl2
-rw-r--r--source/blender/gpu/shaders/material/gpu_shader_material_hair_info.glsl4
-rw-r--r--source/blender/gpu/shaders/material/gpu_shader_material_mix_shader.glsl2
-rw-r--r--source/blender/gpu/shaders/material/gpu_shader_material_principled.glsl6
-rw-r--r--source/blender/gpu/tests/gpu_shader_builtin_test.cc1
-rw-r--r--source/blender/imbuf/intern/anim_movie.c2
-rw-r--r--source/blender/imbuf/intern/jpeg.c8
-rw-r--r--source/blender/imbuf/intern/openexr/openexr_api.cpp31
-rw-r--r--source/blender/imbuf/intern/util_gpu.c2
-rw-r--r--source/blender/io/alembic/intern/abc_reader_mesh.cc2
-rw-r--r--source/blender/io/common/CMakeLists.txt7
-rw-r--r--source/blender/io/common/IO_path_util.hh29
-rw-r--r--source/blender/io/common/IO_path_util_types.h18
-rw-r--r--source/blender/io/common/intern/path_util.cc82
-rw-r--r--source/blender/io/usd/intern/usd_reader_mesh.cc2
-rw-r--r--source/blender/io/wavefront_obj/CMakeLists.txt4
-rw-r--r--source/blender/io/wavefront_obj/IO_wavefront_obj.h4
-rw-r--r--source/blender/io/wavefront_obj/exporter/obj_export_file_writer.cc34
-rw-r--r--source/blender/io/wavefront_obj/exporter/obj_export_file_writer.hh11
-rw-r--r--source/blender/io/wavefront_obj/exporter/obj_export_mtl.cc6
-rw-r--r--source/blender/io/wavefront_obj/exporter/obj_exporter.cc11
-rw-r--r--source/blender/io/wavefront_obj/importer/obj_import_file_reader.cc3
-rw-r--r--source/blender/io/wavefront_obj/importer/obj_import_mesh.cc2
-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.cc (renamed from source/blender/io/common/intern/string_utils.cc)6
-rw-r--r--source/blender/io/wavefront_obj/importer/obj_import_string_utils.hh (renamed from source/blender/io/common/IO_string_utils.hh)11
-rw-r--r--source/blender/io/wavefront_obj/tests/obj_exporter_tests.cc25
-rw-r--r--source/blender/io/wavefront_obj/tests/obj_exporter_tests.hh2
-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)18
-rw-r--r--source/blender/makesdna/DNA_brush_enums.h1
-rw-r--r--source/blender/makesdna/DNA_curves_types.h4
-rw-r--r--source/blender/makesdna/DNA_image_types.h5
-rw-r--r--source/blender/makesdna/DNA_mesh_types.h2
-rw-r--r--source/blender/makesdna/DNA_userdef_types.h2
-rw-r--r--source/blender/makesdna/intern/dna_rename_defs.h2
-rw-r--r--source/blender/makesrna/intern/rna_ID.c2
-rw-r--r--source/blender/makesrna/intern/rna_brush.c9
-rw-r--r--source/blender/makesrna/intern/rna_curves.c10
-rw-r--r--source/blender/makesrna/intern/rna_gpencil_modifier.c9
-rw-r--r--source/blender/makesrna/intern/rna_image.c10
-rw-r--r--source/blender/makesrna/intern/rna_image_api.c5
-rw-r--r--source/blender/makesrna/intern/rna_modifier.c4
-rw-r--r--source/blender/makesrna/intern/rna_nodetree.c2
-rw-r--r--source/blender/makesrna/intern/rna_space.c2
-rw-r--r--source/blender/makesrna/intern/rna_userdef.c5
-rw-r--r--source/blender/makesrna/intern/rna_xr.c57
-rw-r--r--source/blender/modifiers/CMakeLists.txt2
-rw-r--r--source/blender/modifiers/intern/MOD_nodes.cc9
-rw-r--r--source/blender/modifiers/intern/MOD_particlesystem.cc (renamed from source/blender/modifiers/intern/MOD_particlesystem.c)82
-rw-r--r--source/blender/modifiers/intern/MOD_util.h8
-rw-r--r--source/blender/nodes/NOD_geometry_nodes_eval_log.hh8
-rw-r--r--source/blender/nodes/geometry/node_geometry_tree.cc2
-rw-r--r--source/blender/nodes/geometry/node_geometry_util.hh2
-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.cc4
-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.cc537
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_curve_reverse.cc4
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_curve_spline_parameter.cc2
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_curve_spline_type.cc24
-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.cc33
-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.cc32
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_edge_split.cc4
-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_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.cc6
-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_subdivision_surface.cc4
-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.cc18
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_vertex_color.cc16
-rw-r--r--source/blender/nodes/texture/node_texture_util.c4
-rw-r--r--source/blender/python/gpu/gpu_py_shader.c4
-rw-r--r--source/blender/python/intern/bpy_utils_units.c14
-rw-r--r--source/blender/render/intern/bake.c16
-rw-r--r--source/blender/render/intern/multires_bake.c241
-rw-r--r--source/blender/windowmanager/WM_types.h4
-rw-r--r--source/blender/windowmanager/gizmo/intern/wm_gizmo_map.c205
-rw-r--r--source/blender/windowmanager/intern/wm_draw.c2
-rw-r--r--source/blender/windowmanager/intern/wm_event_system.c203
-rw-r--r--source/blender/windowmanager/intern/wm_window.c3
-rw-r--r--source/blender/windowmanager/xr/intern/wm_xr_session.c4
294 files changed, 4420 insertions, 3161 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/blenkernel/BKE_curves.hh b/source/blender/blenkernel/BKE_curves.hh
index bf2d50f63be..87fa26a4f73 100644
--- a/source/blender/blenkernel/BKE_curves.hh
+++ b/source/blender/blenkernel/BKE_curves.hh
@@ -50,7 +50,7 @@ struct BasisCache {
Vector<int> start_indices;
/**
- * The result of #check_valid_size_and_order, to avoid retrieving its inputs later on.
+ * The result of #check_valid_num_and_order, to avoid retrieving its inputs later on.
* If this is true, the data above will be invalid, and original data should be copied
* to the evaluated result.
*/
@@ -127,7 +127,7 @@ class CurvesGeometry : public ::CurvesGeometry {
* Create curves with the given size. Only the position attribute is created, along with the
* offsets.
*/
- CurvesGeometry(int point_size, int curve_size);
+ CurvesGeometry(int point_num, int curve_num);
CurvesGeometry(const CurvesGeometry &other);
CurvesGeometry(CurvesGeometry &&other);
CurvesGeometry &operator=(const CurvesGeometry &other);
@@ -418,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;
@@ -585,11 +585,11 @@ namespace catmull_rom {
* \param points_num: The number of points in the curve.
* \param resolution: The resolution for each segment.
*/
-int calculate_evaluated_size(int points_num, bool cyclic, int resolution);
+int calculate_evaluated_num(int points_num, bool cyclic, int resolution);
/**
* Evaluate the Catmull Rom curve. The length of the #dst span should be calculated with
- * #calculate_evaluated_size and is expected to divide evenly by the #src span's segment size.
+ * #calculate_evaluated_num and is expected to divide evenly by the #src span's segment size.
*/
void interpolate_to_evaluated(GSpan src, bool cyclic, int resolution, GMutableSpan dst);
@@ -606,7 +606,7 @@ namespace nurbs {
/**
* Checks the conditions that a NURBS curve needs to evaluate.
*/
-bool check_valid_size_and_order(int points_num, int8_t order, bool cyclic, KnotsMode knots_mode);
+bool check_valid_num_and_order(int points_num, int8_t order, bool cyclic, KnotsMode knots_mode);
/**
* Calculate the standard evaluated size for a NURBS curve, using the standard that
@@ -616,7 +616,7 @@ bool check_valid_size_and_order(int points_num, int8_t order, bool cyclic, Knots
* for predictability and so that cached basis weights of NURBS curves with these properties can be
* shared.
*/
-int calculate_evaluated_size(
+int calculate_evaluated_num(
int points_num, int8_t order, bool cyclic, int resolution, KnotsMode knots_mode);
/**
@@ -624,7 +624,7 @@ int calculate_evaluated_size(
* The knots must be longer for a cyclic curve, for example, in order to provide weights for the
* last evaluated points that are also influenced by the first control points.
*/
-int knots_size(int points_num, int8_t order, bool cyclic);
+int knots_num(int points_num, int8_t order, bool cyclic);
/**
* Calculate the knots for a curve given its properties, based on built-in standards defined by
@@ -644,7 +644,7 @@ void calculate_knots(
* and a weight for each control point.
*/
void calculate_basis_cache(int points_num,
- int evaluated_size,
+ int evaluated_num,
int8_t order,
bool cyclic,
Span<float> knots,
@@ -671,6 +671,7 @@ void interpolate_to_evaluated(const BasisCache &basis_cache,
} // namespace curves
Curves *curves_new_nomain(int points_num, int curves_num);
+Curves *curves_new_nomain(CurvesGeometry curves);
/**
* Create a new curves data-block containing a single curve with the given length and type.
@@ -685,11 +686,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
{
@@ -719,7 +720,7 @@ inline const std::array<int, CURVE_TYPES_NUM> &CurvesGeometry::curve_type_counts
inline IndexRange CurvesGeometry::points_for_curve(const int index) const
{
/* Offsets are not allocated when there are no curves. */
- BLI_assert(this->curve_size > 0);
+ BLI_assert(this->curve_num > 0);
BLI_assert(this->curve_offsets != nullptr);
const int offset = this->curve_offsets[index];
const int offset_next = this->curve_offsets[index + 1];
@@ -729,7 +730,7 @@ inline IndexRange CurvesGeometry::points_for_curve(const int index) const
inline IndexRange CurvesGeometry::points_for_curves(const IndexRange curves) const
{
/* Offsets are not allocated when there are no curves. */
- BLI_assert(this->curve_size > 0);
+ BLI_assert(this->curve_num > 0);
BLI_assert(this->curve_offsets != nullptr);
const int offset = this->curve_offsets[curves.start()];
const int offset_next = this->curve_offsets[curves.one_after_last()];
@@ -751,7 +752,7 @@ inline IndexRange CurvesGeometry::evaluated_points_for_curve(int index) const
inline IndexRange CurvesGeometry::evaluated_points_for_curves(const IndexRange curves) const
{
BLI_assert(!this->runtime->offsets_cache_dirty);
- BLI_assert(this->curve_size > 0);
+ BLI_assert(this->curve_num > 0);
const int offset = this->runtime->evaluated_offsets_cache[curves.start()];
const int offset_next = this->runtime->evaluated_offsets_cache[curves.one_after_last()];
return {offset, offset_next - offset};
@@ -769,7 +770,7 @@ inline IndexRange CurvesGeometry::lengths_range_for_curve(const int curve_index,
BLI_assert(cyclic == this->cyclic()[curve_index]);
const IndexRange points = this->evaluated_points_for_curve(curve_index);
const int start = points.start() + curve_index;
- return {start, curves::curve_segment_size(points.size(), cyclic)};
+ return {start, curves::curve_segment_num(points.size(), cyclic)};
}
inline Span<float> CurvesGeometry::evaluated_lengths_for_curve(const int curve_index,
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_geometry_set.hh b/source/blender/blenkernel/BKE_geometry_set.hh
index dfd9fccebbd..849c430fd7b 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
@@ -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;
@@ -715,7 +715,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 +949,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 +963,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_image.h b/source/blender/blenkernel/BKE_image.h
index 42d0e66cf49..25f20b82900 100644
--- a/source/blender/blenkernel/BKE_image.h
+++ b/source/blender/blenkernel/BKE_image.h
@@ -454,7 +454,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_mesh.h b/source/blender/blenkernel/BKE_mesh.h
index 091f30825ae..3e06a9d9e9c 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.
diff --git a/source/blender/blenkernel/BKE_modifier.h b/source/blender/blenkernel/BKE_modifier.h
index a38bfb497a2..4749aab4379 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,
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_unit.h b/source/blender/blenkernel/BKE_unit.h
index d6de95a19b7..823d32f83ba 100644
--- a/source/blender/blenkernel/BKE_unit.h
+++ b/source/blender/blenkernel/BKE_unit.h
@@ -91,7 +91,7 @@ const char *BKE_unit_identifier_get(const void *usys_pt, int index);
double BKE_unit_scalar_get(const void *usys_pt, int index);
bool BKE_unit_is_suppressed(const void *usys_pt, int index);
-/** Aligned with #PropertyUnit. */
+/** Aligned with #PropertyUnit and `bpyunits_ucategories_items` in `bpy_utils_units.c`. */
enum {
B_UNIT_NONE = 0,
B_UNIT_LENGTH = 1,
diff --git a/source/blender/blenkernel/CMakeLists.txt b/source/blender/blenkernel/CMakeLists.txt
index c9e88362b80..0b4f81df452 100644
--- a/source/blender/blenkernel/CMakeLists.txt
+++ b/source/blender/blenkernel/CMakeLists.txt
@@ -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
@@ -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
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/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.c
index 0cb0704ff80..7f93eb7b393 100644
--- a/source/blender/blenkernel/intern/attribute.c
+++ b/source/blender/blenkernel/intern/attribute.c
@@ -75,9 +75,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:
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/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..c507e7934a8 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;
@@ -463,7 +463,7 @@ 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(),
+ Curves *curves = blender::bke::curves_new_nomain(curve_eval.total_control_point_num(),
curve_eval.splines().size());
CurveComponent dst_component;
dst_component.replace(curves, GeometryOwnershipType::Editable);
diff --git a/source/blender/blenkernel/intern/curve_nurbs.cc b/source/blender/blenkernel/intern/curve_nurbs.cc
index 45440358221..cd6b64e9a03 100644
--- a/source/blender/blenkernel/intern/curve_nurbs.cc
+++ b/source/blender/blenkernel/intern/curve_nurbs.cc
@@ -10,10 +10,10 @@
namespace blender::bke::curves::nurbs {
-bool check_valid_size_and_order(const int points_num,
- const int8_t order,
- const bool cyclic,
- const KnotsMode knots_mode)
+bool check_valid_num_and_order(const int points_num,
+ const int8_t order,
+ const bool cyclic,
+ const KnotsMode knots_mode)
{
if (points_num < order) {
return false;
@@ -29,19 +29,19 @@ bool check_valid_size_and_order(const int points_num,
return true;
}
-int calculate_evaluated_size(const int points_num,
- const int8_t order,
- const bool cyclic,
- const int resolution,
- const KnotsMode knots_mode)
+int calculate_evaluated_num(const int points_num,
+ const int8_t order,
+ const bool cyclic,
+ const int resolution,
+ const KnotsMode knots_mode)
{
- if (!check_valid_size_and_order(points_num, order, cyclic, knots_mode)) {
+ if (!check_valid_num_and_order(points_num, order, cyclic, knots_mode)) {
return points_num;
}
- return resolution * curve_segment_size(points_num, cyclic);
+ return resolution * curve_segment_num(points_num, cyclic);
}
-int knots_size(const int points_num, const int8_t order, const bool cyclic)
+int knots_num(const int points_num, const int8_t order, const bool cyclic)
{
if (cyclic) {
return points_num + order * 2 - 1;
@@ -55,7 +55,7 @@ void calculate_knots(const int points_num,
const bool cyclic,
MutableSpan<float> knots)
{
- BLI_assert(knots.size() == knots_size(points_num, order, cyclic));
+ BLI_assert(knots.size() == knots_num(points_num, order, cyclic));
UNUSED_VARS_NDEBUG(points_num);
const bool is_bezier = ELEM(mode, NURBS_KNOT_MODE_BEZIER, NURBS_KNOT_MODE_ENDPOINT_BEZIER);
@@ -147,7 +147,7 @@ static void calculate_basis_for_point(const float parameter,
}
void calculate_basis_cache(const int points_num,
- const int evaluated_size,
+ const int evaluated_num,
const int8_t order,
const bool cyclic,
const Span<float> knots,
@@ -157,10 +157,10 @@ void calculate_basis_cache(const int points_num,
const int8_t degree = order - 1;
- basis_cache.weights.resize(evaluated_size * order);
- basis_cache.start_indices.resize(evaluated_size);
+ basis_cache.weights.resize(evaluated_num * order);
+ basis_cache.start_indices.resize(evaluated_num);
- if (evaluated_size == 0) {
+ if (evaluated_num == 0) {
return;
}
@@ -168,12 +168,12 @@ void calculate_basis_cache(const int points_num,
MutableSpan<int> basis_start_indices(basis_cache.start_indices);
const int last_control_point_index = cyclic ? points_num + degree : points_num;
- const int evaluated_segment_size = curve_segment_size(evaluated_size, cyclic);
+ const int evaluated_segment_num = curve_segment_num(evaluated_num, cyclic);
const float start = knots[degree];
const float end = knots[last_control_point_index];
- const float step = (end - start) / evaluated_segment_size;
- for (const int i : IndexRange(evaluated_size)) {
+ const float step = (end - start) / evaluated_segment_num;
+ for (const int i : IndexRange(evaluated_num)) {
/* Clamp parameter due to floating point inaccuracy. */
const float parameter = std::clamp(start + step * i, knots[0], knots[points_num + degree]);
diff --git a/source/blender/blenkernel/intern/curve_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..84ba98db54b 100644
--- a/source/blender/blenkernel/intern/curves.cc
+++ b/source/blender/blenkernel/intern/curves.cc
@@ -78,12 +78,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));
@@ -136,17 +136,17 @@ static void curves_blend_write(BlendWriter *writer, ID *id, const void *id_addre
CustomData_blend_write(writer,
&curves->geometry.point_data,
players,
- curves->geometry.point_size,
+ curves->geometry.point_num,
CD_MASK_ALL,
&curves->id);
CustomData_blend_write(writer,
&curves->geometry.curve_data,
clayers,
- curves->geometry.curve_size,
+ 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) {
@@ -169,11 +169,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__);
@@ -379,4 +379,11 @@ Curves *curves_new_nomain_single(const int points_num, const CurveType type)
return curves;
}
+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 4dd0fad57d4..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,16 +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_size;
+ this->runtime->type_counts[CURVE_TYPE_CATMULL_ROM] = curve_num;
}
/**
@@ -74,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();
@@ -94,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);
}
@@ -110,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);
@@ -130,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);
}
@@ -145,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;
@@ -158,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();
}
@@ -180,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>
@@ -196,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>());
@@ -204,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>
@@ -213,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;
@@ -301,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
@@ -444,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;
}
@@ -472,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();
@@ -484,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;
@@ -587,13 +587,13 @@ void CurvesGeometry::ensure_nurbs_basis_cache() const
const bool is_cyclic = cyclic[curve_index];
const KnotsMode mode = KnotsMode(knots_modes[curve_index]);
- if (!curves::nurbs::check_valid_size_and_order(points.size(), order, is_cyclic, mode)) {
+ if (!curves::nurbs::check_valid_num_and_order(points.size(), order, is_cyclic, mode)) {
basis_caches[curve_index].invalid = true;
continue;
}
- const int knots_size = curves::nurbs::knots_size(points.size(), order, is_cyclic);
- Array<float> knots(knots_size);
+ const int knots_num = curves::nurbs::knots_num(points.size(), order, is_cyclic);
+ Array<float> knots(knots_num);
curves::nurbs::calculate_knots(points.size(), mode, order, is_cyclic, knots);
curves::nurbs::calculate_basis_cache(points.size(),
evaluated_points.size(),
@@ -914,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();
@@ -944,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();
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/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 7c4a7db6462..b565143d08f 100644
--- a/source/blender/blenkernel/intern/geometry_component_curves.cc
+++ b/source/blender/blenkernel/intern/geometry_component_curves.cc
@@ -308,7 +308,7 @@ bool CurveLengthFieldInput::is_equal_to(const fn::FieldNode &other) const
/** \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;
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/image.cc b/source/blender/blenkernel/intern/image.cc
index dfa820519a5..3d894f47ae0 100644
--- a/source/blender/blenkernel/intern/image.cc
+++ b/source/blender/blenkernel/intern/image.cc
@@ -721,6 +721,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) {
@@ -1197,7 +1200,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 +1223,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 +1240,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 +1295,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 +1331,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);
}
}
@@ -2950,8 +2963,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));
@@ -3926,18 +3940,23 @@ static ImBuf *load_image_single(Image *ima,
int flag = IB_rect | IB_multilayer;
*r_cache_ibuf = true;
+ const int tile_number = image_get_tile_number_from_iuser(ima, iuser);
/* is there a PackedFile with this image ? */
if (has_packed && !is_sequence) {
- ImagePackedFile *imapf = static_cast<ImagePackedFile *>(
- BLI_findlink(&ima->packedfiles, view_id));
- if (imapf->packedfile) {
- flag |= imbuf_alpha_flags_for_image(ima);
- ibuf = IMB_ibImageFromMemory((unsigned char *)imapf->packedfile->data,
- imapf->packedfile->size,
- flag,
- ima->colorspace_settings.name,
- "<packed data>");
+ flag |= imbuf_alpha_flags_for_image(ima);
+
+ LISTBASE_FOREACH (ImagePackedFile *, imapf, &ima->packedfiles) {
+ if (imapf->view == view_id && imapf->tile_number == tile_number) {
+ if (imapf->packedfile) {
+ ibuf = IMB_ibImageFromMemory((unsigned char *)imapf->packedfile->data,
+ imapf->packedfile->size,
+ flag,
+ ima->colorspace_settings.name,
+ "<packed data>");
+ }
+ break;
+ }
}
}
else {
@@ -3996,6 +4015,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));
}
@@ -5103,7 +5124,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/lib_override.c b/source/blender/blenkernel/intern/lib_override.c
index a2338eb9b39..9dc64365f0c 100644
--- a/source/blender/blenkernel/intern/lib_override.c
+++ b/source/blender/blenkernel/intern/lib_override.c
@@ -1384,7 +1384,21 @@ void BKE_lib_override_library_main_hierarchy_root_ensure(Main *bmain)
continue;
}
if (id->override_library->hierarchy_root != NULL) {
- continue;
+ if (!ID_IS_OVERRIDE_LIBRARY_REAL(id->override_library->hierarchy_root) ||
+ id->override_library->hierarchy_root->lib != id->lib) {
+ CLOG_ERROR(
+ &LOG,
+ "Existing override hierarchy root ('%s') for ID '%s' is invalid, will try to find a "
+ "new valid one",
+ id->override_library->hierarchy_root != NULL ?
+ id->override_library->hierarchy_root->name :
+ "<NONE>",
+ id->name);
+ id->override_library->hierarchy_root = NULL;
+ }
+ else {
+ continue;
+ }
}
BKE_main_relations_tag_set(bmain, MAINIDRELATIONS_ENTRY_TAGS_PROCESSED, false);
@@ -1402,7 +1416,7 @@ void BKE_lib_override_library_main_hierarchy_root_ensure(Main *bmain)
continue;
}
- lib_override_root_hierarchy_set(bmain, id_root, id_root, NULL);
+ lib_override_root_hierarchy_set(bmain, id_root, id, NULL);
BLI_assert(id->override_library->hierarchy_root != NULL);
}
@@ -1451,6 +1465,7 @@ static void lib_override_library_remap(Main *bmain,
remapper,
ID_REMAP_FORCE_USER_REFCOUNT | ID_REMAP_FORCE_NEVER_NULL_USAGE);
BKE_id_remapper_free(remapper);
+ BLI_linklist_free(nomain_ids, NULL);
}
static bool lib_override_library_resync(Main *bmain,
@@ -2058,6 +2073,10 @@ 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);
+ }
+
LinkNodePair **id_resync_roots_p;
if (!BLI_ghash_ensure_p(id_roots, id_root, (void ***)&id_resync_roots_p)) {
*id_resync_roots_p = MEM_callocN(sizeof(**id_resync_roots_p), __func__);
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/mesh.cc b/source/blender/blenkernel/intern/mesh.cc
index 628f59ae449..4e3544d0f60 100644
--- a/source/blender/blenkernel/intern/mesh.cc
+++ b/source/blender/blenkernel/intern/mesh.cc
@@ -1577,6 +1577,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++) {
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/pbvh_pixels.cc b/source/blender/blenkernel/intern/pbvh_pixels.cc
index 5623cac44ac..8b3fcffd9cd 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);
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_modifier.c b/source/blender/blenkernel/intern/subdiv_modifier.c
index 83772f153d9..3692a3cc4f7 100644
--- a/source/blender/blenkernel/intern/subdiv_modifier.c
+++ b/source/blender/blenkernel/intern/subdiv_modifier.c
@@ -77,7 +77,7 @@ static bool is_subdivision_evaluation_possible_on_gpu(void)
return false;
}
- if (GPU_max_shader_storage_buffer_bindings() < MAX_GPU_SUBDIV_SSBOS) {
+ if (GPU_max_compute_shader_storage_blocks() < MAX_GPU_SUBDIV_SSBOS) {
return false;
}
diff --git a/source/blender/blenlib/BLI_fileops.h b/source/blender/blenlib/BLI_fileops.h
index 3ce2b90e729..9a24b09fc66 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]);
/**
diff --git a/source/blender/blenlib/BLI_length_parameterize.hh b/source/blender/blenlib/BLI_length_parameterize.hh
index 6fe1c6513a2..f13641c3a65 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)
{
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_string.h b/source/blender/blenlib/BLI_string.h
index 45abac33795..15926e8f2d2 100644
--- a/source/blender/blenlib/BLI_string.h
+++ b/source/blender/blenlib/BLI_string.h
@@ -307,7 +307,7 @@ void BLI_str_format_byte_unit(char dst[15], long long int bytes, bool base_10) A
*
* Length of 7 is the maximum of the resulting string, for example, `-15.5K\0`.
*/
-void BLI_str_format_attribute_domain_size(char dst[7], int number_to_format) ATTR_NONNULL();
+void BLI_str_format_decimal_unit(char dst[7], int number_to_format) ATTR_NONNULL();
/**
* Compare two strings without regard to case.
*
@@ -343,8 +343,16 @@ int BLI_strcmp_ignore_pad(const char *str1, const char *str2, char pad) ATTR_WAR
*/
size_t BLI_strnlen(const char *str, size_t maxlen) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
+/**
+ * String case conversion, not affected by locale.
+ */
+
void BLI_str_tolower_ascii(char *str, size_t len) ATTR_NONNULL();
void BLI_str_toupper_ascii(char *str, size_t len) ATTR_NONNULL();
+
+char BLI_tolower_ascii(const char c);
+char BLI_toupper_ascii(const char c);
+
/**
* Strip white-space from end of the string.
*/
diff --git a/source/blender/blenlib/BLI_task.hh b/source/blender/blenlib/BLI_task.hh
index d87a86ce696..904dea66f7a 100644
--- a/source/blender/blenlib/BLI_task.hh
+++ b/source/blender/blenlib/BLI_task.hh
@@ -77,17 +77,19 @@ Value parallel_reduce(IndexRange range,
const Reduction &reduction)
{
#ifdef WITH_TBB
- return tbb::parallel_reduce(
- tbb::blocked_range<int64_t>(range.first(), range.one_after_last(), grain_size),
- identity,
- [&](const tbb::blocked_range<int64_t> &subrange, const Value &ident) {
- return function(IndexRange(subrange.begin(), subrange.size()), ident);
- },
- reduction);
+ if (range.size() >= grain_size) {
+ return tbb::parallel_reduce(
+ tbb::blocked_range<int64_t>(range.first(), range.one_after_last(), grain_size),
+ identity,
+ [&](const tbb::blocked_range<int64_t> &subrange, const Value &ident) {
+ return function(IndexRange(subrange.begin(), subrange.size()), ident);
+ },
+ reduction);
+ }
#else
UNUSED_VARS(grain_size, reduction);
- return function(range, identity);
#endif
+ return function(range, identity);
}
/**
diff --git a/source/blender/blenlib/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/string.c b/source/blender/blenlib/intern/string.c
index 74559751d91..976b9a5cd02 100644
--- a/source/blender/blenlib/intern/string.c
+++ b/source/blender/blenlib/intern/string.c
@@ -914,14 +914,22 @@ size_t BLI_strnlen(const char *s, const size_t maxlen)
/** \name String Case Conversion
* \{ */
+char BLI_tolower_ascii(const char c)
+{
+ return (c >= 'A' && c <= 'Z') ? c + ('a' - 'A') : c;
+}
+
+char BLI_toupper_ascii(const char c)
+{
+ return (c >= 'a' && c <= 'z') ? c - ('a' - 'A') : c;
+}
+
void BLI_str_tolower_ascii(char *str, const size_t len)
{
size_t i;
for (i = 0; (i < len) && str[i]; i++) {
- if (str[i] >= 'A' && str[i] <= 'Z') {
- str[i] += 'a' - 'A';
- }
+ str[i] = BLI_tolower_ascii(str[i]);
}
}
@@ -930,9 +938,7 @@ void BLI_str_toupper_ascii(char *str, const size_t len)
size_t i;
for (i = 0; (i < len) && str[i]; i++) {
- if (str[i] >= 'a' && str[i] <= 'z') {
- str[i] -= 'a' - 'A';
- }
+ str[i] = BLI_toupper_ascii(str[i]);
}
}
@@ -1149,7 +1155,7 @@ void BLI_str_format_byte_unit(char dst[15], long long int bytes, const bool base
BLI_strncpy(dst + len, base_10 ? units_base_10[order] : units_base_2[order], dst_len - len);
}
-void BLI_str_format_attribute_domain_size(char dst[7], int number_to_format)
+void BLI_str_format_decimal_unit(char dst[7], int number_to_format)
{
float number_to_format_converted = number_to_format;
int order = 0;
diff --git a/source/blender/blenlib/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/intern/readfile.c b/source/blender/blenloader/intern/readfile.c
index 6ba97caa0ae..16bad11629a 100644
--- a/source/blender/blenloader/intern/readfile.c
+++ b/source/blender/blenloader/intern/readfile.c
@@ -1477,14 +1477,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));
}
}
}
@@ -3857,14 +3857,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/versioning_300.c b/source/blender/blenloader/intern/versioning_300.c
index 7fd72fec3d0..de47fe49946 100644
--- a/source/blender/blenloader/intern/versioning_300.c
+++ b/source/blender/blenloader/intern/versioning_300.c
@@ -3034,5 +3034,16 @@ void blo_do_versions_300(FileData *fd, Library *UNUSED(lib), Main *bmain)
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;
+ }
+ }
+ }
}
}
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/draw/engines/eevee/eevee_lightcache.c b/source/blender/draw/engines/eevee/eevee_lightcache.c
index 4f562dd9804..0b9909a904b 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,
diff --git a/source/blender/draw/engines/eevee/eevee_lookdev.c b/source/blender/draw/engines/eevee/eevee_lookdev.c
index 79b84bfba4c..a4bd789438d 100644
--- a/source/blender/draw/engines/eevee/eevee_lookdev.c
+++ b/source/blender/draw/engines/eevee/eevee_lookdev.c
@@ -64,7 +64,7 @@ static void eevee_lookdev_hdri_preview_init(EEVEE_Data *vedata, EEVEE_ViewLayerD
DRW_PASS_CREATE(psl->lookdev_diffuse_pass, state);
grp = DRW_shgroup_create(sh, psl->lookdev_diffuse_pass);
- EEVEE_material_bind_resources(grp, gpumat, sldata, vedata, NULL, NULL, false, false);
+ EEVEE_material_bind_resources(grp, gpumat, sldata, vedata, NULL, NULL, -1.0f, false, false);
DRW_shgroup_add_material_resources(grp, gpumat);
DRW_shgroup_call(grp, sphere, NULL);
}
@@ -75,7 +75,7 @@ static void eevee_lookdev_hdri_preview_init(EEVEE_Data *vedata, EEVEE_ViewLayerD
DRW_PASS_CREATE(psl->lookdev_glossy_pass, state);
grp = DRW_shgroup_create(sh, psl->lookdev_glossy_pass);
- EEVEE_material_bind_resources(grp, gpumat, sldata, vedata, NULL, NULL, false, false);
+ EEVEE_material_bind_resources(grp, gpumat, sldata, vedata, NULL, NULL, -1.0f, false, false);
DRW_shgroup_add_material_resources(grp, gpumat);
DRW_shgroup_call(grp, sphere, NULL);
}
diff --git a/source/blender/draw/engines/eevee/eevee_materials.c b/source/blender/draw/engines/eevee/eevee_materials.c
index a81d3e56673..efd27c19654 100644
--- a/source/blender/draw/engines/eevee/eevee_materials.c
+++ b/source/blender/draw/engines/eevee/eevee_materials.c
@@ -67,6 +67,7 @@ void EEVEE_material_bind_resources(DRWShadingGroup *shgrp,
EEVEE_Data *vedata,
const int *ssr_id,
const float *refract_depth,
+ const float alpha_clip_threshold,
bool use_ssrefraction,
bool use_alpha_blend)
{
@@ -91,6 +92,8 @@ void EEVEE_material_bind_resources(DRWShadingGroup *shgrp,
DRW_shgroup_uniform_block(shgrp, "common_block", sldata->common_ubo);
DRW_shgroup_uniform_block_ref(shgrp, "renderpass_block", &pd->renderpass_ubo);
+ DRW_shgroup_uniform_float_copy(shgrp, "alphaClipThreshold", alpha_clip_threshold);
+
DRW_shgroup_uniform_int_copy(shgrp, "outputSssId", 1);
DRW_shgroup_uniform_texture(shgrp, "utilTex", e_data.util_tex);
if (use_diffuse || use_glossy || use_refract) {
@@ -480,6 +483,8 @@ BLI_INLINE void material_shadow(EEVEE_Data *vedata,
/* Shadow Pass */
const bool use_shadow_shader = ma->use_nodes && ma->nodetree &&
ELEM(ma->blend_shadow, MA_BS_CLIP, MA_BS_HASHED);
+ float alpha_clip_threshold = (ma->blend_shadow == MA_BS_CLIP) ? ma->alpha_threshold : -1.0f;
+
int mat_options = VAR_MAT_MESH | VAR_MAT_DEPTH;
SET_FLAG_FROM_TEST(mat_options, use_shadow_shader, VAR_MAT_HASH);
SET_FLAG_FROM_TEST(mat_options, is_hair, VAR_MAT_HAIR);
@@ -503,7 +508,8 @@ BLI_INLINE void material_shadow(EEVEE_Data *vedata,
}
else {
*grp_p = grp = DRW_shgroup_create(sh, psl->shadow_pass);
- EEVEE_material_bind_resources(grp, gpumat, sldata, vedata, NULL, NULL, false, false);
+ EEVEE_material_bind_resources(
+ grp, gpumat, sldata, vedata, NULL, NULL, alpha_clip_threshold, false, false);
}
DRW_shgroup_add_material_resources(grp, gpumat);
@@ -533,6 +539,7 @@ static EeveeMaterialCache material_opaque(EEVEE_Data *vedata,
const bool use_ssrefract = use_gpumat && ((ma->blend_flag & MA_BL_SS_REFRACTION) != 0) &&
((effects->enabled_effects & EFFECT_REFRACT) != 0);
const bool use_depth_shader = use_gpumat && ELEM(ma->blend_method, MA_BM_CLIP, MA_BM_HASHED);
+ float alpha_clip_threshold = (ma->blend_method == MA_BM_CLIP) ? ma->alpha_threshold : -1.0f;
/* HACK: Assume the struct will never be smaller than our variations.
* This allow us to only keep one ghash and avoid bigger keys comparisons/hashing. */
@@ -581,7 +588,8 @@ static EeveeMaterialCache material_opaque(EEVEE_Data *vedata,
}
else {
*grp_p = grp = DRW_shgroup_create(sh, depth_ps);
- EEVEE_material_bind_resources(grp, gpumat, sldata, vedata, NULL, NULL, false, false);
+ EEVEE_material_bind_resources(
+ grp, gpumat, sldata, vedata, NULL, NULL, alpha_clip_threshold, false, false);
}
DRW_shgroup_add_material_resources(grp, gpumat);
@@ -630,8 +638,15 @@ static EeveeMaterialCache material_opaque(EEVEE_Data *vedata,
}
else {
*grp_p = grp = DRW_shgroup_create(sh, shading_pass);
- EEVEE_material_bind_resources(
- grp, gpumat, sldata, vedata, &ssr_id, &ma->refract_depth, use_ssrefract, false);
+ EEVEE_material_bind_resources(grp,
+ gpumat,
+ sldata,
+ vedata,
+ &ssr_id,
+ &ma->refract_depth,
+ alpha_clip_threshold,
+ use_ssrefract,
+ false);
}
DRW_shgroup_add_material_resources(grp, gpumat);
@@ -677,7 +692,7 @@ static EeveeMaterialCache material_transparent(EEVEE_Data *vedata,
DRWShadingGroup *grp = DRW_shgroup_create(sh, psl->transparent_pass);
- EEVEE_material_bind_resources(grp, gpumat, sldata, vedata, NULL, NULL, false, true);
+ EEVEE_material_bind_resources(grp, gpumat, sldata, vedata, NULL, NULL, -1.0f, false, true);
DRW_shgroup_add_material_resources(grp, gpumat);
cur_state = DRW_STATE_WRITE_DEPTH | DRW_STATE_DEPTH_LESS_EQUAL;
@@ -699,7 +714,7 @@ static EeveeMaterialCache material_transparent(EEVEE_Data *vedata,
psl->transparent_pass);
EEVEE_material_bind_resources(
- grp, gpumat, sldata, vedata, &ssr_id, &ma->refract_depth, use_ssrefract, true);
+ grp, gpumat, sldata, vedata, &ssr_id, &ma->refract_depth, -1.0f, use_ssrefract, true);
DRW_shgroup_add_material_resources(grp, gpumat);
cur_state = DRW_STATE_WRITE_COLOR | DRW_STATE_BLEND_CUSTOM;
diff --git a/source/blender/draw/engines/eevee/eevee_private.h b/source/blender/draw/engines/eevee/eevee_private.h
index 3a86640134c..6b9dc6fb017 100644
--- a/source/blender/draw/engines/eevee/eevee_private.h
+++ b/source/blender/draw/engines/eevee/eevee_private.h
@@ -1141,6 +1141,7 @@ void EEVEE_material_bind_resources(DRWShadingGroup *shgrp,
EEVEE_Data *vedata,
const int *ssr_id,
const float *refract_depth,
+ const float alpha_clip_threshold,
bool use_ssrefraction,
bool use_alpha_blend);
/* eevee_lights.c */
diff --git a/source/blender/draw/engines/eevee/shaders/closure_eval_surface_lib.glsl b/source/blender/draw/engines/eevee/shaders/closure_eval_surface_lib.glsl
index fa94b5ed272..0f5290a7c07 100644
--- a/source/blender/draw/engines/eevee/shaders/closure_eval_surface_lib.glsl
+++ b/source/blender/draw/engines/eevee/shaders/closure_eval_surface_lib.glsl
@@ -5,7 +5,7 @@
#pragma BLENDER_REQUIRE(closure_eval_translucent_lib.glsl)
#pragma BLENDER_REQUIRE(renderpass_lib.glsl)
-#ifdef USE_SHADER_TO_RGBA
+#if defined(USE_SHADER_TO_RGBA) || defined(USE_ALPHA_BLEND)
bool do_sss = false;
bool do_ssr = false;
#else
@@ -309,16 +309,19 @@ vec4 closure_to_rgba(Closure closure)
return vec4(closure.radiance, 1.0 - saturate(avg(closure.transmittance)));
}
-Closure closure_add(Closure cl1, Closure cl2)
+Closure closure_add(inout Closure cl1, inout Closure cl2)
{
Closure cl;
cl.radiance = cl1.radiance + cl2.radiance;
cl.transmittance = cl1.transmittance + cl2.transmittance;
cl.holdout = cl1.holdout + cl2.holdout;
+ /* Make sure each closure is only added once to the result. */
+ cl1 = CLOSURE_DEFAULT;
+ cl2 = CLOSURE_DEFAULT;
return cl;
}
-Closure closure_mix(Closure cl1, Closure cl2, float fac)
+Closure closure_mix(inout Closure cl1, inout Closure cl2, float fac)
{
/* Weights have already been applied. */
return closure_add(cl1, cl2);
diff --git a/source/blender/draw/engines/eevee/shaders/closure_eval_volume_lib.glsl b/source/blender/draw/engines/eevee/shaders/closure_eval_volume_lib.glsl
index e450b8ad3c8..5e34d654cfd 100644
--- a/source/blender/draw/engines/eevee/shaders/closure_eval_volume_lib.glsl
+++ b/source/blender/draw/engines/eevee/shaders/closure_eval_volume_lib.glsl
@@ -92,7 +92,7 @@ vec4 closure_to_rgba(Closure closure)
return vec4(0.0);
}
-Closure closure_mix(Closure cl1, Closure cl2, float fac)
+Closure closure_mix(inout Closure cl1, inout Closure cl2, float fac)
{
Closure cl;
cl.absorption = mix(cl1.absorption, cl2.absorption, fac);
@@ -102,7 +102,7 @@ Closure closure_mix(Closure cl1, Closure cl2, float fac)
return cl;
}
-Closure closure_add(Closure cl1, Closure cl2)
+Closure closure_add(inout Closure cl1, inout Closure cl2)
{
Closure cl;
cl.absorption = cl1.absorption + cl2.absorption;
diff --git a/source/blender/draw/engines/eevee/shaders/closure_type_lib.glsl b/source/blender/draw/engines/eevee/shaders/closure_type_lib.glsl
index 492b78a20b6..21d347942ca 100644
--- a/source/blender/draw/engines/eevee/shaders/closure_type_lib.glsl
+++ b/source/blender/draw/engines/eevee/shaders/closure_type_lib.glsl
@@ -49,7 +49,7 @@ struct Closure {
#ifndef GPU_METAL
/* Prototype */
Closure nodetree_exec();
-vec4 closure_to_rgba(Closure);
+vec4 closure_to_rgba(Closure cl);
void output_aov(vec4 color, float value, uint hash);
vec3 coordinate_camera(vec3 P);
vec3 coordinate_screen(vec3 P);
@@ -87,8 +87,8 @@ Closure closure_eval(ClosureDiffuse diffuse,
ClosureReflection clearcoat,
ClosureRefraction refraction);
-Closure closure_add(Closure cl1, Closure cl2);
-Closure closure_mix(Closure cl1, Closure cl2, float fac);
+Closure closure_add(inout Closure cl1, inout Closure cl2);
+Closure closure_mix(inout Closure cl1, inout Closure cl2, float fac);
float ambient_occlusion_eval(vec3 normal,
float distance,
diff --git a/source/blender/draw/engines/eevee/shaders/prepass_frag.glsl b/source/blender/draw/engines/eevee/shaders/prepass_frag.glsl
index c8eea8d7860..15c68dc5829 100644
--- a/source/blender/draw/engines/eevee/shaders/prepass_frag.glsl
+++ b/source/blender/draw/engines/eevee/shaders/prepass_frag.glsl
@@ -11,6 +11,8 @@
#pragma BLENDER_REQUIRE(surface_lib.glsl)
#ifdef USE_ALPHA_HASH
+/* A value of -1.0 will disable alpha clip and use alpha hash. */
+uniform float alphaClipThreshold;
/* From the paper "Hashed Alpha Testing" by Chris Wyman and Morgan McGuire */
float hash(vec2 a)
@@ -76,9 +78,16 @@ void main()
float opacity = saturate(1.0 - avg(cl.transmittance));
- /* Hashed Alpha Testing */
- if (opacity < hashed_alpha_threshold(worldPosition)) {
- discard;
+ if (alphaClipThreshold == -1.0) {
+ /* NOTE: uniform control flow required for dFdx(). */
+ if (opacity < hashed_alpha_threshold(worldPosition)) {
+ discard;
+ }
+ }
+ else {
+ if (opacity <= alphaClipThreshold) {
+ discard;
+ }
}
#endif
}
diff --git a/source/blender/draw/engines/eevee/shaders/surface_lib.glsl b/source/blender/draw/engines/eevee/shaders/surface_lib.glsl
index 1f2f7cb65cc..696e5d4c97b 100644
--- a/source/blender/draw/engines/eevee/shaders/surface_lib.glsl
+++ b/source/blender/draw/engines/eevee/shaders/surface_lib.glsl
@@ -112,6 +112,7 @@ GlobalData init_globals(void)
surf.N = -surf.N;
}
# ifdef HAIR_SHADER
+ vec3 V = cameraVec(surf.P);
/* Shade as a cylinder. */
vec3 B = normalize(cross(worldNormal, hairTangent));
float cos_theta;
@@ -125,7 +126,10 @@ GlobalData init_globals(void)
}
float sin_theta = sqrt(max(0.0, 1.0 - cos_theta * cos_theta));
surf.N = safe_normalize(worldNormal * sin_theta + B * cos_theta);
- surf.T = hairTangent;
+ surf.curve_T = -hairTangent;
+ /* Costly, but follows cycles per pixel tangent space (not following curve shape). */
+ surf.curve_B = cross(V, surf.curve_T);
+ surf.curve_N = safe_normalize(cross(surf.curve_T, surf.curve_B));
surf.is_strand = true;
surf.hair_time = hairTime;
surf.hair_thickness = hairThickness;
@@ -134,7 +138,7 @@ GlobalData init_globals(void)
surf.barycentric_coords = hair_resolve_barycentric(hairBary);
# endif
# else
- surf.T = vec3(0.0);
+ surf.curve_T = surf.curve_B = surf.curve_N = vec3(0.0);
surf.is_strand = false;
surf.hair_time = 0.0;
surf.hair_thickness = 0.0;
diff --git a/source/blender/draw/engines/eevee/shaders/volumetric_vert.glsl b/source/blender/draw/engines/eevee/shaders/volumetric_vert.glsl
index b574e8cdb4c..ce863bdf660 100644
--- a/source/blender/draw/engines/eevee/shaders/volumetric_vert.glsl
+++ b/source/blender/draw/engines/eevee/shaders/volumetric_vert.glsl
@@ -57,3 +57,23 @@ float F_eta(float a, float b)
{
return 0.0;
}
+
+vec3 coordinate_camera(vec3 P)
+{
+ return vec3(0.0);
+}
+
+vec3 coordinate_screen(vec3 P)
+{
+ return vec3(0.0);
+}
+
+vec3 coordinate_reflect(vec3 P, vec3 N)
+{
+ return vec3(0.0);
+}
+
+vec3 coordinate_incoming(vec3 P)
+{
+ return vec3(0.0);
+} \ No newline at end of file
diff --git a/source/blender/draw/engines/eevee_next/shaders/eevee_attributes_lib.glsl b/source/blender/draw/engines/eevee_next/shaders/eevee_attributes_lib.glsl
index abecb373995..3c5acf62e30 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
@@ -164,7 +164,7 @@ float attr_load_float(samplerBuffer cd_buf)
* \{ */
# ifndef OBINFO_LIB
-# error "draw_object_infos is mandatory for volume objects"
+# error draw_object_infos is mandatory for volume objects
# endif
vec3 g_orco;
diff --git a/source/blender/draw/engines/eevee_next/shaders/eevee_geom_curves_vert.glsl b/source/blender/draw/engines/eevee_next/shaders/eevee_geom_curves_vert.glsl
index 11f93ad0d14..708bd153e84 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
@@ -18,7 +18,7 @@ void main()
ViewMatrixInverse[3].xyz,
ViewMatrixInverse[2].xyz,
interp.P,
- T,
+ interp.curves_tangent,
interp.curves_binormal,
interp.curves_time,
interp.curves_thickness,
diff --git a/source/blender/draw/engines/eevee_next/shaders/eevee_nodetree_lib.glsl b/source/blender/draw/engines/eevee_next/shaders/eevee_nodetree_lib.glsl
index 06191a5c007..277b2e35d8b 100644
--- a/source/blender/draw/engines/eevee_next/shaders/eevee_nodetree_lib.glsl
+++ b/source/blender/draw/engines/eevee_next/shaders/eevee_nodetree_lib.glsl
@@ -9,6 +9,7 @@ float g_holdout;
/* The Closure type is never used. Use float as dummy type. */
#define Closure float
+#define CLOSURE_DEFAULT 0.0
/* Sampled closure parameters. */
ClosureDiffuse g_diffuse_data;
diff --git a/source/blender/draw/engines/eevee_next/shaders/eevee_surf_lib.glsl b/source/blender/draw/engines/eevee_next/shaders/eevee_surf_lib.glsl
index 0d8644c9901..30b48edaa78 100644
--- a/source/blender/draw/engines/eevee_next/shaders/eevee_surf_lib.glsl
+++ b/source/blender/draw/engines/eevee_next/shaders/eevee_surf_lib.glsl
@@ -42,6 +42,12 @@ void init_globals_curves()
float sin_theta = sqrt(max(0.0, 1.0 - cos_theta * cos_theta));
g_data.N = normalize(interp.N * sin_theta + interp.curves_binormal * cos_theta);
+ /* Costly, but follows cycles per pixel tangent space (not following curve shape). */
+ vec3 V = cameraVec(g_data.P);
+ g_data.curve_T = -interp.curves_tangent;
+ g_data.curve_B = cross(V, g_data.curve_T);
+ g_data.curve_N = safe_normalize(cross(g_data.curve_T, g_data.curve_B));
+
g_data.is_strand = true;
g_data.hair_time = interp.curves_time;
g_data.hair_thickness = interp.curves_thickness;
@@ -94,6 +100,7 @@ void init_interface()
interp.P = vec3(0.0);
interp.N = vec3(0.0);
interp.barycentric_coords = vec2(0.0);
+ interp.curves_tangent = vec3(0.0);
interp.curves_binormal = vec3(0.0);
interp.curves_time = 0.0;
interp.curves_time_width = 0.0;
diff --git a/source/blender/draw/engines/eevee_next/shaders/infos/eevee_material_info.hh b/source/blender/draw/engines/eevee_next/shaders/infos/eevee_material_info.hh
index cd297de5719..ccd67360073 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
@@ -54,6 +54,7 @@ GPU_SHADER_INTERFACE_INFO(eevee_surf_iface, "interp")
.smooth(Type::VEC3, "P")
.smooth(Type::VEC3, "N")
.smooth(Type::VEC2, "barycentric_coords")
+ .smooth(Type::VEC3, "curves_tangent")
.smooth(Type::VEC3, "curves_binormal")
.smooth(Type::FLOAT, "curves_time")
.smooth(Type::FLOAT, "curves_time_width")
diff --git a/source/blender/draw/engines/gpencil/gpencil_render.c b/source/blender/draw/engines/gpencil/gpencil_render.c
index 19afdb3de5a..c7ef8677336 100644
--- a/source/blender/draw/engines/gpencil/gpencil_render.c
+++ b/source/blender/draw/engines/gpencil/gpencil_render.c
@@ -61,10 +61,10 @@ void GPENCIL_render_init(GPENCIL_Data *vedata,
/* Depth need to be remapped to [0..1] range. */
pix_z = MEM_dupallocN(pix_z);
- int pix_ct = rpass_z_src->rectx * rpass_z_src->recty;
+ int pix_num = rpass_z_src->rectx * rpass_z_src->recty;
if (DRW_view_is_persp_get(view)) {
- for (int i = 0; i < pix_ct; i++) {
+ for (int i = 0; i < pix_num; i++) {
pix_z[i] = (-winmat[3][2] / -pix_z[i]) - winmat[2][2];
pix_z[i] = clamp_f(pix_z[i] * 0.5f + 0.5f, 0.0f, 1.0f);
}
@@ -74,7 +74,7 @@ void GPENCIL_render_init(GPENCIL_Data *vedata,
float near = DRW_view_near_distance_get(view);
float far = DRW_view_far_distance_get(view);
float range_inv = 1.0f / fabsf(far - near);
- for (int i = 0; i < pix_ct; i++) {
+ for (int i = 0; i < pix_num; i++) {
pix_z[i] = (pix_z[i] + near) * range_inv;
pix_z[i] = clamp_f(pix_z[i], 0.0f, 1.0f);
}
@@ -172,11 +172,11 @@ static void GPENCIL_render_result_z(struct RenderLayer *rl,
float winmat[4][4];
DRW_view_winmat_get(NULL, winmat, false);
- int pix_ct = BLI_rcti_size_x(rect) * BLI_rcti_size_y(rect);
+ int pix_num = BLI_rcti_size_x(rect) * BLI_rcti_size_y(rect);
/* Convert GPU depth [0..1] to view Z [near..far] */
if (DRW_view_is_persp_get(NULL)) {
- for (int i = 0; i < pix_ct; i++) {
+ for (int i = 0; i < pix_num; i++) {
if (rp->rect[i] == 1.0f) {
rp->rect[i] = 1e10f; /* Background */
}
@@ -192,7 +192,7 @@ static void GPENCIL_render_result_z(struct RenderLayer *rl,
float far = DRW_view_far_distance_get(NULL);
float range = fabsf(far - near);
- for (int i = 0; i < pix_ct; i++) {
+ for (int i = 0; i < pix_num; i++) {
if (rp->rect[i] == 1.0f) {
rp->rect[i] = 1e10f; /* Background */
}
diff --git a/source/blender/draw/engines/image/image_instance_data.hh b/source/blender/draw/engines/image/image_instance_data.hh
index cb84c7f14ad..358e6fd3bd9 100644
--- a/source/blender/draw/engines/image/image_instance_data.hh
+++ b/source/blender/draw/engines/image/image_instance_data.hh
@@ -75,8 +75,10 @@ struct IMAGE_InstanceData {
TextureInfo &info = texture_infos[i];
const bool is_allocated = info.texture != nullptr;
const bool is_visible = info.visible;
- const bool should_be_freed = !is_visible && is_allocated;
- const bool should_be_created = is_visible && !is_allocated;
+ const bool resolution_changed = assign_if_different(info.last_viewport_size,
+ float2(DRW_viewport_size_get()));
+ const bool should_be_freed = is_allocated && (!is_visible || resolution_changed);
+ const bool should_be_created = is_visible && (!is_allocated || resolution_changed);
if (should_be_freed) {
GPU_texture_free(info.texture);
diff --git a/source/blender/draw/engines/image/image_texture_info.hh b/source/blender/draw/engines/image/image_texture_info.hh
index cd51cdaff3c..9a75941c533 100644
--- a/source/blender/draw/engines/image/image_texture_info.hh
+++ b/source/blender/draw/engines/image/image_texture_info.hh
@@ -46,6 +46,8 @@ struct TextureInfo {
*/
GPUTexture *texture;
+ float2 last_viewport_size = float2(0.0f, 0.0f);
+
~TextureInfo()
{
if (batch != nullptr) {
diff --git a/source/blender/draw/engines/overlay/overlay_gpencil.c b/source/blender/draw/engines/overlay/overlay_gpencil.c
index 072d32c41cd..9531b0dd983 100644
--- a/source/blender/draw/engines/overlay/overlay_gpencil.c
+++ b/source/blender/draw/engines/overlay/overlay_gpencil.c
@@ -297,7 +297,7 @@ void OVERLAY_gpencil_cache_init(OVERLAY_Data *vedata)
}
const int gridlines = (gpd->grid.lines <= 0) ? 1 : gpd->grid.lines;
- int line_ct = gridlines * 4 + 2;
+ const int line_count = gridlines * 4 + 2;
DRWState state = DRW_STATE_WRITE_COLOR | DRW_STATE_BLEND_ALPHA;
state |= (grid_xray) ? DRW_STATE_DEPTH_ALWAYS : DRW_STATE_DEPTH_LESS_EQUAL;
@@ -311,8 +311,8 @@ void OVERLAY_gpencil_cache_init(OVERLAY_Data *vedata)
DRW_shgroup_uniform_vec3_copy(grp, "xAxis", mat[0]);
DRW_shgroup_uniform_vec3_copy(grp, "yAxis", mat[1]);
DRW_shgroup_uniform_vec3_copy(grp, "origin", mat[3]);
- DRW_shgroup_uniform_int_copy(grp, "halfLineCount", line_ct / 2);
- DRW_shgroup_call_procedural_lines(grp, NULL, line_ct);
+ DRW_shgroup_uniform_int_copy(grp, "halfLineCount", line_count / 2);
+ DRW_shgroup_call_procedural_lines(grp, NULL, line_count);
}
}
diff --git a/source/blender/draw/engines/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_render.h b/source/blender/draw/intern/DRW_render.h
index 712118e8282..572b87282e9 100644
--- a/source/blender/draw/intern/DRW_render.h
+++ b/source/blender/draw/intern/DRW_render.h
@@ -430,12 +430,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,
diff --git a/source/blender/draw/intern/draw_cache_extract.h b/source/blender/draw/intern/draw_cache_extract.h
index 4567e470146..cb6006e303a 100644
--- a/source/blender/draw/intern/draw_cache_extract.h
+++ b/source/blender/draw/intern/draw_cache_extract.h
@@ -328,7 +328,6 @@ void mesh_buffer_cache_create_requested(struct TaskGraph *task_graph,
const float obmat[4][4],
bool do_final,
bool do_uvedit,
- bool use_subsurf_fdots,
const Scene *scene,
const struct ToolSettings *ts,
bool use_hide);
diff --git a/source/blender/draw/intern/draw_cache_extract_mesh.cc b/source/blender/draw/intern/draw_cache_extract_mesh.cc
index 8a7b4fc9703..ec544d8e786 100644
--- a/source/blender/draw/intern/draw_cache_extract_mesh.cc
+++ b/source/blender/draw/intern/draw_cache_extract_mesh.cc
@@ -563,7 +563,6 @@ static void mesh_buffer_cache_create_requested(struct TaskGraph *task_graph,
const float obmat[4][4],
const bool do_final,
const bool do_uvedit,
- const bool use_subsurf_fdots,
const Scene *scene,
const ToolSettings *ts,
const bool use_hide)
@@ -687,7 +686,7 @@ static void mesh_buffer_cache_create_requested(struct TaskGraph *task_graph,
MeshRenderData *mr = mesh_render_data_create(
object, me, is_editmode, is_paint_mode, is_mode_active, obmat, do_final, do_uvedit, ts);
mr->use_hide = use_hide;
- mr->use_subsurf_fdots = use_subsurf_fdots;
+ mr->use_subsurf_fdots = mr->me && mr->me->runtime.subsurf_face_dot_tags != nullptr;
mr->use_final_mesh = do_final;
#ifdef DEBUG_TIME
@@ -919,7 +918,6 @@ void mesh_buffer_cache_create_requested(struct TaskGraph *task_graph,
const float obmat[4][4],
const bool do_final,
const bool do_uvedit,
- const bool use_subsurf_fdots,
const Scene *scene,
const ToolSettings *ts,
const bool use_hide)
@@ -935,7 +933,6 @@ void mesh_buffer_cache_create_requested(struct TaskGraph *task_graph,
obmat,
do_final,
do_uvedit,
- use_subsurf_fdots,
scene,
ts,
use_hide);
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..1896df7c650 100644
--- a/source/blender/draw/intern/draw_cache_impl_curves.cc
+++ b/source/blender/draw/intern/draw_cache_impl_curves.cc
@@ -37,6 +37,7 @@
using blender::float3;
using blender::IndexRange;
+using blender::MutableSpan;
using blender::Span;
/* ---------------------------------------------------------------------- */
@@ -147,46 +148,50 @@ static void ensure_seg_pt_count(const Curves &curves, CurvesEvalCache &curves_ca
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 +204,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);
@@ -307,7 +312,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;
diff --git a/source/blender/draw/intern/draw_cache_impl_mesh.c b/source/blender/draw/intern/draw_cache_impl_mesh.c
index 917216b92e6..7dc0244275d 100644
--- a/source/blender/draw/intern/draw_cache_impl_mesh.c
+++ b/source/blender/draw/intern/draw_cache_impl_mesh.c
@@ -708,12 +708,18 @@ static DRW_MeshCDMask mesh_cd_calc_used_gpu_layers(const Object *object,
case CD_MCOL:
case CD_PROP_BYTE_COLOR:
case CD_PROP_COLOR: {
+ /* First check Color attributes, when not found check mesh attributes. Geometry nodes
+ * can generate those layers. */
int vcol_bit = mesh_cd_calc_gpu_layers_vcol_used(&me_query, cd_vdata, cd_ldata, name);
if (vcol_bit != -1) {
cd_used.vcol |= 1UL << (uint)vcol_bit;
+ break;
}
+ if (layer != -1 && domain != ATTR_DOMAIN_NUM) {
+ drw_mesh_attributes_add_request(attributes, type, layer, domain);
+ }
break;
}
case CD_PROP_FLOAT3:
@@ -1231,11 +1237,11 @@ static void sculpt_request_active_vcol(MeshBatchCache *cache, Object *object, Me
&me_query.id, render, ATTR_DOMAIN_MASK_COLOR, CD_MASK_COLOR_ALL);
if (active_i >= 0) {
- cache->cd_used.vcol |= 1UL << (uint)active_i;
+ cache->cd_needed.vcol |= 1UL << (uint)active_i;
}
if (render_i >= 0) {
- cache->cd_used.vcol |= 1UL << (uint)render_i;
+ cache->cd_needed.vcol |= 1UL << (uint)render_i;
}
}
@@ -2128,8 +2134,6 @@ void DRW_mesh_batch_cache_create_requested(struct TaskGraph *task_graph,
MDEPS_ASSERT_MAP_INDEX(TRIS_PER_MAT_INDEX);
- const bool use_subsurf_fdots = me->runtime.subsurf_face_dot_tags != NULL;
-
if (do_uvcage) {
mesh_buffer_cache_create_requested(task_graph,
cache,
@@ -2142,7 +2146,6 @@ void DRW_mesh_batch_cache_create_requested(struct TaskGraph *task_graph,
ob->obmat,
false,
true,
- false,
scene,
ts,
true);
@@ -2160,7 +2163,6 @@ void DRW_mesh_batch_cache_create_requested(struct TaskGraph *task_graph,
ob->obmat,
false,
false,
- use_subsurf_fdots,
scene,
ts,
true);
@@ -2178,7 +2180,6 @@ void DRW_mesh_batch_cache_create_requested(struct TaskGraph *task_graph,
ob->obmat,
true,
false,
- use_subsurf_fdots,
ts,
use_hide);
}
@@ -2199,7 +2200,6 @@ void DRW_mesh_batch_cache_create_requested(struct TaskGraph *task_graph,
ob->obmat,
true,
false,
- use_subsurf_fdots,
scene,
ts,
use_hide);
diff --git a/source/blender/draw/intern/draw_cache_impl_subdivision.cc b/source/blender/draw/intern/draw_cache_impl_subdivision.cc
index 7d245f4158b..8eb0509d615 100644
--- a/source/blender/draw/intern/draw_cache_impl_subdivision.cc
+++ b/source/blender/draw/intern/draw_cache_impl_subdivision.cc
@@ -1904,7 +1904,6 @@ static bool draw_subdiv_create_requested_buffers(const Scene *scene,
const float obmat[4][4],
const bool do_final,
const bool do_uvedit,
- const bool /*use_subsurf_fdots*/,
const ToolSettings *ts,
const bool /*use_hide*/,
OpenSubdiv_EvaluatorCache *evaluator_cache)
@@ -2103,7 +2102,6 @@ void DRW_create_subdivision(const Scene *scene,
const float obmat[4][4],
const bool do_final,
const bool do_uvedit,
- const bool use_subsurf_fdots,
const ToolSettings *ts,
const bool use_hide)
{
@@ -2128,7 +2126,6 @@ void DRW_create_subdivision(const Scene *scene,
obmat,
do_final,
do_uvedit,
- use_subsurf_fdots,
ts,
use_hide,
g_evaluator_cache)) {
diff --git a/source/blender/draw/intern/draw_curves.cc b/source/blender/draw/intern/draw_curves.cc
index 88118361115..2edf596ac63 100644
--- a/source/blender/draw/intern/draw_curves.cc
+++ b/source/blender/draw/intern/draw_curves.cc
@@ -209,7 +209,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;
diff --git a/source/blender/draw/intern/draw_manager.c b/source/blender/draw/intern/draw_manager.c
index bbf40b72c5a..e26502bb066 100644
--- a/source/blender/draw/intern/draw_manager.c
+++ b/source/blender/draw/intern/draw_manager.c
@@ -530,7 +530,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);
@@ -1314,7 +1314,7 @@ void DRW_notify_view_update(const DRWUpdateContext *update_ctx)
const bool gpencil_engine_needed = drw_gpencil_engine_needed(depsgraph, v3d);
- if (G.is_rendering) {
+ if (G.is_rendering && U.experimental.use_draw_manager_acquire_lock) {
return;
}
diff --git a/source/blender/draw/intern/draw_manager.h b/source/blender/draw/intern/draw_manager.h
index 7a9585262ff..2d0837370b2 100644
--- a/source/blender/draw/intern/draw_manager.h
+++ b/source/blender/draw/intern/draw_manager.h
@@ -617,7 +617,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..b0d8017940f 100644
--- a/source/blender/draw/intern/draw_manager_data.c
+++ b/source/blender/draw/intern/draw_manager_data.c
@@ -937,25 +937,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 +1905,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);
diff --git a/source/blender/draw/intern/draw_subdivision.h b/source/blender/draw/intern/draw_subdivision.h
index 6f571084620..2d24d07e037 100644
--- a/source/blender/draw/intern/draw_subdivision.h
+++ b/source/blender/draw/intern/draw_subdivision.h
@@ -194,7 +194,6 @@ void DRW_create_subdivision(const struct Scene *scene,
const float obmat[4][4],
const bool do_final,
const bool do_uvedit,
- const bool use_subsurf_fdots,
const ToolSettings *ts,
const bool use_hide);
diff --git a/source/blender/draw/intern/draw_view_data.cc b/source/blender/draw/intern/draw_view_data.cc
index 0e55d28f6df..3dc28dc9a9a 100644
--- a/source/blender/draw/intern/draw_view_data.cc
+++ b/source/blender/draw/intern/draw_view_data.cc
@@ -88,7 +88,7 @@ void DRW_view_data_default_lists_from_viewport(DRWViewData *view_data, GPUViewpo
});
}
-static void draw_viewport_engines_data_clear(ViewportEngineData *data)
+static void draw_viewport_engines_data_clear(ViewportEngineData *data, bool clear_instance_data)
{
DrawEngineType *engine_type = data->engine_type->draw_engine;
const DrawEngineDataSize *data_size = engine_type->vedata_size;
@@ -103,7 +103,7 @@ static void draw_viewport_engines_data_clear(ViewportEngineData *data)
MEM_SAFE_FREE(data->stl->storage[i]);
}
- if (data->instance_data) {
+ if (clear_instance_data && data->instance_data) {
BLI_assert(engine_type->instance_free != nullptr);
engine_type->instance_free(data->instance_data);
data->instance_data = nullptr;
@@ -120,7 +120,7 @@ static void draw_viewport_engines_data_clear(ViewportEngineData *data)
}
}
-static void draw_view_data_clear(DRWViewData *view_data)
+static void draw_view_data_clear(DRWViewData *view_data, bool free_instance_data)
{
GPU_FRAMEBUFFER_FREE_SAFE(view_data->dfbl.default_fb);
GPU_FRAMEBUFFER_FREE_SAFE(view_data->dfbl.overlay_fb);
@@ -137,23 +137,20 @@ static void draw_view_data_clear(DRWViewData *view_data)
GPU_TEXTURE_FREE_SAFE(view_data->dtxl.depth_in_front);
for (ViewportEngineData &engine : view_data->engines) {
- draw_viewport_engines_data_clear(&engine);
+ draw_viewport_engines_data_clear(&engine, free_instance_data);
}
-
- view_data->texture_list_size[0] = view_data->texture_list_size[1] = 0;
- view_data->cache_time = 0.0f;
}
void DRW_view_data_free(DRWViewData *view_data)
{
- draw_view_data_clear(view_data);
+ draw_view_data_clear(view_data, true);
delete view_data;
}
void DRW_view_data_texture_list_size_validate(DRWViewData *view_data, const int size[2])
{
if (!equals_v2v2_int(view_data->texture_list_size, size)) {
- draw_view_data_clear(view_data);
+ draw_view_data_clear(view_data, false);
copy_v2_v2_int(view_data->texture_list_size, size);
}
}
@@ -195,7 +192,7 @@ void DRW_view_data_free_unused(DRWViewData *view_data)
{
for (ViewportEngineData &engine : view_data->engines) {
if (view_data->enabled_engines.first_index_of_try(&engine) == -1) {
- draw_viewport_engines_data_clear(&engine);
+ draw_viewport_engines_data_clear(&engine, false);
}
}
}
diff --git a/source/blender/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/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/include/ED_fileselect.h b/source/blender/editors/include/ED_fileselect.h
index c367072e6e7..e9fcd2bd5fe 100644
--- a/source/blender/editors/include/ED_fileselect.h
+++ b/source/blender/editors/include/ED_fileselect.h
@@ -164,8 +164,16 @@ void ED_fileselect_window_params_get(const struct wmWindow *win,
int win_size[2],
bool *is_maximized);
+/**
+ * Return the File Browser area in which \a file_operator is active.
+ */
struct ScrArea *ED_fileselect_handler_area_find(const struct wmWindow *win,
const struct wmOperator *file_operator);
+/**
+ * Check if there is any area in \a win that acts as a modal File Browser (#SpaceFile.op is set)
+ * and return it.
+ */
+struct ScrArea *ED_fileselect_handler_area_find_any_with_op(const struct wmWindow *win);
/* TODO: Maybe we should move this to BLI?
* On the other hand, it's using defines from space-file area, so not sure... */
diff --git a/source/blender/editors/include/ED_uvedit.h b/source/blender/editors/include/ED_uvedit.h
index 54d36f44f82..80a75da27f8 100644
--- a/source/blender/editors/include/ED_uvedit.h
+++ b/source/blender/editors/include/ED_uvedit.h
@@ -266,6 +266,10 @@ struct BMLoop **ED_uvedit_selected_verts(const struct Scene *scene,
int *r_verts_len);
void ED_uvedit_get_aspect(struct Object *obedit, float *r_aspx, float *r_aspy);
+void ED_uvedit_get_aspect_from_material(Object *ob,
+ const int material_index,
+ float *r_aspx,
+ float *r_aspy);
void ED_uvedit_active_vert_loop_set(struct BMesh *bm, struct BMLoop *l);
struct BMLoop *ED_uvedit_active_vert_loop_get(struct BMesh *bm);
diff --git a/source/blender/editors/include/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 301171a284d..a996d1e0e76 100644
--- a/source/blender/editors/include/UI_interface.h
+++ b/source/blender/editors/include/UI_interface.h
@@ -184,50 +184,50 @@ enum {
/** #uiBut.flag general state flags. */
enum {
- /* WARNING: the first 7 flags are internal (see #UI_SELECT definition). */
- UI_BUT_ICON_SUBMENU = 1 << 7,
- UI_BUT_ICON_PREVIEW = 1 << 8,
+ /* WARNING: the first 10 flags are internal (see #UI_SELECT definition). */
+ UI_BUT_ICON_SUBMENU = 1 << 10,
+ UI_BUT_ICON_PREVIEW = 1 << 11,
- UI_BUT_NODE_LINK = 1 << 9,
- UI_BUT_NODE_ACTIVE = 1 << 10,
- UI_BUT_DRAG_LOCK = 1 << 11,
+ UI_BUT_NODE_LINK = 1 << 12,
+ UI_BUT_NODE_ACTIVE = 1 << 13,
+ UI_BUT_DRAG_LOCK = 1 << 14,
/** Grayed out and un-editable. */
- UI_BUT_DISABLED = 1 << 12,
+ UI_BUT_DISABLED = 1 << 15,
- UI_BUT_ANIMATED = 1 << 13,
- UI_BUT_ANIMATED_KEY = 1 << 14,
- UI_BUT_DRIVEN = 1 << 15,
- UI_BUT_REDALERT = 1 << 16,
+ UI_BUT_ANIMATED = 1 << 16,
+ UI_BUT_ANIMATED_KEY = 1 << 17,
+ UI_BUT_DRIVEN = 1 << 18,
+ UI_BUT_REDALERT = 1 << 19,
/** Grayed out but still editable. */
- UI_BUT_INACTIVE = 1 << 17,
- UI_BUT_LAST_ACTIVE = 1 << 18,
- UI_BUT_UNDO = 1 << 19,
- UI_BUT_IMMEDIATE = 1 << 20,
- UI_BUT_NO_UTF8 = 1 << 21,
+ UI_BUT_INACTIVE = 1 << 20,
+ UI_BUT_LAST_ACTIVE = 1 << 21,
+ UI_BUT_UNDO = 1 << 22,
+ UI_BUT_IMMEDIATE = 1 << 23,
+ UI_BUT_NO_UTF8 = 1 << 24,
/** For popups, pressing return activates this button, overriding the highlighted button.
* For non-popups this is just used as a display hint for the user to let them
* know the action which is activated when pressing return (file selector for eg). */
- UI_BUT_ACTIVE_DEFAULT = 1 << 23,
+ UI_BUT_ACTIVE_DEFAULT = 1 << 25,
/** This but is "inside" a list item (currently used to change theme colors). */
- UI_BUT_LIST_ITEM = 1 << 24,
+ UI_BUT_LIST_ITEM = 1 << 26,
/** edit this button as well as the active button (not just dragging) */
- UI_BUT_DRAG_MULTI = 1 << 25,
+ UI_BUT_DRAG_MULTI = 1 << 27,
/** Use for popups to start editing the button on initialization. */
- UI_BUT_ACTIVATE_ON_INIT = 1 << 26,
+ UI_BUT_ACTIVATE_ON_INIT = 1 << 28,
/** #uiBut.str contains #UI_SEP_CHAR, used for key shortcuts */
- UI_BUT_HAS_SEP_CHAR = 1 << 27,
+ UI_BUT_HAS_SEP_CHAR = 1 << 29,
/** Don't run updates while dragging (needed in rare cases). */
- UI_BUT_UPDATE_DELAY = 1 << 28,
+ UI_BUT_UPDATE_DELAY = 1u << 30,
/** When widget is in text-edit mode, update value on each char stroke. */
- UI_BUT_TEXTEDIT_UPDATE = 1 << 29,
+ UI_BUT_TEXTEDIT_UPDATE = 1ul << 31,
/** Show 'x' icon to clear/unlink value of text or search button. */
- UI_BUT_VALUE_CLEAR = 1 << 30,
+ UI_BUT_VALUE_CLEAR = 1ul << 32,
/** RNA property of the button is overridden from linked reference data. */
- UI_BUT_OVERRIDDEN = 1u << 31u,
+ UI_BUT_OVERRIDDEN = 1ul << 33,
};
/* Default font size for normal text. */
@@ -462,7 +462,7 @@ enum {
void UI_draw_widget_scroll(struct uiWidgetColors *wcol,
const struct rcti *rect,
const struct rcti *slider,
- int state);
+ uint64_t state);
/**
* Shortening string helper.
@@ -887,9 +887,9 @@ uiBut *UI_but_active_drop_name_button(const struct bContext *C);
bool UI_but_active_drop_name(const struct bContext *C);
bool UI_but_active_drop_color(struct bContext *C);
-void UI_but_flag_enable(uiBut *but, int flag);
-void UI_but_flag_disable(uiBut *but, int flag);
-bool UI_but_flag_is_set(uiBut *but, int flag);
+void UI_but_flag_enable(uiBut *but, uint64_t flag);
+void UI_but_flag_disable(uiBut *but, uint64_t flag);
+bool UI_but_flag_is_set(uiBut *but, uint64_t flag);
void UI_but_drawflag_enable(uiBut *but, int flag);
void UI_but_drawflag_disable(uiBut *but, int flag);
@@ -1682,7 +1682,7 @@ bool UI_search_item_add(uiSearchItems *items,
const char *name,
void *poin,
int iconid,
- int state,
+ uint64_t state,
uint8_t name_prefix_offset);
/**
diff --git a/source/blender/editors/interface/interface.cc b/source/blender/editors/interface/interface.cc
index b7098c26bcd..effd3a64fcd 100644
--- a/source/blender/editors/interface/interface.cc
+++ b/source/blender/editors/interface/interface.cc
@@ -848,7 +848,7 @@ static void ui_but_update_old_active_from_new(uiBut *oldbut, uiBut *but)
BLI_assert(oldbut->active);
/* flags from the buttons we want to refresh, may want to add more here... */
- const int flag_copy = UI_BUT_REDALERT | UI_HAS_ICON | UI_SELECT_DRAW;
+ const uint64_t flag_copy = UI_BUT_REDALERT | UI_HAS_ICON | UI_SELECT_DRAW;
const int drawflag_copy = 0; /* None currently. */
/* still stuff needs to be copied */
@@ -991,7 +991,7 @@ static bool ui_but_update_from_old_block(const bContext *C,
found_active = true;
}
else {
- int flag_copy = UI_BUT_DRAG_MULTI;
+ uint64_t flag_copy = UI_BUT_DRAG_MULTI;
/* Stupid special case: The active button may be inside (as in, overlapped on top) a tree-row
* button which we also want to keep highlighted then. */
@@ -4219,7 +4219,7 @@ static uiBut *ui_def_but(uiBlock *block,
return but;
}
-void ui_def_but_icon(uiBut *but, const int icon, const int flag)
+void ui_def_but_icon(uiBut *but, const int icon, const uint64_t flag)
{
if (icon) {
ui_icon_ensure_deferred(static_cast<const bContext *>(but->block->evil_C),
@@ -5806,17 +5806,17 @@ void UI_block_flag_disable(uiBlock *block, int flag)
block->flag &= ~flag;
}
-void UI_but_flag_enable(uiBut *but, int flag)
+void UI_but_flag_enable(uiBut *but, uint64_t flag)
{
but->flag |= flag;
}
-void UI_but_flag_disable(uiBut *but, int flag)
+void UI_but_flag_disable(uiBut *but, uint64_t flag)
{
but->flag &= ~flag;
}
-bool UI_but_flag_is_set(uiBut *but, int flag)
+bool UI_but_flag_is_set(uiBut *but, uint64_t flag)
{
return (but->flag & flag) != 0;
}
diff --git a/source/blender/editors/interface/interface_anim.c b/source/blender/editors/interface/interface_anim.c
index e838ce37d8e..b77d48552c7 100644
--- a/source/blender/editors/interface/interface_anim.c
+++ b/source/blender/editors/interface/interface_anim.c
@@ -144,7 +144,7 @@ void ui_but_anim_decorate_update_from_flag(uiButDecorator *decorator_but)
return;
}
- const int flag = but_anim->flag;
+ const uint64_t flag = but_anim->flag;
if (flag & UI_BUT_DRIVEN) {
but->icon = ICON_DECORATE_DRIVER;
@@ -162,7 +162,7 @@ void ui_but_anim_decorate_update_from_flag(uiButDecorator *decorator_but)
but->icon = ICON_DECORATE;
}
- const int flag_copy = (UI_BUT_DISABLED | UI_BUT_INACTIVE);
+ const uint64_t flag_copy = (UI_BUT_DISABLED | UI_BUT_INACTIVE);
but->flag = (but->flag & ~flag_copy) | (flag & flag_copy);
}
diff --git a/source/blender/editors/interface/interface_intern.h b/source/blender/editors/interface/interface_intern.h
index c09ff68bbca..e8c5f2bb322 100644
--- a/source/blender/editors/interface/interface_intern.h
+++ b/source/blender/editors/interface/interface_intern.h
@@ -74,7 +74,8 @@ enum {
UI_SELECT_DRAW = (1 << 5),
/** Property search filter is active and the button does not match. */
UI_SEARCH_FILTER_NO_MATCH = (1 << 6),
- /* WARNING: rest of #uiBut.flag in UI_interface.h */
+
+ /* WARNING: rest of #uiBut.flag in UI_interface.h (starting at `1 << 10`). */
};
/** #uiBut.dragflag */
@@ -147,7 +148,8 @@ struct uiBut {
/** Pointer back to the layout item holding this button. */
uiLayout *layout;
- int flag, drawflag;
+ uint64_t flag;
+ int drawflag;
eButType type;
eButPointerType pointype;
short bit, bitnr, retval, strwidth, alignnr;
@@ -709,7 +711,7 @@ extern void ui_but_active_string_clear_and_exit(struct bContext *C, uiBut *but)
extern void ui_but_set_string_interactive(struct bContext *C, uiBut *but, const char *value);
extern uiBut *ui_but_drag_multi_edit_get(uiBut *but);
-void ui_def_but_icon(uiBut *but, int icon, int flag);
+void ui_def_but_icon(uiBut *but, int icon, uint64_t flag);
/**
* Avoid using this where possible since it's better not to ask for an icon in the first place.
*/
@@ -1216,14 +1218,14 @@ void ui_draw_menu_item(const struct uiFontStyle *fstyle,
rcti *rect,
const char *name,
int iconid,
- int state,
+ uint64_t state,
uiMenuItemSeparatorType separator_type,
int *r_xmax);
void ui_draw_preview_item(const struct uiFontStyle *fstyle,
rcti *rect,
const char *name,
int iconid,
- int state,
+ uint64_t state,
eFontStyle_Align text_align);
/**
* Version of #ui_draw_preview_item() that does not draw the menu background and item text based on
@@ -1424,8 +1426,8 @@ uiBlock *ui_block_find_mouse_over(const struct ARegion *region,
bool only_clip);
uiBut *ui_region_find_first_but_test_flag(struct ARegion *region,
- int flag_include,
- int flag_exclude);
+ uint64_t flag_include,
+ uint64_t flag_exclude);
uiBut *ui_region_find_active_but(struct ARegion *region) ATTR_WARN_UNUSED_RESULT;
bool ui_region_contains_point_px(const struct ARegion *region, const int xy[2])
ATTR_NONNULL(1, 2) ATTR_WARN_UNUSED_RESULT;
diff --git a/source/blender/editors/interface/interface_layout.c b/source/blender/editors/interface/interface_layout.c
index c1bb2ed6d18..198195f1d9a 100644
--- a/source/blender/editors/interface/interface_layout.c
+++ b/source/blender/editors/interface/interface_layout.c
@@ -5316,7 +5316,7 @@ static void ui_item_align(uiLayout *litem, short nr)
}
}
-static void ui_item_flag(uiLayout *litem, int flag)
+static void ui_item_flag(uiLayout *litem, uint64_t flag)
{
LISTBASE_FOREACH_BACKWARD (uiItem *, item, &litem->items) {
if (item->type == ITEM_BUTTON) {
diff --git a/source/blender/editors/interface/interface_query.cc b/source/blender/editors/interface/interface_query.cc
index 337b2852d57..b1619df7e4c 100644
--- a/source/blender/editors/interface/interface_query.cc
+++ b/source/blender/editors/interface/interface_query.cc
@@ -699,7 +699,9 @@ uiBut *ui_region_find_active_but(ARegion *region)
return nullptr;
}
-uiBut *ui_region_find_first_but_test_flag(ARegion *region, int flag_include, int flag_exclude)
+uiBut *ui_region_find_first_but_test_flag(ARegion *region,
+ uint64_t flag_include,
+ uint64_t flag_exclude)
{
LISTBASE_FOREACH (uiBlock *, block, &region->uiblocks) {
LISTBASE_FOREACH (uiBut *, but, &block->buttons) {
diff --git a/source/blender/editors/interface/interface_region_search.cc b/source/blender/editors/interface/interface_region_search.cc
index bc497e2647c..016abb2f021 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;
+ uint64_t *states;
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,
+ uint64_t state,
const uint8_t name_prefix_offset)
{
/* hijack for autocomplete */
@@ -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 uint64_t state = ((a == data->active) ? UI_ACTIVE : 0) | data->items.states[a];
/* ensure icon is up-to-date */
ui_icon_ensure_deferred(C, data->items.icons[a], data->preview);
@@ -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 uint64_t state = ((a == data->active) ? UI_ACTIVE : 0) | data->items.states[a];
char *name = data->items.names[a];
int icon = data->items.icons[a];
char *name_sep_test = nullptr;
@@ -847,7 +847,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.states = (uint64_t *)MEM_callocN(data->items.maxitem * sizeof(uint64_t), __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 +913,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 uint64_t state = ((a == data->active) ? UI_ACTIVE : 0) | data->items.states[a];
wmOperatorType *ot = static_cast<wmOperatorType *>(data->items.pointers[a]);
char text_pre[128];
diff --git a/source/blender/editors/interface/interface_template_search_menu.cc b/source/blender/editors/interface/interface_template_search_menu.cc
index c3021028b97..854e3dace3b 100644
--- a/source/blender/editors/interface/interface_template_search_menu.cc
+++ b/source/blender/editors/interface/interface_template_search_menu.cc
@@ -87,7 +87,7 @@ struct MenuSearch_Item {
/** Support a single level sub-menu nesting (for operator buttons that expand). */
const char *drawstr_submenu;
int icon;
- int state;
+ uint64_t state;
MenuSearch_Parent *menu_parent;
MenuType *mt;
diff --git a/source/blender/editors/interface/interface_utils.cc b/source/blender/editors/interface/interface_utils.cc
index 993ccdf92f7..e68d8f12a1f 100644
--- a/source/blender/editors/interface/interface_utils.cc
+++ b/source/blender/editors/interface/interface_utils.cc
@@ -494,7 +494,7 @@ static bool add_collection_search_item(CollItemSearch *cis,
cis->name,
cis->data,
cis->iconid,
- cis->has_sep_char ? (int)UI_BUT_HAS_SEP_CHAR : 0,
+ cis->has_sep_char ? (uint64_t)UI_BUT_HAS_SEP_CHAR : 0,
name_prefix_offset);
}
diff --git a/source/blender/editors/interface/interface_widgets.c b/source/blender/editors/interface/interface_widgets.c
index 98ecf91adbc..2801930ff1d 100644
--- a/source/blender/editors/interface/interface_widgets.c
+++ b/source/blender/editors/interface/interface_widgets.c
@@ -256,10 +256,10 @@ 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 (*state)(struct uiWidgetType *, uint64_t state, int drawflag, eUIEmbossType emboss);
+ void (*draw)(uiWidgetColors *, rcti *, uint64_t state, int roundboxalign, const float zoom);
void (*custom)(
- uiBut *, uiWidgetColors *, rcti *, int state, int roundboxalign, const float zoom);
+ uiBut *, uiWidgetColors *, rcti *, uint64_t state, int roundboxalign, const float zoom);
void (*text)(const uiFontStyle *, const uiWidgetColors *, uiBut *, rcti *);
} uiWidgetType;
@@ -1289,7 +1289,7 @@ 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 uint64_t state)
{
if (state & (UI_BUT_INACTIVE | UI_BUT_DISABLED)) {
if (state & UI_SEARCH_FILTER_NO_MATCH) {
@@ -2446,7 +2446,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 uint64_t state)
{
static uiWidgetColors wcol_theme_s;
@@ -2473,7 +2473,7 @@ static void widget_active_color(uiWidgetColors *wcol)
}
static const uchar *widget_color_blend_from_flags(const uiWidgetStateColors *wcol_state,
- int state,
+ uint64_t state,
int drawflag,
const eUIEmbossType emboss)
{
@@ -2501,7 +2501,7 @@ static const uchar *widget_color_blend_from_flags(const uiWidgetStateColors *wco
}
/* 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, uint64_t state, int drawflag, eUIEmbossType emboss)
{
uiWidgetStateColors *wcol_state = wt->wcol_state;
@@ -2600,7 +2600,10 @@ 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,
+ uint64_t state,
+ int drawflag,
+ eUIEmbossType emboss)
{
uiWidgetStateColors *wcol_state = wt->wcol_state;
@@ -2624,7 +2627,7 @@ static void widget_state_numslider(uiWidgetType *wt, int state, int drawflag, eU
/* labels use theme colors for text */
static void widget_state_option_menu(uiWidgetType *wt,
- int state,
+ uint64_t state,
int drawflag,
eUIEmbossType emboss)
{
@@ -2644,7 +2647,7 @@ static void widget_state_option_menu(uiWidgetType *wt,
}
static void widget_state_nothing(uiWidgetType *wt,
- int UNUSED(state),
+ uint64_t UNUSED(state),
int UNUSED(drawflag),
eUIEmbossType UNUSED(emboss))
{
@@ -2653,7 +2656,7 @@ static void widget_state_nothing(uiWidgetType *wt,
/* special case, button that calls pulldown */
static void widget_state_pulldown(uiWidgetType *wt,
- int UNUSED(state),
+ uint64_t UNUSED(state),
int UNUSED(drawflag),
eUIEmbossType UNUSED(emboss))
{
@@ -2662,7 +2665,7 @@ static void widget_state_pulldown(uiWidgetType *wt,
/* special case, pie menu items */
static void widget_state_pie_menu_item(uiWidgetType *wt,
- int state,
+ uint64_t state,
int UNUSED(drawflag),
eUIEmbossType UNUSED(emboss))
{
@@ -2697,7 +2700,7 @@ static void widget_state_pie_menu_item(uiWidgetType *wt,
/* special case, menu items */
static void widget_state_menu_item(uiWidgetType *wt,
- int state,
+ uint64_t state,
int UNUSED(drawflag),
eUIEmbossType UNUSED(emboss))
{
@@ -2787,7 +2790,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, uint64_t flag, int direction, const float zoom)
{
uiWidgetBase wtb;
int roundboxalign = UI_CNR_ALL;
@@ -3321,8 +3324,12 @@ 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,
+ uint64_t 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);
@@ -3423,13 +3430,13 @@ static void widget_numbut_draw(
}
static void widget_numbut(
- uiWidgetColors *wcol, rcti *rect, int state, int roundboxalign, const float zoom)
+ uiWidgetColors *wcol, rcti *rect, uint64_t 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)
+ uiWidgetColors *wcol, rcti *rect, uint64_t UNUSED(state), int roundboxalign, const float zoom)
{
uiWidgetBase wtb;
widget_init(&wtb);
@@ -3454,7 +3461,7 @@ static void widget_menubut(
static void widget_menubut_embossn(const uiBut *UNUSED(but),
uiWidgetColors *wcol,
rcti *rect,
- int UNUSED(state),
+ uint64_t UNUSED(state),
int UNUSED(roundboxalign))
{
uiWidgetBase wtb;
@@ -3476,14 +3483,17 @@ static void widget_menubut_embossn(const uiBut *UNUSED(but),
static void widget_numbut_embossn(const uiBut *UNUSED(but),
uiWidgetColors *wcol,
rcti *rect,
- int state,
+ uint64_t state,
int roundboxalign,
const float zoom)
{
widget_numbut_draw(wcol, rect, zoom, state, roundboxalign, true);
}
-void UI_draw_widget_scroll(uiWidgetColors *wcol, const rcti *rect, const rcti *slider, int state)
+void UI_draw_widget_scroll(uiWidgetColors *wcol,
+ const rcti *rect,
+ const rcti *slider,
+ uint64_t state)
{
uiWidgetBase wtb;
bool outline = false;
@@ -3573,7 +3583,7 @@ void UI_draw_widget_scroll(uiWidgetColors *wcol, const rcti *rect, const rcti *s
static void widget_scroll(uiBut *but,
uiWidgetColors *wcol,
rcti *rect,
- int state,
+ uint64_t state,
int UNUSED(roundboxalign),
const float UNUSED(zoom))
{
@@ -3635,7 +3645,7 @@ static void widget_scroll(uiBut *but,
static void widget_progressbar(uiBut *but,
uiWidgetColors *wcol,
rcti *rect,
- int UNUSED(state),
+ uint64_t UNUSED(state),
int roundboxalign,
const float zoom)
{
@@ -3669,7 +3679,7 @@ static void widget_progressbar(uiBut *but,
static void widget_treerow_exec(uiWidgetColors *wcol,
rcti *rect,
- int state,
+ uint64_t state,
int UNUSED(roundboxalign),
int indentation,
const float zoom)
@@ -3690,8 +3700,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,
+ uint64_t state,
+ int roundboxalign,
+ const float zoom)
{
uiButTreeRow *tree_row = (uiButTreeRow *)but;
BLI_assert(but->type == UI_BTYPE_TREEROW);
@@ -3701,7 +3715,7 @@ static void widget_treerow(
static void widget_nodesocket(uiBut *but,
uiWidgetColors *wcol,
rcti *rect,
- int UNUSED(state),
+ uint64_t UNUSED(state),
int UNUSED(roundboxalign),
const float UNUSED(zoom))
{
@@ -3737,8 +3751,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,
+ uint64_t state,
+ int roundboxalign,
+ const float zoom)
{
uiWidgetBase wtb, wtb1;
widget_init(&wtb);
@@ -3850,8 +3868,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,
+ uint64_t state,
+ int roundboxalign,
+ const float zoom)
{
BLI_assert(but->type == UI_BTYPE_COLOR);
uiButColor *color_but = (uiButColor *)but;
@@ -3938,7 +3960,7 @@ static void widget_swatch(
static void widget_unitvec(uiBut *but,
uiWidgetColors *wcol,
rcti *rect,
- int UNUSED(state),
+ uint64_t UNUSED(state),
int UNUSED(roundboxalign),
const float zoom)
{
@@ -3946,8 +3968,12 @@ 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,
+ uint64_t state,
+ int roundboxalign,
+ const float zoom)
{
if (state & (UI_BUT_ANIMATED | UI_BUT_ANIMATED_KEY | UI_BUT_DRIVEN | UI_BUT_REDALERT) &&
but->emboss != UI_EMBOSS_NONE) {
@@ -3971,7 +3997,7 @@ static void widget_icon_has_anim(
}
static void widget_textbut(
- uiWidgetColors *wcol, rcti *rect, int state, int roundboxalign, const float zoom)
+ uiWidgetColors *wcol, rcti *rect, uint64_t state, int roundboxalign, const float zoom)
{
if (state & UI_SELECT) {
SWAP(short, wcol->shadetop, wcol->shadedown);
@@ -3989,7 +4015,7 @@ static void widget_textbut(
static void widget_preview_tile(uiBut *but,
uiWidgetColors *wcol,
rcti *rect,
- int UNUSED(state),
+ uint64_t UNUSED(state),
int UNUSED(roundboxalign),
const float UNUSED(zoom))
{
@@ -3999,7 +4025,7 @@ static void widget_preview_tile(uiBut *but,
}
static void widget_menuiconbut(
- uiWidgetColors *wcol, rcti *rect, int UNUSED(state), int roundboxalign, const float zoom)
+ uiWidgetColors *wcol, rcti *rect, uint64_t UNUSED(state), int roundboxalign, const float zoom)
{
uiWidgetBase wtb;
widget_init(&wtb);
@@ -4012,7 +4038,7 @@ static void widget_menuiconbut(
}
static void widget_pulldownbut(
- uiWidgetColors *wcol, rcti *rect, int state, int roundboxalign, const float zoom)
+ uiWidgetColors *wcol, rcti *rect, uint64_t state, int roundboxalign, const float zoom)
{
float back[4];
UI_GetThemeColor4fv(TH_BACK, back);
@@ -4042,7 +4068,7 @@ static void widget_pulldownbut(
static void widget_menu_itembut(uiWidgetColors *wcol,
rcti *rect,
- int UNUSED(state),
+ uint64_t UNUSED(state),
int UNUSED(roundboxalign),
const float zoom)
{
@@ -4066,7 +4092,7 @@ static void widget_menu_itembut(uiWidgetColors *wcol,
static void widget_menu_itembut_unpadded(uiWidgetColors *wcol,
rcti *rect,
- int UNUSED(state),
+ uint64_t UNUSED(state),
int UNUSED(roundboxalign),
const float zoom)
{
@@ -4088,7 +4114,7 @@ static void widget_menu_itembut_unpadded(uiWidgetColors *wcol,
static void widget_menu_radial_itembut(uiBut *but,
uiWidgetColors *wcol,
rcti *rect,
- int UNUSED(state),
+ uint64_t UNUSED(state),
int UNUSED(roundboxalign),
const float zoom)
{
@@ -4114,7 +4140,7 @@ static void widget_menu_radial_itembut(uiBut *but,
static void widget_list_itembut(uiWidgetColors *wcol,
rcti *rect,
- int UNUSED(state),
+ uint64_t UNUSED(state),
int UNUSED(roundboxalign),
const float zoom)
{
@@ -4131,7 +4157,7 @@ static void widget_list_itembut(uiWidgetColors *wcol,
static void widget_optionbut(uiWidgetColors *wcol,
rcti *rect,
- int state,
+ uint64_t state,
int UNUSED(roundboxalign),
const float UNUSED(zoom))
{
@@ -4177,7 +4203,10 @@ 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,
+ uint64_t state,
+ int drawflag,
+ eUIEmbossType emboss)
{
if (state & UI_BUT_LIST_ITEM) {
/* Override default label theme's colors. */
@@ -4204,7 +4233,7 @@ static void widget_state_label(uiWidgetType *wt, int state, int drawflag, eUIEmb
}
static void widget_radiobut(
- uiWidgetColors *wcol, rcti *rect, int UNUSED(state), int roundboxalign, const float zoom)
+ uiWidgetColors *wcol, rcti *rect, uint64_t UNUSED(state), int roundboxalign, const float zoom)
{
uiWidgetBase wtb;
widget_init(&wtb);
@@ -4218,7 +4247,7 @@ static void widget_radiobut(
static void widget_box(uiBut *but,
uiWidgetColors *wcol,
rcti *rect,
- int UNUSED(state),
+ uint64_t UNUSED(state),
int roundboxalign,
const float zoom)
{
@@ -4245,7 +4274,7 @@ static void widget_box(uiBut *but,
}
static void widget_but(
- uiWidgetColors *wcol, rcti *rect, int UNUSED(state), int roundboxalign, const float zoom)
+ uiWidgetColors *wcol, rcti *rect, uint64_t UNUSED(state), int roundboxalign, const float zoom)
{
uiWidgetBase wtb;
widget_init(&wtb);
@@ -4272,7 +4301,7 @@ 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)
+ uiWidgetColors *wcol, rcti *rect, uint64_t state, int roundboxalign, const float zoom)
{
uiWidgetBase wtb;
widget_init(&wtb);
@@ -4291,7 +4320,7 @@ static void widget_roundbut_exec(
}
static void widget_tab(
- uiWidgetColors *wcol, rcti *rect, int state, int roundboxalign, const float zoom)
+ uiWidgetColors *wcol, rcti *rect, uint64_t state, int roundboxalign, const float zoom)
{
const float rad = widget_radius_from_zoom(zoom, wcol);
const bool is_active = (state & UI_SELECT);
@@ -4922,7 +4951,7 @@ 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;
+ uint64_t state = but->flag & ~UI_STATE_FLAGS_ALL;
const int drawflag = but->drawflag;
if (state & UI_SELECT_DRAW) {
@@ -5335,7 +5364,7 @@ void ui_draw_menu_item(const uiFontStyle *fstyle,
rcti *rect,
const char *name,
int iconid,
- int state,
+ uint64_t state,
uiMenuItemSeparatorType separator_type,
int *r_xmax)
{
@@ -5528,7 +5557,7 @@ void ui_draw_preview_item(const uiFontStyle *fstyle,
rcti *rect,
const char *name,
int iconid,
- int state,
+ uint64_t state,
eFontStyle_Align text_align)
{
uiWidgetType *wt = widget_type(UI_WTYPE_MENU_ITEM_UNPADDED);
diff --git a/source/blender/editors/interface/view2d.cc b/source/blender/editors/interface/view2d.cc
index 66171dc13e4..94190c0a39d 100644
--- a/source/blender/editors/interface/view2d.cc
+++ b/source/blender/editors/interface/view2d.cc
@@ -1532,7 +1532,7 @@ void UI_view2d_scrollers_draw(View2D *v2d, const rcti *mask_custom)
uiWidgetColors wcol = btheme->tui.wcol_scroll;
const float alpha_fac = v2d->alpha_hor / 255.0f;
rcti slider;
- int state;
+ uint64_t state;
slider.xmin = scrollers.hor_min;
slider.xmax = scrollers.hor_max;
@@ -1566,7 +1566,7 @@ void UI_view2d_scrollers_draw(View2D *v2d, const rcti *mask_custom)
uiWidgetColors wcol = btheme->tui.wcol_scroll;
rcti slider;
const float alpha_fac = v2d->alpha_vert / 255.0f;
- int state;
+ uint64_t state;
slider.xmin = vert.xmin;
slider.xmax = vert.xmax;
diff --git a/source/blender/editors/io/CMakeLists.txt b/source/blender/editors/io/CMakeLists.txt
index 418a399db28..ef093a01ff8 100644
--- a/source/blender/editors/io/CMakeLists.txt
+++ b/source/blender/editors/io/CMakeLists.txt
@@ -9,6 +9,7 @@ set(INC
../../depsgraph
../../io/alembic
../../io/collada
+ ../../io/common
../../io/gpencil
../../io/usd
../../io/wavefront_obj
diff --git a/source/blender/editors/io/io_obj.c b/source/blender/editors/io/io_obj.c
index 3345d422bd1..886586ff236 100644
--- a/source/blender/editors/io/io_obj.c
+++ b/source/blender/editors/io/io_obj.c
@@ -29,6 +29,7 @@
#include "DEG_depsgraph.h"
+#include "IO_path_util_types.h"
#include "IO_wavefront_obj.h"
#include "io_obj.h"
@@ -59,6 +60,15 @@ static const EnumPropertyItem io_obj_export_evaluation_mode[] = {
"Export objects as they appear in the viewport"},
{0, NULL, 0, NULL, NULL}};
+static const EnumPropertyItem io_obj_path_mode[] = {
+ {PATH_REFERENCE_AUTO, "AUTO", 0, "Auto", "Use Relative paths with subdirectories only"},
+ {PATH_REFERENCE_ABSOLUTE, "ABSOLUTE", 0, "Absolute", "Always write absolute paths"},
+ {PATH_REFERENCE_RELATIVE, "RELATIVE", 0, "Relative", "Write relative paths where possible"},
+ {PATH_REFERENCE_MATCH, "MATCH", 0, "Match", "Match Absolute/Relative setting with input path"},
+ {PATH_REFERENCE_STRIP, "STRIP", 0, "Strip", "Write filename only"},
+ {PATH_REFERENCE_COPY, "COPY", 0, "Copy", "Copy the file to the destination path"},
+ {0, NULL, 0, NULL, NULL}};
+
static int wm_obj_export_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
{
if (!RNA_struct_property_is_set(op->ptr, "filepath")) {
@@ -87,6 +97,7 @@ static int wm_obj_export_exec(bContext *C, wmOperator *op)
return OPERATOR_CANCELLED;
}
struct OBJExportParams export_params;
+ export_params.file_base_for_tests[0] = '\0';
RNA_string_get(op->ptr, "filepath", export_params.filepath);
export_params.blen_filepath = CTX_data_main(C)->filepath;
export_params.export_animation = RNA_boolean_get(op->ptr, "export_animation");
@@ -103,6 +114,7 @@ static int wm_obj_export_exec(bContext *C, wmOperator *op)
export_params.export_uv = RNA_boolean_get(op->ptr, "export_uv");
export_params.export_normals = RNA_boolean_get(op->ptr, "export_normals");
export_params.export_materials = RNA_boolean_get(op->ptr, "export_materials");
+ export_params.path_mode = RNA_enum_get(op->ptr, "path_mode");
export_params.export_triangulated_mesh = RNA_boolean_get(op->ptr, "export_triangulated_mesh");
export_params.export_curves_as_nurbs = RNA_boolean_get(op->ptr, "export_curves_as_nurbs");
@@ -119,9 +131,9 @@ static int wm_obj_export_exec(bContext *C, wmOperator *op)
static void ui_obj_export_settings(uiLayout *layout, PointerRNA *imfptr)
{
-
const bool export_animation = RNA_boolean_get(imfptr, "export_animation");
const bool export_smooth_groups = RNA_boolean_get(imfptr, "export_smooth_groups");
+ const bool export_materials = RNA_boolean_get(imfptr, "export_materials");
uiLayoutSetPropSep(layout, true);
uiLayoutSetPropDecorate(layout, false);
@@ -150,6 +162,9 @@ static void ui_obj_export_settings(uiLayout *layout, PointerRNA *imfptr)
uiItemR(sub, imfptr, "export_selected_objects", 0, IFACE_("Selected Only"), ICON_NONE);
uiItemR(sub, imfptr, "apply_modifiers", 0, IFACE_("Apply Modifiers"), ICON_NONE);
uiItemR(sub, imfptr, "export_eval_mode", 0, IFACE_("Properties"), ICON_NONE);
+ sub = uiLayoutColumn(sub, false);
+ uiLayoutSetEnabled(sub, export_materials);
+ uiItemR(sub, imfptr, "path_mode", 0, IFACE_("Path Mode"), ICON_NONE);
/* Options for what to write. */
box = uiLayoutBox(layout);
@@ -162,6 +177,7 @@ static void ui_obj_export_settings(uiLayout *layout, PointerRNA *imfptr)
uiItemR(sub, imfptr, "export_triangulated_mesh", 0, IFACE_("Triangulated Mesh"), ICON_NONE);
uiItemR(sub, imfptr, "export_curves_as_nurbs", 0, IFACE_("Curves as NURBS"), ICON_NONE);
+ /* Grouping options. */
box = uiLayoutBox(layout);
uiItemL(box, IFACE_("Grouping"), ICON_GROUP);
col = uiLayoutColumn(box, false);
@@ -231,6 +247,8 @@ static bool wm_obj_export_check(bContext *C, wmOperator *op)
void WM_OT_obj_export(struct wmOperatorType *ot)
{
+ PropertyRNA *prop;
+
ot->name = "Export Wavefront OBJ";
ot->description = "Save the scene to a Wavefront OBJ file";
ot->idname = "WM_OT_obj_export";
@@ -244,7 +262,7 @@ void WM_OT_obj_export(struct wmOperatorType *ot)
ot->flag |= OPTYPE_PRESET;
WM_operator_properties_filesel(ot,
- FILE_TYPE_FOLDER | FILE_TYPE_OBJECT_IO,
+ FILE_TYPE_FOLDER,
FILE_BLENDER,
FILE_SAVE,
WM_FILESEL_FILEPATH | WM_FILESEL_SHOW_PROPS,
@@ -320,6 +338,12 @@ void WM_OT_obj_export(struct wmOperatorType *ot)
"Export Materials",
"Export MTL library. There must be a Principled-BSDF node for image textures to "
"be exported to the MTL file");
+ RNA_def_enum(ot->srna,
+ "path_mode",
+ io_obj_path_mode,
+ PATH_REFERENCE_AUTO,
+ "Path Mode",
+ "Method used to reference paths");
RNA_def_boolean(ot->srna,
"export_triangulated_mesh",
false,
@@ -358,6 +382,10 @@ void WM_OT_obj_export(struct wmOperatorType *ot)
"Every smooth-shaded face is assigned group \"1\" and every flat-shaded face \"off\"");
RNA_def_boolean(
ot->srna, "smooth_group_bitflags", false, "Generate Bitflags for Smooth Groups", "");
+
+ /* Only show .obj or .mtl files by default. */
+ prop = RNA_def_string(ot->srna, "filter_glob", "*.obj;*.mtl", 0, "Extension Filter", "");
+ RNA_def_property_flag(prop, PROP_HIDDEN);
}
static int wm_obj_import_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
@@ -415,6 +443,8 @@ static void wm_obj_import_draw(bContext *C, wmOperator *op)
void WM_OT_obj_import(struct wmOperatorType *ot)
{
+ PropertyRNA *prop;
+
ot->name = "Import Wavefront OBJ";
ot->description = "Load a Wavefront OBJ scene";
ot->idname = "WM_OT_obj_import";
@@ -425,7 +455,7 @@ void WM_OT_obj_import(struct wmOperatorType *ot)
ot->ui = wm_obj_import_draw;
WM_operator_properties_filesel(ot,
- FILE_TYPE_FOLDER | FILE_TYPE_OBJECT_IO,
+ FILE_TYPE_FOLDER,
FILE_BLENDER,
FILE_OPENFILE,
WM_FILESEL_FILEPATH | WM_FILESEL_SHOW_PROPS,
@@ -453,4 +483,8 @@ void WM_OT_obj_import(struct wmOperatorType *ot)
false,
"Validate Meshes",
"Check imported mesh objects for invalid data (slow)");
+
+ /* Only show .obj or .mtl files by default. */
+ prop = RNA_def_string(ot->srna, "filter_glob", "*.obj;*.mtl", 0, "Extension Filter", "");
+ RNA_def_property_flag(prop, PROP_HIDDEN);
}
diff --git a/source/blender/editors/io/io_usd.c b/source/blender/editors/io/io_usd.c
index 97ca9b026ec..609230eefea 100644
--- a/source/blender/editors/io/io_usd.c
+++ b/source/blender/editors/io/io_usd.c
@@ -190,6 +190,20 @@ static void wm_usd_export_draw(bContext *UNUSED(C), wmOperator *op)
uiItemR(box, ptr, "use_instancing", 0, NULL, ICON_NONE);
}
+static bool wm_usd_export_check(bContext *UNUSED(C), wmOperator *op)
+{
+ char filepath[FILE_MAX];
+ RNA_string_get(op->ptr, "filepath", filepath);
+
+ if (!BLI_path_extension_check_n(filepath, ".usd", ".usda", ".usdc", NULL)) {
+ BLI_path_extension_ensure(filepath, FILE_MAX, ".usdc");
+ RNA_string_set(op->ptr, "filepath", filepath);
+ return true;
+ }
+
+ return false;
+}
+
void WM_OT_usd_export(struct wmOperatorType *ot)
{
ot->name = "Export USD";
@@ -200,6 +214,7 @@ void WM_OT_usd_export(struct wmOperatorType *ot)
ot->exec = wm_usd_export_exec;
ot->poll = WM_operator_winactive;
ot->ui = wm_usd_export_draw;
+ ot->check = wm_usd_export_check;
ot->flag = OPTYPE_REGISTER; /* No UNDO possible. */
diff --git a/source/blender/editors/mesh/editmesh_knife.c b/source/blender/editors/mesh/editmesh_knife.c
index ee40431c101..5d8cf176b87 100644
--- a/source/blender/editors/mesh/editmesh_knife.c
+++ b/source/blender/editors/mesh/editmesh_knife.c
@@ -190,6 +190,22 @@ typedef struct KnifeBVH {
} KnifeBVH;
+/** Additional per-object data. */
+typedef struct KnifeObjectInfo {
+ const float (*cagecos)[3];
+
+ /**
+ * Optionally allocate triangle indices, these are needed for non-interactive knife
+ * projection as multiple cuts are made without the BVH being updated.
+ * Using these indices the it's possible to access `cagecos` even if the face has been cut
+ * and the loops in `em->looptris` no longer refer to the original triangles, see:
+ */
+ const int (*tri_indices)[3];
+
+ /** Only assigned for convenient access. */
+ BMEditMesh *em;
+} KnifeObjectInfo;
+
/* struct for properties used while drawing */
typedef struct KnifeTool_OpData {
ARegion *region; /* Region that knifetool was activated in. */
@@ -203,6 +219,9 @@ typedef struct KnifeTool_OpData {
Object **objects;
uint objects_len;
+ /** Array `objects_len` length of additional per-object data. */
+ KnifeObjectInfo *objects_info;
+
MemArena *arena;
/* Reused for edge-net filling. */
@@ -220,7 +239,6 @@ typedef struct KnifeTool_OpData {
GHash *facetrimap;
KnifeBVH bvh;
- const float (**cagecos)[3];
BLI_mempool *kverts;
BLI_mempool *kedges;
@@ -1134,6 +1152,52 @@ static void knife_update_header(bContext *C, wmOperator *op, KnifeTool_OpData *k
/** \} */
/* -------------------------------------------------------------------- */
+/** \name Knife Object Info Accessors (#KnifeObjectInfo)
+ * \{ */
+
+static const int *knife_bm_tri_index_get(const KnifeTool_OpData *kcd,
+ int base_index,
+ int tri_index,
+ int tri_index_buf[3])
+{
+ const KnifeObjectInfo *obinfo = &kcd->objects_info[base_index];
+ if (obinfo->tri_indices) {
+ return obinfo->tri_indices[tri_index];
+ }
+ for (int i = 0; i < 3; i++) {
+ tri_index_buf[i] = BM_elem_index_get(obinfo->em->looptris[tri_index][i]->v);
+ }
+ return tri_index_buf;
+}
+
+static void knife_bm_tri_cagecos_get(const KnifeTool_OpData *kcd,
+ int base_index,
+ int tri_index,
+ float cos[3][3])
+{
+ const KnifeObjectInfo *obinfo = &kcd->objects_info[base_index];
+ int tri_ind_buf[3];
+ const int *tri_ind = knife_bm_tri_index_get(kcd, base_index, tri_index, tri_ind_buf);
+ for (int i = 0; i < 3; i++) {
+ copy_v3_v3(cos[i], obinfo->cagecos[tri_ind[i]]);
+ }
+}
+
+static void knife_bm_tri_cagecos_get_worldspace(const KnifeTool_OpData *kcd,
+ int base_index,
+ int tri_index,
+ float cos[3][3])
+{
+ knife_bm_tri_cagecos_get(kcd, base_index, tri_index, cos);
+ const Object *ob = kcd->objects[base_index];
+ for (int i = 0; i < 3; i++) {
+ mul_m4_v3(ob->obmat, cos[i]);
+ }
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
/** \name Knife BVH Utils
* \{ */
@@ -1219,16 +1283,7 @@ static void knife_bvh_init(KnifeTool_OpData *kcd)
if (!test_fn_ret) {
continue;
}
-
- copy_v3_v3(cos[0], kcd->cagecos[b][BM_elem_index_get(looptris[i][0]->v)]);
- copy_v3_v3(cos[1], kcd->cagecos[b][BM_elem_index_get(looptris[i][1]->v)]);
- copy_v3_v3(cos[2], kcd->cagecos[b][BM_elem_index_get(looptris[i][2]->v)]);
-
- /* Convert to world-space. */
- mul_m4_v3(ob->obmat, cos[0]);
- mul_m4_v3(ob->obmat, cos[1]);
- mul_m4_v3(ob->obmat, cos[2]);
-
+ knife_bm_tri_cagecos_get_worldspace(kcd, b, i, cos);
BLI_bvhtree_insert(kcd->bvh.tree, i + tottri, (float *)cos, 3);
}
@@ -1282,12 +1337,7 @@ static void knife_bvh_raycast_cb(void *userdata,
}
}
- copy_v3_v3(tri_cos[0], kcd->cagecos[b][BM_elem_index_get(ltri[0]->v)]);
- copy_v3_v3(tri_cos[1], kcd->cagecos[b][BM_elem_index_get(ltri[1]->v)]);
- copy_v3_v3(tri_cos[2], kcd->cagecos[b][BM_elem_index_get(ltri[2]->v)]);
- mul_m4_v3(ob->obmat, tri_cos[0]);
- mul_m4_v3(ob->obmat, tri_cos[1]);
- mul_m4_v3(ob->obmat, tri_cos[2]);
+ knife_bm_tri_cagecos_get_worldspace(kcd, b, index, tri_cos);
isect =
(ray->radius > 0.0f ?
@@ -1684,7 +1734,7 @@ static KnifeVert *get_bm_knife_vert(KnifeTool_OpData *kcd, BMVert *v, Object *ob
BMFace *f;
if (BM_elem_index_get(v) >= 0) {
- cageco = kcd->cagecos[base_index][BM_elem_index_get(v)];
+ cageco = kcd->objects_info[base_index].cagecos[BM_elem_index_get(v)];
}
else {
cageco = v->co;
@@ -2545,12 +2595,8 @@ static bool knife_ray_intersect_face(KnifeTool_OpData *kcd,
if (tri[0]->f != f) {
break;
}
- copy_v3_v3(lv[0], kcd->cagecos[base_index][BM_elem_index_get(tri[0]->v)]);
- copy_v3_v3(lv[1], kcd->cagecos[base_index][BM_elem_index_get(tri[1]->v)]);
- copy_v3_v3(lv[2], kcd->cagecos[base_index][BM_elem_index_get(tri[2]->v)]);
- mul_m4_v3(ob->obmat, lv[0]);
- mul_m4_v3(ob->obmat, lv[1]);
- mul_m4_v3(ob->obmat, lv[2]);
+
+ knife_bm_tri_cagecos_get_worldspace(kcd, base_index, tri_i, lv);
/* Using epsilon test in case ray is directly through an internal
* tessellation edge and might not hit either tessellation tri with
@@ -2605,9 +2651,10 @@ static void calc_ortho_extent(KnifeTool_OpData *kcd)
ob = kcd->objects[b];
em = BKE_editmesh_from_object(ob);
- if (kcd->cagecos[b]) {
+ const float(*cagecos)[3] = kcd->objects_info[b].cagecos;
+ if (cagecos) {
for (int i = 0; i < em->bm->totvert; i++) {
- copy_v3_v3(ws, kcd->cagecos[b][i]);
+ copy_v3_v3(ws, cagecos[i]);
mul_m4_v3(ob->obmat, ws);
minmax_v3v3_v3(min, max, ws);
}
@@ -3961,10 +4008,13 @@ static void knifetool_undo(KnifeTool_OpData *kcd)
/** \} */
/* -------------------------------------------------------------------- */
-/** \name #KnifeTool_OpData (#op->customdata) Init and Free
+/** \name #KnifeObjectInfo (#kcd->objects_info) Init and Free
* \{ */
-static void knifetool_init_cagecos(KnifeTool_OpData *kcd, Object *ob, uint base_index)
+static void knifetool_init_obinfo(KnifeTool_OpData *kcd,
+ Object *ob,
+ uint base_index,
+ bool use_tri_indices)
{
Scene *scene_eval = (Scene *)DEG_get_evaluated_id(kcd->vc.depsgraph, &kcd->scene->id);
@@ -3973,18 +4023,36 @@ static void knifetool_init_cagecos(KnifeTool_OpData *kcd, Object *ob, uint base_
BM_mesh_elem_index_ensure(em_eval->bm, BM_VERT);
- kcd->cagecos[base_index] = (const float(*)[3])BKE_editmesh_vert_coords_alloc(
+ KnifeObjectInfo *obinfo = &kcd->objects_info[base_index];
+ obinfo->em = em_eval;
+ obinfo->cagecos = (const float(*)[3])BKE_editmesh_vert_coords_alloc(
kcd->vc.depsgraph, em_eval, scene_eval, obedit_eval, NULL);
+
+ if (use_tri_indices) {
+ BMLoop *(*looptris)[3] = em_eval->looptris;
+ int(*tri_indices)[3] = MEM_mallocN(sizeof(int[3]) * em_eval->tottri, __func__);
+ for (int i = 0; i < em_eval->tottri; i++) {
+ BMLoop **tri = looptris[i];
+ tri_indices[i][0] = BM_elem_index_get(tri[0]->v);
+ tri_indices[i][1] = BM_elem_index_get(tri[1]->v);
+ tri_indices[i][2] = BM_elem_index_get(tri[2]->v);
+ }
+ obinfo->tri_indices = tri_indices;
+ }
}
-static void knifetool_free_cagecos(KnifeTool_OpData *kcd, uint base_index)
+static void knifetool_free_obinfo(KnifeTool_OpData *kcd, uint base_index)
{
- if (kcd->cagecos[base_index]) {
- MEM_freeN((void *)kcd->cagecos[base_index]);
- kcd->cagecos[base_index] = NULL;
- }
+ MEM_SAFE_FREE(kcd->objects_info[base_index].cagecos);
+ MEM_SAFE_FREE(kcd->objects_info[base_index].tri_indices);
}
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name #KnifeTool_OpData (#op->customdata) Init and Free
+ * \{ */
+
static void knife_init_colors(KnifeColors *colors)
{
/* Possible BMESH_TODO: add explicit themes or calculate these by
@@ -4018,6 +4086,10 @@ static void knifetool_init(bContext *C,
const float angle_snapping_increment,
const bool is_interactive)
{
+ /* Needed so multiple non-interactive cuts (also called knife-project)
+ * doesn't access indices of loops that were created by cutting, see: T97153. */
+ bool use_tri_indices = !is_interactive;
+
kcd->vc = *vc;
Scene *scene = vc->scene;
@@ -4031,11 +4103,11 @@ static void knifetool_init(bContext *C,
Object *ob;
BMEditMesh *em;
- kcd->cagecos = MEM_callocN(sizeof(*kcd->cagecos) * kcd->objects_len, "knife cagecos");
+ kcd->objects_info = MEM_callocN(sizeof(*kcd->objects_info) * kcd->objects_len, "knife cagecos");
for (uint b = 0; b < kcd->objects_len; b++) {
ob = kcd->objects[b];
em = BKE_editmesh_from_object(ob);
- knifetool_init_cagecos(kcd, ob, b);
+ knifetool_init_obinfo(kcd, ob, b, use_tri_indices);
/* Can't usefully select resulting edges in face mode. */
kcd->select_result = (em->selectmode != SCE_SELECT_FACE);
@@ -4139,9 +4211,9 @@ static void knifetool_exit_ex(KnifeTool_OpData *kcd)
/* Knife BVH cleanup. */
for (int i = 0; i < kcd->objects_len; i++) {
- knifetool_free_cagecos(kcd, i);
+ knifetool_free_obinfo(kcd, i);
}
- MEM_freeN((void *)kcd->cagecos);
+ MEM_freeN((void *)kcd->objects_info);
knife_bvh_free(kcd);
/* Line-hits cleanup. */
@@ -4391,7 +4463,8 @@ static int knifetool_modal(bContext *C, wmOperator *op, const wmEvent *event)
ED_workspace_status_text(C, NULL);
return OPERATOR_CANCELLED;
- case KNF_MODAL_CONFIRM:
+ case KNF_MODAL_CONFIRM: {
+ const bool changed = (kcd->totkvert != 0);
/* finish */
ED_region_tag_redraw(kcd->region);
@@ -4400,11 +4473,11 @@ static int knifetool_modal(bContext *C, wmOperator *op, const wmEvent *event)
ED_workspace_status_text(C, NULL);
/* Cancel to prevent undo push for empty cuts. */
- if (kcd->totkvert == 0) {
+ if (!changed) {
return OPERATOR_CANCELLED;
}
-
return OPERATOR_FINISHED;
+ }
case KNF_MODAL_UNDO:
if (BLI_stack_is_empty(kcd->undostack)) {
ED_region_tag_redraw(kcd->region);
diff --git a/source/blender/editors/object/object_add.cc b/source/blender/editors/object/object_add.cc
index db8860efdd8..b7deade5146 100644
--- a/source/blender/editors/object/object_add.cc
+++ b/source/blender/editors/object/object_add.cc
@@ -2116,6 +2116,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";
@@ -2123,7 +2139,7 @@ void OBJECT_OT_curves_empty_hair_add(wmOperatorType *ot)
ot->idname = "OBJECT_OT_curves_empty_hair_add";
ot->exec = object_curves_empty_hair_add_exec;
- ot->poll = object_curves_add_poll;
+ ot->poll = object_curves_empty_hair_add_poll;
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
@@ -2762,9 +2778,32 @@ static const EnumPropertyItem convert_target_items[] = {
"Point Cloud",
"Point Cloud from Mesh objects"},
#endif
+ {OB_CURVES, "CURVES", ICON_OUTLINER_OB_CURVES, "Curves", "Curves from evaluated curve data"},
{0, nullptr, 0, nullptr, nullptr},
};
+static const EnumPropertyItem *convert_target_items_fn(bContext *UNUSED(C),
+ PointerRNA *UNUSED(ptr),
+ PropertyRNA *UNUSED(prop),
+ bool *r_free)
+{
+ EnumPropertyItem *items = nullptr;
+ int items_num = 0;
+ for (const EnumPropertyItem *item = convert_target_items; item->identifier != nullptr; item++) {
+ if (item->value == OB_CURVES) {
+ if (U.experimental.use_new_curves_type) {
+ RNA_enum_item_add(&items, &items_num, item);
+ }
+ }
+ else {
+ RNA_enum_item_add(&items, &items_num, item);
+ }
+ }
+ RNA_enum_item_end(&items, &items_num);
+ *r_free = true;
+ return items;
+}
+
static void object_data_convert_ensure_curve_cache(Depsgraph *depsgraph, Scene *scene, Object *ob)
{
if (ob->runtime.curve_cache == nullptr) {
@@ -3065,6 +3104,50 @@ static int object_convert_exec(bContext *C, wmOperator *op)
}
ob_gpencil->actcol = actcol;
}
+ else if (target == OB_CURVES) {
+ ob->flag |= OB_DONE;
+
+ Object *ob_eval = DEG_get_evaluated_object(depsgraph, ob);
+ GeometrySet geometry;
+ if (ob_eval->runtime.geometry_set_eval != nullptr) {
+ geometry = *ob_eval->runtime.geometry_set_eval;
+ }
+
+ if (geometry.has_curves()) {
+ if (keep_original) {
+ basen = duplibase_for_convert(bmain, depsgraph, scene, view_layer, base, nullptr);
+ newob = basen->object;
+
+ /* Decrement original curve's usage count. */
+ Curve *legacy_curve = static_cast<Curve *>(newob->data);
+ id_us_min(&legacy_curve->id);
+
+ /* Make a copy of the curve. */
+ newob->data = BKE_id_copy(bmain, &legacy_curve->id);
+ }
+ else {
+ newob = ob;
+ }
+
+ const CurveComponent &curve_component = *geometry.get_component_for_read<CurveComponent>();
+ const Curves *curves_eval = curve_component.get_for_read();
+ Curves *new_curves = static_cast<Curves *>(BKE_id_new(bmain, ID_CV, newob->id.name + 2));
+
+ newob->data = new_curves;
+ newob->type = OB_CURVES;
+
+ blender::bke::CurvesGeometry::wrap(
+ new_curves->geometry) = blender::bke::CurvesGeometry::wrap(curves_eval->geometry);
+ BKE_object_material_from_eval_data(bmain, newob, &curves_eval->id);
+
+ BKE_object_free_derived_caches(newob);
+ BKE_object_free_modifiers(newob, 0);
+ }
+ else {
+ BKE_reportf(
+ op->reports, RPT_WARNING, "Object '%s' has no evaluated curves data", ob->id.name + 2);
+ }
+ }
else if (ob->type == OB_MESH && target == OB_POINTCLOUD) {
ob->flag |= OB_DONE;
@@ -3480,6 +3563,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_edit.c b/source/blender/editors/object/object_edit.c
index cb0e76c11e4..c9626e674f2 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"
@@ -1461,6 +1463,8 @@ void OBJECT_OT_paths_clear(wmOperatorType *ot)
static int shade_smooth_exec(bContext *C, wmOperator *op)
{
const bool use_smooth = STREQ(op->idname, "OBJECT_OT_shade_smooth");
+ const bool use_auto_smooth = RNA_boolean_get(op->ptr, "use_auto_smooth");
+ const float auto_smooth_angle = RNA_float_get(op->ptr, "auto_smooth_angle");
bool changed_multi = false;
bool has_linked_data = false;
@@ -1508,6 +1512,7 @@ static int shade_smooth_exec(bContext *C, wmOperator *op)
bool changed = false;
if (ob->type == OB_MESH) {
BKE_mesh_smooth_flag_set(ob->data, use_smooth);
+ BKE_mesh_auto_smooth_flag_set(ob->data, use_auto_smooth, auto_smooth_angle);
BKE_mesh_batch_cache_dirty_tag(ob->data, BKE_MESH_BATCH_DIRTY_ALL);
changed = true;
}
@@ -1577,6 +1582,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_relations.c b/source/blender/editors/object/object_relations.c
index 5ef8e573e27..76dcfbd8d36 100644
--- a/source/blender/editors/object/object_relations.c
+++ b/source/blender/editors/object/object_relations.c
@@ -1964,7 +1964,7 @@ static void single_objectdata_action_users(
ID *id_act = (ID *)adt->action;
if (single_data_needs_duplication(id_act)) {
DEG_id_tag_update(&ob->id, ID_RECALC_GEOMETRY);
- BKE_animdata_duplicate_id_action(bmain, &ob->id, USER_DUP_ACT | USER_DUP_LINKED_ID);
+ BKE_animdata_duplicate_id_action(bmain, id_obdata, USER_DUP_ACT | USER_DUP_LINKED_ID);
}
}
}
diff --git a/source/blender/editors/sculpt_paint/curves_sculpt_add.cc b/source/blender/editors/sculpt_paint/curves_sculpt_add.cc
index 1fdecf47bbd..f214efb44be 100644
--- a/source/blender/editors/sculpt_paint/curves_sculpt_add.cc
+++ b/source/blender/editors/sculpt_paint/curves_sculpt_add.cc
@@ -18,6 +18,7 @@
#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"
@@ -105,10 +106,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_;
+ int constant_points_per_curve_;
/** Various matrices to convert between coordinate spaces. */
float4x4 curves_to_world_mat_;
@@ -129,6 +131,15 @@ struct AddOperationExecutor {
Vector<int> looptri_indices;
};
+ 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, bContext *C, const StrokeExtension &stroke_extension)
{
self_ = &self;
@@ -172,10 +183,12 @@ struct AddOperationExecutor {
const eBrushFalloffShape falloff_shape = static_cast<eBrushFalloffShape>(
brush_->falloff_shape);
add_amount_ = std::max(0, brush_settings_->add_amount);
- points_per_curve_ = std::max(2, brush_settings_->points_per_curve);
+ 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();
@@ -215,18 +228,28 @@ 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_);
+ }
- curves_->resize(curves_->points_num() + tot_added_points,
- curves_->curves_num() + tot_added_curves);
+ /* Resize to add the correct point count calculated as part of building the offsets. */
+ curves_->resize(curves_->offsets().last(), curves_->curves_num());
- threading::parallel_invoke([&]() { this->initialize_curve_offsets(tot_added_curves); },
- [&]() { this->initialize_attributes(added_points); });
+ this->initialize_attributes(added_points, neighbors_per_curve);
+
+ curves_->update_curve_types();
DEG_id_tag_update(&curves_id_->id, ID_RECALC_GEOMETRY);
ED_region_tag_redraw(region_);
@@ -578,33 +601,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);
@@ -733,15 +765,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));
}
});
}
@@ -762,23 +793,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;
@@ -812,8 +842,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;
@@ -823,7 +853,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;
}
}
}
diff --git a/source/blender/editors/sculpt_paint/paint_image_proj.c b/source/blender/editors/sculpt_paint/paint_image_proj.c
index 1303da71435..02e992029ff 100644
--- a/source/blender/editors/sculpt_paint/paint_image_proj.c
+++ b/source/blender/editors/sculpt_paint/paint_image_proj.c
@@ -7,6 +7,7 @@
*/
#include <float.h>
+#include <limits.h>
#include <math.h>
#include <stdio.h>
#include <string.h>
@@ -35,12 +36,17 @@
#include "IMB_imbuf_types.h"
#include "DNA_brush_types.h"
+#include "DNA_customdata_types.h"
+#include "DNA_defs.h"
#include "DNA_material_types.h"
#include "DNA_mesh_types.h"
#include "DNA_meshdata_types.h"
#include "DNA_node_types.h"
+#include "DNA_object_enums.h"
#include "DNA_object_types.h"
+#include "DNA_scene_types.h"
+#include "BKE_attribute.h"
#include "BKE_brush.h"
#include "BKE_camera.h"
#include "BKE_colorband.h"
@@ -61,6 +67,8 @@
#include "BKE_report.h"
#include "BKE_scene.h"
#include "BKE_screen.h"
+#include "DNA_screen_types.h"
+#include "DNA_space_types.h"
#include "DEG_depsgraph.h"
#include "DEG_depsgraph_query.h"
@@ -76,12 +84,18 @@
#include "GPU_capabilities.h"
#include "GPU_init_exit.h"
+#include "NOD_shader.h"
+
+#include "UI_interface.h"
+#include "UI_resources.h"
+
#include "WM_api.h"
#include "WM_types.h"
#include "RNA_access.h"
#include "RNA_define.h"
#include "RNA_enum_types.h"
+#include "RNA_types.h"
#include "IMB_colormanagement.h"
@@ -6459,6 +6473,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;
+}
+
static void proj_paint_default_color(wmOperator *op, int type, Material *ma)
{
if (RNA_struct_property_is_set(op->ptr, "color")) {
@@ -6516,6 +6562,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;
@@ -6528,7 +6575,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) {
@@ -6538,17 +6585,36 @@ static bool proj_paint_add_slot(bContext *C, wmOperator *op)
ma->use_nodes = true;
- /* try to add an image node */
- imanode = nodeAddStaticNode(C, ntree, SH_NODE_TEX_IMAGE);
-
- ima = proj_paint_image_create(op, bmain, is_data);
- imanode->id = &ima->id;
-
- nodeSetActive(ntree, imanode);
+ const ePaintCanvasSource slot_type = ob->mode == OB_MODE_SCULPT ?
+ (ePaintCanvasSource)RNA_enum_get(op->ptr,
+ "slot_type") :
+ PAINT_CANVAS_SOURCE_IMAGE;
+
+ /* Create a new node. */
+ switch (slot_type) {
+ case PAINT_CANVAS_SOURCE_IMAGE: {
+ new_node = nodeAddStaticNode(C, ntree, SH_NODE_TEX_IMAGE);
+ ima = proj_paint_image_create(op, bmain, is_data);
+ new_node->id = &ima->id;
+ break;
+ }
+ case PAINT_CANVAS_SOURCE_COLOR_ATTRIBUTE: {
+ new_node = nodeAddStaticNode(C, ntree, SH_NODE_ATTRIBUTE);
+ if ((layer = proj_paint_color_attribute_create(op, ob))) {
+ BLI_strncpy_utf8(
+ ((NodeShaderAttribute *)new_node->storage)->name, layer->name, MAX_NAME);
+ }
+ break;
+ }
+ case PAINT_CANVAS_SOURCE_MATERIAL:
+ BLI_assert_unreachable();
+ return false;
+ }
+ nodeSetActive(ntree, new_node);
/* Connect to first available principled BSDF node. */
bNode *in_node = ntreeFindType(ntree, SH_NODE_BSDF_PRINCIPLED);
- bNode *out_node = imanode;
+ bNode *out_node = new_node;
if (in_node != NULL) {
bNodeSocket *out_sock = nodeFindSocket(out_node, SOCK_OUT, "Color");
@@ -6611,6 +6677,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);
@@ -6678,13 +6749,51 @@ static int texture_paint_add_texture_paint_slot_invoke(bContext *C,
int type = get_texture_layer_type(op, "type");
proj_paint_default_color(op, type, ma);
- char imagename[MAX_ID_NAME - 2];
- get_default_texture_layer_name_for_object(ob, type, (char *)&imagename, sizeof(imagename));
- RNA_string_set(op->ptr, "name", imagename);
+ char name[MAX_NAME];
+ get_default_texture_layer_name_for_object(ob, type, (char *)&name, sizeof(name));
+ RNA_string_set(op->ptr, "name", name);
return WM_operator_props_dialog_popup(C, op, 300);
}
+static void texture_paint_add_texture_paint_slot_ui(bContext *C, wmOperator *op)
+{
+ uiLayout *layout = op->layout;
+ uiLayoutSetPropSep(layout, true);
+ uiLayoutSetPropDecorate(layout, false);
+ Object *ob = ED_object_active_context(C);
+ ePaintCanvasSource slot_type = PAINT_CANVAS_SOURCE_IMAGE;
+
+ if (ob->mode == OB_MODE_SCULPT) {
+ slot_type = (ePaintCanvasSource)RNA_enum_get(op->ptr, "slot_type");
+ uiItemR(layout, op->ptr, "slot_type", UI_ITEM_R_EXPAND, NULL, ICON_NONE);
+ }
+
+ uiItemR(layout, op->ptr, "name", 0, NULL, ICON_NONE);
+
+ switch (slot_type) {
+ case PAINT_CANVAS_SOURCE_IMAGE: {
+ uiLayout *col = uiLayoutColumn(layout, true);
+ uiItemR(col, op->ptr, "width", 0, NULL, ICON_NONE);
+ uiItemR(col, op->ptr, "height", 0, NULL, ICON_NONE);
+
+ uiItemR(layout, op->ptr, "alpha", 0, NULL, ICON_NONE);
+ uiItemR(layout, op->ptr, "generated_type", 0, NULL, ICON_NONE);
+ uiItemR(layout, op->ptr, "float", 0, NULL, ICON_NONE);
+ break;
+ }
+ case PAINT_CANVAS_SOURCE_COLOR_ATTRIBUTE:
+ uiItemR(layout, op->ptr, "domain", UI_ITEM_R_EXPAND, NULL, ICON_NONE);
+ uiItemR(layout, op->ptr, "data_type", UI_ITEM_R_EXPAND, NULL, ICON_NONE);
+ break;
+ case PAINT_CANVAS_SOURCE_MATERIAL:
+ BLI_assert_unreachable();
+ break;
+ }
+
+ uiItemR(layout, op->ptr, "color", 0, NULL, ICON_NONE);
+}
+
#define IMA_DEF_NAME N_("Untitled")
void PAINT_OT_add_texture_paint_slot(wmOperatorType *ot)
@@ -6692,40 +6801,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/sculpt.c b/source/blender/editors/sculpt_paint/sculpt.c
index 32b7047c2b0..85ea5d5bfc6 100644
--- a/source/blender/editors/sculpt_paint/sculpt.c
+++ b/source/blender/editors/sculpt_paint/sculpt.c
@@ -5281,7 +5281,7 @@ static bool sculpt_stroke_test_start(bContext *C, struct wmOperator *op, const f
* canvas it is painting on. (ref. use_sculpt_texture_paint). */
if (brush && SCULPT_TOOL_NEEDS_COLOR(brush->sculpt_tool)) {
View3D *v3d = CTX_wm_view3d(C);
- if (v3d) {
+ if (v3d->shading.type == OB_SOLID) {
v3d->shading.color_type = V3D_SHADING_VERTEX_COLOR;
}
}
diff --git a/source/blender/editors/sculpt_paint/sculpt_filter_color.c b/source/blender/editors/sculpt_paint/sculpt_filter_color.c
index 09f13ff110d..f71a814aff4 100644
--- a/source/blender/editors/sculpt_paint/sculpt_filter_color.c
+++ b/source/blender/editors/sculpt_paint/sculpt_filter_color.c
@@ -124,8 +124,8 @@ static void color_filter_task_cb(void *__restrict userdata,
}
case COLOR_FILTER_HUE:
rgb_to_hsv_v(orig_color, hsv_color);
- hue = hsv_color[0] + fade;
- hsv_color[0] = fabs((hsv_color[0] + fade) - hue);
+ hue = hsv_color[0];
+ hsv_color[0] = fmod((hsv_color[0] + fabs(fade)) - hue, 1);
hsv_to_rgb_v(hsv_color, final_color);
break;
case COLOR_FILTER_SATURATION:
@@ -328,8 +328,12 @@ static int sculpt_color_filter_invoke(bContext *C, wmOperator *op, const wmEvent
{
Object *ob = CTX_data_active_object(C);
Sculpt *sd = CTX_data_tool_settings(C)->sculpt;
+ View3D *v3d = CTX_wm_view3d(C);
SculptSession *ss = ob->sculpt;
PBVH *pbvh = ob->sculpt->pbvh;
+ if (v3d->shading.type == OB_SOLID) {
+ v3d->shading.color_type = V3D_SHADING_VERTEX_COLOR;
+ }
const bool use_automasking = SCULPT_is_automasking_enabled(sd, ss, NULL);
if (use_automasking) {
diff --git a/source/blender/editors/sculpt_paint/sculpt_ops.c b/source/blender/editors/sculpt_paint/sculpt_ops.c
index 2b5a20205bd..5aa1dbef74c 100644
--- a/source/blender/editors/sculpt_paint/sculpt_ops.c
+++ b/source/blender/editors/sculpt_paint/sculpt_ops.c
@@ -1043,6 +1043,10 @@ static int sculpt_mask_by_color_invoke(bContext *C, wmOperator *op, const wmEven
Depsgraph *depsgraph = CTX_data_depsgraph_pointer(C);
Object *ob = CTX_data_active_object(C);
SculptSession *ss = ob->sculpt;
+ View3D *v3d = CTX_wm_view3d(C);
+ if (v3d->shading.type == OB_SOLID) {
+ v3d->shading.color_type = V3D_SHADING_VERTEX_COLOR;
+ }
BKE_sculpt_update_object_for_edit(depsgraph, ob, true, true, false);
diff --git a/source/blender/editors/sound/sound_ops.c b/source/blender/editors/sound/sound_ops.c
index a63ed142ed8..2a8a2be8b65 100644
--- a/source/blender/editors/sound/sound_ops.c
+++ b/source/blender/editors/sound/sound_ops.c
@@ -761,7 +761,8 @@ static int sound_pack_exec(bContext *C, wmOperator *op)
sound->packedfile = BKE_packedfile_new(
op->reports, sound->filepath, ID_BLEND_PATH(bmain, &sound->id));
- BKE_sound_load(bmain, sound);
+
+ DEG_id_tag_update_ex(bmain, &sound->id, ID_RECALC_AUDIO);
return OPERATOR_FINISHED;
}
diff --git a/source/blender/editors/space_file/filelist.c b/source/blender/editors/space_file/filelist.c
index 9f71d6f77c7..59ecef7d4c6 100644
--- a/source/blender/editors/space_file/filelist.c
+++ b/source/blender/editors/space_file/filelist.c
@@ -2802,7 +2802,8 @@ int ED_path_extension_type(const char *path)
if (BLI_path_extension_check(path, ".zip")) {
return FILE_TYPE_ARCHIVE;
}
- if (BLI_path_extension_check_n(path, ".obj", ".3ds", ".fbx", ".glb", ".gltf", ".svg", NULL)) {
+ if (BLI_path_extension_check_n(
+ path, ".obj", ".mtl", ".3ds", ".fbx", ".glb", ".gltf", ".svg", NULL)) {
return FILE_TYPE_OBJECT_IO;
}
if (BLI_path_extension_check_array(path, imb_ext_image)) {
diff --git a/source/blender/editors/space_file/filesel.c b/source/blender/editors/space_file/filesel.c
index 011506368ee..ce36e3e4e4f 100644
--- a/source/blender/editors/space_file/filesel.c
+++ b/source/blender/editors/space_file/filesel.c
@@ -1364,3 +1364,21 @@ ScrArea *ED_fileselect_handler_area_find(const wmWindow *win, const wmOperator *
return NULL;
}
+
+ScrArea *ED_fileselect_handler_area_find_any_with_op(const wmWindow *win)
+{
+ const bScreen *screen = WM_window_get_active_screen(win);
+
+ ED_screen_areas_iter (win, screen, area) {
+ if (area->spacetype != SPACE_FILE) {
+ continue;
+ }
+
+ const SpaceFile *sfile = area->spacedata.first;
+ if (sfile->op) {
+ return area;
+ }
+ }
+
+ return NULL;
+}
diff --git a/source/blender/editors/space_image/image_ops.c b/source/blender/editors/space_image/image_ops.c
index aa77aab2283..0cfb924e618 100644
--- a/source/blender/editors/space_image/image_ops.c
+++ b/source/blender/editors/space_image/image_ops.c
@@ -2316,6 +2316,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 +2347,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,7 +2404,7 @@ 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) {
@@ -3040,9 +3048,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 +3117,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 +3150,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_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/node_context_path.cc b/source/blender/editors/space_node/node_context_path.cc
index 4247d5a1fbc..dfc0beb13fc 100644
--- a/source/blender/editors/space_node/node_context_path.cc
+++ b/source/blender/editors/space_node/node_context_path.cc
@@ -139,7 +139,7 @@ static void get_context_path_node_geometry(const bContext &C,
Object *object = CTX_data_active_object(&C);
ui::context_path_add_generic(path, RNA_Object, object);
ModifierData *modifier = BKE_object_active_modifier(object);
- ui::context_path_add_generic(path, RNA_Modifier, modifier, ICON_MODIFIER);
+ ui::context_path_add_generic(path, RNA_Modifier, modifier, ICON_GEOMETRY_NODES);
context_path_add_node_tree_and_node_groups(snode, path);
}
}
diff --git a/source/blender/editors/space_node/node_draw.cc b/source/blender/editors/space_node/node_draw.cc
index 9076b17a926..f5048e0cc67 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;
}
diff --git a/source/blender/editors/space_node/node_edit.cc b/source/blender/editors/space_node/node_edit.cc
index 2d7972e2291..fb2f1bf3751 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,
@@ -293,6 +295,12 @@ static void compo_startjob(void *cjv,
} // 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_select.cc b/source/blender/editors/space_node/node_select.cc
index 1d0097068f1..147cbc5a05c 100644
--- a/source/blender/editors/space_node/node_select.cc
+++ b/source/blender/editors/space_node/node_select.cc
@@ -193,11 +193,6 @@ static bool is_event_over_node_or_socket(bContext *C, const wmEvent *event)
return is_position_over_node_or_socket(*snode, mouse);
}
-static void node_toggle(bNode *node)
-{
- nodeSetSelected(node, !(node->flag & SELECT));
-}
-
void node_socket_select(bNode *node, bNodeSocket &sock)
{
sock.flag |= SELECT;
@@ -510,10 +505,10 @@ void node_select_single(bContext &C, bNode &node)
WM_event_add_notifier(&C, NC_NODE | NA_SELECTED, nullptr);
}
-static int node_mouse_select(bContext *C,
- wmOperator *op,
- const int mval[2],
- bool wait_to_deselect_others)
+static bool node_mouse_select(bContext *C,
+ wmOperator *op,
+ const int mval[2],
+ struct SelectPick_Params *params)
{
Main &bmain = *CTX_data_main(C);
SpaceNode &snode = *CTX_wm_space_node(C);
@@ -525,36 +520,38 @@ static int node_mouse_select(bContext *C,
bNodeSocket *sock = nullptr;
bNodeSocket *tsock;
float cursor[2];
- int ret_value = OPERATOR_CANCELLED;
- const bool extend = RNA_boolean_get(op->ptr, "extend");
/* always do socket_select when extending selection. */
- const bool socket_select = extend || RNA_boolean_get(op->ptr, "socket_select");
- const bool deselect_all = RNA_boolean_get(op->ptr, "deselect_all");
-
- /* These cases are never modal. */
- if (extend || socket_select) {
- wait_to_deselect_others = false;
- }
+ const bool socket_select = (params->sel_op == SEL_OP_XOR) ||
+ RNA_boolean_get(op->ptr, "socket_select");
+ bool changed = false;
+ bool found = false;
+ bool node_was_selected = false;
/* get mouse coordinates in view2d space */
UI_view2d_region_to_view(&region.v2d, mval[0], mval[1], &cursor[0], &cursor[1]);
/* first do socket selection, these generally overlap with nodes. */
if (socket_select) {
+ /* NOTE: unlike nodes #SelectPick_Params isn't fully supported. */
+ const bool extend = (params->sel_op == SEL_OP_XOR);
if (node_find_indicated_socket(snode, &node, &sock, cursor, SOCK_IN)) {
+ found = true;
+ node_was_selected = node->flag & SELECT;
+
/* NOTE: SOCK_IN does not take into account the extend case...
* This feature is not really used anyway currently? */
node_socket_toggle(node, *sock, true);
- ret_value = OPERATOR_FINISHED;
+ changed = true;
}
else if (node_find_indicated_socket(snode, &node, &sock, cursor, SOCK_OUT)) {
+ found = true;
+ node_was_selected = node->flag & SELECT;
+
if (sock->flag & SELECT) {
if (extend) {
node_socket_deselect(node, *sock, true);
- }
- else {
- ret_value = OPERATOR_FINISHED;
+ changed = true;
}
}
else {
@@ -566,6 +563,7 @@ static int node_mouse_select(bContext *C,
continue;
}
node_socket_deselect(node, *tsock, true);
+ changed = true;
}
}
if (!extend) {
@@ -575,69 +573,71 @@ static int node_mouse_select(bContext *C,
}
for (tsock = (bNodeSocket *)tnode->outputs.first; tsock; tsock = tsock->next) {
node_socket_deselect(tnode, *tsock, true);
+ changed = true;
}
}
}
node_socket_select(node, *sock);
- ret_value = OPERATOR_FINISHED;
+ changed = true;
}
}
}
if (!sock) {
+
/* find the closest visible node */
node = node_under_mouse_select(*snode.edittree, (int)cursor[0], (int)cursor[1]);
+ found = (node != nullptr);
+ node_was_selected = node && (node->flag & SELECT);
- if (extend) {
- if (node != nullptr) {
- /* If node is selected but not active, we want to make it active,
- * but not toggle (deselect) it. */
- if (!((node->flag & SELECT) && (node->flag & NODE_ACTIVE) == 0)) {
- node_toggle(node);
- }
- ret_value = OPERATOR_FINISHED;
+ if (params->sel_op == SEL_OP_SET) {
+ if ((found && params->select_passthrough) && (node->flag & SELECT)) {
+ found = false;
}
- }
- else if (deselect_all && node == nullptr) {
- /* Rather than deselecting others, users may want to drag to box-select (drag from empty
- * space) or tweak-translate an already selected item. If these cases may apply, delay
- * deselection. */
- if (wait_to_deselect_others) {
- ret_value = OPERATOR_RUNNING_MODAL;
- }
- else {
- /* Deselect in empty space. */
+ else if (found || params->deselect_all) {
+ /* Deselect everything. */
for (tnode = (bNode *)snode.edittree->nodes.first; tnode; tnode = tnode->next) {
nodeSetSelected(tnode, false);
}
- ret_value = OPERATOR_FINISHED;
+ changed = true;
}
}
- else if (node != nullptr) {
- /* When clicking on an already selected node, we want to wait to deselect
- * others and allow the user to start moving the node without that. */
- if (wait_to_deselect_others && (node->flag & SELECT)) {
- ret_value = OPERATOR_RUNNING_MODAL;
- }
- else {
- nodeSetSelected(node, true);
- for (tnode = (bNode *)snode.edittree->nodes.first; tnode; tnode = tnode->next) {
- if (tnode != node) {
- nodeSetSelected(tnode, false);
- }
+ if (found) {
+ switch (params->sel_op) {
+ case SEL_OP_ADD: {
+ nodeSetSelected(node, true);
+ break;
+ }
+ case SEL_OP_SUB: {
+ nodeSetSelected(node, false);
+ break;
+ }
+ case SEL_OP_XOR: {
+ /* Check active so clicking on an inactive node activates it. */
+ bool is_selected = (node->flag & NODE_SELECT) && (node->flag & NODE_ACTIVE);
+ nodeSetSelected(node, !is_selected);
+ break;
+ }
+ case SEL_OP_SET: {
+ nodeSetSelected(node, true);
+ break;
+ }
+ case SEL_OP_AND: {
+ BLI_assert_unreachable(); /* Doesn't make sense for picking. */
+ break;
}
-
- ret_value = OPERATOR_FINISHED;
}
+
+ changed = true;
}
}
/* update node order */
- if (ret_value != OPERATOR_CANCELLED) {
+ if (changed || found) {
bool active_texture_changed = false;
bool viewer_node_changed = false;
- if (node != nullptr && ret_value != OPERATOR_RUNNING_MODAL) {
+ if ((node != nullptr) && (node_was_selected == false || params->select_passthrough == false)) {
viewer_node_changed = (node->flag & NODE_DO_OUTPUT) == 0 && node->type == GEO_NODE_VIEWER;
ED_node_set_active(&bmain, &snode, snode.edittree, node, &active_texture_changed);
}
@@ -654,23 +654,35 @@ static int node_mouse_select(bContext *C,
WM_event_add_notifier(C, NC_NODE | NA_SELECTED, nullptr);
}
- return ret_value;
+ return changed || found;
}
static int node_select_exec(bContext *C, wmOperator *op)
{
- const bool wait_to_deselect_others = RNA_boolean_get(op->ptr, "wait_to_deselect_others");
-
/* get settings from RNA properties for operator */
int mval[2];
- mval[0] = RNA_int_get(op->ptr, "mouse_x");
- mval[1] = RNA_int_get(op->ptr, "mouse_y");
+ RNA_int_get_array(op->ptr, "location", mval);
+
+ struct SelectPick_Params params = {};
+ ED_select_pick_params_from_operator(op, &params);
/* perform the select */
- const int ret_value = node_mouse_select(C, op, mval, wait_to_deselect_others);
+ const bool changed = node_mouse_select(C, op, mval, &params);
- /* allow tweak event to work too */
- return ret_value | OPERATOR_PASS_THROUGH;
+ if (changed) {
+ return OPERATOR_PASS_THROUGH | OPERATOR_FINISHED;
+ }
+ /* Nothing selected, just passthrough. */
+ return OPERATOR_PASS_THROUGH | OPERATOR_CANCELLED;
+}
+
+static int node_select_invoke(bContext *C, wmOperator *op, const wmEvent *event)
+{
+ RNA_int_set_array(op->ptr, "location", event->mval);
+
+ const int retval = node_select_exec(C, op);
+
+ return WM_operator_flag_only_pass_through_on_press(retval, event);
}
void NODE_OT_select(wmOperatorType *ot)
@@ -684,24 +696,28 @@ void NODE_OT_select(wmOperatorType *ot)
/* api callbacks */
ot->exec = node_select_exec;
- ot->invoke = WM_generic_select_invoke;
- ot->modal = WM_generic_select_modal;
+ ot->invoke = node_select_invoke;
ot->poll = ED_operator_node_active;
/* flags */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
/* properties */
- WM_operator_properties_generic_select(ot);
- prop = RNA_def_boolean(ot->srna, "extend", false, "Extend", "");
- RNA_def_property_flag(prop, PROP_SKIP_SAVE);
+ WM_operator_properties_mouse_select(ot);
+
+ prop = RNA_def_int_vector(ot->srna,
+ "location",
+ 2,
+ NULL,
+ INT_MIN,
+ INT_MAX,
+ "Location",
+ "Mouse location",
+ INT_MIN,
+ INT_MAX);
+ RNA_def_property_flag(prop, PROP_HIDDEN);
+
RNA_def_boolean(ot->srna, "socket_select", false, "Socket Select", "");
- prop = RNA_def_boolean(ot->srna,
- "deselect_all",
- false,
- "Deselect On Nothing",
- "Deselect all when nothing under the cursor");
- RNA_def_property_flag(prop, PROP_SKIP_SAVE);
}
/** \} */
diff --git a/source/blender/editors/space_outliner/outliner_draw.cc b/source/blender/editors/space_outliner/outliner_draw.cc
index ff99416c213..57b0e2022ff 100644
--- a/source/blender/editors/space_outliner/outliner_draw.cc
+++ b/source/blender/editors/space_outliner/outliner_draw.cc
@@ -1809,6 +1809,25 @@ static void outliner_draw_overrides_rna_buts(uiBlock *block,
TreeElementOverridesProperty &override_elem = *tree_element_cast<TreeElementOverridesProperty>(
te);
+ if (!override_elem.is_rna_path_valid) {
+ uiBut *but = uiDefBut(block,
+ UI_BTYPE_LABEL,
+ 0,
+ override_elem.rna_path.c_str(),
+ x + pad_x,
+ te->ys + pad_y,
+ item_max_width,
+ item_height,
+ NULL,
+ 0.0f,
+ 0.0f,
+ 0.0f,
+ 0.0f,
+ "");
+ UI_but_flag_enable(but, UI_BUT_REDALERT);
+ continue;
+ }
+
PointerRNA *ptr = &override_elem.override_rna_ptr;
PropertyRNA *prop = &override_elem.override_rna_prop;
const PropertyType prop_type = RNA_property_type(prop);
@@ -1936,8 +1955,9 @@ static bool outliner_draw_overrides_warning_buts(uiBlock *block,
break;
}
case TSE_LIBRARY_OVERRIDE: {
- const bool is_rna_path_valid = (bool)(POINTER_AS_UINT(te->directdata));
- if (!is_rna_path_valid) {
+ 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_(
diff --git a/source/blender/editors/space_outliner/outliner_edit.cc b/source/blender/editors/space_outliner/outliner_edit.cc
index d6c5901b546..f4e28af3fca 100644
--- a/source/blender/editors/space_outliner/outliner_edit.cc
+++ b/source/blender/editors/space_outliner/outliner_edit.cc
@@ -334,8 +334,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;
@@ -568,187 +576,6 @@ void OUTLINER_OT_id_delete(wmOperatorType *ot)
/** \} */
/* -------------------------------------------------------------------- */
-/** \name ID Remap Operator
- * \{ */
-
-static int outliner_id_remap_exec(bContext *C, wmOperator *op)
-{
- Main *bmain = CTX_data_main(C);
- SpaceOutliner *space_outliner = CTX_wm_space_outliner(C);
-
- const short id_type = (short)RNA_enum_get(op->ptr, "id_type");
- ID *old_id = reinterpret_cast<ID *>(
- BLI_findlink(which_libbase(CTX_data_main(C), id_type), RNA_enum_get(op->ptr, "old_id")));
- ID *new_id = reinterpret_cast<ID *>(
- BLI_findlink(which_libbase(CTX_data_main(C), id_type), RNA_enum_get(op->ptr, "new_id")));
-
- /* check for invalid states */
- if (space_outliner == nullptr) {
- return OPERATOR_CANCELLED;
- }
-
- if (!(old_id && new_id && (old_id != new_id) && (GS(old_id->name) == GS(new_id->name)))) {
- BKE_reportf(op->reports,
- RPT_ERROR_INVALID_INPUT,
- "Invalid old/new ID pair ('%s' / '%s')",
- old_id ? old_id->name : "Invalid ID",
- new_id ? new_id->name : "Invalid ID");
- return OPERATOR_CANCELLED;
- }
-
- if (ID_IS_LINKED(old_id)) {
- BKE_reportf(op->reports,
- RPT_WARNING,
- "Old ID '%s' is linked from a library, indirect usages of this data-block will "
- "not be remapped",
- old_id->name);
- }
-
- BKE_libblock_remap(
- bmain, old_id, new_id, ID_REMAP_SKIP_INDIRECT_USAGE | ID_REMAP_SKIP_NEVER_NULL_USAGE);
-
- BKE_main_lib_objects_recalc_all(bmain);
-
- /* recreate dependency graph to include new objects */
- DEG_relations_tag_update(bmain);
-
- /* Free gpu materials, some materials depend on existing objects,
- * such as lights so freeing correctly refreshes. */
- GPU_materials_free(bmain);
-
- WM_event_add_notifier(C, NC_WINDOW, nullptr);
-
- return OPERATOR_FINISHED;
-}
-
-static bool outliner_id_remap_find_tree_element(bContext *C,
- wmOperator *op,
- ListBase *tree,
- const float y)
-{
- LISTBASE_FOREACH (TreeElement *, te, tree) {
- if (y > te->ys && y < te->ys + UI_UNIT_Y) {
- TreeStoreElem *tselem = TREESTORE(te);
-
- if ((tselem->type == TSE_SOME_ID) && tselem->id) {
- RNA_enum_set(op->ptr, "id_type", GS(tselem->id->name));
- RNA_enum_set_identifier(C, op->ptr, "new_id", tselem->id->name + 2);
- RNA_enum_set_identifier(C, op->ptr, "old_id", tselem->id->name + 2);
- return true;
- }
- }
- if (outliner_id_remap_find_tree_element(C, op, &te->subtree, y)) {
- return true;
- }
- }
- return false;
-}
-
-static int outliner_id_remap_invoke(bContext *C, wmOperator *op, const wmEvent *event)
-{
- SpaceOutliner *space_outliner = CTX_wm_space_outliner(C);
- ARegion *region = CTX_wm_region(C);
- float fmval[2];
-
- if (!RNA_property_is_set(op->ptr, RNA_struct_find_property(op->ptr, "id_type"))) {
- UI_view2d_region_to_view(&region->v2d, event->mval[0], event->mval[1], &fmval[0], &fmval[1]);
-
- outliner_id_remap_find_tree_element(C, op, &space_outliner->tree, fmval[1]);
- }
-
- return WM_operator_props_dialog_popup(C, op, 400);
-}
-
-static const EnumPropertyItem *outliner_id_itemf(bContext *C,
- PointerRNA *ptr,
- PropertyRNA *UNUSED(prop),
- bool *r_free)
-{
- if (C == nullptr) {
- return DummyRNA_NULL_items;
- }
-
- EnumPropertyItem item_tmp = {0}, *item = nullptr;
- int totitem = 0;
- int i = 0;
-
- short id_type = (short)RNA_enum_get(ptr, "id_type");
- ID *id = reinterpret_cast<ID *>(which_libbase(CTX_data_main(C), id_type)->first);
-
- for (; id; id = reinterpret_cast<ID *>(id->next)) {
- item_tmp.identifier = item_tmp.name = id->name + 2;
- item_tmp.value = i++;
- RNA_enum_item_add(&item, &totitem, &item_tmp);
- }
-
- RNA_enum_item_end(&item, &totitem);
- *r_free = true;
-
- return item;
-}
-
-void OUTLINER_OT_id_remap(wmOperatorType *ot)
-{
- PropertyRNA *prop;
-
- /* identifiers */
- ot->name = "Outliner ID Data Remap";
- ot->idname = "OUTLINER_OT_id_remap";
-
- /* callbacks */
- ot->invoke = outliner_id_remap_invoke;
- ot->exec = outliner_id_remap_exec;
- ot->poll = ED_operator_outliner_active;
-
- /* Flags. */
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
-
- prop = RNA_def_enum(ot->srna, "id_type", rna_enum_id_type_items, ID_OB, "ID Type", "");
- RNA_def_property_translation_context(prop, BLT_I18NCONTEXT_ID_ID);
- /* Changing ID type wont make sense, would return early with "Invalid old/new ID pair" anyways.
- */
- RNA_def_property_flag(prop, PROP_HIDDEN);
-
- prop = RNA_def_enum(ot->srna, "old_id", DummyRNA_NULL_items, 0, "Old ID", "Old ID to replace");
- RNA_def_property_enum_funcs_runtime(prop, nullptr, nullptr, outliner_id_itemf);
- RNA_def_property_flag(prop, (PropertyFlag)(PROP_ENUM_NO_TRANSLATE | PROP_HIDDEN));
-
- ot->prop = RNA_def_enum(ot->srna,
- "new_id",
- DummyRNA_NULL_items,
- 0,
- "New ID",
- "New ID to remap all selected IDs' users to");
- RNA_def_property_enum_funcs_runtime(ot->prop, nullptr, nullptr, outliner_id_itemf);
- RNA_def_property_flag(ot->prop, PROP_ENUM_NO_TRANSLATE);
-}
-
-void id_remap_fn(bContext *C,
- ReportList *UNUSED(reports),
- Scene *UNUSED(scene),
- TreeElement *UNUSED(te),
- TreeStoreElem *UNUSED(tsep),
- TreeStoreElem *tselem,
- void *UNUSED(user_data))
-{
- wmOperatorType *ot = WM_operatortype_find("OUTLINER_OT_id_remap", false);
- PointerRNA op_props;
-
- BLI_assert(tselem->id != nullptr);
-
- WM_operator_properties_create_ptr(&op_props, ot);
-
- RNA_enum_set(&op_props, "id_type", GS(tselem->id->name));
- RNA_enum_set_identifier(C, &op_props, "old_id", tselem->id->name + 2);
-
- WM_operator_name_call_ptr(C, ot, WM_OP_INVOKE_DEFAULT, &op_props, nullptr);
-
- WM_operator_properties_free(&op_props);
-}
-
-/** \} */
-
-/* -------------------------------------------------------------------- */
/** \name ID Copy Operator
* \{ */
diff --git a/source/blender/editors/space_outliner/outliner_intern.hh b/source/blender/editors/space_outliner/outliner_intern.hh
index f3bcb7b0f1e..2fdf327cbee 100644
--- a/source/blender/editors/space_outliner/outliner_intern.hh
+++ b/source/blender/editors/space_outliner/outliner_intern.hh
@@ -442,13 +442,6 @@ void id_delete_fn(struct bContext *C,
struct TreeStoreElem *tsep,
struct TreeStoreElem *tselem,
void *user_data);
-void id_remap_fn(struct bContext *C,
- struct ReportList *reports,
- struct Scene *scene,
- struct TreeElement *te,
- struct TreeStoreElem *tsep,
- struct TreeStoreElem *tselem,
- void *user_data);
/**
* To retrieve coordinates with redrawing the entire tree.
@@ -523,7 +516,6 @@ void OUTLINER_OT_scene_operation(struct wmOperatorType *ot);
void OUTLINER_OT_object_operation(struct wmOperatorType *ot);
void OUTLINER_OT_lib_operation(struct wmOperatorType *ot);
void OUTLINER_OT_id_operation(struct wmOperatorType *ot);
-void OUTLINER_OT_id_remap(struct wmOperatorType *ot);
void OUTLINER_OT_id_copy(struct wmOperatorType *ot);
void OUTLINER_OT_id_paste(struct wmOperatorType *ot);
void OUTLINER_OT_data_operation(struct wmOperatorType *ot);
diff --git a/source/blender/editors/space_outliner/outliner_ops.cc b/source/blender/editors/space_outliner/outliner_ops.cc
index 8baac45666e..e053a94c572 100644
--- a/source/blender/editors/space_outliner/outliner_ops.cc
+++ b/source/blender/editors/space_outliner/outliner_ops.cc
@@ -31,7 +31,6 @@ void outliner_operatortypes(void)
WM_operatortype_append(OUTLINER_OT_lib_relocate);
WM_operatortype_append(OUTLINER_OT_id_operation);
WM_operatortype_append(OUTLINER_OT_id_delete);
- WM_operatortype_append(OUTLINER_OT_id_remap);
WM_operatortype_append(OUTLINER_OT_id_copy);
WM_operatortype_append(OUTLINER_OT_id_paste);
WM_operatortype_append(OUTLINER_OT_data_operation);
diff --git a/source/blender/editors/space_outliner/outliner_tools.cc b/source/blender/editors/space_outliner/outliner_tools.cc
index 5da64177e51..f10edc29e37 100644
--- a/source/blender/editors/space_outliner/outliner_tools.cc
+++ b/source/blender/editors/space_outliner/outliner_tools.cc
@@ -1692,7 +1692,6 @@ enum {
OL_OP_SELECT = 1,
OL_OP_DESELECT,
OL_OP_SELECT_HIERARCHY,
- OL_OP_REMAP,
OL_OP_RENAME,
};
@@ -1700,11 +1699,6 @@ static const EnumPropertyItem prop_object_op_types[] = {
{OL_OP_SELECT, "SELECT", ICON_RESTRICT_SELECT_OFF, "Select", ""},
{OL_OP_DESELECT, "DESELECT", 0, "Deselect", ""},
{OL_OP_SELECT_HIERARCHY, "SELECT_HIERARCHY", 0, "Select Hierarchy", ""},
- {OL_OP_REMAP,
- "REMAP",
- 0,
- "Remap Users",
- "Make all users of selected data-blocks to use instead a new chosen one"},
{OL_OP_RENAME, "RENAME", 0, "Rename", ""},
{0, nullptr, 0, nullptr, nullptr},
};
@@ -1759,12 +1753,6 @@ static int outliner_object_operation_exec(bContext *C, wmOperator *op)
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);
@@ -1973,7 +1961,6 @@ enum eOutlinerIdOpTypes {
OUTLINER_IDOP_OVERRIDE_LIBRARY_CLEAR_SINGLE,
OUTLINER_IDOP_SINGLE,
OUTLINER_IDOP_DELETE,
- OUTLINER_IDOP_REMAP,
OUTLINER_IDOP_COPY,
OUTLINER_IDOP_PASTE,
@@ -1991,11 +1978,6 @@ static const EnumPropertyItem prop_id_op_types[] = {
{OUTLINER_IDOP_LOCAL, "LOCAL", 0, "Make Local", ""},
{OUTLINER_IDOP_SINGLE, "SINGLE", 0, "Make Single User", ""},
{OUTLINER_IDOP_DELETE, "DELETE", ICON_X, "Delete", ""},
- {OUTLINER_IDOP_REMAP,
- "REMAP",
- 0,
- "Remap Users",
- "Make all users of selected data-blocks to use instead current (clicked) one"},
{0, "", 0, nullptr, nullptr},
{OUTLINER_IDOP_OVERRIDE_LIBRARY_CREATE,
"OVERRIDE_LIBRARY_CREATE",
@@ -2414,15 +2396,6 @@ static int outliner_id_operation_exec(bContext *C, wmOperator *op)
}
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);
- /* 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 OUTLINER_IDOP_COPY: {
wm->op_undo_depth++;
WM_operator_name_call(C, "OUTLINER_OT_id_copy", WM_OP_INVOKE_DEFAULT, nullptr, nullptr);
@@ -2527,14 +2500,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,14 +2537,6 @@ 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);
diff --git a/source/blender/editors/space_outliner/tree/tree_element_overrides.cc b/source/blender/editors/space_outliner/tree/tree_element_overrides.cc
index 857f5577e59..3a039da86c2 100644
--- a/source/blender/editors/space_outliner/tree/tree_element_overrides.cc
+++ b/source/blender/editors/space_outliner/tree/tree_element_overrides.cc
@@ -84,14 +84,13 @@ TreeElementOverridesProperty::TreeElementOverridesProperty(TreeElement &legacy_t
TreeElementOverridesData &override_data)
: AbstractTreeElement(legacy_te),
override_rna_ptr(override_data.override_rna_ptr),
- override_rna_prop(override_data.override_rna_prop)
+ override_rna_prop(override_data.override_rna_prop),
+ rna_path(override_data.override_property.rna_path),
+ is_rna_path_valid(override_data.is_rna_path_valid)
{
BLI_assert(legacy_te.store_elem->type == TSE_LIBRARY_OVERRIDE);
legacy_te.name = override_data.override_property.rna_path;
- /* Abusing this for now, better way to do it is also pending current refactor of the whole tree
- * code to use C++. */
- legacy_te.directdata = POINTER_FROM_UINT(override_data.is_rna_path_valid);
}
} // namespace blender::ed::outliner
diff --git a/source/blender/editors/space_outliner/tree/tree_element_overrides.hh b/source/blender/editors/space_outliner/tree/tree_element_overrides.hh
index a2d1409f193..b42e1c37a0f 100644
--- a/source/blender/editors/space_outliner/tree/tree_element_overrides.hh
+++ b/source/blender/editors/space_outliner/tree/tree_element_overrides.hh
@@ -8,6 +8,8 @@
#include "RNA_types.h"
+#include "BLI_string_ref.hh"
+
#include "tree_element.hh"
struct ID;
@@ -39,6 +41,9 @@ class TreeElementOverridesProperty final : public AbstractTreeElement {
PointerRNA override_rna_ptr;
PropertyRNA &override_rna_prop;
+ StringRefNull rna_path;
+ bool is_rna_path_valid;
+
public:
TreeElementOverridesProperty(TreeElement &legacy_te, TreeElementOverridesData &override_data);
};
diff --git a/source/blender/editors/space_sequencer/sequencer_add.c b/source/blender/editors/space_sequencer/sequencer_add.c
index 9298eb83b46..469169cf4cc 100644
--- a/source/blender/editors/space_sequencer/sequencer_add.c
+++ b/source/blender/editors/space_sequencer/sequencer_add.c
@@ -136,7 +136,7 @@ static void sequencer_generic_props__internal(wmOperatorType *ot, int flag)
ot->srna,
"overlap_shuffle_override",
false,
- "Override Overlap Shuffle Behaviour",
+ "Override Overlap Shuffle Behavior",
"Use the overlap_mode tool settings to determine how to shuffle overlapping strips");
RNA_def_property_flag(prop, PROP_HIDDEN | PROP_SKIP_SAVE);
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..66eced27b32 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_);
}
/**
@@ -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/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_snap.c b/source/blender/editors/transform/transform_snap.c
index e119b264ae7..769fd28c57b 100644
--- a/source/blender/editors/transform/transform_snap.c
+++ b/source/blender/editors/transform/transform_snap.c
@@ -1020,7 +1020,7 @@ static void snap_calc_uv_fn(TransInfo *t, float *UNUSED(vec))
objects,
objects_len,
t->mval,
- true,
+ t->tsnap.modeSelect == SNAP_NOT_SELECTED,
&dist_sq,
t->tsnap.snapPoint)) {
t->tsnap.snapPoint[0] *= t->aspect[0];
diff --git a/source/blender/editors/transform/transform_snap_object.cc b/source/blender/editors/transform/transform_snap_object.cc
index fade7f47d9c..0505772c668 100644
--- a/source/blender/editors/transform/transform_snap_object.cc
+++ b/source/blender/editors/transform/transform_snap_object.cc
@@ -168,8 +168,13 @@ struct SnapObjectContext {
/** \name Utilities
* \{ */
-/* Mesh used for snapping.
- * If nullptr the BMesh should be used. */
+/**
+ * Mesh used for snapping.
+ *
+ * - When the return value is null the `BKE_editmesh_from_object(ob_eval)` should be used.
+ * - In rare cases there is no evaluated mesh available and a null result doesn't imply an
+ * edit-mesh, so callers need to account for a null edit-mesh too, see: T96536.
+ */
static const Mesh *mesh_for_snap(Object *ob_eval, eSnapEditType edit_mode_type, bool *r_use_hide)
{
const Mesh *me_eval = BKE_object_get_evaluated_mesh(ob_eval);
@@ -998,6 +1003,9 @@ static void raycast_obj_fn(SnapObjectContext *sctx,
const Mesh *me_eval = mesh_for_snap(ob_eval, edit_mode_type, &use_hide);
if (me_eval == nullptr) {
BMEditMesh *em = BKE_editmesh_from_object(ob_eval);
+ if (UNLIKELY(!em)) { /* See #mesh_for_snap doc-string. */
+ return;
+ }
BLI_assert_msg(em == BKE_editmesh_from_object(DEG_get_original_object(ob_eval)),
"Make sure there is only one pointer for looptris");
retval = raycastEditMesh(sctx,
@@ -2696,6 +2704,9 @@ static void snap_obj_fn(SnapObjectContext *sctx,
const Mesh *me_eval = mesh_for_snap(ob_eval, edit_mode_type, &use_hide);
if (me_eval == nullptr) {
BMEditMesh *em = BKE_editmesh_from_object(ob_eval);
+ if (UNLIKELY(!em)) { /* See #mesh_for_snap doc-string. */
+ return;
+ }
BLI_assert_msg(em == BKE_editmesh_from_object(DEG_get_original_object(ob_eval)),
"Make sure there is only one pointer for looptris");
retval = snapEditMesh(
diff --git a/source/blender/editors/uvedit/uvedit_unwrap_ops.c b/source/blender/editors/uvedit/uvedit_unwrap_ops.c
index 34fae2ffb2a..c0ea753ed51 100644
--- a/source/blender/editors/uvedit/uvedit_unwrap_ops.c
+++ b/source/blender/editors/uvedit/uvedit_unwrap_ops.c
@@ -267,26 +267,35 @@ static bool uvedit_have_selection_multi(const Scene *scene,
return have_select;
}
+void ED_uvedit_get_aspect_from_material(Object *ob,
+ const int material_index,
+ float *r_aspx,
+ float *r_aspy)
+{
+ if (UNLIKELY(material_index < 0 || material_index >= ob->totcol)) {
+ *r_aspx = 1.0f;
+ *r_aspy = 1.0f;
+ return;
+ }
+ Image *ima;
+ ED_object_get_active_image(ob, material_index + 1, &ima, NULL, NULL, NULL);
+ ED_image_get_uv_aspect(ima, NULL, r_aspx, r_aspy);
+}
+
void ED_uvedit_get_aspect(Object *ob, float *r_aspx, float *r_aspy)
{
BMEditMesh *em = BKE_editmesh_from_object(ob);
BLI_assert(em != NULL);
bool sloppy = true;
bool selected = false;
- BMFace *efa;
- Image *ima;
-
- efa = BM_mesh_active_face_get(em->bm, sloppy, selected);
-
- if (efa) {
- ED_object_get_active_image(ob, efa->mat_nr + 1, &ima, NULL, NULL, NULL);
-
- ED_image_get_uv_aspect(ima, NULL, r_aspx, r_aspy);
- }
- else {
+ BMFace *efa = BM_mesh_active_face_get(em->bm, sloppy, selected);
+ if (!efa) {
*r_aspx = 1.0f;
*r_aspy = 1.0f;
+ return;
}
+
+ ED_uvedit_get_aspect_from_material(ob, efa->mat_nr, r_aspx, r_aspy);
}
static void construct_param_handle_face_add(ParamHandle *handle,
@@ -1527,49 +1536,88 @@ static void uv_transform_properties(wmOperatorType *ot, int radius)
}
}
-static void correct_uv_aspect(Object *ob, BMEditMesh *em)
+static void shrink_loop_uv_by_aspect_ratio(BMFace *efa,
+ const int cd_loop_uv_offset,
+ const float aspect_y)
{
+ BLI_assert(aspect_y != 1.0f); /* Nothing to do, should be handled by caller. */
+ BLI_assert(aspect_y > 0.0f); /* Negative aspect ratios are not supported. */
+
BMLoop *l;
- BMIter iter, liter;
- MLoopUV *luv;
- BMFace *efa;
- float scale, aspx, aspy;
+ BMIter iter;
+ BM_ITER_ELEM (l, &iter, efa, BM_LOOPS_OF_FACE) {
+ MLoopUV *luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
+ if (aspect_y > 1.0f) {
+ /* Reduce round-off error, i.e. `u = (u - 0.5) / aspect_y + 0.5`. */
+ luv->uv[0] = luv->uv[0] / aspect_y + (0.5f - 0.5f / aspect_y);
+ }
+ else {
+ /* Reduce round-off error, i.e. `v = (v - 0.5) * aspect_y + 0.5`. */
+ luv->uv[1] = luv->uv[1] * aspect_y + (0.5f - 0.5f * aspect_y);
+ }
+ }
+}
+static void correct_uv_aspect(Object *ob, BMEditMesh *em)
+{
const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV);
-
+ float aspx, aspy;
ED_uvedit_get_aspect(ob, &aspx, &aspy);
+ const float aspect_y = aspx / aspy;
+ if (aspect_y == 1.0f) {
+ /* Scaling by 1.0 has no effect. */
+ return;
+ }
+ BMFace *efa;
+ BMIter iter;
+ BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
+ if (BM_elem_flag_test(efa, BM_ELEM_SELECT)) {
+ shrink_loop_uv_by_aspect_ratio(efa, cd_loop_uv_offset, aspect_y);
+ }
+ }
+}
- if (aspx == aspy) {
+static void correct_uv_aspect_per_face(Object *ob, BMEditMesh *em)
+{
+ const int materials_num = ob->totcol;
+ if (materials_num == 0) {
+ /* Without any materials, there is no aspect_y information and nothing to do. */
return;
}
- if (aspx > aspy) {
- scale = aspy / aspx;
+ float *material_aspect_y = BLI_array_alloca(material_aspect_y, materials_num);
+ /* Lazily initialize aspect ratio for materials. */
+ copy_vn_fl(material_aspect_y, materials_num, -1.0f);
- BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
- if (!BM_elem_flag_test(efa, BM_ELEM_SELECT)) {
- continue;
- }
+ const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV);
- BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
- luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
- luv->uv[0] = ((luv->uv[0] - 0.5f) * scale) + 0.5f;
- }
+ BMFace *efa;
+ BMIter iter;
+ BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
+ if (!BM_elem_flag_test(efa, BM_ELEM_SELECT)) {
+ continue;
}
- }
- else {
- scale = aspx / aspy;
- BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
- if (!BM_elem_flag_test(efa, BM_ELEM_SELECT)) {
- continue;
- }
+ const int material_index = efa->mat_nr;
+ if (UNLIKELY(material_index < 0 || material_index >= materials_num)) {
+ /* The index might be for a material slot which is not currently setup. */
+ continue;
+ }
- BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
- luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
- luv->uv[1] = ((luv->uv[1] - 0.5f) * scale) + 0.5f;
- }
+ float aspect_y = material_aspect_y[material_index];
+ if (aspect_y == -1.0f) {
+ /* Lazily initialize aspect ratio for materials. */
+ float aspx, aspy;
+ ED_uvedit_get_aspect_from_material(ob, material_index, &aspx, &aspy);
+ aspect_y = aspx / aspy;
+ material_aspect_y[material_index] = aspect_y;
}
+
+ if (aspect_y == 1.0f) {
+ /* Scaling by 1.0 has no effect. */
+ continue;
+ }
+ shrink_loop_uv_by_aspect_ratio(efa, cd_loop_uv_offset, aspect_y);
}
}
@@ -1613,7 +1661,17 @@ static void uv_map_clip_correct_properties(wmOperatorType *ot)
uv_map_clip_correct_properties_ex(ot, true);
}
-static void uv_map_clip_correct_multi(Object **objects, uint objects_len, wmOperator *op)
+/**
+ * \param per_face_aspect: Calculate the aspect ratio per-face,
+ * otherwise use a single aspect for all UV's based on the material of the active face.
+ * TODO: using per-face aspect may split UV islands so more advanced UV projection methods
+ * such as "Unwrap" & "Smart UV Projections" will need to handle aspect correction themselves.
+ * For now keep using a single aspect for all faces in this case.
+ */
+static void uv_map_clip_correct_multi(Object **objects,
+ uint objects_len,
+ wmOperator *op,
+ bool per_face_aspect)
{
BMFace *efa;
BMLoop *l;
@@ -1633,9 +1691,14 @@ static void uv_map_clip_correct_multi(Object **objects, uint objects_len, wmOper
BMEditMesh *em = BKE_editmesh_from_object(ob);
const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV);
- /* correct for image aspect ratio */
+ /* Correct for image aspect ratio. */
if (correct_aspect) {
- correct_uv_aspect(ob, em);
+ if (per_face_aspect) {
+ correct_uv_aspect_per_face(ob, em);
+ }
+ else {
+ correct_uv_aspect(ob, em);
+ }
}
if (scale_to_bounds) {
@@ -1678,6 +1741,11 @@ static void uv_map_clip_correct_multi(Object **objects, uint objects_len, wmOper
dy = 1.0f / dy;
}
+ if (dx == 1.0f && dy == 1.0f) {
+ /* Scaling by 1.0 has no effect. */
+ return;
+ }
+
for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
Object *ob = objects[ob_index];
@@ -1702,7 +1770,7 @@ static void uv_map_clip_correct_multi(Object **objects, uint objects_len, wmOper
static void uv_map_clip_correct(Object *ob, wmOperator *op)
{
- uv_map_clip_correct_multi(&ob, 1, op);
+ uv_map_clip_correct_multi(&ob, 1, op, true);
}
/** \} */
@@ -2283,7 +2351,9 @@ static int smart_project_exec(bContext *C, wmOperator *op)
.use_seams = true,
});
- uv_map_clip_correct_multi(objects_changed, object_changed_len, op);
+ /* #ED_uvedit_pack_islands_multi only supports `per_face_aspect = false`. */
+ const bool per_face_aspect = false;
+ uv_map_clip_correct_multi(objects_changed, object_changed_len, op, per_face_aspect);
}
MEM_freeN(objects_changed);
@@ -2485,7 +2555,7 @@ static int uv_from_view_exec(bContext *C, wmOperator *op)
}
if (changed_multi) {
- uv_map_clip_correct_multi(objects, objects_len, op);
+ uv_map_clip_correct_multi(objects, objects_len, op, true);
}
MEM_freeN(objects);
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/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..d8f16065e2b
--- /dev/null
+++ b/source/blender/geometry/GEO_mesh_primitive_cuboid.hh
@@ -0,0 +1,18 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+
+#pragma once
+
+struct Mesh;
+struct float3;
+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);
+
+} // 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/intern/mesh_primitive_cuboid.cc b/source/blender/geometry/intern/mesh_primitive_cuboid.cc
new file mode 100644
index 00000000000..e41516d0486
--- /dev/null
+++ b/source/blender/geometry/intern/mesh_primitive_cuboid.cc
@@ -0,0 +1,423 @@
+/* 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;
+}
+
+} // namespace blender::geometry
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/gpencil_modifiers/CMakeLists.txt b/source/blender/gpencil_modifiers/CMakeLists.txt
index f87c85f808f..69fc26c99e9 100644
--- a/source/blender/gpencil_modifiers/CMakeLists.txt
+++ b/source/blender/gpencil_modifiers/CMakeLists.txt
@@ -72,7 +72,6 @@ set(SRC
intern/lineart/MOD_lineart.h
intern/lineart/lineart_intern.h
-
)
if(WITH_TBB)
diff --git a/source/blender/gpencil_modifiers/intern/lineart/lineart_cpu.c b/source/blender/gpencil_modifiers/intern/lineart/lineart_cpu.c
index dbe2ae0b890..b09bb15ce81 100644
--- a/source/blender/gpencil_modifiers/intern/lineart/lineart_cpu.c
+++ b/source/blender/gpencil_modifiers/intern/lineart/lineart_cpu.c
@@ -2358,18 +2358,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];
@@ -2481,13 +2484,6 @@ static void lineart_main_load_geometries(
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);
}
@@ -2506,6 +2502,17 @@ static void lineart_main_load_geometries(
continue;
}
+ if (!lineart_geometry_check_visible(
+ obi->model_view_proj, rb->shift_x, rb->shift_y, use_mesh)) {
+ if (ob->type != OB_MESH) {
+ BKE_id_free(NULL, use_mesh);
+ }
+ if (G.debug_value == 4000) {
+ bound_box_discard_count++;
+ }
+ continue;
+ }
+
if (ob->type != OB_MESH) {
obi->free_use_mesh = true;
}
diff --git a/source/blender/gpu/CMakeLists.txt b/source/blender/gpu/CMakeLists.txt
index 80cc2ac3013..a2db89f849e 100644
--- a/source/blender/gpu/CMakeLists.txt
+++ b/source/blender/gpu/CMakeLists.txt
@@ -536,6 +536,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 0d0542aa528..061b850619f 100644
--- a/source/blender/gpu/GPU_capabilities.h
+++ b/source/blender/gpu/GPU_capabilities.h
@@ -30,6 +30,7 @@ int GPU_max_batch_vertices(void);
int GPU_max_vertex_attribs(void);
int GPU_max_varying_floats(void);
int GPU_max_shader_storage_buffer_bindings(void);
+int GPU_max_compute_shader_storage_blocks(void);
int GPU_extensions_len(void);
const char *GPU_extension_get(int i);
@@ -40,6 +41,7 @@ bool GPU_mip_render_workaround(void);
bool GPU_depth_blitting_workaround(void);
bool GPU_use_main_context_workaround(void);
bool GPU_use_hq_normals_workaround(void);
+bool GPU_clear_viewport_workaround(void);
bool GPU_crappy_amd_driver(void);
bool GPU_compute_shader_support(void);
diff --git a/source/blender/gpu/GPU_shader.h b/source/blender/gpu/GPU_shader.h
index 9d34d2fb0ed..461b0dbb8e4 100644
--- a/source/blender/gpu/GPU_shader.h
+++ b/source/blender/gpu/GPU_shader.h
@@ -282,6 +282,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_texture.h b/source/blender/gpu/GPU_texture.h
index 474205ce8c3..b045d908438 100644
--- a/source/blender/gpu/GPU_texture.h
+++ b/source/blender/gpu/GPU_texture.h
@@ -282,7 +282,7 @@ void *GPU_texture_read(GPUTexture *tex, eGPUDataFormat data_format, int miplvl);
* \warning Only work for 2D texture for now.
* \warning Only clears the MIP 0 of the texture.
* \param data_format: data format of the pixel data.
- * \note The format is float for uniform 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_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 b750dacaca6..4ec215c2d3b 100644
--- a/source/blender/gpu/intern/gpu_capabilities.cc
+++ b/source/blender/gpu/intern/gpu_capabilities.cc
@@ -142,6 +142,11 @@ bool GPU_use_hq_normals_workaround()
return GCaps.use_hq_normals_workaround;
}
+bool GPU_clear_viewport_workaround()
+{
+ return GCaps.clear_viewport_workaround;
+}
+
bool GPU_compute_shader_support()
{
return GCaps.compute_shader_support;
@@ -162,6 +167,11 @@ int GPU_max_shader_storage_buffer_bindings()
return GCaps.max_shader_storage_buffer_bindings;
}
+int GPU_max_compute_shader_storage_blocks()
+{
+ return GCaps.max_compute_shader_storage_blocks;
+}
+
/** \} */
/* -------------------------------------------------------------------- */
diff --git a/source/blender/gpu/intern/gpu_capabilities_private.hh b/source/blender/gpu/intern/gpu_capabilities_private.hh
index 4a951eb8458..a17dbe7f8e6 100644
--- a/source/blender/gpu/intern/gpu_capabilities_private.hh
+++ b/source/blender/gpu/intern/gpu_capabilities_private.hh
@@ -36,6 +36,7 @@ struct GPUCapabilities {
int max_vertex_attribs = 0;
int max_varying_floats = 0;
int max_shader_storage_buffer_bindings = 0;
+ int max_compute_shader_storage_blocks = 0;
int extensions_len = 0;
const char *(*extension_get)(int);
@@ -51,6 +52,7 @@ struct GPUCapabilities {
bool use_main_context_workaround = false;
bool broken_amd_driver = false;
bool use_hq_normals_workaround = false;
+ bool clear_viewport_workaround = false;
/* Vulkan related workarounds. */
/* Metal related workarounds. */
diff --git a/source/blender/gpu/intern/gpu_codegen.cc b/source/blender/gpu/intern/gpu_codegen.cc
index 6f9f9454691..ba0e9d0310a 100644
--- a/source/blender/gpu/intern/gpu_codegen.cc
+++ b/source/blender/gpu/intern/gpu_codegen.cc
@@ -32,6 +32,7 @@
#include "GPU_vertex_format.h"
#include "BLI_sys_types.h" /* for intptr_t support */
+#include "BLI_vector.hh"
#include "gpu_codegen.h"
#include "gpu_material_library.h"
@@ -58,18 +59,27 @@ struct GPUCodegenCreateInfo : ShaderCreateInfo {
/** Duplicate attribute names to avoid reference the GPUNodeGraph directly. */
char attr_names[16][GPU_MAX_SAFE_ATTR_NAME + 1];
char var_names[16][8];
+ blender::Vector<std::array<char, 32>, 16> sampler_names;
+
+ /* Returns the appended name memory location */
+ const char *append_sampler_name(const char name[32])
+ {
+ auto index = sampler_names.append_and_get_index(std::array<char, 32>());
+ char *name_buffer = sampler_names[index].data();
+ memcpy(name_buffer, name, 32);
+ return name_buffer;
+ }
};
/** Optional generated interface. */
StageInterfaceInfo *interface_generated = nullptr;
/** Optional name buffer containing names referenced by StringRefNull. */
- NameBuffer *name_buffer = nullptr;
+ NameBuffer name_buffer;
GPUCodegenCreateInfo(const char *name) : ShaderCreateInfo(name){};
~GPUCodegenCreateInfo()
{
delete interface_generated;
- MEM_delete(name_buffer);
};
};
@@ -292,7 +302,6 @@ void GPUCodegen::generate_attribs()
GPUCodegenCreateInfo &info = *create_info;
- info.name_buffer = MEM_new<GPUCodegenCreateInfo::NameBuffer>("info.name_buffer");
info.interface_generated = new StageInterfaceInfo("codegen_iface", "var_attrs");
StageInterfaceInfo &iface = *info.interface_generated;
info.vertex_out(iface);
@@ -306,11 +315,11 @@ void GPUCodegen::generate_attribs()
BLI_assert_msg(0, "Too many attributes");
break;
}
- STRNCPY(info.name_buffer->attr_names[slot], attr->input_name);
- SNPRINTF(info.name_buffer->var_names[slot], "v%d", attr->id);
+ STRNCPY(info.name_buffer.attr_names[slot], attr->input_name);
+ SNPRINTF(info.name_buffer.var_names[slot], "v%d", attr->id);
- blender::StringRefNull attr_name = info.name_buffer->attr_names[slot];
- blender::StringRefNull var_name = info.name_buffer->var_names[slot];
+ blender::StringRefNull attr_name = info.name_buffer.attr_names[slot];
+ blender::StringRefNull var_name = info.name_buffer.var_names[slot];
eGPUType input_type, iface_type;
@@ -352,14 +361,19 @@ void GPUCodegen::generate_resources()
/* Textures. */
LISTBASE_FOREACH (GPUMaterialTexture *, tex, &graph.textures) {
if (tex->colorband) {
- info.sampler(0, ImageType::FLOAT_1D_ARRAY, tex->sampler_name, Frequency::BATCH);
+ const char *name = info.name_buffer.append_sampler_name(tex->sampler_name);
+ info.sampler(0, ImageType::FLOAT_1D_ARRAY, name, Frequency::BATCH);
}
else if (tex->tiled_mapping_name[0] != '\0') {
- info.sampler(0, ImageType::FLOAT_2D_ARRAY, tex->sampler_name, Frequency::BATCH);
- info.sampler(0, ImageType::FLOAT_1D_ARRAY, tex->tiled_mapping_name, Frequency::BATCH);
+ const char *name = info.name_buffer.append_sampler_name(tex->sampler_name);
+ info.sampler(0, ImageType::FLOAT_2D_ARRAY, name, Frequency::BATCH);
+
+ const char *name_mapping = info.name_buffer.append_sampler_name(tex->tiled_mapping_name);
+ info.sampler(0, ImageType::FLOAT_1D_ARRAY, name_mapping, Frequency::BATCH);
}
else {
- info.sampler(0, ImageType::FLOAT_2D, tex->sampler_name, Frequency::BATCH);
+ const char *name = info.name_buffer.append_sampler_name(tex->sampler_name);
+ info.sampler(0, ImageType::FLOAT_2D, name, Frequency::BATCH);
}
}
diff --git a/source/blender/gpu/intern/gpu_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_index_buffer.cc b/source/blender/gpu/intern/gpu_index_buffer.cc
index 54473b3a44d..146461d1dfb 100644
--- a/source/blender/gpu/intern/gpu_index_buffer.cc
+++ b/source/blender/gpu/intern/gpu_index_buffer.cc
@@ -232,6 +232,7 @@ void IndexBuf::init(uint indices_len, uint32_t *indices, uint min_index, uint ma
data_ = indices;
index_start_ = 0;
index_len_ = indices_len;
+ is_empty_ = min_index > max_index;
#if GPU_TRACK_INDEX_RANGE
/* Everything remains 32 bit while building to keep things simple.
diff --git a/source/blender/gpu/intern/gpu_index_buffer_private.hh b/source/blender/gpu/intern/gpu_index_buffer_private.hh
index 9323a81d393..6ce62ae852e 100644
--- a/source/blender/gpu/intern/gpu_index_buffer_private.hh
+++ b/source/blender/gpu/intern/gpu_index_buffer_private.hh
@@ -45,6 +45,8 @@ class IndexBuf {
bool is_init_ = false;
/** Is this object only a reference to a subrange of another IndexBuf. */
bool is_subrange_ = false;
+ /** True if buffer only contains restart indices. */
+ bool is_empty_ = false;
union {
/** Mapped buffer data. non-NULL indicates not yet sent to VRAM. */
@@ -61,9 +63,12 @@ class IndexBuf {
void init_subrange(IndexBuf *elem_src, uint start, uint length);
void init_build_on_device(uint index_len);
+ /* Returns render index count (not precise). */
uint32_t index_len_get() const
{
- return index_len_;
+ /* Return 0 to bypass drawing for index buffers full of restart indices.
+ * They can lead to graphical glitches on some systems. (See T96892) */
+ return is_empty_ ? 0 : index_len_;
}
/* Return size in byte of the drawable data buffer range. Actual buffer size might be bigger. */
size_t size_get() const
diff --git a/source/blender/gpu/intern/gpu_material.c b/source/blender/gpu/intern/gpu_material.c
index 9253aae8404..e7337073773 100644
--- a/source/blender/gpu/intern/gpu_material.c
+++ b/source/blender/gpu/intern/gpu_material.c
@@ -177,8 +177,8 @@ void GPU_material_free(ListBase *gpumaterial)
{
LISTBASE_FOREACH (LinkData *, link, gpumaterial) {
GPUMaterial *material = link->data;
- GPU_material_free_single(material);
DRW_deferred_shader_remove(material);
+ GPU_material_free_single(material);
}
BLI_freelistN(gpumaterial);
}
diff --git a/source/blender/gpu/intern/gpu_node_graph.c b/source/blender/gpu/intern/gpu_node_graph.c
index f1b36676712..1b76d6a2d70 100644
--- a/source/blender/gpu/intern/gpu_node_graph.c
+++ b/source/blender/gpu/intern/gpu_node_graph.c
@@ -337,6 +337,8 @@ static char attr_prefix_get(CustomDataType type)
switch (type) {
case CD_TANGENT:
return 't';
+ case CD_MCOL:
+ return 'c';
case CD_AUTO_FROM_NAME:
return 'a';
case CD_HAIRLENGTH:
diff --git a/source/blender/gpu/intern/gpu_shader_builtin.c b/source/blender/gpu/intern/gpu_shader_builtin.c
index 13238a03688..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",
@@ -367,6 +372,16 @@ GPUShader *GPU_shader_get_builtin_shader_with_config(eGPUBuiltinShader shader,
if (sh_cfg == GPU_SHADER_CFG_DEFAULT) {
if (stages->create_info != NULL) {
*sh_p = GPU_shader_create_from_info_name(stages->create_info);
+ if (ELEM(shader,
+ GPU_SHADER_3D_POLYLINE_CLIPPED_UNIFORM_COLOR,
+ GPU_SHADER_3D_POLYLINE_UNIFORM_COLOR,
+ GPU_SHADER_3D_POLYLINE_FLAT_COLOR,
+ GPU_SHADER_3D_POLYLINE_SMOOTH_COLOR)) {
+ /* Set a default value for `lineSmooth`.
+ * Ideally this value should be set by the caller. */
+ GPU_shader_bind(*sh_p);
+ GPU_shader_uniform_1i(*sh_p, "lineSmooth", 1);
+ }
}
else {
*sh_p = GPU_shader_create_from_arrays_named(
diff --git a/source/blender/gpu/intern/gpu_shader_dependency.cc b/source/blender/gpu/intern/gpu_shader_dependency.cc
index 76b27dfd52e..ac9f13a3343 100644
--- a/source/blender/gpu/intern/gpu_shader_dependency.cc
+++ b/source/blender/gpu/intern/gpu_shader_dependency.cc
@@ -8,6 +8,7 @@
* shader files.
*/
+#include <algorithm>
#include <iomanip>
#include <iostream>
#include <sstream>
@@ -99,6 +100,10 @@ struct GPUSource {
/* Limit to shared header files to avoid the temptation to use C++ syntax in .glsl files. */
if (filename.endswith(".h") || filename.endswith(".hh")) {
enum_preprocess();
+ quote_preprocess();
+ }
+ else {
+ check_no_quotes();
}
if (is_from_material_library()) {
@@ -175,6 +180,44 @@ struct GPUSource {
}
/**
+ * Some drivers completely forbid quote characters even in unused preprocessor directives.
+ * We fix the cases where we can't manually patch in `enum_preprocess()`.
+ * This check ensure none are present in non-patched sources. (see T97545)
+ */
+ void check_no_quotes()
+ {
+#ifdef DEBUG
+ int64_t pos = -1;
+ do {
+ pos = source.find('"', pos + 1);
+ if (pos == -1) {
+ break;
+ }
+ if (!is_in_comment(source, pos)) {
+ print_error(source, pos, "Quote characters are forbidden in GLSL files");
+ }
+ } while (true);
+#endif
+ }
+
+ /**
+ * Some drivers completely forbid string characters even in unused preprocessor directives.
+ * This fixes the cases we cannot manually patch: Shared headers #includes. (see T97545)
+ * TODO(fclem): This could be done during the datatoc step.
+ */
+ void quote_preprocess()
+ {
+ if (source.find_first_of('"') == -1) {
+ return;
+ }
+
+ processed_source = source;
+ std::replace(processed_source.begin(), processed_source.end(), '"', ' ');
+
+ source = processed_source.c_str();
+ }
+
+ /**
* Transform C,C++ enum declaration into GLSL compatible defines and constants:
*
* \code{.cpp}
@@ -283,6 +326,7 @@ struct GPUSource {
if (last_pos != 0) {
output += input.substr(last_pos);
}
+
processed_source = output;
source = processed_source.c_str();
};
diff --git a/source/blender/gpu/intern/gpu_vertex_buffer.cc b/source/blender/gpu/intern/gpu_vertex_buffer.cc
index 2974547c858..13f409cfba5 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;
diff --git a/source/blender/gpu/intern/gpu_vertex_format.cc b/source/blender/gpu/intern/gpu_vertex_format.cc
index a9ac191754b..59ae862aa51 100644
--- a/source/blender/gpu/intern/gpu_vertex_format.cc
+++ b/source/blender/gpu/intern/gpu_vertex_format.cc
@@ -49,7 +49,7 @@ void GPU_vertformat_copy(GPUVertFormat *dest, const GPUVertFormat *src)
memcpy(dest, src, sizeof(GPUVertFormat));
}
-static uint comp_sz(GPUVertCompType type)
+static uint comp_size(GPUVertCompType type)
{
#if TRUST_NO_ONE
assert(type <= GPU_COMP_F32); /* other types have irregular sizes (not bytes) */
@@ -58,12 +58,12 @@ static uint comp_sz(GPUVertCompType type)
return sizes[type];
}
-static uint attr_sz(const GPUVertAttr *a)
+static uint attr_size(const GPUVertAttr *a)
{
if (a->comp_type == GPU_COMP_I10) {
return 4; /* always packed as 10_10_10_2 */
}
- return a->comp_len * comp_sz(static_cast<GPUVertCompType>(a->comp_type));
+ return a->comp_len * comp_size(static_cast<GPUVertCompType>(a->comp_type));
}
static uint attr_align(const GPUVertAttr *a)
@@ -71,7 +71,7 @@ static uint attr_align(const GPUVertAttr *a)
if (a->comp_type == GPU_COMP_I10) {
return 4; /* always packed as 10_10_10_2 */
}
- uint c = comp_sz(static_cast<GPUVertCompType>(a->comp_type));
+ uint c = comp_size(static_cast<GPUVertCompType>(a->comp_type));
if (a->comp_len == 3 && c <= 2) {
return 4 * c; /* AMD HW can't fetch these well, so pad it out (other vendors too?) */
}
@@ -156,7 +156,7 @@ uint GPU_vertformat_attr_add(GPUVertFormat *format,
attr->comp_len = (comp_type == GPU_COMP_I10) ?
4 :
comp_len; /* system needs 10_10_10_2 to be 4 or BGRA */
- attr->sz = attr_sz(attr);
+ attr->size = attr_size(attr);
attr->offset = 0; /* offsets & stride are calculated later (during pack) */
attr->fetch_mode = fetch_mode;
@@ -294,13 +294,13 @@ uint padding(uint offset, uint alignment)
}
#if PACK_DEBUG
-static void show_pack(uint a_idx, uint sz, uint pad)
+static void show_pack(uint a_idx, uint size, uint pad)
{
const char c = 'A' + a_idx;
for (uint i = 0; i < pad; i++) {
putchar('-');
}
- for (uint i = 0; i < sz; i++) {
+ for (uint i = 0; i < size; i++) {
putchar(c);
}
}
@@ -310,10 +310,10 @@ void VertexFormat_pack(GPUVertFormat *format)
{
GPUVertAttr *a0 = &format->attrs[0];
a0->offset = 0;
- uint offset = a0->sz;
+ uint offset = a0->size;
#if PACK_DEBUG
- show_pack(0, a0->sz, 0);
+ show_pack(0, a0->size, 0);
#endif
for (uint a_idx = 1; a_idx < format->attr_len; a_idx++) {
@@ -321,10 +321,10 @@ void VertexFormat_pack(GPUVertFormat *format)
uint mid_padding = padding(offset, attr_align(a));
offset += mid_padding;
a->offset = offset;
- offset += a->sz;
+ offset += a->size;
#if PACK_DEBUG
- show_pack(a_idx, a->sz, mid_padding);
+ show_pack(a_idx, a->size, mid_padding);
#endif
}
diff --git a/source/blender/gpu/intern/gpu_viewport.c b/source/blender/gpu/intern/gpu_viewport.c
index a0efe12f523..c3118ca320c 100644
--- a/source/blender/gpu/intern/gpu_viewport.c
+++ b/source/blender/gpu/intern/gpu_viewport.c
@@ -21,6 +21,7 @@
#include "DNA_userdef_types.h"
#include "DNA_vec_types.h"
+#include "GPU_capabilities.h"
#include "GPU_framebuffer.h"
#include "GPU_immediate.h"
#include "GPU_matrix.h"
@@ -126,19 +127,23 @@ static void gpu_viewport_textures_create(GPUViewport *viewport)
if (viewport->color_render_tx[0] == NULL) {
viewport->color_render_tx[0] = GPU_texture_create_2d(
"dtxl_color", UNPACK2(size), 1, GPU_RGBA16F, NULL);
- GPU_texture_clear(viewport->color_render_tx[0], GPU_DATA_FLOAT, empty_pixel);
viewport->color_overlay_tx[0] = GPU_texture_create_2d(
"dtxl_color_overlay", UNPACK2(size), 1, GPU_SRGB8_A8, NULL);
- GPU_texture_clear(viewport->color_overlay_tx[0], GPU_DATA_FLOAT, empty_pixel);
+ if (GPU_clear_viewport_workaround()) {
+ GPU_texture_clear(viewport->color_render_tx[0], GPU_DATA_FLOAT, empty_pixel);
+ GPU_texture_clear(viewport->color_overlay_tx[0], GPU_DATA_FLOAT, empty_pixel);
+ }
}
if ((viewport->flag & GPU_VIEWPORT_STEREO) != 0 && viewport->color_render_tx[1] == NULL) {
viewport->color_render_tx[1] = GPU_texture_create_2d(
"dtxl_color_stereo", UNPACK2(size), 1, GPU_RGBA16F, NULL);
- GPU_texture_clear(viewport->color_render_tx[1], GPU_DATA_FLOAT, empty_pixel);
viewport->color_overlay_tx[1] = GPU_texture_create_2d(
"dtxl_color_overlay_stereo", UNPACK2(size), 1, GPU_SRGB8_A8, NULL);
- GPU_texture_clear(viewport->color_overlay_tx[1], GPU_DATA_FLOAT, empty_pixel);
+ if (GPU_clear_viewport_workaround()) {
+ GPU_texture_clear(viewport->color_render_tx[1], GPU_DATA_FLOAT, empty_pixel);
+ GPU_texture_clear(viewport->color_overlay_tx[1], GPU_DATA_FLOAT, empty_pixel);
+ }
}
/* Can be shared with GPUOffscreen. */
@@ -262,12 +267,15 @@ void GPU_viewport_stereo_composite(GPUViewport *viewport, Stereo3dFormat *stereo
return;
}
/* The composite framebuffer object needs to be created in the window context. */
- GPU_framebuffer_ensure_config(&viewport->stereo_comp_fb,
- {
- GPU_ATTACHMENT_NONE,
- GPU_ATTACHMENT_TEXTURE(viewport->color_overlay_tx[0]),
- GPU_ATTACHMENT_TEXTURE(viewport->color_render_tx[0]),
- });
+ GPU_framebuffer_ensure_config(
+ &viewport->stereo_comp_fb,
+ {
+ GPU_ATTACHMENT_NONE,
+ /* We need the sRGB attachment to be first for GL_FRAMEBUFFER_SRGB to be turned on.
+ * Note that this is the opposite of what the texture binding is. */
+ GPU_ATTACHMENT_TEXTURE(viewport->color_overlay_tx[0]),
+ GPU_ATTACHMENT_TEXTURE(viewport->color_render_tx[0]),
+ });
GPUVertFormat *vert_format = immVertexFormat();
uint pos = GPU_vertformat_attr_add(vert_format, "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
diff --git a/source/blender/gpu/opengl/gl_backend.cc b/source/blender/gpu/opengl/gl_backend.cc
index 610fd5d980f..17d9b392c69 100644
--- a/source/blender/gpu/opengl/gl_backend.cc
+++ b/source/blender/gpu/opengl/gl_backend.cc
@@ -419,6 +419,13 @@ static void detect_workarounds()
GCaps.shader_storage_buffer_objects_support = false;
}
+ /* Certain Intel based platforms don't clear the viewport textures. Always clearing leads to
+ * noticeable performance regressions. */
+ if (GPU_type_matches(
+ GPU_DEVICE_INTEL, static_cast<eGPUOSType>(GPU_OS_MAC | GPU_OS_UNIX), GPU_DRIVER_ANY)) {
+ GCaps.clear_viewport_workaround = true;
+ }
+
/* Metal-related Workarounds. */
/* Minimum Per-Vertex stride is 1 byte for OpenGL. */
@@ -503,6 +510,7 @@ void GLBackend::capabilities_init()
glGetIntegeri_v(GL_MAX_COMPUTE_WORK_GROUP_SIZE, 2, &GCaps.max_work_group_size[2]);
glGetIntegerv(GL_MAX_SHADER_STORAGE_BUFFER_BINDINGS,
&GCaps.max_shader_storage_buffer_bindings);
+ glGetIntegerv(GL_MAX_COMPUTE_SHADER_STORAGE_BLOCKS, &GCaps.max_compute_shader_storage_blocks);
}
GCaps.shader_storage_buffer_objects_support = GLEW_ARB_shader_storage_buffer_object;
/* GL specific capabilities. */
diff --git a/source/blender/gpu/opengl/gl_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/shaders/gpu_shader_codegen_lib.glsl b/source/blender/gpu/shaders/gpu_shader_codegen_lib.glsl
index 5c97eada77d..6091a5c834a 100644
--- a/source/blender/gpu/shaders/gpu_shader_codegen_lib.glsl
+++ b/source/blender/gpu/shaders/gpu_shader_codegen_lib.glsl
@@ -191,8 +191,8 @@ struct GlobalData {
vec3 N;
/** Geometric Normal. */
vec3 Ng;
- /** Surface default Tangent. */
- vec3 T;
+ /** Curve Tangent Space. */
+ vec3 curve_T, curve_B, curve_N;
/** Barycentric coordinates. */
vec2 barycentric_coords;
vec3 barycentric_dists;
diff --git a/source/blender/gpu/shaders/gpu_shader_image_overlays_stereo_merge_frag.glsl b/source/blender/gpu/shaders/gpu_shader_image_overlays_stereo_merge_frag.glsl
index 9b1e6fe9d23..522f6de169d 100644
--- a/source/blender/gpu/shaders/gpu_shader_image_overlays_stereo_merge_frag.glsl
+++ b/source/blender/gpu/shaders/gpu_shader_image_overlays_stereo_merge_frag.glsl
@@ -5,18 +5,6 @@
#define S3D_INTERLACE_COLUMN 1
#define S3D_INTERLACE_CHECKERBOARD 2
-/* Composite stereo textures */
-
-#ifndef USE_GPU_SHADER_CREATE_INFO
-uniform sampler2D imageTexture;
-uniform sampler2D overlayTexture;
-
-uniform int stereoDisplaySettings;
-
-layout(location = 0) out vec4 imageColor;
-layout(location = 1) out vec4 overlayColor;
-#endif
-
#define stereo_display_mode (stereoDisplaySettings & ((1 << 3) - 1))
#define stereo_interlace_mode ((stereoDisplaySettings >> 3) & ((1 << 3) - 1))
#define stereo_interlace_swap bool(stereoDisplaySettings >> 6)
diff --git a/source/blender/gpu/shaders/infos/gpu_shader_2D_image_overlays_stereo_merge_info.hh b/source/blender/gpu/shaders/infos/gpu_shader_2D_image_overlays_stereo_merge_info.hh
index 4b2d59cc159..3cacd0f4b8d 100644
--- a/source/blender/gpu/shaders/infos/gpu_shader_2D_image_overlays_stereo_merge_info.hh
+++ b/source/blender/gpu/shaders/infos/gpu_shader_2D_image_overlays_stereo_merge_info.hh
@@ -9,8 +9,8 @@
GPU_SHADER_CREATE_INFO(gpu_shader_2D_image_overlays_stereo_merge)
.vertex_in(0, Type::VEC2, "pos")
- .fragment_out(0, Type::VEC4, "imageColor")
- .fragment_out(1, Type::VEC4, "overlayColor")
+ .fragment_out(0, Type::VEC4, "overlayColor")
+ .fragment_out(1, Type::VEC4, "imageColor")
.sampler(0, ImageType::FLOAT_2D, "imageTexture")
.sampler(1, ImageType::FLOAT_2D, "overlayTexture")
.push_constant(Type::MAT4, "ModelViewProjectionMatrix")
diff --git a/source/blender/gpu/shaders/infos/gpu_shader_3D_depth_only_info.hh b/source/blender/gpu/shaders/infos/gpu_shader_3D_depth_only_info.hh
index e74e7df1a09..0a4da8d17fe 100644
--- a/source/blender/gpu/shaders/infos/gpu_shader_3D_depth_only_info.hh
+++ b/source/blender/gpu/shaders/infos/gpu_shader_3D_depth_only_info.hh
@@ -18,4 +18,5 @@ GPU_SHADER_CREATE_INFO(gpu_shader_3D_depth_only)
GPU_SHADER_CREATE_INFO(gpu_shader_3D_depth_only_clipped)
.additional_info("gpu_shader_3D_depth_only")
- .additional_info("gpu_clip_planes");
+ .additional_info("gpu_clip_planes")
+ .do_static_compilation(true);
diff --git a/source/blender/gpu/shaders/infos/gpu_shader_3D_flat_color_info.hh b/source/blender/gpu/shaders/infos/gpu_shader_3D_flat_color_info.hh
index d23c8985a5d..17d865dbaea 100644
--- a/source/blender/gpu/shaders/infos/gpu_shader_3D_flat_color_info.hh
+++ b/source/blender/gpu/shaders/infos/gpu_shader_3D_flat_color_info.hh
@@ -21,4 +21,5 @@ GPU_SHADER_CREATE_INFO(gpu_shader_3D_flat_color)
GPU_SHADER_CREATE_INFO(gpu_shader_3D_flat_color_clipped)
.additional_info("gpu_shader_3D_flat_color")
- .additional_info("gpu_clip_planes");
+ .additional_info("gpu_clip_planes")
+ .do_static_compilation(true);
diff --git a/source/blender/gpu/shaders/infos/gpu_shader_3D_image_info.hh b/source/blender/gpu/shaders/infos/gpu_shader_3D_image_info.hh
new file mode 100644
index 00000000000..94cf58933af
--- /dev/null
+++ b/source/blender/gpu/shaders/infos/gpu_shader_3D_image_info.hh
@@ -0,0 +1,20 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later
+ * Copyright 2022 Blender Foundation. All rights reserved. */
+
+/** \file
+ * \ingroup gpu
+ */
+
+#include "gpu_interface_info.hh"
+#include "gpu_shader_create_info.hh"
+
+GPU_SHADER_CREATE_INFO(gpu_shader_3D_image)
+ .vertex_in(0, Type::VEC3, "pos")
+ .vertex_in(1, Type::VEC2, "texCoord")
+ .vertex_out(smooth_tex_coord_interp_iface)
+ .fragment_out(0, Type::VEC4, "fragColor")
+ .push_constant(Type::MAT4, "ModelViewProjectionMatrix")
+ .sampler(0, ImageType::FLOAT_2D, "image")
+ .vertex_source("gpu_shader_3D_image_vert.glsl")
+ .fragment_source("gpu_shader_image_frag.glsl")
+ .do_static_compilation(true);
diff --git a/source/blender/gpu/shaders/infos/gpu_shader_3D_point_info.hh b/source/blender/gpu/shaders/infos/gpu_shader_3D_point_info.hh
index 1f9c0056f7d..895787e4f1e 100644
--- a/source/blender/gpu/shaders/infos/gpu_shader_3D_point_info.hh
+++ b/source/blender/gpu/shaders/infos/gpu_shader_3D_point_info.hh
@@ -41,4 +41,5 @@ GPU_SHADER_CREATE_INFO(gpu_shader_3D_point_uniform_size_uniform_color_aa)
GPU_SHADER_CREATE_INFO(gpu_shader_3D_point_uniform_size_uniform_color_aa_clipped)
.additional_info("gpu_shader_3D_point_uniform_size_uniform_color_aa")
- .additional_info("gpu_clip_planes");
+ .additional_info("gpu_clip_planes")
+ .do_static_compilation(true);
diff --git a/source/blender/gpu/shaders/infos/gpu_shader_3D_smooth_color_info.hh b/source/blender/gpu/shaders/infos/gpu_shader_3D_smooth_color_info.hh
index a0c21a4ac7c..4cabe110999 100644
--- a/source/blender/gpu/shaders/infos/gpu_shader_3D_smooth_color_info.hh
+++ b/source/blender/gpu/shaders/infos/gpu_shader_3D_smooth_color_info.hh
@@ -21,4 +21,5 @@ GPU_SHADER_CREATE_INFO(gpu_shader_3D_smooth_color)
GPU_SHADER_CREATE_INFO(gpu_shader_3D_smooth_color_clipped)
.additional_info("gpu_shader_3D_smooth_color")
- .additional_info("gpu_clip_planes");
+ .additional_info("gpu_clip_planes")
+ .do_static_compilation(true);
diff --git a/source/blender/gpu/shaders/material/gpu_shader_material_add_shader.glsl b/source/blender/gpu/shaders/material/gpu_shader_material_add_shader.glsl
index 99117400c57..3f42b6d9094 100644
--- a/source/blender/gpu/shaders/material/gpu_shader_material_add_shader.glsl
+++ b/source/blender/gpu/shaders/material/gpu_shader_material_add_shader.glsl
@@ -1,4 +1,4 @@
-void node_add_shader(Closure shader1, Closure shader2, out Closure shader)
+void node_add_shader(inout Closure shader1, inout Closure shader2, out Closure shader)
{
shader = closure_add(shader1, shader2);
}
diff --git a/source/blender/gpu/shaders/material/gpu_shader_material_eevee_specular.glsl b/source/blender/gpu/shaders/material/gpu_shader_material_eevee_specular.glsl
index c81880184e3..530907859e9 100644
--- a/source/blender/gpu/shaders/material/gpu_shader_material_eevee_specular.glsl
+++ b/source/blender/gpu/shaders/material/gpu_shader_material_eevee_specular.glsl
@@ -64,6 +64,8 @@ void node_eevee_specular(vec4 diffuse,
else {
result = closure_eval(diffuse_data, reflection_data);
}
- result = closure_add(result, closure_eval(emission_data));
- result = closure_add(result, closure_eval(transparency_data));
+ Closure emission_cl = closure_eval(emission_data);
+ Closure transparency_cl = closure_eval(transparency_data);
+ result = closure_add(result, emission_cl);
+ result = closure_add(result, transparency_cl);
}
diff --git a/source/blender/gpu/shaders/material/gpu_shader_material_geometry.glsl b/source/blender/gpu/shaders/material/gpu_shader_material_geometry.glsl
index 5e86a4577ee..4c9ff31622f 100644
--- a/source/blender/gpu/shaders/material/gpu_shader_material_geometry.glsl
+++ b/source/blender/gpu/shaders/material/gpu_shader_material_geometry.glsl
@@ -18,7 +18,7 @@ void node_geometry(vec3 orco,
true_normal = g_data.Ng;
if (g_data.is_strand) {
- tangent = g_data.T;
+ tangent = g_data.curve_T;
}
else {
tangent_orco_z(orco, orco);
diff --git a/source/blender/gpu/shaders/material/gpu_shader_material_hair.glsl b/source/blender/gpu/shaders/material/gpu_shader_material_hair.glsl
index 7bf8795495a..b24f9ab65f0 100644
--- a/source/blender/gpu/shaders/material/gpu_shader_material_hair.glsl
+++ b/source/blender/gpu/shaders/material/gpu_shader_material_hair.glsl
@@ -40,7 +40,7 @@ void node_bsdf_hair_principled(vec4 color,
hair_data.color = color.rgb;
hair_data.offset = offset;
hair_data.roughness = vec2(0.0);
- hair_data.T = g_data.T;
+ hair_data.T = g_data.curve_B;
result = closure_eval(hair_data);
}
diff --git a/source/blender/gpu/shaders/material/gpu_shader_material_hair_info.glsl b/source/blender/gpu/shaders/material/gpu_shader_material_hair_info.glsl
index 8e878b6e14b..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
@@ -5,14 +5,14 @@ void node_hair_info(float hair_length,
out float intercept,
out float out_length,
out float thickness,
- out vec3 tangent,
+ out vec3 normal,
out float random)
{
is_strand = float(g_data.is_strand);
intercept = g_data.hair_time;
thickness = g_data.hair_thickness;
out_length = hair_length;
- tangent = g_data.T;
+ normal = g_data.curve_N;
/* TODO: could be precomputed per strand instead. */
random = wang_hash_noise(uint(g_data.hair_strand_id));
}
diff --git a/source/blender/gpu/shaders/material/gpu_shader_material_mix_shader.glsl b/source/blender/gpu/shaders/material/gpu_shader_material_mix_shader.glsl
index c303d21d7c1..00cfba3ca12 100644
--- a/source/blender/gpu/shaders/material/gpu_shader_material_mix_shader.glsl
+++ b/source/blender/gpu/shaders/material/gpu_shader_material_mix_shader.glsl
@@ -1,4 +1,4 @@
-void node_mix_shader(float fac, Closure shader1, Closure shader2, out Closure shader)
+void node_mix_shader(float fac, inout Closure shader1, inout Closure shader2, out Closure shader)
{
shader = closure_mix(shader1, shader2, fac);
}
diff --git a/source/blender/gpu/shaders/material/gpu_shader_material_principled.glsl b/source/blender/gpu/shaders/material/gpu_shader_material_principled.glsl
index 033dc05c57d..2e695fa3e14 100644
--- a/source/blender/gpu/shaders/material/gpu_shader_material_principled.glsl
+++ b/source/blender/gpu/shaders/material/gpu_shader_material_principled.glsl
@@ -169,6 +169,8 @@ void node_bsdf_principled(vec4 base_color,
/* Un-optimized case. */
result = closure_eval(diffuse_data, reflection_data, clearcoat_data, refraction_data);
}
- result = closure_add(result, closure_eval(emission_data));
- result = closure_add(result, closure_eval(transparency_data));
+ Closure emission_cl = closure_eval(emission_data);
+ Closure transparency_cl = closure_eval(transparency_data);
+ result = closure_add(result, emission_cl);
+ result = closure_add(result, transparency_cl);
}
diff --git a/source/blender/gpu/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/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/jpeg.c b/source/blender/imbuf/intern/jpeg.c
index 80fcceb0aa7..cffa61977f7 100644
--- a/source/blender/imbuf/intern/jpeg.c
+++ b/source/blender/imbuf/intern/jpeg.c
@@ -286,8 +286,8 @@ static ImBuf *ibJpegImageFromCinfo(struct jpeg_decompress_struct *cinfo,
}
if (max_size > 0) {
- /* libjpeg can more quickly decompress while scaling down to 1/2, 1/4, 1/8,
- * while libjpeg-turbo can also do 3/8, 5/8, etc. But max is 1/8. */
+ /* `libjpeg` can more quickly decompress while scaling down to 1/2, 1/4, 1/8,
+ * while `libjpeg-turbo` can also do 3/8, 5/8, etc. But max is 1/8. */
float scale = (float)max_size / MAX2(cinfo->image_width, cinfo->image_height);
cinfo->scale_denom = 8;
cinfo->scale_num = max_uu(1, min_uu(8, ceill(scale * (float)cinfo->scale_denom)));
@@ -520,9 +520,9 @@ struct ImBuf *imb_thumbnail_jpeg(const char *filepath,
if ((fgetc(infile) == JPEG_MARKER_MSB) && (fgetc(infile) == JPEG_MARKER_SOI) &&
(fgetc(infile) == JPEG_MARKER_MSB) && (fgetc(infile) == JPEG_MARKER_APP1)) {
- /* This is a JPEG in Exif format (SOI + APP1), not JFIF (SOI + APP0). */
+ /* This is a JPEG in EXIF format (SOI + APP1), not JFIF (SOI + APP0). */
unsigned int i = JPEG_APP1_MAX;
- /* All Exif data is within this 64K header segment. Skip ahead until next SOI for thumbnail. */
+ /* All EXIF data is within this 64K header segment. Skip ahead until next SOI for thumbnail. */
while (!((fgetc(infile) == JPEG_MARKER_MSB) && (fgetc(infile) == JPEG_MARKER_SOI)) &&
!feof(infile) && i--)
;
diff --git a/source/blender/imbuf/intern/openexr/openexr_api.cpp b/source/blender/imbuf/intern/openexr/openexr_api.cpp
index 9948aaac5da..2281d8d85b3 100644
--- a/source/blender/imbuf/intern/openexr/openexr_api.cpp
+++ b/source/blender/imbuf/intern/openexr/openexr_api.cpp
@@ -1394,12 +1394,10 @@ static int imb_exr_split_channel_name(ExrChannel *echan, char *layname, char *pa
const char *name = echan->m->name.c_str();
const char *end = name + strlen(name);
const char *token;
- char tokenbuf[EXR_TOT_MAXNAME];
- int len;
/* some multilayers have the combined buffer with names A B G R saved */
if (name[1] == 0) {
- echan->chan_id = name[0];
+ echan->chan_id = BLI_toupper_ascii(name[0]);
layname[0] = '\0';
if (ELEM(name[0], 'R', 'G', 'B', 'A')) {
@@ -1416,13 +1414,17 @@ static int imb_exr_split_channel_name(ExrChannel *echan, char *layname, char *pa
}
/* last token is channel identifier */
- len = imb_exr_split_token(name, end, &token);
+ size_t len = imb_exr_split_token(name, end, &token);
if (len == 0) {
printf("multilayer read: bad channel name: %s\n", name);
return 0;
}
+
+ char channelname[EXR_TOT_MAXNAME];
+ BLI_strncpy(channelname, token, std::min(len + 1, sizeof(channelname)));
+
if (len == 1) {
- echan->chan_id = token[0];
+ echan->chan_id = BLI_toupper_ascii(channelname[0]);
}
else if (len > 1) {
bool ok = false;
@@ -1436,36 +1438,35 @@ static int imb_exr_split_channel_name(ExrChannel *echan, char *layname, char *pa
*
* Here we do some magic to distinguish such cases.
*/
- if (ELEM(token[1], 'X', 'Y', 'Z') || ELEM(token[1], 'R', 'G', 'B') ||
- ELEM(token[1], 'U', 'V', 'A')) {
- echan->chan_id = token[1];
+ const char chan_id = BLI_toupper_ascii(channelname[1]);
+ if (ELEM(chan_id, 'X', 'Y', 'Z', 'R', 'G', 'B', 'U', 'V', 'A')) {
+ echan->chan_id = chan_id;
ok = true;
}
}
- else if (BLI_strcaseeq(token, "red")) {
+ else if (BLI_strcaseeq(channelname, "red")) {
echan->chan_id = 'R';
ok = true;
}
- else if (BLI_strcaseeq(token, "green")) {
+ else if (BLI_strcaseeq(channelname, "green")) {
echan->chan_id = 'G';
ok = true;
}
- else if (BLI_strcaseeq(token, "blue")) {
+ else if (BLI_strcaseeq(channelname, "blue")) {
echan->chan_id = 'B';
ok = true;
}
- else if (BLI_strcaseeq(token, "alpha")) {
+ else if (BLI_strcaseeq(channelname, "alpha")) {
echan->chan_id = 'A';
ok = true;
}
- else if (BLI_strcaseeq(token, "depth")) {
+ else if (BLI_strcaseeq(channelname, "depth")) {
echan->chan_id = 'Z';
ok = true;
}
if (ok == false) {
- BLI_strncpy(tokenbuf, token, std::min(len + 1, EXR_TOT_MAXNAME));
- printf("multilayer read: unknown channel token: %s\n", tokenbuf);
+ printf("multilayer read: unknown channel token: %s\n", channelname);
return 0;
}
}
diff --git a/source/blender/imbuf/intern/util_gpu.c b/source/blender/imbuf/intern/util_gpu.c
index 5abbc84b0ea..8da9eb9ccf7 100644
--- a/source/blender/imbuf/intern/util_gpu.c
+++ b/source/blender/imbuf/intern/util_gpu.c
@@ -154,7 +154,7 @@ GPUTexture *IMB_touch_gpu_texture(
GPUTexture *tex;
if (layers > 0) {
- tex = GPU_texture_create_2d_array(name, w, h, layers, 1, tex_format, NULL);
+ tex = GPU_texture_create_2d_array(name, w, h, layers, 9999, tex_format, NULL);
}
else {
tex = GPU_texture_create_2d(name, w, h, 9999, tex_format, NULL);
diff --git a/source/blender/io/alembic/intern/abc_reader_mesh.cc b/source/blender/io/alembic/intern/abc_reader_mesh.cc
index 2d2dcfb1f42..8c62484028d 100644
--- a/source/blender/io/alembic/intern/abc_reader_mesh.cc
+++ b/source/blender/io/alembic/intern/abc_reader_mesh.cc
@@ -622,7 +622,7 @@ void AbcMeshReader::readObjectData(Main *bmain, const Alembic::Abc::ISampleSelec
if (read_mesh != mesh) {
/* XXX FIXME: after 2.80; mesh->flag isn't copied by #BKE_mesh_nomain_to_mesh(). */
/* read_mesh can be freed by BKE_mesh_nomain_to_mesh(), so get the flag before that happens. */
- short autosmooth = (read_mesh->flag & ME_AUTOSMOOTH);
+ uint16_t autosmooth = (read_mesh->flag & ME_AUTOSMOOTH);
BKE_mesh_nomain_to_mesh(read_mesh, mesh, m_object, &CD_MASK_EVERYTHING, true);
mesh->flag |= autosmooth;
}
diff --git a/source/blender/io/common/CMakeLists.txt b/source/blender/io/common/CMakeLists.txt
index b1add38bf01..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
@@ -19,11 +18,12 @@ set(SRC
intern/dupli_parent_finder.cc
intern/dupli_persistent_id.cc
intern/object_identifier.cc
- intern/string_utils.cc
+ intern/path_util.cc
IO_abstract_hierarchy_iterator.h
IO_dupli_persistent_id.hh
- IO_string_utils.hh
+ IO_path_util.hh
+ IO_path_util_types.h
IO_types.h
intern/dupli_parent_finder.hh
)
@@ -42,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_path_util.hh b/source/blender/io/common/IO_path_util.hh
new file mode 100644
index 00000000000..eeb5a9dbcfe
--- /dev/null
+++ b/source/blender/io/common/IO_path_util.hh
@@ -0,0 +1,29 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+#pragma once
+
+#include "BLI_set.hh"
+#include "BLI_string_ref.hh"
+
+#include "IO_path_util_types.h"
+
+namespace blender::io {
+
+/**
+ * Return a filepath relative to a destination directory, for use with
+ * exporters.
+ *
+ * When PATH_REFERENCE_COPY mode is used, the file path pair (source
+ * path, destination path) is added to the `copy_set`.
+ *
+ * Equivalent of bpy_extras.io_utils.path_reference.
+ */
+std::string path_reference(StringRefNull filepath,
+ StringRefNull base_src,
+ StringRefNull base_dst,
+ ePathReferenceMode mode,
+ Set<std::pair<std::string, std::string>> *copy_set = nullptr);
+
+/** Execute copying files of path_reference. */
+void path_reference_copy(const Set<std::pair<std::string, std::string>> &copy_set);
+
+} // namespace blender::io
diff --git a/source/blender/io/common/IO_path_util_types.h b/source/blender/io/common/IO_path_util_types.h
new file mode 100644
index 00000000000..0233f601a81
--- /dev/null
+++ b/source/blender/io/common/IO_path_util_types.h
@@ -0,0 +1,18 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+#pragma once
+
+/** Method used to reference paths. Equivalent of bpy_extras.io_utils.path_reference_mode. */
+typedef enum {
+ /** Use Relative paths with subdirectories only. */
+ PATH_REFERENCE_AUTO = 0,
+ /** Always write absolute paths. */
+ PATH_REFERENCE_ABSOLUTE = 1,
+ /** Write relative paths where possible. */
+ PATH_REFERENCE_RELATIVE = 2,
+ /** Match Absolute/Relative setting with input path. */
+ PATH_REFERENCE_MATCH = 3,
+ /** Filename only. */
+ PATH_REFERENCE_STRIP = 4,
+ /** Copy the file to the destination path. */
+ PATH_REFERENCE_COPY = 5,
+} ePathReferenceMode;
diff --git a/source/blender/io/common/intern/path_util.cc b/source/blender/io/common/intern/path_util.cc
new file mode 100644
index 00000000000..902cf552bf0
--- /dev/null
+++ b/source/blender/io/common/intern/path_util.cc
@@ -0,0 +1,82 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+#include "IO_path_util.hh"
+
+#include "BLI_fileops.h"
+#include "BLI_path_util.h"
+
+namespace blender::io {
+
+std::string path_reference(StringRefNull filepath,
+ StringRefNull base_src,
+ StringRefNull base_dst,
+ ePathReferenceMode mode,
+ Set<std::pair<std::string, std::string>> *copy_set)
+{
+ const bool is_relative = BLI_path_is_rel(filepath.c_str());
+ char filepath_abs[PATH_MAX];
+ BLI_strncpy(filepath_abs, filepath.c_str(), PATH_MAX);
+ BLI_path_abs(filepath_abs, base_src.c_str());
+ BLI_path_normalize(nullptr, filepath_abs);
+
+ /* Figure out final mode to be used. */
+ if (mode == PATH_REFERENCE_MATCH) {
+ mode = is_relative ? PATH_REFERENCE_RELATIVE : PATH_REFERENCE_ABSOLUTE;
+ }
+ else if (mode == PATH_REFERENCE_AUTO) {
+ mode = BLI_path_contains(base_dst.c_str(), filepath_abs) ? PATH_REFERENCE_RELATIVE :
+ PATH_REFERENCE_ABSOLUTE;
+ }
+ else if (mode == PATH_REFERENCE_COPY) {
+ char filepath_cpy[PATH_MAX];
+ BLI_path_join(
+ filepath_cpy, PATH_MAX, base_dst.c_str(), BLI_path_basename(filepath_abs), nullptr);
+ copy_set->add(std::make_pair(filepath_abs, filepath_cpy));
+ BLI_strncpy(filepath_abs, filepath_cpy, PATH_MAX);
+ mode = PATH_REFERENCE_RELATIVE;
+ }
+
+ /* Now we know the final path mode. */
+ if (mode == PATH_REFERENCE_ABSOLUTE) {
+ return filepath_abs;
+ }
+ else if (mode == PATH_REFERENCE_RELATIVE) {
+ char rel_path[PATH_MAX];
+ BLI_strncpy(rel_path, filepath_abs, PATH_MAX);
+ BLI_path_rel(rel_path, base_dst.c_str());
+ /* Can't always find relative path (e.g. between different drives). */
+ if (!BLI_path_is_rel(rel_path)) {
+ return filepath_abs;
+ }
+ return rel_path + 2; /* Skip blender's internal "//" prefix. */
+ }
+ else if (mode == PATH_REFERENCE_STRIP) {
+ return BLI_path_basename(filepath_abs);
+ }
+ BLI_assert_msg(false, "Invalid path reference mode");
+ return filepath_abs;
+}
+
+void path_reference_copy(const Set<std::pair<std::string, std::string>> &copy_set)
+{
+ for (const auto &copy : copy_set) {
+ const char *src = copy.first.c_str();
+ const char *dst = copy.second.c_str();
+ if (!BLI_exists(src)) {
+ fprintf(stderr, "Missing source file '%s', not copying\n", src);
+ continue;
+ }
+ if (0 == BLI_path_cmp_normalized(src, dst)) {
+ continue; /* Source and dest are the same. */
+ }
+ if (!BLI_make_existing_file(dst)) {
+ fprintf(stderr, "Can't make directory for '%s', not copying\n", dst);
+ continue;
+ }
+ if (!BLI_copy(src, dst)) {
+ fprintf(stderr, "Can't copy '%s' to '%s'\n", src, dst);
+ continue;
+ }
+ }
+}
+
+} // namespace blender::io
diff --git a/source/blender/io/usd/intern/usd_reader_mesh.cc b/source/blender/io/usd/intern/usd_reader_mesh.cc
index 328b4109616..e2562eca69b 100644
--- a/source/blender/io/usd/intern/usd_reader_mesh.cc
+++ b/source/blender/io/usd/intern/usd_reader_mesh.cc
@@ -200,7 +200,7 @@ void USDMeshReader::read_object_data(Main *bmain, const double motionSampleTime)
if (read_mesh != mesh) {
/* FIXME: after 2.80; `mesh->flag` isn't copied by #BKE_mesh_nomain_to_mesh() */
/* read_mesh can be freed by BKE_mesh_nomain_to_mesh(), so get the flag before that happens. */
- short autosmooth = (read_mesh->flag & ME_AUTOSMOOTH);
+ uint16_t autosmooth = (read_mesh->flag & ME_AUTOSMOOTH);
BKE_mesh_nomain_to_mesh(read_mesh, mesh, object_, &CD_MASK_MESH, true);
mesh->flag |= autosmooth;
}
diff --git a/source/blender/io/wavefront_obj/CMakeLists.txt b/source/blender/io/wavefront_obj/CMakeLists.txt
index e0fe7ed4992..f7958ef4ec6 100644
--- a/source/blender/io/wavefront_obj/CMakeLists.txt
+++ b/source/blender/io/wavefront_obj/CMakeLists.txt
@@ -15,6 +15,7 @@ set(INC
../../makesrna
../../nodes
../../windowmanager
+ ../../../../extern/fast_float
../../../../extern/fmtlib/include
../../../../intern/guardedalloc
)
@@ -35,6 +36,7 @@ set(SRC
importer/obj_import_mesh.cc
importer/obj_import_mtl.cc
importer/obj_import_nurbs.cc
+ importer/obj_import_string_utils.cc
importer/obj_importer.cc
IO_wavefront_obj.h
@@ -50,6 +52,7 @@ set(SRC
importer/obj_import_mtl.hh
importer/obj_import_nurbs.hh
importer/obj_import_objects.hh
+ importer/obj_import_string_utils.hh
importer/obj_importer.hh
)
@@ -69,6 +72,7 @@ blender_add_lib(bf_wavefront_obj "${SRC}" "${INC}" "${INC_SYS}" "${LIB}")
if(WITH_GTESTS)
set(TEST_SRC
tests/obj_exporter_tests.cc
+ tests/obj_import_string_utils_tests.cc
tests/obj_importer_tests.cc
tests/obj_mtl_parser_tests.cc
diff --git a/source/blender/io/wavefront_obj/IO_wavefront_obj.h b/source/blender/io/wavefront_obj/IO_wavefront_obj.h
index 8b71ec750c0..f7bf678310f 100644
--- a/source/blender/io/wavefront_obj/IO_wavefront_obj.h
+++ b/source/blender/io/wavefront_obj/IO_wavefront_obj.h
@@ -9,6 +9,7 @@
#include "BKE_context.h"
#include "BLI_path_util.h"
#include "DEG_depsgraph.h"
+#include "IO_path_util_types.h"
#ifdef __cplusplus
extern "C" {
@@ -37,6 +38,8 @@ static const int TOTAL_AXES = 3;
struct OBJExportParams {
/** Full path to the destination .OBJ file. */
char filepath[FILE_MAX];
+ /** Pretend that destination file folder is this, if non-empty. Used only for tests. */
+ char file_base_for_tests[FILE_MAX];
/** Full path to current blender file (used for comments in output). */
const char *blen_filepath;
@@ -62,6 +65,7 @@ struct OBJExportParams {
bool export_materials;
bool export_triangulated_mesh;
bool export_curves_as_nurbs;
+ ePathReferenceMode path_mode;
/* Grouping options. */
bool export_object_groups;
diff --git a/source/blender/io/wavefront_obj/exporter/obj_export_file_writer.cc b/source/blender/io/wavefront_obj/exporter/obj_export_file_writer.cc
index 194583e71fe..b027df73b1e 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
@@ -13,6 +13,8 @@
#include "BLI_path_util.h"
#include "BLI_task.hh"
+#include "IO_path_util.hh"
+
#include "obj_export_mesh.hh"
#include "obj_export_mtl.hh"
#include "obj_export_nurbs.hh"
@@ -530,7 +532,11 @@ void MTLWriter::write_bsdf_properties(const MTLMaterial &mtl_material)
void MTLWriter::write_texture_map(
const MTLMaterial &mtl_material,
- const Map<const eMTLSyntaxElement, tex_map_XX>::Item &texture_map)
+ const Map<const eMTLSyntaxElement, tex_map_XX>::Item &texture_map,
+ const char *blen_filedir,
+ const char *dest_dir,
+ ePathReferenceMode path_mode,
+ Set<std::pair<std::string, std::string>> &copy_set)
{
std::string options;
/* Option strings should have their own leading spaces. */
@@ -546,7 +552,11 @@ void MTLWriter::write_texture_map(
#define SYNTAX_DISPATCH(eMTLSyntaxElement) \
if (texture_map.key == eMTLSyntaxElement) { \
- fmt_handler_.write<eMTLSyntaxElement>(options, texture_map.value.image_path); \
+ std::string path = path_reference( \
+ texture_map.value.image_path.c_str(), blen_filedir, dest_dir, path_mode, &copy_set); \
+ /* Always emit forward slashes for cross-platform compatibility. */ \
+ std::replace(path.begin(), path.end(), '\\', '/'); \
+ fmt_handler_.write<eMTLSyntaxElement>(options, path.c_str()); \
return; \
}
@@ -561,25 +571,35 @@ void MTLWriter::write_texture_map(
BLI_assert(!"This map type was not written to the file.");
}
-void MTLWriter::write_materials()
+void MTLWriter::write_materials(const char *blen_filepath,
+ ePathReferenceMode path_mode,
+ const char *dest_dir)
{
if (mtlmaterials_.size() == 0) {
return;
}
+
+ char blen_filedir[PATH_MAX];
+ BLI_split_dir_part(blen_filepath, blen_filedir, PATH_MAX);
+ BLI_path_slash_native(blen_filedir);
+ BLI_path_normalize(nullptr, blen_filedir);
+
std::sort(mtlmaterials_.begin(),
mtlmaterials_.end(),
[](const MTLMaterial &a, const MTLMaterial &b) { return a.name < b.name; });
+ Set<std::pair<std::string, std::string>> copy_set;
for (const MTLMaterial &mtlmat : mtlmaterials_) {
fmt_handler_.write<eMTLSyntaxElement::string>("\n");
fmt_handler_.write<eMTLSyntaxElement::newmtl>(mtlmat.name);
write_bsdf_properties(mtlmat);
- for (const Map<const eMTLSyntaxElement, tex_map_XX>::Item &texture_map :
- mtlmat.texture_maps.items()) {
- if (!texture_map.value.image_path.empty()) {
- write_texture_map(mtlmat, texture_map);
+ for (const auto &tex : mtlmat.texture_maps.items()) {
+ if (tex.value.image_path.empty()) {
+ continue;
}
+ write_texture_map(mtlmat, tex, blen_filedir, dest_dir, path_mode, copy_set);
}
}
+ path_reference_copy(copy_set);
}
Vector<int> MTLWriter::add_materials(const OBJMesh &mesh_to_export)
diff --git a/source/blender/io/wavefront_obj/exporter/obj_export_file_writer.hh b/source/blender/io/wavefront_obj/exporter/obj_export_file_writer.hh
index 96f7d434338..77da7b44276 100644
--- a/source/blender/io/wavefront_obj/exporter/obj_export_file_writer.hh
+++ b/source/blender/io/wavefront_obj/exporter/obj_export_file_writer.hh
@@ -9,6 +9,7 @@
#include "DNA_meshdata_types.h"
#include "BLI_map.hh"
+#include "BLI_set.hh"
#include "BLI_vector.hh"
#include "IO_wavefront_obj.h"
@@ -181,7 +182,9 @@ class MTLWriter : NonMovable, NonCopyable {
* For consistency of output from run to run (useful for testing),
* the materials are sorted by name before writing.
*/
- void write_materials();
+ void write_materials(const char *blen_filepath,
+ ePathReferenceMode path_mode,
+ const char *dest_dir);
StringRefNull mtl_file_path() const;
/**
* Add the materials of the given object to #MTLWriter, de-duplicating
@@ -203,6 +206,10 @@ class MTLWriter : NonMovable, NonCopyable {
* Write a texture map in the form "map_XX -s 1. 1. 1. -o 0. 0. 0. [-bm 1.] path/to/image".
*/
void write_texture_map(const MTLMaterial &mtl_material,
- const Map<const eMTLSyntaxElement, tex_map_XX>::Item &texture_map);
+ const Map<const eMTLSyntaxElement, tex_map_XX>::Item &texture_map,
+ const char *blen_filedir,
+ const char *dest_dir,
+ ePathReferenceMode mode,
+ Set<std::pair<std::string, std::string>> &copy_set);
};
} // namespace blender::io::obj
diff --git a/source/blender/io/wavefront_obj/exporter/obj_export_mtl.cc b/source/blender/io/wavefront_obj/exporter/obj_export_mtl.cc
index c48d5a5f7f0..4ed148ec64e 100644
--- a/source/blender/io/wavefront_obj/exporter/obj_export_mtl.cc
+++ b/source/blender/io/wavefront_obj/exporter/obj_export_mtl.cc
@@ -113,8 +113,7 @@ static const bNode *get_node_of_type(Span<const nodes::OutputSocketRef *> socket
/**
* From a texture image shader node, get the image's filepath.
- * Returned filepath is stripped of initial "//". If packed image is found,
- * only the file "name" is returned.
+ * If packed image is found, only the file "name" is returned.
*/
static const char *get_image_filepath(const bNode *tex_node)
{
@@ -134,9 +133,6 @@ static const char *get_image_filepath(const bNode *tex_node)
"directory as the .MTL file.\n",
path);
}
- if (path[0] == '/' && path[1] == '/') {
- path += 2;
- }
return path;
}
diff --git a/source/blender/io/wavefront_obj/exporter/obj_exporter.cc b/source/blender/io/wavefront_obj/exporter/obj_exporter.cc
index 78b709c884a..b6e636b389d 100644
--- a/source/blender/io/wavefront_obj/exporter/obj_exporter.cc
+++ b/source/blender/io/wavefront_obj/exporter/obj_exporter.cc
@@ -284,7 +284,16 @@ void export_frame(Depsgraph *depsgraph, const OBJExportParams &export_params, co
std::move(exportable_as_mesh), *frame_writer, mtl_writer.get(), export_params);
if (mtl_writer) {
mtl_writer->write_header(export_params.blen_filepath);
- mtl_writer->write_materials();
+ char dest_dir[PATH_MAX];
+ if (export_params.file_base_for_tests[0] == '\0') {
+ BLI_split_dir_part(export_params.filepath, dest_dir, PATH_MAX);
+ }
+ else {
+ BLI_strncpy(dest_dir, export_params.file_base_for_tests, PATH_MAX);
+ }
+ BLI_path_slash_native(dest_dir);
+ BLI_path_normalize(nullptr, dest_dir);
+ mtl_writer->write_materials(export_params.blen_filepath, export_params.path_mode, dest_dir);
}
write_nurbs_curve_objects(std::move(exportable_as_nurbs), *frame_writer);
}
diff --git a/source/blender/io/wavefront_obj/importer/obj_import_file_reader.cc b/source/blender/io/wavefront_obj/importer/obj_import_file_reader.cc
index be322f49840..fa89b49b605 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 {
diff --git a/source/blender/io/wavefront_obj/importer/obj_import_mesh.cc b/source/blender/io/wavefront_obj/importer/obj_import_mesh.cc
index fc40333c24d..8d560bd2c8c 100644
--- a/source/blender/io/wavefront_obj/importer/obj_import_mesh.cc
+++ b/source/blender/io/wavefront_obj/importer/obj_import_mesh.cc
@@ -62,7 +62,7 @@ Object *MeshFromGeometry::create_mesh(Main *bmain,
transform_object(obj, import_params);
/* FIXME: after 2.80; `mesh->flag` isn't copied by #BKE_mesh_nomain_to_mesh() */
- const short autosmooth = (mesh->flag & ME_AUTOSMOOTH);
+ const uint16_t autosmooth = (mesh->flag & ME_AUTOSMOOTH);
Mesh *dst = static_cast<Mesh *>(obj->data);
BKE_mesh_nomain_to_mesh(mesh, dst, obj, &CD_MASK_EVERYTHING, true);
dst->flag |= autosmooth;
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/common/intern/string_utils.cc b/source/blender/io/wavefront_obj/importer/obj_import_string_utils.cc
index 3a12250e14b..c60306c8375 100644
--- a/source/blender/io/common/intern/string_utils.cc
+++ b/source/blender/io/wavefront_obj/importer/obj_import_string_utils.cc
@@ -1,6 +1,6 @@
/* SPDX-License-Identifier: GPL-2.0-or-later */
-#include "IO_string_utils.hh"
+#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,
@@ -11,7 +11,7 @@
#include "fast_float.h"
#include <charconv>
-namespace blender::io {
+namespace blender::io::obj {
StringRef read_next_line(StringRef &buffer)
{
@@ -96,4 +96,4 @@ StringRef parse_int(StringRef str, int fallback, int &dst, bool skip_space)
return StringRef(res.ptr, str.end());
}
-} // namespace blender::io
+} // namespace blender::io::obj
diff --git a/source/blender/io/common/IO_string_utils.hh b/source/blender/io/wavefront_obj/importer/obj_import_string_utils.hh
index 25f1f01c6ed..532224569ac 100644
--- a/source/blender/io/common/IO_string_utils.hh
+++ b/source/blender/io/wavefront_obj/importer/obj_import_string_utils.hh
@@ -5,10 +5,13 @@
#include "BLI_string_ref.hh"
/*
- * Various text parsing utilities commonly used by text-based input formats.
+ * 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).
*/
-namespace blender::io {
+namespace blender::io::obj {
/**
* Fetches next line from an input string buffer.
@@ -18,7 +21,7 @@ namespace blender::io {
* the input line.
*
* Note that backslash (\) character is treated as a line
- * continuation, similar to OBJ file format or a C preprocessor.
+ * continuation.
*/
StringRef read_next_line(StringRef &buffer);
@@ -66,4 +69,4 @@ StringRef parse_float(StringRef str, float fallback, float &dst, bool skip_space
*/
StringRef parse_floats(StringRef str, float fallback, float *dst, int count);
-} // namespace blender::io
+} // namespace blender::io::obj
diff --git a/source/blender/io/wavefront_obj/tests/obj_exporter_tests.cc b/source/blender/io/wavefront_obj/tests/obj_exporter_tests.cc
index f74bfc155dd..8c49af90a82 100644
--- a/source/blender/io/wavefront_obj/tests/obj_exporter_tests.cc
+++ b/source/blender/io/wavefront_obj/tests/obj_exporter_tests.cc
@@ -11,12 +11,15 @@
#include "BKE_appdir.h"
#include "BKE_blender_version.h"
+#include "BKE_main.h"
#include "BLI_fileops.h"
#include "BLI_index_range.hh"
#include "BLI_string_utf8.h"
#include "BLI_vector.hh"
+#include "BLO_readfile.h"
+
#include "DEG_depsgraph.h"
#include "obj_export_file_writer.hh"
@@ -259,11 +262,12 @@ class obj_exporter_regression_test : public obj_exporter_test {
std::string tempdir = std::string(BKE_tempdir_base());
std::string out_file_path = tempdir + BLI_path_basename(golden_obj.c_str());
strncpy(params.filepath, out_file_path.c_str(), FILE_MAX - 1);
- params.blen_filepath = blendfile.c_str();
+ params.blen_filepath = bfile->main->filepath;
+ std::string golden_file_path = blender::tests::flags_test_asset_dir() + "/" + golden_obj;
+ BLI_split_dir_part(golden_file_path.c_str(), params.file_base_for_tests, PATH_MAX);
export_frame(depsgraph, params, out_file_path.c_str());
std::string output_str = read_temp_file_in_string(out_file_path);
- std::string golden_file_path = blender::tests::flags_test_asset_dir() + "/" + golden_obj;
std::string golden_str = read_temp_file_in_string(golden_file_path);
bool are_equal = strings_equal_after_first_lines(output_str, golden_str);
if (save_failing_test_output && !are_equal) {
@@ -432,19 +436,26 @@ TEST_F(obj_exporter_regression_test, cubes_positioned)
_export.params);
}
-/* Note: texture paths in the resulting mtl file currently are always
- * as they are stored in the source .blend file; not relative to where
- * the export is done. When that is properly fixed, the expected .mtl
- * file should be updated. */
-TEST_F(obj_exporter_regression_test, cubes_with_textures)
+TEST_F(obj_exporter_regression_test, cubes_with_textures_strip)
{
OBJExportParamsDefault _export;
+ _export.params.path_mode = PATH_REFERENCE_STRIP;
compare_obj_export_to_golden("io_tests/blend_geometry/cubes_with_textures.blend",
"io_tests/obj/cubes_with_textures.obj",
"io_tests/obj/cubes_with_textures.mtl",
_export.params);
}
+TEST_F(obj_exporter_regression_test, cubes_with_textures_relative)
+{
+ OBJExportParamsDefault _export;
+ _export.params.path_mode = PATH_REFERENCE_RELATIVE;
+ compare_obj_export_to_golden("io_tests/blend_geometry/cubes_with_textures.blend",
+ "io_tests/obj/cubes_with_textures_rel.obj",
+ "io_tests/obj/cubes_with_textures_rel.mtl",
+ _export.params);
+}
+
TEST_F(obj_exporter_regression_test, suzanne_all_data)
{
OBJExportParamsDefault _export;
diff --git a/source/blender/io/wavefront_obj/tests/obj_exporter_tests.hh b/source/blender/io/wavefront_obj/tests/obj_exporter_tests.hh
index 6a821e0b1bf..ef27a65fb4b 100644
--- a/source/blender/io/wavefront_obj/tests/obj_exporter_tests.hh
+++ b/source/blender/io/wavefront_obj/tests/obj_exporter_tests.hh
@@ -11,6 +11,7 @@ struct OBJExportParamsDefault {
OBJExportParamsDefault()
{
params.filepath[0] = '\0';
+ params.file_base_for_tests[0] = '\0';
params.blen_filepath = "";
params.export_animation = false;
params.start_frame = 0;
@@ -26,6 +27,7 @@ struct OBJExportParamsDefault {
params.export_uv = true;
params.export_normals = true;
params.export_materials = true;
+ params.path_mode = PATH_REFERENCE_AUTO;
params.export_triangulated_mesh = false;
params.export_curves_as_nurbs = false;
diff --git a/source/blender/io/common/intern/string_utils_test.cc b/source/blender/io/wavefront_obj/tests/obj_import_string_utils_tests.cc
index a78bd7ab8a3..addb1fa473e 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,7 @@ TEST(string_utils, read_next_line)
EXPECT_TRUE(s.is_empty());
}
-TEST(string_utils, drop_whitespace)
+TEST(obj_import_string_utils, drop_whitespace)
{
/* Empty */
EXPECT_STRREF_EQ("", drop_whitespace(""));
@@ -39,7 +39,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 +59,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 +75,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 +97,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 +115,4 @@ TEST(string_utils, parse_float_invalid)
EXPECT_EQ(val, -4.0f);
}
-} // namespace blender::io
+} // namespace blender::io::obj
diff --git a/source/blender/makesdna/DNA_brush_enums.h b/source/blender/makesdna/DNA_brush_enums.h
index 1d5f1351de0..f409d1c0442 100644
--- a/source/blender/makesdna/DNA_brush_enums.h
+++ b/source/blender/makesdna/DNA_brush_enums.h
@@ -618,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_curves_types.h b/source/blender/makesdna/DNA_curves_types.h
index e2ad5d38bbc..2388f04cc39 100644
--- a/source/blender/makesdna/DNA_curves_types.h
+++ b/source/blender/makesdna/DNA_curves_types.h
@@ -110,11 +110,11 @@ typedef struct CurvesGeometry {
/**
* The total number of control points in all curves.
*/
- int point_size;
+ int point_num;
/**
* The number of curves in the data-block.
*/
- int curve_size;
+ int curve_num;
/**
* Runtime data for curves, stored as a pointer to allow defining this as a C++ class.
diff --git a/source/blender/makesdna/DNA_image_types.h b/source/blender/makesdna/DNA_image_types.h
index 4e66e2446f0..80f592bb66d 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;
diff --git a/source/blender/makesdna/DNA_mesh_types.h b/source/blender/makesdna/DNA_mesh_types.h
index 97e057361c1..4a57f60be26 100644
--- a/source/blender/makesdna/DNA_mesh_types.h
+++ b/source/blender/makesdna/DNA_mesh_types.h
@@ -280,7 +280,7 @@ typedef struct Mesh {
/** Various flags used when editing the mesh. */
char editflag;
/** Mostly more flags used when editing or displaying the mesh. */
- unsigned short flag;
+ uint16_t flag;
/**
* The angle for auto smooth in radians. `M_PI` (180 degrees) causes all edges to be smooth.
diff --git a/source/blender/makesdna/DNA_userdef_types.h b/source/blender/makesdna/DNA_userdef_types.h
index a8fa1fd4271..275a89ec680 100644
--- a/source/blender/makesdna/DNA_userdef_types.h
+++ b/source/blender/makesdna/DNA_userdef_types.h
@@ -652,7 +652,7 @@ typedef struct UserDef_Experimental {
char use_override_templates;
char enable_eevee_next;
char use_sculpt_texture_paint;
- char _pad0[1];
+ char use_draw_manager_acquire_lock;
/** `makesdna` does not allow empty structs. */
} UserDef_Experimental;
diff --git a/source/blender/makesdna/intern/dna_rename_defs.h b/source/blender/makesdna/intern/dna_rename_defs.h
index 281aeae7a60..f25ff5fbbb8 100644
--- a/source/blender/makesdna/intern/dna_rename_defs.h
+++ b/source/blender/makesdna/intern/dna_rename_defs.h
@@ -61,6 +61,8 @@ DNA_STRUCT_RENAME_ELEM(Curve, ext1, extrude)
DNA_STRUCT_RENAME_ELEM(Curve, ext2, bevel_radius)
DNA_STRUCT_RENAME_ELEM(Curve, len_wchar, len_char32)
DNA_STRUCT_RENAME_ELEM(Curve, width, offset)
+DNA_STRUCT_RENAME_ELEM(CurvesGeometry, curve_size, curve_num)
+DNA_STRUCT_RENAME_ELEM(CurvesGeometry, point_size, point_num)
DNA_STRUCT_RENAME_ELEM(CustomDataExternal, filename, filepath)
DNA_STRUCT_RENAME_ELEM(Editing, over_border, overlay_frame_rect)
DNA_STRUCT_RENAME_ELEM(Editing, over_cfra, overlay_frame_abs)
diff --git a/source/blender/makesrna/intern/rna_ID.c b/source/blender/makesrna/intern/rna_ID.c
index b65e08311fe..b0488bbfa7a 100644
--- a/source/blender/makesrna/intern/rna_ID.c
+++ b/source/blender/makesrna/intern/rna_ID.c
@@ -1976,7 +1976,7 @@ static void rna_def_ID(BlenderRNA *brna)
RNA_def_property_ui_text(
prop,
"Extra User",
- "Indicates wether an extra user is set or not (mainly for internal/debug usages)");
+ "Indicates whether an extra user is set or not (mainly for internal/debug usages)");
RNA_def_property_boolean_funcs(prop, NULL, "rna_ID_extra_user_set");
prop = RNA_def_property(srna, "is_embedded_data", PROP_BOOLEAN, PROP_NONE);
diff --git a/source/blender/makesrna/intern/rna_brush.c b/source/blender/makesrna/intern/rna_brush.c
index f7edba24dea..4767ef2c017 100644
--- a/source/blender/makesrna/intern/rna_brush.c
+++ b/source/blender/makesrna/intern/rna_brush.c
@@ -1951,7 +1951,7 @@ static void rna_def_curves_sculpt_options(BlenderRNA *brna)
prop = RNA_def_property(srna, "add_amount", PROP_INT, PROP_NONE);
RNA_def_property_range(prop, 1, INT32_MAX);
- RNA_def_property_ui_text(prop, "Add Amount", "Number of curves added by the Add brush");
+ RNA_def_property_ui_text(prop, "Count", "Number of curves added by the Add brush");
prop = RNA_def_property(srna, "points_per_curve", PROP_INT, PROP_NONE);
RNA_def_property_range(prop, 2, INT32_MAX);
@@ -1975,6 +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(
diff --git a/source/blender/makesrna/intern/rna_curves.c b/source/blender/makesrna/intern/rna_curves.c
index 2dc568d0b8a..60530eb8bf9 100644
--- a/source/blender/makesrna/intern/rna_curves.c
+++ b/source/blender/makesrna/intern/rna_curves.c
@@ -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,7 +47,7 @@ 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);
}
@@ -222,7 +222,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 +230,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 +239,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);
diff --git a/source/blender/makesrna/intern/rna_gpencil_modifier.c b/source/blender/makesrna/intern/rna_gpencil_modifier.c
index 08986afe15e..05e8d5406b4 100644
--- a/source/blender/makesrna/intern/rna_gpencil_modifier.c
+++ b/source/blender/makesrna/intern/rna_gpencil_modifier.c
@@ -233,8 +233,8 @@ static const EnumPropertyItem gpencil_envelope_mode_items[] = {
{0, NULL, 0, NULL, NULL},
};
static const EnumPropertyItem modifier_noise_random_mode_items[] = {
- {GP_NOISE_RANDOM_STEP, "STEP", 0, "Steps", "Apply random every N steps"},
- {GP_NOISE_RANDOM_KEYFRAME, "KEYFRAME", 0, "On Keyframes", "Apply random every keyframe"},
+ {GP_NOISE_RANDOM_STEP, "STEP", 0, "Steps", "Randomize every number of frames"},
+ {GP_NOISE_RANDOM_KEYFRAME, "KEYFRAME", 0, "Keyframes", "Randomize on keyframes only"},
{0, NULL, 0, NULL, NULL},
};
#endif
@@ -929,8 +929,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 interval between randomization steps");
RNA_def_property_update(prop, 0, "rna_GpencilModifier_update");
prop = RNA_def_property(srna, "invert_layers", PROP_BOOLEAN, PROP_NONE);
@@ -967,7 +966,7 @@ static void rna_def_modifier_gpencilnoise(BlenderRNA *brna)
prop = RNA_def_property(srna, "random_mode", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_sdna(prop, NULL, "noise_mode");
RNA_def_property_enum_items(prop, modifier_noise_random_mode_items);
- RNA_def_property_ui_text(prop, "Mode", "How the random changes are applied");
+ RNA_def_property_ui_text(prop, "Mode", "Where to perform randomization");
RNA_def_property_update(prop, 0, "rna_GpencilModifier_update");
RNA_define_lib_overridable(false);
diff --git a/source/blender/makesrna/intern/rna_image.c b/source/blender/makesrna/intern/rna_image.c
index bd3b03add95..81708ac8e65 100644
--- a/source/blender/makesrna/intern/rna_image.c
+++ b/source/blender/makesrna/intern/rna_image.c
@@ -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 897573f9fd9..7bd2040dab0 100644
--- a/source/blender/makesrna/intern/rna_image_api.c
+++ b/source/blender/makesrna/intern/rna_image_api.c
@@ -161,9 +161,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 {
diff --git a/source/blender/makesrna/intern/rna_modifier.c b/source/blender/makesrna/intern/rna_modifier.c
index 456f774648a..6dd7fe53774 100644
--- a/source/blender/makesrna/intern/rna_modifier.c
+++ b/source/blender/makesrna/intern/rna_modifier.c
@@ -130,7 +130,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,
@@ -6991,7 +6991,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_nodetree.c b/source/blender/makesrna/intern/rna_nodetree.c
index 4cd12acd038..9b9afadbd05 100644
--- a/source/blender/makesrna/intern/rna_nodetree.c
+++ b/source/blender/makesrna/intern/rna_nodetree.c
@@ -12369,7 +12369,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_space.c b/source/blender/makesrna/intern/rna_space.c
index 4a7e16e50fa..0907aa884e6 100644
--- a/source/blender/makesrna/intern/rna_space.c
+++ b/source/blender/makesrna/intern/rna_space.c
@@ -3292,7 +3292,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,
diff --git a/source/blender/makesrna/intern/rna_userdef.c b/source/blender/makesrna/intern/rna_userdef.c
index 5ac324b3627..b3d4ae80713 100644
--- a/source/blender/makesrna/intern/rna_userdef.c
+++ b/source/blender/makesrna/intern/rna_userdef.c
@@ -6424,6 +6424,11 @@ static void rna_def_userdef_experimental(BlenderRNA *brna)
RNA_def_property_boolean_sdna(prop, NULL, "use_sculpt_texture_paint", 1);
RNA_def_property_ui_text(prop, "Sculpt Texture Paint", "Use texture painting in Sculpt Mode");
+ prop = RNA_def_property(srna, "use_draw_manager_acquire_lock", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "use_draw_manager_acquire_lock", 1);
+ RNA_def_property_ui_text(
+ prop, "Draw Manager Locking", "Don't lock UI during background rendering");
+
prop = RNA_def_property(srna, "use_extended_asset_browser", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_ui_text(prop,
"Extended Asset Browser",
diff --git a/source/blender/makesrna/intern/rna_xr.c b/source/blender/makesrna/intern/rna_xr.c
index a04b29b8815..696d2d0f31d 100644
--- a/source/blender/makesrna/intern/rna_xr.c
+++ b/source/blender/makesrna/intern/rna_xr.c
@@ -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_nodes.cc b/source/blender/modifiers/intern/MOD_nodes.cc
index 21041e8e1b2..cdf16d813f3 100644
--- a/source/blender/modifiers/intern/MOD_nodes.cc
+++ b/source/blender/modifiers/intern/MOD_nodes.cc
@@ -985,17 +985,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);
}
@@ -1799,7 +1798,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_particlesystem.c b/source/blender/modifiers/intern/MOD_particlesystem.cc
index 032227307e7..0f75038189a 100644
--- a/source/blender/modifiers/intern/MOD_particlesystem.c
+++ b/source/blender/modifiers/intern/MOD_particlesystem.cc
@@ -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_util.h b/source/blender/modifiers/intern/MOD_util.h
index aef254b1103..c37d6a3f2c1 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 \ No newline at end of file
diff --git a/source/blender/nodes/NOD_geometry_nodes_eval_log.hh b/source/blender/nodes/NOD_geometry_nodes_eval_log.hh
index 1ad859aa47b..4fbf5192222 100644
--- a/source/blender/nodes/NOD_geometry_nodes_eval_log.hh
+++ b/source/blender/nodes/NOD_geometry_nodes_eval_log.hh
@@ -103,16 +103,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/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 5b7211e44b4..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`.
*/
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..18cf005c965 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(
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 471d6af560f..d9cc8bcf023 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_curve_resample.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_curve_resample.cc
@@ -1,12 +1,7 @@
/* SPDX-License-Identifier: GPL-2.0-or-later */
-#include "BLI_array.hh"
-#include "BLI_index_mask_ops.hh"
-#include "BLI_length_parameterize.hh"
-#include "BLI_task.hh"
-#include "BLI_timeit.hh"
+#include "GEO_resample_curves.hh"
-#include "BKE_attribute_math.hh"
#include "BKE_curves.hh"
#include "UI_interface.h"
@@ -56,495 +51,6 @@ static void node_update(bNodeTree *ntree, bNode *node)
nodeSetSocketAvailability(ntree, length_socket, mode == GEO_NODE_CURVE_RESAMPLE_LENGTH);
}
-/**
- * Return true if the attribute should be copied/interpolated to the result curves.
- * Don't output attributes that correspond to curve types that have no curves in the result.
- */
-static bool interpolate_attribute_to_curves(const AttributeIDRef &attribute_id,
- const std::array<int, CURVE_TYPES_NUM> &type_counts)
-{
- if (!attribute_id.is_named()) {
- return true;
- }
- if (ELEM(attribute_id.name(),
- "handle_type_left",
- "handle_type_right",
- "handle_left",
- "handle_right")) {
- return type_counts[CURVE_TYPE_BEZIER] != 0;
- }
- if (ELEM(attribute_id.name(), "nurbs_weight")) {
- return type_counts[CURVE_TYPE_NURBS] != 0;
- }
- return true;
-}
-
-/**
- * Return true if the attribute should be copied to poly curves.
- */
-static bool interpolate_attribute_to_poly_curve(const AttributeIDRef &attribute_id)
-{
- static const Set<StringRef> no_interpolation{{
- "handle_type_left",
- "handle_type_right",
- "handle_position_right",
- "handle_position_left",
- "nurbs_weight",
- }};
- return !(attribute_id.is_named() && no_interpolation.contains(attribute_id.name()));
-}
-
-/**
- * Retrieve spans from source and result attributes.
- */
-static void retrieve_attribute_spans(const Span<AttributeIDRef> ids,
- const CurveComponent &src_component,
- CurveComponent &dst_component,
- Vector<GSpan> &src,
- Vector<GMutableSpan> &dst,
- Vector<OutputAttribute> &dst_attributes)
-{
- for (const int i : ids.index_range()) {
- GVArray src_attribute = src_component.attribute_try_get_for_read(ids[i], ATTR_DOMAIN_POINT);
- BLI_assert(src_attribute);
- src.append(src_attribute.get_internal_span());
-
- const CustomDataType data_type = bke::cpp_type_to_custom_data_type(src_attribute.type());
- OutputAttribute dst_attribute = dst_component.attribute_try_get_for_output_only(
- ids[i], ATTR_DOMAIN_POINT, data_type);
- dst.append(dst_attribute.as_span());
- dst_attributes.append(std::move(dst_attribute));
- }
-}
-
-struct AttributesForInterpolation : NonCopyable, NonMovable {
- Vector<GSpan> src;
- Vector<GMutableSpan> dst;
-
- Vector<OutputAttribute> dst_attributes;
-
- Vector<GSpan> src_no_interpolation;
- Vector<GMutableSpan> dst_no_interpolation;
-};
-
-/**
- * Gather a set of all generic attribute IDs to copy to the result curves.
- */
-static void gather_point_attributes_to_interpolate(const CurveComponent &src_component,
- CurveComponent &dst_component,
- AttributesForInterpolation &result)
-{
- const Curves &dst_curves_id = *dst_component.get_for_read();
- const bke::CurvesGeometry &dst_curves = bke::CurvesGeometry::wrap(dst_curves_id.geometry);
-
- VectorSet<AttributeIDRef> ids;
- VectorSet<AttributeIDRef> ids_no_interpolation;
- src_component.attribute_foreach(
- [&](const AttributeIDRef &id, const AttributeMetaData meta_data) {
- if (meta_data.domain != ATTR_DOMAIN_POINT) {
- return true;
- }
- if (!interpolate_attribute_to_curves(id, dst_curves.curve_type_counts())) {
- return true;
- }
- if (interpolate_attribute_to_poly_curve(id)) {
- ids.add_new(id);
- }
- else {
- ids_no_interpolation.add_new(id);
- }
- return true;
- });
-
- /* Position is handled differently since it has non-generic interpolation for Bezier
- * curves and because the evaluated positions are cached for each evaluated point. */
- ids.remove_contained("position");
-
- retrieve_attribute_spans(
- ids, src_component, dst_component, result.src, result.dst, result.dst_attributes);
-
- /* Attributes that aren't interpolated like Bezier handles still have to be be copied
- * to the result when there are any unselected curves of the corresponding type. */
- retrieve_attribute_spans(ids_no_interpolation,
- src_component,
- dst_component,
- result.src_no_interpolation,
- result.dst_no_interpolation,
- result.dst_attributes);
-}
-
-/**
- * Copy the provided point attribute values between all curves in the #curve_ranges index
- * ranges, assuming that all curves are the same size in #src_curves and #dst_curves.
- */
-template<typename T>
-static void copy_between_curves(const bke::CurvesGeometry &src_curves,
- const bke::CurvesGeometry &dst_curves,
- const Span<IndexRange> curve_ranges,
- const Span<T> src,
- const MutableSpan<T> dst)
-{
- threading::parallel_for(curve_ranges.index_range(), 512, [&](IndexRange range) {
- for (const IndexRange range : curve_ranges.slice(range)) {
- const IndexRange src_points = src_curves.points_for_curves(range);
- const IndexRange dst_points = dst_curves.points_for_curves(range);
- /* The arrays might be large, so a threaded copy might make sense here too. */
- dst.slice(dst_points).copy_from(src.slice(src_points));
- }
- });
-}
-static void copy_between_curves(const bke::CurvesGeometry &src_curves,
- const bke::CurvesGeometry &dst_curves,
- const Span<IndexRange> unselected_ranges,
- const GSpan src,
- const GMutableSpan dst)
-{
- attribute_math::convert_to_static_type(src.type(), [&](auto dummy) {
- using T = decltype(dummy);
- copy_between_curves(src_curves, dst_curves, unselected_ranges, src.typed<T>(), dst.typed<T>());
- });
-}
-
-/**
- * Copy the size of every curve in #curve_ranges to the corresponding index in #counts.
- */
-static void fill_curve_counts(const bke::CurvesGeometry &src_curves,
- const Span<IndexRange> curve_ranges,
- MutableSpan<int> counts)
-{
- threading::parallel_for(curve_ranges.index_range(), 512, [&](IndexRange ranges_range) {
- for (const IndexRange curves_range : curve_ranges.slice(ranges_range)) {
- for (const int i : curves_range) {
- counts[i] = src_curves.points_for_curve(i).size();
- }
- }
- });
-}
-
-/**
- * Turn an array of sizes into the offset at each index including all previous sizes.
- */
-static void accumulate_counts_to_offsets(MutableSpan<int> counts_to_offsets)
-{
- int total = 0;
- for (const int i : counts_to_offsets.index_range().drop_back(1)) {
- const int count = counts_to_offsets[i];
- BLI_assert(count > 0);
- counts_to_offsets[i] = total;
- total += count;
- }
- counts_to_offsets.last() = total;
-}
-
-/**
- * Create new curves where the selected curves have been resampled with a number of uniform-length
- * samples defined by the count field. Interpolate attributes to the result, with an accuracy that
- * depends on the curve's resolution parameter.
- *
- * \warning The values provided by the #count_field must be 1 or greater.
- * \warning Curves with no evaluated points must not be selected.
- */
-static Curves *resample_to_uniform_count(const CurveComponent &src_component,
- const Field<bool> &selection_field,
- const Field<int> &count_field)
-{
- const Curves &src_curves_id = *src_component.get_for_read();
- const bke::CurvesGeometry &src_curves = bke::CurvesGeometry::wrap(src_curves_id.geometry);
-
- /* Create the new curves without any points and evaluate the final count directly
- * into the offsets array, in order to be accumulated into offsets later. */
- Curves *dst_curves_id = bke::curves_new_nomain(0, src_curves.curves_num());
- bke::CurvesGeometry &dst_curves = bke::CurvesGeometry::wrap(dst_curves_id->geometry);
- CurveComponent dst_component;
- dst_component.replace(dst_curves_id, GeometryOwnershipType::Editable);
- /* Directly copy curve attributes, since they stay the same (except for curve types). */
- CustomData_copy(&src_curves.curve_data,
- &dst_curves.curve_data,
- CD_MASK_ALL,
- CD_DUPLICATE,
- src_curves.curves_num());
- MutableSpan<int> dst_offsets = dst_curves.offsets_for_write();
-
- GeometryComponentFieldContext field_context{src_component, ATTR_DOMAIN_CURVE};
- fn::FieldEvaluator evaluator{field_context, src_curves.curves_num()};
- evaluator.set_selection(selection_field);
- evaluator.add_with_destination(count_field, dst_offsets);
- evaluator.evaluate();
- const IndexMask selection = evaluator.get_evaluated_selection_as_mask();
- const Vector<IndexRange> unselected_ranges = selection.extract_ranges_invert(
- src_curves.curves_range(), nullptr);
-
- /* Fill the counts for the curves that aren't selected and accumulate the counts into offsets. */
- fill_curve_counts(src_curves, unselected_ranges, dst_offsets);
- accumulate_counts_to_offsets(dst_offsets);
- dst_curves.resize(dst_offsets.last(), dst_curves.curves_num());
-
- /* All resampled curves are poly curves. */
- dst_curves.fill_curve_types(selection, CURVE_TYPE_POLY);
-
- VArray<bool> curves_cyclic = src_curves.cyclic();
- VArray<int8_t> curve_types = src_curves.curve_types();
- Span<float3> evaluated_positions = src_curves.evaluated_positions();
- MutableSpan<float3> dst_positions = dst_curves.positions_for_write();
-
- AttributesForInterpolation attributes;
- gather_point_attributes_to_interpolate(src_component, dst_component, attributes);
-
- src_curves.ensure_evaluated_lengths();
-
- /* Sampling arbitrary attributes works by first interpolating them to the curve's standard
- * "evaluated points" and then interpolating that result with the uniform samples. This is
- * potentially wasteful when down-sampling a curve to many fewer points. There are two possible
- * solutions: only sample the necessary points for interpolation, or first sample curve
- * parameter/segment indices and evaluate the curve directly. */
- Array<int> sample_indices(dst_curves.points_num());
- Array<float> sample_factors(dst_curves.points_num());
-
- /* Use a "for each group of curves: for each attribute: for each curve" pattern to work on
- * smaller sections of data that ideally fit into CPU cache better than simply one attribute at a
- * time or one curve at a time. */
- threading::parallel_for(selection.index_range(), 512, [&](IndexRange selection_range) {
- const IndexMask sliced_selection = selection.slice(selection_range);
-
- Vector<std::byte> evaluated_buffer;
-
- /* Gather uniform samples based on the accumulated lengths of the original curve. */
- for (const int i_curve : sliced_selection) {
- const bool cyclic = curves_cyclic[i_curve];
- const IndexRange dst_points = dst_curves.points_for_curve(i_curve);
- length_parameterize::create_uniform_samples(
- src_curves.evaluated_lengths_for_curve(i_curve, cyclic),
- curves_cyclic[i_curve],
- sample_indices.as_mutable_span().slice(dst_points),
- sample_factors.as_mutable_span().slice(dst_points));
- }
-
- /* For every attribute, evaluate attributes from every curve in the range in the original
- * curve's "evaluated points", then use linear interpolation to sample to the result. */
- for (const int i_attribute : attributes.dst.index_range()) {
- attribute_math::convert_to_static_type(attributes.src[i_attribute].type(), [&](auto dummy) {
- using T = decltype(dummy);
- Span<T> src = attributes.src[i_attribute].typed<T>();
- MutableSpan<T> dst = attributes.dst[i_attribute].typed<T>();
-
- for (const int i_curve : sliced_selection) {
- const IndexRange src_points = src_curves.points_for_curve(i_curve);
- const IndexRange dst_points = dst_curves.points_for_curve(i_curve);
-
- if (curve_types[i_curve] == CURVE_TYPE_POLY) {
- length_parameterize::linear_interpolation(src.slice(src_points),
- sample_indices.as_span().slice(dst_points),
- sample_factors.as_span().slice(dst_points),
- dst.slice(dst_points));
- }
- else {
- const int evaluated_size = src_curves.evaluated_points_for_curve(i_curve).size();
- evaluated_buffer.clear();
- evaluated_buffer.resize(sizeof(T) * evaluated_size);
- MutableSpan<T> evaluated = evaluated_buffer.as_mutable_span().cast<T>();
- src_curves.interpolate_to_evaluated(i_curve, src.slice(src_points), evaluated);
-
- length_parameterize::linear_interpolation(evaluated.as_span(),
- sample_indices.as_span().slice(dst_points),
- sample_factors.as_span().slice(dst_points),
- dst.slice(dst_points));
- }
- }
- });
- }
-
- /* Interpolate the evaluated positions to the resampled curves. */
- for (const int i_curve : sliced_selection) {
- const IndexRange src_points = src_curves.evaluated_points_for_curve(i_curve);
- const IndexRange dst_points = dst_curves.points_for_curve(i_curve);
- length_parameterize::linear_interpolation(evaluated_positions.slice(src_points),
- sample_indices.as_span().slice(dst_points),
- sample_factors.as_span().slice(dst_points),
- dst_positions.slice(dst_points));
- }
-
- /* Fill the default value for non-interpolating attributes that still must be copied. */
- for (GMutableSpan dst : attributes.dst_no_interpolation) {
- for (const int i_curve : sliced_selection) {
- const IndexRange dst_points = dst_curves.points_for_curve(i_curve);
- dst.type().value_initialize_n(dst.slice(dst_points).data(), dst_points.size());
- }
- }
- });
-
- /* Any attribute data from unselected curve points can be directly copied. */
- for (const int i : attributes.src.index_range()) {
- copy_between_curves(
- src_curves, dst_curves, unselected_ranges, attributes.src[i], attributes.dst[i]);
- }
- for (const int i : attributes.src_no_interpolation.index_range()) {
- copy_between_curves(src_curves,
- dst_curves,
- unselected_ranges,
- attributes.src_no_interpolation[i],
- attributes.dst_no_interpolation[i]);
- }
-
- /* Copy positions for unselected curves. */
- Span<float3> src_positions = src_curves.positions();
- copy_between_curves(src_curves, dst_curves, unselected_ranges, src_positions, dst_positions);
-
- for (OutputAttribute &attribute : attributes.dst_attributes) {
- attribute.save();
- }
-
- return dst_curves_id;
-}
-
-/**
- * Evaluate each selected curve to its implicit evaluated points.
- */
-static Curves *resample_to_evaluated(const CurveComponent &src_component,
- const Field<bool> &selection_field)
-{
- const Curves &src_curves_id = *src_component.get_for_read();
- const bke::CurvesGeometry &src_curves = bke::CurvesGeometry::wrap(src_curves_id.geometry);
-
- GeometryComponentFieldContext field_context{src_component, ATTR_DOMAIN_CURVE};
- fn::FieldEvaluator evaluator{field_context, src_curves.curves_num()};
- evaluator.set_selection(selection_field);
- evaluator.evaluate();
- const IndexMask selection = evaluator.get_evaluated_selection_as_mask();
- const Vector<IndexRange> unselected_ranges = selection.extract_ranges_invert(
- src_curves.curves_range(), nullptr);
-
- Curves *dst_curves_id = bke::curves_new_nomain(0, src_curves.curves_num());
- bke::CurvesGeometry &dst_curves = bke::CurvesGeometry::wrap(dst_curves_id->geometry);
- CurveComponent dst_component;
- dst_component.replace(dst_curves_id, GeometryOwnershipType::Editable);
- /* Directly copy curve attributes, since they stay the same (except for curve types). */
- CustomData_copy(&src_curves.curve_data,
- &dst_curves.curve_data,
- CD_MASK_ALL,
- CD_DUPLICATE,
- src_curves.curves_num());
- /* All resampled curves are poly curves. */
- dst_curves.fill_curve_types(selection, CURVE_TYPE_POLY);
- MutableSpan<int> dst_offsets = dst_curves.offsets_for_write();
-
- src_curves.ensure_evaluated_offsets();
- threading::parallel_for(selection.index_range(), 4096, [&](IndexRange range) {
- for (const int i : selection.slice(range)) {
- dst_offsets[i] = src_curves.evaluated_points_for_curve(i).size();
- }
- });
- fill_curve_counts(src_curves, unselected_ranges, dst_offsets);
- accumulate_counts_to_offsets(dst_offsets);
-
- dst_curves.resize(dst_offsets.last(), dst_curves.curves_num());
-
- /* Create the correct number of uniform-length samples for every selected curve. */
- Span<float3> evaluated_positions = src_curves.evaluated_positions();
- MutableSpan<float3> dst_positions = dst_curves.positions_for_write();
-
- AttributesForInterpolation attributes;
- gather_point_attributes_to_interpolate(src_component, dst_component, attributes);
-
- threading::parallel_for(selection.index_range(), 512, [&](IndexRange selection_range) {
- const IndexMask sliced_selection = selection.slice(selection_range);
-
- /* Evaluate generic point attributes directly to the result attributes. */
- for (const int i_attribute : attributes.dst.index_range()) {
- attribute_math::convert_to_static_type(attributes.src[i_attribute].type(), [&](auto dummy) {
- using T = decltype(dummy);
- Span<T> src = attributes.src[i_attribute].typed<T>();
- MutableSpan<T> dst = attributes.dst[i_attribute].typed<T>();
-
- for (const int i_curve : sliced_selection) {
- const IndexRange src_points = src_curves.points_for_curve(i_curve);
- const IndexRange dst_points = dst_curves.points_for_curve(i_curve);
- src_curves.interpolate_to_evaluated(
- i_curve, src.slice(src_points), dst.slice(dst_points));
- }
- });
- }
-
- /* Copy the evaluated positions to the selected curves. */
- for (const int i_curve : sliced_selection) {
- const IndexRange src_points = src_curves.evaluated_points_for_curve(i_curve);
- const IndexRange dst_points = dst_curves.points_for_curve(i_curve);
- dst_positions.slice(dst_points).copy_from(evaluated_positions.slice(src_points));
- }
-
- /* Fill the default value for non-interpolating attributes that still must be copied. */
- for (GMutableSpan dst : attributes.dst_no_interpolation) {
- for (const int i_curve : sliced_selection) {
- const IndexRange dst_points = dst_curves.points_for_curve(i_curve);
- dst.type().value_initialize_n(dst.slice(dst_points).data(), dst_points.size());
- }
- }
- });
-
- /* Any attribute data from unselected curve points can be directly copied. */
- for (const int i : attributes.src.index_range()) {
- copy_between_curves(
- src_curves, dst_curves, unselected_ranges, attributes.src[i], attributes.dst[i]);
- }
- for (const int i : attributes.src_no_interpolation.index_range()) {
- copy_between_curves(src_curves,
- dst_curves,
- unselected_ranges,
- attributes.src_no_interpolation[i],
- attributes.dst_no_interpolation[i]);
- }
-
- /* Copy positions for unselected curves. */
- Span<float3> src_positions = src_curves.positions();
- copy_between_curves(src_curves, dst_curves, unselected_ranges, src_positions, dst_positions);
-
- for (OutputAttribute &attribute : attributes.dst_attributes) {
- attribute.save();
- }
-
- return dst_curves_id;
-}
-
-/**
- * Create a resampled curve point count field for both "uniform" options.
- * The complexity is handled here in order to make the actual resampling functions simpler.
- */
-static Field<int> get_curve_count_field(GeoNodeExecParams params,
- const GeometryNodeCurveResampleMode mode)
-{
- if (mode == GEO_NODE_CURVE_RESAMPLE_COUNT) {
- static fn::CustomMF_SI_SO<int, int> max_one_fn(
- "Clamp Above One",
- [](int value) { return std::max(1, value); },
- fn::CustomMF_presets::AllSpanOrSingle());
- auto clamp_op = std::make_shared<FieldOperation>(
- FieldOperation(max_one_fn, {Field<int>(params.extract_input<Field<int>>("Count"))}));
-
- return Field<int>(std::move(clamp_op));
- }
-
- if (mode == GEO_NODE_CURVE_RESAMPLE_LENGTH) {
- static fn::CustomMF_SI_SI_SO<float, float, int> get_count_fn(
- "Length Input to Count",
- [](const float curve_length, const float sample_length) {
- /* Find the number of sampled segments by dividing the total length by
- * the sample length. Then there is one more sampled point than segment. */
- const int count = int(curve_length / sample_length) + 1;
- return std::max(1, count);
- },
- fn::CustomMF_presets::AllSpanOrSingle());
-
- auto get_count_op = std::make_shared<FieldOperation>(
- FieldOperation(get_count_fn,
- {Field<float>(std::make_shared<bke::CurveLengthFieldInput>()),
- params.extract_input<Field<float>>("Length")}));
-
- return Field<int>(std::move(get_count_op));
- }
-
- BLI_assert_unreachable();
- return {};
-}
-
static void node_geo_exec(GeoNodeExecParams params)
{
GeometrySet geometry_set = params.extract_input<GeometrySet>("Curve");
@@ -555,32 +61,35 @@ static void node_geo_exec(GeoNodeExecParams params)
const Field<bool> selection = params.extract_input<Field<bool>>("Selection");
switch (mode) {
- case GEO_NODE_CURVE_RESAMPLE_COUNT:
+ case GEO_NODE_CURVE_RESAMPLE_COUNT: {
+ Field<int> count = params.extract_input<Field<int>>("Count");
+ geometry_set.modify_geometry_sets([&](GeometrySet &geometry) {
+ if (const CurveComponent *component = geometry.get_component_for_read<CurveComponent>()) {
+ if (!component->is_empty()) {
+ geometry.replace_curves(geometry::resample_to_count(*component, selection, count));
+ }
+ }
+ });
+ break;
+ }
case GEO_NODE_CURVE_RESAMPLE_LENGTH: {
- Field<int> count = get_curve_count_field(params, mode);
-
- geometry_set.modify_geometry_sets([&](GeometrySet &geometry_set) {
- if (!geometry_set.has_curves()) {
- return;
+ Field<int> length = params.extract_input<Field<float>>("Length");
+ geometry_set.modify_geometry_sets([&](GeometrySet &geometry) {
+ if (const CurveComponent *component = geometry.get_component_for_read<CurveComponent>()) {
+ if (!component->is_empty()) {
+ geometry.replace_curves(geometry::resample_to_length(*component, selection, length));
+ }
}
-
- Curves *result = resample_to_uniform_count(
- *geometry_set.get_component_for_read<CurveComponent>(), selection, count);
-
- geometry_set.replace_curves(result);
});
break;
}
case GEO_NODE_CURVE_RESAMPLE_EVALUATED:
- geometry_set.modify_geometry_sets([&](GeometrySet &geometry_set) {
- if (!geometry_set.has_curves()) {
- return;
+ geometry_set.modify_geometry_sets([&](GeometrySet &geometry) {
+ if (const CurveComponent *component = geometry.get_component_for_read<CurveComponent>()) {
+ if (!component->is_empty()) {
+ geometry.replace_curves(geometry::resample_to_evaluated(*component, selection));
+ }
}
-
- Curves *result = resample_to_evaluated(
- *geometry_set.get_component_for_read<CurveComponent>(), selection);
-
- geometry_set.replace_curves(result);
});
break;
}
diff --git a/source/blender/nodes/geometry/nodes/node_geo_curve_reverse.cc b/source/blender/nodes/geometry/nodes/node_geo_curve_reverse.cc
index de29735bd2d..64a174df599 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_curve_reverse.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_curve_reverse.cc
@@ -27,9 +27,9 @@ static void node_geo_exec(GeoNodeExecParams params)
Field<bool> selection_field = params.get_input<Field<bool>>("Selection");
const CurveComponent &component = *geometry_set.get_component_for_read<CurveComponent>();
GeometryComponentFieldContext field_context{component, ATTR_DOMAIN_CURVE};
- const int domain_size = component.attribute_domain_size(ATTR_DOMAIN_CURVE);
+ const int domain_num = component.attribute_domain_num(ATTR_DOMAIN_CURVE);
- fn::FieldEvaluator selection_evaluator{field_context, domain_size};
+ fn::FieldEvaluator selection_evaluator{field_context, domain_num};
selection_evaluator.add(selection_field);
selection_evaluator.evaluate();
const IndexMask selection = selection_evaluator.get_evaluated_as_mask(0);
diff --git a/source/blender/nodes/geometry/nodes/node_geo_curve_spline_parameter.cc b/source/blender/nodes/geometry/nodes/node_geo_curve_spline_parameter.cc
index a548becf24e..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;
}
diff --git a/source/blender/nodes/geometry/nodes/node_geo_curve_spline_type.cc b/source/blender/nodes/geometry/nodes/node_geo_curve_spline_type.cc
index 6e45411a9af..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
@@ -107,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]);
}
}
@@ -134,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));
@@ -151,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] +
@@ -368,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);
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..b45a0d6c81a 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;
}
}
@@ -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 1b26cfe31fe..ee3de995cb1 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_duplicate_elements.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_duplicate_elements.cc
@@ -351,19 +351,19 @@ static void duplicate_curves(GeometrySet &geometry_set,
Array<int> curve_offsets(selection.size() + 1);
Array<int> point_offsets(selection.size() + 1);
- int dst_curves_size = 0;
- int dst_points_size = 0;
+ int dst_curves_num = 0;
+ int dst_points_num = 0;
for (const int i_curve : selection.index_range()) {
const int count = std::max(counts[selection[i_curve]], 0);
- curve_offsets[i_curve] = dst_curves_size;
- point_offsets[i_curve] = dst_points_size;
- dst_curves_size += count;
- dst_points_size += count * curves.points_for_curve(selection[i_curve]).size();
+ curve_offsets[i_curve] = dst_curves_num;
+ point_offsets[i_curve] = dst_points_num;
+ dst_curves_num += count;
+ dst_points_num += count * curves.points_for_curve(selection[i_curve]).size();
}
- curve_offsets.last() = dst_curves_size;
- point_offsets.last() = dst_points_size;
+ curve_offsets.last() = dst_curves_num;
+ point_offsets.last() = dst_points_num;
- Curves *new_curves_id = bke::curves_new_nomain(dst_points_size, dst_curves_size);
+ Curves *new_curves_id = bke::curves_new_nomain(dst_points_num, dst_curves_num);
bke::CurvesGeometry &new_curves = bke::CurvesGeometry::wrap(new_curves_id->geometry);
MutableSpan<int> all_dst_offsets = new_curves.offsets_for_write();
@@ -379,7 +379,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);
@@ -807,7 +807,7 @@ 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) {
@@ -817,13 +817,13 @@ static void duplicate_points_curve(GeometrySet &geometry_set,
}
});
- 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);
@@ -940,10 +940,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();
@@ -1026,7 +1026,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_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_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 2ed6d555684..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
@@ -66,12 +66,12 @@ static void geometry_set_mesh_to_points(GeometrySet &geometry_set,
return;
}
GeometryComponentFieldContext field_context{*mesh_component, domain};
- const int domain_size = mesh_component->attribute_domain_size(domain);
- if (domain_size == 0) {
+ const int domain_num = mesh_component->attribute_domain_num(domain);
+ if (domain_num == 0) {
geometry_set.keep_only({GEO_COMPONENT_TYPE_INSTANCES});
return;
}
- fn::FieldEvaluator evaluator{field_context, domain_size};
+ fn::FieldEvaluator evaluator{field_context, domain_num};
evaluator.set_selection(selection_field);
/* Evaluating directly into the point cloud doesn't work because we are not using the full
* "min_array_size" array but compressing the selected elements into the final array with no
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_subdivision_surface.cc b/source/blender/nodes/geometry/nodes/node_geo_subdivision_surface.cc
index f2a859065c6..9eda5bb34ff 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_subdivision_surface.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_subdivision_surface.cc
@@ -118,8 +118,8 @@ static void node_geo_exec(GeoNodeExecParams params)
}
const MeshComponent &mesh_component = *geometry_set.get_component_for_read<MeshComponent>();
- const int verts_num = mesh_component.attribute_domain_size(ATTR_DOMAIN_POINT);
- const int edges_num = mesh_component.attribute_domain_size(ATTR_DOMAIN_EDGE);
+ const int verts_num = mesh_component.attribute_domain_num(ATTR_DOMAIN_POINT);
+ const int edges_num = mesh_component.attribute_domain_num(ATTR_DOMAIN_EDGE);
if (verts_num == 0 || edges_num == 0) {
return;
}
diff --git a/source/blender/nodes/geometry/nodes/node_geo_transfer_attribute.cc b/source/blender/nodes/geometry/nodes/node_geo_transfer_attribute.cc
index 12e306ba480..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..39d8c453e43 100644
--- a/source/blender/nodes/intern/node_geometry_exec.cc
+++ b/source/blender/nodes/intern/node_geometry_exec.cc
@@ -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/shader/nodes/node_shader_vertex_color.cc b/source/blender/nodes/shader/nodes/node_shader_vertex_color.cc
index a2a9aa9ad91..cba944c671c 100644
--- a/source/blender/nodes/shader/nodes/node_shader_vertex_color.cc
+++ b/source/blender/nodes/shader/nodes/node_shader_vertex_color.cc
@@ -42,10 +42,20 @@ static int node_shader_gpu_vertex_color(GPUMaterial *mat,
GPUNodeStack *out)
{
NodeShaderVertexColor *vertexColor = (NodeShaderVertexColor *)node->storage;
- /* NOTE: using CD_AUTO_FROM_NAME instead of CD_MCOL or CD_PROP_COLOR as geometry nodes may
- * overwrite data which will also change the CustomDataType. This will also make EEVEE and Cycles
+ /* NOTE: using CD_AUTO_FROM_NAME instead of CD_MCOL or CD_PROP_COLOR for named attributes
+ * as geometry nodes may overwrite data which will also change the CustomDataType.
+ * This will also make EEVEE and Cycles
* consistent. See T93179. */
- GPUNodeLink *vertexColorLink = GPU_attribute(mat, CD_AUTO_FROM_NAME, vertexColor->layer_name);
+
+ GPUNodeLink *vertexColorLink;
+
+ if (vertexColor->layer_name[0]) {
+ vertexColorLink = GPU_attribute(mat, CD_AUTO_FROM_NAME, vertexColor->layer_name);
+ }
+ else { /* Fall back on active render color attribute. */
+ vertexColorLink = GPU_attribute(mat, CD_MCOL, vertexColor->layer_name);
+ }
+
return GPU_stack_link(mat, node, "node_vertex_color", in, out, vertexColorLink);
}
diff --git a/source/blender/nodes/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/python/gpu/gpu_py_shader.c b/source/blender/python/gpu/gpu_py_shader.c
index 77333c6dfea..80c48e31510 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"},
diff --git a/source/blender/python/intern/bpy_utils_units.c b/source/blender/python/intern/bpy_utils_units.c
index 3e0698caa50..1e5856a3285 100644
--- a/source/blender/python/intern/bpy_utils_units.c
+++ b/source/blender/python/intern/bpy_utils_units.c
@@ -35,7 +35,7 @@ static const char *bpyunits_usystem_items[] = {
NULL,
};
-static const char *bpyunits_ucategorie_items[] = {
+static const char *bpyunits_ucategories_items[] = {
"NONE",
"LENGTH",
"AREA",
@@ -43,20 +43,26 @@ static const char *bpyunits_ucategorie_items[] = {
"MASS",
"ROTATION",
"TIME",
+ "TIME_ABSOLUTE",
"VELOCITY",
"ACCELERATION",
"CAMERA",
"POWER",
+ "TEMPERATURE",
NULL,
};
+BLI_STATIC_ASSERT(
+ ARRAY_SIZE(bpyunits_ucategories_items) == B_UNIT_TYPE_TOT + 1,
+ "`bpyunits_ucategories_items` should match `B_UNIT_` enum items in `BKE_units.h`")
+
/**
* These fields are just empty placeholders, actual values get set in initializations functions.
* This allows us to avoid many handwriting, and above all,
* to keep all systems/categories definition stuff in `BKE_unit.h`.
*/
static PyStructSequence_Field bpyunits_systems_fields[ARRAY_SIZE(bpyunits_usystem_items)];
-static PyStructSequence_Field bpyunits_categories_fields[ARRAY_SIZE(bpyunits_ucategorie_items)];
+static PyStructSequence_Field bpyunits_categories_fields[ARRAY_SIZE(bpyunits_ucategories_items)];
static PyStructSequence_Desc bpyunits_systems_desc = {
"bpy.utils.units.systems", /* name */
@@ -114,7 +120,7 @@ static bool bpyunits_validate(const char *usys_str, const char *ucat_str, int *r
return false;
}
- *r_ucat = BLI_str_index_in_array(ucat_str, bpyunits_ucategorie_items);
+ *r_ucat = BLI_str_index_in_array(ucat_str, bpyunits_ucategories_items);
if (*r_ucat < 0) {
PyErr_Format(PyExc_ValueError, "Unknown unit category specified: %.200s.", ucat_str);
return false;
@@ -356,7 +362,7 @@ PyObject *BPY_utils_units(void)
/* bpy.utils.units.categories */
item = py_structseq_from_strings(
- &BPyUnitsCategoriesType, &bpyunits_categories_desc, bpyunits_ucategorie_items);
+ &BPyUnitsCategoriesType, &bpyunits_categories_desc, bpyunits_ucategories_items);
PyModule_AddObject(submodule, "categories", item); /* steals ref */
return submodule;
diff --git a/source/blender/render/intern/bake.c b/source/blender/render/intern/bake.c
index 5953c0f0f8f..bf876163013 100644
--- a/source/blender/render/intern/bake.c
+++ b/source/blender/render/intern/bake.c
@@ -330,10 +330,10 @@ static bool cast_ray_highpoly(BVHTreeFromMesh *treeData,
{
int i;
int hit_mesh = -1;
- float hit_distance = max_ray_distance;
- if (hit_distance == 0.0f) {
+ float hit_distance_squared = max_ray_distance * max_ray_distance;
+ if (hit_distance_squared == 0.0f) {
/* No ray distance set, use maximum. */
- hit_distance = FLT_MAX;
+ hit_distance_squared = FLT_MAX;
}
BVHTreeRayHit *hits;
@@ -365,16 +365,14 @@ static bool cast_ray_highpoly(BVHTreeFromMesh *treeData,
}
if (hits[i].index != -1) {
- float distance;
- float hit_world[3];
-
/* distance comparison in world space */
+ float hit_world[3];
mul_v3_m4v3(hit_world, highpoly[i].obmat, hits[i].co);
- distance = len_squared_v3v3(hit_world, co);
+ float distance_squared = len_squared_v3v3(hit_world, co);
- if (distance < hit_distance) {
+ if (distance_squared < hit_distance_squared) {
hit_mesh = i;
- hit_distance = distance;
+ hit_distance_squared = distance_squared;
}
}
}
diff --git a/source/blender/render/intern/multires_bake.c b/source/blender/render/intern/multires_bake.c
index f93397eedab..dc9ad2ddb5e 100644
--- a/source/blender/render/intern/multires_bake.c
+++ b/source/blender/render/intern/multires_bake.c
@@ -464,140 +464,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/windowmanager/WM_types.h b/source/blender/windowmanager/WM_types.h
index 3ee5c85c031..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. */
diff --git a/source/blender/windowmanager/gizmo/intern/wm_gizmo_map.c b/source/blender/windowmanager/gizmo/intern/wm_gizmo_map.c
index a61d73b9f0b..f481f19045d 100644
--- a/source/blender/windowmanager/gizmo/intern/wm_gizmo_map.c
+++ b/source/blender/windowmanager/gizmo/intern/wm_gizmo_map.c
@@ -492,7 +492,8 @@ void WM_gizmomap_draw(wmGizmoMap *gzmap,
static void gizmo_draw_select_3d_loop(const bContext *C,
wmGizmo **visible_gizmos,
- const int visible_gizmos_len)
+ const int visible_gizmos_len,
+ bool *r_use_select_bias)
{
/* TODO(campbell): this depends on depth buffer being written to,
@@ -528,6 +529,10 @@ static void gizmo_draw_select_3d_loop(const bContext *C,
is_depth_skip_prev = is_depth_skip;
}
+ if (gz->select_bias != 0.0) {
+ *r_use_select_bias = true;
+ }
+
/* pass the selection id shifted by 8 bits. Last 8 bits are used for selected gizmo part id */
gz->type->draw_select(C, gz, select_id << 8);
@@ -545,10 +550,7 @@ static int gizmo_find_intersected_3d_intern(wmGizmo **visible_gizmos,
const int visible_gizmos_len,
const bContext *C,
const int co[2],
- const int hotspot,
- const bool use_depth_test,
- const bool has_3d_select_bias,
- int *r_hits)
+ const int hotspot)
{
const wmWindowManager *wm = CTX_wm_manager(C);
ScrArea *area = CTX_wm_area(C);
@@ -562,76 +564,30 @@ static int gizmo_find_intersected_3d_intern(wmGizmo **visible_gizmos,
BLI_rcti_init_pt_radius(&rect, co, hotspot);
- /* The selection mode is assigned for the following reasons:
- *
- * - #GPU_SELECT_ALL: Use it to check if there is anything at the cursor location
- * (only ever runs once).
- * - #GPU_SELECT_PICK_NEAREST: Use if there are more than 1 item at the cursor location,
- * pick the nearest one.
- * - #GPU_SELECT_PICK_ALL: Use for the same purpose as #GPU_SELECT_PICK_NEAREST
- * when the selection depths need to re-ordered based on a bias.
- * */
- const eGPUSelectMode gpu_select_mode =
- (use_depth_test ? (has_3d_select_bias ?
- /* Using select bias means the depths need to be
- * re-calculated based on the bias to pick the best. */
- GPU_SELECT_PICK_ALL :
- /* No bias, just pick the closest. */
- GPU_SELECT_PICK_NEAREST) :
- /* Fast-path (occlusion queries). */
- GPU_SELECT_ALL);
-
- /* When switching between modes and the mouse pointer is over a gizmo, the highlight test is
- * performed before the viewport is fully initialized (region->draw_buffer = NULL).
- * When this is the case we should not use depth testing. */
- GPUViewport *gpu_viewport = WM_draw_region_get_viewport(region);
- if (use_depth_test && gpu_viewport == NULL) {
- return -1;
- }
+ ED_view3d_draw_setup_view(
+ wm, CTX_wm_window(C), depsgraph, CTX_data_scene(C), region, v3d, NULL, NULL, &rect);
- if (GPU_select_is_cached()) {
- GPU_select_begin(buffer, ARRAY_SIZE(buffer), &rect, gpu_select_mode, 0);
- GPU_select_cache_load_id();
- hits = GPU_select_end();
- }
- else {
- /* TODO: waiting for the GPU in the middle of the event loop for every
- * mouse move is bad for performance, we need to find a solution to not
- * use the GPU or draw something once. (see T61474) */
+ bool use_select_bias = false;
- ED_view3d_draw_setup_view(
- wm, CTX_wm_window(C), depsgraph, CTX_data_scene(C), region, v3d, NULL, NULL, &rect);
+ /* TODO: waiting for the GPU in the middle of the event loop for every
+ * mouse move is bad for performance, we need to find a solution to not
+ * use the GPU or draw something once. (see T61474) */
+ GPU_select_begin(buffer, ARRAY_SIZE(buffer), &rect, GPU_SELECT_NEAREST_FIRST_PASS, 0);
+ /* do the drawing */
+ gizmo_draw_select_3d_loop(C, visible_gizmos, visible_gizmos_len, &use_select_bias);
- /* There is no need to bind to the depth buffer outside this function
- * because all future passes the will use the cached depths. */
- GPUFrameBuffer *depth_read_fb = NULL;
- if (use_depth_test) {
- GPUTexture *depth_tx = GPU_viewport_depth_texture(gpu_viewport);
- GPU_framebuffer_ensure_config(&depth_read_fb,
- {
- GPU_ATTACHMENT_TEXTURE(depth_tx),
- GPU_ATTACHMENT_NONE,
- });
- GPU_framebuffer_bind(depth_read_fb);
- }
+ hits = GPU_select_end();
- GPU_select_begin(buffer, ARRAY_SIZE(buffer), &rect, gpu_select_mode, 0);
- gizmo_draw_select_3d_loop(C, visible_gizmos, visible_gizmos_len);
- hits = GPU_select_end();
-
- if (use_depth_test) {
- GPU_framebuffer_restore();
- GPU_framebuffer_free(depth_read_fb);
- }
-
- ED_view3d_draw_setup_view(
- wm, CTX_wm_window(C), depsgraph, CTX_data_scene(C), region, v3d, NULL, NULL, NULL);
+ if (hits > 0) {
+ GPU_select_begin(buffer, ARRAY_SIZE(buffer), &rect, GPU_SELECT_NEAREST_SECOND_PASS, hits);
+ gizmo_draw_select_3d_loop(C, visible_gizmos, visible_gizmos_len, &use_select_bias);
+ GPU_select_end();
}
- /* When selection bias is needed, this function will run again with `use_depth_test` enabled. */
- int hit_found = -1;
+ ED_view3d_draw_setup_view(
+ wm, CTX_wm_window(C), depsgraph, CTX_data_scene(C), region, v3d, NULL, NULL, NULL);
- if (has_3d_select_bias && use_depth_test && (hits > 1)) {
+ if (use_select_bias && (hits > 1)) {
float co_direction[3];
float co_screen[3] = {co[0], co[1], 0.0f};
ED_view3d_win_to_vector(region, (float[2]){UNPACK2(co)}, co_direction);
@@ -643,6 +599,7 @@ static int gizmo_find_intersected_3d_intern(wmGizmo **visible_gizmos,
GPU_matrix_unproject_3fv(co_screen, rv3d->viewinv, rv3d->winmat, viewport, co_3d_origin);
GPUSelectResult *buf_iter = buffer;
+ int hit_found = -1;
float dot_best = FLT_MAX;
for (int i = 0; i < hits; i++, buf_iter++) {
@@ -662,16 +619,11 @@ static int gizmo_find_intersected_3d_intern(wmGizmo **visible_gizmos,
hit_found = buf_iter->id;
}
}
- }
- else {
- const GPUSelectResult *hit_near = GPU_select_buffer_near(buffer, hits);
- if (hit_near) {
- hit_found = hit_near->id;
- }
+ return hit_found;
}
- *r_hits = hits;
- return hit_found;
+ const GPUSelectResult *hit_near = GPU_select_buffer_near(buffer, hits);
+ return hit_near ? hit_near->id : -1;
}
/**
@@ -694,7 +646,6 @@ static wmGizmo *gizmo_find_intersected_3d(bContext *C,
/* Search for 3D gizmo's that use the 2D callback for checking intersections. */
bool has_3d = false;
- bool has_3d_select_bias = false;
{
for (int select_id = 0; select_id < visible_gizmos_len; select_id++) {
wmGizmo *gz = visible_gizmos[select_id];
@@ -710,9 +661,6 @@ static wmGizmo *gizmo_find_intersected_3d(bContext *C,
}
else if (gz->type->draw_select != NULL) {
has_3d = true;
- if (gz->select_bias != 0.0f) {
- has_3d_select_bias = true;
- }
}
}
}
@@ -721,86 +669,39 @@ static wmGizmo *gizmo_find_intersected_3d(bContext *C,
* This way we always use the first hit. */
if (has_3d) {
- /* NOTE(@campbellbarton): The selection logic here uses a fast-path that exits early
- * where possible. This is important as this runs on cursor-motion in the 3D view-port.
- *
- * - First, don't use the depth buffer at all, use occlusion queries to detect any gizmos.
- * If there are no gizmos or only one - early exit, otherwise.
- *
- * - Bind the depth buffer and use selection picking logic.
- * This is much slower than occlusion queries (since it's reading depths while drawing).
- * When there is a single gizmo under the cursor (quite common), early exit, otherwise.
- *
- * - Perform another pass at a reduced size (see: `hotspot_radii`),
- * since the result depths are cached this pass is practically free.
- *
- * Other notes:
- *
- * - If any of these passes fail, use the nearest result from the previous pass.
- *
- * - Drawing is only ever done twice.
- */
-
- /* Order largest to smallest so the first pass can be used as cache for
- * later passes (when `use_depth_test == true`). */
- const int hotspot_radii[] = {
- 10 * U.pixelsize,
- /* This runs on mouse move, careful doing too many tests! */
- 3 * U.pixelsize,
- };
-
- /* Narrowing may assign zero to `hit`, allow falling back to the previous test. */
- int hit_prev = -1;
+ /* The depth buffer is needed for for gizmos to obscure eachother. */
+ GPUViewport *viewport = WM_draw_region_get_viewport(CTX_wm_region(C));
- bool use_depth_test = false;
- bool use_depth_cache = false;
-
- /* Workaround for MS-Windows & NVidia failing to detect any gizmo undo the cursor unless the
- * depth test is enabled, see: T97124.
- * NOTE(@campbellbarton): Ideally the exact cause of this could be tracked down,
- * disable as I don't have a system to test this configuration. */
- if (GPU_type_matches(GPU_DEVICE_NVIDIA | GPU_DEVICE_SOFTWARE, GPU_OS_WIN, GPU_DRIVER_ANY)) {
- use_depth_test = true;
+ /* When switching between modes and the mouse pointer is over a gizmo, the highlight test is
+ * performed before the viewport is fully initialized (region->draw_buffer = NULL).
+ * When this is the case we should not use depth testing. */
+ if (viewport == NULL) {
+ return NULL;
}
+ GPUTexture *depth_tx = GPU_viewport_depth_texture(viewport);
+ GPUFrameBuffer *depth_read_fb = NULL;
+ GPU_framebuffer_ensure_config(&depth_read_fb,
+ {
+ GPU_ATTACHMENT_TEXTURE(depth_tx),
+ GPU_ATTACHMENT_NONE,
+ });
+ GPU_framebuffer_bind(depth_read_fb);
+ const int hotspot_radii[] = {
+ 3 * U.pixelsize,
+ /* This runs on mouse move, careful doing too many tests! */
+ 10 * U.pixelsize,
+ };
for (int i = 0; i < ARRAY_SIZE(hotspot_radii); i++) {
-
- if (use_depth_test && (use_depth_cache == false)) {
- GPU_select_cache_begin();
- use_depth_cache = true;
- }
-
- int hit_count;
- hit = gizmo_find_intersected_3d_intern(visible_gizmos,
- visible_gizmos_len_trim,
- C,
- co,
- hotspot_radii[i],
- use_depth_test,
- has_3d_select_bias,
- &hit_count);
- /* Only continue searching when there are multiple options to narrow down. */
- if (hit_count < 2) {
+ hit = gizmo_find_intersected_3d_intern(
+ visible_gizmos, visible_gizmos_len_trim, C, co, hotspot_radii[i]);
+ if (hit != -1) {
break;
}
-
- /* Fast path for simple case, one item or nothing. */
- if (use_depth_test == false) {
- /* Restart, using depth buffer (slower). */
- use_depth_test = true;
- i = -1;
- }
- hit_prev = hit;
- }
- /* Narrowing the search area may yield no hits,
- * in this case fall back to the previous search. */
- if (hit == -1) {
- hit = hit_prev;
}
- if (use_depth_cache) {
- GPU_select_cache_end();
- }
+ GPU_framebuffer_restore();
+ GPU_framebuffer_free(depth_read_fb);
if (hit != -1) {
const int select_id = hit >> 8;
diff --git a/source/blender/windowmanager/intern/wm_draw.c b/source/blender/windowmanager/intern/wm_draw.c
index 02da798495b..d2ade7b0376 100644
--- a/source/blender/windowmanager/intern/wm_draw.c
+++ b/source/blender/windowmanager/intern/wm_draw.c
@@ -467,7 +467,7 @@ static bool wm_draw_region_bind(bContext *C, ARegion *region, int view)
}
if (region->draw_buffer->viewport) {
- if (G.is_rendering && C != NULL) {
+ if (G.is_rendering && C != NULL && U.experimental.use_draw_manager_acquire_lock) {
Scene *scene = CTX_data_scene(C);
RenderEngineType *render_engine_type = RE_engines_find(scene->r.engine);
if (RE_engine_is_opengl(render_engine_type)) {
diff --git a/source/blender/windowmanager/intern/wm_event_system.c b/source/blender/windowmanager/intern/wm_event_system.c
index 1c3f7ed3e7a..5776184aec0 100644
--- a/source/blender/windowmanager/intern/wm_event_system.c
+++ b/source/blender/windowmanager/intern/wm_event_system.c
@@ -101,6 +101,7 @@ static int wm_operator_call_internal(bContext *C,
static bool wm_operator_check_locked_interface(bContext *C, wmOperatorType *ot);
static wmEvent *wm_event_add_mousemove_to_head(wmWindow *win);
+static void wm_operator_free_for_fileselect(wmOperator *file_operator);
/* -------------------------------------------------------------------- */
/** \name Event Management
@@ -1904,8 +1905,15 @@ void wm_event_free_handler(wmEventHandler *handler)
MEM_freeN(handler);
}
-/* Only set context when area/region is part of screen. */
-static void wm_handler_op_context(bContext *C, wmEventHandler_Op *handler, const wmEvent *event)
+/**
+ * Check if the handler's area and/or region are actually part of the screen, and return them if
+ * so.
+ */
+static void wm_handler_op_context_get_if_valid(bContext *C,
+ wmEventHandler_Op *handler,
+ const wmEvent *event,
+ ScrArea **r_area,
+ ARegion **r_region)
{
wmWindow *win = handler->context.win ? handler->context.win : CTX_wm_window(C);
/* It's probably fine to always use #WM_window_get_active_screen() to get the screen. But this
@@ -1913,12 +1921,15 @@ static void wm_handler_op_context(bContext *C, wmEventHandler_Op *handler, const
* possible. */
bScreen *screen = handler->context.win ? WM_window_get_active_screen(win) : CTX_wm_screen(C);
+ *r_area = NULL;
+ *r_region = NULL;
+
if (screen == NULL || handler->op == NULL) {
return;
}
if (handler->context.area == NULL) {
- CTX_wm_area_set(C, NULL);
+ /* Pass */
}
else {
ScrArea *area = NULL;
@@ -1942,7 +1953,7 @@ static void wm_handler_op_context(bContext *C, wmEventHandler_Op *handler, const
else {
ARegion *region;
wmOperator *op = handler->op ? (handler->op->opm ? handler->op->opm : handler->op) : NULL;
- CTX_wm_area_set(C, area);
+ *r_area = area;
if (op && (op->flag & OP_IS_MODAL_CURSOR_REGION)) {
region = BKE_area_find_region_xy(area, handler->context.region_type, event->xy);
@@ -1965,12 +1976,21 @@ static void wm_handler_op_context(bContext *C, wmEventHandler_Op *handler, const
/* No warning print here, after full-area and back regions are remade. */
if (region) {
- CTX_wm_region_set(C, region);
+ *r_region = region;
}
}
}
}
+static void wm_handler_op_context(bContext *C, wmEventHandler_Op *handler, const wmEvent *event)
+{
+ ScrArea *area = NULL;
+ ARegion *region = NULL;
+ wm_handler_op_context_get_if_valid(C, handler, event, &area, &region);
+ CTX_wm_area_set(C, area);
+ CTX_wm_region_set(C, region);
+}
+
void WM_event_remove_handlers(bContext *C, ListBase *handlers)
{
wmWindowManager *wm = CTX_wm_manager(C);
@@ -2017,7 +2037,13 @@ void WM_event_remove_handlers(bContext *C, ListBase *handlers)
}
WM_cursor_grab_disable(win, NULL);
- WM_operator_free(handler->op);
+
+ if (handler->is_fileselect) {
+ wm_operator_free_for_fileselect(handler->op);
+ }
+ else {
+ WM_operator_free(handler->op);
+ }
}
}
else if (handler_base->type == WM_HANDLER_TYPE_UI) {
@@ -2454,6 +2480,22 @@ static int wm_handler_operator_call(bContext *C,
return WM_HANDLER_BREAK;
}
+static void wm_operator_free_for_fileselect(wmOperator *file_operator)
+{
+ LISTBASE_FOREACH (bScreen *, screen, &G_MAIN->screens) {
+ LISTBASE_FOREACH (ScrArea *, area, &screen->areabase) {
+ if (area->spacetype == SPACE_FILE) {
+ SpaceFile *sfile = area->spacedata.first;
+ if (sfile->op == file_operator) {
+ sfile->op = NULL;
+ }
+ }
+ }
+ }
+
+ WM_operator_free(file_operator);
+}
+
/**
* File-select handlers are only in the window queue,
* so it's safe to switch screens or area types.
@@ -2507,6 +2549,9 @@ static int wm_handler_fileselect_do(bContext *C,
case EVT_FILESELECT_CANCEL:
case EVT_FILESELECT_EXTERNAL_CANCEL: {
wmWindow *ctx_win = CTX_wm_window(C);
+ wmEvent *eventstate = ctx_win->eventstate;
+ /* The root window of the operation as determined in #WM_event_add_fileselect(). */
+ wmWindow *root_win = handler->context.win;
/* Remove link now, for load file case before removing. */
BLI_remlink(handlers, handler);
@@ -2542,21 +2587,17 @@ static int wm_handler_fileselect_do(bContext *C,
ED_fileselect_params_to_userdef(file_area->spacedata.first, win_size, is_maximized);
if (BLI_listbase_is_single(&file_area->spacedata)) {
- BLI_assert(ctx_win != win);
+ BLI_assert(root_win != win);
wm_window_close(C, wm, win);
- CTX_wm_window_set(C, ctx_win); /* #wm_window_close() NULLs. */
+ CTX_wm_window_set(C, root_win); /* #wm_window_close() NULLs. */
/* Some operators expect a drawable context (for #EVT_FILESELECT_EXEC). */
- wm_window_make_drawable(wm, ctx_win);
+ wm_window_make_drawable(wm, root_win);
/* Ensure correct cursor position, otherwise, popups may close immediately after
* opening (#UI_BLOCK_MOVEMOUSE_QUIT). */
- wm_cursor_position_get(
- ctx_win, &ctx_win->eventstate->xy[0], &ctx_win->eventstate->xy[1]);
- wm->winactive = ctx_win; /* Reports use this... */
- if (handler->context.win == win) {
- handler->context.win = NULL;
- }
+ wm_cursor_position_get(root_win, &eventstate->xy[0], &eventstate->xy[1]);
+ wm->winactive = root_win; /* Reports use this... */
}
else if (file_area->full) {
ED_screen_full_prevspace(C, file_area);
@@ -2575,7 +2616,13 @@ static int wm_handler_fileselect_do(bContext *C,
}
}
- wm_handler_op_context(C, handler, ctx_win->eventstate);
+ CTX_wm_window_set(C, root_win);
+ wm_handler_op_context(C, handler, eventstate);
+ /* At this point context is supposed to match the root context determined by
+ * #WM_event_add_fileselect(). */
+ BLI_assert(!CTX_wm_area(C) || (CTX_wm_area(C) == handler->context.area));
+ BLI_assert(!CTX_wm_region(C) || (CTX_wm_region(C) == handler->context.region));
+
ScrArea *handler_area = CTX_wm_area(C);
/* Make sure new context area is ready, the operator callback may operate on it. */
if (handler_area) {
@@ -2644,7 +2691,7 @@ static int wm_handler_fileselect_do(bContext *C,
}
if (retval & (OPERATOR_CANCELLED | OPERATOR_FINISHED)) {
- WM_operator_free(handler->op);
+ wm_operator_free_for_fileselect(handler->op);
}
}
else {
@@ -2659,8 +2706,7 @@ static int wm_handler_fileselect_do(bContext *C,
wm->op_undo_depth--;
}
}
-
- WM_operator_free(handler->op);
+ wm_operator_free_for_fileselect(handler->op);
}
CTX_wm_area_set(C, NULL);
@@ -3981,58 +4027,122 @@ 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);
}
}
+/**
+ * From the context window, try to find a window that is appropriate for use as root window of a
+ * modal File Browser (modal means: there is a #SpaceFile.op to execute). The root window will
+ * become the parent of the File Browser and provides a context to execute the file operator in,
+ * even after closing the File Browser.
+ *
+ * An appropriate window is either of the following:
+ * * A parent window that does not yet contain a modal File Browser. This is determined using
+ * #ED_fileselect_handler_area_find_any_with_op().
+ * * A parent window containing a modal File Browser, but in a maximized/fullscreen state. Users
+ * shouldn't be able to put a temporary screen like the modal File Browser into
+ * maximized/fullscreen state themselves. So this setup indicates that the File Browser was
+ * opened using #USER_TEMP_SPACE_DISPLAY_FULLSCREEN.
+ *
+ * If no appropriate parent window can be found from the context window, return the first
+ * registered window (which can be assumed to be a regular window, e.g. no modal File Browser; this
+ * is asserted).
+ */
+static wmWindow *wm_event_find_fileselect_root_window_from_context(const bContext *C)
+{
+ wmWindow *ctx_win = CTX_wm_window(C);
+
+ for (wmWindow *ctx_win_or_parent = ctx_win; ctx_win_or_parent;
+ ctx_win_or_parent = ctx_win_or_parent->parent) {
+ ScrArea *file_area = ED_fileselect_handler_area_find_any_with_op(ctx_win_or_parent);
+
+ if (!file_area) {
+ return ctx_win_or_parent;
+ }
+
+ if (file_area->full) {
+ return ctx_win_or_parent;
+ }
+ }
+
+ /* Fallback to the first window. */
+ const wmWindowManager *wm = CTX_wm_manager(C);
+ BLI_assert(!ED_fileselect_handler_area_find_any_with_op(wm->windows.first));
+ return wm->windows.first;
+}
+
/* Operator is supposed to have a filled "path" property. */
/* Optional property: file-type (XXX enum?) */
void WM_event_add_fileselect(bContext *C, wmOperator *op)
{
wmWindowManager *wm = CTX_wm_manager(C);
- wmWindow *win = CTX_wm_window(C);
- const bool is_temp_screen = WM_window_is_temp_screen(win);
+ wmWindow *ctx_win = CTX_wm_window(C);
+
+ /* The following vars define the root context. That is essentially the "parent" context of the
+ * File Browser operation, to be restored for eventually executing the file operation. */
+ wmWindow *root_win = wm_event_find_fileselect_root_window_from_context(C);
+ /* Determined later. */
+ ScrArea *root_area = NULL;
+ ARegion *root_region = NULL;
/* Close any popups, like when opening a file browser from the splash. */
- UI_popup_handlers_remove_all(C, &win->modalhandlers);
+ UI_popup_handlers_remove_all(C, &root_win->modalhandlers);
- if (!is_temp_screen) {
- /* Only allow 1 file selector open per window. */
- LISTBASE_FOREACH_MUTABLE (wmEventHandler *, handler_base, &win->modalhandlers) {
- if (handler_base->type == WM_HANDLER_TYPE_OP) {
- wmEventHandler_Op *handler = (wmEventHandler_Op *)handler_base;
- if (handler->is_fileselect == false) {
- continue;
- }
+ /* Setting the context window unsets the context area & screen. Avoid doing that, so operators
+ * calling the file browser can operate in the context the browser was opened in. */
+ if (ctx_win != root_win) {
+ CTX_wm_window_set(C, root_win);
+ }
- ScrArea *file_area = ED_fileselect_handler_area_find(win, handler->op);
+ /* The root window may already have a File Browser open. Cancel it if so, only 1 should be open
+ * per window. The root context of this operation is also used for the new operation. */
+ LISTBASE_FOREACH_MUTABLE (wmEventHandler *, handler_base, &root_win->modalhandlers) {
+ if (handler_base->type == WM_HANDLER_TYPE_OP) {
+ wmEventHandler_Op *handler = (wmEventHandler_Op *)handler_base;
+ if (handler->is_fileselect == false) {
+ continue;
+ }
- if (file_area) {
- CTX_wm_area_set(C, file_area);
- wm_handler_fileselect_do(C, &win->modalhandlers, handler, EVT_FILESELECT_CANCEL);
- }
- /* If not found we stop the handler without changing the screen. */
- else {
- wm_handler_fileselect_do(
- C, &win->modalhandlers, handler, EVT_FILESELECT_EXTERNAL_CANCEL);
- }
+ wm_handler_op_context_get_if_valid(
+ C, handler, ctx_win->eventstate, &root_area, &root_region);
+
+ ScrArea *file_area = ED_fileselect_handler_area_find(root_win, handler->op);
+
+ if (file_area) {
+ CTX_wm_area_set(C, file_area);
+ wm_handler_fileselect_do(C, &root_win->modalhandlers, handler, EVT_FILESELECT_CANCEL);
+ }
+ /* If not found we stop the handler without changing the screen. */
+ else {
+ wm_handler_fileselect_do(
+ C, &root_win->modalhandlers, handler, EVT_FILESELECT_EXTERNAL_CANCEL);
}
}
}
+ BLI_assert(root_win != NULL);
+ /* When not reusing the root context from a previous file browsing operation, use the current
+ * area & region, if they are inside the root window. */
+ if (!root_area && ctx_win == root_win) {
+ root_area = CTX_wm_area(C);
+ root_region = CTX_wm_region(C);
+ }
+
wmEventHandler_Op *handler = MEM_callocN(sizeof(*handler), __func__);
handler->head.type = WM_HANDLER_TYPE_OP;
handler->is_fileselect = true;
handler->op = op;
- handler->context.win = CTX_wm_window(C);
- handler->context.area = CTX_wm_area(C);
- handler->context.region = CTX_wm_region(C);
+ handler->context.win = root_win;
+ handler->context.area = root_area;
+ handler->context.region = root_region;
- BLI_addhead(&win->modalhandlers, handler);
+ BLI_addhead(&root_win->modalhandlers, handler);
/* Check props once before invoking if check is available
* ensures initial properties are valid. */
@@ -4041,6 +4151,10 @@ void WM_event_add_fileselect(bContext *C, wmOperator *op)
}
WM_event_fileselect_event(wm, op, EVT_FILESELECT_FULL_OPEN);
+
+ if (ctx_win != root_win) {
+ CTX_wm_window_set(C, ctx_win);
+ }
}
/** \} */
@@ -5727,6 +5841,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++) {
diff --git a/source/blender/windowmanager/intern/wm_window.c b/source/blender/windowmanager/intern/wm_window.c
index 382a37e09e5..c0427f9be9a 100644
--- a/source/blender/windowmanager/intern/wm_window.c
+++ b/source/blender/windowmanager/intern/wm_window.c
@@ -578,6 +578,9 @@ static void wm_window_ghostwindow_add(wmWindowManager *wm,
wm_window_swap_buffers(win);
+ /* Clear double buffer to avoids flickering of new windows on certain drivers. (See T97600) */
+ GPU_clear_color(0.55f, 0.55f, 0.55f, 1.0f);
+
// GHOST_SetWindowState(ghostwin, GHOST_kWindowStateModified);
}
else {
diff --git a/source/blender/windowmanager/xr/intern/wm_xr_session.c b/source/blender/windowmanager/xr/intern/wm_xr_session.c
index 0a76fd0a25f..2a829e274d9 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) {