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

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJoseph Eagar <joeedh@gmail.com>2022-10-15 09:22:01 +0300
committerJoseph Eagar <joeedh@gmail.com>2022-10-15 09:22:01 +0300
commitaa1f2f243ddb7ed340856ddf97ec650407ad386b (patch)
tree471c95b234e7764ff7368e480308f21dc5bb0ca7
parent278a2137f9a5989f8e9ebb30bbfb761608f0de14 (diff)
parentebe9804cfa421b746148f3067797f16e7f460551 (diff)
Merge branch 'master' into temp-pbvh-split
-rw-r--r--CMakeLists.txt28
-rw-r--r--build_files/build_environment/CMakeLists.txt2
-rw-r--r--build_files/build_environment/cmake/cve_check.cmake73
-rw-r--r--build_files/build_environment/cmake/cve_check.csv.in2
-rw-r--r--build_files/build_environment/cmake/download.cmake1
-rw-r--r--build_files/build_environment/cmake/harvest.cmake2
-rw-r--r--build_files/build_environment/cmake/openpgl.cmake4
-rw-r--r--build_files/build_environment/cmake/versions.cmake69
-rw-r--r--build_files/build_environment/cmake/wayland.cmake9
-rw-r--r--build_files/build_environment/cmake/wayland_libdecor.cmake15
-rw-r--r--build_files/build_environment/cmake/wayland_protocols.cmake9
-rwxr-xr-xbuild_files/build_environment/install_deps.sh8
-rw-r--r--build_files/build_environment/linux/linux-centos7-setup.sh89
-rw-r--r--build_files/cmake/platform/platform_unix.cmake76
-rw-r--r--doc/python_api/requirements.txt4
-rw-r--r--intern/cycles/blender/id_map.h32
-rw-r--r--intern/cycles/blender/object.cpp10
-rw-r--r--intern/cycles/blender/pointcloud.cpp4
-rw-r--r--intern/cycles/blender/shader.cpp115
-rw-r--r--intern/cycles/blender/sync.cpp8
-rw-r--r--intern/cycles/blender/sync.h10
-rw-r--r--intern/cycles/device/metal/device_impl.mm4
-rw-r--r--intern/cycles/device/oneapi/device_impl.cpp27
-rw-r--r--intern/cycles/device/oneapi/device_impl.h2
-rw-r--r--intern/cycles/integrator/path_trace.cpp7
-rw-r--r--intern/cycles/integrator/path_trace_work.cpp4
-rw-r--r--intern/cycles/integrator/path_trace_work_cpu.cpp2
-rw-r--r--intern/cycles/integrator/work_balancer.cpp3
-rw-r--r--intern/cycles/kernel/CMakeLists.txt13
-rw-r--r--intern/cycles/kernel/device/oneapi/kernel.cpp105
-rw-r--r--intern/cycles/kernel/device/oneapi/kernel.h2
-rw-r--r--intern/cycles/kernel/integrator/mnee.h10
-rw-r--r--intern/cycles/kernel/sample/pattern.h2
-rw-r--r--intern/cycles/kernel/types.h6
-rw-r--r--intern/cycles/session/session.cpp4
-rw-r--r--intern/ghost/CMakeLists.txt37
-rw-r--r--intern/ghost/GHOST_C-api.h4
-rw-r--r--intern/ghost/GHOST_ISystem.h10
-rw-r--r--intern/ghost/intern/GHOST_C-api.cpp7
-rw-r--r--intern/ghost/intern/GHOST_ContextGLX.cpp2
-rw-r--r--intern/ghost/intern/GHOST_ISystem.cpp19
-rw-r--r--intern/ghost/intern/GHOST_SystemWayland.cpp210
-rw-r--r--intern/ghost/intern/GHOST_SystemWayland.h21
-rw-r--r--intern/ghost/intern/GHOST_SystemX11.cpp4
-rw-r--r--intern/ghost/intern/GHOST_WindowWayland.cpp301
-rw-r--r--intern/guardedalloc/intern/mallocn.c2
-rw-r--r--intern/guardedalloc/intern/mallocn_lockfree_impl.c10
-rw-r--r--intern/mikktspace/mikktspace.hh7
-rw-r--r--intern/wayland_dynload/intern/wayland_dynload_egl.c2
-rw-r--r--release/scripts/modules/bl_i18n_utils/settings.py4
-rw-r--r--release/scripts/modules/bl_i18n_utils/utils_spell_check.py8
-rw-r--r--release/scripts/modules/sys_info.py7
-rw-r--r--release/scripts/presets/keyconfig/keymap_data/blender_default.py2
-rw-r--r--release/scripts/startup/bl_operators/userpref.py11
-rw-r--r--release/scripts/startup/bl_operators/wm.py9
-rw-r--r--release/scripts/startup/bl_ui/properties_particle.py1
-rw-r--r--release/scripts/startup/bl_ui/space_clip.py6
-rw-r--r--release/scripts/startup/bl_ui/space_image.py33
-rw-r--r--release/scripts/startup/bl_ui/space_node.py1
-rw-r--r--release/scripts/startup/bl_ui/space_sequencer.py2
-rw-r--r--release/scripts/startup/bl_ui/space_userpref.py5
-rw-r--r--release/scripts/startup/bl_ui/space_view3d.py6
-rw-r--r--source/blender/blenkernel/BKE_bvhutils.h10
-rw-r--r--source/blender/blenkernel/BKE_customdata.h26
-rw-r--r--source/blender/blenkernel/BKE_duplilist.h8
-rw-r--r--source/blender/blenkernel/BKE_editmesh_cache.h20
-rw-r--r--source/blender/blenkernel/BKE_mesh.h2
-rw-r--r--source/blender/blenkernel/BKE_mesh_mapping.h4
-rw-r--r--source/blender/blenkernel/BKE_mesh_runtime.h19
-rw-r--r--source/blender/blenkernel/BKE_mesh_types.h146
-rw-r--r--source/blender/blenkernel/BKE_nla.h18
-rw-r--r--source/blender/blenkernel/BKE_pbvh.h13
-rw-r--r--source/blender/blenkernel/intern/DerivedMesh.cc38
-rw-r--r--source/blender/blenkernel/intern/bvhutils.cc14
-rw-r--r--source/blender/blenkernel/intern/cloth.c4
-rw-r--r--source/blender/blenkernel/intern/customdata.cc40
-rw-r--r--source/blender/blenkernel/intern/editmesh.cc8
-rw-r--r--source/blender/blenkernel/intern/geometry_component_mesh.cc83
-rw-r--r--source/blender/blenkernel/intern/gpencil_geom.cc4
-rw-r--r--source/blender/blenkernel/intern/mball_tessellate.cc2
-rw-r--r--source/blender/blenkernel/intern/mesh.cc38
-rw-r--r--source/blender/blenkernel/intern/mesh_convert.cc2
-rw-r--r--source/blender/blenkernel/intern/mesh_debug.cc4
-rw-r--r--source/blender/blenkernel/intern/mesh_fair.cc2
-rw-r--r--source/blender/blenkernel/intern/mesh_iterators.cc34
-rw-r--r--source/blender/blenkernel/intern/mesh_mapping.cc4
-rw-r--r--source/blender/blenkernel/intern/mesh_normals.cc78
-rw-r--r--source/blender/blenkernel/intern/mesh_remap.c2
-rw-r--r--source/blender/blenkernel/intern/mesh_runtime.cc168
-rw-r--r--source/blender/blenkernel/intern/mesh_tangent.cc6
-rw-r--r--source/blender/blenkernel/intern/mesh_wrapper.cc74
-rw-r--r--source/blender/blenkernel/intern/modifier.cc6
-rw-r--r--source/blender/blenkernel/intern/multires.cc2
-rw-r--r--source/blender/blenkernel/intern/nla.c28
-rw-r--r--source/blender/blenkernel/intern/object.cc10
-rw-r--r--source/blender/blenkernel/intern/object_dupli.cc32
-rw-r--r--source/blender/blenkernel/intern/object_update.cc4
-rw-r--r--source/blender/blenkernel/intern/paint.cc15
-rw-r--r--source/blender/blenkernel/intern/particle.c5
-rw-r--r--source/blender/blenkernel/intern/particle_distribute.c3
-rw-r--r--source/blender/blenkernel/intern/particle_system.c3
-rw-r--r--source/blender/blenkernel/intern/pbvh.c203
-rw-r--r--source/blender/blenkernel/intern/pbvh_bmesh.c105
-rw-r--r--source/blender/blenkernel/intern/pbvh_intern.h3
-rw-r--r--source/blender/blenkernel/intern/pointcloud.cc6
-rw-r--r--source/blender/blenkernel/intern/rigidbody.c6
-rw-r--r--source/blender/blenkernel/intern/scene.cc2
-rw-r--r--source/blender/blenkernel/intern/shrinkwrap.cc8
-rw-r--r--source/blender/blenkernel/intern/subdiv_ccg.cc27
-rw-r--r--source/blender/blenkernel/intern/subdiv_mesh.cc10
-rw-r--r--source/blender/blenkernel/intern/subdiv_modifier.cc3
-rw-r--r--source/blender/blenloader/intern/blend_validate.cc4
-rw-r--r--source/blender/blenloader/intern/versioning_250.c2
-rw-r--r--source/blender/blenloader/intern/versioning_280.c2
-rw-r--r--source/blender/blenloader/intern/versioning_300.cc7
-rw-r--r--source/blender/bmesh/CMakeLists.txt16
-rw-r--r--source/blender/bmesh/intern/bmesh_construct.c38
-rw-r--r--source/blender/bmesh/intern/bmesh_mesh_convert.cc68
-rw-r--r--source/blender/bmesh/operators/bmo_normals.c4
-rw-r--r--source/blender/compositor/nodes/COM_CryptomatteNode.cc3
-rw-r--r--source/blender/compositor/realtime_compositor/CMakeLists.txt5
-rw-r--r--source/blender/compositor/realtime_compositor/COM_domain.hh2
-rw-r--r--source/blender/compositor/realtime_compositor/algorithms/COM_algorithm_parallel_reduction.hh58
-rw-r--r--source/blender/compositor/realtime_compositor/algorithms/intern/algorithm_parallel_reduction.cc205
-rw-r--r--source/blender/draw/CMakeLists.txt18
-rw-r--r--source/blender/draw/engines/eevee/eevee_materials.c4
-rw-r--r--source/blender/draw/engines/eevee_next/eevee_camera.hh2
-rw-r--r--source/blender/draw/engines/eevee_next/eevee_instance.cc17
-rw-r--r--source/blender/draw/engines/eevee_next/eevee_instance.hh1
-rw-r--r--source/blender/draw/engines/eevee_next/eevee_material.cc5
-rw-r--r--source/blender/draw/engines/eevee_next/eevee_shader_shared.hh2
-rw-r--r--source/blender/draw/engines/eevee_next/eevee_sync.cc14
-rw-r--r--source/blender/draw/engines/eevee_next/eevee_sync.hh10
-rw-r--r--source/blender/draw/engines/eevee_next/eevee_world.cc3
-rw-r--r--source/blender/draw/engines/eevee_next/shaders/infos/eevee_material_info.hh8
-rw-r--r--source/blender/draw/engines/image/image_drawing_mode.hh2
-rw-r--r--source/blender/draw/engines/overlay/overlay_grid.cc6
-rw-r--r--source/blender/draw/engines/workbench/workbench_engine.c5
-rw-r--r--source/blender/draw/intern/DRW_gpu_wrapper.hh29
-rw-r--r--source/blender/draw/intern/draw_attributes.cc7
-rw-r--r--source/blender/draw/intern/draw_attributes.h8
-rw-r--r--source/blender/draw/intern/draw_cache_extract_mesh.cc2
-rw-r--r--source/blender/draw/intern/draw_cache_extract_mesh_render_data.cc6
-rw-r--r--source/blender/draw/intern/draw_cache_impl_curves.cc91
-rw-r--r--source/blender/draw/intern/draw_cache_impl_mesh.cc51
-rw-r--r--source/blender/draw/intern/draw_cache_impl_subdivision.cc2
-rw-r--r--source/blender/draw/intern/draw_cache_impl_volume.cc (renamed from source/blender/draw/intern/draw_cache_impl_volume.c)57
-rw-r--r--source/blender/draw/intern/draw_debug.cc4
-rw-r--r--source/blender/draw/intern/draw_defines.h2
-rw-r--r--source/blender/draw/intern/draw_instance_data.c56
-rw-r--r--source/blender/draw/intern/draw_manager.c24
-rw-r--r--source/blender/draw/intern/draw_manager.cc34
-rw-r--r--source/blender/draw/intern/draw_manager.h8
-rw-r--r--source/blender/draw/intern/draw_manager.hh32
-rw-r--r--source/blender/draw/intern/draw_manager_data.cc11
-rw-r--r--source/blender/draw/intern/draw_manager_exec.c9
-rw-r--r--source/blender/draw/intern/draw_manager_shader.c41
-rw-r--r--source/blender/draw/intern/draw_manager_text.cc9
-rw-r--r--source/blender/draw/intern/draw_pass.hh12
-rw-r--r--source/blender/draw/intern/draw_pbvh.cc30
-rw-r--r--source/blender/draw/intern/draw_resource.cc13
-rw-r--r--source/blender/draw/intern/draw_shader_shared.h17
-rw-r--r--source/blender/draw/intern/draw_view.hh20
-rw-r--r--source/blender/draw/intern/mesh_extractors/extract_mesh.hh10
-rw-r--r--source/blender/draw/intern/mesh_extractors/extract_mesh_ibo_edituv.cc2
-rw-r--r--source/blender/draw/intern/mesh_extractors/extract_mesh_ibo_fdots.cc2
-rw-r--r--source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_fdots_pos.cc2
-rw-r--r--source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_fdots_uv.cc2
-rw-r--r--source/blender/draw/intern/shaders/draw_object_infos_info.hh8
-rw-r--r--source/blender/editors/curve/editcurve.c7
-rw-r--r--source/blender/editors/gpencil/gpencil_data.c2
-rw-r--r--source/blender/editors/include/ED_node.h28
-rw-r--r--source/blender/editors/include/ED_uvedit.h23
-rw-r--r--source/blender/editors/include/UI_view2d.h2
-rw-r--r--source/blender/editors/interface/interface_dropboxes.cc2
-rw-r--r--source/blender/editors/interface/interface_region_menu_pie.cc2
-rw-r--r--source/blender/editors/interface/interface_region_menu_popup.cc41
-rw-r--r--source/blender/editors/interface/interface_region_popup.cc25
-rw-r--r--source/blender/editors/interface/interface_templates.c2
-rw-r--r--source/blender/editors/io/io_alembic.c2
-rw-r--r--source/blender/editors/io/io_collada.c4
-rw-r--r--source/blender/editors/io/io_obj.c37
-rw-r--r--source/blender/editors/io/io_stl_ops.c2
-rw-r--r--source/blender/editors/io/io_usd.c2
-rw-r--r--source/blender/editors/mesh/editmesh_knife.c225
-rw-r--r--source/blender/editors/mesh/editmesh_knife_project.c9
-rw-r--r--source/blender/editors/mesh/editmesh_select.cc6
-rw-r--r--source/blender/editors/mesh/editmesh_undo.cc13
-rw-r--r--source/blender/editors/mesh/mesh_intern.h3
-rw-r--r--source/blender/editors/mesh/meshtools.cc2
-rw-r--r--source/blender/editors/object/object_modifier.cc37
-rw-r--r--source/blender/editors/object/object_relations.c29
-rw-r--r--source/blender/editors/object/object_vgroup.cc113
-rw-r--r--source/blender/editors/physics/particle_edit.c6
-rw-r--r--source/blender/editors/physics/particle_object.c2
-rw-r--r--source/blender/editors/render/render_shading.cc2
-rw-r--r--source/blender/editors/scene/scene_edit.c1
-rw-r--r--source/blender/editors/sculpt_paint/paint_image_ops_paint.cc7
-rw-r--r--source/blender/editors/sculpt_paint/paint_image_proj.c2
-rw-r--r--source/blender/editors/sculpt_paint/paint_utils.c2
-rw-r--r--source/blender/editors/sculpt_paint/sculpt.c21
-rw-r--r--source/blender/editors/sculpt_paint/sculpt_automasking.cc2
-rw-r--r--source/blender/editors/sculpt_paint/sculpt_brush_types.c2
-rw-r--r--source/blender/editors/sculpt_paint/sculpt_face_set.cc113
-rw-r--r--source/blender/editors/sculpt_paint/sculpt_intern.h2
-rw-r--r--source/blender/editors/sculpt_paint/sculpt_ops.c14
-rw-r--r--source/blender/editors/space_clip/clip_ops.c12
-rw-r--r--source/blender/editors/space_image/image_draw.c28
-rw-r--r--source/blender/editors/space_image/image_ops.c8
-rw-r--r--source/blender/editors/space_image/space_image.c3
-rw-r--r--source/blender/editors/space_info/info_stats.cc5
-rw-r--r--source/blender/editors/space_nla/nla_edit.c17
-rw-r--r--source/blender/editors/space_node/add_node_search.cc3
-rw-r--r--source/blender/editors/space_node/link_drag_search.cc4
-rw-r--r--source/blender/editors/space_node/node_draw.cc2
-rw-r--r--source/blender/editors/space_node/node_edit.cc43
-rw-r--r--source/blender/editors/space_node/node_intern.hh2
-rw-r--r--source/blender/editors/space_node/node_ops.cc12
-rw-r--r--source/blender/editors/space_node/node_relationships.cc329
-rw-r--r--source/blender/editors/space_outliner/outliner_dragdrop.cc2
-rw-r--r--source/blender/editors/space_outliner/outliner_draw.cc76
-rw-r--r--source/blender/editors/space_spreadsheet/spreadsheet_data_source_geometry.cc31
-rw-r--r--source/blender/editors/space_view3d/drawobject.c5
-rw-r--r--source/blender/editors/space_view3d/space_view3d.cc2
-rw-r--r--source/blender/editors/space_view3d/view3d_gizmo_preselect_type.cc6
-rw-r--r--source/blender/editors/space_view3d/view3d_iterators.cc8
-rw-r--r--source/blender/editors/space_view3d/view3d_navigate_ndof.c15
-rw-r--r--source/blender/editors/transform/CMakeLists.txt2
-rw-r--r--source/blender/editors/transform/transform.c52
-rw-r--r--source/blender/editors/transform/transform.h9
-rw-r--r--source/blender/editors/transform/transform_convert.h10
-rw-r--r--source/blender/editors/transform/transform_convert_nla.c43
-rw-r--r--source/blender/editors/transform/transform_convert_node.cc (renamed from source/blender/editors/transform/transform_convert_node.c)34
-rw-r--r--source/blender/editors/transform/transform_ops.c23
-rw-r--r--source/blender/editors/transform/transform_snap.h8
-rw-r--r--source/blender/editors/transform/transform_snap_object.cc28
-rw-r--r--source/blender/editors/uvedit/uvedit_islands.cc264
-rw-r--r--source/blender/editors/uvedit/uvedit_unwrap_ops.c103
-rw-r--r--source/blender/geometry/intern/add_curves_on_mesh.cc7
-rw-r--r--source/blender/gpencil_modifiers/intern/MOD_gpenciloutline.c1
-rw-r--r--source/blender/gpencil_modifiers/intern/lineart/lineart_cpu.c4
-rw-r--r--source/blender/gpu/CMakeLists.txt4
-rw-r--r--source/blender/gpu/GPU_material.h15
-rw-r--r--source/blender/gpu/GPU_uniform_buffer.h1
-rw-r--r--source/blender/gpu/intern/gpu_codegen.cc6
-rw-r--r--source/blender/gpu/intern/gpu_material.c6
-rw-r--r--source/blender/gpu/intern/gpu_node_graph.c77
-rw-r--r--source/blender/gpu/intern/gpu_node_graph.h9
-rw-r--r--source/blender/gpu/metal/mtl_immediate.mm2
-rw-r--r--source/blender/gpu/shaders/compositor/compositor_blur_variable_size.glsl60
-rw-r--r--source/blender/gpu/shaders/compositor/compositor_parallel_reduction.glsl98
-rw-r--r--source/blender/gpu/shaders/compositor/infos/compositor_blur_variable_size_info.hh15
-rw-r--r--source/blender/gpu/shaders/compositor/infos/compositor_parallel_reduction_info.hh76
-rw-r--r--source/blender/gpu/shaders/material/gpu_shader_material_attribute.glsl25
-rw-r--r--source/blender/ikplugin/intern/itasc_plugin.cpp2
-rw-r--r--source/blender/imbuf/IMB_imbuf.h7
-rw-r--r--source/blender/imbuf/intern/anim_movie.c12
-rw-r--r--source/blender/imbuf/intern/transform.cc2
-rw-r--r--source/blender/imbuf/intern/util_gpu.c16
-rw-r--r--source/blender/io/alembic/intern/alembic_capi.cc6
-rw-r--r--source/blender/io/usd/intern/usd_capi_import.cc7
-rw-r--r--source/blender/io/wavefront_obj/IO_wavefront_obj.h3
-rw-r--r--source/blender/io/wavefront_obj/exporter/obj_export_file_writer.cc6
-rw-r--r--source/blender/io/wavefront_obj/exporter/obj_export_mesh.cc4
-rw-r--r--source/blender/io/wavefront_obj/exporter/obj_export_mesh.hh2
-rw-r--r--source/blender/io/wavefront_obj/exporter/obj_export_nurbs.cc4
-rw-r--r--source/blender/io/wavefront_obj/exporter/obj_export_nurbs.hh2
-rw-r--r--source/blender/io/wavefront_obj/importer/importer_mesh_utils.cc3
-rw-r--r--source/blender/io/wavefront_obj/importer/obj_import_file_reader.cc14
-rw-r--r--source/blender/io/wavefront_obj/importer/obj_importer.cc9
-rw-r--r--source/blender/io/wavefront_obj/tests/obj_exporter_tests.cc4
-rw-r--r--source/blender/io/wavefront_obj/tests/obj_exporter_tests.hh2
-rw-r--r--source/blender/io/wavefront_obj/tests/obj_importer_tests.cc71
-rw-r--r--source/blender/makesdna/DNA_brush_enums.h5
-rw-r--r--source/blender/makesdna/DNA_mesh_types.h143
-rw-r--r--source/blender/makesdna/DNA_meshdata_types.h12
-rw-r--r--source/blender/makesdna/DNA_node_types.h21
-rw-r--r--source/blender/makesdna/DNA_scene_types.h2
-rw-r--r--source/blender/makesdna/DNA_space_types.h16
-rw-r--r--source/blender/makesdna/DNA_userdef_enums.h1
-rw-r--r--source/blender/makesdna/DNA_windowmanager_types.h4
-rw-r--r--source/blender/makesrna/intern/rna_brush.c2
-rw-r--r--source/blender/makesrna/intern/rna_fluid.c16
-rw-r--r--source/blender/makesrna/intern/rna_layer.c12
-rw-r--r--source/blender/makesrna/intern/rna_mesh.c46
-rw-r--r--source/blender/makesrna/intern/rna_nodetree.c17
-rw-r--r--source/blender/makesrna/intern/rna_scene.c1
-rw-r--r--source/blender/makesrna/intern/rna_space.c20
-rw-r--r--source/blender/makesrna/intern/rna_texture.c3
-rw-r--r--source/blender/makesrna/intern/rna_userdef.c12
-rw-r--r--source/blender/makesrna/intern/rna_wm.c16
-rw-r--r--source/blender/modifiers/intern/MOD_cast.c3
-rw-r--r--source/blender/modifiers/intern/MOD_datatransfer.cc2
-rw-r--r--source/blender/modifiers/intern/MOD_multires.cc12
-rw-r--r--source/blender/modifiers/intern/MOD_normal_edit.cc2
-rw-r--r--source/blender/modifiers/intern/MOD_particlesystem.cc2
-rw-r--r--source/blender/modifiers/intern/MOD_remesh.c5
-rw-r--r--source/blender/modifiers/intern/MOD_subsurf.cc2
-rw-r--r--source/blender/modifiers/intern/MOD_util.cc6
-rw-r--r--source/blender/modifiers/intern/MOD_uvproject.cc8
-rw-r--r--source/blender/modifiers/intern/MOD_uvwarp.cc8
-rw-r--r--source/blender/modifiers/intern/MOD_wave.cc3
-rw-r--r--source/blender/modifiers/intern/MOD_weighted_normal.cc6
-rw-r--r--source/blender/modifiers/intern/MOD_weightvgedit.cc12
-rw-r--r--source/blender/modifiers/intern/MOD_weightvgmix.cc8
-rw-r--r--source/blender/modifiers/intern/MOD_weightvgproximity.cc12
-rw-r--r--source/blender/nodes/CMakeLists.txt2
-rw-r--r--source/blender/nodes/NOD_static_types.h2
-rw-r--r--source/blender/nodes/composite/CMakeLists.txt1
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_bokehblur.cc63
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_cryptomatte.cc3
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_levels.cc144
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_pixelate.cc5
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_scale.cc1
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_sepcomb_hsva.cc6
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_sepcomb_rgba.cc6
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_sepcomb_ycca.cc6
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_sepcomb_yuva.cc6
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_input_mesh_edge_vertices.cc2
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_mesh_topology_corners_of_vertex.cc4
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_mesh_topology_edges_of_corner.cc4
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_mesh_topology_edges_of_vertex.cc4
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_mesh_topology_face_of_corner.cc4
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_mesh_topology_offset_corner_in_face.cc2
-rw-r--r--source/blender/nodes/intern/node_util.cc (renamed from source/blender/nodes/intern/node_util.c)16
-rw-r--r--source/blender/nodes/intern/socket_search_link.cc63
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_attribute.cc17
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_curves.cc15
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_mix.cc24
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_mix_rgb.cc2
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_sepcomb_hsv.cc4
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_sepcomb_rgb.cc6
-rw-r--r--source/blender/nodes/texture/nodes/node_texture_compose.c3
-rw-r--r--source/blender/python/intern/bpy.c25
-rw-r--r--source/blender/render/intern/bake.c2
-rw-r--r--source/blender/render/intern/texture_margin.cc4
-rw-r--r--source/blender/simulation/intern/hair_volume.cpp14
-rw-r--r--source/blender/windowmanager/WM_api.h7
-rw-r--r--source/blender/windowmanager/intern/wm_operators.c51
-rw-r--r--source/blender/windowmanager/intern/wm_window.c18
-rw-r--r--source/creator/creator_signals.c2
-rw-r--r--tests/python/CMakeLists.txt18
-rw-r--r--tests/python/bl_io_curve_svg_test.py61
-rw-r--r--tests/python/cycles_render_tests.py2
344 files changed, 5326 insertions, 2254 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 8bb685195bd..408cf819ce8 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -242,17 +242,17 @@ if(UNIX AND NOT (APPLE OR HAIKU))
option(WITH_GHOST_X11 "Enable building Blender against X11 for windowing" ON)
mark_as_advanced(WITH_GHOST_X11)
- option(WITH_GHOST_WAYLAND "Enable building Blender against Wayland for windowing (under development)" OFF)
+ option(WITH_GHOST_WAYLAND "Enable building Blender against Wayland for windowing" ON)
mark_as_advanced(WITH_GHOST_WAYLAND)
if(WITH_GHOST_WAYLAND)
- option(WITH_GHOST_WAYLAND_LIBDECOR "Optionally build with LibDecor window decorations" OFF)
+ option(WITH_GHOST_WAYLAND_LIBDECOR "Optionally build with LibDecor window decorations" ON)
mark_as_advanced(WITH_GHOST_WAYLAND_LIBDECOR)
option(WITH_GHOST_WAYLAND_DBUS "Optionally build with DBUS support (used for Cursor themes). May hang on startup systems where DBUS is not used." OFF)
mark_as_advanced(WITH_GHOST_WAYLAND_DBUS)
- option(WITH_GHOST_WAYLAND_DYNLOAD "Enable runtime dynamic WAYLAND libraries loading" OFF)
+ option(WITH_GHOST_WAYLAND_DYNLOAD "Enable runtime dynamic WAYLAND libraries loading" ON)
mark_as_advanced(WITH_GHOST_WAYLAND_DYNLOAD)
endif()
endif()
@@ -1913,9 +1913,25 @@ if(FIRST_RUN)
info_cfg_option(WITH_INSTALL_PORTABLE)
info_cfg_option(WITH_MEM_JEMALLOC)
info_cfg_option(WITH_MEM_VALGRIND)
- info_cfg_option(WITH_X11_XF86VMODE)
- info_cfg_option(WITH_X11_XFIXES)
- info_cfg_option(WITH_X11_XINPUT)
+
+ info_cfg_text("GHOST Options:")
+ info_cfg_option(WITH_GHOST_DEBUG)
+ info_cfg_option(WITH_GHOST_SDL)
+ if(UNIX AND NOT APPLE)
+ info_cfg_option(WITH_GHOST_X11)
+ info_cfg_option(WITH_GHOST_WAYLAND)
+ if(WITH_GHOST_X11)
+ info_cfg_option(WITH_GHOST_XDND)
+ info_cfg_option(WITH_X11_XF86VMODE)
+ info_cfg_option(WITH_X11_XFIXES)
+ info_cfg_option(WITH_X11_XINPUT)
+ endif()
+ if(WITH_GHOST_WAYLAND)
+ info_cfg_option(WITH_GHOST_WAYLAND_DYNLOAD)
+ info_cfg_option(WITH_GHOST_WAYLAND_LIBDECOR)
+ info_cfg_option(WITH_GHOST_WAYLAND_DBUS)
+ endif()
+ endif()
info_cfg_text("Image Formats:")
info_cfg_option(WITH_IMAGE_CINEON)
diff --git a/build_files/build_environment/CMakeLists.txt b/build_files/build_environment/CMakeLists.txt
index 468a434b887..4f40f44ad18 100644
--- a/build_files/build_environment/CMakeLists.txt
+++ b/build_files/build_environment/CMakeLists.txt
@@ -172,6 +172,8 @@ if(UNIX AND NOT APPLE)
include(cmake/wayland_protocols.cmake)
# Can be removed when the build-bot upgrades to v1.20.x or newer.
include(cmake/wayland.cmake)
+ include(cmake/wayland_libdecor.cmake)
endif()
include(cmake/harvest.cmake)
+include(cmake/cve_check.cmake)
diff --git a/build_files/build_environment/cmake/cve_check.cmake b/build_files/build_environment/cmake/cve_check.cmake
new file mode 100644
index 00000000000..dfb190bcffa
--- /dev/null
+++ b/build_files/build_environment/cmake/cve_check.cmake
@@ -0,0 +1,73 @@
+# SPDX-License-Identifier: GPL-2.0-or-later
+
+# CVE Check requirements
+#
+# - A working installation of intels cve-bin-tool [1] has to be available in
+# your path
+#
+# - Not strictly required, but highly recommended is obtaining a NVD key from
+# nist since it significantly speeds up downloading/updating the required
+# databases one can request a key on the following website:
+# https://nvd.nist.gov/developers/request-an-api-key
+
+# Bill of Materials construction
+#
+# This constructs a CSV cve-bin-tool [1] can read and process. Sadly
+# cve-bin-tool at this point does not take a list of CPE's and output a check
+# based on that list. so we need to pick apart the CPE retrieve the vendor,
+# product and version tokens and generate a CSV.
+#
+# [1] https://github.com/intel/cve-bin-tool
+
+# Because not all deps are downloaded (ie python packages) but can still have a
+# xxx_CPE declared loop over all variables and look for variables ending in CPE.
+
+set(SBOMCONTENTS)
+get_cmake_property(_variableNames VARIABLES)
+foreach (_variableName ${_variableNames})
+ if(_variableName MATCHES "CPE$")
+ string(REPLACE ":" ";" CPE_LIST ${${_variableName}})
+ list(GET CPE_LIST 3 CPE_VENDOR)
+ list(GET CPE_LIST 4 CPE_NAME)
+ list(GET CPE_LIST 5 CPE_VERSION)
+ set(SBOMCONTENTS "${SBOMCONTENTS}${CPE_VENDOR},${CPE_NAME},${CPE_VERSION}\n")
+ endif()
+endforeach()
+configure_file(${CMAKE_SOURCE_DIR}/cmake/cve_check.csv.in ${CMAKE_CURRENT_BINARY_DIR}/cve_check.csv @ONLY)
+
+# Custom Targets
+#
+# This defines two new custom targets one could run in the build folder
+# `cve_check` which will output the report to the console, and `cve_check_html`
+# which will write out blender_dependencies.html in the build folder that one
+# could share with other people or be used to get more information on the
+# reported CVE's.
+#
+# cve-bin-tool takes data from the nist nvd database which rate limits
+# unauthenticated requests to 1 requests per 6 seconds making the database
+# download take "quite a bit" of time.
+#
+# When adding -DCVE_CHECK_NVD_KEY=your_api_key_here to your cmake invocation
+# this key will be passed on to cve-bin-tool speeding up the process.
+#
+if(DEFINED CVE_CHECK_NVD_KEY)
+ set(NVD_ARGS --nvd-api-key ${CVE_CHECK_NVD_KEY})
+endif()
+
+# This will just report to the console
+add_custom_target(cve_check
+ COMMAND cve-bin-tool
+ ${NVD_ARGS}
+ -i ${CMAKE_CURRENT_BINARY_DIR}/cve_check.csv
+ --affected-versions
+ SOURCES ${CMAKE_CURRENT_BINARY_DIR}/cve_check.csv
+)
+
+# This will write out blender_dependencies.html
+add_custom_target(cve_check_html
+ COMMAND cve-bin-tool
+ ${NVD_ARGS}
+ -i ${CMAKE_CURRENT_BINARY_DIR}/cve_check.csv
+ -f html
+ SOURCES ${CMAKE_CURRENT_BINARY_DIR}/cve_check.csv
+)
diff --git a/build_files/build_environment/cmake/cve_check.csv.in b/build_files/build_environment/cmake/cve_check.csv.in
new file mode 100644
index 00000000000..6e7e8db5609
--- /dev/null
+++ b/build_files/build_environment/cmake/cve_check.csv.in
@@ -0,0 +1,2 @@
+vendor,product,version
+@SBOMCONTENTS@
diff --git a/build_files/build_environment/cmake/download.cmake b/build_files/build_environment/cmake/download.cmake
index 7c91fe5455e..35bc028a1e3 100644
--- a/build_files/build_environment/cmake/download.cmake
+++ b/build_files/build_environment/cmake/download.cmake
@@ -133,6 +133,7 @@ download_source(NASM)
download_source(XR_OPENXR_SDK)
download_source(WL_PROTOCOLS)
download_source(WAYLAND)
+download_source(WAYLAND_LIBDECOR)
download_source(ISPC)
download_source(GMP)
download_source(POTRACE)
diff --git a/build_files/build_environment/cmake/harvest.cmake b/build_files/build_environment/cmake/harvest.cmake
index 6c920e651fe..9afc1974677 100644
--- a/build_files/build_environment/cmake/harvest.cmake
+++ b/build_files/build_environment/cmake/harvest.cmake
@@ -118,6 +118,8 @@ else()
harvest(wayland-protocols/share/wayland-protocols wayland-protocols/share/wayland-protocols/ "*.xml")
harvest(wayland/bin wayland/bin "wayland-scanner")
+ harvest(wayland/include wayland/include "*.h")
+ harvest(wayland_libdecor/include wayland_libdecor/include "*.h")
else()
harvest(blosc/lib openvdb/lib "*.a")
harvest(xml2/lib opencollada/lib "*.a")
diff --git a/build_files/build_environment/cmake/openpgl.cmake b/build_files/build_environment/cmake/openpgl.cmake
index e6b0cd8eb4a..b41264ac22b 100644
--- a/build_files/build_environment/cmake/openpgl.cmake
+++ b/build_files/build_environment/cmake/openpgl.cmake
@@ -4,11 +4,9 @@
# library itself does not depend on them, so should give no problems.
set(OPENPGL_EXTRA_ARGS
- -DOPENPGL_BUILD_PYTHON=OFF
-DOPENPGL_BUILD_STATIC=ON
-DOPENPGL_TBB_ROOT=${LIBDIR}/tbb
-DTBB_ROOT=${LIBDIR}/tbb
- -Dembree_DIR=${LIBDIR}/embree/lib/cmake/embree-${EMBREE_VERSION}
-DCMAKE_DEBUG_POSTFIX=_d
)
@@ -31,7 +29,6 @@ ExternalProject_Add(external_openpgl
add_dependencies(
external_openpgl
external_tbb
- external_embree
)
if(WIN32)
@@ -43,6 +40,7 @@ if(WIN32)
else()
ExternalProject_Add_Step(external_openpgl after_install
COMMAND ${CMAKE_COMMAND} -E copy ${LIBDIR}/openpgl/lib/openpgl_d.lib ${HARVEST_TARGET}/openpgl/lib/openpgl_d.lib
+ COMMAND ${CMAKE_COMMAND} -E copy ${LIBDIR}/openpgl/lib/cmake/openpgl-${OPENPGL_SHORT_VERSION}/openpgl_Exports-debug.cmake ${HARVEST_TARGET}/openpgl/lib/cmake/openpgl-${OPENPGL_SHORT_VERSION}/openpgl_Exports-debug.cmake
DEPENDEES install
)
endif()
diff --git a/build_files/build_environment/cmake/versions.cmake b/build_files/build_environment/cmake/versions.cmake
index 01996efa9bd..bfc6d27f74d 100644
--- a/build_files/build_environment/cmake/versions.cmake
+++ b/build_files/build_environment/cmake/versions.cmake
@@ -1,10 +1,19 @@
# SPDX-License-Identifier: GPL-2.0-or-later
+# CPE's are used to identify dependencies, for more information on what they
+# are please see https://nvd.nist.gov/products/cpe
+#
+# We use them in combination with cve-bin-tool to scan for known security issues.
+#
+# Not all of our dependencies are currently in the nvd database so not all
+# dependencies have one assigned.
+
set(ZLIB_VERSION 1.2.12)
set(ZLIB_URI https://zlib.net/zlib-${ZLIB_VERSION}.tar.gz)
set(ZLIB_HASH 5fc414a9726be31427b440b434d05f78)
set(ZLIB_HASH_TYPE MD5)
set(ZLIB_FILE zlib-${ZLIB_VERSION}.tar.gz)
+set(ZLIB_CPE "cpe:2.3:a:zlib:zlib:${ZLIB_VERSION}:*:*:*:*:*:*:*")
set(OPENAL_VERSION 1.21.1)
set(OPENAL_URI http://openal-soft.org/openal-releases/openal-soft-${OPENAL_VERSION}.tar.bz2)
@@ -17,12 +26,14 @@ set(PNG_URI http://prdownloads.sourceforge.net/libpng/libpng-${PNG_VERSION}.tar.
set(PNG_HASH 505e70834d35383537b6491e7ae8641f1a4bed1876dbfe361201fc80868d88ca)
set(PNG_HASH_TYPE SHA256)
set(PNG_FILE libpng-${PNG_VERSION}.tar.xz)
+set(PNG_CPE "cpe:2.3:a:libpng:libpng:${PNG_VERSION}:*:*:*:*:*:*:*")
set(JPEG_VERSION 2.1.3)
set(JPEG_URI https://github.com/libjpeg-turbo/libjpeg-turbo/archive/${JPEG_VERSION}.tar.gz)
set(JPEG_HASH 627b980fad0573e08e4c3b80b290fc91)
set(JPEG_HASH_TYPE MD5)
set(JPEG_FILE libjpeg-turbo-${JPEG_VERSION}.tar.gz)
+set(JPEG_CPE "cpe:2.3:a:d.r.commander:libjpeg-turbo:${JPEG_VERSION}:*:*:*:*:*:*:*")
set(BOOST_VERSION 1.78.0)
set(BOOST_VERSION_SHORT 1.78)
@@ -32,12 +43,14 @@ set(BOOST_URI https://boostorg.jfrog.io/artifactory/main/release/${BOOST_VERSION
set(BOOST_HASH c2f6428ac52b0e5a3c9b2e1d8cc832b5)
set(BOOST_HASH_TYPE MD5)
set(BOOST_FILE boost_${BOOST_VERSION_NODOTS}.tar.gz)
+set(BOOST_CPE "cpe:2.3:a:boost:boost:${BOOST_VERSION}:*:*:*:*:*:*:*")
set(BLOSC_VERSION 1.21.1)
set(BLOSC_URI https://github.com/Blosc/c-blosc/archive/v${BLOSC_VERSION}.tar.gz)
set(BLOSC_HASH 134b55813b1dca57019d2a2dc1f7a923)
set(BLOSC_HASH_TYPE MD5)
set(BLOSC_FILE blosc-${BLOSC_VERSION}.tar.gz)
+set(BLOSC_CPE "cpe:2.3:a:c-blosc2_project:c-blosc2:${BLOSC_VERSION}:*:*:*:*:*:*:*")
set(PTHREADS_VERSION 3.0.0)
set(PTHREADS_URI http://prdownloads.sourceforge.net/pthreads4w/pthreads4w-code-v${PTHREADS_VERSION}.zip)
@@ -50,6 +63,7 @@ set(OPENEXR_URI https://github.com/AcademySoftwareFoundation/openexr/archive/v${
set(OPENEXR_HASH a92f38eedd43e56c0af56d4852506886)
set(OPENEXR_HASH_TYPE MD5)
set(OPENEXR_FILE openexr-${OPENEXR_VERSION}.tar.gz)
+set(OPENEXR_CPE "cpe:2.3:a:openexr:openexr:${OPENEXR_VERSION}:*:*:*:*:*:*:*")
set(IMATH_VERSION 3.1.5)
set(IMATH_URI https://github.com/AcademySoftwareFoundation/Imath/archive/v${OPENEXR_VERSION}.tar.gz)
@@ -79,6 +93,7 @@ set(FREETYPE_URI http://prdownloads.sourceforge.net/freetype/freetype-${FREETYPE
set(FREETYPE_HASH bd4e3b007474319909a6b79d50908e85)
set(FREETYPE_HASH_TYPE MD5)
set(FREETYPE_FILE freetype-${FREETYPE_VERSION}.tar.gz)
+SET(FREETYPE_CPE "cpe:2.3:a:freetype:freetype:${FREETYPE_VERSION}:*:*:*:*:*:*:*")
set(EPOXY_VERSION 1.5.10)
set(EPOXY_URI https://github.com/anholt/libepoxy/archive/refs/tags/${EPOXY_VERSION}.tar.gz)
@@ -97,6 +112,7 @@ set(ALEMBIC_URI https://github.com/alembic/alembic/archive/${ALEMBIC_VERSION}.ta
set(ALEMBIC_HASH 2cd8d6e5a3ac4a014e24a4b04f4fadf9)
set(ALEMBIC_HASH_TYPE MD5)
set(ALEMBIC_FILE alembic-${ALEMBIC_VERSION}.tar.gz)
+SET(FREETYPE_CPE "cpe:2.3:a:freetype:freetype:${FREETYPE_VERSION}:*:*:*:*:*:*:*")
set(OPENSUBDIV_VERSION v3_4_4)
set(OPENSUBDIV_URI https://github.com/PixarAnimationStudios/OpenSubdiv/archive/${OPENSUBDIV_VERSION}.tar.gz)
@@ -109,6 +125,7 @@ set(SDL_URI https://www.libsdl.org/release/SDL2-${SDL_VERSION}.tar.gz)
set(SDL_HASH a53acc02e1cca98c4123229069b67c9e)
set(SDL_HASH_TYPE MD5)
set(SDL_FILE SDL2-${SDL_VERSION}.tar.gz)
+set(SDL_CPE "cpe:2.3:a:libsdl:sdl:${SDL_VERSION}:*:*:*:*:*:*:*")
set(OPENCOLLADA_VERSION v1.6.68)
set(OPENCOLLADA_URI https://github.com/KhronosGroup/OpenCOLLADA/archive/${OPENCOLLADA_VERSION}.tar.gz)
@@ -127,6 +144,7 @@ set(LLVM_URI https://github.com/llvm/llvm-project/releases/download/llvmorg-${LL
set(LLVM_HASH 5a4fab4d7fc84aefffb118ac2c8a4fc0)
set(LLVM_HASH_TYPE MD5)
set(LLVM_FILE llvm-project-${LLVM_VERSION}.src.tar.xz)
+set(LLVM_CPE "cpe:2.3:a:llvm:compiler:${LLVM_VERSION}:*:*:*:*:*:*:*")
if(APPLE)
# Cloth physics test is crashing due to this bug:
@@ -154,6 +172,7 @@ set(FMT_URI https://github.com/fmtlib/fmt/archive/refs/tags/${FMT_VERSION}.tar.g
set(FMT_HASH 7bce0e9e022e586b178b150002e7c2339994e3c2bbe44027e9abb0d60f9cce83)
set(FMT_HASH_TYPE SHA256)
set(FMT_FILE fmt-${FMT_VERSION}.tar.gz)
+set(FMT_CPE "cpe:2.3:a:fmt:fmt:${FMT_VERSION}:*:*:*:*:*:*:*")
# 0.6.2 is currently oiio's preferred version although never versions may be available.
# the preferred version can be found in oiio's externalpackages.cmake
@@ -168,6 +187,7 @@ set(TIFF_URI http://download.osgeo.org/libtiff/tiff-${TIFF_VERSION}.tar.gz)
set(TIFF_HASH 376f17f189e9d02280dfe709b2b2bbea)
set(TIFF_HASH_TYPE MD5)
set(TIFF_FILE tiff-${TIFF_VERSION}.tar.gz)
+set(TIFF_CPE "cpe:2.3:a:libtiff:libtiff:${TIFF_VERSION}:*:*:*:*:*:*:*")
set(OSL_VERSION 1.11.17.0)
set(OSL_URI https://github.com/imageworks/OpenShadingLanguage/archive/Release-${OSL_VERSION}.tar.gz)
@@ -182,12 +202,15 @@ set(PYTHON_URI https://www.python.org/ftp/python/${PYTHON_VERSION}/Python-${PYTH
set(PYTHON_HASH 14e8c22458ed7779a1957b26cde01db9)
set(PYTHON_HASH_TYPE MD5)
set(PYTHON_FILE Python-${PYTHON_VERSION}.tar.xz)
+set(PYTHON_CPE "cpe:2.3:a:python:python:${PYTHON_VERSION}:-:*:*:*:*:*:*")
-set(TBB_VERSION 2020_U3)
+set(TBB_YEAR 2020)
+set(TBB_VERSION ${TBB_YEAR}_U3)
set(TBB_URI https://github.com/oneapi-src/oneTBB/archive/${TBB_VERSION}.tar.gz)
set(TBB_HASH 55ec8df6eae5ed6364a47f0e671e460c)
set(TBB_HASH_TYPE MD5)
set(TBB_FILE oneTBB-${TBB_VERSION}.tar.gz)
+set(TBB_CPE "cpe:2.3:a:intel:threading_building_blocks:${TBB_YEAR}:*:*:*:*:*:*:*")
set(OPENVDB_VERSION 9.0.0)
set(OPENVDB_URI https://github.com/AcademySoftwareFoundation/openvdb/archive/v${OPENVDB_VERSION}.tar.gz)
@@ -198,6 +221,7 @@ set(OPENVDB_FILE openvdb-${OPENVDB_VERSION}.tar.gz)
set(IDNA_VERSION 3.3)
set(CHARSET_NORMALIZER_VERSION 2.0.10)
set(URLLIB3_VERSION 1.26.8)
+set(URLLIB3_CPE "cpe:2.3:a:urllib3:urllib3:${URLLIB3_VERSION}:*:*:*:*:*:*:*")
set(CERTIFI_VERSION 2021.10.8)
set(REQUESTS_VERSION 2.27.1)
set(CYTHON_VERSION 0.29.26)
@@ -214,12 +238,14 @@ set(NUMPY_URI https://github.com/numpy/numpy/releases/download/v${NUMPY_VERSION}
set(NUMPY_HASH 252de134862a27bd66705d29622edbfe)
set(NUMPY_HASH_TYPE MD5)
set(NUMPY_FILE numpy-${NUMPY_VERSION}.zip)
+set(NUMPY_CPE "cpe:2.3:a:numpy:numpy:${NUMPY_VERSION}:*:*:*:*:*:*:*")
set(LAME_VERSION 3.100)
set(LAME_URI http://downloads.sourceforge.net/project/lame/lame/3.100/lame-${LAME_VERSION}.tar.gz)
set(LAME_HASH 83e260acbe4389b54fe08e0bdbf7cddb)
set(LAME_HASH_TYPE MD5)
set(LAME_FILE lame-${LAME_VERSION}.tar.gz)
+set(LAME_CPE "cpe:2.3:a:lame_project:lame:${LAME_VERSION}:*:*:*:*:*:*:*")
set(OGG_VERSION 1.3.5)
set(OGG_URI http://downloads.xiph.org/releases/ogg/libogg-${OGG_VERSION}.tar.gz)
@@ -232,6 +258,7 @@ set(VORBIS_URI http://downloads.xiph.org/releases/vorbis/libvorbis-${VORBIS_VERS
set(VORBIS_HASH 0e982409a9c3fc82ee06e08205b1355e5c6aa4c36bca58146ef399621b0ce5ab)
set(VORBIS_HASH_TYPE SHA256)
set(VORBIS_FILE libvorbis-${VORBIS_VERSION}.tar.gz)
+set(VORBIS_CPE "cpe:2.3:a:xiph.org:libvorbis:${VORBIS_VERSION}:*:*:*:*:*:*:*")
set(THEORA_VERSION 1.1.1)
set(THEORA_URI http://downloads.xiph.org/releases/theora/libtheora-${THEORA_VERSION}.tar.bz2)
@@ -244,12 +271,14 @@ set(FLAC_URI http://downloads.xiph.org/releases/flac/flac-${FLAC_VERSION}.tar.xz
set(FLAC_HASH 8ff0607e75a322dd7cd6ec48f4f225471404ae2730d0ea945127b1355155e737 )
set(FLAC_HASH_TYPE SHA256)
set(FLAC_FILE flac-${FLAC_VERSION}.tar.xz)
+set(FLAC_CPE "cpe:2.3:a:flac_project:flac:${FLAC_VERSION}:*:*:*:*:*:*:*")
set(VPX_VERSION 1.11.0)
set(VPX_URI https://github.com/webmproject/libvpx/archive/v${VPX_VERSION}/libvpx-v${VPX_VERSION}.tar.gz)
set(VPX_HASH 965e51c91ad9851e2337aebcc0f517440c637c506f3a03948062e3d5ea129a83)
set(VPX_HASH_TYPE SHA256)
set(VPX_FILE libvpx-v${VPX_VERSION}.tar.gz)
+set(VPX_CPE "cpe:2.3:a:webmproject:libvpx:${VPX_VERSION}:*:*:*:*:*:*:*")
set(OPUS_VERSION 1.3.1)
set(OPUS_URI https://archive.mozilla.org/pub/opus/opus-${OPUS_VERSION}.tar.gz)
@@ -275,12 +304,14 @@ set(OPENJPEG_URI https://github.com/uclouvain/openjpeg/archive/v${OPENJPEG_VERSI
set(OPENJPEG_HASH 8702ba68b442657f11aaeb2b338443ca8d5fb95b0d845757968a7be31ef7f16d)
set(OPENJPEG_HASH_TYPE SHA256)
set(OPENJPEG_FILE openjpeg-v${OPENJPEG_VERSION}.tar.gz)
+set(OPENJPEG_CPE "cpe:2.3:a:uclouvain:openjpeg:${OPENJPEG_VERSION}:*:*:*:*:*:*:*")
set(FFMPEG_VERSION 5.0)
set(FFMPEG_URI http://ffmpeg.org/releases/ffmpeg-${FFMPEG_VERSION}.tar.bz2)
set(FFMPEG_HASH c0130b8db2c763430fd1c6905288d61bc44ee0548ad5fcd2dfd650b88432bed9)
set(FFMPEG_HASH_TYPE SHA256)
set(FFMPEG_FILE ffmpeg-${FFMPEG_VERSION}.tar.bz2)
+set(FFMPEG_CPE "cpe:2.3:a:ffmpeg:ffmpeg:${FFMPEG_VERSION}:*:*:*:*:*:*:*")
set(FFTW_VERSION 3.3.10)
set(FFTW_URI http://www.fftw.org/fftw-${FFTW_VERSION}.tar.gz)
@@ -299,12 +330,14 @@ set(SNDFILE_URI http://www.mega-nerd.com/libsndfile/files/libsndfile-${SNDFILE_V
set(SNDFILE_HASH 646b5f98ce89ac60cdb060fcd398247c)
set(SNDFILE_HASH_TYPE MD5)
set(SNDFILE_FILE libsndfile-${SNDFILE_VERSION}.tar.gz)
+set(SNDFILE_CPE "cpe:2.3:a:libsndfile_project:libsndfile:${SNDFILE_VERSION}:*:*:*:*:*:*:*")
set(WEBP_VERSION 1.2.2)
set(WEBP_URI https://storage.googleapis.com/downloads.webmproject.org/releases/webp/libwebp-${WEBP_VERSION}.tar.gz)
set(WEBP_HASH b5e2e414a8adee4c25fe56b18dd9c549)
set(WEBP_HASH_TYPE MD5)
set(WEBP_FILE libwebp-${WEBP_VERSION}.tar.gz)
+set(WEBP_CPE "cpe:2.3:a:webmproject:libwebp:${WEBP_VERSION}:*:*:*:*:*:*:*")
set(SPNAV_VERSION 0.2.3)
set(SPNAV_URI http://downloads.sourceforge.net/project/spacenav/spacenav%20library%20%28SDK%29/libspnav%20${SPNAV_VERSION}/libspnav-${SPNAV_VERSION}.tar.gz)
@@ -323,6 +356,7 @@ set(XML2_URI http://xmlsoft.org/sources/libxml2-${XML2_VERSION}.tar.gz)
set(XML2_HASH 10942a1dc23137a8aa07f0639cbfece5)
set(XML2_HASH_TYPE MD5)
set(XML2_FILE libxml2-${XML2_VERSION}.tar.gz)
+set(XML2_CPE "cpe:2.3:a:xmlsoft:libxml2:${XML2_VERSION}:*:*:*:*:*:*:*")
set(TINYXML_VERSION 2_6_2)
set(TINYXML_VERSION_DOTS 2.6.2)
@@ -330,12 +364,14 @@ set(TINYXML_URI https://nchc.dl.sourceforge.net/project/tinyxml/tinyxml/${TINYXM
set(TINYXML_HASH c1b864c96804a10526540c664ade67f0)
set(TINYXML_HASH_TYPE MD5)
set(TINYXML_FILE tinyxml_${TINYXML_VERSION}.tar.gz)
+set(TINYXML_CPE "cpe:2.3:a:tinyxml_project:tinyxml:${TINYXML_VERSION_DOTS}:*:*:*:*:*:*:*")
set(YAMLCPP_VERSION 0.6.3)
set(YAMLCPP_URI https://codeload.github.com/jbeder/yaml-cpp/tar.gz/yaml-cpp-${YAMLCPP_VERSION})
set(YAMLCPP_HASH b45bf1089a382e81f6b661062c10d0c2)
set(YAMLCPP_HASH_TYPE MD5)
set(YAMLCPP_FILE yaml-cpp-${YAMLCPP_VERSION}.tar.gz)
+set(YAMLCPP "cpe:2.3:a:yaml-cpp_project:yaml-cpp:${YAMLCPP_VERSION}:*:*:*:*:*:*:*")
set(PYSTRING_VERSION v1.1.3)
set(PYSTRING_URI https://codeload.github.com/imageworks/pystring/tar.gz/refs/tags/${PYSTRING_VERSION})
@@ -344,16 +380,19 @@ set(PYSTRING_HASH_TYPE MD5)
set(PYSTRING_FILE pystring-${PYSTRING_VERSION}.tar.gz)
set(EXPAT_VERSION 2_4_4)
+set(EXPAT_VERSION_DOTS 2.4.4)
set(EXPAT_URI https://github.com/libexpat/libexpat/archive/R_${EXPAT_VERSION}.tar.gz)
set(EXPAT_HASH 2d3e81dee94b452369dc6394ff0f8f98)
set(EXPAT_HASH_TYPE MD5)
set(EXPAT_FILE libexpat-${EXPAT_VERSION}.tar.gz)
+set(EXPAT_CPE "cpe:2.3:a:libexpat_project:libexpat:${EXPAT_VERSION_DOTS}:*:*:*:*:*:*:*")
set(PUGIXML_VERSION 1.10)
set(PUGIXML_URI https://github.com/zeux/pugixml/archive/v${PUGIXML_VERSION}.tar.gz)
set(PUGIXML_HASH 0c208b0664c7fb822bf1b49ad035e8fd)
set(PUGIXML_HASH_TYPE MD5)
set(PUGIXML_FILE pugixml-${PUGIXML_VERSION}.tar.gz)
+set(PUGIXML_CPE "cpe:2.3:a:pugixml_project:pugixml:${PUGIXML_VERSION}:*:*:*:*:*:*:*")
set(FLEXBISON_VERSION 2.5.24)
set(FLEXBISON_URI http://prdownloads.sourceforge.net/winflexbison/win_flex_bison-${FLEXBISON_VERSION}.zip)
@@ -376,12 +415,14 @@ set(BZIP2_URI http://http.debian.net/debian/pool/main/b/bzip2/bzip2_${BZIP2_VERS
set(BZIP2_HASH ab5a03176ee106d3f0fa90e381da478ddae405918153cca248e682cd0c4a2269)
set(BZIP2_HASH_TYPE SHA256)
set(BZIP2_FILE bzip2_${BZIP2_VERSION}.orig.tar.gz)
+set(BZIP2_CPE "cpe:2.3:a:bzip:bzip2:${BZIP2_VERSION}:*:*:*:*:*:*:*")
set(FFI_VERSION 3.3)
set(FFI_URI https://sourceware.org/pub/libffi/libffi-${FFI_VERSION}.tar.gz)
set(FFI_HASH 72fba7922703ddfa7a028d513ac15a85c8d54c8d67f55fa5a4802885dc652056)
set(FFI_HASH_TYPE SHA256)
set(FFI_FILE libffi-${FFI_VERSION}.tar.gz)
+set(FFI_CPE "cpe:2.3:a:libffi_project:libffi:${FFI_VERSION}:*:*:*:*:*:*:*")
set(LZMA_VERSION 5.2.5)
set(LZMA_URI https://tukaani.org/xz/xz-${LZMA_VERSION}.tar.bz2)
@@ -403,12 +444,14 @@ else()
set(SSL_HASH_TYPE SHA256)
set(SSL_FILE openssl-${SSL_VERSION}.tar.gz)
endif()
+set(SSL_CPE "cpe:2.3:a:openssl:openssl:${SSL_VERSION}:*:*:*:*:*:*:*")
set(SQLITE_VERSION 3.31.1)
set(SQLITE_URI https://www.sqlite.org/2018/sqlite-src-3240000.zip)
set(SQLITE_HASH fb558c49ee21a837713c4f1e7e413309aabdd9c7)
set(SQLITE_HASH_TYPE SHA1)
set(SQLITE_FILE sqlite-src-3240000.zip)
+set(SQLITE_CPE "cpe:2.3:a:sqlite:sqlite:${SQLITE_VERSION}:*:*:*:*:*:*:*")
set(EMBREE_VERSION 3.13.4)
set(EMBREE_URI https://github.com/embree/embree/archive/v${EMBREE_VERSION}.zip)
@@ -439,12 +482,14 @@ set(MESA_URI ftp://ftp.freedesktop.org/pub/mesa/mesa-${MESA_VERSION}.tar.xz)
set(MESA_HASH 022c7293074aeeced2278c872db4fa693147c70f8595b076cf3f1ef81520766d)
set(MESA_HASH_TYPE SHA256)
set(MESA_FILE mesa-${MESA_VERSION}.tar.xz)
+set(MESA_CPE "cpe:2.3:a:mesa3d:mesa:${MESA_VERSION}:*:*:*:*:*:*:*")
set(NASM_VERSION 2.15.02)
set(NASM_URI https://github.com/netwide-assembler/nasm/archive/nasm-${NASM_VERSION}.tar.gz)
set(NASM_HASH aded8b796c996a486a56e0515c83e414116decc3b184d88043480b32eb0a8589)
set(NASM_HASH_TYPE SHA256)
set(NASM_FILE nasm-${NASM_VERSION}.tar.gz)
+set(NASM_PCE "cpe:2.3:a:nasm:nasm:${NASM_VERSION}:*:*:*:*:*:*:*")
set(XR_OPENXR_SDK_VERSION 1.0.22)
set(XR_OPENXR_SDK_URI https://github.com/KhronosGroup/OpenXR-SDK/archive/release-${XR_OPENXR_SDK_VERSION}.tar.gz)
@@ -464,6 +509,12 @@ set(WAYLAND_URI https://gitlab.freedesktop.org/wayland/wayland/-/releases/1.21.0
set(WAYLAND_HASH f2653a2293bcd882d756c6a83d278903)
set(WAYLAND_HASH_TYPE MD5)
+set(WAYLAND_LIBDECOR_VERSION 0.1.0)
+set(WAYLAND_LIBDECOR_FILE libdecor-${WAYLAND_LIBDECOR_VERSION}.tar.xz)
+set(WAYLAND_LIBDECOR_URI https://gitlab.gnome.org/jadahl/libdecor/uploads/81adf91d27620e20bcc5f6b9b312d768/libdecor-${WAYLAND_LIBDECOR_VERSION}.tar.xz )
+set(WAYLAND_LIBDECOR_HASH 47b59eba76faa3787f0878bf8700e912)
+set(WAYLAND_LIBDECOR_HASH_TYPE MD5)
+
set(ISPC_VERSION v1.17.0)
set(ISPC_URI https://github.com/ispc/ispc/archive/${ISPC_VERSION}.tar.gz)
set(ISPC_HASH 4f476a3109332a77fe839a9014c60ca9)
@@ -475,12 +526,14 @@ set(GMP_URI https://gmplib.org/download/gmp/gmp-${GMP_VERSION}.tar.xz)
set(GMP_HASH 0b82665c4a92fd2ade7440c13fcaa42b)
set(GMP_HASH_TYPE MD5)
set(GMP_FILE gmp-${GMP_VERSION}.tar.xz)
+set(GMP_CPE "cpe:2.3:a:gmplib:gmp:${GMP_VERSION}:*:*:*:*:*:*:*")
set(POTRACE_VERSION 1.16)
set(POTRACE_URI http://potrace.sourceforge.net/download/${POTRACE_VERSION}/potrace-${POTRACE_VERSION}.tar.gz)
set(POTRACE_HASH 5f0bd87ddd9a620b0c4e65652ef93d69)
set(POTRACE_HASH_TYPE MD5)
set(POTRACE_FILE potrace-${POTRACE_VERSION}.tar.gz)
+set(POTRACE_CPE "cpe:2.3:a:icoasoft:potrace:${POTRACE_VERSION}:*:*:*:*:*:*:*")
set(HARU_VERSION 2_3_0)
set(HARU_URI https://github.com/libharu/libharu/archive/RELEASE_${HARU_VERSION}.tar.gz)
@@ -493,6 +546,7 @@ set(ZSTD_URI https://github.com/facebook/zstd/releases/download/v${ZSTD_VERSION}
set(ZSTD_HASH 5194fbfa781fcf45b98c5e849651aa7b3b0a008c6b72d4a0db760f3002291e94)
set(ZSTD_HASH_TYPE SHA256)
set(ZSTD_FILE zstd-${ZSTD_VERSION}.tar.gz)
+set(ZSTD_CPE "cpe:2.3:a:facebook:zstandard:${ZSTD_VERSION}:*:*:*:*:*:*:*")
set(SSE2NEON_VERSION fe5ff00bb8d19b327714a3c290f3e2ce81ba3525)
set(SSE2NEON_URI https://github.com/DLTcollab/sse2neon/archive/${SSE2NEON_VERSION}.tar.gz)
@@ -500,16 +554,17 @@ set(SSE2NEON_HASH 0780253525d299c31775ef95853698d03db9c7739942af8570000f4a25a5d6
set(SSE2NEON_HASH_TYPE SHA256)
set(SSE2NEON_FILE sse2neon-${SSE2NEON_VERSION}.tar.gz)
-set(BROTLI_VERSION v1.0.9)
-set(BROTLI_URI https://github.com/google/brotli/archive/refs/tags/${BROTLI_VERSION}.tar.gz)
+set(BROTLI_VERSION 1.0.9)
+set(BROTLI_URI https://github.com/google/brotli/archive/refs/tags/v${BROTLI_VERSION}.tar.gz)
set(BROTLI_HASH f9e8d81d0405ba66d181529af42a3354f838c939095ff99930da6aa9cdf6fe46)
set(BROTLI_HASH_TYPE SHA256)
-set(BROTLI_FILE brotli-${BROTLI_VERSION}.tar.gz)
+set(BROTLI_FILE brotli-v${BROTLI_VERSION}.tar.gz)
+set(BROTLI_CPE "cpe:2.3:a:google:brotli:${BROTLI_VERSION}:*:*:*:*:*:*:*")
-set(OPENPGL_VERSION v0.3.1-beta)
-set(OPENPGL_SHORT_VERSION 0.3.1)
+set(OPENPGL_VERSION v0.4.0-beta)
+set(OPENPGL_SHORT_VERSION 0.4.0)
set(OPENPGL_URI https://github.com/OpenPathGuidingLibrary/openpgl/archive/refs/tags/${OPENPGL_VERSION}.tar.gz)
-set(OPENPGL_HASH 3830098c485c962018932766199527aab453a8029528dbbc04d4454d82431e2c)
+set(OPENPGL_HASH 58d5b65c533ce6cac3f7e1d51cf169a5411adf356abcd85f04049bbcaecc2e77)
set(OPENPGL_HASH_TYPE SHA256)
set(OPENPGL_FILE openpgl-${OPENPGL_VERSION}.tar.gz)
diff --git a/build_files/build_environment/cmake/wayland.cmake b/build_files/build_environment/cmake/wayland.cmake
index 29859cc9ba5..799f2513da9 100644
--- a/build_files/build_environment/cmake/wayland.cmake
+++ b/build_files/build_environment/cmake/wayland.cmake
@@ -6,9 +6,11 @@ ExternalProject_Add(external_wayland
URL_HASH ${WAYLAND_HASH_TYPE}=${WAYLAND_HASH}
PREFIX ${BUILD_DIR}/wayland
PATCH_COMMAND ${PATCH_CMD} -d ${BUILD_DIR}/wayland/src/external_wayland < ${PATCH_DIR}/wayland.diff
- # Use `-E` so the `PKG_CONFIG_PATH` can be defined to link against our own LIBEXPAT.
- CONFIGURE_COMMAND ${CMAKE_COMMAND} -E env PKG_CONFIG_PATH=${LIBDIR}/expat/lib/pkgconfig:${LIBDIR}/xml2/lib/pkgconfig:$PKG_CONFIG_PATH
- meson --prefix ${LIBDIR}/wayland -Ddocumentation=false -Dtests=false -Dlibraries=false . ../external_wayland
+ # Use `-E` so the `PKG_CONFIG_PATH` can be defined to link against our own LIBEXPAT & LIBXML2.
+ # Note that passing link args "ffi/lib" should not be needed, but
+ # `pkgconfig` would incorrectly look in "ffi/lib/../lib64" otherwise.
+ CONFIGURE_COMMAND ${CMAKE_COMMAND} -E env PKG_CONFIG_PATH=${LIBDIR}/expat/lib/pkgconfig:${LIBDIR}/xml2/lib/pkgconfig:${LIBDIR}/ffi/lib/pkgconfig:$PKG_CONFIG_PATH
+ meson --prefix ${LIBDIR}/wayland -Ddocumentation=false -Dtests=false -Dc_link_args=-L${LIBDIR}/ffi/lib . ../external_wayland
BUILD_COMMAND ninja
INSTALL_COMMAND ninja install
)
@@ -17,4 +19,5 @@ add_dependencies(
external_wayland
external_expat
external_xml2
+ external_ffi
)
diff --git a/build_files/build_environment/cmake/wayland_libdecor.cmake b/build_files/build_environment/cmake/wayland_libdecor.cmake
new file mode 100644
index 00000000000..f4628fa3a1b
--- /dev/null
+++ b/build_files/build_environment/cmake/wayland_libdecor.cmake
@@ -0,0 +1,15 @@
+# SPDX-License-Identifier: GPL-2.0-or-later
+
+# NOTE: currently only the header file is extracted, no compilation is needed
+# as the library is dynamically loaded when found on the system.
+
+ExternalProject_Add(external_wayland_libdecor
+ URL file://${PACKAGE_DIR}/${WAYLAND_LIBDECOR_FILE}
+ DOWNLOAD_DIR ${DOWNLOAD_DIR}
+ URL_HASH ${WAYLAND_LIBDECOR_HASH_TYPE}=${WAYLAND_LIBDECOR_HASH}
+ PREFIX ${BUILD_DIR}/wayland_libdecor
+ BUILD_COMMAND echo .
+ CONFIGURE_COMMAND echo .
+ INSTALL_COMMAND cp ../external_wayland_libdecor/src/libdecor.h ${LIBDIR}/wayland_libdecor/include/libdecor-0/libdecor.h
+ INSTALL_DIR ${LIBDIR}/wayland_libdecor/include/libdecor-0
+)
diff --git a/build_files/build_environment/cmake/wayland_protocols.cmake b/build_files/build_environment/cmake/wayland_protocols.cmake
index 23d29b49260..9bdbc38fd6c 100644
--- a/build_files/build_environment/cmake/wayland_protocols.cmake
+++ b/build_files/build_environment/cmake/wayland_protocols.cmake
@@ -5,7 +5,14 @@ ExternalProject_Add(external_wayland_protocols
DOWNLOAD_DIR ${DOWNLOAD_DIR}
URL_HASH ${WL_PROTOCOLS_HASH_TYPE}=${WL_PROTOCOLS_HASH}
PREFIX ${BUILD_DIR}/wayland-protocols
- CONFIGURE_COMMAND meson --prefix ${LIBDIR}/wayland-protocols . ../external_wayland_protocols -Dtests=false
+ # Use `-E` so the `PKG_CONFIG_PATH` can be defined to link against our own WAYLAND.
+ CONFIGURE_COMMAND ${CMAKE_COMMAND} -E env PKG_CONFIG_PATH=${LIBDIR}/wayland/lib64/pkgconfig:$PKG_CONFIG_PATH
+ meson --prefix ${LIBDIR}/wayland-protocols . ../external_wayland_protocols -Dtests=false
BUILD_COMMAND ninja
INSTALL_COMMAND ninja install
)
+
+add_dependencies(
+ external_wayland_protocols
+ external_wayland
+)
diff --git a/build_files/build_environment/install_deps.sh b/build_files/build_environment/install_deps.sh
index 5de0547727d..f913ac5e73c 100755
--- a/build_files/build_environment/install_deps.sh
+++ b/build_files/build_environment/install_deps.sh
@@ -1222,7 +1222,7 @@ Those libraries should be available as packages in all recent distributions (opt
* Basics of dev environment (cmake, gcc, svn , git, ...).
* libjpeg, libpng, libtiff, [openjpeg2], [libopenal].
* libx11, libxcursor, libxi, libxrandr, libxinerama (and other libx... as needed).
- * libwayland-client0, libwayland-cursor0, libwayland-egl1, libxkbcommon0, libdbus-1-3, libegl1 (Wayland)
+ * libwayland-client0, libdecor, libwayland-cursor0, libwayland-egl1, libxkbcommon0, libdbus-1-3, libegl1 (Wayland)
* libsqlite3, libzstd, libbz2, libssl, libfftw3, libxml2, libtinyxml, yasm, libyaml-cpp, flex.
* libsdl2, libepoxy, libpugixml, libpotrace, [libgmp], fontconfig, [libharu/libhpdf].\""
@@ -4205,7 +4205,7 @@ install_DEB() {
_packages="gawk cmake cmake-curses-gui build-essential libjpeg-dev libpng-dev libtiff-dev \
git libfreetype6-dev libfontconfig-dev libx11-dev flex bison libxxf86vm-dev \
libxcursor-dev libxi-dev wget libsqlite3-dev libxrandr-dev libxinerama-dev \
- libwayland-dev wayland-protocols libegl-dev libxkbcommon-dev libdbus-1-dev linux-libc-dev \
+ libwayland-dev libdecor-0-dev wayland-protocols libegl-dev libxkbcommon-dev libdbus-1-dev linux-libc-dev \
libbz2-dev libncurses5-dev libssl-dev liblzma-dev libreadline-dev \
libopenal-dev libepoxy-dev yasm \
libsdl2-dev libfftw3-dev patch bzip2 libxml2-dev libtinyxml-dev libjemalloc-dev \
@@ -4928,7 +4928,7 @@ install_RPM() {
_packages="gcc gcc-c++ git make cmake tar bzip2 xz findutils flex bison fontconfig-devel \
libtiff-devel libjpeg-devel libpng-devel sqlite-devel fftw-devel SDL2-devel \
libX11-devel libXi-devel libXcursor-devel libXrandr-devel libXinerama-devel \
- wayland-devel wayland-protocols-devel mesa-libEGL-devel libxkbcommon-devel dbus-devel kernel-headers \
+ wayland-devel libdecor-devel wayland-protocols-devel mesa-libEGL-devel libxkbcommon-devel dbus-devel kernel-headers \
wget ncurses-devel readline-devel $OPENJPEG_DEV openal-soft-devel \
libepoxy-devel yasm patch \
libxml2-devel yaml-cpp-devel tinyxml-devel jemalloc-devel \
@@ -5582,7 +5582,7 @@ install_ARCH() {
fi
_packages="$BASE_DEVEL git cmake fontconfig flex \
- libxi libxcursor libxrandr libxinerama libepoxy libpng libtiff wget openal \
+ libxi libxcursor libxrandr libxinerama libepoxy libdecor libpng libtiff wget openal \
$OPENJPEG_DEV yasm sdl2 fftw \
libxml2 yaml-cpp tinyxml python-requests jemalloc gmp potrace pugixml libharu \
zstd pystring"
diff --git a/build_files/build_environment/linux/linux-centos7-setup.sh b/build_files/build_environment/linux/linux-centos7-setup.sh
index 84c14a1d2be..e664f530edb 100644
--- a/build_files/build_environment/linux/linux-centos7-setup.sh
+++ b/build_files/build_environment/linux/linux-centos7-setup.sh
@@ -1,4 +1,8 @@
-#!/bin/sh
+#!/usr/bin/env bash
+# SPDX-License-Identifier: GPL-2.0-or-later
+
+# This script is part of the official build environment, see WIKI page for details.
+# https://wiki.blender.org/wiki/Building_Blender/Other/CentOS7ReleaseEnvironment
set -e
@@ -22,18 +26,79 @@ yum -y install centos-release-scl
yum -y install devtoolset-9
# Install packages needed for Blender's dependencies.
-yum -y install -y \
- git subversion bzip2 tar cmake3 patch make autoconf automake libtool \
- meson ninja-build \
- libXrandr-devel libXinerama-devel libXcursor-devel libXi-devel \
- libX11-devel libXt-devel \
- mesa-libEGL-devel mesa-libGL-devel mesa-libGLU-devel \
- zlib-devel \
- rubygem-asciidoctor \
- wget tcl yasm python36 python-setuptools bison flex \
- ncurses-devel \
- wayland-devel libwayland-client libwayland-server \
+PACKAGES_FOR_LIBS=(
+ # Used to checkout Blender's code.
+ git
+ # Used to checkout Blender's `../lib/` directory.
+ subversion
+ # Used to extract packages.
+ bzip2
+ # Used to extract packages.
+ tar
+ # Blender and some dependencies use `cmake`.
+ cmake3
+ # Apply patches from Blender's: `./build_files/build_environment/patches`
+ patch
+ # Use by `cmake` and `autoconf`.
+ make
+
+ # Required by: `external_nasm` which uses an `autoconf` build-system.
+ autoconf
+ automake
+ libtool
+
+ # Meta-build system used by various packages.
+ meson
+ # Builds generated by meson use Ninja for the actual build.
+ ninja-build
+
+ # Required by Blender build option: `WITH_GHOST_X11`.
+ libXrandr-devel
+ libXinerama-devel
+ libXcursor-devel
+ libXi-devel
+ libX11-devel
+ libXt-devel
+
+ # Required by Blender build option: `WITH_GHOST_WAYLAND`.
+ mesa-libEGL-devel
+ # Required by: Blender & `external_opensubdiv` (probably others).
+ mesa-libGL-devel
+ mesa-libGLU-devel
+
+ # Required by: `external_ispc`.
+ zlib-devel
+ # TODO: dependencies build without this, consider removal.
+ rubygem-asciidoctor
+ # TODO: dependencies build without this, consider removal.
+ wget
+ # Required by: `external_sqlite` as a build-time dependency (needed for the `tclsh` command).
+ tcl
+ # Required by: `external_aom`.
+ # TODO: Blender is already building `external_nasm` which is listed as an alternative to `yasm`.
+ # Why are both needed?
+ yasm
+
+ # Required by: `meson` (Python based build system).
+ python36
+ # Required by: `mako` (Python module used for building `external_mesa`)
+ python-setuptools
+
+ # Required by: `external_igc` & `external_osl` as a build-time dependency.
+ bison
+ # Required by: `external_osl` as a build-time dependency.
+ flex
+ # TODO: dependencies build without this, consider removal.
+ ncurses-devel
+)
+
+# Additional packages needed for building Blender.
+PACKAGES_FOR_BLENDER=(
+ # Required by Blender build option: `WITH_GHOST_WAYLAND`.
+ libxkbcommon-devel
+)
+yum -y install -y ${PACKAGES_FOR_LIBS[@]} ${PACKAGES_FOR_BLENDER[@]}
# Dependencies for Mesa
yum -y install expat-devel
diff --git a/build_files/cmake/platform/platform_unix.cmake b/build_files/cmake/platform/platform_unix.cmake
index 0aab46b1250..7b7937959bf 100644
--- a/build_files/cmake/platform/platform_unix.cmake
+++ b/build_files/cmake/platform/platform_unix.cmake
@@ -699,14 +699,23 @@ endif()
if(WITH_GHOST_WAYLAND)
find_package(PkgConfig)
- pkg_check_modules(wayland-client wayland-client>=1.12)
- pkg_check_modules(wayland-egl wayland-egl)
- pkg_check_modules(wayland-scanner wayland-scanner)
pkg_check_modules(xkbcommon xkbcommon)
- pkg_check_modules(wayland-cursor wayland-cursor)
- pkg_check_modules(wayland-protocols wayland-protocols>=1.15)
- if(${wayland-protocols_FOUND})
+ # When dynamically linked WAYLAND is used and `${LIBDIR}/wayland` is present,
+ # there is no need to search for the libraries as they are not needed for building.
+ # Only the headers are needed which can reference the known paths.
+ if(EXISTS "${LIBDIR}/wayland" AND WITH_GHOST_WAYLAND_DYNLOAD)
+ set(_use_system_wayland OFF)
+ else()
+ set(_use_system_wayland ON)
+ endif()
+
+ if(_use_system_wayland)
+ pkg_check_modules(wayland-client wayland-client>=1.12)
+ pkg_check_modules(wayland-egl wayland-egl)
+ pkg_check_modules(wayland-scanner wayland-scanner)
+ pkg_check_modules(wayland-cursor wayland-cursor)
+ pkg_check_modules(wayland-protocols wayland-protocols>=1.15)
pkg_get_variable(WAYLAND_PROTOCOLS_DIR wayland-protocols pkgdatadir)
else()
# CentOS 7 packages have too old a version, a newer version exist in the
@@ -720,6 +729,15 @@ if(WITH_GHOST_WAYLAND)
if(EXISTS ${WAYLAND_PROTOCOLS_DIR})
set(wayland-protocols_FOUND ON)
endif()
+
+ set(wayland-client_INCLUDE_DIRS "${LIBDIR}/wayland/include")
+ set(wayland-egl_INCLUDE_DIRS "${LIBDIR}/wayland/include")
+ set(wayland-cursor_INCLUDE_DIRS "${LIBDIR}/wayland/include")
+
+ set(wayland-client_FOUND ON)
+ set(wayland-egl_FOUND ON)
+ set(wayland-scanner_FOUND ON)
+ set(wayland-cursor_FOUND ON)
endif()
if (NOT ${wayland-client_FOUND})
@@ -753,34 +771,18 @@ if(WITH_GHOST_WAYLAND)
endif()
if(WITH_GHOST_WAYLAND_LIBDECOR)
- pkg_check_modules(libdecor REQUIRED libdecor-0>=0.1)
- endif()
-
- list(APPEND PLATFORM_LINKLIBS
- ${xkbcommon_LINK_LIBRARIES}
- )
-
- if(NOT WITH_GHOST_WAYLAND_DYNLOAD)
- list(APPEND PLATFORM_LINKLIBS
- ${wayland-client_LINK_LIBRARIES}
- ${wayland-egl_LINK_LIBRARIES}
- ${wayland-cursor_LINK_LIBRARIES}
- )
+ if(_use_system_wayland)
+ pkg_check_modules(libdecor REQUIRED libdecor-0>=0.1)
+ else()
+ set(libdecor_INCLUDE_DIRS "${LIBDIR}/wayland_libdecor/include/libdecor-0")
+ endif()
endif()
if(WITH_GHOST_WAYLAND_DBUS)
- list(APPEND PLATFORM_LINKLIBS
- ${dbus_LINK_LIBRARIES}
- )
add_definitions(-DWITH_GHOST_WAYLAND_DBUS)
endif()
if(WITH_GHOST_WAYLAND_LIBDECOR)
- if(NOT WITH_GHOST_WAYLAND_DYNLOAD)
- list(APPEND PLATFORM_LINKLIBS
- ${libdecor_LIBRARIES}
- )
- endif()
add_definitions(-DWITH_GHOST_WAYLAND_LIBDECOR)
endif()
@@ -823,6 +825,8 @@ if(WITH_GHOST_WAYLAND)
# End wayland-scanner version check.
endif()
+
+ unset(_use_system_wayland)
endif()
if(WITH_GHOST_X11)
@@ -831,12 +835,8 @@ if(WITH_GHOST_X11)
find_path(X11_XF86keysym_INCLUDE_PATH X11/XF86keysym.h ${X11_INC_SEARCH_PATH})
mark_as_advanced(X11_XF86keysym_INCLUDE_PATH)
- list(APPEND PLATFORM_LINKLIBS ${X11_X11_LIB})
-
if(WITH_X11_XINPUT)
- if(X11_Xinput_LIB)
- list(APPEND PLATFORM_LINKLIBS ${X11_Xinput_LIB})
- else()
+ if(NOT X11_Xinput_LIB)
message(FATAL_ERROR "LibXi not found. Disable WITH_X11_XINPUT if you
want to build without tablet support")
endif()
@@ -846,18 +846,14 @@ if(WITH_GHOST_X11)
# XXX, why doesn't cmake make this available?
find_library(X11_Xxf86vmode_LIB Xxf86vm ${X11_LIB_SEARCH_PATH})
mark_as_advanced(X11_Xxf86vmode_LIB)
- if(X11_Xxf86vmode_LIB)
- list(APPEND PLATFORM_LINKLIBS ${X11_Xxf86vmode_LIB})
- else()
+ if(NOT X11_Xxf86vmode_LIB)
message(FATAL_ERROR "libXxf86vm not found. Disable WITH_X11_XF86VMODE if you
want to build without")
endif()
endif()
if(WITH_X11_XFIXES)
- if(X11_Xfixes_LIB)
- list(APPEND PLATFORM_LINKLIBS ${X11_Xfixes_LIB})
- else()
+ if(NOT X11_Xfixes_LIB)
message(FATAL_ERROR "libXfixes not found. Disable WITH_X11_XFIXES if you
want to build without")
endif()
@@ -866,9 +862,7 @@ if(WITH_GHOST_X11)
if(WITH_X11_ALPHA)
find_library(X11_Xrender_LIB Xrender ${X11_LIB_SEARCH_PATH})
mark_as_advanced(X11_Xrender_LIB)
- if(X11_Xrender_LIB)
- list(APPEND PLATFORM_LINKLIBS ${X11_Xrender_LIB})
- else()
+ if(NOT X11_Xrender_LIB)
message(FATAL_ERROR "libXrender not found. Disable WITH_X11_ALPHA if you
want to build without")
endif()
diff --git a/doc/python_api/requirements.txt b/doc/python_api/requirements.txt
index 7d9bb497329..bf120f24995 100644
--- a/doc/python_api/requirements.txt
+++ b/doc/python_api/requirements.txt
@@ -1,4 +1,4 @@
-sphinx==5.1.1
+sphinx==5.2.3
# Sphinx dependencies that are important
Jinja2==3.1.2
@@ -6,7 +6,7 @@ Pygments==2.13.0
docutils==0.17.1
snowballstemmer==2.2.0
babel==2.10.3
-requests==2.27.1
+requests==2.28.1
# Only needed to match the theme used for the official documentation.
# Without this theme, the default theme will be used.
diff --git a/intern/cycles/blender/id_map.h b/intern/cycles/blender/id_map.h
index e77d2f647bf..5fb17bb0d50 100644
--- a/intern/cycles/blender/id_map.h
+++ b/intern/cycles/blender/id_map.h
@@ -20,7 +20,7 @@ CCL_NAMESPACE_BEGIN
* Utility class to map between Blender datablocks and Cycles data structures,
* and keep track of recalc tags from the dependency graph. */
-template<typename K, typename T> class id_map {
+template<typename K, typename T, typename Flags = uint> class id_map {
public:
id_map(Scene *scene_) : scene(scene_)
{
@@ -63,6 +63,11 @@ template<typename K, typename T> class id_map {
b_recalc.insert(id_ptr);
}
+ bool check_recalc(const BL::ID &id)
+ {
+ return id.ptr.data && b_recalc.find(id.ptr.data) != b_recalc.end();
+ }
+
bool has_recalc()
{
return !(b_recalc.empty());
@@ -154,6 +159,7 @@ template<typename K, typename T> class id_map {
TMapPair &pair = *jt;
if (do_delete && used_set.find(pair.second) == used_set.end()) {
+ flags.erase(pair.second);
scene->delete_node(pair.second);
}
else {
@@ -171,9 +177,33 @@ template<typename K, typename T> class id_map {
return b_map;
}
+ bool test_flag(T *data, Flags val)
+ {
+ typename map<T *, uint>::iterator it = flags.find(data);
+ return it != flags.end() && (it->second & (1 << val)) != 0;
+ }
+
+ void set_flag(T *data, Flags val)
+ {
+ flags[data] |= (1 << val);
+ }
+
+ void clear_flag(T *data, Flags val)
+ {
+ typename map<T *, uint>::iterator it = flags.find(data);
+ if (it != flags.end()) {
+ it->second &= ~(1 << val);
+
+ if (it->second == 0) {
+ flags.erase(it);
+ }
+ }
+ }
+
protected:
map<K, T *> b_map;
set<T *> used_set;
+ map<T *, uint> flags;
set<void *> b_recalc;
Scene *scene;
};
diff --git a/intern/cycles/blender/object.cpp b/intern/cycles/blender/object.cpp
index 8a3c1136104..5af1e18a597 100644
--- a/intern/cycles/blender/object.cpp
+++ b/intern/cycles/blender/object.cpp
@@ -96,6 +96,13 @@ bool BlenderSync::object_is_light(BL::Object &b_ob)
return (b_ob_data && b_ob_data.is_a(&RNA_Light));
}
+bool BlenderSync::object_is_camera(BL::Object &b_ob)
+{
+ BL::ID b_ob_data = b_ob.data();
+
+ return (b_ob_data && b_ob_data.is_a(&RNA_Camera));
+}
+
void BlenderSync::sync_object_motion_init(BL::Object &b_parent, BL::Object &b_ob, Object *object)
{
/* Initialize motion blur for object, detecting if it's enabled and creating motion
@@ -400,7 +407,8 @@ bool BlenderSync::sync_object_attributes(BL::DepsgraphObjectInstance &b_instance
std::string real_name;
BlenderAttributeType type = blender_attribute_name_split_type(name, &real_name);
- if (type != BL::ShaderNodeAttribute::attribute_type_GEOMETRY) {
+ if (type == BL::ShaderNodeAttribute::attribute_type_OBJECT ||
+ type == BL::ShaderNodeAttribute::attribute_type_INSTANCER) {
bool use_instancer = (type == BL::ShaderNodeAttribute::attribute_type_INSTANCER);
float4 value = lookup_instance_property(b_instance, real_name, use_instancer);
diff --git a/intern/cycles/blender/pointcloud.cpp b/intern/cycles/blender/pointcloud.cpp
index 35be2916e43..a679a92d997 100644
--- a/intern/cycles/blender/pointcloud.cpp
+++ b/intern/cycles/blender/pointcloud.cpp
@@ -194,7 +194,7 @@ static void export_pointcloud(Scene *scene,
/* Export points. */
for (int i = 0; i < num_points; i++) {
const float3 co = get_float3(b_attr_position.data[i].vector());
- const float radius = b_attr_radius ? b_attr_radius->data[i].value() : 0.0f;
+ const float radius = b_attr_radius ? b_attr_radius->data[i].value() : 0.01f;
pointcloud->add_point(co, radius);
/* Random number per point. */
@@ -232,7 +232,7 @@ static void export_pointcloud_motion(PointCloud *pointcloud,
for (int i = 0; i < std::min(num_points, b_points_num); i++) {
const float3 co = get_float3(b_attr_position.data[i].vector());
- const float radius = b_attr_radius ? b_attr_radius->data[i].value() : 0.0f;
+ const float radius = b_attr_radius ? b_attr_radius->data[i].value() : 0.01f;
float3 P = co;
P.w = radius;
mP[i] = P;
diff --git a/intern/cycles/blender/shader.cpp b/intern/cycles/blender/shader.cpp
index 9505f4ba58f..dbc49df7f22 100644
--- a/intern/cycles/blender/shader.cpp
+++ b/intern/cycles/blender/shader.cpp
@@ -22,6 +22,8 @@
#include "util/string.h"
#include "util/task.h"
+#include "BKE_duplilist.h"
+
CCL_NAMESPACE_BEGIN
typedef map<void *, ShaderInput *> PtrInputMap;
@@ -103,6 +105,7 @@ static ImageAlphaType get_image_alpha_type(BL::Image &b_image)
static const string_view object_attr_prefix("\x01object:");
static const string_view instancer_attr_prefix("\x01instancer:");
+static const string_view view_layer_attr_prefix("\x01layer:");
static ustring blender_attribute_name_add_type(const string &name, BlenderAttributeType type)
{
@@ -111,6 +114,8 @@ static ustring blender_attribute_name_add_type(const string &name, BlenderAttrib
return ustring::concat(object_attr_prefix, name);
case BL::ShaderNodeAttribute::attribute_type_INSTANCER:
return ustring::concat(instancer_attr_prefix, name);
+ case BL::ShaderNodeAttribute::attribute_type_VIEW_LAYER:
+ return ustring::concat(view_layer_attr_prefix, name);
default:
return ustring(name);
}
@@ -130,6 +135,11 @@ BlenderAttributeType blender_attribute_name_split_type(ustring name, string *r_r
return BL::ShaderNodeAttribute::attribute_type_INSTANCER;
}
+ if (sname.substr(0, view_layer_attr_prefix.size()) == view_layer_attr_prefix) {
+ *r_real_name = sname.substr(view_layer_attr_prefix.size());
+ return BL::ShaderNodeAttribute::attribute_type_VIEW_LAYER;
+ }
+
return BL::ShaderNodeAttribute::attribute_type_GEOMETRY;
}
@@ -205,7 +215,9 @@ static void set_default_value(ShaderInput *input,
}
case SocketType::INT: {
if (b_sock.type() == BL::NodeSocket::type_BOOLEAN) {
- node->set(socket, get_boolean(b_sock.ptr, "default_value"));
+ /* Make sure to call the int overload of set() since this is an integer socket as far as
+ * Cycles is concerned. */
+ node->set(socket, get_boolean(b_sock.ptr, "default_value") ? 1 : 0);
}
else {
node->set(socket, get_int(b_sock.ptr, "default_value"));
@@ -1420,6 +1432,89 @@ static void add_nodes(Scene *scene,
empty_proxy_map);
}
+/* Look up and constant fold all references to View Layer attributes. */
+void BlenderSync::resolve_view_layer_attributes(Shader *shader,
+ ShaderGraph *graph,
+ BL::Depsgraph &b_depsgraph)
+{
+ bool updated = false;
+
+ foreach (ShaderNode *node, graph->nodes) {
+ if (node->is_a(AttributeNode::node_type)) {
+ AttributeNode *attr_node = static_cast<AttributeNode *>(node);
+
+ std::string real_name;
+ BlenderAttributeType type = blender_attribute_name_split_type(attr_node->get_attribute(),
+ &real_name);
+
+ if (type == BL::ShaderNodeAttribute::attribute_type_VIEW_LAYER) {
+ /* Look up the value. */
+ BL::ViewLayer b_layer = b_depsgraph.view_layer_eval();
+ BL::Scene b_scene = b_depsgraph.scene_eval();
+ float4 value;
+
+ BKE_view_layer_find_rgba_attribute((::Scene *)b_scene.ptr.data,
+ (::ViewLayer *)b_layer.ptr.data,
+ real_name.c_str(),
+ &value.x);
+
+ /* Replace all outgoing links, using appropriate output types. */
+ float val_avg = (value.x + value.y + value.z) / 3.0f;
+
+ foreach (ShaderOutput *output, node->outputs) {
+ float val_float;
+ float3 val_float3;
+
+ if (output->type() == SocketType::FLOAT) {
+ val_float = (output->name() == "Alpha") ? value.w : val_avg;
+ val_float3 = make_float3(val_float);
+ }
+ else {
+ val_float = val_avg;
+ val_float3 = float4_to_float3(value);
+ }
+
+ foreach (ShaderInput *sock, output->links) {
+ if (sock->type() == SocketType::FLOAT) {
+ sock->set(val_float);
+ }
+ else if (SocketType::is_float3(sock->type())) {
+ sock->set(val_float3);
+ }
+
+ sock->constant_folded_in = true;
+ }
+
+ graph->disconnect(output);
+ }
+
+ /* Clear the attribute name to avoid further attempts to look up. */
+ attr_node->set_attribute(ustring());
+ updated = true;
+ }
+ }
+ }
+
+ if (updated) {
+ shader_map.set_flag(shader, SHADER_WITH_LAYER_ATTRS);
+ }
+ else {
+ shader_map.clear_flag(shader, SHADER_WITH_LAYER_ATTRS);
+ }
+}
+
+bool BlenderSync::scene_attr_needs_recalc(Shader *shader, BL::Depsgraph &b_depsgraph)
+{
+ if (shader && shader_map.test_flag(shader, SHADER_WITH_LAYER_ATTRS)) {
+ BL::Scene scene = b_depsgraph.scene_eval();
+
+ return shader_map.check_recalc(scene) || shader_map.check_recalc(scene.world()) ||
+ shader_map.check_recalc(scene.camera());
+ }
+
+ return false;
+}
+
/* Sync Materials */
void BlenderSync::sync_materials(BL::Depsgraph &b_depsgraph, bool update_all)
@@ -1438,7 +1533,8 @@ void BlenderSync::sync_materials(BL::Depsgraph &b_depsgraph, bool update_all)
Shader *shader;
/* test if we need to sync */
- if (shader_map.add_or_update(&shader, b_mat) || update_all) {
+ if (shader_map.add_or_update(&shader, b_mat) || update_all ||
+ scene_attr_needs_recalc(shader, b_depsgraph)) {
ShaderGraph *graph = new ShaderGraph();
shader->name = b_mat.name().c_str();
@@ -1459,6 +1555,8 @@ void BlenderSync::sync_materials(BL::Depsgraph &b_depsgraph, bool update_all)
graph->connect(diffuse->output("BSDF"), out->input("Surface"));
}
+ resolve_view_layer_attributes(shader, graph, b_depsgraph);
+
/* settings */
PointerRNA cmat = RNA_pointer_get(&b_mat.ptr, "cycles");
shader->set_use_mis(get_boolean(cmat, "sample_as_light"));
@@ -1515,9 +1613,11 @@ void BlenderSync::sync_world(BL::Depsgraph &b_depsgraph, BL::SpaceView3D &b_v3d,
BlenderViewportParameters new_viewport_parameters(b_v3d, use_developer_ui);
+ Shader *shader = scene->default_background;
+
if (world_recalc || update_all || b_world.ptr.data != world_map ||
- viewport_parameters.shader_modified(new_viewport_parameters)) {
- Shader *shader = scene->default_background;
+ viewport_parameters.shader_modified(new_viewport_parameters) ||
+ scene_attr_needs_recalc(shader, b_depsgraph)) {
ShaderGraph *graph = new ShaderGraph();
/* create nodes */
@@ -1615,6 +1715,8 @@ void BlenderSync::sync_world(BL::Depsgraph &b_depsgraph, BL::SpaceView3D &b_v3d,
background->set_visibility(visibility);
}
+ resolve_view_layer_attributes(shader, graph, b_depsgraph);
+
shader->set_graph(graph);
shader->tag_update(scene);
}
@@ -1681,7 +1783,8 @@ void BlenderSync::sync_lights(BL::Depsgraph &b_depsgraph, bool update_all)
Shader *shader;
/* test if we need to sync */
- if (shader_map.add_or_update(&shader, b_light) || update_all) {
+ if (shader_map.add_or_update(&shader, b_light) || update_all ||
+ scene_attr_needs_recalc(shader, b_depsgraph)) {
ShaderGraph *graph = new ShaderGraph();
/* create nodes */
@@ -1702,6 +1805,8 @@ void BlenderSync::sync_lights(BL::Depsgraph &b_depsgraph, bool update_all)
graph->connect(emission->output("Emission"), out->input("Surface"));
}
+ resolve_view_layer_attributes(shader, graph, b_depsgraph);
+
shader->set_graph(graph);
shader->tag_update(scene);
}
diff --git a/intern/cycles/blender/sync.cpp b/intern/cycles/blender/sync.cpp
index 23bc92de022..a69a94614d3 100644
--- a/intern/cycles/blender/sync.cpp
+++ b/intern/cycles/blender/sync.cpp
@@ -206,6 +206,9 @@ void BlenderSync::sync_recalc(BL::Depsgraph &b_depsgraph, BL::SpaceView3D &b_v3d
}
}
}
+ else if (object_is_camera(b_ob)) {
+ shader_map.set_recalc(b_ob);
+ }
}
/* Mesh */
else if (b_id.is_a(&RNA_Mesh)) {
@@ -218,6 +221,11 @@ void BlenderSync::sync_recalc(BL::Depsgraph &b_depsgraph, BL::SpaceView3D &b_v3d
if (world_map == b_world.ptr.data) {
world_recalc = true;
}
+ shader_map.set_recalc(b_world);
+ }
+ /* World */
+ else if (b_id.is_a(&RNA_Scene)) {
+ shader_map.set_recalc(b_id);
}
/* Volume */
else if (b_id.is_a(&RNA_Volume)) {
diff --git a/intern/cycles/blender/sync.h b/intern/cycles/blender/sync.h
index ae6c2420e55..fbb17bab0c8 100644
--- a/intern/cycles/blender/sync.h
+++ b/intern/cycles/blender/sync.h
@@ -120,6 +120,11 @@ class BlenderSync {
void sync_shaders(BL::Depsgraph &b_depsgraph, BL::SpaceView3D &b_v3d, bool update_all);
void sync_nodes(Shader *shader, BL::ShaderNodeTree &b_ntree);
+ bool scene_attr_needs_recalc(Shader *shader, BL::Depsgraph &b_depsgraph);
+ void resolve_view_layer_attributes(Shader *shader,
+ ShaderGraph *graph,
+ BL::Depsgraph &b_depsgraph);
+
/* Object */
Object *sync_object(BL::Depsgraph &b_depsgraph,
BL::ViewLayer &b_view_layer,
@@ -207,13 +212,16 @@ class BlenderSync {
bool object_is_geometry(BObjectInfo &b_ob_info);
bool object_can_have_geometry(BL::Object &b_ob);
bool object_is_light(BL::Object &b_ob);
+ bool object_is_camera(BL::Object &b_ob);
/* variables */
BL::RenderEngine b_engine;
BL::BlendData b_data;
BL::Scene b_scene;
- id_map<void *, Shader> shader_map;
+ enum ShaderFlags { SHADER_WITH_LAYER_ATTRS };
+
+ id_map<void *, Shader, ShaderFlags> shader_map;
id_map<ObjectKey, Object> object_map;
id_map<void *, Procedural> procedural_map;
id_map<GeometryKey, Geometry> geometry_map;
diff --git a/intern/cycles/device/metal/device_impl.mm b/intern/cycles/device/metal/device_impl.mm
index d1250b83d22..6a16d4bb3b4 100644
--- a/intern/cycles/device/metal/device_impl.mm
+++ b/intern/cycles/device/metal/device_impl.mm
@@ -254,6 +254,10 @@ void MetalDevice::make_source(MetalPipelineType pso_type, const uint kernel_feat
break;
}
+ NSProcessInfo *processInfo = [NSProcessInfo processInfo];
+ NSOperatingSystemVersion macos_ver = [processInfo operatingSystemVersion];
+ global_defines += "#define __KERNEL_METAL_MACOS__ " + to_string(macos_ver.majorVersion) + "\n";
+
string &source = this->source[pso_type];
source = "\n#include \"kernel/device/metal/kernel.metal\"\n";
source = path_source_replace_includes(source, path_get("source"));
diff --git a/intern/cycles/device/oneapi/device_impl.cpp b/intern/cycles/device/oneapi/device_impl.cpp
index 2df605fa047..91f53fd1eae 100644
--- a/intern/cycles/device/oneapi/device_impl.cpp
+++ b/intern/cycles/device/oneapi/device_impl.cpp
@@ -43,7 +43,7 @@ OneapiDevice::OneapiDevice(const DeviceInfo &info, Stats &stats, Profiler &profi
}
size_t globals_segment_size;
- is_finished_ok = kernel_globals_size(device_queue_, globals_segment_size);
+ is_finished_ok = kernel_globals_size(globals_segment_size);
if (is_finished_ok == false) {
set_error("oneAPI constant memory initialization got runtime exception \"" +
oneapi_error_string_ + "\"");
@@ -88,18 +88,26 @@ BVHLayoutMask OneapiDevice::get_bvh_layout_mask() const
bool OneapiDevice::load_kernels(const uint requested_features)
{
assert(device_queue_);
- /* NOTE(@nsirgien): oneAPI can support compilation of kernel code with certain feature set
- * with specialization constants, but it hasn't been implemented yet. */
- (void)requested_features;
bool is_finished_ok = oneapi_run_test_kernel(device_queue_);
if (is_finished_ok == false) {
- set_error("oneAPI kernel load: got runtime exception \"" + oneapi_error_string_ + "\"");
+ set_error("oneAPI test kernel execution: got a runtime exception \"" + oneapi_error_string_ +
+ "\"");
+ return false;
}
else {
- VLOG_INFO << "Runtime compilation done for \"" << info.description << "\"";
+ VLOG_INFO << "Test kernel has been executed successfully for \"" << info.description << "\"";
assert(device_queue_);
}
+
+ is_finished_ok = oneapi_load_kernels(device_queue_, (const unsigned int)requested_features);
+ if (is_finished_ok == false) {
+ set_error("oneAPI kernels loading: got a runtime exception \"" + oneapi_error_string_ + "\"");
+ }
+ else {
+ VLOG_INFO << "Kernels loading (compilation) has been done for \"" << info.description << "\"";
+ }
+
return is_finished_ok;
}
@@ -425,6 +433,11 @@ void OneapiDevice::check_usm(SyclQueue *queue_, const void *usm_ptr, bool allow_
((device_type == sycl::info::device_type::host ||
device_type == sycl::info::device_type::cpu || allow_host) &&
usm_type == sycl::usm::alloc::host));
+# else
+ /* Silence warning about unused arguments. */
+ (void)queue_;
+ (void)usm_ptr;
+ (void)allow_host;
# endif
}
@@ -552,7 +565,7 @@ bool OneapiDevice::queue_synchronize(SyclQueue *queue_)
}
}
-bool OneapiDevice::kernel_globals_size(SyclQueue *queue_, size_t &kernel_global_size)
+bool OneapiDevice::kernel_globals_size(size_t &kernel_global_size)
{
kernel_global_size = sizeof(KernelGlobalsGPU);
diff --git a/intern/cycles/device/oneapi/device_impl.h b/intern/cycles/device/oneapi/device_impl.h
index 3589e881a6e..62034150eac 100644
--- a/intern/cycles/device/oneapi/device_impl.h
+++ b/intern/cycles/device/oneapi/device_impl.h
@@ -104,7 +104,7 @@ class OneapiDevice : public Device {
int get_num_multiprocessors();
int get_max_num_threads_per_multiprocessor();
bool queue_synchronize(SyclQueue *queue);
- bool kernel_globals_size(SyclQueue *queue, size_t &kernel_global_size);
+ bool kernel_globals_size(size_t &kernel_global_size);
void set_global_memory(SyclQueue *queue,
void *kernel_globals,
const char *memory_name,
diff --git a/intern/cycles/integrator/path_trace.cpp b/intern/cycles/integrator/path_trace.cpp
index 6b033cfd051..506d962f13d 100644
--- a/intern/cycles/integrator/path_trace.cpp
+++ b/intern/cycles/integrator/path_trace.cpp
@@ -43,8 +43,11 @@ PathTrace::PathTrace(Device *device,
/* Create path tracing work in advance, so that it can be reused by incremental sampling as much
* as possible. */
device_->foreach_device([&](Device *path_trace_device) {
- path_trace_works_.emplace_back(PathTraceWork::create(
- path_trace_device, film, device_scene, &render_cancel_.is_requested));
+ unique_ptr<PathTraceWork> work = PathTraceWork::create(
+ path_trace_device, film, device_scene, &render_cancel_.is_requested);
+ if (work) {
+ path_trace_works_.emplace_back(std::move(work));
+ }
});
work_balance_infos_.resize(path_trace_works_.size());
diff --git a/intern/cycles/integrator/path_trace_work.cpp b/intern/cycles/integrator/path_trace_work.cpp
index bb5c6e1a61a..a5f98b5475a 100644
--- a/intern/cycles/integrator/path_trace_work.cpp
+++ b/intern/cycles/integrator/path_trace_work.cpp
@@ -23,6 +23,10 @@ unique_ptr<PathTraceWork> PathTraceWork::create(Device *device,
if (device->info.type == DEVICE_CPU) {
return make_unique<PathTraceWorkCPU>(device, film, device_scene, cancel_requested_flag);
}
+ if (device->info.type == DEVICE_DUMMY) {
+ /* Dummy devices can't perform any work. */
+ return nullptr;
+ }
return make_unique<PathTraceWorkGPU>(device, film, device_scene, cancel_requested_flag);
}
diff --git a/intern/cycles/integrator/path_trace_work_cpu.cpp b/intern/cycles/integrator/path_trace_work_cpu.cpp
index d5ac830db58..188ec28cf65 100644
--- a/intern/cycles/integrator/path_trace_work_cpu.cpp
+++ b/intern/cycles/integrator/path_trace_work_cpu.cpp
@@ -285,7 +285,7 @@ void PathTraceWorkCPU::cryptomatte_postproces()
}
#ifdef WITH_PATH_GUIDING
-/* Note: It seems that this is called before every rendering iteration/progression and not once per
+/* NOTE: It seems that this is called before every rendering iteration/progression and not once per
* rendering. May be we find a way to call it only once per rendering. */
void PathTraceWorkCPU::guiding_init_kernel_globals(void *guiding_field,
void *sample_data_storage,
diff --git a/intern/cycles/integrator/work_balancer.cpp b/intern/cycles/integrator/work_balancer.cpp
index 5f1c6c92b9d..0fe170b2791 100644
--- a/intern/cycles/integrator/work_balancer.cpp
+++ b/intern/cycles/integrator/work_balancer.cpp
@@ -17,6 +17,9 @@ void work_balance_do_initial(vector<WorkBalanceInfo> &work_balance_infos)
work_balance_infos[0].weight = 1.0;
return;
}
+ else if (num_infos == 0) {
+ return;
+ }
/* There is no statistics available, so start with an equal distribution. */
const double weight = 1.0 / num_infos;
diff --git a/intern/cycles/kernel/CMakeLists.txt b/intern/cycles/kernel/CMakeLists.txt
index 8f50c7586b8..36c8b23d983 100644
--- a/intern/cycles/kernel/CMakeLists.txt
+++ b/intern/cycles/kernel/CMakeLists.txt
@@ -727,16 +727,9 @@ if(WITH_CYCLES_DEVICE_ONEAPI)
${SRC_UTIL_HEADERS}
)
- set (ONEAPI_OFFLINE_COMPILER_PARALLEL_JOBS 1)
+ set (SYCL_OFFLINE_COMPILER_PARALLEL_JOBS 1 CACHE STRING "Number of parallel compiler instances to use for device binaries compilation (expect ~8GB peak memory usage per instance).")
if (WITH_CYCLES_ONEAPI_BINARIES)
- cmake_host_system_information(RESULT AVAILABLE_MEMORY_AMOUNT QUERY AVAILABLE_PHYSICAL_MEMORY)
- # Conservative value of peak consumption here, just to be fully sure that other backend compilers will have enough memory as well
- set(ONEAPI_GPU_COMPILER_MEMORY_AT_PEAK_MB 8150)
- math(EXPR ONEAPI_OFFLINE_COMPILER_PARALLEL_JOBS "${AVAILABLE_MEMORY_AMOUNT} / ${ONEAPI_GPU_COMPILER_MEMORY_AT_PEAK_MB}")
- if (ONEAPI_OFFLINE_COMPILER_PARALLEL_JOBS LESS 1)
- set(ONEAPI_OFFLINE_COMPILER_PARALLEL_JOBS 1)
- endif()
- message(STATUS "${ONEAPI_OFFLINE_COMPILER_PARALLEL_JOBS} instance(s) of oneAPI offline compiler will be used.")
+ message(STATUS "${SYCL_OFFLINE_COMPILER_PARALLEL_JOBS} instance(s) of oneAPI offline compiler will be used.")
endif()
# SYCL_CPP_FLAGS is a variable that the user can set to pass extra compiler options
set(sycl_compiler_flags
@@ -747,7 +740,7 @@ if(WITH_CYCLES_DEVICE_ONEAPI)
-mllvm -inlinedefault-threshold=250
-mllvm -inlinehint-threshold=350
-fsycl-device-code-split=per_kernel
- -fsycl-max-parallel-link-jobs=${ONEAPI_OFFLINE_COMPILER_PARALLEL_JOBS}
+ -fsycl-max-parallel-link-jobs=${SYCL_OFFLINE_COMPILER_PARALLEL_JOBS}
-shared
-DWITH_ONEAPI
-ffast-math
diff --git a/intern/cycles/kernel/device/oneapi/kernel.cpp b/intern/cycles/kernel/device/oneapi/kernel.cpp
index 1d1700f036d..40e0b1f0b2b 100644
--- a/intern/cycles/kernel/device/oneapi/kernel.cpp
+++ b/intern/cycles/kernel/device/oneapi/kernel.cpp
@@ -25,38 +25,57 @@ void oneapi_set_error_cb(OneAPIErrorCallback cb, void *user_ptr)
s_error_user_ptr = user_ptr;
}
-/* NOTE(@nsirgien): Execution of this simple kernel will check basic functionality and
- * also trigger runtime compilation of all existing oneAPI kernels */
+/* NOTE(@nsirgien): Execution of this simple kernel will check basic functionality like
+ * memory allocations, memory transfers and execution of kernel with USM memory. */
bool oneapi_run_test_kernel(SyclQueue *queue_)
{
assert(queue_);
sycl::queue *queue = reinterpret_cast<sycl::queue *>(queue_);
- size_t N = 8;
- sycl::buffer<float, 1> A(N);
- sycl::buffer<float, 1> B(N);
-
- {
- sycl::host_accessor A_host_acc(A, sycl::write_only);
- for (size_t i = (size_t)0; i < N; i++)
- A_host_acc[i] = rand() % 32;
- }
+ const size_t N = 8;
+ const size_t memory_byte_size = sizeof(int) * N;
+ bool is_computation_correct = true;
try {
- queue->submit([&](sycl::handler &cgh) {
- sycl::accessor A_acc(A, cgh, sycl::read_only);
- sycl::accessor B_acc(B, cgh, sycl::write_only, sycl::no_init);
+ int *A_host = (int *)sycl::aligned_alloc_host(16, memory_byte_size, *queue);
+
+ for (size_t i = (size_t)0; i < N; i++) {
+ A_host[i] = rand() % 32;
+ }
- cgh.parallel_for(N, [=](sycl::id<1> idx) { B_acc[idx] = A_acc[idx] + idx.get(0); });
+ int *A_device = (int *)sycl::malloc_device(memory_byte_size, *queue);
+ int *B_device = (int *)sycl::malloc_device(memory_byte_size, *queue);
+
+ queue->memcpy(A_device, A_host, memory_byte_size);
+ queue->wait_and_throw();
+
+ queue->submit([&](sycl::handler &cgh) {
+ cgh.parallel_for(N, [=](sycl::id<1> idx) { B_device[idx] = A_device[idx] + idx.get(0); });
});
queue->wait_and_throw();
- sycl::host_accessor A_host_acc(A, sycl::read_only);
- sycl::host_accessor B_host_acc(B, sycl::read_only);
+ int *B_host = (int *)sycl::aligned_alloc_host(16, memory_byte_size, *queue);
+
+ queue->memcpy(B_host, B_device, memory_byte_size);
+ queue->wait_and_throw();
for (size_t i = (size_t)0; i < N; i++) {
- float result = A_host_acc[i] + B_host_acc[i];
- (void)result;
+ const int expected_result = i + A_host[i];
+ if (B_host[i] != expected_result) {
+ is_computation_correct = false;
+ if (s_error_cb) {
+ s_error_cb(("Incorrect result in test kernel execution - expected " +
+ std::to_string(expected_result) + ", got " + std::to_string(B_host[i]))
+ .c_str(),
+ s_error_user_ptr);
+ }
+ }
}
+
+ sycl::free(A_host, *queue);
+ sycl::free(B_host, *queue);
+ sycl::free(A_device, *queue);
+ sycl::free(B_device, *queue);
+ queue->wait_and_throw();
}
catch (sycl::exception const &e) {
if (s_error_cb) {
@@ -65,7 +84,7 @@ bool oneapi_run_test_kernel(SyclQueue *queue_)
return false;
}
- return true;
+ return is_computation_correct;
}
/* TODO: Move device information to OneapiDevice initialized on creation and use it. */
@@ -123,6 +142,52 @@ size_t oneapi_kernel_preferred_local_size(SyclQueue *queue,
return std::min(limit_work_group_size, preferred_work_group_size);
}
+bool oneapi_load_kernels(SyclQueue *queue_, const uint requested_features)
+{
+ assert(queue_);
+ sycl::queue *queue = reinterpret_cast<sycl::queue *>(queue_);
+
+ try {
+ sycl::kernel_bundle<sycl::bundle_state::input> all_kernels_bundle =
+ sycl::get_kernel_bundle<sycl::bundle_state::input>(queue->get_context(),
+ {queue->get_device()});
+
+ for (const sycl::kernel_id &kernel_id : all_kernels_bundle.get_kernel_ids()) {
+ const std::string &kernel_name = kernel_id.get_name();
+
+ /* NOTE(@nsirgien): Names in this conditions below should match names from
+ * oneapi_call macro in oneapi_enqueue_kernel below */
+ if (((requested_features & KERNEL_FEATURE_VOLUME) == 0) &&
+ kernel_name.find("oneapi_kernel_integrator_shade_volume") != std::string::npos) {
+ continue;
+ }
+
+ if (((requested_features & KERNEL_FEATURE_MNEE) == 0) &&
+ kernel_name.find("oneapi_kernel_integrator_shade_surface_mnee") != std::string::npos) {
+ continue;
+ }
+
+ if (((requested_features & KERNEL_FEATURE_NODE_RAYTRACE) == 0) &&
+ kernel_name.find("oneapi_kernel_integrator_shade_surface_raytrace") !=
+ std::string::npos) {
+ continue;
+ }
+
+ sycl::kernel_bundle<sycl::bundle_state::input> one_kernel_bundle =
+ sycl::get_kernel_bundle<sycl::bundle_state::input>(queue->get_context(), {kernel_id});
+ sycl::build(one_kernel_bundle, {queue->get_device()}, sycl::property::queue::in_order());
+ }
+ }
+ catch (sycl::exception const &e) {
+ if (s_error_cb) {
+ s_error_cb(e.what(), s_error_user_ptr);
+ }
+ return false;
+ }
+
+ return true;
+}
+
bool oneapi_enqueue_kernel(KernelContext *kernel_context,
int kernel,
size_t global_size,
diff --git a/intern/cycles/kernel/device/oneapi/kernel.h b/intern/cycles/kernel/device/oneapi/kernel.h
index 7456d0e4902..2bfc0b89c87 100644
--- a/intern/cycles/kernel/device/oneapi/kernel.h
+++ b/intern/cycles/kernel/device/oneapi/kernel.h
@@ -48,6 +48,8 @@ CYCLES_KERNEL_ONEAPI_EXPORT bool oneapi_enqueue_kernel(KernelContext *context,
int kernel,
size_t global_size,
void **args);
+CYCLES_KERNEL_ONEAPI_EXPORT bool oneapi_load_kernels(SyclQueue *queue,
+ const unsigned int requested_features);
# ifdef __cplusplus
}
# endif
diff --git a/intern/cycles/kernel/integrator/mnee.h b/intern/cycles/kernel/integrator/mnee.h
index 038f0379bbc..23885306885 100644
--- a/intern/cycles/kernel/integrator/mnee.h
+++ b/intern/cycles/kernel/integrator/mnee.h
@@ -279,7 +279,15 @@ ccl_device_forceinline void mnee_setup_manifold_vertex(KernelGlobals kg,
}
/* Compute constraint derivatives. */
-ccl_device_forceinline bool mnee_compute_constraint_derivatives(
+
+# if defined(__KERNEL_METAL__)
+/* Temporary workaround for front-end compilation bug (incorrect MNEE rendering when this is
+ * inlined). */
+__attribute__((noinline))
+# else
+ccl_device_forceinline
+# endif
+bool mnee_compute_constraint_derivatives(
int vertex_count,
ccl_private ManifoldVertex *vertices,
ccl_private const float3 &surface_sample_pos,
diff --git a/intern/cycles/kernel/sample/pattern.h b/intern/cycles/kernel/sample/pattern.h
index ebdecc1bff9..e12f333b3a5 100644
--- a/intern/cycles/kernel/sample/pattern.h
+++ b/intern/cycles/kernel/sample/pattern.h
@@ -100,7 +100,7 @@ ccl_device_inline bool sample_is_class_A(int pattern, int sample)
if (!(pattern == SAMPLING_PATTERN_PMJ || pattern == SAMPLING_PATTERN_SOBOL_BURLEY)) {
/* Fallback: assign samples randomly.
* This is guaranteed to work "okay" for any sampler, but isn't good.
- * (Note: the seed constant is just a random number to guard against
+ * (NOTE: the seed constant is just a random number to guard against
* possible interactions with other uses of the hash. There's nothing
* special about it.)
*/
diff --git a/intern/cycles/kernel/types.h b/intern/cycles/kernel/types.h
index 1469d915d15..8f7cfd19169 100644
--- a/intern/cycles/kernel/types.h
+++ b/intern/cycles/kernel/types.h
@@ -85,9 +85,9 @@ CCL_NAMESPACE_BEGIN
# define __VOLUME_RECORD_ALL__
#endif /* !__KERNEL_GPU__ */
-/* MNEE currently causes "Compute function exceeds available temporary registers"
- * on Metal, disabled for now. */
-#ifndef __KERNEL_METAL__
+/* MNEE caused "Compute function exceeds available temporary registers" in macOS < 13 due to a bug
+ * in spill buffer allocation sizing. */
+#if !defined(__KERNEL_METAL__) || (__KERNEL_METAL_MACOS__ >= 13)
# define __MNEE__
#endif
diff --git a/intern/cycles/session/session.cpp b/intern/cycles/session/session.cpp
index a0eb3196a34..acaa55f4990 100644
--- a/intern/cycles/session/session.cpp
+++ b/intern/cycles/session/session.cpp
@@ -43,6 +43,10 @@ Session::Session(const SessionParams &params_, const SceneParams &scene_params)
device = Device::create(params.device, stats, profiler);
+ if (device->have_error()) {
+ progress.set_error(device->error_message());
+ }
+
scene = new Scene(scene_params, device);
/* Configure path tracer. */
diff --git a/intern/ghost/CMakeLists.txt b/intern/ghost/CMakeLists.txt
index aa23618ca39..2f8ea1f9065 100644
--- a/intern/ghost/CMakeLists.txt
+++ b/intern/ghost/CMakeLists.txt
@@ -262,6 +262,9 @@ elseif(WITH_GHOST_X11 OR WITH_GHOST_WAYLAND)
${xkbcommon_INCLUDE_DIRS}
${wayland-cursor_INCLUDE_DIRS}
)
+ list(APPEND LIB
+ ${xkbcommon_LINK_LIBRARIES}
+ )
if(WITH_GHOST_WAYLAND_DYNLOAD)
list(APPEND INC_SYS
@@ -271,18 +274,32 @@ elseif(WITH_GHOST_X11 OR WITH_GHOST_WAYLAND)
bf_intern_wayland_dynload
)
add_definitions(-DWITH_GHOST_WAYLAND_DYNLOAD)
+ else()
+ list(APPEND LIB
+ ${wayland-client_LINK_LIBRARIES}
+ ${wayland-egl_LINK_LIBRARIES}
+ ${wayland-cursor_LINK_LIBRARIES}
+ )
endif()
if(WITH_GHOST_WAYLAND_DBUS)
list(APPEND INC_SYS
${dbus_INCLUDE_DIRS}
)
+ list(APPEND LIB
+ ${dbus_LINK_LIBRARIES}
+ )
endif()
if(WITH_GHOST_WAYLAND_LIBDECOR)
list(APPEND INC_SYS
${libdecor_INCLUDE_DIRS}
)
+ if(NOT WITH_GHOST_WAYLAND_DYNLOAD)
+ list(APPEND LIB
+ ${libdecor_LIBRARIES}
+ )
+ endif()
endif()
include(CheckSymbolExists)
@@ -332,16 +349,16 @@ elseif(WITH_GHOST_X11 OR WITH_GHOST_WAYLAND)
${INC_DST}
)
- if(NOT WITH_GHOST_WAYLAND_LIBDECOR)
- # `xdg-shell`.
- generate_protocol_bindings(
- "${WAYLAND_PROTOCOLS_DIR}/stable/xdg-shell/xdg-shell.xml"
- )
- # `xdg-decoration`.
- generate_protocol_bindings(
- "${WAYLAND_PROTOCOLS_DIR}/unstable/xdg-decoration/xdg-decoration-unstable-v1.xml"
- )
- endif()
+ # Used when: LIBDECOR is not needed.
+ # `xdg-shell`.
+ generate_protocol_bindings(
+ "${WAYLAND_PROTOCOLS_DIR}/stable/xdg-shell/xdg-shell.xml"
+ )
+ # `xdg-decoration`.
+ generate_protocol_bindings(
+ "${WAYLAND_PROTOCOLS_DIR}/unstable/xdg-decoration/xdg-decoration-unstable-v1.xml"
+ )
+ # End LIBDECOR alternative.
# `xdg-output`.
generate_protocol_bindings(
diff --git a/intern/ghost/GHOST_C-api.h b/intern/ghost/GHOST_C-api.h
index c9d18be750d..7fda535a7ac 100644
--- a/intern/ghost/GHOST_C-api.h
+++ b/intern/ghost/GHOST_C-api.h
@@ -36,6 +36,10 @@ extern GHOST_SystemHandle GHOST_CreateSystemBackground(void);
*/
extern void GHOST_SystemInitDebug(GHOST_SystemHandle systemhandle, GHOST_Debug debug);
+#if !(defined(WIN32) || defined(__APPLE__))
+extern const char *GHOST_SystemBackend(void);
+#endif
+
/**
* Disposes the one and only system.
* \param systemhandle: The handle to the system.
diff --git a/intern/ghost/GHOST_ISystem.h b/intern/ghost/GHOST_ISystem.h
index 0bf540bd4b6..9fb94ed1525 100644
--- a/intern/ghost/GHOST_ISystem.h
+++ b/intern/ghost/GHOST_ISystem.h
@@ -134,6 +134,15 @@ class GHOST_ISystem {
* \return A pointer to the system.
*/
static GHOST_ISystem *getSystem();
+ /**
+ * Return an identifier for the one and only system.
+ * \warning while it may be tempting this should never be used to check for supported features,
+ * in that case, the GHOST API should be extended to query capabilities.
+ * This is needed for X11/WAYLAND on Unix, without this - there is no convenient way for users to
+ * check if WAYLAND or XWAYLAND are in use since they are dynamically selected at startup.
+ * When dynamically switching between X11/WAYLAND is removed, this function can go too.
+ */
+ static const char *getSystemBackend();
static GHOST_TBacktraceFn getBacktraceFn();
static void setBacktraceFn(GHOST_TBacktraceFn backtrace_fn);
@@ -515,6 +524,7 @@ class GHOST_ISystem {
/** The one and only system */
static GHOST_ISystem *m_system;
+ static const char *m_system_backend_id;
/** Function to call that sets the back-trace. */
static GHOST_TBacktraceFn m_backtrace_fn;
diff --git a/intern/ghost/intern/GHOST_C-api.cpp b/intern/ghost/intern/GHOST_C-api.cpp
index 69fc6b5f2d0..158e979cdf2 100644
--- a/intern/ghost/intern/GHOST_C-api.cpp
+++ b/intern/ghost/intern/GHOST_C-api.cpp
@@ -52,6 +52,13 @@ GHOST_TSuccess GHOST_DisposeSystem(GHOST_SystemHandle systemhandle)
return system->disposeSystem();
}
+#if !(defined(WIN32) || defined(__APPLE__))
+const char *GHOST_SystemBackend()
+{
+ return GHOST_ISystem::getSystemBackend();
+}
+#endif
+
void GHOST_ShowMessageBox(GHOST_SystemHandle systemhandle,
const char *title,
const char *message,
diff --git a/intern/ghost/intern/GHOST_ContextGLX.cpp b/intern/ghost/intern/GHOST_ContextGLX.cpp
index 4c1e2705b50..93708983f37 100644
--- a/intern/ghost/intern/GHOST_ContextGLX.cpp
+++ b/intern/ghost/intern/GHOST_ContextGLX.cpp
@@ -306,7 +306,7 @@ GHOST_TSuccess GHOST_ContextGLX::releaseNativeHandles()
GHOST_TSuccess GHOST_ContextGLX::setSwapInterval(int interval)
{
- if (!epoxy_has_glx_extension(m_display, DefaultScreen(m_display), "GLX_EXT_swap_control")) {
+ if (epoxy_has_glx_extension(m_display, DefaultScreen(m_display), "GLX_EXT_swap_control")) {
::glXSwapIntervalEXT(m_display, m_window, interval);
return GHOST_kSuccess;
}
diff --git a/intern/ghost/intern/GHOST_ISystem.cpp b/intern/ghost/intern/GHOST_ISystem.cpp
index 304d7f0abe6..8e2859ca1e1 100644
--- a/intern/ghost/intern/GHOST_ISystem.cpp
+++ b/intern/ghost/intern/GHOST_ISystem.cpp
@@ -30,6 +30,7 @@
#endif
GHOST_ISystem *GHOST_ISystem::m_system = nullptr;
+const char *GHOST_ISystem::m_system_backend_id = nullptr;
GHOST_TBacktraceFn GHOST_ISystem::m_backtrace_fn = nullptr;
@@ -47,7 +48,7 @@ GHOST_TSuccess GHOST_ISystem::createSystem(bool verbose)
/* Pass. */
#elif defined(WITH_GHOST_WAYLAND)
# if defined(WITH_GHOST_WAYLAND_DYNLOAD)
- const bool has_wayland_libraries = ghost_wl_dynload_libraries();
+ const bool has_wayland_libraries = ghost_wl_dynload_libraries_init();
# else
const bool has_wayland_libraries = true;
# endif
@@ -65,6 +66,9 @@ GHOST_TSuccess GHOST_ISystem::createSystem(bool verbose)
catch (const std::runtime_error &) {
delete m_system;
m_system = nullptr;
+# ifdef WITH_GHOST_WAYLAND_DYNLOAD
+ ghost_wl_dynload_libraries_exit();
+# endif
}
}
else {
@@ -100,6 +104,9 @@ GHOST_TSuccess GHOST_ISystem::createSystem(bool verbose)
catch (const std::runtime_error &) {
delete m_system;
m_system = nullptr;
+# ifdef WITH_GHOST_WAYLAND_DYNLOAD
+ ghost_wl_dynload_libraries_exit();
+# endif
}
}
else {
@@ -122,7 +129,10 @@ GHOST_TSuccess GHOST_ISystem::createSystem(bool verbose)
m_system = new GHOST_SystemCocoa();
#endif
- if ((m_system == nullptr) && verbose) {
+ if (m_system) {
+ m_system_backend_id = backends_attempted[backends_attempted_num - 1];
+ }
+ else if (verbose) {
fprintf(stderr, "GHOST: failed to initialize display for back-end(s): [");
for (int i = 0; i < backends_attempted_num; i++) {
if (i != 0) {
@@ -186,6 +196,11 @@ GHOST_ISystem *GHOST_ISystem::getSystem()
return m_system;
}
+const char *GHOST_ISystem::getSystemBackend()
+{
+ return m_system_backend_id;
+}
+
GHOST_TBacktraceFn GHOST_ISystem::getBacktraceFn()
{
return GHOST_ISystem::m_backtrace_fn;
diff --git a/intern/ghost/intern/GHOST_SystemWayland.cpp b/intern/ghost/intern/GHOST_SystemWayland.cpp
index 0721ca78603..250c7a48899 100644
--- a/intern/ghost/intern/GHOST_SystemWayland.cpp
+++ b/intern/ghost/intern/GHOST_SystemWayland.cpp
@@ -54,6 +54,11 @@
#include <tablet-unstable-v2-client-protocol.h>
#include <xdg-output-unstable-v1-client-protocol.h>
+/* Decorations `xdg_decor`. */
+#include <xdg-decoration-unstable-v1-client-protocol.h>
+#include <xdg-shell-client-protocol.h>
+/* End `xdg_decor`. */
+
#include <fcntl.h>
#include <sys/mman.h>
#include <unistd.h>
@@ -64,6 +69,15 @@
/* Logging, use `ghost.wl.*` prefix. */
#include "CLG_log.h"
+#ifdef WITH_GHOST_WAYLAND_LIBDECOR
+static bool use_libdecor = true;
+# ifdef WITH_GHOST_WAYLAND_DYNLOAD
+static bool has_libdecor = false;
+# else
+static bool has_libdecor = true;
+# endif
+#endif
+
static void keyboard_handle_key_repeat_cancel(struct GWL_Seat *seat);
static void output_handle_done(void *data, struct wl_output *wl_output);
@@ -106,6 +120,15 @@ static bool use_gnome_confine_hack = false;
*/
#define USE_GNOME_KEYBOARD_SUPPRESS_WARNING
+/**
+ * When GNOME is found, require `libdecor`.
+ * This is a hack because it seems there is no way to check if the compositor supports
+ * server side decorations when initializing WAYLAND.
+ */
+#if defined(WITH_GHOST_WAYLAND_LIBDECOR) && defined(WITH_GHOST_X11)
+# define USE_GNOME_NEEDS_LIBDECOR_HACK
+#endif
+
/** \} */
/* -------------------------------------------------------------------- */
@@ -357,6 +380,36 @@ struct WGL_KeyboardDepressedState {
int16_t mods[GHOST_KEY_MODIFIER_NUM] = {0};
};
+#ifdef WITH_GHOST_WAYLAND_LIBDECOR
+struct WGL_LibDecor_System {
+ struct libdecor *context = nullptr;
+};
+
+static void wgl_libdecor_system_destroy(WGL_LibDecor_System *decor)
+{
+ if (decor->context) {
+ libdecor_unref(decor->context);
+ }
+ delete decor;
+}
+#endif
+
+struct WGL_XDG_Decor_System {
+ struct xdg_wm_base *shell = nullptr;
+ struct zxdg_decoration_manager_v1 *manager = nullptr;
+};
+
+static void wgl_xdg_decor_system_destroy(WGL_XDG_Decor_System *decor)
+{
+ if (decor->manager) {
+ zxdg_decoration_manager_v1_destroy(decor->manager);
+ }
+ if (decor->shell) {
+ xdg_wm_base_destroy(decor->shell);
+ }
+ delete decor;
+}
+
struct GWL_Seat {
GHOST_SystemWayland *system = nullptr;
@@ -455,11 +508,10 @@ struct GWL_Display {
struct wl_compositor *compositor = nullptr;
#ifdef WITH_GHOST_WAYLAND_LIBDECOR
- struct libdecor *decor_context = nullptr;
-#else
- struct xdg_wm_base *xdg_shell = nullptr;
- struct zxdg_decoration_manager_v1 *xdg_decoration_manager = nullptr;
+ WGL_LibDecor_System *libdecor = nullptr;
+ bool libdecor_required = false;
#endif
+ WGL_XDG_Decor_System *xdg_decor = nullptr;
struct zxdg_output_manager_v1 *xdg_output_manager = nullptr;
struct wl_shm *shm = nullptr;
@@ -626,18 +678,18 @@ static void display_destroy(GWL_Display *d)
}
#ifdef WITH_GHOST_WAYLAND_LIBDECOR
- if (d->decor_context) {
- libdecor_unref(d->decor_context);
- }
-#else
- if (d->xdg_decoration_manager) {
- zxdg_decoration_manager_v1_destroy(d->xdg_decoration_manager);
+ if (use_libdecor) {
+ if (d->libdecor) {
+ wgl_libdecor_system_destroy(d->libdecor);
+ }
}
-
- if (d->xdg_shell) {
- xdg_wm_base_destroy(d->xdg_shell);
+ else
+#endif
+ {
+ if (d->xdg_decor) {
+ wgl_xdg_decor_system_destroy(d->xdg_decor);
+ }
}
-#endif /* !WITH_GHOST_WAYLAND_LIBDECOR */
if (eglGetDisplay) {
::eglTerminate(eglGetDisplay(EGLNativeDisplayType(d->display)));
@@ -2903,10 +2955,8 @@ static const struct wl_output_listener output_listener = {
/** \name Listener (XDG WM Base), #xdg_wm_base_listener
* \{ */
-#ifndef WITH_GHOST_WAYLAND_LIBDECOR
-
static CLG_LogRef LOG_WL_XDG_WM_BASE = {"ghost.wl.handle.xdg_wm_base"};
-# define LOG (&LOG_WL_XDG_WM_BASE)
+#define LOG (&LOG_WL_XDG_WM_BASE)
static void shell_handle_ping(void * /*data*/,
struct xdg_wm_base *xdg_wm_base,
@@ -2920,9 +2970,7 @@ static const struct xdg_wm_base_listener shell_listener = {
shell_handle_ping,
};
-# undef LOG
-
-#endif /* !WITH_GHOST_WAYLAND_LIBDECOR. */
+#undef LOG
/** \} */
@@ -2978,19 +3026,17 @@ static void global_handle_add(void *data,
display->compositor = static_cast<wl_compositor *>(
wl_registry_bind(wl_registry, name, &wl_compositor_interface, 3));
}
-#ifdef WITH_GHOST_WAYLAND_LIBDECOR
- /* Pass. */
-#else
else if (STREQ(interface, xdg_wm_base_interface.name)) {
- display->xdg_shell = static_cast<xdg_wm_base *>(
+ WGL_XDG_Decor_System &decor = *display->xdg_decor;
+ decor.shell = static_cast<xdg_wm_base *>(
wl_registry_bind(wl_registry, name, &xdg_wm_base_interface, 1));
- xdg_wm_base_add_listener(display->xdg_shell, &shell_listener, nullptr);
+ xdg_wm_base_add_listener(decor.shell, &shell_listener, nullptr);
}
else if (STREQ(interface, zxdg_decoration_manager_v1_interface.name)) {
- display->xdg_decoration_manager = static_cast<zxdg_decoration_manager_v1 *>(
+ WGL_XDG_Decor_System &decor = *display->xdg_decor;
+ decor.manager = static_cast<zxdg_decoration_manager_v1 *>(
wl_registry_bind(wl_registry, name, &zxdg_decoration_manager_v1_interface, 1));
}
-#endif /* !WITH_GHOST_WAYLAND_LIBDECOR. */
else if (STREQ(interface, zxdg_output_manager_v1_interface.name)) {
display->xdg_output_manager = static_cast<zxdg_output_manager_v1 *>(
wl_registry_bind(wl_registry, name, &zxdg_output_manager_v1_interface, 2));
@@ -3048,6 +3094,14 @@ static void global_handle_add(void *data,
}
else {
found = false;
+
+#ifdef USE_GNOME_NEEDS_LIBDECOR_HACK
+ if (STRPREFIX(interface, "gtk_shell")) { /* `gtk_shell1` at time of writing. */
+ /* Only require `libdecor` when built with X11 support,
+ * otherwise there is nothing to fall back on. */
+ display->libdecor_required = true;
+ }
+#endif
}
CLOG_INFO(LOG,
@@ -3102,6 +3156,9 @@ GHOST_SystemWayland::GHOST_SystemWayland() : GHOST_System(), d(new GWL_Display)
throw std::runtime_error("Wayland: unable to connect to display!");
}
+ /* This may be removed later if decorations are required, needed as part of registration. */
+ d->xdg_decor = new WGL_XDG_Decor_System;
+
/* Register interfaces. */
struct wl_registry *registry = wl_display_get_registry(d->display);
wl_registry_add_listener(registry, &registry_listener, d);
@@ -3112,17 +3169,45 @@ GHOST_SystemWayland::GHOST_SystemWayland() : GHOST_System(), d(new GWL_Display)
wl_registry_destroy(registry);
#ifdef WITH_GHOST_WAYLAND_LIBDECOR
- d->decor_context = libdecor_new(d->display, &libdecor_interface);
- if (!d->decor_context) {
- display_destroy(d);
- throw std::runtime_error("Wayland: unable to create window decorations!");
+ if (d->libdecor_required) {
+ wgl_xdg_decor_system_destroy(d->xdg_decor);
+ d->xdg_decor = nullptr;
+
+ if (!has_libdecor) {
+# ifdef WITH_GHOST_X11
+ /* LIBDECOR was the only reason X11 was used, let the user know they need it installed. */
+ fprintf(stderr,
+ "WAYLAND found but libdecor was not, install libdecor for Wayland support, "
+ "falling back to X11\n");
+# endif
+ display_destroy(d);
+ throw std::runtime_error("Wayland: unable to find libdecor!");
+ }
}
-#else
- if (!d->xdg_shell) {
- display_destroy(d);
- throw std::runtime_error("Wayland: unable to access xdg_shell!");
+ else {
+ use_libdecor = false;
+ }
+#endif /* WITH_GHOST_WAYLAND_LIBDECOR */
+
+#ifdef WITH_GHOST_WAYLAND_LIBDECOR
+ if (use_libdecor) {
+ d->libdecor = new WGL_LibDecor_System;
+ WGL_LibDecor_System &decor = *d->libdecor;
+ decor.context = libdecor_new(d->display, &libdecor_interface);
+ if (!decor.context) {
+ display_destroy(d);
+ throw std::runtime_error("Wayland: unable to create window decorations!");
+ }
}
+ else
#endif
+ {
+ WGL_XDG_Decor_System &decor = *d->xdg_decor;
+ if (!decor.shell) {
+ display_destroy(d);
+ throw std::runtime_error("Wayland: unable to access xdg_shell!");
+ }
+ }
/* Register data device per seat for IPC between Wayland clients. */
if (d->data_device_manager) {
@@ -4052,24 +4137,24 @@ wl_compositor *GHOST_SystemWayland::compositor()
#ifdef WITH_GHOST_WAYLAND_LIBDECOR
-libdecor *GHOST_SystemWayland::decor_context()
+libdecor *GHOST_SystemWayland::libdecor_context()
{
- return d->decor_context;
+ return d->libdecor->context;
}
-#else /* WITH_GHOST_WAYLAND_LIBDECOR */
+#endif /* !WITH_GHOST_WAYLAND_LIBDECOR */
-xdg_wm_base *GHOST_SystemWayland::xdg_shell()
+xdg_wm_base *GHOST_SystemWayland::xdg_decor_shell()
{
- return d->xdg_shell;
+ return d->xdg_decor->shell;
}
-zxdg_decoration_manager_v1 *GHOST_SystemWayland::xdg_decoration_manager()
+zxdg_decoration_manager_v1 *GHOST_SystemWayland::xdg_decor_manager()
{
- return d->xdg_decoration_manager;
+ return d->xdg_decor->manager;
}
-#endif /* !WITH_GHOST_WAYLAND_LIBDECOR */
+/* End `xdg_decor`. */
const std::vector<GWL_Output *> &GHOST_SystemWayland::outputs() const
{
@@ -4317,35 +4402,52 @@ bool GHOST_SystemWayland::window_cursor_grab_set(const GHOST_TGrabCursorMode mod
return GHOST_kSuccess;
}
+#ifdef WITH_GHOST_WAYLAND_LIBDECOR
+bool GHOST_SystemWayland::use_libdecor_runtime()
+{
+ return use_libdecor;
+}
+#endif
+
#ifdef WITH_GHOST_WAYLAND_DYNLOAD
-bool ghost_wl_dynload_libraries()
+bool ghost_wl_dynload_libraries_init()
{
- /* Only report when `libwayland-client` is not found when building without X11,
- * which will be used as a fallback. */
# ifdef WITH_GHOST_X11
- bool verbose = false;
+ /* When running in WAYLAND, let the user know when a missing library is the only reason
+ * WAYLAND could not be used. Otherwise it's not obvious why X11 is used as a fallback.
+ * Otherwise when X11 is used, reporting WAYLAND library warnings is unwelcome noise. */
+ bool verbose = getenv("WAYLAND_DISPLAY") != nullptr;
# else
bool verbose = true;
-# endif
+# endif /* !WITH_GHOST_X11 */
if (wayland_dynload_client_init(verbose) && /* `libwayland-client`. */
wayland_dynload_cursor_init(verbose) && /* `libwayland-cursor`. */
- wayland_dynload_egl_init(verbose) && /* `libwayland-egl`. */
+ wayland_dynload_egl_init(verbose) /* `libwayland-egl`. */
+ ) {
# ifdef WITH_GHOST_WAYLAND_LIBDECOR
- wayland_dynload_libdecor_init(verbose) && /* `libdecor-0`. */
+ has_libdecor = wayland_dynload_libdecor_init(verbose); /* `libdecor-0`. */
# endif
- true) {
return true;
}
-# ifdef WITH_GHOST_WAYLAND_LIBDECOR
- wayland_dynload_libdecor_exit();
-# endif
+
wayland_dynload_client_exit();
wayland_dynload_cursor_exit();
wayland_dynload_egl_exit();
return false;
}
+
+void ghost_wl_dynload_libraries_exit()
+{
+ wayland_dynload_client_exit();
+ wayland_dynload_cursor_exit();
+ wayland_dynload_egl_exit();
+# ifdef WITH_GHOST_WAYLAND_LIBDECOR
+ wayland_dynload_libdecor_exit();
+# endif
+}
+
#endif /* WITH_GHOST_WAYLAND_DYNLOAD */
/** \} */
diff --git a/intern/ghost/intern/GHOST_SystemWayland.h b/intern/ghost/intern/GHOST_SystemWayland.h
index caea7b0d748..7d19a5cf8b9 100644
--- a/intern/ghost/intern/GHOST_SystemWayland.h
+++ b/intern/ghost/intern/GHOST_SystemWayland.h
@@ -21,18 +21,12 @@
# include <wayland_dynload_libdecor.h>
# endif
# include <libdecor.h>
-#else
-/* Generated by `wayland-scanner`. */
-# include <xdg-decoration-unstable-v1-client-protocol.h>
-# include <xdg-shell-client-protocol.h>
#endif
#include <string>
class GHOST_WindowWayland;
-struct GWL_Display;
-
bool ghost_wl_output_own(const struct wl_output *wl_output);
void ghost_wl_output_tag(struct wl_output *wl_output);
struct GWL_Output *ghost_wl_output_user_data(struct wl_output *wl_output);
@@ -52,7 +46,8 @@ void ghost_wl_surface_tag_cursor_tablet(struct wl_surface *surface);
* Return true when all required WAYLAND libraries are present,
* Performs dynamic loading when `WITH_GHOST_WAYLAND_DYNLOAD` is in use.
*/
-bool ghost_wl_dynload_libraries();
+bool ghost_wl_dynload_libraries_init();
+void ghost_wl_dynload_libraries_exit();
#endif
struct GWL_Output {
@@ -167,11 +162,11 @@ class GHOST_SystemWayland : public GHOST_System {
wl_compositor *compositor();
#ifdef WITH_GHOST_WAYLAND_LIBDECOR
- libdecor *decor_context();
-#else
- xdg_wm_base *xdg_shell();
- zxdg_decoration_manager_v1 *xdg_decoration_manager();
+ libdecor *libdecor_context();
#endif
+ struct xdg_wm_base *xdg_decor_shell();
+ struct zxdg_decoration_manager_v1 *xdg_decor_manager();
+ /* End `xdg_decor`. */
const std::vector<GWL_Output *> &outputs() const;
@@ -192,6 +187,10 @@ class GHOST_SystemWayland : public GHOST_System {
wl_surface *wl_surface,
int scale);
+#ifdef WITH_GHOST_WAYLAND_LIBDECOR
+ static bool use_libdecor_runtime();
+#endif
+
private:
struct GWL_Display *d;
std::string selection;
diff --git a/intern/ghost/intern/GHOST_SystemX11.cpp b/intern/ghost/intern/GHOST_SystemX11.cpp
index 6b468f041c1..4523f6fa37c 100644
--- a/intern/ghost/intern/GHOST_SystemX11.cpp
+++ b/intern/ghost/intern/GHOST_SystemX11.cpp
@@ -2435,11 +2435,11 @@ GHOST_TSuccess GHOST_SystemX11::showMessageBox(const char *title,
utf8Str,
8,
PropModeReplace,
- (const unsigned char *)title,
+ (const uchar *)title,
int(strlen(title)));
XChangeProperty(
- m_display, window, winType, XA_ATOM, 32, PropModeReplace, (unsigned char *)&typeDialog, 1);
+ m_display, window, winType, XA_ATOM, 32, PropModeReplace, (uchar *)&typeDialog, 1);
}
/* Create buttons GC */
diff --git a/intern/ghost/intern/GHOST_WindowWayland.cpp b/intern/ghost/intern/GHOST_WindowWayland.cpp
index 5f3cb3e3f3a..5f9202f1227 100644
--- a/intern/ghost/intern/GHOST_WindowWayland.cpp
+++ b/intern/ghost/intern/GHOST_WindowWayland.cpp
@@ -31,13 +31,52 @@
# include <libdecor.h>
#endif
+/* Generated by `wayland-scanner`. */
+#include <xdg-decoration-unstable-v1-client-protocol.h>
+#include <xdg-shell-client-protocol.h>
+
/* Logging, use `ghost.wl.*` prefix. */
#include "CLG_log.h"
static constexpr size_t base_dpi = 96;
+#ifdef WITH_GHOST_WAYLAND_LIBDECOR
+/* Access `use_libdecor` in #GHOST_SystemWayland. */
+# define use_libdecor GHOST_SystemWayland::use_libdecor_runtime()
+#endif
+
static GHOST_WindowManager *window_manager = nullptr;
+#ifdef WITH_GHOST_WAYLAND_LIBDECOR
+struct WGL_LibDecor_Window {
+ struct libdecor_frame *frame = nullptr;
+ bool configured = false;
+};
+
+static void wgl_libdecor_window_destroy(WGL_LibDecor_Window *decor)
+{
+ libdecor_frame_unref(decor->frame);
+ delete decor;
+}
+#endif /* WITH_GHOST_WAYLAND_LIBDECOR */
+
+struct WGL_XDG_Decor_Window {
+ struct xdg_surface *surface = nullptr;
+ struct zxdg_toplevel_decoration_v1 *toplevel_decor = nullptr;
+ struct xdg_toplevel *toplevel = nullptr;
+ enum zxdg_toplevel_decoration_v1_mode mode = (enum zxdg_toplevel_decoration_v1_mode)0;
+};
+
+static void wgl_xdg_decor_window_destroy(WGL_XDG_Decor_Window *decor)
+{
+ if (decor->toplevel_decor) {
+ zxdg_toplevel_decoration_v1_destroy(decor->toplevel_decor);
+ }
+ xdg_toplevel_destroy(decor->toplevel);
+ xdg_surface_destroy(decor->surface);
+ delete decor;
+}
+
struct GWL_Window {
GHOST_WindowWayland *w = nullptr;
struct wl_surface *wl_surface = nullptr;
@@ -60,15 +99,9 @@ struct GWL_Window {
uint32_t dpi = 0;
#ifdef WITH_GHOST_WAYLAND_LIBDECOR
- struct libdecor_frame *decor_frame = nullptr;
- bool decor_configured = false;
-#else
- struct xdg_surface *xdg_surface = nullptr;
- struct zxdg_toplevel_decoration_v1 *xdg_toplevel_decoration = nullptr;
- struct xdg_toplevel *xdg_toplevel = nullptr;
-
- enum zxdg_toplevel_decoration_v1_mode decoration_mode = (enum zxdg_toplevel_decoration_v1_mode)0;
+ WGL_LibDecor_Window *libdecor = nullptr;
#endif
+ WGL_XDG_Decor_Window *xdg_decor = nullptr;
wl_egl_window *egl_window = nullptr;
bool is_maximised = false;
@@ -146,10 +179,8 @@ static int outputs_max_scale_or_default(const std::vector<GWL_Output *> &outputs
/** \name Listener (XDG Top Level), #xdg_toplevel_listener
* \{ */
-#ifndef WITH_GHOST_WAYLAND_LIBDECOR
-
static CLG_LogRef LOG_WL_XDG_TOPLEVEL = {"ghost.wl.handle.xdg_toplevel"};
-# define LOG (&LOG_WL_XDG_TOPLEVEL)
+#define LOG (&LOG_WL_XDG_TOPLEVEL)
static void xdg_toplevel_handle_configure(void *data,
xdg_toplevel * /*xdg_toplevel*/,
@@ -197,9 +228,7 @@ static const xdg_toplevel_listener toplevel_listener = {
xdg_toplevel_handle_close,
};
-# undef LOG
-
-#endif /* !WITH_GHOST_WAYLAND_LIBDECOR. */
+#undef LOG
/** \} */
@@ -250,7 +279,7 @@ static void frame_handle_configure(struct libdecor_frame *frame,
libdecor_frame_commit(frame, state, configuration);
libdecor_state_free(state);
- win->decor_configured = true;
+ win->libdecor->configured = true;
}
static void frame_handle_close(struct libdecor_frame * /*frame*/, void *data)
@@ -285,10 +314,8 @@ static struct libdecor_frame_interface libdecor_frame_iface = {
/** \name Listener (XDG Decoration Listener), #zxdg_toplevel_decoration_v1_listener
* \{ */
-#ifndef WITH_GHOST_WAYLAND_LIBDECOR
-
static CLG_LogRef LOG_WL_XDG_TOPLEVEL_DECORATION = {"ghost.wl.handle.xdg_toplevel_decoration"};
-# define LOG (&LOG_WL_XDG_TOPLEVEL_DECORATION)
+#define LOG (&LOG_WL_XDG_TOPLEVEL_DECORATION)
static void xdg_toplevel_decoration_handle_configure(
void *data,
@@ -296,16 +323,14 @@ static void xdg_toplevel_decoration_handle_configure(
const uint32_t mode)
{
CLOG_INFO(LOG, 2, "configure (mode=%u)", mode);
- static_cast<GWL_Window *>(data)->decoration_mode = (zxdg_toplevel_decoration_v1_mode)mode;
+ static_cast<GWL_Window *>(data)->xdg_decor->mode = (zxdg_toplevel_decoration_v1_mode)mode;
}
static const zxdg_toplevel_decoration_v1_listener toplevel_decoration_v1_listener = {
xdg_toplevel_decoration_handle_configure,
};
-# undef LOG
-
-#endif /* !WITH_GHOST_WAYLAND_LIBDECOR. */
+#undef LOG
/** \} */
@@ -313,10 +338,8 @@ static const zxdg_toplevel_decoration_v1_listener toplevel_decoration_v1_listene
/** \name Listener (XDG Surface Handle Configure), #xdg_surface_listener
* \{ */
-#ifndef WITH_GHOST_WAYLAND_LIBDECOR
-
static CLG_LogRef LOG_WL_XDG_SURFACE = {"ghost.wl.handle.xdg_surface"};
-# define LOG (&LOG_WL_XDG_SURFACE)
+#define LOG (&LOG_WL_XDG_SURFACE)
static void xdg_surface_handle_configure(void *data,
xdg_surface *xdg_surface,
@@ -324,7 +347,7 @@ static void xdg_surface_handle_configure(void *data,
{
GWL_Window *win = static_cast<GWL_Window *>(data);
- if (win->xdg_surface != xdg_surface) {
+ if (win->xdg_decor->surface != xdg_surface) {
CLOG_INFO(LOG, 2, "configure (skipped)");
return;
}
@@ -354,9 +377,7 @@ static const xdg_surface_listener xdg_surface_listener = {
xdg_surface_handle_configure,
};
-# undef LOG
-
-#endif /* !WITH_GHOST_WAYLAND_LIBDECOR. */
+#undef LOG
/** \} */
@@ -476,43 +497,64 @@ GHOST_WindowWayland::GHOST_WindowWayland(GHOST_SystemWayland *system,
* when the `w->scale` changed. */
const int32_t size_min[2] = {320, 240};
-#ifdef WITH_GHOST_WAYLAND_LIBDECOR
- /* create window decorations */
- w->decor_frame = libdecor_decorate(
- m_system->decor_context(), w->wl_surface, &libdecor_frame_iface, w);
- libdecor_frame_map(w->decor_frame);
-
- libdecor_frame_set_min_content_size(w->decor_frame, UNPACK2(size_min));
-
- if (parentWindow) {
- libdecor_frame_set_parent(
- w->decor_frame, dynamic_cast<const GHOST_WindowWayland *>(parentWindow)->w->decor_frame);
- }
-#else
- w->xdg_surface = xdg_wm_base_get_xdg_surface(m_system->xdg_shell(), w->wl_surface);
- w->xdg_toplevel = xdg_surface_get_toplevel(w->xdg_surface);
-
- xdg_toplevel_set_min_size(w->xdg_toplevel, UNPACK2(size_min));
+ /* This value is expected to match the base name of the `.desktop` file. see T101805.
+ *
+ * NOTE: the XDG desktop-entry-spec defines that this should follow the "reverse DNS" convention.
+ * For e.g. `org.blender.Blender` - however the `.desktop` file distributed with Blender is
+ * simply called `blender.desktop`, so the it's important to follow that name.
+ * Other distributions such as SNAP & FLATPAK may need to change this value T101779.
+ * Currently there isn't a way to configure this, we may want to support that. */
+ const char *xdg_app_id = "blender";
- if (m_system->xdg_decoration_manager()) {
- w->xdg_toplevel_decoration = zxdg_decoration_manager_v1_get_toplevel_decoration(
- m_system->xdg_decoration_manager(), w->xdg_toplevel);
- zxdg_toplevel_decoration_v1_add_listener(
- w->xdg_toplevel_decoration, &toplevel_decoration_v1_listener, w);
- zxdg_toplevel_decoration_v1_set_mode(w->xdg_toplevel_decoration,
- ZXDG_TOPLEVEL_DECORATION_V1_MODE_SERVER_SIDE);
+#ifdef WITH_GHOST_WAYLAND_LIBDECOR
+ if (use_libdecor) {
+ w->libdecor = new WGL_LibDecor_Window;
+ WGL_LibDecor_Window &decor = *w->libdecor;
+
+ /* create window decorations */
+ decor.frame = libdecor_decorate(
+ m_system->libdecor_context(), w->wl_surface, &libdecor_frame_iface, w);
+ libdecor_frame_map(w->libdecor->frame);
+
+ libdecor_frame_set_min_content_size(decor.frame, UNPACK2(size_min));
+ libdecor_frame_set_app_id(decor.frame, xdg_app_id);
+
+ if (parentWindow) {
+ WGL_LibDecor_Window &decor_parent =
+ *dynamic_cast<const GHOST_WindowWayland *>(parentWindow)->w->libdecor;
+ libdecor_frame_set_parent(decor.frame, decor_parent.frame);
+ }
}
+ else
+#endif
+ {
+ w->xdg_decor = new WGL_XDG_Decor_Window;
+ WGL_XDG_Decor_Window &decor = *w->xdg_decor;
+ decor.surface = xdg_wm_base_get_xdg_surface(m_system->xdg_decor_shell(), w->wl_surface);
+ decor.toplevel = xdg_surface_get_toplevel(decor.surface);
+
+ xdg_toplevel_set_min_size(decor.toplevel, UNPACK2(size_min));
+ xdg_toplevel_set_app_id(decor.toplevel, xdg_app_id);
+
+ if (m_system->xdg_decor_manager()) {
+ decor.toplevel_decor = zxdg_decoration_manager_v1_get_toplevel_decoration(
+ m_system->xdg_decor_manager(), decor.toplevel);
+ zxdg_toplevel_decoration_v1_add_listener(
+ decor.toplevel_decor, &toplevel_decoration_v1_listener, w);
+ zxdg_toplevel_decoration_v1_set_mode(decor.toplevel_decor,
+ ZXDG_TOPLEVEL_DECORATION_V1_MODE_SERVER_SIDE);
+ }
- xdg_surface_add_listener(w->xdg_surface, &xdg_surface_listener, w);
- xdg_toplevel_add_listener(w->xdg_toplevel, &toplevel_listener, w);
+ xdg_surface_add_listener(decor.surface, &xdg_surface_listener, w);
+ xdg_toplevel_add_listener(decor.toplevel, &toplevel_listener, w);
- if (parentWindow && is_dialog) {
- xdg_toplevel_set_parent(
- w->xdg_toplevel, dynamic_cast<const GHOST_WindowWayland *>(parentWindow)->w->xdg_toplevel);
+ if (parentWindow && is_dialog) {
+ WGL_XDG_Decor_Window &decor_parent =
+ *dynamic_cast<const GHOST_WindowWayland *>(parentWindow)->w->xdg_decor;
+ xdg_toplevel_set_parent(decor.toplevel, decor_parent.toplevel);
+ }
}
-#endif /* !WITH_GHOST_WAYLAND_LIBDECOR */
-
setTitle(title);
wl_surface_set_user_data(w->wl_surface, this);
@@ -522,11 +564,14 @@ GHOST_WindowWayland::GHOST_WindowWayland(GHOST_SystemWayland *system,
wl_display_roundtrip(m_system->display());
#ifdef WITH_GHOST_WAYLAND_LIBDECOR
- /* It's important not to return until the window is configured or
- * calls to `setState` from Blender will crash `libdecor`. */
- while (!w->decor_configured) {
- if (libdecor_dispatch(m_system->decor_context(), 0) < 0) {
- break;
+ if (use_libdecor) {
+ WGL_LibDecor_Window &decor = *w->libdecor;
+ /* It's important not to return until the window is configured or
+ * calls to `setState` from Blender will crash `libdecor`. */
+ while (!decor.configured) {
+ if (libdecor_dispatch(m_system->libdecor_context(), 0) < 0) {
+ break;
+ }
}
}
#endif
@@ -535,9 +580,13 @@ GHOST_WindowWayland::GHOST_WindowWayland(GHOST_SystemWayland *system,
setOpaque();
#endif
-#ifndef WITH_GHOST_WAYLAND_LIBDECOR /* Causes a glitch with `libdecor` for some reason. */
- setState(state);
+ /* Causes a glitch with `libdecor` for some reason. */
+#ifdef WITH_GHOST_WAYLAND_LIBDECOR
+ if (use_libdecor == false)
#endif
+ {
+ setState(state);
+ }
/* EGL context. */
if (setDrawingContextType(type) == GHOST_kFailure) {
@@ -596,12 +645,16 @@ GHOST_TSuccess GHOST_WindowWayland::getCursorBitmap(GHOST_CursorBitmapRef *bitma
void GHOST_WindowWayland::setTitle(const char *title)
{
#ifdef WITH_GHOST_WAYLAND_LIBDECOR
- libdecor_frame_set_app_id(w->decor_frame, title);
- libdecor_frame_set_title(w->decor_frame, title);
-#else
- xdg_toplevel_set_title(w->xdg_toplevel, title);
- xdg_toplevel_set_app_id(w->xdg_toplevel, title);
+ if (use_libdecor) {
+ WGL_LibDecor_Window &decor = *w->libdecor;
+ libdecor_frame_set_title(decor.frame, title);
+ }
+ else
#endif
+ {
+ WGL_XDG_Decor_Window &decor = *w->xdg_decor;
+ xdg_toplevel_set_title(decor.toplevel, title);
+ }
this->title = title;
}
@@ -672,14 +725,14 @@ GHOST_WindowWayland::~GHOST_WindowWayland()
wl_egl_window_destroy(w->egl_window);
#ifdef WITH_GHOST_WAYLAND_LIBDECOR
- libdecor_frame_unref(w->decor_frame);
-#else
- if (w->xdg_toplevel_decoration) {
- zxdg_toplevel_decoration_v1_destroy(w->xdg_toplevel_decoration);
+ if (use_libdecor) {
+ wgl_libdecor_window_destroy(w->libdecor);
}
- xdg_toplevel_destroy(w->xdg_toplevel);
- xdg_surface_destroy(w->xdg_surface);
+ else
#endif
+ {
+ wgl_xdg_decor_window_destroy(w->xdg_decor);
+ }
/* Clear any pointers to this window. This is needed because there are no guarantees
* that flushing the display will the "leave" handlers before handling events. */
@@ -711,47 +764,74 @@ GHOST_TSuccess GHOST_WindowWayland::setState(GHOST_TWindowState state)
case GHOST_kWindowStateNormal:
/* Unset states. */
switch (getState()) {
- case GHOST_kWindowStateMaximized:
+ case GHOST_kWindowStateMaximized: {
#ifdef WITH_GHOST_WAYLAND_LIBDECOR
- libdecor_frame_unset_maximized(w->decor_frame);
-#else
- xdg_toplevel_unset_maximized(w->xdg_toplevel);
+ if (use_libdecor) {
+ libdecor_frame_unset_maximized(w->libdecor->frame);
+ }
+ else
#endif
+ {
+ xdg_toplevel_unset_maximized(w->xdg_decor->toplevel);
+ }
break;
- case GHOST_kWindowStateFullScreen:
+ }
+ case GHOST_kWindowStateFullScreen: {
#ifdef WITH_GHOST_WAYLAND_LIBDECOR
- libdecor_frame_unset_fullscreen(w->decor_frame);
-#else
- xdg_toplevel_unset_fullscreen(w->xdg_toplevel);
+ if (use_libdecor) {
+ libdecor_frame_unset_fullscreen(w->libdecor->frame);
+ }
+ else
#endif
+ {
+ xdg_toplevel_unset_fullscreen(w->xdg_decor->toplevel);
+ }
break;
- default:
+ }
+ default: {
break;
+ }
}
break;
- case GHOST_kWindowStateMaximized:
+ case GHOST_kWindowStateMaximized: {
#ifdef WITH_GHOST_WAYLAND_LIBDECOR
- libdecor_frame_set_maximized(w->decor_frame);
-#else
- xdg_toplevel_set_maximized(w->xdg_toplevel);
+ if (use_libdecor) {
+ libdecor_frame_set_maximized(w->libdecor->frame);
+ }
+ else
#endif
+ {
+ xdg_toplevel_set_maximized(w->xdg_decor->toplevel);
+ }
break;
- case GHOST_kWindowStateMinimized:
+ }
+ case GHOST_kWindowStateMinimized: {
#ifdef WITH_GHOST_WAYLAND_LIBDECOR
- libdecor_frame_set_minimized(w->decor_frame);
-#else
- xdg_toplevel_set_minimized(w->xdg_toplevel);
+ if (use_libdecor) {
+ libdecor_frame_set_minimized(w->libdecor->frame);
+ }
+ else
#endif
+ {
+ xdg_toplevel_set_minimized(w->xdg_decor->toplevel);
+ }
break;
- case GHOST_kWindowStateFullScreen:
+ }
+ case GHOST_kWindowStateFullScreen: {
#ifdef WITH_GHOST_WAYLAND_LIBDECOR
- libdecor_frame_set_fullscreen(w->decor_frame, nullptr);
-#else
- xdg_toplevel_set_fullscreen(w->xdg_toplevel, nullptr);
+ if (use_libdecor) {
+ libdecor_frame_set_fullscreen(w->libdecor->frame, nullptr);
+ }
+ else
#endif
+ {
+ xdg_toplevel_set_fullscreen(w->xdg_decor->toplevel, nullptr);
+ }
break;
- case GHOST_kWindowStateEmbedded:
+ }
+ case GHOST_kWindowStateEmbedded: {
return GHOST_kFailure;
+ }
}
return GHOST_kSuccess;
}
@@ -780,20 +860,29 @@ GHOST_TSuccess GHOST_WindowWayland::setOrder(GHOST_TWindowOrder /*order*/)
GHOST_TSuccess GHOST_WindowWayland::beginFullScreen() const
{
#ifdef WITH_GHOST_WAYLAND_LIBDECOR
- libdecor_frame_set_fullscreen(w->decor_frame, nullptr);
-#else
- xdg_toplevel_set_fullscreen(w->xdg_toplevel, nullptr);
+ if (use_libdecor) {
+ libdecor_frame_set_fullscreen(w->libdecor->frame, nullptr);
+ }
+ else
#endif
+ {
+ xdg_toplevel_set_fullscreen(w->xdg_decor->toplevel, nullptr);
+ }
+
return GHOST_kSuccess;
}
GHOST_TSuccess GHOST_WindowWayland::endFullScreen() const
{
#ifdef WITH_GHOST_WAYLAND_LIBDECOR
- libdecor_frame_unset_fullscreen(w->decor_frame);
-#else
- xdg_toplevel_unset_fullscreen(w->xdg_toplevel);
+ if (use_libdecor) {
+ libdecor_frame_unset_fullscreen(w->libdecor->frame);
+ }
+ else
#endif
+ {
+ xdg_toplevel_unset_fullscreen(w->xdg_decor->toplevel);
+ }
return GHOST_kSuccess;
}
diff --git a/intern/guardedalloc/intern/mallocn.c b/intern/guardedalloc/intern/mallocn.c
index 63f06ced31d..984e641e7c1 100644
--- a/intern/guardedalloc/intern/mallocn.c
+++ b/intern/guardedalloc/intern/mallocn.c
@@ -43,7 +43,7 @@ void (*MEM_set_error_callback)(void (*func)(const char *)) = MEM_lockfree_set_er
bool (*MEM_consistency_check)(void) = MEM_lockfree_consistency_check;
void (*MEM_set_memory_debug)(void) = MEM_lockfree_set_memory_debug;
size_t (*MEM_get_memory_in_use)(void) = MEM_lockfree_get_memory_in_use;
-unsigned int (*MEM_get_memory_blocks_in_use)(void) = MEM_lockfree_get_memory_blocks_in_use;
+uint (*MEM_get_memory_blocks_in_use)(void) = MEM_lockfree_get_memory_blocks_in_use;
void (*MEM_reset_peak_memory)(void) = MEM_lockfree_reset_peak_memory;
size_t (*MEM_get_peak_memory)(void) = MEM_lockfree_get_peak_memory;
diff --git a/intern/guardedalloc/intern/mallocn_lockfree_impl.c b/intern/guardedalloc/intern/mallocn_lockfree_impl.c
index b5ee539ff4d..5a969186b19 100644
--- a/intern/guardedalloc/intern/mallocn_lockfree_impl.c
+++ b/intern/guardedalloc/intern/mallocn_lockfree_impl.c
@@ -233,7 +233,7 @@ void *MEM_lockfree_callocN(size_t len, const char *str)
print_error("Calloc returns null: len=" SIZET_FORMAT " in %s, total %u\n",
SIZET_ARG(len),
str,
- (unsigned int)mem_in_use);
+ (uint)mem_in_use);
return NULL;
}
@@ -278,7 +278,7 @@ void *MEM_lockfree_mallocN(size_t len, const char *str)
print_error("Malloc returns null: len=" SIZET_FORMAT " in %s, total %u\n",
SIZET_ARG(len),
str,
- (unsigned int)mem_in_use);
+ (uint)mem_in_use);
return NULL;
}
@@ -292,7 +292,7 @@ void *MEM_lockfree_malloc_arrayN(size_t len, size_t size, const char *str)
SIZET_ARG(len),
SIZET_ARG(size),
str,
- (unsigned int)mem_in_use);
+ (uint)mem_in_use);
abort();
return NULL;
}
@@ -349,7 +349,7 @@ void *MEM_lockfree_mallocN_aligned(size_t len, size_t alignment, const char *str
print_error("Malloc returns null: len=" SIZET_FORMAT " in %s, total %u\n",
SIZET_ARG(len),
str,
- (unsigned int)mem_in_use);
+ (uint)mem_in_use);
return NULL;
}
@@ -401,7 +401,7 @@ size_t MEM_lockfree_get_memory_in_use(void)
return mem_in_use;
}
-unsigned int MEM_lockfree_get_memory_blocks_in_use(void)
+uint MEM_lockfree_get_memory_blocks_in_use(void)
{
return totblock;
}
diff --git a/intern/mikktspace/mikktspace.hh b/intern/mikktspace/mikktspace.hh
index e2c7084566f..9bfa6881f0d 100644
--- a/intern/mikktspace/mikktspace.hh
+++ b/intern/mikktspace/mikktspace.hh
@@ -723,12 +723,11 @@ template<typename Mesh> class Mikktspace {
void build4RuleGroups()
{
- /* Note: This could be parallelized by grouping all [t, i] pairs into
+ /* NOTE: This could be parallelized by grouping all [t, i] pairs into
* shards by hash(triangles[t].vertices[i]). This way, each shard can be processed
* independently and in parallel.
- * However, the groupWithAny logic needs special handling (e.g. lock a mutex when
- * encountering a groupWithAny triangle, then sort it out, then unlock and proceed).
- */
+ * However, the `groupWithAny` logic needs special handling (e.g. lock a mutex when
+ * encountering a `groupWithAny` triangle, then sort it out, then unlock and proceed). */
for (uint t = 0; t < nrTriangles; t++) {
Triangle &triangle = triangles[t];
for (uint i = 0; i < 3; i++) {
diff --git a/intern/wayland_dynload/intern/wayland_dynload_egl.c b/intern/wayland_dynload/intern/wayland_dynload_egl.c
index b62adb6c90e..cfc195c0408 100644
--- a/intern/wayland_dynload/intern/wayland_dynload_egl.c
+++ b/intern/wayland_dynload/intern/wayland_dynload_egl.c
@@ -22,7 +22,7 @@ bool wayland_dynload_egl_init(const bool verbose)
{
/* Library paths. */
const char *paths[] = {
- "libwayland-egl.so.0",
+ "libwayland-egl.so.1",
"libwayland-egl.so",
};
const int paths_num = sizeof(paths) / sizeof(*paths);
diff --git a/release/scripts/modules/bl_i18n_utils/settings.py b/release/scripts/modules/bl_i18n_utils/settings.py
index 95de2abc709..d8f8d58f609 100644
--- a/release/scripts/modules/bl_i18n_utils/settings.py
+++ b/release/scripts/modules/bl_i18n_utils/settings.py
@@ -367,9 +367,9 @@ WARN_MSGID_NOT_CAPITALIZED_ALLOWED = {
"all and invert unselected",
"and AMD driver version 22.10 or newer",
"and AMD Radeon Pro 21.Q4 driver or newer",
- "and Linux driver version xx.xx.23570 or newer",
+ "and Linux driver version xx.xx.23904 or newer",
"and NVIDIA driver version 470 or newer",
- "and Windows driver version 101.3268 or newer",
+ "and Windows driver version 101.3430 or newer",
"available with",
"brown fox",
"can't save image while rendering",
diff --git a/release/scripts/modules/bl_i18n_utils/utils_spell_check.py b/release/scripts/modules/bl_i18n_utils/utils_spell_check.py
index a93f1323562..7fe4d0da0a4 100644
--- a/release/scripts/modules/bl_i18n_utils/utils_spell_check.py
+++ b/release/scripts/modules/bl_i18n_utils/utils_spell_check.py
@@ -389,6 +389,8 @@ class SpellChecker:
"albedo",
"anamorphic",
"anisotropic", "anisotropy",
+ "arcminute", "arcminutes",
+ "arcsecond", "arcseconds",
"bimanual", # OpenXR?
"bitangent",
"boid", "boids",
@@ -449,7 +451,7 @@ class SpellChecker:
"superellipse",
"thumbstick",
"tooltip", "tooltips",
- "trackpad",
+ "touchpad", "trackpad",
"tuple",
"unicode",
"viewport", "viewports",
@@ -650,6 +652,7 @@ class SpellChecker:
"mikktspace",
"minkowski",
"minnaert",
+ "mises", # von Mises-Fisher
"moskowitz", # Pierson-Moskowitz
"musgrave",
"nayar",
@@ -665,6 +668,7 @@ class SpellChecker:
"runge",
"sobol",
"verlet",
+ "von", # von Mises-Fisher
"wilkie",
"worley",
@@ -724,6 +728,7 @@ class SpellChecker:
"lmb", "mmb", "rmb",
"lscm",
"kb",
+ "mis",
"mocap",
"msgid", "msgids",
"mux",
@@ -751,6 +756,7 @@ class SpellChecker:
"uuid",
"vbo", "vbos",
"vfx",
+ "vmm",
"vr",
"wxyz",
"xr",
diff --git a/release/scripts/modules/sys_info.py b/release/scripts/modules/sys_info.py
index 026c39908c0..7f6d0b1e9bf 100644
--- a/release/scripts/modules/sys_info.py
+++ b/release/scripts/modules/sys_info.py
@@ -53,6 +53,13 @@ def write_sysinfo(filepath):
output.write("build linkflags: %s\n" % prepr(bpy.app.build_linkflags))
output.write("build system: %s\n" % prepr(bpy.app.build_system))
+ # Windowing Environment (include when dynamically selectable).
+ from _bpy import _ghost_backend
+ ghost_backend = _ghost_backend()
+ if ghost_backend not in {'NONE', 'DEFAULT'}:
+ output.write("windowing environment: %s\n" % prepr(ghost_backend))
+ del _ghost_backend, ghost_backend
+
# Python info.
output.write(title("Python"))
output.write("version: %s\n" % (sys.version.replace("\n", " ")))
diff --git a/release/scripts/presets/keyconfig/keymap_data/blender_default.py b/release/scripts/presets/keyconfig/keymap_data/blender_default.py
index 5ab9cdb542a..b83c4916330 100644
--- a/release/scripts/presets/keyconfig/keymap_data/blender_default.py
+++ b/release/scripts/presets/keyconfig/keymap_data/blender_default.py
@@ -2073,6 +2073,8 @@ def km_node_editor(params):
op_menu("NODE_MT_add", {"type": 'A', "value": 'PRESS', "shift": True}),
("node.duplicate_move", {"type": 'D', "value": 'PRESS', "shift": True},
{"properties": [("NODE_OT_translate_attach", [("TRANSFORM_OT_translate", [("view2d_edge_pan", True)])])]}),
+ ("node.duplicate_move_linked", {"type": 'D', "value": 'PRESS', "alt": True},
+ {"properties": [("NODE_OT_translate_attach", [("TRANSFORM_OT_translate", [("view2d_edge_pan", True)])])]}),
("node.duplicate_move_keep_inputs", {"type": 'D', "value": 'PRESS', "shift": True, "ctrl": True},
{"properties": [("NODE_OT_translate_attach", [("TRANSFORM_OT_translate", [("view2d_edge_pan", True)])])]}),
("node.parent_set", {"type": 'P', "value": 'PRESS', "ctrl": True}, None),
diff --git a/release/scripts/startup/bl_operators/userpref.py b/release/scripts/startup/bl_operators/userpref.py
index ce23024fed5..6a027c0ce1f 100644
--- a/release/scripts/startup/bl_operators/userpref.py
+++ b/release/scripts/startup/bl_operators/userpref.py
@@ -89,6 +89,17 @@ class PREFERENCES_OT_copy_prev(Operator):
if os.path.isdir(cls._old_version_path(version_split)):
return version_split
version_old = version_old - 1
+
+ # Support loading 2.8x..2.9x startup (any older isn't so useful to load).
+ # NOTE: remove this block for Blender 4.0 and later.
+ if version_old == 299:
+ version_old = 294
+ while version_old >= 280:
+ version_split = version_old // 100, version_old % 100
+ if os.path.isdir(cls._old_version_path(version_split)):
+ return version_split
+ version_old = version_old - 1
+
return None
@classmethod
diff --git a/release/scripts/startup/bl_operators/wm.py b/release/scripts/startup/bl_operators/wm.py
index 9d04cfd5bc8..3b81f75b08a 100644
--- a/release/scripts/startup/bl_operators/wm.py
+++ b/release/scripts/startup/bl_operators/wm.py
@@ -3158,6 +3158,15 @@ class WM_MT_splash_about(Menu):
bpy.app.build_commit_time.decode('utf-8', 'replace')), translate=False)
col.label(text=iface_("Hash: %s") % bpy.app.build_hash.decode('ascii'), translate=False)
col.label(text=iface_("Branch: %s") % bpy.app.build_branch.decode('utf-8', 'replace'), translate=False)
+
+ # This isn't useful information on MS-Windows or Apple systems as dynamically switching
+ # between windowing systems is only supported between X11/WAYLAND.
+ from _bpy import _ghost_backend
+ ghost_backend = _ghost_backend()
+ if ghost_backend not in {'NONE', 'DEFAULT'}:
+ col.label(text=iface_("Windowing Environment: %s") % _ghost_backend(), translate=False)
+ del _ghost_backend, ghost_backend
+
col.separator(factor=2.0)
col.label(text="Blender is free software")
col.label(text="Licensed under the GNU General Public License")
diff --git a/release/scripts/startup/bl_ui/properties_particle.py b/release/scripts/startup/bl_ui/properties_particle.py
index c42275fcd54..8567ddb9372 100644
--- a/release/scripts/startup/bl_ui/properties_particle.py
+++ b/release/scripts/startup/bl_ui/properties_particle.py
@@ -239,6 +239,7 @@ class PARTICLE_PT_context_particles(ParticleButtonsPanel, Panel):
class PARTICLE_PT_emission(ParticleButtonsPanel, Panel):
bl_label = "Emission"
+ bl_translation_context = i18n_contexts.id_particlesettings
COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE', 'BLENDER_EEVEE_NEXT', 'BLENDER_WORKBENCH'}
@classmethod
diff --git a/release/scripts/startup/bl_ui/space_clip.py b/release/scripts/startup/bl_ui/space_clip.py
index c337e8018e6..54b3a20f966 100644
--- a/release/scripts/startup/bl_ui/space_clip.py
+++ b/release/scripts/startup/bl_ui/space_clip.py
@@ -2,7 +2,10 @@
import bpy
from bpy.types import Panel, Header, Menu, UIList
-from bpy.app.translations import pgettext_iface as iface_
+from bpy.app.translations import (
+ pgettext_iface as iface_,
+ contexts as i18n_contexts,
+)
from bl_ui.utils import PresetPanel
from bl_ui.properties_grease_pencil_common import (
AnnotationDrawingToolsPanel,
@@ -1751,6 +1754,7 @@ class CLIP_MT_marker_pie(Menu):
class CLIP_MT_tracking_pie(Menu):
# Tracking Operators
bl_label = "Tracking"
+ bl_translation_context = i18n_contexts.id_movieclip
@classmethod
def poll(cls, context):
diff --git a/release/scripts/startup/bl_ui/space_image.py b/release/scripts/startup/bl_ui/space_image.py
index cefa4bf7d1d..fcbd7bb423d 100644
--- a/release/scripts/startup/bl_ui/space_image.py
+++ b/release/scripts/startup/bl_ui/space_image.py
@@ -1528,36 +1528,23 @@ class IMAGE_PT_overlay_guides(Panel):
layout.active = overlay.show_overlays
row = layout.row()
- row_el = row.column()
- row_el.prop(overlay, "show_grid_background", text="Grid")
+ row.prop(overlay, "show_grid_background", text="Grid")
if overlay.show_grid_background:
- layout.use_property_split = True
-
- col = layout.column(align=False, heading="Grid Over Image")
- col.use_property_decorate = False
- row = col.row(align=True)
- sub = row.row(align=True)
- sub.prop(uvedit, "show_grid_over_image", text="")
+ sub = row.row()
+ sub.prop(uvedit, "show_grid_over_image", text="Over Image")
sub.active = sima.image is not None
- col = layout.column(align=False, heading="Fixed Subdivisions")
- col.use_property_decorate = False
+ layout.row().prop(uvedit, "grid_shape_source", expand=True)
- row = col.row(align=True)
- sub = row.row(align=True)
- sub.prop(uvedit, "use_custom_grid", text="")
- if uvedit.use_custom_grid:
- row = layout.row()
- row.use_property_split = True
- row.use_property_decorate = False
- sub = sub.row(align=True)
- sub.prop(uvedit, "custom_grid_subdivisions", text="")
+ layout.use_property_split = True
+ layout.use_property_decorate = False
row = layout.row()
- row.use_property_split = True
- row.use_property_decorate = False
- row.prop(uvedit, "tile_grid_shape", text="Tiles")
+ row.prop(uvedit, "custom_grid_subdivisions", text="Fixed Subdivisions")
+ row.active = uvedit.grid_shape_source == 'FIXED'
+
+ layout.prop(uvedit, "tile_grid_shape", text="Tiles")
class IMAGE_PT_overlay_uv_edit(Panel):
diff --git a/release/scripts/startup/bl_ui/space_node.py b/release/scripts/startup/bl_ui/space_node.py
index f4070a8289d..593c6400529 100644
--- a/release/scripts/startup/bl_ui/space_node.py
+++ b/release/scripts/startup/bl_ui/space_node.py
@@ -318,6 +318,7 @@ class NODE_MT_node(Menu):
layout.operator("node.clipboard_copy", text="Copy")
layout.operator("node.clipboard_paste", text="Paste")
layout.operator("node.duplicate_move")
+ layout.operator("node.duplicate_move_linked")
layout.operator("node.delete")
layout.operator("node.delete_reconnect")
diff --git a/release/scripts/startup/bl_ui/space_sequencer.py b/release/scripts/startup/bl_ui/space_sequencer.py
index a99df1164a0..e703cf7f9c6 100644
--- a/release/scripts/startup/bl_ui/space_sequencer.py
+++ b/release/scripts/startup/bl_ui/space_sequencer.py
@@ -683,7 +683,7 @@ class SEQUENCER_MT_add(Menu):
elif bpy_data_movieclips_len > 0:
layout.operator_menu_enum("sequencer.movieclip_strip_add", "clip", text="Clip", icon='TRACKER')
else:
- layout.menu("SEQUENCER_MT_add_empty", text="Clip", icon='TRACKER')
+ layout.menu("SEQUENCER_MT_add_empty", text="Clip", text_ctxt=i18n_contexts.id_movieclip, icon='TRACKER')
del bpy_data_movieclips_len
bpy_data_masks_len = len(bpy.data.masks)
diff --git a/release/scripts/startup/bl_ui/space_userpref.py b/release/scripts/startup/bl_ui/space_userpref.py
index a9736feb057..53999f3c154 100644
--- a/release/scripts/startup/bl_ui/space_userpref.py
+++ b/release/scripts/startup/bl_ui/space_userpref.py
@@ -397,17 +397,18 @@ class USERPREF_PT_edit_objects_duplicate_data(EditingPanel, CenterAlignMixIn, Pa
# col.prop(edit, "use_duplicate_fcurve", text="F-Curve") # Not implemented.
col.prop(edit, "use_duplicate_curves", text="Curves")
col.prop(edit, "use_duplicate_grease_pencil", text="Grease Pencil")
+ col.prop(edit, "use_duplicate_lattice", text="Lattice")
col = flow.column()
- col.prop(edit, "use_duplicate_lattice", text="Lattice")
col.prop(edit, "use_duplicate_light", text="Light")
col.prop(edit, "use_duplicate_lightprobe", text="Light Probe")
col.prop(edit, "use_duplicate_material", text="Material")
col.prop(edit, "use_duplicate_mesh", text="Mesh")
col.prop(edit, "use_duplicate_metaball", text="Metaball")
+ col.prop(edit, "use_duplicate_node_tree", text="Node Tree")
+ col.prop(edit, "use_duplicate_particle", text="Particle")
col = flow.column()
- col.prop(edit, "use_duplicate_particle", text="Particle")
if hasattr(edit, "use_duplicate_pointcloud"):
col.prop(edit, "use_duplicate_pointcloud", text="Point Cloud")
col.prop(edit, "use_duplicate_speaker", text="Speaker")
diff --git a/release/scripts/startup/bl_ui/space_view3d.py b/release/scripts/startup/bl_ui/space_view3d.py
index ada2993a16f..3a02492635a 100644
--- a/release/scripts/startup/bl_ui/space_view3d.py
+++ b/release/scripts/startup/bl_ui/space_view3d.py
@@ -3356,8 +3356,7 @@ class VIEW3D_MT_face_sets(Menu):
op = layout.operator("sculpt.face_set_change_visibility", text='Invert Visible Face Sets')
op.mode = 'INVERT'
- op = layout.operator("sculpt.face_set_change_visibility", text='Show All Face Sets')
- op.mode = 'SHOW_ALL'
+ op = layout.operator("sculpt.reveal_all", text='Show All Face Sets')
layout.separator()
@@ -5518,8 +5517,7 @@ class VIEW3D_MT_sculpt_face_sets_edit_pie(Menu):
op = pie.operator("sculpt.face_set_change_visibility", text='Invert Visible')
op.mode = 'INVERT'
- op = pie.operator("sculpt.face_set_change_visibility", text='Show All')
- op.mode = 'SHOW_ALL'
+ op = pie.operator("sculpt.reveal_all", text='Show All')
class VIEW3D_MT_wpaint_vgroup_lock_pie(Menu):
diff --git a/source/blender/blenkernel/BKE_bvhutils.h b/source/blender/blenkernel/BKE_bvhutils.h
index d22abd235df..a0a6ac58c58 100644
--- a/source/blender/blenkernel/BKE_bvhutils.h
+++ b/source/blender/blenkernel/BKE_bvhutils.h
@@ -11,6 +11,10 @@
#include "BLI_threads.h"
#ifdef __cplusplus
+# include <mutex>
+#endif
+
+#ifdef __cplusplus
extern "C" {
#endif
@@ -196,6 +200,8 @@ BVHTree *BKE_bvhtree_from_mesh_get(struct BVHTreeFromMesh *data,
BVHCacheType bvh_cache_type,
int tree_type);
+#ifdef __cplusplus
+
/**
* Builds or queries a BVH-cache for the cache BVH-tree of the request type.
*/
@@ -204,7 +210,9 @@ BVHTree *BKE_bvhtree_from_editmesh_get(BVHTreeFromEditMesh *data,
int tree_type,
BVHCacheType bvh_cache_type,
struct BVHCache **bvh_cache_p,
- ThreadMutex *mesh_eval_mutex);
+ std::mutex *mesh_eval_mutex);
+
+#endif
/**
* Frees data allocated by a call to `bvhtree_from_editmesh_*`.
diff --git a/source/blender/blenkernel/BKE_customdata.h b/source/blender/blenkernel/BKE_customdata.h
index 61f3a0e1d5e..f761e28cbb4 100644
--- a/source/blender/blenkernel/BKE_customdata.h
+++ b/source/blender/blenkernel/BKE_customdata.h
@@ -146,15 +146,6 @@ void CustomData_copy(const struct CustomData *source,
eCDAllocType alloctype,
int totelem);
-/**
- * Like #CustomData_copy but skips copying layers that are stored as flags on #BMesh.
- */
-void CustomData_copy_mesh_to_bmesh(const struct CustomData *source,
- struct CustomData *dest,
- eCustomDataMask mask,
- eCDAllocType alloctype,
- int totelem);
-
/* BMESH_TODO, not really a public function but readfile.c needs it */
void CustomData_update_typemap(struct CustomData *data);
@@ -169,15 +160,6 @@ bool CustomData_merge(const struct CustomData *source,
int totelem);
/**
- * Like #CustomData_copy but skips copying layers that are stored as flags on #BMesh.
- */
-bool CustomData_merge_mesh_to_bmesh(const struct CustomData *source,
- struct CustomData *dest,
- eCustomDataMask mask,
- eCDAllocType alloctype,
- int totelem);
-
-/**
* Reallocate custom data to a new element count. If the new size is larger, the new values use
* the #CD_CONSTRUCT behavior, so trivial types must be initialized by the caller. After being
* resized, the #CustomData does not contain any referenced layers.
@@ -197,6 +179,14 @@ bool CustomData_bmesh_merge(const struct CustomData *source,
char htype);
/**
+ * Remove layers that aren't stored in BMesh or are stored as flags on BMesh.
+ * The `layers` array of the returned #CustomData must be freed, but may be null.
+ * Used during conversion of #Mesh data to #BMesh storage format.
+ */
+CustomData CustomData_shallow_copy_remove_non_bmesh_attributes(const CustomData *src,
+ eCustomDataMask mask);
+
+/**
* NULL's all members and resets the #CustomData.typemap.
*/
void CustomData_reset(struct CustomData *data);
diff --git a/source/blender/blenkernel/BKE_duplilist.h b/source/blender/blenkernel/BKE_duplilist.h
index 8a37348377a..44c4df1fc2e 100644
--- a/source/blender/blenkernel/BKE_duplilist.h
+++ b/source/blender/blenkernel/BKE_duplilist.h
@@ -16,6 +16,7 @@ struct ListBase;
struct Object;
struct ParticleSystem;
struct Scene;
+struct ViewLayer;
struct ViewerPath;
struct GeometrySet;
@@ -83,6 +84,13 @@ bool BKE_object_dupli_find_rgba_attribute(struct Object *ob,
const char *name,
float r_value[4]);
+/** Look up the RGBA value of a view layer/scene/world shader attribute.
+ * \return true if the attribute was found; if not, r_value is also set to zero. */
+bool BKE_view_layer_find_rgba_attribute(struct Scene *scene,
+ struct ViewLayer *layer,
+ const char *name,
+ float r_value[4]);
+
#ifdef __cplusplus
}
#endif
diff --git a/source/blender/blenkernel/BKE_editmesh_cache.h b/source/blender/blenkernel/BKE_editmesh_cache.h
index 2640356ccf6..454a07be4e3 100644
--- a/source/blender/blenkernel/BKE_editmesh_cache.h
+++ b/source/blender/blenkernel/BKE_editmesh_cache.h
@@ -11,15 +11,25 @@ extern "C" {
#endif
struct BMEditMesh;
-struct EditMeshData;
-void BKE_editmesh_cache_ensure_poly_normals(struct BMEditMesh *em, struct EditMeshData *emd);
-void BKE_editmesh_cache_ensure_vert_normals(struct BMEditMesh *em, struct EditMeshData *emd);
+typedef struct EditMeshData {
+ /** when set, \a vertexNos, polyNos are lazy initialized */
+ const float (*vertexCos)[3];
-void BKE_editmesh_cache_ensure_poly_centers(struct BMEditMesh *em, struct EditMeshData *emd);
+ /** lazy initialize (when \a vertexCos is set) */
+ float const (*vertexNos)[3];
+ float const (*polyNos)[3];
+ /** also lazy init but don't depend on \a vertexCos */
+ const float (*polyCos)[3];
+} EditMeshData;
+
+void BKE_editmesh_cache_ensure_poly_normals(struct BMEditMesh *em, EditMeshData *emd);
+void BKE_editmesh_cache_ensure_vert_normals(struct BMEditMesh *em, EditMeshData *emd);
+
+void BKE_editmesh_cache_ensure_poly_centers(struct BMEditMesh *em, EditMeshData *emd);
bool BKE_editmesh_cache_calc_minmax(struct BMEditMesh *em,
- struct EditMeshData *emd,
+ EditMeshData *emd,
float min[3],
float max[3]);
diff --git a/source/blender/blenkernel/BKE_mesh.h b/source/blender/blenkernel/BKE_mesh.h
index 0a000f4543a..0ff7f50f71c 100644
--- a/source/blender/blenkernel/BKE_mesh.h
+++ b/source/blender/blenkernel/BKE_mesh.h
@@ -490,7 +490,7 @@ void BKE_mesh_calc_normals(struct Mesh *me);
* Called after calculating all modifiers.
*/
void BKE_mesh_ensure_normals_for_display(struct Mesh *mesh);
-void BKE_mesh_calc_normals_looptri(struct MVert *mverts,
+void BKE_mesh_calc_normals_looptri(const struct MVert *mverts,
int numVerts,
const struct MLoop *mloop,
const struct MLoopTri *looptri,
diff --git a/source/blender/blenkernel/BKE_mesh_mapping.h b/source/blender/blenkernel/BKE_mesh_mapping.h
index da8431d4f27..9d9c2f57f89 100644
--- a/source/blender/blenkernel/BKE_mesh_mapping.h
+++ b/source/blender/blenkernel/BKE_mesh_mapping.h
@@ -336,7 +336,7 @@ int *BKE_mesh_calc_smoothgroups(const struct MEdge *medge,
#endif
#ifdef __cplusplus
-namespace blender::mesh_topology {
+namespace blender::bke::mesh_topology {
Array<int> build_loop_to_poly_map(Span<MPoly> polys, int loops_num);
@@ -348,5 +348,5 @@ inline int previous_poly_loop(const MPoly &poly, int loop_i)
return loop_i - 1 + (loop_i == poly.loopstart) * poly.totloop;
}
-} // namespace blender::mesh_topology
+} // namespace blender::bke::mesh_topology
#endif
diff --git a/source/blender/blenkernel/BKE_mesh_runtime.h b/source/blender/blenkernel/BKE_mesh_runtime.h
index dfefe125a51..27e04c1a4de 100644
--- a/source/blender/blenkernel/BKE_mesh_runtime.h
+++ b/source/blender/blenkernel/BKE_mesh_runtime.h
@@ -9,6 +9,7 @@
*/
//#include "BKE_customdata.h" /* for eCustomDataMask */
+#include "BKE_mesh_types.h"
#ifdef __cplusplus
extern "C" {
@@ -26,21 +27,10 @@ struct Object;
struct Scene;
/**
- * \brief Initialize the runtime of the given mesh.
- *
- * Function expects that the runtime is already cleared.
- */
-void BKE_mesh_runtime_init_data(struct Mesh *mesh);
-/**
* \brief Free all data (and mutexes) inside the runtime of the given mesh.
*/
void BKE_mesh_runtime_free_data(struct Mesh *mesh);
-/**
- * Clear all pointers which we don't want to be shared on copying the datablock.
- * However, keep all the flags which defines what the mesh is (for example, that
- * it's deformed only, or that its custom data layers are out of date.)
- */
-void BKE_mesh_runtime_reset_on_copy(struct Mesh *mesh, int flag);
+
int BKE_mesh_runtime_looptri_len(const struct Mesh *mesh);
void BKE_mesh_runtime_looptri_recalc(struct Mesh *mesh);
/**
@@ -66,6 +56,11 @@ void BKE_mesh_runtime_verttri_from_looptri(struct MVertTri *r_verttri,
const struct MLoopTri *looptri,
int looptri_num);
+/** \note Only used for access in C. */
+bool BKE_mesh_is_deformed_only(const struct Mesh *mesh);
+/** \note Only used for access in C. */
+eMeshWrapperType BKE_mesh_wrapper_type(const struct Mesh *mesh);
+
/* NOTE: the functions below are defined in DerivedMesh.cc, and are intended to be moved
* to a more suitable location when that file is removed.
* They should also be renamed to use conventions from BKE, not old DerivedMesh.cc.
diff --git a/source/blender/blenkernel/BKE_mesh_types.h b/source/blender/blenkernel/BKE_mesh_types.h
index 0b879c1dfe9..dacc2188abb 100644
--- a/source/blender/blenkernel/BKE_mesh_types.h
+++ b/source/blender/blenkernel/BKE_mesh_types.h
@@ -1,11 +1,35 @@
/* SPDX-License-Identifier: GPL-2.0-or-later
* Copyright 2020 Blender Foundation. All rights reserved. */
+
#pragma once
/** \file
* \ingroup bke
*/
+#ifdef __cplusplus
+
+# include <mutex>
+
+# include "BLI_span.hh"
+
+# include "DNA_customdata_types.h"
+
+# include "MEM_guardedalloc.h"
+
+struct BVHCache;
+struct EditMeshData;
+struct MLoopTri;
+struct ShrinkwrapBoundaryData;
+struct SubdivCCG;
+struct SubsurfRuntimeData;
+
+#endif
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
typedef enum eMeshBatchDirtyMode {
BKE_MESH_BATCH_DIRTY_ALL = 0,
BKE_MESH_BATCH_DIRTY_SELECT,
@@ -14,3 +38,125 @@ typedef enum eMeshBatchDirtyMode {
BKE_MESH_BATCH_DIRTY_UVEDIT_ALL,
BKE_MESH_BATCH_DIRTY_UVEDIT_SELECT,
} eMeshBatchDirtyMode;
+
+/** #MeshRuntime.wrapper_type */
+typedef enum eMeshWrapperType {
+ /** Use mesh data (#Mesh.mvert, #Mesh.medge, #Mesh.mloop, #Mesh.mpoly). */
+ ME_WRAPPER_TYPE_MDATA = 0,
+ /** Use edit-mesh data (#Mesh.edit_mesh, #MeshRuntime.edit_data). */
+ ME_WRAPPER_TYPE_BMESH = 1,
+ /** Use subdivision mesh data (#MeshRuntime.mesh_eval). */
+ ME_WRAPPER_TYPE_SUBD = 2,
+} eMeshWrapperType;
+
+#ifdef __cplusplus
+}
+#endif
+
+#ifdef __cplusplus
+
+namespace blender::bke {
+
+/**
+ * \warning Typical access is done via #Mesh::looptris().
+ */
+struct MLoopTri_Store {
+ /* WARNING! swapping between array (ready-to-be-used data) and array_wip
+ * (where data is actually computed)
+ * shall always be protected by same lock as one used for looptris computing. */
+ MLoopTri *array = nullptr;
+ MLoopTri *array_wip = nullptr;
+ int len = 0;
+ int len_alloc = 0;
+};
+
+struct MeshRuntime {
+ /* Evaluated mesh for objects which do not have effective modifiers.
+ * This mesh is used as a result of modifier stack evaluation.
+ * Since modifier stack evaluation is threaded on object level we need some synchronization. */
+ Mesh *mesh_eval = nullptr;
+ std::mutex eval_mutex;
+
+ /* A separate mutex is needed for normal calculation, because sometimes
+ * the normals are needed while #eval_mutex is already locked. */
+ std::mutex normals_mutex;
+
+ /** Needed to ensure some thread-safety during render data pre-processing. */
+ std::mutex render_mutex;
+
+ /** Lazily initialized SoA data from the #edit_mesh field in #Mesh. */
+ EditMeshData *edit_data = nullptr;
+
+ /**
+ * Data used to efficiently draw the mesh in the viewport, especially useful when
+ * the same mesh is used in many objects or instances. See `draw_cache_impl_mesh.cc`.
+ */
+ void *batch_cache = nullptr;
+
+ /** Cache for derived triangulation of the mesh. */
+ MLoopTri_Store looptris;
+
+ /** Cache for BVH trees generated for the mesh. Defined in 'BKE_bvhutil.c' */
+ BVHCache *bvh_cache = nullptr;
+
+ /** Cache of non-manifold boundary data for Shrinkwrap Target Project. */
+ ShrinkwrapBoundaryData *shrinkwrap_data = nullptr;
+
+ /** Needed in case we need to lazily initialize the mesh. */
+ CustomData_MeshMasks cd_mask_extra = {};
+
+ SubdivCCG *subdiv_ccg = nullptr;
+ int subdiv_ccg_tot_level = 0;
+
+ /** Set by modifier stack if only deformed from original. */
+ bool deformed_only = false;
+ /**
+ * Copied from edit-mesh (hint, draw with edit-mesh data when true).
+ *
+ * Modifiers that edit the mesh data in-place must set this to false
+ * (most #eModifierTypeType_NonGeometrical modifiers). Otherwise the edit-mesh
+ * data will be used for drawing, missing changes from modifiers. See T79517.
+ */
+ bool is_original_bmesh = false;
+
+ /** #eMeshWrapperType and others. */
+ eMeshWrapperType wrapper_type = ME_WRAPPER_TYPE_MDATA;
+ /**
+ * A type mask from wrapper_type,
+ * in case there are differences in finalizing logic between types.
+ */
+ eMeshWrapperType wrapper_type_finalize = ME_WRAPPER_TYPE_MDATA;
+
+ /**
+ * Settings for lazily evaluating the subdivision on the CPU if needed. These are
+ * set in the modifier when GPU subdivision can be performed, and owned by the by
+ * the modifier in the object.
+ */
+ SubsurfRuntimeData *subsurf_runtime_data = nullptr;
+
+ /**
+ * Caches for lazily computed vertex and polygon normals. These are stored here rather than in
+ * #CustomData because they can be calculated on a const mesh, and adding custom data layers on a
+ * const mesh is not thread-safe.
+ */
+ bool vert_normals_dirty = false;
+ bool poly_normals_dirty = false;
+ float (*vert_normals)[3] = nullptr;
+ float (*poly_normals)[3] = nullptr;
+
+ /**
+ * A #BLI_bitmap containing tags for the center vertices of subdivided polygons, set by the
+ * subdivision surface modifier and used by drawing code instead of polygon center face dots.
+ */
+ uint32_t *subsurf_face_dot_tags = nullptr;
+
+ MeshRuntime() = default;
+ /** \warning This does not free all data currently. See #BKE_mesh_runtime_free_data. */
+ ~MeshRuntime() = default;
+
+ MEM_CXX_CLASS_ALLOC_FUNCS("MeshRuntime")
+};
+
+} // namespace blender::bke
+
+#endif
diff --git a/source/blender/blenkernel/BKE_nla.h b/source/blender/blenkernel/BKE_nla.h
index 9d3000759ab..efadd5c11d6 100644
--- a/source/blender/blenkernel/BKE_nla.h
+++ b/source/blender/blenkernel/BKE_nla.h
@@ -246,6 +246,24 @@ float BKE_nlastrip_compute_frame_from_previous_strip(struct NlaStrip *strip);
*/
float BKE_nlastrip_compute_frame_to_next_strip(struct NlaStrip *strip);
+/**
+ * Returns the next strip in this strip's NLA track, or a null pointer.
+ *
+ * \param strip The strip to find the next trip from.
+ * \param check_transitions Whether or not to skip transitions.
+ * \return The next strip in the track, or NULL if none are present.
+ */
+struct NlaStrip *BKE_nlastrip_next_in_track(struct NlaStrip *strip, bool skip_transitions);
+
+/**
+ * Returns the previous strip in this strip's NLA track, or a null pointer.
+ *
+ * \param strip The strip to find the previous trip from.
+ * \param check_transitions Whether or not to skip transitions.
+ * \return The previous strip in the track, or NULL if none are present.
+ */
+struct NlaStrip *BKE_nlastrip_prev_in_track(struct NlaStrip *strip, bool skip_transitions);
+
/* ............ */
/**
diff --git a/source/blender/blenkernel/BKE_pbvh.h b/source/blender/blenkernel/BKE_pbvh.h
index 6d103eab8a7..c3100dd2345 100644
--- a/source/blender/blenkernel/BKE_pbvh.h
+++ b/source/blender/blenkernel/BKE_pbvh.h
@@ -126,6 +126,8 @@ typedef enum {
PBVH_UpdateColor = 1 << 14,
PBVH_RebuildPixels = 1 << 15,
PBVH_TexLeaf = 1 << 16,
+ PBVH_TopologyUpdated = 1 << 17, /* Used internally by pbvh_bmesh.c */
+
} PBVHNodeFlags;
typedef struct PBVHFrustumPlanes {
@@ -266,7 +268,8 @@ void BKE_pbvh_build_grids(PBVH *pbvh,
void **gridfaces,
struct DMFlagMat *flagmats,
unsigned int **grid_hidden,
- struct Mesh *me);
+ struct Mesh *me,
+ struct SubdivCCG *subdiv_ccg);
/**
* Build a PBVH from a BMesh.
*/
@@ -490,7 +493,10 @@ struct GSet *BKE_pbvh_bmesh_node_faces(PBVHNode *node);
*
* Skips triangles that are hidden.
*/
-void BKE_pbvh_bmesh_node_save_orig(struct BMesh *bm, PBVHNode *node);
+void BKE_pbvh_bmesh_node_save_orig(struct BMesh *bm,
+ struct BMLog *log,
+ PBVHNode *node,
+ bool use_original);
void BKE_pbvh_bmesh_after_stroke(PBVH *pbvh);
/* Update Bounding Box/Redraw and clear flags. */
@@ -669,7 +675,8 @@ void BKE_pbvh_gather_proxies(PBVH *pbvh, PBVHNode ***r_array, int *r_tot);
void BKE_pbvh_node_get_bm_orco_data(PBVHNode *node,
int (**r_orco_tris)[3],
int *r_orco_tris_num,
- float (**r_orco_coords)[3]);
+ float (**r_orco_coords)[3],
+ struct BMVert ***r_orco_verts);
/**
* \note doing a full search on all vertices here seems expensive,
diff --git a/source/blender/blenkernel/intern/DerivedMesh.cc b/source/blender/blenkernel/intern/DerivedMesh.cc
index b4cc46619a7..11ef2b08df4 100644
--- a/source/blender/blenkernel/intern/DerivedMesh.cc
+++ b/source/blender/blenkernel/intern/DerivedMesh.cc
@@ -35,6 +35,7 @@
#include "BKE_colorband.h"
#include "BKE_deform.h"
#include "BKE_editmesh.h"
+#include "BKE_editmesh_cache.h"
#include "BKE_geometry_set.hh"
#include "BKE_geometry_set_instances.hh"
#include "BKE_key.h"
@@ -537,7 +538,7 @@ static void mesh_calc_modifier_final_normals(const Mesh *mesh_input,
(final_datamask->lmask & CD_MASK_NORMAL) != 0);
/* Needed as `final_datamask` is not preserved outside modifier stack evaluation. */
- SubsurfRuntimeData *subsurf_runtime_data = mesh_final->runtime.subsurf_runtime_data;
+ SubsurfRuntimeData *subsurf_runtime_data = mesh_final->runtime->subsurf_runtime_data;
if (subsurf_runtime_data) {
subsurf_runtime_data->calc_loop_normals = calc_loop_normals;
}
@@ -585,11 +586,12 @@ static void mesh_calc_finalize(const Mesh *mesh_input, Mesh *mesh_eval)
void BKE_mesh_wrapper_deferred_finalize_mdata(Mesh *me_eval,
const CustomData_MeshMasks *cd_mask_finalize)
{
- if (me_eval->runtime.wrapper_type_finalize & (1 << ME_WRAPPER_TYPE_BMESH)) {
+ if (me_eval->runtime->wrapper_type_finalize & (1 << ME_WRAPPER_TYPE_BMESH)) {
editbmesh_calc_modifier_final_normals(me_eval, cd_mask_finalize);
- me_eval->runtime.wrapper_type_finalize &= ~(1 << ME_WRAPPER_TYPE_BMESH);
+ me_eval->runtime->wrapper_type_finalize = eMeshWrapperType(
+ me_eval->runtime->wrapper_type_finalize & ~(1 << ME_WRAPPER_TYPE_BMESH));
}
- BLI_assert(me_eval->runtime.wrapper_type_finalize == 0);
+ BLI_assert(me_eval->runtime->wrapper_type_finalize == 0);
}
/**
@@ -1052,7 +1054,7 @@ static void mesh_calc_modifiers(struct Depsgraph *depsgraph,
append_mask.lmask |= CD_MASK_PREVIEW_MLOOPCOL;
}
- mesh_final->runtime.deformed_only = false;
+ mesh_final->runtime->deformed_only = false;
}
isPrevDeform = (mti->type == eModifierTypeType_OnlyDeform);
@@ -1119,10 +1121,9 @@ static void mesh_calc_modifiers(struct Depsgraph *depsgraph,
mesh_calc_finalize(mesh_input, mesh_final);
}
else {
- Mesh_Runtime *runtime = &mesh_input->runtime;
+ blender::bke::MeshRuntime *runtime = mesh_input->runtime;
if (runtime->mesh_eval == nullptr) {
- BLI_assert(runtime->eval_mutex != nullptr);
- BLI_mutex_lock((ThreadMutex *)runtime->eval_mutex);
+ std::lock_guard lock{mesh_input->runtime->eval_mutex};
if (runtime->mesh_eval == nullptr) {
/* Not yet finalized by any instance, do it now
* Isolate since computing normals is multithreaded and we are holding a lock. */
@@ -1138,7 +1139,6 @@ static void mesh_calc_modifiers(struct Depsgraph *depsgraph,
/* Already finalized by another instance, reuse. */
mesh_final = runtime->mesh_eval;
}
- BLI_mutex_unlock((ThreadMutex *)runtime->eval_mutex);
}
else if (!mesh_has_modifier_final_normals(mesh_input, &final_datamask, runtime->mesh_eval)) {
/* Modifier stack was (re-)evaluated with a request for additional normals
@@ -1207,7 +1207,7 @@ static void editbmesh_calc_modifier_final_normals(Mesh *mesh_final,
const bool calc_loop_normals = ((mesh_final->flag & ME_AUTOSMOOTH) != 0 ||
(final_datamask->lmask & CD_MASK_NORMAL) != 0);
- SubsurfRuntimeData *subsurf_runtime_data = mesh_final->runtime.subsurf_runtime_data;
+ SubsurfRuntimeData *subsurf_runtime_data = mesh_final->runtime->subsurf_runtime_data;
if (subsurf_runtime_data) {
subsurf_runtime_data->calc_loop_normals = calc_loop_normals;
}
@@ -1234,9 +1234,10 @@ static void editbmesh_calc_modifier_final_normals(Mesh *mesh_final,
static void editbmesh_calc_modifier_final_normals_or_defer(
Mesh *mesh_final, const CustomData_MeshMasks *final_datamask)
{
- if (mesh_final->runtime.wrapper_type != ME_WRAPPER_TYPE_MDATA) {
+ if (mesh_final->runtime->wrapper_type != ME_WRAPPER_TYPE_MDATA) {
/* Generated at draw time. */
- mesh_final->runtime.wrapper_type_finalize = (1 << mesh_final->runtime.wrapper_type);
+ mesh_final->runtime->wrapper_type_finalize = eMeshWrapperType(
+ 1 << mesh_final->runtime->wrapper_type);
return;
}
@@ -1450,7 +1451,7 @@ static void editbmesh_calc_modifiers(struct Depsgraph *depsgraph,
deformed_verts = nullptr;
}
}
- mesh_final->runtime.deformed_only = false;
+ mesh_final->runtime->deformed_only = false;
}
if (r_cage && i == cageIndex) {
@@ -1469,7 +1470,8 @@ static void editbmesh_calc_modifiers(struct Depsgraph *depsgraph,
if (!BKE_mesh_runtime_ensure_edit_data(me_orig)) {
BKE_mesh_runtime_reset_edit_data(me_orig);
}
- me_orig->runtime.edit_data->vertexCos = (const float(*)[3])MEM_dupallocN(deformed_verts);
+ me_orig->runtime->edit_data->vertexCos = (const float(*)[3])MEM_dupallocN(
+ deformed_verts);
}
mesh_cage = BKE_mesh_wrapper_from_editmesh_with_coords(
em_input,
@@ -1583,7 +1585,7 @@ static void mesh_build_data(struct Depsgraph *depsgraph,
* object's runtime: this could cause access freed data on depsgraph destruction (mesh who owns
* the final result might be freed prior to object). */
Mesh *mesh = (Mesh *)ob->data;
- const bool is_mesh_eval_owned = (mesh_eval != mesh->runtime.mesh_eval);
+ const bool is_mesh_eval_owned = (mesh_eval != mesh->runtime->mesh_eval);
BKE_object_eval_assign_data(ob, &mesh_eval->id, is_mesh_eval_owned);
/* Add the final mesh as a non-owning component to the geometry set. */
@@ -1643,7 +1645,7 @@ static void editbmesh_build_data(struct Depsgraph *depsgraph,
}
}
- const bool is_mesh_eval_owned = (me_final != mesh->runtime.mesh_eval);
+ const bool is_mesh_eval_owned = (me_final != mesh->runtime->mesh_eval);
BKE_object_eval_assign_data(obedit, &me_final->id, is_mesh_eval_owned);
obedit->runtime.editmesh_eval_cage = me_cage;
@@ -1899,7 +1901,7 @@ struct MappedUserData {
static void make_vertexcos__mapFunc(void *userData,
int index,
const float co[3],
- const float UNUSED(no[3]))
+ const float /*no*/[3])
{
MappedUserData *mappedData = (MappedUserData *)userData;
@@ -1914,7 +1916,7 @@ static void make_vertexcos__mapFunc(void *userData,
void mesh_get_mapped_verts_coords(Mesh *me_eval, float (*r_cos)[3], const int totcos)
{
- if (me_eval->runtime.deformed_only == false) {
+ if (me_eval->runtime->deformed_only == false) {
MappedUserData userData;
memset(r_cos, 0, sizeof(*r_cos) * totcos);
userData.vertexcos = r_cos;
diff --git a/source/blender/blenkernel/intern/bvhutils.cc b/source/blender/blenkernel/intern/bvhutils.cc
index 58b377eecdb..afc3e525143 100644
--- a/source/blender/blenkernel/intern/bvhutils.cc
+++ b/source/blender/blenkernel/intern/bvhutils.cc
@@ -51,13 +51,13 @@ struct BVHCache {
* When the `r_locked` is filled and the tree could not be found the caches mutex will be
* locked. This mutex can be unlocked by calling `bvhcache_unlock`.
*
- * When `r_locked` is used the `mesh_eval_mutex` must contain the `Mesh_Runtime.eval_mutex`.
+ * When `r_locked` is used the `mesh_eval_mutex` must contain the `MeshRuntime.eval_mutex`.
*/
static bool bvhcache_find(BVHCache **bvh_cache_p,
BVHCacheType type,
BVHTree **r_tree,
bool *r_locked,
- ThreadMutex *mesh_eval_mutex)
+ std::mutex *mesh_eval_mutex)
{
bool do_lock = r_locked;
if (r_locked) {
@@ -69,11 +69,10 @@ static bool bvhcache_find(BVHCache **bvh_cache_p,
return false;
}
/* Lazy initialization of the bvh_cache using the `mesh_eval_mutex`. */
- BLI_mutex_lock(mesh_eval_mutex);
+ std::lock_guard lock{*mesh_eval_mutex};
if (*bvh_cache_p == nullptr) {
*bvh_cache_p = bvhcache_init();
}
- BLI_mutex_unlock(mesh_eval_mutex);
}
BVHCache *bvh_cache = *bvh_cache_p;
@@ -1222,8 +1221,7 @@ BVHTree *BKE_bvhtree_from_mesh_get(struct BVHTreeFromMesh *data,
const BVHCacheType bvh_cache_type,
const int tree_type)
{
- BVHCache **bvh_cache_p = (BVHCache **)&mesh->runtime.bvh_cache;
- ThreadMutex *mesh_eval_mutex = (ThreadMutex *)mesh->runtime.eval_mutex;
+ BVHCache **bvh_cache_p = (BVHCache **)&mesh->runtime->bvh_cache;
const MLoopTri *looptri = nullptr;
int looptri_len = 0;
@@ -1248,7 +1246,7 @@ BVHTree *BKE_bvhtree_from_mesh_get(struct BVHTreeFromMesh *data,
bool lock_started = false;
data->cached = bvhcache_find(
- bvh_cache_p, bvh_cache_type, &data->tree, &lock_started, mesh_eval_mutex);
+ bvh_cache_p, bvh_cache_type, &data->tree, &lock_started, &mesh->runtime->eval_mutex);
if (data->cached) {
BLI_assert(lock_started == false);
@@ -1352,7 +1350,7 @@ BVHTree *BKE_bvhtree_from_editmesh_get(BVHTreeFromEditMesh *data,
const int tree_type,
const BVHCacheType bvh_cache_type,
BVHCache **bvh_cache_p,
- ThreadMutex *mesh_eval_mutex)
+ std::mutex *mesh_eval_mutex)
{
bool lock_started = false;
diff --git a/source/blender/blenkernel/intern/cloth.c b/source/blender/blenkernel/intern/cloth.c
index 56de583e2db..89983eb8f62 100644
--- a/source/blender/blenkernel/intern/cloth.c
+++ b/source/blender/blenkernel/intern/cloth.c
@@ -826,7 +826,7 @@ static void cloth_from_mesh(ClothModifierData *clmd, const Object *ob, Mesh *mes
const MLoop *mloop = BKE_mesh_loops(mesh);
const MLoopTri *looptri = BKE_mesh_runtime_looptri_ensure(mesh);
const uint mvert_num = mesh->totvert;
- const uint looptri_num = mesh->runtime.looptris.len;
+ const uint looptri_num = BKE_mesh_runtime_looptri_len(mesh);
/* Allocate our vertices. */
clmd->clothObject->mvert_num = mvert_num;
@@ -1167,7 +1167,7 @@ static Mesh *cloth_make_rest_mesh(ClothModifierData *clmd, Mesh *mesh)
MVert *mvert = BKE_mesh_verts_for_write(mesh);
/* vertex count is already ensured to match */
- for (unsigned i = 0; i < mesh->totvert; i++, verts++) {
+ for (uint i = 0; i < mesh->totvert; i++, verts++) {
copy_v3_v3(mvert[i].co, verts->xrest);
}
BKE_mesh_tag_coords_changed(new_mesh);
diff --git a/source/blender/blenkernel/intern/customdata.cc b/source/blender/blenkernel/intern/customdata.cc
index be99a8ee87b..6f2390fc28f 100644
--- a/source/blender/blenkernel/intern/customdata.cc
+++ b/source/blender/blenkernel/intern/customdata.cc
@@ -2382,16 +2382,21 @@ static bool attribute_stored_in_bmesh_flag(const StringRef name)
"material_index");
}
-static CustomData shallow_copy_remove_non_bmesh_attributes(const CustomData &src)
+CustomData CustomData_shallow_copy_remove_non_bmesh_attributes(const CustomData *src,
+ const eCustomDataMask mask)
{
Vector<CustomDataLayer> dst_layers;
- for (const CustomDataLayer &layer : Span<CustomDataLayer>{src.layers, src.totlayer}) {
- if (!attribute_stored_in_bmesh_flag(layer.name)) {
- dst_layers.append(layer);
+ for (const CustomDataLayer &layer : Span<CustomDataLayer>{src->layers, src->totlayer}) {
+ if (attribute_stored_in_bmesh_flag(layer.name)) {
+ continue;
+ }
+ if (!(mask & CD_TYPE_AS_MASK(layer.type))) {
+ continue;
}
+ dst_layers.append(layer);
}
- CustomData dst = src;
+ CustomData dst = *src;
dst.layers = static_cast<CustomDataLayer *>(
MEM_calloc_arrayN(dst_layers.size(), sizeof(CustomDataLayer), __func__));
dst.totlayer = dst_layers.size();
@@ -2402,18 +2407,6 @@ static CustomData shallow_copy_remove_non_bmesh_attributes(const CustomData &src
return dst;
}
-bool CustomData_merge_mesh_to_bmesh(const CustomData *source,
- CustomData *dest,
- const eCustomDataMask mask,
- const eCDAllocType alloctype,
- const int totelem)
-{
- CustomData source_copy = shallow_copy_remove_non_bmesh_attributes(*source);
- const bool result = CustomData_merge(&source_copy, dest, mask, alloctype, totelem);
- MEM_SAFE_FREE(source_copy.layers);
- return result;
-}
-
void CustomData_realloc(CustomData *data, const int old_size, const int new_size)
{
BLI_assert(new_size >= 0);
@@ -2463,17 +2456,6 @@ void CustomData_copy(const CustomData *source,
CustomData_merge(source, dest, mask, alloctype, totelem);
}
-void CustomData_copy_mesh_to_bmesh(const CustomData *source,
- CustomData *dest,
- const eCustomDataMask mask,
- const eCDAllocType alloctype,
- const int totelem)
-{
- CustomData source_copy = shallow_copy_remove_non_bmesh_attributes(*source);
- CustomData_copy(&source_copy, dest, mask, alloctype, totelem);
- MEM_SAFE_FREE(source_copy.layers);
-}
-
static void customData_free_layer__internal(CustomDataLayer *layer, const int totelem)
{
const LayerTypeInfo *typeInfo;
@@ -3697,7 +3679,7 @@ bool CustomData_bmesh_merge(const CustomData *source,
destold.layers = static_cast<CustomDataLayer *>(MEM_dupallocN(destold.layers));
}
- if (CustomData_merge_mesh_to_bmesh(source, dest, mask, alloctype, 0) == false) {
+ if (CustomData_merge(source, dest, mask, alloctype, 0) == false) {
if (destold.layers) {
MEM_freeN(destold.layers);
}
diff --git a/source/blender/blenkernel/intern/editmesh.cc b/source/blender/blenkernel/intern/editmesh.cc
index 3a1dcd59f55..b586b4110f2 100644
--- a/source/blender/blenkernel/intern/editmesh.cc
+++ b/source/blender/blenkernel/intern/editmesh.cc
@@ -189,7 +189,7 @@ struct CageUserData {
static void cage_mapped_verts_callback(void *userData,
int index,
const float co[3],
- const float UNUSED(no[3]))
+ const float /*no*/[3])
{
CageUserData *data = static_cast<CageUserData *>(userData);
@@ -240,12 +240,12 @@ const float (*BKE_editmesh_vert_coords_when_deformed(Depsgraph *depsgraph,
Object *object_eval = DEG_get_evaluated_object(depsgraph, ob);
Mesh *editmesh_eval_final = BKE_object_get_editmesh_eval_final(object_eval);
- if ((me->runtime.edit_data != nullptr) && (me->runtime.edit_data->vertexCos != nullptr)) {
+ if ((me->runtime->edit_data != nullptr) && (me->runtime->edit_data->vertexCos != nullptr)) {
/* Deformed, and we have deformed coords already. */
- coords = me->runtime.edit_data->vertexCos;
+ coords = me->runtime->edit_data->vertexCos;
}
else if ((editmesh_eval_final != nullptr) &&
- (editmesh_eval_final->runtime.wrapper_type == ME_WRAPPER_TYPE_BMESH)) {
+ (editmesh_eval_final->runtime->wrapper_type == ME_WRAPPER_TYPE_BMESH)) {
/* If this is an edit-mesh type, leave nullptr as we can use the vertex coords. */
}
else {
diff --git a/source/blender/blenkernel/intern/geometry_component_mesh.cc b/source/blender/blenkernel/intern/geometry_component_mesh.cc
index 228c27cedf7..d148d59a48b 100644
--- a/source/blender/blenkernel/intern/geometry_component_mesh.cc
+++ b/source/blender/blenkernel/intern/geometry_component_mesh.cc
@@ -13,6 +13,7 @@
#include "BKE_geometry_set.hh"
#include "BKE_lib_id.h"
#include "BKE_mesh.h"
+#include "BKE_mesh_mapping.h"
#include "FN_multi_function_builder.hh"
@@ -213,11 +214,15 @@ void adapt_mesh_domain_corner_to_point_impl(const Mesh &mesh,
}
/* Deselect loose vertices without corners that are still selected from the 'true' default. */
- for (const int vert_index : IndexRange(mesh.totvert)) {
- if (loose_verts[vert_index]) {
- r_values[vert_index] = false;
+ /* The record fact says that the value is true.
+ *Writing to the array from different threads is okay because each thread sets the same value. */
+ threading::parallel_for(loose_verts.index_range(), 2048, [&](const IndexRange range) {
+ for (const int vert_index : range) {
+ if (loose_verts[vert_index]) {
+ r_values[vert_index] = false;
+ }
}
- }
+ });
}
static GVArray adapt_mesh_domain_corner_to_point(const Mesh &mesh, const GVArray &varray)
@@ -413,16 +418,16 @@ void adapt_mesh_domain_face_to_point_impl(const Mesh &mesh,
const Span<MLoop> loops = mesh.loops();
r_values.fill(false);
- for (const int poly_index : polys.index_range()) {
- const MPoly &poly = polys[poly_index];
- if (old_values[poly_index]) {
- for (const int loop_index : IndexRange(poly.loopstart, poly.totloop)) {
- const MLoop &loop = loops[loop_index];
- const int vert_index = loop.v;
- r_values[vert_index] = true;
+ threading::parallel_for(polys.index_range(), 2048, [&](const IndexRange range) {
+ for (const int poly_index : range) {
+ if (old_values[poly_index]) {
+ const MPoly &poly = polys[poly_index];
+ for (const MLoop &loop : loops.slice(poly.loopstart, poly.totloop)) {
+ r_values[loop.v] = true;
+ }
}
}
- }
+ });
}
static GVArray adapt_mesh_domain_face_to_point(const Mesh &mesh, const GVArray &varray)
@@ -502,16 +507,16 @@ void adapt_mesh_domain_face_to_edge_impl(const Mesh &mesh,
const Span<MLoop> loops = mesh.loops();
r_values.fill(false);
- for (const int poly_index : polys.index_range()) {
- const MPoly &poly = polys[poly_index];
- if (old_values[poly_index]) {
- for (const int loop_index : IndexRange(poly.loopstart, poly.totloop)) {
- const MLoop &loop = loops[loop_index];
- const int edge_index = loop.e;
- r_values[edge_index] = true;
+ threading::parallel_for(polys.index_range(), 2048, [&](const IndexRange range) {
+ for (const int poly_index : range) {
+ if (old_values[poly_index]) {
+ const MPoly &poly = polys[poly_index];
+ for (const MLoop &loop : loops.slice(poly.loopstart, poly.totloop)) {
+ r_values[loop.e] = true;
+ }
}
}
- }
+ });
}
static GVArray adapt_mesh_domain_face_to_edge(const Mesh &mesh, const GVArray &varray)
@@ -619,7 +624,7 @@ void adapt_mesh_domain_edge_to_corner_impl(const Mesh &mesh,
/* For every corner, mix the values from the adjacent edges on the face. */
for (const int loop_index : IndexRange(poly.loopstart, poly.totloop)) {
- const int loop_index_prev = loop_index - 1 + (loop_index == poly.loopstart) * poly.totloop;
+ const int loop_index_prev = mesh_topology::previous_poly_loop(poly, loop_index);
const MLoop &loop = loops[loop_index];
const MLoop &loop_prev = loops[loop_index_prev];
mixer.mix_in(loop_index, old_values[loop.e]);
@@ -642,17 +647,19 @@ void adapt_mesh_domain_edge_to_corner_impl(const Mesh &mesh,
r_values.fill(false);
- for (const int poly_index : polys.index_range()) {
- const MPoly &poly = polys[poly_index];
- for (const int loop_index : IndexRange(poly.loopstart, poly.totloop)) {
- const int loop_index_prev = loop_index - 1 + (loop_index == poly.loopstart) * poly.totloop;
- const MLoop &loop = loops[loop_index];
- const MLoop &loop_prev = loops[loop_index_prev];
- if (old_values[loop.e] && old_values[loop_prev.e]) {
- r_values[loop_index] = true;
+ threading::parallel_for(polys.index_range(), 2048, [&](const IndexRange range) {
+ for (const int poly_index : range) {
+ const MPoly &poly = polys[poly_index];
+ for (const int loop_index : IndexRange(poly.loopstart, poly.totloop)) {
+ const int loop_index_prev = mesh_topology::previous_poly_loop(poly, loop_index);
+ const MLoop &loop = loops[loop_index];
+ const MLoop &loop_prev = loops[loop_index_prev];
+ if (old_values[loop.e] && old_values[loop_prev.e]) {
+ r_values[loop_index] = true;
+ }
}
}
- }
+ });
}
static GVArray adapt_mesh_domain_edge_to_corner(const Mesh &mesh, const GVArray &varray)
@@ -697,14 +704,18 @@ void adapt_mesh_domain_edge_to_point_impl(const Mesh &mesh,
BLI_assert(r_values.size() == mesh.totvert);
const Span<MEdge> edges = mesh.edges();
+ /* Multiple threads can write to the same index here, but they are only
+ * writing true, and writing to single bytes is expected to be threadsafe. */
r_values.fill(false);
- for (const int edge_index : edges.index_range()) {
- const MEdge &edge = edges[edge_index];
- if (old_values[edge_index]) {
- r_values[edge.v1] = true;
- r_values[edge.v2] = true;
+ threading::parallel_for(edges.index_range(), 4096, [&](const IndexRange range) {
+ for (const int edge_index : range) {
+ if (old_values[edge_index]) {
+ const MEdge &edge = edges[edge_index];
+ r_values[edge.v1] = true;
+ r_values[edge.v2] = true;
+ }
}
- }
+ });
}
static GVArray adapt_mesh_domain_edge_to_point(const Mesh &mesh, const GVArray &varray)
diff --git a/source/blender/blenkernel/intern/gpencil_geom.cc b/source/blender/blenkernel/intern/gpencil_geom.cc
index 92b11ecaa61..52fcdef8a43 100644
--- a/source/blender/blenkernel/intern/gpencil_geom.cc
+++ b/source/blender/blenkernel/intern/gpencil_geom.cc
@@ -1856,6 +1856,10 @@ bool BKE_gpencil_stroke_close(bGPDstroke *gps)
pt->strength = interpf(pt2->strength, pt1->strength, step);
pt->flag = 0;
interp_v4_v4v4(pt->vert_color, pt1->vert_color, pt2->vert_color, step);
+ /* Set point as selected. */
+ if (gps->flag & GP_STROKE_SELECT) {
+ pt->flag |= GP_SPOINT_SELECT;
+ }
/* Set weights. */
if (gps->dvert != nullptr) {
diff --git a/source/blender/blenkernel/intern/mball_tessellate.cc b/source/blender/blenkernel/intern/mball_tessellate.cc
index 5e8d2bc6d76..bb3713e770a 100644
--- a/source/blender/blenkernel/intern/mball_tessellate.cc
+++ b/source/blender/blenkernel/intern/mball_tessellate.cc
@@ -1498,7 +1498,7 @@ Mesh *BKE_mball_polygonize(Depsgraph *depsgraph, Scene *scene, Object *ob)
for (int i = 0; i < mesh->totvert; i++) {
normalize_v3(process.no[i]);
}
- mesh->runtime.vert_normals = process.no;
+ mesh->runtime->vert_normals = process.no;
BKE_mesh_vertex_normals_clear_dirty(mesh);
mesh->totloop = loop_offset;
diff --git a/source/blender/blenkernel/intern/mesh.cc b/source/blender/blenkernel/intern/mesh.cc
index 9e7821428d1..0018c217964 100644
--- a/source/blender/blenkernel/intern/mesh.cc
+++ b/source/blender/blenkernel/intern/mesh.cc
@@ -89,7 +89,7 @@ static void mesh_init_data(ID *id)
CustomData_reset(&mesh->pdata);
CustomData_reset(&mesh->ldata);
- BKE_mesh_runtime_init_data(mesh);
+ mesh->runtime = new blender::bke::MeshRuntime();
/* A newly created mesh does not have normals, so tag them dirty. This will be cleared
* by #BKE_mesh_vertex_normals_clear_dirty or #BKE_mesh_poly_normals_ensure. */
@@ -103,14 +103,19 @@ static void mesh_copy_data(Main *bmain, ID *id_dst, const ID *id_src, const int
Mesh *mesh_dst = (Mesh *)id_dst;
const Mesh *mesh_src = (const Mesh *)id_src;
- BKE_mesh_runtime_reset_on_copy(mesh_dst, flag);
+ mesh_dst->runtime = new blender::bke::MeshRuntime();
+ mesh_dst->runtime->deformed_only = mesh_src->runtime->deformed_only;
+ mesh_dst->runtime->wrapper_type = mesh_src->runtime->wrapper_type;
+ mesh_dst->runtime->wrapper_type_finalize = mesh_src->runtime->wrapper_type_finalize;
+ mesh_dst->runtime->subsurf_runtime_data = mesh_src->runtime->subsurf_runtime_data;
+ mesh_dst->runtime->cd_mask_extra = mesh_src->runtime->cd_mask_extra;
/* Copy face dot tags, since meshes may be duplicated after a subsurf modifier
* or node, but we still need to be able to draw face center vertices. */
- mesh_dst->runtime.subsurf_face_dot_tags = static_cast<uint32_t *>(
- MEM_dupallocN(mesh_src->runtime.subsurf_face_dot_tags));
+ mesh_dst->runtime->subsurf_face_dot_tags = static_cast<uint32_t *>(
+ MEM_dupallocN(mesh_src->runtime->subsurf_face_dot_tags));
if ((mesh_src->id.tag & LIB_TAG_NO_MAIN) == 0) {
/* This is a direct copy of a main mesh, so for now it has the same topology. */
- mesh_dst->runtime.deformed_only = true;
+ mesh_dst->runtime->deformed_only = true;
}
/* This option is set for run-time meshes that have been copied from the current objects mode.
* Currently this is used for edit-mesh although it could be used for sculpt or other
@@ -121,7 +126,7 @@ static void mesh_copy_data(Main *bmain, ID *id_dst, const ID *id_src, const int
*
* While this could be the callers responsibility, keep here since it's
* highly unlikely we want to create a duplicate and not use it for drawing. */
- mesh_dst->runtime.is_original_bmesh = false;
+ mesh_dst->runtime->is_original_bmesh = false;
/* Only do tessface if we have no polys. */
const bool do_tessface = ((mesh_src->totface != 0) && (mesh_src->totpoly == 0));
@@ -194,6 +199,8 @@ static void mesh_free_data(ID *id)
BKE_mesh_runtime_free_data(mesh);
mesh_clear_geometry(mesh);
MEM_SAFE_FREE(mesh->mat);
+
+ delete mesh->runtime;
}
static void mesh_foreach_id(ID *id, LibraryForeachIDData *data)
@@ -229,7 +236,7 @@ static void mesh_blend_write(BlendWriter *writer, ID *id, const void *id_address
mesh->mface = nullptr;
mesh->totface = 0;
memset(&mesh->fdata, 0, sizeof(mesh->fdata));
- mesh->runtime = blender::dna::shallow_zero_initialize();
+ mesh->runtime = nullptr;
/* Do not store actual geometry data in case this is a library override ID. */
if (ID_IS_OVERRIDE_LIBRARY(mesh) && !is_undo) {
@@ -339,8 +346,7 @@ static void mesh_blend_read_data(BlendDataReader *reader, ID *id)
mesh->texflag &= ~ME_AUTOSPACE_EVALUATED;
mesh->edit_mesh = nullptr;
- mesh->runtime = blender::dna::shallow_zero_initialize();
- BKE_mesh_runtime_init_data(mesh);
+ mesh->runtime = new blender::bke::MeshRuntime();
/* happens with old files */
if (mesh->mselect == nullptr) {
@@ -1137,7 +1143,7 @@ static void ensure_orig_index_layer(CustomData &data, const int size)
void BKE_mesh_ensure_default_orig_index_customdata(Mesh *mesh)
{
- BLI_assert(mesh->runtime.wrapper_type == ME_WRAPPER_TYPE_MDATA);
+ BLI_assert(mesh->runtime->wrapper_type == ME_WRAPPER_TYPE_MDATA);
BKE_mesh_ensure_default_orig_index_customdata_no_check(mesh);
}
@@ -2106,8 +2112,8 @@ void BKE_mesh_split_faces(Mesh *mesh, bool free_loop_normals)
}
/* Update normals manually to avoid recalculation after this operation. */
- mesh->runtime.vert_normals = (float(*)[3])MEM_reallocN(mesh->runtime.vert_normals,
- sizeof(float[3]) * mesh->totvert);
+ mesh->runtime->vert_normals = (float(*)[3])MEM_reallocN(mesh->runtime->vert_normals,
+ sizeof(float[3]) * mesh->totvert);
/* Perform actual split of vertices and edges. */
split_faces_split_new_verts(mesh, new_verts, num_new_verts);
@@ -2141,10 +2147,10 @@ void BKE_mesh_eval_geometry(Depsgraph *depsgraph, Mesh *mesh)
/* We are here because something did change in the mesh. This means we can not trust the existing
* evaluated mesh, and we don't know what parts of the mesh did change. So we simply delete the
* evaluated mesh and let objects to re-create it with updated settings. */
- if (mesh->runtime.mesh_eval != nullptr) {
- mesh->runtime.mesh_eval->edit_mesh = nullptr;
- BKE_id_free(nullptr, mesh->runtime.mesh_eval);
- mesh->runtime.mesh_eval = nullptr;
+ if (mesh->runtime->mesh_eval != nullptr) {
+ mesh->runtime->mesh_eval->edit_mesh = nullptr;
+ BKE_id_free(nullptr, mesh->runtime->mesh_eval);
+ mesh->runtime->mesh_eval = nullptr;
}
if (DEG_is_active(depsgraph)) {
Mesh *mesh_orig = (Mesh *)DEG_get_original_id(&mesh->id);
diff --git a/source/blender/blenkernel/intern/mesh_convert.cc b/source/blender/blenkernel/intern/mesh_convert.cc
index b4f729ca507..027423f5774 100644
--- a/source/blender/blenkernel/intern/mesh_convert.cc
+++ b/source/blender/blenkernel/intern/mesh_convert.cc
@@ -903,7 +903,7 @@ static Mesh *mesh_new_from_mesh(Object *object, Mesh *mesh)
{
/* While we could copy this into the new mesh,
* add the data to 'mesh' so future calls to this function don't need to re-convert the data. */
- if (mesh->runtime.wrapper_type == ME_WRAPPER_TYPE_BMESH) {
+ if (mesh->runtime->wrapper_type == ME_WRAPPER_TYPE_BMESH) {
BKE_mesh_wrapper_ensure_mdata(mesh);
}
else {
diff --git a/source/blender/blenkernel/intern/mesh_debug.cc b/source/blender/blenkernel/intern/mesh_debug.cc
index ba4f25c74ee..6cf237a7c8c 100644
--- a/source/blender/blenkernel/intern/mesh_debug.cc
+++ b/source/blender/blenkernel/intern/mesh_debug.cc
@@ -41,9 +41,9 @@ char *BKE_mesh_debug_info(const Mesh *me)
BLI_dynstr_appendf(dynstr, " 'totface': %d,\n", me->totface);
BLI_dynstr_appendf(dynstr, " 'totpoly': %d,\n", me->totpoly);
- BLI_dynstr_appendf(dynstr, " 'runtime.deformed_only': %d,\n", me->runtime.deformed_only);
+ BLI_dynstr_appendf(dynstr, " 'runtime.deformed_only': %d,\n", me->runtime->deformed_only);
BLI_dynstr_appendf(
- dynstr, " 'runtime.is_original_bmesh': %d,\n", me->runtime.is_original_bmesh);
+ dynstr, " 'runtime->is_original_bmesh': %d,\n", me->runtime->is_original_bmesh);
BLI_dynstr_append(dynstr, " 'vert_layers': (\n");
CustomData_debug_info_from_layers(&me->vdata, indent8, dynstr);
diff --git a/source/blender/blenkernel/intern/mesh_fair.cc b/source/blender/blenkernel/intern/mesh_fair.cc
index 5369bc782b6..960e6c43103 100644
--- a/source/blender/blenkernel/intern/mesh_fair.cc
+++ b/source/blender/blenkernel/intern/mesh_fair.cc
@@ -221,7 +221,7 @@ class MeshFairingContext : public FairingContext {
}
}
- loop_to_poly_map_ = blender::mesh_topology::build_loop_to_poly_map(mpoly_, mloop_.size());
+ loop_to_poly_map_ = blender::bke::mesh_topology::build_loop_to_poly_map(mpoly_, mloop_.size());
}
~MeshFairingContext() override
diff --git a/source/blender/blenkernel/intern/mesh_iterators.cc b/source/blender/blenkernel/intern/mesh_iterators.cc
index 46f9780f891..a99e9b2348d 100644
--- a/source/blender/blenkernel/intern/mesh_iterators.cc
+++ b/source/blender/blenkernel/intern/mesh_iterators.cc
@@ -36,18 +36,18 @@ void BKE_mesh_foreach_mapped_vert(
void *userData,
MeshForeachFlag flag)
{
- if (mesh->edit_mesh != nullptr && mesh->runtime.edit_data != nullptr) {
+ if (mesh->edit_mesh != nullptr && mesh->runtime->edit_data != nullptr) {
BMEditMesh *em = mesh->edit_mesh;
BMesh *bm = em->bm;
BMIter iter;
BMVert *eve;
int i;
- if (mesh->runtime.edit_data->vertexCos != nullptr) {
- const float(*vertexCos)[3] = mesh->runtime.edit_data->vertexCos;
+ if (mesh->runtime->edit_data->vertexCos != nullptr) {
+ const float(*vertexCos)[3] = mesh->runtime->edit_data->vertexCos;
const float(*vertexNos)[3];
if (flag & MESH_FOREACH_USE_NORMAL) {
- BKE_editmesh_cache_ensure_vert_normals(em, mesh->runtime.edit_data);
- vertexNos = mesh->runtime.edit_data->vertexNos;
+ BKE_editmesh_cache_ensure_vert_normals(em, mesh->runtime->edit_data);
+ vertexNos = mesh->runtime->edit_data->vertexNos;
}
else {
vertexNos = nullptr;
@@ -96,14 +96,14 @@ void BKE_mesh_foreach_mapped_edge(
void (*func)(void *userData, int index, const float v0co[3], const float v1co[3]),
void *userData)
{
- if (mesh->edit_mesh != nullptr && mesh->runtime.edit_data) {
+ if (mesh->edit_mesh != nullptr && mesh->runtime->edit_data) {
BMEditMesh *em = mesh->edit_mesh;
BMesh *bm = em->bm;
BMIter iter;
BMEdge *eed;
int i;
- if (mesh->runtime.edit_data->vertexCos != nullptr) {
- const float(*vertexCos)[3] = mesh->runtime.edit_data->vertexCos;
+ if (mesh->runtime->edit_data->vertexCos != nullptr) {
+ const float(*vertexCos)[3] = mesh->runtime->edit_data->vertexCos;
BM_mesh_elem_index_ensure(bm, BM_VERT);
BM_ITER_MESH_INDEX (eed, &iter, bm, BM_EDGES_OF_MESH, i) {
@@ -154,13 +154,13 @@ void BKE_mesh_foreach_mapped_loop(Mesh *mesh,
/* We can't use `dm->getLoopDataLayout(dm)` here,
* we want to always access `dm->loopData`, `EditDerivedBMesh` would
* return loop data from BMesh itself. */
- if (mesh->edit_mesh != nullptr && mesh->runtime.edit_data) {
+ if (mesh->edit_mesh != nullptr && mesh->runtime->edit_data) {
BMEditMesh *em = mesh->edit_mesh;
BMesh *bm = em->bm;
BMIter iter;
BMFace *efa;
- const float(*vertexCos)[3] = mesh->runtime.edit_data->vertexCos;
+ const float(*vertexCos)[3] = mesh->runtime->edit_data->vertexCos;
/* XXX: investigate using EditMesh data. */
const float(*lnors)[3] = (flag & MESH_FOREACH_USE_NORMAL) ?
@@ -231,7 +231,7 @@ void BKE_mesh_foreach_mapped_face_center(
void *userData,
MeshForeachFlag flag)
{
- if (mesh->edit_mesh != nullptr && mesh->runtime.edit_data != nullptr) {
+ if (mesh->edit_mesh != nullptr && mesh->runtime->edit_data != nullptr) {
BMEditMesh *em = mesh->edit_mesh;
BMesh *bm = em->bm;
const float(*polyCos)[3];
@@ -240,12 +240,12 @@ void BKE_mesh_foreach_mapped_face_center(
BMIter iter;
int i;
- BKE_editmesh_cache_ensure_poly_centers(em, mesh->runtime.edit_data);
- polyCos = mesh->runtime.edit_data->polyCos; /* always set */
+ BKE_editmesh_cache_ensure_poly_centers(em, mesh->runtime->edit_data);
+ polyCos = mesh->runtime->edit_data->polyCos; /* always set */
if (flag & MESH_FOREACH_USE_NORMAL) {
- BKE_editmesh_cache_ensure_poly_normals(em, mesh->runtime.edit_data);
- polyNos = mesh->runtime.edit_data->polyNos; /* maybe nullptr */
+ BKE_editmesh_cache_ensure_poly_normals(em, mesh->runtime->edit_data);
+ polyNos = mesh->runtime->edit_data->polyNos; /* maybe nullptr */
}
else {
polyNos = nullptr;
@@ -317,7 +317,7 @@ void BKE_mesh_foreach_mapped_subdiv_face_center(
BKE_mesh_vertex_normals_ensure(mesh) :
nullptr;
const int *index = static_cast<const int *>(CustomData_get_layer(&mesh->pdata, CD_ORIGINDEX));
- const BLI_bitmap *facedot_tags = mesh->runtime.subsurf_face_dot_tags;
+ const BLI_bitmap *facedot_tags = mesh->runtime->subsurf_face_dot_tags;
BLI_assert(facedot_tags != nullptr);
if (index) {
@@ -364,7 +364,7 @@ struct MappedVCosData {
static void get_vertexcos__mapFunc(void *user_data,
int index,
const float co[3],
- const float UNUSED(no[3]))
+ const float /*no*/[3])
{
MappedVCosData *mapped_vcos_data = (MappedVCosData *)user_data;
diff --git a/source/blender/blenkernel/intern/mesh_mapping.cc b/source/blender/blenkernel/intern/mesh_mapping.cc
index 667802d5f48..ed4ae94da7f 100644
--- a/source/blender/blenkernel/intern/mesh_mapping.cc
+++ b/source/blender/blenkernel/intern/mesh_mapping.cc
@@ -553,7 +553,7 @@ void BKE_mesh_origindex_map_create_looptri(MeshElemMap **r_map,
*r_mem = indices;
}
-namespace blender::mesh_topology {
+namespace blender::bke::mesh_topology {
Array<int> build_loop_to_poly_map(const Span<MPoly> polys, const int loops_num)
{
@@ -586,7 +586,7 @@ Array<Vector<int>> build_vert_to_loop_map(const Span<MLoop> loops, const int ver
return map;
}
-} // namespace blender::mesh_topology
+} // namespace blender::bke::mesh_topology
/** \} */
diff --git a/source/blender/blenkernel/intern/mesh_normals.cc b/source/blender/blenkernel/intern/mesh_normals.cc
index e589aff1c73..ebb5a72d137 100644
--- a/source/blender/blenkernel/intern/mesh_normals.cc
+++ b/source/blender/blenkernel/intern/mesh_normals.cc
@@ -95,72 +95,72 @@ static void add_v3_v3_atomic(float r[3], const float a[3])
void BKE_mesh_normals_tag_dirty(Mesh *mesh)
{
- mesh->runtime.vert_normals_dirty = true;
- mesh->runtime.poly_normals_dirty = true;
+ mesh->runtime->vert_normals_dirty = true;
+ mesh->runtime->poly_normals_dirty = true;
}
float (*BKE_mesh_vertex_normals_for_write(Mesh *mesh))[3]
{
- if (mesh->runtime.vert_normals == nullptr) {
- mesh->runtime.vert_normals = (float(*)[3])MEM_malloc_arrayN(
+ if (mesh->runtime->vert_normals == nullptr) {
+ mesh->runtime->vert_normals = (float(*)[3])MEM_malloc_arrayN(
mesh->totvert, sizeof(float[3]), __func__);
}
- BLI_assert(MEM_allocN_len(mesh->runtime.vert_normals) >= sizeof(float[3]) * mesh->totvert);
+ BLI_assert(MEM_allocN_len(mesh->runtime->vert_normals) >= sizeof(float[3]) * mesh->totvert);
- return mesh->runtime.vert_normals;
+ return mesh->runtime->vert_normals;
}
float (*BKE_mesh_poly_normals_for_write(Mesh *mesh))[3]
{
- if (mesh->runtime.poly_normals == nullptr) {
- mesh->runtime.poly_normals = (float(*)[3])MEM_malloc_arrayN(
+ if (mesh->runtime->poly_normals == nullptr) {
+ mesh->runtime->poly_normals = (float(*)[3])MEM_malloc_arrayN(
mesh->totpoly, sizeof(float[3]), __func__);
}
- BLI_assert(MEM_allocN_len(mesh->runtime.poly_normals) >= sizeof(float[3]) * mesh->totpoly);
+ BLI_assert(MEM_allocN_len(mesh->runtime->poly_normals) >= sizeof(float[3]) * mesh->totpoly);
- return mesh->runtime.poly_normals;
+ return mesh->runtime->poly_normals;
}
void BKE_mesh_vertex_normals_clear_dirty(Mesh *mesh)
{
- mesh->runtime.vert_normals_dirty = false;
+ mesh->runtime->vert_normals_dirty = false;
BKE_mesh_assert_normals_dirty_or_calculated(mesh);
}
void BKE_mesh_poly_normals_clear_dirty(Mesh *mesh)
{
- mesh->runtime.poly_normals_dirty = false;
+ mesh->runtime->poly_normals_dirty = false;
BKE_mesh_assert_normals_dirty_or_calculated(mesh);
}
bool BKE_mesh_vertex_normals_are_dirty(const Mesh *mesh)
{
- return mesh->runtime.vert_normals_dirty;
+ return mesh->runtime->vert_normals_dirty;
}
bool BKE_mesh_poly_normals_are_dirty(const Mesh *mesh)
{
- return mesh->runtime.poly_normals_dirty;
+ return mesh->runtime->poly_normals_dirty;
}
void BKE_mesh_clear_derived_normals(Mesh *mesh)
{
- MEM_SAFE_FREE(mesh->runtime.vert_normals);
- MEM_SAFE_FREE(mesh->runtime.poly_normals);
+ MEM_SAFE_FREE(mesh->runtime->vert_normals);
+ MEM_SAFE_FREE(mesh->runtime->poly_normals);
- mesh->runtime.vert_normals_dirty = true;
- mesh->runtime.poly_normals_dirty = true;
+ mesh->runtime->vert_normals_dirty = true;
+ mesh->runtime->poly_normals_dirty = true;
}
void BKE_mesh_assert_normals_dirty_or_calculated(const Mesh *mesh)
{
- if (!mesh->runtime.vert_normals_dirty) {
- BLI_assert(mesh->runtime.vert_normals || mesh->totvert == 0);
+ if (!mesh->runtime->vert_normals_dirty) {
+ BLI_assert(mesh->runtime->vert_normals || mesh->totvert == 0);
}
- if (!mesh->runtime.poly_normals_dirty) {
- BLI_assert(mesh->runtime.poly_normals || mesh->totpoly == 0);
+ if (!mesh->runtime->poly_normals_dirty) {
+ BLI_assert(mesh->runtime->poly_normals || mesh->totpoly == 0);
}
}
@@ -348,20 +348,18 @@ void BKE_mesh_calc_normals_poly_and_vertex(const MVert *mvert,
const float (*BKE_mesh_vertex_normals_ensure(const Mesh *mesh))[3]
{
if (!BKE_mesh_vertex_normals_are_dirty(mesh)) {
- BLI_assert(mesh->runtime.vert_normals != nullptr || mesh->totvert == 0);
- return mesh->runtime.vert_normals;
+ BLI_assert(mesh->runtime->vert_normals != nullptr || mesh->totvert == 0);
+ return mesh->runtime->vert_normals;
}
if (mesh->totvert == 0) {
return nullptr;
}
- ThreadMutex *normals_mutex = (ThreadMutex *)mesh->runtime.normals_mutex;
- BLI_mutex_lock(normals_mutex);
+ std::lock_guard lock{mesh->runtime->normals_mutex};
if (!BKE_mesh_vertex_normals_are_dirty(mesh)) {
- BLI_assert(mesh->runtime.vert_normals != nullptr);
- BLI_mutex_unlock(normals_mutex);
- return mesh->runtime.vert_normals;
+ BLI_assert(mesh->runtime->vert_normals != nullptr);
+ return mesh->runtime->vert_normals;
}
float(*vert_normals)[3];
@@ -390,27 +388,24 @@ const float (*BKE_mesh_vertex_normals_ensure(const Mesh *mesh))[3]
BKE_mesh_poly_normals_clear_dirty(&mesh_mutable);
});
- BLI_mutex_unlock(normals_mutex);
return vert_normals;
}
const float (*BKE_mesh_poly_normals_ensure(const Mesh *mesh))[3]
{
if (!BKE_mesh_poly_normals_are_dirty(mesh)) {
- BLI_assert(mesh->runtime.poly_normals != nullptr || mesh->totpoly == 0);
- return mesh->runtime.poly_normals;
+ BLI_assert(mesh->runtime->poly_normals != nullptr || mesh->totpoly == 0);
+ return mesh->runtime->poly_normals;
}
if (mesh->totpoly == 0) {
return nullptr;
}
- ThreadMutex *normals_mutex = (ThreadMutex *)mesh->runtime.normals_mutex;
- BLI_mutex_lock(normals_mutex);
+ std::lock_guard lock{mesh->runtime->normals_mutex};
if (!BKE_mesh_poly_normals_are_dirty(mesh)) {
- BLI_assert(mesh->runtime.poly_normals != nullptr);
- BLI_mutex_unlock(normals_mutex);
- return mesh->runtime.poly_normals;
+ BLI_assert(mesh->runtime->poly_normals != nullptr);
+ return mesh->runtime->poly_normals;
}
float(*poly_normals)[3];
@@ -435,13 +430,12 @@ const float (*BKE_mesh_poly_normals_ensure(const Mesh *mesh))[3]
BKE_mesh_poly_normals_clear_dirty(&mesh_mutable);
});
- BLI_mutex_unlock(normals_mutex);
return poly_normals;
}
void BKE_mesh_ensure_normals_for_display(Mesh *mesh)
{
- switch ((eMeshWrapperType)mesh->runtime.wrapper_type) {
+ switch (mesh->runtime->wrapper_type) {
case ME_WRAPPER_TYPE_SUBD:
case ME_WRAPPER_TYPE_MDATA:
BKE_mesh_vertex_normals_ensure(mesh);
@@ -449,7 +443,7 @@ void BKE_mesh_ensure_normals_for_display(Mesh *mesh)
break;
case ME_WRAPPER_TYPE_BMESH: {
struct BMEditMesh *em = mesh->edit_mesh;
- EditMeshData *emd = mesh->runtime.edit_data;
+ EditMeshData *emd = mesh->runtime->edit_data;
if (emd->vertexCos) {
BKE_editmesh_cache_ensure_vert_normals(em, emd);
BKE_editmesh_cache_ensure_poly_normals(em, emd);
@@ -470,7 +464,7 @@ void BKE_mesh_calc_normals(Mesh *mesh)
#endif
}
-void BKE_mesh_calc_normals_looptri(MVert *mverts,
+void BKE_mesh_calc_normals_looptri(const MVert *mverts,
int numVerts,
const MLoop *mloop,
const MLoopTri *looptri,
@@ -508,7 +502,7 @@ void BKE_mesh_calc_normals_looptri(MVert *mverts,
/* Following Mesh convention; we use vertex coordinate itself for normal in this case. */
for (int i = 0; i < numVerts; i++) {
- MVert *mv = &mverts[i];
+ const MVert *mv = &mverts[i];
float *no = tnorms[i];
if (UNLIKELY(normalize_v3(no) == 0.0f)) {
diff --git a/source/blender/blenkernel/intern/mesh_remap.c b/source/blender/blenkernel/intern/mesh_remap.c
index cb05d33bc2e..90798ea593d 100644
--- a/source/blender/blenkernel/intern/mesh_remap.c
+++ b/source/blender/blenkernel/intern/mesh_remap.c
@@ -1529,7 +1529,7 @@ void BKE_mesh_remap_calc_loops_from_mesh(const int mode,
BLI_bitmap *looptri_active;
looptri_src = BKE_mesh_runtime_looptri_ensure(me_src);
- num_looptri_src = me_src->runtime.looptris.len;
+ num_looptri_src = BKE_mesh_runtime_looptri_len(me_src);
looptri_active = BLI_BITMAP_NEW((size_t)num_looptri_src, __func__);
for (tindex = 0; tindex < num_trees; tindex++) {
diff --git a/source/blender/blenkernel/intern/mesh_runtime.cc b/source/blender/blenkernel/intern/mesh_runtime.cc
index bd9f8242274..e90a298ad8d 100644
--- a/source/blender/blenkernel/intern/mesh_runtime.cc
+++ b/source/blender/blenkernel/intern/mesh_runtime.cc
@@ -17,6 +17,7 @@
#include "BLI_task.hh"
#include "BKE_bvhutils.h"
+#include "BKE_editmesh_cache.h"
#include "BKE_lib_id.h"
#include "BKE_mesh.h"
#include "BKE_mesh_runtime.h"
@@ -30,81 +31,17 @@ using blender::Span;
/** \name Mesh Runtime Struct Utils
* \{ */
-/**
- * \brief Initialize the runtime mutexes of the given mesh.
- *
- * Any existing mutexes will be overridden.
- */
-static void mesh_runtime_init_mutexes(Mesh *mesh)
-{
- mesh->runtime.eval_mutex = MEM_new<ThreadMutex>("mesh runtime eval_mutex");
- BLI_mutex_init(static_cast<ThreadMutex *>(mesh->runtime.eval_mutex));
- mesh->runtime.normals_mutex = MEM_new<ThreadMutex>("mesh runtime normals_mutex");
- BLI_mutex_init(static_cast<ThreadMutex *>(mesh->runtime.normals_mutex));
- mesh->runtime.render_mutex = MEM_new<ThreadMutex>("mesh runtime render_mutex");
- BLI_mutex_init(static_cast<ThreadMutex *>(mesh->runtime.render_mutex));
-}
-
-/**
- * \brief free the mutexes of the given mesh runtime.
- */
-static void mesh_runtime_free_mutexes(Mesh *mesh)
-{
- if (mesh->runtime.eval_mutex != nullptr) {
- BLI_mutex_end(static_cast<ThreadMutex *>(mesh->runtime.eval_mutex));
- MEM_freeN(mesh->runtime.eval_mutex);
- mesh->runtime.eval_mutex = nullptr;
- }
- if (mesh->runtime.normals_mutex != nullptr) {
- BLI_mutex_end(static_cast<ThreadMutex *>(mesh->runtime.normals_mutex));
- MEM_freeN(mesh->runtime.normals_mutex);
- mesh->runtime.normals_mutex = nullptr;
- }
- if (mesh->runtime.render_mutex != nullptr) {
- BLI_mutex_end(static_cast<ThreadMutex *>(mesh->runtime.render_mutex));
- MEM_freeN(mesh->runtime.render_mutex);
- mesh->runtime.render_mutex = nullptr;
- }
-}
-
-void BKE_mesh_runtime_init_data(Mesh *mesh)
-{
- mesh_runtime_init_mutexes(mesh);
-}
-
void BKE_mesh_runtime_free_data(Mesh *mesh)
{
BKE_mesh_runtime_clear_cache(mesh);
- mesh_runtime_free_mutexes(mesh);
-}
-
-void BKE_mesh_runtime_reset_on_copy(Mesh *mesh, const int /*flag*/)
-{
- Mesh_Runtime *runtime = &mesh->runtime;
-
- runtime->mesh_eval = nullptr;
- runtime->edit_data = nullptr;
- runtime->batch_cache = nullptr;
- runtime->subdiv_ccg = nullptr;
- runtime->looptris = blender::dna::shallow_zero_initialize();
- runtime->bvh_cache = nullptr;
- runtime->shrinkwrap_data = nullptr;
- runtime->subsurf_face_dot_tags = nullptr;
-
- runtime->vert_normals_dirty = true;
- runtime->poly_normals_dirty = true;
- runtime->vert_normals = nullptr;
- runtime->poly_normals = nullptr;
-
- mesh_runtime_init_mutexes(mesh);
}
void BKE_mesh_runtime_clear_cache(Mesh *mesh)
{
- if (mesh->runtime.mesh_eval != nullptr) {
- mesh->runtime.mesh_eval->edit_mesh = nullptr;
- BKE_id_free(nullptr, mesh->runtime.mesh_eval);
- mesh->runtime.mesh_eval = nullptr;
+ if (mesh->runtime->mesh_eval != nullptr) {
+ mesh->runtime->mesh_eval->edit_mesh = nullptr;
+ BKE_id_free(nullptr, mesh->runtime->mesh_eval);
+ mesh->runtime->mesh_eval = nullptr;
}
BKE_mesh_runtime_clear_geometry(mesh);
BKE_mesh_batch_cache_free(mesh);
@@ -131,32 +68,32 @@ static void mesh_ensure_looptri_data(Mesh *mesh)
const uint totpoly = mesh->totpoly;
const int looptris_len = poly_to_tri_count(totpoly, mesh->totloop);
- BLI_assert(mesh->runtime.looptris.array_wip == nullptr);
+ BLI_assert(mesh->runtime->looptris.array_wip == nullptr);
- SWAP(MLoopTri *, mesh->runtime.looptris.array, mesh->runtime.looptris.array_wip);
+ SWAP(MLoopTri *, mesh->runtime->looptris.array, mesh->runtime->looptris.array_wip);
- if ((looptris_len > mesh->runtime.looptris.len_alloc) ||
- (looptris_len < mesh->runtime.looptris.len_alloc * 2) || (totpoly == 0)) {
- MEM_SAFE_FREE(mesh->runtime.looptris.array_wip);
- mesh->runtime.looptris.len_alloc = 0;
- mesh->runtime.looptris.len = 0;
+ if ((looptris_len > mesh->runtime->looptris.len_alloc) ||
+ (looptris_len < mesh->runtime->looptris.len_alloc * 2) || (totpoly == 0)) {
+ MEM_SAFE_FREE(mesh->runtime->looptris.array_wip);
+ mesh->runtime->looptris.len_alloc = 0;
+ mesh->runtime->looptris.len = 0;
}
if (totpoly) {
- if (mesh->runtime.looptris.array_wip == nullptr) {
- mesh->runtime.looptris.array_wip = static_cast<MLoopTri *>(
- MEM_malloc_arrayN(looptris_len, sizeof(*mesh->runtime.looptris.array_wip), __func__));
- mesh->runtime.looptris.len_alloc = looptris_len;
+ if (mesh->runtime->looptris.array_wip == nullptr) {
+ mesh->runtime->looptris.array_wip = static_cast<MLoopTri *>(
+ MEM_malloc_arrayN(looptris_len, sizeof(*mesh->runtime->looptris.array_wip), __func__));
+ mesh->runtime->looptris.len_alloc = looptris_len;
}
- mesh->runtime.looptris.len = looptris_len;
+ mesh->runtime->looptris.len = looptris_len;
}
}
void BKE_mesh_runtime_looptri_recalc(Mesh *mesh)
{
mesh_ensure_looptri_data(mesh);
- BLI_assert(mesh->totpoly == 0 || mesh->runtime.looptris.array_wip != nullptr);
+ BLI_assert(mesh->totpoly == 0 || mesh->runtime->looptris.array_wip != nullptr);
const Span<MVert> verts = mesh->verts();
const Span<MPoly> polys = mesh->polys();
const Span<MLoop> loops = mesh->loops();
@@ -167,7 +104,7 @@ void BKE_mesh_runtime_looptri_recalc(Mesh *mesh)
verts.data(),
mesh->totloop,
mesh->totpoly,
- mesh->runtime.looptris.array_wip,
+ mesh->runtime->looptris.array_wip,
BKE_mesh_poly_normals_ensure(mesh));
}
else {
@@ -176,43 +113,40 @@ void BKE_mesh_runtime_looptri_recalc(Mesh *mesh)
verts.data(),
mesh->totloop,
mesh->totpoly,
- mesh->runtime.looptris.array_wip);
+ mesh->runtime->looptris.array_wip);
}
- BLI_assert(mesh->runtime.looptris.array == nullptr);
- atomic_cas_ptr((void **)&mesh->runtime.looptris.array,
- mesh->runtime.looptris.array,
- mesh->runtime.looptris.array_wip);
- mesh->runtime.looptris.array_wip = nullptr;
+ BLI_assert(mesh->runtime->looptris.array == nullptr);
+ atomic_cas_ptr((void **)&mesh->runtime->looptris.array,
+ mesh->runtime->looptris.array,
+ mesh->runtime->looptris.array_wip);
+ mesh->runtime->looptris.array_wip = nullptr;
}
int BKE_mesh_runtime_looptri_len(const Mesh *mesh)
{
/* This is a ported copy of `dm_getNumLoopTri(dm)`. */
const int looptri_len = poly_to_tri_count(mesh->totpoly, mesh->totloop);
- BLI_assert(ELEM(mesh->runtime.looptris.len, 0, looptri_len));
+ BLI_assert(ELEM(mesh->runtime->looptris.len, 0, looptri_len));
return looptri_len;
}
const MLoopTri *BKE_mesh_runtime_looptri_ensure(const Mesh *mesh)
{
- ThreadMutex *mesh_eval_mutex = (ThreadMutex *)mesh->runtime.eval_mutex;
- BLI_mutex_lock(mesh_eval_mutex);
+ std::lock_guard lock{mesh->runtime->eval_mutex};
- MLoopTri *looptri = mesh->runtime.looptris.array;
+ MLoopTri *looptri = mesh->runtime->looptris.array;
if (looptri != nullptr) {
- BLI_assert(BKE_mesh_runtime_looptri_len(mesh) == mesh->runtime.looptris.len);
+ BLI_assert(BKE_mesh_runtime_looptri_len(mesh) == mesh->runtime->looptris.len);
}
else {
/* Must isolate multithreaded tasks while holding a mutex lock. */
blender::threading::isolate_task(
[&]() { BKE_mesh_runtime_looptri_recalc(const_cast<Mesh *>(mesh)); });
- looptri = mesh->runtime.looptris.array;
+ looptri = mesh->runtime->looptris.array;
}
- BLI_mutex_unlock(mesh_eval_mutex);
-
return looptri;
}
@@ -230,17 +164,17 @@ void BKE_mesh_runtime_verttri_from_looptri(MVertTri *r_verttri,
bool BKE_mesh_runtime_ensure_edit_data(struct Mesh *mesh)
{
- if (mesh->runtime.edit_data != nullptr) {
+ if (mesh->runtime->edit_data != nullptr) {
return false;
}
- mesh->runtime.edit_data = MEM_cnew<EditMeshData>(__func__);
+ mesh->runtime->edit_data = MEM_cnew<EditMeshData>(__func__);
return true;
}
bool BKE_mesh_runtime_reset_edit_data(Mesh *mesh)
{
- EditMeshData *edit_data = mesh->runtime.edit_data;
+ EditMeshData *edit_data = mesh->runtime->edit_data;
if (edit_data == nullptr) {
return false;
}
@@ -255,13 +189,13 @@ bool BKE_mesh_runtime_reset_edit_data(Mesh *mesh)
bool BKE_mesh_runtime_clear_edit_data(Mesh *mesh)
{
- if (mesh->runtime.edit_data == nullptr) {
+ if (mesh->runtime->edit_data == nullptr) {
return false;
}
BKE_mesh_runtime_reset_edit_data(mesh);
- MEM_freeN(mesh->runtime.edit_data);
- mesh->runtime.edit_data = nullptr;
+ MEM_freeN(mesh->runtime->edit_data);
+ mesh->runtime->edit_data = nullptr;
return true;
}
@@ -271,22 +205,22 @@ void BKE_mesh_runtime_clear_geometry(Mesh *mesh)
BKE_mesh_tag_coords_changed(mesh);
/* TODO(sergey): Does this really belong here? */
- if (mesh->runtime.subdiv_ccg != nullptr) {
- BKE_subdiv_ccg_destroy(mesh->runtime.subdiv_ccg);
- mesh->runtime.subdiv_ccg = nullptr;
+ if (mesh->runtime->subdiv_ccg != nullptr) {
+ BKE_subdiv_ccg_destroy(mesh->runtime->subdiv_ccg);
+ mesh->runtime->subdiv_ccg = nullptr;
}
BKE_shrinkwrap_discard_boundary_data(mesh);
- MEM_SAFE_FREE(mesh->runtime.subsurf_face_dot_tags);
+ MEM_SAFE_FREE(mesh->runtime->subsurf_face_dot_tags);
}
void BKE_mesh_tag_coords_changed(Mesh *mesh)
{
BKE_mesh_normals_tag_dirty(mesh);
- MEM_SAFE_FREE(mesh->runtime.looptris.array);
- if (mesh->runtime.bvh_cache) {
- bvhcache_free(mesh->runtime.bvh_cache);
- mesh->runtime.bvh_cache = nullptr;
+ MEM_SAFE_FREE(mesh->runtime->looptris.array);
+ if (mesh->runtime->bvh_cache) {
+ bvhcache_free(mesh->runtime->bvh_cache);
+ mesh->runtime->bvh_cache = nullptr;
}
}
@@ -305,6 +239,16 @@ void BKE_mesh_tag_coords_changed_uniformly(Mesh *mesh)
}
}
+bool BKE_mesh_is_deformed_only(const Mesh *mesh)
+{
+ return mesh->runtime->deformed_only;
+}
+
+eMeshWrapperType BKE_mesh_wrapper_type(const struct Mesh *mesh)
+{
+ return mesh->runtime->wrapper_type;
+}
+
/** \} */
/* -------------------------------------------------------------------- */
@@ -317,13 +261,13 @@ void (*BKE_mesh_batch_cache_free_cb)(Mesh *me) = nullptr;
void BKE_mesh_batch_cache_dirty_tag(Mesh *me, eMeshBatchDirtyMode mode)
{
- if (me->runtime.batch_cache) {
+ if (me->runtime->batch_cache) {
BKE_mesh_batch_cache_dirty_tag_cb(me, mode);
}
}
void BKE_mesh_batch_cache_free(Mesh *me)
{
- if (me->runtime.batch_cache) {
+ if (me->runtime->batch_cache) {
BKE_mesh_batch_cache_free_cb(me);
}
}
diff --git a/source/blender/blenkernel/intern/mesh_tangent.cc b/source/blender/blenkernel/intern/mesh_tangent.cc
index 1162986aaf5..49ea23a1552 100644
--- a/source/blender/blenkernel/intern/mesh_tangent.cc
+++ b/source/blender/blenkernel/intern/mesh_tangent.cc
@@ -570,8 +570,6 @@ void BKE_mesh_calc_loop_tangents(Mesh *me_eval,
const char (*tangent_names)[MAX_NAME],
int tangent_names_len)
{
- BKE_mesh_runtime_looptri_ensure(me_eval);
-
/* TODO(@campbellbarton): store in Mesh.runtime to avoid recalculation. */
short tangent_mask = 0;
BKE_mesh_calc_loop_tangent_ex(
@@ -579,8 +577,8 @@ void BKE_mesh_calc_loop_tangents(Mesh *me_eval,
BKE_mesh_polys(me_eval),
uint(me_eval->totpoly),
BKE_mesh_loops(me_eval),
- me_eval->runtime.looptris.array,
- uint(me_eval->runtime.looptris.len),
+ BKE_mesh_runtime_looptri_ensure(me_eval),
+ uint(BKE_mesh_runtime_looptri_len(me_eval)),
&me_eval->ldata,
calc_active_tangent,
tangent_names,
diff --git a/source/blender/blenkernel/intern/mesh_wrapper.cc b/source/blender/blenkernel/intern/mesh_wrapper.cc
index 101fad2fce8..61a95fb4d0e 100644
--- a/source/blender/blenkernel/intern/mesh_wrapper.cc
+++ b/source/blender/blenkernel/intern/mesh_wrapper.cc
@@ -57,13 +57,13 @@ Mesh *BKE_mesh_wrapper_from_editmesh_with_coords(BMEditMesh *em,
BKE_mesh_copy_parameters_for_eval(me, me_settings);
BKE_mesh_runtime_ensure_edit_data(me);
- me->runtime.wrapper_type = ME_WRAPPER_TYPE_BMESH;
+ me->runtime->wrapper_type = ME_WRAPPER_TYPE_BMESH;
if (cd_mask_extra) {
- me->runtime.cd_mask_extra = *cd_mask_extra;
+ me->runtime->cd_mask_extra = *cd_mask_extra;
}
/* Use edit-mesh directly where possible. */
- me->runtime.is_original_bmesh = true;
+ me->runtime->is_original_bmesh = true;
me->edit_mesh = static_cast<BMEditMesh *>(MEM_dupallocN(em));
me->edit_mesh->is_shallow_copy = true;
@@ -81,7 +81,7 @@ Mesh *BKE_mesh_wrapper_from_editmesh_with_coords(BMEditMesh *em,
me->totloop = 0;
#endif
- EditMeshData *edit_data = me->runtime.edit_data;
+ EditMeshData *edit_data = me->runtime->edit_data;
edit_data->vertexCos = vert_coords;
return me;
}
@@ -95,17 +95,14 @@ Mesh *BKE_mesh_wrapper_from_editmesh(BMEditMesh *em,
void BKE_mesh_wrapper_ensure_mdata(Mesh *me)
{
- ThreadMutex *mesh_eval_mutex = (ThreadMutex *)me->runtime.eval_mutex;
- BLI_mutex_lock(mesh_eval_mutex);
-
- if (me->runtime.wrapper_type == ME_WRAPPER_TYPE_MDATA) {
- BLI_mutex_unlock(mesh_eval_mutex);
+ std::lock_guard lock{me->runtime->eval_mutex};
+ if (me->runtime->wrapper_type == ME_WRAPPER_TYPE_MDATA) {
return;
}
/* Must isolate multithreaded tasks while holding a mutex lock. */
blender::threading::isolate_task([&]() {
- switch (static_cast<eMeshWrapperType>(me->runtime.wrapper_type)) {
+ switch (static_cast<eMeshWrapperType>(me->runtime->wrapper_type)) {
case ME_WRAPPER_TYPE_MDATA:
case ME_WRAPPER_TYPE_SUBD: {
break; /* Quiet warning. */
@@ -117,10 +114,10 @@ void BKE_mesh_wrapper_ensure_mdata(Mesh *me)
me->totloop = 0;
BLI_assert(me->edit_mesh != nullptr);
- BLI_assert(me->runtime.edit_data != nullptr);
+ BLI_assert(me->runtime->edit_data != nullptr);
BMEditMesh *em = me->edit_mesh;
- BM_mesh_bm_to_me_for_eval(em->bm, me, &me->runtime.cd_mask_extra);
+ BM_mesh_bm_to_me_for_eval(em->bm, me, &me->runtime->cd_mask_extra);
/* Adding original index layers assumes that all BMesh mesh wrappers are created from
* original edit mode meshes (the only case where adding original indices makes sense).
@@ -132,32 +129,30 @@ void BKE_mesh_wrapper_ensure_mdata(Mesh *me)
* harmful. */
BKE_mesh_ensure_default_orig_index_customdata_no_check(me);
- EditMeshData *edit_data = me->runtime.edit_data;
+ EditMeshData *edit_data = me->runtime->edit_data;
if (edit_data->vertexCos) {
BKE_mesh_vert_coords_apply(me, edit_data->vertexCos);
- me->runtime.is_original_bmesh = false;
+ me->runtime->is_original_bmesh = false;
}
break;
}
}
- if (me->runtime.wrapper_type_finalize) {
- BKE_mesh_wrapper_deferred_finalize_mdata(me, &me->runtime.cd_mask_extra);
+ if (me->runtime->wrapper_type_finalize) {
+ BKE_mesh_wrapper_deferred_finalize_mdata(me, &me->runtime->cd_mask_extra);
}
/* Keep type assignment last, so that read-only access only uses the mdata code paths after all
* the underlying data has been initialized. */
- me->runtime.wrapper_type = ME_WRAPPER_TYPE_MDATA;
+ me->runtime->wrapper_type = ME_WRAPPER_TYPE_MDATA;
});
-
- BLI_mutex_unlock(mesh_eval_mutex);
}
bool BKE_mesh_wrapper_minmax(const Mesh *me, float min[3], float max[3])
{
- switch ((eMeshWrapperType)me->runtime.wrapper_type) {
+ switch (me->runtime->wrapper_type) {
case ME_WRAPPER_TYPE_BMESH:
- return BKE_editmesh_cache_calc_minmax(me->edit_mesh, me->runtime.edit_data, min, max);
+ return BKE_editmesh_cache_calc_minmax(me->edit_mesh, me->runtime->edit_data, min, max);
case ME_WRAPPER_TYPE_MDATA:
case ME_WRAPPER_TYPE_SUBD:
return BKE_mesh_minmax(me, min, max);
@@ -174,11 +169,11 @@ void BKE_mesh_wrapper_vert_coords_copy(const Mesh *me,
float (*vert_coords)[3],
int vert_coords_len)
{
- switch ((eMeshWrapperType)me->runtime.wrapper_type) {
+ switch (me->runtime->wrapper_type) {
case ME_WRAPPER_TYPE_BMESH: {
BMesh *bm = me->edit_mesh->bm;
BLI_assert(vert_coords_len <= bm->totvert);
- EditMeshData *edit_data = me->runtime.edit_data;
+ EditMeshData *edit_data = me->runtime->edit_data;
if (edit_data->vertexCos != nullptr) {
for (int i = 0; i < vert_coords_len; i++) {
copy_v3_v3(vert_coords[i], edit_data->vertexCos[i]);
@@ -212,11 +207,11 @@ void BKE_mesh_wrapper_vert_coords_copy_with_mat4(const Mesh *me,
int vert_coords_len,
const float mat[4][4])
{
- switch ((eMeshWrapperType)me->runtime.wrapper_type) {
+ switch (me->runtime->wrapper_type) {
case ME_WRAPPER_TYPE_BMESH: {
BMesh *bm = me->edit_mesh->bm;
BLI_assert(vert_coords_len == bm->totvert);
- EditMeshData *edit_data = me->runtime.edit_data;
+ EditMeshData *edit_data = me->runtime->edit_data;
if (edit_data->vertexCos != nullptr) {
for (int i = 0; i < vert_coords_len; i++) {
mul_v3_m4v3(vert_coords[i], mat, edit_data->vertexCos[i]);
@@ -253,7 +248,7 @@ void BKE_mesh_wrapper_vert_coords_copy_with_mat4(const Mesh *me,
int BKE_mesh_wrapper_vert_len(const Mesh *me)
{
- switch ((eMeshWrapperType)me->runtime.wrapper_type) {
+ switch (me->runtime->wrapper_type) {
case ME_WRAPPER_TYPE_BMESH:
return me->edit_mesh->bm->totvert;
case ME_WRAPPER_TYPE_MDATA:
@@ -266,7 +261,7 @@ int BKE_mesh_wrapper_vert_len(const Mesh *me)
int BKE_mesh_wrapper_edge_len(const Mesh *me)
{
- switch ((eMeshWrapperType)me->runtime.wrapper_type) {
+ switch (me->runtime->wrapper_type) {
case ME_WRAPPER_TYPE_BMESH:
return me->edit_mesh->bm->totedge;
case ME_WRAPPER_TYPE_MDATA:
@@ -279,7 +274,7 @@ int BKE_mesh_wrapper_edge_len(const Mesh *me)
int BKE_mesh_wrapper_loop_len(const Mesh *me)
{
- switch ((eMeshWrapperType)me->runtime.wrapper_type) {
+ switch (me->runtime->wrapper_type) {
case ME_WRAPPER_TYPE_BMESH:
return me->edit_mesh->bm->totloop;
case ME_WRAPPER_TYPE_MDATA:
@@ -292,7 +287,7 @@ int BKE_mesh_wrapper_loop_len(const Mesh *me)
int BKE_mesh_wrapper_poly_len(const Mesh *me)
{
- switch ((eMeshWrapperType)me->runtime.wrapper_type) {
+ switch (me->runtime->wrapper_type) {
case ME_WRAPPER_TYPE_BMESH:
return me->edit_mesh->bm->totface;
case ME_WRAPPER_TYPE_MDATA:
@@ -311,7 +306,7 @@ int BKE_mesh_wrapper_poly_len(const Mesh *me)
static Mesh *mesh_wrapper_ensure_subdivision(Mesh *me)
{
- SubsurfRuntimeData *runtime_data = (SubsurfRuntimeData *)me->runtime.subsurf_runtime_data;
+ SubsurfRuntimeData *runtime_data = (SubsurfRuntimeData *)me->runtime->subsurf_runtime_data;
if (runtime_data == nullptr || runtime_data->settings.level == 0) {
return me;
}
@@ -359,24 +354,22 @@ static Mesh *mesh_wrapper_ensure_subdivision(Mesh *me)
}
if (subdiv_mesh != me) {
- if (me->runtime.mesh_eval != nullptr) {
- BKE_id_free(nullptr, me->runtime.mesh_eval);
+ if (me->runtime->mesh_eval != nullptr) {
+ BKE_id_free(nullptr, me->runtime->mesh_eval);
}
- me->runtime.mesh_eval = subdiv_mesh;
- me->runtime.wrapper_type = ME_WRAPPER_TYPE_SUBD;
+ me->runtime->mesh_eval = subdiv_mesh;
+ me->runtime->wrapper_type = ME_WRAPPER_TYPE_SUBD;
}
- return me->runtime.mesh_eval;
+ return me->runtime->mesh_eval;
}
Mesh *BKE_mesh_wrapper_ensure_subdivision(Mesh *me)
{
- ThreadMutex *mesh_eval_mutex = (ThreadMutex *)me->runtime.eval_mutex;
- BLI_mutex_lock(mesh_eval_mutex);
+ std::lock_guard lock{me->runtime->eval_mutex};
- if (me->runtime.wrapper_type == ME_WRAPPER_TYPE_SUBD) {
- BLI_mutex_unlock(mesh_eval_mutex);
- return me->runtime.mesh_eval;
+ if (me->runtime->wrapper_type == ME_WRAPPER_TYPE_SUBD) {
+ return me->runtime->mesh_eval;
}
Mesh *result;
@@ -384,7 +377,6 @@ Mesh *BKE_mesh_wrapper_ensure_subdivision(Mesh *me)
/* Must isolate multithreaded tasks while holding a mutex lock. */
blender::threading::isolate_task([&]() { result = mesh_wrapper_ensure_subdivision(me); });
- BLI_mutex_unlock(mesh_eval_mutex);
return result;
}
diff --git a/source/blender/blenkernel/intern/modifier.cc b/source/blender/blenkernel/intern/modifier.cc
index 2eb8ef70a4d..fc1a0f47684 100644
--- a/source/blender/blenkernel/intern/modifier.cc
+++ b/source/blender/blenkernel/intern/modifier.cc
@@ -963,9 +963,9 @@ void BKE_modifier_path_init(char *path, int path_maxlen, const char *name)
*/
static void modwrap_dependsOnNormals(Mesh *me)
{
- switch ((eMeshWrapperType)me->runtime.wrapper_type) {
+ switch (me->runtime->wrapper_type) {
case ME_WRAPPER_TYPE_BMESH: {
- EditMeshData *edit_data = me->runtime.edit_data;
+ EditMeshData *edit_data = me->runtime->edit_data;
if (edit_data->vertexCos) {
/* Note that 'ensure' is acceptable here since these values aren't modified in-place.
* If that changes we'll need to recalculate. */
@@ -993,7 +993,7 @@ struct Mesh *BKE_modifier_modify_mesh(ModifierData *md,
{
const ModifierTypeInfo *mti = BKE_modifier_get_info(ModifierType(md->type));
- if (me->runtime.wrapper_type == ME_WRAPPER_TYPE_BMESH) {
+ if (me->runtime->wrapper_type == ME_WRAPPER_TYPE_BMESH) {
if ((mti->flags & eModifierTypeFlag_AcceptsBMesh) == 0) {
BKE_mesh_wrapper_ensure_mdata(me);
}
diff --git a/source/blender/blenkernel/intern/multires.cc b/source/blender/blenkernel/intern/multires.cc
index 61cfe043927..5ff9602650e 100644
--- a/source/blender/blenkernel/intern/multires.cc
+++ b/source/blender/blenkernel/intern/multires.cc
@@ -397,7 +397,7 @@ void multires_mark_as_modified(Depsgraph *depsgraph, Object *object, MultiresMod
* In a longer term maybe special dependency graph tag can help sanitizing this a bit. */
Object *object_eval = DEG_get_evaluated_object(depsgraph, object);
Mesh *mesh = static_cast<Mesh *>(object_eval->data);
- SubdivCCG *subdiv_ccg = mesh->runtime.subdiv_ccg;
+ SubdivCCG *subdiv_ccg = mesh->runtime->subdiv_ccg;
if (subdiv_ccg == nullptr) {
return;
}
diff --git a/source/blender/blenkernel/intern/nla.c b/source/blender/blenkernel/intern/nla.c
index fd3580a7e88..ba63cdff917 100644
--- a/source/blender/blenkernel/intern/nla.c
+++ b/source/blender/blenkernel/intern/nla.c
@@ -1272,6 +1272,34 @@ float BKE_nlastrip_compute_frame_to_next_strip(NlaStrip *strip)
return limit_next;
}
+NlaStrip *BKE_nlastrip_next_in_track(struct NlaStrip *strip, bool skip_transitions)
+{
+ NlaStrip *next = strip->next;
+ while (next != NULL) {
+ if (skip_transitions && (next->type & NLASTRIP_TYPE_TRANSITION)) {
+ next = next->next;
+ }
+ else {
+ return next;
+ }
+ }
+ return NULL;
+}
+
+NlaStrip *BKE_nlastrip_prev_in_track(struct NlaStrip *strip, bool skip_transitions)
+{
+ NlaStrip *prev = strip->prev;
+ while (prev != NULL) {
+ if (skip_transitions && (prev->type & NLASTRIP_TYPE_TRANSITION)) {
+ prev = prev->prev;
+ }
+ else {
+ return prev;
+ }
+ }
+ return NULL;
+}
+
NlaStrip *BKE_nlastrip_find_active(NlaTrack *nlt)
{
if (nlt == NULL) {
diff --git a/source/blender/blenkernel/intern/object.cc b/source/blender/blenkernel/intern/object.cc
index 9417d1afc7e..2d949fb5c65 100644
--- a/source/blender/blenkernel/intern/object.cc
+++ b/source/blender/blenkernel/intern/object.cc
@@ -1691,7 +1691,7 @@ static void object_update_from_subsurf_ccg(Object *object)
if (mesh_eval == nullptr) {
return;
}
- SubdivCCG *subdiv_ccg = mesh_eval->runtime.subdiv_ccg;
+ SubdivCCG *subdiv_ccg = mesh_eval->runtime->subdiv_ccg;
if (subdiv_ccg == nullptr) {
return;
}
@@ -1699,7 +1699,7 @@ static void object_update_from_subsurf_ccg(Object *object)
if (!subdiv_ccg->dirty.coords && !subdiv_ccg->dirty.hidden) {
return;
}
- const int tot_level = mesh_eval->runtime.subdiv_ccg_tot_level;
+ const int tot_level = mesh_eval->runtime->subdiv_ccg_tot_level;
Object *object_orig = DEG_get_original_object(object);
Mesh *mesh_orig = (Mesh *)object_orig->data;
multiresModifier_reshapeFromCCG(tot_level, mesh_orig, subdiv_ccg);
@@ -3218,7 +3218,7 @@ static void give_parvert(Object *par, int nr, float vec[3])
int count = 0;
int numVerts = me_eval->totvert;
- if (em && me_eval->runtime.wrapper_type == ME_WRAPPER_TYPE_BMESH) {
+ if (em && me_eval->runtime->wrapper_type == ME_WRAPPER_TYPE_BMESH) {
numVerts = em->bm->totvert;
if (em->bm->elem_table_dirty & BM_VERT) {
#ifdef VPARENT_THREADING_HACK
@@ -3233,8 +3233,8 @@ static void give_parvert(Object *par, int nr, float vec[3])
#endif
}
if (nr < numVerts) {
- if (me_eval && me_eval->runtime.edit_data && me_eval->runtime.edit_data->vertexCos) {
- add_v3_v3(vec, me_eval->runtime.edit_data->vertexCos[nr]);
+ if (me_eval && me_eval->runtime->edit_data && me_eval->runtime->edit_data->vertexCos) {
+ add_v3_v3(vec, me_eval->runtime->edit_data->vertexCos[nr]);
}
else {
const BMVert *v = BM_vert_at_index(em->bm, nr);
diff --git a/source/blender/blenkernel/intern/object_dupli.cc b/source/blender/blenkernel/intern/object_dupli.cc
index a56176b7d9b..96da99af97e 100644
--- a/source/blender/blenkernel/intern/object_dupli.cc
+++ b/source/blender/blenkernel/intern/object_dupli.cc
@@ -57,10 +57,12 @@
#include "DEG_depsgraph_query.h"
#include "BLI_hash.h"
+#include "DNA_world_types.h"
#include "NOD_geometry_nodes_log.hh"
#include "RNA_access.h"
#include "RNA_path.h"
+#include "RNA_prototypes.h"
#include "RNA_types.h"
using blender::Array;
@@ -421,8 +423,8 @@ static const Mesh *mesh_data_from_duplicator_object(Object *ob,
/* Note that this will only show deformation if #eModifierMode_OnCage is enabled.
* We could change this but it matches 2.7x behavior. */
me_eval = BKE_object_get_editmesh_eval_cage(ob);
- if ((me_eval == nullptr) || (me_eval->runtime.wrapper_type == ME_WRAPPER_TYPE_BMESH)) {
- EditMeshData *emd = me_eval ? me_eval->runtime.edit_data : nullptr;
+ if ((me_eval == nullptr) || (me_eval->runtime->wrapper_type == ME_WRAPPER_TYPE_BMESH)) {
+ EditMeshData *emd = me_eval ? me_eval->runtime->edit_data : nullptr;
/* Only assign edit-mesh in the case we can't use `me_eval`. */
*r_em = em;
@@ -1916,4 +1918,30 @@ bool BKE_object_dupli_find_rgba_attribute(
return false;
}
+bool BKE_view_layer_find_rgba_attribute(struct Scene *scene,
+ struct ViewLayer *layer,
+ const char *name,
+ float r_value[4])
+{
+ if (layer) {
+ PointerRNA layer_ptr;
+ RNA_pointer_create(&scene->id, &RNA_ViewLayer, layer, &layer_ptr);
+
+ if (find_rna_property_rgba(&layer_ptr, name, r_value)) {
+ return true;
+ }
+ }
+
+ if (find_rna_property_rgba(&scene->id, name, r_value)) {
+ return true;
+ }
+
+ if (scene->world && find_rna_property_rgba(&scene->world->id, name, r_value)) {
+ return true;
+ }
+
+ copy_v4_fl(r_value, 0.0f);
+ return false;
+}
+
/** \} */
diff --git a/source/blender/blenkernel/intern/object_update.cc b/source/blender/blenkernel/intern/object_update.cc
index 5328d956cee..ceef6404bf0 100644
--- a/source/blender/blenkernel/intern/object_update.cc
+++ b/source/blender/blenkernel/intern/object_update.cc
@@ -373,10 +373,8 @@ void BKE_object_select_update(Depsgraph *depsgraph, Object *object)
DEG_debug_print_eval(depsgraph, __func__, object->id.name, object);
if (object->type == OB_MESH && !object->runtime.is_data_eval_owned) {
Mesh *mesh_input = (Mesh *)object->runtime.data_orig;
- Mesh_Runtime *mesh_runtime = &mesh_input->runtime;
- BLI_mutex_lock(static_cast<ThreadMutex *>(mesh_runtime->eval_mutex));
+ std::lock_guard lock{mesh_input->runtime->eval_mutex};
BKE_object_data_select_update(depsgraph, static_cast<ID *>(object->data));
- BLI_mutex_unlock(static_cast<ThreadMutex *>(mesh_runtime->eval_mutex));
}
else {
BKE_object_data_select_update(depsgraph, static_cast<ID *>(object->data));
diff --git a/source/blender/blenkernel/intern/paint.cc b/source/blender/blenkernel/intern/paint.cc
index 00535ea5528..934cfb3cc46 100644
--- a/source/blender/blenkernel/intern/paint.cc
+++ b/source/blender/blenkernel/intern/paint.cc
@@ -1743,7 +1743,7 @@ static void sculpt_update_object(
ss->hide_poly = (bool *)CustomData_get_layer_named(&me->pdata, CD_PROP_BOOL, ".hide_poly");
- ss->subdiv_ccg = me_eval->runtime.subdiv_ccg;
+ ss->subdiv_ccg = me_eval->runtime->subdiv_ccg;
PBVH *pbvh = BKE_sculpt_object_pbvh_ensure(depsgraph, ob);
BLI_assert(pbvh == ss->pbvh);
@@ -2237,7 +2237,8 @@ static PBVH *build_pbvh_from_ccg(Object *ob, SubdivCCG *subdiv_ccg, bool respect
(void **)subdiv_ccg->grid_faces,
subdiv_ccg->grid_flag_mats,
subdiv_ccg->grid_hidden,
- base_mesh);
+ base_mesh,
+ subdiv_ccg);
pbvh_show_mask_set(pbvh, ob->sculpt->show_mask);
pbvh_show_face_sets_set(pbvh, ob->sculpt->show_face_sets);
return pbvh;
@@ -2258,7 +2259,7 @@ PBVH *BKE_sculpt_object_pbvh_ensure(Depsgraph *depsgraph, Object *ob)
if (BKE_pbvh_type(pbvh) == PBVH_GRIDS) {
Object *object_eval = DEG_get_evaluated_object(depsgraph, ob);
Mesh *mesh_eval = static_cast<Mesh *>(object_eval->data);
- SubdivCCG *subdiv_ccg = mesh_eval->runtime.subdiv_ccg;
+ SubdivCCG *subdiv_ccg = mesh_eval->runtime->subdiv_ccg;
if (subdiv_ccg != nullptr) {
BKE_sculpt_bvh_update_from_ccg(pbvh, subdiv_ccg);
}
@@ -2277,8 +2278,8 @@ PBVH *BKE_sculpt_object_pbvh_ensure(Depsgraph *depsgraph, Object *ob)
else {
Object *object_eval = DEG_get_evaluated_object(depsgraph, ob);
Mesh *mesh_eval = static_cast<Mesh *>(object_eval->data);
- if (mesh_eval->runtime.subdiv_ccg != nullptr) {
- pbvh = build_pbvh_from_ccg(ob, mesh_eval->runtime.subdiv_ccg, respect_hide);
+ if (mesh_eval->runtime->subdiv_ccg != nullptr) {
+ pbvh = build_pbvh_from_ccg(ob, mesh_eval->runtime->subdiv_ccg, respect_hide);
}
else if (ob->type == OB_MESH) {
Mesh *me_eval_deform = object_eval->runtime.mesh_deform_eval;
@@ -2287,9 +2288,9 @@ PBVH *BKE_sculpt_object_pbvh_ensure(Depsgraph *depsgraph, Object *ob)
}
BKE_pbvh_pmap_set(pbvh, ob->sculpt->pmap);
- sculpt_attribute_update_refs(ob);
-
ob->sculpt->pbvh = pbvh;
+
+ sculpt_attribute_update_refs(ob);
return pbvh;
}
diff --git a/source/blender/blenkernel/intern/particle.c b/source/blender/blenkernel/intern/particle.c
index 6d42d344b86..d6dd3cf0dbb 100644
--- a/source/blender/blenkernel/intern/particle.c
+++ b/source/blender/blenkernel/intern/particle.c
@@ -60,6 +60,7 @@
#include "BKE_material.h"
#include "BKE_mesh.h"
#include "BKE_mesh_legacy_convert.h"
+#include "BKE_mesh_runtime.h"
#include "BKE_modifier.h"
#include "BKE_object.h"
#include "BKE_particle.h"
@@ -1933,7 +1934,7 @@ int psys_particle_dm_face_lookup(Mesh *mesh_final,
index_mf_to_mpoly_deformed = CustomData_get_layer(&mesh_original->fdata, CD_ORIGINDEX);
}
else {
- BLI_assert(mesh_final->runtime.deformed_only);
+ BLI_assert(BKE_mesh_is_deformed_only(mesh_final));
index_mf_to_mpoly_deformed = index_mf_to_mpoly;
}
BLI_assert(index_mf_to_mpoly_deformed);
@@ -2023,7 +2024,7 @@ static int psys_map_index_on_dm(Mesh *mesh,
return 0;
}
- if (mesh->runtime.deformed_only || index_dmcache == DMCACHE_ISCHILD) {
+ if (BKE_mesh_is_deformed_only(mesh) || index_dmcache == DMCACHE_ISCHILD) {
/* for meshes that are either only deformed or for child particles, the
* index and fw do not require any mapping, so we can directly use it */
if (from == PART_FROM_VERT) {
diff --git a/source/blender/blenkernel/intern/particle_distribute.c b/source/blender/blenkernel/intern/particle_distribute.c
index 4c56a8a9275..0301b83a043 100644
--- a/source/blender/blenkernel/intern/particle_distribute.c
+++ b/source/blender/blenkernel/intern/particle_distribute.c
@@ -29,6 +29,7 @@
#include "BKE_lib_id.h"
#include "BKE_mesh.h"
#include "BKE_mesh_legacy_convert.h"
+#include "BKE_mesh_runtime.h"
#include "BKE_object.h"
#include "BKE_particle.h"
@@ -899,7 +900,7 @@ static int psys_thread_context_init_distribute(ParticleThreadContext *ctx,
return 0;
}
- if (!final_mesh->runtime.deformed_only &&
+ if (!BKE_mesh_is_deformed_only(final_mesh) &&
!CustomData_get_layer(&final_mesh->fdata, CD_ORIGINDEX)) {
printf(
"Can't create particles with the current modifier stack, disable destructive modifiers\n");
diff --git a/source/blender/blenkernel/intern/particle_system.c b/source/blender/blenkernel/intern/particle_system.c
index dec874caff4..c72bbe2fd08 100644
--- a/source/blender/blenkernel/intern/particle_system.c
+++ b/source/blender/blenkernel/intern/particle_system.c
@@ -48,6 +48,7 @@
#include "BKE_lib_id.h"
#include "BKE_lib_query.h"
#include "BKE_mesh_legacy_convert.h"
+#include "BKE_mesh_runtime.h"
#include "BKE_particle.h"
#include "BKE_bvhutils.h"
@@ -319,7 +320,7 @@ void psys_calc_dmcache(Object *ob, Mesh *mesh_final, Mesh *mesh_original, Partic
PARTICLE_P;
/* CACHE LOCATIONS */
- if (!mesh_final->runtime.deformed_only) {
+ if (!BKE_mesh_is_deformed_only(mesh_final)) {
/* Will use later to speed up subsurf/evaluated mesh. */
LinkNode *node, *nodedmelem, **nodearray;
int totdmelem, totelem, i;
diff --git a/source/blender/blenkernel/intern/pbvh.c b/source/blender/blenkernel/intern/pbvh.c
index 075cfc5366f..2b989885ebc 100644
--- a/source/blender/blenkernel/intern/pbvh.c
+++ b/source/blender/blenkernel/intern/pbvh.c
@@ -39,8 +39,10 @@
#define LEAF_LIMIT 10000
-//#define PERFCNTRS
+/* Uncomment to test that faces are only assigned to one PBVHNode */
+//#define VALIDATE_UNIQUE_NODE_FACES
+//#define PERFCNTRS
#define STACK_FIXED_DEPTH 100
typedef struct PBVHStack {
@@ -422,6 +424,56 @@ static bool leaf_needs_material_split(PBVH *pbvh, int offset, int count)
return false;
}
+static int adjust_partition_faces(PBVH *pbvh, int offset, int mid, int count)
+{
+ int poly = pbvh->looptri[pbvh->prim_indices[mid]].poly;
+
+ /* Scan backwards. */
+ while (mid > offset + 2) { /* First node should have at least 1 primitive */
+ if (pbvh->looptri[pbvh->prim_indices[mid - 1]].poly != poly) {
+ return mid;
+ }
+
+ mid--;
+ }
+
+ /* If that didn't work try scanning forward. */
+ while (mid < pbvh->totprim + count) {
+ if (pbvh->looptri[pbvh->prim_indices[mid]].poly != poly) {
+ break;
+ }
+
+ mid++;
+ }
+
+ return mid;
+}
+
+static int adjust_partition_grids(PBVH *pbvh, int offset, int mid, int count)
+{
+ int poly = BKE_subdiv_ccg_grid_to_face_index(pbvh->subdiv_ccg, pbvh->prim_indices[mid]);
+
+ /* Scan backwards. */
+ while (mid > offset + 2) { /* First node should have at least 1 primitive */
+ if (BKE_subdiv_ccg_grid_to_face_index(pbvh->subdiv_ccg, pbvh->prim_indices[mid - 1]) != poly) {
+ return mid;
+ }
+
+ mid--;
+ }
+
+ /* If that didn't work try scanning forward. */
+ while (mid < pbvh->totprim + count) {
+ if (BKE_subdiv_ccg_grid_to_face_index(pbvh->subdiv_ccg, pbvh->prim_indices[mid]) != poly) {
+ break;
+ }
+
+ mid++;
+ }
+
+ return mid;
+}
+
/* Recursively build a node in the tree
*
* vb is the voxel box around all of the primitives contained in
@@ -478,6 +530,13 @@ static void build_sub(PBVH *pbvh, int node_index, BB *cb, BBC *prim_bbc, int off
end = partition_indices_material(pbvh, offset, offset + count - 1);
}
+ if (pbvh->header.type == PBVH_FACES) {
+ end = adjust_partition_faces(pbvh, offset, end, count);
+ }
+ else {
+ end = adjust_partition_grids(pbvh, offset, end, count);
+ }
+
/* Build children */
build_sub(pbvh, pbvh->nodes[node_index].children_offset, NULL, prim_bbc, offset, end - offset);
build_sub(pbvh,
@@ -587,6 +646,73 @@ static void pbvh_draw_args_init(PBVH *pbvh, PBVH_GPU_Args *args, PBVHNode *node)
}
}
+#ifdef VALIDATE_UNIQUE_NODE_FACES
+static void pbvh_validate_node_prims(PBVH *pbvh)
+{
+ int totface = 0;
+
+ if (pbvh->header.type == PBVH_BMESH) {
+ return;
+ }
+
+ for (int i = 0; i < pbvh->totnode; i++) {
+ PBVHNode *node = pbvh->nodes + i;
+
+ if (!(node->flag & PBVH_Leaf)) {
+ continue;
+ }
+
+ for (int j = 0; j < node->totprim; j++) {
+ int poly;
+
+ if (pbvh->header.type == PBVH_FACES) {
+ poly = pbvh->looptri[node->prim_indices[j]].poly;
+ }
+ else {
+ poly = BKE_subdiv_ccg_grid_to_face_index(pbvh->subdiv_ccg, node->prim_indices[j]);
+ }
+
+ totface = max_ii(totface, poly + 1);
+ }
+ }
+
+ int *facemap = (int *)MEM_malloc_arrayN(totface, sizeof(*facemap), __func__);
+
+ for (int i = 0; i < totface; i++) {
+ facemap[i] = -1;
+ }
+
+ for (int i = 0; i < pbvh->totnode; i++) {
+ PBVHNode *node = pbvh->nodes + i;
+
+ if (!(node->flag & PBVH_Leaf)) {
+ continue;
+ }
+
+ for (int j = 0; j < node->totprim; j++) {
+ int poly;
+
+ if (pbvh->header.type == PBVH_FACES) {
+ poly = pbvh->looptri[node->prim_indices[j]].poly;
+ }
+ else {
+ poly = BKE_subdiv_ccg_grid_to_face_index(pbvh->subdiv_ccg, node->prim_indices[j]);
+ }
+
+ if (facemap[poly] != -1 && facemap[poly] != i) {
+ printf("%s: error: face spanned multiple nodes (old: %d new: %d)\n",
+ __func__,
+ facemap[poly],
+ i);
+ }
+
+ facemap[poly] = i;
+ }
+ }
+ MEM_SAFE_FREE(facemap);
+}
+#endif
+
void BKE_pbvh_build_mesh(PBVH *pbvh,
Mesh *mesh,
const MPoly *mpoly,
@@ -645,6 +771,32 @@ void BKE_pbvh_build_mesh(PBVH *pbvh,
BB_expand(&cb, bbc->bcentroid);
}
+ /* Ensure all primitives belonging to the same base face
+ * have the same bounds. This is needed to prevent them
+ * from being swapped away from each other inside the partition
+ * array.
+ */
+ for (int i = 0; i < looptri_num; i++) {
+ const MLoopTri *lt = &looptri[i];
+ int poly = lt->poly;
+ BBC *bbc = prim_bbc + i;
+ int j = i + 1;
+
+ while (j < looptri_num && looptri[j].poly == poly) {
+ BBC *bbc2 = prim_bbc + j;
+
+ BB_expand((BB *)bbc, bbc2->bmin);
+ BB_expand((BB *)bbc, bbc2->bmax);
+ j++;
+ }
+
+ j = i + 1;
+ while (j < looptri_num && looptri[j].poly == poly) {
+ prim_bbc[j] = prim_bbc[i];
+ j++;
+ }
+ }
+
if (looptri_num) {
pbvh_build(pbvh, &cb, prim_bbc, looptri_num);
}
@@ -655,6 +807,10 @@ void BKE_pbvh_build_mesh(PBVH *pbvh,
memset(pbvh->vert_bitmap, 0, sizeof(bool) * totvert);
BKE_pbvh_update_active_vcol(pbvh, mesh);
+
+#ifdef VALIDATE_UNIQUE_NODE_FACES
+ pbvh_validate_node_prims(pbvh);
+#endif
}
void BKE_pbvh_build_grids(PBVH *pbvh,
@@ -664,7 +820,8 @@ void BKE_pbvh_build_grids(PBVH *pbvh,
void **gridfaces,
DMFlagMat *flagmats,
BLI_bitmap **grid_hidden,
- Mesh *me)
+ Mesh *me,
+ SubdivCCG *subdiv_ccg)
{
const int gridsize = key->grid_size;
@@ -675,6 +832,7 @@ void BKE_pbvh_build_grids(PBVH *pbvh,
pbvh->totgrid = totgrid;
pbvh->gridkey = *key;
pbvh->grid_hidden = grid_hidden;
+ pbvh->subdiv_ccg = subdiv_ccg;
pbvh->leaf_limit = max_ii(LEAF_LIMIT / (gridsize * gridsize), 1);
/* We need the base mesh attribute layout for PBVH draw. */
@@ -706,11 +864,40 @@ void BKE_pbvh_build_grids(PBVH *pbvh,
BB_expand(&cb, bbc->bcentroid);
}
+ /* Ensure all primitives belonging to the same base face
+ * have the same bounds. This is needed to prevent them
+ * from being swapped away from each other inside the partition
+ * array.
+ */
+ for (int i = 0; i < totgrid; i++) {
+ int poly = BKE_subdiv_ccg_grid_to_face_index(pbvh->subdiv_ccg, i);
+
+ BBC *bbc = prim_bbc + i;
+ int j = i + 1;
+
+ while (j < totgrid && BKE_subdiv_ccg_grid_to_face_index(pbvh->subdiv_ccg, j) == poly) {
+ BBC *bbc2 = prim_bbc + j;
+
+ BB_expand((BB *)bbc, bbc2->bmin);
+ BB_expand((BB *)bbc, bbc2->bmax);
+ j++;
+ }
+
+ j = i + 1;
+ while (j < totgrid && BKE_subdiv_ccg_grid_to_face_index(pbvh->subdiv_ccg, j) == poly) {
+ prim_bbc[j] = prim_bbc[i];
+ j++;
+ }
+ }
+
if (totgrid) {
pbvh_build(pbvh, &cb, prim_bbc, totgrid);
}
MEM_freeN(prim_bbc);
+#ifdef VALIDATE_UNIQUE_NODE_FACES
+ pbvh_validate_node_prims(pbvh);
+#endif
}
PBVH *BKE_pbvh_new(PBVHType type)
@@ -719,6 +906,11 @@ PBVH *BKE_pbvh_new(PBVHType type)
pbvh->respect_hide = true;
pbvh->draw_cache_invalid = true;
pbvh->header.type = type;
+
+ /* Initialize this to true, instead of waiting for a draw engine
+ * to set it. Prevents a crash in draw manager instancing code.
+ */
+ pbvh->is_drawing = true;
return pbvh;
}
@@ -2056,11 +2248,16 @@ void BKE_pbvh_node_get_proxies(PBVHNode *node, PBVHProxyNode **proxies, int *pro
void BKE_pbvh_node_get_bm_orco_data(PBVHNode *node,
int (**r_orco_tris)[3],
int *r_orco_tris_num,
- float (**r_orco_coords)[3])
+ float (**r_orco_coords)[3],
+ BMVert ***r_orco_verts)
{
*r_orco_tris = node->bm_ortri;
*r_orco_tris_num = node->bm_tot_ortri;
*r_orco_coords = node->bm_orco;
+
+ if (r_orco_verts) {
+ *r_orco_verts = node->bm_orvert;
+ }
}
bool BKE_pbvh_node_has_vert_with_normal_update_tag(PBVH *pbvh, PBVHNode *node)
diff --git a/source/blender/blenkernel/intern/pbvh_bmesh.c b/source/blender/blenkernel/intern/pbvh_bmesh.c
index 516e1fb4639..3b0f35263d3 100644
--- a/source/blender/blenkernel/intern/pbvh_bmesh.c
+++ b/source/blender/blenkernel/intern/pbvh_bmesh.c
@@ -493,7 +493,7 @@ static BMVert *pbvh_bmesh_vert_create(PBVH *pbvh,
BLI_gset_insert(node->bm_unique_verts, v);
BM_ELEM_CD_SET_INT(v, pbvh->cd_vert_node_offset, node_index);
- node->flag |= PBVH_UpdateDrawBuffers | PBVH_UpdateBB;
+ node->flag |= PBVH_UpdateDrawBuffers | PBVH_UpdateBB | PBVH_TopologyUpdated;
/* Log the new vertex */
BM_log_vert_added(pbvh->bm_log, v, cd_vert_mask_offset);
@@ -519,7 +519,7 @@ static BMFace *pbvh_bmesh_face_create(
BM_ELEM_CD_SET_INT(f, pbvh->cd_face_node_offset, node_index);
/* mark node for update */
- node->flag |= PBVH_UpdateDrawBuffers | PBVH_UpdateNormals;
+ node->flag |= PBVH_UpdateDrawBuffers | PBVH_UpdateNormals | PBVH_TopologyUpdated;
node->flag &= ~PBVH_FullyHidden;
/* Log the new face */
@@ -594,7 +594,7 @@ static void pbvh_bmesh_vert_ownership_transfer(PBVH *pbvh, PBVHNode *new_owner,
{
PBVHNode *current_owner = pbvh_bmesh_node_from_vert(pbvh, v);
/* mark node for update */
- current_owner->flag |= PBVH_UpdateDrawBuffers | PBVH_UpdateBB;
+ current_owner->flag |= PBVH_UpdateDrawBuffers | PBVH_UpdateBB | PBVH_TopologyUpdated;
BLI_assert(current_owner != new_owner);
@@ -608,7 +608,7 @@ static void pbvh_bmesh_vert_ownership_transfer(PBVH *pbvh, PBVHNode *new_owner,
BLI_assert(!BLI_gset_haskey(new_owner->bm_other_verts, v));
/* mark node for update */
- new_owner->flag |= PBVH_UpdateDrawBuffers | PBVH_UpdateBB;
+ new_owner->flag |= PBVH_UpdateDrawBuffers | PBVH_UpdateBB | PBVH_TopologyUpdated;
}
static void pbvh_bmesh_vert_remove(PBVH *pbvh, BMVert *v)
@@ -631,7 +631,7 @@ static void pbvh_bmesh_vert_remove(PBVH *pbvh, BMVert *v)
f_node_index_prev = f_node_index;
PBVHNode *f_node = &pbvh->nodes[f_node_index];
- f_node->flag |= PBVH_UpdateDrawBuffers | PBVH_UpdateBB;
+ f_node->flag |= PBVH_UpdateDrawBuffers | PBVH_UpdateBB | PBVH_TopologyUpdated;
/* Remove current ownership */
BLI_gset_remove(f_node->bm_other_verts, v, NULL);
@@ -680,7 +680,7 @@ static void pbvh_bmesh_face_remove(PBVH *pbvh, BMFace *f)
BM_log_face_removed(pbvh->bm_log, f);
/* mark node for update */
- f_node->flag |= PBVH_UpdateDrawBuffers | PBVH_UpdateNormals;
+ f_node->flag |= PBVH_UpdateDrawBuffers | PBVH_UpdateNormals | PBVH_TopologyUpdated;
}
static void pbvh_bmesh_edge_loops(BLI_Buffer *buf, BMEdge *e)
@@ -701,14 +701,9 @@ static void pbvh_bmesh_edge_loops(BLI_Buffer *buf, BMEdge *e)
static void pbvh_bmesh_node_drop_orig(PBVHNode *node)
{
- if (node->bm_orco) {
- MEM_freeN(node->bm_orco);
- }
- if (node->bm_ortri) {
- MEM_freeN(node->bm_ortri);
- }
- node->bm_orco = NULL;
- node->bm_ortri = NULL;
+ MEM_SAFE_FREE(node->bm_orco);
+ MEM_SAFE_FREE(node->bm_ortri);
+ MEM_SAFE_FREE(node->bm_orvert);
node->bm_tot_ortri = 0;
}
@@ -1507,29 +1502,51 @@ bool pbvh_bmesh_node_raycast(PBVHNode *node,
bool hit = false;
float nearest_vertex_co[3] = {0.0f};
+ BLI_assert(!use_original || (BLI_gset_len(node->bm_faces) > 0 && node->bm_tot_ortri));
+
+ use_original = use_original && node->bm_tot_ortri;
+
+ GSetIterator gs_iter;
+
if (use_original && node->bm_tot_ortri) {
for (int i = 0; i < node->bm_tot_ortri; i++) {
- const int *t = node->bm_ortri[i];
- hit |= ray_face_intersection_tri(ray_start,
- isect_precalc,
- node->bm_orco[t[0]],
- node->bm_orco[t[1]],
- node->bm_orco[t[2]],
- depth);
+ float *cos[3];
+
+ cos[0] = node->bm_orco[node->bm_ortri[i][0]];
+ cos[1] = node->bm_orco[node->bm_ortri[i][1]];
+ cos[2] = node->bm_orco[node->bm_ortri[i][2]];
+
+ if (ray_face_intersection_tri(ray_start, isect_precalc, cos[0], cos[1], cos[2], depth)) {
+ hit = true;
+
+ if (r_face_normal) {
+ normal_tri_v3(r_face_normal, cos[0], cos[1], cos[2]);
+ }
+
+ if (r_active_vertex) {
+ float location[3] = {0.0f};
+ madd_v3_v3v3fl(location, ray_start, ray_normal, *depth);
+ for (int j = 0; j < 3; j++) {
+ if (len_squared_v3v3(location, cos[j]) <
+ len_squared_v3v3(location, nearest_vertex_co)) {
+ copy_v3_v3(nearest_vertex_co, cos[j]);
+ r_active_vertex->i = (intptr_t)node->bm_orvert[node->bm_ortri[i][j]];
+ }
+ }
+ }
+ }
}
}
else {
- GSetIterator gs_iter;
-
GSET_ITER (gs_iter, node->bm_faces) {
BMFace *f = BLI_gsetIterator_getKey(&gs_iter);
BLI_assert(f->len == 3);
+
if (!BM_elem_flag_test(f, BM_ELEM_HIDDEN)) {
BMVert *v_tri[3];
BM_face_as_array_vert_tri(f, v_tri);
-
if (ray_face_intersection_tri(
ray_start, isect_precalc, v_tri[0]->co, v_tri[1]->co, v_tri[2]->co, depth)) {
hit = true;
@@ -2016,6 +2033,21 @@ bool BKE_pbvh_bmesh_update_topology(PBVH *pbvh,
BLI_buffer_free(&edge_loops);
BLI_buffer_free(&deleted_faces);
+ /* Go over all changed nodes and check if anything needs to be updated. */
+ for (int n = 0; n < pbvh->totnode; n++) {
+ PBVHNode *node = &pbvh->nodes[n];
+
+ if (node->flag & PBVH_Leaf && node->flag & PBVH_TopologyUpdated) {
+ node->flag &= ~PBVH_TopologyUpdated;
+
+ if (node->bm_ortri) {
+ /* Reallocate original triangle data. */
+ pbvh_bmesh_node_drop_orig(node);
+ BKE_pbvh_bmesh_node_save_orig(pbvh->header.bm, pbvh->bm_log, node, true);
+ }
+ }
+ }
+
#ifdef USE_VERIFY
pbvh_bmesh_verify(pbvh);
#endif
@@ -2023,7 +2055,7 @@ bool BKE_pbvh_bmesh_update_topology(PBVH *pbvh,
return modified;
}
-void BKE_pbvh_bmesh_node_save_orig(BMesh *bm, PBVHNode *node)
+void BKE_pbvh_bmesh_node_save_orig(BMesh *bm, BMLog *log, PBVHNode *node, bool use_original)
{
/* Skip if original coords/triangles are already saved */
if (node->bm_orco) {
@@ -2036,19 +2068,38 @@ void BKE_pbvh_bmesh_node_save_orig(BMesh *bm, PBVHNode *node)
node->bm_orco = MEM_mallocN(sizeof(*node->bm_orco) * totvert, __func__);
node->bm_ortri = MEM_mallocN(sizeof(*node->bm_ortri) * tottri, __func__);
+ node->bm_orvert = MEM_mallocN(sizeof(*node->bm_orvert) * totvert, __func__);
/* Copy out the vertices and assign a temporary index */
int i = 0;
GSetIterator gs_iter;
GSET_ITER (gs_iter, node->bm_unique_verts) {
BMVert *v = BLI_gsetIterator_getKey(&gs_iter);
- copy_v3_v3(node->bm_orco[i], v->co);
+ const float *origco = BM_log_original_vert_co(log, v);
+
+ if (use_original && origco) {
+ copy_v3_v3(node->bm_orco[i], origco);
+ }
+ else {
+ copy_v3_v3(node->bm_orco[i], v->co);
+ }
+
+ node->bm_orvert[i] = v;
BM_elem_index_set(v, i); /* set_dirty! */
i++;
}
GSET_ITER (gs_iter, node->bm_other_verts) {
BMVert *v = BLI_gsetIterator_getKey(&gs_iter);
- copy_v3_v3(node->bm_orco[i], v->co);
+ const float *origco = BM_log_original_vert_co(log, v);
+
+ if (use_original && origco) {
+ copy_v3_v3(node->bm_orco[i], BM_log_original_vert_co(log, v));
+ }
+ else {
+ copy_v3_v3(node->bm_orco[i], v->co);
+ }
+
+ node->bm_orvert[i] = v;
BM_elem_index_set(v, i); /* set_dirty! */
i++;
}
diff --git a/source/blender/blenkernel/intern/pbvh_intern.h b/source/blender/blenkernel/intern/pbvh_intern.h
index c78bfc25cb2..34eb969adac 100644
--- a/source/blender/blenkernel/intern/pbvh_intern.h
+++ b/source/blender/blenkernel/intern/pbvh_intern.h
@@ -116,8 +116,11 @@ struct PBVHNode {
GSet *bm_faces;
GSet *bm_unique_verts;
GSet *bm_other_verts;
+
+ /* Deprecated. Stores original coordinates of triangles. */
float (*bm_orco)[3];
int (*bm_ortri)[3];
+ BMVert **bm_orvert;
int bm_tot_ortri;
/* Used to store the brush color during a stroke and composite it over the original color */
diff --git a/source/blender/blenkernel/intern/pointcloud.cc b/source/blender/blenkernel/intern/pointcloud.cc
index c73bbb91965..119daccce20 100644
--- a/source/blender/blenkernel/intern/pointcloud.cc
+++ b/source/blender/blenkernel/intern/pointcloud.cc
@@ -239,12 +239,6 @@ PointCloud *BKE_pointcloud_new_nomain(const int totpoint)
nullptr, ID_PT, BKE_idtype_idcode_to_name(ID_PT), LIB_ID_CREATE_LOCALIZE));
pointcloud_init_data(&pointcloud->id);
- CustomData_add_layer_named(&pointcloud->pdata,
- CD_PROP_FLOAT,
- CD_SET_DEFAULT,
- nullptr,
- pointcloud->totpoint,
- POINTCLOUD_ATTR_RADIUS);
CustomData_realloc(&pointcloud->pdata, 0, totpoint);
pointcloud->totpoint = totpoint;
diff --git a/source/blender/blenkernel/intern/rigidbody.c b/source/blender/blenkernel/intern/rigidbody.c
index 6b4cddb05f2..ffc6bc8d7a3 100644
--- a/source/blender/blenkernel/intern/rigidbody.c
+++ b/source/blender/blenkernel/intern/rigidbody.c
@@ -404,7 +404,7 @@ static rbCollisionShape *rigidbody_get_shape_trimesh_from_mesh(Object *ob)
const MVert *mvert = BKE_mesh_verts(mesh);
totvert = mesh->totvert;
looptri = BKE_mesh_runtime_looptri_ensure(mesh);
- tottri = mesh->runtime.looptris.len;
+ tottri = BKE_mesh_runtime_looptri_len(mesh);
const MLoop *mloop = BKE_mesh_loops(mesh);
/* sanity checking - potential case when no data will be present */
@@ -679,7 +679,7 @@ void BKE_rigidbody_calc_volume(Object *ob, float *r_vol)
const MVert *mvert = BKE_mesh_verts(mesh);
totvert = mesh->totvert;
lt = BKE_mesh_runtime_looptri_ensure(mesh);
- tottri = mesh->runtime.looptris.len;
+ tottri = BKE_mesh_runtime_looptri_len(mesh);
const MLoop *mloop = BKE_mesh_loops(mesh);
if (totvert > 0 && tottri > 0) {
@@ -753,7 +753,7 @@ void BKE_rigidbody_calc_center_of_mass(Object *ob, float r_center[3])
const MVert *mvert = BKE_mesh_verts(mesh);
totvert = mesh->totvert;
looptri = BKE_mesh_runtime_looptri_ensure(mesh);
- tottri = mesh->runtime.looptris.len;
+ tottri = BKE_mesh_runtime_looptri_len(mesh);
const MLoop *mloop = BKE_mesh_loops(mesh);
if (totvert > 0 && tottri > 0) {
diff --git a/source/blender/blenkernel/intern/scene.cc b/source/blender/blenkernel/intern/scene.cc
index d6183210186..fc47fb71bf3 100644
--- a/source/blender/blenkernel/intern/scene.cc
+++ b/source/blender/blenkernel/intern/scene.cc
@@ -244,7 +244,7 @@ static void scene_init_data(ID *id)
/* Master Collection */
scene->master_collection = BKE_collection_master_add(scene);
- BKE_view_layer_add(scene, "ViewLayer", nullptr, VIEWLAYER_ADD_NEW);
+ BKE_view_layer_add(scene, DATA_("ViewLayer"), nullptr, VIEWLAYER_ADD_NEW);
}
static void scene_copy_markers(Scene *scene_dst, const Scene *scene_src, const int flag)
diff --git a/source/blender/blenkernel/intern/shrinkwrap.cc b/source/blender/blenkernel/intern/shrinkwrap.cc
index 703b012d170..65226a5db9d 100644
--- a/source/blender/blenkernel/intern/shrinkwrap.cc
+++ b/source/blender/blenkernel/intern/shrinkwrap.cc
@@ -140,7 +140,7 @@ bool BKE_shrinkwrap_init_tree(
}
if (shrinkType == MOD_SHRINKWRAP_TARGET_PROJECT) {
- data->boundary = mesh->runtime.shrinkwrap_data;
+ data->boundary = mesh->runtime->shrinkwrap_data;
}
return true;
@@ -153,7 +153,7 @@ void BKE_shrinkwrap_free_tree(ShrinkwrapTreeData *data)
void BKE_shrinkwrap_discard_boundary_data(Mesh *mesh)
{
- ShrinkwrapBoundaryData *data = mesh->runtime.shrinkwrap_data;
+ ShrinkwrapBoundaryData *data = mesh->runtime->shrinkwrap_data;
if (data != nullptr) {
MEM_freeN((void *)data->edge_is_boundary);
@@ -164,7 +164,7 @@ void BKE_shrinkwrap_discard_boundary_data(Mesh *mesh)
MEM_freeN(data);
}
- mesh->runtime.shrinkwrap_data = nullptr;
+ mesh->runtime->shrinkwrap_data = nullptr;
}
/* Accumulate edge for average boundary edge direction. */
@@ -327,7 +327,7 @@ void BKE_shrinkwrap_compute_boundary_data(Mesh *mesh)
{
BKE_shrinkwrap_discard_boundary_data(mesh);
- mesh->runtime.shrinkwrap_data = shrinkwrap_build_boundary_data(mesh);
+ mesh->runtime->shrinkwrap_data = shrinkwrap_build_boundary_data(mesh);
}
/**
diff --git a/source/blender/blenkernel/intern/subdiv_ccg.cc b/source/blender/blenkernel/intern/subdiv_ccg.cc
index 6f583f760ef..bf09be444b1 100644
--- a/source/blender/blenkernel/intern/subdiv_ccg.cc
+++ b/source/blender/blenkernel/intern/subdiv_ccg.cc
@@ -128,7 +128,7 @@ static void subdiv_ccg_alloc_elements(SubdivCCG *subdiv_ccg, Subdiv *subdiv)
subdiv_ccg->num_grids = num_grids;
subdiv_ccg->grids = static_cast<CCGElem **>(
MEM_calloc_arrayN(num_grids, sizeof(CCGElem *), "subdiv ccg grids"));
- subdiv_ccg->grids_storage = static_cast<unsigned char *>(
+ subdiv_ccg->grids_storage = static_cast<uchar *>(
MEM_calloc_arrayN(num_grids, size_t(grid_area) * element_size, "subdiv ccg grids storage"));
const size_t grid_size_in_bytes = size_t(grid_area) * element_size;
for (int grid_index = 0; grid_index < num_grids; grid_index++) {
@@ -286,7 +286,7 @@ static void subdiv_ccg_eval_special_grid(CCGEvalGridsData *data, const int face_
static void subdiv_ccg_eval_grids_task(void *__restrict userdata_v,
const int face_index,
- const TaskParallelTLS *__restrict UNUSED(tls))
+ const TaskParallelTLS *__restrict /*tls*/)
{
CCGEvalGridsData *data = static_cast<CCGEvalGridsData *>(userdata_v);
SubdivCCG *subdiv_ccg = data->subdiv_ccg;
@@ -615,7 +615,7 @@ Mesh *BKE_subdiv_to_ccg_mesh(Subdiv *subdiv,
return nullptr;
}
Mesh *result = BKE_mesh_new_nomain_from_template(coarse_mesh, 0, 0, 0, 0, 0);
- result->runtime.subdiv_ccg = subdiv_ccg;
+ result->runtime->subdiv_ccg = subdiv_ccg;
return result;
}
@@ -779,7 +779,7 @@ static void subdiv_ccg_recalc_inner_normal_task(void *__restrict userdata_v,
subdiv_ccg_average_inner_face_normals(data->subdiv_ccg, data->key, tls, grid_index);
}
-static void subdiv_ccg_recalc_inner_normal_free(const void *__restrict UNUSED(userdata),
+static void subdiv_ccg_recalc_inner_normal_free(const void *__restrict /*userdata*/,
void *__restrict tls_v)
{
RecalcInnerNormalsTLSData *tls = static_cast<RecalcInnerNormalsTLSData *>(tls_v);
@@ -842,7 +842,7 @@ static void subdiv_ccg_recalc_modified_inner_normal_task(void *__restrict userda
subdiv_ccg_average_inner_face_grids(subdiv_ccg, key, face);
}
-static void subdiv_ccg_recalc_modified_inner_normal_free(const void *__restrict UNUSED(userdata),
+static void subdiv_ccg_recalc_modified_inner_normal_free(const void *__restrict /*userdata*/,
void *__restrict tls_v)
{
RecalcInnerNormalsTLSData *tls = static_cast<RecalcInnerNormalsTLSData *>(tls_v);
@@ -1016,7 +1016,7 @@ static void subdiv_ccg_average_inner_face_grids(SubdivCCG *subdiv_ccg,
static void subdiv_ccg_average_inner_grids_task(void *__restrict userdata_v,
const int face_index,
- const TaskParallelTLS *__restrict UNUSED(tls_v))
+ const TaskParallelTLS *__restrict /*tls_v*/)
{
AverageInnerGridsData *data = static_cast<AverageInnerGridsData *>(userdata_v);
SubdivCCG *subdiv_ccg = data->subdiv_ccg;
@@ -1095,7 +1095,7 @@ static void subdiv_ccg_average_grids_boundaries_task(void *__restrict userdata_v
subdiv_ccg_average_grids_boundary(subdiv_ccg, key, adjacent_edge, tls);
}
-static void subdiv_ccg_average_grids_boundaries_free(const void *__restrict UNUSED(userdata),
+static void subdiv_ccg_average_grids_boundaries_free(const void *__restrict /*userdata*/,
void *__restrict tls_v)
{
AverageGridsBoundariesTLSData *tls = static_cast<AverageGridsBoundariesTLSData *>(tls_v);
@@ -1137,7 +1137,7 @@ static void subdiv_ccg_average_grids_corners(SubdivCCG *subdiv_ccg,
static void subdiv_ccg_average_grids_corners_task(void *__restrict userdata_v,
const int n,
- const TaskParallelTLS *__restrict UNUSED(tls_v))
+ const TaskParallelTLS *__restrict /*tls_v*/)
{
AverageGridsCornerData *data = static_cast<AverageGridsCornerData *>(userdata_v);
const int adjacent_vertex_index = data->adjacent_vert_index_map ?
@@ -1323,10 +1323,9 @@ struct StitchFacesInnerGridsData {
CCGFace **effected_ccg_faces;
};
-static void subdiv_ccg_stitch_face_inner_grids_task(
- void *__restrict userdata_v,
- const int face_index,
- const TaskParallelTLS *__restrict UNUSED(tls_v))
+static void subdiv_ccg_stitch_face_inner_grids_task(void *__restrict userdata_v,
+ const int face_index,
+ const TaskParallelTLS *__restrict /*tls_v*/)
{
StitchFacesInnerGridsData *data = static_cast<StitchFacesInnerGridsData *>(userdata_v);
SubdivCCG *subdiv_ccg = data->subdiv_ccg;
@@ -1447,7 +1446,7 @@ BLI_INLINE bool is_inner_edge_grid_coordinate(const SubdivCCG *subdiv_ccg,
return false;
}
-BLI_INLINE SubdivCCGCoord coord_at_prev_row(const SubdivCCG *UNUSED(subdiv_ccg),
+BLI_INLINE SubdivCCGCoord coord_at_prev_row(const SubdivCCG * /*subdiv_ccg*/,
const SubdivCCGCoord *coord)
{
BLI_assert(coord->y > 0);
@@ -1465,7 +1464,7 @@ BLI_INLINE SubdivCCGCoord coord_at_next_row(const SubdivCCG *subdiv_ccg,
return result;
}
-BLI_INLINE SubdivCCGCoord coord_at_prev_col(const SubdivCCG *UNUSED(subdiv_ccg),
+BLI_INLINE SubdivCCGCoord coord_at_prev_col(const SubdivCCG * /*subdiv_ccg*/,
const SubdivCCGCoord *coord)
{
BLI_assert(coord->x > 0);
diff --git a/source/blender/blenkernel/intern/subdiv_mesh.cc b/source/blender/blenkernel/intern/subdiv_mesh.cc
index 00183ea90c2..3b97c1f5e68 100644
--- a/source/blender/blenkernel/intern/subdiv_mesh.cc
+++ b/source/blender/blenkernel/intern/subdiv_mesh.cc
@@ -528,9 +528,9 @@ static bool subdiv_mesh_topology_info(const SubdivForeachContext *foreach_contex
subdiv_context->coarse_mesh, num_vertices, num_edges, 0, num_loops, num_polygons, mask);
subdiv_mesh_ctx_cache_custom_data_layers(subdiv_context);
subdiv_mesh_prepare_accumulator(subdiv_context, num_vertices);
- MEM_SAFE_FREE(subdiv_context->subdiv_mesh->runtime.subsurf_face_dot_tags);
- subdiv_context->subdiv_mesh->runtime.subsurf_face_dot_tags = BLI_BITMAP_NEW(num_vertices,
- __func__);
+ MEM_SAFE_FREE(subdiv_context->subdiv_mesh->runtime->subsurf_face_dot_tags);
+ subdiv_context->subdiv_mesh->runtime->subsurf_face_dot_tags = BLI_BITMAP_NEW(num_vertices,
+ __func__);
return true;
}
@@ -595,7 +595,7 @@ static void evaluate_vertex_and_apply_displacement_copy(const SubdivMeshContext
/* Evaluate undeformed texture coordinate. */
subdiv_vertex_orco_evaluate(ctx, ptex_face_index, u, v, subdiv_vertex_index);
/* Remove face-dot flag. This can happen if there is more than one subsurf modifier. */
- BLI_BITMAP_DISABLE(ctx->subdiv_mesh->runtime.subsurf_face_dot_tags, subdiv_vertex_index);
+ BLI_BITMAP_DISABLE(ctx->subdiv_mesh->runtime->subsurf_face_dot_tags, subdiv_vertex_index);
}
static void evaluate_vertex_and_apply_displacement_interpolate(
@@ -753,7 +753,7 @@ static void subdiv_mesh_tag_center_vertex(const MPoly *coarse_poly,
Mesh *subdiv_mesh)
{
if (subdiv_mesh_is_center_vertex(coarse_poly, u, v)) {
- BLI_BITMAP_ENABLE(subdiv_mesh->runtime.subsurf_face_dot_tags, subdiv_vertex_index);
+ BLI_BITMAP_ENABLE(subdiv_mesh->runtime->subsurf_face_dot_tags, subdiv_vertex_index);
}
}
diff --git a/source/blender/blenkernel/intern/subdiv_modifier.cc b/source/blender/blenkernel/intern/subdiv_modifier.cc
index a5529e9b8fa..84b772db045 100644
--- a/source/blender/blenkernel/intern/subdiv_modifier.cc
+++ b/source/blender/blenkernel/intern/subdiv_modifier.cc
@@ -11,6 +11,7 @@
#include "DNA_scene_types.h"
#include "DNA_userdef_types.h"
+#include "BKE_mesh.h"
#include "BKE_modifier.h"
#include "BKE_subdiv.h"
@@ -143,7 +144,7 @@ bool BKE_subsurf_modifier_can_do_gpu_subdiv(const Scene *scene,
bool BKE_subsurf_modifier_has_gpu_subdiv(const Mesh *mesh)
{
- SubsurfRuntimeData *runtime_data = mesh->runtime.subsurf_runtime_data;
+ SubsurfRuntimeData *runtime_data = mesh->runtime->subsurf_runtime_data;
return runtime_data && runtime_data->has_gpu_subdiv;
}
diff --git a/source/blender/blenloader/intern/blend_validate.cc b/source/blender/blenloader/intern/blend_validate.cc
index 0f43b20c391..7ac0a4fe1af 100644
--- a/source/blender/blenloader/intern/blend_validate.cc
+++ b/source/blender/blenloader/intern/blend_validate.cc
@@ -61,7 +61,7 @@ bool BLO_main_validate_libraries(Main *bmain, ReportList *reports)
for (Main *curmain = bmain->next; curmain != nullptr; curmain = curmain->next) {
Library *curlib = curmain->curlib;
if (curlib == nullptr) {
- BKE_report(reports, RPT_ERROR, "Library database with nullptr library data-block!");
+ BKE_report(reports, RPT_ERROR, "Library database with null library data-block pointer!");
continue;
}
@@ -103,7 +103,7 @@ bool BLO_main_validate_libraries(Main *bmain, ReportList *reports)
is_valid = false;
BKE_reportf(reports,
RPT_ERROR,
- "ID %s has nullptr lib pointer while being in library %s!",
+ "ID %s has null lib pointer while being in library %s!",
id->name,
curlib->filepath);
continue;
diff --git a/source/blender/blenloader/intern/versioning_250.c b/source/blender/blenloader/intern/versioning_250.c
index 9e5ef41892a..3a39ed04d2a 100644
--- a/source/blender/blenloader/intern/versioning_250.c
+++ b/source/blender/blenloader/intern/versioning_250.c
@@ -2316,7 +2316,6 @@ static void lib_node_do_versions_group_indices(bNode *gnode)
/* deprecated */
sock->own_index = link->fromsock->own_index;
sock->to_index = 0;
- sock->groupsock = NULL;
}
}
}
@@ -2329,7 +2328,6 @@ static void lib_node_do_versions_group_indices(bNode *gnode)
/* deprecated */
sock->own_index = link->tosock->own_index;
sock->to_index = 0;
- sock->groupsock = NULL;
}
}
}
diff --git a/source/blender/blenloader/intern/versioning_280.c b/source/blender/blenloader/intern/versioning_280.c
index 061840aee7a..1a8fec49516 100644
--- a/source/blender/blenloader/intern/versioning_280.c
+++ b/source/blender/blenloader/intern/versioning_280.c
@@ -3379,7 +3379,7 @@ void blo_do_versions_280(FileData *fd, Library *UNUSED(lib), Main *bmain)
SpaceImage *sima = (SpaceImage *)sl;
sima->flag &= ~(SI_FLAG_UNUSED_0 | SI_FLAG_UNUSED_1 | SI_FLAG_UNUSED_3 |
SI_FLAG_UNUSED_6 | SI_FLAG_UNUSED_7 | SI_FLAG_UNUSED_8 |
- SI_FLAG_UNUSED_17 | SI_CUSTOM_GRID | SI_FLAG_UNUSED_23 |
+ SI_FLAG_UNUSED_17 | SI_FLAG_UNUSED_18 | SI_FLAG_UNUSED_23 |
SI_FLAG_UNUSED_24);
break;
}
diff --git a/source/blender/blenloader/intern/versioning_300.cc b/source/blender/blenloader/intern/versioning_300.cc
index 0584dd6b059..5328107e1f2 100644
--- a/source/blender/blenloader/intern/versioning_300.cc
+++ b/source/blender/blenloader/intern/versioning_300.cc
@@ -3604,6 +3604,13 @@ void blo_do_versions_300(FileData *fd, Library * /*lib*/, Main *bmain)
v3d->overlay.flag |= V3D_OVERLAY_VIEWER_ATTRIBUTE;
v3d->overlay.viewer_attribute_opacity = 1.0f;
}
+ if (sl->spacetype == SPACE_IMAGE) {
+ SpaceImage *sima = (SpaceImage *)sl;
+ if (sima->flag & SI_FLAG_UNUSED_18) { /* Was #SI_CUSTOM_GRID. */
+ sima->grid_shape_source = SI_GRID_SHAPE_FIXED;
+ sima->flag &= ~SI_FLAG_UNUSED_18;
+ }
+ }
}
}
}
diff --git a/source/blender/bmesh/CMakeLists.txt b/source/blender/bmesh/CMakeLists.txt
index 0efa5f73ae4..77223ecd1c7 100644
--- a/source/blender/bmesh/CMakeLists.txt
+++ b/source/blender/bmesh/CMakeLists.txt
@@ -207,6 +207,22 @@ if(WITH_GMP)
)
endif()
+if(WITH_TBB)
+ add_definitions(-DWITH_TBB)
+ if(WIN32)
+ # TBB includes Windows.h which will define min/max macros
+ # that will collide with the stl versions.
+ add_definitions(-DNOMINMAX)
+ endif()
+ list(APPEND INC_SYS
+ ${TBB_INCLUDE_DIRS}
+ )
+
+ list(APPEND LIB
+ ${TBB_LIBRARIES}
+ )
+endif()
+
blender_add_lib(bf_bmesh "${SRC}" "${INC}" "${INC_SYS}" "${LIB}")
if(MSVC AND NOT MSVC_CLANG)
diff --git a/source/blender/bmesh/intern/bmesh_construct.c b/source/blender/bmesh/intern/bmesh_construct.c
index 3ee9fa7aee4..8125130490a 100644
--- a/source/blender/bmesh/intern/bmesh_construct.c
+++ b/source/blender/bmesh/intern/bmesh_construct.c
@@ -507,26 +507,32 @@ void BM_mesh_copy_init_customdata_from_mesh_array(BMesh *bm_dst,
for (int i = 0; i < me_src_array_len; i++) {
const Mesh *me_src = me_src_array[i];
+ CustomData mesh_vdata = CustomData_shallow_copy_remove_non_bmesh_attributes(
+ &me_src->vdata, CD_MASK_BMESH.vmask);
+ CustomData mesh_edata = CustomData_shallow_copy_remove_non_bmesh_attributes(
+ &me_src->edata, CD_MASK_BMESH.emask);
+ CustomData mesh_pdata = CustomData_shallow_copy_remove_non_bmesh_attributes(
+ &me_src->pdata, CD_MASK_BMESH.lmask);
+ CustomData mesh_ldata = CustomData_shallow_copy_remove_non_bmesh_attributes(
+ &me_src->ldata, CD_MASK_BMESH.pmask);
+
if (i == 0) {
- CustomData_copy_mesh_to_bmesh(
- &me_src->vdata, &bm_dst->vdata, CD_MASK_BMESH.vmask, CD_SET_DEFAULT, 0);
- CustomData_copy_mesh_to_bmesh(
- &me_src->edata, &bm_dst->edata, CD_MASK_BMESH.emask, CD_SET_DEFAULT, 0);
- CustomData_copy_mesh_to_bmesh(
- &me_src->ldata, &bm_dst->ldata, CD_MASK_BMESH.lmask, CD_SET_DEFAULT, 0);
- CustomData_copy_mesh_to_bmesh(
- &me_src->pdata, &bm_dst->pdata, CD_MASK_BMESH.pmask, CD_SET_DEFAULT, 0);
+ CustomData_copy(&mesh_vdata, &bm_dst->vdata, CD_MASK_BMESH.vmask, CD_SET_DEFAULT, 0);
+ CustomData_copy(&mesh_edata, &bm_dst->edata, CD_MASK_BMESH.emask, CD_SET_DEFAULT, 0);
+ CustomData_copy(&mesh_pdata, &bm_dst->pdata, CD_MASK_BMESH.pmask, CD_SET_DEFAULT, 0);
+ CustomData_copy(&mesh_ldata, &bm_dst->ldata, CD_MASK_BMESH.lmask, CD_SET_DEFAULT, 0);
}
else {
- CustomData_merge_mesh_to_bmesh(
- &me_src->vdata, &bm_dst->vdata, CD_MASK_BMESH.vmask, CD_SET_DEFAULT, 0);
- CustomData_merge_mesh_to_bmesh(
- &me_src->edata, &bm_dst->edata, CD_MASK_BMESH.emask, CD_SET_DEFAULT, 0);
- CustomData_merge_mesh_to_bmesh(
- &me_src->ldata, &bm_dst->ldata, CD_MASK_BMESH.lmask, CD_SET_DEFAULT, 0);
- CustomData_merge_mesh_to_bmesh(
- &me_src->pdata, &bm_dst->pdata, CD_MASK_BMESH.pmask, CD_SET_DEFAULT, 0);
+ CustomData_merge(&mesh_vdata, &bm_dst->vdata, CD_MASK_BMESH.vmask, CD_SET_DEFAULT, 0);
+ CustomData_merge(&mesh_edata, &bm_dst->edata, CD_MASK_BMESH.emask, CD_SET_DEFAULT, 0);
+ CustomData_merge(&mesh_pdata, &bm_dst->pdata, CD_MASK_BMESH.pmask, CD_SET_DEFAULT, 0);
+ CustomData_merge(&mesh_ldata, &bm_dst->ldata, CD_MASK_BMESH.lmask, CD_SET_DEFAULT, 0);
}
+
+ MEM_SAFE_FREE(mesh_vdata.layers);
+ MEM_SAFE_FREE(mesh_edata.layers);
+ MEM_SAFE_FREE(mesh_pdata.layers);
+ MEM_SAFE_FREE(mesh_ldata.layers);
}
CustomData_bmesh_init_pool(&bm_dst->vdata, allocsize->totvert, BM_VERT);
diff --git a/source/blender/bmesh/intern/bmesh_mesh_convert.cc b/source/blender/bmesh/intern/bmesh_mesh_convert.cc
index dfbdd64ee7c..d65cac08db8 100644
--- a/source/blender/bmesh/intern/bmesh_mesh_convert.cc
+++ b/source/blender/bmesh/intern/bmesh_mesh_convert.cc
@@ -129,6 +129,10 @@ static BMFace *bm_face_create_from_mpoly(BMesh &bm,
void BM_mesh_bm_from_me(BMesh *bm, const Mesh *me, const struct BMeshFromMeshParams *params)
{
+ if (!me) {
+ /* Sanity check. */
+ return;
+ }
const bool is_new = !(bm->totvert || (bm->vdata.totlayer || bm->edata.totlayer ||
bm->pdata.totlayer || bm->ldata.totlayer));
KeyBlock *actkey;
@@ -136,19 +140,35 @@ void BM_mesh_bm_from_me(BMesh *bm, const Mesh *me, const struct BMeshFromMeshPar
CustomData_MeshMasks mask = CD_MASK_BMESH;
CustomData_MeshMasks_update(&mask, &params->cd_mask_extra);
- if (!me || !me->totvert) {
- if (me && is_new) { /* No verts? still copy custom-data layout. */
- CustomData_copy_mesh_to_bmesh(&me->vdata, &bm->vdata, mask.vmask, CD_CONSTRUCT, 0);
- CustomData_copy_mesh_to_bmesh(&me->edata, &bm->edata, mask.emask, CD_CONSTRUCT, 0);
- CustomData_copy_mesh_to_bmesh(&me->ldata, &bm->ldata, mask.lmask, CD_CONSTRUCT, 0);
- CustomData_copy_mesh_to_bmesh(&me->pdata, &bm->pdata, mask.pmask, CD_CONSTRUCT, 0);
+ CustomData mesh_vdata = CustomData_shallow_copy_remove_non_bmesh_attributes(&me->vdata,
+ mask.vmask);
+ CustomData mesh_edata = CustomData_shallow_copy_remove_non_bmesh_attributes(&me->edata,
+ mask.emask);
+ CustomData mesh_pdata = CustomData_shallow_copy_remove_non_bmesh_attributes(&me->pdata,
+ mask.pmask);
+ CustomData mesh_ldata = CustomData_shallow_copy_remove_non_bmesh_attributes(&me->ldata,
+ mask.lmask);
+ BLI_SCOPED_DEFER([&]() {
+ MEM_SAFE_FREE(mesh_vdata.layers);
+ MEM_SAFE_FREE(mesh_edata.layers);
+ MEM_SAFE_FREE(mesh_pdata.layers);
+ MEM_SAFE_FREE(mesh_ldata.layers);
+ });
+
+ if (me->totvert == 0) {
+ if (is_new) {
+ /* No verts? still copy custom-data layout. */
+ CustomData_copy(&mesh_vdata, &bm->vdata, mask.vmask, CD_CONSTRUCT, 0);
+ CustomData_copy(&mesh_edata, &bm->edata, mask.emask, CD_CONSTRUCT, 0);
+ CustomData_copy(&mesh_pdata, &bm->pdata, mask.pmask, CD_CONSTRUCT, 0);
+ CustomData_copy(&mesh_ldata, &bm->ldata, mask.lmask, CD_CONSTRUCT, 0);
CustomData_bmesh_init_pool(&bm->vdata, me->totvert, BM_VERT);
CustomData_bmesh_init_pool(&bm->edata, me->totedge, BM_EDGE);
CustomData_bmesh_init_pool(&bm->ldata, me->totloop, BM_LOOP);
CustomData_bmesh_init_pool(&bm->pdata, me->totpoly, BM_FACE);
}
- return; /* Sanity check. */
+ return;
}
const float(*vert_normals)[3] = nullptr;
@@ -157,16 +177,16 @@ void BM_mesh_bm_from_me(BMesh *bm, const Mesh *me, const struct BMeshFromMeshPar
}
if (is_new) {
- CustomData_copy_mesh_to_bmesh(&me->vdata, &bm->vdata, mask.vmask, CD_SET_DEFAULT, 0);
- CustomData_copy_mesh_to_bmesh(&me->edata, &bm->edata, mask.emask, CD_SET_DEFAULT, 0);
- CustomData_copy_mesh_to_bmesh(&me->ldata, &bm->ldata, mask.lmask, CD_SET_DEFAULT, 0);
- CustomData_copy_mesh_to_bmesh(&me->pdata, &bm->pdata, mask.pmask, CD_SET_DEFAULT, 0);
+ CustomData_copy(&mesh_vdata, &bm->vdata, mask.vmask, CD_SET_DEFAULT, 0);
+ CustomData_copy(&mesh_edata, &bm->edata, mask.emask, CD_SET_DEFAULT, 0);
+ CustomData_copy(&mesh_pdata, &bm->pdata, mask.pmask, CD_SET_DEFAULT, 0);
+ CustomData_copy(&mesh_ldata, &bm->ldata, mask.lmask, CD_SET_DEFAULT, 0);
}
else {
- CustomData_bmesh_merge(&me->vdata, &bm->vdata, mask.vmask, CD_SET_DEFAULT, bm, BM_VERT);
- CustomData_bmesh_merge(&me->edata, &bm->edata, mask.emask, CD_SET_DEFAULT, bm, BM_EDGE);
- CustomData_bmesh_merge(&me->ldata, &bm->ldata, mask.lmask, CD_SET_DEFAULT, bm, BM_LOOP);
- CustomData_bmesh_merge(&me->pdata, &bm->pdata, mask.pmask, CD_SET_DEFAULT, bm, BM_FACE);
+ CustomData_bmesh_merge(&mesh_vdata, &bm->vdata, mask.vmask, CD_SET_DEFAULT, bm, BM_VERT);
+ CustomData_bmesh_merge(&mesh_edata, &bm->edata, mask.emask, CD_SET_DEFAULT, bm, BM_EDGE);
+ CustomData_bmesh_merge(&mesh_pdata, &bm->pdata, mask.pmask, CD_SET_DEFAULT, bm, BM_FACE);
+ CustomData_bmesh_merge(&mesh_ldata, &bm->ldata, mask.lmask, CD_SET_DEFAULT, bm, BM_LOOP);
}
/* -------------------------------------------------------------------- */
@@ -302,7 +322,7 @@ void BM_mesh_bm_from_me(BMesh *bm, const Mesh *me, const struct BMeshFromMeshPar
}
/* Copy Custom Data */
- CustomData_to_bmesh_block(&me->vdata, &bm->vdata, i, &v->head.data, true);
+ CustomData_to_bmesh_block(&mesh_vdata, &bm->vdata, i, &v->head.data, true);
/* Set shape key original index. */
if (cd_shape_keyindex_offset != -1) {
@@ -338,7 +358,7 @@ void BM_mesh_bm_from_me(BMesh *bm, const Mesh *me, const struct BMeshFromMeshPar
}
/* Copy Custom Data */
- CustomData_to_bmesh_block(&me->edata, &bm->edata, i, &e->head.data, true);
+ CustomData_to_bmesh_block(&mesh_edata, &bm->edata, i, &e->head.data, true);
}
if (is_new) {
bm->elem_index_dirty &= ~BM_EDGE; /* Added in order, clear dirty flag. */
@@ -397,11 +417,11 @@ void BM_mesh_bm_from_me(BMesh *bm, const Mesh *me, const struct BMeshFromMeshPar
BM_elem_index_set(l_iter, totloops++); /* set_ok */
/* Save index of corresponding #MLoop. */
- CustomData_to_bmesh_block(&me->ldata, &bm->ldata, j++, &l_iter->head.data, true);
+ CustomData_to_bmesh_block(&mesh_ldata, &bm->ldata, j++, &l_iter->head.data, true);
} while ((l_iter = l_iter->next) != l_first);
/* Copy Custom Data */
- CustomData_to_bmesh_block(&me->pdata, &bm->pdata, i, &f->head.data, true);
+ CustomData_to_bmesh_block(&mesh_pdata, &bm->pdata, i, &f->head.data, true);
if (params->calc_face_normal) {
BM_face_normal_update(f);
@@ -951,10 +971,10 @@ void BM_mesh_bm_to_me(Main *bmain, BMesh *bm, Mesh *me, const struct BMeshToMesh
{
CustomData_MeshMasks mask = CD_MASK_MESH;
CustomData_MeshMasks_update(&mask, &params->cd_mask_extra);
- CustomData_copy_mesh_to_bmesh(&bm->vdata, &me->vdata, mask.vmask, CD_SET_DEFAULT, me->totvert);
- CustomData_copy_mesh_to_bmesh(&bm->edata, &me->edata, mask.emask, CD_SET_DEFAULT, me->totedge);
- CustomData_copy_mesh_to_bmesh(&bm->ldata, &me->ldata, mask.lmask, CD_SET_DEFAULT, me->totloop);
- CustomData_copy_mesh_to_bmesh(&bm->pdata, &me->pdata, mask.pmask, CD_SET_DEFAULT, me->totpoly);
+ CustomData_copy(&bm->vdata, &me->vdata, mask.vmask, CD_SET_DEFAULT, me->totvert);
+ CustomData_copy(&bm->edata, &me->edata, mask.emask, CD_SET_DEFAULT, me->totedge);
+ CustomData_copy(&bm->ldata, &me->ldata, mask.lmask, CD_SET_DEFAULT, me->totloop);
+ CustomData_copy(&bm->pdata, &me->pdata, mask.pmask, CD_SET_DEFAULT, me->totpoly);
}
CustomData_add_layer(&me->vdata, CD_MVERT, CD_SET_DEFAULT, nullptr, me->totvert);
@@ -1238,7 +1258,7 @@ void BM_mesh_bm_to_me_for_eval(BMesh *bm, Mesh *me, const CustomData_MeshMasks *
* different than the BMesh's. */
BKE_mesh_clear_derived_normals(me);
- me->runtime.deformed_only = true;
+ me->runtime->deformed_only = true;
bke::MutableAttributeAccessor mesh_attributes = me->attributes_for_write();
diff --git a/source/blender/bmesh/operators/bmo_normals.c b/source/blender/bmesh/operators/bmo_normals.c
index 04eaa43c899..0d321e1de8d 100644
--- a/source/blender/bmesh/operators/bmo_normals.c
+++ b/source/blender/bmesh/operators/bmo_normals.c
@@ -3,7 +3,7 @@
/** \file
* \ingroup bmesh
*
- * normal recalculation.
+ * Functionality for flipping faces to make normals consistent.
*/
#include "MEM_guardedalloc.h"
@@ -47,7 +47,7 @@ static bool bmo_recalc_normal_loop_filter_cb(const BMLoop *l, void *UNUSED(user_
* +------------+
* </pre>
*
- * In the example above, the a\ face can point towards the \a center
+ * In the example above, the \a face can point towards the \a center
* which would end up flipping the normals inwards.
*
* To take these spikes into account, find the furthest face-loop-vertex.
diff --git a/source/blender/compositor/nodes/COM_CryptomatteNode.cc b/source/blender/compositor/nodes/COM_CryptomatteNode.cc
index 751ac0003bf..ee31fce0ea8 100644
--- a/source/blender/compositor/nodes/COM_CryptomatteNode.cc
+++ b/source/blender/compositor/nodes/COM_CryptomatteNode.cc
@@ -10,6 +10,7 @@
#include "COM_MultilayerImageOperation.h"
#include "COM_RenderLayersProg.h"
#include "COM_SetAlphaMultiplyOperation.h"
+#include "COM_SetAlphaReplaceOperation.h"
#include "COM_SetColorOperation.h"
namespace blender::compositor {
@@ -48,7 +49,7 @@ void CryptomatteBaseNode::convert_to_operations(NodeConverter &converter,
converter.map_output_socket(output_image_socket, apply_mask_operation->get_output_socket(0));
NodeOutput *output_pick_socket = this->get_output_socket(2);
- SetAlphaMultiplyOperation *extract_pick_operation = new SetAlphaMultiplyOperation();
+ SetAlphaReplaceOperation *extract_pick_operation = new SetAlphaReplaceOperation();
converter.add_operation(extract_pick_operation);
converter.add_input_value(extract_pick_operation->get_input_socket(1), 1.0f);
converter.add_link(cryptomatte_operation->get_output_socket(0),
diff --git a/source/blender/compositor/realtime_compositor/CMakeLists.txt b/source/blender/compositor/realtime_compositor/CMakeLists.txt
index 1f1333332f5..90cbe0988ad 100644
--- a/source/blender/compositor/realtime_compositor/CMakeLists.txt
+++ b/source/blender/compositor/realtime_compositor/CMakeLists.txt
@@ -2,6 +2,7 @@
set(INC
.
+ ./algorithms
../../blenkernel
../../blenlib
../../gpu
@@ -53,6 +54,10 @@ set(SRC
COM_static_shader_manager.hh
COM_texture_pool.hh
COM_utilities.hh
+
+ algorithms/intern/algorithm_parallel_reduction.cc
+
+ algorithms/COM_algorithm_parallel_reduction.hh
)
set(LIB
diff --git a/source/blender/compositor/realtime_compositor/COM_domain.hh b/source/blender/compositor/realtime_compositor/COM_domain.hh
index 54d712f7578..99b40ae61cf 100644
--- a/source/blender/compositor/realtime_compositor/COM_domain.hh
+++ b/source/blender/compositor/realtime_compositor/COM_domain.hh
@@ -28,7 +28,7 @@ struct RealizationOptions {
* result involves projecting it on a different domain, which in turn, involves sampling the
* result at arbitrary locations, the interpolation identifies the method used for computing the
* value at those arbitrary locations. */
- Interpolation interpolation = Interpolation::Nearest;
+ Interpolation interpolation = Interpolation::Bilinear;
/* If true, the result will be repeated infinitely along the horizontal axis when realizing the
* result. If false, regions outside of bounds of the result along the horizontal axis will be
* filled with zeros. */
diff --git a/source/blender/compositor/realtime_compositor/algorithms/COM_algorithm_parallel_reduction.hh b/source/blender/compositor/realtime_compositor/algorithms/COM_algorithm_parallel_reduction.hh
new file mode 100644
index 00000000000..9d0851eff84
--- /dev/null
+++ b/source/blender/compositor/realtime_compositor/algorithms/COM_algorithm_parallel_reduction.hh
@@ -0,0 +1,58 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+
+#pragma once
+
+#include "BLI_math_vec_types.hh"
+
+#include "GPU_texture.h"
+
+#include "COM_context.hh"
+
+namespace blender::realtime_compositor {
+
+/* --------------------------------------------------------------------
+ * Sum Reductions.
+ */
+
+/* Computes the sum of the red channel of all pixels in the given texture. */
+float sum_red(Context &context, GPUTexture *texture);
+
+/* Computes the sum of the green channel of all pixels in the given texture. */
+float sum_green(Context &context, GPUTexture *texture);
+
+/* Computes the sum of the blue channel of all pixels in the given texture. */
+float sum_blue(Context &context, GPUTexture *texture);
+
+/* Computes the sum of the luminance of all pixels in the given texture, using the given luminance
+ * coefficients to compute the luminance. */
+float sum_luminance(Context &context, GPUTexture *texture, float3 luminance_coefficients);
+
+/* --------------------------------------------------------------------
+ * Sum Of Squared Difference Reductions.
+ */
+
+/* Computes the sum of the squared difference between the red channel of all pixels in the given
+ * texture and the given subtrahend. This can be used to compute the standard deviation if the
+ * given subtrahend is the mean. */
+float sum_red_squared_difference(Context &context, GPUTexture *texture, float subtrahend);
+
+/* Computes the sum of the squared difference between the green channel of all pixels in the given
+ * texture and the given subtrahend. This can be used to compute the standard deviation if the
+ * given subtrahend is the mean. */
+float sum_green_squared_difference(Context &context, GPUTexture *texture, float subtrahend);
+
+/* Computes the sum of the squared difference between the blue channel of all pixels in the given
+ * texture and the given subtrahend. This can be used to compute the standard deviation if the
+ * given subtrahend is the mean. */
+float sum_blue_squared_difference(Context &context, GPUTexture *texture, float subtrahend);
+
+/* Computes the sum of the squared difference between the luminance of all pixels in the given
+ * texture and the given subtrahend, using the given luminance coefficients to compute the
+ * luminance. This can be used to compute the standard deviation if the given subtrahend is the
+ * mean. */
+float sum_luminance_squared_difference(Context &context,
+ GPUTexture *texture,
+ float3 luminance_coefficients,
+ float subtrahend);
+
+} // namespace blender::realtime_compositor
diff --git a/source/blender/compositor/realtime_compositor/algorithms/intern/algorithm_parallel_reduction.cc b/source/blender/compositor/realtime_compositor/algorithms/intern/algorithm_parallel_reduction.cc
new file mode 100644
index 00000000000..3266ccd14eb
--- /dev/null
+++ b/source/blender/compositor/realtime_compositor/algorithms/intern/algorithm_parallel_reduction.cc
@@ -0,0 +1,205 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+
+#include "BLI_math_vec_types.hh"
+#include "BLI_math_vector.hh"
+
+#include "MEM_guardedalloc.h"
+
+#include "GPU_compute.h"
+#include "GPU_shader.h"
+#include "GPU_texture.h"
+
+#include "COM_context.hh"
+#include "COM_utilities.hh"
+
+#include "COM_algorithm_parallel_reduction.hh"
+
+namespace blender::realtime_compositor {
+
+/* Reduces the given texture into a single value and returns it. The return value should be freed
+ * by a call to MEM_freeN. The return value is either a pointer to a float, or a pointer to an
+ * array of floats that represents a vector. This depends on the given format, which should be
+ * compatible with the reduction shader.
+ *
+ * The given reduction shader should be bound when calling the function and the shader is expected
+ * to be derived from the compositor_parallel_reduction.glsl shader, see that file for more
+ * information. Also see the compositor_parallel_reduction_info.hh file for example shader
+ * definitions. */
+static float *parallel_reduction_dispatch(Context &context,
+ GPUTexture *texture,
+ GPUShader *shader,
+ eGPUTextureFormat format)
+{
+ GPU_shader_uniform_1b(shader, "is_initial_reduction", true);
+
+ GPUTexture *texture_to_reduce = texture;
+ int2 size_to_reduce = int2(GPU_texture_width(texture), GPU_texture_height(texture));
+
+ /* Dispatch the reduction shader until the texture reduces to a single pixel. */
+ while (size_to_reduce != int2(1)) {
+ const int2 reduced_size = math::divide_ceil(size_to_reduce, int2(16));
+ GPUTexture *reduced_texture = context.texture_pool().acquire(reduced_size, format);
+
+ GPU_memory_barrier(GPU_BARRIER_TEXTURE_FETCH);
+ const int texture_image_unit = GPU_shader_get_texture_binding(shader, "input_tx");
+ GPU_texture_bind(texture_to_reduce, texture_image_unit);
+
+ const int image_unit = GPU_shader_get_texture_binding(shader, "output_img");
+ GPU_texture_image_bind(reduced_texture, image_unit);
+
+ GPU_compute_dispatch(shader, reduced_size.x, reduced_size.y, 1);
+
+ GPU_texture_image_unbind(reduced_texture);
+ GPU_texture_unbind(texture_to_reduce);
+
+ /* Release the input texture only if it is not the source texture, since the source texture is
+ * not acquired or owned by the function. */
+ if (texture_to_reduce != texture) {
+ context.texture_pool().release(texture_to_reduce);
+ }
+
+ texture_to_reduce = reduced_texture;
+ size_to_reduce = reduced_size;
+
+ GPU_shader_uniform_1b(shader, "is_initial_reduction", false);
+ }
+
+ GPU_memory_barrier(GPU_BARRIER_TEXTURE_UPDATE);
+ float *pixel = static_cast<float *>(GPU_texture_read(texture_to_reduce, GPU_DATA_FLOAT, 0));
+
+ /* Release the final texture only if it is not the source texture, since the source texture is
+ * not acquired or owned by the function. */
+ if (texture_to_reduce != texture) {
+ context.texture_pool().release(texture_to_reduce);
+ }
+
+ return pixel;
+}
+
+/* --------------------------------------------------------------------
+ * Sum Reductions.
+ */
+
+float sum_red(Context &context, GPUTexture *texture)
+{
+ GPUShader *shader = context.shader_manager().get("compositor_sum_red");
+ GPU_shader_bind(shader);
+
+ float *reduced_value = parallel_reduction_dispatch(context, texture, shader, GPU_R32F);
+ const float sum = *reduced_value;
+ MEM_freeN(reduced_value);
+ GPU_shader_unbind();
+
+ return sum;
+}
+
+float sum_green(Context &context, GPUTexture *texture)
+{
+ GPUShader *shader = context.shader_manager().get("compositor_sum_green");
+ GPU_shader_bind(shader);
+
+ float *reduced_value = parallel_reduction_dispatch(context, texture, shader, GPU_R32F);
+ const float sum = *reduced_value;
+ MEM_freeN(reduced_value);
+ GPU_shader_unbind();
+
+ return sum;
+}
+
+float sum_blue(Context &context, GPUTexture *texture)
+{
+ GPUShader *shader = context.shader_manager().get("compositor_sum_blue");
+ GPU_shader_bind(shader);
+
+ float *reduced_value = parallel_reduction_dispatch(context, texture, shader, GPU_R32F);
+ const float sum = *reduced_value;
+ MEM_freeN(reduced_value);
+ GPU_shader_unbind();
+
+ return sum;
+}
+
+float sum_luminance(Context &context, GPUTexture *texture, float3 luminance_coefficients)
+{
+ GPUShader *shader = context.shader_manager().get("compositor_sum_luminance");
+ GPU_shader_bind(shader);
+
+ GPU_shader_uniform_3fv(shader, "luminance_coefficients", luminance_coefficients);
+
+ float *reduced_value = parallel_reduction_dispatch(context, texture, shader, GPU_R32F);
+ const float sum = *reduced_value;
+ MEM_freeN(reduced_value);
+ GPU_shader_unbind();
+
+ return sum;
+}
+
+/* --------------------------------------------------------------------
+ * Sum Of Squared Difference Reductions.
+ */
+
+float sum_red_squared_difference(Context &context, GPUTexture *texture, float subtrahend)
+{
+ GPUShader *shader = context.shader_manager().get("compositor_sum_red_squared_difference");
+ GPU_shader_bind(shader);
+
+ GPU_shader_uniform_1f(shader, "subtrahend", subtrahend);
+
+ float *reduced_value = parallel_reduction_dispatch(context, texture, shader, GPU_R32F);
+ const float sum = *reduced_value;
+ MEM_freeN(reduced_value);
+ GPU_shader_unbind();
+
+ return sum;
+}
+
+float sum_green_squared_difference(Context &context, GPUTexture *texture, float subtrahend)
+{
+ GPUShader *shader = context.shader_manager().get("compositor_sum_green_squared_difference");
+ GPU_shader_bind(shader);
+
+ GPU_shader_uniform_1f(shader, "subtrahend", subtrahend);
+
+ float *reduced_value = parallel_reduction_dispatch(context, texture, shader, GPU_R32F);
+ const float sum = *reduced_value;
+ MEM_freeN(reduced_value);
+ GPU_shader_unbind();
+
+ return sum;
+}
+
+float sum_blue_squared_difference(Context &context, GPUTexture *texture, float subtrahend)
+{
+ GPUShader *shader = context.shader_manager().get("compositor_sum_blue_squared_difference");
+ GPU_shader_bind(shader);
+
+ GPU_shader_uniform_1f(shader, "subtrahend", subtrahend);
+
+ float *reduced_value = parallel_reduction_dispatch(context, texture, shader, GPU_R32F);
+ const float sum = *reduced_value;
+ MEM_freeN(reduced_value);
+ GPU_shader_unbind();
+
+ return sum;
+}
+
+float sum_luminance_squared_difference(Context &context,
+ GPUTexture *texture,
+ float3 luminance_coefficients,
+ float subtrahend)
+{
+ GPUShader *shader = context.shader_manager().get("compositor_sum_luminance_squared_difference");
+ GPU_shader_bind(shader);
+
+ GPU_shader_uniform_3fv(shader, "luminance_coefficients", luminance_coefficients);
+ GPU_shader_uniform_1f(shader, "subtrahend", subtrahend);
+
+ float *reduced_value = parallel_reduction_dispatch(context, texture, shader, GPU_R32F);
+ const float sum = *reduced_value;
+ MEM_freeN(reduced_value);
+ GPU_shader_unbind();
+
+ return sum;
+}
+
+} // namespace blender::realtime_compositor
diff --git a/source/blender/draw/CMakeLists.txt b/source/blender/draw/CMakeLists.txt
index d82ae4cd32c..a645bd6b6af 100644
--- a/source/blender/draw/CMakeLists.txt
+++ b/source/blender/draw/CMakeLists.txt
@@ -77,7 +77,7 @@ set(SRC
intern/draw_cache_impl_particles.c
intern/draw_cache_impl_pointcloud.cc
intern/draw_cache_impl_subdivision.cc
- intern/draw_cache_impl_volume.c
+ intern/draw_cache_impl_volume.cc
intern/draw_color_management.cc
intern/draw_command.cc
intern/draw_common.c
@@ -731,6 +731,21 @@ if(WITH_GTESTS)
endif()
endif()
+if(WITH_TBB)
+ add_definitions(-DWITH_TBB)
+ if(WIN32)
+ # TBB includes Windows.h which will define min/max macros
+ # that will collide with the stl versions.
+ add_definitions(-DNOMINMAX)
+ endif()
+ list(APPEND INC_SYS
+ ${TBB_INCLUDE_DIRS}
+ )
+
+ list(APPEND LIB
+ ${TBB_LIBRARIES}
+ )
+endif()
blender_add_lib(bf_draw "${SRC}" "${INC}" "${INC_SYS}" "${LIB}")
@@ -756,3 +771,4 @@ if(WITH_GTESTS)
blender_add_test_lib(bf_draw_tests "${TEST_SRC}" "${INC};${TEST_INC}" "${INC_SYS}" "${LIB};${TEST_LIB}")
endif()
endif()
+
diff --git a/source/blender/draw/engines/eevee/eevee_materials.c b/source/blender/draw/engines/eevee/eevee_materials.c
index 96f62d942d7..c454a58ffe9 100644
--- a/source/blender/draw/engines/eevee/eevee_materials.c
+++ b/source/blender/draw/engines/eevee/eevee_materials.c
@@ -813,6 +813,10 @@ void EEVEE_materials_cache_populate(EEVEE_Data *vedata,
bool use_sculpt_pbvh = BKE_sculptsession_use_pbvh_draw(ob, draw_ctx->v3d) &&
!DRW_state_is_image_render();
+ if (ob->sculpt && ob->sculpt->pbvh) {
+ BKE_pbvh_is_drawing_set(ob->sculpt->pbvh, use_sculpt_pbvh);
+ }
+
/* First get materials for this mesh. */
if (ELEM(ob->type, OB_MESH, OB_SURF)) {
const int materials_len = DRW_cache_object_material_count_get(ob);
diff --git a/source/blender/draw/engines/eevee_next/eevee_camera.hh b/source/blender/draw/engines/eevee_next/eevee_camera.hh
index aaef0f5898d..c1d65dbf31e 100644
--- a/source/blender/draw/engines/eevee_next/eevee_camera.hh
+++ b/source/blender/draw/engines/eevee_next/eevee_camera.hh
@@ -13,7 +13,7 @@ namespace blender::eevee {
class Instance;
-static const float cubeface_mat[6][4][4] = {
+inline constexpr float cubeface_mat[6][4][4] = {
/* Pos X */
{{0.0f, 0.0f, -1.0f, 0.0f},
{0.0f, -1.0f, 0.0f, 0.0f},
diff --git a/source/blender/draw/engines/eevee_next/eevee_instance.cc b/source/blender/draw/engines/eevee_next/eevee_instance.cc
index 8005b27c30e..a0bdf70e254 100644
--- a/source/blender/draw/engines/eevee_next/eevee_instance.cc
+++ b/source/blender/draw/engines/eevee_next/eevee_instance.cc
@@ -106,6 +106,8 @@ void Instance::begin_sync()
gpencil_engine_enabled = false;
+ scene_sync();
+
depth_of_field.sync();
motion_blur.sync();
hiz_buffer.sync();
@@ -115,6 +117,21 @@ void Instance::begin_sync()
film.sync();
}
+void Instance::scene_sync()
+{
+ SceneHandle &sc_handle = sync.sync_scene(scene);
+
+ sc_handle.reset_recalc_flag();
+
+ /* This refers specifically to the Scene camera that can be accessed
+ * via View Layer Attribute nodes, rather than the actual render camera. */
+ if (scene->camera != nullptr) {
+ ObjectHandle &ob_handle = sync.sync_object(scene->camera);
+
+ ob_handle.reset_recalc_flag();
+ }
+}
+
void Instance::object_sync(Object *ob)
{
const bool is_renderable_type = ELEM(ob->type, OB_CURVES, OB_GPENCIL, OB_MESH, OB_LAMP);
diff --git a/source/blender/draw/engines/eevee_next/eevee_instance.hh b/source/blender/draw/engines/eevee_next/eevee_instance.hh
index c8eecbd812d..bc610cd0642 100644
--- a/source/blender/draw/engines/eevee_next/eevee_instance.hh
+++ b/source/blender/draw/engines/eevee_next/eevee_instance.hh
@@ -162,6 +162,7 @@ class Instance {
void render_sample();
void render_read_result(RenderLayer *render_layer, const char *view_name);
+ void scene_sync();
void mesh_sync(Object *ob, ObjectHandle &ob_handle);
void update_eval_members();
diff --git a/source/blender/draw/engines/eevee_next/eevee_material.cc b/source/blender/draw/engines/eevee_next/eevee_material.cc
index b63002df2e3..d190a1f17a3 100644
--- a/source/blender/draw/engines/eevee_next/eevee_material.cc
+++ b/source/blender/draw/engines/eevee_next/eevee_material.cc
@@ -187,6 +187,8 @@ MaterialPass MaterialModule::material_pass_get(Object *ob,
/* Returned material should be ready to be drawn. */
BLI_assert(GPU_material_status(matpass.gpumat) == GPU_MAT_SUCCESS);
+ inst_.manager->register_layer_attributes(matpass.gpumat);
+
if (GPU_material_recalc_flag_get(matpass.gpumat)) {
inst_.sampling.reset();
}
@@ -217,6 +219,9 @@ MaterialPass MaterialModule::material_pass_get(Object *ob,
matpass.sub_pass = &shader_sub->sub(GPU_material_get_name(matpass.gpumat));
matpass.sub_pass->material_set(*inst_.manager, matpass.gpumat);
}
+ else {
+ matpass.sub_pass = nullptr;
+ }
}
return matpass;
diff --git a/source/blender/draw/engines/eevee_next/eevee_shader_shared.hh b/source/blender/draw/engines/eevee_next/eevee_shader_shared.hh
index fd06cdc7f23..f6a96aaaff2 100644
--- a/source/blender/draw/engines/eevee_next/eevee_shader_shared.hh
+++ b/source/blender/draw/engines/eevee_next/eevee_shader_shared.hh
@@ -560,7 +560,7 @@ struct LightCullingData {
uint local_lights_len;
/** Items that are **NOT** processed by the 2.5D culling (i.e: Sun Lights). */
uint sun_lights_len;
- /** Number of items that passes the first culling test. */
+ /** Number of items that passes the first culling test. (local lights only) */
uint visible_count;
/** Extent of one square tile in pixels. */
float tile_size;
diff --git a/source/blender/draw/engines/eevee_next/eevee_sync.cc b/source/blender/draw/engines/eevee_next/eevee_sync.cc
index f2daba48d7a..08cda6f47cf 100644
--- a/source/blender/draw/engines/eevee_next/eevee_sync.cc
+++ b/source/blender/draw/engines/eevee_next/eevee_sync.cc
@@ -68,6 +68,20 @@ WorldHandle &SyncModule::sync_world(::World *world)
return eevee_dd;
}
+SceneHandle &SyncModule::sync_scene(::Scene *scene)
+{
+ DrawEngineType *owner = (DrawEngineType *)&DRW_engine_viewport_eevee_next_type;
+ struct DrawData *dd = DRW_drawdata_ensure(
+ (ID *)scene, owner, sizeof(eevee::SceneHandle), draw_data_init_cb, nullptr);
+ SceneHandle &eevee_dd = *reinterpret_cast<SceneHandle *>(dd);
+
+ const int recalc_flags = ID_RECALC_ALL;
+ if ((eevee_dd.recalc & recalc_flags) != 0) {
+ inst_.sampling.reset();
+ }
+ return eevee_dd;
+}
+
/** \} */
/* -------------------------------------------------------------------- */
diff --git a/source/blender/draw/engines/eevee_next/eevee_sync.hh b/source/blender/draw/engines/eevee_next/eevee_sync.hh
index ab883ce44c2..eda0342c4b6 100644
--- a/source/blender/draw/engines/eevee_next/eevee_sync.hh
+++ b/source/blender/draw/engines/eevee_next/eevee_sync.hh
@@ -139,6 +139,15 @@ struct WorldHandle : public DrawData {
}
};
+struct SceneHandle : public DrawData {
+ void reset_recalc_flag()
+ {
+ if (recalc != 0) {
+ recalc = 0;
+ }
+ }
+};
+
class SyncModule {
private:
Instance &inst_;
@@ -149,6 +158,7 @@ class SyncModule {
ObjectHandle &sync_object(Object *ob);
WorldHandle &sync_world(::World *world);
+ SceneHandle &sync_scene(::Scene *scene);
void sync_mesh(Object *ob,
ObjectHandle &ob_handle,
diff --git a/source/blender/draw/engines/eevee_next/eevee_world.cc b/source/blender/draw/engines/eevee_next/eevee_world.cc
index 313c0bda42e..37f90570028 100644
--- a/source/blender/draw/engines/eevee_next/eevee_world.cc
+++ b/source/blender/draw/engines/eevee_next/eevee_world.cc
@@ -87,6 +87,9 @@ void World::sync()
default_tree.nodetree_get(bl_world);
GPUMaterial *gpumat = inst_.shaders.world_shader_get(bl_world, ntree);
+
+ inst_.manager->register_layer_attributes(gpumat);
+
inst_.pipelines.world.sync(gpumat);
}
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 b632564a9ca..7883bf01aeb 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
@@ -114,11 +114,11 @@ GPU_SHADER_CREATE_INFO(eevee_surf_deferred)
// .image_out(5, Qualifier::WRITE, GPU_R11F_G11F_B10F, "gbuff_emission")
/* Render-passes. */
// .image_out(6, Qualifier::READ_WRITE, GPU_RGBA16F, "rpass_volume_light")
- /* TODO: AOVs maybe? */
.fragment_source("eevee_surf_deferred_frag.glsl")
- // .additional_info("eevee_aov_out", "eevee_sampling_data", "eevee_camera",
- // "eevee_utility_texture")
- ;
+ .additional_info("eevee_camera",
+ "eevee_utility_texture",
+ "eevee_sampling_data",
+ "eevee_aov_out");
GPU_SHADER_CREATE_INFO(eevee_surf_forward)
.vertex_out(eevee_surf_iface)
diff --git a/source/blender/draw/engines/image/image_drawing_mode.hh b/source/blender/draw/engines/image/image_drawing_mode.hh
index 21dac8009f6..8913b7469ed 100644
--- a/source/blender/draw/engines/image/image_drawing_mode.hh
+++ b/source/blender/draw/engines/image/image_drawing_mode.hh
@@ -332,6 +332,7 @@ template<typename TextureMethod> class ScreenSpaceDrawingMode : public AbstractD
offset++;
}
}
+ IMB_gpu_clamp_half_float(&extracted_buffer);
GPU_texture_update_sub(texture,
GPU_DATA_FLOAT,
@@ -388,6 +389,7 @@ template<typename TextureMethod> class ScreenSpaceDrawingMode : public AbstractD
}
BKE_image_release_ibuf(image, tile_buffer, lock);
}
+ IMB_gpu_clamp_half_float(&texture_buffer);
GPU_texture_update(info.texture, GPU_DATA_FLOAT, texture_buffer.rect_float);
imb_freerectImbuf_all(&texture_buffer);
}
diff --git a/source/blender/draw/engines/overlay/overlay_grid.cc b/source/blender/draw/engines/overlay/overlay_grid.cc
index e31c40fff41..7c221e67691 100644
--- a/source/blender/draw/engines/overlay/overlay_grid.cc
+++ b/source/blender/draw/engines/overlay/overlay_grid.cc
@@ -59,8 +59,10 @@ void OVERLAY_grid_init(OVERLAY_Data *vedata)
const bool draw_grid = is_uv_edit || !ED_space_image_has_buffer(sima);
if (background_enabled && draw_grid) {
grid_flag |= SHOW_GRID;
- if (is_uv_edit && (sima->flag & SI_CUSTOM_GRID) != 0) {
- grid_flag |= CUSTOM_GRID;
+ if (is_uv_edit) {
+ if (sima->grid_shape_source != SI_GRID_SHAPE_DYNAMIC) {
+ grid_flag |= CUSTOM_GRID;
+ }
}
}
diff --git a/source/blender/draw/engines/workbench/workbench_engine.c b/source/blender/draw/engines/workbench/workbench_engine.c
index 36a980bd506..fecdad5802c 100644
--- a/source/blender/draw/engines/workbench/workbench_engine.c
+++ b/source/blender/draw/engines/workbench/workbench_engine.c
@@ -14,6 +14,7 @@
#include "BLI_alloca.h"
#include "BKE_editmesh.h"
+#include "BKE_mesh_runtime.h"
#include "BKE_modifier.h"
#include "BKE_object.h"
#include "BKE_paint.h"
@@ -231,7 +232,7 @@ static void workbench_cache_hair_populate(WORKBENCH_PrivateData *wpd,
static const CustomData *workbench_mesh_get_loop_custom_data(const Mesh *mesh)
{
- if (mesh->runtime.wrapper_type == ME_WRAPPER_TYPE_BMESH) {
+ if (BKE_mesh_wrapper_type(mesh) == ME_WRAPPER_TYPE_BMESH) {
BLI_assert(mesh->edit_mesh != NULL);
BLI_assert(mesh->edit_mesh->bm != NULL);
return &mesh->edit_mesh->bm->ldata;
@@ -241,7 +242,7 @@ static const CustomData *workbench_mesh_get_loop_custom_data(const Mesh *mesh)
static const CustomData *workbench_mesh_get_vert_custom_data(const Mesh *mesh)
{
- if (mesh->runtime.wrapper_type == ME_WRAPPER_TYPE_BMESH) {
+ if (BKE_mesh_wrapper_type(mesh) == ME_WRAPPER_TYPE_BMESH) {
BLI_assert(mesh->edit_mesh != NULL);
BLI_assert(mesh->edit_mesh->bm != NULL);
return &mesh->edit_mesh->bm->vdata;
diff --git a/source/blender/draw/intern/DRW_gpu_wrapper.hh b/source/blender/draw/intern/DRW_gpu_wrapper.hh
index d53c5fbeaa5..3be50d471e2 100644
--- a/source/blender/draw/intern/DRW_gpu_wrapper.hh
+++ b/source/blender/draw/intern/DRW_gpu_wrapper.hh
@@ -924,6 +924,35 @@ class TextureFromPool : public Texture, NonMovable {
GPUTexture *stencil_view() = delete;
};
+class TextureRef : public Texture {
+ public:
+ TextureRef() = default;
+
+ ~TextureRef()
+ {
+ this->tx_ = nullptr;
+ }
+
+ void wrap(GPUTexture *tex)
+ {
+ this->tx_ = tex;
+ }
+
+ /** Remove methods that are forbidden with this type of textures. */
+ bool ensure_1d(int, int, eGPUTextureFormat, float *) = delete;
+ bool ensure_1d_array(int, int, int, eGPUTextureFormat, float *) = delete;
+ bool ensure_2d(int, int, int, eGPUTextureFormat, float *) = delete;
+ bool ensure_2d_array(int, int, int, int, eGPUTextureFormat, float *) = delete;
+ bool ensure_3d(int, int, int, int, eGPUTextureFormat, float *) = delete;
+ bool ensure_cube(int, int, eGPUTextureFormat, float *) = delete;
+ bool ensure_cube_array(int, int, int, eGPUTextureFormat, float *) = delete;
+ void filter_mode(bool) = delete;
+ void free() = delete;
+ GPUTexture *mip_view(int) = delete;
+ GPUTexture *layer_view(int) = delete;
+ GPUTexture *stencil_view() = delete;
+};
+
/**
* Dummy type to bind texture as image.
* It is just a GPUTexture in disguise.
diff --git a/source/blender/draw/intern/draw_attributes.cc b/source/blender/draw/intern/draw_attributes.cc
index 011d72e9e8f..cc7c9959850 100644
--- a/source/blender/draw/intern/draw_attributes.cc
+++ b/source/blender/draw/intern/draw_attributes.cc
@@ -44,13 +44,10 @@ void drw_attributes_clear(DRW_Attributes *attributes)
memset(attributes, 0, sizeof(DRW_Attributes));
}
-void drw_attributes_merge(DRW_Attributes *dst,
- const DRW_Attributes *src,
- ThreadMutex *render_mutex)
+void drw_attributes_merge(DRW_Attributes *dst, const DRW_Attributes *src, std::mutex &render_mutex)
{
- BLI_mutex_lock(render_mutex);
+ std::lock_guard lock{render_mutex};
drw_attributes_merge_requests(src, dst);
- BLI_mutex_unlock(render_mutex);
}
bool drw_attributes_overlap(const DRW_Attributes *a, const DRW_Attributes *b)
diff --git a/source/blender/draw/intern/draw_attributes.h b/source/blender/draw/intern/draw_attributes.h
index 786301d0164..00621c711bf 100644
--- a/source/blender/draw/intern/draw_attributes.h
+++ b/source/blender/draw/intern/draw_attributes.h
@@ -9,6 +9,10 @@
#pragma once
+#ifdef __cplusplus
+# include <mutex>
+#endif
+
#include "DNA_customdata_types.h"
#include "DNA_meshdata_types.h"
@@ -56,9 +60,11 @@ BLI_STATIC_ASSERT(sizeof(DRW_MeshCDMask) <= sizeof(uint32_t), "DRW_MeshCDMask ex
void drw_attributes_clear(DRW_Attributes *attributes);
+#ifdef __cplusplus
void drw_attributes_merge(DRW_Attributes *dst,
const DRW_Attributes *src,
- ThreadMutex *render_mutex);
+ std::mutex &render_mutex);
+#endif
/* Return true if all requests in b are in a. */
bool drw_attributes_overlap(const DRW_Attributes *a, const DRW_Attributes *b);
diff --git a/source/blender/draw/intern/draw_cache_extract_mesh.cc b/source/blender/draw/intern/draw_cache_extract_mesh.cc
index d3170f4c776..f533904f355 100644
--- a/source/blender/draw/intern/draw_cache_extract_mesh.cc
+++ b/source/blender/draw/intern/draw_cache_extract_mesh.cc
@@ -686,7 +686,7 @@ 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 = mr->me && mr->me->runtime.subsurf_face_dot_tags != nullptr;
+ mr->use_subsurf_fdots = mr->me && mr->me->runtime->subsurf_face_dot_tags != nullptr;
mr->use_final_mesh = do_final;
#ifdef DEBUG_TIME
diff --git a/source/blender/draw/intern/draw_cache_extract_mesh_render_data.cc b/source/blender/draw/intern/draw_cache_extract_mesh_render_data.cc
index f554e9e67c3..f606701ed09 100644
--- a/source/blender/draw/intern/draw_cache_extract_mesh_render_data.cc
+++ b/source/blender/draw/intern/draw_cache_extract_mesh_render_data.cc
@@ -463,7 +463,7 @@ MeshRenderData *mesh_render_data_create(Object *object,
mr->bm = me->edit_mesh->bm;
mr->edit_bmesh = me->edit_mesh;
mr->me = (do_final) ? editmesh_eval_final : editmesh_eval_cage;
- mr->edit_data = is_mode_active ? mr->me->runtime.edit_data : nullptr;
+ mr->edit_data = is_mode_active ? mr->me->runtime->edit_data : nullptr;
if (mr->edit_data) {
EditMeshData *emd = mr->edit_data;
@@ -499,8 +499,8 @@ MeshRenderData *mesh_render_data_create(Object *object,
/* Use bmesh directly when the object is in edit mode unchanged by any modifiers.
* For non-final UVs, always use original bmesh since the UV editor does not support
* using the cage mesh with deformed coordinates. */
- if ((is_mode_active && mr->me->runtime.is_original_bmesh &&
- mr->me->runtime.wrapper_type == ME_WRAPPER_TYPE_BMESH) ||
+ if ((is_mode_active && mr->me->runtime->is_original_bmesh &&
+ mr->me->runtime->wrapper_type == ME_WRAPPER_TYPE_BMESH) ||
(do_uvedit && !do_final)) {
mr->extract_type = MR_EXTRACT_BMESH;
}
diff --git a/source/blender/draw/intern/draw_cache_impl_curves.cc b/source/blender/draw/intern/draw_cache_impl_curves.cc
index 33b97388620..85dd9ca8695 100644
--- a/source/blender/draw/intern/draw_cache_impl_curves.cc
+++ b/source/blender/draw/intern/draw_cache_impl_curves.cc
@@ -14,9 +14,9 @@
#include "BLI_listbase.h"
#include "BLI_math_base.h"
#include "BLI_math_vec_types.hh"
-#include "BLI_math_vector.h"
#include "BLI_math_vector.hh"
#include "BLI_span.hh"
+#include "BLI_task.hh"
#include "BLI_utildefines.h"
#include "DNA_curves_types.h"
@@ -60,7 +60,7 @@ struct CurvesBatchCache {
* some locking would be necessary because multiple objects can use the same curves data with
* different materials, etc. This is a placeholder to make multi-threading easier in the future.
*/
- ThreadMutex render_mutex;
+ std::mutex render_mutex;
};
static bool curves_batch_cache_valid(const Curves &curves)
@@ -74,15 +74,13 @@ static void curves_batch_cache_init(Curves &curves)
CurvesBatchCache *cache = static_cast<CurvesBatchCache *>(curves.batch_cache);
if (!cache) {
- cache = MEM_cnew<CurvesBatchCache>(__func__);
+ cache = MEM_new<CurvesBatchCache>(__func__);
curves.batch_cache = cache;
}
else {
- memset(cache, 0, sizeof(*cache));
+ cache->curves_cache = {};
}
- BLI_mutex_init(&cache->render_mutex);
-
cache->is_dirty = false;
}
@@ -172,9 +170,8 @@ void DRW_curves_batch_cache_dirty_tag(Curves *curves, int mode)
void DRW_curves_batch_cache_free(Curves *curves)
{
curves_batch_cache_clear(*curves);
- CurvesBatchCache *cache = static_cast<CurvesBatchCache *>(curves->batch_cache);
- BLI_mutex_end(&cache->render_mutex);
- MEM_SAFE_FREE(curves->batch_cache);
+ MEM_delete(static_cast<CurvesBatchCache *>(curves->batch_cache));
+ curves->batch_cache = nullptr;
}
void DRW_curves_batch_cache_free_old(Curves *curves, int ctime)
@@ -226,38 +223,38 @@ static void curves_batch_cache_fill_segments_proc_pos(
MutableSpan<PositionAndParameter> posTime_data,
MutableSpan<float> hairLength_data)
{
+ using namespace blender;
/* TODO: use hair radius layer if available. */
- 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();
+ const bke::CurvesGeometry &curves = bke::CurvesGeometry::wrap(curves_id.geometry);
+ const Span<float3> positions = curves.positions();
- for (const int i_curve : IndexRange(curve_num)) {
- const IndexRange points = curves.points_for_curve(i_curve);
+ threading::parallel_for(curves.curves_range(), 1024, [&](const IndexRange range) {
+ for (const int i_curve : range) {
+ 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);
-
- float total_len = 0.0f;
- 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]);
- }
- curve_posTime_data[i_point].position = curve_positions[i_point];
- curve_posTime_data[i_point].parameter = total_len;
- }
- hairLength_data[i_curve] = total_len;
+ Span<float3> curve_positions = positions.slice(points);
+ MutableSpan<PositionAndParameter> curve_posTime_data = posTime_data.slice(points);
- /* Assign length value. */
- if (total_len > 0.0f) {
- const float factor = 1.0f / total_len;
- /* Divide by total length to have a [0-1] number. */
+ float total_len = 0.0f;
for (const int i_point : curve_positions.index_range()) {
- curve_posTime_data[i_point].parameter *= factor;
+ if (i_point > 0) {
+ total_len += math::distance(curve_positions[i_point - 1], curve_positions[i_point]);
+ }
+ 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. */
+ if (total_len > 0.0f) {
+ const float factor = 1.0f / total_len;
+ /* Divide by total length to have a [0-1] number. */
+ for (const int i_point : curve_positions.index_range()) {
+ curve_posTime_data[i_point].parameter *= factor;
+ }
}
}
- }
+ });
}
static void curves_batch_cache_ensure_procedural_pos(const Curves &curves,
@@ -275,7 +272,7 @@ static void curves_batch_cache_ensure_procedural_pos(const Curves &curves,
GPU_vertbuf_data_alloc(cache.proc_point_buf, cache.point_len);
MutableSpan posTime_data{
- reinterpret_cast<PositionAndParameter *>(GPU_vertbuf_get_data(cache.proc_point_buf)),
+ static_cast<PositionAndParameter *>(GPU_vertbuf_get_data(cache.proc_point_buf)),
cache.point_len};
GPUVertFormat length_format = {0};
@@ -285,8 +282,8 @@ static void curves_batch_cache_ensure_procedural_pos(const Curves &curves,
&length_format, GPU_USAGE_STATIC | GPU_USAGE_FLAG_BUFFER_TEXTURE_ONLY);
GPU_vertbuf_data_alloc(cache.proc_length_buf, cache.strands_len);
- MutableSpan hairLength_data{
- reinterpret_cast<float *>(GPU_vertbuf_get_data(cache.proc_length_buf)), cache.strands_len};
+ MutableSpan hairLength_data{static_cast<float *>(GPU_vertbuf_get_data(cache.proc_length_buf)),
+ cache.strands_len};
curves_batch_cache_fill_segments_proc_pos(curves, posTime_data, hairLength_data);
@@ -310,15 +307,15 @@ static void curves_batch_cache_ensure_procedural_pos(const Curves &curves,
static void curves_batch_cache_ensure_data_edit_points(const Curves &curves_id,
CurvesEvalCache &cache)
{
- const blender::bke::CurvesGeometry &curves = blender::bke::CurvesGeometry::wrap(
- curves_id.geometry);
+ using namespace blender;
+ const bke::CurvesGeometry &curves = bke::CurvesGeometry::wrap(curves_id.geometry);
static GPUVertFormat format_data = {0};
uint data = GPU_vertformat_attr_add(&format_data, "data", GPU_COMP_U8, 1, GPU_FETCH_INT);
GPU_vertbuf_init_with_format(cache.data_edit_points, &format_data);
GPU_vertbuf_data_alloc(cache.data_edit_points, curves.points_num());
- blender::VArray<float> selection;
+ VArray<float> selection;
switch (curves_id.selection_domain) {
case ATTR_DOMAIN_POINT:
selection = curves.selection_point_float();
@@ -380,6 +377,7 @@ static void curves_batch_ensure_attribute(const Curves &curves,
const int subdiv,
const int index)
{
+ using namespace blender;
GPU_VERTBUF_DISCARD_SAFE(cache.proc_attributes_buf[index]);
DRW_TEXTURE_FREE_SAFE(cache.proc_attributes_tex[index]);
@@ -399,15 +397,15 @@ static void curves_batch_ensure_attribute(const Curves &curves,
request.domain == ATTR_DOMAIN_POINT ? curves.geometry.point_num :
curves.geometry.curve_num);
- const blender::bke::AttributeAccessor attributes =
- blender::bke::CurvesGeometry::wrap(curves.geometry).attributes();
+ const bke::AttributeAccessor attributes =
+ bke::CurvesGeometry::wrap(curves.geometry).attributes();
/* TODO(@kevindietrich): float4 is used for scalar attributes as the implicit conversion done
* by OpenGL to vec4 for a scalar `s` will produce a `vec4(s, 0, 0, 1)`. However, following
* the Blender convention, it should be `vec4(s, s, s, 1)`. This could be resolved using a
* similar texture state swizzle to map the attribute correctly as for volume attributes, so we
* can control the conversion ourselves. */
- blender::VArray<ColorGeometry4f> attribute = attributes.lookup_or_default<ColorGeometry4f>(
+ VArray<ColorGeometry4f> attribute = attributes.lookup_or_default<ColorGeometry4f>(
request.attribute_name, request.domain, {0.0f, 0.0f, 0.0f, 1.0f});
MutableSpan<ColorGeometry4f> vbo_span{
@@ -554,7 +552,6 @@ static bool curves_ensure_attributes(const Curves &curves,
GPUMaterial *gpu_material,
int subdiv)
{
- ThreadMutex *render_mutex = &cache.render_mutex;
const CustomData *cd_curve = &curves.geometry.curve_data;
const CustomData *cd_point = &curves.geometry.point_data;
CurvesEvalFinalCache &final_cache = cache.curves_cache.final[subdiv];
@@ -588,9 +585,9 @@ static bool curves_ensure_attributes(const Curves &curves,
GPU_VERTBUF_DISCARD_SAFE(cache.curves_cache.proc_attributes_buf[i]);
DRW_TEXTURE_FREE_SAFE(cache.curves_cache.proc_attributes_tex[i]);
}
- drw_attributes_merge(&final_cache.attr_used, &attrs_needed, render_mutex);
+ drw_attributes_merge(&final_cache.attr_used, &attrs_needed, cache.render_mutex);
}
- drw_attributes_merge(&final_cache.attr_used_over_time, &attrs_needed, render_mutex);
+ drw_attributes_merge(&final_cache.attr_used_over_time, &attrs_needed, cache.render_mutex);
}
bool need_tf_update = false;
@@ -689,7 +686,7 @@ static void request_attribute(Curves &curves, const char *name)
drw_attributes_add_request(
&attributes, name, type, CustomData_get_named_layer(&custom_data, type, name), domain);
- drw_attributes_merge(&final_cache.attr_used, &attributes, &cache.render_mutex);
+ drw_attributes_merge(&final_cache.attr_used, &attributes, cache.render_mutex);
}
GPUTexture **DRW_curves_texture_for_evaluated_attribute(Curves *curves,
diff --git a/source/blender/draw/intern/draw_cache_impl_mesh.cc b/source/blender/draw/intern/draw_cache_impl_mesh.cc
index 5a041493a6a..5ce658abfe4 100644
--- a/source/blender/draw/intern/draw_cache_impl_mesh.cc
+++ b/source/blender/draw/intern/draw_cache_impl_mesh.cc
@@ -554,22 +554,13 @@ BLI_INLINE void mesh_batch_cache_add_request(MeshBatchCache *cache, DRWBatchFlag
static bool mesh_batch_cache_valid(Object *object, Mesh *me)
{
- MeshBatchCache *cache = static_cast<MeshBatchCache *>(me->runtime.batch_cache);
+ MeshBatchCache *cache = static_cast<MeshBatchCache *>(me->runtime->batch_cache);
if (cache == nullptr) {
return false;
}
- if (object->sculpt && object->sculpt->pbvh) {
- if (cache->pbvh_is_drawing != BKE_pbvh_is_drawing(object->sculpt->pbvh)) {
- return false;
- }
-
- if (BKE_pbvh_is_drawing(object->sculpt->pbvh) &&
- BKE_pbvh_draw_cache_invalid(object->sculpt->pbvh)) {
- return false;
- }
- }
+ /* Note: PBVH draw data should not be checked here. */
if (cache->is_editmode != (me->edit_mesh != nullptr)) {
return false;
@@ -588,11 +579,11 @@ static bool mesh_batch_cache_valid(Object *object, Mesh *me)
static void mesh_batch_cache_init(Object *object, Mesh *me)
{
- MeshBatchCache *cache = static_cast<MeshBatchCache *>(me->runtime.batch_cache);
+ MeshBatchCache *cache = static_cast<MeshBatchCache *>(me->runtime->batch_cache);
if (!cache) {
- me->runtime.batch_cache = MEM_cnew<MeshBatchCache>(__func__);
- cache = static_cast<MeshBatchCache *>(me->runtime.batch_cache);
+ me->runtime->batch_cache = MEM_cnew<MeshBatchCache>(__func__);
+ cache = static_cast<MeshBatchCache *>(me->runtime->batch_cache);
}
else {
memset(cache, 0, sizeof(*cache));
@@ -634,7 +625,7 @@ void DRW_mesh_batch_cache_validate(Object *object, Mesh *me)
static MeshBatchCache *mesh_batch_cache_get(Mesh *me)
{
- return static_cast<MeshBatchCache *>(me->runtime.batch_cache);
+ return static_cast<MeshBatchCache *>(me->runtime->batch_cache);
}
static void mesh_batch_cache_check_vertex_group(MeshBatchCache *cache,
@@ -742,7 +733,7 @@ static void mesh_batch_cache_discard_uvedit_select(MeshBatchCache *cache)
void DRW_mesh_batch_cache_dirty_tag(Mesh *me, eMeshBatchDirtyMode mode)
{
- MeshBatchCache *cache = static_cast<MeshBatchCache *>(me->runtime.batch_cache);
+ MeshBatchCache *cache = static_cast<MeshBatchCache *>(me->runtime->batch_cache);
if (cache == nullptr) {
return;
}
@@ -830,7 +821,7 @@ static void mesh_batch_cache_free_subdiv_cache(MeshBatchCache *cache)
static void mesh_batch_cache_clear(Mesh *me)
{
- MeshBatchCache *cache = static_cast<MeshBatchCache *>(me->runtime.batch_cache);
+ MeshBatchCache *cache = static_cast<MeshBatchCache *>(me->runtime->batch_cache);
if (!cache) {
return;
}
@@ -862,7 +853,7 @@ static void mesh_batch_cache_clear(Mesh *me)
void DRW_mesh_batch_cache_free(Mesh *me)
{
mesh_batch_cache_clear(me);
- MEM_SAFE_FREE(me->runtime.batch_cache);
+ MEM_SAFE_FREE(me->runtime->batch_cache);
}
/** \} */
@@ -1017,8 +1008,7 @@ GPUBatch **DRW_mesh_batch_cache_get_surface_shaded(Object *object,
BLI_assert(gpumat_array_len == cache->mat_len);
mesh_cd_layers_type_merge(&cache->cd_needed, cd_needed);
- ThreadMutex *mesh_render_mutex = (ThreadMutex *)me->runtime.render_mutex;
- drw_attributes_merge(&cache->attr_needed, &attrs_needed, mesh_render_mutex);
+ drw_attributes_merge(&cache->attr_needed, &attrs_needed, me->runtime->render_mutex);
mesh_batch_cache_request_surface_batches(cache);
return cache->surface_per_mat;
}
@@ -1046,8 +1036,7 @@ GPUBatch *DRW_mesh_batch_cache_get_surface_vertpaint(Object *object, Mesh *me)
DRW_Attributes attrs_needed{};
request_active_and_default_color_attributes(*object, *me, attrs_needed);
- ThreadMutex *mesh_render_mutex = (ThreadMutex *)me->runtime.render_mutex;
- drw_attributes_merge(&cache->attr_needed, &attrs_needed, mesh_render_mutex);
+ drw_attributes_merge(&cache->attr_needed, &attrs_needed, me->runtime->render_mutex);
mesh_batch_cache_request_surface_batches(cache);
return cache->batch.surface;
@@ -1060,8 +1049,7 @@ GPUBatch *DRW_mesh_batch_cache_get_surface_sculpt(Object *object, Mesh *me)
DRW_Attributes attrs_needed{};
request_active_and_default_color_attributes(*object, *me, attrs_needed);
- ThreadMutex *mesh_render_mutex = (ThreadMutex *)me->runtime.render_mutex;
- drw_attributes_merge(&cache->attr_needed, &attrs_needed, mesh_render_mutex);
+ drw_attributes_merge(&cache->attr_needed, &attrs_needed, me->runtime->render_mutex);
mesh_batch_cache_request_surface_batches(cache);
return cache->batch.surface;
@@ -1300,7 +1288,7 @@ GPUBatch *DRW_mesh_batch_cache_get_surface_edges(Object *object, Mesh *me)
void DRW_mesh_batch_cache_free_old(Mesh *me, int ctime)
{
- MeshBatchCache *cache = static_cast<MeshBatchCache *>(me->runtime.batch_cache);
+ MeshBatchCache *cache = static_cast<MeshBatchCache *>(me->runtime->batch_cache);
if (cache == nullptr) {
return;
@@ -1446,8 +1434,6 @@ void DRW_mesh_batch_cache_create_requested(struct TaskGraph *task_graph,
}
}
- ThreadMutex *mesh_render_mutex = (ThreadMutex *)me->runtime.render_mutex;
-
/* Verify that all surface batches have needed attribute layers.
*/
/* TODO(fclem): We could be a bit smarter here and only do it per
@@ -1485,12 +1471,13 @@ void DRW_mesh_batch_cache_create_requested(struct TaskGraph *task_graph,
cache->batch_ready &= ~(MBC_SURFACE);
mesh_cd_layers_type_merge(&cache->cd_used, cache->cd_needed);
- drw_attributes_merge(&cache->attr_used, &cache->attr_needed, mesh_render_mutex);
+ drw_attributes_merge(&cache->attr_used, &cache->attr_needed, me->runtime->render_mutex);
}
mesh_cd_layers_type_merge(&cache->cd_used_over_time, cache->cd_needed);
mesh_cd_layers_type_clear(&cache->cd_needed);
- drw_attributes_merge(&cache->attr_used_over_time, &cache->attr_needed, mesh_render_mutex);
+ drw_attributes_merge(
+ &cache->attr_used_over_time, &cache->attr_needed, me->runtime->render_mutex);
drw_attributes_clear(&cache->attr_needed);
}
@@ -1537,7 +1524,7 @@ void DRW_mesh_batch_cache_create_requested(struct TaskGraph *task_graph,
const bool do_update_sculpt_normals = ob->sculpt && ob->sculpt->pbvh;
if (do_update_sculpt_normals) {
Mesh *mesh = static_cast<Mesh *>(ob->data);
- BKE_pbvh_update_normals(ob->sculpt->pbvh, mesh->runtime.subdiv_ccg);
+ BKE_pbvh_update_normals(ob->sculpt->pbvh, mesh->runtime->subdiv_ccg);
}
cache->batch_ready |= batch_requested;
@@ -1548,8 +1535,8 @@ void DRW_mesh_batch_cache_create_requested(struct TaskGraph *task_graph,
Mesh *editmesh_eval_cage = BKE_object_get_editmesh_eval_cage(ob);
do_cage = editmesh_eval_final != editmesh_eval_cage;
- do_uvcage = !(editmesh_eval_final->runtime.is_original_bmesh &&
- editmesh_eval_final->runtime.wrapper_type == ME_WRAPPER_TYPE_BMESH);
+ do_uvcage = !(editmesh_eval_final->runtime->is_original_bmesh &&
+ editmesh_eval_final->runtime->wrapper_type == ME_WRAPPER_TYPE_BMESH);
}
const bool do_subdivision = BKE_subsurf_modifier_has_gpu_subdiv(me);
diff --git a/source/blender/draw/intern/draw_cache_impl_subdivision.cc b/source/blender/draw/intern/draw_cache_impl_subdivision.cc
index 9f445be9750..6a9e6c126e9 100644
--- a/source/blender/draw/intern/draw_cache_impl_subdivision.cc
+++ b/source/blender/draw/intern/draw_cache_impl_subdivision.cc
@@ -2036,7 +2036,7 @@ static bool draw_subdiv_create_requested_buffers(Object *ob,
const bool use_hide,
OpenSubdiv_EvaluatorCache *evaluator_cache)
{
- SubsurfRuntimeData *runtime_data = mesh->runtime.subsurf_runtime_data;
+ SubsurfRuntimeData *runtime_data = mesh->runtime->subsurf_runtime_data;
BLI_assert(runtime_data && runtime_data->has_gpu_subdiv);
if (runtime_data->settings.level == 0) {
diff --git a/source/blender/draw/intern/draw_cache_impl_volume.c b/source/blender/draw/intern/draw_cache_impl_volume.cc
index 18a4c81514b..ac5e6fa05b9 100644
--- a/source/blender/draw/intern/draw_cache_impl_volume.c
+++ b/source/blender/draw/intern/draw_cache_impl_volume.cc
@@ -7,7 +7,7 @@
* \brief Volume API for render engines
*/
-#include <string.h>
+#include <cstring>
#include "MEM_guardedalloc.h"
@@ -39,7 +39,7 @@ static void volume_batch_cache_clear(Volume *volume);
/* ---------------------------------------------------------------------- */
/* Volume GPUBatch Cache */
-typedef struct VolumeBatchCache {
+struct VolumeBatchCache {
/* 3D textures */
ListBase grids;
@@ -54,22 +54,22 @@ typedef struct VolumeBatchCache {
/* settings to determine if cache is invalid */
bool is_dirty;
-} VolumeBatchCache;
+};
/* GPUBatch cache management. */
static bool volume_batch_cache_valid(Volume *volume)
{
- VolumeBatchCache *cache = volume->batch_cache;
+ VolumeBatchCache *cache = static_cast<VolumeBatchCache *>(volume->batch_cache);
return (cache && cache->is_dirty == false);
}
static void volume_batch_cache_init(Volume *volume)
{
- VolumeBatchCache *cache = volume->batch_cache;
+ VolumeBatchCache *cache = static_cast<VolumeBatchCache *>(volume->batch_cache);
if (!cache) {
- cache = volume->batch_cache = MEM_callocN(sizeof(*cache), __func__);
+ volume->batch_cache = cache = MEM_cnew<VolumeBatchCache>(__func__);
}
else {
memset(cache, 0, sizeof(*cache));
@@ -89,13 +89,13 @@ void DRW_volume_batch_cache_validate(Volume *volume)
static VolumeBatchCache *volume_batch_cache_get(Volume *volume)
{
DRW_volume_batch_cache_validate(volume);
- return volume->batch_cache;
+ return static_cast<VolumeBatchCache *>(volume->batch_cache);
}
void DRW_volume_batch_cache_dirty_tag(Volume *volume, int mode)
{
- VolumeBatchCache *cache = volume->batch_cache;
- if (cache == NULL) {
+ VolumeBatchCache *cache = static_cast<VolumeBatchCache *>(volume->batch_cache);
+ if (cache == nullptr) {
return;
}
switch (mode) {
@@ -109,7 +109,7 @@ void DRW_volume_batch_cache_dirty_tag(Volume *volume, int mode)
static void volume_batch_cache_clear(Volume *volume)
{
- VolumeBatchCache *cache = volume->batch_cache;
+ VolumeBatchCache *cache = static_cast<VolumeBatchCache *>(volume->batch_cache);
if (!cache) {
return;
}
@@ -130,18 +130,18 @@ void DRW_volume_batch_cache_free(Volume *volume)
volume_batch_cache_clear(volume);
MEM_SAFE_FREE(volume->batch_cache);
}
-typedef struct VolumeWireframeUserData {
+struct VolumeWireframeUserData {
Volume *volume;
Scene *scene;
-} VolumeWireframeUserData;
+};
static void drw_volume_wireframe_cb(
void *userdata, const float (*verts)[3], const int (*edges)[2], int totvert, int totedge)
{
- VolumeWireframeUserData *data = userdata;
+ VolumeWireframeUserData *data = static_cast<VolumeWireframeUserData *>(userdata);
Scene *scene = data->scene;
Volume *volume = data->volume;
- VolumeBatchCache *cache = volume->batch_cache;
+ VolumeBatchCache *cache = static_cast<VolumeBatchCache *>(volume->batch_cache);
const bool do_hq_normals = (scene->r.perf_flag & SCE_PERF_HQ_NORMALS) != 0 ||
GPU_use_hq_normals_workaround();
@@ -181,7 +181,7 @@ static void drw_volume_wireframe_cb(
if (volume->display.wireframe_type == VOLUME_WIREFRAME_POINTS) {
/* Create batch. */
cache->face_wire.batch = GPU_batch_create(
- GPU_PRIM_POINTS, cache->face_wire.pos_nor_in_order, NULL);
+ GPU_PRIM_POINTS, cache->face_wire.pos_nor_in_order, nullptr);
}
else {
/* Create edge index buffer. */
@@ -203,15 +203,15 @@ static void drw_volume_wireframe_cb(
GPUBatch *DRW_volume_batch_cache_get_wireframes_face(Volume *volume)
{
if (volume->display.wireframe_type == VOLUME_WIREFRAME_NONE) {
- return NULL;
+ return nullptr;
}
VolumeBatchCache *cache = volume_batch_cache_get(volume);
- if (cache->face_wire.batch == NULL) {
+ if (cache->face_wire.batch == nullptr) {
const VolumeGrid *volume_grid = BKE_volume_grid_active_get_for_read(volume);
- if (volume_grid == NULL) {
- return NULL;
+ if (volume_grid == nullptr) {
+ return nullptr;
}
/* Create wireframe from OpenVDB tree. */
@@ -228,8 +228,8 @@ GPUBatch *DRW_volume_batch_cache_get_wireframes_face(Volume *volume)
static void drw_volume_selection_surface_cb(
void *userdata, float (*verts)[3], int (*tris)[3], int totvert, int tottris)
{
- Volume *volume = userdata;
- VolumeBatchCache *cache = volume->batch_cache;
+ Volume *volume = static_cast<Volume *>(userdata);
+ VolumeBatchCache *cache = static_cast<VolumeBatchCache *>(volume->batch_cache);
static GPUVertFormat format = {0};
static uint pos_id;
@@ -257,10 +257,10 @@ static void drw_volume_selection_surface_cb(
GPUBatch *DRW_volume_batch_cache_get_selection_surface(Volume *volume)
{
VolumeBatchCache *cache = volume_batch_cache_get(volume);
- if (cache->selection_surface == NULL) {
+ if (cache->selection_surface == nullptr) {
const VolumeGrid *volume_grid = BKE_volume_grid_active_get_for_read(volume);
- if (volume_grid == NULL) {
- return NULL;
+ if (volume_grid == nullptr) {
+ return nullptr;
}
BKE_volume_grid_selection_surface(
volume, volume_grid, drw_volume_selection_surface_cb, volume);
@@ -275,15 +275,14 @@ static DRWVolumeGrid *volume_grid_cache_get(const Volume *volume,
const char *name = BKE_volume_grid_name(grid);
/* Return cached grid. */
- DRWVolumeGrid *cache_grid;
- for (cache_grid = cache->grids.first; cache_grid; cache_grid = cache_grid->next) {
+ LISTBASE_FOREACH (DRWVolumeGrid *, cache_grid, &cache->grids) {
if (STREQ(cache_grid->name, name)) {
return cache_grid;
}
}
/* Allocate new grid. */
- cache_grid = MEM_callocN(sizeof(DRWVolumeGrid), __func__);
+ DRWVolumeGrid *cache_grid = MEM_cnew<DRWVolumeGrid>(__func__);
cache_grid->name = BLI_strdup(name);
BLI_addtail(&cache->grids, cache_grid);
@@ -316,7 +315,7 @@ static DRWVolumeGrid *volume_grid_cache_get(const Volume *volume,
dense_grid.voxels);
/* The texture can be null if the resolution along one axis is larger than
* GL_MAX_3D_TEXTURE_SIZE. */
- if (cache_grid->texture != NULL) {
+ if (cache_grid->texture != nullptr) {
GPU_texture_swizzle_set(cache_grid->texture, (channels == 3) ? "rgb1" : "rrr1");
GPU_texture_wrap_mode(cache_grid->texture, false, false);
BKE_volume_dense_float_grid_clear(&dense_grid);
@@ -339,7 +338,7 @@ DRWVolumeGrid *DRW_volume_batch_cache_get_grid(Volume *volume, const VolumeGrid
{
VolumeBatchCache *cache = volume_batch_cache_get(volume);
DRWVolumeGrid *grid = volume_grid_cache_get(volume, volume_grid, cache);
- return (grid->texture != NULL) ? grid : NULL;
+ return (grid->texture != nullptr) ? grid : nullptr;
}
int DRW_volume_material_count_get(Volume *volume)
diff --git a/source/blender/draw/intern/draw_debug.cc b/source/blender/draw/intern/draw_debug.cc
index 9e0be3d96ae..55de779d85c 100644
--- a/source/blender/draw/intern/draw_debug.cc
+++ b/source/blender/draw/intern/draw_debug.cc
@@ -21,7 +21,7 @@
#include <iomanip>
-#ifdef DEBUG
+#if defined(DEBUG) || defined(WITH_DRAW_DEBUG)
# define DRAW_DEBUG
#else
/* Uncomment to forcibly enable debug draw in release mode. */
@@ -558,7 +558,7 @@ void DebugDraw::display_prints()
int slot = GPU_shader_get_builtin_ssbo(shader, GPU_STORAGE_BUFFER_DEBUG_PRINT);
float f_viewport[4];
GPU_viewport_size_get_f(f_viewport);
- GPU_shader_uniform_4fv(shader, "viewport_size", f_viewport);
+ GPU_shader_uniform_2fv(shader, "viewport_size", f_viewport);
if (gpu_print_buf_used) {
GPU_debug_group_begin("GPU");
diff --git a/source/blender/draw/intern/draw_defines.h b/source/blender/draw/intern/draw_defines.h
index f5976ddd34e..57035717bd7 100644
--- a/source/blender/draw/intern/draw_defines.h
+++ b/source/blender/draw/intern/draw_defines.h
@@ -15,6 +15,8 @@
#define DRW_VIEW_CULLING_UBO_SLOT 1
#define DRW_CLIPPING_UBO_SLOT 2
+#define DRW_LAYER_ATTR_UBO_SLOT 3
+
#define DRW_RESOURCE_ID_SLOT 11
#define DRW_OBJ_MAT_SLOT 10
#define DRW_OBJ_INFOS_SLOT 9
diff --git a/source/blender/draw/intern/draw_instance_data.c b/source/blender/draw/intern/draw_instance_data.c
index a56883ce304..b44c1364af9 100644
--- a/source/blender/draw/intern/draw_instance_data.c
+++ b/source/blender/draw/intern/draw_instance_data.c
@@ -622,6 +622,62 @@ void drw_uniform_attrs_pool_update(GHash *table,
}
}
+GPUUniformBuf *drw_ensure_layer_attribute_buffer()
+{
+ DRWData *data = DST.vmempool;
+
+ if (data->vlattrs_ubo_ready && data->vlattrs_ubo != NULL) {
+ return data->vlattrs_ubo;
+ }
+
+ /* Allocate the buffer data. */
+ const int buf_size = DRW_RESOURCE_CHUNK_LEN;
+
+ if (data->vlattrs_buf == NULL) {
+ data->vlattrs_buf = MEM_calloc_arrayN(
+ buf_size, sizeof(LayerAttribute), "View Layer Attr Data");
+ }
+
+ /* Look up attributes.
+ *
+ * Mirrors code in draw_resource.cc and cycles/blender/shader.cpp.
+ */
+ LayerAttribute *buffer = data->vlattrs_buf;
+ int count = 0;
+
+ LISTBASE_FOREACH (GPULayerAttr *, attr, &data->vlattrs_name_list) {
+ float value[4];
+
+ if (BKE_view_layer_find_rgba_attribute(
+ DST.draw_ctx.scene, DST.draw_ctx.view_layer, attr->name, value)) {
+ LayerAttribute *item = &buffer[count++];
+
+ memcpy(item->data, value, sizeof(item->data));
+ item->hash_code = attr->hash_code;
+
+ /* Check if the buffer is full just in case. */
+ if (count >= buf_size) {
+ break;
+ }
+ }
+ }
+
+ buffer[0].buffer_length = count;
+
+ /* Update or create the UBO object. */
+ if (data->vlattrs_ubo != NULL) {
+ GPU_uniformbuf_update(data->vlattrs_ubo, buffer);
+ }
+ else {
+ data->vlattrs_ubo = GPU_uniformbuf_create_ex(
+ sizeof(*buffer) * buf_size, buffer, "View Layer Attributes");
+ }
+
+ data->vlattrs_ubo_ready = true;
+
+ return data->vlattrs_ubo;
+}
+
DRWSparseUniformBuf *DRW_uniform_attrs_pool_find_ubo(GHash *table,
const struct GPUUniformAttrList *key)
{
diff --git a/source/blender/draw/intern/draw_manager.c b/source/blender/draw/intern/draw_manager.c
index 6dfd434d5c7..da77845feb4 100644
--- a/source/blender/draw/intern/draw_manager.c
+++ b/source/blender/draw/intern/draw_manager.c
@@ -378,6 +378,8 @@ DRWData *DRW_viewport_data_create(void)
drw_data->views = BLI_memblock_create(sizeof(DRWView));
drw_data->images = BLI_memblock_create(sizeof(GPUTexture *));
drw_data->obattrs_ubo_pool = DRW_uniform_attrs_pool_new();
+ drw_data->vlattrs_name_cache = BLI_ghash_new(
+ BLI_ghashutil_inthash_p_simple, BLI_ghashutil_intcmp, "View Layer Attribute names");
{
uint chunk_len = sizeof(DRWObjectMatrix) * DRW_RESOURCE_CHUNK_LEN;
drw_data->obmats = BLI_memblock_create_ex(sizeof(DRWObjectMatrix), chunk_len);
@@ -413,9 +415,24 @@ static void draw_texture_release(DRWData *drw_data)
}
}
+static void draw_prune_vlattrs(DRWData *drw_data)
+{
+ drw_data->vlattrs_ubo_ready = false;
+
+ /* Forget known attributes after they are unused for a few frames. */
+ LISTBASE_FOREACH_MUTABLE (GPULayerAttr *, attr, &drw_data->vlattrs_name_list) {
+ if (++attr->users > 10) {
+ BLI_ghash_remove(
+ drw_data->vlattrs_name_cache, POINTER_FROM_UINT(attr->hash_code), NULL, NULL);
+ BLI_freelinkN(&drw_data->vlattrs_name_list, attr);
+ }
+ }
+}
+
static void drw_viewport_data_reset(DRWData *drw_data)
{
draw_texture_release(drw_data);
+ draw_prune_vlattrs(drw_data);
BLI_memblock_clear(drw_data->commands, NULL);
BLI_memblock_clear(drw_data->commands_small, NULL);
@@ -451,6 +468,12 @@ void DRW_viewport_data_free(DRWData *drw_data)
BLI_memblock_destroy(drw_data->passes, NULL);
BLI_memblock_destroy(drw_data->images, NULL);
DRW_uniform_attrs_pool_free(drw_data->obattrs_ubo_pool);
+ BLI_ghash_free(drw_data->vlattrs_name_cache, NULL, NULL);
+ BLI_freelistN(&drw_data->vlattrs_name_list);
+ if (drw_data->vlattrs_ubo) {
+ GPU_uniformbuf_free(drw_data->vlattrs_ubo);
+ MEM_freeN(drw_data->vlattrs_buf);
+ }
DRW_instance_data_list_free(drw_data->idatalist);
DRW_texture_pool_free(drw_data->texture_pool);
for (int i = 0; i < 2; i++) {
@@ -811,6 +834,7 @@ static bool id_type_can_have_drawdata(const short id_type)
/* has DrawData */
case ID_OB:
case ID_WO:
+ case ID_SCE:
return true;
/* no DrawData */
diff --git a/source/blender/draw/intern/draw_manager.cc b/source/blender/draw/intern/draw_manager.cc
index 169d86b2ea1..c644cadd18c 100644
--- a/source/blender/draw/intern/draw_manager.cc
+++ b/source/blender/draw/intern/draw_manager.cc
@@ -35,6 +35,7 @@ void Manager::begin_sync()
}
acquired_textures.clear();
+ layer_attributes.clear();
#ifdef DEBUG
/* Detect uninitialized data. */
@@ -52,14 +53,46 @@ void Manager::begin_sync()
resource_handle(float4x4::identity());
}
+void Manager::sync_layer_attributes()
+{
+ /* Sort the attribute IDs - the shaders use binary search. */
+ Vector<uint32_t> id_list;
+
+ id_list.reserve(layer_attributes.size());
+
+ for (uint32_t id : layer_attributes.keys()) {
+ id_list.append(id);
+ }
+
+ std::sort(id_list.begin(), id_list.end());
+
+ /* Look up the attributes. */
+ int count = 0, size = layer_attributes_buf.end() - layer_attributes_buf.begin();
+
+ for (uint32_t id : id_list) {
+ if (layer_attributes_buf[count].sync(
+ DST.draw_ctx.scene, DST.draw_ctx.view_layer, layer_attributes.lookup(id))) {
+ /* Check if the buffer is full. */
+ if (++count == size) {
+ break;
+ }
+ }
+ }
+
+ layer_attributes_buf[0].buffer_length = count;
+}
+
void Manager::end_sync()
{
GPU_debug_group_begin("Manager.end_sync");
+ sync_layer_attributes();
+
matrix_buf.push_update();
bounds_buf.push_update();
infos_buf.push_update();
attributes_buf.push_update();
+ layer_attributes_buf.push_update();
attributes_buf_legacy.push_update();
/* Useful for debugging the following resource finalize. But will trigger the drawing of the GPU
@@ -100,6 +133,7 @@ void Manager::resource_bind()
GPU_storagebuf_bind(matrix_buf, DRW_OBJ_MAT_SLOT);
GPU_storagebuf_bind(infos_buf, DRW_OBJ_INFOS_SLOT);
GPU_storagebuf_bind(attributes_buf, DRW_OBJ_ATTR_SLOT);
+ GPU_uniformbuf_bind(layer_attributes_buf, DRW_LAYER_ATTR_UBO_SLOT);
/* 2 is the hardcoded location of the uniform attr UBO. */
/* TODO(@fclem): Remove this workaround. */
GPU_uniformbuf_bind(attributes_buf_legacy, 2);
diff --git a/source/blender/draw/intern/draw_manager.h b/source/blender/draw/intern/draw_manager.h
index 6b5a2cc4f6f..52129049269 100644
--- a/source/blender/draw/intern/draw_manager.h
+++ b/source/blender/draw/intern/draw_manager.h
@@ -335,6 +335,7 @@ typedef enum {
DRW_UNIFORM_BLOCK_OBMATS,
DRW_UNIFORM_BLOCK_OBINFOS,
DRW_UNIFORM_BLOCK_OBATTRS,
+ DRW_UNIFORM_BLOCK_VLATTRS,
DRW_UNIFORM_RESOURCE_CHUNK,
DRW_UNIFORM_RESOURCE_ID,
/** Legacy / Fallback */
@@ -527,6 +528,11 @@ typedef struct DRWData {
struct GPUUniformBuf **matrices_ubo;
struct GPUUniformBuf **obinfos_ubo;
struct GHash *obattrs_ubo_pool;
+ struct GHash *vlattrs_name_cache;
+ struct ListBase vlattrs_name_list;
+ struct LayerAttribute *vlattrs_buf;
+ struct GPUUniformBuf *vlattrs_ubo;
+ bool vlattrs_ubo_ready;
uint ubo_len;
/** Per draw-call volume object data. */
void *volume_grids_ubos; /* VolumeUniformBufPool */
@@ -691,6 +697,8 @@ void drw_uniform_attrs_pool_update(struct GHash *table,
struct Object *dupli_parent,
struct DupliObject *dupli_source);
+GPUUniformBuf *drw_ensure_layer_attribute_buffer(void);
+
double *drw_engine_data_cache_time_get(GPUViewport *viewport);
void *drw_engine_data_engine_data_create(GPUViewport *viewport, void *engine_type);
void *drw_engine_data_engine_data_get(GPUViewport *viewport, void *engine_handle);
diff --git a/source/blender/draw/intern/draw_manager.hh b/source/blender/draw/intern/draw_manager.hh
index fbd3d28d3f4..0a865179cee 100644
--- a/source/blender/draw/intern/draw_manager.hh
+++ b/source/blender/draw/intern/draw_manager.hh
@@ -44,6 +44,7 @@ class Manager {
using ObjectBoundsBuf = StorageArrayBuffer<ObjectBounds, 128>;
using ObjectInfosBuf = StorageArrayBuffer<ObjectInfos, 128>;
using ObjectAttributeBuf = StorageArrayBuffer<ObjectAttribute, 128>;
+ using LayerAttributeBuf = UniformArrayBuffer<LayerAttribute, 512>;
/**
* TODO(@fclem): Remove once we get rid of old EEVEE code-base.
* `DRW_RESOURCE_CHUNK_LEN = 512`.
@@ -87,6 +88,16 @@ class Manager {
ObjectAttributeLegacyBuf attributes_buf_legacy;
/**
+ * Table of all View Layer attributes required by shaders, used to populate the buffer below.
+ */
+ Map<uint32_t, GPULayerAttr> layer_attributes;
+
+ /**
+ * Buffer of layer attribute values, indexed and sorted by the hash.
+ */
+ LayerAttributeBuf layer_attributes_buf;
+
+ /**
* List of textures coming from Image data-blocks.
* They need to be reference-counted in order to avoid being freed in another thread.
*/
@@ -131,6 +142,11 @@ class Manager {
Span<GPUMaterial *> materials);
/**
+ * Collect necessary View Layer attributes.
+ */
+ void register_layer_attributes(GPUMaterial *material);
+
+ /**
* Submit a pass for drawing. All resource reference will be dereferenced and commands will be
* sent to GPU.
*/
@@ -169,6 +185,9 @@ class Manager {
void debug_bind();
void resource_bind();
+
+ private:
+ void sync_layer_attributes();
};
inline ResourceHandle Manager::resource_handle(const ObjectRef ref)
@@ -229,6 +248,19 @@ inline void Manager::extract_object_attributes(ResourceHandle handle,
}
}
+inline void Manager::register_layer_attributes(GPUMaterial *material)
+{
+ const ListBase *attr_list = GPU_material_layer_attributes(material);
+
+ if (attr_list != nullptr) {
+ LISTBASE_FOREACH (const GPULayerAttr *, attr, attr_list) {
+ /** Since layer attributes are global to the whole render pass,
+ * this only collects a table of their names. */
+ layer_attributes.add(attr->hash_code, *attr);
+ }
+ }
+}
+
} // namespace blender::draw
/* TODO(@fclem): This is for testing. The manager should be passed to the engine through the
diff --git a/source/blender/draw/intern/draw_manager_data.cc b/source/blender/draw/intern/draw_manager_data.cc
index 2d0ea58b6e5..0312eecc7b7 100644
--- a/source/blender/draw/intern/draw_manager_data.cc
+++ b/source/blender/draw/intern/draw_manager_data.cc
@@ -695,7 +695,7 @@ static void drw_call_obinfos_init(DRWObjectInfos *ob_infos, Object *ob)
drw_call_calc_orco(ob, ob_infos->orcotexfac);
/* Random float value. */
uint random = (DST.dupli_source) ?
- DST.dupli_source->random_id :
+ DST.dupli_source->random_id :
/* TODO(fclem): this is rather costly to do at runtime. Maybe we can
* put it in ob->runtime and make depsgraph ensure it is up to date. */
BLI_hash_int_2d(BLI_hash_string(ob->id.name + 2), 0);
@@ -1348,7 +1348,7 @@ static void drw_sculpt_generate_calls(DRWSculptCallbackData *scd)
}
Mesh *mesh = static_cast<Mesh *>(scd->ob->data);
- BKE_pbvh_update_normals(pbvh, mesh->runtime.subdiv_ccg);
+ BKE_pbvh_update_normals(pbvh, mesh->runtime->subdiv_ccg);
BKE_pbvh_draw_cb(pbvh,
update_only_visible,
@@ -1841,6 +1841,13 @@ void DRW_shgroup_add_material_resources(DRWShadingGroup *grp, GPUMaterial *mater
grp, loc, DRW_UNIFORM_BLOCK_OBATTRS, uattrs, GPU_SAMPLER_DEFAULT, 0, 1);
grp->uniform_attrs = uattrs;
}
+
+ if (GPU_material_layer_attributes(material) != NULL) {
+ int loc = GPU_shader_get_uniform_block_binding(grp->shader,
+ GPU_LAYER_ATTRIBUTE_UBO_BLOCK_NAME);
+ drw_shgroup_uniform_create_ex(
+ grp, loc, DRW_UNIFORM_BLOCK_VLATTRS, nullptr, GPU_SAMPLER_DEFAULT, 0, 1);
+ }
}
GPUVertFormat *DRW_shgroup_instance_format_array(const DRWInstanceAttrFormat attrs[],
diff --git a/source/blender/draw/intern/draw_manager_exec.c b/source/blender/draw/intern/draw_manager_exec.c
index 3627b0fbf10..8b1b35b5f03 100644
--- a/source/blender/draw/intern/draw_manager_exec.c
+++ b/source/blender/draw/intern/draw_manager_exec.c
@@ -44,6 +44,7 @@ typedef struct DRWCommandsState {
int obmats_loc;
int obinfos_loc;
int obattrs_loc;
+ int vlattrs_loc;
int baseinst_loc;
int chunkid_loc;
int resourceid_loc;
@@ -682,6 +683,10 @@ static void draw_update_uniforms(DRWShadingGroup *shgroup,
uni->uniform_attrs);
DRW_sparse_uniform_buffer_bind(state->obattrs_ubo, 0, uni->location);
break;
+ case DRW_UNIFORM_BLOCK_VLATTRS:
+ state->vlattrs_loc = uni->location;
+ GPU_uniformbuf_bind(drw_ensure_layer_attribute_buffer(), uni->location);
+ break;
case DRW_UNIFORM_RESOURCE_CHUNK:
state->chunkid_loc = uni->location;
GPU_shader_uniform_int(shgroup->shader, uni->location, 0);
@@ -960,6 +965,9 @@ static void draw_call_batching_finish(DRWShadingGroup *shgroup, DRWCommandsState
if (state->obattrs_loc != -1) {
DRW_sparse_uniform_buffer_unbind(state->obattrs_ubo, state->resource_chunk);
}
+ if (state->vlattrs_loc != -1) {
+ GPU_uniformbuf_unbind(DST.vmempool->vlattrs_ubo);
+ }
}
static void draw_shgroup(DRWShadingGroup *shgroup, DRWState pass_state)
@@ -970,6 +978,7 @@ static void draw_shgroup(DRWShadingGroup *shgroup, DRWState pass_state)
.obmats_loc = -1,
.obinfos_loc = -1,
.obattrs_loc = -1,
+ .vlattrs_loc = -1,
.baseinst_loc = -1,
.chunkid_loc = -1,
.resourceid_loc = -1,
diff --git a/source/blender/draw/intern/draw_manager_shader.c b/source/blender/draw/intern/draw_manager_shader.c
index 04a9f3fdd2d..40b05dff51f 100644
--- a/source/blender/draw/intern/draw_manager_shader.c
+++ b/source/blender/draw/intern/draw_manager_shader.c
@@ -237,6 +237,42 @@ static void drw_deferred_shader_add(GPUMaterial *mat, bool deferred)
WM_jobs_start(wm, wm_job);
}
+static void drw_register_shader_vlattrs(GPUMaterial *mat)
+{
+ const ListBase *attrs = GPU_material_layer_attributes(mat);
+
+ if (!attrs) {
+ return;
+ }
+
+ GHash *hash = DST.vmempool->vlattrs_name_cache;
+ ListBase *list = &DST.vmempool->vlattrs_name_list;
+
+ LISTBASE_FOREACH (GPULayerAttr *, attr, attrs) {
+ GPULayerAttr **p_val;
+
+ /* Add to the table and list if newly seen. */
+ if (!BLI_ghash_ensure_p(hash, POINTER_FROM_UINT(attr->hash_code), (void ***)&p_val)) {
+ DST.vmempool->vlattrs_ubo_ready = false;
+
+ GPULayerAttr *new_link = *p_val = MEM_dupallocN(attr);
+
+ /* Insert into the list ensuring sorted order. */
+ GPULayerAttr *link = list->first;
+
+ while (link && link->hash_code <= attr->hash_code) {
+ link = link->next;
+ }
+
+ new_link->prev = new_link->next = NULL;
+ BLI_insertlinkbefore(list, link, new_link);
+ }
+
+ /* Reset the unused frames counter. */
+ (*p_val)->users = 0;
+ }
+}
+
void DRW_deferred_shader_remove(GPUMaterial *mat)
{
LISTBASE_FOREACH (wmWindowManager *, wm, &G_MAIN->wm) {
@@ -382,6 +418,9 @@ GPUMaterial *DRW_shader_from_world(World *wo,
false,
callback,
thunk);
+
+ drw_register_shader_vlattrs(mat);
+
if (DRW_state_is_image_render()) {
/* Do not deferred if doing render. */
deferred = false;
@@ -411,6 +450,8 @@ GPUMaterial *DRW_shader_from_material(Material *ma,
callback,
thunk);
+ drw_register_shader_vlattrs(mat);
+
if (DRW_state_is_image_render()) {
/* Do not deferred if doing render. */
deferred = false;
diff --git a/source/blender/draw/intern/draw_manager_text.cc b/source/blender/draw/intern/draw_manager_text.cc
index d41127c3641..100ef528bc8 100644
--- a/source/blender/draw/intern/draw_manager_text.cc
+++ b/source/blender/draw/intern/draw_manager_text.cc
@@ -15,6 +15,7 @@
#include "BKE_editmesh.h"
#include "BKE_editmesh_cache.h"
#include "BKE_global.h"
+#include "BKE_mesh.h"
#include "BKE_unit.h"
#include "DNA_mesh_types.h"
@@ -233,8 +234,8 @@ void DRW_text_edit_mesh_measure_stats(ARegion *region,
float clip_planes[4][4];
/* allow for displaying shape keys and deform mods */
BMIter iter;
- const float(*vert_coords)[3] = (me->runtime.edit_data ? me->runtime.edit_data->vertexCos :
- nullptr);
+ const float(*vert_coords)[3] = (me->runtime->edit_data ? me->runtime->edit_data->vertexCos :
+ nullptr);
const bool use_coords = (vert_coords != nullptr);
/* when 2 or more edge-info options are enabled, space apart */
@@ -339,8 +340,8 @@ void DRW_text_edit_mesh_measure_stats(ARegion *region,
const float(*poly_normals)[3] = nullptr;
if (use_coords) {
BM_mesh_elem_index_ensure(em->bm, BM_VERT | BM_FACE);
- BKE_editmesh_cache_ensure_poly_normals(em, me->runtime.edit_data);
- poly_normals = me->runtime.edit_data->polyNos;
+ BKE_editmesh_cache_ensure_poly_normals(em, me->runtime->edit_data);
+ poly_normals = me->runtime->edit_data->polyNos;
}
BM_ITER_MESH (eed, &iter, em->bm, BM_EDGES_OF_MESH) {
diff --git a/source/blender/draw/intern/draw_pass.hh b/source/blender/draw/intern/draw_pass.hh
index ee2180712d1..24dfdd1b97b 100644
--- a/source/blender/draw/intern/draw_pass.hh
+++ b/source/blender/draw/intern/draw_pass.hh
@@ -174,9 +174,15 @@ class PassBase {
/**
* Reminders:
- * - (compare_mask & reference) is what is tested against (compare_mask & stencil_value)
+ * - `compare_mask & reference` is what is tested against `compare_mask & stencil_value`
* stencil_value being the value stored in the stencil buffer.
- * - (write-mask & reference) is what gets written if the test condition is fulfilled.
+ * - `write-mask & reference` is what gets written if the test condition is fulfilled.
+ *
+ * This will modify the stencil state until another call to this function.
+ * If not specified before any draw-call, these states will be undefined.
+ *
+ * For more information see:
+ * https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkStencilOpState.html
*/
void state_stencil(uint8_t write_mask, uint8_t reference, uint8_t compare_mask);
@@ -728,7 +734,7 @@ template<class T> inline void PassBase<T>::state_set(DRWState state)
template<class T>
inline void PassBase<T>::state_stencil(uint8_t write_mask, uint8_t reference, uint8_t compare_mask)
{
- create_command(Type::StencilSet).stencil_set = {write_mask, reference, compare_mask};
+ create_command(Type::StencilSet).stencil_set = {write_mask, compare_mask, reference};
}
template<class T> inline void PassBase<T>::shader_set(GPUShader *shader)
diff --git a/source/blender/draw/intern/draw_pbvh.cc b/source/blender/draw/intern/draw_pbvh.cc
index cab260f87ac..60a0d4e6bb2 100644
--- a/source/blender/draw/intern/draw_pbvh.cc
+++ b/source/blender/draw/intern/draw_pbvh.cc
@@ -389,12 +389,19 @@ struct PBVHBatches {
break;
case CD_PBVH_MASK_TYPE:
- foreach_grids([&](int /*x*/, int /*y*/, int /*grid_index*/, CCGElem *elems[4], int i) {
- float *mask = CCG_elem_mask(&args->ccg_key, elems[i]);
+ if (args->ccg_key.has_mask) {
+ foreach_grids([&](int /*x*/, int /*y*/, int /*grid_index*/, CCGElem *elems[4], int i) {
+ float *mask = CCG_elem_mask(&args->ccg_key, elems[i]);
- *static_cast<uchar *>(GPU_vertbuf_raw_step(&access)) = mask ? uchar(*mask * 255.0f) :
- 255;
- });
+ *static_cast<uchar *>(GPU_vertbuf_raw_step(&access)) = uchar(*mask * 255.0f);
+ });
+ }
+ else {
+ foreach_grids(
+ [&](int /*x*/, int /*y*/, int /*grid_index*/, CCGElem * /*elems*/[4], int i) {
+ *static_cast<uchar *>(GPU_vertbuf_raw_step(&access)) = 0;
+ });
+ }
break;
case CD_PBVH_FSET_TYPE: {
@@ -1158,8 +1165,17 @@ struct PBVHBatches {
}
for (PBVHBatch &batch : batches.values()) {
- GPU_batch_elembuf_set(batch.tris, tri_index, false);
- GPU_batch_elembuf_set(batch.lines, lines_index, false);
+ if (tri_index) {
+ GPU_batch_elembuf_set(batch.tris, tri_index, false);
+ }
+ else {
+ /* Still flag the batch as dirty even if we're using the default index layout. */
+ batch.tris->flag |= GPU_BATCH_DIRTY;
+ }
+
+ if (lines_index) {
+ GPU_batch_elembuf_set(batch.lines, lines_index, false);
+ }
}
}
diff --git a/source/blender/draw/intern/draw_resource.cc b/source/blender/draw/intern/draw_resource.cc
index f57058190fb..c1f83c3a5ae 100644
--- a/source/blender/draw/intern/draw_resource.cc
+++ b/source/blender/draw/intern/draw_resource.cc
@@ -38,3 +38,16 @@ bool ObjectAttribute::sync(const blender::draw::ObjectRef &ref, const GPUUniform
}
/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name LayerAttributes
+ * \{ */
+
+bool LayerAttribute::sync(Scene *scene, ViewLayer *layer, const GPULayerAttr &attr)
+{
+ hash_code = attr.hash_code;
+
+ return BKE_view_layer_find_rgba_attribute(scene, layer, attr.name, &data.x);
+}
+
+/** \} */
diff --git a/source/blender/draw/intern/draw_shader_shared.h b/source/blender/draw/intern/draw_shader_shared.h
index 37899e36d8a..75a7e28fa75 100644
--- a/source/blender/draw/intern/draw_shader_shared.h
+++ b/source/blender/draw/intern/draw_shader_shared.h
@@ -15,6 +15,7 @@ typedef struct ObjectBounds ObjectBounds;
typedef struct VolumeInfos VolumeInfos;
typedef struct CurvesInfos CurvesInfos;
typedef struct ObjectAttribute ObjectAttribute;
+typedef struct LayerAttribute LayerAttribute;
typedef struct DrawCommand DrawCommand;
typedef struct DispatchCommand DispatchCommand;
typedef struct DRWDebugPrintBuffer DRWDebugPrintBuffer;
@@ -24,8 +25,10 @@ typedef struct DRWDebugDrawBuffer DRWDebugDrawBuffer;
# ifdef __cplusplus
/* C++ only forward declarations. */
struct Object;
+struct ViewLayer;
struct ID;
struct GPUUniformAttr;
+struct GPULayerAttr;
namespace blender::draw {
@@ -192,6 +195,20 @@ struct ObjectAttribute {
* C++ compiler gives us the same size. */
BLI_STATIC_ASSERT_ALIGN(ObjectAttribute, 20)
+#pragma pack(push, 4)
+struct LayerAttribute {
+ float4 data;
+ uint hash_code;
+ uint buffer_length; /* Only in the first record. */
+ uint _pad1, _pad2;
+
+#if !defined(GPU_SHADER) && defined(__cplusplus)
+ bool sync(Scene *scene, ViewLayer *layer, const GPULayerAttr &attr);
+#endif
+};
+#pragma pack(pop)
+BLI_STATIC_ASSERT_ALIGN(LayerAttribute, 32)
+
/** \} */
/* -------------------------------------------------------------------- */
diff --git a/source/blender/draw/intern/draw_view.hh b/source/blender/draw/intern/draw_view.hh
index 4fc74e3e890..94fb62508bb 100644
--- a/source/blender/draw/intern/draw_view.hh
+++ b/source/blender/draw/intern/draw_view.hh
@@ -79,6 +79,26 @@ class View {
return -(data_.winmat[3][2] + 1.0f) / data_.winmat[2][2];
}
+ const float4x4 &viewmat() const
+ {
+ return data_.viewmat;
+ }
+
+ const float4x4 &viewinv() const
+ {
+ return data_.viewinv;
+ }
+
+ const float4x4 &winmat() const
+ {
+ return data_.winmat;
+ }
+
+ const float4x4 &wininv() const
+ {
+ return data_.wininv;
+ }
+
private:
/** Called from draw manager. */
void bind();
diff --git a/source/blender/draw/intern/mesh_extractors/extract_mesh.hh b/source/blender/draw/intern/mesh_extractors/extract_mesh.hh
index d9bb8d1d2b4..c6230e2695e 100644
--- a/source/blender/draw/intern/mesh_extractors/extract_mesh.hh
+++ b/source/blender/draw/intern/mesh_extractors/extract_mesh.hh
@@ -16,6 +16,8 @@
#include "BKE_customdata.h"
#include "BKE_editmesh.h"
+#include "BKE_editmesh_cache.h"
+#include "BKE_mesh.h"
#include "draw_cache_extract.hh"
@@ -116,7 +118,7 @@ BLI_INLINE const Mesh *editmesh_final_or_this(const Object *object, const Mesh *
BLI_INLINE const CustomData *mesh_cd_ldata_get_from_mesh(const Mesh *me)
{
- switch ((eMeshWrapperType)me->runtime.wrapper_type) {
+ switch (me->runtime->wrapper_type) {
case ME_WRAPPER_TYPE_SUBD:
case ME_WRAPPER_TYPE_MDATA:
return &me->ldata;
@@ -132,7 +134,7 @@ BLI_INLINE const CustomData *mesh_cd_ldata_get_from_mesh(const Mesh *me)
BLI_INLINE const CustomData *mesh_cd_pdata_get_from_mesh(const Mesh *me)
{
- switch ((eMeshWrapperType)me->runtime.wrapper_type) {
+ switch (me->runtime->wrapper_type) {
case ME_WRAPPER_TYPE_SUBD:
case ME_WRAPPER_TYPE_MDATA:
return &me->pdata;
@@ -148,7 +150,7 @@ BLI_INLINE const CustomData *mesh_cd_pdata_get_from_mesh(const Mesh *me)
BLI_INLINE const CustomData *mesh_cd_edata_get_from_mesh(const Mesh *me)
{
- switch ((eMeshWrapperType)me->runtime.wrapper_type) {
+ switch (me->runtime->wrapper_type) {
case ME_WRAPPER_TYPE_SUBD:
case ME_WRAPPER_TYPE_MDATA:
return &me->edata;
@@ -164,7 +166,7 @@ BLI_INLINE const CustomData *mesh_cd_edata_get_from_mesh(const Mesh *me)
BLI_INLINE const CustomData *mesh_cd_vdata_get_from_mesh(const Mesh *me)
{
- switch ((eMeshWrapperType)me->runtime.wrapper_type) {
+ switch (me->runtime->wrapper_type) {
case ME_WRAPPER_TYPE_SUBD:
case ME_WRAPPER_TYPE_MDATA:
return &me->vdata;
diff --git a/source/blender/draw/intern/mesh_extractors/extract_mesh_ibo_edituv.cc b/source/blender/draw/intern/mesh_extractors/extract_mesh_ibo_edituv.cc
index be919b1af67..e40503a9707 100644
--- a/source/blender/draw/intern/mesh_extractors/extract_mesh_ibo_edituv.cc
+++ b/source/blender/draw/intern/mesh_extractors/extract_mesh_ibo_edituv.cc
@@ -557,7 +557,7 @@ static void extract_edituv_fdots_iter_poly_mesh(const MeshRenderData *mr,
const bool mp_select = (efa) ? BM_elem_flag_test_bool(efa, BM_ELEM_SELECT) : false;
if (mr->use_subsurf_fdots) {
- const BLI_bitmap *facedot_tags = mr->me->runtime.subsurf_face_dot_tags;
+ const BLI_bitmap *facedot_tags = mr->me->runtime->subsurf_face_dot_tags;
const MLoop *mloop = mr->mloop;
const int ml_index_end = mp->loopstart + mp->totloop;
diff --git a/source/blender/draw/intern/mesh_extractors/extract_mesh_ibo_fdots.cc b/source/blender/draw/intern/mesh_extractors/extract_mesh_ibo_fdots.cc
index d964f608e52..1b552b01d6b 100644
--- a/source/blender/draw/intern/mesh_extractors/extract_mesh_ibo_fdots.cc
+++ b/source/blender/draw/intern/mesh_extractors/extract_mesh_ibo_fdots.cc
@@ -46,7 +46,7 @@ static void extract_fdots_iter_poly_mesh(const MeshRenderData *mr,
GPUIndexBufBuilder *elb = static_cast<GPUIndexBufBuilder *>(_userdata);
if (mr->use_subsurf_fdots) {
- const BLI_bitmap *facedot_tags = mr->me->runtime.subsurf_face_dot_tags;
+ const BLI_bitmap *facedot_tags = mr->me->runtime->subsurf_face_dot_tags;
const MLoop *mloop = mr->mloop;
const int ml_index_end = mp->loopstart + mp->totloop;
diff --git a/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_fdots_pos.cc b/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_fdots_pos.cc
index 6d93a482623..d43eb6117df 100644
--- a/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_fdots_pos.cc
+++ b/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_fdots_pos.cc
@@ -77,7 +77,7 @@ static void extract_fdots_pos_iter_poly_mesh(const MeshRenderData *mr,
const MVert *mvert = mr->mvert;
const MLoop *mloop = mr->mloop;
- const BLI_bitmap *facedot_tags = mr->me->runtime.subsurf_face_dot_tags;
+ const BLI_bitmap *facedot_tags = mr->me->runtime->subsurf_face_dot_tags;
const int ml_index_end = mp->loopstart + mp->totloop;
for (int ml_index = mp->loopstart; ml_index < ml_index_end; ml_index += 1) {
diff --git a/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_fdots_uv.cc b/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_fdots_uv.cc
index 96240af2ee6..802f000cb43 100644
--- a/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_fdots_uv.cc
+++ b/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_fdots_uv.cc
@@ -74,7 +74,7 @@ static void extract_fdots_uv_iter_poly_mesh(const MeshRenderData *mr,
void *_data)
{
MeshExtract_FdotUV_Data *data = static_cast<MeshExtract_FdotUV_Data *>(_data);
- const BLI_bitmap *facedot_tags = mr->me->runtime.subsurf_face_dot_tags;
+ const BLI_bitmap *facedot_tags = mr->me->runtime->subsurf_face_dot_tags;
const MLoop *mloop = mr->mloop;
const int ml_index_end = mp->loopstart + mp->totloop;
diff --git a/source/blender/draw/intern/shaders/draw_object_infos_info.hh b/source/blender/draw/intern/shaders/draw_object_infos_info.hh
index ad0426e6d3f..33634fb5fcb 100644
--- a/source/blender/draw/intern/shaders/draw_object_infos_info.hh
+++ b/source/blender/draw/intern/shaders/draw_object_infos_info.hh
@@ -19,6 +19,14 @@ GPU_SHADER_CREATE_INFO(draw_curves_infos)
.typedef_source("draw_shader_shared.h")
.uniform_buf(3, "CurvesInfos", "drw_curves", Frequency::BATCH);
+GPU_SHADER_CREATE_INFO(draw_layer_attributes)
+ .typedef_source("draw_shader_shared.h")
+ .define("VLATTR_LIB")
+ .uniform_buf(DRW_LAYER_ATTR_UBO_SLOT,
+ "LayerAttribute",
+ "drw_layer_attrs[DRW_RESOURCE_CHUNK_LEN]",
+ Frequency::BATCH);
+
GPU_SHADER_CREATE_INFO(draw_object_infos_new)
.typedef_source("draw_shader_shared.h")
.define("OBINFO_LIB")
diff --git a/source/blender/editors/curve/editcurve.c b/source/blender/editors/curve/editcurve.c
index cb6652507ed..61e92f0a1c3 100644
--- a/source/blender/editors/curve/editcurve.c
+++ b/source/blender/editors/curve/editcurve.c
@@ -1707,6 +1707,10 @@ static void ed_surf_delete_selected(Object *obedit)
bp++;
}
if (a == 0) {
+ if (cu->actnu == BLI_findindex(editnurb, nu)) {
+ cu->actnu = CU_ACT_NONE;
+ }
+
BLI_remlink(editnurb, nu);
keyIndex_delNurb(cu->editnurb, nu);
BKE_nurb_free(nu);
@@ -6483,6 +6487,7 @@ static int curve_delete_exec(bContext *C, wmOperator *op)
}
else if (type == CURVE_SEGMENT) {
changed = curve_delete_segments(obedit, v3d, false);
+ cu->actnu = CU_ACT_NONE;
}
else {
BLI_assert(0);
@@ -6490,7 +6495,7 @@ static int curve_delete_exec(bContext *C, wmOperator *op)
if (changed) {
changed_multi = true;
- cu->actnu = cu->actvert = CU_ACT_NONE;
+ cu->actvert = CU_ACT_NONE;
if (ED_curve_updateAnimPaths(bmain, obedit->data)) {
WM_event_add_notifier(C, NC_OBJECT | ND_KEYS, obedit);
diff --git a/source/blender/editors/gpencil/gpencil_data.c b/source/blender/editors/gpencil/gpencil_data.c
index 340288b2d74..c6d7eb294fb 100644
--- a/source/blender/editors/gpencil/gpencil_data.c
+++ b/source/blender/editors/gpencil/gpencil_data.c
@@ -623,6 +623,7 @@ void GPENCIL_OT_layer_duplicate_object(wmOperatorType *ot)
true,
"Only Active",
"Copy only active Layer, uncheck to append all layers");
+ RNA_def_property_translation_context(prop, BLT_I18NCONTEXT_ID_GPENCIL);
RNA_def_property_flag(prop, PROP_HIDDEN | PROP_SKIP_SAVE);
}
@@ -3686,6 +3687,7 @@ void GPENCIL_OT_materials_copy_to_object(wmOperatorType *ot)
true,
"Only Active",
"Append only active material, uncheck to append all materials");
+ RNA_def_property_translation_context(prop, BLT_I18NCONTEXT_ID_GPENCIL);
RNA_def_property_flag(prop, PROP_HIDDEN | PROP_SKIP_SAVE);
}
diff --git a/source/blender/editors/include/ED_node.h b/source/blender/editors/include/ED_node.h
index c30b8c5ec6a..24e14fdce72 100644
--- a/source/blender/editors/include/ED_node.h
+++ b/source/blender/editors/include/ED_node.h
@@ -87,17 +87,6 @@ void ED_node_tag_update_id(struct ID *id);
float ED_node_grid_size(void);
-/* node_relationships.cc */
-
-/**
- * Test == 0, clear all intersect flags.
- */
-void ED_node_link_intersect_test(struct ScrArea *area, int test);
-/**
- * Assumes link with #NODE_LINKFLAG_HILITE set.
- */
-void ED_node_link_insert(struct Main *bmain, struct ScrArea *area);
-
/* node_edit.cc */
void ED_node_set_tree_type(struct SpaceNode *snode, struct bNodeTreeType *typeinfo);
@@ -186,3 +175,20 @@ bool ED_space_node_color_sample(struct Main *bmain,
#ifdef __cplusplus
}
#endif
+
+#ifdef __cplusplus
+
+/* node_relationships.cc */
+
+namespace blender::ed::space_node {
+
+void node_insert_on_link_flags_set(SpaceNode &snode, const ARegion &region);
+/**
+ * Assumes link with #NODE_LINKFLAG_HILITE set.
+ */
+void node_insert_on_link_flags(Main &bmain, SpaceNode &snode);
+void node_insert_on_link_flags_clear(bNodeTree &node_tree);
+
+} // namespace blender::ed::space_node
+
+#endif \ No newline at end of file
diff --git a/source/blender/editors/include/ED_uvedit.h b/source/blender/editors/include/ED_uvedit.h
index b499ae0ce59..c8ffbb9acb1 100644
--- a/source/blender/editors/include/ED_uvedit.h
+++ b/source/blender/editors/include/ED_uvedit.h
@@ -339,12 +339,20 @@ bool ED_uvedit_udim_params_from_image_space(const struct SpaceImage *sima,
bool use_active,
struct UVMapUDIM_Params *udim_params);
+typedef enum {
+ ED_UVPACK_MARGIN_SCALED = 0, /* Use scale of existing UVs to multiply margin. */
+ ED_UVPACK_MARGIN_ADD, /* Just add the margin, ignoring any UV scale. */
+ ED_UVPACK_MARGIN_FRACTION, /* Specify a precise fraction of final UV output. */
+} eUVPackIsland_MarginMethod;
+
struct UVPackIsland_Params {
uint rotate : 1;
uint only_selected_uvs : 1;
uint only_selected_faces : 1;
uint use_seams : 1;
uint correct_aspect : 1;
+ eUVPackIsland_MarginMethod margin_method; /* Which formula to use when scaling island margin. */
+ float margin; /* Additional space to add around each island. */
};
/**
@@ -353,9 +361,24 @@ struct UVPackIsland_Params {
bool uv_coords_isect_udim(const struct Image *image,
const int udim_grid[2],
const float coords[2]);
+
+/**
+ * Pack UV islands from multiple objects.
+ *
+ * \param scene: Scene containing the objects to be packed.
+ * \param objects: Array of Objects to pack.
+ * \param objects_len: Length of `objects` array.
+ * \param bmesh_override: BMesh array aligned with `objects`.
+ * Optional, when non-null this overrides object's BMesh.
+ * This is needed to perform UV packing on objects that aren't in edit-mode.
+ * \param udim_params: Parameters to specify UDIM target and UDIM source image.
+ * \param params: Parameters and options to pass to the packing engine.
+ *
+ */
void ED_uvedit_pack_islands_multi(const struct Scene *scene,
Object **objects,
uint objects_len,
+ struct BMesh **bmesh_override,
const struct UVMapUDIM_Params *udim_params,
const struct UVPackIsland_Params *params);
diff --git a/source/blender/editors/include/UI_view2d.h b/source/blender/editors/include/UI_view2d.h
index c357b67722d..f0bf04ed408 100644
--- a/source/blender/editors/include/UI_view2d.h
+++ b/source/blender/editors/include/UI_view2d.h
@@ -103,7 +103,7 @@ enum eView2D_CommonViewTypes {
/** \} */
/* -------------------------------------------------------------------- */
-/** \name Foeard Declarations
+/** \name Forward Declarations
* \{ */
struct View2D;
diff --git a/source/blender/editors/interface/interface_dropboxes.cc b/source/blender/editors/interface/interface_dropboxes.cc
index ebfde05f516..60e1c0abfa1 100644
--- a/source/blender/editors/interface/interface_dropboxes.cc
+++ b/source/blender/editors/interface/interface_dropboxes.cc
@@ -89,7 +89,7 @@ static void ui_drop_material_copy(bContext * /*C*/, wmDrag *drag, wmDropBox *dro
static char *ui_drop_material_tooltip(bContext *C,
wmDrag *drag,
- const int UNUSED(xy[2]),
+ const int /*xy*/[2],
struct wmDropBox * /*drop*/)
{
PointerRNA rna_ptr = CTX_data_pointer_get_type(C, "object", &RNA_Object);
diff --git a/source/blender/editors/interface/interface_region_menu_pie.cc b/source/blender/editors/interface/interface_region_menu_pie.cc
index 9dd6f95e190..f443dd43a3a 100644
--- a/source/blender/editors/interface/interface_region_menu_pie.cc
+++ b/source/blender/editors/interface/interface_region_menu_pie.cc
@@ -222,7 +222,7 @@ int UI_pie_menu_invoke(struct bContext *C, const char *idname, const wmEvent *ev
return (OPERATOR_CANCELLED | OPERATOR_PASS_THROUGH);
}
- pie = UI_pie_menu_begin(C, IFACE_(mt->label), ICON_NONE, event);
+ pie = UI_pie_menu_begin(C, CTX_IFACE_(mt->translation_context, mt->label), ICON_NONE, event);
layout = UI_pie_menu_layout(pie);
UI_menutype_draw(C, mt, layout);
diff --git a/source/blender/editors/interface/interface_region_menu_popup.cc b/source/blender/editors/interface/interface_region_menu_popup.cc
index f88cabb2b70..569f657a544 100644
--- a/source/blender/editors/interface/interface_region_menu_popup.cc
+++ b/source/blender/editors/interface/interface_region_menu_popup.cc
@@ -175,11 +175,7 @@ struct uiPopupMenu {
static uiBlock *ui_block_func_POPUP(bContext *C, uiPopupBlockHandle *handle, void *arg_pup)
{
- uiBlock *block;
uiPopupMenu *pup = static_cast<uiPopupMenu *>(arg_pup);
- int minwidth, width, height;
- char direction;
- bool flip;
if (pup->menu_func) {
pup->block->handle = handle;
@@ -188,6 +184,7 @@ static uiBlock *ui_block_func_POPUP(bContext *C, uiPopupBlockHandle *handle, voi
}
/* Find block minimum width. */
+ int minwidth;
if (uiLayoutGetUnitsX(pup->layout) != 0.0f) {
/* Use the minimum width from the layout if it's set. */
minwidth = uiLayoutGetUnitsX(pup->layout) * UI_UNIT_X;
@@ -207,6 +204,7 @@ static uiBlock *ui_block_func_POPUP(bContext *C, uiPopupBlockHandle *handle, voi
}
/* Find block direction. */
+ char direction;
if (pup->but) {
if (pup->block->direction != 0) {
/* allow overriding the direction from menu_func */
@@ -220,9 +218,9 @@ static uiBlock *ui_block_func_POPUP(bContext *C, uiPopupBlockHandle *handle, voi
direction = UI_DIR_DOWN;
}
- flip = (direction == UI_DIR_DOWN);
+ bool flip = (direction == UI_DIR_DOWN);
- block = pup->block;
+ uiBlock *block = pup->block;
/* in some cases we create the block before the region,
* so we set it delayed here if necessary */
@@ -232,6 +230,7 @@ static uiBlock *ui_block_func_POPUP(bContext *C, uiPopupBlockHandle *handle, voi
block->direction = direction;
+ int width, height;
UI_block_layout_resolve(block, &width, &height);
UI_block_flag_enable(block, UI_BLOCK_MOVEMOUSE_QUIT);
@@ -318,7 +317,6 @@ uiPopupBlockHandle *ui_popup_menu_create(
{
wmWindow *window = CTX_wm_window(C);
const uiStyle *style = UI_style_get_dpi();
- uiPopupBlockHandle *handle;
uiPopupMenu *pup = MEM_cnew<uiPopupMenu>(__func__);
pup->block = UI_block_begin(C, nullptr, __func__, UI_EMBOSS_PULLDOWN);
@@ -357,7 +355,8 @@ uiPopupBlockHandle *ui_popup_menu_create(
pup->menu_func = menu_func;
pup->menu_arg = arg;
- handle = ui_popup_block_create(C, butregion, but, nullptr, ui_block_func_POPUP, pup, nullptr);
+ uiPopupBlockHandle *handle = ui_popup_block_create(
+ C, butregion, but, nullptr, ui_block_func_POPUP, pup, nullptr);
if (!but) {
handle->popup = true;
@@ -384,7 +383,6 @@ uiPopupMenu *UI_popup_menu_begin_ex(bContext *C,
{
const uiStyle *style = UI_style_get_dpi();
uiPopupMenu *pup = MEM_cnew<uiPopupMenu>(__func__);
- uiBut *but;
pup->block = UI_block_begin(C, nullptr, block_name, UI_EMBOSS_PULLDOWN);
pup->block->flag |= UI_BLOCK_POPUP_MEMORY | UI_BLOCK_IS_FLIP;
@@ -423,7 +421,7 @@ uiPopupMenu *UI_popup_menu_begin_ex(bContext *C,
"");
}
else {
- but = uiDefBut(
+ uiBut *but = uiDefBut(
pup->block, UI_BTYPE_LABEL, 0, title, 0, 0, 200, UI_UNIT_Y, nullptr, 0.0, 0.0, 0, 0, "");
but->drawflag = UI_BUT_TEXT_LEFT;
}
@@ -448,20 +446,20 @@ void UI_popup_menu_but_set(uiPopupMenu *pup, struct ARegion *butregion, uiBut *b
void UI_popup_menu_end(bContext *C, uiPopupMenu *pup)
{
wmWindow *window = CTX_wm_window(C);
- uiPopupBlockHandle *menu;
- uiBut *but = nullptr;
- ARegion *butregion = nullptr;
pup->popup = true;
pup->mx = window->eventstate->xy[0];
pup->my = window->eventstate->xy[1];
+ uiBut *but = nullptr;
+ ARegion *butregion = nullptr;
if (pup->but) {
but = pup->but;
butregion = pup->butregion;
}
- menu = ui_popup_block_create(C, butregion, but, nullptr, ui_block_func_POPUP, pup, nullptr);
+ uiPopupBlockHandle *menu = ui_popup_block_create(
+ C, butregion, but, nullptr, ui_block_func_POPUP, pup, nullptr);
menu->popup = true;
UI_popup_handlers_add(C, &window->modalhandlers, menu, 0);
@@ -545,8 +543,6 @@ void UI_popup_menu_reports(bContext *C, ReportList *reports)
int UI_popup_menu_invoke(bContext *C, const char *idname, ReportList *reports)
{
- uiPopupMenu *pup;
- uiLayout *layout;
MenuType *mt = WM_menutype_find(idname, true);
if (mt == nullptr) {
@@ -559,8 +555,9 @@ int UI_popup_menu_invoke(bContext *C, const char *idname, ReportList *reports)
return (OPERATOR_CANCELLED | OPERATOR_PASS_THROUGH);
}
- pup = UI_popup_menu_begin(C, IFACE_(mt->label), ICON_NONE);
- layout = UI_popup_menu_layout(pup);
+ uiPopupMenu *pup = UI_popup_menu_begin(
+ C, CTX_IFACE_(mt->translation_context, mt->label), ICON_NONE);
+ uiLayout *layout = UI_popup_menu_layout(pup);
UI_menutype_draw(C, mt, layout);
@@ -579,9 +576,9 @@ void UI_popup_block_invoke_ex(
bContext *C, uiBlockCreateFunc func, void *arg, uiFreeArgFunc arg_free, bool can_refresh)
{
wmWindow *window = CTX_wm_window(C);
- uiPopupBlockHandle *handle;
- handle = ui_popup_block_create(C, nullptr, nullptr, func, nullptr, arg, arg_free);
+ uiPopupBlockHandle *handle = ui_popup_block_create(
+ C, nullptr, nullptr, func, nullptr, arg, arg_free);
handle->popup = true;
/* It can be useful to disable refresh (even though it will work)
@@ -607,9 +604,9 @@ void UI_popup_block_ex(bContext *C,
wmOperator *op)
{
wmWindow *window = CTX_wm_window(C);
- uiPopupBlockHandle *handle;
- handle = ui_popup_block_create(C, nullptr, nullptr, func, nullptr, arg, nullptr);
+ uiPopupBlockHandle *handle = ui_popup_block_create(
+ C, nullptr, nullptr, func, nullptr, arg, nullptr);
handle->popup = true;
handle->retvalue = 1;
handle->can_refresh = true;
diff --git a/source/blender/editors/interface/interface_region_popup.cc b/source/blender/editors/interface/interface_region_popup.cc
index e93bc4c4bfe..e574cb30b23 100644
--- a/source/blender/editors/interface/interface_region_popup.cc
+++ b/source/blender/editors/interface/interface_region_popup.cc
@@ -69,7 +69,6 @@ static void ui_popup_block_position(wmWindow *window,
/* Compute button position in window coordinates using the source
* button region/block, to position the popup attached to it. */
rctf butrct;
-
if (!handle->refresh) {
ui_block_to_window_rctf(butregion, but->block, &butrct, &but->rect);
@@ -417,14 +416,13 @@ static void ui_popup_block_clip(wmWindow *window, uiBlock *block)
{
const float xmin_orig = block->rect.xmin;
const int margin = UI_SCREEN_MARGIN;
- int winx, winy;
if (block->flag & UI_BLOCK_NO_WIN_CLIP) {
return;
}
- winx = WM_window_pixels_x(window);
- winy = WM_window_pixels_y(window);
+ const int winx = WM_window_pixels_x(window);
+ const int winy = WM_window_pixels_y(window);
/* shift to left if outside of view */
if (block->rect.xmax > winx - margin) {
@@ -549,7 +547,6 @@ uiBlock *ui_popup_block_refresh(bContext *C,
void *arg = handle->popup_create_vars.arg;
uiBlock *block_old = static_cast<uiBlock *>(region->uiblocks.first);
- uiBlock *block;
handle->refresh = (block_old != nullptr);
@@ -561,6 +558,7 @@ uiBlock *ui_popup_block_refresh(bContext *C,
#endif
/* create ui block */
+ uiBlock *block;
if (create_func) {
block = create_func(C, region, arg);
}
@@ -618,16 +616,14 @@ uiBlock *ui_popup_block_refresh(bContext *C,
if (block->flag & UI_BLOCK_RADIAL) {
const int win_width = UI_SCREEN_MARGIN;
- int winx, winy;
-
- int x_offset = 0, y_offset = 0;
- winx = WM_window_pixels_x(window);
- winy = WM_window_pixels_y(window);
+ const int winx = WM_window_pixels_x(window);
+ const int winy = WM_window_pixels_y(window);
copy_v2_v2(block->pie_data.pie_center_init, block->pie_data.pie_center_spawned);
/* only try translation if area is large enough */
+ int x_offset = 0;
if (BLI_rctf_size_x(&block->rect) < winx - (2.0f * win_width)) {
if (block->rect.xmin < win_width) {
x_offset += win_width - block->rect.xmin;
@@ -637,6 +633,7 @@ uiBlock *ui_popup_block_refresh(bContext *C,
}
}
+ int y_offset = 0;
if (BLI_rctf_size_y(&block->rect) < winy - (2.0f * win_width)) {
if (block->rect.ymin < win_width) {
y_offset += win_width - block->rect.ymin;
@@ -756,9 +753,6 @@ uiPopupBlockHandle *ui_popup_block_create(bContext *C,
{
wmWindow *window = CTX_wm_window(C);
uiBut *activebut = UI_context_active_but_get(C);
- static ARegionType type;
- ARegion *region;
- uiBlock *block;
/* disable tooltips from buttons below */
if (activebut) {
@@ -787,9 +781,10 @@ uiPopupBlockHandle *ui_popup_block_create(bContext *C,
handle->can_refresh = false;
/* create area region */
- region = ui_region_temp_add(CTX_wm_screen(C));
+ ARegion *region = ui_region_temp_add(CTX_wm_screen(C));
handle->region = region;
+ static ARegionType type;
memset(&type, 0, sizeof(ARegionType));
type.draw = ui_block_region_draw;
type.layout = ui_block_region_refresh;
@@ -798,7 +793,7 @@ uiPopupBlockHandle *ui_popup_block_create(bContext *C,
UI_region_handlers_add(&region->handlers);
- block = ui_popup_block_refresh(C, handle, butregion, but);
+ uiBlock *block = ui_popup_block_refresh(C, handle, butregion, but);
handle = block->handle;
/* keep centered on window resizing */
diff --git a/source/blender/editors/interface/interface_templates.c b/source/blender/editors/interface/interface_templates.c
index d21f969e431..a3259831c9f 100644
--- a/source/blender/editors/interface/interface_templates.c
+++ b/source/blender/editors/interface/interface_templates.c
@@ -3269,7 +3269,7 @@ void uiTemplatePreview(uiLayout *layout,
uiDefButS(block,
UI_BTYPE_ROW,
B_MATPRV,
- IFACE_("World"),
+ CTX_IFACE_(BLT_I18NCONTEXT_ID_WORLD, "World"),
0,
0,
UI_UNIT_X * 10,
diff --git a/source/blender/editors/io/io_alembic.c b/source/blender/editors/io/io_alembic.c
index d4855f470ff..100d56a6b0d 100644
--- a/source/blender/editors/io/io_alembic.c
+++ b/source/blender/editors/io/io_alembic.c
@@ -658,7 +658,7 @@ void WM_OT_alembic_import(wmOperatorType *ot)
ot->name = "Import Alembic";
ot->description = "Load an Alembic archive";
ot->idname = "WM_OT_alembic_import";
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_PRESET;
ot->invoke = wm_alembic_import_invoke;
ot->exec = wm_alembic_import_exec;
diff --git a/source/blender/editors/io/io_collada.c b/source/blender/editors/io/io_collada.c
index 1048d0eca32..a630f150e0e 100644
--- a/source/blender/editors/io/io_collada.c
+++ b/source/blender/editors/io/io_collada.c
@@ -770,14 +770,12 @@ void WM_OT_collada_import(wmOperatorType *ot)
ot->name = "Import COLLADA";
ot->description = "Load a Collada file";
ot->idname = "WM_OT_collada_import";
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_PRESET;
ot->invoke = WM_operator_filesel;
ot->exec = wm_collada_import_exec;
ot->poll = WM_operator_winactive;
- // ot->flag = OPTYPE_PRESET;
-
ot->ui = wm_collada_import_draw;
WM_operator_properties_filesel(ot,
diff --git a/source/blender/editors/io/io_obj.c b/source/blender/editors/io/io_obj.c
index cb8eafeb52d..7559cd47b27 100644
--- a/source/blender/editors/io/io_obj.c
+++ b/source/blender/editors/io/io_obj.c
@@ -81,7 +81,7 @@ static int wm_obj_export_exec(bContext *C, wmOperator *op)
export_params.forward_axis = RNA_enum_get(op->ptr, "forward_axis");
export_params.up_axis = RNA_enum_get(op->ptr, "up_axis");
- export_params.scaling_factor = RNA_float_get(op->ptr, "scaling_factor");
+ export_params.global_scale = RNA_float_get(op->ptr, "global_scale");
export_params.apply_modifiers = RNA_boolean_get(op->ptr, "apply_modifiers");
export_params.export_eval_mode = RNA_enum_get(op->ptr, "export_eval_mode");
@@ -122,7 +122,7 @@ static void ui_obj_export_settings(uiLayout *layout, PointerRNA *imfptr)
col = uiLayoutColumn(box, false);
sub = uiLayoutColumnWithHeading(col, false, IFACE_("Limit to"));
uiItemR(sub, imfptr, "export_selected_objects", 0, IFACE_("Selected Only"), ICON_NONE);
- uiItemR(sub, imfptr, "scaling_factor", 0, NULL, ICON_NONE);
+ uiItemR(sub, imfptr, "global_scale", 0, NULL, ICON_NONE);
row = uiLayoutRow(box, false);
uiItemR(row, imfptr, "forward_axis", UI_ITEM_R_EXPAND, IFACE_("Forward Axis"), ICON_NONE);
@@ -301,15 +301,16 @@ void WM_OT_obj_export(struct wmOperatorType *ot)
RNA_def_property_update_runtime(prop, (void *)forward_axis_update);
prop = RNA_def_enum(ot->srna, "up_axis", io_transform_axis, IO_AXIS_Y, "Up Axis", "");
RNA_def_property_update_runtime(prop, (void *)up_axis_update);
- RNA_def_float(ot->srna,
- "scaling_factor",
- 1.0f,
- 0.001f,
- 10000.0f,
- "Scale",
- "Upscale the object by this factor",
- 0.01,
- 1000.0f);
+ RNA_def_float(
+ ot->srna,
+ "global_scale",
+ 1.0f,
+ 0.0001f,
+ 10000.0f,
+ "Scale",
+ "Value by which to enlarge or shrink the objects with respect to the world's origin",
+ 0.0001f,
+ 10000.0f);
/* File Writer options. */
RNA_def_boolean(
ot->srna, "apply_modifiers", true, "Apply Modifiers", "Apply modifiers to exported meshes");
@@ -405,6 +406,7 @@ static int wm_obj_import_exec(bContext *C, wmOperator *op)
{
struct OBJImportParams import_params;
RNA_string_get(op->ptr, "filepath", import_params.filepath);
+ import_params.global_scale = RNA_float_get(op->ptr, "global_scale");
import_params.clamp_size = RNA_float_get(op->ptr, "clamp_size");
import_params.forward_axis = RNA_enum_get(op->ptr, "forward_axis");
import_params.up_axis = RNA_enum_get(op->ptr, "up_axis");
@@ -459,6 +461,7 @@ static void ui_obj_import_settings(uiLayout *layout, PointerRNA *imfptr)
uiItemL(box, IFACE_("Transform"), ICON_OBJECT_DATA);
uiLayout *col = uiLayoutColumn(box, false);
uiLayout *sub = uiLayoutColumn(col, false);
+ uiItemR(sub, imfptr, "global_scale", 0, NULL, ICON_NONE);
uiItemR(sub, imfptr, "clamp_size", 0, NULL, ICON_NONE);
sub = uiLayoutColumn(col, false);
@@ -489,7 +492,7 @@ void WM_OT_obj_import(struct wmOperatorType *ot)
ot->name = "Import Wavefront OBJ";
ot->description = "Load a Wavefront OBJ scene";
ot->idname = "WM_OT_obj_import";
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_PRESET;
ot->invoke = wm_obj_import_invoke;
ot->exec = wm_obj_import_exec;
@@ -506,6 +509,16 @@ void WM_OT_obj_import(struct wmOperatorType *ot)
FILE_SORT_DEFAULT);
RNA_def_float(
ot->srna,
+ "global_scale",
+ 1.0f,
+ 0.0001f,
+ 10000.0f,
+ "Scale",
+ "Value by which to enlarge or shrink the objects with respect to the world's origin",
+ 0.0001f,
+ 10000.0f);
+ RNA_def_float(
+ ot->srna,
"clamp_size",
0.0f,
0.0f,
diff --git a/source/blender/editors/io/io_stl_ops.c b/source/blender/editors/io/io_stl_ops.c
index c98e5beaf3b..c27d42a07c0 100644
--- a/source/blender/editors/io/io_stl_ops.c
+++ b/source/blender/editors/io/io_stl_ops.c
@@ -95,7 +95,7 @@ void WM_OT_stl_import(struct wmOperatorType *ot)
ot->exec = wm_stl_import_execute;
ot->poll = WM_operator_winactive;
ot->check = wm_stl_import_check;
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_PRESET;
WM_operator_properties_filesel(ot,
FILE_TYPE_FOLDER,
diff --git a/source/blender/editors/io/io_usd.c b/source/blender/editors/io/io_usd.c
index eb80cabcd7f..c776fbf0dd7 100644
--- a/source/blender/editors/io/io_usd.c
+++ b/source/blender/editors/io/io_usd.c
@@ -500,7 +500,7 @@ void WM_OT_usd_import(struct wmOperatorType *ot)
ot->poll = WM_operator_winactive;
ot->ui = wm_usd_import_draw;
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_PRESET;
WM_operator_properties_filesel(ot,
FILE_TYPE_FOLDER | FILE_TYPE_USD,
diff --git a/source/blender/editors/mesh/editmesh_knife.c b/source/blender/editors/mesh/editmesh_knife.c
index e9897021b4a..a147594b25b 100644
--- a/source/blender/editors/mesh/editmesh_knife.c
+++ b/source/blender/editors/mesh/editmesh_knife.c
@@ -100,7 +100,7 @@ typedef struct KnifeColors {
/* Knife-tool Operator. */
typedef struct KnifeVert {
Object *ob;
- uint base_index;
+ uint ob_index;
BMVert *v; /* Non-NULL if this is an original vert. */
ListBase edges;
ListBase faces;
@@ -142,7 +142,7 @@ typedef struct KnifeLineHit {
KnifeVert *v;
BMFace *f;
Object *ob;
- uint base_index;
+ uint ob_index;
} KnifeLineHit;
typedef struct KnifePosData {
@@ -156,7 +156,7 @@ typedef struct KnifePosData {
KnifeEdge *edge;
BMFace *bmface;
Object *ob; /* Object of the vert, edge or bmface. */
- uint base_index;
+ uint ob_index;
/* When true, the cursor isn't over a face. */
bool is_space;
@@ -182,7 +182,7 @@ typedef struct KnifeBVH {
BVHTree *tree; /* Knife Custom BVH Tree. */
BMLoop *(*looptris)[3]; /* Used by #knife_bvh_raycast_cb to store the intersecting looptri. */
float uv[2]; /* Used by #knife_bvh_raycast_cb to store the intersecting uv. */
- uint base_index;
+ uint ob_index;
/* Use #bm_ray_cast_cb_elem_not_in_face_check. */
bool (*filter_cb)(BMFace *f, void *userdata);
@@ -218,6 +218,7 @@ typedef struct KnifeTool_OpData {
/* Used for swapping current object when in multi-object edit mode. */
Object **objects;
uint objects_len;
+ bool objects_free;
/** Array `objects_len` length of additional per-object data. */
KnifeObjectInfo *objects_info;
@@ -1158,11 +1159,11 @@ static void knife_update_header(bContext *C, wmOperator *op, KnifeTool_OpData *k
* \{ */
static const int *knife_bm_tri_index_get(const KnifeTool_OpData *kcd,
- int base_index,
+ int ob_index,
int tri_index,
int tri_index_buf[3])
{
- const KnifeObjectInfo *obinfo = &kcd->objects_info[base_index];
+ const KnifeObjectInfo *obinfo = &kcd->objects_info[ob_index];
if (obinfo->tri_indices) {
return obinfo->tri_indices[tri_index];
}
@@ -1173,25 +1174,25 @@ static const int *knife_bm_tri_index_get(const KnifeTool_OpData *kcd,
}
static void knife_bm_tri_cagecos_get(const KnifeTool_OpData *kcd,
- int base_index,
+ int ob_index,
int tri_index,
float cos[3][3])
{
- const KnifeObjectInfo *obinfo = &kcd->objects_info[base_index];
+ const KnifeObjectInfo *obinfo = &kcd->objects_info[ob_index];
int tri_ind_buf[3];
- const int *tri_ind = knife_bm_tri_index_get(kcd, base_index, tri_index, tri_ind_buf);
+ const int *tri_ind = knife_bm_tri_index_get(kcd, ob_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 ob_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];
+ knife_bm_tri_cagecos_get(kcd, ob_index, tri_index, cos);
+ const Object *ob = kcd->objects[ob_index];
for (int i = 0; i < 3; i++) {
mul_m4_v3(ob->obmat, cos[i]);
}
@@ -1236,9 +1237,9 @@ static void knife_bvh_init(KnifeTool_OpData *kcd)
bool test_fn_ret = false;
/* Calculate tottri. */
- for (uint b = 0; b < kcd->objects_len; b++) {
+ for (uint ob_index = 0; ob_index < kcd->objects_len; ob_index++) {
ob_tottri = 0;
- ob = kcd->objects[b];
+ ob = kcd->objects[ob_index];
em = BKE_editmesh_from_object(ob);
for (int i = 0; i < em->tottri; i++) {
@@ -1268,8 +1269,8 @@ static void knife_bvh_init(KnifeTool_OpData *kcd)
* Don't forget to update #knife_bvh_intersect_plane!
*/
tottri = 0;
- for (uint b = 0; b < kcd->objects_len; b++) {
- ob = kcd->objects[b];
+ for (uint ob_index = 0; ob_index < kcd->objects_len; ob_index++) {
+ ob = kcd->objects[ob_index];
em = BKE_editmesh_from_object(ob);
looptris = em->looptris;
@@ -1286,7 +1287,7 @@ static void knife_bvh_init(KnifeTool_OpData *kcd)
}
float tri_cos[3][3];
- knife_bm_tri_cagecos_get_worldspace(kcd, b, i, tri_cos);
+ knife_bm_tri_cagecos_get_worldspace(kcd, ob_index, i, tri_cos);
BLI_bvhtree_insert(kcd->bvh.tree, i + tottri, &tri_cos[0][0], 3);
}
@@ -1324,10 +1325,10 @@ static void knife_bvh_raycast_cb(void *userdata,
int tottri;
tottri = 0;
- uint b = 0;
- for (; b < kcd->objects_len; b++) {
+ uint ob_index = 0;
+ for (; ob_index < kcd->objects_len; ob_index++) {
index -= tottri;
- ob = kcd->objects[b];
+ ob = kcd->objects[ob_index];
em = BKE_editmesh_from_object(ob);
tottri = em->tottri;
if (index < tottri) {
@@ -1343,7 +1344,7 @@ static void knife_bvh_raycast_cb(void *userdata,
}
float tri_cos[3][3];
- knife_bm_tri_cagecos_get_worldspace(kcd, b, index, tri_cos);
+ knife_bm_tri_cagecos_get_worldspace(kcd, ob_index, index, tri_cos);
isect = (ray->radius > 0.0f ?
isect_ray_tri_epsilon_v3(
ray->origin, ray->direction, UNPACK3(tri_cos), &dist, uv, ray->radius) :
@@ -1370,7 +1371,7 @@ static void knife_bvh_raycast_cb(void *userdata,
kcd->bvh.looptris = em->looptris;
copy_v2_v2(kcd->bvh.uv, uv);
- kcd->bvh.base_index = b;
+ kcd->bvh.ob_index = ob_index;
}
}
@@ -1382,7 +1383,7 @@ static BMFace *knife_bvh_raycast(KnifeTool_OpData *kcd,
float *r_dist,
float r_hitout[3],
float r_cagehit[3],
- uint *r_base_index)
+ uint *r_ob_index)
{
BMFace *face;
BVHTreeRayHit hit;
@@ -1399,7 +1400,7 @@ static BMFace *knife_bvh_raycast(KnifeTool_OpData *kcd,
/* Hits returned in world space. */
if (r_hitout) {
float tri_cos[3][3];
- knife_bm_tri_cagecos_get_worldspace(kcd, kcd->bvh.base_index, hit.index, tri_cos);
+ knife_bm_tri_cagecos_get_worldspace(kcd, kcd->bvh.ob_index, hit.index, tri_cos);
interp_v3_v3v3v3_uv(r_hitout, UNPACK3(tri_cos), kcd->bvh.uv);
if (r_cagehit) {
@@ -1411,8 +1412,8 @@ static BMFace *knife_bvh_raycast(KnifeTool_OpData *kcd,
*r_dist = hit.dist;
}
- if (r_base_index) {
- *r_base_index = kcd->bvh.base_index;
+ if (r_ob_index) {
+ *r_ob_index = kcd->bvh.ob_index;
}
return face;
@@ -1428,7 +1429,7 @@ static BMFace *knife_bvh_raycast_filter(KnifeTool_OpData *kcd,
float *r_dist,
float r_hitout[3],
float r_cagehit[3],
- uint *r_base_index,
+ uint *r_ob_index,
bool (*filter_cb)(BMFace *f, void *userdata),
void *filter_userdata)
{
@@ -1453,7 +1454,7 @@ static BMFace *knife_bvh_raycast_filter(KnifeTool_OpData *kcd,
/* Hits returned in world space. */
if (r_hitout) {
float tri_cos[3][3];
- knife_bm_tri_cagecos_get_worldspace(kcd, kcd->bvh.base_index, hit.index, tri_cos);
+ knife_bm_tri_cagecos_get_worldspace(kcd, kcd->bvh.ob_index, hit.index, tri_cos);
interp_v3_v3v3v3_uv(r_hitout, UNPACK3(tri_cos), kcd->bvh.uv);
if (r_cagehit) {
@@ -1465,8 +1466,8 @@ static BMFace *knife_bvh_raycast_filter(KnifeTool_OpData *kcd,
*r_dist = hit.dist;
}
- if (r_base_index) {
- *r_base_index = kcd->bvh.base_index;
+ if (r_ob_index) {
+ *r_ob_index = kcd->bvh.ob_index;
}
return face;
@@ -1726,7 +1727,7 @@ static KnifeEdge *new_knife_edge(KnifeTool_OpData *kcd)
}
/* Get a KnifeVert wrapper for an existing BMVert. */
-static KnifeVert *get_bm_knife_vert(KnifeTool_OpData *kcd, BMVert *v, Object *ob, uint base_index)
+static KnifeVert *get_bm_knife_vert(KnifeTool_OpData *kcd, BMVert *v, Object *ob, uint ob_index)
{
KnifeVert *kfv = BLI_ghash_lookup(kcd->origvertmap, v);
const float *cageco;
@@ -1736,7 +1737,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->objects_info[base_index].cagecos[BM_elem_index_get(v)];
+ cageco = kcd->objects_info[ob_index].cagecos[BM_elem_index_get(v)];
}
else {
cageco = v->co;
@@ -1748,7 +1749,7 @@ static KnifeVert *get_bm_knife_vert(KnifeTool_OpData *kcd, BMVert *v, Object *ob
kfv = new_knife_vert(kcd, v->co, cageco_ws);
kfv->v = v;
kfv->ob = ob;
- kfv->base_index = base_index;
+ kfv->ob_index = ob_index;
BLI_ghash_insert(kcd->origvertmap, v, kfv);
BM_ITER_ELEM (f, &bmiter, v, BM_FACES_OF_VERT) {
@@ -1760,7 +1761,7 @@ static KnifeVert *get_bm_knife_vert(KnifeTool_OpData *kcd, BMVert *v, Object *ob
}
/* Get a KnifeEdge wrapper for an existing BMEdge. */
-static KnifeEdge *get_bm_knife_edge(KnifeTool_OpData *kcd, BMEdge *e, Object *ob, uint base_index)
+static KnifeEdge *get_bm_knife_edge(KnifeTool_OpData *kcd, BMEdge *e, Object *ob, uint ob_index)
{
KnifeEdge *kfe = BLI_ghash_lookup(kcd->origedgemap, e);
if (!kfe) {
@@ -1769,8 +1770,8 @@ static KnifeEdge *get_bm_knife_edge(KnifeTool_OpData *kcd, BMEdge *e, Object *ob
kfe = new_knife_edge(kcd);
kfe->e = e;
- kfe->v1 = get_bm_knife_vert(kcd, e->v1, ob, base_index);
- kfe->v2 = get_bm_knife_vert(kcd, e->v2, ob, base_index);
+ kfe->v1 = get_bm_knife_vert(kcd, e->v1, ob, ob_index);
+ kfe->v2 = get_bm_knife_vert(kcd, e->v2, ob, ob_index);
knife_add_to_vert_edges(kcd, kfe);
@@ -1784,10 +1785,7 @@ static KnifeEdge *get_bm_knife_edge(KnifeTool_OpData *kcd, BMEdge *e, Object *ob
return kfe;
}
-static ListBase *knife_get_face_kedges(KnifeTool_OpData *kcd,
- Object *ob,
- uint base_index,
- BMFace *f)
+static ListBase *knife_get_face_kedges(KnifeTool_OpData *kcd, Object *ob, uint ob_index, BMFace *f)
{
ListBase *list = BLI_ghash_lookup(kcd->kedgefacemap, f);
@@ -1798,7 +1796,7 @@ static ListBase *knife_get_face_kedges(KnifeTool_OpData *kcd,
list = knife_empty_list(kcd);
BM_ITER_ELEM (e, &bmiter, f, BM_EDGES_OF_FACE) {
- knife_append_list(kcd, list, get_bm_knife_edge(kcd, e, ob, base_index));
+ knife_append_list(kcd, list, get_bm_knife_edge(kcd, e, ob, ob_index));
}
BLI_ghash_insert(kcd->kedgefacemap, f, list);
@@ -1809,7 +1807,7 @@ static ListBase *knife_get_face_kedges(KnifeTool_OpData *kcd,
static void knife_edge_append_face(KnifeTool_OpData *kcd, KnifeEdge *kfe, BMFace *f)
{
- knife_append_list(kcd, knife_get_face_kedges(kcd, kfe->v1->ob, kfe->v1->base_index, f), kfe);
+ knife_append_list(kcd, knife_get_face_kedges(kcd, kfe->v1->ob, kfe->v1->ob_index, f), kfe);
knife_append_list(kcd, &kfe->faces, f);
}
@@ -1826,7 +1824,7 @@ static KnifeVert *knife_split_edge(KnifeTool_OpData *kcd,
newkfe->v1 = kfe->v1;
newkfe->v2 = new_knife_vert(kcd, co, cageco);
newkfe->v2->ob = kfe->v1->ob;
- newkfe->v2->base_index = kfe->v1->base_index;
+ newkfe->v2->ob_index = kfe->v1->ob_index;
newkfe->v2->is_cut = true;
if (kfe->e) {
knife_add_edge_faces_to_vert(kcd, newkfe->v2, kfe->e);
@@ -2123,7 +2121,7 @@ static void knife_add_single_cut(KnifeTool_OpData *kcd,
BLI_assert(lh1->f);
kfe->v1 = new_knife_vert(kcd, lh1->hit, lh1->cagehit);
kfe->v1->ob = lh1->ob;
- kfe->v1->base_index = lh1->base_index;
+ kfe->v1->ob_index = lh1->ob_index;
kfe->v1->is_cut = true;
kfe->v1->is_face = true;
knife_append_list(kcd, &kfe->v1->faces, lh1->f);
@@ -2141,7 +2139,7 @@ static void knife_add_single_cut(KnifeTool_OpData *kcd,
BLI_assert(lh2->f);
kfe->v2 = new_knife_vert(kcd, lh2->hit, lh2->cagehit);
kfe->v2->ob = lh2->ob;
- kfe->v2->base_index = lh2->base_index;
+ kfe->v2->ob_index = lh2->ob_index;
kfe->v2->is_cut = true;
kfe->v2->is_face = true;
knife_append_list(kcd, &kfe->v2->faces, lh2->f);
@@ -2567,7 +2565,7 @@ static bool knife_ray_intersect_face(KnifeTool_OpData *kcd,
const float v1[3],
const float v2[3],
Object *ob,
- uint base_index,
+ uint ob_index,
BMFace *f,
const float face_tol_sq,
float hit_co[3],
@@ -2600,7 +2598,7 @@ static bool knife_ray_intersect_face(KnifeTool_OpData *kcd,
break;
}
- knife_bm_tri_cagecos_get_worldspace(kcd, base_index, tri_i, tri_cos);
+ knife_bm_tri_cagecos_get_worldspace(kcd, ob_index, tri_i, tri_cos);
/* Using epsilon test in case ray is directly through an internal
* tessellation edge and might not hit either tessellation tri with
@@ -2617,7 +2615,7 @@ static bool knife_ray_intersect_face(KnifeTool_OpData *kcd,
}
interp_v3_v3v3v3_uv(hit_cageco, UNPACK3(tri_cos), ray_tri_uv);
/* Now check that far enough away from verts and edges. */
- list = knife_get_face_kedges(kcd, ob, base_index, f);
+ list = knife_get_face_kedges(kcd, ob, ob_index, f);
for (ref = list->first; ref; ref = ref->next) {
kfe = ref->ref;
if (kfe->is_invalid) {
@@ -2651,11 +2649,11 @@ static void calc_ortho_extent(KnifeTool_OpData *kcd)
float ws[3];
INIT_MINMAX(min, max);
- for (uint b = 0; b < kcd->objects_len; b++) {
- ob = kcd->objects[b];
+ for (uint ob_index = 0; ob_index < kcd->objects_len; ob_index++) {
+ ob = kcd->objects[ob_index];
em = BKE_editmesh_from_object(ob);
- const float(*cagecos)[3] = kcd->objects_info[b].cagecos;
+ const float(*cagecos)[3] = kcd->objects_info[ob_index].cagecos;
if (cagecos) {
for (int i = 0; i < em->bm->totvert; i++) {
copy_v3_v3(ws, cagecos[i]);
@@ -2930,11 +2928,11 @@ static void knife_find_line_hits(KnifeTool_OpData *kcd)
Object *ob;
BMEditMesh *em;
- uint b = 0;
for (i = 0, result = results; i < tot; i++, result++) {
- for (b = 0; b < kcd->objects_len; b++) {
- ob = kcd->objects[b];
+ uint ob_index = 0;
+ for (ob_index = 0; ob_index < kcd->objects_len; ob_index++) {
+ ob = kcd->objects[ob_index];
em = BKE_editmesh_from_object(ob);
if (*result >= 0 && *result < em->tottri) {
ls = (BMLoop **)em->looptris[*result];
@@ -2956,9 +2954,9 @@ static void knife_find_line_hits(KnifeTool_OpData *kcd)
}
/* Don't care what the value is except that it is non-NULL, for iterator. */
BLI_smallhash_insert(&faces, (uintptr_t)f, f);
- BLI_smallhash_insert(&fobs, (uintptr_t)f, (void *)(uintptr_t)b);
+ BLI_smallhash_insert(&fobs, (uintptr_t)f, (void *)(uintptr_t)ob_index);
- list = knife_get_face_kedges(kcd, ob, b, f);
+ list = knife_get_face_kedges(kcd, ob, ob_index, f);
for (ref = list->first; ref; ref = ref->next) {
kfe = ref->ref;
if (kfe->is_invalid) {
@@ -3033,7 +3031,7 @@ static void knife_find_line_hits(KnifeTool_OpData *kcd)
}
hit.ob = v->ob;
- hit.base_index = v->base_index;
+ hit.ob_index = v->ob_index;
copy_v3_v3(hit.hit, v->co);
copy_v3_v3(hit.cagehit, v->cageco);
copy_v2_v2(hit.schit, s);
@@ -3109,7 +3107,7 @@ static void knife_find_line_hits(KnifeTool_OpData *kcd)
transform_point_by_seg_v3(
hit.hit, p_cage, kfe->v1->co, kfe->v2->co, kfe->v1->cageco, kfe->v2->cageco);
hit.ob = kfe->v1->ob;
- hit.base_index = kfe->v1->base_index;
+ hit.ob_index = kfe->v1->ob_index;
copy_v3_v3(hit.cagehit, p_cage);
copy_v2_v2(hit.schit, sint);
hit.perc = lambda;
@@ -3129,16 +3127,16 @@ static void knife_find_line_hits(KnifeTool_OpData *kcd)
val = BLI_smallhash_iternext(&hiter, (uintptr_t *)&f)) {
float p[3], p_cage[3];
- uint base_index = (uint)(uintptr_t)BLI_smallhash_lookup(&fobs, (uintptr_t)f);
- ob = kcd->objects[base_index];
+ uint ob_index = (uint)(uintptr_t)BLI_smallhash_lookup(&fobs, (uintptr_t)f);
+ ob = kcd->objects[ob_index];
if (use_hit_prev &&
- knife_ray_intersect_face(kcd, s1, v1, v3, ob, base_index, f, face_tol_sq, p, p_cage)) {
+ knife_ray_intersect_face(kcd, s1, v1, v3, ob, ob_index, f, face_tol_sq, p, p_cage)) {
if (point_is_visible(kcd, p_cage, s1, (BMElem *)f)) {
memset(&hit, 0, sizeof(hit));
hit.f = f;
hit.ob = ob;
- hit.base_index = base_index;
+ hit.ob_index = ob_index;
copy_v3_v3(hit.hit, p);
copy_v3_v3(hit.cagehit, p_cage);
copy_v2_v2(hit.schit, s1);
@@ -3148,12 +3146,12 @@ static void knife_find_line_hits(KnifeTool_OpData *kcd)
}
if (use_hit_curr &&
- knife_ray_intersect_face(kcd, s2, v2, v4, ob, base_index, f, face_tol_sq, p, p_cage)) {
+ knife_ray_intersect_face(kcd, s2, v2, v4, ob, ob_index, f, face_tol_sq, p, p_cage)) {
if (point_is_visible(kcd, p_cage, s2, (BMElem *)f)) {
memset(&hit, 0, sizeof(hit));
hit.f = f;
hit.ob = ob;
- hit.base_index = base_index;
+ hit.ob_index = ob_index;
copy_v3_v3(hit.hit, p);
copy_v3_v3(hit.cagehit, p_cage);
copy_v2_v2(hit.schit, s2);
@@ -3205,7 +3203,7 @@ static void knife_pos_data_clear(KnifePosData *kpd)
static BMFace *knife_find_closest_face(KnifeTool_OpData *kcd,
Object **r_ob,
- uint *r_base_index,
+ uint *r_ob_index,
bool *is_space,
float r_co[3],
float r_cageco[3])
@@ -3221,7 +3219,7 @@ static BMFace *knife_find_closest_face(KnifeTool_OpData *kcd,
sub_v3_v3v3(ray, origin_ofs, origin);
normalize_v3_v3(ray_normal, ray);
- f = knife_bvh_raycast(kcd, origin, ray_normal, 0.0f, NULL, r_co, r_cageco, r_base_index);
+ f = knife_bvh_raycast(kcd, origin, ray_normal, 0.0f, NULL, r_co, r_cageco, r_ob_index);
if (f && kcd->only_select && BM_elem_flag_test(f, BM_ELEM_SELECT) == 0) {
f = NULL;
@@ -3232,7 +3230,7 @@ static BMFace *knife_find_closest_face(KnifeTool_OpData *kcd,
}
if (f) {
- *r_ob = kcd->objects[*r_base_index];
+ *r_ob = kcd->objects[*r_ob_index];
}
else {
if (kcd->is_interactive) {
@@ -3267,7 +3265,7 @@ static BMFace *knife_find_closest_face(KnifeTool_OpData *kcd,
static int knife_sample_screen_density_from_closest_face(KnifeTool_OpData *kcd,
const float radius,
Object *ob,
- uint base_index,
+ uint ob_index,
BMFace *f,
const float cageco[3])
{
@@ -3280,7 +3278,7 @@ static int knife_sample_screen_density_from_closest_face(KnifeTool_OpData *kcd,
knife_project_v2(kcd, cageco, sco);
- list = knife_get_face_kedges(kcd, ob, base_index, f);
+ list = knife_get_face_kedges(kcd, ob, ob_index, f);
for (ref = list->first; ref; ref = ref->next) {
KnifeEdge *kfe = ref->ref;
int i;
@@ -3329,7 +3327,7 @@ static float knife_snap_size(KnifeTool_OpData *kcd, float maxsize)
if (!kcd->curr.is_space) {
density = (float)knife_sample_screen_density_from_closest_face(
- kcd, maxsize * 2.0f, kcd->curr.ob, kcd->curr.base_index, kcd->curr.bmface, kcd->curr.cage);
+ kcd, maxsize * 2.0f, kcd->curr.ob, kcd->curr.ob_index, kcd->curr.bmface, kcd->curr.cage);
}
return density ? min_ff(maxsize / ((float)density * 0.5f), maxsize) : maxsize;
@@ -3388,7 +3386,7 @@ static void knife_interp_v3_v3v3(const KnifeTool_OpData *kcd,
/* p is closest point on edge to the mouse cursor. */
static KnifeEdge *knife_find_closest_edge_of_face(
- KnifeTool_OpData *kcd, Object *ob, uint base_index, BMFace *f, float p[3], float cagep[3])
+ KnifeTool_OpData *kcd, Object *ob, uint ob_index, BMFace *f, float p[3], float cagep[3])
{
float sco[2];
float maxdist;
@@ -3414,7 +3412,7 @@ static KnifeEdge *knife_find_closest_edge_of_face(
knife_project_v2(kcd, cagep, sco);
/* Look through all edges associated with this face. */
- list = knife_get_face_kedges(kcd, ob, base_index, f);
+ list = knife_get_face_kedges(kcd, ob, ob_index, f);
for (ref = list->first; ref; ref = ref->next) {
KnifeEdge *kfe = ref->ref;
float kfv1_sco[2], kfv2_sco[2], test_cagep[3];
@@ -3479,7 +3477,7 @@ static KnifeEdge *knife_find_closest_edge_of_face(
* this is important for angle snap, which uses the previous mouse position. */
edgesnap = new_knife_vert(kcd, p, cagep);
edgesnap->ob = ob;
- edgesnap->base_index = base_index;
+ edgesnap->ob_index = ob_index;
knife_project_v2(kcd, edgesnap->cageco, kcd->curr.mval);
}
@@ -3906,14 +3904,14 @@ static bool knife_snap_update_from_mval(KnifeTool_OpData *kcd, const float mval[
kcd->curr.ob = kcd->vc.obedit;
kcd->curr.bmface = knife_find_closest_face(kcd,
&kcd->curr.ob,
- &kcd->curr.base_index,
+ &kcd->curr.ob_index,
&kcd->curr.is_space,
kcd->curr.co,
kcd->curr.cage);
if (kcd->curr.bmface) {
kcd->curr.edge = knife_find_closest_edge_of_face(
- kcd, kcd->curr.ob, kcd->curr.base_index, kcd->curr.bmface, kcd->curr.co, kcd->curr.cage);
+ kcd, kcd->curr.ob, kcd->curr.ob_index, kcd->curr.bmface, kcd->curr.co, kcd->curr.cage);
}
if (kcd->curr.edge) {
@@ -4017,7 +4015,7 @@ static void knifetool_undo(KnifeTool_OpData *kcd)
static void knifetool_init_obinfo(KnifeTool_OpData *kcd,
Object *ob,
- uint base_index,
+ uint ob_index,
bool use_tri_indices)
{
@@ -4027,7 +4025,7 @@ static void knifetool_init_obinfo(KnifeTool_OpData *kcd,
BM_mesh_elem_index_ensure(em_eval->bm, BM_VERT);
- KnifeObjectInfo *obinfo = &kcd->objects_info[base_index];
+ KnifeObjectInfo *obinfo = &kcd->objects_info[ob_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);
@@ -4045,10 +4043,10 @@ static void knifetool_init_obinfo(KnifeTool_OpData *kcd,
}
}
-static void knifetool_free_obinfo(KnifeTool_OpData *kcd, uint base_index)
+static void knifetool_free_obinfo(KnifeTool_OpData *kcd, uint ob_index)
{
- MEM_SAFE_FREE(kcd->objects_info[base_index].cagecos);
- MEM_SAFE_FREE(kcd->objects_info[base_index].tri_indices);
+ MEM_SAFE_FREE(kcd->objects_info[ob_index].cagecos);
+ MEM_SAFE_FREE(kcd->objects_info[ob_index].tri_indices);
}
/** \} */
@@ -4081,6 +4079,8 @@ static void knife_init_colors(KnifeColors *colors)
/* called when modal loop selection gets set up... */
static void knifetool_init(ViewContext *vc,
KnifeTool_OpData *kcd,
+ Object **objects,
+ const int objects_len,
const bool only_select,
const bool cut_through,
const bool xray,
@@ -4101,16 +4101,24 @@ static void knifetool_init(ViewContext *vc,
kcd->scene = scene;
kcd->region = vc->region;
- kcd->objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data(
- vc->scene, vc->view_layer, vc->v3d, &kcd->objects_len);
+ if (objects) {
+ kcd->objects = objects;
+ kcd->objects_len = objects_len;
+ kcd->objects_free = false;
+ }
+ else {
+ kcd->objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data(
+ vc->scene, vc->view_layer, vc->v3d, &kcd->objects_len);
+ kcd->objects_free = true;
+ }
Object *ob;
BMEditMesh *em;
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];
+ for (uint ob_index = 0; ob_index < kcd->objects_len; ob_index++) {
+ ob = kcd->objects[ob_index];
em = BKE_editmesh_from_object(ob);
- knifetool_init_obinfo(kcd, ob, b, use_tri_indices);
+ knifetool_init_obinfo(kcd, ob, ob_index, use_tri_indices);
/* Can't usefully select resulting edges in face mode. */
kcd->select_result = (em->selectmode != SCE_SELECT_FACE);
@@ -4225,7 +4233,9 @@ static void knifetool_exit_ex(KnifeTool_OpData *kcd)
}
/* Free object bases. */
- MEM_freeN(kcd->objects);
+ if (kcd->objects_free) {
+ MEM_freeN(kcd->objects);
+ }
/* Destroy kcd itself. */
MEM_freeN(kcd);
@@ -4318,9 +4328,15 @@ static void knifetool_finish_single_post(KnifeTool_OpData *UNUSED(kcd), Object *
/* Called on tool confirmation. */
static void knifetool_finish_ex(KnifeTool_OpData *kcd)
{
- for (uint b = 0; b < kcd->objects_len; b++) {
- Object *ob = kcd->objects[b];
+ /* Separate pre/post passes are needed because `em->looptris` recalculation from the 'post' pass
+ * causes causes triangle indices in #KnifeTool_OpData.bvh to get out of sync.
+ * So perform all the cuts before doing any mesh recalculation, see: T101721. */
+ for (uint ob_index = 0; ob_index < kcd->objects_len; ob_index++) {
+ Object *ob = kcd->objects[ob_index];
knifetool_finish_single_pre(kcd, ob);
+ }
+ for (uint ob_index = 0; ob_index < kcd->objects_len; ob_index++) {
+ Object *ob = kcd->objects[ob_index];
knifetool_finish_single_post(kcd, ob);
}
}
@@ -4789,6 +4805,8 @@ static int knifetool_invoke(bContext *C, wmOperator *op, const wmEvent *event)
knifetool_init(&vc,
kcd,
+ NULL,
+ 0,
only_select,
cut_through,
xray,
@@ -4802,8 +4820,8 @@ static int knifetool_invoke(bContext *C, wmOperator *op, const wmEvent *event)
BMEditMesh *em;
bool faces_selected = false;
- for (uint b = 0; b < kcd->objects_len; b++) {
- obedit = kcd->objects[b];
+ for (uint ob_index = 0; ob_index < kcd->objects_len; ob_index++) {
+ obedit = kcd->objects[ob_index];
em = BKE_editmesh_from_object(obedit);
if (em->bm->totfacesel != 0) {
faces_selected = true;
@@ -4942,7 +4960,12 @@ static bool edbm_mesh_knife_point_isect(LinkNode *polys, const float cent_ss[2])
return false;
}
-void EDBM_mesh_knife(ViewContext *vc, LinkNode *polys, bool use_tag, bool cut_through)
+void EDBM_mesh_knife(ViewContext *vc,
+ Object **objects,
+ const int objects_len,
+ LinkNode *polys,
+ bool use_tag,
+ bool cut_through)
{
KnifeTool_OpData *kcd;
@@ -4959,6 +4982,8 @@ void EDBM_mesh_knife(ViewContext *vc, LinkNode *polys, bool use_tag, bool cut_th
knifetool_init(vc,
kcd,
+ objects,
+ objects_len,
only_select,
cut_through,
xray,
@@ -5000,18 +5025,21 @@ void EDBM_mesh_knife(ViewContext *vc, LinkNode *polys, bool use_tag, bool cut_th
/* Finish. */
{
- Object *ob;
- BMEditMesh *em;
- for (uint b = 0; b < kcd->objects_len; b++) {
-
- ob = kcd->objects[b];
- em = BKE_editmesh_from_object(ob);
+ /* See #knifetool_finish_ex for why multiple passes are needed. */
+ for (uint ob_index = 0; ob_index < kcd->objects_len; ob_index++) {
+ Object *ob = kcd->objects[ob_index];
+ BMEditMesh *em = BKE_editmesh_from_object(ob);
if (use_tag) {
BM_mesh_elem_hflag_enable_all(em->bm, BM_EDGE, BM_ELEM_TAG, false);
}
knifetool_finish_single_pre(kcd, ob);
+ }
+
+ for (uint ob_index = 0; ob_index < kcd->objects_len; ob_index++) {
+ Object *ob = kcd->objects[ob_index];
+ BMEditMesh *em = BKE_editmesh_from_object(ob);
/* Tag faces inside! */
if (use_tag) {
@@ -5104,9 +5132,12 @@ void EDBM_mesh_knife(ViewContext *vc, LinkNode *polys, bool use_tag, bool cut_th
#undef F_ISECT_SET_UNKNOWN
#undef F_ISECT_SET_OUTSIDE
}
+ }
+ for (uint ob_index = 0; ob_index < kcd->objects_len; ob_index++) {
/* Defer freeing data until the BVH tree is finished with, see: #point_is_visible and
* the doc-string for #knifetool_finish_single_post. */
+ Object *ob = kcd->objects[ob_index];
knifetool_finish_single_post(kcd, ob);
}
diff --git a/source/blender/editors/mesh/editmesh_knife_project.c b/source/blender/editors/mesh/editmesh_knife_project.c
index e27d19ab000..6004a2943a2 100644
--- a/source/blender/editors/mesh/editmesh_knife_project.c
+++ b/source/blender/editors/mesh/editmesh_knife_project.c
@@ -132,22 +132,21 @@ static int knifeproject_exec(bContext *C, wmOperator *op)
ViewContext vc;
em_setup_viewcontext(C, &vc);
- /* TODO: Ideally meshes would occlude each other, currently they don't
- * since each knife-project runs as a separate operation. */
uint objects_len;
Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data(
vc.scene, vc.view_layer, vc.v3d, &objects_len);
+
+ EDBM_mesh_knife(&vc, objects, objects_len, polys, true, cut_through);
+
for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
Object *obedit = objects[ob_index];
ED_view3d_viewcontext_init_object(&vc, obedit);
BMEditMesh *em = BKE_editmesh_from_object(obedit);
- EDBM_mesh_knife(&vc, polys, true, cut_through);
-
/* select only tagged faces */
BM_mesh_elem_hflag_disable_all(em->bm, BM_VERT | BM_EDGE | BM_FACE, BM_ELEM_SELECT, false);
- EDBM_selectmode_disable_multi(C, SCE_SELECT_VERTEX, SCE_SELECT_EDGE);
+ EDBM_selectmode_disable(scene, em, SCE_SELECT_VERTEX, SCE_SELECT_EDGE);
BM_mesh_elem_hflag_enable_test(em->bm, BM_FACE, BM_ELEM_SELECT, true, false, BM_ELEM_TAG);
diff --git a/source/blender/editors/mesh/editmesh_select.cc b/source/blender/editors/mesh/editmesh_select.cc
index 0d1e3c08d84..76d0bab8a52 100644
--- a/source/blender/editors/mesh/editmesh_select.cc
+++ b/source/blender/editors/mesh/editmesh_select.cc
@@ -22,7 +22,9 @@
#include "BKE_customdata.h"
#include "BKE_deform.h"
#include "BKE_editmesh.h"
+#include "BKE_editmesh_cache.h"
#include "BKE_layer.h"
+#include "BKE_mesh.h"
#include "BKE_report.h"
#include "WM_api.h"
@@ -1065,8 +1067,8 @@ bool EDBM_unified_findnearest_from_raycast(ViewContext *vc,
{
Mesh *me_eval = (Mesh *)DEG_get_evaluated_id(vc->depsgraph,
static_cast<ID *>(obedit->data));
- if (me_eval->runtime.edit_data) {
- coords = me_eval->runtime.edit_data->vertexCos;
+ if (me_eval->runtime->edit_data) {
+ coords = me_eval->runtime->edit_data->vertexCos;
}
}
diff --git a/source/blender/editors/mesh/editmesh_undo.cc b/source/blender/editors/mesh/editmesh_undo.cc
index f5056021f7d..5c837e61a79 100644
--- a/source/blender/editors/mesh/editmesh_undo.cc
+++ b/source/blender/editors/mesh/editmesh_undo.cc
@@ -101,7 +101,7 @@ struct UndoMesh {
int shapenr;
#ifdef USE_ARRAY_STORE
- /* N`ull arrays are considered empty */
+ /* Null arrays are considered empty. */
struct { /* most data is stored as 'custom' data */
BArrayCustomData *vdata, *edata, *ldata, *pdata;
BArrayState **keyblocks;
@@ -231,7 +231,7 @@ static void um_arraystore_cd_compact(CustomData *cdata,
}
bcd->states[i] = BLI_array_store_state_add(
- bs, layer->data, (size_t)data_len * stride, state_reference);
+ bs, layer->data, size_t(data_len) * stride, state_reference);
}
else {
bcd->states[i] = nullptr;
@@ -334,7 +334,7 @@ static void um_arraystore_compact_ex(UndoMesh *um, const UndoMesh *um_ref, bool
um_ref->store.keyblocks[i] :
nullptr;
um->store.keyblocks[i] = BLI_array_store_state_add(
- bs, keyblock->data, (size_t)keyblock->totelem * stride, state_reference);
+ bs, keyblock->data, size_t(keyblock->totelem) * stride, state_reference);
}
if (keyblock->data) {
@@ -352,7 +352,7 @@ static void um_arraystore_compact_ex(UndoMesh *um, const UndoMesh *um_ref, bool
BArrayStore *bs = BLI_array_store_at_size_ensure(
&um_arraystore.bs_stride, stride, ARRAY_CHUNK_SIZE);
um->store.mselect = BLI_array_store_state_add(
- bs, me->mselect, (size_t)me->totselect * stride, state_reference);
+ bs, me->mselect, size_t(me->totselect) * stride, state_reference);
}
/* keep me->totselect for validation */
@@ -597,6 +597,11 @@ static void *undomesh_from_editmesh(UndoMesh *um, BMEditMesh *em, Key *key, Undo
* on it. Necessary to use the attribute API. */
strcpy(um->me.id.name, "MEundomesh_from_editmesh");
+ /* Runtime data is necessary for some asserts in other code, and the overhead of creating it for
+ * undo meshes should be low. */
+ BLI_assert(um->me.runtime == nullptr);
+ um->me.runtime = new blender::bke::MeshRuntime();
+
CustomData_MeshMasks cd_mask_extra{};
cd_mask_extra.vmask = CD_MASK_SHAPE_KEYINDEX;
BMeshToMeshParams params{};
diff --git a/source/blender/editors/mesh/mesh_intern.h b/source/blender/editors/mesh/mesh_intern.h
index e6505715324..0e20bb18595 100644
--- a/source/blender/editors/mesh/mesh_intern.h
+++ b/source/blender/editors/mesh/mesh_intern.h
@@ -18,6 +18,7 @@ struct BMElem;
struct BMOperator;
struct EnumPropertyItem;
struct LinkNode;
+struct Object;
struct bContext;
struct wmKeyConfig;
struct wmKeyMap;
@@ -177,6 +178,8 @@ void MESH_OT_knife_project(struct wmOperatorType *ot);
* \param use_tag: When set, tag all faces inside the polylines.
*/
void EDBM_mesh_knife(struct ViewContext *vc,
+ struct Object **objects,
+ int objects_len,
struct LinkNode *polys,
bool use_tag,
bool cut_through);
diff --git a/source/blender/editors/mesh/meshtools.cc b/source/blender/editors/mesh/meshtools.cc
index 2210cc67bff..4d75ab7f041 100644
--- a/source/blender/editors/mesh/meshtools.cc
+++ b/source/blender/editors/mesh/meshtools.cc
@@ -1335,7 +1335,7 @@ struct VertPickData {
static void ed_mesh_pick_vert__mapFunc(void *userData,
int index,
const float co[3],
- const float UNUSED(no[3]))
+ const float /*no*/[3])
{
VertPickData *data = static_cast<VertPickData *>(userData);
if (data->hide_vert && data->hide_vert[index]) {
diff --git a/source/blender/editors/object/object_modifier.cc b/source/blender/editors/object/object_modifier.cc
index 872d2367332..c7995809438 100644
--- a/source/blender/editors/object/object_modifier.cc
+++ b/source/blender/editors/object/object_modifier.cc
@@ -21,6 +21,7 @@
#include "DNA_mesh_types.h"
#include "DNA_meshdata_types.h"
#include "DNA_object_force_types.h"
+#include "DNA_pointcloud_types.h"
#include "DNA_scene_types.h"
#include "DNA_space_types.h"
@@ -788,7 +789,9 @@ static bool modifier_apply_obdata(
if (ELEM(mti->type, eModifierTypeType_Constructive, eModifierTypeType_Nonconstructive)) {
BKE_report(
- reports, RPT_ERROR, "Transform curve to mesh in order to apply constructive modifiers");
+ reports,
+ RPT_ERROR,
+ "Cannot apply constructive modifiers on curve. Convert curve to mesh in order to apply");
return false;
}
@@ -855,8 +858,38 @@ static bool modifier_apply_obdata(
Main *bmain = DEG_get_bmain(depsgraph);
BKE_object_material_from_eval_data(bmain, ob, &curves_eval.id);
}
+ else if (ob->type == OB_POINTCLOUD) {
+ PointCloud &points = *static_cast<PointCloud *>(ob->data);
+ if (mti->modifyGeometrySet == nullptr) {
+ BLI_assert_unreachable();
+ return false;
+ }
+
+ /* Create a temporary geometry set and component. */
+ GeometrySet geometry_set;
+ geometry_set.get_component_for_write<PointCloudComponent>().replace(
+ &points, GeometryOwnershipType::ReadOnly);
+
+ ModifierEvalContext mectx = {depsgraph, ob, (ModifierApplyFlag)0};
+ mti->modifyGeometrySet(md_eval, &mectx, &geometry_set);
+ if (!geometry_set.has_pointcloud()) {
+ BKE_report(
+ reports, RPT_ERROR, "Evaluated geometry from modifier does not contain a point cloud");
+ return false;
+ }
+ PointCloud *pointcloud_eval =
+ geometry_set.get_component_for_write<PointCloudComponent>().release();
+
+ /* Anonymous attributes shouldn't be available on the applied geometry. */
+ pointcloud_eval->attributes_for_write().remove_anonymous();
+
+ /* Copy the relevant information to the original. */
+ Main *bmain = DEG_get_bmain(depsgraph);
+ BKE_object_material_from_eval_data(bmain, ob, &pointcloud_eval->id);
+ BKE_pointcloud_nomain_to_pointcloud(pointcloud_eval, &points, true);
+ }
else {
- /* TODO: implement for point clouds and volumes. */
+ /* TODO: implement for volumes. */
BKE_report(reports, RPT_ERROR, "Cannot apply modifier for this object type");
return false;
}
diff --git a/source/blender/editors/object/object_relations.c b/source/blender/editors/object/object_relations.c
index 2f18922f4ee..5da19d76259 100644
--- a/source/blender/editors/object/object_relations.c
+++ b/source/blender/editors/object/object_relations.c
@@ -2318,26 +2318,39 @@ static int make_override_library_exec(bContext *C, wmOperator *op)
id_root = &collection->id;
user_overrides_from_selected_objects = true;
}
- /* Else, poll func ensures us that ID_IS_LINKED(obact) is true. */
+ /* Else, poll func ensures us that ID_IS_LINKED(obact) is true, or that it is already an existing
+ * liboverride. */
else {
+ BLI_assert(ID_IS_LINKED(obact) || ID_IS_OVERRIDE_LIBRARY_REAL(obact));
id_root = &obact->id;
user_overrides_from_selected_objects = true;
}
- const bool do_fully_editable = !user_overrides_from_selected_objects;
-
- GSet *user_overrides_objects_uids = do_fully_editable ? NULL :
- BLI_gset_new(BLI_ghashutil_inthash_p,
- BLI_ghashutil_intcmp,
- __func__);
-
/* Make already existing selected liboverrides editable. */
+ bool is_active_override = false;
FOREACH_SELECTED_OBJECT_BEGIN (view_layer, CTX_wm_view3d(C), ob_iter) {
if (ID_IS_OVERRIDE_LIBRARY_REAL(ob_iter) && !ID_IS_LINKED(ob_iter)) {
ob_iter->id.override_library->flag &= ~IDOVERRIDE_LIBRARY_FLAG_SYSTEM_DEFINED;
+ is_active_override = is_active_override || (&ob_iter->id == id_root);
+ DEG_id_tag_update(&ob_iter->id, ID_RECALC_COPY_ON_WRITE);
}
}
FOREACH_SELECTED_OBJECT_END;
+ /* If the active object is a liboverride, there is no point going further, since in the weird
+ * case where some other selected objects would be linked ones, there is no way to properly
+ * create overrides for them currently.
+ *
+ * Could be added later if really needed, but would rather avoid that extra complexity here. */
+ if (is_active_override) {
+ return OPERATOR_FINISHED;
+ }
+
+ const bool do_fully_editable = !user_overrides_from_selected_objects;
+
+ GSet *user_overrides_objects_uids = do_fully_editable ? NULL :
+ BLI_gset_new(BLI_ghashutil_inthash_p,
+ BLI_ghashutil_intcmp,
+ __func__);
if (do_fully_editable) {
/* Pass. */
diff --git a/source/blender/editors/object/object_vgroup.cc b/source/blender/editors/object/object_vgroup.cc
index 02a247dd15e..d874226f04e 100644
--- a/source/blender/editors/object/object_vgroup.cc
+++ b/source/blender/editors/object/object_vgroup.cc
@@ -2376,22 +2376,6 @@ void ED_vgroup_mirror(Object *ob,
/* TODO: vgroup locking.
* TODO: face masking. */
-#define VGROUP_MIRR_OP \
- dvert_mirror_op(dvert, \
- dvert_mirr, \
- sel, \
- sel_mirr, \
- flip_map, \
- flip_map_len, \
- mirror_weights, \
- flip_vgroups, \
- all_vgroups, \
- def_nr)
-
- BMVert *eve, *eve_mirr;
- MDeformVert *dvert_mirr;
- char sel, sel_mirr;
- int *flip_map = nullptr, flip_map_len;
const int def_nr = BKE_object_defgroup_active_index_get(ob) - 1;
int totmirr = 0, totfail = 0;
@@ -2404,6 +2388,8 @@ void ED_vgroup_mirror(Object *ob,
return;
}
+ int *flip_map = nullptr;
+ int flip_map_len;
if (flip_vgroups) {
flip_map = all_vgroups ? BKE_object_defgroup_flip_map(ob, false, &flip_map_len) :
BKE_object_defgroup_flip_map_single(ob, false, def_nr, &flip_map_len);
@@ -2438,21 +2424,27 @@ void ED_vgroup_mirror(Object *ob,
BM_mesh_elem_hflag_disable_all(em->bm, BM_VERT, BM_ELEM_TAG, false);
/* Go through the list of edit-vertices and assign them. */
+ BMVert *eve, *eve_mirr;
BM_ITER_MESH (eve, &iter, em->bm, BM_VERTS_OF_MESH) {
if (!BM_elem_flag_test(eve, BM_ELEM_TAG)) {
if ((eve_mirr = EDBM_verts_mirror_get(em, eve))) {
if (eve_mirr != eve) {
if (!BM_elem_flag_test(eve_mirr, BM_ELEM_TAG)) {
- sel = BM_elem_flag_test(eve, BM_ELEM_SELECT);
- sel_mirr = BM_elem_flag_test(eve_mirr, BM_ELEM_SELECT);
+ const bool sel = BM_elem_flag_test(eve, BM_ELEM_SELECT);
+ const bool sel_mirr = BM_elem_flag_test(eve_mirr, BM_ELEM_SELECT);
if ((sel || sel_mirr) && (eve != eve_mirr)) {
- MDeformVert *dvert = static_cast<MDeformVert *>(
- BM_ELEM_CD_GET_VOID_P(eve, cd_dvert_offset));
- dvert_mirr = static_cast<MDeformVert *>(
- BM_ELEM_CD_GET_VOID_P(eve_mirr, cd_dvert_offset));
-
- VGROUP_MIRR_OP;
+ dvert_mirror_op(
+ static_cast<MDeformVert *>(BM_ELEM_CD_GET_VOID_P(eve, cd_dvert_offset)),
+ static_cast<MDeformVert *>(BM_ELEM_CD_GET_VOID_P(eve_mirr, cd_dvert_offset)),
+ sel,
+ sel_mirr,
+ flip_map,
+ flip_map_len,
+ mirror_weights,
+ flip_vgroups,
+ all_vgroups,
+ def_nr);
totmirr++;
}
@@ -2471,39 +2463,38 @@ void ED_vgroup_mirror(Object *ob,
}
else {
/* object mode / weight paint */
- int vidx, vidx_mirr;
const bool use_vert_sel = (me->editflag & ME_EDIT_PAINT_VERT_SEL) != 0;
if (me->deform_verts().is_empty()) {
goto cleanup;
}
- if (!use_vert_sel) {
- sel = sel_mirr = true;
- }
-
BLI_bitmap *vert_tag = BLI_BITMAP_NEW(me->totvert, __func__);
MutableSpan<MDeformVert> dverts = me->deform_verts_for_write();
const bke::AttributeAccessor attributes = me->attributes();
const VArray<bool> select_vert = attributes.lookup_or_default<bool>(
".select_vert", ATTR_DOMAIN_POINT, false);
- for (vidx = 0; vidx < me->totvert; vidx++) {
+ for (int vidx = 0; vidx < me->totvert; vidx++) {
if (!BLI_BITMAP_TEST(vert_tag, vidx)) {
+ int vidx_mirr;
if ((vidx_mirr = mesh_get_x_mirror_vert(ob, nullptr, vidx, use_topology)) != -1) {
if (vidx != vidx_mirr) {
if (!BLI_BITMAP_TEST(vert_tag, vidx_mirr)) {
-
- if (use_vert_sel) {
- sel = select_vert[vidx];
- sel_mirr = select_vert[vidx_mirr];
- }
+ const bool sel = use_vert_sel ? select_vert[vidx] : true;
+ const bool sel_mirr = use_vert_sel ? select_vert[vidx_mirr] : true;
if (sel || sel_mirr) {
- MDeformVert *dvert = &dverts[vidx];
- dvert_mirr = &dvert[vidx_mirr];
-
- VGROUP_MIRR_OP;
+ dvert_mirror_op(&dverts[vidx],
+ &dverts[vidx_mirr],
+ sel,
+ sel_mirr,
+ flip_map,
+ flip_map_len,
+ mirror_weights,
+ flip_vgroups,
+ all_vgroups,
+ def_nr);
totmirr++;
}
@@ -2523,9 +2514,6 @@ void ED_vgroup_mirror(Object *ob,
}
else if (ob->type == OB_LATTICE) {
Lattice *lt = vgroup_edit_lattice(ob);
- int i1, i2;
- int u, v, w;
- int pntsu_half;
/* half but found up odd value */
if (lt->pntsu == 1 || lt->dvert == nullptr) {
@@ -2535,29 +2523,33 @@ void ED_vgroup_mirror(Object *ob,
/* unlike editmesh we know that by only looping over the first half of
* the 'u' indices it will cover all points except the middle which is
* ok in this case */
- pntsu_half = lt->pntsu / 2;
+ int pntsu_half = lt->pntsu / 2;
- for (w = 0; w < lt->pntsw; w++) {
- for (v = 0; v < lt->pntsv; v++) {
- for (u = 0; u < pntsu_half; u++) {
+ for (int w = 0; w < lt->pntsw; w++) {
+ for (int v = 0; v < lt->pntsv; v++) {
+ for (int u = 0; u < pntsu_half; u++) {
int u_inv = (lt->pntsu - 1) - u;
if (u != u_inv) {
- BPoint *bp, *bp_mirr;
-
- i1 = BKE_lattice_index_from_uvw(lt, u, v, w);
- i2 = BKE_lattice_index_from_uvw(lt, u_inv, v, w);
+ const int i1 = BKE_lattice_index_from_uvw(lt, u, v, w);
+ const int i2 = BKE_lattice_index_from_uvw(lt, u_inv, v, w);
- bp = &lt->def[i1];
- bp_mirr = &lt->def[i2];
+ const BPoint *bp = &lt->def[i1];
+ const BPoint *bp_mirr = &lt->def[i2];
- sel = bp->f1 & SELECT;
- sel_mirr = bp_mirr->f1 & SELECT;
+ const bool sel = bp->f1 & SELECT;
+ const bool sel_mirr = bp_mirr->f1 & SELECT;
if (sel || sel_mirr) {
- MDeformVert *dvert = &lt->dvert[i1];
- dvert_mirr = &lt->dvert[i2];
-
- VGROUP_MIRR_OP;
+ dvert_mirror_op(&lt->dvert[i1],
+ &lt->dvert[i2],
+ sel,
+ sel_mirr,
+ flip_map,
+ flip_map_len,
+ mirror_weights,
+ flip_vgroups,
+ all_vgroups,
+ def_nr);
totmirr++;
}
}
@@ -2850,8 +2842,9 @@ static bool vertex_group_vert_select_unlocked_poll(bContext *C)
if (def_nr != 0) {
const ListBase *defbase = BKE_object_defgroup_list(ob);
const bDeformGroup *dg = static_cast<const bDeformGroup *>(BLI_findlink(defbase, def_nr - 1));
- if (dg) {
- return !(dg->flag & DG_LOCK_WEIGHT);
+ if (dg && (dg->flag & DG_LOCK_WEIGHT)) {
+ CTX_wm_operator_poll_msg_set(C, "The active vertex group is locked");
+ return false;
}
}
return true;
diff --git a/source/blender/editors/physics/particle_edit.c b/source/blender/editors/physics/particle_edit.c
index 761a6702c6f..e6d0aca7902 100644
--- a/source/blender/editors/physics/particle_edit.c
+++ b/source/blender/editors/physics/particle_edit.c
@@ -3533,7 +3533,7 @@ static void PE_mirror_x(Depsgraph *depsgraph, Scene *scene, Object *ob, int tagg
}
const bool use_dm_final_indices = (psys->part->use_modifier_stack &&
- !psmd_eval->mesh_final->runtime.deformed_only);
+ !BKE_mesh_is_deformed_only(psmd_eval->mesh_final));
/* NOTE: this is not nice to use tessfaces but hard to avoid since pa->num uses tessfaces */
BKE_mesh_tessface_ensure(me);
@@ -4353,7 +4353,7 @@ static void brush_add_count_iter(void *__restrict iter_data_v,
0,
0,
0)) {
- if (psys->part->use_modifier_stack && !psmd_eval->mesh_final->runtime.deformed_only) {
+ if (psys->part->use_modifier_stack && !BKE_mesh_is_deformed_only(psmd_eval->mesh_final)) {
add_pars[iter].num = add_pars[iter].num_dmcache;
add_pars[iter].num_dmcache = DMCACHE_ISCHILD;
}
@@ -4430,7 +4430,7 @@ static int brush_add(const bContext *C, PEData *data, short number)
timestep = psys_get_timestep(&sim);
- if (psys->part->use_modifier_stack || psmd_eval->mesh_final->runtime.deformed_only) {
+ if (psys->part->use_modifier_stack || BKE_mesh_is_deformed_only(psmd_eval->mesh_final)) {
mesh = psmd_eval->mesh_final;
}
else {
diff --git a/source/blender/editors/physics/particle_object.c b/source/blender/editors/physics/particle_object.c
index 08db03db0e9..71ed32caede 100644
--- a/source/blender/editors/physics/particle_object.c
+++ b/source/blender/editors/physics/particle_object.c
@@ -732,7 +732,7 @@ static bool remap_hair_emitter(Depsgraph *depsgraph,
invert_m4_m4(to_imat, to_mat);
const bool use_dm_final_indices = (target_psys->part->use_modifier_stack &&
- !target_psmd->mesh_final->runtime.deformed_only);
+ !BKE_mesh_is_deformed_only(target_psmd->mesh_final));
if (use_dm_final_indices || !target_psmd->mesh_original) {
mesh = target_psmd->mesh_final;
diff --git a/source/blender/editors/render/render_shading.cc b/source/blender/editors/render/render_shading.cc
index 25d5ceb8216..83ce447e8cf 100644
--- a/source/blender/editors/render/render_shading.cc
+++ b/source/blender/editors/render/render_shading.cc
@@ -879,7 +879,7 @@ static int new_world_exec(bContext *C, wmOperator * /*op*/)
wo = new_wo;
}
else {
- wo = BKE_world_add(bmain, DATA_("World"));
+ wo = BKE_world_add(bmain, CTX_DATA_(BLT_I18NCONTEXT_ID_WORLD, "World"));
ED_node_shader_default(C, &wo->id);
wo->use_nodes = true;
}
diff --git a/source/blender/editors/scene/scene_edit.c b/source/blender/editors/scene/scene_edit.c
index f19017cb723..01877deb716 100644
--- a/source/blender/editors/scene/scene_edit.c
+++ b/source/blender/editors/scene/scene_edit.c
@@ -286,6 +286,7 @@ static void SCENE_OT_new(wmOperatorType *ot)
/* properties */
ot->prop = RNA_def_enum(ot->srna, "type", scene_new_items, SCE_COPY_NEW, "Type", "");
+ RNA_def_property_translation_context(ot->prop, BLT_I18NCONTEXT_ID_SCENE);
}
/** \} */
diff --git a/source/blender/editors/sculpt_paint/paint_image_ops_paint.cc b/source/blender/editors/sculpt_paint/paint_image_ops_paint.cc
index ced7949c69f..d5c5aa5cebd 100644
--- a/source/blender/editors/sculpt_paint/paint_image_ops_paint.cc
+++ b/source/blender/editors/sculpt_paint/paint_image_ops_paint.cc
@@ -74,11 +74,8 @@ class AbstractPaintMode {
class ImagePaintMode : public AbstractPaintMode {
public:
- void *paint_new_stroke(bContext *C,
- wmOperator *op,
- Object * /*ob*/,
- const float UNUSED(mouse[2]),
- int mode) override
+ void *paint_new_stroke(
+ bContext *C, wmOperator *op, Object * /*ob*/, const float /*mouse*/[2], int mode) override
{
return paint_2d_new_stroke(C, op, mode);
}
diff --git a/source/blender/editors/sculpt_paint/paint_image_proj.c b/source/blender/editors/sculpt_paint/paint_image_proj.c
index 8ffa78cd457..41d5090b38c 100644
--- a/source/blender/editors/sculpt_paint/paint_image_proj.c
+++ b/source/blender/editors/sculpt_paint/paint_image_proj.c
@@ -4074,7 +4074,7 @@ static bool proj_paint_state_mesh_eval_init(const bContext *C, ProjPaintState *p
ps->totloop_eval = ps->me_eval->totloop;
ps->mlooptri_eval = BKE_mesh_runtime_looptri_ensure(ps->me_eval);
- ps->totlooptri_eval = ps->me_eval->runtime.looptris.len;
+ ps->totlooptri_eval = BKE_mesh_runtime_looptri_len(ps->me_eval);
ps->poly_to_loop_uv = MEM_mallocN(ps->totpoly_eval * sizeof(MLoopUV *), "proj_paint_mtfaces");
diff --git a/source/blender/editors/sculpt_paint/paint_utils.c b/source/blender/editors/sculpt_paint/paint_utils.c
index cb981a3bfb1..ce4a5151a20 100644
--- a/source/blender/editors/sculpt_paint/paint_utils.c
+++ b/source/blender/editors/sculpt_paint/paint_utils.c
@@ -286,7 +286,7 @@ static void imapaint_pick_uv(
const ePaintCanvasSource mode = scene->toolsettings->imapaint.mode;
const MLoopTri *lt = BKE_mesh_runtime_looptri_ensure(me_eval);
- const int tottri = me_eval->runtime.looptris.len;
+ const int tottri = BKE_mesh_runtime_looptri_len(me_eval);
const MVert *mvert = BKE_mesh_verts(me_eval);
const MLoop *mloop = BKE_mesh_loops(me_eval);
diff --git a/source/blender/editors/sculpt_paint/sculpt.c b/source/blender/editors/sculpt_paint/sculpt.c
index 87112616f93..37a630b8065 100644
--- a/source/blender/editors/sculpt_paint/sculpt.c
+++ b/source/blender/editors/sculpt_paint/sculpt.c
@@ -1981,7 +1981,7 @@ static void calc_area_normal_and_center_task_cb(void *__restrict userdata,
int(*orco_tris)[3];
int orco_tris_num;
- BKE_pbvh_node_get_bm_orco_data(data->nodes[n], &orco_tris, &orco_tris_num, &orco_coords);
+ BKE_pbvh_node_get_bm_orco_data(data->nodes[n], &orco_tris, &orco_tris_num, &orco_coords, NULL);
for (int i = 0; i < orco_tris_num; i++) {
const float *co_tri[3] = {
@@ -3289,7 +3289,7 @@ static void sculpt_topology_update(Sculpt *sd,
if (BKE_pbvh_type(ss->pbvh) == PBVH_BMESH) {
BKE_pbvh_node_mark_topology_update(nodes[n]);
- BKE_pbvh_bmesh_node_save_orig(ss->bm, nodes[n]);
+ BKE_pbvh_bmesh_node_save_orig(ss->bm, ss->bm_log, nodes[n], false);
}
}
@@ -4310,7 +4310,8 @@ static void sculpt_update_cache_invariants(
bContext *C, Sculpt *sd, SculptSession *ss, wmOperator *op, const float mval[2])
{
StrokeCache *cache = MEM_callocN(sizeof(StrokeCache), "stroke cache");
- UnifiedPaintSettings *ups = &CTX_data_tool_settings(C)->unified_paint_settings;
+ ToolSettings *tool_settings = CTX_data_tool_settings(C);
+ UnifiedPaintSettings *ups = &tool_settings->unified_paint_settings;
Brush *brush = BKE_paint_brush(&sd->paint);
ViewContext *vc = paint_stroke_view_context(op->customdata);
Object *ob = CTX_data_active_object(C);
@@ -4445,6 +4446,13 @@ static void sculpt_update_cache_invariants(
}
}
+ /* Original coordinates require the sculpt undo system, which isn't used
+ * for image brushes. It's also not necessary, just disable it. */
+ if (brush && brush->sculpt_tool == SCULPT_TOOL_PAINT &&
+ SCULPT_use_image_paint_brush(&tool_settings->paint_mode, ob)) {
+ cache->original = false;
+ }
+
cache->first_time = true;
#define PIXEL_INPUT_THRESHHOLD 5
@@ -5787,15 +5795,14 @@ static int sculpt_brush_stroke_modal(bContext *C, wmOperator *op, const wmEvent
if (!started && ELEM(retval, OPERATOR_FINISHED, OPERATOR_CANCELLED)) {
/* Did the stroke never start? If so push a blank sculpt undo
* step to prevent a global undo step (which is triggered by the
- * OPTYPE_UNDO flag in SCULPT_OT_brush_stroke).
+ * #OPTYPE_UNDO flag in #SCULPT_OT_brush_stroke).
*
* Having blank global undo steps interleaved with sculpt steps
* corrupts the DynTopo undo stack.
* See T101430.
*
- * Note: simply returning OPERATOR_CANCELLED was not
- * sufficient to prevent this.
- */
+ * NOTE: simply returning #OPERATOR_CANCELLED was not
+ * sufficient to prevent this. */
Sculpt *sd = CTX_data_tool_settings(C)->sculpt;
Brush *brush = BKE_paint_brush(&sd->paint);
diff --git a/source/blender/editors/sculpt_paint/sculpt_automasking.cc b/source/blender/editors/sculpt_paint/sculpt_automasking.cc
index 5a0fcd8bc27..505440c9272 100644
--- a/source/blender/editors/sculpt_paint/sculpt_automasking.cc
+++ b/source/blender/editors/sculpt_paint/sculpt_automasking.cc
@@ -503,7 +503,7 @@ float SCULPT_automasking_factor_get(AutomaskingCache *automasking,
PBVHVertRef vert,
AutomaskingNodeData *automask_data)
{
- if (!automasking) {
+ if (!automasking || vert.i == PBVH_REF_NONE) {
return 1.0f;
}
diff --git a/source/blender/editors/sculpt_paint/sculpt_brush_types.c b/source/blender/editors/sculpt_paint/sculpt_brush_types.c
index 041efbb357c..92541d10a59 100644
--- a/source/blender/editors/sculpt_paint/sculpt_brush_types.c
+++ b/source/blender/editors/sculpt_paint/sculpt_brush_types.c
@@ -2149,6 +2149,8 @@ static void do_elastic_deform_brush_task_cb_ex(void *__restrict userdata,
BKE_pbvh_vertex_iter_begin (ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) {
SCULPT_orig_vert_data_update(&orig_data, &vd);
+ SCULPT_automasking_node_update(ss, &automask_data, &vd);
+
float final_disp[3];
switch (brush->elastic_deform_type) {
case BRUSH_ELASTIC_DEFORM_GRAB:
diff --git a/source/blender/editors/sculpt_paint/sculpt_face_set.cc b/source/blender/editors/sculpt_paint/sculpt_face_set.cc
index 15a91e4eaab..ee1238e0f24 100644
--- a/source/blender/editors/sculpt_paint/sculpt_face_set.cc
+++ b/source/blender/editors/sculpt_paint/sculpt_face_set.cc
@@ -198,8 +198,8 @@ static void do_relax_face_sets_brush_task_cb_ex(void *__restrict userdata,
const bool relax_face_sets = !(ss->cache->iteration_count % 3 == 0);
/* This operations needs a strength tweak as the relax deformation is too weak by default. */
- if (relax_face_sets) {
- bstrength *= 2.0f;
+ if (relax_face_sets && data->iteration < 2) {
+ bstrength *= 1.5f;
}
const int thread_id = BLI_task_parallel_thread_id(tls);
@@ -261,6 +261,7 @@ void SCULPT_do_draw_face_sets_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, in
if (ss->cache->alt_smooth) {
SCULPT_boundary_info_ensure(ob);
for (int i = 0; i < 4; i++) {
+ data.iteration = i;
BLI_task_parallel_range(0, totnode, &data, do_relax_face_sets_brush_task_cb_ex, &settings);
}
}
@@ -827,9 +828,6 @@ static int sculpt_face_sets_change_visibility_exec(bContext *C, wmOperator *op)
const int mode = RNA_enum_get(op->ptr, "mode");
const int tot_vert = SCULPT_vertex_count_get(ss);
- const int active_face_set = SCULPT_active_face_set_get(ss);
-
- SCULPT_undo_push_begin(ob, op);
PBVH *pbvh = ob->sculpt->pbvh;
PBVHNode **nodes;
@@ -842,62 +840,86 @@ static int sculpt_face_sets_change_visibility_exec(bContext *C, wmOperator *op)
return OPERATOR_CANCELLED;
}
- SCULPT_undo_push_node(ob, nodes[0], SCULPT_UNDO_FACE_SETS);
-
- if (mode == SCULPT_FACE_SET_VISIBILITY_TOGGLE) {
- bool hidden_vertex = false;
+ const int active_face_set = SCULPT_active_face_set_get(ss);
- /* This can fail with regular meshes with non-manifold geometry as the visibility state can't
- * be synced from face sets to non-manifold vertices. */
- if (BKE_pbvh_type(ss->pbvh) == PBVH_GRIDS) {
- for (int i = 0; i < tot_vert; i++) {
- PBVHVertRef vertex = BKE_pbvh_index_to_vertex(ss->pbvh, i);
+ SCULPT_undo_push_begin(ob, op);
+ for (int i = 0; i < totnode; i++) {
+ SCULPT_undo_push_node(ob, nodes[i], SCULPT_UNDO_HIDDEN);
+ }
- if (!SCULPT_vertex_visible_get(ss, vertex)) {
- hidden_vertex = true;
- break;
+ switch (mode) {
+ case SCULPT_FACE_SET_VISIBILITY_TOGGLE: {
+ bool hidden_vertex = false;
+
+ /* This can fail with regular meshes with non-manifold geometry as the visibility state can't
+ * be synced from face sets to non-manifold vertices. */
+ if (BKE_pbvh_type(ss->pbvh) == PBVH_GRIDS) {
+ for (int i = 0; i < tot_vert; i++) {
+ PBVHVertRef vertex = BKE_pbvh_index_to_vertex(ss->pbvh, i);
+
+ if (!SCULPT_vertex_visible_get(ss, vertex)) {
+ hidden_vertex = true;
+ break;
+ }
}
}
- }
- if (ss->hide_poly) {
- for (int i = 0; i < ss->totfaces; i++) {
- if (ss->hide_poly[i]) {
- hidden_vertex = true;
- break;
+ if (ss->hide_poly) {
+ for (int i = 0; i < ss->totfaces; i++) {
+ if (ss->hide_poly[i]) {
+ hidden_vertex = true;
+ break;
+ }
}
}
- }
- ss->hide_poly = BKE_sculpt_hide_poly_ensure(mesh);
+ ss->hide_poly = BKE_sculpt_hide_poly_ensure(mesh);
- if (hidden_vertex) {
- SCULPT_face_visibility_all_set(ss, true);
- }
- else {
- SCULPT_face_visibility_all_set(ss, false);
- SCULPT_face_set_visibility_set(ss, active_face_set, true);
+ if (hidden_vertex) {
+ SCULPT_face_visibility_all_set(ss, true);
+ }
+ else {
+ if (ss->face_sets) {
+ SCULPT_face_visibility_all_set(ss, false);
+ SCULPT_face_set_visibility_set(ss, active_face_set, true);
+ }
+ else {
+ SCULPT_face_visibility_all_set(ss, true);
+ }
+ }
+ break;
}
- }
+ case SCULPT_FACE_SET_VISIBILITY_SHOW_ACTIVE:
+ ss->hide_poly = BKE_sculpt_hide_poly_ensure(mesh);
- if (mode == SCULPT_FACE_SET_VISIBILITY_SHOW_ACTIVE) {
- ss->hide_poly = BKE_sculpt_hide_poly_ensure(mesh);
- SCULPT_face_visibility_all_set(ss, false);
- SCULPT_face_set_visibility_set(ss, active_face_set, true);
- }
+ if (ss->face_sets) {
+ SCULPT_face_visibility_all_set(ss, false);
+ SCULPT_face_set_visibility_set(ss, active_face_set, true);
+ }
+ else {
+ SCULPT_face_set_visibility_set(ss, active_face_set, true);
+ }
+ break;
+ case SCULPT_FACE_SET_VISIBILITY_HIDE_ACTIVE:
+ ss->hide_poly = BKE_sculpt_hide_poly_ensure(mesh);
- if (mode == SCULPT_FACE_SET_VISIBILITY_HIDE_ACTIVE) {
- ss->hide_poly = BKE_sculpt_hide_poly_ensure(mesh);
- SCULPT_face_set_visibility_set(ss, active_face_set, false);
- }
+ if (ss->face_sets) {
+ SCULPT_face_set_visibility_set(ss, active_face_set, false);
+ }
+ else {
+ SCULPT_face_visibility_all_set(ss, false);
+ }
- if (mode == SCULPT_FACE_SET_VISIBILITY_INVERT) {
- ss->hide_poly = BKE_sculpt_hide_poly_ensure(mesh);
- SCULPT_face_visibility_all_invert(ss);
+ break;
+ case SCULPT_FACE_SET_VISIBILITY_INVERT:
+ ss->hide_poly = BKE_sculpt_hide_poly_ensure(mesh);
+ SCULPT_face_visibility_all_invert(ss);
+ break;
}
/* For modes that use the cursor active vertex, update the rotation origin for viewport
- * navigation. */
+ * navigation.
+ */
if (ELEM(mode, SCULPT_FACE_SET_VISIBILITY_TOGGLE, SCULPT_FACE_SET_VISIBILITY_SHOW_ACTIVE)) {
UnifiedPaintSettings *ups = &CTX_data_tool_settings(C)->unified_paint_settings;
float location[3];
@@ -912,7 +934,6 @@ static int sculpt_face_sets_change_visibility_exec(bContext *C, wmOperator *op)
SCULPT_visibility_sync_all_from_faces(ob);
SCULPT_undo_push_end(ob);
-
for (int i = 0; i < totnode; i++) {
BKE_pbvh_node_mark_update_visibility(nodes[i]);
}
diff --git a/source/blender/editors/sculpt_paint/sculpt_intern.h b/source/blender/editors/sculpt_paint/sculpt_intern.h
index 44ff0da9347..59b0f7f5925 100644
--- a/source/blender/editors/sculpt_paint/sculpt_intern.h
+++ b/source/blender/editors/sculpt_paint/sculpt_intern.h
@@ -332,7 +332,7 @@ typedef struct SculptThreadedTaskData {
int mask_init_seed;
ThreadMutex mutex;
-
+ int iteration;
} SculptThreadedTaskData;
/*************** Brush testing declarations ****************/
diff --git a/source/blender/editors/sculpt_paint/sculpt_ops.c b/source/blender/editors/sculpt_paint/sculpt_ops.c
index 1042356489b..56a35ee1774 100644
--- a/source/blender/editors/sculpt_paint/sculpt_ops.c
+++ b/source/blender/editors/sculpt_paint/sculpt_ops.c
@@ -1116,10 +1116,7 @@ static int sculpt_bake_cavity_exec(bContext *C, wmOperator *op)
SCULPT_undo_push_end(ob);
SCULPT_flush_update_done(C, ob, SCULPT_UPDATE_MASK);
-
- /* Unlike other operators we do not tag the ID for update here;
- * it triggers a PBVH rebuild which is too slow and ruins
- * the interactivity of the tool. */
+ SCULPT_tag_update_overlays(C);
return OPERATOR_FINISHED;
}
@@ -1294,11 +1291,10 @@ static int sculpt_reveal_all_exec(bContext *C, wmOperator *op)
SCULPT_visibility_sync_all_from_faces(ob);
- /* Note: SCULPT_visibility_sync_all_from_faces may have deleted
- * pbvh->hide_vert if hide_poly did not exist, which is why
- * we call BKE_pbvh_update_hide_attributes_from_mesh here instead of
- * after CustomData_free_layer_named above.
- */
+ /* NOTE: #SCULPT_visibility_sync_all_from_faces may have deleted
+ * `pbvh->hide_vert` if hide_poly did not exist, which is why
+ * we call #BKE_pbvh_update_hide_attributes_from_mesh here instead of
+ * after #CustomData_free_layer_named above. */
if (!with_bmesh) {
BKE_pbvh_update_hide_attributes_from_mesh(ss->pbvh);
}
diff --git a/source/blender/editors/space_clip/clip_ops.c b/source/blender/editors/space_clip/clip_ops.c
index f276c2acd1a..a625c124dd3 100644
--- a/source/blender/editors/space_clip/clip_ops.c
+++ b/source/blender/editors/space_clip/clip_ops.c
@@ -1611,7 +1611,9 @@ void CLIP_OT_mode_set(wmOperatorType *ot)
ot->poll = ED_space_clip_poll;
/* properties */
- RNA_def_enum(ot->srna, "mode", rna_enum_clip_editor_mode_items, SC_MODE_TRACKING, "Mode", "");
+ ot->prop = RNA_def_enum(
+ ot->srna, "mode", rna_enum_clip_editor_mode_items, SC_MODE_TRACKING, "Mode", "");
+ RNA_def_property_translation_context(ot->prop, BLT_I18NCONTEXT_ID_MOVIECLIP);
}
/** \} */
@@ -1639,14 +1641,14 @@ static int clip_view_ndof_invoke(bContext *C, wmOperator *UNUSED(op), const wmEv
float pan_vec[3];
const wmNDOFMotionData *ndof = event->customdata;
- const float speed = NDOF_PIXELS_PER_SECOND;
+ const float pan_speed = NDOF_PIXELS_PER_SECOND;
WM_event_ndof_pan_get(ndof, pan_vec, true);
- mul_v2_fl(pan_vec, (speed * ndof->dt) / sc->zoom);
- pan_vec[2] *= -ndof->dt;
+ mul_v3_fl(pan_vec, ndof->dt);
+ mul_v2_fl(pan_vec, pan_speed / sc->zoom);
- sclip_zoom_set_factor(C, 1.0f + pan_vec[2], NULL, false);
+ sclip_zoom_set_factor(C, max_ff(0.0f, 1.0f - pan_vec[2]), NULL, false);
sc->xof += pan_vec[0];
sc->yof += pan_vec[1];
diff --git a/source/blender/editors/space_image/image_draw.c b/source/blender/editors/space_image/image_draw.c
index 42ebed6ec3a..85b1e2b6707 100644
--- a/source/blender/editors/space_image/image_draw.c
+++ b/source/blender/editors/space_image/image_draw.c
@@ -589,15 +589,27 @@ void ED_space_image_grid_steps(SpaceImage *sima,
float grid_steps_y[SI_GRID_STEPS_LEN],
const int grid_dimension)
{
- const int flag = sima->flag;
+ const eSpaceImage_GridShapeSource grid_shape_source = sima->grid_shape_source;
for (int step = 0; step < SI_GRID_STEPS_LEN; step++) {
- if (flag & SI_CUSTOM_GRID) {
- grid_steps_x[step] = 1.0f / sima->custom_grid_subdiv[0];
- grid_steps_y[step] = 1.0f / sima->custom_grid_subdiv[1];
- }
- else {
- grid_steps_x[step] = powf(grid_dimension, step - SI_GRID_STEPS_LEN);
- grid_steps_y[step] = powf(grid_dimension, step - SI_GRID_STEPS_LEN);
+ switch (grid_shape_source) {
+ case SI_GRID_SHAPE_DYNAMIC:
+ grid_steps_x[step] = powf(grid_dimension, step - SI_GRID_STEPS_LEN);
+ grid_steps_y[step] = powf(grid_dimension, step - SI_GRID_STEPS_LEN);
+ break;
+ case SI_GRID_SHAPE_FIXED:
+ grid_steps_x[step] = 1.0f / sima->custom_grid_subdiv[0];
+ grid_steps_y[step] = 1.0f / sima->custom_grid_subdiv[1];
+ break;
+ case SI_GRID_SHAPE_PIXEL: {
+ int pixel_width = IMG_SIZE_FALLBACK;
+ int pixel_height = IMG_SIZE_FALLBACK;
+ ED_space_image_get_size(sima, &pixel_width, &pixel_height);
+ BLI_assert(pixel_width > 0 && pixel_height > 0);
+ grid_steps_x[step] = 1.0f / pixel_width;
+ grid_steps_y[step] = 1.0f / pixel_height;
+ } break;
+ default:
+ BLI_assert_unreachable();
}
}
}
diff --git a/source/blender/editors/space_image/image_ops.c b/source/blender/editors/space_image/image_ops.c
index bb47ad5c6c0..3503c4c8168 100644
--- a/source/blender/editors/space_image/image_ops.c
+++ b/source/blender/editors/space_image/image_ops.c
@@ -762,14 +762,14 @@ static int image_view_ndof_invoke(bContext *C, wmOperator *UNUSED(op), const wmE
float pan_vec[3];
const wmNDOFMotionData *ndof = event->customdata;
- const float speed = NDOF_PIXELS_PER_SECOND;
+ const float pan_speed = NDOF_PIXELS_PER_SECOND;
WM_event_ndof_pan_get(ndof, pan_vec, true);
- mul_v2_fl(pan_vec, (speed * ndof->dt) / sima->zoom);
- pan_vec[2] *= -ndof->dt;
+ mul_v3_fl(pan_vec, ndof->dt);
+ mul_v2_fl(pan_vec, pan_speed / sima->zoom);
- sima_zoom_set_factor(sima, region, 1.0f + pan_vec[2], NULL, false);
+ sima_zoom_set_factor(sima, region, max_ff(0.0f, 1.0f - pan_vec[2]), NULL, false);
sima->xof += pan_vec[0];
sima->yof += pan_vec[1];
diff --git a/source/blender/editors/space_image/space_image.c b/source/blender/editors/space_image/space_image.c
index 71cbcea1c1f..53e1bc0a1e5 100644
--- a/source/blender/editors/space_image/space_image.c
+++ b/source/blender/editors/space_image/space_image.c
@@ -5,6 +5,7 @@
* \ingroup spimage
*/
+#include "DNA_defaults.h"
#include "DNA_gpencil_types.h"
#include "DNA_image_types.h"
#include "DNA_mask_types.h"
@@ -117,6 +118,8 @@ static SpaceLink *image_create(const ScrArea *UNUSED(area), const Scene *UNUSED(
simage->custom_grid_subdiv[0] = 10;
simage->custom_grid_subdiv[1] = 10;
+ simage->mask_info = *DNA_struct_default_get(MaskSpaceInfo);
+
/* header */
region = MEM_callocN(sizeof(ARegion), "header for image");
diff --git a/source/blender/editors/space_info/info_stats.cc b/source/blender/editors/space_info/info_stats.cc
index cac0dbb0067..e8b005b2b67 100644
--- a/source/blender/editors/space_info/info_stats.cc
+++ b/source/blender/editors/space_info/info_stats.cc
@@ -40,6 +40,7 @@
#include "BKE_key.h"
#include "BKE_layer.h"
#include "BKE_main.h"
+#include "BKE_mesh.h"
#include "BKE_object.h"
#include "BKE_paint.h"
#include "BKE_particle.h"
@@ -94,8 +95,8 @@ static bool stats_mesheval(const Mesh *me_eval, bool is_selected, SceneStats *st
int totvert, totedge, totface, totloop;
- const SubdivCCG *subdiv_ccg = me_eval->runtime.subdiv_ccg;
- const SubsurfRuntimeData *subsurf_runtime_data = me_eval->runtime.subsurf_runtime_data;
+ const SubdivCCG *subdiv_ccg = me_eval->runtime->subdiv_ccg;
+ const SubsurfRuntimeData *subsurf_runtime_data = me_eval->runtime->subsurf_runtime_data;
if (subdiv_ccg != nullptr) {
BKE_subdiv_ccg_topology_counters(subdiv_ccg, &totvert, &totedge, &totface, &totloop);
diff --git a/source/blender/editors/space_nla/nla_edit.c b/source/blender/editors/space_nla/nla_edit.c
index 9df25b1229e..8a3c6745259 100644
--- a/source/blender/editors/space_nla/nla_edit.c
+++ b/source/blender/editors/space_nla/nla_edit.c
@@ -2641,6 +2641,8 @@ static int nla_fmodifier_add_exec(bContext *C, wmOperator *op)
void NLA_OT_fmodifier_add(wmOperatorType *ot)
{
+ PropertyRNA *prop;
+
/* identifiers */
ot->name = "Add F-Modifier";
ot->idname = "NLA_OT_fmodifier_add";
@@ -2659,11 +2661,12 @@ void NLA_OT_fmodifier_add(wmOperatorType *ot)
RNA_def_property_translation_context(ot->prop, BLT_I18NCONTEXT_ID_ACTION);
RNA_def_enum_funcs(ot->prop, nla_fmodifier_itemf);
- RNA_def_boolean(ot->srna,
- "only_active",
- true,
- "Only Active",
- "Only add a F-Modifier of the specified type to the active strip");
+ prop = RNA_def_boolean(ot->srna,
+ "only_active",
+ true,
+ "Only Active",
+ "Only add a F-Modifier of the specified type to the active strip");
+ RNA_def_property_translation_context(prop, BLT_I18NCONTEXT_ID_ACTION);
}
/** \} */
@@ -2832,8 +2835,10 @@ void NLA_OT_fmodifier_paste(wmOperatorType *ot)
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
/* properties */
- RNA_def_boolean(
+ ot->prop = RNA_def_boolean(
ot->srna, "only_active", true, "Only Active", "Only paste F-Modifiers on active strip");
+ RNA_def_property_translation_context(ot->prop, BLT_I18NCONTEXT_ID_ACTION);
+
RNA_def_boolean(
ot->srna,
"replace",
diff --git a/source/blender/editors/space_node/add_node_search.cc b/source/blender/editors/space_node/add_node_search.cc
index 819f0abac7c..28e18c20f46 100644
--- a/source/blender/editors/space_node/add_node_search.cc
+++ b/source/blender/editors/space_node/add_node_search.cc
@@ -182,6 +182,9 @@ static void gather_add_node_operations(const bContext &C,
/* Skip the empty group type. */
continue;
}
+ if (StringRefNull(node_type->ui_name).endswith("(Legacy)")) {
+ continue;
+ }
AddNodeItem item{};
item.ui_name = IFACE_(node_type->ui_name);
diff --git a/source/blender/editors/space_node/link_drag_search.cc b/source/blender/editors/space_node/link_drag_search.cc
index 17410937d4c..ffa2d377056 100644
--- a/source/blender/editors/space_node/link_drag_search.cc
+++ b/source/blender/editors/space_node/link_drag_search.cc
@@ -274,7 +274,9 @@ static void gather_socket_link_operations(const bContext &C,
if (!(node_type->poll && node_type->poll(node_type, &node_tree, &disabled_hint))) {
continue;
}
-
+ if (StringRefNull(node_type->ui_name).endswith("(Legacy)")) {
+ continue;
+ }
if (node_type->gather_link_search_ops) {
nodes::GatherLinkSearchOpParams params{*node_type, node_tree, socket, search_link_ops};
node_type->gather_link_search_ops(params);
diff --git a/source/blender/editors/space_node/node_draw.cc b/source/blender/editors/space_node/node_draw.cc
index dc155f5e28d..ee9ebd541a0 100644
--- a/source/blender/editors/space_node/node_draw.cc
+++ b/source/blender/editors/space_node/node_draw.cc
@@ -3011,7 +3011,7 @@ static void node_draw_nodetree(const bContext &C,
}
}
-/* Draw the breadcrumb on the bottom of the editor. */
+/* Draw the breadcrumb on the top of the editor. */
static void draw_tree_path(const bContext &C, ARegion &region)
{
using namespace blender;
diff --git a/source/blender/editors/space_node/node_edit.cc b/source/blender/editors/space_node/node_edit.cc
index 3a80733f06c..48b3d711bdf 100644
--- a/source/blender/editors/space_node/node_edit.cc
+++ b/source/blender/editors/space_node/node_edit.cc
@@ -1361,12 +1361,15 @@ static int node_duplicate_exec(bContext *C, wmOperator *op)
SpaceNode *snode = CTX_wm_space_node(C);
bNodeTree *ntree = snode->edittree;
const bool keep_inputs = RNA_boolean_get(op->ptr, "keep_inputs");
+ bool linked = RNA_boolean_get(op->ptr, "linked") || ((U.dupflag & USER_DUP_NTREE) == 0);
+ const bool dupli_node_tree = !linked;
bool changed = false;
ED_preview_kill_jobs(CTX_wm_manager(C), bmain);
Map<const bNode *, bNode *> node_map;
Map<const bNodeSocket *, bNodeSocket *> socket_map;
+ Map<const ID *, ID *> duplicated_node_groups;
bNode *lastnode = (bNode *)ntree->nodes.last;
LISTBASE_FOREACH (bNode *, node, &ntree->nodes) {
@@ -1374,6 +1377,18 @@ static int node_duplicate_exec(bContext *C, wmOperator *op)
bNode *new_node = bke::node_copy_with_mapping(
ntree, *node, LIB_ID_COPY_DEFAULT, true, socket_map);
node_map.add_new(node, new_node);
+
+ if (node->id && dupli_node_tree) {
+ ID *new_group = duplicated_node_groups.lookup_or_add_cb(node->id, [&]() {
+ ID *new_group = BKE_id_copy(bmain, node->id);
+ /* Remove user added by copying. */
+ id_us_min(new_group);
+ return new_group;
+ });
+ id_us_plus(new_group);
+ id_us_min(new_node->id);
+ new_node->id = new_group;
+ }
changed = true;
}
@@ -1462,6 +1477,8 @@ static int node_duplicate_exec(bContext *C, wmOperator *op)
void NODE_OT_duplicate(wmOperatorType *ot)
{
+ PropertyRNA *prop;
+
/* identifiers */
ot->name = "Duplicate Nodes";
ot->description = "Duplicate selected nodes";
@@ -1476,6 +1493,13 @@ void NODE_OT_duplicate(wmOperatorType *ot)
RNA_def_boolean(
ot->srna, "keep_inputs", false, "Keep Inputs", "Keep the input links to duplicated nodes");
+
+ prop = RNA_def_boolean(ot->srna,
+ "linked",
+ true,
+ "Linked",
+ "Duplicate node but not node trees, linking to the original data");
+ RNA_def_property_flag(prop, PROP_SKIP_SAVE);
}
/* XXX: some code needing updating to operators. */
@@ -2275,6 +2299,7 @@ static int node_clipboard_copy_exec(bContext *C, wmOperator * /*op*/)
newlink->tosock = socket_map.lookup(link->tosock);
newlink->fromnode = node_map.lookup(link->fromnode);
newlink->fromsock = socket_map.lookup(link->fromsock);
+ newlink->multi_input_socket_index = link->multi_input_socket_index;
BKE_node_clipboard_add_link(newlink);
}
@@ -2396,11 +2421,19 @@ static int node_clipboard_paste_exec(bContext *C, wmOperator *op)
}
LISTBASE_FOREACH (bNodeLink *, link, clipboard_links_lb) {
- nodeAddLink(ntree,
- node_map.lookup(link->fromnode),
- socket_map.lookup(link->fromsock),
- node_map.lookup(link->tonode),
- socket_map.lookup(link->tosock));
+ bNodeLink *new_link = nodeAddLink(ntree,
+ node_map.lookup(link->fromnode),
+ socket_map.lookup(link->fromsock),
+ node_map.lookup(link->tonode),
+ socket_map.lookup(link->tosock));
+ new_link->multi_input_socket_index = link->multi_input_socket_index;
+ }
+
+ ntree->ensure_topology_cache();
+
+ for (bNode *new_node : node_map.values()) {
+ /* Update multi input socket indices in case all connected nodes weren't copied. */
+ update_multi_input_indices_for_removed_links(*new_node);
}
Main *bmain = CTX_data_main(C);
diff --git a/source/blender/editors/space_node/node_intern.hh b/source/blender/editors/space_node/node_intern.hh
index 50c03489027..1c3026628a6 100644
--- a/source/blender/editors/space_node/node_intern.hh
+++ b/source/blender/editors/space_node/node_intern.hh
@@ -270,6 +270,8 @@ void NODE_OT_group_edit(wmOperatorType *ot);
/* node_relationships.cc */
+void update_multi_input_indices_for_removed_links(bNode &node);
+
void NODE_OT_link(wmOperatorType *ot);
void NODE_OT_link_make(wmOperatorType *ot);
void NODE_OT_links_cut(wmOperatorType *ot);
diff --git a/source/blender/editors/space_node/node_ops.cc b/source/blender/editors/space_node/node_ops.cc
index 6c52dae5b86..d45c33a3c59 100644
--- a/source/blender/editors/space_node/node_ops.cc
+++ b/source/blender/editors/space_node/node_ops.cc
@@ -174,7 +174,17 @@ void ED_operatormacros_node()
"Duplicate",
"Duplicate selected nodes and move them",
OPTYPE_UNDO | OPTYPE_REGISTER);
- WM_operatortype_macro_define(ot, "NODE_OT_duplicate");
+ mot = WM_operatortype_macro_define(ot, "NODE_OT_duplicate");
+ RNA_boolean_set(mot->ptr, "linked", false);
+ WM_operatortype_macro_define(ot, "NODE_OT_translate_attach");
+
+ ot = WM_operatortype_append_macro(
+ "NODE_OT_duplicate_move_linked",
+ "Duplicate Linked",
+ "Duplicate selected nodes, but not their node trees, and move them",
+ OPTYPE_UNDO | OPTYPE_REGISTER);
+ mot = WM_operatortype_macro_define(ot, "NODE_OT_duplicate");
+ RNA_boolean_set(mot->ptr, "linked", true);
WM_operatortype_macro_define(ot, "NODE_OT_translate_attach");
/* modified operator call for duplicating with input links */
diff --git a/source/blender/editors/space_node/node_relationships.cc b/source/blender/editors/space_node/node_relationships.cc
index 7cf18e2f828..b12afcb1faa 100644
--- a/source/blender/editors/space_node/node_relationships.cc
+++ b/source/blender/editors/space_node/node_relationships.cc
@@ -64,6 +64,10 @@ struct NodeInsertOfsData {
float offset_x; /* offset to apply to node chain */
};
+namespace blender::ed::space_node {
+
+bNodeSocket *get_main_socket(bNodeTree &ntree, bNode &node, eNodeSocketInOut in_out);
+
static void clear_picking_highlight(ListBase *links)
{
LISTBASE_FOREACH (bNodeLink *, link, links) {
@@ -71,10 +75,6 @@ static void clear_picking_highlight(ListBase *links)
}
}
-namespace blender::ed::space_node {
-
-void update_multi_input_indices_for_removed_links(bNode &node);
-
/* -------------------------------------------------------------------- */
/** \name Add Node
* \{ */
@@ -1750,29 +1750,31 @@ static int node_attach_invoke(bContext *C, wmOperator * /*op*/, const wmEvent *e
}
LISTBASE_FOREACH_BACKWARD (bNode *, node, &ntree.nodes) {
- if (node->flag & NODE_SELECT) {
- if (node->parent == nullptr) {
- /* disallow moving a parent into its child */
- if (nodeAttachNodeCheck(frame, node) == false) {
- /* attach all unparented nodes */
- nodeAttachNode(node, frame);
- }
+ if (!(node->flag & NODE_SELECT)) {
+ continue;
+ }
+
+ if (node->parent == nullptr) {
+ /* disallow moving a parent into its child */
+ if (nodeAttachNodeCheck(frame, node) == false) {
+ /* attach all unparented nodes */
+ nodeAttachNode(node, frame);
}
- else {
- /* attach nodes which share parent with the frame */
- bNode *parent;
- for (parent = frame->parent; parent; parent = parent->parent) {
- if (parent == node->parent) {
- break;
- }
+ }
+ else {
+ /* attach nodes which share parent with the frame */
+ bNode *parent;
+ for (parent = frame->parent; parent; parent = parent->parent) {
+ if (parent == node->parent) {
+ break;
}
+ }
- if (parent) {
- /* disallow moving a parent into its child */
- if (nodeAttachNodeCheck(frame, node) == false) {
- nodeDetachNode(node);
- nodeAttachNode(node, frame);
- }
+ if (parent) {
+ /* disallow moving a parent into its child */
+ if (nodeAttachNodeCheck(frame, node) == false) {
+ nodeDetachNode(node);
+ nodeAttachNode(node, frame);
}
}
}
@@ -1881,100 +1883,55 @@ void NODE_OT_detach(wmOperatorType *ot)
/** \name Automatic Node Insert on Dragging
* \{ */
-/* prevent duplicate testing code below */
-static bool ed_node_link_conditions(ScrArea *area,
- bool test,
- SpaceNode **r_snode,
- bNode **r_select)
+static bNode *get_selected_node_for_insertion(bNodeTree &node_tree)
{
- SpaceNode *snode = area ? (SpaceNode *)area->spacedata.first : nullptr;
-
- *r_snode = snode;
- *r_select = nullptr;
-
- /* no unlucky accidents */
- if (area == nullptr || area->spacetype != SPACE_NODE) {
- return false;
- }
-
- if (!test) {
- /* no need to look for a node */
- return true;
- }
-
- bNode *node;
- bNode *select = nullptr;
- for (node = (bNode *)snode->edittree->nodes.first; node; node = node->next) {
+ bNode *selected_node = nullptr;
+ int selected_node_count = 0;
+ for (bNode *node : node_tree.all_nodes()) {
if (node->flag & SELECT) {
- if (select) {
- break;
- }
- select = node;
+ selected_node = node;
+ selected_node_count++;
+ }
+ if (selected_node_count > 1) {
+ return nullptr;
}
}
- /* only one selected */
- if (node || select == nullptr) {
- return false;
+ if (!selected_node) {
+ return nullptr;
}
-
- /* correct node */
- if (BLI_listbase_is_empty(&select->inputs) || BLI_listbase_is_empty(&select->outputs)) {
- return false;
+ if (selected_node->input_sockets().is_empty() || selected_node->output_sockets().is_empty()) {
+ return nullptr;
}
-
- ARegion *region = BKE_area_find_region_type(area, RGN_TYPE_WINDOW);
-
- /* test node for links */
- LISTBASE_FOREACH (bNodeLink *, link, &snode->edittree->links) {
- if (node_link_is_hidden_or_dimmed(region->v2d, *link)) {
- continue;
- }
-
- if (link->tonode == select || link->fromnode == select) {
- return false;
- }
+ if (std::any_of(selected_node->input_sockets().begin(),
+ selected_node->input_sockets().end(),
+ [&](const bNodeSocket *socket) { return socket->is_directly_linked(); })) {
+ return nullptr;
}
-
- *r_select = select;
- return true;
+ if (std::any_of(selected_node->output_sockets().begin(),
+ selected_node->output_sockets().end(),
+ [&](const bNodeSocket *socket) { return socket->is_directly_linked(); })) {
+ return nullptr;
+ };
+ return selected_node;
}
-/** \} */
-
-} // namespace blender::ed::space_node
-
-/* -------------------------------------------------------------------- */
-/** \name Node Line Intersection Test
- * \{ */
-
-void ED_node_link_intersect_test(ScrArea *area, int test)
+void node_insert_on_link_flags_set(SpaceNode &snode, const ARegion &region)
{
- using namespace blender;
- using namespace blender::ed::space_node;
-
- bNode *select;
- SpaceNode *snode;
- if (!ed_node_link_conditions(area, test, &snode, &select)) {
- return;
- }
+ bNodeTree &node_tree = *snode.edittree;
+ node_tree.ensure_topology_cache();
- /* clear flags */
- LISTBASE_FOREACH (bNodeLink *, link, &snode->edittree->links) {
- link->flag &= ~NODE_LINKFLAG_HILITE;
- }
+ node_insert_on_link_flags_clear(node_tree);
- if (test == 0) {
+ bNode *node_to_insert = get_selected_node_for_insertion(node_tree);
+ if (!node_to_insert) {
return;
}
- ARegion *region = BKE_area_find_region_type(area, RGN_TYPE_WINDOW);
-
/* find link to select/highlight */
bNodeLink *selink = nullptr;
float dist_best = FLT_MAX;
- LISTBASE_FOREACH (bNodeLink *, link, &snode->edittree->links) {
-
- if (node_link_is_hidden_or_dimmed(region->v2d, *link)) {
+ LISTBASE_FOREACH (bNodeLink *, link, &node_tree.links) {
+ if (node_link_is_hidden_or_dimmed(region.v2d, *link)) {
continue;
}
@@ -1986,10 +1943,10 @@ void ED_node_link_intersect_test(ScrArea *area, int test)
* upper left node edge of a intersected line segment */
for (int i = 0; i < NODE_LINK_RESOL; i++) {
/* Check if the node rectangle intersects the line from this point to next one. */
- if (BLI_rctf_isect_segment(&select->totr, coords[i], coords[i + 1])) {
+ if (BLI_rctf_isect_segment(&node_to_insert->totr, coords[i], coords[i + 1])) {
/* store the shortest distance to the upper left edge
* of all intersections found so far */
- const float node_xy[] = {select->totr.xmin, select->totr.ymax};
+ const float node_xy[] = {node_to_insert->totr.xmin, node_to_insert->totr.ymax};
/* to be precise coords should be clipped by select->totr,
* but not done since there's no real noticeable difference */
@@ -2009,9 +1966,89 @@ void ED_node_link_intersect_test(ScrArea *area, int test)
}
}
-/** \} */
+void node_insert_on_link_flags_clear(bNodeTree &node_tree)
+{
+ LISTBASE_FOREACH (bNodeLink *, link, &node_tree.links) {
+ link->flag &= ~NODE_LINKFLAG_HILITE;
+ }
+}
-namespace blender::ed::space_node {
+void node_insert_on_link_flags(Main &bmain, SpaceNode &snode)
+{
+ bNodeTree &node_tree = *snode.edittree;
+ node_tree.ensure_topology_cache();
+ bNode *node_to_insert = get_selected_node_for_insertion(node_tree);
+ if (!node_to_insert) {
+ return;
+ }
+
+ /* Find link to insert on. */
+ bNodeTree &ntree = *snode.edittree;
+ bNodeLink *old_link = nullptr;
+ LISTBASE_FOREACH (bNodeLink *, link, &ntree.links) {
+ if (link->flag & NODE_LINKFLAG_HILITE) {
+ old_link = link;
+ break;
+ }
+ }
+ if (old_link == nullptr) {
+ return;
+ }
+
+ old_link->flag &= ~NODE_LINKFLAG_HILITE;
+
+ bNodeSocket *best_input = get_main_socket(ntree, *node_to_insert, SOCK_IN);
+ bNodeSocket *best_output = get_main_socket(ntree, *node_to_insert, SOCK_OUT);
+
+ if (node_to_insert->type != NODE_REROUTE) {
+ /* Ignore main sockets when the types don't match. */
+ if (best_input != nullptr && ntree.typeinfo->validate_link != nullptr &&
+ !ntree.typeinfo->validate_link(static_cast<eNodeSocketDatatype>(old_link->fromsock->type),
+ static_cast<eNodeSocketDatatype>(best_input->type))) {
+ best_input = nullptr;
+ }
+ if (best_output != nullptr && ntree.typeinfo->validate_link != nullptr &&
+ !ntree.typeinfo->validate_link(static_cast<eNodeSocketDatatype>(best_output->type),
+ static_cast<eNodeSocketDatatype>(old_link->tosock->type))) {
+ best_output = nullptr;
+ }
+ }
+
+ bNode *from_node = old_link->fromnode;
+ bNodeSocket *from_socket = old_link->fromsock;
+ bNode *to_node = old_link->tonode;
+
+ if (best_output != nullptr) {
+ /* Relink the "start" of the existing link to the newly inserted node. */
+ old_link->fromnode = node_to_insert;
+ old_link->fromsock = best_output;
+ BKE_ntree_update_tag_link_changed(&ntree);
+ }
+ else {
+ nodeRemLink(&ntree, old_link);
+ }
+
+ if (best_input != nullptr) {
+ /* Add a new link that connects the node on the left to the newly inserted node. */
+ nodeAddLink(&ntree, from_node, from_socket, node_to_insert, best_input);
+ }
+
+ /* Set up insert offset data, it needs stuff from here. */
+ if ((snode.flag & SNODE_SKIP_INSOFFSET) == 0) {
+ BLI_assert(snode.runtime->iofsd == nullptr);
+ NodeInsertOfsData *iofsd = MEM_cnew<NodeInsertOfsData>(__func__);
+
+ iofsd->insert = node_to_insert;
+ iofsd->prev = from_node;
+ iofsd->next = to_node;
+
+ snode.runtime->iofsd = iofsd;
+ }
+
+ ED_node_tree_propagate_change(nullptr, &bmain, &ntree);
+}
+
+/** \} */
/* -------------------------------------------------------------------- */
/** \name Node Insert Offset Operator
@@ -2048,7 +2085,7 @@ static int get_main_socket_priority(const bNodeSocket *socket)
}
/** Get the "main" socket based on the node declaration or an heuristic. */
-static bNodeSocket *get_main_socket(bNodeTree &ntree, bNode &node, eNodeSocketInOut in_out)
+bNodeSocket *get_main_socket(bNodeTree &ntree, bNode &node, eNodeSocketInOut in_out)
{
ListBase *sockets = (in_out == SOCK_IN) ? &node.inputs : &node.outputs;
@@ -2426,85 +2463,3 @@ void NODE_OT_insert_offset(wmOperatorType *ot)
/** \} */
} // namespace blender::ed::space_node
-
-/* -------------------------------------------------------------------- */
-/** \name Note Link Insert
- * \{ */
-
-void ED_node_link_insert(Main *bmain, ScrArea *area)
-{
- using namespace blender::ed::space_node;
-
- bNode *node_to_insert;
- SpaceNode *snode;
- if (!ed_node_link_conditions(area, true, &snode, &node_to_insert)) {
- return;
- }
-
- /* Find link to insert on. */
- bNodeTree &ntree = *snode->edittree;
- bNodeLink *old_link = nullptr;
- LISTBASE_FOREACH (bNodeLink *, link, &ntree.links) {
- if (link->flag & NODE_LINKFLAG_HILITE) {
- old_link = link;
- break;
- }
- }
- if (old_link == nullptr) {
- return;
- }
-
- old_link->flag &= ~NODE_LINKFLAG_HILITE;
-
- bNodeSocket *best_input = get_main_socket(ntree, *node_to_insert, SOCK_IN);
- bNodeSocket *best_output = get_main_socket(ntree, *node_to_insert, SOCK_OUT);
-
- if (node_to_insert->type != NODE_REROUTE) {
- /* Ignore main sockets when the types don't match. */
- if (best_input != nullptr && ntree.typeinfo->validate_link != nullptr &&
- !ntree.typeinfo->validate_link(static_cast<eNodeSocketDatatype>(old_link->fromsock->type),
- static_cast<eNodeSocketDatatype>(best_input->type))) {
- best_input = nullptr;
- }
- if (best_output != nullptr && ntree.typeinfo->validate_link != nullptr &&
- !ntree.typeinfo->validate_link(static_cast<eNodeSocketDatatype>(best_output->type),
- static_cast<eNodeSocketDatatype>(old_link->tosock->type))) {
- best_output = nullptr;
- }
- }
-
- bNode *from_node = old_link->fromnode;
- bNodeSocket *from_socket = old_link->fromsock;
- bNode *to_node = old_link->tonode;
-
- if (best_output != nullptr) {
- /* Relink the "start" of the existing link to the newly inserted node. */
- old_link->fromnode = node_to_insert;
- old_link->fromsock = best_output;
- BKE_ntree_update_tag_link_changed(&ntree);
- }
- else {
- nodeRemLink(&ntree, old_link);
- }
-
- if (best_input != nullptr) {
- /* Add a new link that connects the node on the left to the newly inserted node. */
- nodeAddLink(&ntree, from_node, from_socket, node_to_insert, best_input);
- }
-
- /* Set up insert offset data, it needs stuff from here. */
- if ((snode->flag & SNODE_SKIP_INSOFFSET) == 0) {
- BLI_assert(snode->runtime->iofsd == nullptr);
- NodeInsertOfsData *iofsd = MEM_cnew<NodeInsertOfsData>(__func__);
-
- iofsd->insert = node_to_insert;
- iofsd->prev = from_node;
- iofsd->next = to_node;
-
- snode->runtime->iofsd = iofsd;
- }
-
- ED_node_tree_propagate_change(nullptr, bmain, snode->edittree);
-}
-
-/** \} */
diff --git a/source/blender/editors/space_outliner/outliner_dragdrop.cc b/source/blender/editors/space_outliner/outliner_dragdrop.cc
index 259d879d76f..3b07c6da5fa 100644
--- a/source/blender/editors/space_outliner/outliner_dragdrop.cc
+++ b/source/blender/editors/space_outliner/outliner_dragdrop.cc
@@ -888,7 +888,7 @@ static bool datastack_drop_poll(bContext *C, wmDrag *drag, const wmEvent *event)
static char *datastack_drop_tooltip(bContext * /*C*/,
wmDrag *drag,
- const int UNUSED(xy[2]),
+ const int /*xy*/[2],
struct wmDropBox * /*drop*/)
{
StackDropData *drop_data = static_cast<StackDropData *>(drag->poin);
diff --git a/source/blender/editors/space_outliner/outliner_draw.cc b/source/blender/editors/space_outliner/outliner_draw.cc
index 8a1119d5e66..34d1e1bb546 100644
--- a/source/blender/editors/space_outliner/outliner_draw.cc
+++ b/source/blender/editors/space_outliner/outliner_draw.cc
@@ -2941,16 +2941,66 @@ static bool tselem_draw_icon(uiBlock *block,
return true;
}
+static bool outliner_is_main_row(const ARegion *region, const int ys)
+{
+ int ystart;
+
+ ystart = int(region->v2d.tot.ymax);
+ ystart = UI_UNIT_Y * (ystart / (UI_UNIT_Y)) - OL_Y_OFFSET;
+
+ return ((ys - ystart) / UI_UNIT_Y) % 2;
+}
+
+/**
+ * Get the expected row background color to use for the data-block counter
+ *
+ * This reproduces somes of the logic of outliner_draw_highlights.
+ * At the moment it doesn't implement the search match color since
+ * we don't draw the data-block counter in those cases.
+ */
+static void outliner_get_row_color(const ARegion *region,
+ const TreeElement *te,
+ int ys,
+ float r_color[4])
+{
+ const TreeStoreElem *tselem = TREESTORE(te);
+
+ if ((tselem->flag & TSE_ACTIVE) && (tselem->flag & TSE_SELECTED)) {
+ UI_GetThemeColor3fv(TH_ACTIVE, r_color);
+ }
+ else if (tselem->flag & TSE_SELECTED) {
+ UI_GetThemeColor3fv(TH_SELECT_HIGHLIGHT, r_color);
+ }
+ else if (outliner_is_main_row(region, ys)) {
+ UI_GetThemeColor3fv(TH_BACK, r_color);
+ }
+ else {
+ float color_alternating[4];
+ UI_GetThemeColor4fv(TH_ROW_ALTERNATE, color_alternating);
+ UI_GetThemeColorBlend3f(TH_BACK, TH_ROW_ALTERNATE, color_alternating[3], r_color);
+ }
+
+ if (tselem->flag & TSE_HIGHLIGHTED) {
+ const float color_highlight[4] = {1.0f, 1.0f, 1.0f, 0.13f};
+ interp_v3_v3v3(r_color, r_color, color_highlight, color_highlight[3]);
+ }
+ r_color[3] = 1.0f;
+}
+
/**
* For icon-only children of a collapsed tree,
* Draw small number over the icon to show how many items of this type are displayed.
*/
-static void outliner_draw_iconrow_number(const uiFontStyle *fstyle,
+static void outliner_draw_iconrow_number(const ARegion *region,
+ const uiFontStyle *fstyle,
int offsx,
int ys,
+ const TreeElement *te_visible,
const int num_elements)
{
- const float color[4] = {0.0f, 0.0f, 0.0f, 1.0f};
+ float color[4];
+ outliner_get_row_color(region, te_visible, ys, color);
+
float ufac = 0.25f * UI_UNIT_X;
float offset_x = float(offsx) + UI_UNIT_X * 0.35f;
rctf rect{};
@@ -2961,12 +3011,13 @@ static void outliner_draw_iconrow_number(const uiFontStyle *fstyle,
float(ys) - UI_UNIT_Y * 0.2f + UI_UNIT_Y - ufac);
UI_draw_roundbox_corner_set(UI_CNR_ALL);
- UI_draw_roundbox_aa(&rect, true, float(UI_UNIT_Y) / 2.0f - ufac, color);
+ UI_draw_roundbox_4fv_ex(
+ &rect, color, NULL, 1.0f, color, U.pixelsize, float(UI_UNIT_Y) / 2.0f - ufac);
/* Now the numbers. */
uchar text_col[4];
- UI_GetThemeColor3ubv(TH_TEXT_HI, text_col);
+ UI_GetThemeColor3ubv(TH_TEXT, text_col);
text_col[3] = 255;
uiFontStyle fstyle_small = *fstyle;
@@ -3018,7 +3069,9 @@ static void outliner_draw_active_indicator(const float minx,
GPU_blend(GPU_BLEND_ALPHA); /* Round-box disables. */
}
-static void outliner_draw_iconrow_doit(uiBlock *block,
+static void outliner_draw_iconrow_doit(const ARegion *region,
+ uiBlock *block,
+ TreeElement *te_visible,
TreeElement *te,
const uiFontStyle *fstyle,
int xmax,
@@ -3055,7 +3108,7 @@ static void outliner_draw_iconrow_doit(uiBlock *block,
te->xend = short(*offsx) + UI_UNIT_X;
if (num_elements > 1) {
- outliner_draw_iconrow_number(fstyle, *offsx, ys, num_elements);
+ outliner_draw_iconrow_number(region, fstyle, *offsx, ys, te_visible, num_elements);
te->flag |= TE_ICONROW_MERGED;
}
else {
@@ -3092,6 +3145,7 @@ static void outliner_draw_iconrow(bContext *C,
const uiFontStyle *fstyle,
const TreeViewContext *tvc,
SpaceOutliner *space_outliner,
+ TreeElement *te_visible,
ListBase *lb,
int level,
int xmax,
@@ -3100,6 +3154,7 @@ static void outliner_draw_iconrow(bContext *C,
float alpha_fac,
MergedIconRow *merged)
{
+ const ARegion *region = CTX_wm_region(C);
eOLDrawState active = OL_DRAWSEL_NONE;
LISTBASE_FOREACH (TreeElement *, te, lb) {
@@ -3139,7 +3194,8 @@ static void outliner_draw_iconrow(bContext *C,
TSE_POSE_CHANNEL,
TSE_POSEGRP,
TSE_DEFGROUP)) {
- outliner_draw_iconrow_doit(block, te, fstyle, xmax, offsx, ys, alpha_fac, active, 1);
+ outliner_draw_iconrow_doit(
+ region, block, te_visible, te, fstyle, xmax, offsx, ys, alpha_fac, active, 1);
}
else {
const int index = tree_element_id_type_to_index(te);
@@ -3158,6 +3214,7 @@ static void outliner_draw_iconrow(bContext *C,
fstyle,
tvc,
space_outliner,
+ te,
&te->subtree,
level + 1,
xmax,
@@ -3179,7 +3236,9 @@ static void outliner_draw_iconrow(bContext *C,
for (int j = 0; j < num_subtypes; j++) {
const int index = index_base + j;
if (merged->num_elements[index] != 0) {
- outliner_draw_iconrow_doit(block,
+ outliner_draw_iconrow_doit(region,
+ block,
+ te_visible,
merged->tree_element[index],
fstyle,
xmax,
@@ -3419,6 +3478,7 @@ static void outliner_draw_tree_element(bContext *C,
fstyle,
tvc,
space_outliner,
+ te,
&te->subtree,
0,
xmax,
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 8af12590b0f..b2f9cfc6395 100644
--- a/source/blender/editors/space_spreadsheet/spreadsheet_data_source_geometry.cc
+++ b/source/blender/editors/space_spreadsheet/spreadsheet_data_source_geometry.cc
@@ -487,37 +487,6 @@ GeometrySet spreadsheet_get_display_geometry_set(const SpaceSpreadsheet *sspread
return geometry_set;
}
-class GeometryComponentCacheKey : public SpreadsheetCache::Key {
- public:
- /* Use the pointer to the geometry component as a key to detect when the geometry changed. */
- const GeometryComponent *component;
-
- GeometryComponentCacheKey(const GeometryComponent &component) : component(&component)
- {
- }
-
- uint64_t hash() const override
- {
- return get_default_hash(this->component);
- }
-
- bool is_equal_to(const Key &other) const override
- {
- if (const GeometryComponentCacheKey *other_geo =
- dynamic_cast<const GeometryComponentCacheKey *>(&other)) {
- return this->component == other_geo->component;
- }
- return false;
- }
-};
-
-class GeometryComponentCacheValue : public SpreadsheetCache::Value {
- public:
- /* Stores the result of fields evaluated on a geometry component. Without this, fields would have
- * to be reevaluated on every redraw. */
- Map<std::pair<eAttrDomain, GField>, GArray<>> arrays;
-};
-
std::unique_ptr<DataSource> data_source_from_geometry(const bContext *C, Object *object_eval)
{
SpaceSpreadsheet *sspreadsheet = CTX_wm_space_spreadsheet(C);
diff --git a/source/blender/editors/space_view3d/drawobject.c b/source/blender/editors/space_view3d/drawobject.c
index 36ced74a8b7..6370d56ae8c 100644
--- a/source/blender/editors/space_view3d/drawobject.c
+++ b/source/blender/editors/space_view3d/drawobject.c
@@ -17,6 +17,7 @@
#include "BKE_editmesh.h"
#include "BKE_global.h"
#include "BKE_mesh.h"
+#include "BKE_mesh_runtime.h"
#include "BKE_object.h"
#include "DEG_depsgraph.h"
@@ -94,8 +95,8 @@ void ED_draw_object_facemap(Depsgraph *depsgraph,
const MPoly *mp;
int i;
- if (me->runtime.looptris.array) {
- const MLoopTri *mlt = me->runtime.looptris.array;
+ if (BKE_mesh_runtime_looptri_ensure(me)) {
+ const MLoopTri *mlt = BKE_mesh_runtime_looptri_ensure(me);
for (mp = polys, i = 0; i < mpoly_len; i++, mp++) {
if (facemap_data[i] == facemap) {
for (int j = 2; j < mp->totloop; j++) {
diff --git a/source/blender/editors/space_view3d/space_view3d.cc b/source/blender/editors/space_view3d/space_view3d.cc
index 4ac6f926818..635fbd75d74 100644
--- a/source/blender/editors/space_view3d/space_view3d.cc
+++ b/source/blender/editors/space_view3d/space_view3d.cc
@@ -631,7 +631,7 @@ static bool view3d_object_data_drop_poll(bContext *C, wmDrag *drag, const wmEven
static char *view3d_object_data_drop_tooltip(bContext * /*C*/,
wmDrag * /*drag*/,
- const int UNUSED(xy[2]),
+ const int /*xy*/[2],
wmDropBox * /*drop*/)
{
return BLI_strdup(TIP_("Create object instance from object-data"));
diff --git a/source/blender/editors/space_view3d/view3d_gizmo_preselect_type.cc b/source/blender/editors/space_view3d/view3d_gizmo_preselect_type.cc
index c61eac3c777..793ada4f577 100644
--- a/source/blender/editors/space_view3d/view3d_gizmo_preselect_type.cc
+++ b/source/blender/editors/space_view3d/view3d_gizmo_preselect_type.cc
@@ -19,8 +19,10 @@
#include "BKE_context.h"
#include "BKE_editmesh.h"
+#include "BKE_editmesh_cache.h"
#include "BKE_global.h"
#include "BKE_layer.h"
+#include "BKE_mesh.h"
#include "DEG_depsgraph.h"
#include "DEG_depsgraph_query.h"
@@ -234,8 +236,8 @@ static int gizmo_preselect_elem_test_select(bContext *C, wmGizmo *gz, const int
Object *ob = gz_ele->bases[gz_ele->base_index]->object;
Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C);
Mesh *me_eval = (Mesh *)DEG_get_evaluated_id(depsgraph, static_cast<ID *>(ob->data));
- if (me_eval->runtime.edit_data) {
- coords = me_eval->runtime.edit_data->vertexCos;
+ if (me_eval->runtime->edit_data) {
+ coords = me_eval->runtime->edit_data->vertexCos;
}
}
EDBM_preselect_elem_update_from_single(gz_ele->psel, bm, best.ele, coords);
diff --git a/source/blender/editors/space_view3d/view3d_iterators.cc b/source/blender/editors/space_view3d/view3d_iterators.cc
index 139ac9de6e4..932563863fe 100644
--- a/source/blender/editors/space_view3d/view3d_iterators.cc
+++ b/source/blender/editors/space_view3d/view3d_iterators.cc
@@ -262,7 +262,7 @@ struct foreachScreenFace_userData {
static void meshobject_foreachScreenVert__mapFunc(void *userData,
int index,
const float co[3],
- const float UNUSED(no[3]))
+ const float /*no*/[3])
{
foreachScreenObjectVert_userData *data = static_cast<foreachScreenObjectVert_userData *>(
userData);
@@ -316,7 +316,7 @@ void meshobject_foreachScreenVert(
static void mesh_foreachScreenVert__mapFunc(void *userData,
int index,
const float co[3],
- const float UNUSED(no[3]))
+ const float /*no*/[3])
{
foreachScreenVert_userData *data = static_cast<foreachScreenVert_userData *>(userData);
BMVert *eve = BM_vert_at_index(data->vc.em->bm, index);
@@ -538,7 +538,7 @@ void mesh_foreachScreenEdge_clip_bb_segment(ViewContext *vc,
static void mesh_foreachScreenFace__mapFunc(void *userData,
int index,
const float cent[3],
- const float UNUSED(no[3]))
+ const float /*no*/[3])
{
foreachScreenFace_userData *data = static_cast<foreachScreenFace_userData *>(userData);
BMFace *efa = BM_face_at_index(data->vc.em->bm, index);
@@ -576,7 +576,7 @@ void mesh_foreachScreenFace(
BM_mesh_elem_table_ensure(vc->em->bm, BM_FACE);
- if (me->runtime.subsurf_face_dot_tags != nullptr) {
+ if (me->runtime->subsurf_face_dot_tags != nullptr) {
BKE_mesh_foreach_mapped_subdiv_face_center(
me, mesh_foreachScreenFace__mapFunc, &data, MESH_FOREACH_NOP);
}
diff --git a/source/blender/editors/space_view3d/view3d_navigate_ndof.c b/source/blender/editors/space_view3d/view3d_navigate_ndof.c
index 29e63a72daf..9fb33013c4e 100644
--- a/source/blender/editors/space_view3d/view3d_navigate_ndof.c
+++ b/source/blender/editors/space_view3d/view3d_navigate_ndof.c
@@ -370,14 +370,17 @@ static int view3d_ndof_cameraview_pan_zoom(bContext *C, const wmEvent *event)
return OPERATOR_PASS_THROUGH;
}
+ const float pan_speed = NDOF_PIXELS_PER_SECOND;
const bool has_translate = !is_zero_v2(ndof->tvec);
const bool has_zoom = ndof->tvec[2] != 0.0f;
float pan_vec[3];
WM_event_ndof_pan_get(ndof, pan_vec, true);
- mul_v2_fl(pan_vec, ndof->dt);
- pan_vec[2] *= -ndof->dt;
+ mul_v3_fl(pan_vec, ndof->dt);
+ /* NOTE: unlike image and clip views, the 2D pan doesn't have to be scaled by the zoom level.
+ * #ED_view3d_camera_view_pan already takes the zoom level into account. */
+ mul_v2_fl(pan_vec, pan_speed);
/* NOTE(@campbellbarton): In principle rotating could pass through to regular
* non-camera NDOF behavior (exiting the camera-view and rotating).
@@ -393,16 +396,14 @@ static int view3d_ndof_cameraview_pan_zoom(bContext *C, const wmEvent *event)
bool changed = false;
if (has_translate) {
- const float speed = NDOF_PIXELS_PER_SECOND;
- float event_ofs[2] = {pan_vec[0] * speed, pan_vec[1] * speed};
- if (ED_view3d_camera_view_pan(region, event_ofs)) {
+ /* Use the X & Y of `pan_vec`. */
+ if (ED_view3d_camera_view_pan(region, pan_vec)) {
changed = true;
}
}
if (has_zoom) {
- const float scale = 1.0f + pan_vec[2];
- if (ED_view3d_camera_view_zoom_scale(rv3d, scale)) {
+ if (ED_view3d_camera_view_zoom_scale(rv3d, max_ff(0.0f, 1.0f - pan_vec[2]))) {
changed = true;
}
}
diff --git a/source/blender/editors/transform/CMakeLists.txt b/source/blender/editors/transform/CMakeLists.txt
index ec6f62e0f5b..3787a59c83c 100644
--- a/source/blender/editors/transform/CMakeLists.txt
+++ b/source/blender/editors/transform/CMakeLists.txt
@@ -40,7 +40,7 @@ set(SRC
transform_convert_mesh_uv.c
transform_convert_mesh_vert_cdata.c
transform_convert_nla.c
- transform_convert_node.c
+ transform_convert_node.cc
transform_convert_object.c
transform_convert_object_texspace.c
transform_convert_paintcurve.c
diff --git a/source/blender/editors/transform/transform.c b/source/blender/editors/transform/transform.c
index 6f7eb317b42..93e99f97387 100644
--- a/source/blender/editors/transform/transform.c
+++ b/source/blender/editors/transform/transform.c
@@ -1518,26 +1518,26 @@ void saveTransform(bContext *C, TransInfo *t, wmOperator *op)
}
}
- bool use_prop_edit = false;
- int prop_edit_flag = 0;
- if (t->flag & T_PROP_EDIT_ALL) {
- if (t->flag & T_PROP_EDIT) {
- use_prop_edit = true;
- }
- if (t->flag & T_PROP_CONNECTED) {
- prop_edit_flag |= PROP_EDIT_CONNECTED;
- }
- if (t->flag & T_PROP_PROJECTED) {
- prop_edit_flag |= PROP_EDIT_PROJECTED;
+ /* Save proportional edit settings.
+ * Skip saving proportional edit if it was not actually used. */
+ if (!(t->options & CTX_NO_PET)) {
+ bool use_prop_edit = false;
+ int prop_edit_flag = 0;
+ if (t->flag & T_PROP_EDIT_ALL) {
+ if (t->flag & T_PROP_EDIT) {
+ use_prop_edit = true;
+ }
+ if (t->flag & T_PROP_CONNECTED) {
+ prop_edit_flag |= PROP_EDIT_CONNECTED;
+ }
+ if (t->flag & T_PROP_PROJECTED) {
+ prop_edit_flag |= PROP_EDIT_PROJECTED;
+ }
}
- }
- /* If modal, save settings back in scene if not set as operator argument */
- if ((t->flag & T_MODAL) || (op->flag & OP_IS_REPEAT)) {
- /* save settings if not set in operator */
-
- /* skip saving proportional edit if it was not actually used */
- if (!(t->options & CTX_NO_PET)) {
+ /* If modal, save settings back in scene if not set as operator argument */
+ if ((t->flag & T_MODAL) || (op->flag & OP_IS_REPEAT)) {
+ /* save settings if not set in operator */
if ((prop = RNA_struct_find_property(op->ptr, "use_proportional_edit")) &&
!RNA_property_is_set(op->ptr, prop)) {
BKE_view_layer_synced_ensure(t->scene, t->view_layer);
@@ -1576,6 +1576,14 @@ void saveTransform(bContext *C, TransInfo *t, wmOperator *op)
ts->prop_mode = t->prop_mode;
}
}
+
+ if ((prop = RNA_struct_find_property(op->ptr, "use_proportional_edit"))) {
+ RNA_property_boolean_set(op->ptr, prop, use_prop_edit);
+ RNA_boolean_set(op->ptr, "use_proportional_connected", prop_edit_flag & PROP_EDIT_CONNECTED);
+ RNA_boolean_set(op->ptr, "use_proportional_projected", prop_edit_flag & PROP_EDIT_PROJECTED);
+ RNA_enum_set(op->ptr, "proportional_edit_falloff", t->prop_mode);
+ RNA_float_set(op->ptr, "proportional_size", t->prop_size);
+ }
}
/* Save snapping settings. */
@@ -1635,14 +1643,6 @@ void saveTransform(bContext *C, TransInfo *t, wmOperator *op)
}
}
- if ((prop = RNA_struct_find_property(op->ptr, "use_proportional_edit"))) {
- RNA_property_boolean_set(op->ptr, prop, use_prop_edit);
- RNA_boolean_set(op->ptr, "use_proportional_connected", prop_edit_flag & PROP_EDIT_CONNECTED);
- RNA_boolean_set(op->ptr, "use_proportional_projected", prop_edit_flag & PROP_EDIT_PROJECTED);
- RNA_enum_set(op->ptr, "proportional_edit_falloff", t->prop_mode);
- RNA_float_set(op->ptr, "proportional_size", t->prop_size);
- }
-
if ((prop = RNA_struct_find_property(op->ptr, "mirror"))) {
RNA_property_boolean_set(op->ptr, prop, (t->flag & T_NO_MIRROR) == 0);
}
diff --git a/source/blender/editors/transform/transform.h b/source/blender/editors/transform/transform.h
index 09fc07f57f4..e2bab378cad 100644
--- a/source/blender/editors/transform/transform.h
+++ b/source/blender/editors/transform/transform.h
@@ -19,6 +19,10 @@
#include "transform_data.h"
+#ifdef __cplusplus
+extern "C" {
+#endif
+
/* use node center for transform instead of upper-left corner.
* disabled since it makes absolute snapping not work so nicely
*/
@@ -141,6 +145,7 @@ typedef enum {
/** No cursor wrapping on region bounds */
T_NO_CURSOR_WRAP = 1 << 23,
} eTFlag;
+ENUM_OPERATORS(eTFlag, T_NO_CURSOR_WRAP);
#define T_ALL_RESTRICTIONS (T_NO_CONSTRAINT | T_NULL_ONE)
#define T_PROP_EDIT_ALL (T_PROP_EDIT | T_PROP_CONNECTED | T_PROP_PROJECTED)
@@ -864,3 +869,7 @@ bool checkUseAxisMatrix(TransInfo *t);
th++, i++)
/** \} */
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/source/blender/editors/transform/transform_convert.h b/source/blender/editors/transform/transform_convert.h
index f32bff6dcff..8466fd88e1d 100644
--- a/source/blender/editors/transform/transform_convert.h
+++ b/source/blender/editors/transform/transform_convert.h
@@ -10,6 +10,10 @@
#include "RE_engine.h"
+#ifdef __cplusplus
+extern "C" {
+#endif
+
struct BMEditMesh;
struct BMesh;
struct BezTriple;
@@ -244,7 +248,7 @@ extern TransConvertTypeInfo TransConvertType_MeshVertCData;
extern TransConvertTypeInfo TransConvertType_NLA;
-/* transform_convert_node.c */
+/* transform_convert_node.cc */
extern TransConvertTypeInfo TransConvertType_Node;
@@ -279,3 +283,7 @@ extern TransConvertTypeInfo TransConvertType_SequencerImage;
/* transform_convert_tracking.c */
extern TransConvertTypeInfo TransConvertType_Tracking;
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/source/blender/editors/transform/transform_convert_nla.c b/source/blender/editors/transform/transform_convert_nla.c
index cfa933d1600..af5a51cbff6 100644
--- a/source/blender/editors/transform/transform_convert_nla.c
+++ b/source/blender/editors/transform/transform_convert_nla.c
@@ -56,6 +56,29 @@ typedef struct TransDataNla {
} TransDataNla;
/* -------------------------------------------------------------------- */
+/** \name Transform application to NLA strips
+ * \{ */
+
+/**
+ * \brief Applies a translation to the given NlaStrip.
+ * \param strip_rna_ptr The RNA pointer of the NLA strip to modify.
+ * \param transdata The transformation info structure.
+ */
+static void applyTransformNLA_translation(PointerRNA *strip_rna_ptr, const TransDataNla *transdata)
+{
+ /* NOTE: we write these twice to avoid truncation errors which can arise when
+ * moving the strips a large distance using numeric input T33852.
+ */
+ RNA_float_set(strip_rna_ptr, "frame_start", transdata->h1[0]);
+ RNA_float_set(strip_rna_ptr, "frame_end", transdata->h2[0]);
+
+ RNA_float_set(strip_rna_ptr, "frame_start", transdata->h1[0]);
+ RNA_float_set(strip_rna_ptr, "frame_end", transdata->h2[0]);
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
/** \name NLA Transform Creation
* \{ */
@@ -329,15 +352,8 @@ static void recalcData_nla(TransInfo *t)
*
* this is done as a iterative procedure (done 5 times max for now)
*/
- NlaStrip *prev = strip->prev;
- while (prev != NULL && (prev->type & NLASTRIP_TYPE_TRANSITION)) {
- prev = prev->prev;
- }
-
- NlaStrip *next = strip->next;
- while (next != NULL && (next->type & NLASTRIP_TYPE_TRANSITION)) {
- next = next->next;
- }
+ NlaStrip *prev = BKE_nlastrip_prev_in_track(strip, true);
+ NlaStrip *next = BKE_nlastrip_next_in_track(strip, true);
for (short iter = 0; iter < 5; iter++) {
const bool pExceeded = (prev != NULL) && (tdn->h1[0] < prev->end);
@@ -380,17 +396,10 @@ static void recalcData_nla(TransInfo *t)
/* Use RNA to write the values to ensure that constraints on these are obeyed
* (e.g. for transition strips, the values are taken from the neighbors)
- *
- * NOTE: we write these twice to avoid truncation errors which can arise when
- * moving the strips a large distance using numeric input T33852.
*/
RNA_pointer_create(NULL, &RNA_NlaStrip, strip, &strip_ptr);
- RNA_float_set(&strip_ptr, "frame_start", tdn->h1[0]);
- RNA_float_set(&strip_ptr, "frame_end", tdn->h2[0]);
-
- RNA_float_set(&strip_ptr, "frame_start", tdn->h1[0]);
- RNA_float_set(&strip_ptr, "frame_end", tdn->h2[0]);
+ applyTransformNLA_translation(&strip_ptr, tdn);
/* flush transforms to child strips (since this should be a meta) */
BKE_nlameta_flush_transforms(strip);
diff --git a/source/blender/editors/transform/transform_convert_node.c b/source/blender/editors/transform/transform_convert_node.cc
index ed19789fdd8..eb5eb822d69 100644
--- a/source/blender/editors/transform/transform_convert_node.c
+++ b/source/blender/editors/transform/transform_convert_node.cc
@@ -96,13 +96,13 @@ static bool is_node_parent_select(bNode *node)
return false;
}
-static void createTransNodeData(bContext *UNUSED(C), TransInfo *t)
+static void createTransNodeData(bContext * /*C*/, TransInfo *t)
{
const float dpi_fac = UI_DPI_FAC;
- SpaceNode *snode = t->area->spacedata.first;
+ SpaceNode *snode = static_cast<SpaceNode *>(t->area->spacedata.first);
/* Custom data to enable edge panning during the node transform */
- struct TransCustomDataNode *customdata = MEM_callocN(sizeof(*customdata), __func__);
+ TransCustomDataNode *customdata = MEM_cnew<TransCustomDataNode>(__func__);
UI_view2d_edge_pan_init(t->context,
&customdata->edgepan_data,
NODE_EDGE_PAN_INSIDE_PAD,
@@ -125,7 +125,7 @@ static void createTransNodeData(bContext *UNUSED(C), TransInfo *t)
}
/* Nodes don't support PET and probably never will. */
- t->flag &= ~T_PROP_EDIT_ALL;
+ t->flag = t->flag & ~T_PROP_EDIT_ALL;
/* set transform flags on nodes */
LISTBASE_FOREACH (bNode *, node, &snode->edittree->nodes) {
@@ -142,9 +142,8 @@ static void createTransNodeData(bContext *UNUSED(C), TransInfo *t)
return;
}
- TransData *td = tc->data = MEM_callocN(tc->data_len * sizeof(TransData), "TransNode TransData");
- TransData2D *td2d = tc->data_2d = MEM_callocN(tc->data_len * sizeof(TransData2D),
- "TransNode TransData2D");
+ TransData *td = tc->data = MEM_cnew_array<TransData>(tc->data_len, __func__);
+ TransData2D *td2d = tc->data_2d = MEM_cnew_array<TransData2D>(tc->data_len, __func__);
LISTBASE_FOREACH (bNode *, node, &snode->edittree->nodes) {
if (node->flag & NODE_TRANSFORM) {
@@ -161,9 +160,11 @@ static void createTransNodeData(bContext *UNUSED(C), TransInfo *t)
static void flushTransNodes(TransInfo *t)
{
+ using namespace blender::ed;
const float dpi_fac = UI_DPI_FAC;
+ SpaceNode *snode = static_cast<SpaceNode *>(t->area->spacedata.first);
- struct TransCustomDataNode *customdata = (struct TransCustomDataNode *)t->custom.type.data;
+ TransCustomDataNode *customdata = (TransCustomDataNode *)t->custom.type.data;
if (t->options & CTX_VIEW2D_EDGE_PAN) {
if (t->state == TRANS_CANCEL) {
@@ -196,7 +197,7 @@ static void flushTransNodes(TransInfo *t)
for (int i = 0; i < tc->data_len; i++) {
TransData *td = &tc->data[i];
TransData2D *td2d = &tc->data_2d[i];
- bNode *node = td->extra;
+ bNode *node = static_cast<bNode *>(td->extra);
float loc[2];
add_v2_v2v2(loc, td2d->loc, offset);
@@ -221,7 +222,7 @@ static void flushTransNodes(TransInfo *t)
/* handle intersection with noodles */
if (tc->data_len == 1) {
- ED_node_link_intersect_test(t->area, 1);
+ space_node::node_insert_on_link_flags_set(*snode, *t->region);
}
}
}
@@ -234,13 +235,15 @@ static void flushTransNodes(TransInfo *t)
static void special_aftertrans_update__node(bContext *C, TransInfo *t)
{
- struct Main *bmain = CTX_data_main(C);
+ using namespace blender::ed;
+ Main *bmain = CTX_data_main(C);
+ SpaceNode *snode = (SpaceNode *)t->area->spacedata.first;
+ bNodeTree *ntree = snode->edittree;
+
const bool canceled = (t->state == TRANS_CANCEL);
- SpaceNode *snode = (SpaceNode *)t->area->spacedata.first;
if (canceled && t->remove_on_cancel) {
/* remove selected nodes on cancel */
- bNodeTree *ntree = snode->edittree;
if (ntree) {
LISTBASE_FOREACH_MUTABLE (bNode *, node, &ntree->nodes) {
if (node->flag & NODE_SELECT) {
@@ -253,11 +256,10 @@ static void special_aftertrans_update__node(bContext *C, TransInfo *t)
if (!canceled) {
ED_node_post_apply_transform(C, snode->edittree);
- ED_node_link_insert(bmain, t->area);
+ space_node::node_insert_on_link_flags(*bmain, *snode);
}
- /* clear link line */
- ED_node_link_intersect_test(t->area, 0);
+ space_node::node_insert_on_link_flags_clear(*ntree);
}
/** \} */
diff --git a/source/blender/editors/transform/transform_ops.c b/source/blender/editors/transform/transform_ops.c
index dbda9a26bbf..82791b2a9f5 100644
--- a/source/blender/editors/transform/transform_ops.c
+++ b/source/blender/editors/transform/transform_ops.c
@@ -523,9 +523,7 @@ static int transform_invoke(bContext *C, wmOperator *op, const wmEvent *event)
return OPERATOR_RUNNING_MODAL;
}
-static bool transform_poll_property(const bContext *UNUSED(C),
- wmOperator *op,
- const PropertyRNA *prop)
+static bool transform_poll_property(const bContext *C, wmOperator *op, const PropertyRNA *prop)
{
const char *prop_id = RNA_property_identifier(prop);
@@ -559,12 +557,21 @@ static bool transform_poll_property(const bContext *UNUSED(C),
}
/* Proportional Editing. */
- {
+ if (STRPREFIX(prop_id, "proportional") || STRPREFIX(prop_id, "use_proportional")) {
+ ScrArea *area = CTX_wm_area(C);
+ if (area->spacetype == SPACE_NLA) {
+ /* Hide properties that are not supported in some spaces. */
+ return false;
+ }
+
PropertyRNA *prop_pet = RNA_struct_find_property(op->ptr, "use_proportional_edit");
- if (prop_pet && (prop_pet != prop) && (RNA_property_boolean_get(op->ptr, prop_pet) == false)) {
- if (STRPREFIX(prop_id, "proportional") || STRPREFIX(prop_id, "use_proportional")) {
- return false;
- }
+ if ((prop_pet != prop) && (RNA_property_boolean_get(op->ptr, prop_pet) == false)) {
+ /* If "use_proportional_edit" is false, hide:
+ * - "proportional_edit_falloff",
+ * - "proportional_size",
+ * - "use_proportional_connected",
+ * - "use_proportional_projected". */
+ return false;
}
}
diff --git a/source/blender/editors/transform/transform_snap.h b/source/blender/editors/transform/transform_snap.h
index 3672e76c778..2b78c554ad8 100644
--- a/source/blender/editors/transform/transform_snap.h
+++ b/source/blender/editors/transform/transform_snap.h
@@ -11,6 +11,10 @@
/* For enum. */
#include "DNA_space_types.h"
+#ifdef __cplusplus
+extern "C" {
+#endif
+
bool peelObjectsTransform(struct TransInfo *t,
const float mval[2],
bool use_peel_object,
@@ -92,3 +96,7 @@ void transform_snap_anim_flush_data(TransInfo *t,
TransData *td,
eAnimEdit_AutoSnap autosnap,
float *r_val_final);
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/source/blender/editors/transform/transform_snap_object.cc b/source/blender/editors/transform/transform_snap_object.cc
index 90a13722b63..7971e1ca9af 100644
--- a/source/blender/editors/transform/transform_snap_object.cc
+++ b/source/blender/editors/transform/transform_snap_object.cc
@@ -105,7 +105,7 @@ struct SnapData_EditMesh {
/* Looptris. */
BVHTreeFromEditMesh treedata_editmesh;
- struct Mesh_Runtime *mesh_runtime;
+ blender::bke::MeshRuntime *mesh_runtime;
float min[3], max[3];
void clear()
@@ -189,14 +189,14 @@ static const Mesh *mesh_for_snap(Object *ob_eval, eSnapEditType edit_mode_type,
const Mesh *editmesh_eval_cage = BKE_object_get_editmesh_eval_cage(ob_eval);
if ((edit_mode_type == SNAP_GEOM_FINAL) && editmesh_eval_final) {
- if (editmesh_eval_final->runtime.wrapper_type == ME_WRAPPER_TYPE_BMESH) {
+ if (editmesh_eval_final->runtime->wrapper_type == ME_WRAPPER_TYPE_BMESH) {
return nullptr;
}
me_eval = editmesh_eval_final;
use_hide = true;
}
else if ((edit_mode_type == SNAP_GEOM_CAGE) && editmesh_eval_cage) {
- if (editmesh_eval_cage->runtime.wrapper_type == ME_WRAPPER_TYPE_BMESH) {
+ if (editmesh_eval_cage->runtime->wrapper_type == ME_WRAPPER_TYPE_BMESH) {
return nullptr;
}
me_eval = editmesh_eval_cage;
@@ -253,21 +253,21 @@ static SnapData_Mesh *snap_object_data_mesh_get(SnapObjectContext *sctx,
sod = sod_p->get();
bool is_dirty = false;
if (sod->treedata_mesh.tree && sod->treedata_mesh.cached &&
- !bvhcache_has_tree(me_eval->runtime.bvh_cache, sod->treedata_mesh.tree)) {
+ !bvhcache_has_tree(me_eval->runtime->bvh_cache, sod->treedata_mesh.tree)) {
/* The tree is owned by the Mesh and may have been freed since we last used. */
is_dirty = true;
}
else if (sod->bvhtree[0] && sod->cached[0] &&
- !bvhcache_has_tree(me_eval->runtime.bvh_cache, sod->bvhtree[0])) {
+ !bvhcache_has_tree(me_eval->runtime->bvh_cache, sod->bvhtree[0])) {
/* The tree is owned by the Mesh and may have been freed since we last used. */
is_dirty = true;
}
else if (sod->bvhtree[1] && sod->cached[1] &&
- !bvhcache_has_tree(me_eval->runtime.bvh_cache, sod->bvhtree[1])) {
+ !bvhcache_has_tree(me_eval->runtime->bvh_cache, sod->bvhtree[1])) {
/* The tree is owned by the Mesh and may have been freed since we last used. */
is_dirty = true;
}
- else if (sod->treedata_mesh.looptri != me_eval->runtime.looptris.array) {
+ else if (sod->treedata_mesh.looptri != me_eval->looptris().data()) {
is_dirty = true;
}
else if (sod->treedata_mesh.vert != verts.data()) {
@@ -330,19 +330,19 @@ static SnapData_Mesh *snap_object_data_mesh_get(SnapObjectContext *sctx,
/* Searches for the #Mesh_Runtime associated with the object that is most likely to be updated due
* to changes in the `edit_mesh`. */
-static Mesh_Runtime *snap_object_data_editmesh_runtime_get(Object *ob_eval)
+static blender::bke::MeshRuntime *snap_object_data_editmesh_runtime_get(Object *ob_eval)
{
Mesh *editmesh_eval_final = BKE_object_get_editmesh_eval_final(ob_eval);
if (editmesh_eval_final) {
- return &editmesh_eval_final->runtime;
+ return editmesh_eval_final->runtime;
}
Mesh *editmesh_eval_cage = BKE_object_get_editmesh_eval_cage(ob_eval);
if (editmesh_eval_cage) {
- return &editmesh_eval_cage->runtime;
+ return editmesh_eval_cage->runtime;
}
- return &((Mesh *)ob_eval->data)->runtime;
+ return ((Mesh *)ob_eval->data)->runtime;
}
static SnapData_EditMesh *snap_object_data_editmesh_get(SnapObjectContext *sctx,
@@ -457,7 +457,7 @@ static BVHTreeFromEditMesh *snap_object_data_editmesh_treedata_get(SnapObjectCon
4,
BVHTREE_FROM_EM_LOOPTRI,
&sod->mesh_runtime->bvh_cache,
- static_cast<ThreadMutex *>(sod->mesh_runtime->eval_mutex));
+ &sod->mesh_runtime->eval_mutex);
}
}
if (treedata == nullptr || treedata->tree == nullptr) {
@@ -2923,7 +2923,7 @@ static eSnapMode snapEditMesh(SnapObjectContext *sctx,
2,
BVHTREE_FROM_EM_VERTS,
&sod->mesh_runtime->bvh_cache,
- (ThreadMutex *)sod->mesh_runtime->eval_mutex);
+ &sod->mesh_runtime->eval_mutex);
}
sod->bvhtree[0] = treedata.tree;
sod->cached[0] = treedata.cached;
@@ -2955,7 +2955,7 @@ static eSnapMode snapEditMesh(SnapObjectContext *sctx,
2,
BVHTREE_FROM_EM_EDGES,
&sod->mesh_runtime->bvh_cache,
- static_cast<ThreadMutex *>(sod->mesh_runtime->eval_mutex));
+ &sod->mesh_runtime->eval_mutex);
}
sod->bvhtree[1] = treedata.tree;
sod->cached[1] = treedata.cached;
diff --git a/source/blender/editors/uvedit/uvedit_islands.cc b/source/blender/editors/uvedit/uvedit_islands.cc
index 2648ec5e2f6..bdd05b06d94 100644
--- a/source/blender/editors/uvedit/uvedit_islands.cc
+++ b/source/blender/editors/uvedit/uvedit_islands.cc
@@ -403,6 +403,203 @@ int bm_mesh_calc_uv_islands(const Scene *scene,
/** \} */
+static float pack_islands_scale_margin(const blender::Vector<FaceIsland *> &island_vector,
+ BoxPack *box_array,
+ const float scale,
+ const float margin)
+{
+ for (const int index : island_vector.index_range()) {
+ FaceIsland *island = island_vector[index];
+ BoxPack *box = &box_array[index];
+ box->index = index;
+ box->w = BLI_rctf_size_x(&island->bounds_rect) * scale + 2 * margin;
+ box->h = BLI_rctf_size_y(&island->bounds_rect) * scale + 2 * margin;
+ }
+ float max_u, max_v;
+ BLI_box_pack_2d(box_array, island_vector.size(), &max_u, &max_v);
+ return max_ff(max_u, max_v);
+}
+
+static float pack_islands_margin_fraction(const blender::Vector<FaceIsland *> &island_vector,
+ BoxPack *box_array,
+ const float margin_fraction)
+{
+ /*
+ * Root finding using a combined search / modified-secant method.
+ * First, use a robust search procedure to bracket the root within a factor of 10.
+ * Then, use a modified-secant method to converge.
+ *
+ * This is a specialized solver using domain knowledge to accelerate convergence.
+ */
+
+ float scale_low = 0.0f;
+ float value_low = 0.0f;
+ float scale_high = 0.0f;
+ float value_high = 0.0f;
+ float scale_last = 0.0f;
+
+ /* Scaling smaller than `min_scale_roundoff` is unlikely to fit and
+ * will destroy information in existing UVs. */
+ float min_scale_roundoff = 1e-5f;
+
+ /* Certain inputs might have poor convergence properties.
+ * Use `max_iteration` to prevent an infinite loop. */
+ int max_iteration = 25;
+ for (int iteration = 0; iteration < max_iteration; iteration++) {
+ float scale = 1.0f;
+
+ if (iteration == 0) {
+ BLI_assert(iteration == 0);
+ BLI_assert(scale == 1.0f);
+ BLI_assert(scale_low == 0.0f);
+ BLI_assert(scale_high == 0.0f);
+ }
+ else if (scale_low == 0.0f) {
+ BLI_assert(scale_high > 0.0f);
+ /* Search mode, shrink layout until we can find a scale that fits. */
+ scale = scale_high * 0.1f;
+ }
+ else if (scale_high == 0.0f) {
+ BLI_assert(scale_low > 0.0f);
+ /* Search mode, grow layout until we can find a scale that doesn't fit. */
+ scale = scale_low * 10.0f;
+ }
+ else {
+ /* Bracket mode, use modified secant method to find root. */
+ BLI_assert(scale_low > 0.0f);
+ BLI_assert(scale_high > 0.0f);
+ BLI_assert(value_low <= 0.0f);
+ BLI_assert(value_high >= 0.0f);
+ if (scale_high < scale_low * 1.0001f) {
+ /* Convergence. */
+ break;
+ }
+
+ /* Secant method for area. */
+ scale = (sqrtf(scale_low) * value_high - sqrtf(scale_high) * value_low) /
+ (value_high - value_low);
+ scale = scale * scale;
+
+ if (iteration & 1) {
+ /* Modified binary-search to improve robustness. */
+ scale = sqrtf(scale * sqrtf(scale_low * scale_high));
+ }
+ }
+
+ scale = max_ff(scale, min_scale_roundoff);
+
+ /* Evaluate our `f`. */
+ scale_last = scale;
+ float max_uv = pack_islands_scale_margin(
+ island_vector, box_array, scale_last, margin_fraction);
+ float value = sqrtf(max_uv) - 1.0f;
+
+ if (value <= 0.0f) {
+ scale_low = scale;
+ value_low = value;
+ }
+ else {
+ scale_high = scale;
+ value_high = value;
+ if (scale == min_scale_roundoff) {
+ /* Unable to pack without damaging UVs. */
+ scale_low = scale;
+ break;
+ }
+ }
+ }
+
+ const bool flush = true;
+ if (flush) {
+ /* Write back best pack as a side-effect. First get best pack. */
+ if (scale_last != scale_low) {
+ scale_last = scale_low;
+ float max_uv = pack_islands_scale_margin(
+ island_vector, box_array, scale_last, margin_fraction);
+ UNUSED_VARS(max_uv);
+ /* TODO (?): `if (max_uv < 1.0f) { scale_last /= max_uv; }` */
+ }
+
+ /* Then expand FaceIslands by the correct amount. */
+ for (const int index : island_vector.index_range()) {
+ BoxPack *box = &box_array[index];
+ box->x /= scale_last;
+ box->y /= scale_last;
+ FaceIsland *island = island_vector[index];
+ BLI_rctf_pad(
+ &island->bounds_rect, margin_fraction / scale_last, margin_fraction / scale_last);
+ }
+ }
+ return scale_last;
+}
+
+static float calc_margin_from_aabb_length_sum(const blender::Vector<FaceIsland *> &island_vector,
+ const struct UVPackIsland_Params &params)
+{
+ /* Logic matches behavior from #GEO_uv_parametrizer_pack.
+ * Attempt to give predictable results
+ * not dependent on current UV scale by using
+ * `aabb_length_sum` (was "`area`") to multiply
+ * the margin by the length (was "area").
+ */
+ double aabb_length_sum = 0.0f;
+ for (FaceIsland *island : island_vector) {
+ float w = BLI_rctf_size_x(&island->bounds_rect);
+ float h = BLI_rctf_size_y(&island->bounds_rect);
+ aabb_length_sum += sqrtf(w * h);
+ }
+ return params.margin * aabb_length_sum * 0.1f;
+}
+
+static BoxPack *pack_islands_params(const blender::Vector<FaceIsland *> &island_vector,
+ const struct UVPackIsland_Params &params,
+ float r_scale[2])
+{
+ BoxPack *box_array = static_cast<BoxPack *>(
+ MEM_mallocN(sizeof(*box_array) * island_vector.size(), __func__));
+
+ if (params.margin == 0.0f) {
+ /* Special case for zero margin. Margin_method is ignored as all formulas give same result. */
+ const float max_uv = pack_islands_scale_margin(island_vector, box_array, 1.0f, 0.0f);
+ r_scale[0] = 1.0f / max_uv;
+ r_scale[1] = r_scale[0];
+ return box_array;
+ }
+
+ if (params.margin_method == ED_UVPACK_MARGIN_FRACTION) {
+ /* Uses a line search on scale. ~10x slower than other method. */
+ const float scale = pack_islands_margin_fraction(island_vector, box_array, params.margin);
+ r_scale[0] = scale;
+ r_scale[1] = scale;
+ /* pack_islands_margin_fraction will pad FaceIslands, return early. */
+ return box_array;
+ }
+
+ float margin = params.margin;
+ switch (params.margin_method) {
+ case ED_UVPACK_MARGIN_ADD: /* Default for Blender 2.8 and earlier. */
+ break; /* Nothing to do. */
+ case ED_UVPACK_MARGIN_SCALED: /* Default for Blender 3.3 and later. */
+ margin = calc_margin_from_aabb_length_sum(island_vector, params);
+ break;
+ case ED_UVPACK_MARGIN_FRACTION: /* Added as an option in Blender 3.4. */
+ BLI_assert_unreachable(); /* Handled above. */
+ break;
+ default:
+ BLI_assert_unreachable();
+ }
+
+ const float max_uv = pack_islands_scale_margin(island_vector, box_array, 1.0f, margin);
+ r_scale[0] = 1.0f / max_uv;
+ r_scale[1] = r_scale[0];
+
+ for (int index = 0; index < island_vector.size(); index++) {
+ FaceIsland *island = island_vector[index];
+ BLI_rctf_pad(&island->bounds_rect, margin, margin);
+ }
+ return box_array;
+}
+
/* -------------------------------------------------------------------- */
/** \name Public UV Island Packing
*
@@ -412,6 +609,7 @@ int bm_mesh_calc_uv_islands(const Scene *scene,
void ED_uvedit_pack_islands_multi(const Scene *scene,
Object **objects,
const uint objects_len,
+ BMesh **bmesh_override,
const struct UVMapUDIM_Params *udim_params,
const struct UVPackIsland_Params *params)
{
@@ -419,9 +617,17 @@ void ED_uvedit_pack_islands_multi(const Scene *scene,
for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
Object *obedit = objects[ob_index];
- BMEditMesh *em = BKE_editmesh_from_object(obedit);
-
- const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV);
+ BMesh *bm = nullptr;
+ if (bmesh_override) {
+ /* Note: obedit is still required for aspect ratio and ID_RECALC_GEOMETRY. */
+ bm = bmesh_override[ob_index];
+ }
+ else {
+ BMEditMesh *em = BKE_editmesh_from_object(obedit);
+ bm = em->bm;
+ }
+ BLI_assert(bm);
+ const int cd_loop_uv_offset = CustomData_get_offset(&bm->ldata, CD_MLOOPUV);
if (cd_loop_uv_offset == -1) {
continue;
}
@@ -437,7 +643,7 @@ void ED_uvedit_pack_islands_multi(const Scene *scene,
ListBase island_list = {nullptr};
bm_mesh_calc_uv_islands(scene,
- em->bm,
+ bm,
&island_list,
params->only_selected_faces,
params->only_selected_uvs,
@@ -455,19 +661,12 @@ void ED_uvedit_pack_islands_multi(const Scene *scene,
return;
}
- float margin = scene->toolsettings->uvcalc_margin;
- double area = 0.0f;
-
- BoxPack *boxarray = static_cast<BoxPack *>(
- MEM_mallocN(sizeof(*boxarray) * island_vector.size(), __func__));
-
/* Coordinates of bounding box containing all selected UVs. */
float selection_min_co[2], selection_max_co[2];
INIT_MINMAX2(selection_min_co, selection_max_co);
for (int index = 0; index < island_vector.size(); index++) {
FaceIsland *island = island_vector[index];
-
/* Skip calculation if using specified UDIM option. */
if (udim_params && (udim_params->use_target_udim == false)) {
float bounds_min[2], bounds_max[2];
@@ -489,17 +688,6 @@ void ED_uvedit_pack_islands_multi(const Scene *scene,
bm_face_array_calc_bounds(
island->faces, island->faces_len, island->cd_loop_uv_offset, &island->bounds_rect);
-
- BoxPack *box = &boxarray[index];
- box->index = index;
- box->x = 0.0f;
- box->y = 0.0f;
- box->w = BLI_rctf_size_x(&island->bounds_rect);
- box->h = BLI_rctf_size_y(&island->bounds_rect);
-
- if (margin > 0.0f) {
- area += double(sqrtf(box->w * box->h));
- }
}
/* Center of bounding box containing all selected UVs. */
@@ -509,28 +697,8 @@ void ED_uvedit_pack_islands_multi(const Scene *scene,
selection_center[1] = (selection_min_co[1] + selection_max_co[1]) / 2.0f;
}
- if (margin > 0.0f) {
- /* Logic matches behavior from #GEO_uv_parametrizer_pack,
- * use area so multiply the margin by the area to give
- * predictable results not dependent on UV scale. */
- margin = (margin * float(area)) * 0.1f;
- for (int i = 0; i < island_vector.size(); i++) {
- FaceIsland *island = island_vector[i];
- BoxPack *box = &boxarray[i];
-
- BLI_rctf_pad(&island->bounds_rect, margin, margin);
- box->w = BLI_rctf_size_x(&island->bounds_rect);
- box->h = BLI_rctf_size_y(&island->bounds_rect);
- }
- }
-
- float boxarray_size[2];
- BLI_box_pack_2d(boxarray, island_vector.size(), &boxarray_size[0], &boxarray_size[1]);
-
- /* Don't change the aspect when scaling. */
- boxarray_size[0] = boxarray_size[1] = max_ff(boxarray_size[0], boxarray_size[1]);
-
- const float scale[2] = {1.0f / boxarray_size[0], 1.0f / boxarray_size[1]};
+ float scale[2] = {1.0f, 1.0f};
+ BoxPack *box_array = pack_islands_params(island_vector, *params, scale);
/* Tile offset. */
float base_offset[2] = {0.0f, 0.0f};
@@ -580,14 +748,14 @@ void ED_uvedit_pack_islands_multi(const Scene *scene,
}
for (int i = 0; i < island_vector.size(); i++) {
- FaceIsland *island = island_vector[boxarray[i].index];
+ FaceIsland *island = island_vector[box_array[i].index];
const float pivot[2] = {
island->bounds_rect.xmin,
island->bounds_rect.ymin,
};
const float offset[2] = {
- ((boxarray[i].x * scale[0]) - island->bounds_rect.xmin) + base_offset[0],
- ((boxarray[i].y * scale[1]) - island->bounds_rect.ymin) + base_offset[1],
+ ((box_array[i].x * scale[0]) - island->bounds_rect.xmin) + base_offset[0],
+ ((box_array[i].y * scale[1]) - island->bounds_rect.ymin) + base_offset[1],
};
for (int j = 0; j < island->faces_len; j++) {
BMFace *efa = island->faces[j];
@@ -607,7 +775,7 @@ void ED_uvedit_pack_islands_multi(const Scene *scene,
MEM_freeN(island);
}
- MEM_freeN(boxarray);
+ MEM_freeN(box_array);
}
/** \} */
diff --git a/source/blender/editors/uvedit/uvedit_unwrap_ops.c b/source/blender/editors/uvedit/uvedit_unwrap_ops.c
index 661a2a1b05b..2c977552e72 100644
--- a/source/blender/editors/uvedit/uvedit_unwrap_ops.c
+++ b/source/blender/editors/uvedit/uvedit_unwrap_ops.c
@@ -1050,25 +1050,6 @@ void UV_OT_minimize_stretch(wmOperatorType *ot)
/** \name Pack UV Islands Operator
* \{ */
-static void uvedit_pack_islands(const Scene *scene, Object *ob, BMesh *bm)
-{
- const UnwrapOptions options = {
- .topology_from_uvs = true,
- .only_selected_faces = false,
- .only_selected_uvs = true,
- .fill_holes = false,
- .correct_aspect = false,
- };
-
- bool rotate = true;
- bool ignore_pinned = false;
-
- ParamHandle *handle = construct_param_handle(scene, ob, bm, &options, NULL);
- GEO_uv_parametrizer_pack(handle, scene->toolsettings->uvcalc_margin, rotate, ignore_pinned);
- GEO_uv_parametrizer_flush(handle);
- GEO_uv_parametrizer_delete(handle);
-}
-
/**
* \warning Since this uses #ParamHandle it doesn't work with non-manifold meshes (see T82637).
* Use #ED_uvedit_pack_islands_multi for a more general solution.
@@ -1125,7 +1106,6 @@ static int pack_islands_exec(bContext *C, wmOperator *op)
}
/* RNA props */
- const bool rotate = RNA_boolean_get(op->ptr, "rotate");
const int udim_source = RNA_enum_get(op->ptr, "udim_source");
if (RNA_struct_property_is_set(op->ptr, "margin")) {
scene->toolsettings->uvcalc_margin = RNA_float_get(op->ptr, "margin");
@@ -1139,21 +1119,36 @@ static int pack_islands_exec(bContext *C, wmOperator *op)
const bool use_udim_params = ED_uvedit_udim_params_from_image_space(
sima, use_active, &udim_params);
- ED_uvedit_pack_islands_multi(scene,
- objects,
- objects_len,
- use_udim_params ? &udim_params : NULL,
- &(struct UVPackIsland_Params){
- .rotate = rotate,
- .only_selected_uvs = true,
- .only_selected_faces = true,
- .correct_aspect = true,
- });
+ struct UVPackIsland_Params params = {
+ .rotate = RNA_boolean_get(op->ptr, "rotate"),
+ .only_selected_uvs = true,
+ .only_selected_faces = true,
+ .correct_aspect = true,
+ .margin_method = RNA_enum_get(op->ptr, "margin_method"),
+ .margin = RNA_float_get(op->ptr, "margin"),
+ };
+ ED_uvedit_pack_islands_multi(
+ scene, objects, objects_len, NULL, use_udim_params ? &udim_params : NULL, &params);
MEM_freeN(objects);
return OPERATOR_FINISHED;
}
+const EnumPropertyItem pack_margin_method[] = {
+ {ED_UVPACK_MARGIN_SCALED,
+ "SCALED",
+ 0,
+ "Scaled",
+ "Use scale of existing UVs to multiply margin"},
+ {ED_UVPACK_MARGIN_ADD, "ADD", 0, "Add", "Just add the margin, ignoring any UV scale"},
+ {ED_UVPACK_MARGIN_FRACTION,
+ "FRACTION",
+ 0,
+ "Fraction",
+ "Specify a precise fraction of final UV output"},
+ {0, NULL, 0, NULL, NULL},
+};
+
void UV_OT_pack_islands(wmOperatorType *ot)
{
static const EnumPropertyItem pack_target[] = {
@@ -1180,6 +1175,8 @@ void UV_OT_pack_islands(wmOperatorType *ot)
/* properties */
RNA_def_enum(ot->srna, "udim_source", pack_target, PACK_UDIM_SRC_CLOSEST, "Pack to", "");
RNA_def_boolean(ot->srna, "rotate", true, "Rotate", "Rotate islands for best fit");
+ RNA_def_enum(
+ ot->srna, "margin_method", pack_margin_method, ED_UVPACK_MARGIN_SCALED, "Margin Method", "");
RNA_def_float_factor(
ot->srna, "margin", 0.001f, 0.0f, 1.0f, "Margin", "Space between islands", 0.0f, 1.0f);
}
@@ -2098,6 +2095,8 @@ void UV_OT_unwrap(wmOperatorType *ot)
0,
"Use Subdivision Surface",
"Map UVs taking vertex position after Subdivision Surface modifier has been applied");
+ RNA_def_enum(
+ ot->srna, "margin_method", pack_margin_method, ED_UVPACK_MARGIN_SCALED, "Margin Method", "");
RNA_def_float_factor(
ot->srna, "margin", 0.001f, 0.0f, 1.0f, "Margin", "Space between islands", 0.0f, 1.0f);
}
@@ -2118,7 +2117,6 @@ typedef struct ThickFace {
static int smart_uv_project_thickface_area_cmp_fn(const void *tf_a_p, const void *tf_b_p)
{
-
const ThickFace *tf_a = (ThickFace *)tf_a_p;
const ThickFace *tf_b = (ThickFace *)tf_b_p;
@@ -2412,17 +2410,17 @@ static int smart_project_exec(bContext *C, wmOperator *op)
/* Depsgraph refresh functions are called here. */
const bool correct_aspect = RNA_boolean_get(op->ptr, "correct_aspect");
- ED_uvedit_pack_islands_multi(scene,
- objects_changed,
- object_changed_len,
- NULL,
- &(struct UVPackIsland_Params){
- .rotate = true,
- .only_selected_uvs = only_selected_uvs,
- .only_selected_faces = true,
- .correct_aspect = correct_aspect,
- .use_seams = true,
- });
+
+ const struct UVPackIsland_Params params = {
+ .rotate = true,
+ .only_selected_uvs = only_selected_uvs,
+ .only_selected_faces = true,
+ .correct_aspect = correct_aspect,
+ .use_seams = true,
+ .margin_method = RNA_enum_get(op->ptr, "margin_method"),
+ .margin = RNA_float_get(op->ptr, "island_margin"),
+ };
+ ED_uvedit_pack_islands_multi(scene, objects_changed, object_changed_len, NULL, NULL, &params);
/* #ED_uvedit_pack_islands_multi only supports `per_face_aspect = false`. */
const bool per_face_aspect = false;
@@ -2464,6 +2462,8 @@ void UV_OT_smart_project(wmOperatorType *ot)
DEG2RADF(89.0f));
RNA_def_property_float_default(prop, DEG2RADF(66.0f));
+ RNA_def_enum(
+ ot->srna, "margin_method", pack_margin_method, ED_UVPACK_MARGIN_SCALED, "Margin Method", "");
RNA_def_float(ot->srna,
"island_margin",
0.0f,
@@ -3161,13 +3161,24 @@ void ED_uvedit_add_simple_uvs(Main *bmain, const Scene *scene, Object *ob)
.calc_face_normal = true,
.calc_vert_normal = true,
}));
- /* select all uv loops first - pack parameters needs this to make sure charts are registered */
+ /* Select all UVs for cube_project. */
ED_uvedit_select_all(bm);
/* A cube size of 2.0 maps [-1..1] vertex coords to [0.0..1.0] in UV coords. */
uvedit_unwrap_cube_project(scene, bm, 2.0, false, false, NULL);
- /* Set the margin really quickly before the packing operation. */
- scene->toolsettings->uvcalc_margin = 0.001f;
- uvedit_pack_islands(scene, ob, bm);
+
+ /* Pack UVs. */
+ const struct UVPackIsland_Params params = {
+ .rotate = true,
+ .only_selected_uvs = false,
+ .only_selected_faces = false,
+ .correct_aspect = false,
+ .use_seams = true,
+ .margin_method = ED_UVPACK_MARGIN_SCALED,
+ .margin = 0.001f,
+ };
+ ED_uvedit_pack_islands_multi(scene, &ob, 1, &bm, NULL, &params);
+
+ /* Write back from BMesh to Mesh. */
BM_mesh_bm_to_me(bmain, bm, me, (&(struct BMeshToMeshParams){0}));
BM_mesh_free(bm);
diff --git a/source/blender/geometry/intern/add_curves_on_mesh.cc b/source/blender/geometry/intern/add_curves_on_mesh.cc
index 25935691bf4..a03c9b994a9 100644
--- a/source/blender/geometry/intern/add_curves_on_mesh.cc
+++ b/source/blender/geometry/intern/add_curves_on_mesh.cc
@@ -385,10 +385,11 @@ AddCurvesOnMeshOutputs add_curves_on_mesh(CurvesGeometry &curves,
return true;
}
bke::GSpanAttributeWriter attribute = attributes.lookup_for_write_span(id);
- const int new_elements_num = attribute.domain == ATTR_DOMAIN_POINT ? new_points_num :
- new_curves_num;
+ /* The new elements are added at the end of the array. */
+ const int old_elements_num = attribute.domain == ATTR_DOMAIN_POINT ? old_points_num :
+ old_curves_num;
const CPPType &type = attribute.span.type();
- GMutableSpan new_data = attribute.span.take_back(new_elements_num);
+ GMutableSpan new_data = attribute.span.drop_front(old_elements_num);
type.fill_assign_n(type.default_value(), new_data.data(), new_data.size());
attribute.finish();
return true;
diff --git a/source/blender/gpencil_modifiers/intern/MOD_gpenciloutline.c b/source/blender/gpencil_modifiers/intern/MOD_gpenciloutline.c
index 9a0ee4d9d92..387e3c2d5ce 100644
--- a/source/blender/gpencil_modifiers/intern/MOD_gpenciloutline.c
+++ b/source/blender/gpencil_modifiers/intern/MOD_gpenciloutline.c
@@ -209,6 +209,7 @@ static void generateStrokes(GpencilModifierData *md, Depsgraph *depsgraph, Objec
BKE_gpencil_layer_transform_matrix_get(depsgraph, ob, gpl, diff_mat);
LISTBASE_FOREACH_MUTABLE (bGPDstroke *, gps, &gpf->strokes) {
+ gps->flag &= ~GP_STROKE_TAG;
convert_stroke(md, ob, gpl, gpf, gps, viewmat, diff_mat);
}
}
diff --git a/source/blender/gpencil_modifiers/intern/lineart/lineart_cpu.c b/source/blender/gpencil_modifiers/intern/lineart/lineart_cpu.c
index a8cba959689..c1e71bde254 100644
--- a/source/blender/gpencil_modifiers/intern/lineart/lineart_cpu.c
+++ b/source/blender/gpencil_modifiers/intern/lineart/lineart_cpu.c
@@ -1953,8 +1953,6 @@ static LineartEdgeNeighbor *lineart_build_edge_neighbor(Mesh *me, int total_edge
LineartEdgeNeighbor *edge_nabr = MEM_mallocN(sizeof(LineartEdgeNeighbor) * total_edges,
"LineartEdgeNeighbor arr");
- MLoopTri *mlooptri = me->runtime.looptris.array;
-
TaskParallelSettings en_settings;
BLI_parallel_range_settings_defaults(&en_settings);
/* Set the minimum amount of edges a thread has to process. */
@@ -1963,7 +1961,7 @@ static LineartEdgeNeighbor *lineart_build_edge_neighbor(Mesh *me, int total_edge
EdgeNeighborData en_data;
en_data.adj_e = adj_e;
en_data.edge_nabr = edge_nabr;
- en_data.mlooptri = mlooptri;
+ en_data.mlooptri = BKE_mesh_runtime_looptri_ensure(me);
en_data.mloop = BKE_mesh_loops(me);
BLI_task_parallel_range(0, total_edges, &en_data, lineart_edge_neighbor_init_task, &en_settings);
diff --git a/source/blender/gpu/CMakeLists.txt b/source/blender/gpu/CMakeLists.txt
index e2285a3fd3e..f387a4588b6 100644
--- a/source/blender/gpu/CMakeLists.txt
+++ b/source/blender/gpu/CMakeLists.txt
@@ -332,6 +332,7 @@ set(GLSL_SRC
shaders/compositor/compositor_alpha_crop.glsl
shaders/compositor/compositor_bilateral_blur.glsl
shaders/compositor/compositor_blur.glsl
+ shaders/compositor/compositor_blur_variable_size.glsl
shaders/compositor/compositor_bokeh_image.glsl
shaders/compositor/compositor_box_mask.glsl
shaders/compositor/compositor_convert.glsl
@@ -346,6 +347,7 @@ set(GLSL_SRC
shaders/compositor/compositor_morphological_distance_feather.glsl
shaders/compositor/compositor_morphological_distance_threshold.glsl
shaders/compositor/compositor_morphological_step.glsl
+ shaders/compositor/compositor_parallel_reduction.glsl
shaders/compositor/compositor_projector_lens_distortion.glsl
shaders/compositor/compositor_realize_on_domain.glsl
shaders/compositor/compositor_screen_lens_distortion.glsl
@@ -612,6 +614,7 @@ set(SRC_SHADER_CREATE_INFOS
shaders/compositor/infos/compositor_alpha_crop_info.hh
shaders/compositor/infos/compositor_bilateral_blur_info.hh
shaders/compositor/infos/compositor_blur_info.hh
+ shaders/compositor/infos/compositor_blur_variable_size_info.hh
shaders/compositor/infos/compositor_bokeh_image_info.hh
shaders/compositor/infos/compositor_box_mask_info.hh
shaders/compositor/infos/compositor_convert_info.hh
@@ -626,6 +629,7 @@ set(SRC_SHADER_CREATE_INFOS
shaders/compositor/infos/compositor_morphological_distance_info.hh
shaders/compositor/infos/compositor_morphological_distance_threshold_info.hh
shaders/compositor/infos/compositor_morphological_step_info.hh
+ shaders/compositor/infos/compositor_parallel_reduction_info.hh
shaders/compositor/infos/compositor_projector_lens_distortion_info.hh
shaders/compositor/infos/compositor_realize_on_domain_info.hh
shaders/compositor/infos/compositor_screen_lens_distortion_info.hh
diff --git a/source/blender/gpu/GPU_material.h b/source/blender/gpu/GPU_material.h
index 31354585308..3dad2a1a19a 100644
--- a/source/blender/gpu/GPU_material.h
+++ b/source/blender/gpu/GPU_material.h
@@ -162,6 +162,7 @@ GPUNodeLink *GPU_uniform_attribute(GPUMaterial *mat,
const char *name,
bool use_dupli,
uint32_t *r_hash);
+GPUNodeLink *GPU_layer_attribute(GPUMaterial *mat, const char *name);
GPUNodeLink *GPU_image(GPUMaterial *mat,
struct Image *ima,
struct ImageUser *iuser,
@@ -357,6 +358,20 @@ struct GHash *GPU_uniform_attr_list_hash_new(const char *info);
void GPU_uniform_attr_list_copy(GPUUniformAttrList *dest, const GPUUniformAttrList *src);
void GPU_uniform_attr_list_free(GPUUniformAttrList *set);
+typedef struct GPULayerAttr {
+ struct GPULayerAttr *next, *prev;
+
+ /* Meaningful part of the attribute set key. */
+ char name[64]; /* MAX_CUSTOMDATA_LAYER_NAME */
+ /** Hash of name[64]. */
+ uint32_t hash_code;
+
+ /* Helper fields used by code generation. */
+ int users;
+} GPULayerAttr;
+
+const ListBase *GPU_material_layer_attributes(const GPUMaterial *material);
+
/* A callback passed to GPU_material_from_callbacks to construct the material graph by adding and
* linking the necessary GPU material nodes. */
typedef void (*ConstructGPUMaterialFn)(void *thunk, GPUMaterial *material);
diff --git a/source/blender/gpu/GPU_uniform_buffer.h b/source/blender/gpu/GPU_uniform_buffer.h
index f78719d1963..28f06d6071d 100644
--- a/source/blender/gpu/GPU_uniform_buffer.h
+++ b/source/blender/gpu/GPU_uniform_buffer.h
@@ -44,6 +44,7 @@ void GPU_uniformbuf_unbind_all(void);
#define GPU_UBO_BLOCK_NAME "node_tree"
#define GPU_ATTRIBUTE_UBO_BLOCK_NAME "unf_attrs"
+#define GPU_LAYER_ATTRIBUTE_UBO_BLOCK_NAME "drw_layer_attrs"
#ifdef __cplusplus
}
diff --git a/source/blender/gpu/intern/gpu_codegen.cc b/source/blender/gpu/intern/gpu_codegen.cc
index b02d8a02704..4adeac1b49a 100644
--- a/source/blender/gpu/intern/gpu_codegen.cc
+++ b/source/blender/gpu/intern/gpu_codegen.cc
@@ -183,6 +183,8 @@ static std::ostream &operator<<(std::ostream &stream, const GPUInput *input)
return stream << "var_attrs.v" << input->attr->id;
case GPU_SOURCE_UNIFORM_ATTR:
return stream << "unf_attrs[resource_id].attr" << input->uniform_attr->id;
+ case GPU_SOURCE_LAYER_ATTR:
+ return stream << "attr_load_layer(" << input->layer_attr->hash_code << ")";
case GPU_SOURCE_STRUCT:
return stream << "strct" << input->id;
case GPU_SOURCE_TEX:
@@ -432,6 +434,10 @@ void GPUCodegen::generate_resources()
info.uniform_buf(2, "UniformAttrs", GPU_ATTRIBUTE_UBO_BLOCK_NAME "[512]", Frequency::BATCH);
}
+ if (!BLI_listbase_is_empty(&graph.layer_attrs)) {
+ info.additional_info("draw_layer_attributes");
+ }
+
info.typedef_source_generated = ss.str();
}
diff --git a/source/blender/gpu/intern/gpu_material.c b/source/blender/gpu/intern/gpu_material.c
index 0f9dc8be9c5..ca2a9f5cf28 100644
--- a/source/blender/gpu/intern/gpu_material.c
+++ b/source/blender/gpu/intern/gpu_material.c
@@ -291,6 +291,12 @@ const GPUUniformAttrList *GPU_material_uniform_attributes(const GPUMaterial *mat
return attrs->count > 0 ? attrs : NULL;
}
+const ListBase *GPU_material_layer_attributes(const GPUMaterial *material)
+{
+ const ListBase *attrs = &material->graph.layer_attrs;
+ return !BLI_listbase_is_empty(attrs) ? attrs : NULL;
+}
+
#if 1 /* End of life code. */
/* Eevee Subsurface scattering. */
/* Based on Separable SSS. by Jorge Jimenez and Diego Gutierrez */
diff --git a/source/blender/gpu/intern/gpu_node_graph.c b/source/blender/gpu/intern/gpu_node_graph.c
index e1ae731d49c..c72e7097b33 100644
--- a/source/blender/gpu/intern/gpu_node_graph.c
+++ b/source/blender/gpu/intern/gpu_node_graph.c
@@ -83,6 +83,9 @@ static void gpu_node_input_link(GPUNode *node, GPUNodeLink *link, const eGPUType
case GPU_SOURCE_UNIFORM_ATTR:
input->uniform_attr->users++;
break;
+ case GPU_SOURCE_LAYER_ATTR:
+ input->layer_attr->users++;
+ break;
case GPU_SOURCE_TEX:
case GPU_SOURCE_TEX_TILED_MAPPING:
input->texture->users++;
@@ -133,6 +136,10 @@ static void gpu_node_input_link(GPUNode *node, GPUNodeLink *link, const eGPUType
input->source = GPU_SOURCE_UNIFORM_ATTR;
input->uniform_attr = link->uniform_attr;
break;
+ case GPU_NODE_LINK_LAYER_ATTR:
+ input->source = GPU_SOURCE_LAYER_ATTR;
+ input->layer_attr = link->layer_attr;
+ break;
case GPU_NODE_LINK_CONSTANT:
input->source = (type == GPU_CLOSURE) ? GPU_SOURCE_STRUCT : GPU_SOURCE_CONSTANT;
break;
@@ -430,6 +437,34 @@ static GPUUniformAttr *gpu_node_graph_add_uniform_attribute(GPUNodeGraph *graph,
return attr;
}
+/** Add a new uniform attribute of given type and name. Returns NULL if out of slots. */
+static GPULayerAttr *gpu_node_graph_add_layer_attribute(GPUNodeGraph *graph, const char *name)
+{
+ /* Find existing attribute. */
+ ListBase *attrs = &graph->layer_attrs;
+ GPULayerAttr *attr = attrs->first;
+
+ for (; attr; attr = attr->next) {
+ if (STREQ(attr->name, name)) {
+ break;
+ }
+ }
+
+ /* Add new requested attribute to the list. */
+ if (attr == NULL) {
+ attr = MEM_callocN(sizeof(*attr), __func__);
+ STRNCPY(attr->name, name);
+ attr->hash_code = BLI_ghashutil_strhash_p(attr->name);
+ BLI_addtail(attrs, attr);
+ }
+
+ if (attr != NULL) {
+ attr->users++;
+ }
+
+ return attr;
+}
+
static GPUMaterialTexture *gpu_node_graph_add_texture(GPUNodeGraph *graph,
Image *ima,
ImageUser *iuser,
@@ -546,6 +581,17 @@ GPUNodeLink *GPU_uniform_attribute(GPUMaterial *mat,
return link;
}
+GPUNodeLink *GPU_layer_attribute(GPUMaterial *mat, const char *name)
+{
+ GPUNodeGraph *graph = gpu_material_node_graph(mat);
+ GPULayerAttr *attr = gpu_node_graph_add_layer_attribute(graph, name);
+
+ GPUNodeLink *link = gpu_node_link_create();
+ link->link_type = GPU_NODE_LINK_LAYER_ATTR;
+ link->layer_attr = attr;
+ return link;
+}
+
GPUNodeLink *GPU_constant(const float *num)
{
GPUNodeLink *link = gpu_node_link_create();
@@ -767,14 +813,22 @@ static void gpu_inputs_free(ListBase *inputs)
GPUInput *input;
for (input = inputs->first; input; input = input->next) {
- if (input->source == GPU_SOURCE_ATTR) {
- input->attr->users--;
- }
- else if (input->source == GPU_SOURCE_UNIFORM_ATTR) {
- input->uniform_attr->users--;
- }
- else if (ELEM(input->source, GPU_SOURCE_TEX, GPU_SOURCE_TEX_TILED_MAPPING)) {
- input->texture->users--;
+ switch (input->source) {
+ case GPU_SOURCE_ATTR:
+ input->attr->users--;
+ break;
+ case GPU_SOURCE_UNIFORM_ATTR:
+ input->uniform_attr->users--;
+ break;
+ case GPU_SOURCE_LAYER_ATTR:
+ input->layer_attr->users--;
+ break;
+ case GPU_SOURCE_TEX:
+ case GPU_SOURCE_TEX_TILED_MAPPING:
+ input->texture->users--;
+ break;
+ default:
+ break;
}
if (input->link) {
@@ -826,6 +880,7 @@ void gpu_node_graph_free(GPUNodeGraph *graph)
BLI_freelistN(&graph->textures);
BLI_freelistN(&graph->attributes);
GPU_uniform_attr_list_free(&graph->uniform_attrs);
+ BLI_freelistN(&graph->layer_attrs);
if (graph->used_libraries) {
BLI_gset_free(graph->used_libraries, NULL);
@@ -908,4 +963,10 @@ void gpu_node_graph_prune_unused(GPUNodeGraph *graph)
uattrs->count--;
}
}
+
+ LISTBASE_FOREACH_MUTABLE (GPULayerAttr *, attr, &graph->layer_attrs) {
+ if (attr->users == 0) {
+ BLI_freelinkN(&graph->layer_attrs, attr);
+ }
+ }
}
diff --git a/source/blender/gpu/intern/gpu_node_graph.h b/source/blender/gpu/intern/gpu_node_graph.h
index 7db22151f86..de0a0687b13 100644
--- a/source/blender/gpu/intern/gpu_node_graph.h
+++ b/source/blender/gpu/intern/gpu_node_graph.h
@@ -31,6 +31,7 @@ typedef enum eGPUDataSource {
GPU_SOURCE_UNIFORM,
GPU_SOURCE_ATTR,
GPU_SOURCE_UNIFORM_ATTR,
+ GPU_SOURCE_LAYER_ATTR,
GPU_SOURCE_STRUCT,
GPU_SOURCE_TEX,
GPU_SOURCE_TEX_TILED_MAPPING,
@@ -42,6 +43,7 @@ typedef enum {
GPU_NODE_LINK_NONE = 0,
GPU_NODE_LINK_ATTR,
GPU_NODE_LINK_UNIFORM_ATTR,
+ GPU_NODE_LINK_LAYER_ATTR,
GPU_NODE_LINK_COLORBAND,
GPU_NODE_LINK_CONSTANT,
GPU_NODE_LINK_IMAGE,
@@ -95,6 +97,8 @@ struct GPUNodeLink {
struct GPUMaterialAttribute *attr;
/* GPU_NODE_LINK_UNIFORM_ATTR */
struct GPUUniformAttr *uniform_attr;
+ /* GPU_NODE_LINK_LAYER_ATTR */
+ struct GPULayerAttr *layer_attr;
/* GPU_NODE_LINK_IMAGE_BLENDER */
struct GPUMaterialTexture *texture;
/* GPU_NODE_LINK_DIFFERENTIATE_FLOAT_FN */
@@ -131,6 +135,8 @@ typedef struct GPUInput {
struct GPUMaterialAttribute *attr;
/* GPU_SOURCE_UNIFORM_ATTR */
struct GPUUniformAttr *uniform_attr;
+ /* GPU_SOURCE_LAYER_ATTR */
+ struct GPULayerAttr *layer_attr;
/* GPU_SOURCE_FUNCTION_CALL */
char function_call[64];
};
@@ -171,6 +177,9 @@ typedef struct GPUNodeGraph {
/* The list of uniform attributes. */
GPUUniformAttrList uniform_attrs;
+ /* The list of layer attributes. */
+ ListBase layer_attrs;
+
/** Set of all the GLSL lib code blocks . */
GSet *used_libraries;
} GPUNodeGraph;
diff --git a/source/blender/gpu/metal/mtl_immediate.mm b/source/blender/gpu/metal/mtl_immediate.mm
index aaebe7e20f8..4b63a3b1ce2 100644
--- a/source/blender/gpu/metal/mtl_immediate.mm
+++ b/source/blender/gpu/metal/mtl_immediate.mm
@@ -125,7 +125,7 @@ void MTLImmediate::end()
* TODO(Metal): Cache this vertex state based on Vertex format and shaders. */
for (int i = 0; i < interface->get_total_attributes(); i++) {
- /* Note: Attribute in VERTEX FORMAT does not necessarily share the same array index as
+ /* NOTE: Attribute in VERTEX FORMAT does not necessarily share the same array index as
* attributes in shader interface. */
GPUVertAttr *attr = nullptr;
const MTLShaderInputAttribute &mtl_shader_attribute = interface->get_attribute(i);
diff --git a/source/blender/gpu/shaders/compositor/compositor_blur_variable_size.glsl b/source/blender/gpu/shaders/compositor/compositor_blur_variable_size.glsl
new file mode 100644
index 00000000000..e7e5aac12a5
--- /dev/null
+++ b/source/blender/gpu/shaders/compositor/compositor_blur_variable_size.glsl
@@ -0,0 +1,60 @@
+#pragma BLENDER_REQUIRE(gpu_shader_common_math_utils.glsl)
+#pragma BLENDER_REQUIRE(gpu_shader_compositor_texture_utilities.glsl)
+
+/* Given the texel in the range [-radius, radius] in both axis, load the appropriate weight from
+ * the weights texture, where the texel (0, 0) is considered the center of weights texture. */
+vec4 load_weight(ivec2 texel, float radius)
+{
+ /* The center zero texel is always assigned a unit weight regardless of the corresponding weight
+ * in the weights texture. That's to guarantee that at last the center pixel will be accumulated
+ * even if the weights texture is zero at its center. */
+ if (texel == ivec2(0)) {
+ return vec4(1.0);
+ }
+
+ /* Add the radius to transform the texel into the range [0, radius * 2], then divide by the upper
+ * bound plus one to transform the texel into the normalized range [0, 1] needed to sample the
+ * weights sampler. Finally, also add 0.5 to sample at the center of the pixels. */
+ return texture(weights_tx, (texel + vec2(radius + 0.5)) / (radius * 2 + 1));
+}
+
+void main()
+{
+ ivec2 texel = ivec2(gl_GlobalInvocationID.xy);
+
+ /* The mask input is treated as a boolean. If it is zero, then no blurring happens for this
+ * pixel. Otherwise, the pixel is blurred normally and the mask value is irrelevant. */
+ float mask = texture_load(mask_tx, texel).x;
+ if (mask == 0.0) {
+ imageStore(output_img, texel, texture_load(input_tx, texel));
+ return;
+ }
+
+ float center_size = texture_load(size_tx, texel).x * base_size;
+
+ /* Go over the window of the given search radius and accumulate the colors multiplied by their
+ * respective weights as well as the weights themselves, but only if both the size of the center
+ * pixel and the size of the candidate pixel are less than both the x and y distances of the
+ * candidate pixel. */
+ vec4 accumulated_color = vec4(0.0);
+ vec4 accumulated_weight = vec4(0.0);
+ for (int y = -search_radius; y <= search_radius; y++) {
+ for (int x = -search_radius; x <= search_radius; x++) {
+ float candidate_size = texture_load(size_tx, texel + ivec2(x, y)).x * base_size;
+
+ /* Skip accumulation if either the x or y distances of the candidate pixel are larger than
+ * either the center or candidate pixel size. Note that the max and min functions here denote
+ * "either" in the aforementioned description. */
+ float size = min(center_size, candidate_size);
+ if (max(abs(x), abs(y)) > size) {
+ continue;
+ }
+
+ vec4 weight = load_weight(ivec2(x, y), size);
+ accumulated_color += texture_load(input_tx, texel + ivec2(x, y)) * weight;
+ accumulated_weight += weight;
+ }
+ }
+
+ imageStore(output_img, texel, safe_divide(accumulated_color, accumulated_weight));
+}
diff --git a/source/blender/gpu/shaders/compositor/compositor_parallel_reduction.glsl b/source/blender/gpu/shaders/compositor/compositor_parallel_reduction.glsl
new file mode 100644
index 00000000000..f6f84aa24c1
--- /dev/null
+++ b/source/blender/gpu/shaders/compositor/compositor_parallel_reduction.glsl
@@ -0,0 +1,98 @@
+#pragma BLENDER_REQUIRE(gpu_shader_compositor_texture_utilities.glsl)
+
+/* This shader reduces the given texture into a smaller texture of a size equal to the number of
+ * work groups. In particular, each work group reduces its contents into a single value and writes
+ * that value to a single pixel in the output image. The shader can be dispatched multiple times to
+ * eventually reduce the image into a single pixel.
+ *
+ * The shader works by loading the whole data of each work group into a linear array, then it
+ * reduces the second half of the array onto the first half of the array, then it reduces the
+ * second quarter of the array onto the first quarter or the array, and so on until only one
+ * element remains. The following figure illustrates the process for sum reduction on 8 elements.
+ *
+ * .---. .---. .---. .---. .---. .---. .---. .---.
+ * | 0 | | 1 | | 2 | | 3 | | 4 | | 5 | | 6 | | 7 | Original data.
+ * '---' '---' '---' '---' '---' '---' '---' '---'
+ * |.____|_____|_____|_____| | | |
+ * || |.____|_____|___________| | |
+ * || || |.____|_________________| |
+ * || || || |.______________________| <--First reduction. Stride = 4.
+ * || || || ||
+ * .---. .---. .---. .----.
+ * | 4 | | 6 | | 8 | | 10 | <--Data after first reduction.
+ * '---' '---' '---' '----'
+ * |.____|_____| |
+ * || |.__________| <--Second reduction. Stride = 2.
+ * || ||
+ * .----. .----.
+ * | 12 | | 16 | <--Data after second reduction.
+ * '----' '----'
+ * |.____|
+ * || <--Third reduction. Stride = 1.
+ * .----.
+ * | 28 |
+ * '----' <--Data after third reduction.
+ *
+ *
+ * The shader is generic enough to implement many types of reductions. This is done by using macros
+ * that the developer should define to implement a certain reduction operation. Those include,
+ * TYPE, IDENTITY, INITIALIZE, LOAD, and REDUCE. See the implementation below for more information
+ * as well as the compositor_parallel_reduction_info.hh for example reductions operations. */
+
+/* Doing the reduction in shared memory is faster, so create a shared array where the whole data
+ * of the work group will be loaded and reduced. The 2D structure of the work group is irrelevant
+ * for reduction, so we just load the data in a 1D array to simplify reduction. The developer is
+ * expected to define the TYPE macro to be a float or a vec4, depending on the type of data being
+ * reduced. */
+const uint reduction_size = gl_WorkGroupSize.x * gl_WorkGroupSize.y;
+shared TYPE reduction_data[reduction_size];
+
+void main()
+{
+ /* Load the data from the texture, while returning IDENTITY for out of bound coordinates. The
+ * developer is expected to define the IDENTITY macro to be a vec4 that does not affect the
+ * output of the reduction. For instance, sum reductions have an identity of vec4(0.0), while
+ * max value reductions have an identity of vec4(FLT_MIN). */
+ vec4 value = texture_load(input_tx, ivec2(gl_GlobalInvocationID.xy), IDENTITY);
+
+ /* Initialize the shared array given the previously loaded value. This step can be different
+ * depending on whether this is the initial reduction pass or a latter one. Indeed, the input
+ * texture for the initial reduction is the source texture itself, while the input texture to a
+ * latter reduction pass is an intermediate texture after one or more reductions have happened.
+ * This is significant because the data being reduced might be computed from the original data
+ * and different from it, for instance, when summing the luminance of an image, the original data
+ * is a vec4 color, while the reduced data is a float luminance value. So for the initial
+ * reduction pass, the luminance will be computed from the color, reduced, then stored into an
+ * intermediate float texture. On the other hand, for latter reduction passes, the luminance will
+ * be loaded directly and reduced without extra processing. So the developer is expected to
+ * define the INITIALIZE and LOAD macros to be expressions that derive the needed value from the
+ * loaded value for the initial reduction pass and latter ones respectively. */
+ reduction_data[gl_LocalInvocationIndex] = is_initial_reduction ? INITIALIZE(value) : LOAD(value);
+
+ /* Reduce the reduction data by half on every iteration until only one element remains. See the
+ * above figure for an intuitive understanding of the stride value. */
+ for (uint stride = reduction_size / 2; stride > 0; stride /= 2) {
+ barrier();
+
+ /* Only the threads up to the current stride should be active as can be seen in the diagram
+ * above. */
+ if (gl_LocalInvocationIndex >= stride) {
+ continue;
+ }
+
+ /* Reduce each two elements that are stride apart, writing the result to the element with the
+ * lower index, as can be seen in the diagram above. The developer is expected to define the
+ * REDUCE macro to be a commutative and associative binary operator suitable for parallel
+ * reduction. */
+ reduction_data[gl_LocalInvocationIndex] = REDUCE(
+ reduction_data[gl_LocalInvocationIndex], reduction_data[gl_LocalInvocationIndex + stride]);
+ }
+
+ /* Finally, the result of the reduction is available as the first element in the reduction data,
+ * write it to the pixel corresponding to the work group, making sure only the one thread writes
+ * it. */
+ barrier();
+ if (gl_LocalInvocationIndex == 0) {
+ imageStore(output_img, ivec2(gl_WorkGroupID.xy), vec4(reduction_data[0]));
+ }
+}
diff --git a/source/blender/gpu/shaders/compositor/infos/compositor_blur_variable_size_info.hh b/source/blender/gpu/shaders/compositor/infos/compositor_blur_variable_size_info.hh
new file mode 100644
index 00000000000..05b6385fd1e
--- /dev/null
+++ b/source/blender/gpu/shaders/compositor/infos/compositor_blur_variable_size_info.hh
@@ -0,0 +1,15 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+
+#include "gpu_shader_create_info.hh"
+
+GPU_SHADER_CREATE_INFO(compositor_blur_variable_size)
+ .local_group_size(16, 16)
+ .push_constant(Type::FLOAT, "base_size")
+ .push_constant(Type::INT, "search_radius")
+ .sampler(0, ImageType::FLOAT_2D, "input_tx")
+ .sampler(1, ImageType::FLOAT_2D, "weights_tx")
+ .sampler(2, ImageType::FLOAT_2D, "size_tx")
+ .sampler(3, ImageType::FLOAT_2D, "mask_tx")
+ .image(0, GPU_RGBA16F, Qualifier::WRITE, ImageType::FLOAT_2D, "output_img")
+ .compute_source("compositor_blur_variable_size.glsl")
+ .do_static_compilation(true);
diff --git a/source/blender/gpu/shaders/compositor/infos/compositor_parallel_reduction_info.hh b/source/blender/gpu/shaders/compositor/infos/compositor_parallel_reduction_info.hh
new file mode 100644
index 00000000000..2e661f280af
--- /dev/null
+++ b/source/blender/gpu/shaders/compositor/infos/compositor_parallel_reduction_info.hh
@@ -0,0 +1,76 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+
+#include "gpu_shader_create_info.hh"
+
+GPU_SHADER_CREATE_INFO(compositor_parallel_reduction_shared)
+ .local_group_size(16, 16)
+ .push_constant(Type::BOOL, "is_initial_reduction")
+ .sampler(0, ImageType::FLOAT_2D, "input_tx")
+ .compute_source("compositor_parallel_reduction.glsl");
+
+/* --------------------------------------------------------------------
+ * Sum Reductions.
+ */
+
+GPU_SHADER_CREATE_INFO(compositor_sum_float_shared)
+ .additional_info("compositor_parallel_reduction_shared")
+ .image(0, GPU_R32F, Qualifier::WRITE, ImageType::FLOAT_2D, "output_img")
+ .define("TYPE", "float")
+ .define("IDENTITY", "vec4(0.0)")
+ .define("LOAD(value)", "value.x")
+ .define("REDUCE(lhs, rhs)", "lhs + rhs");
+
+GPU_SHADER_CREATE_INFO(compositor_sum_red)
+ .additional_info("compositor_sum_float_shared")
+ .define("INITIALIZE(value)", "value.r")
+ .do_static_compilation(true);
+
+GPU_SHADER_CREATE_INFO(compositor_sum_green)
+ .additional_info("compositor_sum_float_shared")
+ .define("INITIALIZE(value)", "value.g")
+ .do_static_compilation(true);
+
+GPU_SHADER_CREATE_INFO(compositor_sum_blue)
+ .additional_info("compositor_sum_float_shared")
+ .define("INITIALIZE(value)", "value.b")
+ .do_static_compilation(true);
+
+GPU_SHADER_CREATE_INFO(compositor_sum_luminance)
+ .additional_info("compositor_sum_float_shared")
+ .push_constant(Type::VEC3, "luminance_coefficients")
+ .define("INITIALIZE(value)", "dot(value.rgb, luminance_coefficients)")
+ .do_static_compilation(true);
+
+/* --------------------------------------------------------------------
+ * Sum Of Squared Difference Reductions.
+ */
+
+GPU_SHADER_CREATE_INFO(compositor_sum_squared_difference_float_shared)
+ .additional_info("compositor_parallel_reduction_shared")
+ .image(0, GPU_R32F, Qualifier::WRITE, ImageType::FLOAT_2D, "output_img")
+ .push_constant(Type::FLOAT, "subtrahend")
+ .define("TYPE", "float")
+ .define("IDENTITY", "vec4(subtrahend)")
+ .define("LOAD(value)", "value.x")
+ .define("REDUCE(lhs, rhs)", "lhs + rhs");
+
+GPU_SHADER_CREATE_INFO(compositor_sum_red_squared_difference)
+ .additional_info("compositor_sum_squared_difference_float_shared")
+ .define("INITIALIZE(value)", "pow(value.r - subtrahend, 2.0)")
+ .do_static_compilation(true);
+
+GPU_SHADER_CREATE_INFO(compositor_sum_green_squared_difference)
+ .additional_info("compositor_sum_squared_difference_float_shared")
+ .define("INITIALIZE(value)", "pow(value.g - subtrahend, 2.0)")
+ .do_static_compilation(true);
+
+GPU_SHADER_CREATE_INFO(compositor_sum_blue_squared_difference)
+ .additional_info("compositor_sum_squared_difference_float_shared")
+ .define("INITIALIZE(value)", "pow(value.b - subtrahend, 2.0)")
+ .do_static_compilation(true);
+
+GPU_SHADER_CREATE_INFO(compositor_sum_luminance_squared_difference)
+ .additional_info("compositor_sum_squared_difference_float_shared")
+ .push_constant(Type::VEC3, "luminance_coefficients")
+ .define("INITIALIZE(value)", "pow(dot(value.rgb, luminance_coefficients) - subtrahend, 2.0)")
+ .do_static_compilation(true);
diff --git a/source/blender/gpu/shaders/material/gpu_shader_material_attribute.glsl b/source/blender/gpu/shaders/material/gpu_shader_material_attribute.glsl
index bacf089deb1..8d0016a2206 100644
--- a/source/blender/gpu/shaders/material/gpu_shader_material_attribute.glsl
+++ b/source/blender/gpu/shaders/material/gpu_shader_material_attribute.glsl
@@ -29,6 +29,31 @@ void node_attribute_uniform(vec4 attr, const float attr_hash, out vec4 out_attr)
out_attr = attr_load_uniform(attr, floatBitsToUint(attr_hash));
}
+vec4 attr_load_layer(const uint attr_hash)
+{
+#ifdef VLATTR_LIB
+ /* The first record of the buffer stores the length. */
+ uint left = 0, right = drw_layer_attrs[0].buffer_length;
+
+ while (left < right) {
+ uint mid = (left + right) / 2;
+ uint hash = drw_layer_attrs[mid].hash_code;
+
+ if (hash < attr_hash) {
+ left = mid + 1;
+ }
+ else if (hash > attr_hash) {
+ right = mid;
+ }
+ else {
+ return drw_layer_attrs[mid].data;
+ }
+ }
+#endif
+
+ return vec4(0.0);
+}
+
void node_attribute(
vec4 attr, out vec4 outcol, out vec3 outvec, out float outf, out float outalpha)
{
diff --git a/source/blender/ikplugin/intern/itasc_plugin.cpp b/source/blender/ikplugin/intern/itasc_plugin.cpp
index 78fb75ddb40..9317f14b7f1 100644
--- a/source/blender/ikplugin/intern/itasc_plugin.cpp
+++ b/source/blender/ikplugin/intern/itasc_plugin.cpp
@@ -1783,7 +1783,7 @@ static void execute_scene(struct Depsgraph *depsgraph,
for (i = ikscene->targets.size(); i > 0; i--) {
IK_Target *iktarget = ikscene->targets[i - 1];
if (!(iktarget->blenderConstraint->flag & CONSTRAINT_OFF) && iktarget->constraint) {
- unsigned int nvalues;
+ uint nvalues;
const iTaSC::ConstraintValues *values;
values = iktarget->constraint->getControlParameters(&nvalues);
iktarget->errorCallback(values, nvalues, iktarget);
diff --git a/source/blender/imbuf/IMB_imbuf.h b/source/blender/imbuf/IMB_imbuf.h
index 7e652e31506..5c76dfe52df 100644
--- a/source/blender/imbuf/IMB_imbuf.h
+++ b/source/blender/imbuf/IMB_imbuf.h
@@ -895,6 +895,13 @@ eGPUTextureFormat IMB_gpu_get_texture_format(const struct ImBuf *ibuf,
bool use_grayscale);
/**
+ * Ensures that values stored in the float rect can safely loaded into half float gpu textures.
+ *
+ * Does nothing when given image_buffer doesn't contain a float rect.
+ */
+void IMB_gpu_clamp_half_float(struct ImBuf *image_buffer);
+
+/**
* The `ibuf` is only here to detect the storage type. The produced texture will have undefined
* content. It will need to be populated by using #IMB_update_gpu_texture_sub().
*/
diff --git a/source/blender/imbuf/intern/anim_movie.c b/source/blender/imbuf/intern/anim_movie.c
index 4f8fe0d8cdc..71e0d0fe11e 100644
--- a/source/blender/imbuf/intern/anim_movie.c
+++ b/source/blender/imbuf/intern/anim_movie.c
@@ -1093,12 +1093,14 @@ static int ffmpeg_seek_by_byte(AVFormatContext *pFormatCtx)
static int64_t ffmpeg_get_seek_pts(struct anim *anim, int64_t pts_to_search)
{
- /* Step back half a frame position to make sure that we get the requested
- * frame and not the one after it. This is a workaround as ffmpeg will
- * sometimes not seek to a frame after the requested pts even if
- * AVSEEK_FLAG_BACKWARD is specified.
+ /* FFmpeg seeks internally using DTS values instead of PTS. In some files DTS and PTS values are
+ * offset and sometimes ffmpeg fails to take this into account when seeking.
+ * Therefore we need to seek backwards a certain offset to make sure the frame we want is in
+ * front of us. It is not possible to determine the exact needed offset, this value is determined
+ * experimentally. Note: Too big offset can impact performance. Current 3 frame offset has no
+ * measurable impact.
*/
- return pts_to_search - (ffmpeg_steps_per_frame_get(anim) / 2);
+ return pts_to_search - (ffmpeg_steps_per_frame_get(anim) * 3);
}
/* This gives us an estimate of which pts our requested frame will have.
diff --git a/source/blender/imbuf/intern/transform.cc b/source/blender/imbuf/intern/transform.cc
index edded204527..6d3452c64db 100644
--- a/source/blender/imbuf/intern/transform.cc
+++ b/source/blender/imbuf/intern/transform.cc
@@ -134,7 +134,7 @@ class NoDiscard : public BaseDiscard {
*
* Will never discard any pixels.
*/
- bool should_discard(const TransformUserData & /*user_data*/, const float UNUSED(uv[2])) override
+ bool should_discard(const TransformUserData & /*user_data*/, const float /*uv*/[2]) override
{
return false;
}
diff --git a/source/blender/imbuf/intern/util_gpu.c b/source/blender/imbuf/intern/util_gpu.c
index 6f1275e1812..dd509677d8d 100644
--- a/source/blender/imbuf/intern/util_gpu.c
+++ b/source/blender/imbuf/intern/util_gpu.c
@@ -370,3 +370,19 @@ eGPUTextureFormat IMB_gpu_get_texture_format(const ImBuf *ibuf,
return gpu_texture_format;
}
+
+void IMB_gpu_clamp_half_float(ImBuf *image_buffer)
+{
+ const float half_min = -65504;
+ const float half_max = 65504;
+ if (!image_buffer->rect_float) {
+ return;
+ }
+
+ int rect_float_len = image_buffer->x * image_buffer->y *
+ (image_buffer->channels == 0 ? 4 : image_buffer->channels);
+
+ for (int i = 0; i < rect_float_len; i++) {
+ image_buffer->rect_float[i] = clamp_f(image_buffer->rect_float[i], half_min, half_max);
+ }
+}
diff --git a/source/blender/io/alembic/intern/alembic_capi.cc b/source/blender/io/alembic/intern/alembic_capi.cc
index 39595089109..b92ce5b4cfb 100644
--- a/source/blender/io/alembic/intern/alembic_capi.cc
+++ b/source/blender/io/alembic/intern/alembic_capi.cc
@@ -608,15 +608,11 @@ static void import_endjob(void *user_data)
lc = BKE_layer_collection_get_active(view_layer);
- /* Add all objects to the collection (don't do sync for each object). */
- BKE_layer_collection_resync_forbid();
for (AbcObjectReader *reader : data->readers) {
Object *ob = reader->object();
BKE_collection_object_add(data->bmain, lc->collection, ob);
}
- /* Sync the collection, and do view layer operations. */
- BKE_layer_collection_resync_allow();
- BKE_main_collection_sync(data->bmain);
+ /* Sync and do the view layer operations. */
BKE_view_layer_synced_ensure(scene, view_layer);
for (AbcObjectReader *reader : data->readers) {
Object *ob = reader->object();
diff --git a/source/blender/io/usd/intern/usd_capi_import.cc b/source/blender/io/usd/intern/usd_capi_import.cc
index 5808c6bc77a..b8cc43beeb9 100644
--- a/source/blender/io/usd/intern/usd_capi_import.cc
+++ b/source/blender/io/usd/intern/usd_capi_import.cc
@@ -317,8 +317,7 @@ static void import_endjob(void *customdata)
lc = BKE_layer_collection_get_active(view_layer);
- /* Add all objects to the collection (don't do sync for each object). */
- BKE_layer_collection_resync_forbid();
+ /* Add all objects to the collection. */
for (USDPrimReader *reader : data->archive->readers()) {
if (!reader) {
continue;
@@ -330,9 +329,7 @@ static void import_endjob(void *customdata)
BKE_collection_object_add(data->bmain, lc->collection, ob);
}
- /* Sync the collection, and do view layer operations. */
- BKE_layer_collection_resync_allow();
- BKE_main_collection_sync(data->bmain);
+ /* Sync and do the view layer operations. */
BKE_view_layer_synced_ensure(scene, view_layer);
for (USDPrimReader *reader : data->archive->readers()) {
if (!reader) {
diff --git a/source/blender/io/wavefront_obj/IO_wavefront_obj.h b/source/blender/io/wavefront_obj/IO_wavefront_obj.h
index 0a92bbca477..cf6464eeb37 100644
--- a/source/blender/io/wavefront_obj/IO_wavefront_obj.h
+++ b/source/blender/io/wavefront_obj/IO_wavefront_obj.h
@@ -35,7 +35,7 @@ struct OBJExportParams {
/* Geometry Transform options. */
eIOAxis forward_axis;
eIOAxis up_axis;
- float scaling_factor;
+ float global_scale;
/* File Write Options. */
bool export_selected_objects;
@@ -65,6 +65,7 @@ struct OBJImportParams {
char filepath[FILE_MAX];
/** Value 0 disables clamping. */
float clamp_size;
+ float global_scale;
eIOAxis forward_axis;
eIOAxis up_axis;
bool import_vertex_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 95be927589e..5c81cf7abca 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
@@ -261,7 +261,7 @@ void OBJWriter::write_vertex_coords(FormatHandler &fh,
BLI_assert(tot_count == attribute.size());
obj_parallel_chunked_output(fh, tot_count, [&](FormatHandler &buf, int i) {
- float3 vertex = obj_mesh_data.calc_vertex_coords(i, export_params_.scaling_factor);
+ float3 vertex = obj_mesh_data.calc_vertex_coords(i, export_params_.global_scale);
ColorGeometry4f linear = attribute.get(i);
float srgb[3];
linearrgb_to_srgb_v3_v3(srgb, linear);
@@ -270,7 +270,7 @@ void OBJWriter::write_vertex_coords(FormatHandler &fh,
}
else {
obj_parallel_chunked_output(fh, tot_count, [&](FormatHandler &buf, int i) {
- float3 vertex = obj_mesh_data.calc_vertex_coords(i, export_params_.scaling_factor);
+ float3 vertex = obj_mesh_data.calc_vertex_coords(i, export_params_.global_scale);
buf.write_obj_vertex(vertex[0], vertex[1], vertex[2]);
});
}
@@ -435,7 +435,7 @@ void OBJWriter::write_nurbs_curve(FormatHandler &fh, const OBJCurve &obj_nurbs_d
const int total_vertices = obj_nurbs_data.total_spline_vertices(spline_idx);
for (int vertex_idx = 0; vertex_idx < total_vertices; vertex_idx++) {
const float3 vertex_coords = obj_nurbs_data.vertex_coordinates(
- spline_idx, vertex_idx, export_params_.scaling_factor);
+ spline_idx, vertex_idx, export_params_.global_scale);
fh.write_obj_vertex(vertex_coords[0], vertex_coords[1], vertex_coords[2]);
}
diff --git a/source/blender/io/wavefront_obj/exporter/obj_export_mesh.cc b/source/blender/io/wavefront_obj/exporter/obj_export_mesh.cc
index 9f19a6390d3..d00c09b9013 100644
--- a/source/blender/io/wavefront_obj/exporter/obj_export_mesh.cc
+++ b/source/blender/io/wavefront_obj/exporter/obj_export_mesh.cc
@@ -265,13 +265,13 @@ const char *OBJMesh::get_object_material_name(const int16_t mat_nr) const
return mat->id.name + 2;
}
-float3 OBJMesh::calc_vertex_coords(const int vert_index, const float scaling_factor) const
+float3 OBJMesh::calc_vertex_coords(const int vert_index, const float global_scale) const
{
float3 r_coords;
const Span<MVert> verts = export_mesh_eval_->verts();
copy_v3_v3(r_coords, verts[vert_index].co);
mul_m4_v3(world_and_axes_transform_, r_coords);
- mul_v3_fl(r_coords, scaling_factor);
+ mul_v3_fl(r_coords, global_scale);
return r_coords;
}
diff --git a/source/blender/io/wavefront_obj/exporter/obj_export_mesh.hh b/source/blender/io/wavefront_obj/exporter/obj_export_mesh.hh
index db29f5651ed..ec98468e2de 100644
--- a/source/blender/io/wavefront_obj/exporter/obj_export_mesh.hh
+++ b/source/blender/io/wavefront_obj/exporter/obj_export_mesh.hh
@@ -161,7 +161,7 @@ class OBJMesh : NonCopyable {
/**
* Calculate coordinates of the vertex at the given index.
*/
- float3 calc_vertex_coords(int vert_index, float scaling_factor) const;
+ float3 calc_vertex_coords(int vert_index, float global_scale) const;
/**
* Calculate vertex indices of all vertices of the polygon at the given index.
*/
diff --git a/source/blender/io/wavefront_obj/exporter/obj_export_nurbs.cc b/source/blender/io/wavefront_obj/exporter/obj_export_nurbs.cc
index 172a59e5341..812c3e7b5d4 100644
--- a/source/blender/io/wavefront_obj/exporter/obj_export_nurbs.cc
+++ b/source/blender/io/wavefront_obj/exporter/obj_export_nurbs.cc
@@ -55,14 +55,14 @@ int OBJCurve::total_spline_vertices(const int spline_index) const
float3 OBJCurve::vertex_coordinates(const int spline_index,
const int vertex_index,
- const float scaling_factor) const
+ const float global_scale) const
{
const Nurb *const nurb = static_cast<Nurb *>(BLI_findlink(&export_curve_->nurb, spline_index));
float3 r_coord;
const BPoint &bpoint = nurb->bp[vertex_index];
copy_v3_v3(r_coord, bpoint.vec);
mul_m4_v3(world_axes_transform_, r_coord);
- mul_v3_fl(r_coord, scaling_factor);
+ mul_v3_fl(r_coord, global_scale);
return r_coord;
}
diff --git a/source/blender/io/wavefront_obj/exporter/obj_export_nurbs.hh b/source/blender/io/wavefront_obj/exporter/obj_export_nurbs.hh
index 65389d44f59..3f93112200f 100644
--- a/source/blender/io/wavefront_obj/exporter/obj_export_nurbs.hh
+++ b/source/blender/io/wavefront_obj/exporter/obj_export_nurbs.hh
@@ -37,7 +37,7 @@ class OBJCurve : NonCopyable {
/**
* Get coordinates of the vertex at the given index on the given spline.
*/
- float3 vertex_coordinates(int spline_index, int vertex_index, float scaling_factor) const;
+ float3 vertex_coordinates(int spline_index, int vertex_index, float global_scale) const;
/**
* Get total control points of the NURBS spline at the given index. This is different than total
* vertices of a spline.
diff --git a/source/blender/io/wavefront_obj/importer/importer_mesh_utils.cc b/source/blender/io/wavefront_obj/importer/importer_mesh_utils.cc
index f33753d720d..204237088ab 100644
--- a/source/blender/io/wavefront_obj/importer/importer_mesh_utils.cc
+++ b/source/blender/io/wavefront_obj/importer/importer_mesh_utils.cc
@@ -103,6 +103,9 @@ void transform_object(Object *object, const OBJImportParams &import_params)
IO_AXIS_Y, IO_AXIS_Z, import_params.forward_axis, import_params.up_axis, axes_transform);
copy_m4_m3(obmat, axes_transform);
+ float scale_vec[3] = {
+ import_params.global_scale, import_params.global_scale, import_params.global_scale};
+ rescale_m4(obmat, scale_vec);
BKE_object_apply_mat4(object, obmat, true, false);
if (import_params.clamp_size != 0.0f) {
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 bd1c2d32a12..0781028c880 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
@@ -508,6 +508,15 @@ void OBJParser::parse(Vector<std::unique_ptr<Geometry>> &r_all_geometries,
}
/* Faces. */
else if (parse_keyword(p, end, "f")) {
+ /* If we don't have a material index assigned yet, get one.
+ * It means "usemtl" state came from the previous object. */
+ if (state_material_index == -1 && !state_material_name.empty() &&
+ curr_geom->material_indices_.is_empty()) {
+ curr_geom->material_indices_.add_new(state_material_name, 0);
+ curr_geom->material_order_.append(state_material_name);
+ state_material_index = 0;
+ }
+
geom_add_polygon(curr_geom,
p,
end,
@@ -524,7 +533,10 @@ void OBJParser::parse(Vector<std::unique_ptr<Geometry>> &r_all_geometries,
else if (parse_keyword(p, end, "o")) {
state_shaded_smooth = false;
state_group_name = "";
- state_material_name = "";
+ /* Reset object-local material index that's used in face infos.
+ * NOTE: do not reset the material name; that has to carry over
+ * into the next object if needed. */
+ state_material_index = -1;
curr_geom = create_geometry(
curr_geom, GEOM_MESH, StringRef(p, end).trim(), r_all_geometries);
}
diff --git a/source/blender/io/wavefront_obj/importer/obj_importer.cc b/source/blender/io/wavefront_obj/importer/obj_importer.cc
index ccbcce64d65..a42ec47151d 100644
--- a/source/blender/io/wavefront_obj/importer/obj_importer.cc
+++ b/source/blender/io/wavefront_obj/importer/obj_importer.cc
@@ -42,9 +42,6 @@ static void geometry_to_blender_objects(Main *bmain,
{
LayerCollection *lc = BKE_layer_collection_get_active(view_layer);
- /* Don't do collection syncs for each object, will do once after the loop. */
- BKE_layer_collection_resync_forbid();
-
/* Sort objects by name: creating many objects is much faster if the creation
* order is sorted by name. */
blender::parallel_sort(
@@ -73,12 +70,8 @@ static void geometry_to_blender_objects(Main *bmain,
}
}
- /* Sync the collection after all objects are created. */
- BKE_layer_collection_resync_allow();
- BKE_main_collection_sync(bmain);
+ /* Do object selections in a separate loop (allows just one view layer sync). */
BKE_view_layer_synced_ensure(scene, view_layer);
-
- /* After collection sync, select objects in the view layer and do DEG updates. */
for (Object *obj : objects) {
Base *base = BKE_view_layer_base_find(view_layer, obj);
BKE_view_layer_base_select_and_set_active(view_layer, base);
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 dcba78ac99e..5de3cdcd851 100644
--- a/source/blender/io/wavefront_obj/tests/obj_exporter_tests.cc
+++ b/source/blender/io/wavefront_obj/tests/obj_exporter_tests.cc
@@ -306,7 +306,7 @@ TEST_F(obj_exporter_regression_test, all_tris)
TEST_F(obj_exporter_regression_test, all_quads)
{
OBJExportParamsDefault _export;
- _export.params.scaling_factor = 2.0f;
+ _export.params.global_scale = 2.0f;
_export.params.export_materials = false;
compare_obj_export_to_golden(
"io_tests/blend_geometry/all_quads.blend", "io_tests/obj/all_quads.obj", "", _export.params);
@@ -429,7 +429,7 @@ TEST_F(obj_exporter_regression_test, cubes_positioned)
{
OBJExportParamsDefault _export;
_export.params.export_materials = false;
- _export.params.scaling_factor = 2.0f;
+ _export.params.global_scale = 2.0f;
compare_obj_export_to_golden("io_tests/blend_geometry/cubes_positioned.blend",
"io_tests/obj/cubes_positioned.obj",
"",
diff --git a/source/blender/io/wavefront_obj/tests/obj_exporter_tests.hh b/source/blender/io/wavefront_obj/tests/obj_exporter_tests.hh
index 006d86312b6..a4d452e1309 100644
--- a/source/blender/io/wavefront_obj/tests/obj_exporter_tests.hh
+++ b/source/blender/io/wavefront_obj/tests/obj_exporter_tests.hh
@@ -19,7 +19,7 @@ struct OBJExportParamsDefault {
params.forward_axis = IO_AXIS_NEGATIVE_Z;
params.up_axis = IO_AXIS_Y;
- params.scaling_factor = 1.f;
+ params.global_scale = 1.f;
params.apply_modifiers = true;
params.export_eval_mode = DAG_EVAL_VIEWPORT;
diff --git a/source/blender/io/wavefront_obj/tests/obj_importer_tests.cc b/source/blender/io/wavefront_obj/tests/obj_importer_tests.cc
index 8d1171097b8..f459e1ab1bd 100644
--- a/source/blender/io/wavefront_obj/tests/obj_importer_tests.cc
+++ b/source/blender/io/wavefront_obj/tests/obj_importer_tests.cc
@@ -8,6 +8,7 @@
#include "BKE_curve.h"
#include "BKE_customdata.h"
#include "BKE_main.h"
+#include "BKE_material.h"
#include "BKE_mesh.h"
#include "BKE_object.h"
#include "BKE_scene.h"
@@ -22,6 +23,7 @@
#include "DEG_depsgraph_query.h"
#include "DNA_curve_types.h"
+#include "DNA_material_types.h"
#include "DNA_mesh_types.h"
#include "DNA_meshdata_types.h"
#include "DNA_scene_types.h"
@@ -41,6 +43,7 @@ struct Expectation {
float3 normal_first;
float2 uv_first;
float4 color_first = {-1, -1, -1, -1};
+ std::string first_mat;
};
class obj_importer_test : public BlendfileLoadingBaseTest {
@@ -57,6 +60,7 @@ class obj_importer_test : public BlendfileLoadingBaseTest {
}
OBJImportParams params;
+ params.global_scale = 1.0f;
params.clamp_size = 0;
params.forward_axis = IO_AXIS_NEGATIVE_Z;
params.up_axis = IO_AXIS_Y;
@@ -132,6 +136,10 @@ class obj_importer_test : public BlendfileLoadingBaseTest {
// int cyclic = (nurb->flagu & CU_NURB_CYCLIC) ? 1 : 0;
// EXPECT_EQ(cyclic, exp.mesh_totloop_or_curve_cyclic);
}
+ if (!exp.first_mat.empty()) {
+ Material *mat = BKE_object_material_get(object, 1);
+ ASSERT_STREQ(mat ? mat->id.name : "<null>", exp.first_mat.c_str());
+ }
++object_index;
}
DEG_OBJECT_ITER_END;
@@ -309,7 +317,42 @@ TEST_F(obj_importer_test, import_materials)
{
Expectation expect[] = {
{"OBCube", OB_MESH, 8, 12, 6, 24, float3(1, 1, -1), float3(-1, 1, 1)},
- {"OBmaterials", OB_MESH, 8, 12, 6, 24, float3(-1, -1, 1), float3(1, -1, -1)},
+ {"OBmaterials",
+ OB_MESH,
+ 8,
+ 12,
+ 6,
+ 24,
+ float3(-1, -1, 1),
+ float3(1, -1, -1),
+ float3(0),
+ float2(0),
+ float4(-1),
+ "MAno_textures_red"},
+ {"OBObjMtlAfter",
+ OB_MESH,
+ 3,
+ 3,
+ 1,
+ 3,
+ float3(3, 0, 0),
+ float3(5, 0, 0),
+ float3(0),
+ float2(0),
+ float4(-1),
+ "MAno_textures_red"},
+ {"OBObjMtlBefore",
+ OB_MESH,
+ 3,
+ 3,
+ 1,
+ 3,
+ float3(6, 0, 0),
+ float3(8, 0, 0),
+ float3(0),
+ float2(0),
+ float4(-1),
+ "MAClay"},
};
import_and_check("materials.obj", expect, std::size(expect), 4, 8);
}
@@ -327,7 +370,9 @@ TEST_F(obj_importer_test, import_cubes_with_textures_rel)
float3(1, 1, -1),
float3(-1, -1, 1),
float3(0, 1, 0),
- float2(0.9935f, 0.0020f)},
+ float2(0.9935f, 0.0020f),
+ float4(-1),
+ "MAMat_BaseRoughEmissNormal10"},
{"OBCubeTexMul",
OB_MESH,
8,
@@ -337,7 +382,9 @@ TEST_F(obj_importer_test, import_cubes_with_textures_rel)
float3(4, -2, -1),
float3(2, -4, 1),
float3(0, 1, 0),
- float2(0.9935f, 0.0020f)},
+ float2(0.9935f, 0.0020f),
+ float4(-1),
+ "MAMat_BaseMul"},
{"OBCubeTiledTex",
OB_MESH,
8,
@@ -347,7 +394,9 @@ TEST_F(obj_importer_test, import_cubes_with_textures_rel)
float3(4, 1, -1),
float3(2, -1, 1),
float3(0, 1, 0),
- float2(0.9935f, 0.0020f)},
+ float2(0.9935f, 0.0020f),
+ float4(-1),
+ "MAMat_BaseTiled"},
{"OBCubeTiledTexFromAnotherFolder",
OB_MESH,
8,
@@ -357,7 +406,9 @@ TEST_F(obj_importer_test, import_cubes_with_textures_rel)
float3(7, 1, -1),
float3(5, -1, 1),
float3(0, 1, 0),
- float2(0.9935f, 0.0020f)},
+ float2(0.9935f, 0.0020f),
+ float4(-1),
+ "MAMat_EmissTiledAnotherFolder"},
};
import_and_check("cubes_with_textures_rel.obj", expect, std::size(expect), 4, 4);
}
@@ -455,7 +506,10 @@ TEST_F(obj_importer_test, import_all_objects)
26,
float3(28, 1, -1),
float3(26, 1, 1),
- float3(-1, 0, 0)},
+ float3(-1, 0, 0),
+ float2(0),
+ float4(-1),
+ "MARed"},
{"OBNurbsCircle",
OB_MESH,
96,
@@ -491,7 +545,10 @@ TEST_F(obj_importer_test, import_all_objects)
26,
float3(4, 1, -1),
float3(2, 1, 1),
- float3(0.5774f, 0.5773f, 0.5774f)},
+ float3(0.5774f, 0.5773f, 0.5774f),
+ float2(0),
+ float4(-1),
+ "MAMaterial"},
{"OBSurface",
OB_MESH,
256,
diff --git a/source/blender/makesdna/DNA_brush_enums.h b/source/blender/makesdna/DNA_brush_enums.h
index 570b569a4dd..8b889e17762 100644
--- a/source/blender/makesdna/DNA_brush_enums.h
+++ b/source/blender/makesdna/DNA_brush_enums.h
@@ -330,9 +330,8 @@ typedef enum eAutomasking_flag {
BRUSH_AUTOMASKING_BOUNDARY_FACE_SETS = (1 << 3),
BRUSH_AUTOMASKING_CAVITY_NORMAL = (1 << 4),
- /* Note: normal and inverted are mutually exclusive,
- * inverted has priority if both bits are set.
- */
+ /* NOTE: normal and inverted are mutually exclusive,
+ * inverted has priority if both bits are set. */
BRUSH_AUTOMASKING_CAVITY_INVERTED = (1 << 5),
BRUSH_AUTOMASKING_CAVITY_ALL = (1 << 4) | (1 << 5),
BRUSH_AUTOMASKING_CAVITY_USE_CURVE = (1 << 6),
diff --git a/source/blender/makesdna/DNA_mesh_types.h b/source/blender/makesdna/DNA_mesh_types.h
index 2a17dbab8b3..3f951583741 100644
--- a/source/blender/makesdna/DNA_mesh_types.h
+++ b/source/blender/makesdna/DNA_mesh_types.h
@@ -19,10 +19,14 @@ namespace blender {
template<typename T> class Span;
template<typename T> class MutableSpan;
namespace bke {
+struct MeshRuntime;
class AttributeAccessor;
class MutableAttributeAccessor;
} // namespace bke
} // namespace blender
+using MeshRuntimeHandle = blender::bke::MeshRuntime;
+#else
+typedef struct MeshRuntimeHandle MeshRuntimeHandle;
#endif
#ifdef __cplusplus
@@ -30,133 +34,14 @@ extern "C" {
#endif
struct AnimData;
-struct BVHCache;
struct Ipo;
struct Key;
struct MCol;
struct MEdge;
struct MFace;
-struct MLoopCol;
struct MLoopTri;
struct MVert;
struct Material;
-struct Mesh;
-struct SubdivCCG;
-struct SubsurfRuntimeData;
-
-#
-#
-typedef struct EditMeshData {
- /** when set, \a vertexNos, polyNos are lazy initialized */
- const float (*vertexCos)[3];
-
- /** lazy initialize (when \a vertexCos is set) */
- float const (*vertexNos)[3];
- float const (*polyNos)[3];
- /** also lazy init but don't depend on \a vertexCos */
- const float (*polyCos)[3];
-} EditMeshData;
-
-/**
- * \warning Typical access is done via
- * #BKE_mesh_runtime_looptri_ensure, #BKE_mesh_runtime_looptri_len.
- */
-struct MLoopTri_Store {
- DNA_DEFINE_CXX_METHODS(MLoopTri_Store)
-
- /* WARNING! swapping between array (ready-to-be-used data) and array_wip
- * (where data is actually computed)
- * shall always be protected by same lock as one used for looptris computing. */
- struct MLoopTri *array, *array_wip;
- int len;
- int len_alloc;
-};
-
-/** Runtime data, not saved in files. */
-typedef struct Mesh_Runtime {
- DNA_DEFINE_CXX_METHODS(Mesh_Runtime)
-
- /* Evaluated mesh for objects which do not have effective modifiers.
- * This mesh is used as a result of modifier stack evaluation.
- * Since modifier stack evaluation is threaded on object level we need some synchronization. */
- struct Mesh *mesh_eval;
- void *eval_mutex;
-
- /* A separate mutex is needed for normal calculation, because sometimes
- * the normals are needed while #eval_mutex is already locked. */
- void *normals_mutex;
-
- /** Needed to ensure some thread-safety during render data pre-processing. */
- void *render_mutex;
-
- /** Lazily initialized SoA data from the #edit_mesh field in #Mesh. */
- struct EditMeshData *edit_data;
-
- /**
- * Data used to efficiently draw the mesh in the viewport, especially useful when
- * the same mesh is used in many objects or instances. See `draw_cache_impl_mesh.cc`.
- */
- void *batch_cache;
-
- /** Cache for derived triangulation of the mesh. */
- struct MLoopTri_Store looptris;
-
- /** Cache for BVH trees generated for the mesh. Defined in 'BKE_bvhutil.c' */
- struct BVHCache *bvh_cache;
-
- /** Cache of non-manifold boundary data for Shrinkwrap Target Project. */
- struct ShrinkwrapBoundaryData *shrinkwrap_data;
-
- /** Needed in case we need to lazily initialize the mesh. */
- CustomData_MeshMasks cd_mask_extra;
-
- struct SubdivCCG *subdiv_ccg;
- int subdiv_ccg_tot_level;
-
- /** Set by modifier stack if only deformed from original. */
- char deformed_only;
- /**
- * Copied from edit-mesh (hint, draw with edit-mesh data when true).
- *
- * Modifiers that edit the mesh data in-place must set this to false
- * (most #eModifierTypeType_NonGeometrical modifiers). Otherwise the edit-mesh
- * data will be used for drawing, missing changes from modifiers. See T79517.
- */
- char is_original_bmesh;
-
- /** #eMeshWrapperType and others. */
- char wrapper_type;
- /**
- * A type mask from wrapper_type,
- * in case there are differences in finalizing logic between types.
- */
- char wrapper_type_finalize;
-
- /**
- * Settings for lazily evaluating the subdivision on the CPU if needed. These are
- * set in the modifier when GPU subdivision can be performed, and owned by the by
- * the modifier in the object.
- */
- struct SubsurfRuntimeData *subsurf_runtime_data;
- void *_pad1;
-
- /**
- * Caches for lazily computed vertex and polygon normals. These are stored here rather than in
- * #CustomData because they can be calculated on a const mesh, and adding custom data layers on a
- * const mesh is not thread-safe.
- */
- char _pad2[6];
- char vert_normals_dirty;
- char poly_normals_dirty;
- float (*vert_normals)[3];
- float (*poly_normals)[3];
-
- /**
- * A #BLI_bitmap containing tags for the center vertices of subdivided polygons, set by the
- * subdivision surface modifier and used by drawing code instead of polygon center face dots.
- */
- uint32_t *subsurf_face_dot_tags;
-} Mesh_Runtime;
typedef struct Mesh {
DNA_DEFINE_CXX_METHODS(Mesh)
@@ -316,9 +201,13 @@ typedef struct Mesh {
char _pad1[4];
- void *_pad2;
-
- Mesh_Runtime runtime;
+ /**
+ * Data that isn't saved in files, including caches of derived data, temporary data to improve
+ * the editing experience, etc. Runtime data is created when reading files and can be accessed
+ * without null checks, with the exception of some temporary meshes which should allocate and
+ * free the data if they are passed to functions that expect run-time data.
+ */
+ MeshRuntimeHandle *runtime;
#ifdef __cplusplus
/**
* Array of vertex positions (and various other data). Edges and faces are defined by indices
@@ -383,16 +272,6 @@ typedef struct TFace {
/* **************** MESH ********************* */
-/** #Mesh_Runtime.wrapper_type */
-typedef enum eMeshWrapperType {
- /** Use mesh data (#Mesh.mvert, #Mesh.medge, #Mesh.mloop, #Mesh.mpoly). */
- ME_WRAPPER_TYPE_MDATA = 0,
- /** Use edit-mesh data (#Mesh.edit_mesh, #Mesh_Runtime.edit_data). */
- ME_WRAPPER_TYPE_BMESH = 1,
- /** Use subdivision mesh data (#Mesh_Runtime.mesh_eval). */
- ME_WRAPPER_TYPE_SUBD = 2,
-} eMeshWrapperType;
-
/** #Mesh.texflag */
enum {
ME_AUTOSPACE = 1,
diff --git a/source/blender/makesdna/DNA_meshdata_types.h b/source/blender/makesdna/DNA_meshdata_types.h
index 52e398ffff5..a1781265278 100644
--- a/source/blender/makesdna/DNA_meshdata_types.h
+++ b/source/blender/makesdna/DNA_meshdata_types.h
@@ -21,7 +21,7 @@ extern "C" {
/**
* Mesh Vertices.
*
- * Typically accessed from #Mesh.mvert
+ * Typically accessed from #Mesh.verts()
*/
typedef struct MVert {
float co[3];
@@ -51,7 +51,7 @@ enum {
/**
* Mesh Edges.
*
- * Typically accessed from #Mesh.medge
+ * Typically accessed with #Mesh.edges()
*/
typedef struct MEdge {
/** Un-ordered vertex indices (cannot match). */
@@ -79,10 +79,10 @@ enum {
};
/**
- * Mesh Faces
+ * Mesh Faces.
* This only stores the polygon size & flags, the vertex & edge indices are stored in the #MLoop.
*
- * Typically accessed from #Mesh.mpoly.
+ * Typically accessed with #Mesh.polys().
*/
typedef struct MPoly {
/** Offset into loop array and number of loops in the face. */
@@ -109,7 +109,7 @@ enum {
* Mesh Face Corners.
* "Loop" is an internal name for the corner of a polygon (#MPoly).
*
- * Typically accessed from #Mesh.mloop.
+ * Typically accessed with #Mesh.loops().
*/
typedef struct MLoop {
/** Vertex index into an #MVert array. */
@@ -376,7 +376,7 @@ typedef struct MDisps {
/**
* Used for hiding parts of a multires mesh.
- * Essentially the multires equivalent of the mesh ".hide_vert" boolean layer.
+ * Essentially the multires equivalent of the mesh ".hide_vert" boolean attribute.
*
* \note This is a bitmap, keep in sync with type used in BLI_bitmap.h
*/
diff --git a/source/blender/makesdna/DNA_node_types.h b/source/blender/makesdna/DNA_node_types.h
index 963567133d9..315bcbd971c 100644
--- a/source/blender/makesdna/DNA_node_types.h
+++ b/source/blender/makesdna/DNA_node_types.h
@@ -135,16 +135,16 @@ typedef struct bNodeSocket {
/** Default input value used for unlinked sockets. */
void *default_value;
- /* execution data */
- /** Local stack index. */
+ /** Local stack index for "node_exec". */
short stack_index;
- /* XXX deprecated, kept for forward compatibility */
- short stack_type DNA_DEPRECATED;
char display_shape;
/* #eAttrDomain used when the geometry nodes modifier creates an attribute for a group
* output. */
char attribute_domain;
+
+ char _pad[2];
+
/* Runtime-only cache of the number of input links, for multi-input sockets. */
short total_inputs;
@@ -170,9 +170,6 @@ typedef struct bNodeSocket {
int own_index DNA_DEPRECATED;
/* XXX deprecated, only used for restoring old group node links */
int to_index DNA_DEPRECATED;
- /* XXX deprecated, still forward compatible since verification
- * restores pointer from matching own_index. */
- struct bNodeSocket *groupsock DNA_DEPRECATED;
/** A link pointer, set in #BKE_ntree_update_main. */
struct bNodeLink *link;
@@ -1686,6 +1683,7 @@ enum {
SHD_ATTRIBUTE_GEOMETRY = 0,
SHD_ATTRIBUTE_OBJECT = 1,
SHD_ATTRIBUTE_INSTANCER = 2,
+ SHD_ATTRIBUTE_VIEW_LAYER = 3,
};
/* toon modes */
@@ -2076,6 +2074,15 @@ typedef enum CMPNodeFilterMethod {
CMP_NODE_FILTER_SHARP_DIAMOND = 7,
} CMPNodeFilterMethod;
+/* Levels Node. Stored in custom1. */
+typedef enum CMPNodeLevelsChannel {
+ CMP_NODE_LEVLES_LUMINANCE = 1,
+ CMP_NODE_LEVLES_RED = 2,
+ CMP_NODE_LEVLES_GREEN = 3,
+ CMP_NODE_LEVLES_BLUE = 4,
+ CMP_NODE_LEVLES_LUMINANCE_BT709 = 5,
+} CMPNodeLevelsChannel;
+
/* Plane track deform node. */
enum {
diff --git a/source/blender/makesdna/DNA_scene_types.h b/source/blender/makesdna/DNA_scene_types.h
index 2db81693f51..5fa5d4c7787 100644
--- a/source/blender/makesdna/DNA_scene_types.h
+++ b/source/blender/makesdna/DNA_scene_types.h
@@ -1761,6 +1761,8 @@ typedef struct Scene {
ID id;
/** Animation data (must be immediately after id for utilities to use it). */
struct AnimData *adt;
+ /* runtime (must be immediately after id for utilities to use it). */
+ DrawDataList drawdata;
struct Object *camera;
struct World *world;
diff --git a/source/blender/makesdna/DNA_space_types.h b/source/blender/makesdna/DNA_space_types.h
index 7f0dd2f9be6..809c8be7bc4 100644
--- a/source/blender/makesdna/DNA_space_types.h
+++ b/source/blender/makesdna/DNA_space_types.h
@@ -1184,6 +1184,12 @@ typedef struct SpaceImageOverlay {
char _pad[4];
} SpaceImageOverlay;
+typedef enum eSpaceImage_GridShapeSource {
+ SI_GRID_SHAPE_DYNAMIC = 0,
+ SI_GRID_SHAPE_FIXED = 1,
+ SI_GRID_SHAPE_PIXEL = 2,
+} eSpaceImage_GridShapeSource;
+
typedef struct SpaceImage {
SpaceLink *next, *prev;
/** Storage of regions for inactive spaces. */
@@ -1230,7 +1236,9 @@ typedef struct SpaceImage {
char around;
char gizmo_flag;
- char _pad1[3];
+
+ char grid_shape_source;
+ char _pad1[2];
int flag;
@@ -1239,7 +1247,7 @@ typedef struct SpaceImage {
int tile_grid_shape[2];
/**
* UV editor custom-grid. Value of `{M,N}` will produce `MxN` grid.
- * Use when #SI_CUSTOM_GRID is set.
+ * Use when `custom_grid_shape == SI_GRID_SHAPE_FIXED`.
*/
int custom_grid_subdiv[2];
@@ -1266,7 +1274,7 @@ typedef enum eSpaceImage_PixelRoundMode {
SI_PIXEL_ROUND_DISABLED = 0,
SI_PIXEL_ROUND_CENTER = 1,
SI_PIXEL_ROUND_CORNER = 2,
-} eSpaceImage_Round_Mode;
+} eSpaceImage_PixelRoundMode;
/** #SpaceImage.mode */
typedef enum eSpaceImage_Mode {
@@ -1300,7 +1308,7 @@ typedef enum eSpaceImage_Flag {
SI_FULLWINDOW = (1 << 16),
SI_FLAG_UNUSED_17 = (1 << 17),
- SI_CUSTOM_GRID = (1 << 18),
+ SI_FLAG_UNUSED_18 = (1 << 18),
/**
* This means that the image is drawn until it reaches the view edge,
diff --git a/source/blender/makesdna/DNA_userdef_enums.h b/source/blender/makesdna/DNA_userdef_enums.h
index e90aa0e0f07..dc368819ab0 100644
--- a/source/blender/makesdna/DNA_userdef_enums.h
+++ b/source/blender/makesdna/DNA_userdef_enums.h
@@ -39,6 +39,7 @@ typedef enum eDupli_ID_Flags {
USER_DUP_LATTICE = (1 << 17),
USER_DUP_CAMERA = (1 << 18),
USER_DUP_SPEAKER = (1 << 19),
+ USER_DUP_NTREE = (1 << 20),
USER_DUP_OBDATA = (~0) & ((1 << 24) - 1),
diff --git a/source/blender/makesdna/DNA_windowmanager_types.h b/source/blender/makesdna/DNA_windowmanager_types.h
index d57cca0b055..9b235fac049 100644
--- a/source/blender/makesdna/DNA_windowmanager_types.h
+++ b/source/blender/makesdna/DNA_windowmanager_types.h
@@ -364,7 +364,7 @@ typedef struct wmOperatorTypeMacro {
struct wmOperatorTypeMacro *next, *prev;
/* operator id */
- char idname[64];
+ char idname[64]; /* OP_MAX_TYPENAME */
/* rna pointer to access properties, like keymap */
/** Operator properties, assigned to ptr->data and can be written to a file. */
struct IDProperty *properties;
@@ -551,7 +551,7 @@ typedef struct wmOperator {
/* saved */
/** Used to retrieve type pointer. */
- char idname[64];
+ char idname[64]; /* OP_MAX_TYPENAME */
/** Saved, user-settable properties. */
IDProperty *properties;
diff --git a/source/blender/makesrna/intern/rna_brush.c b/source/blender/makesrna/intern/rna_brush.c
index 3c9590ddcbe..5e4b08d8a41 100644
--- a/source/blender/makesrna/intern/rna_brush.c
+++ b/source/blender/makesrna/intern/rna_brush.c
@@ -92,7 +92,7 @@ static const EnumPropertyItem rna_enum_brush_texture_slot_map_texture_mode_items
#endif
/* clang-format off */
-/* Note: we don't actually turn these into a single enum bitmask property,
+/* Note: we don't actually turn these into a single enum bit-mask property,
* instead we construct individual boolean properties. */
const EnumPropertyItem RNA_automasking_flags[] = {
{BRUSH_AUTOMASKING_TOPOLOGY, "use_automasking_topology", 0,"Topology", "Affect only vertices connected to the active vertex under the brush"},
diff --git a/source/blender/makesrna/intern/rna_fluid.c b/source/blender/makesrna/intern/rna_fluid.c
index a12ba7d9287..bd601d0a736 100644
--- a/source/blender/makesrna/intern/rna_fluid.c
+++ b/source/blender/makesrna/intern/rna_fluid.c
@@ -785,29 +785,29 @@ static const EnumPropertyItem *rna_Fluid_cobafield_itemf(bContext *UNUSED(C),
tmp.value = FLUID_DOMAIN_FIELD_PHI;
tmp.identifier = "PHI";
tmp.icon = 0;
- tmp.name = N_("Fluid Levelset");
- tmp.description = N_("Levelset representation of the fluid");
+ tmp.name = N_("Fluid Level Set");
+ tmp.description = N_("Level set representation of the fluid");
RNA_enum_item_add(&item, &totitem, &tmp);
tmp.value = FLUID_DOMAIN_FIELD_PHI_IN;
tmp.identifier = "PHI_IN";
tmp.icon = 0;
- tmp.name = N_("Inflow Levelset");
- tmp.description = N_("Levelset representation of the inflow");
+ tmp.name = N_("Inflow Level Set");
+ tmp.description = N_("Level set representation of the inflow");
RNA_enum_item_add(&item, &totitem, &tmp);
tmp.value = FLUID_DOMAIN_FIELD_PHI_OUT;
tmp.identifier = "PHI_OUT";
tmp.icon = 0;
- tmp.name = N_("Outflow Levelset");
- tmp.description = N_("Levelset representation of the outflow");
+ tmp.name = N_("Outflow Level Set");
+ tmp.description = N_("Level set representation of the outflow");
RNA_enum_item_add(&item, &totitem, &tmp);
tmp.value = FLUID_DOMAIN_FIELD_PHI_OBSTACLE;
tmp.identifier = "PHI_OBSTACLE";
tmp.icon = 0;
- tmp.name = N_("Obstacle Levelset");
- tmp.description = N_("Levelset representation of the obstacles");
+ tmp.name = N_("Obstacle Level Set");
+ tmp.description = N_("Level set representation of the obstacles");
RNA_enum_item_add(&item, &totitem, &tmp);
}
diff --git a/source/blender/makesrna/intern/rna_layer.c b/source/blender/makesrna/intern/rna_layer.c
index 427a38094be..b08d4b60fcc 100644
--- a/source/blender/makesrna/intern/rna_layer.c
+++ b/source/blender/makesrna/intern/rna_layer.c
@@ -369,6 +369,16 @@ static bool rna_LayerCollection_has_selected_objects(LayerCollection *lc,
return false;
}
+void rna_LayerCollection_children_begin(CollectionPropertyIterator *iter, PointerRNA *ptr)
+{
+ Scene *scene = (Scene *)ptr->owner_id;
+ LayerCollection *lc = (LayerCollection *)ptr->data;
+ ViewLayer *view_layer = BKE_view_layer_find_from_collection(scene, lc);
+ BKE_view_layer_synced_ensure(scene, view_layer);
+
+ rna_iterator_listbase_begin(iter, &lc->layer_collections, NULL);
+}
+
static bool rna_LayerCollection_children_lookupint(struct PointerRNA *ptr,
int key,
struct PointerRNA *r_ptr)
@@ -435,7 +445,7 @@ static void rna_def_layer_collection(BlenderRNA *brna)
RNA_def_property_struct_type(prop, "LayerCollection");
RNA_def_property_ui_text(prop, "Children", "Child layer collections");
RNA_def_property_collection_funcs(prop,
- NULL,
+ "rna_LayerCollection_children_begin",
NULL,
NULL,
NULL,
diff --git a/source/blender/makesrna/intern/rna_mesh.c b/source/blender/makesrna/intern/rna_mesh.c
index 9c6702142f7..bad099815a4 100644
--- a/source/blender/makesrna/intern/rna_mesh.c
+++ b/source/blender/makesrna/intern/rna_mesh.c
@@ -406,12 +406,39 @@ static int rna_MeshLoopTriangle_index_get(PointerRNA *ptr)
{
const Mesh *mesh = rna_mesh(ptr);
const MLoopTri *ltri = (MLoopTri *)ptr->data;
- const int index = (int)(ltri - mesh->runtime.looptris.array);
+ const int index = (int)(ltri - BKE_mesh_runtime_looptri_ensure(mesh));
BLI_assert(index >= 0);
- BLI_assert(index < mesh->runtime.looptris.len);
+ BLI_assert(index < BKE_mesh_runtime_looptri_len(mesh));
return index;
}
+static void rna_Mesh_loop_triangles_begin(CollectionPropertyIterator *iter, PointerRNA *ptr)
+{
+ const Mesh *mesh = rna_mesh(ptr);
+ const MLoopTri *looptris = BKE_mesh_runtime_looptri_ensure(mesh);
+ rna_iterator_array_begin(
+ iter, (void *)looptris, sizeof(MLoopTri), BKE_mesh_runtime_looptri_len(mesh), false, NULL);
+}
+
+static int rna_Mesh_loop_triangles_length(PointerRNA *ptr)
+{
+ const Mesh *mesh = rna_mesh(ptr);
+ return BKE_mesh_runtime_looptri_len(mesh);
+}
+
+int rna_Mesh_loop_triangles_lookup_int(PointerRNA *ptr, int index, PointerRNA *r_ptr)
+{
+ const Mesh *mesh = rna_mesh(ptr);
+ if (index < 0 || index >= BKE_mesh_runtime_looptri_len(mesh)) {
+ return false;
+ }
+ /* Casting away const is okay because this RNA type doesn't allow changing the value. */
+ r_ptr->owner_id = (ID *)&mesh->id;
+ r_ptr->type = &RNA_MeshLoopTriangle;
+ r_ptr->data = (void *)&BKE_mesh_runtime_looptri_ensure(mesh)[index];
+ return true;
+}
+
static void rna_MeshVertex_normal_get(PointerRNA *ptr, float *value)
{
Mesh *mesh = rna_mesh(ptr);
@@ -1502,8 +1529,9 @@ static char *rna_MeshPolygon_path(const PointerRNA *ptr)
static char *rna_MeshLoopTriangle_path(const PointerRNA *ptr)
{
- return BLI_sprintfN("loop_triangles[%d]",
- (int)((MLoopTri *)ptr->data - rna_mesh(ptr)->runtime.looptris.array));
+ return BLI_sprintfN(
+ "loop_triangles[%d]",
+ (int)((MLoopTri *)ptr->data - BKE_mesh_runtime_looptri_ensure(rna_mesh(ptr))));
}
static char *rna_MeshEdge_path(const PointerRNA *ptr)
@@ -3684,7 +3712,15 @@ static void rna_def_mesh(BlenderRNA *brna)
NULL);
prop = RNA_def_property(srna, "loop_triangles", PROP_COLLECTION, PROP_NONE);
- RNA_def_property_collection_sdna(prop, NULL, "runtime.looptris.array", "runtime.looptris.len");
+ RNA_def_property_collection_funcs(prop,
+ "rna_Mesh_loop_triangles_begin",
+ "rna_iterator_array_next",
+ "rna_iterator_array_end",
+ "rna_iterator_array_get",
+ "rna_Mesh_loop_triangles_length",
+ "rna_Mesh_loop_triangles_lookup_int",
+ NULL,
+ NULL);
RNA_def_property_struct_type(prop, "MeshLoopTriangle");
RNA_def_property_override_flag(prop, PROPOVERRIDE_IGNORE);
RNA_def_property_ui_text(prop, "Loop Triangles", "Tessellation of mesh polygons into triangles");
diff --git a/source/blender/makesrna/intern/rna_nodetree.c b/source/blender/makesrna/intern/rna_nodetree.c
index a0a933c3f90..0b0970a835e 100644
--- a/source/blender/makesrna/intern/rna_nodetree.c
+++ b/source/blender/makesrna/intern/rna_nodetree.c
@@ -5242,6 +5242,11 @@ static void def_sh_attribute(StructRNA *srna)
"The attribute is associated with the instancer particle system or object, "
"falling back to the Object mode if the attribute isn't found, or the object "
"is not instanced"},
+ {SHD_ATTRIBUTE_VIEW_LAYER,
+ "VIEW_LAYER",
+ 0,
+ "View Layer",
+ "The attribute is associated with the View Layer, Scene or World that is being rendered"},
{0, NULL, 0, NULL, NULL},
};
PropertyRNA *prop;
@@ -5504,6 +5509,7 @@ static void def_sh_tex_image(StructRNA *srna)
RNA_def_property_enum_items(prop, prop_image_extension);
RNA_def_property_ui_text(
prop, "Extension", "How the image is extrapolated past its original bounds");
+ RNA_def_property_translation_context(prop, BLT_I18NCONTEXT_ID_IMAGE);
RNA_def_property_update(prop, 0, "rna_Node_update");
prop = RNA_def_property(srna, "image_user", PROP_POINTER, PROP_NONE);
@@ -5568,6 +5574,7 @@ static void def_geo_image_texture(StructRNA *srna)
RNA_def_property_enum_items(prop, prop_image_extension);
RNA_def_property_ui_text(
prop, "Extension", "How the image is extrapolated past its original bounds");
+ RNA_def_property_translation_context(prop, BLT_I18NCONTEXT_ID_IMAGE);
RNA_def_property_update(prop, 0, "rna_Node_update");
}
@@ -6806,11 +6813,11 @@ static void def_cmp_levels(StructRNA *srna)
PropertyRNA *prop;
static const EnumPropertyItem channel_items[] = {
- {1, "COMBINED_RGB", 0, "Combined", "Combined RGB"},
- {2, "RED", 0, "Red", "Red Channel"},
- {3, "GREEN", 0, "Green", "Green Channel"},
- {4, "BLUE", 0, "Blue", "Blue Channel"},
- {5, "LUMINANCE", 0, "Luminance", "Luminance Channel"},
+ {CMP_NODE_LEVLES_LUMINANCE, "COMBINED_RGB", 0, "Combined", "Combined RGB"},
+ {CMP_NODE_LEVLES_RED, "RED", 0, "Red", "Red Channel"},
+ {CMP_NODE_LEVLES_GREEN, "GREEN", 0, "Green", "Green Channel"},
+ {CMP_NODE_LEVLES_BLUE, "BLUE", 0, "Blue", "Blue Channel"},
+ {CMP_NODE_LEVLES_LUMINANCE_BT709, "LUMINANCE", 0, "Luminance", "Luminance Channel"},
{0, NULL, 0, NULL, NULL},
};
diff --git a/source/blender/makesrna/intern/rna_scene.c b/source/blender/makesrna/intern/rna_scene.c
index 70afc763c2d..8fc504f192e 100644
--- a/source/blender/makesrna/intern/rna_scene.c
+++ b/source/blender/makesrna/intern/rna_scene.c
@@ -7861,6 +7861,7 @@ void RNA_def_scene(BlenderRNA *brna)
RNA_def_property_flag(prop, PROP_EDITABLE);
RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_LIBRARY);
RNA_def_property_ui_text(prop, "World", "World used for rendering the scene");
+ RNA_def_property_translation_context(prop, BLT_I18NCONTEXT_ID_WORLD);
RNA_def_property_update(prop, NC_SCENE | ND_WORLD, "rna_Scene_world_update");
prop = RNA_def_property(srna, "objects", PROP_COLLECTION, PROP_NONE);
diff --git a/source/blender/makesrna/intern/rna_space.c b/source/blender/makesrna/intern/rna_space.c
index 738b41828e0..3cd8020ca6c 100644
--- a/source/blender/makesrna/intern/rna_space.c
+++ b/source/blender/makesrna/intern/rna_space.c
@@ -3510,6 +3510,13 @@ static void rna_def_space_image_uv(BlenderRNA *brna)
{0, NULL, 0, NULL, NULL},
};
+ static const EnumPropertyItem grid_shape_source_items[] = {
+ {SI_GRID_SHAPE_DYNAMIC, "DYNAMIC", 0, "Dynamic", "Dynamic grid"},
+ {SI_GRID_SHAPE_FIXED, "FIXED", 0, "Fixed", "Manually set grid divisions"},
+ {SI_GRID_SHAPE_PIXEL, "PIXEL", 0, "Pixel", "Grid aligns with pixels from image"},
+ {0, NULL, 0, NULL, NULL},
+ };
+
srna = RNA_def_struct(brna, "SpaceUVEditor", NULL);
RNA_def_struct_sdna(srna, "SpaceImage");
RNA_def_struct_nested(brna, srna, "SpaceImageEditor");
@@ -3583,10 +3590,9 @@ static void rna_def_space_image_uv(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "Grid Over Image", "Show the grid over the image");
RNA_def_property_update(prop, NC_SPACE | ND_SPACE_IMAGE, NULL);
- prop = RNA_def_property(srna, "use_custom_grid", PROP_BOOLEAN, PROP_NONE);
- RNA_def_property_boolean_sdna(prop, NULL, "flag", SI_CUSTOM_GRID);
- RNA_def_property_boolean_default(prop, true);
- RNA_def_property_ui_text(prop, "Custom Grid", "Use a grid with a user-defined number of steps");
+ prop = RNA_def_property(srna, "grid_shape_source", PROP_ENUM, PROP_NONE);
+ RNA_def_property_enum_items(prop, grid_shape_source_items);
+ RNA_def_property_ui_text(prop, "Grid Shape Source", "Specify source for the grid shape");
RNA_def_property_update(prop, NC_SPACE | ND_SPACE_IMAGE, NULL);
prop = RNA_def_property(srna, "custom_grid_subdivisions", PROP_INT, PROP_XYZ);
@@ -4087,6 +4093,7 @@ static void rna_def_space_view3d_shading(BlenderRNA *brna)
prop = RNA_def_property(srna, "background_type", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_items(prop, background_type_items);
RNA_def_property_ui_text(prop, "Background", "Way to display the background");
+ RNA_def_property_translation_context(prop, BLT_I18NCONTEXT_EDITOR_VIEW3D);
RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D | NS_VIEW3D_SHADING, NULL);
prop = RNA_def_property(srna, "background_color", PROP_FLOAT, PROP_COLOR);
@@ -5265,6 +5272,7 @@ static void rna_def_space_properties(BlenderRNA *brna)
RNA_def_property_enum_funcs(
prop, NULL, "rna_SpaceProperties_context_set", "rna_SpaceProperties_context_itemf");
RNA_def_property_ui_text(prop, "", "");
+ RNA_def_property_translation_context(prop, BLT_I18NCONTEXT_ID_ID);
RNA_def_property_update(
prop, NC_SPACE | ND_SPACE_PROPERTIES, "rna_SpaceProperties_context_update");
@@ -6562,6 +6570,7 @@ static void rna_def_fileselect_entry(BlenderRNA *brna)
prop,
"Data-block Type",
"The type of the data-block, if the file represents one ('NONE' otherwise)");
+ RNA_def_property_translation_context(prop, BLT_I18NCONTEXT_ID_ID);
prop = RNA_def_property(srna, "local_id", PROP_POINTER, PROP_NONE);
RNA_def_property_struct_type(prop, "ID");
@@ -7314,12 +7323,14 @@ static void rna_def_space_node(BlenderRNA *brna)
RNA_def_property_enum_sdna(prop, NULL, "texfrom");
RNA_def_property_enum_items(prop, texture_id_type_items);
RNA_def_property_ui_text(prop, "Texture Type", "Type of data to take texture from");
+ RNA_def_property_translation_context(prop, BLT_I18NCONTEXT_ID_ID);
RNA_def_property_update(prop, NC_SPACE | ND_SPACE_NODE, NULL);
prop = RNA_def_property(srna, "shader_type", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_sdna(prop, NULL, "shaderfrom");
RNA_def_property_enum_items(prop, shader_type_items);
RNA_def_property_ui_text(prop, "Shader Type", "Type of data to take shader from");
+ RNA_def_property_translation_context(prop, BLT_I18NCONTEXT_ID_ID);
RNA_def_property_update(prop, NC_SPACE | ND_SPACE_NODE, NULL);
prop = RNA_def_property(srna, "id", PROP_POINTER, PROP_NONE);
@@ -7515,6 +7526,7 @@ static void rna_def_space_clip(BlenderRNA *brna)
RNA_def_property_enum_sdna(prop, NULL, "mode");
RNA_def_property_enum_items(prop, rna_enum_clip_editor_mode_items);
RNA_def_property_ui_text(prop, "Mode", "Editing context being displayed");
+ RNA_def_property_translation_context(prop, BLT_I18NCONTEXT_ID_MOVIECLIP);
RNA_def_property_update(prop, NC_SPACE | ND_SPACE_CLIP, "rna_SpaceClipEditor_clip_mode_update");
/* view */
diff --git a/source/blender/makesrna/intern/rna_texture.c b/source/blender/makesrna/intern/rna_texture.c
index 26849bfa622..2254db4edaf 100644
--- a/source/blender/makesrna/intern/rna_texture.c
+++ b/source/blender/makesrna/intern/rna_texture.c
@@ -24,6 +24,8 @@
#include "BKE_node_tree_update.h"
#include "BKE_paint.h"
+#include "BLT_translation.h"
+
#include "RNA_define.h"
#include "RNA_enum_types.h"
@@ -1191,6 +1193,7 @@ static void rna_def_texture_image(BlenderRNA *brna)
RNA_def_property_enum_items(prop, prop_image_extension);
RNA_def_property_ui_text(
prop, "Extension", "How the image is extrapolated past its original bounds");
+ RNA_def_property_translation_context(prop, BLT_I18NCONTEXT_ID_IMAGE);
RNA_def_property_update(prop, 0, "rna_Texture_update");
prop = RNA_def_property(srna, "repeat_x", PROP_INT, PROP_NONE);
diff --git a/source/blender/makesrna/intern/rna_userdef.c b/source/blender/makesrna/intern/rna_userdef.c
index c9e3822c996..e22ae205b0a 100644
--- a/source/blender/makesrna/intern/rna_userdef.c
+++ b/source/blender/makesrna/intern/rna_userdef.c
@@ -4057,6 +4057,7 @@ static void rna_def_userdef_studiolights(BlenderRNA *brna)
STUDIOLIGHT_TYPE_WORLD,
"Type",
"The type for the new studio light");
+ RNA_def_property_translation_context(parm, BLT_I18NCONTEXT_ID_LIGHT);
RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
parm = RNA_def_pointer(func, "studio_light", "StudioLight", "", "Newly created StudioLight");
RNA_def_function_return(func, parm);
@@ -4117,6 +4118,7 @@ static void rna_def_userdef_studiolight(BlenderRNA *brna)
RNA_def_property_enum_funcs(prop, "rna_UserDef_studiolight_type_get", NULL, NULL);
RNA_def_property_clear_flag(prop, PROP_EDITABLE);
RNA_def_property_ui_text(prop, "Type", "");
+ RNA_def_property_translation_context(prop, BLT_I18NCONTEXT_ID_LIGHT);
prop = RNA_def_property(srna, "name", PROP_STRING, PROP_NONE);
RNA_def_property_string_funcs(
@@ -5230,6 +5232,12 @@ static void rna_def_userdef_edit(BlenderRNA *brna)
RNA_def_property_ui_text(
prop, "Duplicate Volume", "Causes volume data to be duplicated with the object");
+ prop = RNA_def_property(srna, "use_duplicate_node_tree", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "dupflag", USER_DUP_NTREE);
+ RNA_def_property_ui_text(prop,
+ "Duplicate Node Tree",
+ "Make copies of node groups when duplicating nodes in the node editor");
+
/* Currently only used for insert offset (aka auto-offset),
* maybe also be useful for later stuff though. */
prop = RNA_def_property(srna, "node_margin", PROP_INT, PROP_PIXEL);
@@ -5742,8 +5750,8 @@ static void rna_def_userdef_input(BlenderRNA *brna)
RNA_def_property_boolean_negative_sdna(prop, NULL, "uiflag", USER_NO_MULTITOUCH_GESTURES);
RNA_def_property_ui_text(
prop,
- "Multitouch Gestures",
- "Use multitouch gestures for navigation with touchpad, instead of scroll wheel emulation");
+ "Multi-touch Gestures",
+ "Use multi-touch gestures for navigation with touchpad, instead of scroll wheel emulation");
RNA_def_property_update(prop, 0, "rna_userdef_input_devices");
prop = RNA_def_property(srna, "invert_mouse_zoom", PROP_BOOLEAN, PROP_NONE);
diff --git a/source/blender/makesrna/intern/rna_wm.c b/source/blender/makesrna/intern/rna_wm.c
index 7fd590005fd..5b5544120a1 100644
--- a/source/blender/makesrna/intern/rna_wm.c
+++ b/source/blender/makesrna/intern/rna_wm.c
@@ -1644,12 +1644,7 @@ static StructRNA *rna_MacroOperator_register(Main *bmain,
return NULL;
}
- if (strlen(identifier) >= sizeof(dummyop.idname)) {
- BKE_reportf(reports,
- RPT_ERROR,
- "Registering operator class: '%s' is too long, maximum length is %d",
- identifier,
- (int)sizeof(dummyop.idname));
+ if (!WM_operator_py_idname_ok_or_report(reports, identifier, dummyot.idname)) {
return NULL;
}
@@ -1661,10 +1656,6 @@ static StructRNA *rna_MacroOperator_register(Main *bmain,
}
}
- if (!WM_operator_py_idname_ok_or_report(reports, identifier, dummyot.idname)) {
- return NULL;
- }
-
char idname_conv[sizeof(dummyop.idname)];
WM_operator_bl_idname(idname_conv, dummyot.idname); /* convert the idname from python */
@@ -1867,8 +1858,9 @@ static void rna_def_operator_common(StructRNA *srna)
/* Registration */
prop = RNA_def_property(srna, "bl_idname", PROP_STRING, PROP_NONE);
RNA_def_property_string_sdna(prop, NULL, "type->idname");
- /* Without setting the length the pointer size would be used. -3 because `.` -> `_OT_`. */
- RNA_def_property_string_maxlength(prop, OP_MAX_TYPENAME - 3);
+ /* String stored here is the 'BL' identifier (`OPMODULE_OT_my_op`),
+ * not the 'python' identifier (`opmodule.my_op`). */
+ RNA_def_property_string_maxlength(prop, OP_MAX_TYPENAME);
RNA_def_property_string_funcs(prop, NULL, NULL, "rna_Operator_bl_idname_set");
// RNA_def_property_clear_flag(prop, PROP_EDITABLE);
RNA_def_property_flag(prop, PROP_REGISTER);
diff --git a/source/blender/modifiers/intern/MOD_cast.c b/source/blender/modifiers/intern/MOD_cast.c
index 1a4942fcaf1..30be1d33653 100644
--- a/source/blender/modifiers/intern/MOD_cast.c
+++ b/source/blender/modifiers/intern/MOD_cast.c
@@ -23,6 +23,7 @@
#include "BKE_lib_id.h"
#include "BKE_lib_query.h"
#include "BKE_mesh.h"
+#include "BKE_mesh_runtime.h"
#include "BKE_mesh_wrapper.h"
#include "BKE_modifier.h"
#include "BKE_screen.h"
@@ -494,7 +495,7 @@ static void deformVertsEM(ModifierData *md,
mesh_src = MOD_deform_mesh_eval_get(ctx->object, editData, mesh, NULL, verts_num, false);
}
- if (mesh && mesh->runtime.wrapper_type == ME_WRAPPER_TYPE_MDATA) {
+ if (mesh && BKE_mesh_wrapper_type(mesh) == ME_WRAPPER_TYPE_MDATA) {
BLI_assert(mesh->totvert == verts_num);
}
diff --git a/source/blender/modifiers/intern/MOD_datatransfer.cc b/source/blender/modifiers/intern/MOD_datatransfer.cc
index 4b6170598dd..25e8eb8fa20 100644
--- a/source/blender/modifiers/intern/MOD_datatransfer.cc
+++ b/source/blender/modifiers/intern/MOD_datatransfer.cc
@@ -213,7 +213,7 @@ static Mesh *modifyMesh(ModifierData *md, const ModifierEvalContext *ctx, Mesh *
dtmd->defgrp_name,
invert_vgroup,
&reports)) {
- result->runtime.is_original_bmesh = false;
+ result->runtime->is_original_bmesh = false;
}
if (BKE_reports_contain(&reports, RPT_ERROR)) {
diff --git a/source/blender/modifiers/intern/MOD_multires.cc b/source/blender/modifiers/intern/MOD_multires.cc
index e4c90eb237b..2bc3763c46b 100644
--- a/source/blender/modifiers/intern/MOD_multires.cc
+++ b/source/blender/modifiers/intern/MOD_multires.cc
@@ -230,7 +230,7 @@ static Mesh *modifyMesh(ModifierData *md, const ModifierEvalContext *ctx, Mesh *
if ((ctx->object->mode & OB_MODE_SCULPT) && !for_orco && !for_render && !sculpt_base_mesh) {
/* NOTE: CCG takes ownership over Subdiv. */
result = multires_as_ccg(mmd, ctx, mesh, subdiv);
- result->runtime.subdiv_ccg_tot_level = mmd->totlvl;
+ result->runtime->subdiv_ccg_tot_level = mmd->totlvl;
/* TODO(sergey): Usually it is sculpt stroke's update variants which
* takes care of this, but is possible that we need this before the
* stroke: i.e. when exiting blender right after stroke is done.
@@ -238,7 +238,7 @@ static Mesh *modifyMesh(ModifierData *md, const ModifierEvalContext *ctx, Mesh *
* surely there is a better way of solving this. */
if (ctx->object->sculpt != nullptr) {
SculptSession *sculpt_session = ctx->object->sculpt;
- sculpt_session->subdiv_ccg = result->runtime.subdiv_ccg;
+ sculpt_session->subdiv_ccg = result->runtime->subdiv_ccg;
sculpt_session->multires.active = true;
sculpt_session->multires.modifier = mmd;
sculpt_session->multires.level = mmd->sculptlvl;
@@ -343,7 +343,7 @@ static void panel_draw(const bContext *C, Panel *panel)
modifier_panel_end(layout, ptr);
}
-static void subdivisions_panel_draw(const bContext *UNUSED(C), Panel *panel)
+static void subdivisions_panel_draw(const bContext * /*C*/, Panel *panel)
{
uiLayout *row;
uiLayout *layout = panel->layout;
@@ -406,7 +406,7 @@ static void subdivisions_panel_draw(const bContext *UNUSED(C), Panel *panel)
uiItemO(layout, IFACE_("Delete Higher"), ICON_NONE, "OBJECT_OT_multires_higher_levels_delete");
}
-static void shape_panel_draw(const bContext *UNUSED(C), Panel *panel)
+static void shape_panel_draw(const bContext * /*C*/, Panel *panel)
{
uiLayout *row;
uiLayout *layout = panel->layout;
@@ -421,7 +421,7 @@ static void shape_panel_draw(const bContext *UNUSED(C), Panel *panel)
uiItemO(row, IFACE_("Apply Base"), ICON_NONE, "OBJECT_OT_multires_base_apply");
}
-static void generate_panel_draw(const bContext *UNUSED(C), Panel *panel)
+static void generate_panel_draw(const bContext * /*C*/, Panel *panel)
{
uiLayout *col, *row;
uiLayout *layout = panel->layout;
@@ -449,7 +449,7 @@ static void generate_panel_draw(const bContext *UNUSED(C), Panel *panel)
}
}
-static void advanced_panel_draw(const bContext *UNUSED(C), Panel *panel)
+static void advanced_panel_draw(const bContext * /*C*/, Panel *panel)
{
uiLayout *col;
uiLayout *layout = panel->layout;
diff --git a/source/blender/modifiers/intern/MOD_normal_edit.cc b/source/blender/modifiers/intern/MOD_normal_edit.cc
index 6f86bf1d8cb..43ded18fcc4 100644
--- a/source/blender/modifiers/intern/MOD_normal_edit.cc
+++ b/source/blender/modifiers/intern/MOD_normal_edit.cc
@@ -623,7 +623,7 @@ static Mesh *normalEditModifier_do(NormalEditModifierData *enmd,
MEM_SAFE_FREE(loopnors);
- result->runtime.is_original_bmesh = false;
+ result->runtime->is_original_bmesh = false;
return result;
}
diff --git a/source/blender/modifiers/intern/MOD_particlesystem.cc b/source/blender/modifiers/intern/MOD_particlesystem.cc
index b957bd26ca6..66291520176 100644
--- a/source/blender/modifiers/intern/MOD_particlesystem.cc
+++ b/source/blender/modifiers/intern/MOD_particlesystem.cc
@@ -159,7 +159,7 @@ static void deformVerts(ModifierData *md,
BKE_mesh_tessface_ensure(psmd->mesh_final);
- if (!psmd->mesh_final->runtime.deformed_only) {
+ if (!psmd->mesh_final->runtime->deformed_only) {
/* 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). */
diff --git a/source/blender/modifiers/intern/MOD_remesh.c b/source/blender/modifiers/intern/MOD_remesh.c
index 4241ca5a591..d6241fcb290 100644
--- a/source/blender/modifiers/intern/MOD_remesh.c
+++ b/source/blender/modifiers/intern/MOD_remesh.c
@@ -67,10 +67,9 @@ static void init_dualcon_mesh(DualConInput *input, Mesh *mesh)
input->mloop = (void *)BKE_mesh_loops(mesh);
input->loop_stride = sizeof(MLoop);
- BKE_mesh_runtime_looptri_ensure(mesh);
- input->looptri = (void *)mesh->runtime.looptris.array;
+ input->looptri = (void *)BKE_mesh_runtime_looptri_ensure(mesh);
input->tri_stride = sizeof(MLoopTri);
- input->tottri = mesh->runtime.looptris.len;
+ input->tottri = BKE_mesh_runtime_looptri_len(mesh);
INIT_MINMAX(input->min, input->max);
BKE_mesh_minmax(mesh, input->min, input->max);
diff --git a/source/blender/modifiers/intern/MOD_subsurf.cc b/source/blender/modifiers/intern/MOD_subsurf.cc
index 991bd0d876c..5e77f0ffa9e 100644
--- a/source/blender/modifiers/intern/MOD_subsurf.cc
+++ b/source/blender/modifiers/intern/MOD_subsurf.cc
@@ -208,7 +208,7 @@ static void subdiv_cache_mesh_wrapper_settings(const ModifierEvalContext *ctx,
runtime_data->calc_loop_normals = false; /* Set at the end of modifier stack evaluation. */
runtime_data->use_loop_normals = (smd->flags & eSubsurfModifierFlag_UseCustomNormals);
- mesh->runtime.subsurf_runtime_data = runtime_data;
+ mesh->runtime->subsurf_runtime_data = runtime_data;
}
/* Modifier itself. */
diff --git a/source/blender/modifiers/intern/MOD_util.cc b/source/blender/modifiers/intern/MOD_util.cc
index 7d66f75b20f..589a3d28ad9 100644
--- a/source/blender/modifiers/intern/MOD_util.cc
+++ b/source/blender/modifiers/intern/MOD_util.cc
@@ -57,7 +57,7 @@ void MOD_init_texture(MappingInfoModifierData *dmd, const ModifierEvalContext *c
/* TODO: to be renamed to get_texture_coords once we are done with moving modifiers to Mesh. */
void MOD_get_texture_coords(MappingInfoModifierData *dmd,
- const ModifierEvalContext *UNUSED(ctx),
+ const ModifierEvalContext * /*ctx*/,
Object *ob,
Mesh *mesh,
float (*cos)[3],
@@ -188,7 +188,7 @@ Mesh *MOD_deform_mesh_eval_get(Object *ob,
&mesh_prior_modifiers->id,
nullptr,
(LIB_ID_COPY_LOCALIZE | LIB_ID_COPY_CD_REFERENCE));
- mesh->runtime.deformed_only = 1;
+ mesh->runtime->deformed_only = 1;
}
if (em != nullptr) {
@@ -218,7 +218,7 @@ Mesh *MOD_deform_mesh_eval_get(Object *ob,
}
}
- if (mesh && mesh->runtime.wrapper_type == ME_WRAPPER_TYPE_MDATA) {
+ if (mesh && mesh->runtime->wrapper_type == ME_WRAPPER_TYPE_MDATA) {
BLI_assert(mesh->totvert == verts_num);
}
diff --git a/source/blender/modifiers/intern/MOD_uvproject.cc b/source/blender/modifiers/intern/MOD_uvproject.cc
index 248b7b48a7c..c07b2059b5b 100644
--- a/source/blender/modifiers/intern/MOD_uvproject.cc
+++ b/source/blender/modifiers/intern/MOD_uvproject.cc
@@ -52,7 +52,7 @@ static void initData(ModifierData *md)
MEMCPY_STRUCT_AFTER(umd, DNA_struct_default_get(UVProjectModifierData), modifier);
}
-static void requiredDataMask(ModifierData *UNUSED(md), CustomData_MeshMasks *r_cddata_masks)
+static void requiredDataMask(ModifierData * /*md*/, CustomData_MeshMasks *r_cddata_masks)
{
/* ask for UV coordinates */
r_cddata_masks->lmask |= CD_MASK_MLOOPUV;
@@ -90,7 +90,7 @@ struct Projector {
};
static Mesh *uvprojectModifier_do(UVProjectModifierData *umd,
- const ModifierEvalContext *UNUSED(ctx),
+ const ModifierEvalContext * /*ctx*/,
Object *ob,
Mesh *mesh)
{
@@ -283,7 +283,7 @@ static Mesh *uvprojectModifier_do(UVProjectModifierData *umd,
}
}
- mesh->runtime.is_original_bmesh = false;
+ mesh->runtime->is_original_bmesh = false;
return mesh;
}
@@ -298,7 +298,7 @@ static Mesh *modifyMesh(ModifierData *md, const ModifierEvalContext *ctx, Mesh *
return result;
}
-static void panel_draw(const bContext *UNUSED(C), Panel *panel)
+static void panel_draw(const bContext * /*C*/, Panel *panel)
{
uiLayout *sub;
uiLayout *layout = panel->layout;
diff --git a/source/blender/modifiers/intern/MOD_uvwarp.cc b/source/blender/modifiers/intern/MOD_uvwarp.cc
index 85fd8946d0b..4ec273bcbc6 100644
--- a/source/blender/modifiers/intern/MOD_uvwarp.cc
+++ b/source/blender/modifiers/intern/MOD_uvwarp.cc
@@ -93,7 +93,7 @@ struct UVWarpData {
static void uv_warp_compute(void *__restrict userdata,
const int i,
- const TaskParallelTLS *__restrict UNUSED(tls))
+ const TaskParallelTLS *__restrict /*tls*/)
{
const UVWarpData *data = static_cast<const UVWarpData *>(userdata);
@@ -216,7 +216,7 @@ static Mesh *modifyMesh(ModifierData *md, const ModifierEvalContext *ctx, Mesh *
settings.use_threading = (polys_num > 1000);
BLI_task_parallel_range(0, polys_num, &data, uv_warp_compute, &settings);
- mesh->runtime.is_original_bmesh = false;
+ mesh->runtime->is_original_bmesh = false;
return mesh;
}
@@ -241,7 +241,7 @@ static void updateDepsgraph(ModifierData *md, const ModifierUpdateDepsgraphConte
DEG_add_depends_on_transform_relation(ctx->node, "UVWarp Modifier");
}
-static void panel_draw(const bContext *UNUSED(C), Panel *panel)
+static void panel_draw(const bContext * /*C*/, Panel *panel)
{
uiLayout *col;
uiLayout *layout = panel->layout;
@@ -283,7 +283,7 @@ static void panel_draw(const bContext *UNUSED(C), Panel *panel)
modifier_panel_end(layout, ptr);
}
-static void transform_panel_draw(const bContext *UNUSED(C), Panel *panel)
+static void transform_panel_draw(const bContext * /*C*/, Panel *panel)
{
uiLayout *layout = panel->layout;
diff --git a/source/blender/modifiers/intern/MOD_wave.cc b/source/blender/modifiers/intern/MOD_wave.cc
index 962bb60c8ad..647e0324707 100644
--- a/source/blender/modifiers/intern/MOD_wave.cc
+++ b/source/blender/modifiers/intern/MOD_wave.cc
@@ -21,6 +21,7 @@
#include "BKE_context.h"
#include "BKE_deform.h"
#include "BKE_editmesh.h"
+#include "BKE_editmesh_cache.h"
#include "BKE_lib_id.h"
#include "BKE_lib_query.h"
#include "BKE_mesh.h"
@@ -337,7 +338,7 @@ static void deformVertsEM(ModifierData *md,
if (!ELEM(mesh_src, nullptr, mesh)) {
/* Important not to free `vertexCos` owned by the caller. */
- EditMeshData *edit_data = mesh_src->runtime.edit_data;
+ EditMeshData *edit_data = mesh_src->runtime->edit_data;
if (edit_data->vertexCos == vertexCos) {
edit_data->vertexCos = nullptr;
}
diff --git a/source/blender/modifiers/intern/MOD_weighted_normal.cc b/source/blender/modifiers/intern/MOD_weighted_normal.cc
index e7b1cb45234..1ebd5423d39 100644
--- a/source/blender/modifiers/intern/MOD_weighted_normal.cc
+++ b/source/blender/modifiers/intern/MOD_weighted_normal.cc
@@ -676,7 +676,7 @@ static Mesh *modifyMesh(ModifierData *md, const ModifierEvalContext *ctx, Mesh *
MEM_SAFE_FREE(wn_data.mode_pair);
MEM_SAFE_FREE(wn_data.items_data);
- result->runtime.is_original_bmesh = false;
+ result->runtime->is_original_bmesh = false;
return result;
}
@@ -705,12 +705,12 @@ static void requiredDataMask(ModifierData *md, CustomData_MeshMasks *r_cddata_ma
}
}
-static bool dependsOnNormals(ModifierData *UNUSED(md))
+static bool dependsOnNormals(ModifierData * /*md*/)
{
return true;
}
-static void panel_draw(const bContext *UNUSED(C), Panel *panel)
+static void panel_draw(const bContext * /*C*/, Panel *panel)
{
uiLayout *col;
uiLayout *layout = panel->layout;
diff --git a/source/blender/modifiers/intern/MOD_weightvgedit.cc b/source/blender/modifiers/intern/MOD_weightvgedit.cc
index bcfd47491d5..e4fbca633f7 100644
--- a/source/blender/modifiers/intern/MOD_weightvgedit.cc
+++ b/source/blender/modifiers/intern/MOD_weightvgedit.cc
@@ -96,7 +96,7 @@ static void requiredDataMask(ModifierData *md, CustomData_MeshMasks *r_cddata_ma
/* No need to ask for CD_PREVIEW_MLOOPCOL... */
}
-static bool dependsOnTime(Scene *UNUSED(scene), ModifierData *md)
+static bool dependsOnTime(Scene * /*scene*/, ModifierData *md)
{
WeightVGEditModifierData *wmd = (WeightVGEditModifierData *)md;
@@ -142,7 +142,7 @@ static void updateDepsgraph(ModifierData *md, const ModifierUpdateDepsgraphConte
}
}
-static bool isDisabled(const Scene *UNUSED(scene), ModifierData *md, bool UNUSED(useRenderParams))
+static bool isDisabled(const Scene * /*scene*/, ModifierData *md, bool /*useRenderParams*/)
{
WeightVGEditModifierData *wmd = (WeightVGEditModifierData *)md;
/* If no vertex group, bypass. */
@@ -278,13 +278,13 @@ static Mesh *modifyMesh(ModifierData *md, const ModifierEvalContext *ctx, Mesh *
MEM_freeN(new_w);
MEM_freeN(dw);
- mesh->runtime.is_original_bmesh = false;
+ mesh->runtime->is_original_bmesh = false;
/* Return the vgroup-modified mesh. */
return mesh;
}
-static void panel_draw(const bContext *UNUSED(C), Panel *panel)
+static void panel_draw(const bContext * /*C*/, Panel *panel)
{
uiLayout *sub, *col, *row;
uiLayout *layout = panel->layout;
@@ -326,7 +326,7 @@ static void panel_draw(const bContext *UNUSED(C), Panel *panel)
modifier_panel_end(layout, ptr);
}
-static void falloff_panel_draw(const bContext *UNUSED(C), Panel *panel)
+static void falloff_panel_draw(const bContext * /*C*/, Panel *panel)
{
uiLayout *row, *sub;
uiLayout *layout = panel->layout;
@@ -366,7 +366,7 @@ static void panelRegister(ARegionType *region_type)
region_type, "influence", "Influence", nullptr, influence_panel_draw, panel_type);
}
-static void blendWrite(BlendWriter *writer, const ID *UNUSED(id_owner), const ModifierData *md)
+static void blendWrite(BlendWriter *writer, const ID * /*id_owner*/, const ModifierData *md)
{
const WeightVGEditModifierData *wmd = (const WeightVGEditModifierData *)md;
diff --git a/source/blender/modifiers/intern/MOD_weightvgmix.cc b/source/blender/modifiers/intern/MOD_weightvgmix.cc
index 720f9fac948..d860e93d535 100644
--- a/source/blender/modifiers/intern/MOD_weightvgmix.cc
+++ b/source/blender/modifiers/intern/MOD_weightvgmix.cc
@@ -144,7 +144,7 @@ static void requiredDataMask(ModifierData *md, CustomData_MeshMasks *r_cddata_ma
/* No need to ask for CD_PREVIEW_MLOOPCOL... */
}
-static bool dependsOnTime(Scene *UNUSED(scene), ModifierData *md)
+static bool dependsOnTime(Scene * /*scene*/, ModifierData *md)
{
WeightVGMixModifierData *wmd = (WeightVGMixModifierData *)md;
@@ -190,7 +190,7 @@ static void updateDepsgraph(ModifierData *md, const ModifierUpdateDepsgraphConte
}
}
-static bool isDisabled(const Scene *UNUSED(scene), ModifierData *md, bool UNUSED(useRenderParams))
+static bool isDisabled(const Scene * /*scene*/, ModifierData *md, bool /*useRenderParams*/)
{
WeightVGMixModifierData *wmd = (WeightVGMixModifierData *)md;
/* If no vertex group, bypass. */
@@ -438,13 +438,13 @@ static Mesh *modifyMesh(ModifierData *md, const ModifierEvalContext *ctx, Mesh *
MEM_freeN(dw2);
MEM_SAFE_FREE(indices);
- mesh->runtime.is_original_bmesh = false;
+ mesh->runtime->is_original_bmesh = false;
/* Return the vgroup-modified mesh. */
return mesh;
}
-static void panel_draw(const bContext *UNUSED(C), Panel *panel)
+static void panel_draw(const bContext * /*C*/, Panel *panel)
{
uiLayout *layout = panel->layout;
diff --git a/source/blender/modifiers/intern/MOD_weightvgproximity.cc b/source/blender/modifiers/intern/MOD_weightvgproximity.cc
index faee2b9e6d5..93052f4215d 100644
--- a/source/blender/modifiers/intern/MOD_weightvgproximity.cc
+++ b/source/blender/modifiers/intern/MOD_weightvgproximity.cc
@@ -345,7 +345,7 @@ static void requiredDataMask(ModifierData *md, CustomData_MeshMasks *r_cddata_ma
/* No need to ask for CD_PREVIEW_MLOOPCOL... */
}
-static bool dependsOnTime(Scene *UNUSED(scene), ModifierData *md)
+static bool dependsOnTime(Scene * /*scene*/, ModifierData *md)
{
WeightVGProximityModifierData *wmd = (WeightVGProximityModifierData *)md;
@@ -403,7 +403,7 @@ static void updateDepsgraph(ModifierData *md, const ModifierUpdateDepsgraphConte
}
}
-static bool isDisabled(const Scene *UNUSED(scene), ModifierData *md, bool UNUSED(useRenderParams))
+static bool isDisabled(const Scene * /*scene*/, ModifierData *md, bool /*useRenderParams*/)
{
WeightVGProximityModifierData *wmd = (WeightVGProximityModifierData *)md;
/* If no vertex group, bypass. */
@@ -639,13 +639,13 @@ static Mesh *modifyMesh(ModifierData *md, const ModifierEvalContext *ctx, Mesh *
TIMEIT_END(perf);
#endif
- mesh->runtime.is_original_bmesh = false;
+ mesh->runtime->is_original_bmesh = false;
/* Return the vgroup-modified mesh. */
return mesh;
}
-static void panel_draw(const bContext *UNUSED(C), Panel *panel)
+static void panel_draw(const bContext * /*C*/, Panel *panel)
{
uiLayout *col;
uiLayout *layout = panel->layout;
@@ -673,7 +673,7 @@ static void panel_draw(const bContext *UNUSED(C), Panel *panel)
uiItemR(layout, ptr, "normalize", 0, nullptr, ICON_NONE);
}
-static void falloff_panel_draw(const bContext *UNUSED(C), Panel *panel)
+static void falloff_panel_draw(const bContext * /*C*/, Panel *panel)
{
uiLayout *row, *sub;
uiLayout *layout = panel->layout;
@@ -714,7 +714,7 @@ static void panelRegister(ARegionType *region_type)
region_type, "influence", "Influence", nullptr, influence_panel_draw, panel_type);
}
-static void blendWrite(BlendWriter *writer, const ID *UNUSED(id_owner), const ModifierData *md)
+static void blendWrite(BlendWriter *writer, const ID * /*id_owner*/, const ModifierData *md)
{
const WeightVGProximityModifierData *wmd = (const WeightVGProximityModifierData *)md;
diff --git a/source/blender/nodes/CMakeLists.txt b/source/blender/nodes/CMakeLists.txt
index 422ee747649..2398aefc67a 100644
--- a/source/blender/nodes/CMakeLists.txt
+++ b/source/blender/nodes/CMakeLists.txt
@@ -50,7 +50,7 @@ set(SRC
intern/node_multi_function.cc
intern/node_socket.cc
intern/node_socket_declarations.cc
- intern/node_util.c
+ intern/node_util.cc
intern/socket_search_link.cc
NOD_common.h
diff --git a/source/blender/nodes/NOD_static_types.h b/source/blender/nodes/NOD_static_types.h
index d1504060665..9671f8148ec 100644
--- a/source/blender/nodes/NOD_static_types.h
+++ b/source/blender/nodes/NOD_static_types.h
@@ -369,7 +369,7 @@ DefNode(GeometryNode, GEO_NODE_MESH_TO_POINTS, def_geo_mesh_to_points, "MESH_TO_
DefNode(GeometryNode, GEO_NODE_MESH_TO_VOLUME, def_geo_mesh_to_volume, "MESH_TO_VOLUME", MeshToVolume, "Mesh to Volume", "Create a fog volume with the shape of the input mesh's surface")
DefNode(GeometryNode, GEO_NODE_MESH_TOPOLOGY_CORNERS_OF_FACE, 0, "CORNERS_OF_FACE", CornersOfFace, "Corners of Face", "Retrieve corners that make up a face")
DefNode(GeometryNode, GEO_NODE_MESH_TOPOLOGY_CORNERS_OF_VERTEX, 0, "CORNERS_OF_VERTEX", CornersOfVertex, "Corners of Vertex", "Retrieve face corners connected to vertices")
-DefNode(GeometryNode, GEO_NODE_MESH_TOPOLOGY_EDGES_OF_CORNER, 0, "EDGES_OF_CORNER", EdgesOfCorner, "Edges of Corner", "Retrieve the edges on boths sides of a face corner")
+DefNode(GeometryNode, GEO_NODE_MESH_TOPOLOGY_EDGES_OF_CORNER, 0, "EDGES_OF_CORNER", EdgesOfCorner, "Edges of Corner", "Retrieve the edges on both sides of a face corner")
DefNode(GeometryNode, GEO_NODE_MESH_TOPOLOGY_EDGES_OF_VERTEX, 0, "EDGES_OF_VERTEX", EdgesOfVertex, "Edges of Vertex", "Retrieve the edges connected to each vertex")
DefNode(GeometryNode, GEO_NODE_MESH_TOPOLOGY_FACE_OF_CORNER, 0, "FACE_OF_CORNER", FaceOfCorner, "Face of Corner", "Retrieve the face each face corner is part of")
DefNode(GeometryNode, GEO_NODE_MESH_TOPOLOGY_OFFSET_CORNER_IN_FACE, 0, "OFFSET_CORNER_IN_FACE", OffsetCornerInFace, "Offset Corner in Face", "Retrieve corners in the same face as another")
diff --git a/source/blender/nodes/composite/CMakeLists.txt b/source/blender/nodes/composite/CMakeLists.txt
index 2537e8e93cc..4255a2dde21 100644
--- a/source/blender/nodes/composite/CMakeLists.txt
+++ b/source/blender/nodes/composite/CMakeLists.txt
@@ -18,6 +18,7 @@ set(INC
../../render
../../windowmanager
../../compositor/realtime_compositor
+ ../../compositor/realtime_compositor/algorithms
../../../../intern/guardedalloc
# dna_type_offsets.h
diff --git a/source/blender/nodes/composite/nodes/node_composite_bokehblur.cc b/source/blender/nodes/composite/nodes/node_composite_bokehblur.cc
index 731c559dfdc..a581d87a463 100644
--- a/source/blender/nodes/composite/nodes/node_composite_bokehblur.cc
+++ b/source/blender/nodes/composite/nodes/node_composite_bokehblur.cc
@@ -70,10 +70,20 @@ class BokehBlurOperation : public NodeOperation {
return;
}
+ if (get_input("Size").is_single_value() || !get_variable_size()) {
+ execute_constant_size();
+ }
+ else {
+ execute_variable_size();
+ }
+ }
+
+ void execute_constant_size()
+ {
GPUShader *shader = shader_manager().get("compositor_blur");
GPU_shader_bind(shader);
- GPU_shader_uniform_1i(shader, "radius", compute_blur_radius());
+ GPU_shader_uniform_1i(shader, "radius", int(compute_blur_radius()));
GPU_shader_uniform_1b(shader, "extend_bounds", get_extend_bounds());
const Result &input_image = get_input("Image");
@@ -88,7 +98,7 @@ class BokehBlurOperation : public NodeOperation {
Domain domain = compute_domain();
if (get_extend_bounds()) {
/* Add a radius amount of pixels in both sides of the image, hence the multiply by 2. */
- domain.size += int2(compute_blur_radius() * 2);
+ domain.size += int2(int(compute_blur_radius()) * 2);
}
Result &output_image = get_result("Image");
@@ -104,7 +114,42 @@ class BokehBlurOperation : public NodeOperation {
input_mask.unbind_as_texture();
}
- int compute_blur_radius()
+ void execute_variable_size()
+ {
+ GPUShader *shader = shader_manager().get("compositor_blur_variable_size");
+ GPU_shader_bind(shader);
+
+ GPU_shader_uniform_1f(shader, "base_size", compute_blur_radius());
+ GPU_shader_uniform_1i(shader, "search_radius", get_max_size());
+
+ const Result &input_image = get_input("Image");
+ input_image.bind_as_texture(shader, "input_tx");
+
+ const Result &input_weights = get_input("Bokeh");
+ input_weights.bind_as_texture(shader, "weights_tx");
+
+ const Result &input_size = get_input("Size");
+ input_size.bind_as_texture(shader, "size_tx");
+
+ const Result &input_mask = get_input("Bounding box");
+ input_mask.bind_as_texture(shader, "mask_tx");
+
+ const Domain domain = compute_domain();
+ Result &output_image = get_result("Image");
+ output_image.allocate_texture(domain);
+ output_image.bind_as_image(shader, "output_img");
+
+ compute_dispatch_threads_at_least(shader, domain.size);
+
+ GPU_shader_unbind();
+ output_image.unbind_as_image();
+ input_image.unbind_as_texture();
+ input_weights.unbind_as_texture();
+ input_size.unbind_as_texture();
+ input_mask.unbind_as_texture();
+ }
+
+ float compute_blur_radius()
{
const int2 image_size = get_input("Image").domain().size;
const int max_size = math::max(image_size.x, image_size.y);
@@ -124,7 +169,7 @@ class BokehBlurOperation : public NodeOperation {
return true;
}
- if (compute_blur_radius() == 0) {
+ if (compute_blur_radius() == 0.0f) {
return true;
}
@@ -142,6 +187,16 @@ class BokehBlurOperation : public NodeOperation {
{
return bnode().custom1 & CMP_NODEFLAG_BLUR_EXTEND_BOUNDS;
}
+
+ bool get_variable_size()
+ {
+ return bnode().custom1 & CMP_NODEFLAG_BLUR_VARIABLE_SIZE;
+ }
+
+ int get_max_size()
+ {
+ return static_cast<int>(bnode().custom4);
+ }
};
static NodeOperation *get_compositor_operation(Context &context, DNode node)
diff --git a/source/blender/nodes/composite/nodes/node_composite_cryptomatte.cc b/source/blender/nodes/composite/nodes/node_composite_cryptomatte.cc
index 23a9385c4fc..fa3b14ae015 100644
--- a/source/blender/nodes/composite/nodes/node_composite_cryptomatte.cc
+++ b/source/blender/nodes/composite/nodes/node_composite_cryptomatte.cc
@@ -415,7 +415,8 @@ void register_node_type_cmp_cryptomatte_legacy()
static bNodeType ntype;
- cmp_node_type_base(&ntype, CMP_NODE_CRYPTOMATTE_LEGACY, "Cryptomatte", NODE_CLASS_MATTE);
+ cmp_node_type_base(
+ &ntype, CMP_NODE_CRYPTOMATTE_LEGACY, "Cryptomatte (Legacy)", NODE_CLASS_MATTE);
node_type_socket_templates(&ntype, nullptr, file_ns::cmp_node_cryptomatte_out);
node_type_init(&ntype, legacy_file_ns::node_init_cryptomatte_legacy);
node_type_storage(
diff --git a/source/blender/nodes/composite/nodes/node_composite_levels.cc b/source/blender/nodes/composite/nodes/node_composite_levels.cc
index a4fe1f33813..4c901372b9f 100644
--- a/source/blender/nodes/composite/nodes/node_composite_levels.cc
+++ b/source/blender/nodes/composite/nodes/node_composite_levels.cc
@@ -5,9 +5,18 @@
* \ingroup cmpnodes
*/
+#include <cmath>
+
+#include "BLI_assert.h"
+#include "BLI_math_vec_types.hh"
+#include "BLI_math_vector.hh"
+
#include "UI_interface.h"
#include "UI_resources.h"
+#include "IMB_colormanagement.h"
+
+#include "COM_algorithm_parallel_reduction.hh"
#include "COM_node_operation.hh"
#include "node_composite_util.hh"
@@ -18,7 +27,9 @@ namespace blender::nodes::node_composite_levels_cc {
static void cmp_node_levels_declare(NodeDeclarationBuilder &b)
{
- b.add_input<decl::Color>(N_("Image")).default_value({0.0f, 0.0f, 0.0f, 1.0f});
+ b.add_input<decl::Color>(N_("Image"))
+ .default_value({0.0f, 0.0f, 0.0f, 1.0f})
+ .compositor_domain_priority(0);
b.add_output<decl::Float>(N_("Mean"));
b.add_output<decl::Float>(N_("Std Dev"));
}
@@ -36,13 +47,140 @@ static void node_composit_buts_view_levels(uiLayout *layout, bContext * /*C*/, P
using namespace blender::realtime_compositor;
class LevelsOperation : public NodeOperation {
+ private:
+ constexpr static float luminance_coefficients_bt709_[3] = {0.2126f, 0.7152f, 0.0722f};
+
public:
using NodeOperation::NodeOperation;
void execute() override
{
- get_result("Mean").allocate_invalid();
- get_result("Std Dev").allocate_invalid();
+ if (get_input("Image").is_single_value()) {
+ execute_single_value();
+ return;
+ }
+
+ const float mean = compute_mean();
+
+ Result &mean_result = get_result("Mean");
+ if (mean_result.should_compute()) {
+ mean_result.allocate_single_value();
+ mean_result.set_float_value(mean);
+ }
+
+ Result &standard_deviation_result = get_result("Std Dev");
+ if (standard_deviation_result.should_compute()) {
+ const float standard_deviation = compute_standard_deviation(mean);
+ standard_deviation_result.allocate_single_value();
+ standard_deviation_result.set_float_value(standard_deviation);
+ }
+ }
+
+ void execute_single_value()
+ {
+ Result &standard_deviation_result = get_result("Std Dev");
+ if (standard_deviation_result.should_compute()) {
+ standard_deviation_result.allocate_single_value();
+ standard_deviation_result.set_float_value(0.0f);
+ }
+
+ Result &mean_result = get_result("Mean");
+ if (!mean_result.should_compute()) {
+ return;
+ }
+
+ mean_result.allocate_single_value();
+ const float3 input = float3(get_input("Image").get_color_value());
+
+ switch (get_channel()) {
+ case CMP_NODE_LEVLES_RED:
+ mean_result.set_float_value(input.x);
+ break;
+ case CMP_NODE_LEVLES_GREEN:
+ mean_result.set_float_value(input.y);
+ break;
+ case CMP_NODE_LEVLES_BLUE:
+ mean_result.set_float_value(input.z);
+ break;
+ case CMP_NODE_LEVLES_LUMINANCE_BT709:
+ mean_result.set_float_value(math::dot(input, float3(luminance_coefficients_bt709_)));
+ break;
+ case CMP_NODE_LEVLES_LUMINANCE: {
+ float luminance_coefficients[3];
+ IMB_colormanagement_get_luminance_coefficients(luminance_coefficients);
+ mean_result.set_float_value(math::dot(input, float3(luminance_coefficients)));
+ break;
+ }
+ default:
+ BLI_assert_unreachable();
+ break;
+ }
+ }
+
+ float compute_mean()
+ {
+ const Result &input = get_input("Image");
+ return compute_sum() / (input.domain().size.x * input.domain().size.y);
+ }
+
+ float compute_sum()
+ {
+ const Result &input = get_input("Image");
+ switch (get_channel()) {
+ case CMP_NODE_LEVLES_RED:
+ return sum_red(context(), input.texture());
+ case CMP_NODE_LEVLES_GREEN:
+ return sum_green(context(), input.texture());
+ case CMP_NODE_LEVLES_BLUE:
+ return sum_blue(context(), input.texture());
+ case CMP_NODE_LEVLES_LUMINANCE_BT709:
+ return sum_luminance(context(), input.texture(), float3(luminance_coefficients_bt709_));
+ case CMP_NODE_LEVLES_LUMINANCE: {
+ float luminance_coefficients[3];
+ IMB_colormanagement_get_luminance_coefficients(luminance_coefficients);
+ return sum_luminance(context(), input.texture(), float3(luminance_coefficients));
+ }
+ default:
+ BLI_assert_unreachable();
+ return 0.0f;
+ }
+ }
+
+ float compute_standard_deviation(float mean)
+ {
+ const Result &input = get_input("Image");
+ const float sum = compute_sum_squared_difference(mean);
+ return std::sqrt(sum / (input.domain().size.x * input.domain().size.y));
+ }
+
+ float compute_sum_squared_difference(float subtrahend)
+ {
+ const Result &input = get_input("Image");
+ switch (get_channel()) {
+ case CMP_NODE_LEVLES_RED:
+ return sum_red_squared_difference(context(), input.texture(), subtrahend);
+ case CMP_NODE_LEVLES_GREEN:
+ return sum_green_squared_difference(context(), input.texture(), subtrahend);
+ case CMP_NODE_LEVLES_BLUE:
+ return sum_blue_squared_difference(context(), input.texture(), subtrahend);
+ case CMP_NODE_LEVLES_LUMINANCE_BT709:
+ return sum_luminance_squared_difference(
+ context(), input.texture(), float3(luminance_coefficients_bt709_), subtrahend);
+ case CMP_NODE_LEVLES_LUMINANCE: {
+ float luminance_coefficients[3];
+ IMB_colormanagement_get_luminance_coefficients(luminance_coefficients);
+ return sum_luminance_squared_difference(
+ context(), input.texture(), float3(luminance_coefficients), subtrahend);
+ }
+ default:
+ BLI_assert_unreachable();
+ return 0.0f;
+ }
+ }
+
+ CMPNodeLevelsChannel get_channel()
+ {
+ return static_cast<CMPNodeLevelsChannel>(bnode().custom1);
}
};
diff --git a/source/blender/nodes/composite/nodes/node_composite_pixelate.cc b/source/blender/nodes/composite/nodes/node_composite_pixelate.cc
index c4e42f8247d..c65bb7bb747 100644
--- a/source/blender/nodes/composite/nodes/node_composite_pixelate.cc
+++ b/source/blender/nodes/composite/nodes/node_composite_pixelate.cc
@@ -36,7 +36,10 @@ class PixelateOperation : public NodeOperation {
* matches its apparent size, that is, its size after the domain transformation. The pixelate
* node has no effect if the input is scaled-up. See the compute_domain method for more
* information. */
- get_input("Color").pass_through(get_result("Color"));
+ Result &result = get_result("Color");
+ get_input("Color").pass_through(result);
+
+ result.get_realization_options().interpolation = Interpolation::Nearest;
}
/* Compute a smaller-sized domain that matches the apparent size of the input while having a unit
diff --git a/source/blender/nodes/composite/nodes/node_composite_scale.cc b/source/blender/nodes/composite/nodes/node_composite_scale.cc
index b9f1f2da6a8..c524d7b8da9 100644
--- a/source/blender/nodes/composite/nodes/node_composite_scale.cc
+++ b/source/blender/nodes/composite/nodes/node_composite_scale.cc
@@ -88,7 +88,6 @@ class ScaleOperation : public NodeOperation {
get_translation(), 0.0f, get_scale());
result.transform(transformation);
- result.get_realization_options().interpolation = Interpolation::Bilinear;
}
float2 get_scale()
diff --git a/source/blender/nodes/composite/nodes/node_composite_sepcomb_hsva.cc b/source/blender/nodes/composite/nodes/node_composite_sepcomb_hsva.cc
index b655c0db106..3483285793a 100644
--- a/source/blender/nodes/composite/nodes/node_composite_sepcomb_hsva.cc
+++ b/source/blender/nodes/composite/nodes/node_composite_sepcomb_hsva.cc
@@ -54,7 +54,8 @@ void register_node_type_cmp_sephsva()
static bNodeType ntype;
- cmp_node_type_base(&ntype, CMP_NODE_SEPHSVA_LEGACY, "Separate HSVA", NODE_CLASS_CONVERTER);
+ cmp_node_type_base(
+ &ntype, CMP_NODE_SEPHSVA_LEGACY, "Separate HSVA (Legacy)", NODE_CLASS_CONVERTER);
ntype.declare = file_ns::cmp_node_sephsva_declare;
ntype.gather_link_search_ops = nullptr;
ntype.get_compositor_shader_node = file_ns::get_compositor_shader_node;
@@ -107,7 +108,8 @@ void register_node_type_cmp_combhsva()
static bNodeType ntype;
- cmp_node_type_base(&ntype, CMP_NODE_COMBHSVA_LEGACY, "Combine HSVA", NODE_CLASS_CONVERTER);
+ cmp_node_type_base(
+ &ntype, CMP_NODE_COMBHSVA_LEGACY, "Combine HSVA (Legacy)", NODE_CLASS_CONVERTER);
ntype.declare = file_ns::cmp_node_combhsva_declare;
ntype.gather_link_search_ops = nullptr;
ntype.get_compositor_shader_node = file_ns::get_compositor_shader_node;
diff --git a/source/blender/nodes/composite/nodes/node_composite_sepcomb_rgba.cc b/source/blender/nodes/composite/nodes/node_composite_sepcomb_rgba.cc
index 1f4c9fd153f..9308052454d 100644
--- a/source/blender/nodes/composite/nodes/node_composite_sepcomb_rgba.cc
+++ b/source/blender/nodes/composite/nodes/node_composite_sepcomb_rgba.cc
@@ -54,7 +54,8 @@ void register_node_type_cmp_seprgba()
static bNodeType ntype;
- cmp_node_type_base(&ntype, CMP_NODE_SEPRGBA_LEGACY, "Separate RGBA", NODE_CLASS_CONVERTER);
+ cmp_node_type_base(
+ &ntype, CMP_NODE_SEPRGBA_LEGACY, "Separate RGBA (Legacy)", NODE_CLASS_CONVERTER);
ntype.declare = file_ns::cmp_node_seprgba_declare;
ntype.gather_link_search_ops = nullptr;
ntype.get_compositor_shader_node = file_ns::get_compositor_shader_node;
@@ -107,7 +108,8 @@ void register_node_type_cmp_combrgba()
static bNodeType ntype;
- cmp_node_type_base(&ntype, CMP_NODE_COMBRGBA_LEGACY, "Combine RGBA", NODE_CLASS_CONVERTER);
+ cmp_node_type_base(
+ &ntype, CMP_NODE_COMBRGBA_LEGACY, "Combine RGBA (Legacy)", NODE_CLASS_CONVERTER);
ntype.declare = file_ns::cmp_node_combrgba_declare;
ntype.gather_link_search_ops = nullptr;
ntype.get_compositor_shader_node = file_ns::get_compositor_shader_node;
diff --git a/source/blender/nodes/composite/nodes/node_composite_sepcomb_ycca.cc b/source/blender/nodes/composite/nodes/node_composite_sepcomb_ycca.cc
index 78be1efbd8e..82fc37a18f6 100644
--- a/source/blender/nodes/composite/nodes/node_composite_sepcomb_ycca.cc
+++ b/source/blender/nodes/composite/nodes/node_composite_sepcomb_ycca.cc
@@ -81,7 +81,8 @@ void register_node_type_cmp_sepycca()
static bNodeType ntype;
- cmp_node_type_base(&ntype, CMP_NODE_SEPYCCA_LEGACY, "Separate YCbCrA", NODE_CLASS_CONVERTER);
+ cmp_node_type_base(
+ &ntype, CMP_NODE_SEPYCCA_LEGACY, "Separate YCbCrA (Legacy)", NODE_CLASS_CONVERTER);
ntype.declare = file_ns::cmp_node_sepycca_declare;
node_type_init(&ntype, file_ns::node_composit_init_mode_sepycca);
ntype.gather_link_search_ops = nullptr;
@@ -168,7 +169,8 @@ void register_node_type_cmp_combycca()
static bNodeType ntype;
- cmp_node_type_base(&ntype, CMP_NODE_COMBYCCA_LEGACY, "Combine YCbCrA", NODE_CLASS_CONVERTER);
+ cmp_node_type_base(
+ &ntype, CMP_NODE_COMBYCCA_LEGACY, "Combine YCbCrA (Legacy)", NODE_CLASS_CONVERTER);
ntype.declare = file_ns::cmp_node_combycca_declare;
node_type_init(&ntype, file_ns::node_composit_init_mode_combycca);
ntype.gather_link_search_ops = nullptr;
diff --git a/source/blender/nodes/composite/nodes/node_composite_sepcomb_yuva.cc b/source/blender/nodes/composite/nodes/node_composite_sepcomb_yuva.cc
index 1f0eb04cfc3..b12e70ad9b8 100644
--- a/source/blender/nodes/composite/nodes/node_composite_sepcomb_yuva.cc
+++ b/source/blender/nodes/composite/nodes/node_composite_sepcomb_yuva.cc
@@ -54,7 +54,8 @@ void register_node_type_cmp_sepyuva()
static bNodeType ntype;
- cmp_node_type_base(&ntype, CMP_NODE_SEPYUVA_LEGACY, "Separate YUVA", NODE_CLASS_CONVERTER);
+ cmp_node_type_base(
+ &ntype, CMP_NODE_SEPYUVA_LEGACY, "Separate YUVA (Legacy)", NODE_CLASS_CONVERTER);
ntype.declare = file_ns::cmp_node_sepyuva_declare;
ntype.gather_link_search_ops = nullptr;
ntype.get_compositor_shader_node = file_ns::get_compositor_shader_node;
@@ -107,7 +108,8 @@ void register_node_type_cmp_combyuva()
static bNodeType ntype;
- cmp_node_type_base(&ntype, CMP_NODE_COMBYUVA_LEGACY, "Combine YUVA", NODE_CLASS_CONVERTER);
+ cmp_node_type_base(
+ &ntype, CMP_NODE_COMBYUVA_LEGACY, "Combine YUVA (Legacy)", NODE_CLASS_CONVERTER);
ntype.declare = file_ns::cmp_node_combyuva_declare;
ntype.gather_link_search_ops = nullptr;
ntype.get_compositor_shader_node = file_ns::get_compositor_shader_node;
diff --git a/source/blender/nodes/geometry/nodes/node_geo_input_mesh_edge_vertices.cc b/source/blender/nodes/geometry/nodes/node_geo_input_mesh_edge_vertices.cc
index 149d44b2207..513ddd76055 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_input_mesh_edge_vertices.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_input_mesh_edge_vertices.cc
@@ -113,7 +113,7 @@ class EdgePositionFieldInput final : public bke::MeshFieldInput {
GVArray get_varray_for_context(const Mesh &mesh,
const eAttrDomain domain,
- IndexMask UNUSED(mask)) const final
+ IndexMask /*mask*/) const final
{
return construct_edge_positions_gvarray(mesh, vertex_, domain);
}
diff --git a/source/blender/nodes/geometry/nodes/node_geo_mesh_topology_corners_of_vertex.cc b/source/blender/nodes/geometry/nodes/node_geo_mesh_topology_corners_of_vertex.cc
index f45ff826a60..cce3f4e3648 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_mesh_topology_corners_of_vertex.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_mesh_topology_corners_of_vertex.cc
@@ -60,8 +60,8 @@ class CornersOfVertInput final : public bke::MeshFieldInput {
{
const IndexRange vert_range(mesh.totvert);
const Span<MLoop> loops = mesh.loops();
- Array<Vector<int>> vert_to_loop_map = mesh_topology::build_vert_to_loop_map(loops,
- mesh.totvert);
+ Array<Vector<int>> vert_to_loop_map = bke::mesh_topology::build_vert_to_loop_map(loops,
+ mesh.totvert);
const bke::MeshFieldContext context{mesh, domain};
fn::FieldEvaluator evaluator{context, &mask};
diff --git a/source/blender/nodes/geometry/nodes/node_geo_mesh_topology_edges_of_corner.cc b/source/blender/nodes/geometry/nodes/node_geo_mesh_topology_edges_of_corner.cc
index c46c64448bf..84b560cb48a 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_mesh_topology_edges_of_corner.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_mesh_topology_edges_of_corner.cc
@@ -77,13 +77,13 @@ class CornerPreviousEdgeFieldInput final : public bke::MeshFieldInput {
}
const Span<MPoly> polys = mesh.polys();
const Span<MLoop> loops = mesh.loops();
- Array<int> loop_to_poly_map = mesh_topology::build_loop_to_poly_map(polys, mesh.totloop);
+ Array<int> loop_to_poly_map = bke::mesh_topology::build_loop_to_poly_map(polys, mesh.totloop);
return VArray<int>::ForFunc(
mesh.totloop,
[polys, loops, loop_to_poly_map = std::move(loop_to_poly_map)](const int corner_i) {
const int poly_i = loop_to_poly_map[corner_i];
const MPoly &poly = polys[poly_i];
- const int corner_i_prev = mesh_topology::previous_poly_loop(poly, corner_i);
+ const int corner_i_prev = bke::mesh_topology::previous_poly_loop(poly, corner_i);
return loops[corner_i_prev].e;
});
}
diff --git a/source/blender/nodes/geometry/nodes/node_geo_mesh_topology_edges_of_vertex.cc b/source/blender/nodes/geometry/nodes/node_geo_mesh_topology_edges_of_vertex.cc
index d099cd7f8cc..053ef61deed 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_mesh_topology_edges_of_vertex.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_mesh_topology_edges_of_vertex.cc
@@ -60,8 +60,8 @@ class EdgesOfVertInput final : public bke::MeshFieldInput {
{
const IndexRange vert_range(mesh.totvert);
const Span<MEdge> edges = mesh.edges();
- Array<Vector<int>> vert_to_edge_map = mesh_topology::build_vert_to_edge_map(edges,
- mesh.totvert);
+ Array<Vector<int>> vert_to_edge_map = bke::mesh_topology::build_vert_to_edge_map(edges,
+ mesh.totvert);
const bke::MeshFieldContext context{mesh, domain};
fn::FieldEvaluator evaluator{context, &mask};
diff --git a/source/blender/nodes/geometry/nodes/node_geo_mesh_topology_face_of_corner.cc b/source/blender/nodes/geometry/nodes/node_geo_mesh_topology_face_of_corner.cc
index 99def9e8bd1..d9f944ca11e 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_mesh_topology_face_of_corner.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_mesh_topology_face_of_corner.cc
@@ -36,7 +36,7 @@ class CornerFaceIndexInput final : public bke::MeshFieldInput {
return {};
}
return VArray<int>::ForContainer(
- mesh_topology::build_loop_to_poly_map(mesh.polys(), mesh.totloop));
+ bke::mesh_topology::build_loop_to_poly_map(mesh.polys(), mesh.totloop));
}
uint64_t hash() const final
@@ -65,7 +65,7 @@ class CornerIndexInFaceInput final : public bke::MeshFieldInput {
return {};
}
const Span<MPoly> polys = mesh.polys();
- Array<int> loop_to_poly_map = mesh_topology::build_loop_to_poly_map(polys, mesh.totloop);
+ Array<int> loop_to_poly_map = bke::mesh_topology::build_loop_to_poly_map(polys, mesh.totloop);
return VArray<int>::ForFunc(
mesh.totloop, [polys, loop_to_poly_map = std::move(loop_to_poly_map)](const int corner_i) {
const int poly_i = loop_to_poly_map[corner_i];
diff --git a/source/blender/nodes/geometry/nodes/node_geo_mesh_topology_offset_corner_in_face.cc b/source/blender/nodes/geometry/nodes/node_geo_mesh_topology_offset_corner_in_face.cc
index d7ea097be94..2cb9ae82fa1 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_mesh_topology_offset_corner_in_face.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_mesh_topology_offset_corner_in_face.cc
@@ -52,7 +52,7 @@ class OffsetCornerInFaceFieldInput final : public bke::MeshFieldInput {
const VArray<int> corner_indices = evaluator.get_evaluated<int>(0);
const VArray<int> offsets = evaluator.get_evaluated<int>(1);
- Array<int> loop_to_poly_map = mesh_topology::build_loop_to_poly_map(polys, mesh.totloop);
+ Array<int> loop_to_poly_map = bke::mesh_topology::build_loop_to_poly_map(polys, mesh.totloop);
Array<int> offset_corners(mask.min_array_size());
threading::parallel_for(mask.index_range(), 2048, [&](const IndexRange range) {
diff --git a/source/blender/nodes/intern/node_util.c b/source/blender/nodes/intern/node_util.cc
index ddab455509d..17be20b4e4b 100644
--- a/source/blender/nodes/intern/node_util.c
+++ b/source/blender/nodes/intern/node_util.cc
@@ -37,7 +37,7 @@
void node_free_curves(bNode *node)
{
- BKE_curvemapping_free(node->storage);
+ BKE_curvemapping_free(static_cast<CurveMapping *>(node->storage));
}
void node_free_standard_storage(bNode *node)
@@ -49,7 +49,7 @@ void node_free_standard_storage(bNode *node)
void node_copy_curves(bNodeTree *UNUSED(dest_ntree), bNode *dest_node, const bNode *src_node)
{
- dest_node->storage = BKE_curvemapping_copy(src_node->storage);
+ dest_node->storage = BKE_curvemapping_copy(static_cast<CurveMapping *>(src_node->storage));
}
void node_copy_standard_storage(bNodeTree *UNUSED(dest_ntree),
@@ -63,7 +63,7 @@ void *node_initexec_curves(bNodeExecContext *UNUSED(context),
bNode *node,
bNodeInstanceKey UNUSED(key))
{
- BKE_curvemapping_init(node->storage);
+ BKE_curvemapping_init(static_cast<CurveMapping *>(node->storage));
return NULL; /* unused return */
}
@@ -87,9 +87,9 @@ void node_sock_label_clear(bNodeSocket *sock)
void node_math_update(bNodeTree *ntree, bNode *node)
{
- bNodeSocket *sock1 = BLI_findlink(&node->inputs, 0);
- bNodeSocket *sock2 = BLI_findlink(&node->inputs, 1);
- bNodeSocket *sock3 = BLI_findlink(&node->inputs, 2);
+ bNodeSocket *sock1 = static_cast<bNodeSocket *>(BLI_findlink(&node->inputs, 0));
+ bNodeSocket *sock2 = static_cast<bNodeSocket *>(BLI_findlink(&node->inputs, 1));
+ bNodeSocket *sock3 = static_cast<bNodeSocket *>(BLI_findlink(&node->inputs, 2));
nodeSetSocketAvailability(ntree,
sock2,
!ELEM(node->custom1,
@@ -305,7 +305,9 @@ static bNodeSocket *node_find_linkable_socket(bNodeTree *ntree,
bNode *node,
bNodeSocket *to_socket)
{
- bNodeSocket *first = to_socket->in_out == SOCK_IN ? node->inputs.first : node->outputs.first;
+ bNodeSocket *first = to_socket->in_out == SOCK_IN ?
+ static_cast<bNodeSocket *>(node->inputs.first) :
+ static_cast<bNodeSocket *>((node->outputs.first));
/* Wrap around the list end. */
bNodeSocket *socket_iter = to_socket->next ? to_socket->next : first;
diff --git a/source/blender/nodes/intern/socket_search_link.cc b/source/blender/nodes/intern/socket_search_link.cc
index 0bd838ff002..b440952b503 100644
--- a/source/blender/nodes/intern/socket_search_link.cc
+++ b/source/blender/nodes/intern/socket_search_link.cc
@@ -125,64 +125,23 @@ void search_link_ops_for_declarations(GatherLinkSearchOpParams &params,
}
}
-static void search_link_ops_for_socket_templates(GatherLinkSearchOpParams &params,
- const bNodeSocketTemplate *templates,
- const eNodeSocketInOut in_out)
-{
- const bNodeType &node_type = params.node_type();
- const bNodeTreeType &node_tree_type = *params.node_tree().typeinfo;
-
- Set<StringRef> socket_names;
- for (const bNodeSocketTemplate *socket_template = templates; socket_template->type != -1;
- socket_template++) {
- eNodeSocketDatatype from = (eNodeSocketDatatype)socket_template->type;
- eNodeSocketDatatype to = (eNodeSocketDatatype)params.other_socket().type;
- if (in_out == SOCK_IN) {
- std::swap(from, to);
- }
- if (node_tree_type.validate_link && !node_tree_type.validate_link(from, to)) {
- continue;
- }
- if (!socket_names.add(socket_template->name)) {
- /* See comment in #search_link_ops_for_declarations. */
- continue;
- }
-
- params.add_item(
- socket_template->name, [socket_template, node_type, in_out](LinkSearchOpParams &params) {
- bNode &node = params.add_node(node_type);
- bNodeSocket *new_node_socket = bke::node_find_enabled_socket(
- node, in_out, socket_template->name);
- if (new_node_socket != nullptr) {
- /* Rely on the way #nodeAddLink switches in/out if necessary. */
- nodeAddLink(&params.node_tree, &params.node, &params.socket, &node, new_node_socket);
- }
- });
- }
-}
-
void search_link_ops_for_basic_node(GatherLinkSearchOpParams &params)
{
const bNodeType &node_type = params.node_type();
+ if (!node_type.declare) {
+ return;
+ }
- if (node_type.declare) {
- if (node_type.declaration_is_dynamic) {
- /* Dynamic declarations (whatever they end up being) aren't supported
- * by this function, but still avoid a crash in release builds. */
- BLI_assert_unreachable();
- return;
- }
+ if (node_type.declaration_is_dynamic) {
+ /* Dynamic declarations (whatever they end up being) aren't supported
+ * by this function, but still avoid a crash in release builds. */
+ BLI_assert_unreachable();
+ return;
+ }
- const NodeDeclaration &declaration = *node_type.fixed_declaration;
+ const NodeDeclaration &declaration = *node_type.fixed_declaration;
- search_link_ops_for_declarations(params, declaration.sockets(params.in_out()));
- }
- else if (node_type.inputs && params.in_out() == SOCK_IN) {
- search_link_ops_for_socket_templates(params, node_type.inputs, SOCK_IN);
- }
- else if (node_type.outputs && params.in_out() == SOCK_OUT) {
- search_link_ops_for_socket_templates(params, node_type.outputs, SOCK_OUT);
- }
+ search_link_ops_for_declarations(params, declaration.sockets(params.in_out()));
}
} // namespace blender::nodes
diff --git a/source/blender/nodes/shader/nodes/node_shader_attribute.cc b/source/blender/nodes/shader/nodes/node_shader_attribute.cc
index 77cf6b163d0..4694599f064 100644
--- a/source/blender/nodes/shader/nodes/node_shader_attribute.cc
+++ b/source/blender/nodes/shader/nodes/node_shader_attribute.cc
@@ -42,6 +42,16 @@ static int node_shader_gpu_attribute(GPUMaterial *mat,
if (is_varying) {
cd_attr = GPU_attribute(mat, CD_AUTO_FROM_NAME, attr->name);
+
+ if (STREQ(attr->name, "color")) {
+ GPU_link(mat, "node_attribute_color", cd_attr, &cd_attr);
+ }
+ else if (STREQ(attr->name, "temperature")) {
+ GPU_link(mat, "node_attribute_temperature", cd_attr, &cd_attr);
+ }
+ }
+ else if (attr->type == SHD_ATTRIBUTE_VIEW_LAYER) {
+ cd_attr = GPU_layer_attribute(mat, attr->name);
}
else {
cd_attr = GPU_uniform_attribute(mat,
@@ -52,13 +62,6 @@ static int node_shader_gpu_attribute(GPUMaterial *mat,
GPU_link(mat, "node_attribute_uniform", cd_attr, GPU_constant(&attr_hash), &cd_attr);
}
- if (STREQ(attr->name, "color")) {
- GPU_link(mat, "node_attribute_color", cd_attr, &cd_attr);
- }
- else if (STREQ(attr->name, "temperature")) {
- GPU_link(mat, "node_attribute_temperature", cd_attr, &cd_attr);
- }
-
GPU_stack_link(mat, node, "node_attribute", in, out, cd_attr);
if (is_varying) {
diff --git a/source/blender/nodes/shader/nodes/node_shader_curves.cc b/source/blender/nodes/shader/nodes/node_shader_curves.cc
index 439f2002ebc..c4dbc3ce6f1 100644
--- a/source/blender/nodes/shader/nodes/node_shader_curves.cc
+++ b/source/blender/nodes/shader/nodes/node_shader_curves.cc
@@ -12,7 +12,12 @@ namespace blender::nodes::node_shader_curves_cc {
static void sh_node_curve_vec_declare(NodeDeclarationBuilder &b)
{
b.is_function_node();
- b.add_input<decl::Float>(N_("Fac")).min(0.0f).max(1.0f).default_value(1.0f).subtype(PROP_FACTOR);
+ b.add_input<decl::Float>(N_("Fac"))
+ .no_muted_links()
+ .min(0.0f)
+ .max(1.0f)
+ .default_value(1.0f)
+ .subtype(PROP_FACTOR);
b.add_input<decl::Vector>(N_("Vector")).min(-1.0f).max(1.0f);
b.add_output<decl::Vector>(N_("Vector"));
}
@@ -127,7 +132,12 @@ namespace blender::nodes::node_shader_curves_cc {
static void sh_node_curve_rgb_declare(NodeDeclarationBuilder &b)
{
b.is_function_node();
- b.add_input<decl::Float>(N_("Fac")).min(0.0f).max(1.0f).default_value(1.0f).subtype(PROP_FACTOR);
+ b.add_input<decl::Float>(N_("Fac"))
+ .no_muted_links()
+ .min(0.0f)
+ .max(1.0f)
+ .default_value(1.0f)
+ .subtype(PROP_FACTOR);
b.add_input<decl::Color>(N_("Color")).default_value({1.0f, 1.0f, 1.0f, 1.0f});
b.add_output<decl::Color>(N_("Color"));
}
@@ -270,6 +280,7 @@ static void sh_node_curve_float_declare(NodeDeclarationBuilder &b)
{
b.is_function_node();
b.add_input<decl::Float>(N_("Factor"))
+ .no_muted_links()
.min(0.0f)
.max(1.0f)
.default_value(1.0f)
diff --git a/source/blender/nodes/shader/nodes/node_shader_mix.cc b/source/blender/nodes/shader/nodes/node_shader_mix.cc
index 2efd57155b9..878648105d1 100644
--- a/source/blender/nodes/shader/nodes/node_shader_mix.cc
+++ b/source/blender/nodes/shader/nodes/node_shader_mix.cc
@@ -123,6 +123,19 @@ static void sh_node_mix_update(bNodeTree *ntree, bNode *node)
nodeSetSocketAvailability(ntree, sock_factor_vec, use_vector_factor);
}
+class SocketSearchOp {
+ public:
+ std::string socket_name;
+ int type = MA_RAMP_BLEND;
+ void operator()(LinkSearchOpParams &params)
+ {
+ bNode &node = params.add_node("ShaderNodeMix");
+ node_storage(node).data_type = SOCK_RGBA;
+ node_storage(node).blend_type = type;
+ params.update_and_connect_available_socket(node, socket_name);
+ }
+};
+
static void node_mix_gather_link_searches(GatherLinkSearchOpParams &params)
{
const eNodeSocketDatatype sock_type = static_cast<eNodeSocketDatatype>(
@@ -132,6 +145,17 @@ static void node_mix_gather_link_searches(GatherLinkSearchOpParams &params)
const eNodeSocketDatatype type = ELEM(sock_type, SOCK_BOOLEAN, SOCK_INT) ? SOCK_FLOAT :
sock_type;
+ const int weight = ELEM(params.other_socket().type, SOCK_RGBA) ? 0 : -1;
+ const std::string socket_name = params.in_out() == SOCK_IN ? "A" : "Result";
+ for (const EnumPropertyItem *item = rna_enum_ramp_blend_items; item->identifier != nullptr;
+ item++) {
+ if (item->name != nullptr && item->identifier[0] != '\0') {
+ params.add_item(CTX_IFACE_(BLT_I18NCONTEXT_ID_NODETREE, item->name),
+ SocketSearchOp{socket_name, item->value},
+ weight);
+ }
+ }
+
if (params.in_out() == SOCK_OUT) {
params.add_item(IFACE_("Result"), [type](LinkSearchOpParams &params) {
bNode &node = params.add_node("ShaderNodeMix");
diff --git a/source/blender/nodes/shader/nodes/node_shader_mix_rgb.cc b/source/blender/nodes/shader/nodes/node_shader_mix_rgb.cc
index ef0374e4539..d1578b48c79 100644
--- a/source/blender/nodes/shader/nodes/node_shader_mix_rgb.cc
+++ b/source/blender/nodes/shader/nodes/node_shader_mix_rgb.cc
@@ -150,7 +150,7 @@ void register_node_type_sh_mix_rgb()
static bNodeType ntype;
- sh_fn_node_type_base(&ntype, SH_NODE_MIX_RGB_LEGACY, "Mix", NODE_CLASS_OP_COLOR);
+ sh_fn_node_type_base(&ntype, SH_NODE_MIX_RGB_LEGACY, "Mix (Legacy)", NODE_CLASS_OP_COLOR);
ntype.declare = file_ns::sh_node_mix_rgb_declare;
ntype.labelfunc = node_blend_label;
node_type_gpu(&ntype, file_ns::gpu_shader_mix_rgb);
diff --git a/source/blender/nodes/shader/nodes/node_shader_sepcomb_hsv.cc b/source/blender/nodes/shader/nodes/node_shader_sepcomb_hsv.cc
index 985342ac15d..b297ead1847 100644
--- a/source/blender/nodes/shader/nodes/node_shader_sepcomb_hsv.cc
+++ b/source/blender/nodes/shader/nodes/node_shader_sepcomb_hsv.cc
@@ -36,7 +36,7 @@ void register_node_type_sh_sephsv()
static bNodeType ntype;
- sh_node_type_base(&ntype, SH_NODE_SEPHSV_LEGACY, "Separate HSV", NODE_CLASS_CONVERTER);
+ sh_node_type_base(&ntype, SH_NODE_SEPHSV_LEGACY, "Separate HSV (Legacy)", NODE_CLASS_CONVERTER);
ntype.declare = file_ns::node_declare_sephsv;
node_type_gpu(&ntype, file_ns::gpu_shader_sephsv);
ntype.gather_link_search_ops = nullptr;
@@ -73,7 +73,7 @@ void register_node_type_sh_combhsv()
static bNodeType ntype;
- sh_node_type_base(&ntype, SH_NODE_COMBHSV_LEGACY, "Combine HSV", NODE_CLASS_CONVERTER);
+ sh_node_type_base(&ntype, SH_NODE_COMBHSV_LEGACY, "Combine HSV (Legacy)", NODE_CLASS_CONVERTER);
ntype.declare = file_ns::node_declare_combhsv;
node_type_gpu(&ntype, file_ns::gpu_shader_combhsv);
ntype.gather_link_search_ops = nullptr;
diff --git a/source/blender/nodes/shader/nodes/node_shader_sepcomb_rgb.cc b/source/blender/nodes/shader/nodes/node_shader_sepcomb_rgb.cc
index 07586a54765..c298998cad5 100644
--- a/source/blender/nodes/shader/nodes/node_shader_sepcomb_rgb.cc
+++ b/source/blender/nodes/shader/nodes/node_shader_sepcomb_rgb.cc
@@ -76,7 +76,8 @@ void register_node_type_sh_seprgb()
static bNodeType ntype;
- sh_fn_node_type_base(&ntype, SH_NODE_SEPRGB_LEGACY, "Separate RGB", NODE_CLASS_CONVERTER);
+ sh_fn_node_type_base(
+ &ntype, SH_NODE_SEPRGB_LEGACY, "Separate RGB (Legacy)", NODE_CLASS_CONVERTER);
ntype.declare = file_ns::sh_node_seprgb_declare;
node_type_gpu(&ntype, file_ns::gpu_shader_seprgb);
ntype.build_multi_function = file_ns::sh_node_seprgb_build_multi_function;
@@ -120,7 +121,8 @@ void register_node_type_sh_combrgb()
static bNodeType ntype;
- sh_fn_node_type_base(&ntype, SH_NODE_COMBRGB_LEGACY, "Combine RGB", NODE_CLASS_CONVERTER);
+ sh_fn_node_type_base(
+ &ntype, SH_NODE_COMBRGB_LEGACY, "Combine RGB (Legacy)", NODE_CLASS_CONVERTER);
ntype.declare = file_ns::sh_node_combrgb_declare;
node_type_gpu(&ntype, file_ns::gpu_shader_combrgb);
ntype.build_multi_function = file_ns::sh_node_combrgb_build_multi_function;
diff --git a/source/blender/nodes/texture/nodes/node_texture_compose.c b/source/blender/nodes/texture/nodes/node_texture_compose.c
index ef14062c72d..e36bc248ed1 100644
--- a/source/blender/nodes/texture/nodes/node_texture_compose.c
+++ b/source/blender/nodes/texture/nodes/node_texture_compose.c
@@ -42,7 +42,8 @@ void register_node_type_tex_compose(void)
{
static bNodeType ntype;
- tex_node_type_base(&ntype, TEX_NODE_COMPOSE_LEGACY, "Combine RGBA", NODE_CLASS_OP_COLOR);
+ tex_node_type_base(
+ &ntype, TEX_NODE_COMPOSE_LEGACY, "Combine RGBA (Legacy)", NODE_CLASS_OP_COLOR);
node_type_socket_templates(&ntype, inputs, outputs);
node_type_exec(&ntype, NULL, NULL, exec);
diff --git a/source/blender/python/intern/bpy.c b/source/blender/python/intern/bpy.c
index 77710d6df37..36d53d69eff 100644
--- a/source/blender/python/intern/bpy.c
+++ b/source/blender/python/intern/bpy.c
@@ -29,6 +29,8 @@
#include "GPU_state.h"
+#include "WM_api.h" /* For #WM_ghost_backend */
+
#include "bpy.h"
#include "bpy_app.h"
#include "bpy_capi_utils.h"
@@ -536,6 +538,17 @@ static PyObject *bpy_rna_enum_items_static(PyObject *UNUSED(self))
return result;
}
+/* This is only exposed for (Unix/Linux), see: #GHOST_ISystem::getSystemBackend for details. */
+PyDoc_STRVAR(bpy_ghost_backend_doc,
+ ".. function:: _ghost_backend()\n"
+ "\n"
+ " :return: An identifier for the GHOST back-end.\n"
+ " :rtype: string\n");
+static PyObject *bpy_ghost_backend(PyObject *UNUSED(self))
+{
+ return PyUnicode_FromString(WM_ghost_backend());
+}
+
static PyMethodDef bpy_methods[] = {
{"script_paths", (PyCFunction)bpy_script_paths, METH_NOARGS, bpy_script_paths_doc},
{"blend_paths",
@@ -552,10 +565,6 @@ static PyMethodDef bpy_methods[] = {
(PyCFunction)bpy_resource_path,
METH_VARARGS | METH_KEYWORDS,
bpy_resource_path_doc},
- {"_driver_secure_code_test",
- (PyCFunction)bpy_driver_secure_code_test,
- METH_VARARGS | METH_KEYWORDS,
- bpy_driver_secure_code_test_doc},
{"escape_identifier", (PyCFunction)bpy_escape_identifier, METH_O, bpy_escape_identifier_doc},
{"unescape_identifier",
(PyCFunction)bpy_unescape_identifier,
@@ -566,6 +575,14 @@ static PyMethodDef bpy_methods[] = {
(PyCFunction)bpy_rna_enum_items_static,
METH_NOARGS,
bpy_rna_enum_items_static_doc},
+
+ /* Private functions (not part of the public API and may be removed at any time). */
+ {"_driver_secure_code_test",
+ (PyCFunction)bpy_driver_secure_code_test,
+ METH_VARARGS | METH_KEYWORDS,
+ bpy_driver_secure_code_test_doc},
+ {"_ghost_backend", (PyCFunction)bpy_ghost_backend, METH_NOARGS, bpy_ghost_backend_doc},
+
{NULL, NULL, 0, NULL},
};
diff --git a/source/blender/render/intern/bake.c b/source/blender/render/intern/bake.c
index 59719fb4590..8fd62f7ec34 100644
--- a/source/blender/render/intern/bake.c
+++ b/source/blender/render/intern/bake.c
@@ -590,7 +590,7 @@ bool RE_bake_pixels_populate_from_objects(struct Mesh *me_low,
me_highpoly[i] = highpoly[i].me;
BKE_mesh_runtime_looptri_ensure(me_highpoly[i]);
- if (me_highpoly[i]->runtime.looptris.len != 0) {
+ if (BKE_mesh_runtime_looptri_len(me_highpoly[i]) != 0) {
/* Create a BVH-tree for each `highpoly` object. */
BKE_bvhtree_from_mesh_get(&treeData[i], me_highpoly[i], BVHTREE_FROM_LOOPTRI, 2);
diff --git a/source/blender/render/intern/texture_margin.cc b/source/blender/render/intern/texture_margin.cc
index a42ddb6b830..3366111ed33 100644
--- a/source/blender/render/intern/texture_margin.cc
+++ b/source/blender/render/intern/texture_margin.cc
@@ -290,8 +290,8 @@ class TextureMarginMap {
void build_tables()
{
- loop_to_poly_map_ = blender::mesh_topology::build_loop_to_poly_map({mpoly_, totpoly_},
- totloop_);
+ loop_to_poly_map_ = blender::bke::mesh_topology::build_loop_to_poly_map({mpoly_, totpoly_},
+ totloop_);
loop_adjacency_map_.resize(totloop_, -1);
diff --git a/source/blender/simulation/intern/hair_volume.cpp b/source/blender/simulation/intern/hair_volume.cpp
index cb6c963b7d2..97042f433c2 100644
--- a/source/blender/simulation/intern/hair_volume.cpp
+++ b/source/blender/simulation/intern/hair_volume.cpp
@@ -618,17 +618,17 @@ BLI_INLINE void hair_volume_eval_grid_vertex_sample(HairGridVert *vert,
}
void SIM_hair_volume_add_segment(HairGrid *grid,
- const float UNUSED(x1[3]),
- const float UNUSED(v1[3]),
+ const float /*x1*/[3],
+ const float /*v1*/[3],
const float x2[3],
const float v2[3],
const float x3[3],
const float v3[3],
- const float UNUSED(x4[3]),
- const float UNUSED(v4[3]),
- const float UNUSED(dir1[3]),
- const float UNUSED(dir2[3]),
- const float UNUSED(dir3[3]))
+ const float /*x4*/[3],
+ const float /*v4*/[3],
+ const float /*dir1*/[3],
+ const float /*dir2*/[3],
+ const float /*dir3*/[3])
{
/* XXX simplified test implementation using a series of discrete sample along the segment,
* instead of finding the closest point for all affected grid vertices. */
diff --git a/source/blender/windowmanager/WM_api.h b/source/blender/windowmanager/WM_api.h
index 5b6f7939ab9..1f9de8040f6 100644
--- a/source/blender/windowmanager/WM_api.h
+++ b/source/blender/windowmanager/WM_api.h
@@ -119,6 +119,13 @@ void WM_init_splash(struct bContext *C);
void WM_init_opengl(void);
+/**
+ * Return an identifier for the underlying GHOST implementation.
+ * \warning Use of this function should be limited & never for compatibility checks.
+ * see: #GHOST_ISystem::getSystemBackend for details.
+ */
+const char *WM_ghost_backend(void);
+
void WM_check(struct bContext *C);
void WM_reinit_gizmomap_all(struct Main *bmain);
diff --git a/source/blender/windowmanager/intern/wm_operators.c b/source/blender/windowmanager/intern/wm_operators.c
index 58791dbd00a..fa89e7a4caa 100644
--- a/source/blender/windowmanager/intern/wm_operators.c
+++ b/source/blender/windowmanager/intern/wm_operators.c
@@ -107,19 +107,32 @@
/** \name Operator API
* \{ */
+#define OP_BL_SEP_STRING "_OT_"
+#define OP_BL_SEP_LEN 4
+
+#define OP_PY_SEP_CHAR '.'
+#define OP_PY_SEP_LEN 1
+
+/* Difference between python 'identifier' and BL/C code one ("." separator replaced by "_OT_"),
+ * and final `\0` char. */
+#define OP_MAX_PY_IDNAME (OP_MAX_TYPENAME - OP_BL_SEP_LEN + OP_PY_SEP_LEN - 1)
+
size_t WM_operator_py_idname(char *dst, const char *src)
{
- const char *sep = strstr(src, "_OT_");
+ const char *sep = strstr(src, OP_BL_SEP_STRING);
if (sep) {
- int ofs = (sep - src);
+ const size_t sep_offset = (size_t)(sep - src);
/* NOTE: we use ascii `tolower` instead of system `tolower`, because the
* latter depends on the locale, and can lead to `idname` mismatch. */
- memcpy(dst, src, sizeof(char) * ofs);
- BLI_str_tolower_ascii(dst, ofs);
+ memcpy(dst, src, sep_offset);
+ BLI_str_tolower_ascii(dst, sep_offset);
- dst[ofs] = '.';
- return BLI_strncpy_rlen(dst + (ofs + 1), sep + 4, OP_MAX_TYPENAME - (ofs + 1)) + (ofs + 1);
+ dst[sep_offset] = OP_PY_SEP_CHAR;
+ return BLI_strncpy_rlen(dst + (sep_offset + OP_PY_SEP_LEN),
+ sep + OP_BL_SEP_LEN,
+ OP_MAX_TYPENAME - sep_offset - OP_PY_SEP_LEN) +
+ (sep_offset + OP_PY_SEP_LEN);
}
/* Should not happen but support just in case. */
return BLI_strncpy_rlen(dst, src, OP_MAX_TYPENAME);
@@ -127,15 +140,19 @@ size_t WM_operator_py_idname(char *dst, const char *src)
size_t WM_operator_bl_idname(char *dst, const char *src)
{
- const char *sep = strchr(src, '.');
- int from_len;
- if (sep && (from_len = strlen(src)) < OP_MAX_TYPENAME - 3) {
- const int ofs = (sep - src);
- memcpy(dst, src, sizeof(char) * ofs);
- BLI_str_toupper_ascii(dst, ofs);
- memcpy(dst + ofs, "_OT_", 4);
- memcpy(dst + (ofs + 4), sep + 1, (from_len - ofs));
- return (from_len - ofs) - 1;
+ const size_t from_len = (size_t)strlen(src);
+
+ const char *sep = strchr(src, OP_PY_SEP_CHAR);
+ if (sep && (from_len <= OP_MAX_PY_IDNAME)) {
+ const size_t sep_offset = (size_t)(sep - src);
+ memcpy(dst, src, sep_offset);
+ BLI_str_toupper_ascii(dst, sep_offset);
+
+ memcpy(dst + sep_offset, OP_BL_SEP_STRING, OP_BL_SEP_LEN);
+ BLI_strncpy(dst + sep_offset + OP_BL_SEP_LEN,
+ sep + OP_PY_SEP_LEN,
+ from_len - sep_offset - OP_PY_SEP_LEN + 1);
+ return from_len + OP_BL_SEP_LEN - OP_PY_SEP_LEN;
}
/* Should not happen but support just in case. */
return BLI_strncpy_rlen(dst, src, OP_MAX_TYPENAME);
@@ -166,14 +183,14 @@ bool WM_operator_py_idname_ok_or_report(ReportList *reports,
}
}
- if (i > (MAX_NAME - 3)) {
+ if (i > OP_MAX_PY_IDNAME) {
BKE_reportf(reports,
RPT_ERROR,
"Registering operator class: '%s', invalid bl_idname '%s', "
"is too long, maximum length is %d",
classname,
idname,
- MAX_NAME - 3);
+ OP_MAX_PY_IDNAME);
return false;
}
diff --git a/source/blender/windowmanager/intern/wm_window.c b/source/blender/windowmanager/intern/wm_window.c
index a4f92da2774..b1b13390932 100644
--- a/source/blender/windowmanager/intern/wm_window.c
+++ b/source/blender/windowmanager/intern/wm_window.c
@@ -91,6 +91,9 @@
/* the global to talk to ghost */
static GHOST_SystemHandle g_system = NULL;
+#if !(defined(WIN32) || defined(__APPLE__))
+static const char *g_system_backend_id = NULL;
+#endif
typedef enum eWinOverrideFlag {
WIN_OVERRIDE_GEOM = (1 << 0),
@@ -1552,6 +1555,9 @@ void wm_ghost_init(bContext *C)
/* This will leak memory, it's preferable to crashing. */
exit(1);
}
+#if !(defined(WIN32) || defined(__APPLE__))
+ g_system_backend_id = GHOST_SystemBackend();
+#endif
GHOST_Debug debug = {0};
if (G.debug & G_DEBUG_GHOST) {
@@ -1597,6 +1603,18 @@ void wm_ghost_exit(void)
g_system = NULL;
}
+const char *WM_ghost_backend(void)
+{
+#if !(defined(WIN32) || defined(__APPLE__))
+ return g_system_backend_id ? g_system_backend_id : "NONE";
+#else
+ /* While this could be supported, at the moment it's only needed with GHOST X11/WAYLAND
+ * to check which was selected and the API call may be removed after that's no longer needed.
+ * Use dummy values to prevent this being used on other systems. */
+ return g_system ? "DEFAULT" : "NONE";
+#endif
+}
+
/** \} */
/* -------------------------------------------------------------------- */
diff --git a/source/creator/creator_signals.c b/source/creator/creator_signals.c
index c016372e6b0..f67c4dde41d 100644
--- a/source/creator/creator_signals.c
+++ b/source/creator/creator_signals.c
@@ -66,7 +66,6 @@ static void sig_handle_fpe(int UNUSED(sig))
# endif
/* Handling `Ctrl-C` event in the console. */
-# if !defined(WITH_HEADLESS)
static void sig_handle_blender_esc(int sig)
{
G.is_break = true; /* forces render loop to read queue, not sure if its needed */
@@ -81,7 +80,6 @@ static void sig_handle_blender_esc(int sig)
count++;
}
}
-# endif
static void sig_handle_crash_backtrace(FILE *fp)
{
diff --git a/tests/python/CMakeLists.txt b/tests/python/CMakeLists.txt
index fe00cce2572..b3decc06161 100644
--- a/tests/python/CMakeLists.txt
+++ b/tests/python/CMakeLists.txt
@@ -630,6 +630,24 @@ add_blender_test(
)
endif()
+# SVG Import
+if(True)
+ set(_svg_render_tests path)
+
+ foreach(render_test ${_svg_render_tests})
+ add_python_test(
+ io_curve_svg_${render_test}
+ ${CMAKE_CURRENT_LIST_DIR}/bl_io_curve_svg_test.py
+ -blender "${TEST_BLENDER_EXE}"
+ -testdir "${TEST_SRC_DIR}/io_tests/svg/${render_test}"
+ -idiff "${OPENIMAGEIO_IDIFF}"
+ -outdir "${TEST_OUT_DIR}/io_curve_svg"
+ )
+ endforeach()
+
+ unset(_svg_render_tests)
+endif()
+
if(WITH_CYCLES OR WITH_OPENGL_RENDER_TESTS)
if(NOT OPENIMAGEIO_IDIFF)
message(WARNING "Disabling render tests because OIIO idiff does not exist")
diff --git a/tests/python/bl_io_curve_svg_test.py b/tests/python/bl_io_curve_svg_test.py
new file mode 100644
index 00000000000..092dfa5497a
--- /dev/null
+++ b/tests/python/bl_io_curve_svg_test.py
@@ -0,0 +1,61 @@
+#!/usr/bin/env python3
+# SPDX-License-Identifier: Apache-2.0
+
+import argparse
+import os
+import sys
+from pathlib import Path
+
+
+def get_arguments(filepath, output_filepath):
+ dirname = os.path.dirname(filepath)
+ basedir = os.path.dirname(dirname)
+
+ args = [
+ "--background",
+ "-noaudio",
+ "--factory-startup",
+ "--enable-autoexec",
+ "--debug-memory",
+ "--debug-exit-on-error",
+ filepath,
+ "-E", "CYCLES",
+ "-o", output_filepath,
+ "-F", "PNG",
+ "--python", os.path.join(basedir, "util", "import_svg.py"),
+ "-f", "1",
+ ]
+
+ return args
+
+
+def create_argparse():
+ parser = argparse.ArgumentParser()
+ parser.add_argument("-blender", nargs="+")
+ parser.add_argument("-testdir", nargs=1)
+ parser.add_argument("-outdir", nargs=1)
+ parser.add_argument("-idiff", nargs=1)
+ return parser
+
+
+def main():
+ parser = create_argparse()
+ args = parser.parse_args()
+
+ blender = args.blender[0]
+ test_dir = args.testdir[0]
+ idiff = args.idiff[0]
+ output_dir = args.outdir[0]
+
+ from modules import render_report
+ report = render_report.Report('IO Curve SVG', output_dir, idiff)
+ report.set_pixelated(True)
+ print(test_dir)
+
+ ok = report.run(test_dir, blender, get_arguments, batch=True)
+
+ sys.exit(not ok)
+
+
+if __name__ == "__main__":
+ main()
diff --git a/tests/python/cycles_render_tests.py b/tests/python/cycles_render_tests.py
index 4f823f854bf..c7e12dd5b7c 100644
--- a/tests/python/cycles_render_tests.py
+++ b/tests/python/cycles_render_tests.py
@@ -33,7 +33,7 @@ BLACKLIST_OPTIX = [
]
BLACKLIST_METAL = [
- # No MNEE for Metal currently
+ # MNEE only works on Metal with macOS >= 13
"underwater_caustics.blend",
]