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:
authorHoward Trickey <howard.trickey@gmail.com>2022-10-24 20:33:11 +0300
committerHoward Trickey <howard.trickey@gmail.com>2022-10-24 20:33:11 +0300
commita41a1bfc494e4015406549e137114ef5a450aaf0 (patch)
treedbdc95584f91aded4b777bac30074f9f78d8c89c
parentfc8f9e420426570dcb3e026ecbe8145cd0fae5ca (diff)
parent53795877727d67185de858a480c8090ca7eb8e36 (diff)
Merge branch 'master' into bevelv2
-rw-r--r--CMakeLists.txt31
-rw-r--r--build_files/build_environment/CMakeLists.txt4
-rw-r--r--build_files/build_environment/cmake/aom.cmake6
-rw-r--r--build_files/build_environment/cmake/cve_check.cmake75
-rw-r--r--build_files/build_environment/cmake/cve_check.csv.in23
-rw-r--r--build_files/build_environment/cmake/download.cmake3
-rw-r--r--build_files/build_environment/cmake/ffmpeg.cmake6
-rw-r--r--build_files/build_environment/cmake/freetype.cmake4
-rw-r--r--build_files/build_environment/cmake/gmp.cmake1
-rw-r--r--build_files/build_environment/cmake/llvm.cmake1
-rw-r--r--build_files/build_environment/cmake/opencollada.cmake33
-rw-r--r--build_files/build_environment/cmake/openpgl.cmake4
-rw-r--r--build_files/build_environment/cmake/options.cmake37
-rw-r--r--build_files/build_environment/cmake/osl.cmake3
-rw-r--r--build_files/build_environment/cmake/png.cmake8
-rw-r--r--build_files/build_environment/cmake/python.cmake17
-rw-r--r--build_files/build_environment/cmake/sndfile.cmake7
-rw-r--r--build_files/build_environment/cmake/sqlite.cmake1
-rw-r--r--build_files/build_environment/cmake/ssl.cmake1
-rw-r--r--build_files/build_environment/cmake/tiff.cmake1
-rw-r--r--build_files/build_environment/cmake/versions.cmake206
-rw-r--r--build_files/build_environment/cmake/wayland.cmake8
-rw-r--r--build_files/build_environment/cmake/wayland_protocols.cmake9
-rw-r--r--build_files/build_environment/cmake/xml2.cmake64
-rw-r--r--build_files/build_environment/dependencies.dot120
-rwxr-xr-xbuild_files/build_environment/install_deps.sh28
-rw-r--r--build_files/build_environment/linux/linux-centos7-setup.sh89
-rw-r--r--build_files/build_environment/patches/aom.diff18
-rw-r--r--build_files/build_environment/patches/ffmpeg.diff40
-rw-r--r--build_files/build_environment/patches/gmp.diff15
-rw-r--r--build_files/build_environment/patches/opencollada.diff25
-rw-r--r--build_files/build_environment/patches/osl.diff135
-rw-r--r--build_files/build_environment/patches/python_windows.diff24
-rw-r--r--build_files/build_environment/patches/sndfile.diff42
-rw-r--r--build_files/build_environment/patches/sqlite.diff14
-rw-r--r--build_files/build_environment/patches/ssl.diff10
-rw-r--r--build_files/cmake/Modules/FindOSL.cmake15
-rw-r--r--build_files/cmake/Modules/FindOpenSubdiv.cmake15
-rw-r--r--build_files/cmake/Modules/FindSYCL.cmake41
-rw-r--r--build_files/cmake/config/blender_full.cmake4
-rw-r--r--build_files/cmake/config/blender_release.cmake4
-rw-r--r--build_files/cmake/macros.cmake18
-rw-r--r--build_files/cmake/platform/platform_apple.cmake102
-rw-r--r--build_files/cmake/platform/platform_unix.cmake251
-rw-r--r--build_files/cmake/platform/platform_win32.cmake92
-rw-r--r--build_files/windows/svn_update.cmd24
-rw-r--r--doc/python_api/requirements.txt4
-rw-r--r--intern/cycles/CMakeLists.txt6
-rw-r--r--intern/cycles/app/CMakeLists.txt5
-rw-r--r--intern/cycles/blender/addon/engine.py15
-rw-r--r--intern/cycles/blender/addon/properties.py1
-rw-r--r--intern/cycles/blender/pointcloud.cpp4
-rw-r--r--intern/cycles/blender/shader.cpp4
-rw-r--r--intern/cycles/blender/sync.cpp206
-rw-r--r--intern/cycles/cmake/external_libs.cmake56
-rw-r--r--intern/cycles/device/CMakeLists.txt22
-rw-r--r--intern/cycles/device/cuda/queue.cpp2
-rw-r--r--intern/cycles/device/cuda/queue.h2
-rw-r--r--intern/cycles/device/hip/queue.cpp2
-rw-r--r--intern/cycles/device/hip/queue.h2
-rw-r--r--intern/cycles/device/metal/device_impl.mm14
-rw-r--r--intern/cycles/device/metal/kernel.mm13
-rw-r--r--intern/cycles/device/metal/queue.h2
-rw-r--r--intern/cycles/device/metal/queue.mm51
-rw-r--r--intern/cycles/device/metal/util.mm6
-rw-r--r--intern/cycles/device/oneapi/device.cpp4
-rw-r--r--intern/cycles/device/oneapi/device_impl.cpp72
-rw-r--r--intern/cycles/device/oneapi/device_impl.h4
-rw-r--r--intern/cycles/device/oneapi/queue.cpp2
-rw-r--r--intern/cycles/device/oneapi/queue.h2
-rw-r--r--intern/cycles/device/queue.h2
-rw-r--r--intern/cycles/integrator/path_trace.cpp8
-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/path_trace_work_gpu.cpp31
-rw-r--r--intern/cycles/integrator/work_balancer.cpp3
-rw-r--r--intern/cycles/kernel/CMakeLists.txt47
-rw-r--r--intern/cycles/kernel/bvh/shadow_all.h2
-rw-r--r--intern/cycles/kernel/bvh/util.h8
-rw-r--r--intern/cycles/kernel/device/cpu/bvh.h2
-rw-r--r--intern/cycles/kernel/device/gpu/parallel_active_index.h33
-rw-r--r--intern/cycles/kernel/device/metal/context_begin.h37
-rw-r--r--intern/cycles/kernel/device/metal/kernel.metal2
-rw-r--r--intern/cycles/kernel/device/oneapi/compat.h45
-rw-r--r--intern/cycles/kernel/device/oneapi/globals.h9
-rw-r--r--intern/cycles/kernel/device/oneapi/kernel.cpp118
-rw-r--r--intern/cycles/kernel/device/oneapi/kernel.h2
-rw-r--r--intern/cycles/kernel/device/optix/bvh.h2
-rw-r--r--intern/cycles/kernel/integrator/mnee.h10
-rw-r--r--intern/cycles/kernel/integrator/state_flow.h6
-rw-r--r--intern/cycles/kernel/sample/pattern.h2
-rw-r--r--intern/cycles/kernel/types.h6
-rw-r--r--intern/cycles/scene/image_oiio.cpp18
-rw-r--r--intern/cycles/session/session.cpp4
-rw-r--r--intern/cycles/util/math.h10
-rw-r--r--intern/cycles/util/math_float3.h12
-rw-r--r--intern/cycles/util/ssef.h25
-rw-r--r--intern/ffmpeg/tests/ffmpeg_codecs.cc7
-rw-r--r--intern/ghost/CMakeLists.txt47
-rw-r--r--intern/ghost/GHOST_C-api.h6
-rw-r--r--intern/ghost/GHOST_ISystem.h16
-rw-r--r--intern/ghost/GHOST_Types.h14
-rw-r--r--intern/ghost/intern/GHOST_C-api.cpp11
-rw-r--r--intern/ghost/intern/GHOST_ContextCGL.h3
-rw-r--r--intern/ghost/intern/GHOST_ContextCGL.mm4
-rw-r--r--intern/ghost/intern/GHOST_ContextGLX.cpp2
-rw-r--r--intern/ghost/intern/GHOST_Debug.h34
-rw-r--r--intern/ghost/intern/GHOST_ISystem.cpp27
-rw-r--r--intern/ghost/intern/GHOST_NDOFManager.cpp571
-rw-r--r--intern/ghost/intern/GHOST_NDOFManager.h56
-rw-r--r--intern/ghost/intern/GHOST_NDOFManagerUnix.cpp16
-rw-r--r--intern/ghost/intern/GHOST_NDOFManagerUnix.h2
-rw-r--r--intern/ghost/intern/GHOST_System.cpp2
-rw-r--r--intern/ghost/intern/GHOST_SystemCocoa.h2
-rw-r--r--intern/ghost/intern/GHOST_SystemCocoa.mm5
-rw-r--r--intern/ghost/intern/GHOST_SystemHeadless.h3
-rw-r--r--intern/ghost/intern/GHOST_SystemSDL.cpp3
-rw-r--r--intern/ghost/intern/GHOST_SystemSDL.h1
-rw-r--r--intern/ghost/intern/GHOST_SystemWayland.cpp1947
-rw-r--r--intern/ghost/intern/GHOST_SystemWayland.h47
-rw-r--r--intern/ghost/intern/GHOST_SystemWin32.cpp3
-rw-r--r--intern/ghost/intern/GHOST_SystemWin32.h2
-rw-r--r--intern/ghost/intern/GHOST_SystemX11.cpp8
-rw-r--r--intern/ghost/intern/GHOST_SystemX11.h2
-rw-r--r--intern/ghost/intern/GHOST_WindowCocoa.mm4
-rw-r--r--intern/ghost/intern/GHOST_WindowWayland.cpp494
-rw-r--r--intern/ghost/intern/GHOST_WindowWayland.h6
-rw-r--r--intern/ghost/test/gears/GHOST_Test.cpp21
-rw-r--r--intern/guardedalloc/intern/mallocn.c2
-rw-r--r--intern/guardedalloc/intern/mallocn_lockfree_impl.c10
-rw-r--r--intern/mantaflow/intern/MANTA_main.cpp40
-rw-r--r--intern/mikktspace/mikktspace.hh7
-rw-r--r--intern/opensubdiv/CMakeLists.txt6
-rw-r--r--intern/wayland_dynload/extern/wayland_dynload_client.h1
-rw-r--r--intern/wayland_dynload/intern/wayland_dynload_egl.c2
-rw-r--r--make.bat10
-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/gpu_extras/batch.py4
-rw-r--r--release/scripts/modules/sys_info.py8
-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_data_curves.py8
-rw-r--r--release/scripts/startup/bl_ui/properties_output.py16
-rw-r--r--release/scripts/startup/bl_ui/properties_paint_common.py72
-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.py89
-rw-r--r--release/scripts/startup/bl_ui/space_view3d_toolbar.py65
-rw-r--r--source/blender/blenfont/intern/blf.c8
-rw-r--r--source/blender/blenfont/intern/blf_dir.c2
-rw-r--r--source/blender/blenfont/intern/blf_font_default.c2
-rw-r--r--source/blender/blenkernel/BKE_attribute.hh2
-rw-r--r--source/blender/blenkernel/BKE_blender_version.h2
-rw-r--r--source/blender/blenkernel/BKE_brush.h21
-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_editmesh_cache.h20
-rw-r--r--source/blender/blenkernel/BKE_geometry_fields.hh13
-rw-r--r--source/blender/blenkernel/BKE_geometry_set.hh251
-rw-r--r--source/blender/blenkernel/BKE_instances.hh270
-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_node.h6
-rw-r--r--source/blender/blenkernel/BKE_paint.h14
-rw-r--r--source/blender/blenkernel/BKE_pbvh.h15
-rw-r--r--source/blender/blenkernel/BKE_writeffmpeg.h2
-rw-r--r--source/blender/blenkernel/CMakeLists.txt2
-rw-r--r--source/blender/blenkernel/intern/DerivedMesh.cc38
-rw-r--r--source/blender/blenkernel/intern/appdir.c30
-rw-r--r--source/blender/blenkernel/intern/asset_catalog.cc11
-rw-r--r--source/blender/blenkernel/intern/asset_catalog_test.cc76
-rw-r--r--source/blender/blenkernel/intern/asset_library_service_test.cc7
-rw-r--r--source/blender/blenkernel/intern/attribute_access.cc17
-rw-r--r--source/blender/blenkernel/intern/blender_undo.c2
-rw-r--r--source/blender/blenkernel/intern/blendfile.c4
-rw-r--r--source/blender/blenkernel/intern/blendfile_link_append.c6
-rw-r--r--source/blender/blenkernel/intern/bpath.c4
-rw-r--r--source/blender/blenkernel/intern/brush.cc22
-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/curve_to_mesh_convert.cc10
-rw-r--r--source/blender/blenkernel/intern/curves.cc5
-rw-r--r--source/blender/blenkernel/intern/curves_geometry.cc22
-rw-r--r--source/blender/blenkernel/intern/customdata.cc48
-rw-r--r--source/blender/blenkernel/intern/editmesh.cc8
-rw-r--r--source/blender/blenkernel/intern/fluid.c15
-rw-r--r--source/blender/blenkernel/intern/geometry_component_instances.cc385
-rw-r--r--source/blender/blenkernel/intern/geometry_fields.cc16
-rw-r--r--source/blender/blenkernel/intern/geometry_set.cc63
-rw-r--r--source/blender/blenkernel/intern/geometry_set_instances.cc45
-rw-r--r--source/blender/blenkernel/intern/gpencil_geom.cc4
-rw-r--r--source/blender/blenkernel/intern/image.cc27
-rw-r--r--source/blender/blenkernel/intern/image_format.cc7
-rw-r--r--source/blender/blenkernel/intern/image_save.cc6
-rw-r--r--source/blender/blenkernel/intern/instances.cc337
-rw-r--r--source/blender/blenkernel/intern/layer.c2
-rw-r--r--source/blender/blenkernel/intern/lib_id_delete.c70
-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.cc12
-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.cc8
-rw-r--r--source/blender/blenkernel/intern/multires.cc2
-rw-r--r--source/blender/blenkernel/intern/nla.c30
-rw-r--r--source/blender/blenkernel/intern/node.cc44
-rw-r--r--source/blender/blenkernel/intern/object.cc11
-rw-r--r--source/blender/blenkernel/intern/object_dupli.cc21
-rw-r--r--source/blender/blenkernel/intern/object_update.cc6
-rw-r--r--source/blender/blenkernel/intern/ocean.c2
-rw-r--r--source/blender/blenkernel/intern/packedFile.c2
-rw-r--r--source/blender/blenkernel/intern/paint.cc36
-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.c212
-rw-r--r--source/blender/blenkernel/intern/pbvh_bmesh.c105
-rw-r--r--source/blender/blenkernel/intern/pbvh_intern.h5
-rw-r--r--source/blender/blenkernel/intern/pointcache.c6
-rw-r--r--source/blender/blenkernel/intern/pointcloud.cc6
-rw-r--r--source/blender/blenkernel/intern/preferences.c3
-rw-r--r--source/blender/blenkernel/intern/rigidbody.c6
-rw-r--r--source/blender/blenkernel/intern/scene.cc5
-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/blenkernel/intern/volume.cc4
-rw-r--r--source/blender/blenkernel/intern/writeavi.c3
-rw-r--r--source/blender/blenkernel/intern/writeffmpeg.c236
-rw-r--r--source/blender/blenlib/BLI_array_utils.hh5
-rw-r--r--source/blender/blenlib/BLI_path_util.h106
-rw-r--r--source/blender/blenlib/BLI_string.h22
-rw-r--r--source/blender/blenlib/intern/BLI_filelist.c2
-rw-r--r--source/blender/blenlib/intern/array_utils.cc5
-rw-r--r--source/blender/blenlib/intern/fileops.c4
-rw-r--r--source/blender/blenlib/intern/path_util.c60
-rw-r--r--source/blender/blenlib/intern/string.c30
-rw-r--r--source/blender/blenlib/tests/BLI_path_util_test.cc2
-rw-r--r--source/blender/blenlib/tests/BLI_string_test.cc97
-rw-r--r--source/blender/blenloader/BLO_readfile.h5
-rw-r--r--source/blender/blenloader/CMakeLists.txt2
-rw-r--r--source/blender/blenloader/intern/blend_validate.cc4
-rw-r--r--source/blender/blenloader/intern/readblenentry.cc15
-rw-r--r--source/blender/blenloader/intern/versioning_250.c4
-rw-r--r--source/blender/blenloader/intern/versioning_280.c2
-rw-r--r--source/blender/blenloader/intern/versioning_300.cc37
-rw-r--r--source/blender/blenloader/intern/versioning_defaults.cc (renamed from source/blender/blenloader/intern/versioning_defaults.c)132
-rw-r--r--source/blender/blenloader/tests/blendfile_loading_base_test.cc2
-rw-r--r--source/blender/blentranslation/intern/blt_lang.c2
-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/intern/COM_Debug.cc2
-rw-r--r--source/blender/compositor/nodes/COM_CryptomatteNode.cc3
-rw-r--r--source/blender/compositor/nodes/COM_OutputFileNode.cc2
-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.hh103
-rw-r--r--source/blender/compositor/realtime_compositor/algorithms/intern/algorithm_parallel_reduction.cc309
-rw-r--r--source/blender/depsgraph/intern/builder/deg_builder_nodes.cc5
-rw-r--r--source/blender/draw/CMakeLists.txt20
-rw-r--r--source/blender/draw/engines/eevee/eevee_materials.c13
-rw-r--r--source/blender/draw/engines/eevee/shaders/cubemap_lib.glsl4
-rw-r--r--source/blender/draw/engines/eevee/shaders/effect_dof_scatter_vert.glsl6
-rw-r--r--source/blender/draw/engines/eevee_next/eevee_shader_shared.hh2
-rw-r--r--source/blender/draw/engines/eevee_next/eevee_sync.cc6
-rw-r--r--source/blender/draw/engines/eevee_next/shaders/eevee_geom_gpencil_vert.glsl36
-rw-r--r--source/blender/draw/engines/eevee_next/shaders/infos/eevee_material_info.hh8
-rw-r--r--source/blender/draw/engines/gpencil/gpencil_engine.c58
-rw-r--r--source/blender/draw/engines/gpencil/gpencil_shader_shared.h3
-rw-r--r--source/blender/draw/engines/gpencil/shaders/gpencil_common_lib.glsl595
-rw-r--r--source/blender/draw/engines/gpencil/shaders/gpencil_vert.glsl21
-rw-r--r--source/blender/draw/engines/gpencil/shaders/infos/gpencil_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/overlay/overlay_outline.cc22
-rw-r--r--source/blender/draw/engines/overlay/overlay_particle.cc4
-rw-r--r--source/blender/draw/engines/overlay/shaders/overlay_motion_path_line_vert_no_geom.glsl12
-rw-r--r--source/blender/draw/engines/overlay/shaders/overlay_outline_prepass_gpencil_vert.glsl15
-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.h12
-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_gpencil.cc (renamed from source/blender/draw/intern/draw_cache_impl_gpencil.c)265
-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_curves.cc5
-rw-r--r--source/blender/draw/intern/draw_debug.cc2
-rw-r--r--source/blender/draw/intern/draw_hair.cc5
-rw-r--r--source/blender/draw/intern/draw_manager.c21
-rw-r--r--source/blender/draw/intern/draw_manager.h2
-rw-r--r--source/blender/draw/intern/draw_manager_data.cc43
-rw-r--r--source/blender/draw/intern/draw_manager_shader.c2
-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_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/common_gpencil_lib.glsl88
-rw-r--r--source/blender/draw/intern/shaders/draw_view_info.hh17
-rw-r--r--source/blender/editors/armature/pose_transform.c4
-rw-r--r--source/blender/editors/asset/intern/asset_list.cc2
-rw-r--r--source/blender/editors/asset/intern/asset_ops.cc2
-rw-r--r--source/blender/editors/gpencil/annotate_paint.c3
-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.h25
-rw-r--r--source/blender/editors/include/UI_interface.h4
-rw-r--r--source/blender/editors/include/UI_interface.hh1
-rw-r--r--source/blender/editors/include/UI_interface_icons.h12
-rw-r--r--source/blender/editors/include/UI_view2d.h2
-rw-r--r--source/blender/editors/interface/interface.cc5
-rw-r--r--source/blender/editors/interface/interface_context_path.cc14
-rw-r--r--source/blender/editors/interface/interface_dropboxes.cc2
-rw-r--r--source/blender/editors/interface/interface_icons.c121
-rw-r--r--source/blender/editors/interface/interface_intern.h4
-rw-r--r--source/blender/editors/interface/interface_layout.c4
-rw-r--r--source/blender/editors/interface/interface_ops.cc4
-rw-r--r--source/blender/editors/interface/interface_panel.cc6
-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/interface/interface_widgets.c15
-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_gpencil_import.c2
-rw-r--r--source/blender/editors/io/io_obj.c40
-rw-r--r--source/blender/editors/io/io_stl_ops.c4
-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_mask_extract.c4
-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_add.cc197
-rw-r--r--source/blender/editors/object/object_modifier.cc42
-rw-r--r--source/blender/editors/object/object_relations.c29
-rw-r--r--source/blender/editors/object/object_vgroup.cc108
-rw-r--r--source/blender/editors/physics/dynamicpaint_ops.c4
-rw-r--r--source/blender/editors/physics/particle_edit.c6
-rw-r--r--source/blender/editors/physics/particle_object.c9
-rw-r--r--source/blender/editors/physics/physics_fluid.c16
-rw-r--r--source/blender/editors/render/render_preview.cc2
-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/screen/area.c3
-rw-r--r--source/blender/editors/screen/workspace_edit.c5
-rw-r--r--source/blender/editors/sculpt_paint/paint_image_2d.c6
-rw-r--r--source/blender/editors/sculpt_paint/paint_image_ops_paint.cc7
-rw-r--r--source/blender/editors/sculpt_paint/paint_image_proj.c7
-rw-r--r--source/blender/editors/sculpt_paint/paint_mask.c16
-rw-r--r--source/blender/editors/sculpt_paint/paint_utils.c2
-rw-r--r--source/blender/editors/sculpt_paint/paint_vertex.cc9
-rw-r--r--source/blender/editors/sculpt_paint/sculpt.c40
-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_expand.c18
-rw-r--r--source/blender/editors/sculpt_paint/sculpt_face_set.cc142
-rw-r--r--source/blender/editors/sculpt_paint/sculpt_filter_mask.c3
-rw-r--r--source/blender/editors/sculpt_paint/sculpt_intern.h2
-rw-r--r--source/blender/editors/sculpt_paint/sculpt_mask_expand.c8
-rw-r--r--source/blender/editors/sculpt_paint/sculpt_mask_init.c4
-rw-r--r--source/blender/editors/sculpt_paint/sculpt_ops.c21
-rw-r--r--source/blender/editors/space_clip/clip_ops.c14
-rw-r--r--source/blender/editors/space_file/file_draw.c71
-rw-r--r--source/blender/editors/space_file/file_ops.c17
-rw-r--r--source/blender/editors/space_file/filelist.cc43
-rw-r--r--source/blender/editors/space_file/filesel.c2
-rw-r--r--source/blender/editors/space_file/fsmenu.c26
-rw-r--r--source/blender/editors/space_file/space_file.c2
-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/image_sequence.c4
-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_info/textview.c3
-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.cc5
-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.cc332
-rw-r--r--source/blender/editors/space_outliner/outliner_dragdrop.cc2
-rw-r--r--source/blender/editors/space_outliner/outliner_draw.cc88
-rw-r--r--source/blender/editors/space_outliner/outliner_edit.cc4
-rw-r--r--source/blender/editors/space_sequencer/sequencer_add.c6
-rw-r--r--source/blender/editors/space_sequencer/sequencer_draw.c2
-rw-r--r--source/blender/editors/space_sequencer/sequencer_edit.c2
-rw-r--r--source/blender/editors/space_sequencer/space_sequencer.c2
-rw-r--r--source/blender/editors/space_spreadsheet/spreadsheet_column.cc3
-rw-r--r--source/blender/editors/space_spreadsheet/spreadsheet_data_source_geometry.cc80
-rw-r--r--source/blender/editors/space_spreadsheet/spreadsheet_layout.cc13
-rw-r--r--source/blender/editors/space_spreadsheet/spreadsheet_row_filter.cc16
-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/space_view3d/view3d_navigate_walk.c16
-rw-r--r--source/blender/editors/space_view3d/view3d_ops.c4
-rw-r--r--source/blender/editors/transform/CMakeLists.txt2
-rw-r--r--source/blender/editors/transform/transform.c98
-rw-r--r--source/blender/editors/transform/transform.h16
-rw-r--r--source/blender/editors/transform/transform_constraints.c15
-rw-r--r--source/blender/editors/transform/transform_convert.h12
-rw-r--r--source/blender/editors/transform/transform_convert_mesh.c2
-rw-r--r--source/blender/editors/transform/transform_convert_mesh_edge.c2
-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)81
-rw-r--r--source/blender/editors/transform/transform_mode_curveshrinkfatten.c22
-rw-r--r--source/blender/editors/transform/transform_mode_translate.c103
-rw-r--r--source/blender/editors/transform/transform_ops.c23
-rw-r--r--source/blender/editors/transform/transform_snap.c131
-rw-r--r--source/blender/editors/transform/transform_snap.h11
-rw-r--r--source/blender/editors/transform/transform_snap_object.cc28
-rw-r--r--source/blender/editors/util/ed_util.c2
-rw-r--r--source/blender/editors/util/ed_viewer_path.cc3
-rw-r--r--source/blender/editors/uvedit/uvedit_islands.cc290
-rw-r--r--source/blender/editors/uvedit/uvedit_ops.c4
-rw-r--r--source/blender/editors/uvedit/uvedit_unwrap_ops.c158
-rw-r--r--source/blender/freestyle/intern/blender_interface/BlenderFileLoader.cpp3
-rw-r--r--source/blender/freestyle/intern/python/BPy_Freestyle.cpp2
-rw-r--r--source/blender/geometry/intern/add_curves_on_mesh.cc7
-rw-r--r--source/blender/geometry/intern/fillet_curves.cc6
-rw-r--r--source/blender/geometry/intern/realize_instances.cc47
-rw-r--r--source/blender/geometry/intern/resample_curves.cc3
-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.txt15
-rw-r--r--source/blender/gpu/GPU_context.h2
-rw-r--r--source/blender/gpu/GPU_shader.h4
-rw-r--r--source/blender/gpu/intern/gpu_context.cc12
-rw-r--r--source/blender/gpu/intern/gpu_framebuffer_private.hh5
-rw-r--r--source/blender/gpu/intern/gpu_immediate.cc11
-rw-r--r--source/blender/gpu/intern/gpu_immediate_private.hh8
-rw-r--r--source/blender/gpu/intern/gpu_shader_builder.cc49
-rw-r--r--source/blender/gpu/intern/gpu_shader_builder_stubs.cc9
-rw-r--r--source/blender/gpu/intern/gpu_shader_builtin.c5
-rw-r--r--source/blender/gpu/intern/gpu_texture_private.hh9
-rw-r--r--source/blender/gpu/intern/gpu_vertex_format.cc8
-rw-r--r--source/blender/gpu/intern/gpu_viewport.c4
-rw-r--r--source/blender/gpu/metal/mtl_backend.mm3
-rw-r--r--source/blender/gpu/metal/mtl_batch.hh115
-rw-r--r--source/blender/gpu/metal/mtl_batch.mm998
-rw-r--r--source/blender/gpu/metal/mtl_context.mm10
-rw-r--r--source/blender/gpu/metal/mtl_drawlist.hh58
-rw-r--r--source/blender/gpu/metal/mtl_drawlist.mm284
-rw-r--r--source/blender/gpu/metal/mtl_immediate.mm5
-rw-r--r--source/blender/gpu/metal/mtl_pso_descriptor_state.hh13
-rw-r--r--source/blender/gpu/metal/mtl_shader_interface.mm10
-rw-r--r--source/blender/gpu/metal/mtl_texture.hh4
-rw-r--r--source/blender/gpu/metal/mtl_texture.mm97
-rw-r--r--source/blender/gpu/opengl/gl_batch.cc4
-rw-r--r--source/blender/gpu/opengl/gl_shader_interface.cc10
-rw-r--r--source/blender/gpu/shaders/compositor/compositor_blur.glsl21
-rw-r--r--source/blender/gpu/shaders/compositor/compositor_blur_variable_size.glsl71
-rw-r--r--source/blender/gpu/shaders/compositor/compositor_normalize.glsl10
-rw-r--r--source/blender/gpu/shaders/compositor/compositor_parallel_reduction.glsl98
-rw-r--r--source/blender/gpu/shaders/compositor/compositor_tone_map_photoreceptor.glsl22
-rw-r--r--source/blender/gpu/shaders/compositor/compositor_tone_map_simple.glsl26
-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_normalize_info.hh12
-rw-r--r--source/blender/gpu/shaders/compositor/infos/compositor_parallel_reduction_info.hh149
-rw-r--r--source/blender/gpu/shaders/compositor/infos/compositor_tone_map_photoreceptor_info.hh16
-rw-r--r--source/blender/gpu/shaders/compositor/infos/compositor_tone_map_simple_info.hh13
-rw-r--r--source/blender/gpu/shaders/gpu_shader_icon_frag.glsl42
-rw-r--r--source/blender/gpu/shaders/gpu_shader_icon_vert.glsl37
-rw-r--r--source/blender/gpu/shaders/infos/gpu_interface_info.hh3
-rw-r--r--source/blender/gpu/shaders/infos/gpu_shader_icon_info.hh22
-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/colormanagement.c2
-rw-r--r--source/blender/imbuf/intern/indexer.c16
-rw-r--r--source/blender/imbuf/intern/transform.cc2
-rw-r--r--source/blender/imbuf/intern/util_gpu.c27
-rw-r--r--source/blender/io/alembic/intern/abc_reader_mesh.cc6
-rw-r--r--source/blender/io/alembic/intern/alembic_capi.cc6
-rw-r--r--source/blender/io/collada/DocumentExporter.cpp2
-rw-r--r--source/blender/io/collada/DocumentImporter.cpp2
-rw-r--r--source/blender/io/collada/ImageExporter.cpp2
-rw-r--r--source/blender/io/common/intern/path_util.cc3
-rw-r--r--source/blender/io/stl/CMakeLists.txt2
-rw-r--r--source/blender/io/usd/intern/usd_capi_import.cc7
-rw-r--r--source/blender/io/usd/intern/usd_reader_mesh.cc6
-rw-r--r--source/blender/io/usd/intern/usd_writer_material.cc12
-rw-r--r--source/blender/io/usd/intern/usd_writer_volume.cc2
-rw-r--r--source/blender/io/usd/tests/usd_tests_common.cc2
-rw-r--r--source/blender/io/wavefront_obj/CMakeLists.txt4
-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.cc16
-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_defaults.h2
-rw-r--r--source/blender/makesdna/DNA_brush_enums.h5
-rw-r--r--source/blender/makesdna/DNA_gpencil_types.h10
-rw-r--r--source/blender/makesdna/DNA_mesh_types.h143
-rw-r--r--source/blender/makesdna/DNA_node_types.h26
-rw-r--r--source/blender/makesdna/DNA_scene_types.h1
-rw-r--r--source/blender/makesdna/DNA_space_types.h20
-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/makesdna/intern/CMakeLists.txt2
-rw-r--r--source/blender/makesrna/intern/CMakeLists.txt2
-rw-r--r--source/blender/makesrna/intern/rna_brush.c14
-rw-r--r--source/blender/makesrna/intern/rna_fluid.c16
-rw-r--r--source/blender/makesrna/intern/rna_gpencil_modifier.c14
-rw-r--r--source/blender/makesrna/intern/rna_internal.h4
-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.c12
-rw-r--r--source/blender/makesrna/intern/rna_object_api.c2
-rw-r--r--source/blender/makesrna/intern/rna_scene.c4
-rw-r--r--source/blender/makesrna/intern/rna_sculpt_paint.c9
-rw-r--r--source/blender/makesrna/intern/rna_sequencer.c8
-rw-r--r--source/blender/makesrna/intern/rna_space.c36
-rw-r--r--source/blender/makesrna/intern/rna_space_api.c6
-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.c38
-rw-r--r--source/blender/makesrna/intern/rna_xr.c2
-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_normalize.cc47
-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/composite/nodes/node_composite_tonemap.cc248
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_collection_info.cc18
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_deform_curves_on_surface.cc29
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_delete_geometry.cc47
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_distribute_points_in_volume.cc3
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_dual_mesh.cc46
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_duplicate_elements.cc57
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_extrude_mesh.cc77
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_flip_faces.cc3
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_geometry_to_instance.cc12
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_input_instance_rotation.cc9
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_input_instance_scale.cc9
-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_instance_on_points.cc56
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_instances_to_points.cc5
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_join_geometry.cc38
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_mesh_topology_corners_of_vertex.cc8
-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.cc8
-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/geometry/nodes/node_geo_object_info.cc10
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_rotate_instances.cc17
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_sample_nearest_surface.cc6
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_scale_instances.cc17
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_string_to_curves.cc24
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_transform.cc19
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_translate_instances.cc19
-rw-r--r--source/blender/nodes/intern/geometry_nodes_lazy_function.cc46
-rw-r--r--source/blender/nodes/intern/geometry_nodes_log.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_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/CMakeLists.txt2
-rw-r--r--source/blender/nodes/texture/nodes/node_texture_compose.c3
-rw-r--r--source/blender/python/gpu/gpu_py_platform.c27
-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/engine.cc55
-rw-r--r--source/blender/render/intern/render_result.cc89
-rw-r--r--source/blender/render/intern/texture_margin.cc4
-rw-r--r--source/blender/sequencer/intern/proxy.c4
-rw-r--r--source/blender/sequencer/intern/render.c2
-rw-r--r--source/blender/sequencer/intern/strip_add.c4
-rw-r--r--source/blender/sequencer/intern/utils.c2
-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_dragdrop.cc3
-rw-r--r--source/blender/windowmanager/intern/wm_event_system.cc2
-rw-r--r--source/blender/windowmanager/intern/wm_files.c40
-rw-r--r--source/blender/windowmanager/intern/wm_files_link.c10
-rw-r--r--source/blender/windowmanager/intern/wm_init_exit.c2
-rw-r--r--source/blender/windowmanager/intern/wm_operators.c51
-rw-r--r--source/blender/windowmanager/intern/wm_platform_support.c2
-rw-r--r--source/blender/windowmanager/intern/wm_playanim.c5
-rw-r--r--source/blender/windowmanager/intern/wm_splash_screen.c4
-rw-r--r--source/blender/windowmanager/intern/wm_window.c45
-rw-r--r--source/blender/windowmanager/intern/wm_window_private.h5
-rw-r--r--source/blender/windowmanager/wm_event_types.h55
-rw-r--r--source/creator/creator_args.c44
-rw-r--r--source/creator/creator_signals.c9
-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
657 files changed, 13680 insertions, 7244 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 408cf819ce8..f2f34ca3dd2 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -336,11 +336,9 @@ if(APPLE)
else()
set(WITH_COREAUDIO OFF)
endif()
-if(NOT WIN32)
+if(UNIX AND NOT APPLE)
option(WITH_JACK "Enable JACK Support (http://www.jackaudio.org)" ON)
- if(UNIX AND NOT APPLE)
- option(WITH_JACK_DYNLOAD "Enable runtime dynamic JACK libraries loading" OFF)
- endif()
+ option(WITH_JACK_DYNLOAD "Enable runtime dynamic JACK libraries loading" OFF)
else()
set(WITH_JACK OFF)
endif()
@@ -489,13 +487,12 @@ endif()
if(NOT APPLE)
option(WITH_CYCLES_DEVICE_ONEAPI "Enable Cycles oneAPI compute support" OFF)
option(WITH_CYCLES_ONEAPI_BINARIES "Enable Ahead-Of-Time compilation for Cycles oneAPI device" OFF)
- option(WITH_CYCLES_ONEAPI_SYCL_HOST_ENABLED "Enable use of SYCL host (CPU) device execution by oneAPI implementation. This option is for debugging purposes and impacts GPU execution." OFF)
# https://www.intel.com/content/www/us/en/develop/documentation/oneapi-dpcpp-cpp-compiler-dev-guide-and-reference/top/compilation/ahead-of-time-compilation.html
+ # acm-g10 is the architecture for the first Arc Alchemist GPUs but we'll keep using dg2 until IGC dependency is updated to support acm-g10.
set(CYCLES_ONEAPI_SPIR64_GEN_DEVICES "dg2" CACHE STRING "oneAPI Intel GPU architectures to build binaries for")
set(CYCLES_ONEAPI_SYCL_TARGETS spir64 spir64_gen CACHE STRING "oneAPI targets to build AOT binaries for")
- mark_as_advanced(WITH_CYCLES_ONEAPI_SYCL_HOST_ENABLED)
mark_as_advanced(CYCLES_ONEAPI_SPIR64_GEN_DEVICES)
mark_as_advanced(CYCLES_ONEAPI_SYCL_TARGETS)
endif()
@@ -780,6 +777,8 @@ endif()
# -----------------------------------------------------------------------------
# Check for Conflicting/Unsupported Configurations
+option(WITH_STRICT_BUILD_OPTIONS "When requirements for a build option are not met, error instead of disabling the option" OFF)
+
if(NOT WITH_BLENDER AND NOT WITH_CYCLES_STANDALONE AND NOT WITH_CYCLES_HYDRA_RENDER_DELEGATE)
message(FATAL_ERROR
"At least one of WITH_BLENDER or WITH_CYCLES_STANDALONE "
@@ -895,10 +894,7 @@ endif()
if(WITH_BUILDINFO)
find_package(Git)
- if(NOT GIT_FOUND)
- message(WARNING "Git was not found, disabling WITH_BUILDINFO")
- set(WITH_BUILDINFO OFF)
- endif()
+ set_and_warn_library_found("Git" GIT_FOUND WITH_BUILDINFO)
endif()
if(WITH_AUDASPACE)
@@ -938,9 +934,10 @@ if(WITH_INTERNATIONAL)
WARNING
"Translation path '${CMAKE_SOURCE_DIR}/release/datafiles/locale' is missing, "
"This is a 'git submodule', which are known not to work with bridges to other version "
- "control systems, disabling 'WITH_INTERNATIONAL'."
+ "control systems."
)
- set(WITH_INTERNATIONAL OFF)
+ set(TRANSLATIONS_FOUND OFF)
+ set_and_warn_library_found("Translations" TRANSLATIONS_FOUND WITH_INTERNATIONAL)
endif()
endif()
@@ -1245,6 +1242,8 @@ if(WITH_OPENMP)
find_package(OpenMP)
endif()
+ set_and_warn_library_found("OpenMP" OPENMP_FOUND WITH_OPENMP)
+
if(OPENMP_FOUND)
if(NOT WITH_OPENMP_STATIC)
string(APPEND CMAKE_C_FLAGS " ${OpenMP_C_FLAGS}")
@@ -1260,9 +1259,6 @@ if(WITH_OPENMP)
find_library_static(OpenMP_LIBRARIES gomp ${CMAKE_CXX_IMPLICIT_LINK_DIRECTORIES})
endif()
- else()
- message(STATUS "OpenMP not found, disabling WITH_OPENMP")
- set(WITH_OPENMP OFF)
endif()
mark_as_advanced(
@@ -1277,10 +1273,7 @@ endif()
if(WITH_BULLET AND WITH_SYSTEM_BULLET)
find_package(Bullet)
- if(NOT BULLET_FOUND)
- message(STATUS "Bullet not found, disabling WITH_BULLET")
- set(WITH_BULLET OFF)
- endif()
+ set_and_warn_library_found("Bullet" BULLET_FOUND WITH_BULLET)
else()
set(BULLET_INCLUDE_DIRS "${CMAKE_SOURCE_DIR}/extern/bullet2/src")
# set(BULLET_LIBRARIES "")
diff --git a/build_files/build_environment/CMakeLists.txt b/build_files/build_environment/CMakeLists.txt
index 03c85742ada..023d113b551 100644
--- a/build_files/build_environment/CMakeLists.txt
+++ b/build_files/build_environment/CMakeLists.txt
@@ -97,6 +97,8 @@ include(cmake/embree.cmake)
include(cmake/openpgl.cmake)
include(cmake/fmt.cmake)
include(cmake/robinmap.cmake)
+include(cmake/xml2.cmake)
+
if(NOT APPLE)
include(cmake/xr_openxr.cmake)
if(NOT WIN32 OR BUILD_MODE STREQUAL Release)
@@ -149,7 +151,6 @@ if(NOT WIN32 OR ENABLE_MINGW64)
endif()
if(UNIX)
include(cmake/flac.cmake)
- include(cmake/xml2.cmake)
if(NOT APPLE)
include(cmake/spnav.cmake)
include(cmake/jemalloc.cmake)
@@ -176,3 +177,4 @@ if(UNIX AND NOT APPLE)
endif()
include(cmake/harvest.cmake)
+include(cmake/cve_check.cmake)
diff --git a/build_files/build_environment/cmake/aom.cmake b/build_files/build_environment/cmake/aom.cmake
index 9f64439771f..11c81c3f6e4 100644
--- a/build_files/build_environment/cmake/aom.cmake
+++ b/build_files/build_environment/cmake/aom.cmake
@@ -8,11 +8,6 @@ if(WIN32)
# building with mingw, it'll have an unhappy time with that and
# we need to clear them out.
set(AOM_CMAKE_FLAGS )
- # CMake will correctly identify phreads being available, however
- # we do not want to use them, as that gains a dependency on
- # libpthreadswin.dll which we do not want. when pthreads is not
- # available oam will use a pthreads emulation layer using win32 threads
- set(AOM_EXTRA_ARGS_WIN32 -DCMAKE_HAVE_PTHREAD_H=OFF)
else()
set(AOM_GENERATOR "Unix Makefiles")
set(AOM_CMAKE_FLAGS ${DEFAULT_CMAKE_FLAGS})
@@ -36,6 +31,7 @@ ExternalProject_Add(external_aom
DOWNLOAD_DIR ${DOWNLOAD_DIR}
URL_HASH ${AOM_HASH_TYPE}=${AOM_HASH}
PREFIX ${BUILD_DIR}/aom
+ PATCH_COMMAND ${PATCH_CMD} --verbose -p 1 -N -d ${BUILD_DIR}/aom/src/external_aom < ${PATCH_DIR}/aom.diff
CONFIGURE_COMMAND ${CONFIGURE_ENV} &&
cd ${BUILD_DIR}/aom/src/external_aom-build/ &&
${CMAKE_COMMAND} -G "${AOM_GENERATOR}" -DCMAKE_INSTALL_PREFIX=${LIBDIR}/aom ${AOM_CMAKE_FLAGS} ${AOM_EXTRA_ARGS} ${BUILD_DIR}/aom/src/external_aom/
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..ac42444aef1
--- /dev/null
+++ b/build_files/build_environment/cmake/cve_check.cmake
@@ -0,0 +1,75 @@
+# 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}})
+ string(REPLACE "_CPE" "_ID" CPE_DEPNAME ${_variableName})
+ list(GET CPE_LIST 3 CPE_VENDOR)
+ list(GET CPE_LIST 4 CPE_NAME)
+ list(GET CPE_LIST 5 CPE_VERSION)
+ set(${CPE_DEPNAME} "${CPE_VENDOR},${CPE_NAME},${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..734a24f8c77
--- /dev/null
+++ b/build_files/build_environment/cmake/cve_check.csv.in
@@ -0,0 +1,23 @@
+vendor,product,version,cve_number,remarks,comment
+@OPENJPEG_ID@,CVE-2016-9675,Ignored,issue in convert command line tool not used by blender
+@PYTHON_ID@,CVE-2009-2940,Ignored,issue in pygresql not used by blender
+@PYTHON_ID@,CVE-2020-29396,Ignored,issue in odoo not used by blender
+@PYTHON_ID@,CVE-2021-32052,Ignored,issue in django not used by blender
+@PYTHON_ID@,CVE-2009-3720,Ignored,already fixed in libexpat version used
+@SSL_ID@,CVE-2009-1390,Ignored,issue in mutt not used by blender
+@SSL_ID@,CVE-2009-3765,Ignored,issue in mutt not used by blender
+@SSL_ID@,CVE-2009-3766,Ignored,issue in mutt not used by blender
+@SSL_ID@,CVE-2009-3767,Ignored,issue in ldap not used by blender
+@SSL_ID@,CVE-2019-0190,Ignored,issue in apache not used by blender
+@TIFF_ID@,CVE-2022-2056,Ignored,issue in tiff command line tool not used by blender
+@TIFF_ID@,CVE-2022-2057,Ignored,issue in tiff command line tool not used by blender
+@TIFF_ID@,CVE-2022-2058,Ignored,issue in tiff command line tool not used by blender
+@TIFF_ID@,CVE-2022-2519,Ignored,issue in tiff command line tool not used by blender
+@TIFF_ID@,CVE-2022-2520,Ignored,issue in tiff command line tool not used by blender
+@TIFF_ID@,CVE-2022-2521,Ignored,issue in tiff command line tool not used by blender
+@TIFF_ID@,CVE-2022-2953,Ignored,issue in tiff command line tool not used by blender
+@TIFF_ID@,CVE-2022-34526,Ignored,issue in tiff command line tool not used by blender
+@XML2_ID@,CVE-2016-3709,Ignored,not affecting blender and not considered a security issue upstream
+@GMP_ID@,CVE-2021-43618,Mitigated,patched using upstream commit 561a9c25298e
+@SQLITE_ID@,CVE-2022-35737,Ignored,only affects SQLITE_ENABLE_STAT4 compile option not used by blender or python
+@SBOMCONTENTS@
diff --git a/build_files/build_environment/cmake/download.cmake b/build_files/build_environment/cmake/download.cmake
index 35bc028a1e3..8d75f0ff0ed 100644
--- a/build_files/build_environment/cmake/download.cmake
+++ b/build_files/build_environment/cmake/download.cmake
@@ -62,7 +62,7 @@ function(download_source dep)
# since the actual build of the dep will notify the
# platform maintainer if there is a problem with the
# source package and refuse to build.
- if(NOT PACKAGE_USE_UPSTREAM_SOURCES)
+ if(NOT PACKAGE_USE_UPSTREAM_SOURCES OR FORCE_CHECK_HASH)
file(${TARGET_HASH_TYPE} ${TARGET_FILE} LOCAL_HASH)
if(NOT ${TARGET_HASH} STREQUAL ${LOCAL_HASH})
message(FATAL_ERROR "${TARGET_FILE} ${TARGET_HASH_TYPE} mismatch\nExpected\t: ${TARGET_HASH}\nActual\t: ${LOCAL_HASH}")
@@ -114,7 +114,6 @@ download_source(WEBP)
download_source(SPNAV)
download_source(JEMALLOC)
download_source(XML2)
-download_source(TINYXML)
download_source(YAMLCPP)
download_source(EXPAT)
download_source(PUGIXML)
diff --git a/build_files/build_environment/cmake/ffmpeg.cmake b/build_files/build_environment/cmake/ffmpeg.cmake
index 7730607c514..e2b60e161f2 100644
--- a/build_files/build_environment/cmake/ffmpeg.cmake
+++ b/build_files/build_environment/cmake/ffmpeg.cmake
@@ -16,12 +16,6 @@ if(WIN32)
--enable-libopenjpeg
--disable-mediafoundation
)
- if("${CMAKE_SIZEOF_VOID_P}" EQUAL "4")
- set(FFMPEG_EXTRA_FLAGS
- ${FFMPEG_EXTRA_FLAGS}
- --x86asmexe=yasm
- )
- endif()
else()
set(FFMPEG_EXTRA_FLAGS
${FFMPEG_EXTRA_FLAGS}
diff --git a/build_files/build_environment/cmake/freetype.cmake b/build_files/build_environment/cmake/freetype.cmake
index b6f53ede2db..842e5c42e25 100644
--- a/build_files/build_environment/cmake/freetype.cmake
+++ b/build_files/build_environment/cmake/freetype.cmake
@@ -7,8 +7,11 @@ set(FREETYPE_EXTRA_ARGS
-DFT_DISABLE_HARFBUZZ=ON
-DFT_DISABLE_PNG=ON
-DFT_REQUIRE_BROTLI=ON
+ -DFT_REQUIRE_ZLIB=ON
-DPC_BROTLIDEC_INCLUDEDIR=${LIBDIR}/brotli/include
-DPC_BROTLIDEC_LIBDIR=${LIBDIR}/brotli/lib
+ -DZLIB_LIBRARY=${LIBDIR}/zlib/lib/${ZLIB_LIBRARY}
+ -DZLIB_INCLUDE_DIR=${LIBDIR}/zlib/include
)
ExternalProject_Add(external_freetype
@@ -23,6 +26,7 @@ ExternalProject_Add(external_freetype
add_dependencies(
external_freetype
external_brotli
+ external_zlib
)
if(BUILD_MODE STREQUAL Release AND WIN32)
diff --git a/build_files/build_environment/cmake/gmp.cmake b/build_files/build_environment/cmake/gmp.cmake
index e624778869e..ddfdba6662d 100644
--- a/build_files/build_environment/cmake/gmp.cmake
+++ b/build_files/build_environment/cmake/gmp.cmake
@@ -27,6 +27,7 @@ ExternalProject_Add(external_gmp
DOWNLOAD_DIR ${DOWNLOAD_DIR}
URL_HASH ${GMP_HASH_TYPE}=${GMP_HASH}
PREFIX ${BUILD_DIR}/gmp
+ PATCH_COMMAND ${PATCH_CMD} -p 1 -d ${BUILD_DIR}/gmp/src/external_gmp < ${PATCH_DIR}/gmp.diff
CONFIGURE_COMMAND ${CONFIGURE_ENV_NO_PERL} && cd ${BUILD_DIR}/gmp/src/external_gmp/ && ${CONFIGURE_COMMAND} --prefix=${LIBDIR}/gmp ${GMP_OPTIONS} ${GMP_EXTRA_ARGS}
BUILD_COMMAND ${CONFIGURE_ENV_NO_PERL} && cd ${BUILD_DIR}/gmp/src/external_gmp/ && make -j${MAKE_THREADS}
INSTALL_COMMAND ${CONFIGURE_ENV_NO_PERL} && cd ${BUILD_DIR}/gmp/src/external_gmp/ && make install
diff --git a/build_files/build_environment/cmake/llvm.cmake b/build_files/build_environment/cmake/llvm.cmake
index e4ddc7db846..11f6bf7c218 100644
--- a/build_files/build_environment/cmake/llvm.cmake
+++ b/build_files/build_environment/cmake/llvm.cmake
@@ -9,6 +9,7 @@ endif()
if(APPLE)
set(LLVM_XML2_ARGS
-DLIBXML2_LIBRARY=${LIBDIR}/xml2/lib/libxml2.a
+ -DLIBXML2_INCLUDE_DIR=${LIBDIR}/xml2/include/libxml2
)
set(LLVM_BUILD_CLANG_TOOLS_EXTRA ^^clang-tools-extra)
set(BUILD_CLANG_TOOLS ON)
diff --git a/build_files/build_environment/cmake/opencollada.cmake b/build_files/build_environment/cmake/opencollada.cmake
index b2ae1a1a351..9473aafbe88 100644
--- a/build_files/build_environment/cmake/opencollada.cmake
+++ b/build_files/build_environment/cmake/opencollada.cmake
@@ -4,6 +4,16 @@ if(UNIX)
set(OPENCOLLADA_EXTRA_ARGS
-DLIBXML2_INCLUDE_DIR=${LIBDIR}/xml2/include/libxml2
-DLIBXML2_LIBRARIES=${LIBDIR}/xml2/lib/libxml2.a)
+else()
+ set(OPENCOLLADA_EXTRA_ARGS
+ -DCMAKE_DEBUG_POSTFIX=_d
+ -DLIBXML2_INCLUDE_DIR=${LIBDIR}/xml2/include/libxml2
+ )
+ if(BUILD_MODE STREQUAL Release)
+ list(APPEND OPENCOLLADA_EXTRA_ARGS -DLIBXML2_LIBRARIES=${LIBDIR}/xml2/lib/libxml2s.lib)
+ else()
+ list(APPEND OPENCOLLADA_EXTRA_ARGS -DLIBXML2_LIBRARIES=${LIBDIR}/xml2/lib/libxml2sd.lib)
+ endif()
endif()
ExternalProject_Add(external_opencollada
@@ -16,12 +26,11 @@ ExternalProject_Add(external_opencollada
INSTALL_DIR ${LIBDIR}/opencollada
)
-if(UNIX)
- add_dependencies(
- external_opencollada
- external_xml2
- )
-endif()
+
+add_dependencies(
+ external_opencollada
+ external_xml2
+)
if(WIN32)
if(BUILD_MODE STREQUAL Release)
@@ -32,17 +41,7 @@ if(WIN32)
endif()
if(BUILD_MODE STREQUAL Debug)
ExternalProject_Add_Step(external_opencollada after_install
- COMMAND ${CMAKE_COMMAND} -E copy ${LIBDIR}/opencollada/lib/opencollada/buffer.lib ${HARVEST_TARGET}/opencollada/lib/opencollada/buffer_d.lib
- COMMAND ${CMAKE_COMMAND} -E copy ${LIBDIR}/opencollada/lib/opencollada/ftoa.lib ${HARVEST_TARGET}/opencollada/lib/opencollada/ftoa_d.lib
- COMMAND ${CMAKE_COMMAND} -E copy ${LIBDIR}/opencollada/lib/opencollada/GeneratedSaxParser.lib ${HARVEST_TARGET}/opencollada/lib/opencollada/GeneratedSaxParser_d.lib
- COMMAND ${CMAKE_COMMAND} -E copy ${LIBDIR}/opencollada/lib/opencollada/MathMLSolver.lib ${HARVEST_TARGET}/opencollada/lib/opencollada/MathMLSolver_d.lib
- COMMAND ${CMAKE_COMMAND} -E copy ${LIBDIR}/opencollada/lib/opencollada/OpenCOLLADABaseUtils.lib ${HARVEST_TARGET}/opencollada/lib/opencollada/OpenCOLLADABaseUtils_d.lib
- COMMAND ${CMAKE_COMMAND} -E copy ${LIBDIR}/opencollada/lib/opencollada/OpenCOLLADAFramework.lib ${HARVEST_TARGET}/opencollada/lib/opencollada/OpenCOLLADAFramework_d.lib
- COMMAND ${CMAKE_COMMAND} -E copy ${LIBDIR}/opencollada/lib/opencollada/OpenCOLLADASaxFrameworkLoader.lib ${HARVEST_TARGET}/opencollada/lib/opencollada/OpenCOLLADASaxFrameworkLoader_d.lib
- COMMAND ${CMAKE_COMMAND} -E copy ${LIBDIR}/opencollada/lib/opencollada/OpenCOLLADAStreamWriter.lib ${HARVEST_TARGET}/opencollada/lib/opencollada/OpenCOLLADAStreamWriter_d.lib
- COMMAND ${CMAKE_COMMAND} -E copy ${LIBDIR}/opencollada/lib/opencollada/pcre.lib ${HARVEST_TARGET}/opencollada/lib/opencollada/pcre_d.lib
- COMMAND ${CMAKE_COMMAND} -E copy ${LIBDIR}/opencollada/lib/opencollada/UTF.lib ${HARVEST_TARGET}/opencollada/lib/opencollada/UTF_d.lib
- COMMAND ${CMAKE_COMMAND} -E copy ${LIBDIR}/opencollada/lib/opencollada/xml.lib ${HARVEST_TARGET}/opencollada/lib/opencollada/xml_d.lib
+ COMMAND ${CMAKE_COMMAND} -E copy_directory ${LIBDIR}/opencollada/lib ${HARVEST_TARGET}/opencollada/lib
DEPENDEES install
)
endif()
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/options.cmake b/build_files/build_environment/cmake/options.cmake
index 299b82f6d05..9058e945f6d 100644
--- a/build_files/build_environment/cmake/options.cmake
+++ b/build_files/build_environment/cmake/options.cmake
@@ -3,6 +3,7 @@
if(WIN32)
option(ENABLE_MINGW64 "Enable building of ffmpeg/iconv/libsndfile/fftw3 by installing mingw64" ON)
endif()
+option(FORCE_CHECK_HASH "Force a check of all hashses during CMake the configure phase" OFF)
option(WITH_BOOST_PYTHON "Enable building of boost with python support" OFF)
cmake_host_system_information(RESULT NUM_CORES QUERY NUMBER_OF_LOGICAL_CORES)
set(MAKE_THREADS ${NUM_CORES} CACHE STRING "Number of threads to run make with")
@@ -101,34 +102,16 @@ else()
set(LIBPREFIX "lib")
if(APPLE)
- # Let's get the current Xcode dir, to support xcode-select
- execute_process(
- COMMAND xcode-select --print-path
- OUTPUT_VARIABLE XCODE_DEV_PATH OUTPUT_STRIP_TRAILING_WHITESPACE
- )
- execute_process(
- COMMAND xcodebuild -version -sdk macosx SDKVersion
- OUTPUT_VARIABLE MACOSX_SDK_VERSION OUTPUT_STRIP_TRAILING_WHITESPACE)
-
- if(NOT CMAKE_OSX_ARCHITECTURES)
- execute_process(COMMAND uname -m OUTPUT_VARIABLE ARCHITECTURE OUTPUT_STRIP_TRAILING_WHITESPACE)
- message(STATUS "Detected native architecture ${ARCHITECTURE}.")
- set(CMAKE_OSX_ARCHITECTURES "${ARCHITECTURE}")
- endif()
- if("${CMAKE_OSX_ARCHITECTURES}" STREQUAL "x86_64")
- set(OSX_DEPLOYMENT_TARGET 10.13)
- else()
- set(OSX_DEPLOYMENT_TARGET 11.00)
- endif()
- set(OSX_SYSROOT ${XCODE_DEV_PATH}/Platforms/MacOSX.platform/Developer/SDKs/MacOSX.sdk)
+ # Use same Xcode detection as Blender itself.
+ include(../cmake/platform/platform_apple_xcode.cmake)
if("${CMAKE_OSX_ARCHITECTURES}" STREQUAL "arm64")
set(BLENDER_PLATFORM_ARM ON)
endif()
- set(PLATFORM_CFLAGS "-isysroot ${OSX_SYSROOT} -mmacosx-version-min=${OSX_DEPLOYMENT_TARGET} -arch ${CMAKE_OSX_ARCHITECTURES}")
- set(PLATFORM_CXXFLAGS "-isysroot ${OSX_SYSROOT} -mmacosx-version-min=${OSX_DEPLOYMENT_TARGET} -std=c++11 -stdlib=libc++ -arch ${CMAKE_OSX_ARCHITECTURES}")
- set(PLATFORM_LDFLAGS "-isysroot ${OSX_SYSROOT} -mmacosx-version-min=${OSX_DEPLOYMENT_TARGET} -arch ${CMAKE_OSX_ARCHITECTURES}")
+ set(PLATFORM_CFLAGS "-isysroot ${CMAKE_OSX_SYSROOT} -mmacosx-version-min=${CMAKE_OSX_DEPLOYMENT_TARGET} -arch ${CMAKE_OSX_ARCHITECTURES}")
+ set(PLATFORM_CXXFLAGS "-isysroot ${CMAKE_OSX_SYSROOT} -mmacosx-version-min=${CMAKE_OSX_DEPLOYMENT_TARGET} -std=c++11 -stdlib=libc++ -arch ${CMAKE_OSX_ARCHITECTURES}")
+ set(PLATFORM_LDFLAGS "-isysroot ${CMAKE_OSX_SYSROOT} -mmacosx-version-min=${CMAKE_OSX_DEPLOYMENT_TARGET} -arch ${CMAKE_OSX_ARCHITECTURES}")
if("${CMAKE_OSX_ARCHITECTURES}" STREQUAL "x86_64")
set(PLATFORM_BUILD_TARGET --build=x86_64-apple-darwin17.0.0) # OS X 10.13
else()
@@ -136,8 +119,8 @@ else()
endif()
set(PLATFORM_CMAKE_FLAGS
-DCMAKE_OSX_ARCHITECTURES:STRING=${CMAKE_OSX_ARCHITECTURES}
- -DCMAKE_OSX_DEPLOYMENT_TARGET:STRING=${OSX_DEPLOYMENT_TARGET}
- -DCMAKE_OSX_SYSROOT:PATH=${OSX_SYSROOT}
+ -DCMAKE_OSX_DEPLOYMENT_TARGET:STRING=${CMAKE_OSX_DEPLOYMENT_TARGET}
+ -DCMAKE_OSX_SYSROOT:PATH=${CMAKE_OSX_SYSROOT}
)
else()
if("${CMAKE_SYSTEM_PROCESSOR}" STREQUAL "aarch64")
@@ -171,8 +154,8 @@ else()
set(BLENDER_CMAKE_CXX_FLAGS_RELWITHDEBINFO "-O2 -g -DNDEBUG ${PLATFORM_CXXFLAGS}")
set(CONFIGURE_ENV
- export MACOSX_DEPLOYMENT_TARGET=${OSX_DEPLOYMENT_TARGET} &&
- export MACOSX_SDK_VERSION=${OSX_DEPLOYMENT_TARGET} &&
+ export MACOSX_DEPLOYMENT_TARGET=${CMAKE_OSX_DEPLOYMENT_TARGET} &&
+ export MACOSX_SDK_VERSION=${CMAKE_OSX_DEPLOYMENT_TARGET} &&
export CFLAGS=${PLATFORM_CFLAGS} &&
export CXXFLAGS=${PLATFORM_CXXFLAGS} &&
export LDFLAGS=${PLATFORM_LDFLAGS}
diff --git a/build_files/build_environment/cmake/osl.cmake b/build_files/build_environment/cmake/osl.cmake
index 9719de94d47..a5d000e4f44 100644
--- a/build_files/build_environment/cmake/osl.cmake
+++ b/build_files/build_environment/cmake/osl.cmake
@@ -32,6 +32,8 @@ set(OSL_EXTRA_ARGS
-DUSE_Qt5=OFF
-DINSTALL_DOCS=OFF
-Dpugixml_ROOT=${LIBDIR}/pugixml
+ -DTIFF_ROOT=${LIBDIR}/tiff
+ -DJPEG_ROOT=${LIBDIR}/jpeg
-DUSE_PYTHON=OFF
-DCMAKE_CXX_STANDARD=14
-DImath_ROOT=${LIBDIR}/imath
@@ -81,6 +83,7 @@ if(WIN32)
COMMAND ${CMAKE_COMMAND} -E copy ${LIBDIR}/osl/lib/oslcomp.lib ${HARVEST_TARGET}/osl/lib/oslcomp_d.lib
COMMAND ${CMAKE_COMMAND} -E copy ${LIBDIR}/osl/lib/oslexec.lib ${HARVEST_TARGET}/osl/lib/oslexec_d.lib
COMMAND ${CMAKE_COMMAND} -E copy ${LIBDIR}/osl/lib/oslquery.lib ${HARVEST_TARGET}/osl/lib/oslquery_d.lib
+ COMMAND ${CMAKE_COMMAND} -E copy ${LIBDIR}/osl/lib/oslnoise.lib ${HARVEST_TARGET}/osl/lib/oslnoise_d.lib
DEPENDEES install
)
endif()
diff --git a/build_files/build_environment/cmake/png.cmake b/build_files/build_environment/cmake/png.cmake
index 890be673cb8..371f2608e2a 100644
--- a/build_files/build_environment/cmake/png.cmake
+++ b/build_files/build_environment/cmake/png.cmake
@@ -24,6 +24,14 @@ add_dependencies(
external_zlib
)
+if(WIN32 AND BUILD_MODE STREQUAL Release)
+ ExternalProject_Add_Step(external_png after_install
+ COMMAND ${CMAKE_COMMAND} -E copy_directory ${LIBDIR}/png/include/ ${HARVEST_TARGET}/png/include/
+ COMMAND ${CMAKE_COMMAND} -E copy ${LIBDIR}/png/lib/libpng16_static${LIBEXT} ${HARVEST_TARGET}/png/lib/libpng${LIBEXT}
+ DEPENDEES install
+ )
+endif()
+
if(WIN32 AND BUILD_MODE STREQUAL Debug)
ExternalProject_Add_Step(external_png after_install
COMMAND ${CMAKE_COMMAND} -E copy ${LIBDIR}/png/lib/libpng16_staticd${LIBEXT} ${LIBDIR}/png/lib/libpng16${LIBEXT}
diff --git a/build_files/build_environment/cmake/python.cmake b/build_files/build_environment/cmake/python.cmake
index 8fed10e9d72..72ae27ddfdb 100644
--- a/build_files/build_environment/cmake/python.cmake
+++ b/build_files/build_environment/cmake/python.cmake
@@ -15,9 +15,11 @@ if(WIN32)
endmacro()
set(PYTHON_EXTERNALS_FOLDER ${BUILD_DIR}/python/src/external_python/externals)
+ set(ZLIB_SOURCE_FOLDER ${BUILD_DIR}/zlib/src/external_zlib)
set(DOWNLOADS_EXTERNALS_FOLDER ${DOWNLOAD_DIR}/externals)
cmake_to_dos_path(${PYTHON_EXTERNALS_FOLDER} PYTHON_EXTERNALS_FOLDER_DOS)
+ cmake_to_dos_path(${ZLIB_SOURCE_FOLDER} ZLIB_SOURCE_FOLDER_DOS)
cmake_to_dos_path(${DOWNLOADS_EXTERNALS_FOLDER} DOWNLOADS_EXTERNALS_FOLDER_DOS)
ExternalProject_Add(external_python
@@ -25,12 +27,21 @@ if(WIN32)
DOWNLOAD_DIR ${DOWNLOAD_DIR}
URL_HASH ${PYTHON_HASH_TYPE}=${PYTHON_HASH}
PREFIX ${BUILD_DIR}/python
- CONFIGURE_COMMAND ""
+ # Python will download its own deps and there's very little we can do about
+ # that beyond placing some code in their externals dir before it tries.
+ # the foldernames *HAVE* to match the ones inside pythons get_externals.cmd.
+ # python 3.10.8 still ships zlib 1.2.12, replace it with our 1.2.13
+ # copy until they update.
+ CONFIGURE_COMMAND mkdir ${PYTHON_EXTERNALS_FOLDER_DOS} &&
+ mklink /J ${PYTHON_EXTERNALS_FOLDER_DOS}\\zlib-1.2.12 ${ZLIB_SOURCE_FOLDER_DOS} &&
+ ${CMAKE_COMMAND} -E copy ${ZLIB_SOURCE_FOLDER}/../external_zlib-build/zconf.h ${PYTHON_EXTERNALS_FOLDER}/zlib-1.2.12/zconf.h
BUILD_COMMAND cd ${BUILD_DIR}/python/src/external_python/pcbuild/ && set IncludeTkinter=false && call build.bat -e -p x64 -c ${BUILD_MODE}
- PATCH_COMMAND ${PATCH_CMD} --verbose -p1 -d ${BUILD_DIR}/python/src/external_python < ${PATCH_DIR}/python_windows.diff
INSTALL_COMMAND ${PYTHON_BINARY_INTERNAL} ${PYTHON_SRC}/PC/layout/main.py -b ${PYTHON_SRC}/PCbuild/amd64 -s ${PYTHON_SRC} -t ${PYTHON_SRC}/tmp/ --include-stable --include-pip --include-dev --include-launchers --include-venv --include-symbols ${PYTHON_EXTRA_INSTLAL_FLAGS} --copy ${LIBDIR}/python
)
-
+ add_dependencies(
+ external_python
+ external_zlib
+ )
else()
if(APPLE)
# Disable functions that can be in 10.13 sdk but aren't available on 10.9 target.
diff --git a/build_files/build_environment/cmake/sndfile.cmake b/build_files/build_environment/cmake/sndfile.cmake
index 192c25f5ed1..a2ac2a33779 100644
--- a/build_files/build_environment/cmake/sndfile.cmake
+++ b/build_files/build_environment/cmake/sndfile.cmake
@@ -11,18 +11,11 @@ else()
set(SNDFILE_OPTIONS --enable-static --disable-shared )
endif()
-if(UNIX)
- set(SNDFILE_PATCH_CMD ${PATCH_CMD} --verbose -p 0 -d ${BUILD_DIR}/sndfile/src/external_sndfile < ${PATCH_DIR}/sndfile.diff)
-else()
- set(SNDFILE_PATCH_CMD)
-endif()
-
ExternalProject_Add(external_sndfile
URL file://${PACKAGE_DIR}/${SNDFILE_FILE}
DOWNLOAD_DIR ${DOWNLOAD_DIR}
URL_HASH ${SNDFILE_HASH_TYPE}=${SNDFILE_HASH}
PREFIX ${BUILD_DIR}/sndfile
- PATCH_COMMAND ${SNDFILE_PATCH_CMD}
CONFIGURE_COMMAND ${CONFIGURE_ENV} && cd ${BUILD_DIR}/sndfile/src/external_sndfile/ && ${SNDFILE_ENV} ${CONFIGURE_COMMAND} ${SNDFILE_OPTIONS} --prefix=${mingw_LIBDIR}/sndfile
BUILD_COMMAND ${CONFIGURE_ENV} && cd ${BUILD_DIR}/sndfile/src/external_sndfile/ && make -j${MAKE_THREADS}
INSTALL_COMMAND ${CONFIGURE_ENV} && cd ${BUILD_DIR}/sndfile/src/external_sndfile/ && make install
diff --git a/build_files/build_environment/cmake/sqlite.cmake b/build_files/build_environment/cmake/sqlite.cmake
index c82d832574a..c151a495ff1 100644
--- a/build_files/build_environment/cmake/sqlite.cmake
+++ b/build_files/build_environment/cmake/sqlite.cmake
@@ -48,7 +48,6 @@ ExternalProject_Add(external_sqlite
DOWNLOAD_DIR ${DOWNLOAD_DIR}
URL_HASH ${SQLITE_HASH_TYPE}=${SQLITE_HASH}
PREFIX ${BUILD_DIR}/sqlite
- PATCH_COMMAND ${PATCH_CMD} -p 1 -d ${BUILD_DIR}/sqlite/src/external_sqlite < ${PATCH_DIR}/sqlite.diff
CONFIGURE_COMMAND ${SQLITE_CONFIGURE_ENV} && cd ${BUILD_DIR}/sqlite/src/external_sqlite/ && ${CONFIGURE_COMMAND} --prefix=${LIBDIR}/sqlite ${SQLITE_CONFIGURATION_ARGS}
BUILD_COMMAND ${CONFIGURE_ENV} && cd ${BUILD_DIR}/sqlite/src/external_sqlite/ && make -j${MAKE_THREADS}
INSTALL_COMMAND ${CONFIGURE_ENV} && cd ${BUILD_DIR}/sqlite/src/external_sqlite/ && make install
diff --git a/build_files/build_environment/cmake/ssl.cmake b/build_files/build_environment/cmake/ssl.cmake
index 21c4d2418c3..628187dc0ac 100644
--- a/build_files/build_environment/cmake/ssl.cmake
+++ b/build_files/build_environment/cmake/ssl.cmake
@@ -5,6 +5,7 @@ set(SSL_PATCH_CMD echo .)
if(APPLE)
set(SSL_OS_COMPILER "blender-darwin-${CMAKE_OSX_ARCHITECTURES}")
+ set(SSL_PATCH_CMD ${PATCH_CMD} --verbose -p 0 -d ${BUILD_DIR}/ssl/src/external_ssl < ${PATCH_DIR}/ssl.diff)
else()
if(BLENDER_PLATFORM_ARM)
set(SSL_OS_COMPILER "blender-linux-aarch64")
diff --git a/build_files/build_environment/cmake/tiff.cmake b/build_files/build_environment/cmake/tiff.cmake
index 1f8e9442ae5..1ac2e4c6058 100644
--- a/build_files/build_environment/cmake/tiff.cmake
+++ b/build_files/build_environment/cmake/tiff.cmake
@@ -25,6 +25,7 @@ ExternalProject_Add(external_tiff
add_dependencies(
external_tiff
external_zlib
+ external_jpeg
)
if(WIN32)
if(BUILD_MODE STREQUAL Release)
diff --git a/build_files/build_environment/cmake/versions.cmake b/build_files/build_environment/cmake/versions.cmake
index 938ecd393dc..06a923e5c22 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
-set(ZLIB_VERSION 1.2.12)
+# 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.13)
set(ZLIB_URI https://zlib.net/zlib-${ZLIB_VERSION}.tar.gz)
-set(ZLIB_HASH 5fc414a9726be31427b440b434d05f78)
+set(ZLIB_HASH 9b8aa094c4e5765dabf4da391f00d15c)
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)
@@ -74,11 +88,12 @@ else()
set(OPENEXR_VERSION_POSTFIX)
endif()
-set(FREETYPE_VERSION 2.11.1)
+set(FREETYPE_VERSION 2.12.1)
set(FREETYPE_URI http://prdownloads.sourceforge.net/freetype/freetype-${FREETYPE_VERSION}.tar.gz)
-set(FREETYPE_HASH bd4e3b007474319909a6b79d50908e85)
+set(FREETYPE_HASH 8bc5c9c9df7ac12c504f8918552a7cf2)
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:
@@ -141,9 +159,9 @@ set(OPENMP_URI https://github.com/llvm/llvm-project/releases/download/llvmorg-${
set(OPENMP_HASH_TYPE MD5)
set(OPENMP_FILE openmp-${OPENMP_VERSION}.src.tar.xz)
-set(OPENIMAGEIO_VERSION v2.3.13.0)
+set(OPENIMAGEIO_VERSION v2.3.20.0)
set(OPENIMAGEIO_URI https://github.com/OpenImageIO/oiio/archive/refs/tags/${OPENIMAGEIO_VERSION}.tar.gz)
-set(OPENIMAGEIO_HASH de45fb38501c4581062b522b53b6141c)
+set(OPENIMAGEIO_HASH defb1fe7c8e64bac60eb3cacaf5c3736)
set(OPENIMAGEIO_HASH_TYPE MD5)
set(OPENIMAGEIO_FILE OpenImageIO-${OPENIMAGEIO_VERSION}.tar.gz)
@@ -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,26 +187,30 @@ 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)
-set(OSL_HASH 63265472ce14548839ace2e21e401544)
+set(OSL_VERSION 1.12.6.2)
+set(OSL_URI https://github.com/AcademySoftwareFoundation/OpenShadingLanguage/archive/refs/tags/v${OSL_VERSION}.tar.gz)
+set(OSL_HASH 6fef11548adfdd3e5b25c49d2dae96ee)
set(OSL_HASH_TYPE MD5)
set(OSL_FILE OpenShadingLanguage-${OSL_VERSION}.tar.gz)
-set(PYTHON_VERSION 3.10.2)
+set(PYTHON_VERSION 3.10.8)
set(PYTHON_SHORT_VERSION 3.10)
set(PYTHON_SHORT_VERSION_NO_DOTS 310)
set(PYTHON_URI https://www.python.org/ftp/python/${PYTHON_VERSION}/Python-${PYTHON_VERSION}.tar.xz)
-set(PYTHON_HASH 14e8c22458ed7779a1957b26cde01db9)
+set(PYTHON_HASH e92356b012ed4d0e09675131d39b1bde)
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)
@@ -269,18 +298,20 @@ set(XVIDCORE_HASH abbdcbd39555691dd1c9b4d08f0a031376a3b211652c0d8b3b8aa9be1303ce
set(XVIDCORE_HASH_TYPE SHA256)
set(XVIDCORE_FILE xvidcore-${XVIDCORE_VERSION}.tar.gz)
-set(OPENJPEG_VERSION 2.4.0)
-set(OPENJPEG_SHORT_VERSION 2.4)
+set(OPENJPEG_VERSION 2.5.0)
+set(OPENJPEG_SHORT_VERSION 2.5)
set(OPENJPEG_URI https://github.com/uclouvain/openjpeg/archive/v${OPENJPEG_VERSION}.tar.gz)
-set(OPENJPEG_HASH 8702ba68b442657f11aaeb2b338443ca8d5fb95b0d845757968a7be31ef7f16d)
+set(OPENJPEG_HASH 0333806d6adecc6f7a91243b2b839ff4d2053823634d4f6ed7a59bc87409122a)
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_VERSION 5.1.2)
set(FFMPEG_URI http://ffmpeg.org/releases/ffmpeg-${FFMPEG_VERSION}.tar.bz2)
-set(FFMPEG_HASH c0130b8db2c763430fd1c6905288d61bc44ee0548ad5fcd2dfd650b88432bed9)
+set(FFMPEG_HASH 39a0bcc8d98549f16c570624678246a6ac736c066cebdb409f9502e915b22f2b)
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)
@@ -294,17 +325,19 @@ set(ICONV_HASH 7d2a800b952942bb2880efb00cfd524c)
set(ICONV_HASH_TYPE MD5)
set(ICONV_FILE libiconv-${ICONV_VERSION}.tar.gz)
-set(SNDFILE_VERSION 1.0.28)
-set(SNDFILE_URI http://www.mega-nerd.com/libsndfile/files/libsndfile-${SNDFILE_VERSION}.tar.gz)
-set(SNDFILE_HASH 646b5f98ce89ac60cdb060fcd398247c)
+set(SNDFILE_VERSION 1.1.0)
+set(SNDFILE_URI https://github.com/libsndfile/libsndfile/releases/download/1.1.0/libsndfile-${SNDFILE_VERSION}.tar.xz)
+set(SNDFILE_HASH e63dead2b4f0aaf323687619d007ee6a)
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)
@@ -318,24 +351,19 @@ set(JEMALLOC_HASH 3d41fbf006e6ebffd489bdb304d009ae)
set(JEMALLOC_HASH_TYPE MD5)
set(JEMALLOC_FILE jemalloc-${JEMALLOC_VERSION}.tar.bz2)
-set(XML2_VERSION 2.9.10)
-set(XML2_URI http://xmlsoft.org/sources/libxml2-${XML2_VERSION}.tar.gz)
-set(XML2_HASH 10942a1dc23137a8aa07f0639cbfece5)
+set(XML2_VERSION 2.10.3)
+set(XML2_URI https://download.gnome.org/sources/libxml2/2.10/libxml2-${XML2_VERSION}.tar.xz)
+set(XML2_HASH f9edac7fac232b3657a003fd9a5bbe42)
set(XML2_HASH_TYPE MD5)
-set(XML2_FILE libxml2-${XML2_VERSION}.tar.gz)
-
-set(TINYXML_VERSION 2_6_2)
-set(TINYXML_VERSION_DOTS 2.6.2)
-set(TINYXML_URI https://nchc.dl.sourceforge.net/project/tinyxml/tinyxml/${TINYXML_VERSION_DOTS}/tinyxml_${TINYXML_VERSION}.tar.gz)
-set(TINYXML_HASH c1b864c96804a10526540c664ade67f0)
-set(TINYXML_HASH_TYPE MD5)
-set(TINYXML_FILE tinyxml_${TINYXML_VERSION}.tar.gz)
+set(XML2_FILE libxml2-${XML2_VERSION}.tar.xz)
+set(XML2_CPE "cpe:2.3:a:xmlsoft:libxml2:${XML2_VERSION}:*:*:*:*:*:*:*")
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})
@@ -343,17 +371,20 @@ set(PYSTRING_HASH f2c68786b359f5e4e62bed53bc4fb86d)
set(PYSTRING_HASH_TYPE MD5)
set(PYSTRING_FILE pystring-${PYSTRING_VERSION}.tar.gz)
-set(EXPAT_VERSION 2_4_4)
+set(EXPAT_VERSION 2_4_9)
+set(EXPAT_VERSION_DOTS 2.4.9)
set(EXPAT_URI https://github.com/libexpat/libexpat/archive/R_${EXPAT_VERSION}.tar.gz)
-set(EXPAT_HASH 2d3e81dee94b452369dc6394ff0f8f98)
+set(EXPAT_HASH b59a2aa796be1ee177bbab3b7231dfa5)
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)
@@ -371,17 +402,26 @@ set(FLEX_FILE flex-${FLEX_VERSION}.tar.gz)
# NOTE: bzip.org domain does no longer belong to BZip 2 project, so we download
# sources from Debian packaging.
+#
+# NOTE 2: This will *HAVE* to match the version python ships on windows which
+# is hardcoded in pythons PCbuild/get_externals.bat. For compliance reasons there
+# can be no exceptions to this.
set(BZIP2_VERSION 1.0.8)
set(BZIP2_URI http://http.debian.net/debian/pool/main/b/bzip2/bzip2_${BZIP2_VERSION}.orig.tar.gz)
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}:*:*:*:*:*:*:*")
+# NOTE: This will *HAVE* to match the version python ships on windows which
+# is hardcoded in pythons PCbuild/get_externals.bat. For compliance reasons there
+# can be no exceptions to this.
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)
@@ -389,26 +429,26 @@ set(LZMA_HASH 5117f930900b341493827d63aa910ff5e011e0b994197c3b71c08a20228a42df)
set(LZMA_HASH_TYPE SHA256)
set(LZMA_FILE xz-${LZMA_VERSION}.tar.bz2)
-if(BLENDER_PLATFORM_ARM)
- # Need at least 1.1.1i for aarch64 support (https://github.com/openssl/openssl/pull/13218)
- set(SSL_VERSION 1.1.1i)
- set(SSL_URI https://www.openssl.org/source/openssl-${SSL_VERSION}.tar.gz)
- set(SSL_HASH e8be6a35fe41d10603c3cc635e93289ed00bf34b79671a3a4de64fcee00d5242)
- set(SSL_HASH_TYPE SHA256)
- set(SSL_FILE openssl-${SSL_VERSION}.tar.gz)
-else()
- set(SSL_VERSION 1.1.1g)
- set(SSL_URI https://www.openssl.org/source/openssl-${SSL_VERSION}.tar.gz)
- set(SSL_HASH ddb04774f1e32f0c49751e21b67216ac87852ceb056b75209af2443400636d46)
- set(SSL_HASH_TYPE SHA256)
- set(SSL_FILE openssl-${SSL_VERSION}.tar.gz)
-endif()
-
-set(SQLITE_VERSION 3.31.1)
-set(SQLITE_URI https://www.sqlite.org/2018/sqlite-src-3240000.zip)
-set(SQLITE_HASH fb558c49ee21a837713c4f1e7e413309aabdd9c7)
+# NOTE: This will *HAVE* to match the version python ships on windows which
+# is hardcoded in pythons PCbuild/get_externals.bat. For compliance reasons there
+# can be no exceptions to this.
+set(SSL_VERSION 1.1.1q)
+set(SSL_URI https://www.openssl.org/source/openssl-${SSL_VERSION}.tar.gz)
+set(SSL_HASH d7939ce614029cdff0b6c20f0e2e5703158a489a72b2507b8bd51bf8c8fd10ca)
+set(SSL_HASH_TYPE SHA256)
+set(SSL_FILE openssl-${SSL_VERSION}.tar.gz)
+set(SSL_CPE "cpe:2.3:a:openssl:openssl:${SSL_VERSION}:*:*:*:*:*:*:*")
+
+# Note: This will *HAVE* to match the version python ships on windows which
+# is hardcoded in pythons PCbuild/get_externals.bat for compliance reasons there
+# can be no exceptions to this.
+set(SQLITE_VERSION 3.37.2)
+set(SQLLITE_LONG_VERSION 3370200)
+set(SQLITE_URI https://www.sqlite.org/2022/sqlite-autoconf-${SQLLITE_LONG_VERSION}.tar.gz)
+set(SQLITE_HASH e56faacadfb4154f8fbd0f2a3f827d13706b70a1)
set(SQLITE_HASH_TYPE SHA1)
-set(SQLITE_FILE sqlite-src-3240000.zip)
+set(SQLITE_FILE sqlite-autoconf-${SQLLITE_LONG_VERSION}.tar.gz)
+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 +479,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)
@@ -481,12 +523,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)
@@ -499,6 +543,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)
@@ -506,28 +551,29 @@ 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 1f090f88ab2bad028e8b3619aa926f4f97cf7b2c175b904704d2fec8593dd3cd)
set(OPENPGL_HASH_TYPE SHA256)
set(OPENPGL_FILE openpgl-${OPENPGL_VERSION}.tar.gz)
-set(LEVEL_ZERO_VERSION v1.7.15)
+set(LEVEL_ZERO_VERSION v1.8.5)
set(LEVEL_ZERO_URI https://github.com/oneapi-src/level-zero/archive/refs/tags/${LEVEL_ZERO_VERSION}.tar.gz)
-set(LEVEL_ZERO_HASH c39bb05a8e5898aa6c444e1704105b93d3f1888b9c333f8e7e73825ffbfb2617)
+set(LEVEL_ZERO_HASH b6e9663bbcc53c148d32376998298bec6f7c434ef2218c61fa708963e3a09394)
set(LEVEL_ZERO_HASH_TYPE SHA256)
set(LEVEL_ZERO_FILE level-zero-${LEVEL_ZERO_VERSION}.tar.gz)
-set(DPCPP_VERSION 20220812)
+set(DPCPP_VERSION 20221019)
set(DPCPP_URI https://github.com/intel/llvm/archive/refs/tags/sycl-nightly/${DPCPP_VERSION}.tar.gz)
-set(DPCPP_HASH 0e3c95346c295f5cf80f3a42d80b1c49481955898530242636ddc002627248d6)
+set(DPCPP_HASH 2f533946e91ce3829431758ea17b0b834b960c1a796e9e4563c86e03eb9603a2)
set(DPCPP_HASH_TYPE SHA256)
set(DPCPP_FILE DPCPP-${DPCPP_VERSION}.tar.gz)
@@ -540,9 +586,9 @@ set(DPCPP_FILE DPCPP-${DPCPP_VERSION}.tar.gz)
# will take care of building them, unpack is being done in dpcpp_deps.cmake
# Source llvm/lib/SYCLLowerIR/CMakeLists.txt
-set(VCINTRINSICS_VERSION 984bb27baacce6ee5c716c2e64845f2a1928025b)
+set(VCINTRINSICS_VERSION abce9184b7a3a7fe1b02289b9285610d9dc45465)
set(VCINTRINSICS_URI https://github.com/intel/vc-intrinsics/archive/${VCINTRINSICS_VERSION}.tar.gz)
-set(VCINTRINSICS_HASH abea415a15a0dd11fdc94dee8fb462910f2548311b787e02f42509789e1b0d7b)
+set(VCINTRINSICS_HASH 3e9fd471246b87633b26f7e15e17ab7733d357458c53d5c5881c03929d6c551f)
set(VCINTRINSICS_HASH_TYPE SHA256)
set(VCINTRINSICS_FILE vc-intrinsics-${VCINTRINSICS_VERSION}.tar.gz)
@@ -554,9 +600,9 @@ set(OPENCLHEADERS_HASH_TYPE SHA256)
set(OPENCLHEADERS_FILE opencl_headers-${OPENCLHEADERS_VERSION}.tar.gz)
# Source opencl/CMakeLists.txt
-set(ICDLOADER_VERSION aec3952654832211636fc4af613710f80e203b0a)
+set(ICDLOADER_VERSION 792682ad3d877ab38573b997808bab3b43902b70)
set(ICDLOADER_URI https://github.com/KhronosGroup/OpenCL-ICD-Loader/archive/${ICDLOADER_VERSION}.tar.gz)
-set(ICDLOADER_HASH e1880551d67bd8dc31d13de63b94bbfd6b1f315b6145dad1ffcd159b89bda93c)
+set(ICDLOADER_HASH b33a0320d94bf300efa1da97931ded506d27813bd1148da6858fe79d412d1ea2)
set(ICDLOADER_HASH_TYPE SHA256)
set(ICDLOADER_FILE icdloader-${ICDLOADER_VERSION}.tar.gz)
@@ -571,9 +617,9 @@ set(MP11_FILE mp11-${MP11_VERSION}.tar.gz)
# Source llvm-spirv/CMakeLists.txt (repo)
# Source llvm-spirv/spirv-headers-tag.conf (hash)
-set(SPIRV_HEADERS_VERSION 36c0c1596225e728bd49abb7ef56a3953e7ed468)
+set(SPIRV_HEADERS_VERSION 5a121866927a16ab9d49bed4788b532c7fcea766)
set(SPIRV_HEADERS_URI https://github.com/KhronosGroup/SPIRV-Headers/archive/${SPIRV_HEADERS_VERSION}.tar.gz)
-set(SPIRV_HEADERS_HASH 7a5c89633f8740456fe8adee052033e134476d267411d1336c0cb1e587a9229a)
+set(SPIRV_HEADERS_HASH ec8ecb471a62672697846c436501638ab25447ae9d4a6761e0bfe8a9a839502a)
set(SPIRV_HEADERS_HASH_TYPE SHA256)
set(SPIRV_HEADERS_FILE SPIR-V-Headers-${SPIRV_HEADERS_VERSION}.tar.gz)
@@ -588,9 +634,9 @@ set(SPIRV_HEADERS_FILE SPIR-V-Headers-${SPIRV_HEADERS_VERSION}.tar.gz)
# compiler, the versions used are taken from the following location
# https://github.com/intel/intel-graphics-compiler/releases
-set(IGC_VERSION 1.0.11222)
+set(IGC_VERSION 1.0.12149.1)
set(IGC_URI https://github.com/intel/intel-graphics-compiler/archive/refs/tags/igc-${IGC_VERSION}.tar.gz)
-set(IGC_HASH d92f0608dcbb52690855685f9447282e5c09c0ba98ae35fabf114fcf8b1e9fcf)
+set(IGC_HASH 44f67f24e3bc5130f9f062533abf8154782a9d0a992bc19b498639a8521ae836)
set(IGC_HASH_TYPE SHA256)
set(IGC_FILE igc-${IGC_VERSION}.tar.gz)
@@ -610,15 +656,15 @@ set(IGC_LLVM_FILE ${IGC_LLVM_VERSION}.tar.gz)
#
# WARNING WARNING WARNING
-set(IGC_OPENCL_CLANG_VERSION bbdd1587f577397a105c900be114b56755d1f7dc)
+set(IGC_OPENCL_CLANG_VERSION 363a5262d8c7cff3fb28f3bdb5d85c8d7e91c1bb)
set(IGC_OPENCL_CLANG_URI https://github.com/intel/opencl-clang/archive/${IGC_OPENCL_CLANG_VERSION}.tar.gz)
-set(IGC_OPENCL_CLANG_HASH d08315f1b0d8a6fef33de2b3e6aa7356534c324910634962c72523d970773efc)
+set(IGC_OPENCL_CLANG_HASH aa8cf72bb239722ce8ce44f79413c6887ecc8ca18477dd520aa5c4809756da9a)
set(IGC_OPENCL_CLANG_HASH_TYPE SHA256)
set(IGC_OPENCL_CLANG_FILE opencl-clang-${IGC_OPENCL_CLANG_VERSION}.tar.gz)
-set(IGC_VCINTRINSICS_VERSION v0.4.0)
+set(IGC_VCINTRINSICS_VERSION v0.5.0)
set(IGC_VCINTRINSICS_URI https://github.com/intel/vc-intrinsics/archive/refs/tags/${IGC_VCINTRINSICS_VERSION}.tar.gz)
-set(IGC_VCINTRINSICS_HASH c8b92682ad5031cf9d5b82a40e7d5c0e763cd9278660adbcaa69aab988e4b589)
+set(IGC_VCINTRINSICS_HASH 70bb47c5e32173cf61514941e83ae7c7eb4485e6d2fca60cfa1f50d4f42c41f2)
set(IGC_VCINTRINSICS_HASH_TYPE SHA256)
set(IGC_VCINTRINSICS_FILE vc-intrinsics-${IGC_VCINTRINSICS_VERSION}.tar.gz)
@@ -634,9 +680,9 @@ set(IGC_SPIRV_TOOLS_HASH 6e19900e948944243024aedd0a201baf3854b377b9cc7a386553bc1
set(IGC_SPIRV_TOOLS_HASH_TYPE SHA256)
set(IGC_SPIRV_TOOLS_FILE SPIR-V-Tools-${IGC_SPIRV_TOOLS_VERSION}.tar.gz)
-set(IGC_SPIRV_TRANSLATOR_VERSION 99420daab98998a7e36858befac9c5ed109d4920)
+set(IGC_SPIRV_TRANSLATOR_VERSION a31ffaeef77e23d500b3ea3d35e0c42ff5648ad9)
set(IGC_SPIRV_TRANSLATOR_URI https://github.com/KhronosGroup/SPIRV-LLVM-Translator/archive/${IGC_SPIRV_TRANSLATOR_VERSION}.tar.gz)
-set(IGC_SPIRV_TRANSLATOR_HASH 77dfb4ddb6bfb993535562c02ddea23f0a0d1c5a0258c1afe7e27c894ff783a8)
+set(IGC_SPIRV_TRANSLATOR_HASH 9e26c96a45341b8f8af521bacea20e752623346340addd02af95d669f6e89252)
set(IGC_SPIRV_TRANSLATOR_HASH_TYPE SHA256)
set(IGC_SPIRV_TRANSLATOR_FILE SPIR-V-Translator-${IGC_SPIRV_TRANSLATOR_VERSION}.tar.gz)
@@ -644,15 +690,15 @@ set(IGC_SPIRV_TRANSLATOR_FILE SPIR-V-Translator-${IGC_SPIRV_TRANSLATOR_VERSION}.
### Intel Graphics Compiler DEPS END ###
########################################
-set(GMMLIB_VERSION intel-gmmlib-22.1.2)
+set(GMMLIB_VERSION intel-gmmlib-22.1.8)
set(GMMLIB_URI https://github.com/intel/gmmlib/archive/refs/tags/${GMMLIB_VERSION}.tar.gz)
-set(GMMLIB_HASH 3b9a6d5e7e3f5748b3d0a2fb0e980ae943907fece0980bd9c0508e71c838e334)
+set(GMMLIB_HASH bf23e9a3742b4fb98c7666c9e9b29f3219e4b2fb4d831aaf4eed71f5e2d17368)
set(GMMLIB_HASH_TYPE SHA256)
set(GMMLIB_FILE ${GMMLIB_VERSION}.tar.gz)
-set(OCLOC_VERSION 22.20.23198)
+set(OCLOC_VERSION 22.38.24278)
set(OCLOC_URI https://github.com/intel/compute-runtime/archive/refs/tags/${OCLOC_VERSION}.tar.gz)
-set(OCLOC_HASH ab22b8bf2560a57fdd3def0e35a62ca75991406f959c0263abb00cd6cd9ae998)
+set(OCLOC_HASH db0c542fccd651e6404b15a74d46027f1ce0eda8dc9e25a40cbb6c0faef257ee)
set(OCLOC_HASH_TYPE SHA256)
set(OCLOC_FILE ocloc-${OCLOC_VERSION}.tar.gz)
diff --git a/build_files/build_environment/cmake/wayland.cmake b/build_files/build_environment/cmake/wayland.cmake
index 799f2513da9..c73db1d10ff 100644
--- a/build_files/build_environment/cmake/wayland.cmake
+++ b/build_files/build_environment/cmake/wayland.cmake
@@ -7,10 +7,14 @@ ExternalProject_Add(external_wayland
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 & LIBXML2.
- # Note that passing link args "ffi/lib" should not be needed, but
+ #
+ # NOTE: passing link args "ffi/lib" should not be needed, but
# `pkgconfig` would incorrectly look in "ffi/lib/../lib64" otherwise.
+ #
+ # NOTE: `-lm` is needed for `libxml2` which is a static library that uses `libm.so`,
+ # without this, math symbols such as `floor` aren't found.
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
+ meson --prefix ${LIBDIR}/wayland -Ddocumentation=false -Dtests=false -D "c_link_args=-L${LIBDIR}/ffi/lib -lm" . ../external_wayland
BUILD_COMMAND ninja
INSTALL_COMMAND ninja install
)
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/cmake/xml2.cmake b/build_files/build_environment/cmake/xml2.cmake
index cd24fd836b0..3d31ec131bb 100644
--- a/build_files/build_environment/cmake/xml2.cmake
+++ b/build_files/build_environment/cmake/xml2.cmake
@@ -1,20 +1,48 @@
# SPDX-License-Identifier: GPL-2.0-or-later
-ExternalProject_Add(external_xml2
- URL file://${PACKAGE_DIR}/${XML2_FILE}
- DOWNLOAD_DIR ${DOWNLOAD_DIR}
- URL_HASH ${XML2_HASH_TYPE}=${XML2_HASH}
- PREFIX ${BUILD_DIR}/xml2
- CONFIGURE_COMMAND ${CONFIGURE_ENV} && cd ${BUILD_DIR}/xml2/src/external_xml2/ && ${CONFIGURE_COMMAND}
- --prefix=${LIBDIR}/xml2
- --disable-shared
- --enable-static
- --with-pic
- --with-python=no
- --with-lzma=no
- --with-zlib=no
- --with-iconv=no
- BUILD_COMMAND ${CONFIGURE_ENV} && cd ${BUILD_DIR}/xml2/src/external_xml2/ && make -j${MAKE_THREADS}
- INSTALL_COMMAND ${CONFIGURE_ENV} && cd ${BUILD_DIR}/xml2/src/external_xml2/ && make install
- INSTALL_DIR ${LIBDIR}/xml2
-)
+if(WIN32)
+ set(XML2_EXTRA_ARGS
+ -DLIBXML2_WITH_ZLIB=OFF
+ -DLIBXML2_WITH_LZMA=OFF
+ -DLIBXML2_WITH_PYTHON=OFF
+ -DLIBXML2_WITH_ICONV=OFF
+ -DLIBXML2_WITH_TESTS=OFF
+ -DLIBXML2_WITH_PROGRAMS=OFF
+ -DBUILD_SHARED_LIBS=OFF
+ )
+ ExternalProject_Add(external_xml2
+ URL file://${PACKAGE_DIR}/${XML2_FILE}
+ DOWNLOAD_DIR ${DOWNLOAD_DIR}
+ URL_HASH ${XML2_HASH_TYPE}=${XML2_HASH}
+ CMAKE_ARGS -DCMAKE_INSTALL_PREFIX=${LIBDIR}/xml2 ${DEFAULT_CMAKE_FLAGS} ${XML2_EXTRA_ARGS}
+ PREFIX ${BUILD_DIR}/xml2
+ INSTALL_DIR ${LIBDIR}/xml2
+ )
+else()
+ ExternalProject_Add(external_xml2
+ URL file://${PACKAGE_DIR}/${XML2_FILE}
+ DOWNLOAD_DIR ${DOWNLOAD_DIR}
+ URL_HASH ${XML2_HASH_TYPE}=${XML2_HASH}
+ PREFIX ${BUILD_DIR}/xml2
+ CONFIGURE_COMMAND ${CONFIGURE_ENV} && cd ${BUILD_DIR}/xml2/src/external_xml2/ && ${CONFIGURE_COMMAND}
+ --prefix=${LIBDIR}/xml2
+ --disable-shared
+ --enable-static
+ --with-pic
+ --with-python=no
+ --with-lzma=no
+ --with-zlib=no
+ --with-iconv=no
+ BUILD_COMMAND ${CONFIGURE_ENV} && cd ${BUILD_DIR}/xml2/src/external_xml2/ && make -j${MAKE_THREADS}
+ INSTALL_COMMAND ${CONFIGURE_ENV} && cd ${BUILD_DIR}/xml2/src/external_xml2/ && make install
+ INSTALL_DIR ${LIBDIR}/xml2
+ )
+endif()
+
+if(WIN32 AND BUILD_MODE STREQUAL Release)
+ ExternalProject_Add_Step(external_xml2 after_install
+ COMMAND ${CMAKE_COMMAND} -E copy_directory ${LIBDIR}/xml2/include ${HARVEST_TARGET}/xml2/include
+ COMMAND ${CMAKE_COMMAND} -E copy ${LIBDIR}/xml2/lib/libxml2s.lib ${HARVEST_TARGET}/xml2/lib/libxml2s.lib
+ DEPENDEES install
+ )
+endif()
diff --git a/build_files/build_environment/dependencies.dot b/build_files/build_environment/dependencies.dot
index 7e8637fbced..bb42856c3ac 100644
--- a/build_files/build_environment/dependencies.dot
+++ b/build_files/build_environment/dependencies.dot
@@ -1,96 +1,114 @@
strict graph {
-graph[autosize = false, size = "25.7,8.3!", resolution = 300, overlap = false, splines = false, outputorder=edgesfirst ];
- node [style=filled fillcolor=white];
- external_alembic -- external_boost;
- external_alembic -- external_zlib;
+graph[autosize = false, size = "25.7,8.3!", resolution = 300];
external_alembic -- external_openexr;
+ external_alembic -- external_imath;
external_blosc -- external_zlib;
external_blosc -- external_pthreads;
- external_boost -- Make_Python_Environment;
- external_clang -- ll;
+ external_boost -- external_python;
+ external_boost -- external_numpy;
+ external_dpcpp -- external_python;
+ external_dpcpp -- external_python_site_packages;
+ external_dpcpp -- external_vcintrinsics;
+ external_dpcpp -- external_openclheaders;
+ external_dpcpp -- external_icdloader;
+ external_dpcpp -- external_mp11;
+ external_dpcpp -- external_level_zero;
+ external_dpcpp -- external_spirvheaders;
+ external_embree -- external_tbb;
external_ffmpeg -- external_zlib;
- external_ffmpeg -- external_faad;
external_ffmpeg -- external_openjpeg;
external_ffmpeg -- external_xvidcore;
external_ffmpeg -- external_x264;
+ external_ffmpeg -- external_opus;
external_ffmpeg -- external_vpx;
external_ffmpeg -- external_theora;
external_ffmpeg -- external_vorbis;
external_ffmpeg -- external_ogg;
external_ffmpeg -- external_lame;
+ external_ffmpeg -- external_aom;
external_ffmpeg -- external_zlib_mingw;
- external_numpy -- Make_Python_Environment;
+ external_ffmpeg -- external_nasm;
+ external_freetype -- external_brotli;
+ external_freetype -- external_zlib;
+ external_gmpxx -- external_gmp;
+ external_igc_llvm -- external_igc_opencl_clang;
+ external_igc_spirv_translator -- external_igc_opencl_clang;
+ external_igc -- external_igc_vcintrinsics;
+ external_igc -- external_igc_llvm;
+ external_igc -- external_igc_opencl_clang;
+ external_igc -- external_igc_vcintrinsics;
+ external_igc -- external_igc_spirv_headers;
+ external_igc -- external_igc_spirv_tools;
+ external_igc -- external_igc_spirv_translator;
+ external_igc -- external_flex;
+ external_ispc -- ll;
+ external_ispc -- external_python;
+ external_ispc -- external_flexbison;
+ external_ispc -- external_flex;
+ ll -- external_xml2;
+ ll -- external_python;
+ external_mesa -- ll;
+ external_numpy -- external_python;
+ external_numpy -- external_python_site_packages;
+ external_ocloc -- external_igc;
+ external_ocloc -- external_gmmlib;
external_opencollada -- external_xml2;
- external_opencolorio -- external_boost;
- external_opencolorio -- external_tinyxml;
external_opencolorio -- external_yamlcpp;
+ external_opencolorio -- external_expat;
+ external_opencolorio -- external_imath;
+ external_opencolorio -- external_pystring;
external_openexr -- external_zlib;
+ external_openimagedenoise -- external_tbb;
+ external_openimagedenoise -- external_ispc;
+ external_openimagedenoise -- external_python;
external_openimageio -- external_png;
external_openimageio -- external_zlib;
external_openimageio -- external_openexr;
- external_openimageio -- external_openexr;
+ external_openimageio -- external_imath;
external_openimageio -- external_jpeg;
external_openimageio -- external_boost;
external_openimageio -- external_tiff;
- external_openimageio -- external_opencolorio;
+ external_openimageio -- external_pugixml;
+ external_openimageio -- external_fmt;
+ external_openimageio -- external_robinmap;
external_openimageio -- external_openjpeg;
external_openimageio -- external_webp;
- external_openimageio -- external_opencolorio_extra;
- external_openmp -- external_clang;
+ external_openmp -- ll;
+ external_openpgl -- external_tbb;
external_opensubdiv -- external_tbb;
openvdb -- external_tbb;
openvdb -- external_boost;
- openvdb -- external_openexr;
- openvdb -- external_openexr;
openvdb -- external_zlib;
openvdb -- external_blosc;
external_osl -- external_boost;
external_osl -- ll;
- external_osl -- external_clang;
- external_osl -- external_openexr;
external_osl -- external_openexr;
external_osl -- external_zlib;
- external_osl -- external_flexbison;
external_osl -- external_openimageio;
external_osl -- external_pugixml;
+ external_osl -- external_flexbison;
+ external_osl -- external_flex;
external_png -- external_zlib;
- external_python_site_packages -- Make_Python_Environment;
+ external_python -- external_bzip2;
+ external_python -- external_ffi;
+ external_python -- external_lzma;
+ external_python -- external_ssl;
+ external_python -- external_sqlite;
+ external_python -- external_zlib;
+ external_python_site_packages -- external_python;
external_sndfile -- external_ogg;
external_sndfile -- external_vorbis;
external_sndfile -- external_flac;
external_theora -- external_vorbis;
external_theora -- external_ogg;
external_tiff -- external_zlib;
+ external_usd -- external_tbb;
+ external_usd -- external_boost;
+ external_usd -- external_opensubdiv;
external_vorbis -- external_ogg;
- blender-- external_ffmpeg;
- blender-- external_alembic;
- blender-- external_openjpeg;
- blender-- external_opencolorio;
- blender-- external_openexr;
- blender-- external_opensubdiv;
- blender-- openvdb;
- blender-- external_osl;
- blender-- external_boost;
- blender-- external_jpeg;
- blender-- external_png;
- blender-- external_python;
- blender-- external_sndfile;
- blender-- external_iconv;
- blender-- external_fftw3;
- external_python-- external_python_site_packages;
- external_python_site_packages-- requests;
- external_python_site_packages-- idna;
- external_python_site_packages-- chardet;
- external_python_site_packages-- urllib3;
- external_python_site_packages-- certifi;
- external_python-- external_numpy;
- external_usd-- external_boost;
- external_usd-- external_tbb;
- blender-- external_opencollada;
- blender-- external_sdl;
- blender-- external_freetype;
- blender-- external_pthreads;
- blender-- external_zlib;
- blender-- external_openal;
- blender-- external_usd;
+ external_wayland -- external_expat;
+ external_wayland -- external_xml2;
+ external_wayland -- external_ffi;
+ external_wayland_protocols -- external_wayland;
+ external_x264 -- external_nasm;
}
diff --git a/build_files/build_environment/install_deps.sh b/build_files/build_environment/install_deps.sh
index 5de0547727d..5a191f7669b 100755
--- a/build_files/build_environment/install_deps.sh
+++ b/build_files/build_environment/install_deps.sh
@@ -394,7 +394,7 @@ CLANG_FORMAT_VERSION="10.0"
CLANG_FORMAT_VERSION_MIN="6.0"
CLANG_FORMAT_VERSION_MEX="14.0"
-PYTHON_VERSION="3.10.2"
+PYTHON_VERSION="3.10.8"
PYTHON_VERSION_SHORT="3.10"
PYTHON_VERSION_MIN="3.10"
PYTHON_VERSION_MEX="3.12"
@@ -505,7 +505,7 @@ OPENEXR_FORCE_REBUILD=false
OPENEXR_SKIP=false
_with_built_openexr=false
-OIIO_VERSION="2.3.13.0"
+OIIO_VERSION="2.3.20.0"
OIIO_VERSION_SHORT="2.3"
OIIO_VERSION_MIN="2.1.12"
OIIO_VERSION_MEX="2.4.0"
@@ -523,8 +523,8 @@ LLVM_FORCE_REBUILD=false
LLVM_SKIP=false
# OSL needs to be compiled for now!
-OSL_VERSION="1.11.17.0"
-OSL_VERSION_SHORT="1.11"
+OSL_VERSION="1.12.6.2"
+OSL_VERSION_SHORT="1.12"
OSL_VERSION_MIN="1.11"
OSL_VERSION_MEX="2.0"
OSL_FORCE_BUILD=false
@@ -602,10 +602,10 @@ LEVEL_ZERO_FORCE_BUILD=false
LEVEL_ZERO_FORCE_REBUILD=false
LEVEL_ZERO_SKIP=false
-OPENPGL_VERSION="0.3.1"
-OPENPGL_VERSION_SHORT="0.3"
+OPENPGL_VERSION="0.4.0"
+OPENPGL_VERSION_SHORT="0.4"
OPENPGL_VERSION_MIN="0.3.1"
-OPENPGL_VERSION_MEX="0.3.2"
+OPENPGL_VERSION_MEX="0.5"
OPENPGL_FORCE_BUILD=false
OPENPGL_FORCE_REBUILD=false
OPENPGL_SKIP=false
@@ -618,8 +618,8 @@ XR_OPENXR_FORCE_BUILD=false
XR_OPENXR_FORCE_REBUILD=false
XR_OPENXR_SKIP=false
-FFMPEG_VERSION="5.0"
-FFMPEG_VERSION_SHORT="5.0"
+FFMPEG_VERSION="5.1.2"
+FFMPEG_VERSION_SHORT="5.1"
FFMPEG_VERSION_MIN="4.0"
FFMPEG_VERSION_MEX="6.0"
FFMPEG_FORCE_BUILD=false
@@ -1139,7 +1139,7 @@ LLVM_SOURCE=( "$_LLVM_SOURCE_ROOT/llvm-$LLVM_VERSION.src.tar.xz" )
LLVM_CLANG_SOURCE=( "$_LLVM_SOURCE_ROOT/clang-$LLVM_VERSION.src.tar.xz" "$_LLVM_SOURCE_ROOT/cfe-$LLVM_VERSION.src.tar.xz" )
OSL_USE_REPO=false
-OSL_SOURCE=( "https://github.com/imageworks/OpenShadingLanguage/archive/Release-$OSL_VERSION.tar.gz" )
+OSL_SOURCE=( "https://github.com/imageworks/OpenShadingLanguage/archive/v$OSL_VERSION.tar.gz" )
#~ OSL_SOURCE_REPO=( "https://github.com/imageworks/OpenShadingLanguage.git" )
#~ OSL_SOURCE_REPO_BRANCH="master"
#~ OSL_SOURCE_REPO_UID="85179714e1bc69cd25ecb6bb711c1a156685d395"
@@ -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/build_environment/patches/aom.diff b/build_files/build_environment/patches/aom.diff
new file mode 100644
index 00000000000..1611cff5dca
--- /dev/null
+++ b/build_files/build_environment/patches/aom.diff
@@ -0,0 +1,18 @@
+diff -Naur libaom-3.4.0/build/cmake/aom_configure.cmake external_aom/build/cmake/aom_configure.cmake
+--- libaom-3.4.0/build/cmake/aom_configure.cmake 2022-06-17 11:46:18 -0600
++++ external_aom/build/cmake/aom_configure.cmake 2022-10-16 15:35:54 -0600
+@@ -15,8 +15,12 @@
+
+ include(FindGit)
+ include(FindPerl)
+-include(FindThreads)
+-
++# Blender: This will drag in a dep on libwinpthreads which we prefer
++# not to have, aom will fallback on a native win32 thread wrapper
++# if pthreads are not found.
++if(NOT WIN32)
++ include(FindThreads)
++endif()
+ include("${AOM_ROOT}/build/cmake/aom_config_defaults.cmake")
+ include("${AOM_ROOT}/build/cmake/aom_experiment_deps.cmake")
+ include("${AOM_ROOT}/build/cmake/aom_optimization.cmake")
diff --git a/build_files/build_environment/patches/ffmpeg.diff b/build_files/build_environment/patches/ffmpeg.diff
index c255f7c37a3..ac104a20ffe 100644
--- a/build_files/build_environment/patches/ffmpeg.diff
+++ b/build_files/build_environment/patches/ffmpeg.diff
@@ -68,34 +68,18 @@
+
return ret;
}
---- a/libavcodec/rl.c
-+++ b/libavcodec/rl.c
-@@ -71,17 +71,19 @@
- av_cold void ff_rl_init_vlc(RLTable *rl, unsigned static_size)
- {
- int i, q;
-- VLC_TYPE table[1500][2] = {{0}};
-+ VLC_TYPE (*table)[2] = av_calloc(sizeof(VLC_TYPE), 1500 * 2);
- VLC vlc = { .table = table, .table_allocated = static_size };
-- av_assert0(static_size <= FF_ARRAY_ELEMS(table));
-+ av_assert0(static_size < 1500);
- init_vlc(&vlc, 9, rl->n + 1, &rl->table_vlc[0][1], 4, 2, &rl->table_vlc[0][0], 4, 2, INIT_VLC_USE_NEW_STATIC);
+diff --git a/libavcodec/x86/simple_idct.asm b/libavcodec/x86/simple_idct.asm
+index dcf0da6df121..982b2f0bbba1 100644
+--- a/libavcodec/x86/simple_idct.asm
++++ b/libavcodec/x86/simple_idct.asm
+@@ -25,9 +25,9 @@
- for (q = 0; q < 32; q++) {
- int qmul = q * 2;
- int qadd = (q - 1) | 1;
+ %include "libavutil/x86/x86util.asm"
-- if (!rl->rl_vlc[q])
-+ if (!rl->rl_vlc[q]){
-+ av_free(table);
- return;
-+ }
+-%if ARCH_X86_32
+ SECTION_RODATA
- if (q == 0) {
- qmul = 1;
-@@ -113,4 +115,5 @@
- rl->rl_vlc[q][i].run = run;
- }
- }
-+ av_free(table);
- }
++%if ARCH_X86_32
+ cextern pb_80
+
+ wm1010: dw 0, 0xffff, 0, 0xffff
diff --git a/build_files/build_environment/patches/gmp.diff b/build_files/build_environment/patches/gmp.diff
new file mode 100644
index 00000000000..bf22f93bc4f
--- /dev/null
+++ b/build_files/build_environment/patches/gmp.diff
@@ -0,0 +1,15 @@
+--- a/mpz/inp_raw.c Tue Dec 22 23:49:51 2020 +0100
++++ b/mpz/inp_raw.c Thu Oct 21 19:06:49 2021 +0200
+@@ -88,8 +88,11 @@
+
+ abs_csize = ABS (csize);
+
++ if (UNLIKELY (abs_csize > ~(mp_bitcnt_t) 0 / 8))
++ return 0; /* Bit size overflows */
++
+ /* round up to a multiple of limbs */
+- abs_xsize = BITS_TO_LIMBS (abs_csize*8);
++ abs_xsize = BITS_TO_LIMBS ((mp_bitcnt_t) abs_csize * 8);
+
+ if (abs_xsize != 0)
+ {
diff --git a/build_files/build_environment/patches/opencollada.diff b/build_files/build_environment/patches/opencollada.diff
index e8efc1a6909..02eab251a13 100644
--- a/build_files/build_environment/patches/opencollada.diff
+++ b/build_files/build_environment/patches/opencollada.diff
@@ -130,3 +130,28 @@ index 715d903..24423ce 100644
{
string id = node.attribute("id").value();
size_t line = node.line();
+diff -Naur a/CMakeLists.txt b/CMakeLists.txt
+--- a/CMakeLists.txt
++++ b/CMakeLists.txt
+@@ -274,7 +274,7 @@
+ add_subdirectory(${EXTERNAL_LIBRARIES}/UTF)
+ add_subdirectory(common/libBuffer)
+ add_subdirectory(${EXTERNAL_LIBRARIES}/MathMLSolver)
+-add_subdirectory(${EXTERNAL_LIBRARIES}/zlib)
++#add_subdirectory(${EXTERNAL_LIBRARIES}/zlib)
+
+ # building OpenCOLLADA libs
+ add_subdirectory(COLLADABaseUtils)
+@@ -284,10 +284,10 @@
+ add_subdirectory(COLLADAStreamWriter)
+
+ # building COLLADAValidator app
+-add_subdirectory(COLLADAValidator)
++#add_subdirectory(COLLADAValidator)
+
+ # DAE validator app
+-add_subdirectory(DAEValidator)
++#add_subdirectory(DAEValidator)
+
+ # Library export
+ install(EXPORT LibraryExport DESTINATION ${OPENCOLLADA_INST_CMAKECONFIG} FILE OpenCOLLADATargets.cmake)
diff --git a/build_files/build_environment/patches/osl.diff b/build_files/build_environment/patches/osl.diff
index 28e1d6e101d..3f4a485b037 100644
--- a/build_files/build_environment/patches/osl.diff
+++ b/build_files/build_environment/patches/osl.diff
@@ -1,67 +1,53 @@
-diff -Naur OpenShadingLanguage-Release-1.9.9/src/include/OSL/llvm_util.h external_osl/src/include/OSL/llvm_util.h
---- OpenShadingLanguage-Release-1.9.9/src/include/OSL/llvm_util.h 2018-05-01 16:39:02 -0600
-+++ external_osl/src/include/OSL/llvm_util.h 2018-08-25 14:05:00 -0600
-@@ -33,6 +33,8 @@
-
- #include <vector>
-
-+#define OSL_HAS_BLENDER_CLEANUP_FIX
-+
- #ifdef LLVM_NAMESPACE
- namespace llvm = LLVM_NAMESPACE;
- #endif
-@@ -487,6 +489,7 @@
- std::string func_name (llvm::Function *f);
-
- static size_t total_jit_memory_held ();
-+ static void Cleanup ();
-
- private:
- class MemoryManager;
-diff -Naur OpenShadingLanguage-Release-1.9.9/src/liboslexec/llvm_util.cpp external_osl/src/liboslexec/llvm_util.cpp
---- OpenShadingLanguage-Release-1.9.9/src/liboslexec/llvm_util.cpp 2018-05-01 16:39:02 -0600
-+++ external_osl/src/liboslexec/llvm_util.cpp 2018-08-25 14:04:27 -0600
-@@ -140,7 +140,10 @@
- };
-
-
--
-+void LLVM_Util::Cleanup ()
-+{
-+ if(jitmm_hold) jitmm_hold->clear();
-+}
-
- size_t
- LLVM_Util::total_jit_memory_held ()
-diff -Naur org/CMakeLists.txt external_osl/CMakeLists.txt
---- org/CMakeLists.txt 2020-12-01 12:37:15 -0700
-+++ external_osl/CMakeLists.txt 2021-01-20 13:26:50 -0700
-@@ -84,6 +84,11 @@
+diff -Naur OpenShadingLanguage-1.12.6.2/CMakeLists.txt external_osl/CMakeLists.txt
+--- OpenShadingLanguage-1.12.6.2/CMakeLists.txt 2022-09-30 17:43:53 -0600
++++ external_osl/CMakeLists.txt 2022-10-15 14:49:26 -0600
+@@ -101,6 +101,11 @@
CACHE STRING "Directory where OptiX PTX files will be installed")
set (CMAKE_DEBUG_POSTFIX "" CACHE STRING "Library naming postfix for Debug builds (e.g., '_debug')")
-
+
+set (USE_OIIO_STATIC ON CACHE BOOL "If OIIO is built static")
+if (USE_OIIO_STATIC)
+ add_definitions ("-DOIIO_STATIC_BUILD=1")
+ add_definitions ("-DOIIO_STATIC_DEFINE=1")
+endif ()
-
+
set (OSL_NO_DEFAULT_TEXTURESYSTEM OFF CACHE BOOL "Do not use create a raw OIIO::TextureSystem")
if (OSL_NO_DEFAULT_TEXTURESYSTEM)
-diff -Naur external_osl_orig/src/cmake/externalpackages.cmake external_osl/src/cmake/externalpackages.cmake
---- external_osl_orig/src/cmake/externalpackages.cmake 2021-06-01 13:44:18 -0600
-+++ external_osl/src/cmake/externalpackages.cmake 2021-06-28 07:44:32 -0600
-@@ -80,6 +80,7 @@
-
-
+diff -Naur OpenShadingLanguage-1.12.6.2/src/cmake/externalpackages.cmake external_osl/src/cmake/externalpackages.cmake
+--- OpenShadingLanguage-1.12.6.2/src/cmake/externalpackages.cmake 2022-09-30 17:43:53 -0600
++++ external_osl/src/cmake/externalpackages.cmake 2022-10-15 14:49:26 -0600
+@@ -77,6 +77,7 @@
+
+
checked_find_package (ZLIB REQUIRED) # Needed by several packages
+checked_find_package (PNG REQUIRED) # Needed since OIIO needs it
-
+
# IlmBase & OpenEXR
checked_find_package (OpenEXR REQUIRED
-diff -Naur external_osl_orig/src/liboslcomp/oslcomp.cpp external_osl/src/liboslcomp/oslcomp.cpp
---- external_osl_orig/src/liboslcomp/oslcomp.cpp 2021-06-01 13:44:18 -0600
-+++ external_osl/src/liboslcomp/oslcomp.cpp 2021-06-28 09:11:06 -0600
+diff -Naur OpenShadingLanguage-1.12.6.2/src/include/OSL/llvm_util.h external_osl/src/include/OSL/llvm_util.h
+--- OpenShadingLanguage-1.12.6.2/src/include/OSL/llvm_util.h 2022-09-30 17:43:53 -0600
++++ external_osl/src/include/OSL/llvm_util.h 2022-10-15 15:37:24 -0600
+@@ -9,6 +9,8 @@
+ #include <unordered_set>
+ #include <vector>
+
++#define OSL_HAS_BLENDER_CLEANUP_FIX
++
+ #ifdef LLVM_NAMESPACE
+ namespace llvm = LLVM_NAMESPACE;
+ #endif
+@@ -455,7 +457,7 @@
+ llvm::BasicBlock* masked_return_block() const;
+
+ bool is_masking_required() const { return m_is_masking_required; }
+-
++ static void Cleanup ();
+ struct ScopedMasking {
+ ScopedMasking() {}
+
+diff -Naur OpenShadingLanguage-1.12.6.2/src/liboslcomp/oslcomp.cpp external_osl/src/liboslcomp/oslcomp.cpp
+--- OpenShadingLanguage-1.12.6.2/src/liboslcomp/oslcomp.cpp 2022-09-30 17:43:53 -0600
++++ external_osl/src/liboslcomp/oslcomp.cpp 2022-10-15 14:49:26 -0600
@@ -21,6 +21,13 @@
#if !defined(__STDC_CONSTANT_MACROS)
# define __STDC_CONSTANT_MACROS 1
@@ -76,3 +62,50 @@ diff -Naur external_osl_orig/src/liboslcomp/oslcomp.cpp external_osl/src/liboslc
#include <clang/Basic/TargetInfo.h>
#include <clang/Frontend/CompilerInstance.h>
#include <clang/Frontend/TextDiagnosticPrinter.h>
+diff -Naur OpenShadingLanguage-1.12.6.2/src/liboslexec/llvm_util.cpp external_osl/src/liboslexec/llvm_util.cpp
+--- OpenShadingLanguage-1.12.6.2/src/liboslexec/llvm_util.cpp 2022-09-30 17:43:53 -0600
++++ external_osl/src/liboslexec/llvm_util.cpp 2022-10-15 15:53:11 -0600
+@@ -116,8 +116,6 @@
+ return { A.data(), size_t(A.size()) };
+ }
+
+-
+-
+ namespace pvt {
+
+ typedef llvm::SectionMemoryManager LLVMMemoryManager;
+@@ -182,6 +180,13 @@
+ ++jit_mem_hold_users;
+ }
+
++void
++LLVM_Util::Cleanup()
++{
++ if (jitmm_hold)
++ jitmm_hold->clear();
++}
++
+
+ LLVM_Util::ScopedJitMemoryUser::~ScopedJitMemoryUser()
+ {
+diff --git a/src/include/OSL/mask.h b/src/include/OSL/mask.h
+index 24197af..b9275f6 100644
+--- a/src/include/OSL/mask.h
++++ b/src/include/OSL/mask.h
+@@ -4,7 +4,6 @@
+
+ #pragma once
+
+-#include <immintrin.h>
+ #include <type_traits>
+
+ #include <OSL/oslconfig.h>
+@@ -23,6 +22,8 @@ using std::countr_zero;
+
+ #elif OSL_INTEL_CLASSIC_COMPILER_VERSION
+
++#include <immintrin.h>
++
+ OSL_FORCEINLINE int popcount(uint32_t x) noexcept { return _mm_popcnt_u32(x);}
+ OSL_FORCEINLINE int popcount(uint64_t x) noexcept { return _mm_popcnt_u64(x); }
+ OSL_FORCEINLINE int countr_zero(uint32_t x) noexcept { return _bit_scan_forward(x); }
diff --git a/build_files/build_environment/patches/python_windows.diff b/build_files/build_environment/patches/python_windows.diff
deleted file mode 100644
index f9c89a90fde..00000000000
--- a/build_files/build_environment/patches/python_windows.diff
+++ /dev/null
@@ -1,24 +0,0 @@
-diff -Naur orig/PCbuild/get_externals.bat Python-3.10.2/PCbuild/get_externals.bat
---- orig/PCbuild/get_externals.bat 2022-01-13 11:52:14 -0700
-+++ Python-3.10.2/PCbuild/get_externals.bat 2022-08-17 11:24:42 -0600
-@@ -51,7 +51,7 @@
- echo.Fetching external libraries...
-
- set libraries=
--set libraries=%libraries% bzip2-1.0.6
-+set libraries=%libraries% bzip2-1.0.8
- if NOT "%IncludeLibffiSrc%"=="false" set libraries=%libraries% libffi-3.3.0
- if NOT "%IncludeSSLSrc%"=="false" set libraries=%libraries% openssl-1.1.1m
- set libraries=%libraries% sqlite-3.35.5.0
- diff -Naur orig/PCbuild/python.props external_python/PCbuild/python.props
---- orig/PCbuild/python.props 2022-01-13 11:52:14 -0700
-+++ external_python/PCbuild/python.props 2022-08-17 11:38:38 -0600
-@@ -58,7 +58,7 @@
- <ExternalsDir Condition="$(ExternalsDir) == ''">$([System.IO.Path]::GetFullPath(`$(PySourcePath)externals`))</ExternalsDir>
- <ExternalsDir Condition="!HasTrailingSlash($(ExternalsDir))">$(ExternalsDir)\</ExternalsDir>
- <sqlite3Dir>$(ExternalsDir)sqlite-3.35.5.0\</sqlite3Dir>
-- <bz2Dir>$(ExternalsDir)bzip2-1.0.6\</bz2Dir>
-+ <bz2Dir>$(ExternalsDir)bzip2-1.0.8\</bz2Dir>
- <lzmaDir>$(ExternalsDir)xz-5.2.2\</lzmaDir>
- <libffiDir>$(ExternalsDir)libffi-3.3.0\</libffiDir>
- <libffiOutDir>$(ExternalsDir)libffi-3.3.0\$(ArchName)\</libffiOutDir>
diff --git a/build_files/build_environment/patches/sndfile.diff b/build_files/build_environment/patches/sndfile.diff
deleted file mode 100644
index ab43baa78df..00000000000
--- a/build_files/build_environment/patches/sndfile.diff
+++ /dev/null
@@ -1,42 +0,0 @@
---- src/Makefile.in 2017-09-26 01:28:47.000000000 +0300
-+++ src/Makefile.in 2017-09-26 01:19:06.000000000 +0300
-@@ -513,7 +513,7 @@
- libcommon_la_SOURCES = common.c file_io.c command.c pcm.c ulaw.c alaw.c \
- float32.c double64.c ima_adpcm.c ms_adpcm.c gsm610.c dwvw.c vox_adpcm.c \
- interleave.c strings.c dither.c cart.c broadcast.c audio_detect.c \
-- ima_oki_adpcm.c ima_oki_adpcm.h alac.c chunk.c ogg.c chanmap.c \
-+ ima_oki_adpcm.c ima_oki_adpcm.h alac.c chunk.c ogg.c chanmap.c \
- windows.c id3.c $(WIN_VERSION_FILE)
-
-
-@@ -719,10 +719,10 @@
- $(AM_V_CCLD)$(LINK) $(GSM610_libgsm_la_OBJECTS) $(GSM610_libgsm_la_LIBADD) $(LIBS)
-
- libcommon.la: $(libcommon_la_OBJECTS) $(libcommon_la_DEPENDENCIES) $(EXTRA_libcommon_la_DEPENDENCIES)
-- $(AM_V_CCLD)$(LINK) $(libcommon_la_OBJECTS) $(libcommon_la_LIBADD) $(LIBS)
-+ $(AM_V_CCLD)$(LINK) $(libcommon_la_OBJECTS) $(libcommon_la_LIBADD) $(LIBS) $(EXTERNAL_XIPH_LIBS)
-
- libsndfile.la: $(libsndfile_la_OBJECTS) $(libsndfile_la_DEPENDENCIES) $(EXTRA_libsndfile_la_DEPENDENCIES)
-- $(AM_V_CCLD)$(libsndfile_la_LINK) -rpath $(libdir) $(libsndfile_la_OBJECTS) $(libsndfile_la_LIBADD) $(LIBS)
-+ $(AM_V_CCLD)$(libsndfile_la_LINK) -rpath $(libdir) $(libsndfile_la_OBJECTS) $(libsndfile_la_LIBADD) $(LIBS) $(EXTERNAL_XIPH_LIBS)
-
- clean-checkPROGRAMS:
- @list='$(check_PROGRAMS)'; test -n "$$list" || exit 0; \
-@@ -924,7 +924,7 @@
- @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libsndfile_la_CPPFLAGS) $(CPPFLAGS) $(libsndfile_la_CFLAGS) $(CFLAGS) -c -o libsndfile_la-dwd.lo `test -f 'dwd.c' || echo '$(srcdir)/'`dwd.c
-
- libsndfile_la-flac.lo: flac.c
--@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libsndfile_la_CPPFLAGS) $(CPPFLAGS) $(libsndfile_la_CFLAGS) $(CFLAGS) -MT libsndfile_la-flac.lo -MD -MP -MF $(DEPDIR)/libsndfile_la-flac.Tpo -c -o libsndfile_la-flac.lo `test -f 'flac.c' || echo '$(srcdir)/'`flac.c
-+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libsndfile_la_CPPFLAGS) $(CPPFLAGS) $(libsndfile_la_CFLAGS) $(CFLAGS) $(EXTERNAL_XIPH_CFLAGS) -MT libsndfile_la-flac.lo -MD -MP -MF $(DEPDIR)/libsndfile_la-flac.Tpo -c -o libsndfile_la-flac.lo `test -f 'flac.c' || echo '$(srcdir)/'`flac.c
- @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libsndfile_la-flac.Tpo $(DEPDIR)/libsndfile_la-flac.Plo
- @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='flac.c' object='libsndfile_la-flac.lo' libtool=yes @AMDEPBACKSLASH@
- @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@@ -1092,7 +1092,7 @@
- @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libsndfile_la_CPPFLAGS) $(CPPFLAGS) $(libsndfile_la_CFLAGS) $(CFLAGS) -c -o libsndfile_la-rf64.lo `test -f 'rf64.c' || echo '$(srcdir)/'`rf64.c
-
- libsndfile_la-ogg_vorbis.lo: ogg_vorbis.c
--@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libsndfile_la_CPPFLAGS) $(CPPFLAGS) $(libsndfile_la_CFLAGS) $(CFLAGS) -MT libsndfile_la-ogg_vorbis.lo -MD -MP -MF $(DEPDIR)/libsndfile_la-ogg_vorbis.Tpo -c -o libsndfile_la-ogg_vorbis.lo `test -f 'ogg_vorbis.c' || echo '$(srcdir)/'`ogg_vorbis.c
-+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libsndfile_la_CPPFLAGS) $(CPPFLAGS) $(libsndfile_la_CFLAGS) $(CFLAGS) $(EXTERNAL_XIPH_CFLAGS) -MT libsndfile_la-ogg_vorbis.lo -MD -MP -MF $(DEPDIR)/libsndfile_la-ogg_vorbis.Tpo -c -o libsndfile_la-ogg_vorbis.lo `test -f 'ogg_vorbis.c' || echo '$(srcdir)/'`ogg_vorbis.c
- @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libsndfile_la-ogg_vorbis.Tpo $(DEPDIR)/libsndfile_la-ogg_vorbis.Plo
- @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='ogg_vorbis.c' object='libsndfile_la-ogg_vorbis.lo' libtool=yes @AMDEPBACKSLASH@
- @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
diff --git a/build_files/build_environment/patches/sqlite.diff b/build_files/build_environment/patches/sqlite.diff
deleted file mode 100644
index 80f1384f9cf..00000000000
--- a/build_files/build_environment/patches/sqlite.diff
+++ /dev/null
@@ -1,14 +0,0 @@
-Only in external_sqlite_orig: config.log
-diff -ru external_sqlite_orig/config.sub external_sqlite/config.sub
---- external_sqlite_orig/config.sub 2020-07-10 14:06:42.000000000 +0200
-+++ external_sqlite/config.sub 2020-07-10 14:10:24.000000000 +0200
-@@ -314,6 +314,7 @@
- # Recognize the basic CPU types with company name.
- 580-* \
- | a29k-* \
-+ | aarch64-* \
- | alpha-* | alphaev[4-8]-* | alphaev56-* | alphaev6[78]-* \
- | alpha64-* | alpha64ev[4-8]-* | alpha64ev56-* | alpha64ev6[78]-* \
- | alphapca5[67]-* | alpha64pca5[67]-* | arc-* \
-Only in external_sqlite: mksourceid
-Only in external_sqlite: sqlite3session.h
diff --git a/build_files/build_environment/patches/ssl.diff b/build_files/build_environment/patches/ssl.diff
new file mode 100644
index 00000000000..7bb4413952c
--- /dev/null
+++ b/build_files/build_environment/patches/ssl.diff
@@ -0,0 +1,10 @@
+--- ./test/v3ext.c 2022-07-05 11:08:33.000000000 +0200
++++ ./test/v3ext.c 2022-10-18 13:58:05.000000000 +0200
+@@ -8,6 +8,7 @@
+ */
+
+ #include <stdio.h>
++#include <string.h>
+ #include <openssl/x509.h>
+ #include <openssl/x509v3.h>
+ #include <openssl/pem.h>
diff --git a/build_files/cmake/Modules/FindOSL.cmake b/build_files/cmake/Modules/FindOSL.cmake
index ab5de53d3c9..a8d8344ae66 100644
--- a/build_files/cmake/Modules/FindOSL.cmake
+++ b/build_files/cmake/Modules/FindOSL.cmake
@@ -20,6 +20,7 @@ IF(NOT OSL_ROOT_DIR AND NOT $ENV{OSL_ROOT_DIR} STREQUAL "")
ENDIF()
SET(_osl_FIND_COMPONENTS
+ oslnoise
oslcomp
oslexec
oslquery
@@ -39,7 +40,6 @@ FIND_PATH(OSL_INCLUDE_DIR
include
)
-SET(_osl_LIBRARIES)
FOREACH(COMPONENT ${_osl_FIND_COMPONENTS})
STRING(TOUPPER ${COMPONENT} UPPERCOMPONENT)
@@ -51,9 +51,20 @@ FOREACH(COMPONENT ${_osl_FIND_COMPONENTS})
PATH_SUFFIXES
lib64 lib
)
- LIST(APPEND _osl_LIBRARIES "${OSL_${UPPERCOMPONENT}_LIBRARY}")
ENDFOREACH()
+# Note linking order matters, and oslnoise existence depends on version.
+SET(_osl_LIBRARIES ${OSL_OSLCOMP_LIBRARY})
+IF(APPLE)
+ list(APPEND _osl_LIBRARIES -force_load ${OSL_OSLEXEC_LIBRARY})
+ELSE()
+ list(APPEND _osl_LIBRARIES ${OSL_OSLEXEC_LIBRARY})
+ENDIF()
+list(APPEND _osl_LIBRARIES ${OSL_OSLQUERY_LIBRARY})
+IF(OSL_OSLNOISE_LIBRARY)
+ list(APPEND _osl_LIBRARIES ${OSL_OSLNOISE_LIBRARY})
+ENDIF()
+
FIND_PROGRAM(OSL_COMPILER oslc
HINTS ${_osl_SEARCH_DIRS}
PATH_SUFFIXES bin)
diff --git a/build_files/cmake/Modules/FindOpenSubdiv.cmake b/build_files/cmake/Modules/FindOpenSubdiv.cmake
index 37a2cddf3de..66d3b435c46 100644
--- a/build_files/cmake/Modules/FindOpenSubdiv.cmake
+++ b/build_files/cmake/Modules/FindOpenSubdiv.cmake
@@ -71,21 +71,6 @@ FIND_PACKAGE_HANDLE_STANDARD_ARGS(OpenSubdiv DEFAULT_MSG
IF(OPENSUBDIV_FOUND)
SET(OPENSUBDIV_LIBRARIES ${_opensubdiv_LIBRARIES})
SET(OPENSUBDIV_INCLUDE_DIRS ${OPENSUBDIV_INCLUDE_DIR})
-
- # Find available compute controllers.
-
- FIND_PACKAGE(OpenMP)
- IF(OPENMP_FOUND)
- SET(OPENSUBDIV_HAS_OPENMP TRUE)
- ELSE()
- SET(OPENSUBDIV_HAS_OPENMP FALSE)
- ENDIF()
-
- OPENSUBDIV_CHECK_CONTROLLER("tbbEvaluator.h" OPENSUBDIV_HAS_TBB)
- OPENSUBDIV_CHECK_CONTROLLER("clEvaluator.h" OPENSUBDIV_HAS_OPENCL)
- OPENSUBDIV_CHECK_CONTROLLER("cudaEvaluator.h" OPENSUBDIV_HAS_CUDA)
- OPENSUBDIV_CHECK_CONTROLLER("glXFBEvaluator.h" OPENSUBDIV_HAS_GLSL_TRANSFORM_FEEDBACK)
- OPENSUBDIV_CHECK_CONTROLLER("glComputeEvaluator.h" OPENSUBDIV_HAS_GLSL_COMPUTE)
ENDIF()
MARK_AS_ADVANCED(
diff --git a/build_files/cmake/Modules/FindSYCL.cmake b/build_files/cmake/Modules/FindSYCL.cmake
index 139ebad46b1..1ccbee179fb 100644
--- a/build_files/cmake/Modules/FindSYCL.cmake
+++ b/build_files/cmake/Modules/FindSYCL.cmake
@@ -30,6 +30,7 @@ SET(_sycl_search_dirs
# dpcpp binary.
FIND_PROGRAM(SYCL_COMPILER
NAMES
+ icpx
dpcpp
clang++
HINTS
@@ -45,6 +46,7 @@ FIND_PROGRAM(SYCL_COMPILER
if(NOT SYCL_COMPILER)
FIND_PROGRAM(SYCL_COMPILER
NAMES
+ icpx
dpcpp
HINTS
${_sycl_search_dirs}
@@ -55,6 +57,8 @@ endif()
FIND_LIBRARY(SYCL_LIBRARY
NAMES
+ sycl7
+ sycl6
sycl
HINTS
${_sycl_search_dirs}
@@ -63,34 +67,51 @@ FIND_LIBRARY(SYCL_LIBRARY
)
if(WIN32)
- string(REPLACE ".lib" "d.lib" SYCL_LIBRARY_DEBUG ${SYCL_LIBRARY})
- set(SYCL_LIBRARY_DEBUG ${SYCL_LIBRARY_DEBUG} CACHE FILEPATH "Path to SYCL debug library")
-else()
- set(SYCL_LIBRARY_DEBUG ${SYCL_LIBRARY} CACHE FILEPATH "Path to SYCL debug library")
+ FIND_LIBRARY(SYCL_LIBRARY_DEBUG
+ NAMES
+ sycl7d
+ sycl6d
+ sycld
+ HINTS
+ ${_sycl_search_dirs}
+ PATH_SUFFIXES
+ lib64 lib
+ )
endif()
FIND_PATH(SYCL_INCLUDE_DIR
NAMES
- CL/sycl.hpp
+ sycl/sycl.hpp
HINTS
${_sycl_search_dirs}
PATH_SUFFIXES
include
- include/sycl
)
+IF(EXISTS "${SYCL_INCLUDE_DIR}/sycl/version.hpp")
+ FILE(STRINGS "${SYCL_INCLUDE_DIR}/sycl/version.hpp" _libsycl_major_version REGEX "^#define __LIBSYCL_MAJOR_VERSION[ \t].*$")
+ STRING(REGEX MATCHALL "[0-9]+" _libsycl_major_version ${_libsycl_major_version})
+ FILE(STRINGS "${SYCL_INCLUDE_DIR}/sycl/version.hpp" _libsycl_minor_version REGEX "^#define __LIBSYCL_MINOR_VERSION[ \t].*$")
+ STRING(REGEX MATCHALL "[0-9]+" _libsycl_minor_version ${_libsycl_minor_version})
+ FILE(STRINGS "${SYCL_INCLUDE_DIR}/sycl/version.hpp" _libsycl_patch_version REGEX "^#define __LIBSYCL_PATCH_VERSION[ \t].*$")
+ STRING(REGEX MATCHALL "[0-9]+" _libsycl_patch_version ${_libsycl_patch_version})
+
+ SET(SYCL_VERSION "${_libsycl_major_version}.${_libsycl_minor_version}.${_libsycl_patch_version}")
+ENDIF()
+
INCLUDE(FindPackageHandleStandardArgs)
-FIND_PACKAGE_HANDLE_STANDARD_ARGS(SYCL DEFAULT_MSG SYCL_LIBRARY SYCL_INCLUDE_DIR)
+FIND_PACKAGE_HANDLE_STANDARD_ARGS(SYCL
+ REQUIRED_VARS SYCL_LIBRARY SYCL_INCLUDE_DIR
+ VERSION_VAR SYCL_VERSION
+)
IF(SYCL_FOUND)
- get_filename_component(_SYCL_INCLUDE_PARENT_DIR ${SYCL_INCLUDE_DIR} DIRECTORY)
- SET(SYCL_INCLUDE_DIR ${SYCL_INCLUDE_DIR} ${_SYCL_INCLUDE_PARENT_DIR})
+ SET(SYCL_INCLUDE_DIR ${SYCL_INCLUDE_DIR} ${SYCL_INCLUDE_DIR}/sycl)
ELSE()
SET(SYCL_SYCL_FOUND FALSE)
ENDIF()
MARK_AS_ADVANCED(
_SYCL_INCLUDE_PARENT_DIR
- SYCL_LIBRARY_DEBUG
)
diff --git a/build_files/cmake/config/blender_full.cmake b/build_files/cmake/config/blender_full.cmake
index 958eb17522b..95304bd64c7 100644
--- a/build_files/cmake/config/blender_full.cmake
+++ b/build_files/cmake/config/blender_full.cmake
@@ -66,13 +66,11 @@ set(WITH_MEM_JEMALLOC ON CACHE BOOL "" FORCE)
if(APPLE)
set(WITH_COREAUDIO ON CACHE BOOL "" FORCE)
endif()
-if(NOT WIN32)
- set(WITH_JACK ON CACHE BOOL "" FORCE)
-endif()
if(WIN32)
set(WITH_WASAPI ON CACHE BOOL "" FORCE)
endif()
if(UNIX AND NOT APPLE)
+ set(WITH_JACK ON CACHE BOOL "" FORCE)
set(WITH_DOC_MANPAGE ON CACHE BOOL "" FORCE)
set(WITH_GHOST_XDND ON CACHE BOOL "" FORCE)
set(WITH_PULSEAUDIO ON CACHE BOOL "" FORCE)
diff --git a/build_files/cmake/config/blender_release.cmake b/build_files/cmake/config/blender_release.cmake
index d5f5230862b..74bbcb223c3 100644
--- a/build_files/cmake/config/blender_release.cmake
+++ b/build_files/cmake/config/blender_release.cmake
@@ -67,13 +67,11 @@ if(APPLE)
set(WITH_COREAUDIO ON CACHE BOOL "" FORCE)
set(WITH_CYCLES_DEVICE_METAL ON CACHE BOOL "" FORCE)
endif()
-if(NOT WIN32)
- set(WITH_JACK ON CACHE BOOL "" FORCE)
-endif()
if(WIN32)
set(WITH_WASAPI ON CACHE BOOL "" FORCE)
endif()
if(UNIX AND NOT APPLE)
+ set(WITH_JACK ON CACHE BOOL "" FORCE)
set(WITH_DOC_MANPAGE ON CACHE BOOL "" FORCE)
set(WITH_GHOST_XDND ON CACHE BOOL "" FORCE)
set(WITH_PULSEAUDIO ON CACHE BOOL "" FORCE)
diff --git a/build_files/cmake/macros.cmake b/build_files/cmake/macros.cmake
index 3acea19079b..8af45690862 100644
--- a/build_files/cmake/macros.cmake
+++ b/build_files/cmake/macros.cmake
@@ -1205,11 +1205,27 @@ macro(set_and_warn_dependency
_dependency _setting _val)
# when $_dependency is disabled, forces $_setting = $_val
if(NOT ${${_dependency}} AND ${${_setting}})
- message(STATUS "'${_dependency}' is disabled: forcing 'set(${_setting} ${_val})'")
+ if(WITH_STRICT_BUILD_OPTIONS)
+ message(SEND_ERROR "${_dependency} disabled but required by ${_setting}")
+ else()
+ message(STATUS "${_dependency} is disabled, setting ${_setting}=${_val}")
+ endif()
set(${_setting} ${_val})
endif()
endmacro()
+macro(set_and_warn_library_found
+ _library_name _library_found _setting)
+ if(NOT ${${_library_found}} AND ${${_setting}})
+ if(WITH_STRICT_BUILD_OPTIONS)
+ message(SEND_ERROR "${_library_name} required but not found")
+ else()
+ message(STATUS "${_library_name} not found, disabling ${_setting}")
+ endif()
+ set(${_setting} OFF)
+ endif()
+endmacro()
+
macro(without_system_libs_begin)
set(CMAKE_IGNORE_PATH "${CMAKE_PLATFORM_IMPLICIT_LINK_DIRECTORIES};${CMAKE_SYSTEM_INCLUDE_PATH};${CMAKE_C_IMPLICIT_INCLUDE_DIRECTORIES};${CMAKE_CXX_IMPLICIT_INCLUDE_DIRECTORIES}")
endmacro()
diff --git a/build_files/cmake/platform/platform_apple.cmake b/build_files/cmake/platform/platform_apple.cmake
index 9f1824ec827..c5fe3c908de 100644
--- a/build_files/cmake/platform/platform_apple.cmake
+++ b/build_files/cmake/platform/platform_apple.cmake
@@ -43,22 +43,18 @@ find_package(BZip2 REQUIRED)
list(APPEND ZLIB_LIBRARIES ${BZIP2_LIBRARIES})
if(WITH_OPENAL)
- find_package(OpenAL)
- if(NOT OPENAL_FOUND)
- message(WARNING "OpenAL not found, disabling WITH_OPENAL")
- set(WITH_OPENAL OFF)
- endif()
+ find_package(OpenAL REQUIRED)
endif()
if(WITH_JACK)
find_library(JACK_FRAMEWORK
NAMES jackmp
)
- if(NOT JACK_FRAMEWORK)
- message(STATUS "JACK not found, disabling WITH_JACK")
- set(WITH_JACK OFF)
- else()
+
+ if(JACK_FRAMEWORK)
set(JACK_INCLUDE_DIRS ${JACK_FRAMEWORK}/headers)
+ else()
+ set_and_warn_library_found("JACK" JACK_FRAMEWORK WITH_JACK)
endif()
endif()
@@ -101,11 +97,7 @@ if(WITH_ALEMBIC)
endif()
if(WITH_USD)
- find_package(USD)
- if(NOT USD_FOUND)
- message(STATUS "USD not found, disabling WITH_USD")
- set(WITH_USD OFF)
- endif()
+ find_package(USD REQUIRED)
endif()
if(WITH_OPENSUBDIV)
@@ -227,20 +219,12 @@ find_package(JPEG REQUIRED)
if(WITH_IMAGE_TIFF)
set(TIFF_ROOT ${LIBDIR}/tiff)
- find_package(TIFF)
- if(NOT TIFF_FOUND)
- message(WARNING "TIFF not found, disabling WITH_IMAGE_TIFF")
- set(WITH_IMAGE_TIFF OFF)
- endif()
+ find_package(TIFF REQUIRED)
endif()
if(WITH_IMAGE_WEBP)
set(WEBP_ROOT_DIR ${LIBDIR}/webp)
- find_package(WebP)
- if(NOT WEBP_FOUND)
- message(WARNING "WebP not found, disabling WITH_IMAGE_WEBP")
- set(WITH_IMAGE_WEBP OFF)
- endif()
+ find_package(WebP REQUIRED)
endif()
if(WITH_BOOST)
@@ -270,11 +254,7 @@ if(WITH_INTERNATIONAL OR WITH_CODEC_FFMPEG)
endif()
if(WITH_PUGIXML)
- find_package(PugiXML)
- if(NOT PUGIXML_FOUND)
- message(WARNING "PugiXML not found, disabling WITH_PUGIXML")
- set(WITH_PUGIXML OFF)
- endif()
+ find_package(PugiXML REQUIRED)
endif()
if(WITH_OPENIMAGEIO)
@@ -292,12 +272,7 @@ if(WITH_OPENIMAGEIO)
endif()
if(WITH_OPENCOLORIO)
- find_package(OpenColorIO 2.0.0)
-
- if(NOT OPENCOLORIO_FOUND)
- set(WITH_OPENCOLORIO OFF)
- message(STATUS "OpenColorIO not found, disabling WITH_OPENCOLORIO")
- endif()
+ find_package(OpenColorIO 2.0.0 REQUIRED)
endif()
if(WITH_OPENVDB)
@@ -331,23 +306,7 @@ if(WITH_LLVM)
endif()
if(WITH_CYCLES AND WITH_CYCLES_OSL)
- set(CYCLES_OSL ${LIBDIR}/osl)
-
- find_library(OSL_LIB_EXEC NAMES oslexec PATHS ${CYCLES_OSL}/lib)
- find_library(OSL_LIB_COMP NAMES oslcomp PATHS ${CYCLES_OSL}/lib)
- find_library(OSL_LIB_QUERY NAMES oslquery PATHS ${CYCLES_OSL}/lib)
- # WARNING! depends on correct order of OSL libs linking
- list(APPEND OSL_LIBRARIES ${OSL_LIB_COMP} -force_load ${OSL_LIB_EXEC} ${OSL_LIB_QUERY})
- find_path(OSL_INCLUDE_DIR OSL/oslclosure.h PATHS ${CYCLES_OSL}/include)
- find_program(OSL_COMPILER NAMES oslc PATHS ${CYCLES_OSL}/bin)
- find_path(OSL_SHADER_DIR NAMES stdosl.h PATHS ${CYCLES_OSL}/share/OSL/shaders)
-
- if(OSL_INCLUDE_DIR AND OSL_LIBRARIES AND OSL_COMPILER AND OSL_SHADER_DIR)
- set(OSL_FOUND TRUE)
- else()
- message(WARNING "OSL not found, disabling WITH_CYCLES_OSL")
- set(WITH_CYCLES_OSL OFF)
- endif()
+ find_package(OSL REQUIRED)
endif()
if(WITH_CYCLES AND WITH_CYCLES_EMBREE)
@@ -365,28 +324,15 @@ if(WITH_CYCLES AND WITH_CYCLES_EMBREE)
endif()
if(WITH_OPENIMAGEDENOISE)
- find_package(OpenImageDenoise)
-
- if(NOT OPENIMAGEDENOISE_FOUND)
- set(WITH_OPENIMAGEDENOISE OFF)
- message(STATUS "OpenImageDenoise not found, disabling WITH_OPENIMAGEDENOISE")
- endif()
+ find_package(OpenImageDenoise REQUIRED)
endif()
if(WITH_TBB)
- find_package(TBB)
- if(NOT TBB_FOUND)
- message(WARNING "TBB not found, disabling WITH_TBB")
- set(WITH_TBB OFF)
- endif()
+ find_package(TBB REQUIRED)
endif()
if(WITH_POTRACE)
- find_package(Potrace)
- if(NOT POTRACE_FOUND)
- message(WARNING "potrace not found, disabling WITH_POTRACE")
- set(WITH_POTRACE OFF)
- endif()
+ find_package(Potrace REQUIRED)
endif()
# CMake FindOpenMP doesn't know about AppleClang before 3.12, so provide custom flags.
@@ -406,30 +352,18 @@ if(WITH_OPENMP)
endif()
if(WITH_XR_OPENXR)
- find_package(XR_OpenXR_SDK)
- if(NOT XR_OPENXR_SDK_FOUND)
- message(WARNING "OpenXR-SDK was not found, disabling WITH_XR_OPENXR")
- set(WITH_XR_OPENXR OFF)
- endif()
+ find_package(XR_OpenXR_SDK REQUIRED)
endif()
if(WITH_GMP)
- find_package(GMP)
- if(NOT GMP_FOUND)
- message(WARNING "GMP not found, disabling WITH_GMP")
- set(WITH_GMP OFF)
- endif()
+ find_package(GMP REQUIRED)
endif()
if(WITH_HARU)
- find_package(Haru)
- if(NOT HARU_FOUND)
- message(WARNING "Haru not found, disabling WITH_HARU")
- set(WITH_HARU OFF)
- endif()
+ find_package(Haru REQUIRED)
endif()
-if(WITH_CYCLES_PATH_GUIDING)
+if(WITH_CYCLES AND WITH_CYCLES_PATH_GUIDING)
find_package(openpgl QUIET)
if(openpgl_FOUND)
get_target_property(OPENPGL_LIBRARIES openpgl::openpgl LOCATION)
diff --git a/build_files/cmake/platform/platform_unix.cmake b/build_files/cmake/platform/platform_unix.cmake
index 0b137ae93d6..424926afe39 100644
--- a/build_files/cmake/platform/platform_unix.cmake
+++ b/build_files/cmake/platform/platform_unix.cmake
@@ -174,32 +174,24 @@ endif()
if(WITH_IMAGE_OPENEXR)
find_package_wrapper(OpenEXR) # our own module
- if(NOT OPENEXR_FOUND)
- set(WITH_IMAGE_OPENEXR OFF)
- endif()
+ set_and_warn_library_found("OpenEXR" OPENEXR_FOUND WITH_IMAGE_OPENEXR)
endif()
if(WITH_IMAGE_OPENJPEG)
find_package_wrapper(OpenJPEG)
- if(NOT OPENJPEG_FOUND)
- set(WITH_IMAGE_OPENJPEG OFF)
- endif()
+ set_and_warn_library_found("OpenJPEG" OPENJPEG_FOUND WITH_IMAGE_OPENJPEG)
endif()
if(WITH_IMAGE_TIFF)
# XXX Linking errors with debian static tiff :/
# find_package_wrapper(TIFF)
find_package(TIFF)
- if(NOT TIFF_FOUND)
- set(WITH_IMAGE_TIFF OFF)
- endif()
+ set_and_warn_library_found("TIFF" TIFF_FOUND WITH_IMAGE_TIFF)
endif()
if(WITH_OPENAL)
find_package_wrapper(OpenAL)
- if(NOT OPENAL_FOUND)
- set(WITH_OPENAL OFF)
- endif()
+ set_and_warn_library_found("OpenAL" OPENAL_FOUND WITH_OPENAL)
endif()
if(WITH_SDL)
@@ -221,18 +213,14 @@ if(WITH_SDL)
SDL_LIBRARY
)
# unset(SDLMAIN_LIBRARY CACHE)
- if(NOT SDL_FOUND)
- set(WITH_SDL OFF)
- endif()
+ set_and_warn_library_found("SDL" SDL_FOUND WITH_SDL)
endif()
endif()
# Codecs
if(WITH_CODEC_SNDFILE)
find_package_wrapper(SndFile)
- if(NOT SNDFILE_FOUND)
- set(WITH_CODEC_SNDFILE OFF)
- endif()
+ set_and_warn_library_found("libsndfile" SNDFILE_FOUND WITH_CODEC_SNDFILE)
endif()
if(WITH_CODEC_FFMPEG)
@@ -260,17 +248,12 @@ if(WITH_CODEC_FFMPEG)
endif()
find_package(FFmpeg)
- if(NOT FFMPEG_FOUND)
- set(WITH_CODEC_FFMPEG OFF)
- message(STATUS "FFmpeg not found, disabling it")
- endif()
+ set_and_warn_library_found("FFmpeg" FFMPEG_FOUND WITH_CODEC_FFMPEG)
endif()
if(WITH_FFTW3)
find_package_wrapper(Fftw3)
- if(NOT FFTW3_FOUND)
- set(WITH_FFTW3 OFF)
- endif()
+ set_and_warn_library_found("fftw3" FFTW3_FOUND WITH_FFTW3)
endif()
if(WITH_OPENCOLLADA)
@@ -285,25 +268,23 @@ if(WITH_OPENCOLLADA)
endif()
find_package_wrapper(XML2)
else()
- set(WITH_OPENCOLLADA OFF)
+ set_and_warn_library_found("OpenCollada" OPENCOLLADA_FOUND WITH_OPENCOLLADA)
endif()
endif()
if(WITH_MEM_JEMALLOC)
find_package_wrapper(JeMalloc)
- if(NOT JEMALLOC_FOUND)
- set(WITH_MEM_JEMALLOC OFF)
- endif()
+ set_and_warn_library_found("JeMalloc" JEMALLOC_FOUND WITH_MEM_JEMALLOC)
endif()
if(WITH_INPUT_NDOF)
find_package_wrapper(Spacenav)
+ set_and_warn_library_found("SpaceNav" SPACENAV_FOUND WITH_INPUT_NDOF)
+
if(SPACENAV_FOUND)
# use generic names within blenders buildsystem.
set(NDOF_INCLUDE_DIRS ${SPACENAV_INCLUDE_DIRS})
set(NDOF_LIBRARIES ${SPACENAV_LIBRARIES})
- else()
- set(WITH_INPUT_NDOF OFF)
endif()
endif()
@@ -313,6 +294,8 @@ if(WITH_CYCLES AND WITH_CYCLES_OSL)
set(OSL_ROOT ${CYCLES_OSL})
endif()
find_package_wrapper(OSL)
+ set_and_warn_library_found("OSL" OSL_FOUND WITH_CYCLES_OSL)
+
if(OSL_FOUND)
if(${OSL_LIBRARY_VERSION_MAJOR} EQUAL "1" AND ${OSL_LIBRARY_VERSION_MINOR} LESS "6")
# Note: --whole-archive is needed to force loading of all symbols in liboslexec,
@@ -323,13 +306,10 @@ if(WITH_CYCLES AND WITH_CYCLES_OSL)
-Wl,--no-whole-archive ${OSL_OSLQUERY_LIBRARY}
)
endif()
- else()
- message(STATUS "OSL not found, disabling it from Cycles")
- set(WITH_CYCLES_OSL OFF)
endif()
endif()
-if(WITH_CYCLES_DEVICE_ONEAPI)
+if(WITH_CYCLES AND WITH_CYCLES_DEVICE_ONEAPI)
set(CYCLES_LEVEL_ZERO ${LIBDIR}/level-zero CACHE PATH "Path to Level Zero installation")
if(EXISTS ${CYCLES_LEVEL_ZERO} AND NOT LEVEL_ZERO_ROOT_DIR)
set(LEVEL_ZERO_ROOT_DIR ${CYCLES_LEVEL_ZERO})
@@ -341,35 +321,27 @@ if(WITH_CYCLES_DEVICE_ONEAPI)
endif()
file(GLOB _sycl_runtime_libraries
${SYCL_ROOT_DIR}/lib/libsycl.so
- ${SYCL_ROOT_DIR}/lib/libsycl.so.[0-9]
- ${SYCL_ROOT_DIR}/lib/libsycl.so.[0-9].[0-9].[0-9]-[0-9]
+ ${SYCL_ROOT_DIR}/lib/libsycl.so.*
${SYCL_ROOT_DIR}/lib/libpi_level_zero.so
)
+ list(FILTER _sycl_runtime_libraries EXCLUDE REGEX ".*\.py")
list(APPEND PLATFORM_BUNDLED_LIBRARIES ${_sycl_runtime_libraries})
unset(_sycl_runtime_libraries)
endif()
if(WITH_OPENVDB)
find_package_wrapper(OpenVDB)
- find_package_wrapper(Blosc)
-
- if(NOT OPENVDB_FOUND)
- set(WITH_OPENVDB OFF)
- set(WITH_OPENVDB_BLOSC OFF)
- message(STATUS "OpenVDB not found, disabling it")
- elseif(NOT BLOSC_FOUND)
- set(WITH_OPENVDB_BLOSC OFF)
- message(STATUS "Blosc not found, disabling it for OpenVBD")
+ set_and_warn_library_found("OpenVDB" OPENVDB_FOUND WITH_OPENVDB)
+
+ if(OPENVDB_FOUND)
+ find_package_wrapper(Blosc)
+ set_and_warn_library_found("Blosc" BLOSC_FOUND WITH_OPENVDB_BLOSC)
endif()
endif()
if(WITH_NANOVDB)
find_package_wrapper(NanoVDB)
-
- if(NOT NANOVDB_FOUND)
- set(WITH_NANOVDB OFF)
- message(STATUS "NanoVDB not found, disabling it")
- endif()
+ set_and_warn_library_found("NanoVDB" NANOVDB_FOUND WITH_NANOVDB)
endif()
if(WITH_CPU_SIMD AND SUPPORT_NEON_BUILD)
@@ -378,18 +350,12 @@ endif()
if(WITH_ALEMBIC)
find_package_wrapper(Alembic)
-
- if(NOT ALEMBIC_FOUND)
- set(WITH_ALEMBIC OFF)
- endif()
+ set_and_warn_library_found("Alembic" ALEMBIC_FOUND WITH_ALEMBIC)
endif()
if(WITH_USD)
find_package_wrapper(USD)
-
- if(NOT USD_FOUND)
- set(WITH_USD OFF)
- endif()
+ set_and_warn_library_found("USD" USD_FOUND WITH_USD)
endif()
if(WITH_BOOST)
@@ -442,20 +408,13 @@ endif()
if(WITH_PUGIXML)
find_package_wrapper(PugiXML)
-
- if(NOT PUGIXML_FOUND)
- set(WITH_PUGIXML OFF)
- message(STATUS "PugiXML not found, disabling WITH_PUGIXML")
- endif()
+ set_and_warn_library_found("PugiXML" PUGIXML_FOUND WITH_PUGIXML)
endif()
if(WITH_IMAGE_WEBP)
set(WEBP_ROOT_DIR ${LIBDIR}/webp)
find_package_wrapper(WebP)
- if(NOT WEBP_FOUND)
- set(WITH_IMAGE_WEBP OFF)
- message(WARNING "WebP not found, disabling WITH_IMAGE_WEBP")
- endif()
+ set_and_warn_library_found("WebP" WEBP_FOUND WITH_IMAGE_WEBP)
endif()
if(WITH_OPENIMAGEIO)
@@ -480,10 +439,7 @@ if(WITH_OPENIMAGEIO)
list(APPEND OPENIMAGEIO_LIBRARIES "${WEBP_LIBRARIES}")
endif()
- if(NOT OPENIMAGEIO_FOUND)
- set(WITH_OPENIMAGEIO OFF)
- message(STATUS "OpenImageIO not found, disabling WITH_CYCLES")
- endif()
+ set_and_warn_library_found("OPENIMAGEIO" OPENIMAGEIO_FOUND WITH_OPENIMAGEIO)
endif()
if(WITH_OPENCOLORIO)
@@ -493,10 +449,7 @@ if(WITH_OPENCOLORIO)
set(OPENCOLORIO_LIBPATH) # TODO, remove and reference the absolute path everywhere
set(OPENCOLORIO_DEFINITIONS)
- if(NOT OPENCOLORIO_FOUND)
- set(WITH_OPENCOLORIO OFF)
- message(STATUS "OpenColorIO not found")
- endif()
+ set_and_warn_library_found("OpenColorIO" OPENCOLORIO_FOUND WITH_OPENCOLORIO)
endif()
if(WITH_CYCLES AND WITH_CYCLES_EMBREE)
@@ -505,11 +458,7 @@ endif()
if(WITH_OPENIMAGEDENOISE)
find_package_wrapper(OpenImageDenoise)
-
- if(NOT OPENIMAGEDENOISE_FOUND)
- set(WITH_OPENIMAGEDENOISE OFF)
- message(STATUS "OpenImageDenoise not found")
- endif()
+ set_and_warn_library_found("OpenImageDenoise" OPENIMAGEDENOISE_FOUND WITH_OPENIMAGEDENOISE)
endif()
if(WITH_LLVM)
@@ -518,24 +467,19 @@ if(WITH_LLVM)
endif()
find_package_wrapper(LLVM)
- if(WITH_CLANG)
- find_package_wrapper(Clang)
- endif()
- # Symbol conflicts with same UTF library used by OpenCollada
- if(EXISTS ${LIBDIR})
- if(WITH_OPENCOLLADA AND (${LLVM_VERSION} VERSION_LESS "4.0.0"))
- list(REMOVE_ITEM OPENCOLLADA_LIBRARIES ${OPENCOLLADA_UTF_LIBRARY})
+ set_and_warn_library_found("LLVM" LLVM_FOUND WITH_LLVM)
+
+ if(LLVM_FOUND)
+ if(WITH_CLANG)
+ find_package_wrapper(Clang)
+ set_and_warn_library_found("Clang" CLANG_FOUND WITH_CLANG)
endif()
- endif()
- if(NOT LLVM_FOUND)
- set(WITH_LLVM OFF)
- set(WITH_CLANG OFF)
- message(STATUS "LLVM not found")
- else()
- if(NOT CLANG_FOUND)
- set(WITH_CLANG OFF)
- message(STATUS "Clang not found")
+ # Symbol conflicts with same UTF library used by OpenCollada
+ if(EXISTS ${LIBDIR})
+ if(WITH_OPENCOLLADA AND (${LLVM_VERSION} VERSION_LESS "4.0.0"))
+ list(REMOVE_ITEM OPENCOLLADA_LIBRARIES ${OPENCOLLADA_UTF_LIBRARY})
+ endif()
endif()
endif()
endif()
@@ -546,53 +490,35 @@ if(WITH_OPENSUBDIV)
set(OPENSUBDIV_LIBRARIES ${OPENSUBDIV_LIBRARIES})
set(OPENSUBDIV_LIBPATH) # TODO, remove and reference the absolute path everywhere
- if(NOT OPENSUBDIV_FOUND)
- set(WITH_OPENSUBDIV OFF)
- message(STATUS "OpenSubdiv not found")
- endif()
+ set_and_warn_library_found("OpenSubdiv" OPENSUBDIV_FOUND WITH_OPENSUBDIV)
endif()
if(WITH_TBB)
find_package_wrapper(TBB)
- if(NOT TBB_FOUND)
- message(WARNING "TBB not found, disabling WITH_TBB")
- set(WITH_TBB OFF)
- endif()
+ set_and_warn_library_found("TBB" TBB_FOUND WITH_TBB)
endif()
if(WITH_XR_OPENXR)
find_package(XR_OpenXR_SDK)
- if(NOT XR_OPENXR_SDK_FOUND)
- message(WARNING "OpenXR-SDK not found, disabling WITH_XR_OPENXR")
- set(WITH_XR_OPENXR OFF)
- endif()
+ set_and_warn_library_found("OpenXR-SDK" XR_OPENXR_SDK_FOUND WITH_XR_OPENXR)
endif()
if(WITH_GMP)
find_package_wrapper(GMP)
- if(NOT GMP_FOUND)
- message(WARNING "GMP not found, disabling WITH_GMP")
- set(WITH_GMP OFF)
- endif()
+ set_and_warn_library_found("GMP" GMP_FOUND WITH_GMP)
endif()
if(WITH_POTRACE)
find_package_wrapper(Potrace)
- if(NOT POTRACE_FOUND)
- message(WARNING "potrace not found, disabling WITH_POTRACE")
- set(WITH_POTRACE OFF)
- endif()
+ set_and_warn_library_found("Potrace" POTRACE_FOUND WITH_POTRACE)
endif()
if(WITH_HARU)
find_package_wrapper(Haru)
- if(NOT HARU_FOUND)
- message(WARNING "Haru not found, disabling WITH_HARU")
- set(WITH_HARU OFF)
- endif()
+ set_and_warn_library_found("Haru" HARU_FOUND WITH_HARU)
endif()
-if(WITH_CYCLES_PATH_GUIDING)
+if(WITH_CYCLES AND WITH_CYCLES_PATH_GUIDING)
find_package_wrapper(openpgl)
if(openpgl_FOUND)
get_target_property(OPENPGL_LIBRARIES openpgl::openpgl LOCATION)
@@ -676,25 +602,20 @@ endif()
# Jack is intended to use the system library.
if(WITH_JACK)
find_package_wrapper(Jack)
- if(NOT JACK_FOUND)
- set(WITH_JACK OFF)
- endif()
+ set_and_warn_library_found("JACK" JACK_FOUND WITH_JACK)
endif()
# Pulse is intended to use the system library.
if(WITH_PULSEAUDIO)
find_package_wrapper(Pulse)
- if(NOT PULSE_FOUND)
- set(WITH_PULSEAUDIO OFF)
- endif()
+ set_and_warn_library_found("PulseAudio" PULSE_FOUND WITH_PULSEAUDIO)
endif()
# Audio IO
if(WITH_SYSTEM_AUDASPACE)
find_package_wrapper(Audaspace)
- if(NOT AUDASPACE_FOUND OR NOT AUDASPACE_C_FOUND)
- message(FATAL_ERROR "Audaspace external library not found!")
- endif()
+ set(AUDASPACE_FOUND ${AUDASPACE_FOUND} AND ${AUDASPACE_C_FOUND})
+ set_and_warn_library_found("External Audaspace" AUDASPACE_FOUND WITH_SYSTEM_AUDASPACE)
endif()
if(WITH_GHOST_WAYLAND)
@@ -740,30 +661,12 @@ if(WITH_GHOST_WAYLAND)
set(wayland-cursor_FOUND ON)
endif()
- if (NOT ${wayland-client_FOUND})
- message(STATUS "wayland-client not found, disabling WITH_GHOST_WAYLAND")
- set(WITH_GHOST_WAYLAND OFF)
- endif()
- if (NOT ${wayland-egl_FOUND})
- message(STATUS "wayland-egl not found, disabling WITH_GHOST_WAYLAND")
- set(WITH_GHOST_WAYLAND OFF)
- endif()
- if (NOT ${wayland-scanner_FOUND})
- message(STATUS "wayland-scanner not found, disabling WITH_GHOST_WAYLAND")
- set(WITH_GHOST_WAYLAND OFF)
- endif()
- if (NOT ${wayland-cursor_FOUND})
- message(STATUS "wayland-cursor not found, disabling WITH_GHOST_WAYLAND")
- set(WITH_GHOST_WAYLAND OFF)
- endif()
- if (NOT ${wayland-protocols_FOUND})
- message(STATUS "wayland-protocols not found, disabling WITH_GHOST_WAYLAND")
- set(WITH_GHOST_WAYLAND OFF)
- endif()
- if (NOT ${xkbcommon_FOUND})
- message(STATUS "xkbcommon not found, disabling WITH_GHOST_WAYLAND")
- set(WITH_GHOST_WAYLAND OFF)
- endif()
+ set_and_warn_library_found("wayland-client" wayland-client_FOUND WITH_GHOST_WAYLAND)
+ set_and_warn_library_found("wayland-egl" wayland-egl_FOUND WITH_GHOST_WAYLAND)
+ set_and_warn_library_found("wayland-scanner" wayland-scanner_FOUND WITH_GHOST_WAYLAND)
+ set_and_warn_library_found("wayland-cursor" wayland-cursor_FOUND WITH_GHOST_WAYLAND)
+ set_and_warn_library_found("wayland-protocols" wayland-protocols_FOUND WITH_GHOST_WAYLAND)
+ set_and_warn_library_found("xkbcommon" xkbcommon_FOUND WITH_GHOST_WAYLAND)
if(WITH_GHOST_WAYLAND)
if(WITH_GHOST_WAYLAND_DBUS)
@@ -778,31 +681,11 @@ if(WITH_GHOST_WAYLAND)
endif()
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}
- )
- 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()
@@ -855,12 +738,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()
@@ -870,18 +749,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()
@@ -890,9 +765,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/build_files/cmake/platform/platform_win32.cmake b/build_files/cmake/platform/platform_win32.cmake
index 7031b1faac4..3818076634a 100644
--- a/build_files/cmake/platform/platform_win32.cmake
+++ b/build_files/cmake/platform/platform_win32.cmake
@@ -326,18 +326,10 @@ if(WITH_FFTW3)
endif()
if(WITH_IMAGE_WEBP)
- windows_find_package(WebP)
- if(NOT WEBP_FOUND)
- if(EXISTS ${LIBDIR}/webp)
- set(WEBP_INCLUDE_DIRS ${LIBDIR}/webp/include)
- set(WEBP_ROOT_DIR ${LIBDIR}/webp)
- set(WEBP_LIBRARIES ${LIBDIR}/webp/lib/webp.lib ${LIBDIR}/webp/lib/webpdemux.lib ${LIBDIR}/webp/lib/webpmux.lib)
- set(WEBP_FOUND ON)
- else()
- message(STATUS "WITH_IMAGE_WEBP is ON but WEBP libraries are not found, setting WITH_IMAGE_WEBP=OFF")
- set(WITH_IMAGE_WEBP OFF)
- endif()
- endif()
+ set(WEBP_INCLUDE_DIRS ${LIBDIR}/webp/include)
+ set(WEBP_ROOT_DIR ${LIBDIR}/webp)
+ set(WEBP_LIBRARIES ${LIBDIR}/webp/lib/webp.lib ${LIBDIR}/webp/lib/webpdemux.lib ${LIBDIR}/webp/lib/webpmux.lib)
+ set(WEBP_FOUND ON)
endif()
if(WITH_OPENCOLLADA)
@@ -358,7 +350,6 @@ if(WITH_OPENCOLLADA)
optimized ${OPENCOLLADA}/lib/opencollada/OpenCOLLADAStreamWriter.lib
optimized ${OPENCOLLADA}/lib/opencollada/MathMLSolver.lib
optimized ${OPENCOLLADA}/lib/opencollada/GeneratedSaxParser.lib
- optimized ${OPENCOLLADA}/lib/opencollada/xml.lib
optimized ${OPENCOLLADA}/lib/opencollada/buffer.lib
optimized ${OPENCOLLADA}/lib/opencollada/ftoa.lib
@@ -368,10 +359,14 @@ if(WITH_OPENCOLLADA)
debug ${OPENCOLLADA}/lib/opencollada/OpenCOLLADAStreamWriter_d.lib
debug ${OPENCOLLADA}/lib/opencollada/MathMLSolver_d.lib
debug ${OPENCOLLADA}/lib/opencollada/GeneratedSaxParser_d.lib
- debug ${OPENCOLLADA}/lib/opencollada/xml_d.lib
debug ${OPENCOLLADA}/lib/opencollada/buffer_d.lib
debug ${OPENCOLLADA}/lib/opencollada/ftoa_d.lib
)
+ if(EXISTS ${LIBDIR}/xml2/lib/libxml2s.lib) # 3.4 libraries
+ list(APPEND OPENCOLLADA_LIBRARIES ${LIBDIR}/xml2/lib/libxml2s.lib)
+ else()
+ list(APPEND OPENCOLLADA_LIBRARIES ${OPENCOLLADA}/lib/opencollada/xml.lib)
+ endif()
list(APPEND OPENCOLLADA_LIBRARIES ${OPENCOLLADA}/lib/opencollada/UTF.lib)
@@ -679,11 +674,11 @@ endif()
if(WITH_IMAGE_OPENJPEG)
set(OPENJPEG ${LIBDIR}/openjpeg)
- set(OPENJPEG_INCLUDE_DIRS ${OPENJPEG}/include/openjpeg-2.4)
+ set(OPENJPEG_INCLUDE_DIRS ${OPENJPEG}/include/openjpeg-2.5)
if(NOT EXISTS "${OPENJPEG_INCLUDE_DIRS}")
- # when not found, could be an older lib folder with openjpeg 2.3
- # to ease the transition period, fall back if 2.4 is not found.
- set(OPENJPEG_INCLUDE_DIRS ${OPENJPEG}/include/openjpeg-2.3)
+ # when not found, could be an older lib folder with openjpeg 2.4
+ # to ease the transition period, fall back if 2.5 is not found.
+ set(OPENJPEG_INCLUDE_DIRS ${OPENJPEG}/include/openjpeg-2.4)
endif()
set(OPENJPEG_LIBRARIES ${OPENJPEG}/lib/openjp2.lib)
endif()
@@ -700,12 +695,6 @@ if(WITH_OPENSUBDIV)
debug ${OPENSUBDIV_LIBPATH}/osdCPU_d.lib
debug ${OPENSUBDIV_LIBPATH}/osdGPU_d.lib
)
- set(OPENSUBDIV_HAS_OPENMP TRUE)
- set(OPENSUBDIV_HAS_TBB FALSE)
- set(OPENSUBDIV_HAS_OPENCL TRUE)
- set(OPENSUBDIV_HAS_CUDA FALSE)
- set(OPENSUBDIV_HAS_GLSL_TRANSFORM_FEEDBACK TRUE)
- set(OPENSUBDIV_HAS_GLSL_COMPUTE TRUE)
endif()
endif()
@@ -773,9 +762,11 @@ if(WITH_CYCLES AND WITH_CYCLES_OSL)
find_library(OSL_LIB_EXEC NAMES oslexec PATHS ${CYCLES_OSL}/lib)
find_library(OSL_LIB_COMP NAMES oslcomp PATHS ${CYCLES_OSL}/lib)
find_library(OSL_LIB_QUERY NAMES oslquery PATHS ${CYCLES_OSL}/lib)
+ find_library(OSL_LIB_NOISE NAMES oslnoise PATHS ${CYCLES_OSL}/lib)
find_library(OSL_LIB_EXEC_DEBUG NAMES oslexec_d PATHS ${CYCLES_OSL}/lib)
find_library(OSL_LIB_COMP_DEBUG NAMES oslcomp_d PATHS ${CYCLES_OSL}/lib)
find_library(OSL_LIB_QUERY_DEBUG NAMES oslquery_d PATHS ${CYCLES_OSL}/lib)
+ find_library(OSL_LIB_NOISE_DEBUG NAMES oslnoise_d PATHS ${CYCLES_OSL}/lib)
list(APPEND OSL_LIBRARIES
optimized ${OSL_LIB_COMP}
optimized ${OSL_LIB_EXEC}
@@ -785,15 +776,14 @@ if(WITH_CYCLES AND WITH_CYCLES_OSL)
debug ${OSL_LIB_QUERY_DEBUG}
${PUGIXML_LIBRARIES}
)
+ if(OSL_LIB_NOISE)
+ list(APPEND OSL_LIBRARIES optimized ${OSL_LIB_NOISE})
+ endif()
+ if(OSL_LIB_NOISE_DEBUG)
+ list(APPEND OSL_LIBRARIES debug ${OSL_LIB_NOISE_DEBUG})
+ endif()
find_path(OSL_INCLUDE_DIR OSL/oslclosure.h PATHS ${CYCLES_OSL}/include)
find_program(OSL_COMPILER NAMES oslc PATHS ${CYCLES_OSL}/bin)
-
- if(OSL_INCLUDE_DIR AND OSL_LIBRARIES AND OSL_COMPILER)
- set(OSL_FOUND TRUE)
- else()
- message(STATUS "OSL not found")
- set(WITH_CYCLES_OSL OFF)
- endif()
endif()
if(WITH_CYCLES AND WITH_CYCLES_EMBREE)
@@ -893,21 +883,16 @@ if(WINDOWS_PYTHON_DEBUG)
endif()
if(WITH_XR_OPENXR)
- if(EXISTS ${LIBDIR}/xr_openxr_sdk)
- set(XR_OPENXR_SDK ${LIBDIR}/xr_openxr_sdk)
- set(XR_OPENXR_SDK_LIBPATH ${LIBDIR}/xr_openxr_sdk/lib)
- set(XR_OPENXR_SDK_INCLUDE_DIR ${XR_OPENXR_SDK}/include)
- # This is the old name of this library, it is checked to
- # support the transition between the old and new lib versions
- # this can be removed after the next lib update.
- if(EXISTS ${XR_OPENXR_SDK_LIBPATH}/openxr_loader_d.lib)
- set(XR_OPENXR_SDK_LIBRARIES optimized ${XR_OPENXR_SDK_LIBPATH}/openxr_loader.lib debug ${XR_OPENXR_SDK_LIBPATH}/openxr_loader_d.lib)
- else()
- set(XR_OPENXR_SDK_LIBRARIES optimized ${XR_OPENXR_SDK_LIBPATH}/openxr_loader.lib debug ${XR_OPENXR_SDK_LIBPATH}/openxr_loaderd.lib)
- endif()
+ set(XR_OPENXR_SDK ${LIBDIR}/xr_openxr_sdk)
+ set(XR_OPENXR_SDK_LIBPATH ${LIBDIR}/xr_openxr_sdk/lib)
+ set(XR_OPENXR_SDK_INCLUDE_DIR ${XR_OPENXR_SDK}/include)
+ # This is the old name of this library, it is checked to
+ # support the transition between the old and new lib versions
+ # this can be removed after the next lib update.
+ if(EXISTS ${XR_OPENXR_SDK_LIBPATH}/openxr_loader_d.lib)
+ set(XR_OPENXR_SDK_LIBRARIES optimized ${XR_OPENXR_SDK_LIBPATH}/openxr_loader.lib debug ${XR_OPENXR_SDK_LIBPATH}/openxr_loader_d.lib)
else()
- message(WARNING "OpenXR-SDK was not found, disabling WITH_XR_OPENXR")
- set(WITH_XR_OPENXR OFF)
+ set(XR_OPENXR_SDK_LIBRARIES optimized ${XR_OPENXR_SDK_LIBPATH}/openxr_loader.lib debug ${XR_OPENXR_SDK_LIBPATH}/openxr_loaderd.lib)
endif()
endif()
@@ -925,18 +910,13 @@ if(WITH_POTRACE)
endif()
if(WITH_HARU)
- if(EXISTS ${LIBDIR}/haru)
- set(HARU_FOUND ON)
- set(HARU_ROOT_DIR ${LIBDIR}/haru)
- set(HARU_INCLUDE_DIRS ${HARU_ROOT_DIR}/include)
- set(HARU_LIBRARIES ${HARU_ROOT_DIR}/lib/libhpdfs.lib)
- else()
- message(WARNING "Haru was not found, disabling WITH_HARU")
- set(WITH_HARU OFF)
- endif()
+ set(HARU_FOUND ON)
+ set(HARU_ROOT_DIR ${LIBDIR}/haru)
+ set(HARU_INCLUDE_DIRS ${HARU_ROOT_DIR}/include)
+ set(HARU_LIBRARIES ${HARU_ROOT_DIR}/lib/libhpdfs.lib)
endif()
-if(WITH_CYCLES_PATH_GUIDING)
+if(WITH_CYCLES AND WITH_CYCLES_PATH_GUIDING)
find_package(openpgl QUIET)
if(openpgl_FOUND)
get_target_property(OPENPGL_LIBRARIES_RELEASE openpgl::openpgl LOCATION_RELEASE)
@@ -952,7 +932,7 @@ endif()
set(ZSTD_INCLUDE_DIRS ${LIBDIR}/zstd/include)
set(ZSTD_LIBRARIES ${LIBDIR}/zstd/lib/zstd_static.lib)
-if(WITH_CYCLES_DEVICE_ONEAPI)
+if(WITH_CYCLES AND WITH_CYCLES_DEVICE_ONEAPI)
set(LEVEL_ZERO_ROOT_DIR ${LIBDIR}/level_zero)
set(CYCLES_SYCL ${LIBDIR}/dpcpp CACHE PATH "Path to oneAPI DPC++ compiler")
if(EXISTS ${CYCLES_SYCL} AND NOT SYCL_ROOT_DIR)
diff --git a/build_files/windows/svn_update.cmd b/build_files/windows/svn_update.cmd
new file mode 100644
index 00000000000..f91f03f15b3
--- /dev/null
+++ b/build_files/windows/svn_update.cmd
@@ -0,0 +1,24 @@
+if "%BUILD_VS_YEAR%"=="2019" set BUILD_VS_LIBDIRPOST=vc15
+if "%BUILD_VS_YEAR%"=="2022" set BUILD_VS_LIBDIRPOST=vc15
+
+set BUILD_VS_SVNDIR=win64_%BUILD_VS_LIBDIRPOST%
+set BUILD_VS_LIBDIR="%BLENDER_DIR%..\lib\%BUILD_VS_SVNDIR%"
+
+cd %BUILD_VS_LIBDIR%
+:RETRY
+"%SVN%" update
+if errorlevel 1 (
+ set /p LibRetry= "Error during update, retry? y/n"
+ if /I "!LibRetry!"=="Y" (
+ "%SVN%" cleanup
+ goto RETRY
+ )
+ echo.
+ echo Error: Download of external libraries failed.
+ echo This is needed for building, please manually run 'svn cleanup' and 'svn update' in
+ echo %BUILD_VS_LIBDIR% , until this is resolved you CANNOT make a successful blender build
+ echo.
+ exit /b 1
+)
+
+cd %BLENDER_DIR% \ No newline at end of file
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/CMakeLists.txt b/intern/cycles/CMakeLists.txt
index f619e6b104e..329aa3990f6 100644
--- a/intern/cycles/CMakeLists.txt
+++ b/intern/cycles/CMakeLists.txt
@@ -263,8 +263,7 @@ if(WITH_CYCLES_DEVICE_OPTIX)
${OPTIX_INCLUDE_DIR}
)
else()
- message(STATUS "OptiX not found, disabling it from Cycles")
- set(WITH_CYCLES_DEVICE_OPTIX OFF)
+ set_and_warn_library_found("OptiX" OPTIX_FOUND WITH_CYCLES_DEVICE_OPTIX)
endif()
endif()
@@ -387,8 +386,7 @@ if(CMAKE_COMPILER_IS_GNUCXX OR CMAKE_C_COMPILER_ID MATCHES "Clang")
endif()
if(WITH_CYCLES_HYDRA_RENDER_DELEGATE AND (NOT WITH_USD))
- message(STATUS "USD not found, disabling WITH_CYCLES_HYDRA_RENDER_DELEGATE")
- set(WITH_CYCLES_HYDRA_RENDER_DELEGATE OFF)
+ set_and_warn_library_found("USD" WITH_USD WITH_CYCLES_HYDRA_RENDER_DELEGATE)
endif()
if(WITH_CYCLES_HYDRA_RENDER_DELEGATE AND (NOT WITH_BLENDER) AND (NOT WITH_CYCLES_STANDALONE))
set(CYCLES_INSTALL_PATH ${CYCLES_INSTALL_PATH}/hdCycles/resources)
diff --git a/intern/cycles/app/CMakeLists.txt b/intern/cycles/app/CMakeLists.txt
index 0988b1c0ac4..1c7a861ea93 100644
--- a/intern/cycles/app/CMakeLists.txt
+++ b/intern/cycles/app/CMakeLists.txt
@@ -43,7 +43,10 @@ else()
endif()
if(WITH_CYCLES_STANDALONE AND WITH_CYCLES_STANDALONE_GUI)
- list(APPEND INC_SYS ${Epoxy_INCLUDE_DIRS} ${SDL2_INCLUDE_DIRS})
+ list(APPEND INC_SYS
+ ${Epoxy_INCLUDE_DIRS}
+ ${SDL2_INCLUDE_DIRS}
+ )
list(APPEND LIB ${Epoxy_LIBRARIES} ${SDL2_LIBRARIES})
endif()
diff --git a/intern/cycles/blender/addon/engine.py b/intern/cycles/blender/addon/engine.py
index 794338fe78e..e33891fa7a2 100644
--- a/intern/cycles/blender/addon/engine.py
+++ b/intern/cycles/blender/addon/engine.py
@@ -209,22 +209,25 @@ def list_render_passes(scene, srl):
yield ("Debug Sample Count", "X", 'VALUE')
# Cryptomatte passes.
- crypto_depth = (srl.pass_cryptomatte_depth + 1) // 2
+ # NOTE: Name channels are lowercase RGBA so that compression rules check in OpenEXR DWA code
+ # uses lossless compression. Reportedly this naming is the only one which works good from the
+ # interoperability point of view. Using XYZW naming is not portable.
+ crypto_depth = (min(16, srl.pass_cryptomatte_depth) + 1) // 2
if srl.use_pass_cryptomatte_object:
for i in range(0, crypto_depth):
- yield ("CryptoObject" + '{:02d}'.format(i), "RGBA", 'COLOR')
+ yield ("CryptoObject" + '{:02d}'.format(i), "rgba", 'COLOR')
if srl.use_pass_cryptomatte_material:
for i in range(0, crypto_depth):
- yield ("CryptoMaterial" + '{:02d}'.format(i), "RGBA", 'COLOR')
+ yield ("CryptoMaterial" + '{:02d}'.format(i), "rgba", 'COLOR')
if srl.use_pass_cryptomatte_asset:
for i in range(0, crypto_depth):
- yield ("CryptoAsset" + '{:02d}'.format(i), "RGBA", 'COLOR')
+ yield ("CryptoAsset" + '{:02d}'.format(i), "rgba", 'COLOR')
# Denoising passes.
if scene.cycles.use_denoising and crl.use_denoising:
yield ("Noisy Image", "RGBA", 'COLOR')
if crl.use_pass_shadow_catcher:
- yield ("Noisy Shadow Catcher", "RGBA", 'COLOR')
+ yield ("Noisy Shadow Catcher", "RGB", 'COLOR')
if crl.denoising_store_passes:
yield ("Denoising Normal", "XYZ", 'VECTOR')
yield ("Denoising Albedo", "RGB", 'COLOR')
@@ -232,6 +235,8 @@ def list_render_passes(scene, srl):
# Custom AOV passes.
for aov in srl.aovs:
+ if not aov.is_valid:
+ continue
if aov.type == 'VALUE':
yield (aov.name, "X", 'VALUE')
else:
diff --git a/intern/cycles/blender/addon/properties.py b/intern/cycles/blender/addon/properties.py
index b7ce76d8f44..425d123e9e6 100644
--- a/intern/cycles/blender/addon/properties.py
+++ b/intern/cycles/blender/addon/properties.py
@@ -1651,6 +1651,7 @@ class CyclesPreferences(bpy.types.AddonPreferences):
box.prop(
device, "use", text=device.name
.replace('(TM)', unicodedata.lookup('TRADE MARK SIGN'))
+ .replace('(tm)', unicodedata.lookup('TRADE MARK SIGN'))
.replace('(R)', unicodedata.lookup('REGISTERED SIGN'))
.replace('(C)', unicodedata.lookup('COPYRIGHT SIGN'))
)
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 fd32e7ca1d7..dbc49df7f22 100644
--- a/intern/cycles/blender/shader.cpp
+++ b/intern/cycles/blender/shader.cpp
@@ -215,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"));
diff --git a/intern/cycles/blender/sync.cpp b/intern/cycles/blender/sync.cpp
index a69a94614d3..5251f0fee9c 100644
--- a/intern/cycles/blender/sync.cpp
+++ b/intern/cycles/blender/sync.cpp
@@ -575,68 +575,72 @@ void BlenderSync::sync_images()
/* Passes */
-static PassType get_blender_pass_type(BL::RenderPass &b_pass)
+static bool get_known_pass_type(BL::RenderPass &b_pass, PassType &type, PassMode &mode)
{
string name = b_pass.name();
-#define MAP_PASS(passname, passtype) \
+#define MAP_PASS(passname, passtype, noisy) \
if (name == passname) { \
- return passtype; \
+ type = passtype; \
+ mode = (noisy) ? PassMode::NOISY : PassMode::DENOISED; \
+ return true; \
} \
((void)0)
- /* NOTE: Keep in sync with defined names from DNA_scene_types.h */
+ /* NOTE: Keep in sync with defined names from engine.py */
- MAP_PASS("Combined", PASS_COMBINED);
- MAP_PASS("Noisy Image", PASS_COMBINED);
+ MAP_PASS("Combined", PASS_COMBINED, false);
+ MAP_PASS("Noisy Image", PASS_COMBINED, true);
- MAP_PASS("Depth", PASS_DEPTH);
- MAP_PASS("Mist", PASS_MIST);
- MAP_PASS("Position", PASS_POSITION);
- MAP_PASS("Normal", PASS_NORMAL);
- MAP_PASS("IndexOB", PASS_OBJECT_ID);
- MAP_PASS("UV", PASS_UV);
- MAP_PASS("Vector", PASS_MOTION);
- MAP_PASS("IndexMA", PASS_MATERIAL_ID);
+ MAP_PASS("Depth", PASS_DEPTH, false);
+ MAP_PASS("Mist", PASS_MIST, false);
+ MAP_PASS("Position", PASS_POSITION, false);
+ MAP_PASS("Normal", PASS_NORMAL, false);
+ MAP_PASS("IndexOB", PASS_OBJECT_ID, false);
+ MAP_PASS("UV", PASS_UV, false);
+ MAP_PASS("Vector", PASS_MOTION, false);
+ MAP_PASS("IndexMA", PASS_MATERIAL_ID, false);
- MAP_PASS("DiffDir", PASS_DIFFUSE_DIRECT);
- MAP_PASS("GlossDir", PASS_GLOSSY_DIRECT);
- MAP_PASS("TransDir", PASS_TRANSMISSION_DIRECT);
- MAP_PASS("VolumeDir", PASS_VOLUME_DIRECT);
+ MAP_PASS("DiffDir", PASS_DIFFUSE_DIRECT, false);
+ MAP_PASS("GlossDir", PASS_GLOSSY_DIRECT, false);
+ MAP_PASS("TransDir", PASS_TRANSMISSION_DIRECT, false);
+ MAP_PASS("VolumeDir", PASS_VOLUME_DIRECT, false);
- MAP_PASS("DiffInd", PASS_DIFFUSE_INDIRECT);
- MAP_PASS("GlossInd", PASS_GLOSSY_INDIRECT);
- MAP_PASS("TransInd", PASS_TRANSMISSION_INDIRECT);
- MAP_PASS("VolumeInd", PASS_VOLUME_INDIRECT);
+ MAP_PASS("DiffInd", PASS_DIFFUSE_INDIRECT, false);
+ MAP_PASS("GlossInd", PASS_GLOSSY_INDIRECT, false);
+ MAP_PASS("TransInd", PASS_TRANSMISSION_INDIRECT, false);
+ MAP_PASS("VolumeInd", PASS_VOLUME_INDIRECT, false);
- MAP_PASS("DiffCol", PASS_DIFFUSE_COLOR);
- MAP_PASS("GlossCol", PASS_GLOSSY_COLOR);
- MAP_PASS("TransCol", PASS_TRANSMISSION_COLOR);
+ MAP_PASS("DiffCol", PASS_DIFFUSE_COLOR, false);
+ MAP_PASS("GlossCol", PASS_GLOSSY_COLOR, false);
+ MAP_PASS("TransCol", PASS_TRANSMISSION_COLOR, false);
- MAP_PASS("Emit", PASS_EMISSION);
- MAP_PASS("Env", PASS_BACKGROUND);
- MAP_PASS("AO", PASS_AO);
- MAP_PASS("Shadow", PASS_SHADOW);
+ MAP_PASS("Emit", PASS_EMISSION, false);
+ MAP_PASS("Env", PASS_BACKGROUND, false);
+ MAP_PASS("AO", PASS_AO, false);
+ MAP_PASS("Shadow", PASS_SHADOW, false);
- MAP_PASS("BakePrimitive", PASS_BAKE_PRIMITIVE);
- MAP_PASS("BakeDifferential", PASS_BAKE_DIFFERENTIAL);
+ MAP_PASS("BakePrimitive", PASS_BAKE_PRIMITIVE, false);
+ MAP_PASS("BakeDifferential", PASS_BAKE_DIFFERENTIAL, false);
- MAP_PASS("Denoising Normal", PASS_DENOISING_NORMAL);
- MAP_PASS("Denoising Albedo", PASS_DENOISING_ALBEDO);
- MAP_PASS("Denoising Depth", PASS_DENOISING_DEPTH);
+ MAP_PASS("Denoising Normal", PASS_DENOISING_NORMAL, true);
+ MAP_PASS("Denoising Albedo", PASS_DENOISING_ALBEDO, true);
+ MAP_PASS("Denoising Depth", PASS_DENOISING_DEPTH, true);
- MAP_PASS("Shadow Catcher", PASS_SHADOW_CATCHER);
- MAP_PASS("Noisy Shadow Catcher", PASS_SHADOW_CATCHER);
+ MAP_PASS("Shadow Catcher", PASS_SHADOW_CATCHER, false);
+ MAP_PASS("Noisy Shadow Catcher", PASS_SHADOW_CATCHER, true);
- MAP_PASS("AdaptiveAuxBuffer", PASS_ADAPTIVE_AUX_BUFFER);
- MAP_PASS("Debug Sample Count", PASS_SAMPLE_COUNT);
+ MAP_PASS("AdaptiveAuxBuffer", PASS_ADAPTIVE_AUX_BUFFER, false);
+ MAP_PASS("Debug Sample Count", PASS_SAMPLE_COUNT, false);
if (string_startswith(name, cryptomatte_prefix)) {
- return PASS_CRYPTOMATTE;
+ type = PASS_CRYPTOMATTE;
+ mode = PassMode::DENOISED;
+ return true;
}
#undef MAP_PASS
- return PASS_NONE;
+ return false;
}
static Pass *pass_add(Scene *scene,
@@ -655,8 +659,6 @@ static Pass *pass_add(Scene *scene,
void BlenderSync::sync_render_passes(BL::RenderLayer &b_rlay, BL::ViewLayer &b_view_layer)
{
- PointerRNA cscene = RNA_pointer_get(&b_scene.ptr, "cycles");
-
/* Delete all existing passes. */
set<Pass *> clear_passes(scene->passes.begin(), scene->passes.end());
scene->delete_nodes(clear_passes);
@@ -664,103 +666,23 @@ void BlenderSync::sync_render_passes(BL::RenderLayer &b_rlay, BL::ViewLayer &b_v
/* Always add combined pass. */
pass_add(scene, PASS_COMBINED, "Combined");
- /* Blender built-in data and light passes. */
- for (BL::RenderPass &b_pass : b_rlay.passes) {
- const PassType pass_type = get_blender_pass_type(b_pass);
-
- if (pass_type == PASS_NONE) {
- LOG(ERROR) << "Unknown pass " << b_pass.name();
- continue;
- }
-
- if (pass_type == PASS_MOTION &&
- (b_view_layer.use_motion_blur() && b_scene.render().use_motion_blur())) {
- continue;
- }
-
- pass_add(scene, pass_type, b_pass.name().c_str());
- }
-
- PointerRNA crl = RNA_pointer_get(&b_view_layer.ptr, "cycles");
-
- /* Debug passes. */
- if (get_boolean(crl, "pass_debug_sample_count")) {
- b_engine.add_pass("Debug Sample Count", 1, "X", b_view_layer.name().c_str());
- pass_add(scene, PASS_SAMPLE_COUNT, "Debug Sample Count");
- }
-
- /* Cycles specific passes. */
- if (get_boolean(crl, "use_pass_volume_direct")) {
- b_engine.add_pass("VolumeDir", 3, "RGB", b_view_layer.name().c_str());
- pass_add(scene, PASS_VOLUME_DIRECT, "VolumeDir");
- }
- if (get_boolean(crl, "use_pass_volume_indirect")) {
- b_engine.add_pass("VolumeInd", 3, "RGB", b_view_layer.name().c_str());
- pass_add(scene, PASS_VOLUME_INDIRECT, "VolumeInd");
- }
- if (get_boolean(crl, "use_pass_shadow_catcher")) {
- b_engine.add_pass("Shadow Catcher", 3, "RGB", b_view_layer.name().c_str());
- pass_add(scene, PASS_SHADOW_CATCHER, "Shadow Catcher");
- }
-
/* Cryptomatte stores two ID/weight pairs per RGBA layer.
- * User facing parameter is the number of pairs.
- *
- * NOTE: Name channels lowercase RGBA so that compression rules check in OpenEXR DWA code uses
- * lossless compression. Reportedly this naming is the only one which works good from the
- * interoperability point of view. Using XYZW naming is not portable. */
+ * User facing parameter is the number of pairs. */
int crypto_depth = divide_up(min(16, b_view_layer.pass_cryptomatte_depth()), 2);
scene->film->set_cryptomatte_depth(crypto_depth);
CryptomatteType cryptomatte_passes = CRYPT_NONE;
if (b_view_layer.use_pass_cryptomatte_object()) {
- for (int i = 0; i < crypto_depth; i++) {
- string passname = cryptomatte_prefix + string_printf("Object%02d", i);
- b_engine.add_pass(passname.c_str(), 4, "rgba", b_view_layer.name().c_str());
- pass_add(scene, PASS_CRYPTOMATTE, passname.c_str());
- }
cryptomatte_passes = (CryptomatteType)(cryptomatte_passes | CRYPT_OBJECT);
}
if (b_view_layer.use_pass_cryptomatte_material()) {
- for (int i = 0; i < crypto_depth; i++) {
- string passname = cryptomatte_prefix + string_printf("Material%02d", i);
- b_engine.add_pass(passname.c_str(), 4, "rgba", b_view_layer.name().c_str());
- pass_add(scene, PASS_CRYPTOMATTE, passname.c_str());
- }
cryptomatte_passes = (CryptomatteType)(cryptomatte_passes | CRYPT_MATERIAL);
}
if (b_view_layer.use_pass_cryptomatte_asset()) {
- for (int i = 0; i < crypto_depth; i++) {
- string passname = cryptomatte_prefix + string_printf("Asset%02d", i);
- b_engine.add_pass(passname.c_str(), 4, "rgba", b_view_layer.name().c_str());
- pass_add(scene, PASS_CRYPTOMATTE, passname.c_str());
- }
cryptomatte_passes = (CryptomatteType)(cryptomatte_passes | CRYPT_ASSET);
}
scene->film->set_cryptomatte_passes(cryptomatte_passes);
- /* Denoising passes. */
- const bool use_denoising = get_boolean(cscene, "use_denoising") &&
- get_boolean(crl, "use_denoising");
- const bool store_denoising_passes = get_boolean(crl, "denoising_store_passes");
- if (use_denoising) {
- b_engine.add_pass("Noisy Image", 4, "RGBA", b_view_layer.name().c_str());
- pass_add(scene, PASS_COMBINED, "Noisy Image", PassMode::NOISY);
- if (get_boolean(crl, "use_pass_shadow_catcher")) {
- b_engine.add_pass("Noisy Shadow Catcher", 3, "RGB", b_view_layer.name().c_str());
- pass_add(scene, PASS_SHADOW_CATCHER, "Noisy Shadow Catcher", PassMode::NOISY);
- }
- }
- if (store_denoising_passes) {
- b_engine.add_pass("Denoising Normal", 3, "XYZ", b_view_layer.name().c_str());
- pass_add(scene, PASS_DENOISING_NORMAL, "Denoising Normal", PassMode::NOISY);
-
- b_engine.add_pass("Denoising Albedo", 3, "RGB", b_view_layer.name().c_str());
- pass_add(scene, PASS_DENOISING_ALBEDO, "Denoising Albedo", PassMode::NOISY);
-
- b_engine.add_pass("Denoising Depth", 1, "Z", b_view_layer.name().c_str());
- pass_add(scene, PASS_DENOISING_DEPTH, "Denoising Depth", PassMode::NOISY);
- }
-
+ /* Path guiding debug passes. */
#ifdef WITH_CYCLES_DEBUG
b_engine.add_pass("Guiding Color", 3, "RGB", b_view_layer.name().c_str());
pass_add(scene, PASS_GUIDING_COLOR, "Guiding Color", PassMode::NOISY);
@@ -772,6 +694,8 @@ void BlenderSync::sync_render_passes(BL::RenderLayer &b_rlay, BL::ViewLayer &b_v
pass_add(scene, PASS_GUIDING_AVG_ROUGHNESS, "Guiding Average Roughness", PassMode::NOISY);
#endif
+ unordered_set<string> expected_passes;
+
/* Custom AOV passes. */
BL::ViewLayer::aovs_iterator b_aov_iter;
for (b_view_layer.aovs.begin(b_aov_iter); b_aov_iter != b_view_layer.aovs.end(); ++b_aov_iter) {
@@ -781,16 +705,10 @@ void BlenderSync::sync_render_passes(BL::RenderLayer &b_rlay, BL::ViewLayer &b_v
}
string name = b_aov.name();
- bool is_color = b_aov.type() == BL::AOV::type_COLOR;
+ PassType type = (b_aov.type() == BL::AOV::type_COLOR) ? PASS_AOV_COLOR : PASS_AOV_VALUE;
- if (is_color) {
- b_engine.add_pass(name.c_str(), 4, "RGBA", b_view_layer.name().c_str());
- pass_add(scene, PASS_AOV_COLOR, name.c_str());
- }
- else {
- b_engine.add_pass(name.c_str(), 1, "X", b_view_layer.name().c_str());
- pass_add(scene, PASS_AOV_VALUE, name.c_str());
- }
+ pass_add(scene, type, name.c_str());
+ expected_passes.insert(name);
}
/* Light Group passes. */
@@ -802,9 +720,29 @@ void BlenderSync::sync_render_passes(BL::RenderLayer &b_rlay, BL::ViewLayer &b_v
string name = string_printf("Combined_%s", b_lightgroup.name().c_str());
- b_engine.add_pass(name.c_str(), 3, "RGB", b_view_layer.name().c_str());
Pass *pass = pass_add(scene, PASS_COMBINED, name.c_str(), PassMode::NOISY);
pass->set_lightgroup(ustring(b_lightgroup.name()));
+ expected_passes.insert(name);
+ }
+
+ /* Sync the passes that were defined in engine.py. */
+ for (BL::RenderPass &b_pass : b_rlay.passes) {
+ PassType pass_type = PASS_NONE;
+ PassMode pass_mode = PassMode::DENOISED;
+
+ if (!get_known_pass_type(b_pass, pass_type, pass_mode)) {
+ if (!expected_passes.count(b_pass.name())) {
+ LOG(ERROR) << "Unknown pass " << b_pass.name();
+ }
+ continue;
+ }
+
+ if (pass_type == PASS_MOTION &&
+ (b_view_layer.use_motion_blur() && b_scene.render().use_motion_blur())) {
+ continue;
+ }
+
+ pass_add(scene, pass_type, b_pass.name().c_str(), pass_mode);
}
scene->film->set_pass_alpha_threshold(b_view_layer.pass_alpha_threshold());
diff --git a/intern/cycles/cmake/external_libs.cmake b/intern/cycles/cmake/external_libs.cmake
index 9524cda54f5..44542a08156 100644
--- a/intern/cycles/cmake/external_libs.cmake
+++ b/intern/cycles/cmake/external_libs.cmake
@@ -289,8 +289,7 @@ if(CYCLES_STANDALONE_REPOSITORY AND WITH_CYCLES_PATH_GUIDING)
endif()
get_target_property(OPENPGL_INCLUDE_DIR openpgl::openpgl INTERFACE_INCLUDE_DIRECTORIES)
else()
- set(WITH_CYCLES_PATH_GUIDING OFF)
- message(STATUS "OpenPGL not found, disabling WITH_CYCLES_PATH_GUIDING")
+ set_and_warn_library_found("OpenPGL" openpgl_FOUND WITH_CYCLES_PATH_GUIDING)
endif()
endif()
@@ -588,16 +587,14 @@ if(WITH_CYCLES_STANDALONE AND WITH_CYCLES_STANDALONE_GUI)
# We can't use the version from the Blender precompiled libraries because
# it does not include the video subsystem.
find_package(SDL2 REQUIRED)
+ set_and_warn_library_found("SDL" SDL2_FOUND WITH_CYCLES_STANDALONE_GUI)
- if(NOT SDL2_FOUND)
- set(WITH_CYCLES_STANDALONE_GUI OFF)
- message(STATUS "SDL not found, disabling Cycles standalone GUI")
+ if(SDL2_FOUND)
+ include_directories(
+ SYSTEM
+ ${SDL2_INCLUDE_DIRS}
+ )
endif()
-
- include_directories(
- SYSTEM
- ${SDL2_INCLUDE_DIRS}
- )
endif()
###########################################################################
@@ -606,11 +603,11 @@ endif()
if(WITH_CYCLES_DEVICE_CUDA AND (WITH_CYCLES_CUDA_BINARIES OR NOT WITH_CUDA_DYNLOAD))
find_package(CUDA) # Try to auto locate CUDA toolkit
+ set_and_warn_library_found("CUDA compiler" CUDA_FOUND WITH_CYCLES_CUDA_BINARIES)
+
if(CUDA_FOUND)
message(STATUS "Found CUDA ${CUDA_NVCC_EXECUTABLE} (${CUDA_VERSION})")
else()
- message(STATUS "CUDA compiler not found, disabling WITH_CYCLES_CUDA_BINARIES")
- set(WITH_CYCLES_CUDA_BINARIES OFF)
if(NOT WITH_CUDA_DYNLOAD)
message(STATUS "Additionally falling back to dynamic CUDA load")
set(WITH_CUDA_DYNLOAD ON)
@@ -624,11 +621,10 @@ endif()
if(WITH_CYCLES_HIP_BINARIES AND WITH_CYCLES_DEVICE_HIP)
find_package(HIP)
+ set_and_warn_library_found("HIP compiler" HIP_FOUND WITH_CYCLES_HIP_BINARIES)
+
if(HIP_FOUND)
message(STATUS "Found HIP ${HIP_HIPCC_EXECUTABLE} (${HIP_VERSION})")
- else()
- message(STATUS "HIP compiler not found, disabling WITH_CYCLES_HIP_BINARIES")
- set(WITH_CYCLES_HIP_BINARIES OFF)
endif()
endif()
@@ -644,13 +640,17 @@ if(WITH_CYCLES_DEVICE_METAL)
find_library(METAL_LIBRARY Metal)
# This file was added in the 12.0 SDK, use it as a way to detect the version.
- if(METAL_LIBRARY AND NOT EXISTS "${METAL_LIBRARY}/Headers/MTLFunctionStitching.h")
- message(STATUS "Metal version too old, must be SDK 12.0 or newer, disabling WITH_CYCLES_DEVICE_METAL")
- set(WITH_CYCLES_DEVICE_METAL OFF)
- elseif(NOT METAL_LIBRARY)
- message(STATUS "Metal not found, disabling WITH_CYCLES_DEVICE_METAL")
- set(WITH_CYCLES_DEVICE_METAL OFF)
- else()
+ if(METAL_LIBRARY)
+ if(EXISTS "${METAL_LIBRARY}/Headers/MTLFunctionStitching.h")
+ set(METAL_FOUND ON)
+ else()
+ message(STATUS "Metal version too old, must be SDK 12.0 or newer")
+ set(METAL_FOUND OFF)
+ endif()
+ endif()
+
+ set_and_warn_library_found("Metal" METAL_FOUND WITH_CYCLES_DEVICE_METAL)
+ if(METAL_FOUND)
message(STATUS "Found Metal: ${METAL_LIBRARY}")
endif()
endif()
@@ -662,9 +662,10 @@ endif()
if(WITH_CYCLES_DEVICE_ONEAPI)
find_package(SYCL)
find_package(LevelZero)
+ set_and_warn_library_found("oneAPI" SYCL_FOUND WITH_CYCLES_DEVICE_ONEAPI)
+ set_and_warn_library_found("Level Zero" LEVEL_ZERO_FOUND WITH_CYCLES_DEVICE_ONEAPI)
- if(SYCL_FOUND AND LEVEL_ZERO_FOUND)
- message(STATUS "Found oneAPI: ${SYCL_LIBRARY}")
+ if(SYCL_FOUND AND SYCL_VERSION VERSION_GREATER_EQUAL 6.0 AND LEVEL_ZERO_FOUND)
message(STATUS "Found Level Zero: ${LEVEL_ZERO_LIBRARY}")
if(WITH_CYCLES_ONEAPI_BINARIES)
@@ -675,13 +676,14 @@ if(WITH_CYCLES_DEVICE_ONEAPI)
endif()
if(NOT EXISTS ${OCLOC_INSTALL_DIR})
- message(STATUS "oneAPI ocloc not found in ${OCLOC_INSTALL_DIR}, disabling WITH_CYCLES_ONEAPI_BINARIES."
+ set(OCLOC_FOUND OFF)
+ message(STATUS "oneAPI ocloc not found in ${OCLOC_INSTALL_DIR}."
" A different ocloc directory can be set using OCLOC_INSTALL_DIR cmake variable.")
- set(WITH_CYCLES_ONEAPI_BINARIES OFF)
+ set_and_warn_library_found("ocloc" OCLOC_FOUND WITH_CYCLES_ONEAPI_BINARIES)
endif()
endif()
else()
- message(STATUS "oneAPI or Level Zero not found, disabling WITH_CYCLES_DEVICE_ONEAPI")
+ message(STATUS "SYCL 6.0+ or Level Zero not found, disabling WITH_CYCLES_DEVICE_ONEAPI")
set(WITH_CYCLES_DEVICE_ONEAPI OFF)
endif()
endif()
diff --git a/intern/cycles/device/CMakeLists.txt b/intern/cycles/device/CMakeLists.txt
index 5516e97f34f..5296d819e42 100644
--- a/intern/cycles/device/CMakeLists.txt
+++ b/intern/cycles/device/CMakeLists.txt
@@ -187,18 +187,22 @@ if(WITH_CYCLES_DEVICE_METAL)
)
endif()
if (WITH_CYCLES_DEVICE_ONEAPI)
+ if(WITH_CYCLES_ONEAPI_BINARIES)
+ set(cycles_kernel_oneapi_lib_suffix "_aot")
+ else()
+ set(cycles_kernel_oneapi_lib_suffix "_jit")
+ endif()
if(WIN32)
- set(cycles_kernel_oneapi_lib ${CMAKE_CURRENT_BINARY_DIR}/../kernel/cycles_kernel_oneapi.lib)
+ set(cycles_kernel_oneapi_lib ${CMAKE_CURRENT_BINARY_DIR}/../kernel/cycles_kernel_oneapi${cycles_kernel_oneapi_lib_suffix}.lib)
else()
- set(cycles_kernel_oneapi_lib ${CMAKE_CURRENT_BINARY_DIR}/../kernel/libcycles_kernel_oneapi.so)
+ set(cycles_kernel_oneapi_lib ${CMAKE_CURRENT_BINARY_DIR}/../kernel/libcycles_kernel_oneapi${cycles_kernel_oneapi_lib_suffix}.so)
+ endif()
+ list(APPEND LIB ${cycles_kernel_oneapi_lib})
+ if(WIN32)
+ list(APPEND LIB debug ${SYCL_LIBRARY_DEBUG} optimized ${SYCL_LIBRARY})
+ else()
+ list(APPEND LIB ${SYCL_LIBRARY})
endif()
- list(APPEND LIB
- ${cycles_kernel_oneapi_lib}
- "$<$<CONFIG:Debug>:${SYCL_LIBRARY_DEBUG}>"
- "$<$<CONFIG:Release>:${SYCL_LIBRARY}>"
- "$<$<CONFIG:RelWithDebInfo>:${SYCL_LIBRARY}>"
- "$<$<CONFIG:MinSizeRel>:${SYCL_LIBRARY}>"
- )
add_definitions(-DWITH_ONEAPI)
list(APPEND SRC
${SRC_ONEAPI}
diff --git a/intern/cycles/device/cuda/queue.cpp b/intern/cycles/device/cuda/queue.cpp
index 84b0a1e0dd6..69fae03e32c 100644
--- a/intern/cycles/device/cuda/queue.cpp
+++ b/intern/cycles/device/cuda/queue.cpp
@@ -49,7 +49,7 @@ int CUDADeviceQueue::num_concurrent_states(const size_t state_size) const
return num_states;
}
-int CUDADeviceQueue::num_concurrent_busy_states() const
+int CUDADeviceQueue::num_concurrent_busy_states(const size_t /*state_size*/) const
{
const int max_num_threads = cuda_device_->get_num_multiprocessors() *
cuda_device_->get_max_num_threads_per_multiprocessor();
diff --git a/intern/cycles/device/cuda/queue.h b/intern/cycles/device/cuda/queue.h
index b450f5b3592..7107afe70c9 100644
--- a/intern/cycles/device/cuda/queue.h
+++ b/intern/cycles/device/cuda/queue.h
@@ -23,7 +23,7 @@ class CUDADeviceQueue : public DeviceQueue {
~CUDADeviceQueue();
virtual int num_concurrent_states(const size_t state_size) const override;
- virtual int num_concurrent_busy_states() const override;
+ virtual int num_concurrent_busy_states(const size_t state_size) const override;
virtual void init_execution() override;
diff --git a/intern/cycles/device/hip/queue.cpp b/intern/cycles/device/hip/queue.cpp
index 3f8b6267100..e93a9b4df3a 100644
--- a/intern/cycles/device/hip/queue.cpp
+++ b/intern/cycles/device/hip/queue.cpp
@@ -49,7 +49,7 @@ int HIPDeviceQueue::num_concurrent_states(const size_t state_size) const
return num_states;
}
-int HIPDeviceQueue::num_concurrent_busy_states() const
+int HIPDeviceQueue::num_concurrent_busy_states(const size_t /*state_size*/) const
{
const int max_num_threads = hip_device_->get_num_multiprocessors() *
hip_device_->get_max_num_threads_per_multiprocessor();
diff --git a/intern/cycles/device/hip/queue.h b/intern/cycles/device/hip/queue.h
index 729d8a19acb..df0678108af 100644
--- a/intern/cycles/device/hip/queue.h
+++ b/intern/cycles/device/hip/queue.h
@@ -23,7 +23,7 @@ class HIPDeviceQueue : public DeviceQueue {
~HIPDeviceQueue();
virtual int num_concurrent_states(const size_t state_size) const override;
- virtual int num_concurrent_busy_states() const override;
+ virtual int num_concurrent_busy_states(const size_t state_size) const override;
virtual void init_execution() override;
diff --git a/intern/cycles/device/metal/device_impl.mm b/intern/cycles/device/metal/device_impl.mm
index d1250b83d22..6f1042b1e55 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"));
@@ -292,9 +296,11 @@ void MetalDevice::make_source(MetalPipelineType pso_type, const uint kernel_feat
}
source = global_defines + source;
+# if 0
metal_printf("================\n%s================\n\%s================\n",
global_defines.c_str(),
baked_constants.c_str());
+# endif
/* Generate an MD5 from the source and include any baked constants. This is used when caching
* PSOs. */
@@ -335,6 +341,14 @@ bool MetalDevice::compile_and_load(MetalPipelineType pso_type)
MTLCompileOptions *options = [[MTLCompileOptions alloc] init];
+# if defined(MAC_OS_VERSION_13_0)
+ if (@available(macos 13.0, *)) {
+ if (device_vendor == METAL_GPU_INTEL) {
+ [options setOptimizationLevel:MTLLibraryOptimizationLevelSize];
+ }
+ }
+# endif
+
options.fastMathEnabled = YES;
if (@available(macOS 12.0, *)) {
options.languageVersion = MTLLanguageVersion2_4;
diff --git a/intern/cycles/device/metal/kernel.mm b/intern/cycles/device/metal/kernel.mm
index 5e0cb6d18f4..55938d1a03a 100644
--- a/intern/cycles/device/metal/kernel.mm
+++ b/intern/cycles/device/metal/kernel.mm
@@ -162,6 +162,13 @@ bool ShaderCache::should_load_kernel(DeviceKernel device_kernel,
}
}
+ if (device_kernel == DEVICE_KERNEL_INTEGRATOR_SHADE_SURFACE_MNEE) {
+ if ((device->kernel_features & KERNEL_FEATURE_MNEE) == 0) {
+ /* Skip shade_surface_mnee kernel if the scene doesn't require it. */
+ return false;
+ }
+ }
+
if (pso_type != PSO_GENERIC) {
/* Only specialize kernels where it can make an impact. */
if (device_kernel < DEVICE_KERNEL_INTEGRATOR_INTERSECT_CLOSEST ||
@@ -317,6 +324,12 @@ bool MetalKernelPipeline::should_use_binary_archive() const
}
}
+ /* Workaround for Intel GPU having issue using Binary Archives */
+ MetalGPUVendor gpu_vendor = MetalInfo::get_device_vendor(mtlDevice);
+ if (gpu_vendor == METAL_GPU_INTEL) {
+ return false;
+ }
+
if (pso_type == PSO_GENERIC) {
/* Archive the generic kernels. */
return true;
diff --git a/intern/cycles/device/metal/queue.h b/intern/cycles/device/metal/queue.h
index fc32740f3e1..2a6c12e2a60 100644
--- a/intern/cycles/device/metal/queue.h
+++ b/intern/cycles/device/metal/queue.h
@@ -23,7 +23,7 @@ class MetalDeviceQueue : public DeviceQueue {
~MetalDeviceQueue();
virtual int num_concurrent_states(const size_t) const override;
- virtual int num_concurrent_busy_states() const override;
+ virtual int num_concurrent_busy_states(const size_t) const override;
virtual int num_sort_partition_elements() const override;
virtual void init_execution() override;
diff --git a/intern/cycles/device/metal/queue.mm b/intern/cycles/device/metal/queue.mm
index 5ac63a16c61..c0df2c8553f 100644
--- a/intern/cycles/device/metal/queue.mm
+++ b/intern/cycles/device/metal/queue.mm
@@ -264,33 +264,46 @@ MetalDeviceQueue::~MetalDeviceQueue()
}
}
-int MetalDeviceQueue::num_concurrent_states(const size_t /*state_size*/) const
+int MetalDeviceQueue::num_concurrent_states(const size_t state_size) const
{
- /* METAL_WIP */
- /* TODO: compute automatically. */
- /* TODO: must have at least num_threads_per_block. */
- int result = 1048576;
- if (metal_device_->device_vendor == METAL_GPU_AMD) {
- result *= 2;
+ static int result = 0;
+ if (result) {
+ return result;
}
- else if (metal_device_->device_vendor == METAL_GPU_APPLE) {
+
+ result = 1048576;
+ if (metal_device_->device_vendor == METAL_GPU_APPLE) {
result *= 4;
+
+ if (MetalInfo::get_apple_gpu_architecture(metal_device_->mtlDevice) == APPLE_M2) {
+ size_t system_ram = system_physical_ram();
+ size_t allocated_so_far = [metal_device_->mtlDevice currentAllocatedSize];
+ size_t max_recommended_working_set = [metal_device_->mtlDevice recommendedMaxWorkingSetSize];
+
+ /* Determine whether we can double the state count, and leave enough GPU-available memory
+ * (1/8 the system RAM or 1GB - whichever is largest). Enlarging the state size allows us to
+ * keep dispatch sizes high and minimize work submission overheads. */
+ size_t min_headroom = std::max(system_ram / 8, size_t(1024 * 1024 * 1024));
+ size_t total_state_size = result * state_size;
+ if (max_recommended_working_set - allocated_so_far - total_state_size * 2 >= min_headroom) {
+ result *= 2;
+ metal_printf("Doubling state count to exploit available RAM (new size = %d)\n", result);
+ }
+ }
+ }
+ else if (metal_device_->device_vendor == METAL_GPU_AMD) {
+ /* METAL_WIP */
+ /* TODO: compute automatically. */
+ /* TODO: must have at least num_threads_per_block. */
+ result *= 2;
}
return result;
}
-int MetalDeviceQueue::num_concurrent_busy_states() const
+int MetalDeviceQueue::num_concurrent_busy_states(const size_t state_size) const
{
- /* METAL_WIP */
- /* TODO: compute automatically. */
- int result = 65536;
- if (metal_device_->device_vendor == METAL_GPU_AMD) {
- result *= 2;
- }
- else if (metal_device_->device_vendor == METAL_GPU_APPLE) {
- result *= 4;
- }
- return result;
+ /* A 1:4 busy:total ratio gives best rendering performance, independent of total state count. */
+ return num_concurrent_states(state_size) / 4;
}
int MetalDeviceQueue::num_sort_partition_elements() const
diff --git a/intern/cycles/device/metal/util.mm b/intern/cycles/device/metal/util.mm
index 65c67c400fe..f47638fac15 100644
--- a/intern/cycles/device/metal/util.mm
+++ b/intern/cycles/device/metal/util.mm
@@ -110,6 +110,12 @@ vector<id<MTLDevice>> const &MetalInfo::get_usable_devices()
usable |= (vendor == METAL_GPU_AMD);
}
+# if defined(MAC_OS_VERSION_13_0)
+ if (@available(macos 13.0, *)) {
+ usable |= (vendor == METAL_GPU_INTEL);
+ }
+# endif
+
if (usable) {
metal_printf("- %s\n", device_name.c_str());
[device retain];
diff --git a/intern/cycles/device/oneapi/device.cpp b/intern/cycles/device/oneapi/device.cpp
index f303ab41627..66d6f749e30 100644
--- a/intern/cycles/device/oneapi/device.cpp
+++ b/intern/cycles/device/oneapi/device.cpp
@@ -39,7 +39,7 @@ bool device_oneapi_init()
_putenv_s("SYCL_CACHE_THRESHOLD", "0");
}
if (getenv("SYCL_DEVICE_FILTER") == nullptr) {
- _putenv_s("SYCL_DEVICE_FILTER", "host,level_zero");
+ _putenv_s("SYCL_DEVICE_FILTER", "level_zero");
}
if (getenv("SYCL_ENABLE_PCI") == nullptr) {
_putenv_s("SYCL_ENABLE_PCI", "1");
@@ -50,7 +50,7 @@ bool device_oneapi_init()
# elif __linux__
setenv("SYCL_CACHE_PERSISTENT", "1", false);
setenv("SYCL_CACHE_THRESHOLD", "0", false);
- setenv("SYCL_DEVICE_FILTER", "host,level_zero", false);
+ setenv("SYCL_DEVICE_FILTER", "level_zero", false);
setenv("SYCL_ENABLE_PCI", "1", false);
setenv("SYCL_PI_LEVEL_ZERO_USE_COPY_ENGINE_FOR_IN_ORDER_QUEUE", "0", false);
# endif
diff --git a/intern/cycles/device/oneapi/device_impl.cpp b/intern/cycles/device/oneapi/device_impl.cpp
index 2df605fa047..3588b75713b 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;
}
@@ -422,9 +430,14 @@ void OneapiDevice::check_usm(SyclQueue *queue_, const void *usm_ptr, bool allow_
sycl::usm::alloc usm_type = get_pointer_type(usm_ptr, queue->get_context());
(void)usm_type;
assert(usm_type == sycl::usm::alloc::device ||
- ((device_type == sycl::info::device_type::host ||
- device_type == sycl::info::device_type::cpu || allow_host) &&
- usm_type == sycl::usm::alloc::host));
+ ((device_type == sycl::info::device_type::cpu || allow_host) &&
+ usm_type == sycl::usm::alloc::host ||
+ usm_type == sycl::usm::alloc::unknown));
+# 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);
@@ -658,14 +671,6 @@ std::vector<sycl::device> OneapiDevice::available_devices()
if (getenv("CYCLES_ONEAPI_ALL_DEVICES") != nullptr)
allow_all_devices = true;
- /* Host device is useful only for debugging at the moment
- * so we hide this device with default build settings. */
-# ifdef WITH_ONEAPI_SYCL_HOST_ENABLED
- bool allow_host = true;
-# else
- bool allow_host = false;
-# endif
-
const std::vector<sycl::platform> &oneapi_platforms = sycl::platform::get_platforms();
std::vector<sycl::device> available_devices;
@@ -677,17 +682,11 @@ std::vector<sycl::device> OneapiDevice::available_devices()
}
const std::vector<sycl::device> &oneapi_devices =
- (allow_all_devices || allow_host) ? platform.get_devices(sycl::info::device_type::all) :
- platform.get_devices(sycl::info::device_type::gpu);
+ (allow_all_devices) ? platform.get_devices(sycl::info::device_type::all) :
+ platform.get_devices(sycl::info::device_type::gpu);
for (const sycl::device &device : oneapi_devices) {
- if (allow_all_devices) {
- /* still filter out host device if build doesn't support it. */
- if (allow_host || !device.is_host()) {
- available_devices.push_back(device);
- }
- }
- else {
+ if (!allow_all_devices) {
bool filter_out = false;
/* For now we support all Intel(R) Arc(TM) devices and likely any future GPU,
@@ -699,11 +698,11 @@ std::vector<sycl::device> OneapiDevice::available_devices()
int number_of_eus = 96;
int threads_per_eu = 7;
if (device.has(sycl::aspect::ext_intel_gpu_eu_count)) {
- number_of_eus = device.get_info<sycl::info::device::ext_intel_gpu_eu_count>();
+ number_of_eus = device.get_info<sycl::ext::intel::info::device::gpu_eu_count>();
}
if (device.has(sycl::aspect::ext_intel_gpu_hw_threads_per_eu)) {
threads_per_eu =
- device.get_info<sycl::info::device::ext_intel_gpu_hw_threads_per_eu>();
+ device.get_info<sycl::ext::intel::info::device::gpu_hw_threads_per_eu>();
}
/* This filters out all Level-Zero supported GPUs from older generation than Arc. */
if (number_of_eus <= 96 && threads_per_eu == 7) {
@@ -719,9 +718,6 @@ std::vector<sycl::device> OneapiDevice::available_devices()
}
}
}
- else if (!allow_host && device.is_host()) {
- filter_out = true;
- }
else if (!allow_all_devices) {
filter_out = true;
}
@@ -784,9 +780,7 @@ char *OneapiDevice::device_capabilities()
GET_NUM_ATTR(native_vector_width_double)
GET_NUM_ATTR(native_vector_width_half)
- size_t max_clock_frequency =
- (size_t)(device.is_host() ? (size_t)0 :
- device.get_info<sycl::info::device::max_clock_frequency>());
+ size_t max_clock_frequency = device.get_info<sycl::info::device::max_clock_frequency>();
WRITE_ATTR("max_clock_frequency", max_clock_frequency)
GET_NUM_ATTR(address_bits)
@@ -824,7 +818,7 @@ void OneapiDevice::iterate_devices(OneAPIDeviceIteratorCallback cb, void *user_p
std::string name = device.get_info<sycl::info::device::name>();
std::string id = "ONEAPI_" + platform_name + "_" + name;
if (device.has(sycl::aspect::ext_intel_pci_address)) {
- id.append("_" + device.get_info<sycl::info::device::ext_intel_pci_address>());
+ id.append("_" + device.get_info<sycl::ext::intel::info::device::pci_address>());
}
(cb)(id.c_str(), name.c_str(), num, user_ptr);
num++;
@@ -842,7 +836,7 @@ int OneapiDevice::get_num_multiprocessors()
{
const sycl::device &device = reinterpret_cast<sycl::queue *>(device_queue_)->get_device();
if (device.has(sycl::aspect::ext_intel_gpu_eu_count)) {
- return device.get_info<sycl::info::device::ext_intel_gpu_eu_count>();
+ return device.get_info<sycl::ext::intel::info::device::gpu_eu_count>();
}
else
return 0;
@@ -853,8 +847,8 @@ int OneapiDevice::get_max_num_threads_per_multiprocessor()
const sycl::device &device = reinterpret_cast<sycl::queue *>(device_queue_)->get_device();
if (device.has(sycl::aspect::ext_intel_gpu_eu_simd_width) &&
device.has(sycl::aspect::ext_intel_gpu_hw_threads_per_eu)) {
- return device.get_info<sycl::info::device::ext_intel_gpu_eu_simd_width>() *
- device.get_info<sycl::info::device::ext_intel_gpu_hw_threads_per_eu>();
+ return device.get_info<sycl::ext::intel::info::device::gpu_eu_simd_width>() *
+ device.get_info<sycl::ext::intel::info::device::gpu_hw_threads_per_eu>();
}
else
return 0;
diff --git a/intern/cycles/device/oneapi/device_impl.h b/intern/cycles/device/oneapi/device_impl.h
index 3589e881a6e..197cf03d60d 100644
--- a/intern/cycles/device/oneapi/device_impl.h
+++ b/intern/cycles/device/oneapi/device_impl.h
@@ -3,7 +3,7 @@
#ifdef WITH_ONEAPI
-# include <CL/sycl.hpp>
+# include <sycl/sycl.hpp>
# include "device/device.h"
# include "device/oneapi/device.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/device/oneapi/queue.cpp b/intern/cycles/device/oneapi/queue.cpp
index 9632b14d485..3d019661aa8 100644
--- a/intern/cycles/device/oneapi/queue.cpp
+++ b/intern/cycles/device/oneapi/queue.cpp
@@ -43,7 +43,7 @@ int OneapiDeviceQueue::num_concurrent_states(const size_t state_size) const
return num_states;
}
-int OneapiDeviceQueue::num_concurrent_busy_states() const
+int OneapiDeviceQueue::num_concurrent_busy_states(const size_t /*state_size*/) const
{
const int max_num_threads = oneapi_device_->get_num_multiprocessors() *
oneapi_device_->get_max_num_threads_per_multiprocessor();
diff --git a/intern/cycles/device/oneapi/queue.h b/intern/cycles/device/oneapi/queue.h
index 32363bf2a6e..bbd947b49cb 100644
--- a/intern/cycles/device/oneapi/queue.h
+++ b/intern/cycles/device/oneapi/queue.h
@@ -25,7 +25,7 @@ class OneapiDeviceQueue : public DeviceQueue {
virtual int num_concurrent_states(const size_t state_size) const override;
- virtual int num_concurrent_busy_states() const override;
+ virtual int num_concurrent_busy_states(const size_t state_size) const override;
virtual void init_execution() override;
diff --git a/intern/cycles/device/queue.h b/intern/cycles/device/queue.h
index 1d6a8d736b7..e27e081a407 100644
--- a/intern/cycles/device/queue.h
+++ b/intern/cycles/device/queue.h
@@ -103,7 +103,7 @@ class DeviceQueue {
/* Number of states which keeps the device occupied with work without losing performance.
* The renderer will add more work (when available) when number of active paths falls below this
* value. */
- virtual int num_concurrent_busy_states() const = 0;
+ virtual int num_concurrent_busy_states(const size_t state_size) const = 0;
/* Number of elements in a partition of sorted shaders, that improves memory locality of
* integrator state fetch at the cost of decreased coherence for shader kernel execution. */
diff --git a/intern/cycles/integrator/path_trace.cpp b/intern/cycles/integrator/path_trace.cpp
index 6b033cfd051..8e8fbd86be0 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());
@@ -1293,6 +1296,7 @@ void PathTrace::set_guiding_params(const GuidingParams &guiding_params, const bo
# if OPENPGL_VERSION_MINOR >= 4
field_args.deterministic = guiding_params.deterministic;
# endif
+ reinterpret_cast<PGLKDTreeArguments *>(field_args.spatialSturctureArguments)->maxDepth = 16;
openpgl::cpp::Device *guiding_device = static_cast<openpgl::cpp::Device *>(
device_->get_guiding_device());
if (guiding_device) {
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/path_trace_work_gpu.cpp b/intern/cycles/integrator/path_trace_work_gpu.cpp
index ee250a6916b..48f6cf3c903 100644
--- a/intern/cycles/integrator/path_trace_work_gpu.cpp
+++ b/intern/cycles/integrator/path_trace_work_gpu.cpp
@@ -18,13 +18,15 @@
CCL_NAMESPACE_BEGIN
-static size_t estimate_single_state_size()
+static size_t estimate_single_state_size(const uint kernel_features)
{
size_t state_size = 0;
#define KERNEL_STRUCT_BEGIN(name) for (int array_index = 0;; array_index++) {
-#define KERNEL_STRUCT_MEMBER(parent_struct, type, name, feature) state_size += sizeof(type);
-#define KERNEL_STRUCT_ARRAY_MEMBER(parent_struct, type, name, feature) state_size += sizeof(type);
+#define KERNEL_STRUCT_MEMBER(parent_struct, type, name, feature) \
+ state_size += (kernel_features & (feature)) ? sizeof(type) : 0;
+#define KERNEL_STRUCT_ARRAY_MEMBER(parent_struct, type, name, feature) \
+ state_size += (kernel_features & (feature)) ? sizeof(type) : 0;
#define KERNEL_STRUCT_END(name) \
break; \
}
@@ -76,16 +78,11 @@ PathTraceWorkGPU::PathTraceWorkGPU(Device *device,
num_queued_paths_(device, "num_queued_paths", MEM_READ_WRITE),
work_tiles_(device, "work_tiles", MEM_READ_WRITE),
display_rgba_half_(device, "display buffer half", MEM_READ_WRITE),
- max_num_paths_(queue_->num_concurrent_states(estimate_single_state_size())),
- min_num_active_main_paths_(queue_->num_concurrent_busy_states()),
+ max_num_paths_(0),
+ min_num_active_main_paths_(0),
max_active_main_path_index_(0)
{
memset(&integrator_state_gpu_, 0, sizeof(integrator_state_gpu_));
-
- /* Limit number of active paths to the half of the overall state. This is due to the logic in the
- * path compaction which relies on the fact that regeneration does not happen sooner than half of
- * the states are available again. */
- min_num_active_main_paths_ = min(min_num_active_main_paths_, max_num_paths_ / 2);
}
void PathTraceWorkGPU::alloc_integrator_soa()
@@ -103,6 +100,20 @@ void PathTraceWorkGPU::alloc_integrator_soa()
integrator_state_soa_volume_stack_size_ = max(integrator_state_soa_volume_stack_size_,
requested_volume_stack_size);
+ /* Deterine the number of path states. Deferring this for as long as possible allows the backend
+ * to make better decisions about memory availability. */
+ if (max_num_paths_ == 0) {
+ size_t single_state_size = estimate_single_state_size(kernel_features);
+
+ max_num_paths_ = queue_->num_concurrent_states(single_state_size);
+ min_num_active_main_paths_ = queue_->num_concurrent_busy_states(single_state_size);
+
+ /* Limit number of active paths to the half of the overall state. This is due to the logic in
+ * the path compaction which relies on the fact that regeneration does not happen sooner than
+ * half of the states are available again. */
+ min_num_active_main_paths_ = min(min_num_active_main_paths_, max_num_paths_ / 2);
+ }
+
/* Allocate a device only memory buffer before for each struct member, and then
* write the pointers into a struct that resides in constant memory.
*
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..81c5f593974 100644
--- a/intern/cycles/kernel/CMakeLists.txt
+++ b/intern/cycles/kernel/CMakeLists.txt
@@ -713,10 +713,17 @@ endif()
# oneAPI module
if(WITH_CYCLES_DEVICE_ONEAPI)
+ if(WITH_CYCLES_ONEAPI_BINARIES)
+ set(cycles_kernel_oneapi_lib_suffix "_aot")
+ else()
+ set(cycles_kernel_oneapi_lib_suffix "_jit")
+ endif()
+
if(WIN32)
- set(cycles_kernel_oneapi_lib ${CMAKE_CURRENT_BINARY_DIR}/cycles_kernel_oneapi.dll)
+ set(cycles_kernel_oneapi_lib ${CMAKE_CURRENT_BINARY_DIR}/cycles_kernel_oneapi${cycles_kernel_oneapi_lib_suffix}.dll)
+ set(cycles_kernel_oneapi_linker_lib ${CMAKE_CURRENT_BINARY_DIR}/cycles_kernel_oneapi${cycles_kernel_oneapi_lib_suffix}.lib)
else()
- set(cycles_kernel_oneapi_lib ${CMAKE_CURRENT_BINARY_DIR}/libcycles_kernel_oneapi.so)
+ set(cycles_kernel_oneapi_lib ${CMAKE_CURRENT_BINARY_DIR}/libcycles_kernel_oneapi${cycles_kernel_oneapi_lib_suffix}.so)
endif()
set(cycles_oneapi_kernel_sources
@@ -727,16 +734,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 +747,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
@@ -758,10 +758,6 @@ if(WITH_CYCLES_DEVICE_ONEAPI)
${SYCL_CPP_FLAGS}
)
- if (WITH_CYCLES_ONEAPI_SYCL_HOST_ENABLED)
- list(APPEND sycl_compiler_flags -DWITH_ONEAPI_SYCL_HOST_ENABLED)
- endif()
-
# Set defaults for spir64 and spir64_gen options
if (NOT DEFINED CYCLES_ONEAPI_SYCL_OPTIONS_spir64)
set(CYCLES_ONEAPI_SYCL_OPTIONS_spir64 "-options '-ze-opt-large-register-file -ze-opt-regular-grf-kernel integrator_intersect'")
@@ -774,6 +770,8 @@ if(WITH_CYCLES_DEVICE_ONEAPI)
string(PREPEND CYCLES_ONEAPI_SYCL_OPTIONS_spir64_gen "-device ${CYCLES_ONEAPI_SPIR64_GEN_DEVICES} ")
if (WITH_CYCLES_ONEAPI_BINARIES)
+ # AoT binaries aren't currently reused when calling sycl::build.
+ list (APPEND sycl_compiler_flags -DSYCL_SKIP_KERNELS_PRELOAD)
# Iterate over all targest and their options
list (JOIN CYCLES_ONEAPI_SYCL_TARGETS "," targets_string)
list (APPEND sycl_compiler_flags -fsycl-targets=${targets_string})
@@ -826,12 +824,17 @@ if(WITH_CYCLES_DEVICE_ONEAPI)
-DONEAPI_EXPORT)
string(REPLACE /Redist/ /Tools/ MSVC_TOOLS_DIR ${MSVC_REDIST_DIR})
- if(NOT CMAKE_VS_WINDOWS_TARGET_PLATFORM_VERSION) # case for Ninja on Windows
+ # Version Folder between Redist and Tools can mismatch sometimes
+ if(NOT EXISTS ${MSVC_TOOLS_DIR})
+ get_filename_component(cmake_ar_dir ${CMAKE_AR} DIRECTORY)
+ get_filename_component(MSVC_TOOLS_DIR "${cmake_ar_dir}/../../../" ABSOLUTE)
+ endif()
+ if(CMAKE_VS_WINDOWS_TARGET_PLATFORM_VERSION)
+ set(WINDOWS_KIT_DIR ${WINDOWS_KITS_DIR}/Lib/${CMAKE_VS_WINDOWS_TARGET_PLATFORM_VERSION})
+ else() # case for Ninja on Windows
get_filename_component(cmake_mt_dir ${CMAKE_MT} DIRECTORY)
string(REPLACE /bin/ /Lib/ WINDOWS_KIT_DIR ${cmake_mt_dir})
get_filename_component(WINDOWS_KIT_DIR "${WINDOWS_KIT_DIR}/../" ABSOLUTE)
- else()
- set(WINDOWS_KIT_DIR ${WINDOWS_KITS_DIR}/Lib/${CMAKE_VS_WINDOWS_TARGET_PLATFORM_VERSION})
endif()
list(APPEND sycl_compiler_flags
-L "${MSVC_TOOLS_DIR}/lib/x64"
@@ -843,15 +846,13 @@ if(WITH_CYCLES_DEVICE_ONEAPI)
set(sycl_compiler_flags_RelWithDebInfo ${sycl_compiler_flags})
set(sycl_compiler_flags_MinSizeRel ${sycl_compiler_flags})
list(APPEND sycl_compiler_flags_RelWithDebInfo -g)
- get_filename_component(sycl_library_debug_name ${SYCL_LIBRARY_DEBUG} NAME_WE)
list(APPEND sycl_compiler_flags_Debug
-g
-D_DEBUG
- -nostdlib -Xclang --dependent-lib=msvcrtd
- -Xclang --dependent-lib=${sycl_library_debug_name})
+ -nostdlib -Xclang --dependent-lib=msvcrtd)
add_custom_command(
- OUTPUT ${cycles_kernel_oneapi_lib}
+ OUTPUT ${cycles_kernel_oneapi_lib} ${cycles_kernel_oneapi_linker_lib}
COMMAND ${CMAKE_COMMAND} -E env
"LIB=${sycl_compiler_root}/../lib" # for compiler to find sycl.lib
"PATH=${OCLOC_INSTALL_DIR}\;${sycl_compiler_root}"
diff --git a/intern/cycles/kernel/bvh/shadow_all.h b/intern/cycles/kernel/bvh/shadow_all.h
index 2ffe1496c72..b31ba479e4f 100644
--- a/intern/cycles/kernel/bvh/shadow_all.h
+++ b/intern/cycles/kernel/bvh/shadow_all.h
@@ -229,7 +229,7 @@ ccl_device_inline
/* Always use baked shadow transparency for curves. */
if (isect.type & PRIMITIVE_CURVE) {
*r_throughput *= intersection_curve_shadow_transparency(
- kg, isect.object, isect.prim, isect.u);
+ kg, isect.object, isect.prim, isect.type, isect.u);
if (*r_throughput < CURVE_SHADOW_TRANSPARENCY_CUTOFF) {
return true;
diff --git a/intern/cycles/kernel/bvh/util.h b/intern/cycles/kernel/bvh/util.h
index a57703a8b8c..9ba787550c5 100644
--- a/intern/cycles/kernel/bvh/util.h
+++ b/intern/cycles/kernel/bvh/util.h
@@ -190,10 +190,8 @@ ccl_device_inline int intersection_find_attribute(KernelGlobals kg,
/* Cut-off value to stop transparent shadow tracing when practically opaque. */
#define CURVE_SHADOW_TRANSPARENCY_CUTOFF 0.001f
-ccl_device_inline float intersection_curve_shadow_transparency(KernelGlobals kg,
- const int object,
- const int prim,
- const float u)
+ccl_device_inline float intersection_curve_shadow_transparency(
+ KernelGlobals kg, const int object, const int prim, const int type, const float u)
{
/* Find attribute. */
const int offset = intersection_find_attribute(kg, object, ATTR_STD_SHADOW_TRANSPARENCY);
@@ -204,7 +202,7 @@ ccl_device_inline float intersection_curve_shadow_transparency(KernelGlobals kg,
/* Interpolate transparency between curve keys. */
const KernelCurve kcurve = kernel_data_fetch(curves, prim);
- const int k0 = kcurve.first_key + PRIMITIVE_UNPACK_SEGMENT(kcurve.type);
+ const int k0 = kcurve.first_key + PRIMITIVE_UNPACK_SEGMENT(type);
const int k1 = k0 + 1;
const float f0 = kernel_data_fetch(attributes_float, offset + k0);
diff --git a/intern/cycles/kernel/device/cpu/bvh.h b/intern/cycles/kernel/device/cpu/bvh.h
index d9267e1cd6d..2d7d8c2d704 100644
--- a/intern/cycles/kernel/device/cpu/bvh.h
+++ b/intern/cycles/kernel/device/cpu/bvh.h
@@ -252,7 +252,7 @@ ccl_device void kernel_embree_filter_occluded_func(const RTCFilterFunctionNArgum
/* Always use baked shadow transparency for curves. */
if (current_isect.type & PRIMITIVE_CURVE) {
ctx->throughput *= intersection_curve_shadow_transparency(
- kg, current_isect.object, current_isect.prim, current_isect.u);
+ kg, current_isect.object, current_isect.prim, current_isect.type, current_isect.u);
if (ctx->throughput < CURVE_SHADOW_TRANSPARENCY_CUTOFF) {
ctx->opaque_hit = true;
diff --git a/intern/cycles/kernel/device/gpu/parallel_active_index.h b/intern/cycles/kernel/device/gpu/parallel_active_index.h
index c1df49c4f49..38cdcb572eb 100644
--- a/intern/cycles/kernel/device/gpu/parallel_active_index.h
+++ b/intern/cycles/kernel/device/gpu/parallel_active_index.h
@@ -23,22 +23,6 @@ CCL_NAMESPACE_BEGIN
* and keep device specific code in compat.h */
#ifdef __KERNEL_ONEAPI__
-# ifdef WITH_ONEAPI_SYCL_HOST_ENABLED
-template<typename IsActiveOp>
-void cpu_serial_active_index_array_impl(const uint num_states,
- ccl_global int *ccl_restrict indices,
- ccl_global int *ccl_restrict num_indices,
- IsActiveOp is_active_op)
-{
- int write_index = 0;
- for (int state_index = 0; state_index < num_states; state_index++) {
- if (is_active_op(state_index))
- indices[write_index++] = state_index;
- }
- *num_indices = write_index;
- return;
-}
-# endif /* WITH_ONEAPI_SYCL_HOST_ENABLED */
template<typename IsActiveOp>
void gpu_parallel_active_index_array_impl(const uint num_states,
@@ -182,18 +166,11 @@ __device__
num_simd_groups, \
simdgroup_offset)
#elif defined(__KERNEL_ONEAPI__)
-# ifdef WITH_ONEAPI_SYCL_HOST_ENABLED
-# define gpu_parallel_active_index_array( \
- blocksize, num_states, indices, num_indices, is_active_op) \
- if (ccl_gpu_global_size_x() == 1) \
- cpu_serial_active_index_array_impl(num_states, indices, num_indices, is_active_op); \
- else \
- gpu_parallel_active_index_array_impl(num_states, indices, num_indices, is_active_op);
-# else
-# define gpu_parallel_active_index_array( \
- blocksize, num_states, indices, num_indices, is_active_op) \
- gpu_parallel_active_index_array_impl(num_states, indices, num_indices, is_active_op)
-# endif
+
+# define gpu_parallel_active_index_array( \
+ blocksize, num_states, indices, num_indices, is_active_op) \
+ gpu_parallel_active_index_array_impl(num_states, indices, num_indices, is_active_op)
+
#else
# define gpu_parallel_active_index_array( \
diff --git a/intern/cycles/kernel/device/metal/context_begin.h b/intern/cycles/kernel/device/metal/context_begin.h
index 99cb1e3826e..e75ec9cadec 100644
--- a/intern/cycles/kernel/device/metal/context_begin.h
+++ b/intern/cycles/kernel/device/metal/context_begin.h
@@ -34,21 +34,48 @@ class MetalKernelContext {
kernel_assert(0);
return 0;
}
-
+
+#ifdef __KERNEL_METAL_INTEL__
+ template<typename TextureType, typename CoordsType>
+ inline __attribute__((__always_inline__))
+ auto ccl_gpu_tex_object_read_intel_workaround(TextureType texture_array,
+ const uint tid, const uint sid,
+ CoordsType coords) const
+ {
+ switch(sid) {
+ default:
+ case 0: return texture_array[tid].tex.sample(sampler(address::repeat, filter::nearest), coords);
+ case 1: return texture_array[tid].tex.sample(sampler(address::clamp_to_edge, filter::nearest), coords);
+ case 2: return texture_array[tid].tex.sample(sampler(address::clamp_to_zero, filter::nearest), coords);
+ case 3: return texture_array[tid].tex.sample(sampler(address::repeat, filter::linear), coords);
+ case 4: return texture_array[tid].tex.sample(sampler(address::clamp_to_edge, filter::linear), coords);
+ case 5: return texture_array[tid].tex.sample(sampler(address::clamp_to_zero, filter::linear), coords);
+ }
+ }
+#endif
+
// texture2d
template<>
inline __attribute__((__always_inline__))
float4 ccl_gpu_tex_object_read_2D(ccl_gpu_tex_object_2D tex, float x, float y) const {
const uint tid(tex);
const uint sid(tex >> 32);
+#ifndef __KERNEL_METAL_INTEL__
return metal_ancillaries->textures_2d[tid].tex.sample(metal_samplers[sid], float2(x, y));
+#else
+ return ccl_gpu_tex_object_read_intel_workaround(metal_ancillaries->textures_2d, tid, sid, float2(x, y));
+#endif
}
template<>
inline __attribute__((__always_inline__))
float ccl_gpu_tex_object_read_2D(ccl_gpu_tex_object_2D tex, float x, float y) const {
const uint tid(tex);
const uint sid(tex >> 32);
+#ifndef __KERNEL_METAL_INTEL__
return metal_ancillaries->textures_2d[tid].tex.sample(metal_samplers[sid], float2(x, y)).x;
+#else
+ return ccl_gpu_tex_object_read_intel_workaround(metal_ancillaries->textures_2d, tid, sid, float2(x, y)).x;
+#endif
}
// texture3d
@@ -57,14 +84,22 @@ class MetalKernelContext {
float4 ccl_gpu_tex_object_read_3D(ccl_gpu_tex_object_3D tex, float x, float y, float z) const {
const uint tid(tex);
const uint sid(tex >> 32);
+#ifndef __KERNEL_METAL_INTEL__
return metal_ancillaries->textures_3d[tid].tex.sample(metal_samplers[sid], float3(x, y, z));
+#else
+ return ccl_gpu_tex_object_read_intel_workaround(metal_ancillaries->textures_3d, tid, sid, float3(x, y, z));
+#endif
}
template<>
inline __attribute__((__always_inline__))
float ccl_gpu_tex_object_read_3D(ccl_gpu_tex_object_3D tex, float x, float y, float z) const {
const uint tid(tex);
const uint sid(tex >> 32);
+#ifndef __KERNEL_METAL_INTEL__
return metal_ancillaries->textures_3d[tid].tex.sample(metal_samplers[sid], float3(x, y, z)).x;
+#else
+ return ccl_gpu_tex_object_read_intel_workaround(metal_ancillaries->textures_3d, tid, sid, float3(x, y, z)).x;
+#endif
}
# include "kernel/device/gpu/image.h"
diff --git a/intern/cycles/kernel/device/metal/kernel.metal b/intern/cycles/kernel/device/metal/kernel.metal
index 5646c7446db..8b69ee025cd 100644
--- a/intern/cycles/kernel/device/metal/kernel.metal
+++ b/intern/cycles/kernel/device/metal/kernel.metal
@@ -228,7 +228,7 @@ bool metalrt_shadow_all_hit(constant KernelParamsMetal &launch_params_metal,
/* Always use baked shadow transparency for curves. */
if (type & PRIMITIVE_CURVE) {
float throughput = payload.throughput;
- throughput *= context.intersection_curve_shadow_transparency(nullptr, object, prim, u);
+ throughput *= context.intersection_curve_shadow_transparency(nullptr, object, prim, type, u);
payload.throughput = throughput;
payload.num_hits += 1;
diff --git a/intern/cycles/kernel/device/oneapi/compat.h b/intern/cycles/kernel/device/oneapi/compat.h
index 8ae40b0612e..dfaec65130c 100644
--- a/intern/cycles/kernel/device/oneapi/compat.h
+++ b/intern/cycles/kernel/device/oneapi/compat.h
@@ -55,18 +55,6 @@
#define ccl_gpu_kernel(block_num_threads, thread_num_registers)
#define ccl_gpu_kernel_threads(block_num_threads)
-#ifdef WITH_ONEAPI_SYCL_HOST_ENABLED
-# define KG_ND_ITEMS \
- kg->nd_item_local_id_0 = item.get_local_id(0); \
- kg->nd_item_local_range_0 = item.get_local_range(0); \
- kg->nd_item_group_0 = item.get_group(0); \
- kg->nd_item_group_range_0 = item.get_group_range(0); \
- kg->nd_item_global_id_0 = item.get_global_id(0); \
- kg->nd_item_global_range_0 = item.get_global_range(0);
-#else
-# define KG_ND_ITEMS
-#endif
-
#define ccl_gpu_kernel_signature(name, ...) \
void oneapi_kernel_##name(KernelGlobalsGPU *ccl_restrict kg, \
size_t kernel_global_size, \
@@ -76,8 +64,7 @@ void oneapi_kernel_##name(KernelGlobalsGPU *ccl_restrict kg, \
(kg); \
cgh.parallel_for<class kernel_##name>( \
sycl::nd_range<1>(kernel_global_size, kernel_local_size), \
- [=](sycl::nd_item<1> item) { \
- KG_ND_ITEMS
+ [=](sycl::nd_item<1> item) {
#define ccl_gpu_kernel_postfix \
}); \
@@ -95,31 +82,17 @@ void oneapi_kernel_##name(KernelGlobalsGPU *ccl_restrict kg, \
} ccl_gpu_kernel_lambda_pass((ONEAPIKernelContext *)kg)
/* GPU thread, block, grid size and index */
-#ifndef WITH_ONEAPI_SYCL_HOST_ENABLED
-# define ccl_gpu_thread_idx_x (sycl::ext::oneapi::experimental::this_nd_item<1>().get_local_id(0))
-# define ccl_gpu_block_dim_x (sycl::ext::oneapi::experimental::this_nd_item<1>().get_local_range(0))
-# define ccl_gpu_block_idx_x (sycl::ext::oneapi::experimental::this_nd_item<1>().get_group(0))
-# define ccl_gpu_grid_dim_x (sycl::ext::oneapi::experimental::this_nd_item<1>().get_group_range(0))
-# define ccl_gpu_warp_size (sycl::ext::oneapi::experimental::this_sub_group().get_local_range()[0])
-# define ccl_gpu_thread_mask(thread_warp) uint(0xFFFFFFFF >> (ccl_gpu_warp_size - thread_warp))
-
-# define ccl_gpu_global_id_x() (sycl::ext::oneapi::experimental::this_nd_item<1>().get_global_id(0))
-# define ccl_gpu_global_size_x() (sycl::ext::oneapi::experimental::this_nd_item<1>().get_global_range(0))
-#else
-# define ccl_gpu_thread_idx_x (kg->nd_item_local_id_0)
-# define ccl_gpu_block_dim_x (kg->nd_item_local_range_0)
-# define ccl_gpu_block_idx_x (kg->nd_item_group_0)
-# define ccl_gpu_grid_dim_x (kg->nd_item_group_range_0)
-# define ccl_gpu_warp_size (sycl::ext::oneapi::experimental::this_sub_group().get_local_range()[0])
-# define ccl_gpu_thread_mask(thread_warp) uint(0xFFFFFFFF >> (ccl_gpu_warp_size - thread_warp))
-
-# define ccl_gpu_global_id_x() (kg->nd_item_global_id_0)
-# define ccl_gpu_global_size_x() (kg->nd_item_global_range_0)
-#endif
+#define ccl_gpu_thread_idx_x (sycl::ext::oneapi::experimental::this_nd_item<1>().get_local_id(0))
+#define ccl_gpu_block_dim_x (sycl::ext::oneapi::experimental::this_nd_item<1>().get_local_range(0))
+#define ccl_gpu_block_idx_x (sycl::ext::oneapi::experimental::this_nd_item<1>().get_group(0))
+#define ccl_gpu_grid_dim_x (sycl::ext::oneapi::experimental::this_nd_item<1>().get_group_range(0))
+#define ccl_gpu_warp_size (sycl::ext::oneapi::experimental::this_sub_group().get_local_range()[0])
+#define ccl_gpu_thread_mask(thread_warp) uint(0xFFFFFFFF >> (ccl_gpu_warp_size - thread_warp))
+#define ccl_gpu_global_id_x() (sycl::ext::oneapi::experimental::this_nd_item<1>().get_global_id(0))
+#define ccl_gpu_global_size_x() (sycl::ext::oneapi::experimental::this_nd_item<1>().get_global_range(0))
/* GPU warp synchronization */
-
#define ccl_gpu_syncthreads() sycl::ext::oneapi::experimental::this_nd_item<1>().barrier()
#define ccl_gpu_local_syncthreads() sycl::ext::oneapi::experimental::this_nd_item<1>().barrier(sycl::access::fence_space::local_space)
#ifdef __SYCL_DEVICE_ONLY__
diff --git a/intern/cycles/kernel/device/oneapi/globals.h b/intern/cycles/kernel/device/oneapi/globals.h
index d60f4f135ba..116620eb725 100644
--- a/intern/cycles/kernel/device/oneapi/globals.h
+++ b/intern/cycles/kernel/device/oneapi/globals.h
@@ -23,15 +23,6 @@ typedef struct KernelGlobalsGPU {
#undef KERNEL_DATA_ARRAY
IntegratorStateGPU *integrator_state;
const KernelData *__data;
-#ifdef WITH_ONEAPI_SYCL_HOST_ENABLED
- size_t nd_item_local_id_0;
- size_t nd_item_local_range_0;
- size_t nd_item_group_0;
- size_t nd_item_group_range_0;
-
- size_t nd_item_global_id_0;
- size_t nd_item_global_range_0;
-#endif
} KernelGlobalsGPU;
typedef ccl_global KernelGlobalsGPU *ccl_restrict KernelGlobals;
diff --git a/intern/cycles/kernel/device/oneapi/kernel.cpp b/intern/cycles/kernel/device/oneapi/kernel.cpp
index 1d1700f036d..525ae288f0c 100644
--- a/intern/cycles/kernel/device/oneapi/kernel.cpp
+++ b/intern/cycles/kernel/device/oneapi/kernel.cpp
@@ -8,7 +8,7 @@
# include <map>
# include <set>
-# include <CL/sycl.hpp>
+# include <sycl/sycl.hpp>
# include "kernel/device/oneapi/compat.h"
# include "kernel/device/oneapi/globals.h"
@@ -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;
+ }
+
+ int *A_device = (int *)sycl::malloc_device(memory_byte_size, *queue);
+ int *B_device = (int *)sycl::malloc_device(memory_byte_size, *queue);
- cgh.parallel_for(N, [=](sycl::id<1> idx) { B_acc[idx] = A_acc[idx] + idx.get(0); });
+ 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,56 @@ 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)
+{
+# ifdef SYCL_SKIP_KERNELS_PRELOAD
+ (void)queue_;
+ (void)requested_features;
+# else
+ 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);
+ }
+ }
+ catch (sycl::exception const &e) {
+ if (s_error_cb) {
+ s_error_cb(e.what(), s_error_user_ptr);
+ }
+ return false;
+ }
+# endif
+ return true;
+}
+
bool oneapi_enqueue_kernel(KernelContext *kernel_context,
int kernel,
size_t global_size,
@@ -161,13 +230,6 @@ bool oneapi_enqueue_kernel(KernelContext *kernel_context,
/* NOTE(@nsirgien): As for now non-uniform work-groups don't work on most oneAPI devices,
* we extend work size to fit uniformity requirements. */
global_size = groups_count * local_size;
-
-# ifdef WITH_ONEAPI_SYCL_HOST_ENABLED
- if (queue->get_device().is_host()) {
- global_size = 1;
- local_size = 1;
- }
-# endif
}
/* Let the compiler throw an error if there are any kernels missing in this implementation. */
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/device/optix/bvh.h b/intern/cycles/kernel/device/optix/bvh.h
index fb9907709ce..6d81b44660c 100644
--- a/intern/cycles/kernel/device/optix/bvh.h
+++ b/intern/cycles/kernel/device/optix/bvh.h
@@ -202,7 +202,7 @@ extern "C" __global__ void __anyhit__kernel_optix_shadow_all_hit()
/* Always use baked shadow transparency for curves. */
if (type & PRIMITIVE_CURVE) {
float throughput = __uint_as_float(optixGetPayload_1());
- throughput *= intersection_curve_shadow_transparency(nullptr, object, prim, u);
+ throughput *= intersection_curve_shadow_transparency(nullptr, object, prim, type, u);
optixSetPayload_1(__float_as_uint(throughput));
optixSetPayload_2(uint16_pack_to_uint(num_recorded_hits, num_hits + 1));
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/integrator/state_flow.h b/intern/cycles/kernel/integrator/state_flow.h
index 4b03c665e17..40961b1c5fb 100644
--- a/intern/cycles/kernel/integrator/state_flow.h
+++ b/intern/cycles/kernel/integrator/state_flow.h
@@ -76,6 +76,9 @@ ccl_device_forceinline IntegratorShadowState integrator_shadow_path_init(
&kernel_integrator_state.next_shadow_path_index[0], 1);
atomic_fetch_and_add_uint32(&kernel_integrator_state.queue_counter->num_queued[next_kernel], 1);
INTEGRATOR_STATE_WRITE(shadow_state, shadow_path, queued_kernel) = next_kernel;
+# ifdef __PATH_GUIDING__
+ INTEGRATOR_STATE_WRITE(shadow_state, shadow_path, path_segment) = nullptr;
+# endif
return shadow_state;
}
@@ -181,6 +184,9 @@ ccl_device_forceinline IntegratorShadowState integrator_shadow_path_init(
{
IntegratorShadowState shadow_state = (is_ao) ? &state->ao : &state->shadow;
INTEGRATOR_STATE_WRITE(shadow_state, shadow_path, queued_kernel) = next_kernel;
+# ifdef __PATH_GUIDING__
+ INTEGRATOR_STATE_WRITE(shadow_state, shadow_path, path_segment) = nullptr;
+# endif
return shadow_state;
}
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/scene/image_oiio.cpp b/intern/cycles/scene/image_oiio.cpp
index 8792393e5a1..7bcf1ccb073 100644
--- a/intern/cycles/scene/image_oiio.cpp
+++ b/intern/cycles/scene/image_oiio.cpp
@@ -192,8 +192,22 @@ bool OIIOImageLoader::load_pixels(const ImageMetaData &metadata,
return false;
}
- const bool do_associate_alpha = associate_alpha &&
- spec.get_int_attribute("oiio:UnassociatedAlpha", 0);
+ bool do_associate_alpha = false;
+ if (associate_alpha) {
+ do_associate_alpha = spec.get_int_attribute("oiio:UnassociatedAlpha", 0);
+
+ if (!do_associate_alpha && spec.alpha_channel != -1) {
+ /* Workaround OIIO not detecting TGA file alpha the same as Blender (since #3019).
+ * We want anything not marked as premultiplied alpha to get associated. */
+ if (strcmp(in->format_name(), "targa") == 0) {
+ do_associate_alpha = spec.get_int_attribute("targa:alpha_type", -1) != 4;
+ }
+ /* OIIO DDS reader never sets UnassociatedAlpha attribute. */
+ if (strcmp(in->format_name(), "dds") == 0) {
+ do_associate_alpha = true;
+ }
+ }
+ }
switch (metadata.type) {
case IMAGE_DATA_TYPE_BYTE:
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/cycles/util/math.h b/intern/cycles/util/math.h
index 0905b3ec5c9..3a2e0e074a2 100644
--- a/intern/cycles/util/math.h
+++ b/intern/cycles/util/math.h
@@ -417,15 +417,11 @@ ccl_device_inline int floor_to_int(float f)
return float_to_int(floorf(f));
}
-ccl_device_inline int quick_floor_to_int(float x)
-{
- return float_to_int(x) - ((x < 0) ? 1 : 0);
-}
-
ccl_device_inline float floorfrac(float x, ccl_private int *i)
{
- *i = quick_floor_to_int(x);
- return x - *i;
+ float f = floorf(x);
+ *i = float_to_int(f);
+ return x - f;
}
ccl_device_inline int ceil_to_int(float f)
diff --git a/intern/cycles/util/math_float3.h b/intern/cycles/util/math_float3.h
index c408eadf195..eec7122b9dc 100644
--- a/intern/cycles/util/math_float3.h
+++ b/intern/cycles/util/math_float3.h
@@ -535,18 +535,6 @@ ccl_device_inline float3 pow(float3 v, float e)
return make_float3(powf(v.x, e), powf(v.y, e), powf(v.z, e));
}
-ccl_device_inline int3 quick_floor_to_int3(const float3 a)
-{
-#ifdef __KERNEL_SSE__
- int3 b = int3(_mm_cvttps_epi32(a.m128));
- int3 isneg = int3(_mm_castps_si128(_mm_cmplt_ps(a.m128, _mm_set_ps1(0.0f))));
- /* Unsaturated add 0xffffffff is the same as subtract -1. */
- return b + isneg;
-#else
- return make_int3(quick_floor_to_int(a.x), quick_floor_to_int(a.y), quick_floor_to_int(a.z));
-#endif
-}
-
ccl_device_inline bool isfinite_safe(float3 v)
{
return isfinite_safe(v.x) && isfinite_safe(v.y) && isfinite_safe(v.z);
diff --git a/intern/cycles/util/ssef.h b/intern/cycles/util/ssef.h
index a2fff94303e..1e2bfa90354 100644
--- a/intern/cycles/util/ssef.h
+++ b/intern/cycles/util/ssef.h
@@ -5,6 +5,8 @@
#ifndef __UTIL_SSEF_H__
#define __UTIL_SSEF_H__
+#include <math.h>
+
#include "util/ssei.h"
CCL_NAMESPACE_BEGIN
@@ -521,7 +523,7 @@ __forceinline const ssef round_zero(const ssef &a)
__forceinline const ssef floor(const ssef &a)
{
# ifdef __KERNEL_NEON__
- return vrndnq_f32(a);
+ return vrndmq_f32(a);
# else
return _mm_round_ps(a, _MM_FROUND_TO_NEG_INF);
# endif
@@ -534,6 +536,12 @@ __forceinline const ssef ceil(const ssef &a)
return _mm_round_ps(a, _MM_FROUND_TO_POS_INF);
# endif
}
+# else
+/* Non-SSE4.1 fallback, needed for floorfrac. */
+__forceinline const ssef floor(const ssef &a)
+{
+ return _mm_set_ps(floorf(a.f[3]), floorf(a.f[2]), floorf(a.f[1]), floorf(a.f[0]));
+}
# endif
__forceinline ssei truncatei(const ssef &a)
@@ -541,20 +549,11 @@ __forceinline ssei truncatei(const ssef &a)
return _mm_cvttps_epi32(a.m128);
}
-/* This is about 25% faster than straightforward floor to integer conversion
- * due to better pipelining.
- *
- * Unsaturated add 0xffffffff (a < 0) is the same as subtract -1.
- */
-__forceinline ssei floori(const ssef &a)
-{
- return truncatei(a) + cast((a < 0.0f).m128);
-}
-
__forceinline ssef floorfrac(const ssef &x, ssei *i)
{
- *i = floori(x);
- return x - ssef(*i);
+ ssef f = floor(x);
+ *i = truncatei(f);
+ return x - f;
}
////////////////////////////////////////////////////////////////////////////////
diff --git a/intern/ffmpeg/tests/ffmpeg_codecs.cc b/intern/ffmpeg/tests/ffmpeg_codecs.cc
index d0c40736884..e5c33202417 100644
--- a/intern/ffmpeg/tests/ffmpeg_codecs.cc
+++ b/intern/ffmpeg/tests/ffmpeg_codecs.cc
@@ -130,6 +130,7 @@ FFMPEG_TEST_VCODEC_ID(AV_CODEC_ID_DVVIDEO, AV_PIX_FMT_YUV420P)
FFMPEG_TEST_VCODEC_ID(AV_CODEC_ID_MPEG1VIDEO, AV_PIX_FMT_YUV420P)
FFMPEG_TEST_VCODEC_ID(AV_CODEC_ID_MPEG2VIDEO, AV_PIX_FMT_YUV420P)
FFMPEG_TEST_VCODEC_ID(AV_CODEC_ID_FLV1, AV_PIX_FMT_YUV420P)
+FFMPEG_TEST_VCODEC_ID(AV_CODEC_ID_AV1, AV_PIX_FMT_YUV420P)
/* Audio codecs */
@@ -149,6 +150,12 @@ FFMPEG_TEST_VCODEC_NAME(libx264, AV_PIX_FMT_YUV420P)
FFMPEG_TEST_VCODEC_NAME(libvpx, AV_PIX_FMT_YUV420P)
FFMPEG_TEST_VCODEC_NAME(libopenjpeg, AV_PIX_FMT_YUV420P)
FFMPEG_TEST_VCODEC_NAME(libxvid, AV_PIX_FMT_YUV420P)
+/* aom's AV1 encoder is "libaom-av1". FFMPEG_TEST_VCODEC_NAME(libaom-av1, ...)
+ * will not work because the dash will not work with the test macro. */
+TEST(ffmpeg, libaom_av1_AV_PIX_FMT_YUV420P)
+{
+ EXPECT_TRUE(test_codec_video_by_name("libaom-av1", AV_PIX_FMT_YUV420P));
+}
FFMPEG_TEST_ACODEC_NAME(libvorbis, AV_SAMPLE_FMT_FLTP)
FFMPEG_TEST_ACODEC_NAME(libopus, AV_SAMPLE_FMT_FLT)
FFMPEG_TEST_ACODEC_NAME(libmp3lame, AV_SAMPLE_FMT_FLTP)
diff --git a/intern/ghost/CMakeLists.txt b/intern/ghost/CMakeLists.txt
index aa23618ca39..fb10530bfae 100644
--- a/intern/ghost/CMakeLists.txt
+++ b/intern/ghost/CMakeLists.txt
@@ -262,27 +262,44 @@ 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
- ../../intern/wayland_dynload/extern
+ ../wayland_dynload/extern
)
list(APPEND LIB
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(
@@ -355,10 +372,18 @@ elseif(WITH_GHOST_X11 OR WITH_GHOST_WAYLAND)
generate_protocol_bindings(
"${WAYLAND_PROTOCOLS_DIR}/unstable/relative-pointer/relative-pointer-unstable-v1.xml"
)
+ # Pointer-gestures (multi-touch).
+ generate_protocol_bindings(
+ "${WAYLAND_PROTOCOLS_DIR}/unstable/pointer-gestures/pointer-gestures-unstable-v1.xml"
+ )
# Tablet.
generate_protocol_bindings(
"${WAYLAND_PROTOCOLS_DIR}/unstable/tablet/tablet-unstable-v2.xml"
)
+ # Primary-selection.
+ generate_protocol_bindings(
+ "${WAYLAND_PROTOCOLS_DIR}/unstable/primary-selection/primary-selection-unstable-v1.xml"
+ )
add_definitions(-DWITH_GHOST_WAYLAND)
diff --git a/intern/ghost/GHOST_C-api.h b/intern/ghost/GHOST_C-api.h
index c9d18be750d..62984c762c1 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.
@@ -158,7 +162,6 @@ extern void GHOST_GetAllDisplayDimensions(GHOST_SystemHandle systemhandle,
* \param height: The height the window.
* \param state: The state of the window when opened.
* \param is_dialog: Stay on top of parent window, no icon in taskbar, can't be minimized.
- * \param type: The type of drawing context installed in this window.
* \param glSettings: Misc OpenGL options.
* \return A handle to the new window ( == NULL if creation failed).
*/
@@ -171,7 +174,6 @@ extern GHOST_WindowHandle GHOST_CreateWindow(GHOST_SystemHandle systemhandle,
uint32_t height,
GHOST_TWindowState state,
bool is_dialog,
- GHOST_TDrawingContextType type,
GHOST_GLSettings glSettings);
/**
diff --git a/intern/ghost/GHOST_ISystem.h b/intern/ghost/GHOST_ISystem.h
index 0bf540bd4b6..edaeca1e159 100644
--- a/intern/ghost/GHOST_ISystem.h
+++ b/intern/ghost/GHOST_ISystem.h
@@ -118,9 +118,11 @@ class GHOST_ISystem {
/**
* Creates the one and only system.
* \param verbose: report back-ends that were attempted no back-end could be loaded.
+ * \param background: loading the system for background rendering (no visible windows).
* \return An indication of success.
*/
- static GHOST_TSuccess createSystem(bool verbose);
+
+ static GHOST_TSuccess createSystem(bool verbose, bool background);
static GHOST_TSuccess createSystemBackground();
/**
@@ -134,6 +136,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);
@@ -223,7 +234,6 @@ class GHOST_ISystem {
* \param width: The width the window.
* \param height: The height the window.
* \param state: The state of the window when opened.
- * \param type: The type of drawing context installed in this window.
* \param glSettings: Misc OpenGL settings.
* \param exclusive: Use to show the window on top and ignore others (used full-screen).
* \param is_dialog: Stay on top of parent window, no icon in taskbar, can't be minimized.
@@ -236,7 +246,6 @@ class GHOST_ISystem {
uint32_t width,
uint32_t height,
GHOST_TWindowState state,
- GHOST_TDrawingContextType type,
GHOST_GLSettings glSettings,
const bool exclusive = false,
const bool is_dialog = false,
@@ -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/GHOST_Types.h b/intern/ghost/GHOST_Types.h
index 182eb6eb7d2..db4eeff3122 100644
--- a/intern/ghost/GHOST_Types.h
+++ b/intern/ghost/GHOST_Types.h
@@ -60,10 +60,6 @@ typedef struct {
int hot_spot[2];
} GHOST_CursorBitmapRef;
-typedef struct {
- int flags;
-} GHOST_GLSettings;
-
typedef enum {
GHOST_glStereoVisual = (1 << 0),
GHOST_glDebugContext = (1 << 1),
@@ -157,6 +153,9 @@ typedef enum {
#ifdef WIN32
GHOST_kDrawingContextTypeD3D,
#endif
+#ifdef __APPLE__
+ GHOST_kDrawingContextTypeMetal,
+#endif
} GHOST_TDrawingContextType;
typedef enum {
@@ -526,7 +525,7 @@ typedef struct {
} GHOST_TStringArray;
typedef enum {
- GHOST_kNotStarted,
+ GHOST_kNotStarted = 0,
GHOST_kStarting,
GHOST_kInProgress,
GHOST_kFinishing,
@@ -598,6 +597,11 @@ typedef struct {
uint32_t frequency;
} GHOST_DisplaySetting;
+typedef struct {
+ int flags;
+ GHOST_TDrawingContextType context_type;
+} GHOST_GLSettings;
+
typedef enum {
/** Axis that cursor grab will wrap. */
GHOST_kDebugDefault = (1 << 1),
diff --git a/intern/ghost/intern/GHOST_C-api.cpp b/intern/ghost/intern/GHOST_C-api.cpp
index 69fc6b5f2d0..0c595b27148 100644
--- a/intern/ghost/intern/GHOST_C-api.cpp
+++ b/intern/ghost/intern/GHOST_C-api.cpp
@@ -24,7 +24,7 @@
GHOST_SystemHandle GHOST_CreateSystem(void)
{
- GHOST_ISystem::createSystem(true);
+ GHOST_ISystem::createSystem(true, false);
GHOST_ISystem *system = GHOST_ISystem::getSystem();
return (GHOST_SystemHandle)system;
@@ -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,
@@ -154,7 +161,6 @@ GHOST_WindowHandle GHOST_CreateWindow(GHOST_SystemHandle systemhandle,
uint32_t height,
GHOST_TWindowState state,
bool is_dialog,
- GHOST_TDrawingContextType type,
GHOST_GLSettings glSettings)
{
GHOST_ISystem *system = (GHOST_ISystem *)systemhandle;
@@ -165,7 +171,6 @@ GHOST_WindowHandle GHOST_CreateWindow(GHOST_SystemHandle systemhandle,
width,
height,
state,
- type,
glSettings,
false,
is_dialog,
diff --git a/intern/ghost/intern/GHOST_ContextCGL.h b/intern/ghost/intern/GHOST_ContextCGL.h
index 130b926f25c..d19fffffb43 100644
--- a/intern/ghost/intern/GHOST_ContextCGL.h
+++ b/intern/ghost/intern/GHOST_ContextCGL.h
@@ -30,7 +30,8 @@ class GHOST_ContextCGL : public GHOST_Context {
GHOST_ContextCGL(bool stereoVisual,
NSView *metalView,
CAMetalLayer *metalLayer,
- NSOpenGLView *openglView);
+ NSOpenGLView *openglView,
+ GHOST_TDrawingContextType type);
/**
* Destructor.
diff --git a/intern/ghost/intern/GHOST_ContextCGL.mm b/intern/ghost/intern/GHOST_ContextCGL.mm
index ff53ecdbbba..9dad337a5d6 100644
--- a/intern/ghost/intern/GHOST_ContextCGL.mm
+++ b/intern/ghost/intern/GHOST_ContextCGL.mm
@@ -46,8 +46,10 @@ int GHOST_ContextCGL::s_sharedCount = 0;
GHOST_ContextCGL::GHOST_ContextCGL(bool stereoVisual,
NSView *metalView,
CAMetalLayer *metalLayer,
- NSOpenGLView *openGLView)
+ NSOpenGLView *openGLView,
+ GHOST_TDrawingContextType type)
: GHOST_Context(stereoVisual),
+ m_useMetalForRendering(type == GHOST_kDrawingContextTypeMetal),
m_metalView(metalView),
m_metalLayer(metalLayer),
m_metalCmdQueue(nil),
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_Debug.h b/intern/ghost/intern/GHOST_Debug.h
index ec1a0b34be6..64eff7f9aed 100644
--- a/intern/ghost/intern/GHOST_Debug.h
+++ b/intern/ghost/intern/GHOST_Debug.h
@@ -15,29 +15,41 @@
# endif
#endif
-#if defined(WITH_GHOST_DEBUG) || (!defined(NDEBUG))
-# include <iostream>
-# include <stdio.h> //for printf()
-#endif // WITH_GHOST_DEBUG
+#include <iostream>
+#include <stdio.h> /* For `printf()`. */
#if defined(WITH_GHOST_DEBUG)
# define GHOST_PRINT(x) \
{ \
std::cout << x; \
} \
- (void)0
+ ((void)0)
# define GHOST_PRINTF(x, ...) \
{ \
printf(x, __VA_ARGS__); \
} \
- (void)0
+ ((void)0)
#else
-# define GHOST_PRINT(x)
-# define GHOST_PRINTF(x, ...)
+/* Expand even when `WITH_GHOST_DEBUG` is disabled to prevent expressions
+ * becoming invalid even when the option is disable. */
+# define GHOST_PRINT(x) \
+ { \
+ if (false) { \
+ std::cout << x; \
+ } \
+ } \
+ ((void)0)
+# define GHOST_PRINTF(x, ...) \
+ { \
+ if (false) { \
+ printf(x, __VA_ARGS__); \
+ } \
+ } \
+ ((void)0)
+
#endif /* `!defined(WITH_GHOST_DEBUG)` */
#ifdef WITH_ASSERT_ABORT
-# include <stdio.h> //for fprintf()
# include <stdlib.h> //for abort()
# define GHOST_ASSERT(x, info) \
{ \
@@ -48,7 +60,7 @@
abort(); \
} \
} \
- (void)0
+ ((void)0)
/* Assert in non-release builds too. */
#elif defined(WITH_GHOST_DEBUG) || (!defined(NDEBUG))
# define GHOST_ASSERT(x, info) \
@@ -59,7 +71,7 @@
GHOST_PRINT("\n"); \
} \
} \
- (void)0
+ ((void)0)
#else /* `defined(WITH_GHOST_DEBUG) || (!defined(NDEBUG))` */
# define GHOST_ASSERT(x, info) ((void)0)
#endif /* `defined(WITH_GHOST_DEBUG) || (!defined(NDEBUG))` */
diff --git a/intern/ghost/intern/GHOST_ISystem.cpp b/intern/ghost/intern/GHOST_ISystem.cpp
index 304d7f0abe6..696848ce623 100644
--- a/intern/ghost/intern/GHOST_ISystem.cpp
+++ b/intern/ghost/intern/GHOST_ISystem.cpp
@@ -30,10 +30,11 @@
#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;
-GHOST_TSuccess GHOST_ISystem::createSystem(bool verbose)
+GHOST_TSuccess GHOST_ISystem::createSystem(bool verbose, [[maybe_unused]] bool background)
{
/* When GHOST fails to start, report the back-ends that were attempted.
* A Verbose argument could be supported in printing isn't always desired. */
@@ -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
@@ -60,11 +61,14 @@ GHOST_TSuccess GHOST_ISystem::createSystem(bool verbose)
if (has_wayland_libraries) {
backends_attempted[backends_attempted_num++] = "WAYLAND";
try {
- m_system = new GHOST_SystemWayland();
+ m_system = new GHOST_SystemWayland(background);
}
catch (const std::runtime_error &) {
delete m_system;
m_system = nullptr;
+# ifdef WITH_GHOST_WAYLAND_DYNLOAD
+ ghost_wl_dynload_libraries_exit();
+# endif
}
}
else {
@@ -95,11 +99,14 @@ GHOST_TSuccess GHOST_ISystem::createSystem(bool verbose)
if (has_wayland_libraries) {
backends_attempted[backends_attempted_num++] = "WAYLAND";
try {
- m_system = new GHOST_SystemWayland();
+ m_system = new GHOST_SystemWayland(background);
}
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) {
@@ -150,7 +160,7 @@ GHOST_TSuccess GHOST_ISystem::createSystemBackground()
if (!m_system) {
#if !defined(WITH_HEADLESS)
/* Try to create a off-screen render surface with the graphical systems. */
- success = createSystem(false);
+ success = createSystem(false, true);
if (success) {
return success;
}
@@ -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_NDOFManager.cpp b/intern/ghost/intern/GHOST_NDOFManager.cpp
index b1bd5287d24..9e9b9f14c43 100644
--- a/intern/ghost/intern/GHOST_NDOFManager.cpp
+++ b/intern/ghost/intern/GHOST_NDOFManager.cpp
@@ -7,53 +7,50 @@
#include "GHOST_WindowManager.h"
#include "GHOST_utildefines.h"
+/* Logging, use `ghost.ndof.*` prefix. */
+#include "CLG_log.h"
+
#include <climits>
#include <cmath>
-#include <cstdio> /* For error/info reporting. */
#include <cstring> /* For memory functions. */
-#ifdef DEBUG_NDOF_MOTION
-/* Printable version of each GHOST_TProgress value. */
-static const char *progress_string[] = {
- "not started", "starting", "in progress", "finishing", "finished"};
-#endif
+/* -------------------------------------------------------------------- */
+/** \name NDOF Enum Strings
+ * \{ */
+
+/* Printable values for #GHOST_TProgress enum (keep aligned). */
+static const char *ndof_progress_string[] = {
+ "not started",
+ "starting",
+ "in progress",
+ "finishing",
+ "finished",
+};
-#ifdef DEBUG_NDOF_BUTTONS
+/* Printable values for #NDOF_ButtonT enum (keep aligned) */
static const char *ndof_button_names[] = {
- /* used internally, never sent */
- "NDOF_BUTTON_NONE",
- /* these two are available from any 3Dconnexion device */
+ /* Exclude `NDOF_BUTTON_NONE` (-1). */
"NDOF_BUTTON_MENU",
"NDOF_BUTTON_FIT",
- /* standard views */
"NDOF_BUTTON_TOP",
"NDOF_BUTTON_BOTTOM",
"NDOF_BUTTON_LEFT",
"NDOF_BUTTON_RIGHT",
"NDOF_BUTTON_FRONT",
"NDOF_BUTTON_BACK",
- /* more views */
"NDOF_BUTTON_ISO1",
"NDOF_BUTTON_ISO2",
- /* 90 degree rotations */
"NDOF_BUTTON_ROLL_CW",
"NDOF_BUTTON_ROLL_CCW",
"NDOF_BUTTON_SPIN_CW",
"NDOF_BUTTON_SPIN_CCW",
"NDOF_BUTTON_TILT_CW",
"NDOF_BUTTON_TILT_CCW",
- /* device control */
"NDOF_BUTTON_ROTATE",
"NDOF_BUTTON_PANZOOM",
"NDOF_BUTTON_DOMINANT",
"NDOF_BUTTON_PLUS",
"NDOF_BUTTON_MINUS",
- /* keyboard emulation */
- "NDOF_BUTTON_ESC",
- "NDOF_BUTTON_ALT",
- "NDOF_BUTTON_SHIFT",
- "NDOF_BUTTON_CTRL",
- /* general-purpose buttons */
"NDOF_BUTTON_1",
"NDOF_BUTTON_2",
"NDOF_BUTTON_3",
@@ -64,18 +61,47 @@ static const char *ndof_button_names[] = {
"NDOF_BUTTON_8",
"NDOF_BUTTON_9",
"NDOF_BUTTON_10",
- /* more general-purpose buttons */
"NDOF_BUTTON_A",
"NDOF_BUTTON_B",
"NDOF_BUTTON_C",
- /* the end */
- "NDOF_BUTTON_LAST"};
-#endif
+ "NDOF_BUTTON_V1",
+ "NDOF_BUTTON_V2",
+ "NDOF_BUTTON_V3",
+ /* Keyboard emulation. */
+ "NDOF_BUTTON_ESC",
+ "NDOF_BUTTON_ENTER",
+ "NDOF_BUTTON_DELETE",
+ "NDOF_BUTTON_TAB",
+ "NDOF_BUTTON_SPACE",
+ "NDOF_BUTTON_ALT",
+ "NDOF_BUTTON_SHIFT",
+ "NDOF_BUTTON_CTRL",
+};
+
+static const char *ndof_device_names[] = {
+ "UnknownDevice",
+ "SpaceNavigator",
+ "SpaceExplorer",
+ "SpacePilotPro",
+ "SpaceMousePro",
+ "SpaceMouseWireless",
+ "SpaceMouseProWireless",
+ "SpaceMouseEnterprise",
+ "SpacePilot",
+ "Spaceball5000",
+ "SpaceTraveler",
+};
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name NDOF Button Maps
+ * \{ */
/* Shared by the latest 3Dconnexion hardware
* SpacePilotPro uses all of these
* smaller devices use only some, based on button mask. */
-static const NDOF_ButtonT Modern3Dx_HID_map[] = {
+static const NDOF_ButtonT ndof_HID_map_Modern3Dx[] = {
NDOF_BUTTON_MENU, NDOF_BUTTON_FIT, NDOF_BUTTON_TOP, NDOF_BUTTON_LEFT,
NDOF_BUTTON_RIGHT, NDOF_BUTTON_FRONT, NDOF_BUTTON_BOTTOM, NDOF_BUTTON_BACK,
NDOF_BUTTON_ROLL_CW, NDOF_BUTTON_ROLL_CCW, NDOF_BUTTON_ISO1, NDOF_BUTTON_ISO2,
@@ -85,7 +111,7 @@ static const NDOF_ButtonT Modern3Dx_HID_map[] = {
NDOF_BUTTON_SHIFT, NDOF_BUTTON_CTRL, NDOF_BUTTON_ROTATE, NDOF_BUTTON_PANZOOM,
NDOF_BUTTON_DOMINANT, NDOF_BUTTON_PLUS, NDOF_BUTTON_MINUS};
-static const NDOF_ButtonT SpaceExplorer_HID_map[] = {
+static const NDOF_ButtonT ndof_HID_map_SpaceExplorer[] = {
NDOF_BUTTON_1,
NDOF_BUTTON_2,
NDOF_BUTTON_TOP,
@@ -103,9 +129,8 @@ static const NDOF_ButtonT SpaceExplorer_HID_map[] = {
NDOF_BUTTON_ROTATE,
};
-/* This is the older SpacePilot (sans Pro)
- * thanks to polosson for info about this device. */
-static const NDOF_ButtonT SpacePilot_HID_map[] = {
+/* This is the older SpacePilot (sans Pro). */
+static const NDOF_ButtonT ndof_HID_map_SpacePilot[] = {
NDOF_BUTTON_1, NDOF_BUTTON_2, NDOF_BUTTON_3, NDOF_BUTTON_4,
NDOF_BUTTON_5, NDOF_BUTTON_6, NDOF_BUTTON_TOP, NDOF_BUTTON_LEFT,
NDOF_BUTTON_RIGHT, NDOF_BUTTON_FRONT, NDOF_BUTTON_ESC, NDOF_BUTTON_ALT,
@@ -114,7 +139,7 @@ static const NDOF_ButtonT SpacePilot_HID_map[] = {
NDOF_BUTTON_NONE /* the CONFIG button -- what does it do? */
};
-static const NDOF_ButtonT Generic_HID_map[] = {
+static const NDOF_ButtonT ndof_HID_map_Generic[] = {
NDOF_BUTTON_1,
NDOF_BUTTON_2,
NDOF_BUTTON_3,
@@ -129,41 +154,91 @@ static const NDOF_ButtonT Generic_HID_map[] = {
NDOF_BUTTON_C,
};
-static const int genericButtonCount = ARRAY_SIZE(Generic_HID_map);
+/* Values taken from: https://github.com/FreeSpacenav/spacenavd/wiki/Device-button-names */
+static const NDOF_ButtonT ndof_HID_map_SpaceMouseEnterprise[] = {
+ NDOF_BUTTON_1, /* (0) */
+ NDOF_BUTTON_2, /* (1) */
+ NDOF_BUTTON_3, /* (2) */
+ NDOF_BUTTON_4, /* (3) */
+ NDOF_BUTTON_5, /* (4) */
+ NDOF_BUTTON_6, /* (5) */
+ NDOF_BUTTON_7, /* (6) */
+ NDOF_BUTTON_8, /* (7) */
+ NDOF_BUTTON_9, /* (8) */
+ NDOF_BUTTON_A, /* Labeled "10" (9). */
+ NDOF_BUTTON_B, /* Labeled "11" (10). */
+ NDOF_BUTTON_C, /* Labeled "12" (11). */
+ NDOF_BUTTON_MENU, /* (12). */
+ NDOF_BUTTON_FIT, /* (13). */
+ NDOF_BUTTON_TOP, /* (14). */
+ NDOF_BUTTON_RIGHT, /* (15). */
+ NDOF_BUTTON_FRONT, /* (16). */
+ NDOF_BUTTON_ROLL_CW, /* (17). */
+ NDOF_BUTTON_ESC, /* (18). */
+ NDOF_BUTTON_ALT, /* (19). */
+ NDOF_BUTTON_SHIFT, /* (20). */
+ NDOF_BUTTON_CTRL, /* (21). */
+ NDOF_BUTTON_ROTATE, /* Labeled "Lock Rotate" (22). */
+ NDOF_BUTTON_ENTER, /* Labeled "Enter" (23). */
+ NDOF_BUTTON_DELETE, /* (24). */
+ NDOF_BUTTON_TAB, /* (25). */
+ NDOF_BUTTON_SPACE, /* (26). */
+ NDOF_BUTTON_V1, /* Labeled "V1" (27). */
+ NDOF_BUTTON_V2, /* Labeled "V2" (28). */
+ NDOF_BUTTON_V3, /* Labeled "V3" (29). */
+ NDOF_BUTTON_ISO1, /* Labeled "ISO1" (30). */
+};
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name NDOF Manager Class
+ * \{ */
+
+static const int genericButtonCount = ARRAY_SIZE(ndof_HID_map_Generic);
GHOST_NDOFManager::GHOST_NDOFManager(GHOST_System &sys)
- : m_system(sys),
- m_deviceType(NDOF_UnknownDevice), /* Each platform has its own device detection code. */
- m_buttonCount(genericButtonCount),
- m_buttonMask(0),
- m_hidMap(Generic_HID_map),
- m_buttons(0),
- m_motionTime(0),
- m_prevMotionTime(0),
- m_motionState(GHOST_kNotStarted),
- m_motionEventPending(false),
- m_deadZone(0.0f)
+ : system_(sys),
+ device_type_(NDOF_UnknownDevice), /* Each platform has its own device detection code. */
+ hid_map_button_num_(genericButtonCount),
+ hid_map_button_mask_(0),
+ hid_map_(ndof_HID_map_Generic),
+ button_depressed_(0),
+ motion_time_(0),
+ motion_time_prev_(0),
+ motion_state_(GHOST_kNotStarted),
+ motion_event_pending_(false),
+ motion_dead_zone_(0.0f)
{
/* To avoid the rare situation where one triple is updated and
* the other is not, initialize them both here: */
- memset(m_translation, 0, sizeof(m_translation));
- memset(m_rotation, 0, sizeof(m_rotation));
+ memset(translation_, 0, sizeof(translation_));
+ memset(rotation_, 0, sizeof(rotation_));
}
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name NDOF Device Setup
+ * \{ */
+
+static CLG_LogRef LOG_NDOF_DEVICE = {"ghost.ndof.device"};
+#define LOG (&LOG_NDOF_DEVICE)
+
bool GHOST_NDOFManager::setDevice(ushort vendor_id, ushort product_id)
{
/* Call this function until it returns true
* it's a good idea to stop calling it after that, as it will "forget"
- * whichever device it already found */
+ * whichever device it already found. */
/* Default to safe generic behavior for "unknown" devices
* unidentified devices will emit motion events like normal
* rogue buttons do nothing by default, but can be customized by the user. */
- m_deviceType = NDOF_UnknownDevice;
- m_hidMap = Generic_HID_map;
- m_buttonCount = genericButtonCount;
- m_buttonMask = 0;
+ device_type_ = NDOF_UnknownDevice;
+ hid_map_ = ndof_HID_map_Generic;
+ hid_map_button_num_ = genericButtonCount;
+ hid_map_button_mask_ = 0;
/* "mystery device" owners can help build a HID_map for their hardware
* A few users have already contributed information about several older devices
@@ -173,112 +248,165 @@ bool GHOST_NDOFManager::setDevice(ushort vendor_id, ushort product_id)
case 0x046D: /* Logitech (3Dconnexion was a subsidiary). */
switch (product_id) {
/* -- current devices -- */
- case 0xC626: /* full-size SpaceNavigator */
- case 0xC628: /* the "for Notebooks" one */
- puts("ndof: using SpaceNavigator");
- m_deviceType = NDOF_SpaceNavigator;
- m_buttonCount = 2;
- m_hidMap = Modern3Dx_HID_map;
+ case 0xC626: /* Full-size SpaceNavigator. */
+ case 0xC628: /* The "for Notebooks" one. */
+ {
+ device_type_ = NDOF_SpaceNavigator;
+ hid_map_button_num_ = 2;
+ hid_map_ = ndof_HID_map_Modern3Dx;
break;
- case 0xC627:
- puts("ndof: using SpaceExplorer");
- m_deviceType = NDOF_SpaceExplorer;
- m_buttonCount = 15;
- m_hidMap = SpaceExplorer_HID_map;
+ }
+ case 0xC627: {
+ device_type_ = NDOF_SpaceExplorer;
+ hid_map_button_num_ = 15;
+ hid_map_ = ndof_HID_map_SpaceExplorer;
break;
- case 0xC629:
- puts("ndof: using SpacePilot Pro");
- m_deviceType = NDOF_SpacePilotPro;
- m_buttonCount = 31;
- m_hidMap = Modern3Dx_HID_map;
+ }
+ case 0xC629: {
+ device_type_ = NDOF_SpacePilotPro;
+ hid_map_button_num_ = 31;
+ hid_map_ = ndof_HID_map_Modern3Dx;
break;
- case 0xC62B:
- puts("ndof: using SpaceMouse Pro");
- m_deviceType = NDOF_SpaceMousePro;
- m_buttonCount = 27;
- /* ^^ actually has 15 buttons, but their HID codes range from 0 to 26 */
- m_buttonMask = 0x07C0F137;
- m_hidMap = Modern3Dx_HID_map;
+ }
+ case 0xC62B: {
+ device_type_ = NDOF_SpaceMousePro;
+ hid_map_button_num_ = 27; /* 15 physical buttons, but HID codes range from 0 to 26. */
+ hid_map_button_mask_ = 0x07C0F137;
+ hid_map_ = ndof_HID_map_Modern3Dx;
break;
+ }
/* -- older devices -- */
- case 0xC625:
- puts("ndof: using SpacePilot");
- m_deviceType = NDOF_SpacePilot;
- m_buttonCount = 21;
- m_hidMap = SpacePilot_HID_map;
+ case 0xC625: {
+ device_type_ = NDOF_SpacePilot;
+ hid_map_button_num_ = 21;
+ hid_map_ = ndof_HID_map_SpacePilot;
break;
- case 0xC621:
- puts("ndof: using Spaceball 5000");
- m_deviceType = NDOF_Spaceball5000;
- m_buttonCount = 12;
+ }
+ case 0xC621: {
+ device_type_ = NDOF_Spaceball5000;
+ hid_map_button_num_ = 12;
break;
- case 0xC623:
- puts("ndof: using SpaceTraveler");
- m_deviceType = NDOF_SpaceTraveler;
- m_buttonCount = 8;
+ }
+ case 0xC623: {
+ device_type_ = NDOF_SpaceTraveler;
+ hid_map_button_num_ = 8;
break;
-
- default:
- printf("ndof: unknown Logitech product %04hx\n", product_id);
+ }
+ default: {
+ CLOG_INFO(LOG, 2, "unknown Logitech product %04hx", product_id);
+ }
}
break;
- case 0x256F: /* 3Dconnexion */
+ case 0x256F: /* 3Dconnexion. */
switch (product_id) {
case 0xC62E: /* Plugged in. */
case 0xC62F: /* Wireless. */
- puts("ndof: using SpaceMouse Wireless");
- m_deviceType = NDOF_SpaceMouseWireless;
- m_buttonCount = 2;
- m_hidMap = Modern3Dx_HID_map;
+ {
+ device_type_ = NDOF_SpaceMouseWireless;
+ hid_map_button_num_ = 2;
+ hid_map_ = ndof_HID_map_Modern3Dx;
break;
+ }
case 0xC631: /* Plugged in. */
case 0xC632: /* Wireless. */
- puts("ndof: using SpaceMouse Pro Wireless");
- m_deviceType = NDOF_SpaceMouseProWireless;
- m_buttonCount = 27;
- /* ^^ actually has 15 buttons, but their HID codes range from 0 to 26. */
- m_buttonMask = 0x07C0F137;
- m_hidMap = Modern3Dx_HID_map;
+ {
+ device_type_ = NDOF_SpaceMouseProWireless;
+ hid_map_button_num_ = 27; /* 15 physical buttons, but HID codes range from 0 to 26. */
+ hid_map_button_mask_ = 0x07C0F137;
+ hid_map_ = ndof_HID_map_Modern3Dx;
break;
- case 0xC633:
- puts("ndof: using SpaceMouse Enterprise");
- m_deviceType = NDOF_SpaceMouseEnterprise;
- m_buttonCount = 31;
- m_hidMap = Modern3Dx_HID_map;
+ }
+ case 0xC633: {
+ device_type_ = NDOF_SpaceMouseEnterprise;
+ hid_map_button_num_ = 31;
+ hid_map_ = ndof_HID_map_SpaceMouseEnterprise;
break;
-
- default:
- printf("ndof: unknown 3Dconnexion product %04hx\n", product_id);
+ }
+ default: {
+ CLOG_INFO(LOG, 2, "unknown 3Dconnexion product %04hx", product_id);
+ }
}
break;
default:
- printf("ndof: unknown device %04hx:%04hx\n", vendor_id, product_id);
+ CLOG_INFO(LOG, 2, "unknown device %04hx:%04hx", vendor_id, product_id);
}
- if (m_buttonMask == 0) {
- m_buttonMask = int(~(UINT_MAX << m_buttonCount));
+ if (device_type_ != NDOF_UnknownDevice) {
+ CLOG_INFO(LOG, 2, "using %s", ndof_device_names[device_type_]);
}
-#ifdef DEBUG_NDOF_BUTTONS
- printf("ndof: %d buttons -> hex:%X\n", m_buttonCount, m_buttonMask);
-#endif
+ if (hid_map_button_mask_ == 0) {
+ hid_map_button_mask_ = int(~(UINT_MAX << hid_map_button_num_));
+ }
+
+ CLOG_INFO(LOG, 2, "%d buttons -> hex:%X", hid_map_button_num_, (uint)hid_map_button_mask_);
- return m_deviceType != NDOF_UnknownDevice;
+ return device_type_ != NDOF_UnknownDevice;
}
+#undef LOG
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name NDOF Update State
+ * \{ */
+
void GHOST_NDOFManager::updateTranslation(const int t[3], uint64_t time)
{
- memcpy(m_translation, t, sizeof(m_translation));
- m_motionTime = time;
- m_motionEventPending = true;
+ memcpy(translation_, t, sizeof(translation_));
+ motion_time_ = time;
+ motion_event_pending_ = true;
}
void GHOST_NDOFManager::updateRotation(const int r[3], uint64_t time)
{
- memcpy(m_rotation, r, sizeof(m_rotation));
- m_motionTime = time;
- m_motionEventPending = true;
+ memcpy(rotation_, r, sizeof(rotation_));
+ motion_time_ = time;
+ motion_event_pending_ = true;
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name NDOF Buttons
+ * \{ */
+
+static CLG_LogRef LOG_NDOF_BUTTONS = {"ghost.ndof.buttons"};
+#define LOG (&LOG_NDOF_BUTTONS)
+
+static GHOST_TKey ghost_map_keyboard_from_ndof_buttom(const NDOF_ButtonT button)
+{
+ switch (button) {
+ case NDOF_BUTTON_ESC: {
+ return GHOST_kKeyEsc;
+ }
+ case NDOF_BUTTON_ENTER: {
+ return GHOST_kKeyEnter;
+ }
+ case NDOF_BUTTON_DELETE: {
+ return GHOST_kKeyDelete;
+ }
+ case NDOF_BUTTON_TAB: {
+ return GHOST_kKeyTab;
+ }
+ case NDOF_BUTTON_SPACE: {
+ return GHOST_kKeySpace;
+ }
+ case NDOF_BUTTON_ALT: {
+ return GHOST_kKeyLeftAlt;
+ }
+ case NDOF_BUTTON_SHIFT: {
+ return GHOST_kKeyLeftShift;
+ }
+ case NDOF_BUTTON_CTRL: {
+ return GHOST_kKeyLeftControl;
+ }
+ default: {
+ return GHOST_kKeyUnknown;
+ }
+ }
}
void GHOST_NDOFManager::sendButtonEvent(NDOF_ButtonT button,
@@ -286,7 +414,7 @@ void GHOST_NDOFManager::sendButtonEvent(NDOF_ButtonT button,
uint64_t time,
GHOST_IWindow *window)
{
- GHOST_ASSERT(button > NDOF_BUTTON_NONE && button < NDOF_BUTTON_LAST,
+ GHOST_ASSERT(button > NDOF_BUTTON_NONE && button < NDOF_BUTTON_NUM,
"rogue button trying to escape NDOF manager");
GHOST_EventNDOFButton *event = new GHOST_EventNDOFButton(time, window);
@@ -295,11 +423,7 @@ void GHOST_NDOFManager::sendButtonEvent(NDOF_ButtonT button,
data->action = press ? GHOST_kPress : GHOST_kRelease;
data->button = button;
-#ifdef DEBUG_NDOF_BUTTONS
- printf("%s %s\n", ndof_button_names[button], press ? "pressed" : "released");
-#endif
-
- m_system.pushEvent(event);
+ system_.pushEvent(event);
}
void GHOST_NDOFManager::sendKeyEvent(GHOST_TKey key,
@@ -310,62 +434,59 @@ void GHOST_NDOFManager::sendKeyEvent(GHOST_TKey key,
GHOST_TEventType type = press ? GHOST_kEventKeyDown : GHOST_kEventKeyUp;
GHOST_EventKey *event = new GHOST_EventKey(time, type, window, key, false);
-#ifdef DEBUG_NDOF_BUTTONS
- printf("keyboard %s\n", press ? "down" : "up");
-#endif
-
- m_system.pushEvent(event);
+ system_.pushEvent(event);
}
void GHOST_NDOFManager::updateButton(int button_number, bool press, uint64_t time)
{
- GHOST_IWindow *window = m_system.getWindowManager()->getActiveWindow();
-
-#ifdef DEBUG_NDOF_BUTTONS
- printf("ndof: button %d -> ", button_number);
-#endif
-
- NDOF_ButtonT button = (button_number < m_buttonCount) ? m_hidMap[button_number] :
- NDOF_BUTTON_NONE;
+ if (button_number >= hid_map_button_num_) {
+ CLOG_INFO(LOG,
+ 2,
+ "button=%d, press=%d (out of range %d, ignoring!)",
+ button_number,
+ (int)press,
+ hid_map_button_num_);
+ return;
+ }
+ const NDOF_ButtonT button = hid_map_[button_number];
+ if (button == NDOF_BUTTON_NONE) {
+ CLOG_INFO(
+ LOG, 2, "button=%d, press=%d (mapped to none, ignoring!)", button_number, (int)press);
+ return;
+ }
- switch (button) {
- case NDOF_BUTTON_NONE:
-#ifdef DEBUG_NDOF_BUTTONS
- printf("discarded\n");
-#endif
- break;
- case NDOF_BUTTON_ESC:
- sendKeyEvent(GHOST_kKeyEsc, press, time, window);
- break;
- case NDOF_BUTTON_ALT:
- sendKeyEvent(GHOST_kKeyLeftAlt, press, time, window);
- break;
- case NDOF_BUTTON_SHIFT:
- sendKeyEvent(GHOST_kKeyLeftShift, press, time, window);
- break;
- case NDOF_BUTTON_CTRL:
- sendKeyEvent(GHOST_kKeyLeftControl, press, time, window);
- break;
- default:
- sendButtonEvent(button, press, time, window);
+ CLOG_INFO(LOG,
+ 2,
+ "button=%d, press=%d, name=%s",
+ button_number,
+ (int)press,
+ ndof_button_names[button]);
+
+ GHOST_IWindow *window = system_.getWindowManager()->getActiveWindow();
+ const GHOST_TKey key = ghost_map_keyboard_from_ndof_buttom(button);
+ if (key != GHOST_kKeyUnknown) {
+ sendKeyEvent(key, press, time, window);
+ }
+ else {
+ sendButtonEvent(button, press, time, window);
}
int mask = 1 << button_number;
if (press) {
- m_buttons |= mask; /* Set this button's bit. */
+ button_depressed_ |= mask; /* Set this button's bit. */
}
else {
- m_buttons &= ~mask; /* Clear this button's bit. */
+ button_depressed_ &= ~mask; /* Clear this button's bit. */
}
}
void GHOST_NDOFManager::updateButtons(int button_bits, uint64_t time)
{
- button_bits &= m_buttonMask; /* Discard any "garbage" bits. */
+ button_bits &= hid_map_button_mask_; /* Discard any "garbage" bits. */
- int diff = m_buttons ^ button_bits;
+ int diff = button_depressed_ ^ button_bits;
- for (int button_number = 0; button_number < m_buttonCount; ++button_number) {
+ for (int button_number = 0; button_number < hid_map_button_num_; ++button_number) {
int mask = 1 << button_number;
if (diff & mask) {
@@ -375,19 +496,27 @@ void GHOST_NDOFManager::updateButtons(int button_bits, uint64_t time)
}
}
+#undef LOG
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name NDOF Motion
+ * \{ */
+
+static CLG_LogRef LOG_NDOF_MOTION = {"ghost.ndof.motion"};
+#define LOG (&LOG_NDOF_MOTION)
+
void GHOST_NDOFManager::setDeadZone(float dz)
{
if (dz < 0.0f) {
/* Negative values don't make sense, so clamp at zero. */
dz = 0.0f;
}
- else if (dz > 0.5f) {
- /* Warn the rogue user/developer, but allow it. */
- GHOST_PRINTF("ndof: dead zone of %.2f is rather high...\n", dz);
- }
- m_deadZone = dz;
+ motion_dead_zone_ = dz;
- GHOST_PRINTF("ndof: dead zone set to %.2f\n", dz);
+ /* Warn the rogue user/developer about high dead-zone, but allow it. */
+ CLOG_INFO(LOG, 2, "dead zone set to %.2f%s", dz, (dz > 0.5f) ? " (unexpectedly high)" : "");
}
static bool atHomePosition(GHOST_TEventNDOFMotionData *ndof)
@@ -402,29 +531,27 @@ static bool nearHomePosition(GHOST_TEventNDOFMotionData *ndof, float threshold)
if (threshold == 0.0f) {
return atHomePosition(ndof);
}
- else {
#define HOME(foo) (fabsf(ndof->foo) < threshold)
- return HOME(tx) && HOME(ty) && HOME(tz) && HOME(rx) && HOME(ry) && HOME(rz);
+ return HOME(tx) && HOME(ty) && HOME(tz) && HOME(rx) && HOME(ry) && HOME(rz);
#undef HOME
- }
}
bool GHOST_NDOFManager::sendMotionEvent()
{
- if (!m_motionEventPending) {
+ if (!motion_event_pending_) {
return false;
}
- m_motionEventPending = false; /* Any pending motion is handled right now. */
+ motion_event_pending_ = false; /* Any pending motion is handled right now. */
- GHOST_IWindow *window = m_system.getWindowManager()->getActiveWindow();
+ GHOST_IWindow *window = system_.getWindowManager()->getActiveWindow();
- if (window == NULL) {
- m_motionState = GHOST_kNotStarted; /* Avoid large `dt` times when changing windows. */
+ if (window == nullptr) {
+ motion_state_ = GHOST_kNotStarted; /* Avoid large `dt` times when changing windows. */
return false; /* Delivery will fail, so don't bother sending. */
}
- GHOST_EventNDOFMotion *event = new GHOST_EventNDOFMotion(m_motionTime, window);
+ GHOST_EventNDOFMotion *event = new GHOST_EventNDOFMotion(motion_time_, window);
GHOST_TEventNDOFMotionData *data = (GHOST_TEventNDOFMotionData *)event->getData();
/* Scale axis values here to normalize them to around +/- 1
@@ -432,76 +559,82 @@ bool GHOST_NDOFManager::sendMotionEvent()
const float scale = 1.0f / 350.0f; /* 3Dconnexion devices send +/- 350 usually */
- data->tx = scale * m_translation[0];
- data->ty = scale * m_translation[1];
- data->tz = scale * m_translation[2];
-
- data->rx = scale * m_rotation[0];
- data->ry = scale * m_rotation[1];
- data->rz = scale * m_rotation[2];
+ data->tx = scale * translation_[0];
+ data->ty = scale * translation_[1];
+ data->tz = scale * translation_[2];
- data->dt = 0.001f * (m_motionTime - m_prevMotionTime); /* In seconds. */
- m_prevMotionTime = m_motionTime;
+ data->rx = scale * rotation_[0];
+ data->ry = scale * rotation_[1];
+ data->rz = scale * rotation_[2];
+ data->dt = 0.001f * (motion_time_ - motion_time_prev_); /* In seconds. */
+ motion_time_prev_ = motion_time_;
- bool weHaveMotion = !nearHomePosition(data, m_deadZone);
+ bool weHaveMotion = !nearHomePosition(data, motion_dead_zone_);
/* Determine what kind of motion event to send `(Starting, InProgress, Finishing)`
* and where that leaves this NDOF manager `(NotStarted, InProgress, Finished)`. */
- switch (m_motionState) {
+ switch (motion_state_) {
case GHOST_kNotStarted:
- case GHOST_kFinished:
+ case GHOST_kFinished: {
if (weHaveMotion) {
data->progress = GHOST_kStarting;
- m_motionState = GHOST_kInProgress;
+ motion_state_ = GHOST_kInProgress;
/* Previous motion time will be ancient, so just make up a reasonable time delta. */
data->dt = 0.0125f;
}
else {
/* Send no event and keep current state. */
-#ifdef DEBUG_NDOF_MOTION
- printf("ndof motion ignored -- %s\n", progress_string[data->progress]);
-#endif
+ CLOG_INFO(LOG, 2, "motion ignored");
delete event;
return false;
}
break;
- case GHOST_kInProgress:
+ }
+ case GHOST_kInProgress: {
if (weHaveMotion) {
data->progress = GHOST_kInProgress;
/* Remain 'InProgress'. */
}
else {
data->progress = GHOST_kFinishing;
- m_motionState = GHOST_kFinished;
+ motion_state_ = GHOST_kFinished;
}
break;
- default:
+ }
+ default: {
/* Will always be one of the above. */
break;
+ }
}
-#ifdef DEBUG_NDOF_MOTION
- printf("ndof motion sent -- %s\n", progress_string[data->progress]);
-
- /* Show details about this motion event. */
- printf(" T=(%d,%d,%d) R=(%d,%d,%d) raw\n",
- m_translation[0],
- m_translation[1],
- m_translation[2],
- m_rotation[0],
- m_rotation[1],
- m_rotation[2]);
- printf(" T=(%.2f,%.2f,%.2f) R=(%.2f,%.2f,%.2f) dt=%.3f\n",
- data->tx,
- data->ty,
- data->tz,
- data->rx,
- data->ry,
- data->rz,
- data->dt);
+#if 1
+ CLOG_INFO(LOG,
+ 2,
+ "motion sent, T=(%.2f,%.2f,%.2f), R=(%.2f,%.2f,%.2f) dt=%.3f, status=%s",
+ data->tx,
+ data->ty,
+ data->tz,
+ data->rx,
+ data->ry,
+ data->rz,
+ data->dt,
+ ndof_progress_string[data->progress]);
+#else
+ /* Raw values, may be useful for debugging. */
+ CLOG_INFO(LOG,
+ 2,
+ "motion sent, T=(%d,%d,%d) R=(%d,%d,%d) status=%s",
+ translation_[0],
+ translation_[1],
+ translation_[2],
+ rotation_[0],
+ rotation_[1],
+ rotation_[2],
+ ndof_progress_string[data->progress]);
#endif
-
- m_system.pushEvent(event);
+ system_.pushEvent(event);
return true;
}
+
+/** \} */
diff --git a/intern/ghost/intern/GHOST_NDOFManager.h b/intern/ghost/intern/GHOST_NDOFManager.h
index d49e6326722..2d5bba14aa4 100644
--- a/intern/ghost/intern/GHOST_NDOFManager.h
+++ b/intern/ghost/intern/GHOST_NDOFManager.h
@@ -8,11 +8,8 @@
#include "GHOST_System.h"
-// #define DEBUG_NDOF_MOTION
-// #define DEBUG_NDOF_BUTTONS
-
typedef enum {
- NDOF_UnknownDevice,
+ NDOF_UnknownDevice = 0,
/* Current devices. */
NDOF_SpaceNavigator,
@@ -32,8 +29,8 @@ typedef enum {
/* NDOF device button event types */
typedef enum {
- /* Used internally, never sent. */
- NDOF_BUTTON_NONE,
+ /* Used internally, never sent or used as an index. */
+ NDOF_BUTTON_NONE = -1,
/* These two are available from any 3Dconnexion device. */
NDOF_BUTTON_MENU,
NDOF_BUTTON_FIT,
@@ -61,11 +58,6 @@ typedef enum {
NDOF_BUTTON_DOMINANT,
NDOF_BUTTON_PLUS,
NDOF_BUTTON_MINUS,
- /* Keyboard emulation. */
- NDOF_BUTTON_ESC,
- NDOF_BUTTON_ALT,
- NDOF_BUTTON_SHIFT,
- NDOF_BUTTON_CTRL,
/* General-purpose buttons.
* Users can assign functions via keymap editor. */
NDOF_BUTTON_1,
@@ -82,8 +74,20 @@ typedef enum {
NDOF_BUTTON_A,
NDOF_BUTTON_B,
NDOF_BUTTON_C,
- /* The end. */
- NDOF_BUTTON_LAST
+ /* Store Views. */
+ NDOF_BUTTON_V1,
+ NDOF_BUTTON_V2,
+ NDOF_BUTTON_V3,
+ /* Keyboard emulation. */
+ NDOF_BUTTON_ESC,
+ NDOF_BUTTON_ENTER,
+ NDOF_BUTTON_DELETE,
+ NDOF_BUTTON_TAB,
+ NDOF_BUTTON_SPACE,
+ NDOF_BUTTON_ALT,
+ NDOF_BUTTON_SHIFT,
+ NDOF_BUTTON_CTRL,
+#define NDOF_BUTTON_NUM (NDOF_BUTTON_CTRL + 1)
} NDOF_ButtonT;
class GHOST_NDOFManager {
@@ -143,25 +147,25 @@ class GHOST_NDOFManager {
bool sendMotionEvent();
protected:
- GHOST_System &m_system;
+ GHOST_System &system_;
private:
void sendButtonEvent(NDOF_ButtonT, bool press, uint64_t time, GHOST_IWindow *);
void sendKeyEvent(GHOST_TKey, bool press, uint64_t time, GHOST_IWindow *);
- NDOF_DeviceT m_deviceType;
- int m_buttonCount;
- int m_buttonMask;
- const NDOF_ButtonT *m_hidMap;
+ NDOF_DeviceT device_type_;
+ int hid_map_button_num_;
+ int hid_map_button_mask_;
+ const NDOF_ButtonT *hid_map_;
- int m_translation[3];
- int m_rotation[3];
- int m_buttons; /* Bit field. */
+ int translation_[3];
+ int rotation_[3];
+ int button_depressed_; /* Bit field. */
- uint64_t m_motionTime; /* In milliseconds. */
- uint64_t m_prevMotionTime; /* Time of most recent motion event sent. */
+ uint64_t motion_time_; /* In milliseconds. */
+ uint64_t motion_time_prev_; /* Time of most recent motion event sent. */
- GHOST_TProgress m_motionState;
- bool m_motionEventPending;
- float m_deadZone; /* Discard motion with each component < this. */
+ GHOST_TProgress motion_state_;
+ bool motion_event_pending_;
+ float motion_dead_zone_; /* Discard motion with each component < this. */
};
diff --git a/intern/ghost/intern/GHOST_NDOFManagerUnix.cpp b/intern/ghost/intern/GHOST_NDOFManagerUnix.cpp
index 94bf0337371..0ccf4dc9bfb 100644
--- a/intern/ghost/intern/GHOST_NDOFManagerUnix.cpp
+++ b/intern/ghost/intern/GHOST_NDOFManagerUnix.cpp
@@ -10,7 +10,7 @@
#define SPNAV_SOCK_PATH "/var/run/spnav.sock"
GHOST_NDOFManagerUnix::GHOST_NDOFManagerUnix(GHOST_System &sys)
- : GHOST_NDOFManager(sys), m_available(false)
+ : GHOST_NDOFManager(sys), available_(false)
{
if (access(SPNAV_SOCK_PATH, F_OK) != 0) {
#ifdef DEBUG
@@ -20,7 +20,7 @@ GHOST_NDOFManagerUnix::GHOST_NDOFManagerUnix(GHOST_System &sys)
#endif
}
else if (spnav_open() != -1) {
- m_available = true;
+ available_ = true;
/* determine exactly which device (if any) is plugged in */
@@ -45,14 +45,14 @@ GHOST_NDOFManagerUnix::GHOST_NDOFManagerUnix(GHOST_System &sys)
GHOST_NDOFManagerUnix::~GHOST_NDOFManagerUnix()
{
- if (m_available) {
+ if (available_) {
spnav_close();
}
}
bool GHOST_NDOFManagerUnix::available()
{
- return m_available;
+ return available_;
}
/*
@@ -74,7 +74,7 @@ bool GHOST_NDOFManagerUnix::processEvents()
{
bool anyProcessed = false;
- if (m_available) {
+ if (available_) {
spnav_event e;
#ifdef USE_FINISH_GLITCH_WORKAROUND
@@ -85,7 +85,7 @@ bool GHOST_NDOFManagerUnix::processEvents()
switch (e.type) {
case SPNAV_EVENT_MOTION: {
/* convert to blender view coords */
- uint64_t now = m_system.getMilliSeconds();
+ uint64_t now = system_.getMilliSeconds();
const int t[3] = {int(e.motion.x), int(e.motion.y), int(-e.motion.z)};
const int r[3] = {int(-e.motion.rx), int(-e.motion.ry), int(e.motion.rz)};
@@ -97,7 +97,7 @@ bool GHOST_NDOFManagerUnix::processEvents()
break;
}
case SPNAV_EVENT_BUTTON:
- uint64_t now = m_system.getMilliSeconds();
+ uint64_t now = system_.getMilliSeconds();
updateButton(e.button.bnum, e.button.press, now);
break;
}
@@ -106,7 +106,7 @@ bool GHOST_NDOFManagerUnix::processEvents()
#ifdef USE_FINISH_GLITCH_WORKAROUND
if (motion_test_prev == true && motion_test == false) {
- uint64_t now = m_system.getMilliSeconds();
+ uint64_t now = system_.getMilliSeconds();
const int v[3] = {0, 0, 0};
updateTranslation(v, now);
diff --git a/intern/ghost/intern/GHOST_NDOFManagerUnix.h b/intern/ghost/intern/GHOST_NDOFManagerUnix.h
index fd603e3cb54..2b98fad974f 100644
--- a/intern/ghost/intern/GHOST_NDOFManagerUnix.h
+++ b/intern/ghost/intern/GHOST_NDOFManagerUnix.h
@@ -15,5 +15,5 @@ class GHOST_NDOFManagerUnix : public GHOST_NDOFManager {
bool processEvents();
private:
- bool m_available;
+ bool available_;
};
diff --git a/intern/ghost/intern/GHOST_System.cpp b/intern/ghost/intern/GHOST_System.cpp
index 94d021fd822..670ede35989 100644
--- a/intern/ghost/intern/GHOST_System.cpp
+++ b/intern/ghost/intern/GHOST_System.cpp
@@ -384,6 +384,7 @@ GHOST_TSuccess GHOST_System::createFullScreenWindow(GHOST_Window **window,
if (stereoVisual) {
glSettings.flags |= GHOST_glStereoVisual;
}
+ glSettings.context_type = GHOST_kDrawingContextTypeOpenGL;
/* NOTE: don't use #getCurrentDisplaySetting() because on X11 we may
* be zoomed in and the desktop may be bigger than the viewport. */
GHOST_ASSERT(m_displayManager,
@@ -395,7 +396,6 @@ GHOST_TSuccess GHOST_System::createFullScreenWindow(GHOST_Window **window,
settings.xPixels,
settings.yPixels,
GHOST_kWindowStateNormal,
- GHOST_kDrawingContextTypeOpenGL,
glSettings,
true /* exclusive */);
return (*window == nullptr) ? GHOST_kFailure : GHOST_kSuccess;
diff --git a/intern/ghost/intern/GHOST_SystemCocoa.h b/intern/ghost/intern/GHOST_SystemCocoa.h
index dbb41c7fddf..0211694aad4 100644
--- a/intern/ghost/intern/GHOST_SystemCocoa.h
+++ b/intern/ghost/intern/GHOST_SystemCocoa.h
@@ -77,7 +77,6 @@ class GHOST_SystemCocoa : public GHOST_System {
* \param width: The width the window.
* \param height: The height the window.
* \param state: The state of the window when opened.
- * \param type: The type of drawing context installed in this window.
* \param glSettings: Misc OpenGL settings.
* \param exclusive: Use to show the window on top and ignore others (used full-screen).
* \param parentWindow: Parent (embedder) window.
@@ -89,7 +88,6 @@ class GHOST_SystemCocoa : public GHOST_System {
uint32_t width,
uint32_t height,
GHOST_TWindowState state,
- GHOST_TDrawingContextType type,
GHOST_GLSettings glSettings,
const bool exclusive = false,
const bool is_dialog = false,
diff --git a/intern/ghost/intern/GHOST_SystemCocoa.mm b/intern/ghost/intern/GHOST_SystemCocoa.mm
index bfa90114e4c..a1016dd4843 100644
--- a/intern/ghost/intern/GHOST_SystemCocoa.mm
+++ b/intern/ghost/intern/GHOST_SystemCocoa.mm
@@ -689,7 +689,6 @@ GHOST_IWindow *GHOST_SystemCocoa::createWindow(const char *title,
uint32_t width,
uint32_t height,
GHOST_TWindowState state,
- GHOST_TDrawingContextType type,
GHOST_GLSettings glSettings,
const bool exclusive,
const bool is_dialog,
@@ -719,7 +718,7 @@ GHOST_IWindow *GHOST_SystemCocoa::createWindow(const char *title,
width,
height,
state,
- type,
+ glSettings.context_type,
glSettings.flags & GHOST_glStereoVisual,
glSettings.flags & GHOST_glDebugContext,
is_dialog,
@@ -751,7 +750,7 @@ GHOST_IWindow *GHOST_SystemCocoa::createWindow(const char *title,
*/
GHOST_IContext *GHOST_SystemCocoa::createOffscreenContext(GHOST_GLSettings glSettings)
{
- GHOST_Context *context = new GHOST_ContextCGL(false, NULL, NULL, NULL);
+ GHOST_Context *context = new GHOST_ContextCGL(false, NULL, NULL, NULL, glSettings.context_type);
if (context->initializeDrawingContext())
return context;
else
diff --git a/intern/ghost/intern/GHOST_SystemHeadless.h b/intern/ghost/intern/GHOST_SystemHeadless.h
index b02a82fc9eb..66af65f763d 100644
--- a/intern/ghost/intern/GHOST_SystemHeadless.h
+++ b/intern/ghost/intern/GHOST_SystemHeadless.h
@@ -142,7 +142,6 @@ class GHOST_SystemHeadless : public GHOST_System {
uint32_t width,
uint32_t height,
GHOST_TWindowState state,
- GHOST_TDrawingContextType type,
GHOST_GLSettings glSettings,
const bool /*exclusive*/,
const bool /*is_dialog*/,
@@ -155,7 +154,7 @@ class GHOST_SystemHeadless : public GHOST_System {
height,
state,
parentWindow,
- type,
+ glSettings.context_type,
((glSettings.flags & GHOST_glStereoVisual) != 0));
}
diff --git a/intern/ghost/intern/GHOST_SystemSDL.cpp b/intern/ghost/intern/GHOST_SystemSDL.cpp
index ad5c4dc85fb..9174664adc4 100644
--- a/intern/ghost/intern/GHOST_SystemSDL.cpp
+++ b/intern/ghost/intern/GHOST_SystemSDL.cpp
@@ -42,7 +42,6 @@ GHOST_IWindow *GHOST_SystemSDL::createWindow(const char *title,
uint32_t width,
uint32_t height,
GHOST_TWindowState state,
- GHOST_TDrawingContextType type,
GHOST_GLSettings glSettings,
const bool exclusive,
const bool /* is_dialog */,
@@ -57,7 +56,7 @@ GHOST_IWindow *GHOST_SystemSDL::createWindow(const char *title,
width,
height,
state,
- type,
+ glSettings.context_type,
((glSettings.flags & GHOST_glStereoVisual) != 0),
exclusive,
parentWindow);
diff --git a/intern/ghost/intern/GHOST_SystemSDL.h b/intern/ghost/intern/GHOST_SystemSDL.h
index bee277ba674..385bfb841e3 100644
--- a/intern/ghost/intern/GHOST_SystemSDL.h
+++ b/intern/ghost/intern/GHOST_SystemSDL.h
@@ -71,7 +71,6 @@ class GHOST_SystemSDL : public GHOST_System {
uint32_t width,
uint32_t height,
GHOST_TWindowState state,
- GHOST_TDrawingContextType type,
GHOST_GLSettings glSettings,
const bool exclusive = false,
const bool is_dialog = false,
diff --git a/intern/ghost/intern/GHOST_SystemWayland.cpp b/intern/ghost/intern/GHOST_SystemWayland.cpp
index 0721ca78603..67f475a2963 100644
--- a/intern/ghost/intern/GHOST_SystemWayland.cpp
+++ b/intern/ghost/intern/GHOST_SystemWayland.cpp
@@ -10,6 +10,7 @@
#include "GHOST_EventCursor.h"
#include "GHOST_EventDragnDrop.h"
#include "GHOST_EventKey.h"
+#include "GHOST_EventTrackpad.h"
#include "GHOST_EventWheel.h"
#include "GHOST_PathUtils.h"
#include "GHOST_TimerManager.h"
@@ -50,10 +51,17 @@
/* Generated by `wayland-scanner`. */
#include <pointer-constraints-unstable-v1-client-protocol.h>
+#include <pointer-gestures-unstable-v1-client-protocol.h>
+#include <primary-selection-unstable-v1-client-protocol.h>
#include <relative-pointer-unstable-v1-client-protocol.h>
#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,10 +72,23 @@
/* 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);
+static void gwl_seat_capability_pointer_disable(GWL_Seat *seat);
+static void gwl_seat_capability_keyboard_disable(GWL_Seat *seat);
+static void gwl_seat_capability_touch_disable(GWL_Seat *seat);
+
/* -------------------------------------------------------------------- */
/** \name Local Defines
*
@@ -102,10 +123,21 @@ static bool use_gnome_confine_hack = false;
* This define could be removed without changing any functionality,
* it just means GNOME users will see verbose warning messages that alert them about
* a known problem that needs to be fixed up-stream.
+ *
+ * This has been fixed for GNOME 43. Keep the workaround until support for gnome 42 is dropped.
* See: https://gitlab.gnome.org/GNOME/mutter/-/issues/2457
*/
#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
+
/** \} */
/* -------------------------------------------------------------------- */
@@ -117,8 +149,7 @@ static bool use_gnome_confine_hack = false;
* \{ */
/**
- * The event codes are used to
- * to differentiate from which mouse button an event comes from.
+ * The event codes are used to differentiate from which mouse button an event comes from.
*/
#define BTN_LEFT 0x110
#define BTN_RIGHT 0x111
@@ -167,48 +198,93 @@ struct GWL_ModifierInfo {
};
static const GWL_ModifierInfo g_modifier_info_table[MOD_INDEX_NUM] = {
- [MOD_INDEX_SHIFT] =
- {
- .display_name = "Shift",
- .xkb_id = XKB_MOD_NAME_SHIFT,
- .key_l = GHOST_kKeyLeftShift,
- .key_r = GHOST_kKeyRightShift,
- .mod_l = GHOST_kModifierKeyLeftShift,
- .mod_r = GHOST_kModifierKeyRightShift,
- },
- [MOD_INDEX_ALT] =
- {
- .display_name = "Alt",
- .xkb_id = XKB_MOD_NAME_ALT,
- .key_l = GHOST_kKeyLeftAlt,
- .key_r = GHOST_kKeyRightAlt,
- .mod_l = GHOST_kModifierKeyLeftAlt,
- .mod_r = GHOST_kModifierKeyRightAlt,
- },
- [MOD_INDEX_CTRL] =
- {
- .display_name = "Control",
- .xkb_id = XKB_MOD_NAME_CTRL,
- .key_l = GHOST_kKeyLeftControl,
- .key_r = GHOST_kKeyRightControl,
- .mod_l = GHOST_kModifierKeyLeftControl,
- .mod_r = GHOST_kModifierKeyRightControl,
- },
- [MOD_INDEX_OS] =
- {
- .display_name = "OS",
- .xkb_id = XKB_MOD_NAME_LOGO,
- .key_l = GHOST_kKeyLeftOS,
- .key_r = GHOST_kKeyRightOS,
- .mod_l = GHOST_kModifierKeyLeftOS,
- .mod_r = GHOST_kModifierKeyRightOS,
- },
+ /* MOD_INDEX_SHIFT */
+ {
+ /* display_name */ "Shift",
+ /* xkb_id */ XKB_MOD_NAME_SHIFT,
+ /* key_l */ GHOST_kKeyLeftShift,
+ /* key_r */ GHOST_kKeyRightShift,
+ /* mod_l */ GHOST_kModifierKeyLeftShift,
+ /* mod_r */ GHOST_kModifierKeyRightShift,
+ },
+ /* MOD_INDEX_ALT */
+ {
+ /* display_name */ "Alt",
+ /* xkb_id */ XKB_MOD_NAME_ALT,
+ /* key_l */ GHOST_kKeyLeftAlt,
+ /* key_r */ GHOST_kKeyRightAlt,
+ /* mod_l */ GHOST_kModifierKeyLeftAlt,
+ /* mod_r */ GHOST_kModifierKeyRightAlt,
+ },
+ /* MOD_INDEX_CTRL */
+ {
+ /* display_name */ "Control",
+ /* xkb_id */ XKB_MOD_NAME_CTRL,
+ /* key_l */ GHOST_kKeyLeftControl,
+ /* key_r */ GHOST_kKeyRightControl,
+ /* mod_l */ GHOST_kModifierKeyLeftControl,
+ /* mod_r */ GHOST_kModifierKeyRightControl,
+ },
+ /* MOD_INDEX_OS */
+ {
+ /* display_name */ "OS",
+ /* xkb_id */ XKB_MOD_NAME_LOGO,
+ /* key_l */ GHOST_kKeyLeftOS,
+ /* key_r */ GHOST_kKeyRightOS,
+ /* mod_l */ GHOST_kModifierKeyLeftOS,
+ /* mod_r */ GHOST_kModifierKeyRightOS,
+ },
};
/** \} */
/* -------------------------------------------------------------------- */
-/** \name Private Types & Defines
+/** \name Internal #GWL_SimpleBuffer Type
+ * \{ */
+
+struct GWL_SimpleBuffer {
+ /** Constant data, but may be freed. */
+ const char *data = nullptr;
+ size_t data_size = 0;
+};
+
+static void gwl_simple_buffer_free_data(GWL_SimpleBuffer *buffer)
+{
+ free(const_cast<char *>(buffer->data));
+ buffer->data = nullptr;
+ buffer->data_size = 0;
+}
+
+static void gwl_simple_buffer_set_and_take_ownership(GWL_SimpleBuffer *buffer,
+ const char *data,
+ size_t data_size)
+{
+ free(const_cast<char *>(buffer->data));
+ buffer->data = data;
+ buffer->data_size = data_size;
+}
+
+static void gwl_simple_buffer_set_from_string(GWL_SimpleBuffer *buffer, const char *str)
+{
+ free(const_cast<char *>(buffer->data));
+ buffer->data_size = strlen(str);
+ char *data = static_cast<char *>(malloc(buffer->data_size));
+ std::memcpy(data, str, buffer->data_size);
+ buffer->data = data;
+}
+
+static char *gwl_simple_buffer_as_string(const GWL_SimpleBuffer *buffer)
+{
+ char *buffer_str = static_cast<char *>(malloc(buffer->data_size + 1));
+ memcpy(buffer_str, buffer->data, buffer->data_size);
+ buffer_str[buffer->data_size] = '\0';
+ return buffer_str;
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Internal #GWL_Cursor Type
* \{ */
/**
@@ -226,16 +302,26 @@ struct GWL_Cursor {
* the hardware cursor is used.
*/
bool is_hardware = true;
+ /** When true, a custom image is used to display the cursor (stored in `wl_image`). */
bool is_custom = false;
struct wl_surface *wl_surface = nullptr;
struct wl_buffer *wl_buffer = nullptr;
struct wl_cursor_image wl_image = {0};
struct wl_cursor_theme *wl_theme = nullptr;
void *custom_data = nullptr;
+ /** The size of `custom_data` in bytes. */
size_t custom_data_size = 0;
- int size = 0;
+ /**
+ * The name of the theme (loaded by DBUS, depends on #WITH_GHOST_WAYLAND_DBUS).
+ * When disabled, leave as an empty string and the default theme will be used.
+ */
std::string theme_name;
-
+ /**
+ * The size of the cursor (when looking up a cursor theme).
+ * This must be scaled by the maximum output scale when passing to wl_cursor_theme_load.
+ * See #update_cursor_scale.
+ * */
+ int theme_size = 0;
int custom_scale = 1;
};
@@ -246,6 +332,7 @@ struct GWL_Cursor {
*/
struct GWL_TabletTool {
struct GWL_Seat *seat = nullptr;
+ /** Tablets have a separate cursor to the 'pointer', this surface is used for cursor drawing. */
struct wl_surface *wl_surface_cursor = nullptr;
/** Used to delay clearing tablet focused wl_surface until the frame is handled. */
bool proximity = false;
@@ -253,23 +340,51 @@ struct GWL_TabletTool {
GHOST_TabletData data = GHOST_TABLET_DATA_NONE;
};
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Internal #GWL_DataOffer Type
+ * \{ */
+
+/**
+ * Data storage used for clipboard paste & drag-and-drop.
+ */
struct GWL_DataOffer {
- std::unordered_set<std::string> types;
- uint32_t source_actions = 0;
- uint32_t dnd_action = 0;
struct wl_data_offer *id = nullptr;
+ std::unordered_set<std::string> types;
std::atomic<bool> in_use = false;
+
struct {
+ /**
+ * Bit-mask with available drop options.
+ * #WL_DATA_DEVICE_MANAGER_DND_ACTION_COPY, #WL_DATA_DEVICE_MANAGER_DND_ACTION_MOVE.. etc.
+ * The application that initializes the drag may set these depending on modifiers held
+ * \note when dragging begins. Currently ghost doesn't make use of these.
+ */
+ enum wl_data_device_manager_dnd_action source_actions = WL_DATA_DEVICE_MANAGER_DND_ACTION_NONE;
+ enum wl_data_device_manager_dnd_action action = WL_DATA_DEVICE_MANAGER_DND_ACTION_NONE;
/** Compatible with #GWL_Seat.xy coordinates. */
wl_fixed_t xy[2] = {0, 0};
} dnd;
};
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Internal #GWL_DataSource Type
+ * \{ */
+
struct GWL_DataSource {
- struct wl_data_source *data_source = nullptr;
- char *buffer_out = nullptr;
+ struct wl_data_source *wl_source = nullptr;
+ GWL_SimpleBuffer buffer_out;
};
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Internal #GWL_Seat Type (#wl_seat wrapper & associated types)
+ * \{ */
+
/**
* Data used to implement client-side key-repeat.
*
@@ -335,6 +450,52 @@ struct GWL_SeatStatePointer {
};
/**
+ * Scroll state, applying to pointer (not tablet) events.
+ * Otherwise this would be part of #GWL_SeatStatePointer.
+ */
+struct GWL_SeatStatePointerScroll {
+ /** Smooth scrolling (handled & reset with pointer "frame" callback). */
+ wl_fixed_t smooth_xy[2] = {0, 0};
+ /** Discrete scrolling (handled & reset with pointer "frame" callback). */
+ int32_t discrete_xy[2] = {0, 0};
+ /** The source of scroll event. */
+ enum wl_pointer_axis_source axis_source = WL_POINTER_AXIS_SOURCE_WHEEL;
+};
+
+/**
+ * Utility struct to access rounded values from a scaled `wl_fixed_t`,
+ * without loosing information.
+ *
+ * As the rounded result is rounded to a lower precision integer,
+ * the high precision value is accumulated and converted to an integer to
+ * prevent the accumulation of rounded values giving an inaccurate result.
+ *
+ * \note This is simple but doesn't read well when expanded multiple times inline.
+ */
+struct GWL_ScaledFixedT {
+ wl_fixed_t value = 0;
+ wl_fixed_t factor = 1;
+};
+
+static int gwl_scaled_fixed_t_add_and_calc_rounded_delta(GWL_ScaledFixedT *sf,
+ const wl_fixed_t add)
+{
+ const int result_prev = wl_fixed_to_int(sf->value * sf->factor);
+ sf->value += add;
+ const int result_curr = wl_fixed_to_int(sf->value * sf->factor);
+ return result_curr - result_prev;
+}
+
+/**
+ * Gesture state.
+ * This is needed so the gesture values can be converted to deltas.
+ */
+struct GWL_SeatStatePointerGesture_Pinch {
+ GWL_ScaledFixedT scale;
+ GWL_ScaledFixedT rotation;
+};
+
+/**
* State of the keyboard (in #GWL_Seat).
*/
struct GWL_SeatStateKeyboard {
@@ -353,18 +514,105 @@ struct GWL_SeatStateKeyboard {
*
* Needed as #GWL_Seat.xkb_state doesn't store which modifier keys are held.
*/
-struct WGL_KeyboardDepressedState {
+struct GWL_KeyboardDepressedState {
int16_t mods[GHOST_KEY_MODIFIER_NUM] = {0};
};
+#ifdef WITH_GHOST_WAYLAND_LIBDECOR
+struct GWL_LibDecor_System {
+ struct libdecor *context = nullptr;
+};
+
+static void gwl_libdecor_system_destroy(GWL_LibDecor_System *decor)
+{
+ if (decor->context) {
+ libdecor_unref(decor->context);
+ }
+ delete decor;
+}
+#endif
+
+struct GWL_XDG_Decor_System {
+ struct xdg_wm_base *shell = nullptr;
+ struct zxdg_decoration_manager_v1 *manager = nullptr;
+};
+
+static void gwl_xdg_decor_system_destroy(GWL_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_PrimarySelection_DataOffer {
+ struct zwp_primary_selection_offer_v1 *id = nullptr;
+ std::atomic<bool> in_use = false;
+
+ std::unordered_set<std::string> types;
+};
+
+struct GWL_PrimarySelection_DataSource {
+ struct zwp_primary_selection_source_v1 *wp_source = nullptr;
+ GWL_SimpleBuffer buffer_out;
+};
+
+/** Primary selection support. */
+struct GWL_PrimarySelection {
+
+ GWL_PrimarySelection_DataSource *data_source = nullptr;
+ std::mutex data_source_mutex;
+
+ GWL_PrimarySelection_DataOffer *data_offer = nullptr;
+ std::mutex data_offer_mutex;
+};
+
+static void gwl_primary_selection_discard_offer(GWL_PrimarySelection *primary)
+{
+ if (primary->data_offer == nullptr) {
+ return;
+ }
+ zwp_primary_selection_offer_v1_destroy(primary->data_offer->id);
+ delete primary->data_offer;
+ primary->data_offer = nullptr;
+}
+
+static void gwl_primary_selection_discard_source(GWL_PrimarySelection *primary)
+{
+ GWL_PrimarySelection_DataSource *data_source = primary->data_source;
+ if (data_source == nullptr) {
+ return;
+ }
+ gwl_simple_buffer_free_data(&data_source->buffer_out);
+ if (data_source->wp_source) {
+ zwp_primary_selection_source_v1_destroy(data_source->wp_source);
+ }
+ delete primary->data_source;
+ primary->data_source = nullptr;
+}
+
struct GWL_Seat {
GHOST_SystemWayland *system = nullptr;
std::string name;
struct wl_seat *wl_seat = nullptr;
struct wl_pointer *wl_pointer = nullptr;
+ struct wl_touch *wl_touch = nullptr;
struct wl_keyboard *wl_keyboard = nullptr;
- struct zwp_tablet_seat_v2 *tablet_seat = nullptr;
+ struct zwp_tablet_seat_v2 *wp_tablet_seat = nullptr;
+
+#ifdef ZWP_POINTER_GESTURE_HOLD_V1_INTERFACE
+ struct zwp_pointer_gesture_hold_v1 *wp_pointer_gesture_hold = nullptr;
+#endif
+#ifdef ZWP_POINTER_GESTURE_PINCH_V1_INTERFACE
+ struct zwp_pointer_gesture_pinch_v1 *wp_pointer_gesture_pinch = nullptr;
+#endif
+#ifdef ZWP_POINTER_GESTURE_SWIPE_V1_INTERFACE
+ struct zwp_pointer_gesture_swipe_v1 *wp_pointer_gesture_swipe = nullptr;
+#endif
/** All currently active tablet tools (needed for changing the cursor). */
std::unordered_set<zwp_tablet_tool_v2 *> tablet_tools;
@@ -373,6 +621,8 @@ struct GWL_Seat {
uint32_t cursor_source_serial = 0;
GWL_SeatStatePointer pointer;
+ GWL_SeatStatePointerScroll pointer_scroll;
+ GWL_SeatStatePointerGesture_Pinch pointer_gesture_pinch;
/** Mostly this can be interchanged with `pointer` however it can't be locked/confined. */
GWL_SeatStatePointer tablet;
@@ -387,9 +637,9 @@ struct GWL_Seat {
struct GWL_Cursor cursor;
- struct zwp_relative_pointer_v1 *relative_pointer = nullptr;
- struct zwp_locked_pointer_v1 *locked_pointer = nullptr;
- struct zwp_confined_pointer_v1 *confined_pointer = nullptr;
+ struct zwp_relative_pointer_v1 *wp_relative_pointer = nullptr;
+ struct zwp_locked_pointer_v1 *wp_locked_pointer = nullptr;
+ struct zwp_confined_pointer_v1 *wp_confined_pointer = nullptr;
struct xkb_context *xkb_context = nullptr;
@@ -405,7 +655,7 @@ struct GWL_Seat {
struct xkb_state *xkb_state_empty_with_numlock = nullptr;
/** Keys held matching `xkb_state`. */
- struct WGL_KeyboardDepressedState key_depressed;
+ struct GWL_KeyboardDepressedState key_depressed;
#ifdef USE_GNOME_KEYBOARD_SUPPRESS_WARNING
struct {
@@ -432,7 +682,7 @@ struct GWL_Seat {
struct wl_surface *wl_surface_focus_dnd = nullptr;
- struct wl_data_device *data_device = nullptr;
+ struct wl_data_device *wl_data_device = nullptr;
/** Drag & Drop. */
struct GWL_DataOffer *data_offer_dnd = nullptr;
std::mutex data_offer_dnd_mutex;
@@ -444,35 +694,47 @@ struct GWL_Seat {
struct GWL_DataSource *data_source = nullptr;
std::mutex data_source_mutex;
+ struct zwp_primary_selection_device_v1 *wp_primary_selection_device = nullptr;
+ struct GWL_PrimarySelection primary_selection;
+
/** Last device that was active. */
uint32_t data_source_serial = 0;
};
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Internal #GWL_Display Type (#wl_display & #wl_compositor wrapper)
+ * \{ */
+
struct GWL_Display {
GHOST_SystemWayland *system = nullptr;
- struct wl_display *display = nullptr;
- struct wl_compositor *compositor = nullptr;
+ struct wl_display *wl_display = nullptr;
+ struct wl_compositor *wl_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;
+ GWL_LibDecor_System *libdecor = nullptr;
+ bool libdecor_required = false;
#endif
+ GWL_XDG_Decor_System *xdg_decor = nullptr;
struct zxdg_output_manager_v1 *xdg_output_manager = nullptr;
- struct wl_shm *shm = nullptr;
+ struct wl_shm *wl_shm = nullptr;
std::vector<GWL_Output *> outputs;
std::vector<GWL_Seat *> seats;
- struct wl_data_device_manager *data_device_manager = nullptr;
- struct zwp_tablet_manager_v2 *tablet_manager = nullptr;
- struct zwp_relative_pointer_manager_v1 *relative_pointer_manager = nullptr;
- struct zwp_pointer_constraints_v1 *pointer_constraints = nullptr;
-};
+ struct wl_data_device_manager *wl_data_device_manager = nullptr;
+ struct zwp_tablet_manager_v2 *wp_tablet_manager = nullptr;
+ struct zwp_relative_pointer_manager_v1 *wp_relative_pointer_manager = nullptr;
+ struct zwp_pointer_constraints_v1 *wp_pointer_constraints = nullptr;
+ struct zwp_pointer_gestures_v1 *wp_pointer_gestures = nullptr;
-#undef LOG
+ struct zwp_primary_selection_device_manager_v1 *wp_primary_selection_device_manager = nullptr;
+
+ GWL_SimpleBuffer clipboard;
+ GWL_SimpleBuffer clipboard_primary;
+};
/** \} */
@@ -482,8 +744,8 @@ struct GWL_Display {
static GHOST_WindowManager *window_manager = nullptr;
-/** Check this lock before accessing `GHOST_SystemWayland::selection` from a thread. */
-static std::mutex system_selection_mutex;
+/** Check this lock before accessing #GHOST_SystemWayland::clipboard_ from a thread. */
+static std::mutex system_clipboard_mutex;
/**
* Callback for WAYLAND to run when there is an error.
@@ -526,31 +788,31 @@ static GWL_SeatStatePointer *seat_state_pointer_from_cursor_surface(GWL_Seat *se
return nullptr;
}
-static void display_destroy(GWL_Display *d)
+static void display_destroy(GWL_Display *display)
{
- if (d->data_device_manager) {
- wl_data_device_manager_destroy(d->data_device_manager);
+ if (display->wl_data_device_manager) {
+ wl_data_device_manager_destroy(display->wl_data_device_manager);
}
- if (d->tablet_manager) {
- zwp_tablet_manager_v2_destroy(d->tablet_manager);
+ if (display->wp_tablet_manager) {
+ zwp_tablet_manager_v2_destroy(display->wp_tablet_manager);
}
- for (GWL_Output *output : d->outputs) {
+ for (GWL_Output *output : display->outputs) {
wl_output_destroy(output->wl_output);
delete output;
}
- for (GWL_Seat *seat : d->seats) {
+ for (GWL_Seat *seat : display->seats) {
/* First handle members that require locking.
* While highly unlikely, it's possible they are being used while this function runs. */
{
std::lock_guard lock{seat->data_source_mutex};
if (seat->data_source) {
- free(seat->data_source->buffer_out);
- if (seat->data_source->data_source) {
- wl_data_source_destroy(seat->data_source->data_source);
+ gwl_simple_buffer_free_data(&seat->data_source->buffer_out);
+ if (seat->data_source->wl_source) {
+ wl_data_source_destroy(seat->data_source->wl_source);
}
delete seat->data_source;
}
@@ -572,32 +834,39 @@ static void display_destroy(GWL_Display *d)
}
}
- if (seat->data_device) {
- wl_data_device_release(seat->data_device);
+ {
+ GWL_PrimarySelection *primary = &seat->primary_selection;
+ std::lock_guard lock{primary->data_offer_mutex};
+ gwl_primary_selection_discard_offer(primary);
}
- if (seat->cursor.custom_data) {
- munmap(seat->cursor.custom_data, seat->cursor.custom_data_size);
+ {
+ GWL_PrimarySelection *primary = &seat->primary_selection;
+ std::lock_guard lock{primary->data_source_mutex};
+ gwl_primary_selection_discard_source(primary);
}
- if (seat->wl_pointer) {
- if (seat->cursor.wl_surface) {
- wl_surface_destroy(seat->cursor.wl_surface);
- }
- if (seat->cursor.wl_theme) {
- wl_cursor_theme_destroy(seat->cursor.wl_theme);
- }
- if (seat->wl_pointer) {
- wl_pointer_destroy(seat->wl_pointer);
- }
+ if (seat->wp_primary_selection_device) {
+ zwp_primary_selection_device_v1_destroy(seat->wp_primary_selection_device);
}
- if (seat->wl_keyboard) {
- if (seat->key_repeat.timer) {
- keyboard_handle_key_repeat_cancel(seat);
- }
- wl_keyboard_destroy(seat->wl_keyboard);
+
+ if (seat->wl_data_device) {
+ wl_data_device_release(seat->wl_data_device);
+ }
+
+ if (seat->cursor.custom_data) {
+ munmap(seat->cursor.custom_data, seat->cursor.custom_data_size);
}
+ /* Disable all capabilities as a way to free:
+ * - `seat.wl_pointer` (and related cursor variables).
+ * - `seat.wl_touch`.
+ * - `seat.wl_keyboard`.
+ */
+ gwl_seat_capability_pointer_disable(seat);
+ gwl_seat_capability_keyboard_disable(seat);
+ gwl_seat_capability_touch_disable(seat);
+
/* Un-referencing checks for NULL case. */
xkb_state_unref(seat->xkb_state);
xkb_state_unref(seat->xkb_state_empty);
@@ -609,45 +878,55 @@ static void display_destroy(GWL_Display *d)
delete seat;
}
- if (d->shm) {
- wl_shm_destroy(d->shm);
+ if (display->wl_shm) {
+ wl_shm_destroy(display->wl_shm);
}
- if (d->relative_pointer_manager) {
- zwp_relative_pointer_manager_v1_destroy(d->relative_pointer_manager);
+ if (display->wp_relative_pointer_manager) {
+ zwp_relative_pointer_manager_v1_destroy(display->wp_relative_pointer_manager);
}
- if (d->pointer_constraints) {
- zwp_pointer_constraints_v1_destroy(d->pointer_constraints);
+ if (display->wp_pointer_constraints) {
+ zwp_pointer_constraints_v1_destroy(display->wp_pointer_constraints);
}
- if (d->compositor) {
- wl_compositor_destroy(d->compositor);
+ if (display->wp_pointer_gestures) {
+ zwp_pointer_gestures_v1_destroy(display->wp_pointer_gestures);
+ }
+
+ if (display->wl_compositor) {
+ wl_compositor_destroy(display->wl_compositor);
}
#ifdef WITH_GHOST_WAYLAND_LIBDECOR
- if (d->decor_context) {
- libdecor_unref(d->decor_context);
+ if (use_libdecor) {
+ if (display->libdecor) {
+ gwl_libdecor_system_destroy(display->libdecor);
+ }
}
-#else
- if (d->xdg_decoration_manager) {
- zxdg_decoration_manager_v1_destroy(d->xdg_decoration_manager);
+ else
+#endif
+ {
+ if (display->xdg_decor) {
+ gwl_xdg_decor_system_destroy(display->xdg_decor);
+ }
}
- if (d->xdg_shell) {
- xdg_wm_base_destroy(d->xdg_shell);
+ if (eglGetDisplay) {
+ ::eglTerminate(eglGetDisplay(EGLNativeDisplayType(display->wl_display)));
}
-#endif /* !WITH_GHOST_WAYLAND_LIBDECOR */
- if (eglGetDisplay) {
- ::eglTerminate(eglGetDisplay(EGLNativeDisplayType(d->display)));
+ if (display->wl_display) {
+ wl_display_disconnect(display->wl_display);
}
- if (d->display) {
- wl_display_disconnect(d->display);
+ {
+ std::lock_guard lock{system_clipboard_mutex};
+ gwl_simple_buffer_free_data(&display->clipboard);
+ gwl_simple_buffer_free_data(&display->clipboard_primary);
}
- delete d;
+ delete display;
}
static GHOST_TKey xkb_map_gkey(const xkb_keysym_t sym)
@@ -785,9 +1064,24 @@ static GHOST_TKey xkb_map_gkey_or_scan_code(const xkb_keysym_t sym, const uint32
return gkey;
}
-static GHOST_TTabletMode tablet_tool_map_type(enum zwp_tablet_tool_v2_type wl_tablet_tool_type)
+static int pointer_axis_as_index(const uint32_t axis)
+{
+ switch (axis) {
+ case WL_POINTER_AXIS_HORIZONTAL_SCROLL: {
+ return 0;
+ }
+ case WL_POINTER_AXIS_VERTICAL_SCROLL: {
+ return 1;
+ }
+ default: {
+ return -1;
+ }
+ }
+}
+
+static GHOST_TTabletMode tablet_tool_map_type(enum zwp_tablet_tool_v2_type wp_tablet_tool_type)
{
- switch (wl_tablet_tool_type) {
+ switch (wp_tablet_tool_type) {
case ZWP_TABLET_TOOL_V2_TYPE_ERASER: {
return GHOST_kTabletModeEraser;
}
@@ -802,7 +1096,7 @@ static GHOST_TTabletMode tablet_tool_map_type(enum zwp_tablet_tool_v2_type wl_ta
}
}
- GHOST_PRINT("unknown tablet tool: " << wl_tablet_tool_type << std::endl);
+ GHOST_PRINT("unknown tablet tool: " << wp_tablet_tool_type << std::endl);
return GHOST_kTabletModeStylus;
}
@@ -993,7 +1287,7 @@ static void keyboard_depressed_state_key_event(GWL_Seat *seat,
}
static void keyboard_depressed_state_push_events_from_change(
- GWL_Seat *seat, const WGL_KeyboardDepressedState &key_depressed_prev)
+ GWL_Seat *seat, const GWL_KeyboardDepressedState &key_depressed_prev)
{
GHOST_IWindow *win = ghost_wl_surface_user_data(seat->keyboard.wl_surface);
GHOST_SystemWayland *system = seat->system;
@@ -1131,15 +1425,81 @@ static void dnd_events(const GWL_Seat *const seat, const GHOST_TEventType event)
}
}
-static std::string read_pipe(GWL_DataOffer *data_offer,
- const std::string mime_receive,
- std::mutex *mutex)
+/**
+ * Read from `fd` into a buffer which is returned.
+ * \return the buffer or null on failure.
+ */
+static const char *read_file_as_buffer(const int fd, size_t *r_len)
+{
+ struct ByteChunk {
+ ByteChunk *next;
+ char data[4096 - sizeof(ByteChunk *)];
+ };
+ ByteChunk *chunk_first = nullptr, **chunk_link_p = &chunk_first;
+ bool ok = true;
+ size_t len = 0;
+ while (true) {
+ ByteChunk *chunk = static_cast<typeof(chunk)>(malloc(sizeof(*chunk)));
+ if (UNLIKELY(chunk == nullptr)) {
+ CLOG_WARN(LOG, "unable to allocate chunk for file buffer");
+ ok = false;
+ break;
+ }
+ chunk->next = nullptr;
+ const ssize_t len_chunk = read(fd, chunk->data, sizeof(chunk->data));
+ if (len_chunk <= 0) {
+ if (UNLIKELY(len_chunk < 0)) {
+ CLOG_WARN(LOG, "error reading from pipe: %s", std::strerror(errno));
+ ok = false;
+ }
+ free(chunk);
+ break;
+ }
+ if (chunk_first == nullptr) {
+ chunk_first = chunk;
+ }
+ *chunk_link_p = chunk;
+ chunk_link_p = &chunk->next;
+ len += len_chunk;
+ }
+
+ char *buf = nullptr;
+ if (ok) {
+ buf = static_cast<char *>(malloc(len));
+ if (UNLIKELY(buf == nullptr)) {
+ CLOG_WARN(LOG, "unable to allocate file buffer: %zu bytes", len);
+ ok = false;
+ }
+ }
+
+ *r_len = ok ? len : 0;
+ char *buf_stride = buf;
+ while (chunk_first) {
+ if (ok) {
+ const size_t len_chunk = std::min(len, sizeof(chunk_first->data));
+ memcpy(buf_stride, chunk_first->data, len_chunk);
+ buf_stride += len_chunk;
+ len -= len_chunk;
+ }
+ ByteChunk *chunk = chunk_first->next;
+ free(chunk_first);
+ chunk_first = chunk;
+ }
+
+ return buf;
+}
+
+static const char *read_buffer_from_data_offer(GWL_DataOffer *data_offer,
+ const char *mime_receive,
+ std::mutex *mutex,
+ size_t *r_len)
{
int pipefd[2];
if (UNLIKELY(pipe(pipefd) != 0)) {
- return {};
+ CLOG_WARN(LOG, "error creating pipe: %s", std::strerror(errno));
+ return nullptr;
}
- wl_data_offer_receive(data_offer->id, mime_receive.c_str(), pipefd[1]);
+ wl_data_offer_receive(data_offer->id, mime_receive, pipefd[1]);
close(pipefd[1]);
data_offer->in_use.store(false);
@@ -1149,15 +1509,34 @@ static std::string read_pipe(GWL_DataOffer *data_offer,
}
/* WARNING: `data_offer` may be freed from now on. */
- std::string data;
- ssize_t len;
- char buffer[4096];
- while ((len = read(pipefd[0], buffer, sizeof(buffer))) > 0) {
- data.insert(data.end(), buffer, buffer + len);
- }
+ const char *buf = read_file_as_buffer(pipefd[0], r_len);
close(pipefd[0]);
+ return buf;
+}
+
+static const char *read_buffer_from_primary_selection_offer(
+ GWL_PrimarySelection_DataOffer *data_offer,
+ const char *mime_receive,
+ std::mutex *mutex,
+ size_t *r_len)
+{
+ int pipefd[2];
+ if (UNLIKELY(pipe(pipefd) != 0)) {
+ CLOG_WARN(LOG, "error creating pipe: %s", std::strerror(errno));
+ return nullptr;
+ }
+ zwp_primary_selection_offer_v1_receive(data_offer->id, mime_receive, pipefd[1]);
+ close(pipefd[1]);
- return data;
+ data_offer->in_use.store(false);
+
+ if (mutex) {
+ mutex->unlock();
+ }
+ /* WARNING: `data_offer` may be freed from now on. */
+ const char *buf = read_file_as_buffer(pipefd[0], r_len);
+ close(pipefd[0]);
+ return buf;
}
/**
@@ -1183,16 +1562,22 @@ static void data_source_handle_send(void *data,
CLOG_INFO(LOG, 2, "send");
- const char *const buffer = seat->data_source->buffer_out;
- if (write(fd, buffer, strlen(buffer)) < 0) {
- GHOST_PRINT("error writing to clipboard: " << std::strerror(errno) << std::endl);
+ const char *const buffer = seat->data_source->buffer_out.data;
+ if (UNLIKELY(write(fd, buffer, seat->data_source->buffer_out.data_size) < 0)) {
+ CLOG_WARN(LOG, "error writing to clipboard: %s", std::strerror(errno));
}
close(fd);
}
-static void data_source_handle_cancelled(void * /*data*/, struct wl_data_source *wl_data_source)
+static void data_source_handle_cancelled(void *data, struct wl_data_source *wl_data_source)
{
CLOG_INFO(LOG, 2, "cancelled");
+ GWL_Seat *seat = static_cast<GWL_Seat *>(data);
+ GWL_DataSource *data_source = seat->data_source;
+ if (seat->data_source->wl_source == wl_data_source) {
+ data_source->wl_source = nullptr;
+ }
+
wl_data_source_destroy(wl_data_source);
}
@@ -1261,7 +1646,8 @@ static void data_offer_handle_offer(void *data,
const char *mime_type)
{
CLOG_INFO(LOG, 2, "offer (mime_type=%s)", mime_type);
- static_cast<GWL_DataOffer *>(data)->types.insert(mime_type);
+ GWL_DataOffer *data_offer = static_cast<GWL_DataOffer *>(data);
+ data_offer->types.insert(mime_type);
}
static void data_offer_handle_source_actions(void *data,
@@ -1269,7 +1655,8 @@ static void data_offer_handle_source_actions(void *data,
const uint32_t source_actions)
{
CLOG_INFO(LOG, 2, "source_actions (%u)", source_actions);
- static_cast<GWL_DataOffer *>(data)->source_actions = source_actions;
+ GWL_DataOffer *data_offer = static_cast<GWL_DataOffer *>(data);
+ data_offer->dnd.source_actions = (enum wl_data_device_manager_dnd_action)source_actions;
}
static void data_offer_handle_action(void *data,
@@ -1277,7 +1664,8 @@ static void data_offer_handle_action(void *data,
const uint32_t dnd_action)
{
CLOG_INFO(LOG, 2, "actions (%u)", dnd_action);
- static_cast<GWL_DataOffer *>(data)->dnd_action = dnd_action;
+ GWL_DataOffer *data_offer = static_cast<GWL_DataOffer *>(data);
+ data_offer->dnd.action = (enum wl_data_device_manager_dnd_action)dnd_action;
}
static const struct wl_data_offer_listener data_offer_listener = {
@@ -1400,7 +1788,11 @@ static void data_device_handle_drop(void *data, struct wl_data_device * /*wl_dat
const std::string mime_receive) {
const wl_fixed_t xy[2] = {UNPACK2(data_offer->dnd.xy)};
- const std::string data = read_pipe(data_offer, mime_receive, nullptr);
+ size_t data_buf_len = 0;
+ const char *data_buf = read_buffer_from_data_offer(
+ data_offer, mime_receive.c_str(), nullptr, &data_buf_len);
+ std::string data = data_buf ? std::string(data_buf, data_buf_len) : "";
+ free(const_cast<char *>(data_buf));
CLOG_INFO(
LOG, 2, "drop_read_uris mime_receive=%s, data=%s", mime_receive.c_str(), data.c_str());
@@ -1466,7 +1858,7 @@ static void data_device_handle_drop(void *data, struct wl_data_device * /*wl_dat
* 'text_update_edited' to behave like dropped text was pasted. */
CLOG_INFO(LOG, 2, "drop_read_uris_fn (text_plain, text_utf8), unhandled!");
}
- wl_display_roundtrip(system->display());
+ wl_display_roundtrip(system->wl_display());
};
/* Pass in `seat->wl_surface_focus_dnd` instead of accessing it from `seat` since the leave
@@ -1499,7 +1891,6 @@ static void data_device_handle_selection(void *data,
return;
}
CLOG_INFO(LOG, 2, "selection");
-
/* Get new data offer. */
data_offer = static_cast<GWL_DataOffer *>(wl_data_offer_get_user_data(id));
seat->data_offer_copy_paste = data_offer;
@@ -1516,12 +1907,15 @@ static void data_device_handle_selection(void *data,
break;
}
}
- const std::string data = read_pipe(
- data_offer, mime_receive, &seat->data_offer_copy_paste_mutex);
+
+ size_t data_len = 0;
+ const char *data = read_buffer_from_data_offer(
+ data_offer, mime_receive.c_str(), &seat->data_offer_copy_paste_mutex, &data_len);
{
- std::lock_guard lock{system_selection_mutex};
- system->selection_set(data);
+ std::lock_guard lock{system_clipboard_mutex};
+ GWL_SimpleBuffer *buf = system->clipboard_data(false);
+ gwl_simple_buffer_set_and_take_ownership(buf, data, data_len);
}
};
@@ -1595,7 +1989,8 @@ static bool update_cursor_scale(GWL_Cursor &cursor,
wl_surface_set_buffer_scale(wl_cursor_surface, scale);
}
wl_cursor_theme_destroy(cursor.wl_theme);
- cursor.wl_theme = wl_cursor_theme_load(cursor.theme_name.c_str(), scale * cursor.size, shm);
+ cursor.wl_theme = wl_cursor_theme_load(
+ cursor.theme_name.c_str(), scale * cursor.theme_size, shm);
return true;
}
return false;
@@ -1616,7 +2011,7 @@ static void cursor_surface_handle_enter(void *data,
wl_surface);
const GWL_Output *reg_output = ghost_wl_output_user_data(wl_output);
seat_state_pointer->outputs.insert(reg_output);
- update_cursor_scale(seat->cursor, seat->system->shm(), seat_state_pointer, wl_surface);
+ update_cursor_scale(seat->cursor, seat->system->wl_shm(), seat_state_pointer, wl_surface);
}
static void cursor_surface_handle_leave(void *data,
@@ -1634,7 +2029,7 @@ static void cursor_surface_handle_leave(void *data,
wl_surface);
const GWL_Output *reg_output = ghost_wl_output_user_data(wl_output);
seat_state_pointer->outputs.erase(reg_output);
- update_cursor_scale(seat->cursor, seat->system->shm(), seat_state_pointer, wl_surface);
+ update_cursor_scale(seat->cursor, seat->system->wl_shm(), seat_state_pointer, wl_surface);
}
static const struct wl_surface_listener cursor_surface_listener = {
@@ -1675,6 +2070,15 @@ static void pointer_handle_enter(void *data,
seat->pointer.serial = serial;
seat->pointer.xy[0] = surface_x;
seat->pointer.xy[1] = surface_y;
+
+ /* Resetting scroll events is likely unnecessary,
+ * do this to avoid any possible problems as it's harmless. */
+ seat->pointer_scroll.smooth_xy[0] = 0;
+ seat->pointer_scroll.smooth_xy[1] = 0;
+ seat->pointer_scroll.discrete_xy[0] = 0;
+ seat->pointer_scroll.discrete_xy[1] = 0;
+ seat->pointer_scroll.axis_source = WL_POINTER_AXIS_SOURCE_WHEEL;
+
seat->pointer.wl_surface = wl_surface;
win->setCursorShape(win->getCursorShape());
@@ -1786,24 +2190,91 @@ static void pointer_handle_button(void *data,
}
}
-static void pointer_handle_axis(void * /*data*/,
+static void pointer_handle_axis(void *data,
struct wl_pointer * /*wl_pointer*/,
const uint32_t /*time*/,
const uint32_t axis,
const wl_fixed_t value)
{
+ /* NOTE: this is used for touch based scrolling - or other input that doesn't scroll with
+ * discrete "steps". This allows supporting smooth-scrolling without "touch" gesture support. */
CLOG_INFO(LOG, 2, "axis (axis=%u, value=%d)", axis, value);
+ const int index = pointer_axis_as_index(axis);
+ if (UNLIKELY(index == -1)) {
+ return;
+ }
+ GWL_Seat *seat = static_cast<GWL_Seat *>(data);
+ seat->pointer_scroll.smooth_xy[index] = value;
}
-static void pointer_handle_frame(void * /*data*/, struct wl_pointer * /*wl_pointer*/)
+static void pointer_handle_frame(void *data, struct wl_pointer * /*wl_pointer*/)
{
CLOG_INFO(LOG, 2, "frame");
+ GWL_Seat *seat = static_cast<GWL_Seat *>(data);
+
+ /* Both discrete and smooth events may be set at once, never generate events for both
+ * as this will be handling the same event in to different ways.
+ * Prioritize discrete axis events for the mouse wheel, otherwise smooth scroll. */
+ if (seat->pointer_scroll.axis_source == WL_POINTER_AXIS_SOURCE_WHEEL) {
+ if (seat->pointer_scroll.discrete_xy[0]) {
+ seat->pointer_scroll.smooth_xy[0] = 0;
+ }
+ if (seat->pointer_scroll.discrete_xy[1]) {
+ seat->pointer_scroll.smooth_xy[1] = 0;
+ }
+ }
+ else {
+ if (seat->pointer_scroll.smooth_xy[0]) {
+ seat->pointer_scroll.discrete_xy[0] = 0;
+ }
+ if (seat->pointer_scroll.smooth_xy[1]) {
+ seat->pointer_scroll.discrete_xy[1] = 0;
+ }
+ }
+
+ /* Discrete X axis currently unsupported. */
+ if (seat->pointer_scroll.discrete_xy[1]) {
+ if (wl_surface *wl_surface_focus = seat->pointer.wl_surface) {
+ GHOST_WindowWayland *win = ghost_wl_surface_user_data(wl_surface_focus);
+ const int32_t discrete = seat->pointer_scroll.discrete_xy[1];
+ seat->system->pushEvent(new GHOST_EventWheel(
+ seat->system->getMilliSeconds(), win, std::signbit(discrete) ? +1 : -1));
+ }
+ seat->pointer_scroll.discrete_xy[0] = 0;
+ seat->pointer_scroll.discrete_xy[1] = 0;
+ }
+
+ if (seat->pointer_scroll.smooth_xy[0] || seat->pointer_scroll.smooth_xy[1]) {
+ if (wl_surface *wl_surface_focus = seat->pointer.wl_surface) {
+ GHOST_WindowWayland *win = ghost_wl_surface_user_data(wl_surface_focus);
+ const wl_fixed_t scale = win->scale();
+ seat->system->pushEvent(new GHOST_EventTrackpad(
+ seat->system->getMilliSeconds(),
+ win,
+ GHOST_kTrackpadEventScroll,
+ wl_fixed_to_int(scale * seat->pointer.xy[0]),
+ wl_fixed_to_int(scale * seat->pointer.xy[1]),
+ /* NOTE: scaling the delta doesn't seem necessary.
+ * NOTE: inverting delta gives correct results, see: QTBUG-85767. */
+ -wl_fixed_to_int(seat->pointer_scroll.smooth_xy[0]),
+ -wl_fixed_to_int(seat->pointer_scroll.smooth_xy[1]),
+ /* TODO: investigate a way to request this configuration from the system. */
+ false));
+ }
+
+ seat->pointer_scroll.smooth_xy[0] = 0;
+ seat->pointer_scroll.smooth_xy[1] = 0;
+ }
+
+ seat->pointer_scroll.axis_source = WL_POINTER_AXIS_SOURCE_WHEEL;
}
-static void pointer_handle_axis_source(void * /*data*/,
+static void pointer_handle_axis_source(void *data,
struct wl_pointer * /*wl_pointer*/,
uint32_t axis_source)
{
CLOG_INFO(LOG, 2, "axis_source (axis_source=%u)", axis_source);
+ GWL_Seat *seat = static_cast<GWL_Seat *>(data);
+ seat->pointer_scroll.axis_source = (enum wl_pointer_axis_source)axis_source;
}
static void pointer_handle_axis_stop(void * /*data*/,
struct wl_pointer * /*wl_pointer*/,
@@ -1817,18 +2288,15 @@ static void pointer_handle_axis_discrete(void *data,
uint32_t axis,
int32_t discrete)
{
+ /* NOTE: a discrete axis are typically mouse wheel events.
+ * The non-discrete version of this function is used for touch-pad. */
CLOG_INFO(LOG, 2, "axis_discrete (axis=%u, discrete=%d)", axis, discrete);
-
- GWL_Seat *seat = static_cast<GWL_Seat *>(data);
- if (axis != WL_POINTER_AXIS_VERTICAL_SCROLL) {
+ const int index = pointer_axis_as_index(axis);
+ if (UNLIKELY(index == -1)) {
return;
}
-
- if (wl_surface *wl_surface_focus = seat->pointer.wl_surface) {
- GHOST_WindowWayland *win = ghost_wl_surface_user_data(wl_surface_focus);
- seat->system->pushEvent(new GHOST_EventWheel(
- seat->system->getMilliSeconds(), win, std::signbit(discrete) ? +1 : -1));
- }
+ GWL_Seat *seat = static_cast<GWL_Seat *>(data);
+ seat->pointer_scroll.discrete_xy[index] = discrete;
}
static const struct wl_pointer_listener pointer_listener = {
@@ -1848,6 +2316,312 @@ static const struct wl_pointer_listener pointer_listener = {
/** \} */
/* -------------------------------------------------------------------- */
+/** \name Listener (Pointer Gesture: Hold), #zwp_pointer_gesture_hold_v1_listener
+ * \{ */
+
+#ifdef ZWP_POINTER_GESTURE_HOLD_V1_INTERFACE
+static CLG_LogRef LOG_WL_POINTER_GESTURE_HOLD = {"ghost.wl.handle.pointer_gesture.hold"};
+# define LOG (&LOG_WL_POINTER_GESTURE_HOLD)
+
+static void gesture_hold_handle_begin(
+ void * /*data*/,
+ struct zwp_pointer_gesture_hold_v1 * /*zwp_pointer_gesture_hold_v1*/,
+ uint32_t /*serial*/,
+ uint32_t /*time*/,
+ struct wl_surface * /*surface*/,
+ uint32_t fingers)
+{
+ CLOG_INFO(LOG, 2, "begin (fingers=%u)", fingers);
+}
+
+static void gesture_hold_handle_end(
+ void * /*data*/,
+ struct zwp_pointer_gesture_hold_v1 * /*zwp_pointer_gesture_hold_v1*/,
+ uint32_t /*serial*/,
+ uint32_t /*time*/,
+ int32_t cancelled)
+{
+ CLOG_INFO(LOG, 2, "end (cancelled=%i)", cancelled);
+}
+
+static const struct zwp_pointer_gesture_hold_v1_listener gesture_hold_listener = {
+ gesture_hold_handle_begin,
+ gesture_hold_handle_end,
+};
+
+# undef LOG
+#endif /* ZWP_POINTER_GESTURE_HOLD_V1_INTERFACE */
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Listener (Pointer Gesture: Pinch), #zwp_pointer_gesture_pinch_v1_listener
+ * \{ */
+
+#ifdef ZWP_POINTER_GESTURE_PINCH_V1_INTERFACE
+static CLG_LogRef LOG_WL_POINTER_GESTURE_PINCH = {"ghost.wl.handle.pointer_gesture.pinch"};
+# define LOG (&LOG_WL_POINTER_GESTURE_PINCH)
+
+static void gesture_pinch_handle_begin(void *data,
+ struct zwp_pointer_gesture_pinch_v1 * /*pinch*/,
+ uint32_t /*serial*/,
+ uint32_t /*time*/,
+ struct wl_surface * /*surface*/,
+ uint32_t fingers)
+{
+ CLOG_INFO(LOG, 2, "begin (fingers=%u)", fingers);
+ GWL_Seat *seat = static_cast<GWL_Seat *>(data);
+ /* Reset defaults. */
+ seat->pointer_gesture_pinch = GWL_SeatStatePointerGesture_Pinch{};
+
+ GHOST_WindowWayland *win = nullptr;
+ if (wl_surface *wl_surface_focus = seat->pointer.wl_surface) {
+ win = ghost_wl_surface_user_data(wl_surface_focus);
+ }
+ const wl_fixed_t win_scale = win ? win->scale() : 1;
+
+ /* NOTE(@campbellbarton): Scale factors match Blender's operators & default preferences.
+ * For these values to work correctly, operator logic will need to be changed not to scale input
+ * by the region size (as with 3D view zoom) or preference for 3D view orbit sensitivity.
+ *
+ * By working "correctly" I mean that a rotation action where the users fingers rotate to
+ * opposite locations should always rotate the viewport 180d, since users will expect the
+ * physical location of their fingers to match the viewport.
+ * Similarly with zoom, the scale value from the pinch action can be mapped to a zoom level
+ * although unlike rotation, an inexact mapping is less noticeable.
+ * Users may even prefer the zoom level to be scaled - which could be a preference. */
+ seat->pointer_gesture_pinch.scale.value = wl_fixed_from_int(1);
+ /* The value 300 matches a value used in clip & image zoom operators.
+ * It seems OK for the 3D view too. */
+ seat->pointer_gesture_pinch.scale.factor = 300 * win_scale;
+ /* The value 5 is used on macOS and roughly maps 1:1 with turntable rotation,
+ * although preferences can scale the sensitivity (which would be skipped ideally). */
+ seat->pointer_gesture_pinch.rotation.factor = 5 * win_scale;
+}
+
+static void gesture_pinch_handle_update(void *data,
+ struct zwp_pointer_gesture_pinch_v1 * /*pinch*/,
+ uint32_t /*time*/,
+ wl_fixed_t dx,
+ wl_fixed_t dy,
+ wl_fixed_t scale,
+ wl_fixed_t rotation)
+{
+ CLOG_INFO(LOG,
+ 2,
+ "update (dx=%.3f, dy=%.3f, scale=%.3f, rotation=%.3f)",
+ wl_fixed_to_double(dx),
+ wl_fixed_to_double(dy),
+ wl_fixed_to_double(scale),
+ wl_fixed_to_double(rotation));
+
+ GWL_Seat *seat = static_cast<GWL_Seat *>(data);
+
+ GHOST_WindowWayland *win = nullptr;
+
+ if (wl_surface *wl_surface_focus = seat->pointer.wl_surface) {
+ win = ghost_wl_surface_user_data(wl_surface_focus);
+ }
+
+ /* Scale defaults to `wl_fixed_from_int(1)` which may change while pinching.
+ * This needs to be converted to a delta. */
+ const wl_fixed_t scale_delta = scale - seat->pointer_gesture_pinch.scale.value;
+ const int scale_as_delta_px = gwl_scaled_fixed_t_add_and_calc_rounded_delta(
+ &seat->pointer_gesture_pinch.scale, scale_delta);
+
+ /* Rotation in degrees, unlike scale this is a delta. */
+ const int rotation_as_delta_px = gwl_scaled_fixed_t_add_and_calc_rounded_delta(
+ &seat->pointer_gesture_pinch.rotation, rotation);
+
+ if (win) {
+ const wl_fixed_t win_scale = win->scale();
+ const int32_t event_xy[2] = {
+ wl_fixed_to_int(win_scale * seat->pointer.xy[0]),
+ wl_fixed_to_int(win_scale * seat->pointer.xy[1]),
+ };
+ if (scale_as_delta_px) {
+ seat->system->pushEvent(new GHOST_EventTrackpad(seat->system->getMilliSeconds(),
+ win,
+ GHOST_kTrackpadEventMagnify,
+ event_xy[0],
+ event_xy[1],
+ scale_as_delta_px,
+ 0,
+ false));
+ }
+
+ if (rotation_as_delta_px) {
+ seat->system->pushEvent(new GHOST_EventTrackpad(seat->system->getMilliSeconds(),
+ win,
+ GHOST_kTrackpadEventRotate,
+ event_xy[0],
+ event_xy[1],
+ rotation_as_delta_px,
+ 0,
+ false));
+ }
+ }
+}
+
+static void gesture_pinch_handle_end(void * /*data*/,
+ struct zwp_pointer_gesture_pinch_v1 * /*pinch*/,
+ uint32_t /*serial*/,
+ uint32_t /*time*/,
+ int32_t cancelled)
+{
+ CLOG_INFO(LOG, 2, "end (cancelled=%i)", cancelled);
+}
+
+static const struct zwp_pointer_gesture_pinch_v1_listener gesture_pinch_listener = {
+ gesture_pinch_handle_begin,
+ gesture_pinch_handle_update,
+ gesture_pinch_handle_end,
+};
+
+# undef LOG
+#endif /* ZWP_POINTER_GESTURE_PINCH_V1_INTERFACE */
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Listener (Pointer Gesture: Swipe), #zwp_pointer_gesture_swipe_v1
+ *
+ * \note In both Gnome-Shell & KDE this gesture isn't emitted at time of writing,
+ * instead, high resolution 2D #wl_pointer_listener.axis data is generated which works well.
+ * There may be some situations where WAYLAND compositors generate this gesture
+ * (swiping with 3+ fingers, for e.g.). So keep this to allow logging & testing gestures.
+ * \{ */
+
+#ifdef ZWP_POINTER_GESTURE_SWIPE_V1_INTERFACE
+static CLG_LogRef LOG_WL_POINTER_GESTURE_SWIPE = {"ghost.wl.handle.pointer_gesture.swipe"};
+# define LOG (&LOG_WL_POINTER_GESTURE_SWIPE)
+
+static void gesture_swipe_handle_begin(
+ void * /*data*/,
+ struct zwp_pointer_gesture_swipe_v1 * /*zwp_pointer_gesture_swipe_v1*/,
+ uint32_t /*serial*/,
+ uint32_t /*time*/,
+ struct wl_surface * /*surface*/,
+ uint32_t fingers)
+{
+ CLOG_INFO(LOG, 2, "begin (fingers=%u)", fingers);
+}
+
+static void gesture_swipe_handle_update(
+ void * /*data*/,
+ struct zwp_pointer_gesture_swipe_v1 * /*zwp_pointer_gesture_swipe_v1*/,
+ uint32_t /*time*/,
+ wl_fixed_t dx,
+ wl_fixed_t dy)
+{
+ CLOG_INFO(LOG, 2, "update (dx=%.3f, dy=%.3f)", wl_fixed_to_double(dx), wl_fixed_to_double(dy));
+}
+
+static void gesture_swipe_handle_end(
+ void * /*data*/,
+ struct zwp_pointer_gesture_swipe_v1 * /*zwp_pointer_gesture_swipe_v1*/,
+ uint32_t /*serial*/,
+ uint32_t /*time*/,
+ int32_t cancelled)
+{
+ CLOG_INFO(LOG, 2, "end (cancelled=%i)", cancelled);
+}
+
+static const struct zwp_pointer_gesture_swipe_v1_listener gesture_swipe_listener = {
+ gesture_swipe_handle_begin,
+ gesture_swipe_handle_update,
+ gesture_swipe_handle_end,
+};
+
+# undef LOG
+#endif /* ZWP_POINTER_GESTURE_SWIPE_V1_INTERFACE */
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Listener (Touch Seat), #wl_touch_listener
+ *
+ * TODO(@campbellbarton): Only setup the callbacks for now as I don't have
+ * hardware that generates touch events.
+ * \{ */
+
+static CLG_LogRef LOG_WL_TOUCH = {"ghost.wl.handle.touch"};
+#define LOG (&LOG_WL_TOUCH)
+
+static void touch_seat_handle_down(void * /*data*/,
+ struct wl_touch * /*wl_touch*/,
+ uint32_t /*serial*/,
+ uint32_t /*time*/,
+ struct wl_surface * /*wl_surface*/,
+ int32_t /*id*/,
+ wl_fixed_t /*x*/,
+ wl_fixed_t /*y*/)
+{
+ CLOG_INFO(LOG, 2, "down");
+}
+
+static void touch_seat_handle_up(void * /*data*/,
+ struct wl_touch * /*wl_touch*/,
+ uint32_t /*serial*/,
+ uint32_t /*time*/,
+ int32_t /*id*/)
+{
+ CLOG_INFO(LOG, 2, "up");
+}
+
+static void touch_seat_handle_motion(void * /*data*/,
+ struct wl_touch * /*wl_touch*/,
+ uint32_t /*time*/,
+ int32_t /*id*/,
+ wl_fixed_t /*x*/,
+ wl_fixed_t /*y*/)
+{
+ CLOG_INFO(LOG, 2, "motion");
+}
+
+static void touch_seat_handle_frame(void * /*data*/, struct wl_touch * /*wl_touch*/)
+{
+ CLOG_INFO(LOG, 2, "frame");
+}
+
+static void touch_seat_handle_cancel(void * /*data*/, struct wl_touch * /*wl_touch*/)
+{
+
+ CLOG_INFO(LOG, 2, "cancel");
+}
+
+static void touch_seat_handle_shape(void * /*data*/,
+ struct wl_touch * /*touch*/,
+ int32_t /*id*/,
+ wl_fixed_t /*major*/,
+ wl_fixed_t /*minor*/)
+{
+ CLOG_INFO(LOG, 2, "shape");
+}
+
+static void touch_seat_handle_orientation(void * /*data*/,
+ struct wl_touch * /*touch*/,
+ int32_t /*id*/,
+ wl_fixed_t /*orientation*/)
+{
+ CLOG_INFO(LOG, 2, "orientation");
+}
+
+static const struct wl_touch_listener touch_seat_listener = {
+ touch_seat_handle_down,
+ touch_seat_handle_up,
+ touch_seat_handle_motion,
+ touch_seat_handle_frame,
+ touch_seat_handle_cancel,
+ touch_seat_handle_shape,
+ touch_seat_handle_orientation,
+};
+
+#undef LOG
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
/** \name Listener (Tablet Tool), #zwp_tablet_tool_v2_listener
* \{ */
@@ -2206,7 +2980,7 @@ static void tablet_seat_handle_tool_added(void *data,
tablet_tool->seat = seat;
/* Every tool has it's own cursor wl_surface. */
- tablet_tool->wl_surface_cursor = wl_compositor_create_surface(seat->system->compositor());
+ tablet_tool->wl_surface_cursor = wl_compositor_create_surface(seat->system->wl_compositor());
ghost_wl_surface_tag_cursor_tablet(tablet_tool->wl_surface_cursor);
wl_surface_add_listener(tablet_tool->wl_surface_cursor, &cursor_surface_listener, (void *)seat);
@@ -2326,7 +3100,7 @@ static void keyboard_handle_enter(void *data,
/* If there are any keys held when activating the window,
* modifiers will be compared against the seat state,
* only enabling modifiers that were previously disabled. */
- WGL_KeyboardDepressedState key_depressed_prev = seat->key_depressed;
+ GWL_KeyboardDepressedState key_depressed_prev = seat->key_depressed;
keyboard_depressed_state_reset(seat);
uint32_t *key;
@@ -2536,11 +3310,10 @@ static void keyboard_handle_key(void *data,
/* Start timer for repeating key, if applicable. */
if ((seat->key_repeat.rate > 0) && (etype == GHOST_kEventKeyDown) &&
xkb_keymap_key_repeats(xkb_state_get_keymap(seat->xkb_state), key_code)) {
- key_repeat_payload = new GWL_KeyRepeatPlayload({
- .seat = seat,
- .key_code = key_code,
- .key_data = {.gkey = gkey},
- });
+ key_repeat_payload = new GWL_KeyRepeatPlayload();
+ key_repeat_payload->seat = seat;
+ key_repeat_payload->key_code = key_code;
+ key_repeat_payload->key_data.gkey = gkey;
}
}
@@ -2630,12 +3403,306 @@ static const struct wl_keyboard_listener keyboard_listener = {
/** \} */
/* -------------------------------------------------------------------- */
+/** \name Listener (Primary Selection Offer), #zwp_primary_selection_offer_v1_listener
+ * \{ */
+
+static CLG_LogRef LOG_WL_PRIMARY_SELECTION_OFFER = {"ghost.wl.handle.primary_selection_offer"};
+#define LOG (&LOG_WL_PRIMARY_SELECTION_OFFER)
+
+static void primary_selection_offer_offer(void *data,
+ struct zwp_primary_selection_offer_v1 *id,
+ const char *type)
+{
+ GWL_PrimarySelection_DataOffer *data_offer = static_cast<GWL_PrimarySelection_DataOffer *>(data);
+ if (data_offer->id != id) {
+ CLOG_INFO(LOG, 2, "offer: %p: offer for unknown selection %p of %s (skipped)", data, id, type);
+ return;
+ }
+
+ data_offer->types.insert(std::string(type));
+}
+
+static const struct zwp_primary_selection_offer_v1_listener primary_selection_offer_listener = {
+ primary_selection_offer_offer,
+};
+
+#undef LOG
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Listener (Primary Selection Device), #zwp_primary_selection_device_v1_listener
+ * \{ */
+
+static CLG_LogRef LOG_WL_PRIMARY_SELECTION_DEVICE = {"ghost.wl.handle.primary_selection_device"};
+#define LOG (&LOG_WL_PRIMARY_SELECTION_DEVICE)
+
+static void primary_selection_device_handle_data_offer(
+ void * /*data*/,
+ struct zwp_primary_selection_device_v1 * /*zwp_primary_selection_device_v1*/,
+ struct zwp_primary_selection_offer_v1 *id)
+{
+ CLOG_INFO(LOG, 2, "data_offer");
+
+ GWL_PrimarySelection_DataOffer *data_offer = new GWL_PrimarySelection_DataOffer;
+ data_offer->id = id;
+ zwp_primary_selection_offer_v1_add_listener(id, &primary_selection_offer_listener, data_offer);
+}
+
+static void primary_selection_device_handle_selection(
+ void *data,
+ struct zwp_primary_selection_device_v1 * /*zwp_primary_selection_device_v1*/,
+ struct zwp_primary_selection_offer_v1 *id)
+{
+ GWL_PrimarySelection *primary = static_cast<GWL_PrimarySelection *>(data);
+
+ std::lock_guard lock{primary->data_offer_mutex};
+
+ /* Delete old data offer. */
+ if (primary->data_offer != nullptr) {
+ gwl_primary_selection_discard_offer(primary);
+ }
+
+ if (id == nullptr) {
+ CLOG_INFO(LOG, 2, "selection: (skipped)");
+ return;
+ }
+ CLOG_INFO(LOG, 2, "selection");
+ /* Get new data offer. */
+ GWL_PrimarySelection_DataOffer *data_offer = static_cast<GWL_PrimarySelection_DataOffer *>(
+ zwp_primary_selection_offer_v1_get_user_data(id));
+ primary->data_offer = data_offer;
+
+ auto read_selection_fn = [](GWL_PrimarySelection *primary) {
+ GHOST_SystemWayland *system = static_cast<GHOST_SystemWayland *>(GHOST_ISystem::getSystem());
+ primary->data_offer_mutex.lock();
+
+ GWL_PrimarySelection_DataOffer *data_offer = primary->data_offer;
+ std::string mime_receive;
+ for (const std::string type : {mime_text_utf8, mime_text_plain}) {
+ if (data_offer->types.count(type)) {
+ mime_receive = type;
+ break;
+ }
+ }
+ size_t data_len = 0;
+ const char *data = read_buffer_from_primary_selection_offer(
+ data_offer, mime_receive.c_str(), &primary->data_offer_mutex, &data_len);
+
+ {
+ std::lock_guard lock{system_clipboard_mutex};
+ GWL_SimpleBuffer *buf = system->clipboard_data(true);
+ gwl_simple_buffer_set_and_take_ownership(buf, data, data_len);
+ }
+ };
+
+ std::thread read_thread(read_selection_fn, primary);
+ read_thread.detach();
+}
+
+static const struct zwp_primary_selection_device_v1_listener primary_selection_device_listener = {
+ primary_selection_device_handle_data_offer,
+ primary_selection_device_handle_selection,
+};
+
+#undef LOG
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Listener (Primary Selection Source), #zwp_primary_selection_source_v1_listener
+ * \{ */
+
+static CLG_LogRef LOG_WL_PRIMARY_SELECTION_SOURCE = {"ghost.wl.handle.primary_selection_source"};
+#define LOG (&LOG_WL_PRIMARY_SELECTION_SOURCE)
+
+static void primary_selection_source_send(void *data,
+ struct zwp_primary_selection_source_v1 * /*source*/,
+ const char * /*mime_type*/,
+ int32_t fd)
+{
+ CLOG_INFO(LOG, 2, "send");
+
+ GWL_PrimarySelection *primary = static_cast<GWL_PrimarySelection *>(data);
+
+ std::lock_guard lock{primary->data_source_mutex};
+ GWL_PrimarySelection_DataSource *data_source = primary->data_source;
+
+ const char *const buffer = data_source->buffer_out.data;
+ if (UNLIKELY(write(fd, buffer, data_source->buffer_out.data_size) < 0)) {
+ CLOG_WARN(LOG, "error writing to primary clipboard: %s", std::strerror(errno));
+ }
+ close(fd);
+}
+
+static void primary_selection_source_cancelled(void *data,
+ struct zwp_primary_selection_source_v1 *source)
+{
+ CLOG_INFO(LOG, 2, "cancelled");
+
+ GWL_PrimarySelection *primary = static_cast<GWL_PrimarySelection *>(data);
+
+ if (source == primary->data_source->wp_source) {
+ gwl_primary_selection_discard_source(primary);
+ }
+}
+
+static const struct zwp_primary_selection_source_v1_listener primary_selection_source_listener = {
+ primary_selection_source_send,
+ primary_selection_source_cancelled,
+};
+
+#undef LOG
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
/** \name Listener (Seat), #wl_seat_listener
* \{ */
static CLG_LogRef LOG_WL_SEAT = {"ghost.wl.handle.seat"};
#define LOG (&LOG_WL_SEAT)
+static void gwl_seat_capability_pointer_enable(GWL_Seat *seat)
+{
+ if (seat->wl_pointer) {
+ return;
+ }
+ seat->wl_pointer = wl_seat_get_pointer(seat->wl_seat);
+ seat->cursor.wl_surface = wl_compositor_create_surface(seat->system->wl_compositor());
+ seat->cursor.visible = true;
+ seat->cursor.wl_buffer = nullptr;
+ if (!get_cursor_settings(seat->cursor.theme_name, seat->cursor.theme_size)) {
+ seat->cursor.theme_name = std::string();
+ seat->cursor.theme_size = default_cursor_size;
+ }
+ wl_pointer_add_listener(seat->wl_pointer, &pointer_listener, seat);
+
+ wl_surface_add_listener(seat->cursor.wl_surface, &cursor_surface_listener, seat);
+ ghost_wl_surface_tag_cursor_pointer(seat->cursor.wl_surface);
+
+ zwp_pointer_gestures_v1 *pointer_gestures = seat->system->wp_pointer_gestures();
+ if (pointer_gestures) {
+#ifdef ZWP_POINTER_GESTURE_HOLD_V1_INTERFACE
+ { /* Hold gesture. */
+ struct zwp_pointer_gesture_hold_v1 *gesture = zwp_pointer_gestures_v1_get_hold_gesture(
+ pointer_gestures, seat->wl_pointer);
+ zwp_pointer_gesture_hold_v1_set_user_data(gesture, seat);
+ zwp_pointer_gesture_hold_v1_add_listener(gesture, &gesture_hold_listener, seat);
+ seat->wp_pointer_gesture_hold = gesture;
+ }
+#endif
+#ifdef ZWP_POINTER_GESTURE_PINCH_V1_INTERFACE
+ { /* Pinch gesture. */
+ struct zwp_pointer_gesture_pinch_v1 *gesture = zwp_pointer_gestures_v1_get_pinch_gesture(
+ pointer_gestures, seat->wl_pointer);
+ zwp_pointer_gesture_pinch_v1_set_user_data(gesture, seat);
+ zwp_pointer_gesture_pinch_v1_add_listener(gesture, &gesture_pinch_listener, seat);
+ seat->wp_pointer_gesture_pinch = gesture;
+ }
+#endif
+#ifdef ZWP_POINTER_GESTURE_SWIPE_V1_INTERFACE
+ { /* Swipe gesture. */
+ struct zwp_pointer_gesture_swipe_v1 *gesture = zwp_pointer_gestures_v1_get_swipe_gesture(
+ pointer_gestures, seat->wl_pointer);
+ zwp_pointer_gesture_swipe_v1_set_user_data(gesture, seat);
+ zwp_pointer_gesture_swipe_v1_add_listener(gesture, &gesture_swipe_listener, seat);
+ seat->wp_pointer_gesture_swipe = gesture;
+ }
+#endif
+ }
+}
+
+static void gwl_seat_capability_pointer_disable(GWL_Seat *seat)
+{
+ if (!seat->wl_pointer) {
+ return;
+ }
+
+ zwp_pointer_gestures_v1 *pointer_gestures = seat->system->wp_pointer_gestures();
+ if (pointer_gestures) {
+#ifdef ZWP_POINTER_GESTURE_HOLD_V1_INTERFACE
+ { /* Hold gesture. */
+ struct zwp_pointer_gesture_hold_v1 **gesture_p = &seat->wp_pointer_gesture_hold;
+ if (*gesture_p) {
+ zwp_pointer_gesture_hold_v1_destroy(*gesture_p);
+ *gesture_p = nullptr;
+ }
+ }
+#endif
+#ifdef ZWP_POINTER_GESTURE_PINCH_V1_INTERFACE
+ { /* Pinch gesture. */
+ struct zwp_pointer_gesture_pinch_v1 **gesture_p = &seat->wp_pointer_gesture_pinch;
+ if (*gesture_p) {
+ zwp_pointer_gesture_pinch_v1_destroy(*gesture_p);
+ *gesture_p = nullptr;
+ }
+ }
+#endif
+#ifdef ZWP_POINTER_GESTURE_SWIPE_V1_INTERFACE
+ { /* Swipe gesture. */
+ struct zwp_pointer_gesture_swipe_v1 **gesture_p = &seat->wp_pointer_gesture_swipe;
+ if (*gesture_p) {
+ zwp_pointer_gesture_swipe_v1_destroy(*gesture_p);
+ *gesture_p = nullptr;
+ }
+ }
+#endif
+ }
+
+ if (seat->cursor.wl_surface) {
+ wl_surface_destroy(seat->cursor.wl_surface);
+ seat->cursor.wl_surface = nullptr;
+ }
+ if (seat->cursor.wl_theme) {
+ wl_cursor_theme_destroy(seat->cursor.wl_theme);
+ seat->cursor.wl_theme = nullptr;
+ }
+
+ wl_pointer_destroy(seat->wl_pointer);
+ seat->wl_pointer = nullptr;
+}
+
+static void gwl_seat_capability_keyboard_enable(GWL_Seat *seat)
+{
+ if (seat->wl_keyboard) {
+ return;
+ }
+ seat->wl_keyboard = wl_seat_get_keyboard(seat->wl_seat);
+ wl_keyboard_add_listener(seat->wl_keyboard, &keyboard_listener, seat);
+}
+
+static void gwl_seat_capability_keyboard_disable(GWL_Seat *seat)
+{
+ if (!seat->wl_keyboard) {
+ return;
+ }
+ if (seat->key_repeat.timer) {
+ keyboard_handle_key_repeat_cancel(seat);
+ }
+ wl_keyboard_destroy(seat->wl_keyboard);
+ seat->wl_keyboard = nullptr;
+}
+
+static void gwl_seat_capability_touch_enable(GWL_Seat *seat)
+{
+ if (seat->wl_touch) {
+ return;
+ }
+ seat->wl_touch = wl_seat_get_touch(seat->wl_seat);
+ wl_touch_set_user_data(seat->wl_touch, seat);
+ wl_touch_add_listener(seat->wl_touch, &touch_seat_listener, seat);
+}
+
+static void gwl_seat_capability_touch_disable(GWL_Seat *seat)
+{
+ if (!seat->wl_touch) {
+ return;
+ }
+ wl_touch_destroy(seat->wl_touch);
+ seat->wl_touch = nullptr;
+}
+
static void seat_handle_capabilities(void *data,
struct wl_seat *wl_seat,
const uint32_t capabilities)
@@ -2648,27 +3715,43 @@ static void seat_handle_capabilities(void *data,
(capabilities & WL_SEAT_CAPABILITY_TOUCH) != 0);
GWL_Seat *seat = static_cast<GWL_Seat *>(data);
- seat->wl_pointer = nullptr;
- seat->wl_keyboard = nullptr;
+ GHOST_ASSERT(seat->wl_seat == wl_seat, "Seat mismatch");
if (capabilities & WL_SEAT_CAPABILITY_POINTER) {
- seat->wl_pointer = wl_seat_get_pointer(wl_seat);
- seat->cursor.wl_surface = wl_compositor_create_surface(seat->system->compositor());
- seat->cursor.visible = true;
- seat->cursor.wl_buffer = nullptr;
- if (!get_cursor_settings(seat->cursor.theme_name, seat->cursor.size)) {
- seat->cursor.theme_name = std::string();
- seat->cursor.size = default_cursor_size;
- }
- wl_pointer_add_listener(seat->wl_pointer, &pointer_listener, data);
-
- wl_surface_add_listener(seat->cursor.wl_surface, &cursor_surface_listener, data);
- ghost_wl_surface_tag_cursor_pointer(seat->cursor.wl_surface);
+ gwl_seat_capability_pointer_enable(seat);
+ }
+ else {
+ gwl_seat_capability_pointer_disable(seat);
}
if (capabilities & WL_SEAT_CAPABILITY_KEYBOARD) {
- seat->wl_keyboard = wl_seat_get_keyboard(wl_seat);
- wl_keyboard_add_listener(seat->wl_keyboard, &keyboard_listener, data);
+ gwl_seat_capability_keyboard_enable(seat);
+ }
+ else {
+ gwl_seat_capability_keyboard_disable(seat);
+ }
+
+ if (capabilities & WL_SEAT_CAPABILITY_TOUCH) {
+ gwl_seat_capability_touch_enable(seat);
+ }
+ else {
+ gwl_seat_capability_touch_disable(seat);
+ }
+
+ /* TODO(@campbellbarton): this could be moved out elsewhere. */
+ if (seat->system) {
+ zwp_primary_selection_device_manager_v1 *primary_selection_device_manager =
+ seat->system->wp_primary_selection_manager();
+ if (primary_selection_device_manager) {
+ if (seat->wp_primary_selection_device == nullptr) {
+ seat->wp_primary_selection_device = zwp_primary_selection_device_manager_v1_get_device(
+ primary_selection_device_manager, seat->wl_seat);
+
+ zwp_primary_selection_device_v1_add_listener(seat->wp_primary_selection_device,
+ &primary_selection_device_listener,
+ &seat->primary_selection);
+ }
+ }
}
}
@@ -2903,10 +3986,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 +4001,7 @@ static const struct xdg_wm_base_listener shell_listener = {
shell_handle_ping,
};
-# undef LOG
-
-#endif /* !WITH_GHOST_WAYLAND_LIBDECOR. */
+#undef LOG
/** \} */
@@ -2975,22 +4054,20 @@ static void global_handle_add(void *data,
struct GWL_Display *display = static_cast<struct GWL_Display *>(data);
if (STREQ(interface, wl_compositor_interface.name)) {
- display->compositor = static_cast<wl_compositor *>(
+ display->wl_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 *>(
+ GWL_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 *>(
+ GWL_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));
@@ -3027,27 +4104,46 @@ static void global_handle_add(void *data,
wl_seat_add_listener(seat->wl_seat, &seat_listener, seat);
}
else if (STREQ(interface, wl_shm_interface.name)) {
- display->shm = static_cast<wl_shm *>(
+ display->wl_shm = static_cast<wl_shm *>(
wl_registry_bind(wl_registry, name, &wl_shm_interface, 1));
}
else if (STREQ(interface, wl_data_device_manager_interface.name)) {
- display->data_device_manager = static_cast<wl_data_device_manager *>(
+ display->wl_data_device_manager = static_cast<wl_data_device_manager *>(
wl_registry_bind(wl_registry, name, &wl_data_device_manager_interface, 3));
}
else if (STREQ(interface, zwp_tablet_manager_v2_interface.name)) {
- display->tablet_manager = static_cast<zwp_tablet_manager_v2 *>(
+ display->wp_tablet_manager = static_cast<zwp_tablet_manager_v2 *>(
wl_registry_bind(wl_registry, name, &zwp_tablet_manager_v2_interface, 1));
}
else if (STREQ(interface, zwp_relative_pointer_manager_v1_interface.name)) {
- display->relative_pointer_manager = static_cast<zwp_relative_pointer_manager_v1 *>(
+ display->wp_relative_pointer_manager = static_cast<zwp_relative_pointer_manager_v1 *>(
wl_registry_bind(wl_registry, name, &zwp_relative_pointer_manager_v1_interface, 1));
}
else if (STREQ(interface, zwp_pointer_constraints_v1_interface.name)) {
- display->pointer_constraints = static_cast<zwp_pointer_constraints_v1 *>(
+ display->wp_pointer_constraints = static_cast<zwp_pointer_constraints_v1 *>(
wl_registry_bind(wl_registry, name, &zwp_pointer_constraints_v1_interface, 1));
}
+ else if (STREQ(interface, zwp_pointer_gestures_v1_interface.name)) {
+ display->wp_pointer_gestures = static_cast<zwp_pointer_gestures_v1 *>(
+ wl_registry_bind(wl_registry, name, &zwp_pointer_gestures_v1_interface, 3));
+ }
+
+ else if (!strcmp(interface, zwp_primary_selection_device_manager_v1_interface.name)) {
+ display->wp_primary_selection_device_manager =
+ static_cast<zwp_primary_selection_device_manager_v1 *>(wl_registry_bind(
+ wl_registry, name, &zwp_primary_selection_device_manager_v1_interface, 1));
+ }
+
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,
@@ -3090,60 +4186,103 @@ static const struct wl_registry_listener registry_listener = {
* WAYLAND specific implementation of the #GHOST_System interface.
* \{ */
-GHOST_SystemWayland::GHOST_SystemWayland() : GHOST_System(), d(new GWL_Display)
+GHOST_SystemWayland::GHOST_SystemWayland(bool background)
+ : GHOST_System(), display_(new GWL_Display)
{
wl_log_set_handler_client(ghost_wayland_log_handler);
- d->system = this;
+ display_->system = this;
/* Connect to the Wayland server. */
- d->display = wl_display_connect(nullptr);
- if (!d->display) {
- display_destroy(d);
+ display_->wl_display = wl_display_connect(nullptr);
+ if (!display_->wl_display) {
+ display_destroy(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. */
+ display_->xdg_decor = new GWL_XDG_Decor_System;
+
/* Register interfaces. */
- struct wl_registry *registry = wl_display_get_registry(d->display);
- wl_registry_add_listener(registry, &registry_listener, d);
+ struct wl_registry *registry = wl_display_get_registry(display_->wl_display);
+ wl_registry_add_listener(registry, &registry_listener, display_);
/* Call callback for registry listener. */
- wl_display_roundtrip(d->display);
+ wl_display_roundtrip(display_->wl_display);
/* Call callbacks for registered listeners. */
- wl_display_roundtrip(d->display);
+ wl_display_roundtrip(display_->wl_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!");
+ /* Ignore windowing requirements when running in background mode,
+ * as it doesn't make sense to fall back to X11 because of windowing functionality
+ * in background mode, also LIBDECOR is crashing in background mode `blender -b -f 1`
+ * for e.g. while it could be fixed, requiring the library at all makes no sense . */
+ if (background) {
+ display_->libdecor_required = false;
}
-#else
- if (!d->xdg_shell) {
- display_destroy(d);
- throw std::runtime_error("Wayland: unable to access xdg_shell!");
+
+ if (display_->libdecor_required) {
+ gwl_xdg_decor_system_destroy(display_->xdg_decor);
+ display_->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(display_);
+ throw std::runtime_error("Wayland: unable to find libdecor!");
+
+ use_libdecor = true;
+ }
+ }
+ else {
+ use_libdecor = false;
+ }
+#endif /* WITH_GHOST_WAYLAND_LIBDECOR */
+
+#ifdef WITH_GHOST_WAYLAND_LIBDECOR
+ if (use_libdecor) {
+ display_->libdecor = new GWL_LibDecor_System;
+ GWL_LibDecor_System &decor = *display_->libdecor;
+ decor.context = libdecor_new(display_->wl_display, &libdecor_interface);
+ if (!decor.context) {
+ display_destroy(display_);
+ throw std::runtime_error("Wayland: unable to create window decorations!");
+ }
}
+ else
#endif
+ {
+ GWL_XDG_Decor_System &decor = *display_->xdg_decor;
+ if (!decor.shell) {
+ display_destroy(display_);
+ 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) {
- for (GWL_Seat *seat : d->seats) {
- seat->data_device = wl_data_device_manager_get_data_device(d->data_device_manager,
- seat->wl_seat);
- wl_data_device_add_listener(seat->data_device, &data_device_listener, seat);
+ if (display_->wl_data_device_manager) {
+ for (GWL_Seat *seat : display_->seats) {
+ seat->wl_data_device = wl_data_device_manager_get_data_device(
+ display_->wl_data_device_manager, seat->wl_seat);
+ wl_data_device_add_listener(seat->wl_data_device, &data_device_listener, seat);
}
}
- if (d->tablet_manager) {
- for (GWL_Seat *seat : d->seats) {
- seat->tablet_seat = zwp_tablet_manager_v2_get_tablet_seat(d->tablet_manager, seat->wl_seat);
- zwp_tablet_seat_v2_add_listener(seat->tablet_seat, &tablet_seat_listener, seat);
+ if (display_->wp_tablet_manager) {
+ for (GWL_Seat *seat : display_->seats) {
+ seat->wp_tablet_seat = zwp_tablet_manager_v2_get_tablet_seat(display_->wp_tablet_manager,
+ seat->wl_seat);
+ zwp_tablet_seat_v2_add_listener(seat->wp_tablet_seat, &tablet_seat_listener, seat);
}
}
}
GHOST_SystemWayland::~GHOST_SystemWayland()
{
- display_destroy(d);
+ display_destroy(display_);
}
GHOST_TSuccess GHOST_SystemWayland::init()
@@ -3178,10 +4317,10 @@ bool GHOST_SystemWayland::processEvents(bool waitForEvent)
#endif /* WITH_INPUT_NDOF */
if (waitForEvent) {
- wl_display_dispatch(d->display);
+ wl_display_dispatch(display_->wl_display);
}
else {
- wl_display_roundtrip(d->display);
+ wl_display_roundtrip(display_->wl_display);
}
if (getEventManager()->getNumEvents() > 0) {
@@ -3198,11 +4337,11 @@ bool GHOST_SystemWayland::setConsoleWindowState(GHOST_TConsoleWindowState /*acti
GHOST_TSuccess GHOST_SystemWayland::getModifierKeys(GHOST_ModifierKeys &keys) const
{
- if (UNLIKELY(d->seats.empty())) {
+ if (UNLIKELY(display_->seats.empty())) {
return GHOST_kFailure;
}
- GWL_Seat *seat = d->seats[0];
+ GWL_Seat *seat = display_->seats[0];
const xkb_mod_mask_t state = xkb_state_serialize_mods(seat->xkb_state, XKB_STATE_MODS_DEPRESSED);
@@ -3215,7 +4354,7 @@ GHOST_TSuccess GHOST_SystemWayland::getModifierKeys(GHOST_ModifierKeys &keys) co
}
#endif
- /* Use local #WGL_KeyboardDepressedState to check which key is pressed.
+ /* Use local #GWL_KeyboardDepressedState to check which key is pressed.
* Use XKB as the source of truth, if there is any discrepancy. */
for (int i = 0; i < MOD_INDEX_NUM; i++) {
if (UNLIKELY(seat->xkb_keymap_mod_index[i] == XKB_MOD_INVALID)) {
@@ -3260,10 +4399,10 @@ GHOST_TSuccess GHOST_SystemWayland::getModifierKeys(GHOST_ModifierKeys &keys) co
GHOST_TSuccess GHOST_SystemWayland::getButtons(GHOST_Buttons &buttons) const
{
- if (UNLIKELY(d->seats.empty())) {
+ if (UNLIKELY(display_->seats.empty())) {
return GHOST_kFailure;
}
- GWL_Seat *seat = d->seats[0];
+ GWL_Seat *seat = display_->seats[0];
GWL_SeatStatePointer *seat_state_pointer = seat_state_pointer_active(seat);
if (!seat_state_pointer) {
return GHOST_kFailure;
@@ -3273,48 +4412,92 @@ GHOST_TSuccess GHOST_SystemWayland::getButtons(GHOST_Buttons &buttons) const
return GHOST_kSuccess;
}
-char *GHOST_SystemWayland::getClipboard(bool /*selection*/) const
+char *GHOST_SystemWayland::getClipboard(bool selection) const
{
- char *clipboard = static_cast<char *>(malloc(selection.size() + 1));
- memcpy(clipboard, selection.data(), selection.size() + 1);
- return clipboard;
+ const GWL_SimpleBuffer *buf = clipboard_data(selection);
+ if (buf->data == nullptr) {
+ return nullptr;
+ }
+ return gwl_simple_buffer_as_string(buf);
}
-void GHOST_SystemWayland::putClipboard(const char *buffer, bool /*selection*/) const
+static void system_clipboard_put_primary_selection(GWL_Display *display, const char *buffer)
{
- if (UNLIKELY(!d->data_device_manager || d->seats.empty())) {
+ if (!display->wp_primary_selection_device_manager) {
return;
}
+ GWL_Seat *seat = display->seats[0];
+ GWL_PrimarySelection *primary = &seat->primary_selection;
+
+ std::lock_guard lock{primary->data_source_mutex};
+
+ gwl_primary_selection_discard_source(primary);
+
+ GWL_PrimarySelection_DataSource *data_source = new GWL_PrimarySelection_DataSource;
+ primary->data_source = data_source;
+
+ /* Copy buffer. */
+ gwl_simple_buffer_set_from_string(&data_source->buffer_out, buffer);
+
+ data_source->wp_source = zwp_primary_selection_device_manager_v1_create_source(
+ display->wp_primary_selection_device_manager);
+
+ zwp_primary_selection_source_v1_add_listener(
+ data_source->wp_source, &primary_selection_source_listener, primary);
+
+ for (const std::string &type : mime_send) {
+ zwp_primary_selection_source_v1_offer(data_source->wp_source, type.c_str());
+ }
- GWL_Seat *seat = d->seats[0];
+ if (seat->wp_primary_selection_device) {
+ zwp_primary_selection_device_v1_set_selection(
+ seat->wp_primary_selection_device, data_source->wp_source, seat->data_source_serial);
+ }
+}
+
+static void system_clipboard_put(GWL_Display *display, const char *buffer)
+{
+ GWL_Seat *seat = display->seats[0];
std::lock_guard lock{seat->data_source_mutex};
GWL_DataSource *data_source = seat->data_source;
/* Copy buffer. */
- free(data_source->buffer_out);
- const size_t buffer_size = strlen(buffer) + 1;
- data_source->buffer_out = static_cast<char *>(malloc(buffer_size));
- std::memcpy(data_source->buffer_out, buffer, buffer_size);
+ gwl_simple_buffer_set_from_string(&data_source->buffer_out, buffer);
- data_source->data_source = wl_data_device_manager_create_data_source(d->data_device_manager);
+ data_source->wl_source = wl_data_device_manager_create_data_source(
+ display->wl_data_device_manager);
- wl_data_source_add_listener(data_source->data_source, &data_source_listener, seat);
+ wl_data_source_add_listener(data_source->wl_source, &data_source_listener, seat);
for (const std::string &type : mime_send) {
- wl_data_source_offer(data_source->data_source, type.c_str());
+ wl_data_source_offer(data_source->wl_source, type.c_str());
}
- if (seat->data_device) {
+ if (seat->wl_data_device) {
wl_data_device_set_selection(
- seat->data_device, data_source->data_source, seat->data_source_serial);
+ seat->wl_data_device, data_source->wl_source, seat->data_source_serial);
+ }
+}
+
+void GHOST_SystemWayland::putClipboard(const char *buffer, bool selection) const
+{
+ if (UNLIKELY(!display_->wl_data_device_manager || display_->seats.empty())) {
+ return;
+ }
+
+ if (selection) {
+ system_clipboard_put_primary_selection(display_, buffer);
+ }
+ else {
+ system_clipboard_put(display_, buffer);
}
}
uint8_t GHOST_SystemWayland::getNumDisplays() const
{
- return d ? uint8_t(d->outputs.size()) : 0;
+ return display_ ? uint8_t(display_->outputs.size()) : 0;
}
static GHOST_TSuccess getCursorPositionClientRelative_impl(
@@ -3337,7 +4520,7 @@ static GHOST_TSuccess setCursorPositionClientRelative_impl(GWL_Seat *seat,
/* NOTE: WAYLAND doesn't support warping the cursor.
* However when grab is enabled, we already simulate a cursor location
* so that can be set to a new location. */
- if (!seat->relative_pointer) {
+ if (!seat->wp_relative_pointer) {
return GHOST_kFailure;
}
const wl_fixed_t scale = win->scale();
@@ -3356,10 +4539,10 @@ GHOST_TSuccess GHOST_SystemWayland::getCursorPositionClientRelative(const GHOST_
int32_t &x,
int32_t &y) const
{
- if (UNLIKELY(d->seats.empty())) {
+ if (UNLIKELY(display_->seats.empty())) {
return GHOST_kFailure;
}
- GWL_Seat *seat = d->seats[0];
+ GWL_Seat *seat = display_->seats[0];
GWL_SeatStatePointer *seat_state_pointer = seat_state_pointer_active(seat);
if (!seat_state_pointer || !seat_state_pointer->wl_surface) {
return GHOST_kFailure;
@@ -3372,20 +4555,20 @@ GHOST_TSuccess GHOST_SystemWayland::setCursorPositionClientRelative(GHOST_IWindo
const int32_t x,
const int32_t y)
{
- if (UNLIKELY(d->seats.empty())) {
+ if (UNLIKELY(display_->seats.empty())) {
return GHOST_kFailure;
}
- GWL_Seat *seat = d->seats[0];
+ GWL_Seat *seat = display_->seats[0];
GHOST_WindowWayland *win = static_cast<GHOST_WindowWayland *>(window);
return setCursorPositionClientRelative_impl(seat, win, x, y);
}
GHOST_TSuccess GHOST_SystemWayland::getCursorPosition(int32_t &x, int32_t &y) const
{
- if (UNLIKELY(d->seats.empty())) {
+ if (UNLIKELY(display_->seats.empty())) {
return GHOST_kFailure;
}
- GWL_Seat *seat = d->seats[0];
+ GWL_Seat *seat = display_->seats[0];
GWL_SeatStatePointer *seat_state_pointer = seat_state_pointer_active(seat);
if (!seat_state_pointer) {
return GHOST_kFailure;
@@ -3400,10 +4583,10 @@ GHOST_TSuccess GHOST_SystemWayland::getCursorPosition(int32_t &x, int32_t &y) co
GHOST_TSuccess GHOST_SystemWayland::setCursorPosition(const int32_t x, const int32_t y)
{
- if (UNLIKELY(d->seats.empty())) {
+ if (UNLIKELY(display_->seats.empty())) {
return GHOST_kFailure;
}
- GWL_Seat *seat = d->seats[0];
+ GWL_Seat *seat = display_->seats[0];
/* Intentionally different from `getCursorPosition` which supports both tablet & pointer.
* In the case of setting the cursor location, tablets don't support this. */
@@ -3420,8 +4603,8 @@ void GHOST_SystemWayland::getMainDisplayDimensions(uint32_t &width, uint32_t &he
return;
}
/* We assume first output as main. */
- width = uint32_t(d->outputs[0]->size_native[0]);
- height = uint32_t(d->outputs[0]->size_native[1]);
+ width = uint32_t(display_->outputs[0]->size_native[0]);
+ height = uint32_t(display_->outputs[0]->size_native[1]);
}
void GHOST_SystemWayland::getAllDisplayDimensions(uint32_t &width, uint32_t &height) const
@@ -3429,7 +4612,7 @@ void GHOST_SystemWayland::getAllDisplayDimensions(uint32_t &width, uint32_t &hei
int32_t xy_min[2] = {INT32_MAX, INT32_MAX};
int32_t xy_max[2] = {INT32_MIN, INT32_MIN};
- for (const GWL_Output *output : d->outputs) {
+ for (const GWL_Output *output : display_->outputs) {
int32_t xy[2] = {0, 0};
if (output->has_position_logical) {
xy[0] = output->position_logical[0];
@@ -3490,10 +4673,10 @@ static GHOST_Context *createOffscreenContext_impl(GHOST_SystemWayland *system,
GHOST_IContext *GHOST_SystemWayland::createOffscreenContext(GHOST_GLSettings /*glSettings*/)
{
/* Create new off-screen window. */
- wl_surface *wl_surface = wl_compositor_create_surface(compositor());
+ wl_surface *wl_surface = wl_compositor_create_surface(wl_compositor());
wl_egl_window *egl_window = wl_surface ? wl_egl_window_create(wl_surface, 1, 1) : nullptr;
- GHOST_Context *context = createOffscreenContext_impl(this, d->display, egl_window);
+ GHOST_Context *context = createOffscreenContext_impl(this, display_->wl_display, egl_window);
if (!context) {
GHOST_PRINT("Cannot create off-screen EGL context" << std::endl);
@@ -3530,7 +4713,6 @@ GHOST_IWindow *GHOST_SystemWayland::createWindow(const char *title,
const uint32_t width,
const uint32_t height,
const GHOST_TWindowState state,
- const GHOST_TDrawingContextType type,
const GHOST_GLSettings glSettings,
const bool exclusive,
const bool is_dialog,
@@ -3550,7 +4732,7 @@ GHOST_IWindow *GHOST_SystemWayland::createWindow(const char *title,
height,
state,
parentWindow,
- type,
+ glSettings.context_type,
is_dialog,
((glSettings.flags & GHOST_glStereoVisual) != 0),
exclusive);
@@ -3578,22 +4760,22 @@ GHOST_IWindow *GHOST_SystemWayland::createWindow(const char *title,
*/
static void cursor_buffer_show(const GWL_Seat *seat)
{
- const GWL_Cursor *c = &seat->cursor;
+ const GWL_Cursor *cursor = &seat->cursor;
if (seat->wl_pointer) {
- const int scale = c->is_custom ? c->custom_scale : seat->pointer.theme_scale;
- const int32_t hotspot_x = int32_t(c->wl_image.hotspot_x) / scale;
- const int32_t hotspot_y = int32_t(c->wl_image.hotspot_y) / scale;
+ const int scale = cursor->is_custom ? cursor->custom_scale : seat->pointer.theme_scale;
+ const int32_t hotspot_x = int32_t(cursor->wl_image.hotspot_x) / scale;
+ const int32_t hotspot_y = int32_t(cursor->wl_image.hotspot_y) / scale;
if (seat->wl_pointer) {
wl_pointer_set_cursor(
- seat->wl_pointer, seat->pointer.serial, c->wl_surface, hotspot_x, hotspot_y);
+ seat->wl_pointer, seat->pointer.serial, cursor->wl_surface, hotspot_x, hotspot_y);
}
}
if (!seat->tablet_tools.empty()) {
- const int scale = c->is_custom ? c->custom_scale : seat->tablet.theme_scale;
- const int32_t hotspot_x = int32_t(c->wl_image.hotspot_x) / scale;
- const int32_t hotspot_y = int32_t(c->wl_image.hotspot_y) / scale;
+ const int scale = cursor->is_custom ? cursor->custom_scale : seat->tablet.theme_scale;
+ const int32_t hotspot_x = int32_t(cursor->wl_image.hotspot_x) / scale;
+ const int32_t hotspot_y = int32_t(cursor->wl_image.hotspot_y) / scale;
for (struct zwp_tablet_tool_v2 *zwp_tablet_tool_v2 : seat->tablet_tools) {
GWL_TabletTool *tablet_tool = static_cast<GWL_TabletTool *>(
zwp_tablet_tool_v2_get_user_data(zwp_tablet_tool_v2));
@@ -3656,21 +4838,21 @@ static void cursor_buffer_set_surface_impl(const GWL_Seat *seat,
static void cursor_buffer_set(const GWL_Seat *seat, wl_buffer *buffer)
{
- const GWL_Cursor *c = &seat->cursor;
+ const GWL_Cursor *cursor = &seat->cursor;
const wl_cursor_image *wl_image = &seat->cursor.wl_image;
- const bool visible = (c->visible && c->is_hardware);
+ const bool visible = (cursor->visible && cursor->is_hardware);
/* This is a requirement of WAYLAND, when this isn't the case,
* it causes Blender's window to close intermittently. */
if (seat->wl_pointer) {
const int scale = cursor_buffer_compatible_scale_from_image(
- wl_image, c->is_custom ? c->custom_scale : seat->pointer.theme_scale);
+ wl_image, cursor->is_custom ? cursor->custom_scale : seat->pointer.theme_scale);
const int32_t hotspot_x = int32_t(wl_image->hotspot_x) / scale;
const int32_t hotspot_y = int32_t(wl_image->hotspot_y) / scale;
- cursor_buffer_set_surface_impl(seat, buffer, c->wl_surface, scale);
+ cursor_buffer_set_surface_impl(seat, buffer, cursor->wl_surface, scale);
wl_pointer_set_cursor(seat->wl_pointer,
seat->pointer.serial,
- visible ? c->wl_surface : nullptr,
+ visible ? cursor->wl_surface : nullptr,
hotspot_x,
hotspot_y);
}
@@ -3678,7 +4860,7 @@ static void cursor_buffer_set(const GWL_Seat *seat, wl_buffer *buffer)
/* Set the cursor for all tablet tools as well. */
if (!seat->tablet_tools.empty()) {
const int scale = cursor_buffer_compatible_scale_from_image(
- wl_image, c->is_custom ? c->custom_scale : seat->tablet.theme_scale);
+ wl_image, cursor->is_custom ? cursor->custom_scale : seat->tablet.theme_scale);
const int32_t hotspot_x = int32_t(wl_image->hotspot_x) / scale;
const int32_t hotspot_y = int32_t(wl_image->hotspot_y) / scale;
for (struct zwp_tablet_tool_v2 *zwp_tablet_tool_v2 : seat->tablet_tools) {
@@ -3756,7 +4938,7 @@ static bool cursor_is_software(const GHOST_TGrabCursorMode mode, const bool use_
GHOST_TSuccess GHOST_SystemWayland::setCursorShape(const GHOST_TStandardCursor shape)
{
- if (UNLIKELY(d->seats.empty())) {
+ if (UNLIKELY(display_->seats.empty())) {
return GHOST_kFailure;
}
auto cursor_find = cursors.find(shape);
@@ -3764,31 +4946,32 @@ GHOST_TSuccess GHOST_SystemWayland::setCursorShape(const GHOST_TStandardCursor s
cursors.at(GHOST_kStandardCursorDefault) :
(*cursor_find).second;
- GWL_Seat *seat = d->seats[0];
- GWL_Cursor *c = &seat->cursor;
+ GWL_Seat *seat = display_->seats[0];
+ GWL_Cursor *cursor = &seat->cursor;
- if (!c->wl_theme) {
+ if (!cursor->wl_theme) {
/* The cursor wl_surface hasn't entered an output yet. Initialize theme with scale 1. */
- c->wl_theme = wl_cursor_theme_load(c->theme_name.c_str(), c->size, d->seats[0]->system->shm());
+ cursor->wl_theme = wl_cursor_theme_load(
+ cursor->theme_name.c_str(), cursor->theme_size, wl_shm());
}
- wl_cursor *cursor = wl_cursor_theme_get_cursor(c->wl_theme, cursor_name);
+ wl_cursor *wl_cursor = wl_cursor_theme_get_cursor(cursor->wl_theme, cursor_name);
- if (!cursor) {
+ if (!wl_cursor) {
GHOST_PRINT("cursor '" << cursor_name << "' does not exist" << std::endl);
return GHOST_kFailure;
}
- struct wl_cursor_image *image = cursor->images[0];
+ struct wl_cursor_image *image = wl_cursor->images[0];
struct wl_buffer *buffer = wl_cursor_image_get_buffer(image);
if (!buffer) {
return GHOST_kFailure;
}
- c->visible = true;
- c->is_custom = false;
- c->wl_buffer = buffer;
- c->wl_image = *image;
+ cursor->visible = true;
+ cursor->is_custom = false;
+ cursor->wl_buffer = buffer;
+ cursor->wl_image = *image;
cursor_buffer_set(seat, buffer);
@@ -3816,11 +4999,11 @@ GHOST_TSuccess GHOST_SystemWayland::setCustomCursorShape(uint8_t *bitmap,
const int hotY,
const bool /*canInvertColor*/)
{
- if (UNLIKELY(d->seats.empty())) {
+ if (UNLIKELY(display_->seats.empty())) {
return GHOST_kFailure;
}
- GWL_Cursor *cursor = &d->seats[0]->cursor;
+ GWL_Cursor *cursor = &display_->seats[0]->cursor;
if (cursor->custom_data) {
munmap(cursor->custom_data, cursor->custom_data_size);
@@ -3829,8 +5012,11 @@ GHOST_TSuccess GHOST_SystemWayland::setCustomCursorShape(uint8_t *bitmap,
}
const int32_t size_xy[2] = {sizex, sizey};
- wl_buffer *buffer = ghost_wl_buffer_create_for_image(
- d->shm, size_xy, WL_SHM_FORMAT_ARGB8888, &cursor->custom_data, &cursor->custom_data_size);
+ wl_buffer *buffer = ghost_wl_buffer_create_for_image(display_->wl_shm,
+ size_xy,
+ WL_SHM_FORMAT_ARGB8888,
+ &cursor->custom_data,
+ &cursor->custom_data_size);
if (buffer == nullptr) {
return GHOST_kFailure;
}
@@ -3876,14 +5062,14 @@ GHOST_TSuccess GHOST_SystemWayland::setCustomCursorShape(uint8_t *bitmap,
cursor->wl_image.hotspot_x = uint32_t(hotX);
cursor->wl_image.hotspot_y = uint32_t(hotY);
- cursor_buffer_set(d->seats[0], buffer);
+ cursor_buffer_set(display_->seats[0], buffer);
return GHOST_kSuccess;
}
GHOST_TSuccess GHOST_SystemWayland::getCursorBitmap(GHOST_CursorBitmapRef *bitmap)
{
- GWL_Cursor *cursor = &d->seats[0]->cursor;
+ GWL_Cursor *cursor = &display_->seats[0]->cursor;
if (cursor->custom_data == nullptr) {
return GHOST_kFailure;
}
@@ -3904,11 +5090,11 @@ GHOST_TSuccess GHOST_SystemWayland::getCursorBitmap(GHOST_CursorBitmapRef *bitma
GHOST_TSuccess GHOST_SystemWayland::setCursorVisibility(const bool visible)
{
- if (UNLIKELY(d->seats.empty())) {
+ if (UNLIKELY(display_->seats.empty())) {
return GHOST_kFailure;
}
- GWL_Seat *seat = d->seats[0];
+ GWL_Seat *seat = display_->seats[0];
cursor_visible_set(seat, visible, seat->cursor.is_hardware, CURSOR_VISIBLE_ALWAYS_SET);
return GHOST_kSuccess;
}
@@ -3928,12 +5114,12 @@ bool GHOST_SystemWayland::supportsWindowPosition()
bool GHOST_SystemWayland::getCursorGrabUseSoftwareDisplay(const GHOST_TGrabCursorMode mode)
{
- if (UNLIKELY(d->seats.empty())) {
+ if (UNLIKELY(display_->seats.empty())) {
return false;
}
#ifdef USE_GNOME_CONFINE_HACK
- GWL_Seat *seat = d->seats[0];
+ GWL_Seat *seat = display_->seats[0];
const bool use_software_confine = seat->use_pointer_software_confine;
#else
const bool use_software_confine = false;
@@ -3972,11 +5158,10 @@ static GWL_SeatStateGrab seat_grab_state_from_mode(const GHOST_TGrabCursorMode m
const bool use_software_confine)
{
/* Initialize all members. */
- const struct GWL_SeatStateGrab grab_state = {
- /* Warping happens to require software cursor which also hides. */
- .use_lock = ELEM(mode, GHOST_kGrabWrap, GHOST_kGrabHide) || use_software_confine,
- .use_confine = (mode == GHOST_kGrabNormal) && (use_software_confine == false),
- };
+ GWL_SeatStateGrab grab_state;
+ /* Warping happens to require software cursor which also hides. */
+ grab_state.use_lock = ELEM(mode, GHOST_kGrabWrap, GHOST_kGrabHide) || use_software_confine;
+ grab_state.use_confine = (mode == GHOST_kGrabNormal) && (use_software_confine == false);
return grab_state;
}
@@ -4040,45 +5225,55 @@ void ghost_wl_surface_tag_cursor_tablet(struct wl_surface *wl_surface)
* Expose some members via methods.
* \{ */
-wl_display *GHOST_SystemWayland::display()
+wl_display *GHOST_SystemWayland::wl_display()
+{
+ return display_->wl_display;
+}
+
+wl_compositor *GHOST_SystemWayland::wl_compositor()
+{
+ return display_->wl_compositor;
+}
+
+struct zwp_primary_selection_device_manager_v1 *GHOST_SystemWayland::wp_primary_selection_manager()
{
- return d->display;
+ return display_->wp_primary_selection_device_manager;
}
-wl_compositor *GHOST_SystemWayland::compositor()
+struct zwp_pointer_gestures_v1 *GHOST_SystemWayland::wp_pointer_gestures()
{
- return d->compositor;
+ return display_->wp_pointer_gestures;
}
#ifdef WITH_GHOST_WAYLAND_LIBDECOR
-libdecor *GHOST_SystemWayland::decor_context()
+libdecor *GHOST_SystemWayland::libdecor_context()
{
- return d->decor_context;
+ return display_->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 display_->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 display_->xdg_decor->manager;
}
-#endif /* !WITH_GHOST_WAYLAND_LIBDECOR */
+/* End `xdg_decor`. */
const std::vector<GWL_Output *> &GHOST_SystemWayland::outputs() const
{
- return d->outputs;
+ return display_->outputs;
}
-wl_shm *GHOST_SystemWayland::shm() const
+struct wl_shm *GHOST_SystemWayland::wl_shm() const
{
- return d->shm;
+ return display_->wl_shm;
}
/** \} */
@@ -4112,11 +5307,6 @@ GHOST_WindowWayland *ghost_wl_surface_user_data(struct wl_surface *wl_surface)
* Functionality only used for the WAYLAND implementation.
* \{ */
-void GHOST_SystemWayland::selection_set(const std::string &selection)
-{
- this->selection = selection;
-}
-
void GHOST_SystemWayland::window_surface_unref(const wl_surface *wl_surface)
{
#define SURFACE_CLEAR_PTR(surface_test) \
@@ -4126,7 +5316,7 @@ void GHOST_SystemWayland::window_surface_unref(const wl_surface *wl_surface)
((void)0);
/* Only clear window surfaces (not cursors, off-screen surfaces etc). */
- for (GWL_Seat *seat : d->seats) {
+ for (GWL_Seat *seat : display_->seats) {
SURFACE_CLEAR_PTR(seat->pointer.wl_surface);
SURFACE_CLEAR_PTR(seat->tablet.wl_surface);
SURFACE_CLEAR_PTR(seat->keyboard.wl_surface);
@@ -4144,11 +5334,11 @@ bool GHOST_SystemWayland::window_cursor_grab_set(const GHOST_TGrabCursorMode mod
const int scale)
{
/* Ignore, if the required protocols are not supported. */
- if (UNLIKELY(!d->relative_pointer_manager || !d->pointer_constraints)) {
+ if (UNLIKELY(!display_->wp_relative_pointer_manager || !display_->wp_pointer_constraints)) {
return GHOST_kFailure;
}
- if (UNLIKELY(d->seats.empty())) {
+ if (UNLIKELY(display_->seats.empty())) {
return GHOST_kFailure;
}
/* No change, success. */
@@ -4156,7 +5346,7 @@ bool GHOST_SystemWayland::window_cursor_grab_set(const GHOST_TGrabCursorMode mod
return GHOST_kSuccess;
}
- GWL_Seat *seat = d->seats[0];
+ GWL_Seat *seat = display_->seats[0];
#ifdef USE_GNOME_CONFINE_HACK
const bool was_software_confine = seat->use_pointer_software_confine;
@@ -4183,11 +5373,11 @@ bool GHOST_SystemWayland::window_cursor_grab_set(const GHOST_TGrabCursorMode mod
* in this case disable the current locks as it makes logic confusing,
* postpone changing the cursor to avoid flickering. */
if (!grab_state_next.use_lock) {
- if (seat->relative_pointer) {
- zwp_relative_pointer_v1_destroy(seat->relative_pointer);
- seat->relative_pointer = nullptr;
+ if (seat->wp_relative_pointer) {
+ zwp_relative_pointer_v1_destroy(seat->wp_relative_pointer);
+ seat->wp_relative_pointer = nullptr;
}
- if (seat->locked_pointer) {
+ if (seat->wp_locked_pointer) {
/* Potentially add a motion event so the application has updated X/Y coordinates. */
int32_t xy_motion[2] = {0, 0};
bool xy_motion_create_event = false;
@@ -4216,7 +5406,7 @@ bool GHOST_SystemWayland::window_cursor_grab_set(const GHOST_TGrabCursorMode mod
seat->pointer.xy[0] = xy_next[0];
seat->pointer.xy[1] = xy_next[1];
- zwp_locked_pointer_v1_set_cursor_position_hint(seat->locked_pointer, UNPACK2(xy_next));
+ zwp_locked_pointer_v1_set_cursor_position_hint(seat->wp_locked_pointer, UNPACK2(xy_next));
wl_surface_commit(wl_surface);
}
else if (mode_current == GHOST_kGrabHide) {
@@ -4226,7 +5416,8 @@ bool GHOST_SystemWayland::window_cursor_grab_set(const GHOST_TGrabCursorMode mod
wl_fixed_from_int(init_grab_xy[0]) / scale,
wl_fixed_from_int(init_grab_xy[1]) / scale,
};
- zwp_locked_pointer_v1_set_cursor_position_hint(seat->locked_pointer, UNPACK2(xy_next));
+ zwp_locked_pointer_v1_set_cursor_position_hint(seat->wp_locked_pointer,
+ UNPACK2(xy_next));
wl_surface_commit(wl_surface);
/* NOTE(@campbellbarton): The new cursor position is a hint,
@@ -4240,7 +5431,7 @@ bool GHOST_SystemWayland::window_cursor_grab_set(const GHOST_TGrabCursorMode mod
#ifdef USE_GNOME_CONFINE_HACK
else if (mode_current == GHOST_kGrabNormal) {
if (was_software_confine) {
- zwp_locked_pointer_v1_set_cursor_position_hint(seat->locked_pointer,
+ zwp_locked_pointer_v1_set_cursor_position_hint(seat->wp_locked_pointer,
UNPACK2(seat->pointer.xy));
wl_surface_commit(wl_surface);
}
@@ -4256,15 +5447,15 @@ bool GHOST_SystemWayland::window_cursor_grab_set(const GHOST_TGrabCursorMode mod
GHOST_TABLET_DATA_NONE));
}
- zwp_locked_pointer_v1_destroy(seat->locked_pointer);
- seat->locked_pointer = nullptr;
+ zwp_locked_pointer_v1_destroy(seat->wp_locked_pointer);
+ seat->wp_locked_pointer = nullptr;
}
}
if (!grab_state_next.use_confine) {
- if (seat->confined_pointer) {
- zwp_confined_pointer_v1_destroy(seat->confined_pointer);
- seat->confined_pointer = nullptr;
+ if (seat->wp_confined_pointer) {
+ zwp_confined_pointer_v1_destroy(seat->wp_confined_pointer);
+ seat->wp_confined_pointer = nullptr;
}
}
@@ -4275,12 +5466,12 @@ bool GHOST_SystemWayland::window_cursor_grab_set(const GHOST_TGrabCursorMode mod
* possible to support #GHOST_kGrabWrap by pragmatically settings it's coordinates.
* An alternative could be to draw the cursor in software (and hide the real cursor),
* or just accept a locked cursor on WAYLAND. */
- seat->relative_pointer = zwp_relative_pointer_manager_v1_get_relative_pointer(
- d->relative_pointer_manager, seat->wl_pointer);
+ seat->wp_relative_pointer = zwp_relative_pointer_manager_v1_get_relative_pointer(
+ display_->wp_relative_pointer_manager, seat->wl_pointer);
zwp_relative_pointer_v1_add_listener(
- seat->relative_pointer, &relative_pointer_listener, seat);
- seat->locked_pointer = zwp_pointer_constraints_v1_lock_pointer(
- d->pointer_constraints,
+ seat->wp_relative_pointer, &relative_pointer_listener, seat);
+ seat->wp_locked_pointer = zwp_pointer_constraints_v1_lock_pointer(
+ display_->wp_pointer_constraints,
wl_surface,
seat->wl_pointer,
nullptr,
@@ -4297,8 +5488,8 @@ bool GHOST_SystemWayland::window_cursor_grab_set(const GHOST_TGrabCursorMode mod
}
else if (grab_state_next.use_confine) {
if (!grab_state_prev.use_confine) {
- seat->confined_pointer = zwp_pointer_constraints_v1_confine_pointer(
- d->pointer_constraints,
+ seat->wp_confined_pointer = zwp_pointer_constraints_v1_confine_pointer(
+ display_->wp_pointer_constraints,
wl_surface,
seat->wl_pointer,
nullptr,
@@ -4317,35 +5508,57 @@ bool GHOST_SystemWayland::window_cursor_grab_set(const GHOST_TGrabCursorMode mod
return GHOST_kSuccess;
}
+struct GWL_SimpleBuffer *GHOST_SystemWayland::clipboard_data(bool selection) const
+{
+ return selection ? &display_->clipboard_primary : &display_->clipboard;
+}
+
+#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..c27f175002e 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 {
@@ -89,11 +84,12 @@ struct GWL_Output {
class GHOST_SystemWayland : public GHOST_System {
public:
- GHOST_SystemWayland();
+ GHOST_SystemWayland(bool background);
+ GHOST_SystemWayland() : GHOST_SystemWayland(true){};
~GHOST_SystemWayland() override;
- GHOST_TSuccess init();
+ GHOST_TSuccess init() override;
bool processEvents(bool waitForEvent) override;
@@ -133,7 +129,6 @@ class GHOST_SystemWayland : public GHOST_System {
uint32_t width,
uint32_t height,
GHOST_TWindowState state,
- GHOST_TDrawingContextType type,
GHOST_GLSettings glSettings,
const bool exclusive,
const bool is_dialog,
@@ -155,32 +150,31 @@ class GHOST_SystemWayland : public GHOST_System {
GHOST_TSuccess setCursorVisibility(bool visible);
- bool supportsCursorWarp();
- bool supportsWindowPosition();
+ bool supportsCursorWarp() override;
+ bool supportsWindowPosition() override;
bool getCursorGrabUseSoftwareDisplay(const GHOST_TGrabCursorMode mode);
/* WAYLAND direct-data access. */
- wl_display *display();
-
- wl_compositor *compositor();
+ struct wl_display *wl_display();
+ struct wl_compositor *wl_compositor();
+ struct zwp_primary_selection_device_manager_v1 *wp_primary_selection_manager();
+ struct zwp_pointer_gestures_v1 *wp_pointer_gestures();
#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;
- wl_shm *shm() const;
+ struct wl_shm *wl_shm() const;
/* WAYLAND utility functions. */
- void selection_set(const std::string &selection);
-
/** Clear all references to this surface to prevent accessing NULL pointers. */
void window_surface_unref(const wl_surface *wl_surface);
@@ -192,7 +186,12 @@ class GHOST_SystemWayland : public GHOST_System {
wl_surface *wl_surface,
int scale);
+ struct GWL_SimpleBuffer *clipboard_data(bool selection) const;
+
+#ifdef WITH_GHOST_WAYLAND_LIBDECOR
+ static bool use_libdecor_runtime();
+#endif
+
private:
- struct GWL_Display *d;
- std::string selection;
+ struct GWL_Display *display_;
};
diff --git a/intern/ghost/intern/GHOST_SystemWin32.cpp b/intern/ghost/intern/GHOST_SystemWin32.cpp
index 667198241f0..54c892d296e 100644
--- a/intern/ghost/intern/GHOST_SystemWin32.cpp
+++ b/intern/ghost/intern/GHOST_SystemWin32.cpp
@@ -213,7 +213,6 @@ GHOST_IWindow *GHOST_SystemWin32::createWindow(const char *title,
uint32_t width,
uint32_t height,
GHOST_TWindowState state,
- GHOST_TDrawingContextType type,
GHOST_GLSettings glSettings,
const bool exclusive,
const bool is_dialog,
@@ -227,7 +226,7 @@ GHOST_IWindow *GHOST_SystemWin32::createWindow(const char *title,
width,
height,
state,
- type,
+ glSettings.context_type,
((glSettings.flags & GHOST_glStereoVisual) != 0),
false,
(GHOST_WindowWin32 *)parentWindow,
diff --git a/intern/ghost/intern/GHOST_SystemWin32.h b/intern/ghost/intern/GHOST_SystemWin32.h
index f5cd0055b34..98a7e5dfb35 100644
--- a/intern/ghost/intern/GHOST_SystemWin32.h
+++ b/intern/ghost/intern/GHOST_SystemWin32.h
@@ -103,7 +103,6 @@ class GHOST_SystemWin32 : public GHOST_System {
* \param width: The width the window.
* \param height: The height the window.
* \param state: The state of the window when opened.
- * \param type: The type of drawing context installed in this window.
* \param glSettings: Misc OpenGL settings.
* \param exclusive: Use to show the window on top and ignore others (used full-screen).
* \param parentWindow: Parent window.
@@ -115,7 +114,6 @@ class GHOST_SystemWin32 : public GHOST_System {
uint32_t width,
uint32_t height,
GHOST_TWindowState state,
- GHOST_TDrawingContextType type,
GHOST_GLSettings glSettings,
const bool exclusive = false,
const bool is_dialog = false,
diff --git a/intern/ghost/intern/GHOST_SystemX11.cpp b/intern/ghost/intern/GHOST_SystemX11.cpp
index 6b468f041c1..5c89febe97c 100644
--- a/intern/ghost/intern/GHOST_SystemX11.cpp
+++ b/intern/ghost/intern/GHOST_SystemX11.cpp
@@ -308,7 +308,6 @@ void GHOST_SystemX11::getAllDisplayDimensions(uint32_t &width, uint32_t &height)
* \param width: The width the window.
* \param height: The height the window.
* \param state: The state of the window when opened.
- * \param type: The type of drawing context installed in this window.
* \param glSettings: Misc OpenGL settings.
* \param exclusive: Use to show the window on top and ignore others (used full-screen).
* \param parentWindow: Parent window.
@@ -320,7 +319,6 @@ GHOST_IWindow *GHOST_SystemX11::createWindow(const char *title,
uint32_t width,
uint32_t height,
GHOST_TWindowState state,
- GHOST_TDrawingContextType type,
GHOST_GLSettings glSettings,
const bool exclusive,
const bool is_dialog,
@@ -341,7 +339,7 @@ GHOST_IWindow *GHOST_SystemX11::createWindow(const char *title,
height,
state,
(GHOST_WindowX11 *)parentWindow,
- type,
+ glSettings.context_type,
is_dialog,
((glSettings.flags & GHOST_glStereoVisual) != 0),
exclusive,
@@ -2435,11 +2433,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_SystemX11.h b/intern/ghost/intern/GHOST_SystemX11.h
index 572be30174d..1f071da6da7 100644
--- a/intern/ghost/intern/GHOST_SystemX11.h
+++ b/intern/ghost/intern/GHOST_SystemX11.h
@@ -113,7 +113,6 @@ class GHOST_SystemX11 : public GHOST_System {
* \param width: The width the window.
* \param height: The height the window.
* \param state: The state of the window when opened.
- * \param type: The type of drawing context installed in this window.
* \param stereoVisual: Create a stereo visual for quad buffered stereo.
* \param exclusive: Use to show the window on top and ignore others (used full-screen).
* \param parentWindow: Parent (embedder) window.
@@ -125,7 +124,6 @@ class GHOST_SystemX11 : public GHOST_System {
uint32_t width,
uint32_t height,
GHOST_TWindowState state,
- GHOST_TDrawingContextType type,
GHOST_GLSettings glSettings,
const bool exclusive = false,
const bool is_dialog = false,
diff --git a/intern/ghost/intern/GHOST_WindowCocoa.mm b/intern/ghost/intern/GHOST_WindowCocoa.mm
index 737fd64bdf0..bc1f1e99a3a 100644
--- a/intern/ghost/intern/GHOST_WindowCocoa.mm
+++ b/intern/ghost/intern/GHOST_WindowCocoa.mm
@@ -803,10 +803,10 @@ GHOST_TSuccess GHOST_WindowCocoa::setOrder(GHOST_TWindowOrder order)
GHOST_Context *GHOST_WindowCocoa::newDrawingContext(GHOST_TDrawingContextType type)
{
- if (type == GHOST_kDrawingContextTypeOpenGL) {
+ if (type == GHOST_kDrawingContextTypeOpenGL || type == GHOST_kDrawingContextTypeMetal) {
GHOST_Context *context = new GHOST_ContextCGL(
- m_wantStereoVisual, m_metalView, m_metalLayer, m_openGLView);
+ m_wantStereoVisual, m_metalView, m_metalLayer, m_openGLView, type);
if (context->initializeDrawingContext())
return context;
diff --git a/intern/ghost/intern/GHOST_WindowWayland.cpp b/intern/ghost/intern/GHOST_WindowWayland.cpp
index 5f3cb3e3f3a..986e18d7a87 100644
--- a/intern/ghost/intern/GHOST_WindowWayland.cpp
+++ b/intern/ghost/intern/GHOST_WindowWayland.cpp
@@ -31,15 +31,54 @@
# 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;
+ GHOST_WindowWayland *ghost_window = nullptr;
struct wl_surface *wl_surface = nullptr;
/**
* Outputs on which the window is currently shown on.
@@ -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*/,
@@ -189,7 +220,7 @@ static void xdg_toplevel_handle_configure(void *data,
static void xdg_toplevel_handle_close(void *data, xdg_toplevel * /*xdg_toplevel*/)
{
CLOG_INFO(LOG, 2, "close");
- static_cast<GWL_Window *>(data)->w->close();
+ static_cast<GWL_Window *>(data)->ghost_window->close();
}
static const xdg_toplevel_listener toplevel_listener = {
@@ -197,9 +228,7 @@ static const xdg_toplevel_listener toplevel_listener = {
xdg_toplevel_handle_close,
};
-# undef LOG
-
-#endif /* !WITH_GHOST_WAYLAND_LIBDECOR. */
+#undef LOG
/** \} */
@@ -234,7 +263,7 @@ static void frame_handle_configure(struct libdecor_frame *frame,
win->size[1] = win->scale * size_next[1];
wl_egl_window_resize(win->egl_window, UNPACK2(win->size), 0, 0);
- win->w->notify_size();
+ win->ghost_window->notify_size();
if (!libdecor_configuration_get_window_state(configuration, &window_state)) {
window_state = LIBDECOR_WINDOW_STATE_NONE;
@@ -244,20 +273,20 @@ static void frame_handle_configure(struct libdecor_frame *frame,
win->is_fullscreen = window_state & LIBDECOR_WINDOW_STATE_FULLSCREEN;
win->is_active = window_state & LIBDECOR_WINDOW_STATE_ACTIVE;
- win->is_active ? win->w->activate() : win->w->deactivate();
+ win->is_active ? win->ghost_window->activate() : win->ghost_window->deactivate();
state = libdecor_state_new(UNPACK2(size_next));
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)
{
CLOG_INFO(LOG, 2, "close");
- static_cast<GWL_Window *>(data)->w->close();
+ static_cast<GWL_Window *>(data)->ghost_window->close();
}
static void frame_handle_commit(struct libdecor_frame * /*frame*/, void *data)
@@ -265,8 +294,8 @@ static void frame_handle_commit(struct libdecor_frame * /*frame*/, void *data)
CLOG_INFO(LOG, 2, "commit");
/* We have to swap twice to keep any pop-up menus alive. */
- static_cast<GWL_Window *>(data)->w->swapBuffers();
- static_cast<GWL_Window *>(data)->w->swapBuffers();
+ static_cast<GWL_Window *>(data)->ghost_window->swapBuffers();
+ static_cast<GWL_Window *>(data)->ghost_window->swapBuffers();
}
static struct libdecor_frame_interface libdecor_frame_iface = {
@@ -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;
}
@@ -337,14 +360,14 @@ static void xdg_surface_handle_configure(void *data,
wl_egl_window_resize(win->egl_window, UNPACK2(win->size), 0, 0);
win->size_pending[0] = 0;
win->size_pending[1] = 0;
- win->w->notify_size();
+ win->ghost_window->notify_size();
}
if (win->is_active) {
- win->w->activate();
+ win->ghost_window->activate();
}
else {
- win->w->deactivate();
+ win->ghost_window->deactivate();
}
xdg_surface_ack_configure(xdg_surface, serial);
@@ -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
/** \} */
@@ -418,7 +439,7 @@ static struct wl_surface_listener wl_surface_listener = {
GHOST_TSuccess GHOST_WindowWayland::hasCursorShape(GHOST_TStandardCursor cursorShape)
{
- return m_system->hasCursorShape(cursorShape);
+ return system_->hasCursorShape(cursorShape);
}
GHOST_WindowWayland::GHOST_WindowWayland(GHOST_SystemWayland *system,
@@ -434,20 +455,20 @@ GHOST_WindowWayland::GHOST_WindowWayland(GHOST_SystemWayland *system,
const bool stereoVisual,
const bool exclusive)
: GHOST_Window(width, height, state, stereoVisual, exclusive),
- m_system(system),
- w(new GWL_Window)
+ system_(system),
+ window_(new GWL_Window)
{
/* Globally store pointer to window manager. */
if (!window_manager) {
- window_manager = m_system->getWindowManager();
+ window_manager = system_->getWindowManager();
}
- w->w = this;
+ window_->ghost_window = this;
- w->size[0] = int32_t(width);
- w->size[1] = int32_t(height);
+ window_->size[0] = int32_t(width);
+ window_->size[1] = int32_t(height);
- w->is_dialog = is_dialog;
+ window_->is_dialog = is_dialog;
/* NOTE(@campbellbarton): The scale set here to avoid flickering on startup.
* When all monitors use the same scale (which is quite common) there aren't any problems.
@@ -458,75 +479,100 @@ GHOST_WindowWayland::GHOST_WindowWayland(GHOST_SystemWayland *system,
*
* Using the maximum scale is best as it results in the window first being smaller,
* avoiding a large window flashing before it's made smaller. */
- w->scale = outputs_max_scale_or_default(this->m_system->outputs(), 1, &w->dpi);
+ window_->scale = outputs_max_scale_or_default(system_->outputs(), 1, &window_->dpi);
/* Window surfaces. */
- w->wl_surface = wl_compositor_create_surface(m_system->compositor());
- ghost_wl_surface_tag(w->wl_surface);
+ window_->wl_surface = wl_compositor_create_surface(system_->wl_compositor());
+ ghost_wl_surface_tag(window_->wl_surface);
- wl_surface_set_buffer_scale(w->wl_surface, w->scale);
+ wl_surface_set_buffer_scale(window_->wl_surface, window_->scale);
- wl_surface_add_listener(w->wl_surface, &wl_surface_listener, this);
+ wl_surface_add_listener(window_->wl_surface, &wl_surface_listener, this);
- w->egl_window = wl_egl_window_create(w->wl_surface, int(w->size[0]), int(w->size[1]));
+ window_->egl_window = wl_egl_window_create(
+ window_->wl_surface, int(window_->size[0]), int(window_->size[1]));
/* NOTE: The limit is in points (not pixels) so Hi-DPI will limit to larger number of pixels.
* This has the advantage that the size limit is the same when moving the window between monitors
* with different scales set. If it was important to limit in pixels it could be re-calculated
- * when the `w->scale` changed. */
+ * when the `window_->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) {
+ window_->libdecor = new WGL_LibDecor_Window;
+ WGL_LibDecor_Window &decor = *window_->libdecor;
+
+ /* create window decorations */
+ decor.frame = libdecor_decorate(
+ system_->libdecor_context(), window_->wl_surface, &libdecor_frame_iface, window_);
+ libdecor_frame_map(window_->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)->window_->libdecor;
+ libdecor_frame_set_parent(decor.frame, decor_parent.frame);
+ }
}
+ else
+#endif
+ {
+ window_->xdg_decor = new WGL_XDG_Decor_Window;
+ WGL_XDG_Decor_Window &decor = *window_->xdg_decor;
+ decor.surface = xdg_wm_base_get_xdg_surface(system_->xdg_decor_shell(), window_->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 (system_->xdg_decor_manager()) {
+ decor.toplevel_decor = zxdg_decoration_manager_v1_get_toplevel_decoration(
+ system_->xdg_decor_manager(), decor.toplevel);
+ zxdg_toplevel_decoration_v1_add_listener(
+ decor.toplevel_decor, &toplevel_decoration_v1_listener, window_);
+ 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, window_);
+ xdg_toplevel_add_listener(decor.toplevel, &toplevel_listener, window_);
- 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)->window_->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);
+ wl_surface_set_user_data(window_->wl_surface, this);
/* Call top-level callbacks. */
- wl_surface_commit(w->wl_surface);
- wl_display_roundtrip(m_system->display());
+ wl_surface_commit(window_->wl_surface);
+ wl_display_roundtrip(system_->wl_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 = *window_->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(system_->libdecor_context(), 0) < 0) {
+ break;
+ }
}
}
#endif
@@ -535,9 +581,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) {
@@ -558,13 +608,13 @@ GHOST_TSuccess GHOST_WindowWayland::setWindowCursorGrab(GHOST_TGrabCursorMode mo
}
bounds = &bounds_buf;
}
- if (m_system->window_cursor_grab_set(mode,
- m_cursorGrab,
- m_cursorGrabInitPos,
- bounds,
- m_cursorGrabAxis,
- w->wl_surface,
- w->scale)) {
+ if (system_->window_cursor_grab_set(mode,
+ m_cursorGrab,
+ m_cursorGrabInitPos,
+ bounds,
+ m_cursorGrabAxis,
+ window_->wl_surface,
+ window_->scale)) {
return GHOST_kSuccess;
}
return GHOST_kFailure;
@@ -572,43 +622,47 @@ GHOST_TSuccess GHOST_WindowWayland::setWindowCursorGrab(GHOST_TGrabCursorMode mo
GHOST_TSuccess GHOST_WindowWayland::setWindowCursorShape(GHOST_TStandardCursor shape)
{
- const GHOST_TSuccess ok = m_system->setCursorShape(shape);
+ const GHOST_TSuccess ok = system_->setCursorShape(shape);
m_cursorShape = (ok == GHOST_kSuccess) ? shape : GHOST_kStandardCursorDefault;
return ok;
}
bool GHOST_WindowWayland::getCursorGrabUseSoftwareDisplay()
{
- return m_system->getCursorGrabUseSoftwareDisplay(m_cursorGrab);
+ return system_->getCursorGrabUseSoftwareDisplay(m_cursorGrab);
}
GHOST_TSuccess GHOST_WindowWayland::setWindowCustomCursorShape(
uint8_t *bitmap, uint8_t *mask, int sizex, int sizey, int hotX, int hotY, bool canInvertColor)
{
- return m_system->setCustomCursorShape(bitmap, mask, sizex, sizey, hotX, hotY, canInvertColor);
+ return system_->setCustomCursorShape(bitmap, mask, sizex, sizey, hotX, hotY, canInvertColor);
}
GHOST_TSuccess GHOST_WindowWayland::getCursorBitmap(GHOST_CursorBitmapRef *bitmap)
{
- return m_system->getCursorBitmap(bitmap);
+ return system_->getCursorBitmap(bitmap);
}
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 = *window_->libdecor;
+ libdecor_frame_set_title(decor.frame, title);
+ }
+ else
#endif
+ {
+ WGL_XDG_Decor_Window &decor = *window_->xdg_decor;
+ xdg_toplevel_set_title(decor.toplevel, title);
+ }
- this->title = title;
+ title_ = title;
}
std::string GHOST_WindowWayland::getTitle() const
{
- return this->title.empty() ? "untitled" : this->title;
+ return title_.empty() ? "untitled" : title_;
}
void GHOST_WindowWayland::getWindowBounds(GHOST_Rect &bounds) const
@@ -618,29 +672,29 @@ void GHOST_WindowWayland::getWindowBounds(GHOST_Rect &bounds) const
void GHOST_WindowWayland::getClientBounds(GHOST_Rect &bounds) const
{
- bounds.set(0, 0, UNPACK2(w->size));
+ bounds.set(0, 0, UNPACK2(window_->size));
}
GHOST_TSuccess GHOST_WindowWayland::setClientWidth(const uint32_t width)
{
- return setClientSize(width, uint32_t(w->size[1]));
+ return setClientSize(width, uint32_t(window_->size[1]));
}
GHOST_TSuccess GHOST_WindowWayland::setClientHeight(const uint32_t height)
{
- return setClientSize(uint32_t(w->size[0]), height);
+ return setClientSize(uint32_t(window_->size[0]), height);
}
GHOST_TSuccess GHOST_WindowWayland::setClientSize(const uint32_t width, const uint32_t height)
{
- wl_egl_window_resize(w->egl_window, int(width), int(height), 0, 0);
+ wl_egl_window_resize(window_->egl_window, int(width), int(height), 0, 0);
/* Override any pending size that may be set. */
- w->size_pending[0] = 0;
- w->size_pending[1] = 0;
+ window_->size_pending[0] = 0;
+ window_->size_pending[1] = 0;
- w->size[0] = width;
- w->size[1] = height;
+ window_->size[0] = width;
+ window_->size[1] = height;
notify_size();
@@ -669,40 +723,40 @@ GHOST_WindowWayland::~GHOST_WindowWayland()
{
releaseNativeHandles();
- wl_egl_window_destroy(w->egl_window);
+ wl_egl_window_destroy(window_->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(window_->libdecor);
}
- xdg_toplevel_destroy(w->xdg_toplevel);
- xdg_surface_destroy(w->xdg_surface);
+ else
#endif
+ {
+ wgl_xdg_decor_window_destroy(window_->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. */
- m_system->window_surface_unref(w->wl_surface);
+ system_->window_surface_unref(window_->wl_surface);
- wl_surface_destroy(w->wl_surface);
+ wl_surface_destroy(window_->wl_surface);
/* NOTE(@campbellbarton): Flushing will often run the appropriate handlers event
* (#wl_surface_listener.leave in particular) to avoid attempted access to the freed surfaces.
* This is not fool-proof though, hence the call to #window_surface_unref, see: T99078. */
- wl_display_flush(m_system->display());
+ wl_display_flush(system_->wl_display());
- delete w;
+ delete window_;
}
uint16_t GHOST_WindowWayland::getDPIHint()
{
- return w->dpi;
+ return window_->dpi;
}
GHOST_TSuccess GHOST_WindowWayland::setWindowCursorVisibility(bool visible)
{
- return m_system->setCursorVisibility(visible);
+ return system_->setCursorVisibility(visible);
}
GHOST_TSuccess GHOST_WindowWayland::setState(GHOST_TWindowState state)
@@ -711,57 +765,84 @@ 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(window_->libdecor->frame);
+ }
+ else
#endif
+ {
+ xdg_toplevel_unset_maximized(window_->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(window_->libdecor->frame);
+ }
+ else
#endif
+ {
+ xdg_toplevel_unset_fullscreen(window_->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(window_->libdecor->frame);
+ }
+ else
#endif
+ {
+ xdg_toplevel_set_maximized(window_->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(window_->libdecor->frame);
+ }
+ else
#endif
+ {
+ xdg_toplevel_set_minimized(window_->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(window_->libdecor->frame, nullptr);
+ }
+ else
#endif
+ {
+ xdg_toplevel_set_fullscreen(window_->xdg_decor->toplevel, nullptr);
+ }
break;
- case GHOST_kWindowStateEmbedded:
+ }
+ case GHOST_kWindowStateEmbedded: {
return GHOST_kFailure;
+ }
}
return GHOST_kSuccess;
}
GHOST_TWindowState GHOST_WindowWayland::getState() const
{
- if (w->is_fullscreen) {
+ if (window_->is_fullscreen) {
return GHOST_kWindowStateFullScreen;
}
- if (w->is_maximised) {
+ if (window_->is_maximised) {
return GHOST_kWindowStateMaximized;
}
return GHOST_kWindowStateNormal;
@@ -780,26 +861,35 @@ 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(window_->libdecor->frame, nullptr);
+ }
+ else
#endif
+ {
+ xdg_toplevel_set_fullscreen(window_->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(window_->libdecor->frame);
+ }
+ else
#endif
+ {
+ xdg_toplevel_unset_fullscreen(window_->xdg_decor->toplevel);
+ }
return GHOST_kSuccess;
}
bool GHOST_WindowWayland::isDialog() const
{
- return w->is_dialog;
+ return window_->is_dialog;
}
#ifdef GHOST_OPENGL_ALPHA
@@ -808,9 +898,9 @@ void GHOST_WindowWayland::setOpaque() const
struct wl_region *region;
/* Make the window opaque. */
- region = wl_compositor_create_region(m_system->compositor());
- wl_region_add(region, 0, 0, UNPACK2(w->size));
- wl_surface_set_opaque_region(w->surface, region);
+ region = wl_compositor_create_region(system_->compositor());
+ wl_region_add(region, 0, 0, UNPACK2(window_->size));
+ wl_surface_set_opaque_region(window_->surface, region);
wl_region_destroy(region);
}
#endif
@@ -828,10 +918,10 @@ GHOST_Context *GHOST_WindowWayland::newDrawingContext(GHOST_TDrawingContextType
break;
case GHOST_kDrawingContextTypeOpenGL:
for (int minor = 6; minor >= 0; --minor) {
- context = new GHOST_ContextEGL(this->m_system,
+ context = new GHOST_ContextEGL(system_,
m_wantStereoVisual,
- EGLNativeWindowType(w->egl_window),
- EGLNativeDisplayType(m_system->display()),
+ EGLNativeWindowType(window_->egl_window),
+ EGLNativeDisplayType(system_->wl_display()),
EGL_CONTEXT_OPENGL_CORE_PROFILE_BIT,
4,
minor,
@@ -844,10 +934,10 @@ GHOST_Context *GHOST_WindowWayland::newDrawingContext(GHOST_TDrawingContextType
}
delete context;
}
- context = new GHOST_ContextEGL(this->m_system,
+ context = new GHOST_ContextEGL(system_,
m_wantStereoVisual,
- EGLNativeWindowType(w->egl_window),
- EGLNativeDisplayType(m_system->display()),
+ EGLNativeWindowType(window_->egl_window),
+ EGLNativeDisplayType(system_->wl_display()),
EGL_CONTEXT_OPENGL_CORE_PROFILE_BIT,
3,
3,
@@ -856,7 +946,12 @@ GHOST_Context *GHOST_WindowWayland::newDrawingContext(GHOST_TDrawingContextType
EGL_OPENGL_API);
}
- return (context->initializeDrawingContext() == GHOST_kSuccess) ? context : nullptr;
+ if (context->initializeDrawingContext()) {
+ return context;
+ }
+
+ delete context;
+ return nullptr;
}
/** \} */
@@ -869,22 +964,22 @@ GHOST_Context *GHOST_WindowWayland::newDrawingContext(GHOST_TDrawingContextType
uint16_t GHOST_WindowWayland::dpi() const
{
- return w->dpi;
+ return window_->dpi;
}
int GHOST_WindowWayland::scale() const
{
- return w->scale;
+ return window_->scale;
}
wl_surface *GHOST_WindowWayland::wl_surface() const
{
- return w->wl_surface;
+ return window_->wl_surface;
}
const std::vector<GWL_Output *> &GHOST_WindowWayland::outputs()
{
- return w->outputs;
+ return window_->outputs;
}
/** \} */
@@ -897,24 +992,24 @@ const std::vector<GWL_Output *> &GHOST_WindowWayland::outputs()
GHOST_TSuccess GHOST_WindowWayland::close()
{
- return m_system->pushEvent(
- new GHOST_Event(m_system->getMilliSeconds(), GHOST_kEventWindowClose, this));
+ return system_->pushEvent(
+ new GHOST_Event(system_->getMilliSeconds(), GHOST_kEventWindowClose, this));
}
GHOST_TSuccess GHOST_WindowWayland::activate()
{
- if (m_system->getWindowManager()->setActiveWindow(this) == GHOST_kFailure) {
+ if (system_->getWindowManager()->setActiveWindow(this) == GHOST_kFailure) {
return GHOST_kFailure;
}
- return m_system->pushEvent(
- new GHOST_Event(m_system->getMilliSeconds(), GHOST_kEventWindowActivate, this));
+ return system_->pushEvent(
+ new GHOST_Event(system_->getMilliSeconds(), GHOST_kEventWindowActivate, this));
}
GHOST_TSuccess GHOST_WindowWayland::deactivate()
{
- m_system->getWindowManager()->setWindowInactive(this);
- return m_system->pushEvent(
- new GHOST_Event(m_system->getMilliSeconds(), GHOST_kEventWindowDeactivate, this));
+ system_->getWindowManager()->setWindowInactive(this);
+ return system_->pushEvent(
+ new GHOST_Event(system_->getMilliSeconds(), GHOST_kEventWindowDeactivate, this));
}
GHOST_TSuccess GHOST_WindowWayland::notify_size()
@@ -923,8 +1018,8 @@ GHOST_TSuccess GHOST_WindowWayland::notify_size()
setOpaque();
#endif
- return m_system->pushEvent(
- new GHOST_Event(m_system->getMilliSeconds(), GHOST_kEventWindowSize, this));
+ return system_->pushEvent(
+ new GHOST_Event(system_->getMilliSeconds(), GHOST_kEventWindowSize, this));
}
/** \} */
@@ -941,30 +1036,29 @@ GHOST_TSuccess GHOST_WindowWayland::notify_size()
bool GHOST_WindowWayland::outputs_changed_update_scale()
{
uint32_t dpi_next;
- const int scale_next = outputs_max_scale_or_default(this->outputs(), 0, &dpi_next);
+ const int scale_next = outputs_max_scale_or_default(outputs(), 0, &dpi_next);
if (UNLIKELY(scale_next == 0)) {
return false;
}
- GWL_Window *win = this->w;
- const uint32_t dpi_curr = win->dpi;
- const int scale_curr = win->scale;
+ const uint32_t dpi_curr = window_->dpi;
+ const int scale_curr = window_->scale;
bool changed = false;
if (scale_next != scale_curr) {
/* Unlikely but possible there is a pending size change is set. */
- win->size_pending[0] = (win->size_pending[0] / scale_curr) * scale_next;
- win->size_pending[1] = (win->size_pending[1] / scale_curr) * scale_next;
+ window_->size_pending[0] = (window_->size_pending[0] / scale_curr) * scale_next;
+ window_->size_pending[1] = (window_->size_pending[1] / scale_curr) * scale_next;
- win->scale = scale_next;
- wl_surface_set_buffer_scale(w->wl_surface, scale_next);
+ window_->scale = scale_next;
+ wl_surface_set_buffer_scale(window_->wl_surface, scale_next);
changed = true;
}
if (dpi_next != dpi_curr) {
/* Using the real DPI will cause wrong scaling of the UI
* use a multiplier for the default DPI as workaround. */
- win->dpi = dpi_next;
+ window_->dpi = dpi_next;
changed = true;
/* As this is a low-level function, we might want adding this event to be optional,
@@ -979,7 +1073,7 @@ bool GHOST_WindowWayland::outputs_changed_update_scale()
bool GHOST_WindowWayland::outputs_enter(GWL_Output *output)
{
- std::vector<GWL_Output *> &outputs = w->outputs;
+ std::vector<GWL_Output *> &outputs = window_->outputs;
auto it = std::find(outputs.begin(), outputs.end(), output);
if (it != outputs.end()) {
return false;
@@ -990,7 +1084,7 @@ bool GHOST_WindowWayland::outputs_enter(GWL_Output *output)
bool GHOST_WindowWayland::outputs_leave(GWL_Output *output)
{
- std::vector<GWL_Output *> &outputs = w->outputs;
+ std::vector<GWL_Output *> &outputs = window_->outputs;
auto it = std::find(outputs.begin(), outputs.end(), output);
if (it == outputs.end()) {
return false;
diff --git a/intern/ghost/intern/GHOST_WindowWayland.h b/intern/ghost/intern/GHOST_WindowWayland.h
index 9b4c17ecd95..e95f5386310 100644
--- a/intern/ghost/intern/GHOST_WindowWayland.h
+++ b/intern/ghost/intern/GHOST_WindowWayland.h
@@ -115,9 +115,9 @@ class GHOST_WindowWayland : public GHOST_Window {
bool outputs_changed_update_scale();
private:
- GHOST_SystemWayland *m_system;
- struct GWL_Window *w;
- std::string title;
+ GHOST_SystemWayland *system_;
+ struct GWL_Window *window_;
+ std::string title_;
/**
* \param type: The type of rendering context create.
diff --git a/intern/ghost/test/gears/GHOST_Test.cpp b/intern/ghost/test/gears/GHOST_Test.cpp
index 1891f1eca77..3c9206b2010 100644
--- a/intern/ghost/test/gears/GHOST_Test.cpp
+++ b/intern/ghost/test/gears/GHOST_Test.cpp
@@ -407,17 +407,12 @@ Application::Application(GHOST_ISystem *system)
stereo(false)
{
GHOST_GLSettings glSettings = {0};
+ glSettings.context_type = GHOST_kDrawingContextTypeOpenGL;
fApp = this;
// Create the main window
- m_mainWindow = system->createWindow("gears - main window",
- 10,
- 64,
- 320,
- 200,
- GHOST_kWindowStateNormal,
- GHOST_kDrawingContextTypeOpenGL,
- glSettings);
+ m_mainWindow = system->createWindow(
+ "gears - main window", 10, 64, 320, 200, GHOST_kWindowStateNormal, glSettings);
if (!m_mainWindow) {
std::cout << "could not create main window\n";
@@ -425,14 +420,8 @@ Application::Application(GHOST_ISystem *system)
}
// Create a secondary window
- m_secondaryWindow = system->createWindow("gears - secondary window",
- 340,
- 64,
- 320,
- 200,
- GHOST_kWindowStateNormal,
- GHOST_kDrawingContextTypeOpenGL,
- glSettings);
+ m_secondaryWindow = system->createWindow(
+ "gears - secondary window", 340, 64, 320, 200, GHOST_kWindowStateNormal, glSettings);
if (!m_secondaryWindow) {
std::cout << "could not create secondary window\n";
exit(-1);
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/mantaflow/intern/MANTA_main.cpp b/intern/mantaflow/intern/MANTA_main.cpp
index f5f22dc700b..5708cdc81aa 100644
--- a/intern/mantaflow/intern/MANTA_main.cpp
+++ b/intern/mantaflow/intern/MANTA_main.cpp
@@ -1507,13 +1507,9 @@ bool MANTA::bakeData(FluidModifierData *fmd, int framenr)
string volume_format = getCacheFileEnding(fds->cache_data_format);
+ BLI_path_join(cacheDirData, sizeof(cacheDirData), fds->cache_directory, FLUID_DOMAIN_DIR_DATA);
BLI_path_join(
- cacheDirData, sizeof(cacheDirData), fds->cache_directory, FLUID_DOMAIN_DIR_DATA, nullptr);
- BLI_path_join(cacheDirGuiding,
- sizeof(cacheDirGuiding),
- fds->cache_directory,
- FLUID_DOMAIN_DIR_GUIDE,
- nullptr);
+ cacheDirGuiding, sizeof(cacheDirGuiding), fds->cache_directory, FLUID_DOMAIN_DIR_GUIDE);
BLI_path_make_safe(cacheDirData);
BLI_path_make_safe(cacheDirGuiding);
@@ -1540,7 +1536,7 @@ bool MANTA::bakeNoise(FluidModifierData *fmd, int framenr)
string volume_format = getCacheFileEnding(fds->cache_data_format);
BLI_path_join(
- cacheDirNoise, sizeof(cacheDirNoise), fds->cache_directory, FLUID_DOMAIN_DIR_NOISE, nullptr);
+ cacheDirNoise, sizeof(cacheDirNoise), fds->cache_directory, FLUID_DOMAIN_DIR_NOISE);
BLI_path_make_safe(cacheDirNoise);
ss.str("");
@@ -1566,8 +1562,7 @@ bool MANTA::bakeMesh(FluidModifierData *fmd, int framenr)
string volume_format = getCacheFileEnding(fds->cache_data_format);
string mesh_format = getCacheFileEnding(fds->cache_mesh_format);
- BLI_path_join(
- cacheDirMesh, sizeof(cacheDirMesh), fds->cache_directory, FLUID_DOMAIN_DIR_MESH, nullptr);
+ BLI_path_join(cacheDirMesh, sizeof(cacheDirMesh), fds->cache_directory, FLUID_DOMAIN_DIR_MESH);
BLI_path_make_safe(cacheDirMesh);
ss.str("");
@@ -1596,8 +1591,7 @@ bool MANTA::bakeParticles(FluidModifierData *fmd, int framenr)
BLI_path_join(cacheDirParticles,
sizeof(cacheDirParticles),
fds->cache_directory,
- FLUID_DOMAIN_DIR_PARTICLES,
- nullptr);
+ FLUID_DOMAIN_DIR_PARTICLES);
BLI_path_make_safe(cacheDirParticles);
ss.str("");
@@ -1623,11 +1617,8 @@ bool MANTA::bakeGuiding(FluidModifierData *fmd, int framenr)
string volume_format = getCacheFileEnding(fds->cache_data_format);
string resumable_cache = !(fds->flags & FLUID_DOMAIN_USE_RESUMABLE_CACHE) ? "False" : "True";
- BLI_path_join(cacheDirGuiding,
- sizeof(cacheDirGuiding),
- fds->cache_directory,
- FLUID_DOMAIN_DIR_GUIDE,
- nullptr);
+ BLI_path_join(
+ cacheDirGuiding, sizeof(cacheDirGuiding), fds->cache_directory, FLUID_DOMAIN_DIR_GUIDE);
BLI_path_make_safe(cacheDirGuiding);
ss.str("");
@@ -1678,13 +1669,11 @@ bool MANTA::exportSmokeScript(FluidModifierData *fmd)
FluidDomainSettings *fds = fmd->domain;
- BLI_path_join(
- cacheDir, sizeof(cacheDir), fds->cache_directory, FLUID_DOMAIN_DIR_SCRIPT, nullptr);
+ BLI_path_join(cacheDir, sizeof(cacheDir), fds->cache_directory, FLUID_DOMAIN_DIR_SCRIPT);
BLI_path_make_safe(cacheDir);
/* Create 'script' subdir if it does not exist already */
BLI_dir_create_recursive(cacheDir);
- BLI_path_join(
- cacheDirScript, sizeof(cacheDirScript), cacheDir, FLUID_DOMAIN_SMOKE_SCRIPT, nullptr);
+ BLI_path_join(cacheDirScript, sizeof(cacheDirScript), cacheDir, FLUID_DOMAIN_SMOKE_SCRIPT);
BLI_path_make_safe(cacheDir);
bool noise = fds->flags & FLUID_DOMAIN_USE_NOISE;
@@ -1791,13 +1780,11 @@ bool MANTA::exportLiquidScript(FluidModifierData *fmd)
FluidDomainSettings *fds = fmd->domain;
- BLI_path_join(
- cacheDir, sizeof(cacheDir), fds->cache_directory, FLUID_DOMAIN_DIR_SCRIPT, nullptr);
+ BLI_path_join(cacheDir, sizeof(cacheDir), fds->cache_directory, FLUID_DOMAIN_DIR_SCRIPT);
BLI_path_make_safe(cacheDir);
/* Create 'script' subdir if it does not exist already */
BLI_dir_create_recursive(cacheDir);
- BLI_path_join(
- cacheDirScript, sizeof(cacheDirScript), cacheDir, FLUID_DOMAIN_LIQUID_SCRIPT, nullptr);
+ BLI_path_join(cacheDirScript, sizeof(cacheDirScript), cacheDir, FLUID_DOMAIN_LIQUID_SCRIPT);
BLI_path_make_safe(cacheDirScript);
bool mesh = fds->flags & FLUID_DOMAIN_USE_MESH;
@@ -2323,8 +2310,7 @@ bool MANTA::hasGuiding(FluidModifierData *fmd, int framenr, bool sourceDomain)
string MANTA::getDirectory(FluidModifierData *fmd, string subdirectory)
{
char directory[FILE_MAX];
- BLI_path_join(
- directory, sizeof(directory), fmd->domain->cache_directory, subdirectory.c_str(), nullptr);
+ BLI_path_join(directory, sizeof(directory), fmd->domain->cache_directory, subdirectory.c_str());
BLI_path_make_safe(directory);
return directory;
}
@@ -2335,7 +2321,7 @@ string MANTA::getFile(
char targetFile[FILE_MAX];
string path = getDirectory(fmd, subdirectory);
string filename = fname + "_####" + extension;
- BLI_join_dirfile(targetFile, sizeof(targetFile), path.c_str(), filename.c_str());
+ BLI_path_join(targetFile, sizeof(targetFile), path.c_str(), filename.c_str());
BLI_path_frame(targetFile, framenr, 0);
return targetFile;
}
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/opensubdiv/CMakeLists.txt b/intern/opensubdiv/CMakeLists.txt
index 1dddd70928a..920b8d5c542 100644
--- a/intern/opensubdiv/CMakeLists.txt
+++ b/intern/opensubdiv/CMakeLists.txt
@@ -81,12 +81,6 @@ if(WITH_OPENSUBDIV)
)
endif()
- opensubdiv_define_component(OPENSUBDIV_HAS_OPENMP)
- opensubdiv_define_component(OPENSUBDIV_HAS_OPENCL)
- opensubdiv_define_component(OPENSUBDIV_HAS_CUDA)
- opensubdiv_define_component(OPENSUBDIV_HAS_GLSL_TRANSFORM_FEEDBACK)
- opensubdiv_define_component(OPENSUBDIV_HAS_GLSL_COMPUTE)
-
if(WIN32)
add_definitions(-DNOMINMAX)
add_definitions(-D_USE_MATH_DEFINES)
diff --git a/intern/wayland_dynload/extern/wayland_dynload_client.h b/intern/wayland_dynload/extern/wayland_dynload_client.h
index 8e9dddd91a3..d80ef5c9f0c 100644
--- a/intern/wayland_dynload/extern/wayland_dynload_client.h
+++ b/intern/wayland_dynload/extern/wayland_dynload_client.h
@@ -41,6 +41,7 @@ WAYLAND_DYNLOAD_IFACE(wl_seat_interface)
WAYLAND_DYNLOAD_IFACE(wl_shm_interface)
WAYLAND_DYNLOAD_IFACE(wl_shm_pool_interface)
WAYLAND_DYNLOAD_IFACE(wl_surface_interface)
+WAYLAND_DYNLOAD_IFACE(wl_touch_interface)
#else
/* Header guard. */
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/make.bat b/make.bat
index ff8059b0754..0be70053ce1 100644
--- a/make.bat
+++ b/make.bat
@@ -62,9 +62,17 @@ if "%SVN_FIX%" == "1" (
)
if "%BUILD_UPDATE%" == "1" (
+ REM First see if the SVN libs are there and check them out if they are not.
call "%BLENDER_DIR%\build_files\windows\check_libraries.cmd"
if errorlevel 1 goto EOF
-
+ REM Then update SVN platform libraries, since updating python while python is
+ REM running tends to be problematic. The python script that update_sources
+ REM calls later on may still try to switch branches and run into trouble,
+ REM but for *most* people this will side step the problem.
+ call "%BLENDER_DIR%\build_files\windows\svn_update.cmd"
+ REM Finally call the python script shared between all platforms that updates git
+ REM and does any other SVN work like update the tests or branch switches
+ REM if required.
call "%BLENDER_DIR%\build_files\windows\update_sources.cmd"
goto EOF
)
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/gpu_extras/batch.py b/release/scripts/modules/gpu_extras/batch.py
index ba8e3879a8e..6c9ab52c1a3 100644
--- a/release/scripts/modules/gpu_extras/batch.py
+++ b/release/scripts/modules/gpu_extras/batch.py
@@ -34,13 +34,13 @@ def batch_for_shader(shader, type, content, *, indices=None):
return 'I32'
def recommended_attr_len(attr_name):
- item = content[attr_name][0]
attr_len = 1
try:
+ item = content[attr_name][0]
while True:
attr_len *= len(item)
item = item[0]
- except TypeError:
+ except (TypeError, IndexError):
pass
return attr_len
diff --git a/release/scripts/modules/sys_info.py b/release/scripts/modules/sys_info.py
index 026c39908c0..5bd38acb19c 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", " ")))
@@ -177,6 +184,7 @@ def write_sysinfo(filepath):
output.write("vendor:\t\t%r\n" % gpu.platform.vendor_get())
output.write("version:\t%r\n" % gpu.platform.version_get())
output.write("device type:\t%r\n" % gpu.platform.device_type_get())
+ output.write("backend type:\t%r\n" % gpu.platform.backend_type_get())
output.write("extensions:\n")
glext = sorted(gpu.capabilities.extensions_get())
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_data_curves.py b/release/scripts/startup/bl_ui/properties_data_curves.py
index ff0eabeb7d9..df80bdb4552 100644
--- a/release/scripts/startup/bl_ui/properties_data_curves.py
+++ b/release/scripts/startup/bl_ui/properties_data_curves.py
@@ -44,7 +44,13 @@ class DATA_PT_curves_surface(DataButtonsPanel, Panel):
layout.use_property_split = True
layout.prop(ob.data, "surface")
- layout.prop(ob.data, "surface_uv_map", text="UV Map")
+ has_surface = ob.data.surface is not None
+ if has_surface:
+ layout.prop_search(ob.data, "surface_uv_map", ob.data.surface.data, "uv_layers", text="UV Map")
+ else:
+ row = layout.row()
+ row.prop(ob.data, "surface_uv_map", text="UV Map")
+ row.enabled = has_surface
class CURVES_MT_add_attribute(Menu):
diff --git a/release/scripts/startup/bl_ui/properties_output.py b/release/scripts/startup/bl_ui/properties_output.py
index ca0e698500e..61384f25afb 100644
--- a/release/scripts/startup/bl_ui/properties_output.py
+++ b/release/scripts/startup/bl_ui/properties_output.py
@@ -380,7 +380,14 @@ class RENDER_PT_encoding_video(RenderOutputButtonsPanel, Panel):
layout = self.layout
ffmpeg = context.scene.render.ffmpeg
- needs_codec = ffmpeg.format in {'AVI', 'QUICKTIME', 'MKV', 'OGG', 'MPEG4', 'WEBM'}
+ needs_codec = ffmpeg.format in {
+ 'AVI',
+ 'QUICKTIME',
+ 'MKV',
+ 'OGG',
+ 'MPEG4',
+ 'WEBM'
+ }
if needs_codec:
layout.prop(ffmpeg, "codec")
@@ -391,7 +398,12 @@ class RENDER_PT_encoding_video(RenderOutputButtonsPanel, Panel):
layout.prop(ffmpeg, "use_lossless_output")
# Output quality
- use_crf = needs_codec and ffmpeg.codec in {'H264', 'MPEG4', 'WEBM'}
+ use_crf = needs_codec and ffmpeg.codec in {
+ 'H264',
+ 'MPEG4',
+ 'WEBM',
+ 'AV1'
+ }
if use_crf:
layout.prop(ffmpeg, "constant_rate_factor")
diff --git a/release/scripts/startup/bl_ui/properties_paint_common.py b/release/scripts/startup/bl_ui/properties_paint_common.py
index 72a87703bd5..0e49a506e73 100644
--- a/release/scripts/startup/bl_ui/properties_paint_common.py
+++ b/release/scripts/startup/bl_ui/properties_paint_common.py
@@ -928,60 +928,80 @@ def brush_settings_advanced(layout, context, brush, popover=False):
use_frontface = False
if mode == 'SCULPT':
+ sculpt = context.tool_settings.sculpt
capabilities = brush.sculpt_capabilities
use_accumulate = capabilities.has_accumulate
use_frontface = True
col = layout.column(heading="Auto-Masking", align=True)
- # topology automasking
+ col = layout.column(align=True)
col.prop(brush, "use_automasking_topology", text="Topology")
-
- # face masks automasking
col.prop(brush, "use_automasking_face_sets", text="Face Sets")
- # boundary edges/face sets automasking
+ layout.separator()
+
+ col = layout.column(align=True)
col.prop(brush, "use_automasking_boundary_edges", text="Mesh Boundary")
col.prop(brush, "use_automasking_boundary_face_sets", text="Face Sets Boundary")
- col.prop(brush, "use_automasking_cavity", text="Cavity")
- col.prop(brush, "use_automasking_cavity_inverted", text="Cavity (Inverted)")
- col.prop(brush, "use_automasking_start_normal", text="Area Normal")
- col.prop(brush, "use_automasking_view_normal", text="View Normal")
- col.separator()
- col.prop(brush, "automasking_boundary_edges_propagation_steps")
+ if brush.use_automasking_boundary_edges or brush.use_automasking_boundary_face_sets:
+ col = layout.column()
+ col.use_property_split = False
+ split = col.split(factor=0.4)
+ col = split.column()
+ split.prop(brush, "automasking_boundary_edges_propagation_steps")
- sculpt = context.tool_settings.sculpt
+ layout.separator()
- if brush.use_automasking_start_normal:
- col.separator()
+ col = layout.column(align=True)
+ row = col.row()
+ row.prop(brush, "use_automasking_cavity", text="Cavity")
- col.prop(sculpt, "automasking_start_normal_limit")
- col.prop(sculpt, "automasking_start_normal_falloff")
+ is_cavity_active = brush.use_automasking_cavity or brush.use_automasking_cavity_inverted
- if brush.use_automasking_view_normal:
- col.separator()
+ if is_cavity_active:
+ row.operator("sculpt.mask_from_cavity", text="Create Mask")
- col.prop(brush, "use_automasking_view_occlusion", text="Occlusion")
- col.prop(sculpt, "automasking_view_normal_limit")
- col.prop(sculpt, "automasking_view_normal_falloff")
+ col.prop(brush, "use_automasking_cavity_inverted", text="Cavity (inverted)")
- if brush.use_automasking_cavity or brush.use_automasking_cavity_inverted:
- col.separator()
+ if is_cavity_active:
+ col = layout.column(align=True)
+ col.prop(brush, "automasking_cavity_factor", text="Factor")
+ col.prop(brush, "automasking_cavity_blur_steps", text="Blur")
- col.prop(brush, "automasking_cavity_factor", text="Cavity Factor")
- col.prop(brush, "automasking_cavity_blur_steps", text="Cavity Blur")
- col.prop(brush, "use_automasking_custom_cavity_curve", text="Use Curve")
+ col = layout.column()
+ col.prop(brush, "use_automasking_custom_cavity_curve", text="Custom Curve")
if brush.use_automasking_custom_cavity_curve:
col.template_curve_mapping(brush, "automasking_cavity_curve")
layout.separator()
+ col = layout.column(align=True)
+ col.prop(brush, "use_automasking_view_normal", text="View Normal")
+
+ if brush.use_automasking_view_normal:
+ col.prop(brush, "use_automasking_view_occlusion", text="Occlusion")
+ subcol = col.column(align=True)
+ subcol.active = not brush.use_automasking_view_occlusion
+ subcol.prop(sculpt, "automasking_view_normal_limit", text="Limit")
+ subcol.prop(sculpt, "automasking_view_normal_falloff", text="Falloff")
+
+ col = layout.column()
+ col.prop(brush, "use_automasking_start_normal", text="Area Normal")
+
+ if brush.use_automasking_start_normal:
+ col = layout.column(align=True)
+ col.prop(sculpt, "automasking_start_normal_limit", text="Limit")
+ col.prop(sculpt, "automasking_start_normal_falloff", text="Falloff")
+
+ layout.separator()
+
# sculpt plane settings
if capabilities.has_sculpt_plane:
layout.prop(brush, "sculpt_plane")
- col = layout.column(heading="Use Original", align=True)
+ col = layout.column(heading="Original", align=True)
col.prop(brush, "use_original_normal", text="Normal")
col.prop(brush, "use_original_plane", text="Plane")
layout.separator()
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..39684aaf161 100644
--- a/release/scripts/startup/bl_ui/space_view3d.py
+++ b/release/scripts/startup/bl_ui/space_view3d.py
@@ -838,12 +838,18 @@ class VIEW3D_HT_header(Header):
text="Guides",
)
- layout.separator_spacer()
+ elif object_mode == 'SCULPT':
+ layout.popover(
+ panel="VIEW3D_PT_sculpt_automasking",
+ text="",
+ icon="MOD_MASK"
+ )
+
else:
# Transform settings depending on tool header visibility
VIEW3D_HT_header.draw_xform_template(layout, context)
- layout.separator_spacer()
+ layout.separator_spacer()
# Viewport Settings
layout.popover(
@@ -3012,6 +3018,7 @@ class VIEW3D_MT_brush_paint_modes(Menu):
layout.prop(brush, "use_paint_vertex", text="Vertex Paint")
layout.prop(brush, "use_paint_weight", text="Weight Paint")
layout.prop(brush, "use_paint_image", text="Texture Paint")
+ layout.prop(brush, "use_paint_sculpt_curves", text="Sculpt Curves")
class VIEW3D_MT_paint_vertex(Menu):
@@ -3356,8 +3363,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 +5524,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):
@@ -7682,6 +7687,77 @@ class VIEW3D_PT_paint_weight_context_menu(Panel):
)
+class VIEW3D_PT_sculpt_automasking(Panel):
+ bl_space_type = 'VIEW_3D'
+ bl_region_type = 'HEADER'
+ bl_label = "Auto-Masking"
+ bl_ui_units_x = 10
+
+ def draw(self, context):
+ layout = self.layout
+
+ tool_settings = context.tool_settings
+ sculpt = tool_settings.sculpt
+ layout.label(text="Auto-Masking")
+
+ col = layout.column(align=True)
+ col.prop(sculpt, "use_automasking_topology", text="Topology")
+ col.prop(sculpt, "use_automasking_face_sets", text="Face Sets")
+
+ col.separator()
+
+ col = layout.column(align=True)
+ col.prop(sculpt, "use_automasking_boundary_edges", text="Mesh Boundary")
+ col.prop(sculpt, "use_automasking_boundary_face_sets", text="Face Sets Boundary")
+
+ if sculpt.use_automasking_boundary_edges or sculpt.use_automasking_boundary_face_sets:
+ col.prop(sculpt.brush, "automasking_boundary_edges_propagation_steps")
+
+ col.separator()
+
+ col = layout.column(align=True)
+ row = col.row()
+ row.prop(sculpt, "use_automasking_cavity", text="Cavity")
+
+ is_cavity_active = sculpt.use_automasking_cavity or sculpt.use_automasking_cavity_inverted
+
+ if is_cavity_active:
+ row.operator("sculpt.mask_from_cavity", text="Create Mask")
+
+ col.prop(sculpt, "use_automasking_cavity_inverted", text="Cavity (inverted)")
+
+ if is_cavity_active:
+ col = layout.column(align=True)
+ col.prop(sculpt, "automasking_cavity_factor", text="Factor")
+ col.prop(sculpt, "automasking_cavity_blur_steps", text="Blur")
+
+ col = layout.column()
+ col.prop(sculpt, "use_automasking_custom_cavity_curve", text="Custom Curve")
+
+ if sculpt.use_automasking_custom_cavity_curve:
+ col.template_curve_mapping(sculpt, "automasking_cavity_curve")
+
+ col.separator()
+
+ col = layout.column(align=True)
+ col.prop(sculpt, "use_automasking_view_normal", text="View Normal")
+
+ if sculpt.use_automasking_view_normal:
+ col.prop(sculpt, "use_automasking_view_occlusion", text="Occlusion")
+ subcol = col.column(align=True)
+ subcol.active = not sculpt.use_automasking_view_occlusion
+ subcol.prop(sculpt, "automasking_view_normal_limit", text="Limit")
+ subcol.prop(sculpt, "automasking_view_normal_falloff", text="Falloff")
+
+ col = layout.column()
+ col.prop(sculpt, "use_automasking_start_normal", text="Area Normal")
+
+ if sculpt.use_automasking_start_normal:
+ col = layout.column(align=True)
+ col.prop(sculpt, "automasking_start_normal_limit", text="Limit")
+ col.prop(sculpt, "automasking_start_normal_falloff", text="Falloff")
+
+
class VIEW3D_PT_sculpt_context_menu(Panel):
# Only for popover, these are dummy values.
bl_space_type = 'VIEW_3D'
@@ -8072,6 +8148,7 @@ classes = (
VIEW3D_PT_gpencil_sculpt_context_menu,
VIEW3D_PT_gpencil_weight_context_menu,
VIEW3D_PT_gpencil_draw_context_menu,
+ VIEW3D_PT_sculpt_automasking,
VIEW3D_PT_sculpt_context_menu,
TOPBAR_PT_gpencil_materials,
TOPBAR_PT_gpencil_vertexcolor,
diff --git a/release/scripts/startup/bl_ui/space_view3d_toolbar.py b/release/scripts/startup/bl_ui/space_view3d_toolbar.py
index 3357676bf2f..fec156580cf 100644
--- a/release/scripts/startup/bl_ui/space_view3d_toolbar.py
+++ b/release/scripts/startup/bl_ui/space_view3d_toolbar.py
@@ -52,6 +52,8 @@ class VIEW3D_MT_brush_context_menu(Menu):
elif context.sculpt_object:
layout.prop_menu_enum(brush, "sculpt_tool")
layout.operator("brush.reset")
+ elif context.tool_settings.curves_sculpt:
+ layout.prop_menu_enum(brush, "curves_sculpt_tool")
class VIEW3D_MT_brush_gpencil_context_menu(Menu):
@@ -81,22 +83,6 @@ class VIEW3D_MT_brush_gpencil_context_menu(Menu):
layout.operator("gpencil.brush_reset_all")
-class VIEW3D_MT_brush_context_menu_paint_modes(Menu):
- bl_label = "Enabled Modes"
-
- def draw(self, context):
- layout = self.layout
-
- settings = UnifiedPaintPanel.paint_settings(context)
- brush = settings.brush
-
- layout.prop(brush, "use_paint_sculpt", text="Sculpt")
- layout.prop(brush, "use_paint_uv_sculpt", text="UV Sculpt")
- layout.prop(brush, "use_paint_vertex", text="Vertex Paint")
- layout.prop(brush, "use_paint_weight", text="Weight Paint")
- layout.prop(brush, "use_paint_image", text="Texture Paint")
-
-
class View3DPanel:
bl_space_type = 'VIEW_3D'
bl_region_type = 'UI'
@@ -964,52 +950,6 @@ class VIEW3D_PT_sculpt_options(Panel, View3DPaintPanel):
col.prop(sculpt, "use_sculpt_delay_updates")
col.prop(sculpt, "use_deform_only")
- col.separator()
-
- col = layout.column(heading="Auto-Masking", align=True)
-
- col.prop(sculpt, "use_automasking_topology", text="Topology")
- col.prop(sculpt, "use_automasking_face_sets", text="Face Sets")
- col.prop(sculpt, "use_automasking_boundary_edges", text="Mesh Boundary")
- col.prop(sculpt, "use_automasking_boundary_face_sets", text="Face Sets Boundary")
- col.prop(sculpt, "use_automasking_cavity", text="Cavity")
- col.prop(sculpt, "use_automasking_cavity_inverted", text="Cavity (Inverted)")
- col.prop(sculpt, "use_automasking_start_normal", text="Area Normal")
- col.prop(sculpt, "use_automasking_view_normal", text="View Normal")
-
- if sculpt.use_automasking_start_normal:
- col.separator()
-
- col.prop(sculpt, "automasking_start_normal_limit")
- col.prop(sculpt, "automasking_start_normal_falloff")
-
- if sculpt.use_automasking_view_normal:
- col.separator()
-
- col.prop(sculpt, "use_automasking_view_occlusion", text="Occlusion")
- col.prop(sculpt, "automasking_view_normal_limit")
- col.prop(sculpt, "automasking_view_normal_falloff")
-
- col.separator()
- col.prop(sculpt.brush, "automasking_boundary_edges_propagation_steps")
-
- if sculpt.use_automasking_cavity or sculpt.use_automasking_cavity_inverted:
- col.separator()
-
- col2 = col.column()
- props = col2.operator("sculpt.mask_from_cavity", text="Mask From Cavity")
- props.use_automask_settings = True
-
- col2 = col.column()
-
- col2.prop(sculpt, "automasking_cavity_factor", text="Cavity Factor")
- col2.prop(sculpt, "automasking_cavity_blur_steps", text="Cavity Blur")
-
- col2.prop(sculpt, "use_automasking_custom_cavity_curve", text="Use Curve")
-
- if sculpt.use_automasking_custom_cavity_curve:
- col2.template_curve_mapping(sculpt, "automasking_cavity_curve")
-
class VIEW3D_PT_sculpt_options_gravity(Panel, View3DPaintPanel):
bl_context = ".sculpt_mode" # dot on purpose (access from topbar)
@@ -2419,7 +2359,6 @@ class VIEW3D_PT_gpencil_brush_presets(Panel, PresetPanel):
classes = (
VIEW3D_MT_brush_context_menu,
VIEW3D_MT_brush_gpencil_context_menu,
- VIEW3D_MT_brush_context_menu_paint_modes,
VIEW3D_PT_tools_object_options,
VIEW3D_PT_tools_object_options_transform,
VIEW3D_PT_tools_meshedit_options,
diff --git a/source/blender/blenfont/intern/blf.c b/source/blender/blenfont/intern/blf.c
index a673f4a1bc7..d4f5be617fd 100644
--- a/source/blender/blenfont/intern/blf.c
+++ b/source/blender/blenfont/intern/blf.c
@@ -162,6 +162,14 @@ int BLF_load_unique(const char *name)
}
FontBLF *font = blf_font_new(name, filepath);
+
+ /* XXX: Temporarily disable kerning in our main font. Kerning had been accidentally removed from
+ * our font in 3.1. In 3.4 we disable kerning here in the new version to keep spacing the same
+ * (T101506). Enable again later with change of font, placement, or rendering - Harley. */
+ if (font && BLI_str_endswith(filepath, BLF_DEFAULT_PROPORTIONAL_FONT)) {
+ font->face_flags &= ~FT_FACE_FLAG_KERNING;
+ }
+
MEM_freeN(filepath);
if (!font) {
diff --git a/source/blender/blenfont/intern/blf_dir.c b/source/blender/blenfont/intern/blf_dir.c
index 8534a8c583f..395d981cb0b 100644
--- a/source/blender/blenfont/intern/blf_dir.c
+++ b/source/blender/blenfont/intern/blf_dir.c
@@ -115,7 +115,7 @@ char *blf_dir_search(const char *file)
char *s = NULL;
for (dir = global_font_dir.first; dir; dir = dir->next) {
- BLI_join_dirfile(full_path, sizeof(full_path), dir->path, file);
+ BLI_path_join(full_path, sizeof(full_path), dir->path, file);
if (BLI_exists(full_path)) {
s = BLI_strdup(full_path);
break;
diff --git a/source/blender/blenfont/intern/blf_font_default.c b/source/blender/blenfont/intern/blf_font_default.c
index d35692f6eae..63b1cf34db5 100644
--- a/source/blender/blenfont/intern/blf_font_default.c
+++ b/source/blender/blenfont/intern/blf_font_default.c
@@ -32,7 +32,7 @@ static int blf_load_font_default(const char *filename, const bool unique)
}
char filepath[FILE_MAX];
- BLI_join_dirfile(filepath, sizeof(filepath), dir, filename);
+ BLI_path_join(filepath, sizeof(filepath), dir, filename);
return (unique) ? BLF_load_unique(filepath) : BLF_load(filepath);
}
diff --git a/source/blender/blenkernel/BKE_attribute.hh b/source/blender/blenkernel/BKE_attribute.hh
index 7b13b8a2b09..a4f9d73c31e 100644
--- a/source/blender/blenkernel/BKE_attribute.hh
+++ b/source/blender/blenkernel/BKE_attribute.hh
@@ -793,7 +793,9 @@ class CustomDataAttributes {
~CustomDataAttributes();
CustomDataAttributes(const CustomDataAttributes &other);
CustomDataAttributes(CustomDataAttributes &&other);
+
CustomDataAttributes &operator=(const CustomDataAttributes &other);
+ CustomDataAttributes &operator=(CustomDataAttributes &&other);
void reallocate(int size);
diff --git a/source/blender/blenkernel/BKE_blender_version.h b/source/blender/blenkernel/BKE_blender_version.h
index 3c8f7d758b6..806fff2099e 100644
--- a/source/blender/blenkernel/BKE_blender_version.h
+++ b/source/blender/blenkernel/BKE_blender_version.h
@@ -25,7 +25,7 @@ extern "C" {
/* Blender file format version. */
#define BLENDER_FILE_VERSION BLENDER_VERSION
-#define BLENDER_FILE_SUBVERSION 3
+#define BLENDER_FILE_SUBVERSION 5
/* Minimum Blender version that supports reading file written with the current
* version. Older Blender versions will test this and show a warning if the file
diff --git a/source/blender/blenkernel/BKE_brush.h b/source/blender/blenkernel/BKE_brush.h
index 4d728002c87..a763b3d12c2 100644
--- a/source/blender/blenkernel/BKE_brush.h
+++ b/source/blender/blenkernel/BKE_brush.h
@@ -18,7 +18,9 @@ extern "C" {
struct Brush;
struct ImBuf;
struct ImagePool;
+struct Object;
struct Main;
+struct MTex;
struct Scene;
struct ToolSettings;
struct UnifiedPaintSettings;
@@ -109,6 +111,7 @@ float BKE_brush_curve_strength(const struct Brush *br, float p, float len);
*/
float BKE_brush_sample_tex_3d(const struct Scene *scene,
const struct Brush *br,
+ const struct MTex *mtex,
const float point[3],
float rgba[4],
int thread,
@@ -120,6 +123,24 @@ float BKE_brush_sample_masktex(const struct Scene *scene,
struct ImagePool *pool);
/**
+ * Get the mask texture for this given object mode.
+ *
+ * This is preferred above using mtex/mask_mtex attributes directly as due to legacy these
+ * attributes got switched in sculpt mode.
+ */
+const struct MTex *BKE_brush_mask_texture_get(const struct Brush *brush,
+ const eObjectMode object_mode);
+
+/**
+ * Get the color texture for this given object mode.
+ *
+ * This is preferred above using mtex/mask_mtex attributes directly as due to legacy these
+ * attributes got switched in sculpt mode.
+ */
+const struct MTex *BKE_brush_color_texture_get(const struct Brush *brush,
+ const eObjectMode object_mode);
+
+/**
* Radial control.
*/
struct ImBuf *BKE_brush_gen_radial_control_imbuf(struct Brush *br,
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_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_geometry_fields.hh b/source/blender/blenkernel/BKE_geometry_fields.hh
index 988e0017f04..2eef67dba98 100644
--- a/source/blender/blenkernel/BKE_geometry_fields.hh
+++ b/source/blender/blenkernel/BKE_geometry_fields.hh
@@ -75,14 +75,14 @@ class PointCloudFieldContext : public fn::FieldContext {
class InstancesFieldContext : public fn::FieldContext {
private:
- const InstancesComponent &instances_;
+ const Instances &instances_;
public:
- InstancesFieldContext(const InstancesComponent &instances) : instances_(instances)
+ InstancesFieldContext(const Instances &instances) : instances_(instances)
{
}
- const InstancesComponent &instances() const
+ const Instances &instances() const
{
return instances_;
}
@@ -128,13 +128,13 @@ class GeometryFieldContext : public fn::FieldContext {
const Mesh *mesh() const;
const CurvesGeometry *curves() const;
const PointCloud *pointcloud() const;
- const InstancesComponent *instances() const;
+ const Instances *instances() const;
private:
GeometryFieldContext(const Mesh &mesh, eAttrDomain domain);
GeometryFieldContext(const CurvesGeometry &curves, eAttrDomain domain);
GeometryFieldContext(const PointCloud &points);
- GeometryFieldContext(const InstancesComponent &instances);
+ GeometryFieldContext(const Instances &instances);
};
class GeometryFieldInput : public fn::FieldInput {
@@ -187,8 +187,7 @@ class InstancesFieldInput : public fn::FieldInput {
GVArray get_varray_for_context(const fn::FieldContext &context,
IndexMask mask,
ResourceScope &scope) const override;
- virtual GVArray get_varray_for_context(const InstancesComponent &instances,
- IndexMask mask) const = 0;
+ virtual GVArray get_varray_for_context(const Instances &instances, IndexMask mask) const = 0;
};
class AttributeFieldInput : public GeometryFieldInput {
diff --git a/source/blender/blenkernel/BKE_geometry_set.hh b/source/blender/blenkernel/BKE_geometry_set.hh
index 2ef9556afc7..b488806c8e7 100644
--- a/source/blender/blenkernel/BKE_geometry_set.hh
+++ b/source/blender/blenkernel/BKE_geometry_set.hh
@@ -43,6 +43,7 @@ enum class GeometryOwnershipType {
namespace blender::bke {
class ComponentAttributeProviders;
class CurvesEditHints;
+class Instances;
} // namespace blender::bke
class GeometryComponent;
@@ -246,6 +247,12 @@ struct GeometrySet {
*/
static GeometrySet create_with_curves(
Curves *curves, GeometryOwnershipType ownership = GeometryOwnershipType::Owned);
+ /**
+ * Create a new geometry set that only contains the given instances.
+ */
+ static GeometrySet create_with_instances(
+ blender::bke::Instances *instances,
+ GeometryOwnershipType ownership = GeometryOwnershipType::Owned);
/* Utility methods for access. */
/**
@@ -294,6 +301,10 @@ struct GeometrySet {
*/
const Curves *get_curves_for_read() const;
/**
+ * Returns read-only instances or null.
+ */
+ const blender::bke::Instances *get_instances_for_read() const;
+ /**
* Returns read-only curve edit hints or null.
*/
const blender::bke::CurvesEditHints *get_curve_edit_hints_for_read() const;
@@ -315,6 +326,10 @@ struct GeometrySet {
*/
Curves *get_curves_for_write();
/**
+ * Returns mutable instances or null. No ownership is transferred.
+ */
+ blender::bke::Instances *get_instances_for_write();
+ /**
* Returns mutable curve edit hints or null.
*/
blender::bke::CurvesEditHints *get_curve_edit_hints_for_write();
@@ -339,6 +354,11 @@ struct GeometrySet {
*/
void replace_curves(Curves *curves,
GeometryOwnershipType ownership = GeometryOwnershipType::Owned);
+ /**
+ * Clear the existing instances and replace them with the given one.
+ */
+ void replace_instances(blender::bke::Instances *instances,
+ GeometryOwnershipType ownership = GeometryOwnershipType::Owned);
private:
/**
@@ -515,244 +535,35 @@ class CurveComponent : public GeometryComponent {
};
/**
- * Holds a reference to conceptually unique geometry or a pointer to object/collection data
- * that is instanced with a transform in #InstancesComponent.
- */
-class InstanceReference {
- public:
- enum class Type {
- /**
- * An empty instance. This allows an `InstanceReference` to be default constructed without
- * being in an invalid state. There might also be other use cases that we haven't explored much
- * yet (such as changing the instance later on, and "disabling" some instances).
- */
- None,
- Object,
- Collection,
- GeometrySet,
- };
-
- private:
- Type type_ = Type::None;
- /** Depending on the type this is either null, an Object or Collection pointer. */
- void *data_ = nullptr;
- std::unique_ptr<GeometrySet> geometry_set_;
-
- public:
- InstanceReference() = default;
-
- InstanceReference(Object &object) : type_(Type::Object), data_(&object)
- {
- }
-
- InstanceReference(Collection &collection) : type_(Type::Collection), data_(&collection)
- {
- }
-
- InstanceReference(GeometrySet geometry_set)
- : type_(Type::GeometrySet),
- geometry_set_(std::make_unique<GeometrySet>(std::move(geometry_set)))
- {
- }
-
- InstanceReference(const InstanceReference &other) : type_(other.type_), data_(other.data_)
- {
- if (other.geometry_set_) {
- geometry_set_ = std::make_unique<GeometrySet>(*other.geometry_set_);
- }
- }
-
- InstanceReference(InstanceReference &&other)
- : type_(other.type_), data_(other.data_), geometry_set_(std::move(other.geometry_set_))
- {
- other.type_ = Type::None;
- other.data_ = nullptr;
- }
-
- InstanceReference &operator=(const InstanceReference &other)
- {
- if (this == &other) {
- return *this;
- }
- this->~InstanceReference();
- new (this) InstanceReference(other);
- return *this;
- }
-
- InstanceReference &operator=(InstanceReference &&other)
- {
- if (this == &other) {
- return *this;
- }
- this->~InstanceReference();
- new (this) InstanceReference(std::move(other));
- return *this;
- }
-
- Type type() const
- {
- return type_;
- }
-
- Object &object() const
- {
- BLI_assert(type_ == Type::Object);
- return *(Object *)data_;
- }
-
- Collection &collection() const
- {
- BLI_assert(type_ == Type::Collection);
- return *(Collection *)data_;
- }
-
- const GeometrySet &geometry_set() const
- {
- BLI_assert(type_ == Type::GeometrySet);
- return *geometry_set_;
- }
-
- bool owns_direct_data() const
- {
- if (type_ != Type::GeometrySet) {
- /* The object and collection instances are not direct data. */
- return true;
- }
- return geometry_set_->owns_direct_data();
- }
-
- void ensure_owns_direct_data()
- {
- if (type_ != Type::GeometrySet) {
- return;
- }
- geometry_set_->ensure_owns_direct_data();
- }
-
- uint64_t hash() const
- {
- return blender::get_default_hash_2(data_, geometry_set_.get());
- }
-
- friend bool operator==(const InstanceReference &a, const InstanceReference &b)
- {
- return a.data_ == b.data_ && a.geometry_set_.get() == b.geometry_set_.get();
- }
-};
-
-/**
- * A geometry component that stores instances. The instance data can be any type described by
- * #InstanceReference. Geometry instances can even contain instances themselves, for nested
- * instancing. Each instance has an index into an array of unique instance data, and a transform.
- * The component can also store generic attributes for each instance.
- *
- * The component works differently from other geometry components in that it stores
- * data about instancing directly, rather than owning a pointer to a separate data structure.
- *
- * This component is not responsible for handling the interface to a render engine, or other
- * areas that work with all visible geometry, that is handled by the dependency graph iterator
- * (see `DEG_depsgraph_query.h`).
+ * A geometry component that stores #Instances.
*/
class InstancesComponent : public GeometryComponent {
private:
- /**
- * Indexed set containing information about the data that is instanced.
- * Actual instances store an index ("handle") into this set.
- */
- blender::VectorSet<InstanceReference> references_;
-
- /** Index into `references_`. Determines what data is instanced. */
- blender::Vector<int> instance_reference_handles_;
- /** Transformation of the instances. */
- blender::Vector<blender::float4x4> instance_transforms_;
-
- /* These almost unique ids are generated based on the `id` attribute, which might not contain
- * unique ids at all. They are *almost* unique, because under certain very unlikely
- * circumstances, they are not unique. Code using these ids should not crash when they are not
- * unique but can generally expect them to be unique. */
- mutable std::mutex almost_unique_ids_mutex_;
- mutable blender::Array<int> almost_unique_ids_;
-
- blender::bke::CustomDataAttributes attributes_;
+ blender::bke::Instances *instances_ = nullptr;
+ GeometryOwnershipType ownership_ = GeometryOwnershipType::Owned;
public:
InstancesComponent();
- ~InstancesComponent() = default;
+ ~InstancesComponent();
GeometryComponent *copy() const override;
void clear();
- void reserve(int min_capacity);
- /**
- * Resize the transform, handles, and attributes to the specified capacity.
- *
- * \note This function should be used carefully, only when it's guaranteed
- * that the data will be filled.
- */
- void resize(int capacity);
+ const blender::bke::Instances *get_for_read() const;
+ blender::bke::Instances *get_for_write();
- /**
- * Returns a handle for the given reference.
- * If the reference exists already, the handle of the existing reference is returned.
- * Otherwise a new handle is added.
- */
- int add_reference(const InstanceReference &reference);
- /**
- * Add a reference to the instance reference with an index specified by the #instance_handle
- * argument. For adding many instances, using #resize and accessing the transform array directly
- * is preferred.
- */
- void add_instance(int instance_handle, const blender::float4x4 &transform);
-
- blender::Span<InstanceReference> references() const;
- void remove_unused_references();
-
- /**
- * If references have a collection or object type, convert them into geometry instances
- * recursively. After that, the geometry sets can be edited. There may still be instances of
- * other types of they can't be converted to geometry sets.
- */
- void ensure_geometry_instances();
- /**
- * With write access to the instances component, the data in the instanced geometry sets can be
- * changed. This is a function on the component rather than each reference to ensure `const`
- * correctness for that reason.
- */
- GeometrySet &geometry_set_from_reference(int reference_index);
-
- blender::Span<int> instance_reference_handles() const;
- blender::MutableSpan<int> instance_reference_handles();
- blender::MutableSpan<blender::float4x4> instance_transforms();
- blender::Span<blender::float4x4> instance_transforms() const;
-
- int instances_num() const;
- int references_num() const;
-
- /**
- * Remove the indices that are not contained in the mask input, and remove unused instance
- * references afterwards.
- */
- void remove_instances(const blender::IndexMask mask);
-
- blender::Span<int> almost_unique_ids() const;
-
- blender::bke::CustomDataAttributes &instance_attributes();
- const blender::bke::CustomDataAttributes &instance_attributes() const;
-
- std::optional<blender::bke::AttributeAccessor> attributes() const final;
- std::optional<blender::bke::MutableAttributeAccessor> attributes_for_write() final;
-
- void foreach_referenced_geometry(
- blender::FunctionRef<void(const GeometrySet &geometry_set)> callback) const;
+ void replace(blender::bke::Instances *instances,
+ GeometryOwnershipType ownership = GeometryOwnershipType::Owned);
bool is_empty() const final;
bool owns_direct_data() const override;
void ensure_owns_direct_data() override;
- static constexpr inline GeometryComponentType static_type = GEO_COMPONENT_TYPE_INSTANCES;
+ std::optional<blender::bke::AttributeAccessor> attributes() const final;
+ std::optional<blender::bke::MutableAttributeAccessor> attributes_for_write() final;
- private:
+ static constexpr inline GeometryComponentType static_type = GEO_COMPONENT_TYPE_INSTANCES;
};
/**
diff --git a/source/blender/blenkernel/BKE_instances.hh b/source/blender/blenkernel/BKE_instances.hh
new file mode 100644
index 00000000000..f17ebba0dfa
--- /dev/null
+++ b/source/blender/blenkernel/BKE_instances.hh
@@ -0,0 +1,270 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+
+#pragma once
+
+/** \file
+ * \ingroup bke
+ *
+ * #Instances is a container for geometry instances. It fulfills some key requirements:
+ * - Support nested instances.
+ * - Support instance attributes.
+ * - Support referencing different kinds of instances (objects, collections, geometry sets).
+ * - Support efficiently iterating over the instanced geometries, i.e. without have to iterate over
+ * all instances.
+ *
+ * #Instances has an ordered set of #InstanceReference. An #InstanceReference contains information
+ * about a particular instanced geometry. Each #InstanceReference has a handle (integer index)
+ * which is then stored per instance. Many instances can use the same #InstanceReference.
+ */
+
+#include <mutex>
+
+#include "BLI_float4x4.hh"
+#include "BLI_vector.hh"
+#include "BLI_vector_set.hh"
+
+#include "BKE_attribute.hh"
+
+struct GeometrySet;
+struct Object;
+struct Collection;
+
+namespace blender::bke {
+
+/**
+ * Holds a reference to conceptually unique geometry or a pointer to object/collection data
+ * that is instanced with a transform in #Instances.
+ */
+class InstanceReference {
+ public:
+ enum class Type {
+ /**
+ * An empty instance. This allows an `InstanceReference` to be default constructed without
+ * being in an invalid state. There might also be other use cases that we haven't explored
+ * much yet (such as changing the instance later on, and "disabling" some instances).
+ */
+ None,
+ Object,
+ Collection,
+ GeometrySet,
+ };
+
+ private:
+ Type type_ = Type::None;
+ /** Depending on the type this is either null, an Object or Collection pointer. */
+ void *data_ = nullptr;
+ std::unique_ptr<GeometrySet> geometry_set_;
+
+ public:
+ InstanceReference() = default;
+ InstanceReference(Object &object);
+ InstanceReference(Collection &collection);
+ InstanceReference(GeometrySet geometry_set);
+
+ InstanceReference(const InstanceReference &other);
+ InstanceReference(InstanceReference &&other);
+
+ InstanceReference &operator=(const InstanceReference &other);
+ InstanceReference &operator=(InstanceReference &&other);
+
+ Type type() const;
+ Object &object() const;
+ Collection &collection() const;
+ const GeometrySet &geometry_set() const;
+
+ bool owns_direct_data() const;
+ void ensure_owns_direct_data();
+
+ uint64_t hash() const;
+ friend bool operator==(const InstanceReference &a, const InstanceReference &b);
+};
+
+class Instances {
+ private:
+ /**
+ * Indexed set containing information about the data that is instanced.
+ * Actual instances store an index ("handle") into this set.
+ */
+ blender::VectorSet<InstanceReference> references_;
+
+ /** Indices into `references_`. Determines what data is instanced. */
+ blender::Vector<int> reference_handles_;
+ /** Transformation of the instances. */
+ blender::Vector<blender::float4x4> transforms_;
+
+ /* These almost unique ids are generated based on the `id` attribute, which might not contain
+ * unique ids at all. They are *almost* unique, because under certain very unlikely
+ * circumstances, they are not unique. Code using these ids should not crash when they are not
+ * unique but can generally expect them to be unique. */
+ mutable std::mutex almost_unique_ids_mutex_;
+ mutable blender::Array<int> almost_unique_ids_;
+
+ CustomDataAttributes attributes_;
+
+ public:
+ Instances() = default;
+ Instances(const Instances &other);
+
+ void reserve(int min_capacity);
+ /**
+ * Resize the transform, handles, and attributes to the specified capacity.
+ *
+ * \note This function should be used carefully, only when it's guaranteed
+ * that the data will be filled.
+ */
+ void resize(int capacity);
+
+ /**
+ * Returns a handle for the given reference.
+ * If the reference exists already, the handle of the existing reference is returned.
+ * Otherwise a new handle is added.
+ */
+ int add_reference(const InstanceReference &reference);
+ /**
+ * Add a reference to the instance reference with an index specified by the #instance_handle
+ * argument. For adding many instances, using #resize and accessing the transform array
+ * directly is preferred.
+ */
+ void add_instance(int instance_handle, const blender::float4x4 &transform);
+
+ blender::Span<InstanceReference> references() const;
+ void remove_unused_references();
+
+ /**
+ * If references have a collection or object type, convert them into geometry instances
+ * recursively. After that, the geometry sets can be edited. There may still be instances of
+ * other types of they can't be converted to geometry sets.
+ */
+ void ensure_geometry_instances();
+ /**
+ * With write access to the instances component, the data in the instanced geometry sets can be
+ * changed. This is a function on the component rather than each reference to ensure `const`
+ * correctness for that reason.
+ */
+ GeometrySet &geometry_set_from_reference(int reference_index);
+
+ blender::Span<int> reference_handles() const;
+ blender::MutableSpan<int> reference_handles();
+ blender::MutableSpan<blender::float4x4> transforms();
+ blender::Span<blender::float4x4> transforms() const;
+
+ int instances_num() const;
+ int references_num() const;
+
+ /**
+ * Remove the indices that are not contained in the mask input, and remove unused instance
+ * references afterwards.
+ */
+ void remove(const blender::IndexMask mask);
+ /**
+ * Get an id for every instance. These can be used for e.g. motion blur.
+ */
+ blender::Span<int> almost_unique_ids() const;
+
+ blender::bke::AttributeAccessor attributes() const;
+ blender::bke::MutableAttributeAccessor attributes_for_write();
+
+ CustomDataAttributes &custom_data_attributes();
+ const CustomDataAttributes &custom_data_attributes() const;
+
+ void foreach_referenced_geometry(
+ blender::FunctionRef<void(const GeometrySet &geometry_set)> callback) const;
+
+ bool owns_direct_data() const;
+ void ensure_owns_direct_data();
+};
+
+/* -------------------------------------------------------------------- */
+/** \name #InstanceReference Inline Methods
+ * \{ */
+
+inline InstanceReference::InstanceReference(Object &object) : type_(Type::Object), data_(&object)
+{
+}
+
+inline InstanceReference::InstanceReference(Collection &collection)
+ : type_(Type::Collection), data_(&collection)
+{
+}
+
+inline InstanceReference::InstanceReference(const InstanceReference &other)
+ : type_(other.type_), data_(other.data_)
+{
+ if (other.geometry_set_) {
+ geometry_set_ = std::make_unique<GeometrySet>(*other.geometry_set_);
+ }
+}
+
+inline InstanceReference::InstanceReference(InstanceReference &&other)
+ : type_(other.type_), data_(other.data_), geometry_set_(std::move(other.geometry_set_))
+{
+ other.type_ = Type::None;
+ other.data_ = nullptr;
+}
+
+inline InstanceReference &InstanceReference::operator=(const InstanceReference &other)
+{
+ if (this == &other) {
+ return *this;
+ }
+ this->~InstanceReference();
+ new (this) InstanceReference(other);
+ return *this;
+}
+
+inline InstanceReference &InstanceReference::operator=(InstanceReference &&other)
+{
+ if (this == &other) {
+ return *this;
+ }
+ this->~InstanceReference();
+ new (this) InstanceReference(std::move(other));
+ return *this;
+}
+
+inline InstanceReference::Type InstanceReference::type() const
+{
+ return type_;
+}
+
+inline Object &InstanceReference::object() const
+{
+ BLI_assert(type_ == Type::Object);
+ return *(Object *)data_;
+}
+
+inline Collection &InstanceReference::collection() const
+{
+ BLI_assert(type_ == Type::Collection);
+ return *(Collection *)data_;
+}
+
+inline const GeometrySet &InstanceReference::geometry_set() const
+{
+ BLI_assert(type_ == Type::GeometrySet);
+ return *geometry_set_;
+}
+
+inline CustomDataAttributes &Instances::custom_data_attributes()
+{
+ return attributes_;
+}
+
+inline const CustomDataAttributes &Instances::custom_data_attributes() const
+{
+ return attributes_;
+}
+
+inline uint64_t InstanceReference::hash() const
+{
+ return blender::get_default_hash_2(data_, geometry_set_.get());
+}
+
+inline bool operator==(const InstanceReference &a, const InstanceReference &b)
+{
+ return a.data_ == b.data_ && a.geometry_set_.get() == b.geometry_set_.get();
+}
+
+/** \} */
+
+} // namespace blender::bke
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..80f61086052 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 Shrink-wrap 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_node.h b/source/blender/blenkernel/BKE_node.h
index e2ed024c6f6..9ceb5cf1d4c 100644
--- a/source/blender/blenkernel/BKE_node.h
+++ b/source/blender/blenkernel/BKE_node.h
@@ -792,6 +792,12 @@ void nodeChainIterBackwards(const bNodeTree *ntree,
*/
void nodeParentsIter(bNode *node, bool (*callback)(bNode *, void *), void *userdata);
+/**
+ * A dangling reroute node is a reroute node that does *not* have a "data source", i.e. no
+ * non-reroute node is connected to its input.
+ */
+bool nodeIsDanglingReroute(const struct bNodeTree *ntree, const struct bNode *node);
+
struct bNodeLink *nodeFindLink(struct bNodeTree *ntree,
const struct bNodeSocket *from,
const struct bNodeSocket *to);
diff --git a/source/blender/blenkernel/BKE_paint.h b/source/blender/blenkernel/BKE_paint.h
index 5312292d431..437a22e4782 100644
--- a/source/blender/blenkernel/BKE_paint.h
+++ b/source/blender/blenkernel/BKE_paint.h
@@ -860,7 +860,19 @@ int *BKE_sculpt_face_sets_ensure(struct Mesh *mesh);
* (see #SCULPT_visibility_sync_all_from_faces).
*/
bool *BKE_sculpt_hide_poly_ensure(struct Mesh *mesh);
-int BKE_sculpt_mask_layers_ensure(struct Object *ob, struct MultiresModifierData *mmd);
+
+/**
+ * Ensures a mask layer exists. If depsgraph and bmain are non-null,
+ * a mask doesn't exist and the object has a multi-resolution modifier
+ * then the scene depsgraph will be evaluated to update the runtime
+ * subdivision data.
+ *
+ * \note always call *before* #BKE_sculpt_update_object_for_edit.
+ */
+int BKE_sculpt_mask_layers_ensure(struct Depsgraph *depsgraph,
+ struct Main *bmain,
+ struct Object *ob,
+ struct MultiresModifierData *mmd);
void BKE_sculpt_toolsettings_data_ensure(struct Scene *scene);
struct PBVH *BKE_sculpt_object_pbvh_ensure(struct Depsgraph *depsgraph, struct Object *ob);
diff --git a/source/blender/blenkernel/BKE_pbvh.h b/source/blender/blenkernel/BKE_pbvh.h
index 467a7c7f306..b375d69b61c 100644
--- a/source/blender/blenkernel/BKE_pbvh.h
+++ b/source/blender/blenkernel/BKE_pbvh.h
@@ -125,6 +125,7 @@ typedef enum {
PBVH_UpdateTopology = 1 << 13,
PBVH_UpdateColor = 1 << 14,
PBVH_RebuildPixels = 1 << 15,
+ PBVH_TopologyUpdated = 1 << 16, /* Used internally by pbvh_bmesh.c */
} PBVHNodeFlags;
@@ -266,7 +267,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.
*/
@@ -485,7 +487,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. */
@@ -500,7 +505,8 @@ void BKE_pbvh_grids_update(PBVH *pbvh,
struct CCGElem **grids,
void **gridfaces,
struct DMFlagMat *flagmats,
- unsigned int **grid_hidden);
+ unsigned int **grid_hidden,
+ struct CCGKey *key);
void BKE_pbvh_subdiv_cgg_set(PBVH *pbvh, struct SubdivCCG *subdiv_ccg);
void BKE_pbvh_face_sets_set(PBVH *pbvh, int *face_sets);
@@ -664,7 +670,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/BKE_writeffmpeg.h b/source/blender/blenkernel/BKE_writeffmpeg.h
index 736f7548bb4..cfe246eb470 100644
--- a/source/blender/blenkernel/BKE_writeffmpeg.h
+++ b/source/blender/blenkernel/BKE_writeffmpeg.h
@@ -27,6 +27,7 @@ enum {
FFMPEG_OGG = 10,
FFMPEG_INVALID = 11,
FFMPEG_WEBM = 12,
+ FFMPEG_AV1 = 13,
};
enum {
@@ -38,6 +39,7 @@ enum {
FFMPEG_PRESET_H264 = 5,
FFMPEG_PRESET_THEORA = 6,
FFMPEG_PRESET_XVID = 7,
+ FFMPEG_PRESET_AV1 = 8,
};
struct RenderData;
diff --git a/source/blender/blenkernel/CMakeLists.txt b/source/blender/blenkernel/CMakeLists.txt
index 97bdff217d0..7d43fa7e6af 100644
--- a/source/blender/blenkernel/CMakeLists.txt
+++ b/source/blender/blenkernel/CMakeLists.txt
@@ -163,6 +163,7 @@ set(SRC
intern/image_gpu.cc
intern/image_partial_update.cc
intern/image_save.cc
+ intern/instances.cc
intern/ipo.c
intern/kelvinlet.c
intern/key.c
@@ -398,6 +399,7 @@ set(SRC
BKE_image_partial_update.hh
BKE_image_save.h
BKE_image_wrappers.hh
+ BKE_instances.hh
BKE_ipo.h
BKE_kelvinlet.h
BKE_key.h
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/appdir.c b/source/blender/blenkernel/intern/appdir.c
index b2f1e75cd1d..965f48d1e51 100644
--- a/source/blender/blenkernel/intern/appdir.c
+++ b/source/blender/blenkernel/intern/appdir.c
@@ -191,7 +191,7 @@ bool BKE_appdir_folder_documents(char *dir)
char try_documents_path[FILE_MAXDIR];
/* Own attempt at getting a valid Documents path. */
- BLI_path_join(try_documents_path, sizeof(try_documents_path), home_path, N_("Documents"), NULL);
+ BLI_path_join(try_documents_path, sizeof(try_documents_path), home_path, N_("Documents"));
if (!BLI_is_dir(try_documents_path)) {
return false;
}
@@ -214,11 +214,11 @@ bool BKE_appdir_folder_caches(char *r_path, const size_t path_len)
#ifdef WIN32
BLI_path_join(
- r_path, path_len, caches_root_path, "Blender Foundation", "Blender", "Cache", SEP_STR, NULL);
+ r_path, path_len, caches_root_path, "Blender Foundation", "Blender", "Cache", SEP_STR);
#elif defined(__APPLE__)
- BLI_path_join(r_path, path_len, caches_root_path, "Blender", SEP_STR, NULL);
+ BLI_path_join(r_path, path_len, caches_root_path, "Blender", SEP_STR);
#else /* __linux__ */
- BLI_path_join(r_path, path_len, caches_root_path, "blender", SEP_STR, NULL);
+ BLI_path_join(r_path, path_len, caches_root_path, "blender", SEP_STR);
#endif
return true;
@@ -281,7 +281,9 @@ static bool test_path(char *targetpath,
/* Only the last argument should be NULL. */
BLI_assert(!(folder_name == NULL && (subfolder_name != NULL)));
- BLI_path_join(targetpath, targetpath_len, path_base, folder_name, subfolder_name, NULL);
+ const char *path_array[] = {path_base, folder_name, subfolder_name};
+ const int path_array_num = (folder_name ? (subfolder_name ? 3 : 2) : 1);
+ BLI_path_join_array(targetpath, targetpath_len, path_array, path_array_num);
if (check_is_dir == false) {
CLOG_INFO(&LOG, 3, "using without test: '%s'", targetpath);
return true;
@@ -365,7 +367,9 @@ static bool get_path_local_ex(char *targetpath,
STR_OR_FALLBACK(subfolder_name));
if (folder_name) { /* `subfolder_name` may be NULL. */
- BLI_path_join(relfolder, sizeof(relfolder), folder_name, subfolder_name, NULL);
+ const char *path_array[] = {folder_name, subfolder_name};
+ const int path_array_num = subfolder_name ? 2 : 1;
+ BLI_path_join_array(relfolder, sizeof(relfolder), path_array, path_array_num);
}
else {
relfolder[0] = '\0';
@@ -379,8 +383,7 @@ static bool get_path_local_ex(char *targetpath,
* we must move the blender_version dir with contents to Resources.
* Add 4 + 9 for the temporary `/../` path & `Resources`. */
char osx_resourses[FILE_MAX + 4 + 9];
- BLI_path_join(
- osx_resourses, sizeof(osx_resourses), g_app.program_dirname, "..", "Resources", NULL);
+ BLI_path_join(osx_resourses, sizeof(osx_resourses), g_app.program_dirname, "..", "Resources");
/* Remove the '/../' added above. */
BLI_path_normalize(NULL, osx_resourses);
path_base = osx_resourses;
@@ -525,7 +528,9 @@ static bool get_path_system_ex(char *targetpath,
char relfolder[FILE_MAX];
if (folder_name) { /* `subfolder_name` may be NULL. */
- BLI_path_join(relfolder, sizeof(relfolder), folder_name, subfolder_name, NULL);
+ const char *path_array[] = {folder_name, subfolder_name};
+ const int path_array_num = subfolder_name ? 2 : 1;
+ BLI_path_join_array(relfolder, sizeof(relfolder), path_array, path_array_num);
}
else {
relfolder[0] = '\0';
@@ -949,7 +954,7 @@ bool BKE_appdir_program_python_search(char *fullpath,
if (python_bin_dir) {
for (int i = 0; i < ARRAY_SIZE(python_names); i++) {
- BLI_join_dirfile(fullpath, fullpath_len, python_bin_dir, python_names[i]);
+ BLI_path_join(fullpath, fullpath_len, python_bin_dir, python_names[i]);
if (
#ifdef _WIN32
@@ -1018,7 +1023,7 @@ bool BKE_appdir_app_template_id_search(const char *app_template, char *path, siz
{
for (int i = 0; i < ARRAY_SIZE(app_template_directory_id); i++) {
char subdir[FILE_MAX];
- BLI_join_dirfile(subdir, sizeof(subdir), app_template_directory_search[i], app_template);
+ BLI_path_join(subdir, sizeof(subdir), app_template_directory_search[i], app_template);
if (BKE_appdir_folder_id_ex(app_template_directory_id[i], subdir, path, path_len)) {
return true;
}
@@ -1041,8 +1046,7 @@ bool BKE_appdir_app_template_has_userpref(const char *app_template)
}
char userpref_path[FILE_MAX];
- BLI_path_join(
- userpref_path, sizeof(userpref_path), app_template_path, BLENDER_USERPREF_FILE, NULL);
+ BLI_path_join(userpref_path, sizeof(userpref_path), app_template_path, BLENDER_USERPREF_FILE);
return BLI_exists(userpref_path);
}
diff --git a/source/blender/blenkernel/intern/asset_catalog.cc b/source/blender/blenkernel/intern/asset_catalog.cc
index f7b14cc3479..38c712d7e75 100644
--- a/source/blender/blenkernel/intern/asset_catalog.cc
+++ b/source/blender/blenkernel/intern/asset_catalog.cc
@@ -284,10 +284,10 @@ AssetCatalog *AssetCatalogService::create_catalog(const AssetCatalogPath &catalo
static std::string asset_definition_default_file_path_from_dir(StringRef asset_library_root)
{
char file_path[PATH_MAX];
- BLI_join_dirfile(file_path,
- sizeof(file_path),
- asset_library_root.data(),
- AssetCatalogService::DEFAULT_CATALOG_FILENAME.data());
+ BLI_path_join(file_path,
+ sizeof(file_path),
+ asset_library_root.data(),
+ AssetCatalogService::DEFAULT_CATALOG_FILENAME.data());
return file_path;
}
@@ -515,8 +515,7 @@ CatalogFilePath AssetCatalogService::find_suitable_cdf_path_for_writing(
BLI_path_join(asset_lib_cdf_path,
sizeof(asset_lib_cdf_path),
suitable_root_path,
- DEFAULT_CATALOG_FILENAME.c_str(),
- nullptr);
+ DEFAULT_CATALOG_FILENAME.c_str());
return asset_lib_cdf_path;
}
diff --git a/source/blender/blenkernel/intern/asset_catalog_test.cc b/source/blender/blenkernel/intern/asset_catalog_test.cc
index 81eb1786322..ee2dd652b61 100644
--- a/source/blender/blenkernel/intern/asset_catalog_test.cc
+++ b/source/blender/blenkernel/intern/asset_catalog_test.cc
@@ -98,7 +98,7 @@ class AssetCatalogTest : public testing::Test {
FAIL();
}
- asset_library_root_ = test_files_dir + "/" + "asset_library";
+ asset_library_root_ = test_files_dir + SEP_STR + "asset_library";
temp_library_path_ = "";
}
@@ -116,7 +116,7 @@ class AssetCatalogTest : public testing::Test {
{
BKE_tempdir_init("");
const CatalogFilePath tempdir = BKE_tempdir_session();
- temp_library_path_ = tempdir + "test-temporary-path/";
+ temp_library_path_ = tempdir + "test-temporary-path" + SEP_STR;
return temp_library_path_;
}
@@ -202,9 +202,10 @@ class AssetCatalogTest : public testing::Test {
void save_from_memory_into_existing_asset_lib(const bool should_top_level_cdf_exist)
{
const CatalogFilePath target_dir = create_temp_path(); /* Has trailing slash. */
- const CatalogFilePath original_cdf_file = asset_library_root_ + "/blender_assets.cats.txt";
- const CatalogFilePath registered_asset_lib = target_dir + "my_asset_library/";
- const CatalogFilePath asset_lib_subdir = registered_asset_lib + "subdir/";
+ const CatalogFilePath original_cdf_file = asset_library_root_ + SEP_STR +
+ "blender_assets.cats.txt";
+ const CatalogFilePath registered_asset_lib = target_dir + "my_asset_library" + SEP_STR;
+ const CatalogFilePath asset_lib_subdir = registered_asset_lib + "subdir" + SEP_STR;
CatalogFilePath cdf_toplevel = registered_asset_lib +
AssetCatalogService::DEFAULT_CATALOG_FILENAME;
CatalogFilePath cdf_in_subdir = asset_lib_subdir +
@@ -272,7 +273,7 @@ class AssetCatalogTest : public testing::Test {
TEST_F(AssetCatalogTest, load_single_file)
{
AssetCatalogService service(asset_library_root_);
- service.load_from_disk(asset_library_root_ + "/" + "blender_assets.cats.txt");
+ service.load_from_disk(asset_library_root_ + SEP_STR + "blender_assets.cats.txt");
/* Test getting a non-existent catalog ID. */
EXPECT_EQ(nullptr, service.find_catalog(BLI_uuid_generate_random()));
@@ -313,7 +314,7 @@ TEST_F(AssetCatalogTest, load_single_file)
TEST_F(AssetCatalogTest, load_catalog_path_backslashes)
{
AssetCatalogService service(asset_library_root_);
- service.load_from_disk(asset_library_root_ + "/" + "blender_assets.cats.txt");
+ service.load_from_disk(asset_library_root_ + SEP_STR + "blender_assets.cats.txt");
const AssetCatalog *found_by_id = service.find_catalog(UUID_POSES_ELLIE_BACKSLASHES);
ASSERT_NE(nullptr, found_by_id);
@@ -332,7 +333,7 @@ TEST_F(AssetCatalogTest, load_catalog_path_backslashes)
TEST_F(AssetCatalogTest, is_first_loaded_flag)
{
AssetCatalogService service(asset_library_root_);
- service.load_from_disk(asset_library_root_ + "/" + "blender_assets.cats.txt");
+ service.load_from_disk(asset_library_root_ + SEP_STR + "blender_assets.cats.txt");
AssetCatalog *new_cat = service.create_catalog("never/before/seen/path");
EXPECT_FALSE(new_cat->flags.is_first_loaded)
@@ -435,7 +436,7 @@ TEST_F(AssetCatalogTest, insert_item_into_tree)
TEST_F(AssetCatalogTest, load_single_file_into_tree)
{
AssetCatalogService service(asset_library_root_);
- service.load_from_disk(asset_library_root_ + "/" + "blender_assets.cats.txt");
+ service.load_from_disk(asset_library_root_ + SEP_STR + "blender_assets.cats.txt");
/* Contains not only paths from the CDF but also the missing parents (implicitly defined
* catalogs). */
@@ -476,7 +477,7 @@ TEST_F(AssetCatalogTest, foreach_in_tree)
}
AssetCatalogService service(asset_library_root_);
- service.load_from_disk(asset_library_root_ + "/" + "blender_assets.cats.txt");
+ service.load_from_disk(asset_library_root_ + SEP_STR + "blender_assets.cats.txt");
std::vector<AssetCatalogPath> expected_root_items{{"character", "path"}};
AssetCatalogTree *tree = service.get_catalog_tree();
@@ -499,7 +500,7 @@ TEST_F(AssetCatalogTest, foreach_in_tree)
TEST_F(AssetCatalogTest, find_catalog_by_path)
{
TestableAssetCatalogService service(asset_library_root_);
- service.load_from_disk(asset_library_root_ + "/" +
+ service.load_from_disk(asset_library_root_ + SEP_STR +
AssetCatalogService::DEFAULT_CATALOG_FILENAME);
AssetCatalog *catalog;
@@ -522,7 +523,7 @@ TEST_F(AssetCatalogTest, find_catalog_by_path)
TEST_F(AssetCatalogTest, write_single_file)
{
TestableAssetCatalogService service(asset_library_root_);
- service.load_from_disk(asset_library_root_ + "/" +
+ service.load_from_disk(asset_library_root_ + SEP_STR +
AssetCatalogService::DEFAULT_CATALOG_FILENAME);
const CatalogFilePath save_to_path = use_temp_path() +
@@ -550,7 +551,7 @@ TEST_F(AssetCatalogTest, write_single_file)
TEST_F(AssetCatalogTest, read_write_unicode_filepath)
{
TestableAssetCatalogService service(asset_library_root_);
- const CatalogFilePath load_from_path = asset_library_root_ + "/новый/" +
+ const CatalogFilePath load_from_path = asset_library_root_ + SEP_STR + "новый" + SEP_STR +
AssetCatalogService::DEFAULT_CATALOG_FILENAME;
service.load_from_disk(load_from_path);
@@ -588,8 +589,9 @@ TEST_F(AssetCatalogTest, on_blendfile_save__with_existing_cdf)
const CatalogFilePath top_level_dir = create_temp_path(); /* Has trailing slash. */
/* Create a copy of the CDF in SVN, so we can safely write to it. */
- const CatalogFilePath original_cdf_file = asset_library_root_ + "/blender_assets.cats.txt";
- const CatalogFilePath cdf_dirname = top_level_dir + "other_dir/";
+ const CatalogFilePath original_cdf_file = asset_library_root_ + SEP_STR +
+ "blender_assets.cats.txt";
+ const CatalogFilePath cdf_dirname = top_level_dir + "other_dir" + SEP_STR;
const CatalogFilePath cdf_filename = cdf_dirname + AssetCatalogService::DEFAULT_CATALOG_FILENAME;
ASSERT_TRUE(BLI_dir_create_recursive(cdf_dirname.c_str()));
ASSERT_EQ(0, BLI_copy(original_cdf_file.c_str(), cdf_filename.c_str()))
@@ -600,7 +602,7 @@ TEST_F(AssetCatalogTest, on_blendfile_save__with_existing_cdf)
service.load_from_disk();
const AssetCatalog *cat = service.create_catalog("some/catalog/path");
- const CatalogFilePath blendfilename = top_level_dir + "subdir/some_file.blend";
+ const CatalogFilePath blendfilename = top_level_dir + "subdir" + SEP_STR + "some_file.blend";
ASSERT_TRUE(service.write_to_disk(blendfilename));
EXPECT_EQ(cdf_filename, service.get_catalog_definition_file()->file_path);
@@ -650,7 +652,8 @@ TEST_F(AssetCatalogTest, on_blendfile_save__from_memory_into_empty_directory)
TEST_F(AssetCatalogTest, on_blendfile_save__from_memory_into_existing_cdf_and_merge)
{
const CatalogFilePath target_dir = create_temp_path(); /* Has trailing slash. */
- const CatalogFilePath original_cdf_file = asset_library_root_ + "/blender_assets.cats.txt";
+ const CatalogFilePath original_cdf_file = asset_library_root_ + SEP_STR +
+ "blender_assets.cats.txt";
CatalogFilePath writable_cdf_file = target_dir + AssetCatalogService::DEFAULT_CATALOG_FILENAME;
BLI_path_slash_native(writable_cdf_file.data());
ASSERT_EQ(0, BLI_copy(original_cdf_file.c_str(), writable_cdf_file.c_str()));
@@ -719,7 +722,7 @@ TEST_F(AssetCatalogTest, create_first_catalog_from_scratch)
service.write_to_disk(temp_lib_root + "phony.blend");
EXPECT_TRUE(BLI_is_dir(temp_lib_root.c_str()));
- const CatalogFilePath definition_file_path = temp_lib_root + "/" +
+ const CatalogFilePath definition_file_path = temp_lib_root + SEP_STR +
AssetCatalogService::DEFAULT_CATALOG_FILENAME;
EXPECT_TRUE(BLI_is_file(definition_file_path.c_str()));
@@ -739,7 +742,7 @@ TEST_F(AssetCatalogTest, create_catalog_after_loading_file)
/* Copy the asset catalog definition files to a separate location, so that we can test without
* overwriting the test file in SVN. */
- const CatalogFilePath default_catalog_path = asset_library_root_ + "/" +
+ const CatalogFilePath default_catalog_path = asset_library_root_ + SEP_STR +
AssetCatalogService::DEFAULT_CATALOG_FILENAME;
const CatalogFilePath writable_catalog_path = temp_lib_root +
AssetCatalogService::DEFAULT_CATALOG_FILENAME;
@@ -801,7 +804,7 @@ TEST_F(AssetCatalogTest, create_catalog_simple_name)
TEST_F(AssetCatalogTest, delete_catalog_leaf)
{
AssetCatalogService service(asset_library_root_);
- service.load_from_disk(asset_library_root_ + "/" + "blender_assets.cats.txt");
+ service.load_from_disk(asset_library_root_ + SEP_STR + "blender_assets.cats.txt");
/* Delete a leaf catalog, i.e. one that is not a parent of another catalog.
* This keeps this particular test easy. */
@@ -833,7 +836,7 @@ TEST_F(AssetCatalogTest, delete_catalog_leaf)
TEST_F(AssetCatalogTest, delete_catalog_parent_by_id)
{
TestableAssetCatalogService service(asset_library_root_);
- service.load_from_disk(asset_library_root_ + "/" + "blender_assets.cats.txt");
+ service.load_from_disk(asset_library_root_ + SEP_STR + "blender_assets.cats.txt");
/* Delete a parent catalog. */
service.delete_catalog_by_id_soft(UUID_POSES_RUZENA);
@@ -847,7 +850,7 @@ TEST_F(AssetCatalogTest, delete_catalog_parent_by_id)
TEST_F(AssetCatalogTest, delete_catalog_parent_by_path)
{
AssetCatalogService service(asset_library_root_);
- service.load_from_disk(asset_library_root_ + "/" + "blender_assets.cats.txt");
+ service.load_from_disk(asset_library_root_ + SEP_STR + "blender_assets.cats.txt");
/* Create an extra catalog with the to-be-deleted path, and one with a child of that.
* This creates some duplicates that are bound to occur in production asset libraries as well.
@@ -887,14 +890,14 @@ TEST_F(AssetCatalogTest, delete_catalog_parent_by_path)
TEST_F(AssetCatalogTest, delete_catalog_write_to_disk)
{
TestableAssetCatalogService service(asset_library_root_);
- service.load_from_disk(asset_library_root_ + "/" +
+ service.load_from_disk(asset_library_root_ + SEP_STR +
AssetCatalogService::DEFAULT_CATALOG_FILENAME);
service.delete_catalog_by_id_soft(UUID_POSES_ELLIE);
const CatalogFilePath save_to_path = use_temp_path();
AssetCatalogDefinitionFile *cdf = service.get_catalog_definition_file();
- cdf->write_to_disk(save_to_path + "/" + AssetCatalogService::DEFAULT_CATALOG_FILENAME);
+ cdf->write_to_disk(save_to_path + SEP_STR + AssetCatalogService::DEFAULT_CATALOG_FILENAME);
AssetCatalogService loaded_service(save_to_path);
loaded_service.load_from_disk();
@@ -911,7 +914,7 @@ TEST_F(AssetCatalogTest, delete_catalog_write_to_disk)
TEST_F(AssetCatalogTest, update_catalog_path)
{
AssetCatalogService service(asset_library_root_);
- service.load_from_disk(asset_library_root_ + "/" +
+ service.load_from_disk(asset_library_root_ + SEP_STR +
AssetCatalogService::DEFAULT_CATALOG_FILENAME);
const AssetCatalog *orig_cat = service.find_catalog(UUID_POSES_RUZENA);
@@ -940,7 +943,7 @@ TEST_F(AssetCatalogTest, update_catalog_path)
TEST_F(AssetCatalogTest, update_catalog_path_simple_name)
{
AssetCatalogService service(asset_library_root_);
- service.load_from_disk(asset_library_root_ + "/" +
+ service.load_from_disk(asset_library_root_ + SEP_STR +
AssetCatalogService::DEFAULT_CATALOG_FILENAME);
service.update_catalog_path(UUID_POSES_RUZENA, "charlib/Ružena");
@@ -956,7 +959,7 @@ TEST_F(AssetCatalogTest, update_catalog_path_simple_name)
TEST_F(AssetCatalogTest, update_catalog_path_longer_than_simplename)
{
AssetCatalogService service(asset_library_root_);
- service.load_from_disk(asset_library_root_ + "/" +
+ service.load_from_disk(asset_library_root_ + SEP_STR +
AssetCatalogService::DEFAULT_CATALOG_FILENAME);
const std::string new_path =
"this/is/a/very/long/path/that/exceeds/the/simple-name/length/of/assets";
@@ -978,7 +981,7 @@ TEST_F(AssetCatalogTest, update_catalog_path_longer_than_simplename)
TEST_F(AssetCatalogTest, update_catalog_path_add_slashes)
{
AssetCatalogService service(asset_library_root_);
- service.load_from_disk(asset_library_root_ + "/" +
+ service.load_from_disk(asset_library_root_ + SEP_STR +
AssetCatalogService::DEFAULT_CATALOG_FILENAME);
const AssetCatalog *orig_cat = service.find_catalog(UUID_POSES_RUZENA);
@@ -1019,8 +1022,10 @@ TEST_F(AssetCatalogTest, update_catalog_path_add_slashes)
TEST_F(AssetCatalogTest, merge_catalog_files)
{
const CatalogFilePath cdf_dir = create_temp_path();
- const CatalogFilePath original_cdf_file = asset_library_root_ + "/blender_assets.cats.txt";
- const CatalogFilePath modified_cdf_file = asset_library_root_ + "/modified_assets.cats.txt";
+ const CatalogFilePath original_cdf_file = asset_library_root_ + SEP_STR +
+ "blender_assets.cats.txt";
+ const CatalogFilePath modified_cdf_file = asset_library_root_ + SEP_STR +
+ "modified_assets.cats.txt";
const CatalogFilePath temp_cdf_file = cdf_dir + "blender_assets.cats.txt";
ASSERT_EQ(0, BLI_copy(original_cdf_file.c_str(), temp_cdf_file.c_str()));
@@ -1059,8 +1064,10 @@ TEST_F(AssetCatalogTest, merge_catalog_files)
TEST_F(AssetCatalogTest, refresh_catalogs_with_modification)
{
const CatalogFilePath cdf_dir = create_temp_path();
- const CatalogFilePath original_cdf_file = asset_library_root_ + "/blender_assets.cats.txt";
- const CatalogFilePath modified_cdf_file = asset_library_root_ + "/catalog_reload_test.cats.txt";
+ const CatalogFilePath original_cdf_file = asset_library_root_ + SEP_STR +
+ "blender_assets.cats.txt";
+ const CatalogFilePath modified_cdf_file = asset_library_root_ + SEP_STR +
+ "catalog_reload_test.cats.txt";
const CatalogFilePath temp_cdf_file = cdf_dir + "blender_assets.cats.txt";
ASSERT_EQ(0, BLI_copy(original_cdf_file.c_str(), temp_cdf_file.c_str()));
@@ -1131,8 +1138,9 @@ TEST_F(AssetCatalogTest, refresh_catalogs_with_modification)
TEST_F(AssetCatalogTest, backups)
{
const CatalogFilePath cdf_dir = create_temp_path();
- const CatalogFilePath original_cdf_file = asset_library_root_ + "/blender_assets.cats.txt";
- const CatalogFilePath writable_cdf_file = cdf_dir + "/blender_assets.cats.txt";
+ const CatalogFilePath original_cdf_file = asset_library_root_ + SEP_STR +
+ "blender_assets.cats.txt";
+ const CatalogFilePath writable_cdf_file = cdf_dir + SEP_STR + "blender_assets.cats.txt";
ASSERT_EQ(0, BLI_copy(original_cdf_file.c_str(), writable_cdf_file.c_str()));
/* Read a CDF, modify, and write it. */
diff --git a/source/blender/blenkernel/intern/asset_library_service_test.cc b/source/blender/blenkernel/intern/asset_library_service_test.cc
index de6180cb684..d105c5644de 100644
--- a/source/blender/blenkernel/intern/asset_library_service_test.cc
+++ b/source/blender/blenkernel/intern/asset_library_service_test.cc
@@ -39,7 +39,7 @@ class AssetLibraryServiceTest : public testing::Test {
if (test_files_dir.empty()) {
FAIL();
}
- asset_library_root_ = test_files_dir + "/" + "asset_library";
+ asset_library_root_ = test_files_dir + SEP_STR + "asset_library";
temp_library_path_ = "";
}
@@ -59,7 +59,7 @@ class AssetLibraryServiceTest : public testing::Test {
{
BKE_tempdir_init("");
const CatalogFilePath tempdir = BKE_tempdir_session();
- temp_library_path_ = tempdir + "test-temporary-path/";
+ temp_library_path_ = tempdir + "test-temporary-path" + SEP_STR;
return temp_library_path_;
}
@@ -168,7 +168,8 @@ TEST_F(AssetLibraryServiceTest, has_any_unsaved_catalogs)
TEST_F(AssetLibraryServiceTest, has_any_unsaved_catalogs_after_write)
{
const CatalogFilePath writable_dir = create_temp_path(); /* Has trailing slash. */
- const CatalogFilePath original_cdf_file = asset_library_root_ + "/blender_assets.cats.txt";
+ const CatalogFilePath original_cdf_file = asset_library_root_ + SEP_STR +
+ "blender_assets.cats.txt";
CatalogFilePath writable_cdf_file = writable_dir + AssetCatalogService::DEFAULT_CATALOG_FILENAME;
BLI_path_slash_native(writable_cdf_file.data());
ASSERT_EQ(0, BLI_copy(original_cdf_file.c_str(), writable_cdf_file.c_str()));
diff --git a/source/blender/blenkernel/intern/attribute_access.cc b/source/blender/blenkernel/intern/attribute_access.cc
index b86353bdb74..544427cfdd3 100644
--- a/source/blender/blenkernel/intern/attribute_access.cc
+++ b/source/blender/blenkernel/intern/attribute_access.cc
@@ -642,15 +642,26 @@ CustomDataAttributes::CustomDataAttributes(CustomDataAttributes &&other)
size_ = other.size_;
data = other.data;
CustomData_reset(&other.data);
+ other.size_ = 0;
}
CustomDataAttributes &CustomDataAttributes::operator=(const CustomDataAttributes &other)
{
- if (this != &other) {
- CustomData_copy(&other.data, &data, CD_MASK_ALL, CD_DUPLICATE, other.size_);
- size_ = other.size_;
+ if (this == &other) {
+ return *this;
}
+ this->~CustomDataAttributes();
+ new (this) CustomDataAttributes(other);
+ return *this;
+}
+CustomDataAttributes &CustomDataAttributes::operator=(CustomDataAttributes &&other)
+{
+ if (this == &other) {
+ return *this;
+ }
+ this->~CustomDataAttributes();
+ new (this) CustomDataAttributes(std::move(other));
return *this;
}
diff --git a/source/blender/blenkernel/intern/blender_undo.c b/source/blender/blenkernel/intern/blender_undo.c
index a5096b4f9eb..f22dfc6054a 100644
--- a/source/blender/blenkernel/intern/blender_undo.c
+++ b/source/blender/blenkernel/intern/blender_undo.c
@@ -116,7 +116,7 @@ MemFileUndoData *BKE_memfile_undo_encode(Main *bmain, MemFileUndoData *mfu_prev)
counter = counter % U.undosteps;
BLI_snprintf(numstr, sizeof(numstr), "%d.blend", counter);
- BLI_join_dirfile(filepath, sizeof(filepath), BKE_tempdir_session(), numstr);
+ BLI_path_join(filepath, sizeof(filepath), BKE_tempdir_session(), numstr);
/* success = */ /* UNUSED */ BLO_write_file(
bmain, filepath, fileflags, &(const struct BlendFileWriteParams){0}, NULL);
diff --git a/source/blender/blenkernel/intern/blendfile.c b/source/blender/blenkernel/intern/blendfile.c
index 6546659f6cd..85a43b7c479 100644
--- a/source/blender/blenkernel/intern/blendfile.c
+++ b/source/blender/blenkernel/intern/blendfile.c
@@ -737,7 +737,7 @@ bool BKE_blendfile_userdef_write_all(ReportList *reports)
if ((cfgdir = BKE_appdir_folder_id_create(BLENDER_USER_CONFIG, NULL))) {
bool ok_write;
- BLI_path_join(filepath, sizeof(filepath), cfgdir, BLENDER_USERPREF_FILE, NULL);
+ BLI_path_join(filepath, sizeof(filepath), cfgdir, BLENDER_USERPREF_FILE);
printf("Writing userprefs: '%s' ", filepath);
if (use_template_userpref) {
@@ -764,7 +764,7 @@ bool BKE_blendfile_userdef_write_all(ReportList *reports)
if (use_template_userpref) {
if ((cfgdir = BKE_appdir_folder_id_create(BLENDER_USER_CONFIG, U.app_template))) {
/* Also save app-template prefs */
- BLI_path_join(filepath, sizeof(filepath), cfgdir, BLENDER_USERPREF_FILE, NULL);
+ BLI_path_join(filepath, sizeof(filepath), cfgdir, BLENDER_USERPREF_FILE);
printf("Writing userprefs app-template: '%s' ", filepath);
if (BKE_blendfile_userdef_write(filepath, reports) != 0) {
diff --git a/source/blender/blenkernel/intern/blendfile_link_append.c b/source/blender/blenkernel/intern/blendfile_link_append.c
index 394469e19a4..4dd225c09ec 100644
--- a/source/blender/blenkernel/intern/blendfile_link_append.c
+++ b/source/blender/blenkernel/intern/blendfile_link_append.c
@@ -1494,6 +1494,7 @@ void BKE_blendfile_library_relocate(BlendfileLinkAppendContext *lapp_context,
* code is wrong, we need to redo it here after adding them back to main. */
BKE_main_id_refcount_recompute(bmain, false);
+ BKE_layer_collection_resync_forbid();
/* Note that in reload case, we also want to replace indirect usages. */
const short remap_flags = ID_REMAP_SKIP_NEVER_NULL_USAGE |
(do_reload ? 0 : ID_REMAP_SKIP_INDIRECT_USAGE);
@@ -1523,6 +1524,8 @@ void BKE_blendfile_library_relocate(BlendfileLinkAppendContext *lapp_context,
id_us_plus_no_lib(&old_key->id);
}
}
+ BKE_layer_collection_resync_allow();
+ BKE_main_collection_sync_remap(bmain);
BKE_main_unlock(bmain);
@@ -1614,6 +1617,9 @@ void BKE_blendfile_library_relocate(BlendfileLinkAppendContext *lapp_context,
(id->tag & LIB_TAG_PRE_EXISTING) == 0) {
continue;
}
+ if ((id->override_library->reference->tag & LIB_TAG_MISSING) == 0) {
+ id->tag &= ~LIB_TAG_MISSING;
+ }
if ((id->override_library->reference->tag & LIB_TAG_PRE_EXISTING) == 0) {
BKE_lib_override_library_update(bmain, id);
}
diff --git a/source/blender/blenkernel/intern/bpath.c b/source/blender/blenkernel/intern/bpath.c
index f639d03ae0f..6bf121675bc 100644
--- a/source/blender/blenkernel/intern/bpath.c
+++ b/source/blender/blenkernel/intern/bpath.c
@@ -155,7 +155,7 @@ bool BKE_bpath_foreach_path_dirfile_fixed_process(BPathForeachPathData *bpath_da
char path_src[FILE_MAX];
char path_dst[FILE_MAX];
- BLI_join_dirfile(path_src, sizeof(path_src), path_dir, path_file);
+ BLI_path_join(path_src, sizeof(path_src), path_dir, path_file);
/* So that functions can access the old value. */
BLI_strncpy(path_dst, path_src, FILE_MAX);
@@ -279,7 +279,7 @@ static bool missing_files_find__recursive(const char *search_directory,
continue;
}
- BLI_join_dirfile(path, sizeof(path), search_directory, de->d_name);
+ BLI_path_join(path, sizeof(path), search_directory, de->d_name);
if (BLI_stat(path, &status) == -1) {
CLOG_WARN(&LOG, "Cannot get file status (`stat()`) of '%s'", path);
diff --git a/source/blender/blenkernel/intern/brush.cc b/source/blender/blenkernel/intern/brush.cc
index 20d86ea5a2d..6f1435e90b8 100644
--- a/source/blender/blenkernel/intern/brush.cc
+++ b/source/blender/blenkernel/intern/brush.cc
@@ -1974,19 +1974,37 @@ void BKE_brush_curve_preset(Brush *b, eCurveMappingPreset preset)
BKE_curvemapping_changed(cumap, false);
}
+const struct MTex *BKE_brush_mask_texture_get(const struct Brush *brush,
+ const eObjectMode object_mode)
+{
+ if (object_mode == OB_MODE_SCULPT) {
+ return &brush->mtex;
+ }
+ return &brush->mask_mtex;
+}
+
+const struct MTex *BKE_brush_color_texture_get(const struct Brush *brush,
+ const eObjectMode object_mode)
+{
+ if (object_mode == OB_MODE_SCULPT) {
+ return &brush->mask_mtex;
+ }
+ return &brush->mtex;
+}
+
float BKE_brush_sample_tex_3d(const Scene *scene,
const Brush *br,
+ const MTex *mtex,
const float point[3],
float rgba[4],
const int thread,
struct ImagePool *pool)
{
UnifiedPaintSettings *ups = &scene->toolsettings->unified_paint_settings;
- const MTex *mtex = &br->mtex;
float intensity = 1.0;
bool hasrgb = false;
- if (!mtex->tex) {
+ if (mtex == nullptr || mtex->tex == nullptr) {
intensity = 1;
}
else if (mtex->brush_map_mode == MTEX_MAP_MODE_3D) {
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/curve_to_mesh_convert.cc b/source/blender/blenkernel/intern/curve_to_mesh_convert.cc
index b9fea2a27b8..ecf3be9bd81 100644
--- a/source/blender/blenkernel/intern/curve_to_mesh_convert.cc
+++ b/source/blender/blenkernel/intern/curve_to_mesh_convert.cc
@@ -332,7 +332,8 @@ static eAttrDomain get_attribute_domain_for_mesh(const AttributeAccessor &mesh_a
static bool should_add_attribute_to_mesh(const AttributeAccessor &curve_attributes,
const AttributeAccessor &mesh_attributes,
- const AttributeIDRef &id)
+ const AttributeIDRef &id,
+ const AttributeMetaData &meta_data)
{
/* The position attribute has special non-generic evaluation. */
@@ -346,6 +347,9 @@ static bool should_add_attribute_to_mesh(const AttributeAccessor &curve_attribut
if (!id.should_be_kept()) {
return false;
}
+ if (meta_data.data_type == CD_PROP_STRING) {
+ return false;
+ }
return true;
}
@@ -714,7 +718,7 @@ Mesh *curve_to_mesh_sweep(const CurvesGeometry &main,
MutableAttributeAccessor mesh_attributes = mesh->attributes_for_write();
main_attributes.for_all([&](const AttributeIDRef &id, const AttributeMetaData meta_data) {
- if (!should_add_attribute_to_mesh(main_attributes, mesh_attributes, id)) {
+ if (!should_add_attribute_to_mesh(main_attributes, mesh_attributes, id, meta_data)) {
return true;
}
main_attributes_set.add_new(id);
@@ -751,7 +755,7 @@ Mesh *curve_to_mesh_sweep(const CurvesGeometry &main,
if (main_attributes.contains(id)) {
return true;
}
- if (!should_add_attribute_to_mesh(profile_attributes, mesh_attributes, id)) {
+ if (!should_add_attribute_to_mesh(profile_attributes, mesh_attributes, id, meta_data)) {
return true;
}
const eAttrDomain src_domain = meta_data.domain;
diff --git a/source/blender/blenkernel/intern/curves.cc b/source/blender/blenkernel/intern/curves.cc
index 01be22a57b0..72e53023d6d 100644
--- a/source/blender/blenkernel/intern/curves.cc
+++ b/source/blender/blenkernel/intern/curves.cc
@@ -287,7 +287,10 @@ static void curves_evaluate_modifiers(struct Depsgraph *depsgraph,
{
/* Modifier evaluation modes. */
const bool use_render = (DEG_get_mode(depsgraph) == DAG_EVAL_RENDER);
- const int required_mode = use_render ? eModifierMode_Render : eModifierMode_Realtime;
+ int required_mode = use_render ? eModifierMode_Render : eModifierMode_Realtime;
+ if (BKE_object_is_in_editmode(object)) {
+ required_mode = (ModifierMode)(int(required_mode) | eModifierMode_Editmode);
+ }
ModifierApplyFlag apply_flag = use_render ? MOD_APPLY_RENDER : MOD_APPLY_USECACHE;
const ModifierEvalContext mectx = {depsgraph, object, apply_flag};
diff --git a/source/blender/blenkernel/intern/curves_geometry.cc b/source/blender/blenkernel/intern/curves_geometry.cc
index f5c845443f1..7c338480c71 100644
--- a/source/blender/blenkernel/intern/curves_geometry.cc
+++ b/source/blender/blenkernel/intern/curves_geometry.cc
@@ -9,6 +9,7 @@
#include "MEM_guardedalloc.h"
+#include "BLI_array_utils.hh"
#include "BLI_bounds.hh"
#include "BLI_index_mask_ops.hh"
#include "BLI_length_parameterize.hh"
@@ -1111,21 +1112,11 @@ static void copy_between_buffers(const CPPType &type,
src_range.size());
}
-template<typename T>
-static void copy_with_map(const Span<T> src, const Span<int> map, MutableSpan<T> dst)
-{
- threading::parallel_for(map.index_range(), 1024, [&](const IndexRange range) {
- for (const int i : range) {
- dst[i] = src[map[i]];
- }
- });
-}
-
static void copy_with_map(const GSpan src, const Span<int> map, GMutableSpan dst)
{
attribute_math::convert_to_static_type(src.type(), [&](auto dummy) {
using T = decltype(dummy);
- copy_with_map(src.typed<T>(), map, dst.typed<T>());
+ array_utils::gather(src.typed<T>(), map, dst.typed<T>());
});
}
@@ -1233,6 +1224,10 @@ static CurvesGeometry copy_with_removed_points(const CurvesGeometry &curves,
attribute.dst.finish();
}
+ if (new_curves.curves_num() != curves.curves_num()) {
+ new_curves.remove_attributes_based_on_types();
+ }
+
return new_curves;
}
@@ -1338,6 +1333,8 @@ static CurvesGeometry copy_with_removed_curves(const CurvesGeometry &curves,
attribute.dst.finish();
}
+ new_curves.remove_attributes_based_on_types();
+
return new_curves;
}
@@ -1402,6 +1399,9 @@ void CurvesGeometry::reverse_curves(const IndexMask curves_to_reverse)
if (meta_data.domain != ATTR_DOMAIN_POINT) {
return true;
}
+ if (meta_data.data_type == CD_PROP_STRING) {
+ return true;
+ }
if (id.is_named() && bezier_handle_names.contains(id.name())) {
return true;
}
diff --git a/source/blender/blenkernel/intern/customdata.cc b/source/blender/blenkernel/intern/customdata.cc
index be99a8ee87b..03a0f17a4bb 100644
--- a/source/blender/blenkernel/intern/customdata.cc
+++ b/source/blender/blenkernel/intern/customdata.cc
@@ -19,6 +19,7 @@
#include "BLI_bitmap.h"
#include "BLI_color.hh"
+#include "BLI_cpp_type_make.hh"
#include "BLI_endian_switch.h"
#include "BLI_index_range.hh"
#include "BLI_math.h"
@@ -2382,16 +2383,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 +2408,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 +2457,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 +3680,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);
}
@@ -5405,6 +5388,8 @@ const blender::CPPType *custom_data_type_to_cpp_type(const eCustomDataType type)
return &CPPType::get<int8_t>();
case CD_PROP_BYTE_COLOR:
return &CPPType::get<ColorGeometry4b>();
+ case CD_PROP_STRING:
+ return &CPPType::get<MStringProperty>();
default:
return nullptr;
}
@@ -5437,6 +5422,9 @@ eCustomDataType cpp_type_to_custom_data_type(const blender::CPPType &type)
if (type.is<ColorGeometry4b>()) {
return CD_PROP_BYTE_COLOR;
}
+ if (type.is<MStringProperty>()) {
+ return CD_PROP_STRING;
+ }
return static_cast<eCustomDataType>(-1);
}
@@ -5448,3 +5436,5 @@ size_t CustomData_get_elem_size(CustomDataLayer *layer)
{
return LAYERTYPEINFO[layer->type].size;
}
+
+BLI_CPP_TYPE_MAKE(MStringProperty, MStringProperty, CPPTypeFlags::None);
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/fluid.c b/source/blender/blenkernel/intern/fluid.c
index 0a39207184a..5470231cd07 100644
--- a/source/blender/blenkernel/intern/fluid.c
+++ b/source/blender/blenkernel/intern/fluid.c
@@ -327,17 +327,17 @@ void BKE_fluid_cache_free(FluidDomainSettings *fds, Object *ob, int cache_map)
if (cache_map & FLUID_DOMAIN_OUTDATED_DATA) {
flags &= ~(FLUID_DOMAIN_BAKING_DATA | FLUID_DOMAIN_BAKED_DATA | FLUID_DOMAIN_OUTDATED_DATA);
- BLI_path_join(temp_dir, sizeof(temp_dir), fds->cache_directory, FLUID_DOMAIN_DIR_CONFIG, NULL);
+ BLI_path_join(temp_dir, sizeof(temp_dir), fds->cache_directory, FLUID_DOMAIN_DIR_CONFIG);
BLI_path_abs(temp_dir, relbase);
if (BLI_exists(temp_dir)) {
BLI_delete(temp_dir, true, true);
}
- BLI_path_join(temp_dir, sizeof(temp_dir), fds->cache_directory, FLUID_DOMAIN_DIR_DATA, NULL);
+ BLI_path_join(temp_dir, sizeof(temp_dir), fds->cache_directory, FLUID_DOMAIN_DIR_DATA);
BLI_path_abs(temp_dir, relbase);
if (BLI_exists(temp_dir)) {
BLI_delete(temp_dir, true, true);
}
- BLI_path_join(temp_dir, sizeof(temp_dir), fds->cache_directory, FLUID_DOMAIN_DIR_SCRIPT, NULL);
+ BLI_path_join(temp_dir, sizeof(temp_dir), fds->cache_directory, FLUID_DOMAIN_DIR_SCRIPT);
BLI_path_abs(temp_dir, relbase);
if (BLI_exists(temp_dir)) {
BLI_delete(temp_dir, true, true);
@@ -346,7 +346,7 @@ void BKE_fluid_cache_free(FluidDomainSettings *fds, Object *ob, int cache_map)
}
if (cache_map & FLUID_DOMAIN_OUTDATED_NOISE) {
flags &= ~(FLUID_DOMAIN_BAKING_NOISE | FLUID_DOMAIN_BAKED_NOISE | FLUID_DOMAIN_OUTDATED_NOISE);
- BLI_path_join(temp_dir, sizeof(temp_dir), fds->cache_directory, FLUID_DOMAIN_DIR_NOISE, NULL);
+ BLI_path_join(temp_dir, sizeof(temp_dir), fds->cache_directory, FLUID_DOMAIN_DIR_NOISE);
BLI_path_abs(temp_dir, relbase);
if (BLI_exists(temp_dir)) {
BLI_delete(temp_dir, true, true);
@@ -355,7 +355,7 @@ void BKE_fluid_cache_free(FluidDomainSettings *fds, Object *ob, int cache_map)
}
if (cache_map & FLUID_DOMAIN_OUTDATED_MESH) {
flags &= ~(FLUID_DOMAIN_BAKING_MESH | FLUID_DOMAIN_BAKED_MESH | FLUID_DOMAIN_OUTDATED_MESH);
- BLI_path_join(temp_dir, sizeof(temp_dir), fds->cache_directory, FLUID_DOMAIN_DIR_MESH, NULL);
+ BLI_path_join(temp_dir, sizeof(temp_dir), fds->cache_directory, FLUID_DOMAIN_DIR_MESH);
BLI_path_abs(temp_dir, relbase);
if (BLI_exists(temp_dir)) {
BLI_delete(temp_dir, true, true);
@@ -365,8 +365,7 @@ void BKE_fluid_cache_free(FluidDomainSettings *fds, Object *ob, int cache_map)
if (cache_map & FLUID_DOMAIN_OUTDATED_PARTICLES) {
flags &= ~(FLUID_DOMAIN_BAKING_PARTICLES | FLUID_DOMAIN_BAKED_PARTICLES |
FLUID_DOMAIN_OUTDATED_PARTICLES);
- BLI_path_join(
- temp_dir, sizeof(temp_dir), fds->cache_directory, FLUID_DOMAIN_DIR_PARTICLES, NULL);
+ BLI_path_join(temp_dir, sizeof(temp_dir), fds->cache_directory, FLUID_DOMAIN_DIR_PARTICLES);
BLI_path_abs(temp_dir, relbase);
if (BLI_exists(temp_dir)) {
BLI_delete(temp_dir, true, true);
@@ -375,7 +374,7 @@ void BKE_fluid_cache_free(FluidDomainSettings *fds, Object *ob, int cache_map)
}
if (cache_map & FLUID_DOMAIN_OUTDATED_GUIDE) {
flags &= ~(FLUID_DOMAIN_BAKING_GUIDE | FLUID_DOMAIN_BAKED_GUIDE | FLUID_DOMAIN_OUTDATED_GUIDE);
- BLI_path_join(temp_dir, sizeof(temp_dir), fds->cache_directory, FLUID_DOMAIN_DIR_GUIDE, NULL);
+ BLI_path_join(temp_dir, sizeof(temp_dir), fds->cache_directory, FLUID_DOMAIN_DIR_GUIDE);
BLI_path_abs(temp_dir, relbase);
if (BLI_exists(temp_dir)) {
BLI_delete(temp_dir, true, true);
diff --git a/source/blender/blenkernel/intern/geometry_component_instances.cc b/source/blender/blenkernel/intern/geometry_component_instances.cc
index 0b5f7cbf902..be1d9524509 100644
--- a/source/blender/blenkernel/intern/geometry_component_instances.cc
+++ b/source/blender/blenkernel/intern/geometry_component_instances.cc
@@ -16,6 +16,7 @@
#include "BKE_attribute_math.hh"
#include "BKE_geometry_set.hh"
#include "BKE_geometry_set_instances.hh"
+#include "BKE_instances.hh"
#include "attribute_access_intern.hh"
@@ -29,8 +30,8 @@ using blender::MutableSpan;
using blender::Set;
using blender::Span;
using blender::VectorSet;
-
-BLI_CPP_TYPE_MAKE(InstanceReference, InstanceReference, CPPTypeFlags::None)
+using blender::bke::InstanceReference;
+using blender::bke::Instances;
/* -------------------------------------------------------------------- */
/** \name Geometry Component Implementation
@@ -40,339 +41,76 @@ InstancesComponent::InstancesComponent() : GeometryComponent(GEO_COMPONENT_TYPE_
{
}
-GeometryComponent *InstancesComponent::copy() const
-{
- InstancesComponent *new_component = new InstancesComponent();
- new_component->instance_reference_handles_ = instance_reference_handles_;
- new_component->instance_transforms_ = instance_transforms_;
- new_component->references_ = references_;
- new_component->attributes_ = attributes_;
- return new_component;
-}
-
-void InstancesComponent::reserve(int min_capacity)
+InstancesComponent::~InstancesComponent()
{
- instance_reference_handles_.reserve(min_capacity);
- instance_transforms_.reserve(min_capacity);
- attributes_.reallocate(min_capacity);
+ this->clear();
}
-void InstancesComponent::resize(int capacity)
+GeometryComponent *InstancesComponent::copy() const
{
- instance_reference_handles_.resize(capacity);
- instance_transforms_.resize(capacity);
- attributes_.reallocate(capacity);
+ InstancesComponent *new_component = new InstancesComponent();
+ if (instances_ != nullptr) {
+ new_component->instances_ = new Instances(*instances_);
+ new_component->ownership_ = GeometryOwnershipType::Owned;
+ }
+ return new_component;
}
void InstancesComponent::clear()
{
- instance_reference_handles_.clear();
- instance_transforms_.clear();
- attributes_.clear();
- references_.clear();
-}
-
-void InstancesComponent::add_instance(const int instance_handle, const float4x4 &transform)
-{
- BLI_assert(instance_handle >= 0);
- BLI_assert(instance_handle < references_.size());
- instance_reference_handles_.append(instance_handle);
- instance_transforms_.append(transform);
- attributes_.reallocate(this->instances_num());
-}
-
-blender::Span<int> InstancesComponent::instance_reference_handles() const
-{
- return instance_reference_handles_;
-}
-
-blender::MutableSpan<int> InstancesComponent::instance_reference_handles()
-{
- return instance_reference_handles_;
-}
-
-blender::MutableSpan<blender::float4x4> InstancesComponent::instance_transforms()
-{
- return instance_transforms_;
-}
-blender::Span<blender::float4x4> InstancesComponent::instance_transforms() const
-{
- return instance_transforms_;
-}
-
-GeometrySet &InstancesComponent::geometry_set_from_reference(const int reference_index)
-{
- /* If this assert fails, it means #ensure_geometry_instances must be called first or that the
- * reference can't be converted to a geometry set. */
- BLI_assert(references_[reference_index].type() == InstanceReference::Type::GeometrySet);
-
- /* The const cast is okay because the instance's hash in the set
- * is not changed by adjusting the data inside the geometry set. */
- return const_cast<GeometrySet &>(references_[reference_index].geometry_set());
-}
-
-int InstancesComponent::add_reference(const InstanceReference &reference)
-{
- return references_.index_of_or_add_as(reference);
-}
-
-blender::Span<InstanceReference> InstancesComponent::references() const
-{
- return references_;
-}
-
-template<typename T>
-static void copy_data_based_on_mask(Span<T> src, MutableSpan<T> dst, IndexMask mask)
-{
- BLI_assert(src.data() != dst.data());
- using namespace blender;
- threading::parallel_for(mask.index_range(), 1024, [&](IndexRange range) {
- for (const int i : range) {
- dst[i] = src[mask[i]];
- }
- });
-}
-
-void InstancesComponent::remove_instances(const IndexMask mask)
-{
- using namespace blender;
- if (mask.is_range() && mask.as_range().start() == 0) {
- /* Deleting from the end of the array can be much faster since no data has to be shifted. */
- this->resize(mask.size());
- this->remove_unused_references();
- return;
+ BLI_assert(this->is_mutable());
+ if (ownership_ == GeometryOwnershipType::Owned) {
+ delete instances_;
}
-
- Vector<int> new_handles(mask.size());
- copy_data_based_on_mask<int>(this->instance_reference_handles(), new_handles, mask);
- instance_reference_handles_ = std::move(new_handles);
- Vector<float4x4> new_transforms(mask.size());
- copy_data_based_on_mask<float4x4>(this->instance_transforms(), new_transforms, mask);
- instance_transforms_ = std::move(new_transforms);
-
- const bke::CustomDataAttributes &src_attributes = attributes_;
-
- bke::CustomDataAttributes dst_attributes;
- dst_attributes.reallocate(mask.size());
-
- src_attributes.foreach_attribute(
- [&](const bke::AttributeIDRef &id, const bke::AttributeMetaData &meta_data) {
- if (!id.should_be_kept()) {
- return true;
- }
-
- GSpan src = *src_attributes.get_for_read(id);
- dst_attributes.create(id, meta_data.data_type);
- GMutableSpan dst = *dst_attributes.get_for_write(id);
-
- attribute_math::convert_to_static_type(src.type(), [&](auto dummy) {
- using T = decltype(dummy);
- copy_data_based_on_mask<T>(src.typed<T>(), dst.typed<T>(), mask);
- });
- return true;
- },
- ATTR_DOMAIN_INSTANCE);
-
- attributes_ = std::move(dst_attributes);
- this->remove_unused_references();
+ instances_ = nullptr;
}
-void InstancesComponent::remove_unused_references()
+bool InstancesComponent::is_empty() const
{
- using namespace blender;
- using namespace blender::bke;
-
- const int tot_instances = this->instances_num();
- const int tot_references_before = references_.size();
-
- if (tot_instances == 0) {
- /* If there are no instances, no reference is needed. */
- references_.clear();
- return;
- }
- if (tot_references_before == 1) {
- /* There is only one reference and at least one instance. So the only existing reference is
- * used. Nothing to do here. */
- return;
- }
-
- Array<bool> usage_by_handle(tot_references_before, false);
- std::mutex mutex;
-
- /* Loop over all instances to see which references are used. */
- threading::parallel_for(IndexRange(tot_instances), 1000, [&](IndexRange range) {
- /* Use local counter to avoid lock contention. */
- Array<bool> local_usage_by_handle(tot_references_before, false);
-
- for (const int i : range) {
- const int handle = instance_reference_handles_[i];
- BLI_assert(handle >= 0 && handle < tot_references_before);
- local_usage_by_handle[handle] = true;
- }
-
- std::lock_guard lock{mutex};
- for (const int i : IndexRange(tot_references_before)) {
- usage_by_handle[i] |= local_usage_by_handle[i];
- }
- });
-
- if (!usage_by_handle.as_span().contains(false)) {
- /* All references are used. */
- return;
- }
-
- /* Create new references and a mapping for the handles. */
- Vector<int> handle_mapping;
- VectorSet<InstanceReference> new_references;
- int next_new_handle = 0;
- bool handles_have_to_be_updated = false;
- for (const int old_handle : IndexRange(tot_references_before)) {
- if (!usage_by_handle[old_handle]) {
- /* Add some dummy value. It won't be read again. */
- handle_mapping.append(-1);
- }
- else {
- const InstanceReference &reference = references_[old_handle];
- handle_mapping.append(next_new_handle);
- new_references.add_new(reference);
- if (old_handle != next_new_handle) {
- handles_have_to_be_updated = true;
- }
- next_new_handle++;
+ if (instances_ != nullptr) {
+ if (instances_->instances_num() > 0) {
+ return false;
}
}
- references_ = new_references;
-
- if (!handles_have_to_be_updated) {
- /* All remaining handles are the same as before, so they don't have to be updated. This happens
- * when unused handles are only at the end. */
- return;
- }
-
- /* Update handles of instances. */
- threading::parallel_for(IndexRange(tot_instances), 1000, [&](IndexRange range) {
- for (const int i : range) {
- instance_reference_handles_[i] = handle_mapping[instance_reference_handles_[i]];
- }
- });
-}
-
-int InstancesComponent::instances_num() const
-{
- return instance_transforms_.size();
-}
-
-int InstancesComponent::references_num() const
-{
- return references_.size();
-}
-
-bool InstancesComponent::is_empty() const
-{
- return this->instance_reference_handles_.size() == 0;
+ return true;
}
bool InstancesComponent::owns_direct_data() const
{
- for (const InstanceReference &reference : references_) {
- if (!reference.owns_direct_data()) {
- return false;
- }
+ if (instances_ != nullptr) {
+ return instances_->owns_direct_data();
}
return true;
}
void InstancesComponent::ensure_owns_direct_data()
{
- BLI_assert(this->is_mutable());
- for (const InstanceReference &const_reference : references_) {
- /* Const cast is fine because we are not changing anything that would change the hash of the
- * reference. */
- InstanceReference &reference = const_cast<InstanceReference &>(const_reference);
- reference.ensure_owns_direct_data();
+ if (instances_ != nullptr) {
+ instances_->ensure_owns_direct_data();
}
}
-static blender::Array<int> generate_unique_instance_ids(Span<int> original_ids)
+const blender::bke::Instances *InstancesComponent::get_for_read() const
{
- using namespace blender;
- Array<int> unique_ids(original_ids.size());
-
- Set<int> used_unique_ids;
- used_unique_ids.reserve(original_ids.size());
- Vector<int> instances_with_id_collision;
- for (const int instance_index : original_ids.index_range()) {
- const int original_id = original_ids[instance_index];
- if (used_unique_ids.add(original_id)) {
- /* The original id has not been used by another instance yet. */
- unique_ids[instance_index] = original_id;
- }
- else {
- /* The original id of this instance collided with a previous instance, it needs to be looked
- * at again in a second pass. Don't generate a new random id here, because this might collide
- * with other existing ids. */
- instances_with_id_collision.append(instance_index);
- }
- }
-
- Map<int, RandomNumberGenerator> generator_by_original_id;
- for (const int instance_index : instances_with_id_collision) {
- const int original_id = original_ids[instance_index];
- RandomNumberGenerator &rng = generator_by_original_id.lookup_or_add_cb(original_id, [&]() {
- RandomNumberGenerator rng;
- rng.seed_random(original_id);
- return rng;
- });
-
- const int max_iteration = 100;
- for (int iteration = 0;; iteration++) {
- /* Try generating random numbers until an unused one has been found. */
- const int random_id = rng.get_int32();
- if (used_unique_ids.add(random_id)) {
- /* This random id is not used by another instance. */
- unique_ids[instance_index] = random_id;
- break;
- }
- if (iteration == max_iteration) {
- /* It seems to be very unlikely that we ever run into this case (assuming there are less
- * than 2^30 instances). However, if that happens, it's better to use an id that is not
- * unique than to be stuck in an infinite loop. */
- unique_ids[instance_index] = original_id;
- break;
- }
- }
- }
-
- return unique_ids;
+ return instances_;
}
-blender::Span<int> InstancesComponent::almost_unique_ids() const
+blender::bke::Instances *InstancesComponent::get_for_write()
{
- std::lock_guard lock(almost_unique_ids_mutex_);
- std::optional<GSpan> instance_ids_gspan = attributes_.get_for_read("id");
- if (instance_ids_gspan) {
- Span<int> instance_ids = instance_ids_gspan->typed<int>();
- if (almost_unique_ids_.size() != instance_ids.size()) {
- almost_unique_ids_ = generate_unique_instance_ids(instance_ids);
- }
- }
- else {
- almost_unique_ids_.reinitialize(this->instances_num());
- for (const int i : almost_unique_ids_.index_range()) {
- almost_unique_ids_[i] = i;
- }
+ BLI_assert(this->is_mutable());
+ if (ownership_ == GeometryOwnershipType::ReadOnly) {
+ instances_ = new Instances(*instances_);
+ ownership_ = GeometryOwnershipType::Owned;
}
- return almost_unique_ids_;
+ return instances_;
}
-blender::bke::CustomDataAttributes &InstancesComponent::instance_attributes()
+void InstancesComponent::replace(Instances *instances, GeometryOwnershipType ownership)
{
- return this->attributes_;
-}
-
-const blender::bke::CustomDataAttributes &InstancesComponent::instance_attributes() const
-{
- return this->attributes_;
+ BLI_assert(this->is_mutable());
+ this->clear();
+ instances_ = instances;
+ ownership_ = ownership;
}
namespace blender::bke {
@@ -397,16 +135,21 @@ class InstancePositionAttributeProvider final : public BuiltinAttributeProvider
GVArray try_get_for_read(const void *owner) const final
{
- const InstancesComponent &instances_component = *static_cast<const InstancesComponent *>(
- owner);
- Span<float4x4> transforms = instances_component.instance_transforms();
+ const Instances *instances = static_cast<const Instances *>(owner);
+ if (instances == nullptr) {
+ return {};
+ }
+ Span<float4x4> transforms = instances->transforms();
return VArray<float3>::ForDerivedSpan<float4x4, get_transform_position>(transforms);
}
GAttributeWriter try_get_for_write(void *owner) const final
{
- InstancesComponent &instances_component = *static_cast<InstancesComponent *>(owner);
- MutableSpan<float4x4> transforms = instances_component.instance_transforms();
+ Instances *instances = static_cast<Instances *>(owner);
+ if (instances == nullptr) {
+ return {};
+ }
+ MutableSpan<float4x4> transforms = instances->transforms();
return {VMutableArray<float3>::ForDerivedSpan<float4x4,
get_transform_position,
set_transform_position>(transforms),
@@ -434,16 +177,16 @@ static ComponentAttributeProviders create_attribute_providers_for_instances()
static InstancePositionAttributeProvider position;
static CustomDataAccessInfo instance_custom_data_access = {
[](void *owner) -> CustomData * {
- InstancesComponent &inst = *static_cast<InstancesComponent *>(owner);
- return &inst.instance_attributes().data;
+ Instances *instances = static_cast<Instances *>(owner);
+ return &instances->custom_data_attributes().data;
},
[](const void *owner) -> const CustomData * {
- const InstancesComponent &inst = *static_cast<const InstancesComponent *>(owner);
- return &inst.instance_attributes().data;
+ const Instances *instances = static_cast<const Instances *>(owner);
+ return &instances->custom_data_attributes().data;
},
[](const void *owner) -> int {
- const InstancesComponent &inst = *static_cast<const InstancesComponent *>(owner);
- return inst.instances_num();
+ const Instances *instances = static_cast<const Instances *>(owner);
+ return instances->instances_num();
}};
/**
@@ -479,10 +222,10 @@ static AttributeAccessorFunctions get_instances_accessor_functions()
if (owner == nullptr) {
return 0;
}
- const InstancesComponent &instances = *static_cast<const InstancesComponent *>(owner);
+ const Instances *instances = static_cast<const Instances *>(owner);
switch (domain) {
case ATTR_DOMAIN_INSTANCE:
- return instances.instances_num();
+ return instances->instances_num();
default:
return 0;
}
@@ -508,18 +251,30 @@ static const AttributeAccessorFunctions &get_instances_accessor_functions_ref()
return fn;
}
+blender::bke::AttributeAccessor Instances::attributes() const
+{
+ return blender::bke::AttributeAccessor(this,
+ blender::bke::get_instances_accessor_functions_ref());
+}
+
+blender::bke::MutableAttributeAccessor Instances::attributes_for_write()
+{
+ return blender::bke::MutableAttributeAccessor(
+ this, blender::bke::get_instances_accessor_functions_ref());
+}
+
} // namespace blender::bke
std::optional<blender::bke::AttributeAccessor> InstancesComponent::attributes() const
{
- return blender::bke::AttributeAccessor(this,
+ return blender::bke::AttributeAccessor(instances_,
blender::bke::get_instances_accessor_functions_ref());
}
std::optional<blender::bke::MutableAttributeAccessor> InstancesComponent::attributes_for_write()
{
return blender::bke::MutableAttributeAccessor(
- this, blender::bke::get_instances_accessor_functions_ref());
+ instances_, blender::bke::get_instances_accessor_functions_ref());
}
/** \} */
diff --git a/source/blender/blenkernel/intern/geometry_fields.cc b/source/blender/blenkernel/intern/geometry_fields.cc
index b492af4af77..82ffda57398 100644
--- a/source/blender/blenkernel/intern/geometry_fields.cc
+++ b/source/blender/blenkernel/intern/geometry_fields.cc
@@ -4,6 +4,7 @@
#include "BKE_curves.hh"
#include "BKE_geometry_fields.hh"
#include "BKE_geometry_set.hh"
+#include "BKE_instances.hh"
#include "BKE_mesh.h"
#include "BKE_pointcloud.h"
#include "BKE_type_conversions.hh"
@@ -64,7 +65,7 @@ GeometryFieldContext::GeometryFieldContext(const GeometryComponent &component,
case GEO_COMPONENT_TYPE_INSTANCES: {
const InstancesComponent &instances_component = static_cast<const InstancesComponent &>(
component);
- geometry_ = &instances_component;
+ geometry_ = instances_component.get_for_read();
break;
}
case GEO_COMPONENT_TYPE_VOLUME:
@@ -86,7 +87,7 @@ GeometryFieldContext::GeometryFieldContext(const PointCloud &points)
: geometry_(&points), type_(GEO_COMPONENT_TYPE_POINT_CLOUD), domain_(ATTR_DOMAIN_POINT)
{
}
-GeometryFieldContext::GeometryFieldContext(const InstancesComponent &instances)
+GeometryFieldContext::GeometryFieldContext(const Instances &instances)
: geometry_(&instances), type_(GEO_COMPONENT_TYPE_INSTANCES), domain_(ATTR_DOMAIN_INSTANCE)
{
}
@@ -102,7 +103,7 @@ std::optional<AttributeAccessor> GeometryFieldContext::attributes() const
if (const PointCloud *pointcloud = this->pointcloud()) {
return pointcloud->attributes();
}
- if (const InstancesComponent *instances = this->instances()) {
+ if (const Instances *instances = this->instances()) {
return instances->attributes();
}
return {};
@@ -124,11 +125,10 @@ const PointCloud *GeometryFieldContext::pointcloud() const
static_cast<const PointCloud *>(geometry_) :
nullptr;
}
-const InstancesComponent *GeometryFieldContext::instances() const
+const Instances *GeometryFieldContext::instances() const
{
- return this->type() == GEO_COMPONENT_TYPE_INSTANCES ?
- static_cast<const InstancesComponent *>(geometry_) :
- nullptr;
+ return this->type() == GEO_COMPONENT_TYPE_INSTANCES ? static_cast<const Instances *>(geometry_) :
+ nullptr;
}
GVArray GeometryFieldInput::get_varray_for_context(const fn::FieldContext &context,
@@ -230,7 +230,7 @@ GVArray InstancesFieldInput::get_varray_for_context(const fn::FieldContext &cont
{
if (const GeometryFieldContext *geometry_context = dynamic_cast<const GeometryFieldContext *>(
&context)) {
- if (const InstancesComponent *instances = geometry_context->instances()) {
+ if (const Instances *instances = geometry_context->instances()) {
return this->get_varray_for_context(*instances, mask);
}
}
diff --git a/source/blender/blenkernel/intern/geometry_set.cc b/source/blender/blenkernel/intern/geometry_set.cc
index 46ff8141504..ee4c398c3d6 100644
--- a/source/blender/blenkernel/intern/geometry_set.cc
+++ b/source/blender/blenkernel/intern/geometry_set.cc
@@ -9,6 +9,7 @@
#include "BKE_attribute.h"
#include "BKE_curves.hh"
#include "BKE_geometry_set.hh"
+#include "BKE_instances.hh"
#include "BKE_lib_id.h"
#include "BKE_mesh.h"
#include "BKE_mesh_wrapper.h"
@@ -31,6 +32,8 @@ using blender::MutableSpan;
using blender::Span;
using blender::StringRef;
using blender::Vector;
+using blender::bke::InstanceReference;
+using blender::bke::Instances;
/* -------------------------------------------------------------------- */
/** \name Geometry Component
@@ -256,8 +259,7 @@ std::ostream &operator<<(std::ostream &stream, const GeometrySet &geometry_set)
parts.append(std::to_string(BKE_volume_num_grids(volume)) + " volume grids");
}
if (geometry_set.has_instances()) {
- parts.append(std::to_string(
- geometry_set.get_component_for_read<InstancesComponent>()->instances_num()) +
+ parts.append(std::to_string(geometry_set.get_instances_for_read()->instances_num()) +
" instances");
}
if (geometry_set.get_curve_edit_hints_for_read()) {
@@ -338,6 +340,12 @@ const Curves *GeometrySet::get_curves_for_read() const
return (component == nullptr) ? nullptr : component->get_for_read();
}
+const Instances *GeometrySet::get_instances_for_read() const
+{
+ const InstancesComponent *component = this->get_component_for_read<InstancesComponent>();
+ return (component == nullptr) ? nullptr : component->get_for_read();
+}
+
const blender::bke::CurvesEditHints *GeometrySet::get_curve_edit_hints_for_read() const
{
const GeometryComponentEditData *component =
@@ -354,7 +362,8 @@ bool GeometrySet::has_pointcloud() const
bool GeometrySet::has_instances() const
{
const InstancesComponent *component = this->get_component_for_read<InstancesComponent>();
- return component != nullptr && component->instances_num() >= 1;
+ return component != nullptr && component->get_for_read() != nullptr &&
+ component->get_for_read()->instances_num() >= 1;
}
bool GeometrySet::has_volume() const
@@ -428,6 +437,14 @@ GeometrySet GeometrySet::create_with_curves(Curves *curves, GeometryOwnershipTyp
return geometry_set;
}
+GeometrySet GeometrySet::create_with_instances(Instances *instances,
+ GeometryOwnershipType ownership)
+{
+ GeometrySet geometry_set;
+ geometry_set.replace_instances(instances, ownership);
+ return geometry_set;
+}
+
void GeometrySet::replace_mesh(Mesh *mesh, GeometryOwnershipType ownership)
{
if (mesh == nullptr) {
@@ -456,6 +473,20 @@ void GeometrySet::replace_curves(Curves *curves, GeometryOwnershipType ownership
component.replace(curves, ownership);
}
+void GeometrySet::replace_instances(Instances *instances, GeometryOwnershipType ownership)
+{
+ if (instances == nullptr) {
+ this->remove<InstancesComponent>();
+ return;
+ }
+ if (instances == this->get_instances_for_read()) {
+ return;
+ }
+ this->remove<InstancesComponent>();
+ InstancesComponent &component = this->get_component_for_write<InstancesComponent>();
+ component.replace(instances, ownership);
+}
+
void GeometrySet::replace_pointcloud(PointCloud *pointcloud, GeometryOwnershipType ownership)
{
if (pointcloud == nullptr) {
@@ -508,6 +539,12 @@ Curves *GeometrySet::get_curves_for_write()
return component == nullptr ? nullptr : component->get_for_write();
}
+Instances *GeometrySet::get_instances_for_write()
+{
+ InstancesComponent *component = this->get_component_ptr<InstancesComponent>();
+ return component == nullptr ? nullptr : component->get_for_write();
+}
+
blender::bke::CurvesEditHints *GeometrySet::get_curve_edit_hints_for_write()
{
if (!this->has<GeometryComponentEditData>()) {
@@ -539,7 +576,7 @@ void GeometrySet::attribute_foreach(const Span<GeometryComponentType> component_
}
}
if (include_instances && this->has_instances()) {
- const InstancesComponent &instances = *this->get_component_for_read<InstancesComponent>();
+ const Instances &instances = *this->get_instances_for_read();
instances.foreach_referenced_geometry([&](const GeometrySet &instance_geometry_set) {
instance_geometry_set.attribute_foreach(component_types, include_instances, callback);
});
@@ -570,7 +607,10 @@ void GeometrySet::gather_attributes_for_propagation(
return;
}
}
-
+ if (meta_data.data_type == CD_PROP_STRING) {
+ /* Propagating string attributes is not supported yet. */
+ return;
+ }
if (!attribute_id.should_be_kept()) {
return;
}
@@ -611,7 +651,7 @@ static void gather_component_types_recursive(const GeometrySet &geometry_set,
if (!include_instances) {
return;
}
- const InstancesComponent *instances = geometry_set.get_component_for_read<InstancesComponent>();
+ const blender::bke::Instances *instances = geometry_set.get_instances_for_read();
if (instances == nullptr) {
return;
}
@@ -638,12 +678,11 @@ static void gather_mutable_geometry_sets(GeometrySet &geometry_set,
}
/* In the future this can be improved by deduplicating instance references across different
* instances. */
- InstancesComponent &instances_component =
- geometry_set.get_component_for_write<InstancesComponent>();
- instances_component.ensure_geometry_instances();
- for (const int handle : instances_component.references().index_range()) {
- if (instances_component.references()[handle].type() == InstanceReference::Type::GeometrySet) {
- GeometrySet &instance_geometry = instances_component.geometry_set_from_reference(handle);
+ Instances &instances = *geometry_set.get_instances_for_write();
+ instances.ensure_geometry_instances();
+ for (const int handle : instances.references().index_range()) {
+ if (instances.references()[handle].type() == InstanceReference::Type::GeometrySet) {
+ GeometrySet &instance_geometry = instances.geometry_set_from_reference(handle);
gather_mutable_geometry_sets(instance_geometry, r_geometry_sets);
}
}
diff --git a/source/blender/blenkernel/intern/geometry_set_instances.cc b/source/blender/blenkernel/intern/geometry_set_instances.cc
index 0ae49a586f1..e078991187d 100644
--- a/source/blender/blenkernel/intern/geometry_set_instances.cc
+++ b/source/blender/blenkernel/intern/geometry_set_instances.cc
@@ -2,6 +2,7 @@
#include "BKE_collection.h"
#include "BKE_geometry_set_instances.hh"
+#include "BKE_instances.hh"
#include "BKE_material.h"
#include "BKE_mesh.h"
#include "BKE_mesh_wrapper.h"
@@ -62,12 +63,11 @@ GeometrySet object_get_evaluated_geometry_set(const Object &object)
return geometry_set;
}
if (object.type == OB_EMPTY && object.instance_collection != nullptr) {
- GeometrySet geometry_set;
Collection &collection = *object.instance_collection;
- InstancesComponent &instances = geometry_set.get_component_for_write<InstancesComponent>();
- const int handle = instances.add_reference(collection);
- instances.add_instance(handle, float4x4::identity());
- return geometry_set;
+ std::unique_ptr<Instances> instances = std::make_unique<Instances>();
+ const int handle = instances->add_reference(collection);
+ instances->add_instance(handle, float4x4::identity());
+ return GeometrySet::create_with_instances(instances.release());
}
/* Return by value since there is not always an existing geometry set owned elsewhere to use. */
@@ -115,12 +115,11 @@ static void geometry_set_collect_recursive(const GeometrySet &geometry_set,
r_sets.append({geometry_set, {transform}});
if (geometry_set.has_instances()) {
- const InstancesComponent &instances_component =
- *geometry_set.get_component_for_read<InstancesComponent>();
+ const Instances &instances = *geometry_set.get_instances_for_read();
- Span<float4x4> transforms = instances_component.instance_transforms();
- Span<int> handles = instances_component.instance_reference_handles();
- Span<InstanceReference> references = instances_component.references();
+ Span<float4x4> transforms = instances.transforms();
+ Span<int> handles = instances.reference_handles();
+ Span<InstanceReference> references = instances.references();
for (const int i : transforms.index_range()) {
const InstanceReference &reference = references[handles[i]];
const float4x4 instance_transform = transform * transforms[i];
@@ -156,9 +155,7 @@ void geometry_set_gather_instances(const GeometrySet &geometry_set,
geometry_set_collect_recursive(geometry_set, float4x4::identity(), r_instance_groups);
}
-} // namespace blender::bke
-
-void InstancesComponent::foreach_referenced_geometry(
+void Instances::foreach_referenced_geometry(
blender::FunctionRef<void(const GeometrySet &geometry_set)> callback) const
{
using namespace blender::bke;
@@ -191,7 +188,7 @@ void InstancesComponent::foreach_referenced_geometry(
}
}
-void InstancesComponent::ensure_geometry_instances()
+void Instances::ensure_geometry_instances()
{
using namespace blender;
using namespace blender::bke;
@@ -211,9 +208,7 @@ void InstancesComponent::ensure_geometry_instances()
const Object &object = reference.object();
GeometrySet object_geometry_set = object_get_evaluated_geometry_set(object);
if (object_geometry_set.has_instances()) {
- InstancesComponent &component =
- object_geometry_set.get_component_for_write<InstancesComponent>();
- component.ensure_geometry_instances();
+ object_geometry_set.get_instances_for_write()->ensure_geometry_instances();
}
new_references.add_new(std::move(object_geometry_set));
break;
@@ -221,22 +216,22 @@ void InstancesComponent::ensure_geometry_instances()
case InstanceReference::Type::Collection: {
/* Create a new reference that contains a geometry set that contains all objects from the
* collection as instances. */
- GeometrySet collection_geometry_set;
- InstancesComponent &component =
- collection_geometry_set.get_component_for_write<InstancesComponent>();
+ std::unique_ptr<Instances> instances = std::make_unique<Instances>();
Collection &collection = reference.collection();
FOREACH_COLLECTION_OBJECT_RECURSIVE_BEGIN (&collection, object) {
- const int handle = component.add_reference(*object);
- component.add_instance(handle, object->obmat);
- float4x4 &transform = component.instance_transforms().last();
+ const int handle = instances->add_reference(*object);
+ instances->add_instance(handle, object->obmat);
+ float4x4 &transform = instances->transforms().last();
sub_v3_v3(transform.values[3], collection.instance_offset);
}
FOREACH_COLLECTION_OBJECT_RECURSIVE_END;
- component.ensure_geometry_instances();
- new_references.add_new(std::move(collection_geometry_set));
+ instances->ensure_geometry_instances();
+ new_references.add_new(GeometrySet::create_with_instances(instances.release()));
break;
}
}
}
references_ = std::move(new_references);
}
+
+} // namespace blender::bke
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/image.cc b/source/blender/blenkernel/intern/image.cc
index 409eb0067b5..eae8b454189 100644
--- a/source/blender/blenkernel/intern/image.cc
+++ b/source/blender/blenkernel/intern/image.cc
@@ -297,7 +297,7 @@ static void image_foreach_path(ID *id, BPathForeachPathData *bpath_data)
/* Put the filepath back together using the new directory and the original file name. */
char new_dir[FILE_MAXDIR];
BLI_split_dir_part(temp_path, new_dir, sizeof(new_dir));
- BLI_join_dirfile(ima->filepath, sizeof(ima->filepath), new_dir, orig_file);
+ BLI_path_join(ima->filepath, sizeof(ima->filepath), new_dir, orig_file);
}
}
else {
@@ -3082,16 +3082,10 @@ void BKE_image_signal(Main *bmain, Image *ima, ImageUser *iuser, int signal)
/* Free all but the first tile. */
image_remove_all_tiles(ima);
- /* If the remaining tile is generated, we need to again ensure that we
- * wouldn't continue to use the old filepath.
- *
- * Otherwise, if this used to be a UDIM image, get the concrete filepath associated
+ /* If this used to be a UDIM image, get the concrete filepath associated
* with the remaining tile and use that as the new filepath. */
ImageTile *base_tile = BKE_image_get_tile(ima, 0);
- if ((base_tile->gen_flag & IMA_GEN_TILE) != 0) {
- ima->filepath[0] = '\0';
- }
- else if (BKE_image_is_filename_tokenized(ima->filepath)) {
+ if (BKE_image_is_filename_tokenized(ima->filepath)) {
const bool was_relative = BLI_path_is_rel(ima->filepath);
eUDIM_TILE_FORMAT tile_format;
@@ -3183,10 +3177,14 @@ void BKE_image_signal(Main *bmain, Image *ima, ImageUser *iuser, int signal)
* left. */
image_remove_all_tiles(ima);
- int remaining_tile_number = ((ImageTile *)ima->tiles.first)->tile_number;
+ ImageTile *base_tile = BKE_image_get_tile(ima, 0);
+ int remaining_tile_number = base_tile->tile_number;
bool needs_final_cleanup = true;
- /* Add in all the new tiles. */
+ /* Add in all the new tiles. As the image is proven to be on disk at this point, remove
+ * the generation flag from the remaining tile in case this was previously a generated
+ * image. */
+ base_tile->gen_flag &= ~IMA_GEN_TILE;
LISTBASE_FOREACH (LinkData *, new_tile, &new_tiles) {
int new_tile_number = POINTER_AS_INT(new_tile->data);
BKE_image_add_tile(ima, new_tile_number, nullptr);
@@ -3202,6 +3200,11 @@ void BKE_image_signal(Main *bmain, Image *ima, ImageUser *iuser, int signal)
}
BLI_freelistN(&new_tiles);
}
+ else if (ima->filepath[0] != '\0') {
+ /* If the filepath is set at this point remove the generation flag. */
+ ImageTile *base_tile = BKE_image_get_tile(ima, 0);
+ base_tile->gen_flag &= ~IMA_GEN_TILE;
+ }
if (iuser) {
image_tag_reload(ima, nullptr, iuser, ima);
@@ -3331,7 +3334,7 @@ bool BKE_image_get_tile_info(char *filepath, ListBase *tiles, int *r_tile_start,
MEM_SAFE_FREE(udim_pattern);
if (all_valid_udim && min_udim <= IMA_UDIM_MAX) {
- BLI_join_dirfile(filepath, FILE_MAX, dirname, filename);
+ BLI_path_join(filepath, FILE_MAX, dirname, filename);
*r_tile_start = min_udim;
*r_tile_range = max_udim - min_udim + 1;
diff --git a/source/blender/blenkernel/intern/image_format.cc b/source/blender/blenkernel/intern/image_format.cc
index 8d1aeac76fb..5b861eff166 100644
--- a/source/blender/blenkernel/intern/image_format.cc
+++ b/source/blender/blenkernel/intern/image_format.cc
@@ -201,6 +201,7 @@ bool BKE_imtype_is_movie(const char imtype)
case R_IMF_IMTYPE_H264:
case R_IMF_IMTYPE_THEORA:
case R_IMF_IMTYPE_XVID:
+ case R_IMF_IMTYPE_AV1:
return true;
}
return false;
@@ -433,7 +434,8 @@ static bool do_add_image_extension(char *string,
R_IMF_IMTYPE_FFMPEG,
R_IMF_IMTYPE_H264,
R_IMF_IMTYPE_THEORA,
- R_IMF_IMTYPE_XVID)) {
+ R_IMF_IMTYPE_XVID,
+ R_IMF_IMTYPE_AV1)) {
if (!BLI_path_extension_check(string, extension_test = ".png")) {
extension = extension_test;
}
@@ -627,7 +629,8 @@ void BKE_image_format_to_imbuf(ImBuf *ibuf, const ImageFormatData *imf)
R_IMF_IMTYPE_FFMPEG,
R_IMF_IMTYPE_H264,
R_IMF_IMTYPE_THEORA,
- R_IMF_IMTYPE_XVID)) {
+ R_IMF_IMTYPE_XVID,
+ R_IMF_IMTYPE_AV1)) {
ibuf->ftype = IMB_FTYPE_PNG;
if (imtype == R_IMF_IMTYPE_PNG) {
diff --git a/source/blender/blenkernel/intern/image_save.cc b/source/blender/blenkernel/intern/image_save.cc
index e227f9cba5e..003211e6288 100644
--- a/source/blender/blenkernel/intern/image_save.cc
+++ b/source/blender/blenkernel/intern/image_save.cc
@@ -175,12 +175,12 @@ bool BKE_image_save_options_init(ImageSaveOptions *opts,
BLI_strncpy(opts->filepath, G.ima, sizeof(opts->filepath));
}
else {
- BLI_path_join(opts->filepath, sizeof(opts->filepath), "//", DATA_("untitled"), nullptr);
+ BLI_path_join(opts->filepath, sizeof(opts->filepath), "//", DATA_("untitled"));
BLI_path_abs(opts->filepath, BKE_main_blendfile_path(bmain));
}
}
else {
- BLI_path_join(opts->filepath, sizeof(opts->filepath), "//", ima->id.name + 2, nullptr);
+ BLI_path_join(opts->filepath, sizeof(opts->filepath), "//", ima->id.name + 2);
BLI_path_make_safe(opts->filepath);
BLI_path_abs(opts->filepath, is_prev_save ? G.ima : BKE_main_blendfile_path(bmain));
}
@@ -968,6 +968,7 @@ bool BKE_image_render_write(ReportList *reports,
/* optional preview images for exr */
if (ok && (image_format.flag & R_IMF_FLAG_PREVIEW_JPG)) {
image_format.imtype = R_IMF_IMTYPE_JPEG90;
+ image_format.depth = R_IMF_CHAN_DEPTH_8;
if (BLI_path_extension_check(filepath, ".exr")) {
filepath[strlen(filepath) - 4] = 0;
@@ -1025,6 +1026,7 @@ bool BKE_image_render_write(ReportList *reports,
/* optional preview images for exr */
if (ok && is_exr_rr && (image_format.flag & R_IMF_FLAG_PREVIEW_JPG)) {
image_format.imtype = R_IMF_IMTYPE_JPEG90;
+ image_format.depth = R_IMF_CHAN_DEPTH_8;
if (BLI_path_extension_check(filepath, ".exr")) {
filepath[strlen(filepath) - 4] = 0;
diff --git a/source/blender/blenkernel/intern/instances.cc b/source/blender/blenkernel/intern/instances.cc
new file mode 100644
index 00000000000..4675562e927
--- /dev/null
+++ b/source/blender/blenkernel/intern/instances.cc
@@ -0,0 +1,337 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+
+#include "BLI_array_utils.hh"
+#include "BLI_cpp_type_make.hh"
+#include "BLI_rand.hh"
+#include "BLI_task.hh"
+
+#include "BKE_attribute_math.hh"
+#include "BKE_geometry_set.hh"
+#include "BKE_instances.hh"
+
+BLI_CPP_TYPE_MAKE(InstanceReference, blender::bke::InstanceReference, CPPTypeFlags::None)
+
+namespace blender::bke {
+
+InstanceReference::InstanceReference(GeometrySet geometry_set)
+ : type_(Type::GeometrySet),
+ geometry_set_(std::make_unique<GeometrySet>(std::move(geometry_set)))
+{
+}
+
+void InstanceReference::ensure_owns_direct_data()
+{
+ if (type_ != Type::GeometrySet) {
+ return;
+ }
+ geometry_set_->ensure_owns_direct_data();
+}
+
+bool InstanceReference::owns_direct_data() const
+{
+ if (type_ != Type::GeometrySet) {
+ /* The object and collection instances are not direct data. */
+ return true;
+ }
+ return geometry_set_->owns_direct_data();
+}
+
+Instances::Instances(const Instances &other)
+ : references_(other.references_),
+ reference_handles_(other.reference_handles_),
+ transforms_(other.transforms_),
+ almost_unique_ids_(other.almost_unique_ids_),
+ attributes_(other.attributes_)
+{
+}
+
+void Instances::reserve(int min_capacity)
+{
+ reference_handles_.reserve(min_capacity);
+ transforms_.reserve(min_capacity);
+ attributes_.reallocate(min_capacity);
+}
+
+void Instances::resize(int capacity)
+{
+ reference_handles_.resize(capacity);
+ transforms_.resize(capacity);
+ attributes_.reallocate(capacity);
+}
+
+void Instances::add_instance(const int instance_handle, const float4x4 &transform)
+{
+ BLI_assert(instance_handle >= 0);
+ BLI_assert(instance_handle < references_.size());
+ reference_handles_.append(instance_handle);
+ transforms_.append(transform);
+ attributes_.reallocate(this->instances_num());
+}
+
+blender::Span<int> Instances::reference_handles() const
+{
+ return reference_handles_;
+}
+
+blender::MutableSpan<int> Instances::reference_handles()
+{
+ return reference_handles_;
+}
+
+blender::MutableSpan<blender::float4x4> Instances::transforms()
+{
+ return transforms_;
+}
+blender::Span<blender::float4x4> Instances::transforms() const
+{
+ return transforms_;
+}
+
+GeometrySet &Instances::geometry_set_from_reference(const int reference_index)
+{
+ /* If this assert fails, it means #ensure_geometry_instances must be called first or that the
+ * reference can't be converted to a geometry set. */
+ BLI_assert(references_[reference_index].type() == InstanceReference::Type::GeometrySet);
+
+ /* The const cast is okay because the instance's hash in the set
+ * is not changed by adjusting the data inside the geometry set. */
+ return const_cast<GeometrySet &>(references_[reference_index].geometry_set());
+}
+
+int Instances::add_reference(const InstanceReference &reference)
+{
+ return references_.index_of_or_add_as(reference);
+}
+
+blender::Span<InstanceReference> Instances::references() const
+{
+ return references_;
+}
+
+void Instances::remove(const IndexMask mask)
+{
+ using namespace blender;
+ if (mask.is_range() && mask.as_range().start() == 0) {
+ /* Deleting from the end of the array can be much faster since no data has to be shifted. */
+ this->resize(mask.size());
+ this->remove_unused_references();
+ return;
+ }
+
+ const Span<int> old_handles = this->reference_handles();
+ Vector<int> new_handles(mask.size());
+ array_utils::gather(old_handles, mask.indices(), new_handles.as_mutable_span());
+ reference_handles_ = std::move(new_handles);
+
+ const Span<float4x4> old_tansforms = this->transforms();
+ Vector<float4x4> new_transforms(mask.size());
+ array_utils::gather(old_tansforms, mask.indices(), new_transforms.as_mutable_span());
+ transforms_ = std::move(new_transforms);
+
+ const bke::CustomDataAttributes &src_attributes = attributes_;
+
+ bke::CustomDataAttributes dst_attributes;
+ dst_attributes.reallocate(mask.size());
+
+ src_attributes.foreach_attribute(
+ [&](const bke::AttributeIDRef &id, const bke::AttributeMetaData &meta_data) {
+ if (!id.should_be_kept()) {
+ return true;
+ }
+
+ GSpan src = *src_attributes.get_for_read(id);
+ dst_attributes.create(id, meta_data.data_type);
+ GMutableSpan dst = *dst_attributes.get_for_write(id);
+ array_utils::gather(src, mask.indices(), dst);
+
+ return true;
+ },
+ ATTR_DOMAIN_INSTANCE);
+
+ attributes_ = std::move(dst_attributes);
+ this->remove_unused_references();
+}
+
+void Instances::remove_unused_references()
+{
+ using namespace blender;
+ using namespace blender::bke;
+
+ const int tot_instances = this->instances_num();
+ const int tot_references_before = references_.size();
+
+ if (tot_instances == 0) {
+ /* If there are no instances, no reference is needed. */
+ references_.clear();
+ return;
+ }
+ if (tot_references_before == 1) {
+ /* There is only one reference and at least one instance. So the only existing reference is
+ * used. Nothing to do here. */
+ return;
+ }
+
+ Array<bool> usage_by_handle(tot_references_before, false);
+ std::mutex mutex;
+
+ /* Loop over all instances to see which references are used. */
+ threading::parallel_for(IndexRange(tot_instances), 1000, [&](IndexRange range) {
+ /* Use local counter to avoid lock contention. */
+ Array<bool> local_usage_by_handle(tot_references_before, false);
+
+ for (const int i : range) {
+ const int handle = reference_handles_[i];
+ BLI_assert(handle >= 0 && handle < tot_references_before);
+ local_usage_by_handle[handle] = true;
+ }
+
+ std::lock_guard lock{mutex};
+ for (const int i : IndexRange(tot_references_before)) {
+ usage_by_handle[i] |= local_usage_by_handle[i];
+ }
+ });
+
+ if (!usage_by_handle.as_span().contains(false)) {
+ /* All references are used. */
+ return;
+ }
+
+ /* Create new references and a mapping for the handles. */
+ Vector<int> handle_mapping;
+ VectorSet<InstanceReference> new_references;
+ int next_new_handle = 0;
+ bool handles_have_to_be_updated = false;
+ for (const int old_handle : IndexRange(tot_references_before)) {
+ if (!usage_by_handle[old_handle]) {
+ /* Add some dummy value. It won't be read again. */
+ handle_mapping.append(-1);
+ }
+ else {
+ const InstanceReference &reference = references_[old_handle];
+ handle_mapping.append(next_new_handle);
+ new_references.add_new(reference);
+ if (old_handle != next_new_handle) {
+ handles_have_to_be_updated = true;
+ }
+ next_new_handle++;
+ }
+ }
+ references_ = new_references;
+
+ if (!handles_have_to_be_updated) {
+ /* All remaining handles are the same as before, so they don't have to be updated. This happens
+ * when unused handles are only at the end. */
+ return;
+ }
+
+ /* Update handles of instances. */
+ threading::parallel_for(IndexRange(tot_instances), 1000, [&](IndexRange range) {
+ for (const int i : range) {
+ reference_handles_[i] = handle_mapping[reference_handles_[i]];
+ }
+ });
+}
+
+int Instances::instances_num() const
+{
+ return transforms_.size();
+}
+
+int Instances::references_num() const
+{
+ return references_.size();
+}
+
+bool Instances::owns_direct_data() const
+{
+ for (const InstanceReference &reference : references_) {
+ if (!reference.owns_direct_data()) {
+ return false;
+ }
+ }
+ return true;
+}
+
+void Instances::ensure_owns_direct_data()
+{
+ for (const InstanceReference &const_reference : references_) {
+ /* `const` cast is fine because we are not changing anything that would change the hash of the
+ * reference. */
+ InstanceReference &reference = const_cast<InstanceReference &>(const_reference);
+ reference.ensure_owns_direct_data();
+ }
+}
+
+static blender::Array<int> generate_unique_instance_ids(Span<int> original_ids)
+{
+ using namespace blender;
+ Array<int> unique_ids(original_ids.size());
+
+ Set<int> used_unique_ids;
+ used_unique_ids.reserve(original_ids.size());
+ Vector<int> instances_with_id_collision;
+ for (const int instance_index : original_ids.index_range()) {
+ const int original_id = original_ids[instance_index];
+ if (used_unique_ids.add(original_id)) {
+ /* The original id has not been used by another instance yet. */
+ unique_ids[instance_index] = original_id;
+ }
+ else {
+ /* The original id of this instance collided with a previous instance, it needs to be looked
+ * at again in a second pass. Don't generate a new random id here, because this might collide
+ * with other existing ids. */
+ instances_with_id_collision.append(instance_index);
+ }
+ }
+
+ Map<int, RandomNumberGenerator> generator_by_original_id;
+ for (const int instance_index : instances_with_id_collision) {
+ const int original_id = original_ids[instance_index];
+ RandomNumberGenerator &rng = generator_by_original_id.lookup_or_add_cb(original_id, [&]() {
+ RandomNumberGenerator rng;
+ rng.seed_random(original_id);
+ return rng;
+ });
+
+ const int max_iteration = 100;
+ for (int iteration = 0;; iteration++) {
+ /* Try generating random numbers until an unused one has been found. */
+ const int random_id = rng.get_int32();
+ if (used_unique_ids.add(random_id)) {
+ /* This random id is not used by another instance. */
+ unique_ids[instance_index] = random_id;
+ break;
+ }
+ if (iteration == max_iteration) {
+ /* It seems to be very unlikely that we ever run into this case (assuming there are less
+ * than 2^30 instances). However, if that happens, it's better to use an id that is not
+ * unique than to be stuck in an infinite loop. */
+ unique_ids[instance_index] = original_id;
+ break;
+ }
+ }
+ }
+
+ return unique_ids;
+}
+
+blender::Span<int> Instances::almost_unique_ids() const
+{
+ std::lock_guard lock(almost_unique_ids_mutex_);
+ std::optional<GSpan> instance_ids_gspan = attributes_.get_for_read("id");
+ if (instance_ids_gspan) {
+ Span<int> instance_ids = instance_ids_gspan->typed<int>();
+ if (almost_unique_ids_.size() != instance_ids.size()) {
+ almost_unique_ids_ = generate_unique_instance_ids(instance_ids);
+ }
+ }
+ else {
+ almost_unique_ids_.reinitialize(this->instances_num());
+ for (const int i : almost_unique_ids_.index_range()) {
+ almost_unique_ids_[i] = i;
+ }
+ }
+ return almost_unique_ids_;
+}
+
+} // namespace blender::bke
diff --git a/source/blender/blenkernel/intern/layer.c b/source/blender/blenkernel/intern/layer.c
index fcb0adfde34..06d69b6ff61 100644
--- a/source/blender/blenkernel/intern/layer.c
+++ b/source/blender/blenkernel/intern/layer.c
@@ -1049,7 +1049,7 @@ static void layer_collection_objects_sync(ViewLayer *view_layer,
}
/* Holdout and indirect only */
- if ((layer->flag & LAYER_COLLECTION_HOLDOUT) || (base->object->visibility_flag & OB_HOLDOUT)) {
+ if ((layer->flag & LAYER_COLLECTION_HOLDOUT)) {
base->flag_from_collection |= BASE_HOLDOUT;
}
if (layer->flag & LAYER_COLLECTION_INDIRECT_ONLY) {
diff --git a/source/blender/blenkernel/intern/lib_id_delete.c b/source/blender/blenkernel/intern/lib_id_delete.c
index f4f5ca7a1d7..1a80376f482 100644
--- a/source/blender/blenkernel/intern/lib_id_delete.c
+++ b/source/blender/blenkernel/intern/lib_id_delete.c
@@ -16,6 +16,7 @@
#include "BLI_utildefines.h"
+#include "BLI_linklist.h"
#include "BLI_listbase.h"
#include "BKE_anim_data.h"
@@ -23,10 +24,10 @@
#include "BKE_idprop.h"
#include "BKE_idtype.h"
#include "BKE_key.h"
+#include "BKE_layer.h"
#include "BKE_lib_id.h"
#include "BKE_lib_override.h"
#include "BKE_lib_remap.h"
-#include "BKE_library.h"
#include "BKE_main.h"
#include "BKE_main_namemap.h"
@@ -202,7 +203,6 @@ static size_t id_delete(Main *bmain, const bool do_tagged_deletion)
{
const int tag = LIB_TAG_DOIT;
ListBase *lbarray[INDEX_ID_MAX];
- Link dummy_link = {0};
int base_count, i;
/* Used by batch tagged deletion, when we call BKE_id_free then, id is no more in Main database,
@@ -217,6 +217,9 @@ static size_t id_delete(Main *bmain, const bool do_tagged_deletion)
BKE_main_lock(bmain);
if (do_tagged_deletion) {
+ struct IDRemapper *id_remapper = BKE_id_remapper_create();
+ BKE_layer_collection_resync_forbid();
+
/* Main idea of batch deletion is to remove all IDs to be deleted from Main database.
* This means that we won't have to loop over all deleted IDs to remove usages
* of other deleted IDs.
@@ -227,7 +230,6 @@ static size_t id_delete(Main *bmain, const bool do_tagged_deletion)
bool keep_looping = true;
while (keep_looping) {
ID *id, *id_next;
- ID *last_remapped_id = tagged_deleted_ids.last;
keep_looping = false;
/* First tag and remove from Main all datablocks directly from target lib.
@@ -243,6 +245,7 @@ static size_t id_delete(Main *bmain, const bool do_tagged_deletion)
BLI_remlink(lb, id);
BKE_main_namemap_remove_name(bmain, id, id->name + 2);
BLI_addtail(&tagged_deleted_ids, id);
+ BKE_id_remapper_add(id_remapper, id, NULL);
/* Do not tag as no_main now, we want to unlink it first (lower-level ID management
* code has some specific handling of 'no main' IDs that would be a problem in that
* case). */
@@ -251,33 +254,38 @@ static size_t id_delete(Main *bmain, const bool do_tagged_deletion)
}
}
}
- if (last_remapped_id == NULL) {
- dummy_link.next = tagged_deleted_ids.first;
- last_remapped_id = (ID *)(&dummy_link);
- }
- for (id = last_remapped_id->next; id; id = id->next) {
- /* Will tag 'never NULL' users of this ID too.
- *
- * NOTE: #BKE_libblock_unlink() cannot be used here, since it would ignore indirect
- * links, this can lead to nasty crashing here in second, actual deleting loop.
- * Also, this will also flag users of deleted data that cannot be unlinked
- * (object using deleted obdata, etc.), so that they also get deleted. */
- BKE_libblock_remap_locked(bmain,
- id,
- NULL,
- (ID_REMAP_FLAG_NEVER_NULL_USAGE |
- ID_REMAP_FORCE_NEVER_NULL_USAGE |
- ID_REMAP_FORCE_INTERNAL_RUNTIME_POINTERS));
- /* Since we removed ID from Main,
- * we also need to unlink its own other IDs usages ourself. */
- BKE_libblock_relink_ex(
- bmain,
- id,
- NULL,
- NULL,
- (ID_REMAP_FORCE_INTERNAL_RUNTIME_POINTERS | ID_REMAP_SKIP_USER_CLEAR));
- }
+
+ /* Will tag 'never NULL' users of this ID too.
+ *
+ * NOTE: #BKE_libblock_unlink() cannot be used here, since it would ignore indirect
+ * links, this can lead to nasty crashing here in second, actual deleting loop.
+ * Also, this will also flag users of deleted data that cannot be unlinked
+ * (object using deleted obdata, etc.), so that they also get deleted. */
+ BKE_libblock_remap_multiple_locked(bmain,
+ id_remapper,
+ ID_REMAP_FLAG_NEVER_NULL_USAGE |
+ ID_REMAP_FORCE_NEVER_NULL_USAGE |
+ ID_REMAP_FORCE_INTERNAL_RUNTIME_POINTERS);
+ BKE_id_remapper_clear(id_remapper);
+ }
+
+ /* Since we removed IDs from Main, their own other IDs usages need to be removed 'manually'. */
+ LinkNode *cleanup_ids = NULL;
+ for (ID *id = tagged_deleted_ids.first; id; id = id->next) {
+ BLI_linklist_prepend(&cleanup_ids, id);
}
+ BKE_libblock_relink_multiple(bmain,
+ cleanup_ids,
+ ID_REMAP_TYPE_CLEANUP,
+ id_remapper,
+ ID_REMAP_FORCE_INTERNAL_RUNTIME_POINTERS |
+ ID_REMAP_SKIP_USER_CLEAR);
+
+ BKE_id_remapper_free(id_remapper);
+ BLI_linklist_free(cleanup_ids, NULL);
+
+ BKE_layer_collection_resync_allow();
+ BKE_main_collection_sync_remap(bmain);
/* Now we can safely mark that ID as not being in Main database anymore. */
/* NOTE: This needs to be done in a separate loop than above, otherwise some user-counts of
@@ -285,6 +293,10 @@ static size_t id_delete(Main *bmain, const bool do_tagged_deletion)
* is never affected). */
for (ID *id = tagged_deleted_ids.first; id; id = id->next) {
id->tag |= LIB_TAG_NO_MAIN;
+ /* Usercount needs to be reset artificially, since some usages may not be cleared in batch
+ * deletion (typically, if one deleted ID uses another deleted ID, this may not be cleared by
+ * remapping code, depending on order in which these are handled). */
+ id->us = ID_FAKE_USERS(id);
}
}
else {
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..784d35a8d65 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 {
@@ -1313,6 +1313,7 @@ void BKE_mesh_nomain_to_mesh(Mesh *mesh_src, Mesh *mesh_dst, Object *ob)
CustomData_duplicate_referenced_layers(&mesh_src->pdata, mesh_src->totpoly);
CustomData_duplicate_referenced_layers(&mesh_src->ldata, mesh_src->totloop);
+ const bool verts_num_changed = mesh_dst->totvert != mesh_src->totvert;
mesh_dst->totvert = mesh_src->totvert;
mesh_dst->totedge = mesh_src->totedge;
mesh_dst->totpoly = mesh_src->totpoly;
@@ -1339,11 +1340,10 @@ void BKE_mesh_nomain_to_mesh(Mesh *mesh_src, Mesh *mesh_dst, Object *ob)
const int uid_active = ob ? find_object_active_key_uid(*key_dst, *ob) : -1;
move_shapekey_layers_to_keyblocks(*mesh_dst, mesh_src->vdata, *key_dst, uid_active);
}
- else if (mesh_src->totvert != mesh_dst->totvert) {
- CLOG_ERROR(&LOG, "Mesh in Main '%s' lost shape keys", mesh_src->id.name);
- if (mesh_src->key) {
- id_us_min(&mesh_src->key->id);
- }
+ else if (verts_num_changed) {
+ CLOG_WARN(&LOG, "Shape key data lost when replacing mesh '%s' in Main", mesh_src->id.name);
+ id_us_min(&mesh_dst->key->id);
+ mesh_dst->key = nullptr;
}
}
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..92a7c778b68 100644
--- a/source/blender/blenkernel/intern/modifier.cc
+++ b/source/blender/blenkernel/intern/modifier.cc
@@ -955,7 +955,7 @@ const char *BKE_modifier_path_relbase_from_global(Object *ob)
void BKE_modifier_path_init(char *path, int path_maxlen, const char *name)
{
const char *blendfile_path = BKE_main_blendfile_path_from_global();
- BLI_join_dirfile(path, path_maxlen, blendfile_path[0] ? "//" : BKE_tempdir_session(), name);
+ BLI_path_join(path, path_maxlen, blendfile_path[0] ? "//" : BKE_tempdir_session(), name);
}
/**
@@ -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..24663d6db05 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) {
@@ -1890,7 +1918,7 @@ bool BKE_nla_action_stash(AnimData *adt, const bool is_liboverride)
* NOTE: this must be done *after* adding the strip to the track, or else
* the strip locking will prevent the strip from getting added
*/
- nlt->flag = (NLATRACK_MUTED | NLATRACK_PROTECTED);
+ nlt->flag |= (NLATRACK_MUTED | NLATRACK_PROTECTED);
strip->flag &= ~(NLASTRIP_FLAG_SELECT | NLASTRIP_FLAG_ACTIVE);
/* also mark the strip for auto syncing the length, so that the strips accurately
diff --git a/source/blender/blenkernel/intern/node.cc b/source/blender/blenkernel/intern/node.cc
index 44daa7d968d..aa25953d85a 100644
--- a/source/blender/blenkernel/intern/node.cc
+++ b/source/blender/blenkernel/intern/node.cc
@@ -516,10 +516,6 @@ void ntreeBlendWrite(BlendWriter *writer, bNodeTree *ntree)
write_node_socket(writer, sock);
}
- LISTBASE_FOREACH (bNodeLink *, link, &node->internal_links) {
- BLO_write_struct(writer, bNodeLink, link);
- }
-
if (node->storage) {
if (ELEM(ntree->type, NTREE_SHADER, NTREE_GEOMETRY) &&
ELEM(node->type, SH_NODE_CURVE_VEC, SH_NODE_CURVE_RGB, SH_NODE_CURVE_FLOAT)) {
@@ -703,13 +699,7 @@ void ntreeBlendReadData(BlendDataReader *reader, ID *owner_id, bNodeTree *ntree)
BLO_read_data_address(reader, &node->prop);
IDP_BlendDataRead(reader, &node->prop);
- BLO_read_list(reader, &node->internal_links);
- LISTBASE_FOREACH (bNodeLink *, link, &node->internal_links) {
- BLO_read_data_address(reader, &link->fromnode);
- BLO_read_data_address(reader, &link->fromsock);
- BLO_read_data_address(reader, &link->tonode);
- BLO_read_data_address(reader, &link->tosock);
- }
+ BLI_listbase_clear(&node->internal_links);
if (node->type == CMP_NODE_MOVIEDISTORTION) {
/* Do nothing, this is runtime cache and hence handled by generic code using
@@ -2157,6 +2147,38 @@ void nodeParentsIter(bNode *node, bool (*callback)(bNode *, void *), void *userd
}
}
+bool nodeIsDanglingReroute(const bNodeTree *ntree, const bNode *node)
+{
+ ntree->ensure_topology_cache();
+ BLI_assert(blender::bke::node_tree_runtime::topology_cache_is_available(*ntree));
+ BLI_assert(!ntree->has_available_link_cycle());
+
+ const bNode *iter_node = node;
+ if (!iter_node->is_reroute()) {
+ return false;
+ }
+
+ while (true) {
+ const blender::Span<const bNodeLink *> links =
+ iter_node->input_socket(0).directly_linked_links();
+ BLI_assert(links.size() <= 1);
+ if (links.is_empty()) {
+ return true;
+ }
+ const bNodeLink &link = *links[0];
+ if (!link.is_available()) {
+ return false;
+ }
+ if (link.is_muted()) {
+ return false;
+ }
+ iter_node = link.fromnode;
+ if (!iter_node->is_reroute()) {
+ return false;
+ }
+ }
+}
+
/* ************** Add stuff ********** */
void nodeUniqueName(bNodeTree *ntree, bNode *node)
diff --git a/source/blender/blenkernel/intern/object.cc b/source/blender/blenkernel/intern/object.cc
index 9417d1afc7e..d98f5e85028 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);
@@ -1902,6 +1902,7 @@ bool BKE_object_is_in_editmode(const Object *ob)
/* Grease Pencil object has no edit mode data. */
return GPENCIL_EDIT_MODE((bGPdata *)ob->data);
case OB_CURVES:
+ /* Curves object has no edit mode data. */
return ob->mode == OB_MODE_EDIT;
default:
return false;
@@ -3218,7 +3219,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 +3234,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 306e508dc83..d43eff6f9b4 100644
--- a/source/blender/blenkernel/intern/object_dupli.cc
+++ b/source/blender/blenkernel/intern/object_dupli.cc
@@ -41,6 +41,7 @@
#include "BKE_geometry_set.hh"
#include "BKE_global.h"
#include "BKE_idprop.h"
+#include "BKE_instances.hh"
#include "BKE_lattice.h"
#include "BKE_main.h"
#include "BKE_mesh.h"
@@ -70,6 +71,8 @@ using blender::float3;
using blender::float4x4;
using blender::Span;
using blender::Vector;
+using blender::bke::InstanceReference;
+using blender::bke::Instances;
namespace geo_log = blender::nodes::geo_eval_log;
/* -------------------------------------------------------------------- */
@@ -423,8 +426,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;
@@ -874,8 +877,8 @@ static void make_duplis_geometry_set_impl(const DupliContext *ctx,
}
const bool creates_duplis_for_components = component_index >= 1;
- const InstancesComponent *component = geometry_set.get_component_for_read<InstancesComponent>();
- if (component == nullptr) {
+ const Instances *instances = geometry_set.get_instances_for_read();
+ if (instances == nullptr) {
return;
}
@@ -890,13 +893,13 @@ static void make_duplis_geometry_set_impl(const DupliContext *ctx,
instances_ctx = &new_instances_ctx;
}
- Span<float4x4> instance_offset_matrices = component->instance_transforms();
- Span<int> instance_reference_handles = component->instance_reference_handles();
- Span<int> almost_unique_ids = component->almost_unique_ids();
- Span<InstanceReference> references = component->references();
+ Span<float4x4> instance_offset_matrices = instances->transforms();
+ Span<int> reference_handles = instances->reference_handles();
+ Span<int> almost_unique_ids = instances->almost_unique_ids();
+ Span<InstanceReference> references = instances->references();
for (int64_t i : instance_offset_matrices.index_range()) {
- const InstanceReference &reference = references[instance_reference_handles[i]];
+ const InstanceReference &reference = references[reference_handles[i]];
const int id = almost_unique_ids[i];
const DupliContext *ctx_for_instance = instances_ctx;
diff --git a/source/blender/blenkernel/intern/object_update.cc b/source/blender/blenkernel/intern/object_update.cc
index 5328d956cee..e53090bcffe 100644
--- a/source/blender/blenkernel/intern/object_update.cc
+++ b/source/blender/blenkernel/intern/object_update.cc
@@ -292,6 +292,8 @@ void BKE_object_batch_cache_dirty_tag(Object *ob)
BKE_lattice_batch_cache_dirty_tag((struct Lattice *)ob->data, BKE_LATTICE_BATCH_DIRTY_ALL);
break;
case OB_CURVES_LEGACY:
+ case OB_SURF:
+ case OB_FONT:
BKE_curve_batch_cache_dirty_tag((struct Curve *)ob->data, BKE_CURVE_BATCH_DIRTY_ALL);
break;
case OB_MBALL: {
@@ -373,10 +375,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/ocean.c b/source/blender/blenkernel/intern/ocean.c
index 396c3443a73..bcf382b6022 100644
--- a/source/blender/blenkernel/intern/ocean.c
+++ b/source/blender/blenkernel/intern/ocean.c
@@ -1144,7 +1144,7 @@ static void cache_filename(
break;
}
- BLI_join_dirfile(cachepath, sizeof(cachepath), path, fname);
+ BLI_path_join(cachepath, sizeof(cachepath), path, fname);
BKE_image_path_from_imtype(
string, cachepath, relbase, frame, R_IMF_IMTYPE_OPENEXR, true, true, "");
diff --git a/source/blender/blenkernel/intern/packedFile.c b/source/blender/blenkernel/intern/packedFile.c
index 901b42ac0b2..0c9d9f5b048 100644
--- a/source/blender/blenkernel/intern/packedFile.c
+++ b/source/blender/blenkernel/intern/packedFile.c
@@ -545,7 +545,7 @@ static void unpack_generate_paths(const char *name,
break;
}
if (dir_name) {
- BLI_path_join(r_relpath, relpathlen, "//", dir_name, tempname, NULL);
+ BLI_path_join(r_relpath, relpathlen, "//", dir_name, tempname);
}
}
diff --git a/source/blender/blenkernel/intern/paint.cc b/source/blender/blenkernel/intern/paint.cc
index 00535ea5528..408cd117e32 100644
--- a/source/blender/blenkernel/intern/paint.cc
+++ b/source/blender/blenkernel/intern/paint.cc
@@ -54,6 +54,7 @@
#include "BKE_object.h"
#include "BKE_paint.h"
#include "BKE_pbvh.h"
+#include "BKE_scene.h"
#include "BKE_subdiv_ccg.h"
#include "BKE_subsurf.h"
@@ -1042,6 +1043,8 @@ eObjectMode BKE_paint_object_mode_from_paintmode(ePaintMode mode)
return OB_MODE_TEXTURE_PAINT;
case PAINT_MODE_SCULPT_UV:
return OB_MODE_EDIT;
+ case PAINT_MODE_SCULPT_CURVES:
+ return OB_MODE_SCULPT_CURVES;
case PAINT_MODE_INVALID:
default:
return OB_MODE_OBJECT;
@@ -1743,7 +1746,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);
@@ -1785,8 +1788,8 @@ static void sculpt_update_object(
/* If the fully evaluated mesh has the same topology as the deform-only version, use it.
* This matters because crazyspace evaluation is very restrictive and excludes even modifiers
* that simply recompute vertex weights (which can even include Geometry Nodes). */
- if (me_eval_deform->polys().data() == me_eval->polys().data() &&
- me_eval_deform->loops().data() == me_eval->loops().data() &&
+ if (me_eval_deform->totpoly == me_eval->totpoly &&
+ me_eval_deform->totloop == me_eval->totloop &&
me_eval_deform->totvert == me_eval->totvert) {
BKE_sculptsession_free_deformMats(ss);
@@ -1986,7 +1989,10 @@ bool *BKE_sculpt_hide_poly_ensure(Mesh *mesh)
&mesh->pdata, CD_PROP_BOOL, CD_SET_DEFAULT, nullptr, mesh->totpoly, ".hide_poly"));
}
-int BKE_sculpt_mask_layers_ensure(Object *ob, MultiresModifierData *mmd)
+int BKE_sculpt_mask_layers_ensure(Depsgraph *depsgraph,
+ Main *bmain,
+ Object *ob,
+ MultiresModifierData *mmd)
{
Mesh *me = static_cast<Mesh *>(ob->data);
const Span<MPoly> polys = me->polys();
@@ -2045,6 +2051,9 @@ int BKE_sculpt_mask_layers_ensure(Object *ob, MultiresModifierData *mmd)
}
/* The evaluated multires CCG must be updated to contain the new data. */
DEG_id_tag_update(&ob->id, ID_RECALC_GEOMETRY);
+ if (depsgraph) {
+ BKE_scene_graph_evaluated_ensure(depsgraph, bmain);
+ }
ret |= SCULPT_MASK_LAYER_CALC_LOOP;
}
@@ -2237,7 +2246,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 +2268,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 +2287,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,19 +2297,23 @@ 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;
}
void BKE_sculpt_bvh_update_from_ccg(PBVH *pbvh, SubdivCCG *subdiv_ccg)
{
+ CCGKey key;
+ BKE_subdiv_ccg_key_top_level(&key, subdiv_ccg);
+
BKE_pbvh_grids_update(pbvh,
subdiv_ccg->grids,
(void **)subdiv_ccg->grid_faces,
subdiv_ccg->grid_flag_mats,
- subdiv_ccg->grid_hidden);
+ subdiv_ccg->grid_hidden,
+ &key);
}
bool BKE_sculptsession_use_pbvh_draw(const Object *ob, const View3D * /*v3d*/)
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 a7595952cac..98e89b09060 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;
}
@@ -2044,11 +2236,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)
@@ -2867,9 +3064,14 @@ void BKE_pbvh_draw_debug_cb(PBVH *pbvh,
}
}
-void BKE_pbvh_grids_update(
- PBVH *pbvh, CCGElem **grids, void **gridfaces, DMFlagMat *flagmats, BLI_bitmap **grid_hidden)
+void BKE_pbvh_grids_update(PBVH *pbvh,
+ CCGElem **grids,
+ void **gridfaces,
+ DMFlagMat *flagmats,
+ BLI_bitmap **grid_hidden,
+ CCGKey *key)
{
+ pbvh->gridkey = *key;
pbvh->grids = grids;
pbvh->gridfaces = gridfaces;
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 bdfd3ad3d09..368a9ffa1ea 100644
--- a/source/blender/blenkernel/intern/pbvh_intern.h
+++ b/source/blender/blenkernel/intern/pbvh_intern.h
@@ -96,7 +96,7 @@ struct PBVHNode {
/* Indicates whether this node is a leaf or not; also used for
* marking various updates that need to be applied. */
- PBVHNodeFlags flag : 16;
+ PBVHNodeFlags flag : 32;
/* Used for raycasting: how close bb is to the ray point. */
float tmin;
@@ -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/pointcache.c b/source/blender/blenkernel/intern/pointcache.c
index 5ec69f9bc45..ac98bed2cf0 100644
--- a/source/blender/blenkernel/intern/pointcache.c
+++ b/source/blender/blenkernel/intern/pointcache.c
@@ -2640,7 +2640,7 @@ void BKE_ptcache_id_clear(PTCacheID *pid, int mode, uint cfra)
if (STREQLEN(filepath, de->d_name, len)) { /* Do we have the right prefix. */
if (mode == PTCACHE_CLEAR_ALL) {
pid->cache->last_exact = MIN2(pid->cache->startframe, 0);
- BLI_join_dirfile(path_full, sizeof(path_full), path, de->d_name);
+ BLI_path_join(path_full, sizeof(path_full), path, de->d_name);
BLI_delete(path_full, false, false);
}
else {
@@ -2650,7 +2650,7 @@ void BKE_ptcache_id_clear(PTCacheID *pid, int mode, uint cfra)
if (frame != -1) {
if ((mode == PTCACHE_CLEAR_BEFORE && frame < cfra) ||
(mode == PTCACHE_CLEAR_AFTER && frame > cfra)) {
- BLI_join_dirfile(path_full, sizeof(path_full), path, de->d_name);
+ BLI_path_join(path_full, sizeof(path_full), path, de->d_name);
BLI_delete(path_full, false, false);
if (pid->cache->cached_frames && frame >= sta && frame <= end) {
pid->cache->cached_frames[frame - sta] = 0;
@@ -3524,7 +3524,7 @@ void BKE_ptcache_disk_cache_rename(PTCacheID *pid, const char *name_src, const c
const int frame = ptcache_frame_from_filename(de->d_name, ext);
if (frame != -1) {
- BLI_join_dirfile(old_path_full, sizeof(old_path_full), path, de->d_name);
+ BLI_path_join(old_path_full, sizeof(old_path_full), path, de->d_name);
ptcache_filepath(pid, new_path_full, frame, true, true);
BLI_rename(old_path_full, new_path_full);
}
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/preferences.c b/source/blender/blenkernel/intern/preferences.c
index b2e795901fb..dd76f9eddc1 100644
--- a/source/blender/blenkernel/intern/preferences.c
+++ b/source/blender/blenkernel/intern/preferences.c
@@ -115,8 +115,7 @@ void BKE_preferences_asset_library_default_add(UserDef *userdef)
userdef, DATA_(BKE_PREFS_ASSET_LIBRARY_DEFAULT_NAME), NULL);
/* Add new "Default" library under '[doc_path]/Blender/Assets'. */
- BLI_path_join(
- library->path, sizeof(library->path), documents_path, N_("Blender"), N_("Assets"), NULL);
+ BLI_path_join(library->path, sizeof(library->path), documents_path, N_("Blender"), N_("Assets"));
}
/** \} */
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..bd26075f81f 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)
@@ -280,6 +280,9 @@ static void scene_copy_data(Main *bmain, ID *id_dst, const ID *id_src, const int
}
/* View Layers */
+ LISTBASE_FOREACH (ViewLayer *, view_layer, &scene_src->view_layers) {
+ BKE_view_layer_synced_ensure(scene_src, view_layer);
+ }
BLI_duplicatelist(&scene_dst->view_layers, &scene_src->view_layers);
for (ViewLayer *view_layer_src = static_cast<ViewLayer *>(scene_src->view_layers.first),
*view_layer_dst = static_cast<ViewLayer *>(scene_dst->view_layers.first);
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/blenkernel/intern/volume.cc b/source/blender/blenkernel/intern/volume.cc
index 7c54b4d3f2f..e81657f9ef0 100644
--- a/source/blender/blenkernel/intern/volume.cc
+++ b/source/blender/blenkernel/intern/volume.cc
@@ -445,7 +445,7 @@ struct VolumeGrid {
* may actually be loaded by another user while this is false. But only after
* calling load() and is_loaded changes to true is it safe to access.
*
- * Const write access to this must be protected by `entry->mutex`.
+ * `const` write access to this must be protected by `entry->mutex`.
*/
mutable bool is_loaded;
};
@@ -480,7 +480,7 @@ struct VolumeGridVector : public std::list<VolumeGrid> {
metadata.reset();
}
- /* Mutex for file loading of grids list. Const write access to the fields after this must be
+ /* Mutex for file loading of grids list. `const` write access to the fields after this must be
* protected by locking with this mutex. */
mutable std::mutex mutex;
/* Absolute file path that grids have been loaded from. */
diff --git a/source/blender/blenkernel/intern/writeavi.c b/source/blender/blenkernel/intern/writeavi.c
index dbdf8cc395d..de2e196c163 100644
--- a/source/blender/blenkernel/intern/writeavi.c
+++ b/source/blender/blenkernel/intern/writeavi.c
@@ -122,7 +122,8 @@ bMovieHandle *BKE_movie_handle_get(const char imtype)
R_IMF_IMTYPE_FFMPEG,
R_IMF_IMTYPE_H264,
R_IMF_IMTYPE_XVID,
- R_IMF_IMTYPE_THEORA)) {
+ R_IMF_IMTYPE_THEORA,
+ R_IMF_IMTYPE_AV1)) {
mh.start_movie = BKE_ffmpeg_start;
mh.append_movie = BKE_ffmpeg_append;
mh.end_movie = BKE_ffmpeg_end;
diff --git a/source/blender/blenkernel/intern/writeffmpeg.c b/source/blender/blenkernel/intern/writeffmpeg.c
index 99df07b6105..0d3a790ba00 100644
--- a/source/blender/blenkernel/intern/writeffmpeg.c
+++ b/source/blender/blenkernel/intern/writeffmpeg.c
@@ -299,6 +299,10 @@ static const char **get_file_extensions(int format)
static const char *rv[] = {".webm", NULL};
return rv;
}
+ case FFMPEG_AV1: {
+ static const char *rv[] = {".mp4", ".mkv", NULL};
+ return rv;
+ }
default:
return NULL;
}
@@ -455,6 +459,204 @@ static AVRational calc_time_base(uint den, double num, int codec_id)
return time_base;
}
+static const AVCodec *get_av1_encoder(
+ FFMpegContext *context, RenderData *rd, AVDictionary **opts, int rectx, int recty)
+{
+ /* There are three possible encoders for AV1: libaom-av1, librav1e, and libsvtav1. librav1e tends
+ * to give the best compression quality while libsvtav1 tends to be the fastest encoder. One of
+ * each will be picked based on the preset setting, and if a particular encoder is not available,
+ * then use the default returned by FFMpeg. */
+ const AVCodec *codec = NULL;
+ switch (context->ffmpeg_preset) {
+ case FFM_PRESET_BEST:
+ /* Default to libaom-av1 for BEST preset due to it performing better than rav1e in terms of
+ * video quality (VMAF scores). Fallback to rav1e if libaom-av1 isn't available. */
+ codec = avcodec_find_encoder_by_name("libaom-av1");
+ if (!codec) {
+ codec = avcodec_find_encoder_by_name("librav1e");
+ }
+ break;
+ case FFM_PRESET_REALTIME:
+ codec = avcodec_find_encoder_by_name("libsvtav1");
+ break;
+ case FFM_PRESET_GOOD:
+ default:
+ codec = avcodec_find_encoder_by_name("libaom-av1");
+ break;
+ }
+
+ /* Use the default AV1 encoder if the specified encoder wasn't found. */
+ if (!codec) {
+ codec = avcodec_find_encoder(AV_CODEC_ID_AV1);
+ }
+
+ /* Apply AV1 encoder specific settings. */
+ if (codec) {
+ if (strcmp(codec->name, "librav1e") == 0) {
+ /* Set "tiles" to 8 to enable multi-threaded encoding. */
+ if (rd->threads > 8) {
+ ffmpeg_dict_set_int(opts, "tiles", rd->threads);
+ }
+ else {
+ ffmpeg_dict_set_int(opts, "tiles", 8);
+ }
+
+ /* Use a reasonable speed setting based on preset. Speed ranges from 0-10.
+ * Must check context->ffmpeg_preset again in case this encoder was selected due to the
+ * absence of another. */
+ switch (context->ffmpeg_preset) {
+ case FFM_PRESET_BEST:
+ ffmpeg_dict_set_int(opts, "speed", 4);
+ break;
+ case FFM_PRESET_REALTIME:
+ ffmpeg_dict_set_int(opts, "speed", 10);
+ break;
+ case FFM_PRESET_GOOD:
+ default:
+ ffmpeg_dict_set_int(opts, "speed", 6);
+ break;
+ }
+ if (context->ffmpeg_crf >= 0) {
+ /* librav1e does not use -crf, but uses -qp in the range of 0-255. Calculates the roughly
+ * equivalent float, and truncates it to an integer. */
+ unsigned int qp_value = ((float)context->ffmpeg_crf) * 255.0F / 51.0F;
+ if (qp_value > 255) {
+ qp_value = 255;
+ }
+ ffmpeg_dict_set_int(opts, "qp", qp_value);
+ }
+ /* Set gop_size as rav1e's "--keyint". */
+ char buffer[64];
+ BLI_snprintf(buffer, sizeof(buffer), "keyint=%d", context->ffmpeg_gop_size);
+ av_dict_set(opts, "rav1e-params", buffer, 0);
+ }
+ else if (strcmp(codec->name, "libsvtav1") == 0) {
+ /* Set preset value based on ffmpeg_preset.
+ * Must check context->ffmpeg_preset again in case this encoder was selected due to the
+ * absence of another. */
+ switch (context->ffmpeg_preset) {
+ case FFM_PRESET_REALTIME:
+ ffmpeg_dict_set_int(opts, "preset", 8);
+ break;
+ case FFM_PRESET_BEST:
+ ffmpeg_dict_set_int(opts, "preset", 3);
+ break;
+ case FFM_PRESET_GOOD:
+ default:
+ ffmpeg_dict_set_int(opts, "preset", 5);
+ break;
+ }
+ if (context->ffmpeg_crf >= 0) {
+ /* libsvtav1 does not support crf until FFmpeg builds since 2022-02-24, use qp as fallback.
+ */
+ ffmpeg_dict_set_int(opts, "qp", context->ffmpeg_crf);
+ }
+ }
+ else if (strcmp(codec->name, "libaom-av1") == 0) {
+ /* Speed up libaom-av1 encoding by enabling multithreading and setting tiles. */
+ ffmpeg_dict_set_int(opts, "row-mt", 1);
+ const char *tiles_string = NULL;
+ bool tiles_string_is_dynamic = false;
+ if (rd->threads > 0) {
+ /* See if threads is a square. */
+ int threads_sqrt = sqrtf(rd->threads);
+ if (threads_sqrt < 4) {
+ /* Ensure a default minimum. */
+ threads_sqrt = 4;
+ }
+ if (is_power_of_2_i(threads_sqrt) && threads_sqrt * threads_sqrt == rd->threads) {
+ /* Is a square num, therefore just do "sqrt x sqrt" for tiles parameter. */
+ int digits = 0;
+ for (int t_sqrt_copy = threads_sqrt; t_sqrt_copy > 0; t_sqrt_copy /= 10) {
+ ++digits;
+ }
+ /* A char array need only an alignment of 1. */
+ char *tiles_string_mut = (char *)calloc(digits * 2 + 2, 1);
+ BLI_snprintf(tiles_string_mut, digits * 2 + 2, "%dx%d", threads_sqrt, threads_sqrt);
+ tiles_string_is_dynamic = true;
+ tiles_string = tiles_string_mut;
+ }
+ else {
+ /* Is not a square num, set greater side based on longer side, or use a square if both
+ sides are equal. */
+ int sqrt_p2 = power_of_2_min_i(threads_sqrt);
+ if (sqrt_p2 < 2) {
+ /* Ensure a default minimum. */
+ sqrt_p2 = 2;
+ }
+ int sqrt_p2_next = power_of_2_min_i((int)rd->threads / sqrt_p2);
+ if (sqrt_p2_next < 1) {
+ sqrt_p2_next = 1;
+ }
+ if (sqrt_p2 > sqrt_p2_next) {
+ /* Ensure sqrt_p2_next is greater or equal to sqrt_p2. */
+ int temp = sqrt_p2;
+ sqrt_p2 = sqrt_p2_next;
+ sqrt_p2_next = temp;
+ }
+ int combined_digits = 0;
+ for (int sqrt_p2_copy = sqrt_p2; sqrt_p2_copy > 0; sqrt_p2_copy /= 10) {
+ ++combined_digits;
+ }
+ for (int sqrt_p2_copy = sqrt_p2_next; sqrt_p2_copy > 0; sqrt_p2_copy /= 10) {
+ ++combined_digits;
+ }
+ /* A char array need only an alignment of 1. */
+ char *tiles_string_mut = (char *)calloc(combined_digits + 2, 1);
+ if (rectx > recty) {
+ BLI_snprintf(tiles_string_mut, combined_digits + 2, "%dx%d", sqrt_p2_next, sqrt_p2);
+ }
+ else if (rectx < recty) {
+ BLI_snprintf(tiles_string_mut, combined_digits + 2, "%dx%d", sqrt_p2, sqrt_p2_next);
+ }
+ else {
+ BLI_snprintf(tiles_string_mut, combined_digits + 2, "%dx%d", sqrt_p2, sqrt_p2);
+ }
+ tiles_string_is_dynamic = true;
+ tiles_string = tiles_string_mut;
+ }
+ }
+ else {
+ /* Thread count unknown, default to 8. */
+ if (rectx > recty) {
+ tiles_string = "4x2";
+ }
+ else if (rectx < recty) {
+ tiles_string = "2x4";
+ }
+ else {
+ tiles_string = "2x2";
+ }
+ }
+ av_dict_set(opts, "tiles", tiles_string, 0);
+ if (tiles_string_is_dynamic) {
+ free((void *)tiles_string);
+ }
+ /* libaom-av1 uses "cpu-used" instead of "preset" for defining compression quality.
+ * This value is in a range from 0-8. 0 and 8 are extremes, but we will allow 8.
+ * Must check context->ffmpeg_preset again in case this encoder was selected due to the
+ * absence of another. */
+ switch (context->ffmpeg_preset) {
+ case FFM_PRESET_REALTIME:
+ ffmpeg_dict_set_int(opts, "cpu-used", 8);
+ break;
+ case FFM_PRESET_BEST:
+ ffmpeg_dict_set_int(opts, "cpu-used", 4);
+ break;
+ case FFM_PRESET_GOOD:
+ default:
+ ffmpeg_dict_set_int(opts, "cpu-used", 6);
+ break;
+ }
+
+ /* CRF related settings is similar to H264 for libaom-av1, so we will rely on those settings
+ * applied later. */
+ }
+ }
+
+ return codec;
+}
+
/* prepare a video stream for the output file */
static AVStream *alloc_video_stream(FFMpegContext *context,
@@ -480,7 +682,14 @@ static AVStream *alloc_video_stream(FFMpegContext *context,
/* Set up the codec context */
- codec = avcodec_find_encoder(codec_id);
+ if (codec_id == AV_CODEC_ID_AV1) {
+ /* Use get_av1_encoder() to get the ideal (hopefully) encoder for AV1 based
+ * on given parameters, and also set up opts. */
+ codec = get_av1_encoder(context, rd, &opts, rectx, recty);
+ }
+ else {
+ codec = avcodec_find_encoder(codec_id);
+ }
if (!codec) {
fprintf(stderr, "Couldn't find valid video codec\n");
context->video_codec = NULL;
@@ -568,7 +777,9 @@ static AVStream *alloc_video_stream(FFMpegContext *context,
default:
printf("Unknown preset number %i, ignoring.\n", context->ffmpeg_preset);
}
- if (preset_name != NULL) {
+ /* "codec_id != AV_CODEC_ID_AV1" is required due to "preset" already being set by an AV1 codec.
+ */
+ if (preset_name != NULL && codec_id != AV_CODEC_ID_AV1) {
av_dict_set(&opts, "preset", preset_name, 0);
}
if (deadline_name != NULL) {
@@ -951,6 +1162,9 @@ static int start_ffmpeg_impl(FFMpegContext *context,
case FFMPEG_FLV:
video_codec = AV_CODEC_ID_FLV1;
break;
+ case FFMPEG_AV1:
+ video_codec = AV_CODEC_ID_AV1;
+ break;
default:
/* These containers are not restricted to any specific codec types.
* Currently we expect these to be .avi, .mov, .mkv, and .mp4.
@@ -1482,6 +1696,18 @@ void BKE_ffmpeg_preset_set(RenderData *rd, int preset)
rd->ffcodecdata.mux_packet_size = 2048;
rd->ffcodecdata.mux_rate = 10080000;
break;
+ case FFMPEG_PRESET_AV1:
+ rd->ffcodecdata.type = FFMPEG_AV1;
+ rd->ffcodecdata.codec = AV_CODEC_ID_AV1;
+ rd->ffcodecdata.video_bitrate = 6000;
+ rd->ffcodecdata.gop_size = is_ntsc ? 18 : 15;
+ rd->ffcodecdata.rc_max_rate = 9000;
+ rd->ffcodecdata.rc_min_rate = 0;
+ rd->ffcodecdata.rc_buffer_size = 224 * 8;
+ rd->ffcodecdata.mux_packet_size = 2048;
+ rd->ffcodecdata.mux_rate = 10080000;
+
+ break;
}
}
@@ -1521,6 +1747,12 @@ void BKE_ffmpeg_image_type_verify(RenderData *rd, const ImageFormatData *imf)
audio = 1;
}
}
+ else if (imf->imtype == R_IMF_IMTYPE_AV1) {
+ if (rd->ffcodecdata.codec != AV_CODEC_ID_AV1) {
+ BKE_ffmpeg_preset_set(rd, FFMPEG_PRESET_AV1);
+ audio = 1;
+ }
+ }
if (audio && rd->ffcodecdata.audio_codec < 0) {
rd->ffcodecdata.audio_codec = AV_CODEC_ID_NONE;
diff --git a/source/blender/blenlib/BLI_array_utils.hh b/source/blender/blenlib/BLI_array_utils.hh
index 95b3bde10f4..264ac00e034 100644
--- a/source/blender/blenlib/BLI_array_utils.hh
+++ b/source/blender/blenlib/BLI_array_utils.hh
@@ -42,6 +42,11 @@ void gather(const GVArray &src, IndexMask indices, GMutableSpan dst, int64_t gra
/**
* Fill the destination span by gathering indexed values from the `src` array.
*/
+void gather(GSpan src, IndexMask indices, GMutableSpan dst, int64_t grain_size = 4096);
+
+/**
+ * Fill the destination span by gathering indexed values from the `src` array.
+ */
template<typename T>
inline void gather(const VArray<T> &src,
const IndexMask indices,
diff --git a/source/blender/blenlib/BLI_path_util.h b/source/blender/blenlib/BLI_path_util.h
index 1e45e76afe1..d4d2ddead71 100644
--- a/source/blender/blenlib/BLI_path_util.h
+++ b/source/blender/blenlib/BLI_path_util.h
@@ -7,7 +7,9 @@
*/
#include "BLI_compiler_attrs.h"
+#include "BLI_compiler_compat.h"
#include "BLI_utildefines.h"
+#include "BLI_utildefines_variadic.h"
#ifdef __cplusplus
extern "C" {
@@ -69,17 +71,15 @@ const char *BLI_path_extension(const char *filepath) ATTR_NONNULL();
*/
void BLI_path_append(char *__restrict dst, size_t maxlen, const char *__restrict file)
ATTR_NONNULL();
+
/**
- * Simple appending of filename to dir, does not check for valid path!
- * Puts result into `dst`, which may be same area as `dir`.
- *
- * \note Consider using #BLI_path_join for more general path joining
- * that de-duplicates separators and can handle an arbitrary number of paths.
+ * See #BLI_path_join doc-string.
*/
-void BLI_join_dirfile(char *__restrict dst,
- size_t maxlen,
- const char *__restrict dir,
- const char *__restrict file) ATTR_NONNULL();
+size_t BLI_path_join_array(char *__restrict dst,
+ const size_t dst_len,
+ const char *path_array[],
+ const int path_array_num);
+
/**
* Join multiple strings into a path, ensuring only a single path separator between each,
* and trailing slash is kept.
@@ -95,8 +95,92 @@ void BLI_join_dirfile(char *__restrict dst,
* \note If you want a trailing slash, add `SEP_STR` as the last path argument,
* duplicate slashes will be cleaned up.
*/
-size_t BLI_path_join(char *__restrict dst, size_t dst_len, const char *path, ...)
- ATTR_NONNULL(1, 3) ATTR_SENTINEL(0);
+#define BLI_path_join(...) VA_NARGS_CALL_OVERLOAD(_BLI_path_join_, __VA_ARGS__)
+
+#define _BLI_PATH_JOIN_ARGS_1 char *__restrict dst, size_t dst_len, const char *a
+#define _BLI_PATH_JOIN_ARGS_2 _BLI_PATH_JOIN_ARGS_1, const char *b
+#define _BLI_PATH_JOIN_ARGS_3 _BLI_PATH_JOIN_ARGS_2, const char *c
+#define _BLI_PATH_JOIN_ARGS_4 _BLI_PATH_JOIN_ARGS_3, const char *d
+#define _BLI_PATH_JOIN_ARGS_5 _BLI_PATH_JOIN_ARGS_4, const char *e
+#define _BLI_PATH_JOIN_ARGS_6 _BLI_PATH_JOIN_ARGS_5, const char *f
+#define _BLI_PATH_JOIN_ARGS_7 _BLI_PATH_JOIN_ARGS_6, const char *g
+#define _BLI_PATH_JOIN_ARGS_8 _BLI_PATH_JOIN_ARGS_7, const char *h
+#define _BLI_PATH_JOIN_ARGS_9 _BLI_PATH_JOIN_ARGS_8, const char *i
+#define _BLI_PATH_JOIN_ARGS_10 _BLI_PATH_JOIN_ARGS_9, const char *j
+
+BLI_INLINE size_t _BLI_path_join_3(_BLI_PATH_JOIN_ARGS_1) ATTR_NONNULL();
+BLI_INLINE size_t _BLI_path_join_4(_BLI_PATH_JOIN_ARGS_2) ATTR_NONNULL();
+BLI_INLINE size_t _BLI_path_join_5(_BLI_PATH_JOIN_ARGS_3) ATTR_NONNULL();
+BLI_INLINE size_t _BLI_path_join_6(_BLI_PATH_JOIN_ARGS_4) ATTR_NONNULL();
+BLI_INLINE size_t _BLI_path_join_7(_BLI_PATH_JOIN_ARGS_5) ATTR_NONNULL();
+BLI_INLINE size_t _BLI_path_join_8(_BLI_PATH_JOIN_ARGS_6) ATTR_NONNULL();
+BLI_INLINE size_t _BLI_path_join_9(_BLI_PATH_JOIN_ARGS_7) ATTR_NONNULL();
+BLI_INLINE size_t _BLI_path_join_10(_BLI_PATH_JOIN_ARGS_8) ATTR_NONNULL();
+BLI_INLINE size_t _BLI_path_join_11(_BLI_PATH_JOIN_ARGS_9) ATTR_NONNULL();
+BLI_INLINE size_t _BLI_path_join_12(_BLI_PATH_JOIN_ARGS_10) ATTR_NONNULL();
+
+BLI_INLINE size_t _BLI_path_join_3(_BLI_PATH_JOIN_ARGS_1)
+{
+ const char *path_array[] = {a};
+ return BLI_path_join_array(dst, dst_len, path_array, ARRAY_SIZE(path_array));
+}
+BLI_INLINE size_t _BLI_path_join_4(_BLI_PATH_JOIN_ARGS_2)
+{
+ const char *path_array[] = {a, b};
+ return BLI_path_join_array(dst, dst_len, path_array, ARRAY_SIZE(path_array));
+}
+BLI_INLINE size_t _BLI_path_join_5(_BLI_PATH_JOIN_ARGS_3)
+{
+ const char *path_array[] = {a, b, c};
+ return BLI_path_join_array(dst, dst_len, path_array, ARRAY_SIZE(path_array));
+}
+BLI_INLINE size_t _BLI_path_join_6(_BLI_PATH_JOIN_ARGS_4)
+{
+ const char *path_array[] = {a, b, c, d};
+ return BLI_path_join_array(dst, dst_len, path_array, ARRAY_SIZE(path_array));
+}
+BLI_INLINE size_t _BLI_path_join_7(_BLI_PATH_JOIN_ARGS_5)
+{
+ const char *path_array[] = {a, b, c, d, e};
+ return BLI_path_join_array(dst, dst_len, path_array, ARRAY_SIZE(path_array));
+}
+BLI_INLINE size_t _BLI_path_join_8(_BLI_PATH_JOIN_ARGS_6)
+{
+ const char *path_array[] = {a, b, c, d, e, f};
+ return BLI_path_join_array(dst, dst_len, path_array, ARRAY_SIZE(path_array));
+}
+BLI_INLINE size_t _BLI_path_join_9(_BLI_PATH_JOIN_ARGS_7)
+{
+ const char *path_array[] = {a, b, c, d, e, f, g};
+ return BLI_path_join_array(dst, dst_len, path_array, ARRAY_SIZE(path_array));
+}
+BLI_INLINE size_t _BLI_path_join_10(_BLI_PATH_JOIN_ARGS_8)
+{
+ const char *path_array[] = {a, b, c, d, e, f, g, h};
+ return BLI_path_join_array(dst, dst_len, path_array, ARRAY_SIZE(path_array));
+}
+BLI_INLINE size_t _BLI_path_join_11(_BLI_PATH_JOIN_ARGS_9)
+{
+ const char *path_array[] = {a, b, c, d, e, f, g, h, i};
+ return BLI_path_join_array(dst, dst_len, path_array, ARRAY_SIZE(path_array));
+}
+BLI_INLINE size_t _BLI_path_join_12(_BLI_PATH_JOIN_ARGS_10)
+{
+ const char *path_array[] = {a, b, c, d, e, f, g, h, i, j};
+ return BLI_path_join_array(dst, dst_len, path_array, ARRAY_SIZE(path_array));
+}
+
+#undef _BLI_PATH_JOIN_ARGS_1
+#undef _BLI_PATH_JOIN_ARGS_2
+#undef _BLI_PATH_JOIN_ARGS_3
+#undef _BLI_PATH_JOIN_ARGS_4
+#undef _BLI_PATH_JOIN_ARGS_5
+#undef _BLI_PATH_JOIN_ARGS_6
+#undef _BLI_PATH_JOIN_ARGS_7
+#undef _BLI_PATH_JOIN_ARGS_8
+#undef _BLI_PATH_JOIN_ARGS_9
+#undef _BLI_PATH_JOIN_ARGS_10
+
/**
* Like Python's `os.path.basename()`
*
diff --git a/source/blender/blenlib/BLI_string.h b/source/blender/blenlib/BLI_string.h
index 15926e8f2d2..17abcf52ecc 100644
--- a/source/blender/blenlib/BLI_string.h
+++ b/source/blender/blenlib/BLI_string.h
@@ -309,6 +309,28 @@ void BLI_str_format_byte_unit(char dst[15], long long int bytes, bool base_10) A
*/
void BLI_str_format_decimal_unit(char dst[7], int number_to_format) ATTR_NONNULL();
/**
+ * Format a count to up to 3 places (plus minus sign, plus '\0' terminator) string using long
+ * number names abbreviations. Used to produce a compact representation of large numbers as
+ * integers.
+ *
+ * It shows a lower bound instead of rounding the number.
+ *
+ * 1 -> 1
+ * 15 -> 15
+ * 155 -> 155
+ * 1555 -> 1K
+ * 15555 -> 15K
+ * 155555 -> .1M
+ * 1555555 -> 1M
+ * 15555555 -> 15M
+ * 155555555 -> .1B
+ * 1000000000 -> 1B
+ * ...
+ *
+ * Length of 5 is the maximum of the resulting string, for example, `-15K\0`.
+ */
+void BLI_str_format_integer_unit(char dst[5], int number_to_format) ATTR_NONNULL();
+/**
* Compare two strings without regard to case.
*
* \retval True if the strings are equal, false otherwise.
diff --git a/source/blender/blenlib/intern/BLI_filelist.c b/source/blender/blenlib/intern/BLI_filelist.c
index 1ce6beab933..4bcb023691a 100644
--- a/source/blender/blenlib/intern/BLI_filelist.c
+++ b/source/blender/blenlib/intern/BLI_filelist.c
@@ -174,7 +174,7 @@ static void bli_builddir(struct BuildDirCtx *dir_ctx, const char *dirname)
struct direntry *file = &dir_ctx->files[dir_ctx->files_num];
while (dlink) {
char fullname[PATH_MAX];
- BLI_join_dirfile(fullname, sizeof(fullname), dirname, dlink->name);
+ BLI_path_join(fullname, sizeof(fullname), dirname, dlink->name);
memset(file, 0, sizeof(struct direntry));
file->relname = dlink->name;
file->path = BLI_strdup(fullname);
diff --git a/source/blender/blenlib/intern/array_utils.cc b/source/blender/blenlib/intern/array_utils.cc
index a837d6aceec..2a231228dcb 100644
--- a/source/blender/blenlib/intern/array_utils.cc
+++ b/source/blender/blenlib/intern/array_utils.cc
@@ -28,4 +28,9 @@ void gather(const GVArray &src,
});
}
+void gather(const GSpan src, const IndexMask indices, GMutableSpan dst, const int64_t grain_size)
+{
+ gather(GVArray::ForSpan(src), indices, dst, grain_size);
+}
+
} // namespace blender::array_utils
diff --git a/source/blender/blenlib/intern/fileops.c b/source/blender/blenlib/intern/fileops.c
index 3abd482d6b3..a157302e51e 100644
--- a/source/blender/blenlib/intern/fileops.c
+++ b/source/blender/blenlib/intern/fileops.c
@@ -627,7 +627,7 @@ static void join_dirfile_alloc(char **dst, size_t *alloc_len, const char *dir, c
*alloc_len = len;
- BLI_join_dirfile(*dst, len + 1, dir, file);
+ BLI_path_join(*dst, len + 1, dir, file);
}
static char *strip_last_slash(const char *dir)
@@ -1184,7 +1184,7 @@ static const char *check_destination(const char *file, const char *to)
len = strlen(to) + strlen(filename) + 1;
path = MEM_callocN(len + 1, "check_destination path");
- BLI_join_dirfile(path, len + 1, to, filename);
+ BLI_path_join(path, len + 1, to, filename);
MEM_freeN(str);
diff --git a/source/blender/blenlib/intern/path_util.c b/source/blender/blenlib/intern/path_util.c
index 6ff4d57aecb..afe8c3cc033 100644
--- a/source/blender/blenlib/intern/path_util.c
+++ b/source/blender/blenlib/intern/path_util.c
@@ -625,7 +625,7 @@ bool BLI_path_parent_dir(char *path)
const char parent_dir[] = {'.', '.', SEP, '\0'}; /* "../" or "..\\" */
char tmp[FILE_MAX + 4];
- BLI_join_dirfile(tmp, sizeof(tmp), path, parent_dir);
+ BLI_path_join(tmp, sizeof(tmp), path, parent_dir);
BLI_path_normalize(NULL, tmp); /* does all the work of normalizing the path for us */
if (!BLI_path_extension_check(tmp, parent_dir)) {
@@ -1025,7 +1025,7 @@ bool BLI_path_abs_from_cwd(char *path, const size_t maxlen)
if (BLI_current_working_dir(cwd, sizeof(cwd))) {
char origpath[FILE_MAX];
BLI_strncpy(origpath, path, FILE_MAX);
- BLI_join_dirfile(path, maxlen, cwd, origpath);
+ BLI_path_join(path, maxlen, cwd, origpath);
}
else {
printf("Could not get the current working directory - $PWD for an unknown reason.\n");
@@ -1448,56 +1448,20 @@ void BLI_path_append(char *__restrict dst, const size_t maxlen, const char *__re
BLI_strncpy(dst + dirlen, file, maxlen - dirlen);
}
-void BLI_join_dirfile(char *__restrict dst,
- const size_t maxlen,
- const char *__restrict dir,
- const char *__restrict file)
-{
-#ifdef DEBUG_STRSIZE
- memset(dst, 0xff, sizeof(*dst) * maxlen);
-#endif
- size_t dirlen = BLI_strnlen(dir, maxlen);
-
- /* Arguments can't match. */
- BLI_assert(!ELEM(dst, dir, file));
-
- /* Files starting with a separator cause a double-slash which could later be interpreted
- * as a relative path where: `dir == "/"` and `file == "/file"` would result in "//file". */
- BLI_assert(file[0] != SEP);
-
- if (dirlen == maxlen) {
- memcpy(dst, dir, dirlen);
- dst[dirlen - 1] = '\0';
- return; /* dir fills the path */
- }
-
- memcpy(dst, dir, dirlen + 1);
-
- if (dirlen + 1 >= maxlen) {
- return; /* fills the path */
- }
-
- /* inline BLI_path_slash_ensure */
- if ((dirlen > 0) && !ELEM(dst[dirlen - 1], SEP, ALTSEP)) {
- dst[dirlen++] = SEP;
- dst[dirlen] = '\0';
- }
-
- if (dirlen >= maxlen) {
- return; /* fills the path */
- }
-
- BLI_strncpy(dst + dirlen, file, maxlen - dirlen);
-}
-
-size_t BLI_path_join(char *__restrict dst, const size_t dst_len, const char *path, ...)
+size_t BLI_path_join_array(char *__restrict dst,
+ const size_t dst_len,
+ const char *path_array[],
+ const int path_array_num)
{
+ BLI_assert(path_array_num > 0);
#ifdef DEBUG_STRSIZE
memset(dst, 0xff, sizeof(*dst) * dst_len);
#endif
if (UNLIKELY(dst_len == 0)) {
return 0;
}
+ const char *path = path_array[0];
+
const size_t dst_last = dst_len - 1;
size_t ofs = BLI_strncpy_rlen(dst, path, dst_len);
@@ -1519,9 +1483,8 @@ size_t BLI_path_join(char *__restrict dst, const size_t dst_len, const char *pat
has_trailing_slash = (path[len] != '\0');
}
- va_list args;
- va_start(args, path);
- while ((path = (const char *)va_arg(args, const char *))) {
+ for (int path_index = 1; path_index < path_array_num; path_index++) {
+ path = path_array[path_index];
has_trailing_slash = false;
const char *path_init = path;
while (ELEM(path[0], SEP, ALTSEP)) {
@@ -1556,7 +1519,6 @@ size_t BLI_path_join(char *__restrict dst, const size_t dst_len, const char *pat
has_trailing_slash = (path_init != path);
}
}
- va_end(args);
if (has_trailing_slash) {
if ((ofs != dst_last) && (ofs != 0) && (ELEM(dst[ofs - 1], SEP, ALTSEP) == 0)) {
diff --git a/source/blender/blenlib/intern/string.c b/source/blender/blenlib/intern/string.c
index 89d31c5e93f..755d2dbd55d 100644
--- a/source/blender/blenlib/intern/string.c
+++ b/source/blender/blenlib/intern/string.c
@@ -1176,4 +1176,34 @@ void BLI_str_format_decimal_unit(char dst[7], int number_to_format)
BLI_snprintf(dst, dst_len, "%.*f%s", decimals, number_to_format_converted, units[order]);
}
+void BLI_str_format_integer_unit(char dst[5], const int number_to_format)
+{
+ float number_to_format_converted = number_to_format;
+ int order = 0;
+ const float base = 1000;
+ const char *units[] = {"", "K", "M", "B"};
+ const int units_num = ARRAY_SIZE(units);
+
+ while ((fabsf(number_to_format_converted) >= base) && ((order + 1) < units_num)) {
+ number_to_format_converted /= base;
+ order++;
+ }
+
+ const bool add_dot = (abs(number_to_format) > 99999) && fabsf(number_to_format_converted) > 99;
+
+ if (add_dot) {
+ number_to_format_converted /= 100;
+ order++;
+ }
+
+ const size_t dst_len = 5;
+ BLI_snprintf(dst,
+ dst_len,
+ "%s%s%d%s",
+ number_to_format < 0 ? "-" : "",
+ add_dot ? "." : "",
+ (int)floorf(fabsf(number_to_format_converted)),
+ units[order]);
+}
+
/** \} */
diff --git a/source/blender/blenlib/tests/BLI_path_util_test.cc b/source/blender/blenlib/tests/BLI_path_util_test.cc
index 2d415534693..89e537235db 100644
--- a/source/blender/blenlib/tests/BLI_path_util_test.cc
+++ b/source/blender/blenlib/tests/BLI_path_util_test.cc
@@ -207,7 +207,7 @@ TEST(path_util, NameAtIndex_NoneComplexNeg)
char result[(out_size) + 1024]; \
/* check we don't write past the last byte */ \
result[out_size] = '\0'; \
- BLI_path_join(result, out_size, __VA_ARGS__, NULL); \
+ BLI_path_join(result, out_size, __VA_ARGS__); \
/* simplify expected string */ \
BLI_str_replace_char(result, '\\', '/'); \
EXPECT_STREQ(result, expect); \
diff --git a/source/blender/blenlib/tests/BLI_string_test.cc b/source/blender/blenlib/tests/BLI_string_test.cc
index 9bdf6075c70..d726fbccf20 100644
--- a/source/blender/blenlib/tests/BLI_string_test.cc
+++ b/source/blender/blenlib/tests/BLI_string_test.cc
@@ -515,6 +515,103 @@ TEST(string, StrFormatDecimalUnits)
EXPECT_STREQ("-2.1B", size_str);
}
+/* BLI_str_format_integer_unit */
+TEST(string, StrFormatIntegerUnits)
+{
+ char size_str[7];
+ int size;
+
+ BLI_str_format_integer_unit(size_str, size = 0);
+ EXPECT_STREQ("0", size_str);
+ BLI_str_format_integer_unit(size_str, size = 1);
+ EXPECT_STREQ("1", size_str);
+ BLI_str_format_integer_unit(size_str, size = 10);
+ EXPECT_STREQ("10", size_str);
+ BLI_str_format_integer_unit(size_str, size = 15);
+ EXPECT_STREQ("15", size_str);
+ BLI_str_format_integer_unit(size_str, size = 100);
+ EXPECT_STREQ("100", size_str);
+ BLI_str_format_integer_unit(size_str, size = 155);
+ EXPECT_STREQ("155", size_str);
+ BLI_str_format_integer_unit(size_str, size = 1000);
+ EXPECT_STREQ("1K", size_str);
+ BLI_str_format_integer_unit(size_str, size = 1555);
+ EXPECT_STREQ("1K", size_str);
+ BLI_str_format_integer_unit(size_str, size = 10000);
+ EXPECT_STREQ("10K", size_str);
+ BLI_str_format_integer_unit(size_str, size = 15555);
+ EXPECT_STREQ("15K", size_str);
+ BLI_str_format_integer_unit(size_str, size = 100000);
+ EXPECT_STREQ(".1M", size_str);
+ BLI_str_format_integer_unit(size_str, size = 155555);
+ EXPECT_STREQ(".1M", size_str);
+ BLI_str_format_integer_unit(size_str, size = 1000000);
+ EXPECT_STREQ("1M", size_str);
+ BLI_str_format_integer_unit(size_str, size = 1555555);
+ EXPECT_STREQ("1M", size_str);
+ BLI_str_format_integer_unit(size_str, size = 2555555);
+ EXPECT_STREQ("2M", size_str);
+ BLI_str_format_integer_unit(size_str, size = 10000000);
+ EXPECT_STREQ("10M", size_str);
+ BLI_str_format_integer_unit(size_str, size = 15555555);
+ EXPECT_STREQ("15M", size_str);
+ BLI_str_format_integer_unit(size_str, size = 100000000);
+ EXPECT_STREQ(".1B", size_str);
+ BLI_str_format_integer_unit(size_str, size = 155555555);
+ EXPECT_STREQ(".1B", size_str);
+ BLI_str_format_integer_unit(size_str, size = 255555555);
+ EXPECT_STREQ(".2B", size_str);
+ BLI_str_format_integer_unit(size_str, size = 1000000000);
+ EXPECT_STREQ("1B", size_str);
+
+ /* Largest possible value. */
+ BLI_str_format_integer_unit(size_str, size = INT32_MAX);
+ EXPECT_STREQ("2B", size_str);
+
+ BLI_str_format_integer_unit(size_str, size = -0);
+ EXPECT_STREQ("0", size_str);
+ BLI_str_format_integer_unit(size_str, size = -1);
+ EXPECT_STREQ("-1", size_str);
+ BLI_str_format_integer_unit(size_str, size = -10);
+ EXPECT_STREQ("-10", size_str);
+ BLI_str_format_integer_unit(size_str, size = -15);
+ EXPECT_STREQ("-15", size_str);
+ BLI_str_format_integer_unit(size_str, size = -100);
+ EXPECT_STREQ("-100", size_str);
+ BLI_str_format_integer_unit(size_str, size = -155);
+ EXPECT_STREQ("-155", size_str);
+ BLI_str_format_integer_unit(size_str, size = -1000);
+ EXPECT_STREQ("-1K", size_str);
+ BLI_str_format_integer_unit(size_str, size = -1555);
+ EXPECT_STREQ("-1K", size_str);
+ BLI_str_format_integer_unit(size_str, size = -10000);
+ EXPECT_STREQ("-10K", size_str);
+ BLI_str_format_integer_unit(size_str, size = -15555);
+ EXPECT_STREQ("-15K", size_str);
+ BLI_str_format_integer_unit(size_str, size = -100000);
+ EXPECT_STREQ("-.1M", size_str);
+ BLI_str_format_integer_unit(size_str, size = -155555);
+ EXPECT_STREQ("-.1M", size_str);
+ BLI_str_format_integer_unit(size_str, size = -1000000);
+ EXPECT_STREQ("-1M", size_str);
+ BLI_str_format_integer_unit(size_str, size = -1555555);
+ EXPECT_STREQ("-1M", size_str);
+ BLI_str_format_integer_unit(size_str, size = -10000000);
+ EXPECT_STREQ("-10M", size_str);
+ BLI_str_format_integer_unit(size_str, size = -15555555);
+ EXPECT_STREQ("-15M", size_str);
+ BLI_str_format_integer_unit(size_str, size = -100000000);
+ EXPECT_STREQ("-.1B", size_str);
+ BLI_str_format_integer_unit(size_str, size = -155555555);
+ EXPECT_STREQ("-.1B", size_str);
+ BLI_str_format_integer_unit(size_str, size = -1000000000);
+ EXPECT_STREQ("-1B", size_str);
+
+ /* Smallest possible value. */
+ BLI_str_format_integer_unit(size_str, size = -INT32_MAX);
+ EXPECT_STREQ("-2B", size_str);
+}
+
struct WordInfo {
WordInfo() = default;
WordInfo(int start, int end) : start(start), end(end)
diff --git a/source/blender/blenloader/BLO_readfile.h b/source/blender/blenloader/BLO_readfile.h
index 93040fa01ee..75a1956ce12 100644
--- a/source/blender/blenloader/BLO_readfile.h
+++ b/source/blender/blenloader/BLO_readfile.h
@@ -182,6 +182,11 @@ void BLO_blendfiledata_free(BlendFileData *bfd);
typedef struct BLODataBlockInfo {
char name[64]; /* MAX_NAME */
struct AssetMetaData *asset_data;
+ /* Optimization: Tag data-blocks for which we know there is no preview.
+ * Knowing this can be used to skip the (potentially expensive) preview loading process. If this
+ * is set to true it means we looked for a preview and couldn't find one. False may mean that
+ * either no preview was found, or that it wasn't looked for in the first place. */
+ bool no_preview_found;
} BLODataBlockInfo;
/**
diff --git a/source/blender/blenloader/CMakeLists.txt b/source/blender/blenloader/CMakeLists.txt
index f0209d1337c..86793d38b0b 100644
--- a/source/blender/blenloader/CMakeLists.txt
+++ b/source/blender/blenloader/CMakeLists.txt
@@ -47,7 +47,7 @@ set(SRC
intern/versioning_400.cc
intern/versioning_common.cc
intern/versioning_cycles.c
- intern/versioning_defaults.c
+ intern/versioning_defaults.cc
intern/versioning_dna.c
intern/versioning_legacy.c
intern/versioning_userdef.c
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/readblenentry.cc b/source/blender/blenloader/intern/readblenentry.cc
index 55ac2d31277..ead796c0e28 100644
--- a/source/blender/blenloader/intern/readblenentry.cc
+++ b/source/blender/blenloader/intern/readblenentry.cc
@@ -138,11 +138,15 @@ LinkNode *BLO_blendhandle_get_datablock_info(BlendHandle *bh,
BHead *bhead;
int tot = 0;
+ const int sdna_nr_preview_image = DNA_struct_find_nr(fd->filesdna, "PreviewImage");
+
for (bhead = blo_bhead_first(fd); bhead; bhead = blo_bhead_next(fd, bhead)) {
if (bhead->code == ENDB) {
break;
}
if (bhead->code == ofblocktype) {
+ BHead *id_bhead = bhead;
+
const char *name = blo_bhead_id_name(fd, bhead) + 2;
AssetMetaData *asset_meta_data = blo_bhead_id_asset_data_address(fd, bhead);
@@ -165,6 +169,17 @@ LinkNode *BLO_blendhandle_get_datablock_info(BlendHandle *bh,
STRNCPY(info->name, name);
info->asset_data = asset_meta_data;
+ bool has_preview = false;
+ /* See if we can find a preview in the data of this ID. */
+ for (BHead *data_bhead = blo_bhead_next(fd, id_bhead); data_bhead->code == DATA;
+ data_bhead = blo_bhead_next(fd, data_bhead)) {
+ if (data_bhead->SDNAnr == sdna_nr_preview_image) {
+ has_preview = true;
+ break;
+ }
+ }
+ info->no_preview_found = !has_preview;
+
BLI_linklist_prepend(&infos, info);
tot++;
}
diff --git a/source/blender/blenloader/intern/versioning_250.c b/source/blender/blenloader/intern/versioning_250.c
index 9e5ef41892a..0b543ad735b 100644
--- a/source/blender/blenloader/intern/versioning_250.c
+++ b/source/blender/blenloader/intern/versioning_250.c
@@ -630,7 +630,7 @@ static bool seq_sound_proxy_update_cb(Sequence *seq, void *user_data)
Main *bmain = (Main *)user_data;
if (seq->type == SEQ_TYPE_SOUND_HD) {
char str[FILE_MAX];
- BLI_join_dirfile(str, sizeof(str), seq->strip->dir, seq->strip->stripdata->name);
+ BLI_path_join(str, sizeof(str), seq->strip->dir, seq->strip->stripdata->name);
BLI_path_abs(str, BKE_main_blendfile_path(bmain));
seq->sound = BKE_sound_new_file(bmain, str);
}
@@ -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..a2bd7fd2fd1 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;
+ }
+ }
}
}
}
@@ -3616,6 +3623,36 @@ void blo_do_versions_300(FileData *fd, Library * /*lib*/, Main *bmain)
}
}
+ if (!MAIN_VERSION_ATLEAST(bmain, 304, 4)) {
+ /* Update brush sculpt settings. */
+ LISTBASE_FOREACH (Brush *, brush, &bmain->brushes) {
+ brush->automasking_cavity_factor = 1.0f;
+ }
+ }
+
+ if (!MAIN_VERSION_ATLEAST(bmain, 304, 5)) {
+ /* Fix for T101622 - update flags of sequence editor regions that were not initialized
+ * properly. */
+ LISTBASE_FOREACH (bScreen *, screen, &bmain->screens) {
+ LISTBASE_FOREACH (ScrArea *, area, &screen->areabase) {
+ LISTBASE_FOREACH (SpaceLink *, sl, &area->spacedata) {
+ ListBase *regionbase = (sl == area->spacedata.first) ? &area->regionbase :
+ &sl->regionbase;
+ if (sl->spacetype == SPACE_SEQ) {
+ LISTBASE_FOREACH (ARegion *, region, regionbase) {
+ if (region->regiontype == RGN_TYPE_TOOLS) {
+ region->v2d.flag &= ~V2D_VIEWSYNC_AREA_VERTICAL;
+ }
+ if (region->regiontype == RGN_TYPE_CHANNELS) {
+ region->v2d.flag |= V2D_VIEWSYNC_AREA_VERTICAL;
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+
/**
* Versioning code until next subversion bump goes here.
*
diff --git a/source/blender/blenloader/intern/versioning_defaults.c b/source/blender/blenloader/intern/versioning_defaults.cc
index 06903865381..da23e9cb49f 100644
--- a/source/blender/blenloader/intern/versioning_defaults.c
+++ b/source/blender/blenloader/intern/versioning_defaults.cc
@@ -15,6 +15,7 @@
#include "BLI_listbase.h"
#include "BLI_math.h"
+#include "BLI_math_vec_types.hh"
#include "BLI_string.h"
#include "BLI_system.h"
#include "BLI_utildefines.h"
@@ -36,6 +37,7 @@
#include "DNA_workspace_types.h"
#include "BKE_appdir.h"
+#include "BKE_attribute.hh"
#include "BKE_brush.h"
#include "BKE_colortools.h"
#include "BKE_curveprofile.h"
@@ -119,7 +121,7 @@ static void blo_update_defaults_screen(bScreen *screen,
if (area->spacetype == SPACE_IMAGE) {
if (STREQ(workspace_name, "UV Editing")) {
- SpaceImage *sima = area->spacedata.first;
+ SpaceImage *sima = static_cast<SpaceImage *>(area->spacedata.first);
if (sima->mode == SI_MODE_VIEW) {
sima->mode = SI_MODE_UV;
}
@@ -127,7 +129,7 @@ static void blo_update_defaults_screen(bScreen *screen,
}
else if (area->spacetype == SPACE_ACTION) {
/* Show markers region, hide channels and collapse summary in timelines. */
- SpaceAction *saction = area->spacedata.first;
+ SpaceAction *saction = static_cast<SpaceAction *>(area->spacedata.first);
saction->flag |= SACTION_SHOW_MARKERS;
if (saction->mode == SACTCONT_TIMELINE) {
saction->ads.flag |= ADS_FLAG_SUMMARY_COLLAPSED;
@@ -148,15 +150,15 @@ static void blo_update_defaults_screen(bScreen *screen,
}
}
else if (area->spacetype == SPACE_GRAPH) {
- SpaceGraph *sipo = area->spacedata.first;
+ SpaceGraph *sipo = static_cast<SpaceGraph *>(area->spacedata.first);
sipo->flag |= SIPO_SHOW_MARKERS;
}
else if (area->spacetype == SPACE_NLA) {
- SpaceNla *snla = area->spacedata.first;
+ SpaceNla *snla = static_cast<SpaceNla *>(area->spacedata.first);
snla->flag |= SNLA_SHOW_MARKERS;
}
else if (area->spacetype == SPACE_SEQ) {
- SpaceSeq *seq = area->spacedata.first;
+ SpaceSeq *seq = static_cast<SpaceSeq *>(area->spacedata.first);
seq->flag |= SEQ_SHOW_MARKERS | SEQ_ZOOM_TO_FIT | SEQ_USE_PROXIES | SEQ_SHOW_OVERLAY;
seq->render_size = SEQ_RENDER_SIZE_PROXY_100;
seq->timeline_overlay.flag |= SEQ_TIMELINE_SHOW_STRIP_SOURCE | SEQ_TIMELINE_SHOW_STRIP_NAME |
@@ -166,12 +168,12 @@ static void blo_update_defaults_screen(bScreen *screen,
}
else if (area->spacetype == SPACE_TEXT) {
/* Show syntax and line numbers in Script workspace text editor. */
- SpaceText *stext = area->spacedata.first;
+ SpaceText *stext = static_cast<SpaceText *>(area->spacedata.first);
stext->showsyntax = true;
stext->showlinenrs = true;
}
else if (area->spacetype == SPACE_VIEW3D) {
- View3D *v3d = area->spacedata.first;
+ View3D *v3d = static_cast<View3D *>(area->spacedata.first);
/* Screen space cavity by default for faster performance. */
v3d->shading.cavity_type = V3D_SHADING_CAVITY_CURVATURE;
v3d->shading.flag |= V3D_SHADING_SPECULAR_HIGHLIGHT;
@@ -195,7 +197,7 @@ static void blo_update_defaults_screen(bScreen *screen,
v3d->overlay.normals_constant_screen_size = 7.0f;
}
else if (area->spacetype == SPACE_CLIP) {
- SpaceClip *sclip = area->spacedata.first;
+ SpaceClip *sclip = static_cast<SpaceClip *>(area->spacedata.first);
sclip->around = V3D_AROUND_CENTER_MEDIAN;
sclip->mask_info.blend_factor = 0.7f;
sclip->mask_info.draw_flag = MASK_DRAWFLAG_SPLINE;
@@ -206,7 +208,9 @@ static void blo_update_defaults_screen(bScreen *screen,
const bool hide_image_tool_header = STREQ(workspace_name, "Rendering");
LISTBASE_FOREACH (ScrArea *, area, &screen->areabase) {
LISTBASE_FOREACH (SpaceLink *, sl, &area->spacedata) {
- ListBase *regionbase = (sl == area->spacedata.first) ? &area->regionbase : &sl->regionbase;
+ ListBase *regionbase = (sl == static_cast<SpaceLink *>(area->spacedata.first)) ?
+ &area->regionbase :
+ &sl->regionbase;
LISTBASE_FOREACH (ARegion *, region, regionbase) {
if (region->regiontype == RGN_TYPE_TOOL_HEADER) {
@@ -226,12 +230,12 @@ static void blo_update_defaults_screen(bScreen *screen,
if (app_template && STREQ(app_template, "2D_Animation")) {
LISTBASE_FOREACH (ScrArea *, area, &screen->areabase) {
if (area->spacetype == SPACE_ACTION) {
- SpaceAction *saction = area->spacedata.first;
+ SpaceAction *saction = static_cast<SpaceAction *>(area->spacedata.first);
/* Enable Sliders. */
saction->flag |= SACTION_SLIDERS;
}
else if (area->spacetype == SPACE_VIEW3D) {
- View3D *v3d = area->spacedata.first;
+ View3D *v3d = static_cast<View3D *>(area->spacedata.first);
/* Set Material Color by default. */
v3d->shading.color_type = V3D_SHADING_MATERIAL_COLOR;
/* Enable Annotations. */
@@ -252,7 +256,7 @@ void BLO_update_defaults_workspace(WorkSpace *workspace, const char *app_templat
if (blo_is_builtin_template(app_template)) {
/* Clear all tools to use default options instead, ignore the tool saved in the file. */
while (!BLI_listbase_is_empty(&workspace->tools)) {
- BKE_workspace_tool_remove(workspace, workspace->tools.first);
+ BKE_workspace_tool_remove(workspace, static_cast<bToolRef *>(workspace->tools.first));
}
/* For 2D animation template. */
@@ -268,7 +272,7 @@ void BLO_update_defaults_workspace(WorkSpace *workspace, const char *app_templat
LISTBASE_FOREACH (ScrArea *, area, &screen->areabase) {
LISTBASE_FOREACH (ARegion *, region, &area->regionbase) {
if (area->spacetype == SPACE_VIEW3D) {
- View3D *v3d = area->spacedata.first;
+ View3D *v3d = static_cast<View3D *>(area->spacedata.first);
v3d->shading.flag &= ~V3D_SHADING_CAVITY;
copy_v3_fl(v3d->shading.single_color, 1.0f);
STRNCPY(v3d->shading.matcap, "basic_1");
@@ -296,7 +300,8 @@ static void blo_update_defaults_scene(Main *bmain, Scene *scene)
}
/* Rename render layers. */
- BKE_view_layer_rename(bmain, scene, scene->view_layers.first, "ViewLayer");
+ BKE_view_layer_rename(
+ bmain, scene, static_cast<ViewLayer *>(scene->view_layers.first), "ViewLayer");
/* Disable Z pass by default. */
LISTBASE_FOREACH (ViewLayer *, view_layer, &scene->view_layers) {
@@ -308,7 +313,7 @@ static void blo_update_defaults_scene(Main *bmain, Scene *scene)
scene->eevee.bloom_clamp = 0.0f;
scene->eevee.motion_blur_shutter = 0.5f;
- copy_v3_v3(scene->display.light_direction, (float[3]){M_SQRT1_3, M_SQRT1_3, M_SQRT1_3});
+ copy_v3_v3(scene->display.light_direction, blender::float3(M_SQRT1_3));
copy_v2_fl2(scene->safe_areas.title, 0.1f, 0.05f);
copy_v2_fl2(scene->safe_areas.action, 0.035f, 0.035f);
@@ -344,9 +349,9 @@ static void blo_update_defaults_scene(Main *bmain, Scene *scene)
}
/* Correct default startup UV's. */
- Mesh *me = BLI_findstring(&bmain->meshes, "Cube", offsetof(ID, name) + 2);
+ Mesh *me = static_cast<Mesh *>(BLI_findstring(&bmain->meshes, "Cube", offsetof(ID, name) + 2));
if (me && (me->totloop == 24) && CustomData_has_layer(&me->ldata, CD_MLOOPUV)) {
- MLoopUV *mloopuv = CustomData_get_layer(&me->ldata, CD_MLOOPUV);
+ MLoopUV *mloopuv = static_cast<MLoopUV *>(CustomData_get_layer(&me->ldata, CD_MLOOPUV));
const float uv_values[24][2] = {
{0.625, 0.50}, {0.875, 0.50}, {0.875, 0.75}, {0.625, 0.75}, {0.375, 0.75}, {0.625, 0.75},
{0.625, 1.00}, {0.375, 1.00}, {0.375, 0.00}, {0.625, 0.00}, {0.625, 0.25}, {0.375, 0.25},
@@ -373,7 +378,7 @@ static void blo_update_defaults_scene(Main *bmain, Scene *scene)
void BLO_update_defaults_startup_blend(Main *bmain, const char *app_template)
{
/* For all app templates. */
- for (WorkSpace *workspace = bmain->workspaces.first; workspace; workspace = workspace->id.next) {
+ LISTBASE_FOREACH (WorkSpace *, workspace, &bmain->workspaces) {
BLO_update_defaults_workspace(workspace, app_template);
}
@@ -389,7 +394,8 @@ void BLO_update_defaults_startup_blend(Main *bmain, const char *app_template)
do_versions_rename_id(bmain, ID_BR, "Draw Pen", "Pen");
/* Pen Soft brush. */
- brush = (Brush *)do_versions_rename_id(bmain, ID_BR, "Draw Soft", "Pencil Soft");
+ brush = reinterpret_cast<Brush *>(
+ do_versions_rename_id(bmain, ID_BR, "Draw Soft", "Pencil Soft"));
if (brush) {
brush->gpencil_settings->icon_id = GP_BRUSH_ICON_PEN;
}
@@ -407,7 +413,8 @@ void BLO_update_defaults_startup_blend(Main *bmain, const char *app_template)
do_versions_rename_id(bmain, ID_BR, "Draw Block", "Marker Chisel");
/* Remove useless Fill Area.001 brush. */
- brush = BLI_findstring(&bmain->brushes, "Fill Area.001", offsetof(ID, name) + 2);
+ brush = static_cast<Brush *>(
+ BLI_findstring(&bmain->brushes, "Fill Area.001", offsetof(ID, name) + 2));
if (brush) {
BKE_id_delete(bmain, brush);
}
@@ -421,21 +428,24 @@ void BLO_update_defaults_startup_blend(Main *bmain, const char *app_template)
do_versions_rename_id(bmain, ID_MA, "Black Dots", "Dots Stroke");
/* Dots Stroke. */
- ma = BLI_findstring(&bmain->materials, "Dots Stroke", offsetof(ID, name) + 2);
+ ma = static_cast<Material *>(
+ BLI_findstring(&bmain->materials, "Dots Stroke", offsetof(ID, name) + 2));
if (ma == NULL) {
ma = BKE_gpencil_material_add(bmain, "Dots Stroke");
}
ma->gp_style->mode = GP_MATERIAL_MODE_DOT;
/* Squares Stroke. */
- ma = BLI_findstring(&bmain->materials, "Squares Stroke", offsetof(ID, name) + 2);
+ ma = static_cast<Material *>(
+ BLI_findstring(&bmain->materials, "Squares Stroke", offsetof(ID, name) + 2));
if (ma == NULL) {
ma = BKE_gpencil_material_add(bmain, "Squares Stroke");
}
ma->gp_style->mode = GP_MATERIAL_MODE_SQUARE;
/* Change Solid Stroke settings. */
- ma = BLI_findstring(&bmain->materials, "Solid Stroke", offsetof(ID, name) + 2);
+ ma = static_cast<Material *>(
+ BLI_findstring(&bmain->materials, "Solid Stroke", offsetof(ID, name) + 2));
if (ma != NULL) {
ma->gp_style->mix_rgba[3] = 1.0f;
ma->gp_style->texture_offset[0] = -0.5f;
@@ -443,7 +453,8 @@ void BLO_update_defaults_startup_blend(Main *bmain, const char *app_template)
}
/* Change Solid Fill settings. */
- ma = BLI_findstring(&bmain->materials, "Solid Fill", offsetof(ID, name) + 2);
+ ma = static_cast<Material *>(
+ BLI_findstring(&bmain->materials, "Solid Fill", offsetof(ID, name) + 2));
if (ma != NULL) {
ma->gp_style->flag &= ~GP_MATERIAL_STROKE_SHOW;
ma->gp_style->mix_rgba[3] = 1.0f;
@@ -451,14 +462,15 @@ void BLO_update_defaults_startup_blend(Main *bmain, const char *app_template)
ma->gp_style->mix_factor = 0.5f;
}
- Object *ob = BLI_findstring(&bmain->objects, "Stroke", offsetof(ID, name) + 2);
+ Object *ob = static_cast<Object *>(
+ BLI_findstring(&bmain->objects, "Stroke", offsetof(ID, name) + 2));
if (ob && ob->type == OB_GPENCIL) {
ob->dtx |= OB_USE_GPENCIL_LIGHTS;
}
}
/* Reset all grease pencil brushes. */
- Scene *scene = bmain->scenes.first;
+ Scene *scene = static_cast<Scene *>(bmain->scenes.first);
BKE_brush_gpencil_paint_presets(bmain, scene->toolsettings, true);
BKE_brush_gpencil_sculpt_presets(bmain, scene->toolsettings, true);
BKE_brush_gpencil_vertex_presets(bmain, scene->toolsettings, true);
@@ -511,7 +523,7 @@ void BLO_update_defaults_startup_blend(Main *bmain, const char *app_template)
}
/* Scenes */
- for (Scene *scene = bmain->scenes.first; scene; scene = scene->id.next) {
+ LISTBASE_FOREACH (Scene *, scene, &bmain->scenes) {
blo_update_defaults_scene(bmain, scene);
if (app_template && STREQ(app_template, "Video_Editing")) {
@@ -537,7 +549,7 @@ void BLO_update_defaults_startup_blend(Main *bmain, const char *app_template)
do_versions_rename_id(bmain, ID_LA, "Lamp", "Light");
if (app_template && STREQ(app_template, "2D_Animation")) {
- for (Object *object = bmain->objects.first; object; object = object->id.next) {
+ LISTBASE_FOREACH (Object *, object, &bmain->objects) {
if (object->type == OB_GPENCIL) {
/* Set grease pencil object in drawing mode */
bGPdata *gpd = (bGPdata *)object->data;
@@ -548,7 +560,7 @@ void BLO_update_defaults_startup_blend(Main *bmain, const char *app_template)
}
}
- for (Mesh *mesh = bmain->meshes.first; mesh; mesh = mesh->id.next) {
+ LISTBASE_FOREACH (Mesh *, mesh, &bmain->meshes) {
/* Match default for new meshes. */
mesh->smoothresh = DEG2RADF(30);
/* Match voxel remesher options for all existing meshes in templates. */
@@ -565,22 +577,23 @@ void BLO_update_defaults_startup_blend(Main *bmain, const char *app_template)
CustomData_free_layers(&mesh->vdata, CD_PAINT_MASK, mesh->totvert);
CustomData_free_layers(&mesh->ldata, CD_GRID_PAINT_MASK, mesh->totloop);
}
+ mesh->attributes_for_write().remove(".sculpt_face_set");
}
- for (Camera *camera = bmain->cameras.first; camera; camera = camera->id.next) {
+ LISTBASE_FOREACH (Camera *, camera, &bmain->cameras) {
/* Initialize to a useful value. */
camera->dof.focus_distance = 10.0f;
camera->dof.aperture_fstop = 2.8f;
}
- for (Light *light = bmain->lights.first; light; light = light->id.next) {
+ LISTBASE_FOREACH (Light *, light, &bmain->lights) {
/* Fix lights defaults. */
light->clipsta = 0.05f;
light->att_dist = 40.0f;
}
/* Materials */
- for (Material *ma = bmain->materials.first; ma; ma = ma->id.next) {
+ LISTBASE_FOREACH (Material *, ma, &bmain->materials) {
/* Update default material to be a bit more rough. */
ma->roughness = 0.5f;
@@ -588,7 +601,8 @@ void BLO_update_defaults_startup_blend(Main *bmain, const char *app_template)
LISTBASE_FOREACH (bNode *, node, &ma->nodetree->nodes) {
if (node->type == SH_NODE_BSDF_PRINCIPLED) {
bNodeSocket *roughness_socket = nodeFindSocket(node, SOCK_IN, "Roughness");
- bNodeSocketValueFloat *roughness_data = roughness_socket->default_value;
+ bNodeSocketValueFloat *roughness_data = static_cast<bNodeSocketValueFloat *>(
+ roughness_socket->default_value);
roughness_data->value = 0.5f;
node->custom2 = SHD_SUBSURFACE_RANDOM_WALK;
BKE_ntree_update_tag_node_property(ma->nodetree, node);
@@ -606,13 +620,14 @@ void BLO_update_defaults_startup_blend(Main *bmain, const char *app_template)
/* Enable for UV sculpt (other brush types will be created as needed),
* without this the grab brush will be active but not selectable from the list. */
const char *brush_name = "Grab";
- Brush *brush = BLI_findstring(&bmain->brushes, brush_name, offsetof(ID, name) + 2);
+ Brush *brush = static_cast<Brush *>(
+ BLI_findstring(&bmain->brushes, brush_name, offsetof(ID, name) + 2));
if (brush) {
brush->ob_mode |= OB_MODE_EDIT;
}
}
- for (Brush *brush = bmain->brushes.first; brush; brush = brush->id.next) {
+ LISTBASE_FOREACH (Brush *, brush, &bmain->brushes) {
brush->blur_kernel_radius = 2;
/* Use full strength for all non-sculpt brushes,
@@ -632,13 +647,15 @@ void BLO_update_defaults_startup_blend(Main *bmain, const char *app_template)
Brush *brush;
brush_name = "Smear";
- brush = BLI_findstring(&bmain->brushes, brush_name, offsetof(ID, name) + 2);
+ brush = static_cast<Brush *>(
+ BLI_findstring(&bmain->brushes, brush_name, offsetof(ID, name) + 2));
if (brush) {
brush->spacing = 3.0;
}
brush_name = "Draw Sharp";
- brush = BLI_findstring(&bmain->brushes, brush_name, offsetof(ID, name) + 2);
+ brush = static_cast<Brush *>(
+ BLI_findstring(&bmain->brushes, brush_name, offsetof(ID, name) + 2));
if (!brush) {
brush = BKE_brush_add(bmain, brush_name, OB_MODE_SCULPT);
id_us_min(&brush->id);
@@ -646,7 +663,8 @@ void BLO_update_defaults_startup_blend(Main *bmain, const char *app_template)
}
brush_name = "Elastic Deform";
- brush = BLI_findstring(&bmain->brushes, brush_name, offsetof(ID, name) + 2);
+ brush = static_cast<Brush *>(
+ BLI_findstring(&bmain->brushes, brush_name, offsetof(ID, name) + 2));
if (!brush) {
brush = BKE_brush_add(bmain, brush_name, OB_MODE_SCULPT);
id_us_min(&brush->id);
@@ -654,7 +672,8 @@ void BLO_update_defaults_startup_blend(Main *bmain, const char *app_template)
}
brush_name = "Pose";
- brush = BLI_findstring(&bmain->brushes, brush_name, offsetof(ID, name) + 2);
+ brush = static_cast<Brush *>(
+ BLI_findstring(&bmain->brushes, brush_name, offsetof(ID, name) + 2));
if (!brush) {
brush = BKE_brush_add(bmain, brush_name, OB_MODE_SCULPT);
id_us_min(&brush->id);
@@ -662,7 +681,8 @@ void BLO_update_defaults_startup_blend(Main *bmain, const char *app_template)
}
brush_name = "Multi-plane Scrape";
- brush = BLI_findstring(&bmain->brushes, brush_name, offsetof(ID, name) + 2);
+ brush = static_cast<Brush *>(
+ BLI_findstring(&bmain->brushes, brush_name, offsetof(ID, name) + 2));
if (!brush) {
brush = BKE_brush_add(bmain, brush_name, OB_MODE_SCULPT);
id_us_min(&brush->id);
@@ -670,7 +690,8 @@ void BLO_update_defaults_startup_blend(Main *bmain, const char *app_template)
}
brush_name = "Clay Thumb";
- brush = BLI_findstring(&bmain->brushes, brush_name, offsetof(ID, name) + 2);
+ brush = static_cast<Brush *>(
+ BLI_findstring(&bmain->brushes, brush_name, offsetof(ID, name) + 2));
if (!brush) {
brush = BKE_brush_add(bmain, brush_name, OB_MODE_SCULPT);
id_us_min(&brush->id);
@@ -678,7 +699,8 @@ void BLO_update_defaults_startup_blend(Main *bmain, const char *app_template)
}
brush_name = "Cloth";
- brush = BLI_findstring(&bmain->brushes, brush_name, offsetof(ID, name) + 2);
+ brush = static_cast<Brush *>(
+ BLI_findstring(&bmain->brushes, brush_name, offsetof(ID, name) + 2));
if (!brush) {
brush = BKE_brush_add(bmain, brush_name, OB_MODE_SCULPT);
id_us_min(&brush->id);
@@ -686,7 +708,8 @@ void BLO_update_defaults_startup_blend(Main *bmain, const char *app_template)
}
brush_name = "Slide Relax";
- brush = BLI_findstring(&bmain->brushes, brush_name, offsetof(ID, name) + 2);
+ brush = static_cast<Brush *>(
+ BLI_findstring(&bmain->brushes, brush_name, offsetof(ID, name) + 2));
if (!brush) {
brush = BKE_brush_add(bmain, brush_name, OB_MODE_SCULPT);
id_us_min(&brush->id);
@@ -694,7 +717,8 @@ void BLO_update_defaults_startup_blend(Main *bmain, const char *app_template)
}
brush_name = "Paint";
- brush = BLI_findstring(&bmain->brushes, brush_name, offsetof(ID, name) + 2);
+ brush = static_cast<Brush *>(
+ BLI_findstring(&bmain->brushes, brush_name, offsetof(ID, name) + 2));
if (!brush) {
brush = BKE_brush_add(bmain, brush_name, OB_MODE_SCULPT);
id_us_min(&brush->id);
@@ -702,7 +726,8 @@ void BLO_update_defaults_startup_blend(Main *bmain, const char *app_template)
}
brush_name = "Smear";
- brush = BLI_findstring(&bmain->brushes, brush_name, offsetof(ID, name) + 2);
+ brush = static_cast<Brush *>(
+ BLI_findstring(&bmain->brushes, brush_name, offsetof(ID, name) + 2));
if (!brush) {
brush = BKE_brush_add(bmain, brush_name, OB_MODE_SCULPT);
id_us_min(&brush->id);
@@ -710,7 +735,8 @@ void BLO_update_defaults_startup_blend(Main *bmain, const char *app_template)
}
brush_name = "Boundary";
- brush = BLI_findstring(&bmain->brushes, brush_name, offsetof(ID, name) + 2);
+ brush = static_cast<Brush *>(
+ BLI_findstring(&bmain->brushes, brush_name, offsetof(ID, name) + 2));
if (!brush) {
brush = BKE_brush_add(bmain, brush_name, OB_MODE_SCULPT);
id_us_min(&brush->id);
@@ -718,7 +744,8 @@ void BLO_update_defaults_startup_blend(Main *bmain, const char *app_template)
}
brush_name = "Simplify";
- brush = BLI_findstring(&bmain->brushes, brush_name, offsetof(ID, name) + 2);
+ brush = static_cast<Brush *>(
+ BLI_findstring(&bmain->brushes, brush_name, offsetof(ID, name) + 2));
if (!brush) {
brush = BKE_brush_add(bmain, brush_name, OB_MODE_SCULPT);
id_us_min(&brush->id);
@@ -726,7 +753,8 @@ void BLO_update_defaults_startup_blend(Main *bmain, const char *app_template)
}
brush_name = "Draw Face Sets";
- brush = BLI_findstring(&bmain->brushes, brush_name, offsetof(ID, name) + 2);
+ brush = static_cast<Brush *>(
+ BLI_findstring(&bmain->brushes, brush_name, offsetof(ID, name) + 2));
if (!brush) {
brush = BKE_brush_add(bmain, brush_name, OB_MODE_SCULPT);
id_us_min(&brush->id);
@@ -734,7 +762,8 @@ void BLO_update_defaults_startup_blend(Main *bmain, const char *app_template)
}
brush_name = "Multires Displacement Eraser";
- brush = BLI_findstring(&bmain->brushes, brush_name, offsetof(ID, name) + 2);
+ brush = static_cast<Brush *>(
+ BLI_findstring(&bmain->brushes, brush_name, offsetof(ID, name) + 2));
if (!brush) {
brush = BKE_brush_add(bmain, brush_name, OB_MODE_SCULPT);
id_us_min(&brush->id);
@@ -742,7 +771,8 @@ void BLO_update_defaults_startup_blend(Main *bmain, const char *app_template)
}
brush_name = "Multires Displacement Smear";
- brush = BLI_findstring(&bmain->brushes, brush_name, offsetof(ID, name) + 2);
+ brush = static_cast<Brush *>(
+ BLI_findstring(&bmain->brushes, brush_name, offsetof(ID, name) + 2));
if (!brush) {
brush = BKE_brush_add(bmain, brush_name, OB_MODE_SCULPT);
id_us_min(&brush->id);
@@ -750,7 +780,7 @@ void BLO_update_defaults_startup_blend(Main *bmain, const char *app_template)
}
/* Use the same tool icon color in the brush cursor */
- for (brush = bmain->brushes.first; brush; brush = brush->id.next) {
+ LISTBASE_FOREACH (Brush *, brush, &bmain->brushes) {
if (brush->ob_mode & OB_MODE_SCULPT) {
BLI_assert(brush->sculpt_tool != 0);
BKE_brush_sculpt_reset(brush);
diff --git a/source/blender/blenloader/tests/blendfile_loading_base_test.cc b/source/blender/blenloader/tests/blendfile_loading_base_test.cc
index 615e30a728e..b657970d45f 100644
--- a/source/blender/blenloader/tests/blendfile_loading_base_test.cc
+++ b/source/blender/blenloader/tests/blendfile_loading_base_test.cc
@@ -117,7 +117,7 @@ bool BlendfileLoadingBaseTest::blendfile_load(const char *filepath)
}
char abspath[FILENAME_MAX];
- BLI_path_join(abspath, sizeof(abspath), test_assets_dir.c_str(), filepath, nullptr);
+ BLI_path_join(abspath, sizeof(abspath), test_assets_dir.c_str(), filepath);
BlendFileReadReport bf_reports = {nullptr};
bfile = BLO_read_from_file(abspath, BLO_READ_SKIP_NONE, &bf_reports);
diff --git a/source/blender/blentranslation/intern/blt_lang.c b/source/blender/blentranslation/intern/blt_lang.c
index 0662adfb9ed..b8523f289c7 100644
--- a/source/blender/blentranslation/intern/blt_lang.c
+++ b/source/blender/blentranslation/intern/blt_lang.c
@@ -72,7 +72,7 @@ static void fill_locales(void)
free_locales();
- BLI_join_dirfile(languages, FILE_MAX, languages_path, "languages");
+ BLI_path_join(languages, FILE_MAX, languages_path, "languages");
line = lines = BLI_file_read_as_lines(languages);
/* This whole "parsing" code is a bit weak, in that it expects strictly formatted input file...
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/intern/COM_Debug.cc b/source/blender/compositor/intern/COM_Debug.cc
index d0f0be590f6..d184e5540ea 100644
--- a/source/blender/compositor/intern/COM_Debug.cc
+++ b/source/blender/compositor/intern/COM_Debug.cc
@@ -428,7 +428,7 @@ void DebugInfo::graphviz(const ExecutionSystem *system, StringRefNull name)
else {
BLI_strncpy(basename, (name + ".dot").c_str(), sizeof(basename));
}
- BLI_join_dirfile(filepath, sizeof(filepath), BKE_tempdir_session(), basename);
+ BLI_path_join(filepath, sizeof(filepath), BKE_tempdir_session(), basename);
file_index_++;
std::cout << "Writing compositor debug to: " << filepath << "\n";
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/nodes/COM_OutputFileNode.cc b/source/blender/compositor/nodes/COM_OutputFileNode.cc
index c83bcf42efd..fc4270cc222 100644
--- a/source/blender/compositor/nodes/COM_OutputFileNode.cc
+++ b/source/blender/compositor/nodes/COM_OutputFileNode.cc
@@ -104,7 +104,7 @@ void OutputFileNode::convert_to_operations(NodeConverter &converter,
char path[FILE_MAX];
/* combine file path for the input */
- BLI_join_dirfile(path, FILE_MAX, storage->base_path, sockdata->path);
+ BLI_path_join(path, FILE_MAX, storage->base_path, sockdata->path);
NodeOperation *output_operation = nullptr;
diff --git a/source/blender/compositor/realtime_compositor/CMakeLists.txt b/source/blender/compositor/realtime_compositor/CMakeLists.txt
index 1f1333332f5..bab0b5385ec 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..f6d479f9bbe
--- /dev/null
+++ b/source/blender/compositor/realtime_compositor/algorithms/COM_algorithm_parallel_reduction.hh
@@ -0,0 +1,103 @@
+/* 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);
+
+/* Computes the sum of the logarithm of the luminance of all pixels in the given texture, using the
+ * given luminance coefficients to compute the luminance. */
+float sum_log_luminance(Context &context, GPUTexture *texture, float3 luminance_coefficients);
+
+/* Computes the sum of the colors of all pixels in the given texture. */
+float4 sum_color(Context &context, GPUTexture *texture);
+
+/* --------------------------------------------------------------------
+ * 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);
+
+/* --------------------------------------------------------------------
+ * Maximum Reductions.
+ */
+
+/* Computes the maximum luminance of all pixels in the given texture, using the given luminance
+ * coefficients to compute the luminance. */
+float maximum_luminance(Context &context, GPUTexture *texture, float3 luminance_coefficients);
+
+/* Computes the maximum float of all pixels in the given float texture, limited to the given range.
+ * Values outside of the given range are ignored. If non of the pixel values are in the range, the
+ * lower bound of the range is returned. For instance, if the given range is [-10, 10] and the
+ * image contains the values {2, 5, 11}, the maximum will be 5, since 11 is outside of the range.
+ * This is particularly useful for Z Depth normalization, since Z Depth can contain near infinite
+ * values, so enforcing an upper bound is beneficial. */
+float maximum_float_in_range(Context &context,
+ GPUTexture *texture,
+ float lower_bound,
+ float upper_bound);
+
+/* --------------------------------------------------------------------
+ * Minimum Reductions.
+ */
+
+/* Computes the minimum luminance of all pixels in the given texture, using the given luminance
+ * coefficients to compute the luminance. */
+float minimum_luminance(Context &context, GPUTexture *texture, float3 luminance_coefficients);
+
+/* Computes the minimum float of all pixels in the given float texture, limited to the given range.
+ * Values outside of the given range are ignored. If non of the pixel values are in the range, the
+ * upper bound of the range is returned. For instance, if the given range is [-10, 10] and the
+ * image contains the values {-11, 2, 5}, the minimum will be 2, since -11 is outside of the range.
+ * This is particularly useful for Z Depth normalization, since Z Depth can contain near infinite
+ * values, so enforcing a lower bound is beneficial. */
+float minimum_float_in_range(Context &context,
+ GPUTexture *texture,
+ float lower_bound,
+ float upper_bound);
+
+} // 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..9672431992d
--- /dev/null
+++ b/source/blender/compositor/realtime_compositor/algorithms/intern/algorithm_parallel_reduction.cc
@@ -0,0 +1,309 @@
+/* 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;
+}
+
+float sum_log_luminance(Context &context, GPUTexture *texture, float3 luminance_coefficients)
+{
+ GPUShader *shader = context.shader_manager().get("compositor_sum_log_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;
+}
+
+float4 sum_color(Context &context, GPUTexture *texture)
+{
+ GPUShader *shader = context.shader_manager().get("compositor_sum_color");
+ GPU_shader_bind(shader);
+
+ float *reduced_value = parallel_reduction_dispatch(context, texture, shader, GPU_RGBA32F);
+ const float4 sum = float4(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;
+}
+
+/* --------------------------------------------------------------------
+ * Maximum Reductions.
+ */
+
+float maximum_luminance(Context &context, GPUTexture *texture, float3 luminance_coefficients)
+{
+ GPUShader *shader = context.shader_manager().get("compositor_maximum_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 maximum = *reduced_value;
+ MEM_freeN(reduced_value);
+ GPU_shader_unbind();
+
+ return maximum;
+}
+
+float maximum_float_in_range(Context &context,
+ GPUTexture *texture,
+ float lower_bound,
+ float upper_bound)
+{
+ GPUShader *shader = context.shader_manager().get("compositor_maximum_float_in_range");
+ GPU_shader_bind(shader);
+
+ GPU_shader_uniform_1f(shader, "lower_bound", lower_bound);
+ GPU_shader_uniform_1f(shader, "upper_bound", upper_bound);
+
+ float *reduced_value = parallel_reduction_dispatch(context, texture, shader, GPU_R32F);
+ const float maximum = *reduced_value;
+ MEM_freeN(reduced_value);
+ GPU_shader_unbind();
+
+ return maximum;
+}
+
+/* --------------------------------------------------------------------
+ * Minimum Reductions.
+ */
+
+float minimum_luminance(Context &context, GPUTexture *texture, float3 luminance_coefficients)
+{
+ GPUShader *shader = context.shader_manager().get("compositor_minimum_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 minimum = *reduced_value;
+ MEM_freeN(reduced_value);
+ GPU_shader_unbind();
+
+ return minimum;
+}
+
+float minimum_float_in_range(Context &context,
+ GPUTexture *texture,
+ float lower_bound,
+ float upper_bound)
+{
+ GPUShader *shader = context.shader_manager().get("compositor_minimum_float_in_range");
+ GPU_shader_bind(shader);
+
+ GPU_shader_uniform_1f(shader, "lower_bound", lower_bound);
+ GPU_shader_uniform_1f(shader, "upper_bound", upper_bound);
+
+ float *reduced_value = parallel_reduction_dispatch(context, texture, shader, GPU_R32F);
+ const float minimum = *reduced_value;
+ MEM_freeN(reduced_value);
+ GPU_shader_unbind();
+
+ return minimum;
+}
+
+} // namespace blender::realtime_compositor
diff --git a/source/blender/depsgraph/intern/builder/deg_builder_nodes.cc b/source/blender/depsgraph/intern/builder/deg_builder_nodes.cc
index f95c0700a47..c84852788fd 100644
--- a/source/blender/depsgraph/intern/builder/deg_builder_nodes.cc
+++ b/source/blender/depsgraph/intern/builder/deg_builder_nodes.cc
@@ -453,6 +453,11 @@ static int foreach_id_cow_detect_need_for_update_callback(LibraryIDLinkCallbackD
if (id == nullptr) {
return IDWALK_RET_NOP;
}
+ if (!ID_TYPE_IS_COW(GS(id->name))) {
+ /* No need to go further if the id never had a cow copy in the depsgraph. This function is
+ * only concerned with keeping the mapping between original and COW ids intact. */
+ return IDWALK_RET_NOP;
+ }
DepsgraphNodeBuilder *builder = static_cast<DepsgraphNodeBuilder *>(cb_data->user_data);
ID *id_cow_self = cb_data->id_self;
diff --git a/source/blender/draw/CMakeLists.txt b/source/blender/draw/CMakeLists.txt
index d82ae4cd32c..1c17f92f073 100644
--- a/source/blender/draw/CMakeLists.txt
+++ b/source/blender/draw/CMakeLists.txt
@@ -71,13 +71,13 @@ set(SRC
intern/draw_attributes.cc
intern/draw_cache_impl_curve.cc
intern/draw_cache_impl_curves.cc
- intern/draw_cache_impl_gpencil.c
+ intern/draw_cache_impl_gpencil.cc
intern/draw_cache_impl_lattice.c
intern/draw_cache_impl_mesh.cc
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 ff7dda1152c..068b18f1117 100644
--- a/source/blender/draw/engines/eevee/eevee_materials.c
+++ b/source/blender/draw/engines/eevee/eevee_materials.c
@@ -759,7 +759,8 @@ BLI_INLINE Material *eevee_object_material_get(Object *ob, int slot, bool holdou
BLI_INLINE EeveeMaterialCache eevee_material_cache_get(
EEVEE_Data *vedata, EEVEE_ViewLayerData *sldata, Object *ob, int slot, bool is_hair)
{
- const bool holdout = (ob->base_flag & BASE_HOLDOUT) != 0;
+ const bool holdout = ((ob->base_flag & BASE_HOLDOUT) != 0) ||
+ ((ob->visibility_flag & OB_HOLDOUT) != 0);
EeveeMaterialCache matcache;
Material *ma = eevee_object_material_get(ob, slot, holdout);
switch (ma->blend_method) {
@@ -812,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);
@@ -919,17 +924,14 @@ void EEVEE_particle_hair_cache_populate(EEVEE_Data *vedata,
if (matcache.depth_grp) {
*matcache.depth_grp_p = DRW_shgroup_hair_create_sub(
ob, psys, md, matcache.depth_grp, NULL);
- DRW_shgroup_add_material_resources(*matcache.depth_grp_p, matcache.shading_gpumat);
}
if (matcache.shading_grp) {
*matcache.shading_grp_p = DRW_shgroup_hair_create_sub(
ob, psys, md, matcache.shading_grp, matcache.shading_gpumat);
- DRW_shgroup_add_material_resources(*matcache.shading_grp_p, matcache.shading_gpumat);
}
if (matcache.shadow_grp) {
*matcache.shadow_grp_p = DRW_shgroup_hair_create_sub(
ob, psys, md, matcache.shadow_grp, NULL);
- DRW_shgroup_add_material_resources(*matcache.shadow_grp_p, matcache.shading_gpumat);
*cast_shadow = true;
}
@@ -949,16 +951,13 @@ void EEVEE_object_curves_cache_populate(EEVEE_Data *vedata,
if (matcache.depth_grp) {
*matcache.depth_grp_p = DRW_shgroup_curves_create_sub(ob, matcache.depth_grp, NULL);
- DRW_shgroup_add_material_resources(*matcache.depth_grp_p, matcache.shading_gpumat);
}
if (matcache.shading_grp) {
*matcache.shading_grp_p = DRW_shgroup_curves_create_sub(
ob, matcache.shading_grp, matcache.shading_gpumat);
- DRW_shgroup_add_material_resources(*matcache.shading_grp_p, matcache.shading_gpumat);
}
if (matcache.shadow_grp) {
*matcache.shadow_grp_p = DRW_shgroup_curves_create_sub(ob, matcache.shadow_grp, NULL);
- DRW_shgroup_add_material_resources(*matcache.shadow_grp_p, matcache.shading_gpumat);
*cast_shadow = true;
}
diff --git a/source/blender/draw/engines/eevee/shaders/cubemap_lib.glsl b/source/blender/draw/engines/eevee/shaders/cubemap_lib.glsl
index 90272400915..5af317b7398 100644
--- a/source/blender/draw/engines/eevee/shaders/cubemap_lib.glsl
+++ b/source/blender/draw/engines/eevee/shaders/cubemap_lib.glsl
@@ -96,7 +96,7 @@ vec4 cubemap_seamless(sampler2DArray tex, vec4 cubevec, float lod)
/* Mix all colors to get the corner color. */
vec4 col3 = (col + col1 + col2) / 3.0;
- vec2 mix_fac = uv_border * 0.5;
+ vec2 mix_fac = saturate(uv_border * 0.5);
return mix(mix(col, col2, mix_fac.x), mix(col1, col3, mix_fac.x), mix_fac.y);
}
else if (any(border)) {
@@ -108,7 +108,7 @@ vec4 cubemap_seamless(sampler2DArray tex, vec4 cubevec, float lod)
uv = cubemap_face_coord(cubevec.xyz, face);
coord = vec3(uv, cubevec.w * 6.0 + face);
- float mix_fac = max(uv_border.x, uv_border.y) * 0.5;
+ float mix_fac = saturate(max(uv_border.x, uv_border.y) * 0.5);
return mix(col, textureLod(tex, coord, lod), mix_fac);
}
else {
diff --git a/source/blender/draw/engines/eevee/shaders/effect_dof_scatter_vert.glsl b/source/blender/draw/engines/eevee/shaders/effect_dof_scatter_vert.glsl
index 51a351babd3..5f04cdcebfa 100644
--- a/source/blender/draw/engines/eevee/shaders/effect_dof_scatter_vert.glsl
+++ b/source/blender/draw/engines/eevee/shaders/effect_dof_scatter_vert.glsl
@@ -95,7 +95,11 @@ void main()
weights = dof_layer_weight(cocs) * dof_sample_weight(cocs);
/* Filter NaNs. */
- weights = select(weights, vec4(0.0), equal(cocs, vec4(0.0)));
+ for (int i = 0; i < 4; i++) {
+ if (isnan(weights[i]) || isinf(weights[i])) {
+ weights[i] = 0.0;
+ }
+ }
color1 = colors[0] * weights[0];
color2 = colors[1] * weights[1];
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 08cda6f47cf..cbd735ec29c 100644
--- a/source/blender/draw/engines/eevee_next/eevee_sync.cc
+++ b/source/blender/draw/engines/eevee_next/eevee_sync.cc
@@ -248,17 +248,17 @@ static void gpencil_stroke_sync(bGPDlayer * /*gpl*/,
return;
}
+ GPUBatch *geom = DRW_cache_gpencil_get(iter.ob, iter.cfra);
+
if (show_fill) {
- GPUBatch *geom = DRW_cache_gpencil_fills_get(iter.ob, iter.cfra);
int vfirst = gps->runtime.fill_start * 3;
int vcount = gps->tot_triangles * 3;
gpencil_drawcall_add(iter, geom, material, vfirst, vcount, false);
}
if (show_stroke) {
- GPUBatch *geom = DRW_cache_gpencil_strokes_get(iter.ob, iter.cfra);
/* Start one vert before to have gl_InstanceID > 0 (see shader). */
- int vfirst = gps->runtime.stroke_start - 1;
+ int vfirst = gps->runtime.stroke_start * 3;
/* Include "potential" cyclic vertex and start adj vertex (see shader). */
int vcount = gps->totpoints + 1 + 1;
gpencil_drawcall_add(iter, geom, material, vfirst, vcount, true);
diff --git a/source/blender/draw/engines/eevee_next/shaders/eevee_geom_gpencil_vert.glsl b/source/blender/draw/engines/eevee_next/shaders/eevee_geom_gpencil_vert.glsl
index 38debf14eda..87a5bf71c45 100644
--- a/source/blender/draw/engines/eevee_next/shaders/eevee_geom_gpencil_vert.glsl
+++ b/source/blender/draw/engines/eevee_next/shaders/eevee_geom_gpencil_vert.glsl
@@ -16,30 +16,18 @@ void main()
float hardness;
vec2 thickness;
- gl_Position = gpencil_vertex(ma,
- ma1,
- ma2,
- ma3,
- pos,
- pos1,
- pos2,
- pos3,
- uv1,
- uv2,
- col1,
- col2,
- fcol1,
- /* TODO */
- vec4(1024.0, 1024.0, 1.0 / 1024.0, 1.0 / 1024.0),
- interp.P,
- interp.N,
- g_color,
- strength,
- g_uvs,
- sspos,
- aspect,
- thickness,
- hardness);
+ gl_Position = gpencil_vertex(
+ /* TODO */
+ vec4(1024.0, 1024.0, 1.0 / 1024.0, 1.0 / 1024.0),
+ interp.P,
+ interp.N,
+ g_color,
+ strength,
+ g_uvs,
+ sspos,
+ aspect,
+ thickness,
+ hardness);
#ifdef MAT_VELOCITY
/* GPencil do not support deformation motion blur. */
vec3 lP_curr = transform_point(ModelMatrixInverse, interp.P);
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/gpencil/gpencil_engine.c b/source/blender/draw/engines/gpencil/gpencil_engine.c
index b24e4c605e4..21e536ffbd4 100644
--- a/source/blender/draw/engines/gpencil/gpencil_engine.c
+++ b/source/blender/draw/engines/gpencil/gpencil_engine.c
@@ -342,7 +342,6 @@ typedef struct gpIterPopulateData {
int stroke_index_offset;
/* Infos for call batching. */
struct GPUBatch *geom;
- bool instancing;
int vfirst, vcount;
} gpIterPopulateData;
@@ -352,12 +351,7 @@ static void gpencil_drawcall_flush(gpIterPopulateData *iter)
{
#if !DISABLE_BATCHING
if (iter->geom != NULL) {
- if (iter->instancing) {
- DRW_shgroup_call_instance_range(iter->grp, iter->ob, iter->geom, iter->vfirst, iter->vcount);
- }
- else {
- DRW_shgroup_call_range(iter->grp, iter->ob, iter->geom, iter->vfirst, iter->vcount);
- }
+ DRW_shgroup_call_range(iter->grp, iter->ob, iter->geom, iter->vfirst, iter->vcount);
}
#endif
@@ -367,25 +361,22 @@ static void gpencil_drawcall_flush(gpIterPopulateData *iter)
}
/* Group draw-calls that are consecutive and with the same type. Reduces GPU driver overhead. */
-static void gpencil_drawcall_add(
- gpIterPopulateData *iter, struct GPUBatch *geom, bool instancing, int v_first, int v_count)
+static void gpencil_drawcall_add(gpIterPopulateData *iter,
+ struct GPUBatch *geom,
+ int v_first,
+ int v_count)
{
#if DISABLE_BATCHING
- if (instancing) {
- DRW_shgroup_call_instance_range(iter->grp, iter->ob, geom, v_first, v_count);
- }
- else {
- DRW_shgroup_call_range(iter->grp, iter->ob, geom, v_first, v_count);
- }
+ DRW_shgroup_call_range(iter->grp, iter->ob, geom, v_first, v_count);
+ return;
#endif
int last = iter->vfirst + iter->vcount;
/* Interrupt draw-call grouping if the sequence is not consecutive. */
- if ((geom != iter->geom) || (v_first - last > 3)) {
+ if ((geom != iter->geom) || (v_first - last > 0)) {
gpencil_drawcall_flush(iter);
}
iter->geom = geom;
- iter->instancing = instancing;
if (iter->vfirst == -1) {
iter->vfirst = v_first;
}
@@ -516,25 +507,36 @@ static void gpencil_stroke_cache_populate(bGPDlayer *gpl,
bool do_sbuffer = (iter->do_sbuffer_call == DRAW_NOW);
+ GPUBatch *geom = do_sbuffer ? DRW_cache_gpencil_sbuffer_get(iter->ob, show_fill) :
+ DRW_cache_gpencil_get(iter->ob, iter->pd->cfra);
+ if (geom != iter->geom) {
+ gpencil_drawcall_flush(iter);
+
+ GPUVertBuf *position_tx = do_sbuffer ?
+ DRW_cache_gpencil_sbuffer_position_buffer_get(iter->ob,
+ show_fill) :
+ DRW_cache_gpencil_position_buffer_get(iter->ob, iter->pd->cfra);
+ GPUVertBuf *color_tx = do_sbuffer ?
+ DRW_cache_gpencil_sbuffer_color_buffer_get(iter->ob, show_fill) :
+ DRW_cache_gpencil_color_buffer_get(iter->ob, iter->pd->cfra);
+ DRW_shgroup_buffer_texture(iter->grp, "gp_pos_tx", position_tx);
+ DRW_shgroup_buffer_texture(iter->grp, "gp_col_tx", color_tx);
+ }
+
if (show_fill) {
- GPUBatch *geom = do_sbuffer ? DRW_cache_gpencil_sbuffer_fill_get(iter->ob) :
- DRW_cache_gpencil_fills_get(iter->ob, iter->pd->cfra);
int vfirst = gps->runtime.fill_start * 3;
int vcount = gps->tot_triangles * 3;
- gpencil_drawcall_add(iter, geom, false, vfirst, vcount);
+ gpencil_drawcall_add(iter, geom, vfirst, vcount);
}
if (show_stroke) {
- GPUBatch *geom = do_sbuffer ? DRW_cache_gpencil_sbuffer_stroke_get(iter->ob) :
- DRW_cache_gpencil_strokes_get(iter->ob, iter->pd->cfra);
- /* Start one vert before to have gl_InstanceID > 0 (see shader). */
- int vfirst = gps->runtime.stroke_start - 1;
- /* Include "potential" cyclic vertex and start adj vertex (see shader). */
- int vcount = gps->totpoints + 1 + 1;
- gpencil_drawcall_add(iter, geom, true, vfirst, vcount);
+ int vfirst = gps->runtime.stroke_start * 3;
+ bool is_cyclic = ((gps->flag & GP_STROKE_CYCLIC) != 0) && (gps->totpoints > 2);
+ int vcount = (gps->totpoints + (int)is_cyclic) * 2 * 3;
+ gpencil_drawcall_add(iter, geom, vfirst, vcount);
}
- iter->stroke_index_last = gps->runtime.stroke_start + gps->totpoints + 1;
+ iter->stroke_index_last = gps->runtime.vertex_start + gps->totpoints + 1;
}
static void gpencil_sbuffer_cache_populate_fast(GPENCIL_Data *vedata, gpIterPopulateData *iter)
diff --git a/source/blender/draw/engines/gpencil/gpencil_shader_shared.h b/source/blender/draw/engines/gpencil/gpencil_shader_shared.h
index 4c621e955b9..3f0f73e7c13 100644
--- a/source/blender/draw/engines/gpencil/gpencil_shader_shared.h
+++ b/source/blender/draw/engines/gpencil/gpencil_shader_shared.h
@@ -41,6 +41,9 @@ enum gpLightType {
GP_LIGHT_TYPE_AMBIENT = 3u,
};
+#define GP_IS_STROKE_VERTEX_BIT (1 << 30)
+#define GP_VERTEX_ID_SHIFT 2
+
/* Avoid compiler funkiness with enum types not being strongly typed in C. */
#ifndef GPU_SHADER
# define gpMaterialFlag uint
diff --git a/source/blender/draw/engines/gpencil/shaders/gpencil_common_lib.glsl b/source/blender/draw/engines/gpencil/shaders/gpencil_common_lib.glsl
index 7ddfdc5f65c..642939136c8 100644
--- a/source/blender/draw/engines/gpencil/shaders/gpencil_common_lib.glsl
+++ b/source/blender/draw/engines/gpencil/shaders/gpencil_common_lib.glsl
@@ -1,92 +1,4 @@
-/* Must match C declaration. */
-struct gpMaterial {
- vec4 stroke_color;
- vec4 fill_color;
- vec4 fill_mix_color;
- vec4 fill_uv_rot_scale;
- vec4 fill_uv_offset;
- /* Put float/int at the end to avoid padding error */
- /* Some drivers are completely messing the alignment or the fetches here.
- * We are forced to pack these into vec4 otherwise we only get 0.0 as value. */
- vec4 gp_mat_packed_1;
- // float stroke_texture_mix;
- // float stroke_u_scale;
- // float fill_texture_mix;
- // int gp_flag;
- /* Please ensure 16 byte alignment (multiple of vec4). */
-};
-
-#define MATERIAL(m) materials[m + gpMaterialOffset]
-
-#define stroke_texture_mix gp_mat_packed_1.x
-#define stroke_u_scale gp_mat_packed_1.y
-#define fill_texture_mix gp_mat_packed_1.z
-#define GP_FLAG(m) floatBitsToInt(MATERIAL(m).gp_mat_packed_1.w)
-
-/* flag */
-#define GP_STROKE_ALIGNMENT_STROKE 1
-#define GP_STROKE_ALIGNMENT_OBJECT 2
-#define GP_STROKE_ALIGNMENT_FIXED 3
-#define GP_STROKE_ALIGNMENT 0x3
-#define GP_STROKE_OVERLAP (1 << 2)
-#define GP_STROKE_TEXTURE_USE (1 << 3)
-#define GP_STROKE_TEXTURE_STENCIL (1 << 4)
-#define GP_STROKE_TEXTURE_PREMUL (1 << 5)
-#define GP_STROKE_DOTS (1 << 6)
-#define GP_STROKE_HOLDOUT (1 << 7)
-#define GP_FILL_HOLDOUT (1 << 8)
-#define GP_FILL_TEXTURE_USE (1 << 10)
-#define GP_FILL_TEXTURE_PREMUL (1 << 11)
-#define GP_FILL_TEXTURE_CLIP (1 << 12)
-#define GP_FILL_GRADIENT_USE (1 << 13)
-#define GP_FILL_GRADIENT_RADIAL (1 << 14)
-/* High bits are used to pass material ID to fragment shader. */
-#define GP_MATID_SHIFT 16
-
-/* Multiline defines can crash blender with certain GPU drivers. */
-/* clang-format off */
-#define GP_FILL_FLAGS (GP_FILL_TEXTURE_USE | GP_FILL_TEXTURE_PREMUL | GP_FILL_TEXTURE_CLIP | GP_FILL_GRADIENT_USE | GP_FILL_GRADIENT_RADIAL | GP_FILL_HOLDOUT)
-/* clang-format on */
-
-#define GP_FLAG_TEST(flag, val) (((flag) & (val)) != 0)
-
-/* Must match C declaration. */
-struct gpLight {
- vec4 color_type;
- vec4 right;
- vec4 up;
- vec4 forward;
- vec4 position;
- /* Please ensure 16 byte alignment (multiple of vec4). */
-};
-
-#define spot_size right.w
-#define spot_blend up.w
-
-#define GP_LIGHT_TYPE_POINT 0.0
-#define GP_LIGHT_TYPE_SPOT 1.0
-#define GP_LIGHT_TYPE_SUN 2.0
-#define GP_LIGHT_TYPE_AMBIENT 3.0
-
-#ifdef GP_MATERIAL_BUFFER_LEN
-
-layout(std140) uniform gpMaterialBlock
-{
- gpMaterial materials[GP_MATERIAL_BUFFER_LEN];
-};
-
-#endif
-
-#ifdef GPENCIL_LIGHT_BUFFER_LEN
-
-layout(std140) uniform gpLightBlock
-{
- gpLight lights[GPENCIL_LIGHT_BUFFER_LEN];
-};
-
-#endif
-
/* Must match eGPLayerBlendModes */
#define MODE_REGULAR 0
#define MODE_HARDLIGHT 1
@@ -149,510 +61,3 @@ void blend_mode_output(
break;
}
}
-
-#ifndef USE_GPU_SHADER_CREATE_INFO
-
-IN_OUT ShaderStageInterface
-{
- vec4 finalColorMul;
- vec4 finalColorAdd;
- vec3 finalPos;
- vec2 finalUvs;
- noperspective float strokeThickness;
- noperspective float unclampedThickness;
- noperspective float strokeHardeness;
- flat vec2 strokeAspect;
- flat vec2 strokePt1;
- flat vec2 strokePt2;
- flat int matFlag;
- flat float depth;
-};
-
-#endif
-
-#ifdef GPU_FRAGMENT_SHADER
-
-# define linearstep(p0, p1, v) (clamp(((v) - (p0)) / abs((p1) - (p0)), 0.0, 1.0))
-
-float stroke_round_cap_mask(vec2 p1, vec2 p2, vec2 aspect, float thickness, float hardfac)
-{
- /* We create our own uv space to avoid issues with triangulation and linear
- * interpolation artifacts. */
- vec2 line = p2.xy - p1.xy;
- vec2 pos = gl_FragCoord.xy - p1.xy;
- float line_len = length(line);
- float half_line_len = line_len * 0.5;
- /* Normalize */
- line = (line_len > 0.0) ? (line / line_len) : vec2(1.0, 0.0);
- /* Create a uv space that englobe the whole segment into a capsule. */
- vec2 uv_end;
- uv_end.x = max(abs(dot(line, pos) - half_line_len) - half_line_len, 0.0);
- uv_end.y = dot(vec2(-line.y, line.x), pos);
- /* Divide by stroke radius. */
- uv_end /= thickness;
- uv_end *= aspect;
-
- float dist = clamp(1.0 - length(uv_end) * 2.0, 0.0, 1.0);
- if (hardfac > 0.999) {
- return step(1e-8, dist);
- }
- else {
- /* Modulate the falloff profile */
- float hardness = 1.0 - hardfac;
- dist = pow(dist, mix(0.01, 10.0, hardness));
- return smoothstep(0.0, 1.0, dist);
- }
-}
-
-#endif
-
-uniform vec2 sizeViewport;
-uniform vec2 sizeViewportInv;
-
-/* Per Object */
-uniform bool strokeOrder3d;
-uniform int gpMaterialOffset;
-uniform float thicknessScale;
-uniform float thicknessWorldScale;
-#define thicknessIsScreenSpace (thicknessWorldScale < 0.0)
-
-#ifdef GPU_VERTEX_SHADER
-
-/* Per Layer */
-uniform float thicknessOffset;
-uniform float vertexColorOpacity;
-uniform vec4 layerTint;
-uniform float layerOpacity; /* Used for onion skin. */
-uniform float strokeIndexOffset = 0.0;
-
-/* All of these attributes are quad loaded the same way
- * as GL_LINES_ADJACENCY would feed a geometry shader:
- * - ma reference the previous adjacency point.
- * - ma1 reference the current line first point.
- * - ma2 reference the current line second point.
- * - ma3 reference the next adjacency point.
- * Note that we are rendering quad instances and not using any index buffer (except for fills).
- */
-/* x is material index, y is stroke_id, z is point_id, w is aspect & rotation & hardness packed. */
-in ivec4 ma;
-in ivec4 ma1;
-in ivec4 ma2;
-in ivec4 ma3;
-/* Position contains thickness in 4th component. */
-in vec4 pos; /* Prev adj vert */
-in vec4 pos1; /* Current edge */
-in vec4 pos2; /* Current edge */
-in vec4 pos3; /* Next adj vert */
-/* xy is UV for fills, z is U of stroke, w is strength. */
-in vec4 uv1;
-in vec4 uv2;
-in vec4 col1;
-in vec4 col2;
-in vec4 fcol1;
-/* WARNING: Max attribute count is actually 14 because OSX OpenGL implementation
- * considers gl_VertexID and gl_InstanceID as vertex attribute. (see T74536) */
-# define stroke_id1 ma1.y
-# define point_id1 ma1.z
-# define thickness1 pos1.w
-# define thickness2 pos2.w
-# define strength1 uv1.w
-# define strength2 uv2.w
-/* Packed! need to be decoded. */
-# define hardness1 ma1.w
-# define hardness2 ma2.w
-# define uvrot1 ma1.w
-# define aspect1 ma1.w
-
-vec2 decode_aspect(int packed_data)
-{
- float asp = float(uint(packed_data) & 0x1FFu) * (1.0 / 255.0);
- return (asp > 1.0) ? vec2(1.0, (asp - 1.0)) : vec2(asp, 1.0);
-}
-
-float decode_uvrot(int packed_data)
-{
- uint udata = uint(packed_data);
- float uvrot = 1e-8 + float((udata & 0x1FE00u) >> 9u) * (1.0 / 255.0);
- return ((udata & 0x20000u) != 0u) ? -uvrot : uvrot;
-}
-
-float decode_hardness(int packed_data)
-{
- return float((uint(packed_data) & 0x3FC0000u) >> 18u) * (1.0 / 255.0);
-}
-
-void discard_vert()
-{
- /* We set the vertex at the camera origin to generate 0 fragments. */
- gl_Position = vec4(0.0, 0.0, -3e36, 0.0);
-}
-
-vec2 project_to_screenspace(vec4 v)
-{
- return ((v.xy / v.w) * 0.5 + 0.5) * sizeViewport;
-}
-
-vec2 rotate_90deg(vec2 v)
-{
- /* Counter Clock-Wise. */
- return vec2(-v.y, v.x);
-}
-
-mat4 model_matrix_get()
-{
- return ModelMatrix;
-}
-
-vec3 transform_point(mat4 m, vec3 v)
-{
- return (m * vec4(v, 1.0)).xyz;
-}
-
-vec2 safe_normalize(vec2 v)
-{
- float len_sqr = dot(v, v);
- if (len_sqr > 0.0) {
- return v / sqrt(len_sqr);
- }
- else {
- return vec2(1.0, 0.0);
- }
-}
-
-vec2 safe_normalize_len(vec2 v, out float len)
-{
- len = sqrt(dot(v, v));
- if (len > 0.0) {
- return v / len;
- }
- else {
- return vec2(1.0, 0.0);
- }
-}
-
-float stroke_thickness_modulate(float thickness)
-{
- /* Modify stroke thickness by object and layer factors. */
- thickness *= thicknessScale;
- thickness += thicknessOffset;
- thickness = max(1.0, thickness);
-
- if (thicknessIsScreenSpace) {
- /* Multiply offset by view Z so that offset is constant in screenspace.
- * (e.i: does not change with the distance to camera) */
- thickness *= gl_Position.w;
- }
- else {
- /* World space point size. */
- thickness *= thicknessWorldScale * drw_view.winmat[1][1] * sizeViewport.y;
- }
- return thickness;
-}
-
-float clamp_small_stroke_thickness(float thickness)
-{
- /* To avoid aliasing artifacts, we clamp the line thickness and
- * reduce its opacity in the fragment shader. */
- float min_thickness = gl_Position.w * 1.3;
- thickness = max(min_thickness, thickness);
-
- return thickness;
-}
-
-# ifdef GP_MATERIAL_BUFFER_LEN
-void color_output(vec4 stroke_col, vec4 vert_col, float vert_strength, float mix_tex)
-{
- /* Mix stroke with other colors. */
- vec4 mixed_col = stroke_col;
- mixed_col.rgb = mix(mixed_col.rgb, vert_col.rgb, vert_col.a * vertexColorOpacity);
- mixed_col.rgb = mix(mixed_col.rgb, layerTint.rgb, layerTint.a);
- mixed_col.a *= vert_strength * layerOpacity;
- /**
- * This is what the fragment shader looks like.
- * out = col * finalColorMul + col.a * finalColorAdd.
- * finalColorMul is how much of the texture color to keep.
- * finalColorAdd is how much of the mixed color to add.
- * Note that we never add alpha. This is to keep the texture act as a stencil.
- * We do however, modulate the alpha (reduce it).
- */
- /* We add the mixed color. This is 100% mix (no texture visible). */
- finalColorMul = vec4(mixed_col.aaa, mixed_col.a);
- finalColorAdd = vec4(mixed_col.rgb * mixed_col.a, 0.0);
- /* Then we blend according to the texture mix factor.
- * Note that we keep the alpha modulation. */
- finalColorMul.rgb *= mix_tex;
- finalColorAdd.rgb *= 1.0 - mix_tex;
-}
-# endif
-
-void stroke_vertex()
-{
- int m = ma1.x;
- bool is_dot = false;
- bool is_squares = false;
-
-# ifdef GP_MATERIAL_BUFFER_LEN
- if (m != -1) {
- is_dot = GP_FLAG_TEST(GP_FLAG(m), GP_STROKE_ALIGNMENT);
- is_squares = !GP_FLAG_TEST(GP_FLAG(m), GP_STROKE_DOTS);
- }
-# endif
-
- /* Special Case. Stroke with single vert are rendered as dots. Do not discard them. */
- if (!is_dot && ma.x == -1 && ma2.x == -1) {
- is_dot = true;
- is_squares = false;
- }
-
- /* Endpoints, we discard the vertices. */
- if (ma1.x == -1 || (!is_dot && ma2.x == -1)) {
- discard_vert();
- return;
- }
-
- mat4 model_mat = model_matrix_get();
-
- /* Avoid using a vertex attribute for quad positioning. */
- float x = float(gl_VertexID & 1) * 2.0 - 1.0; /* [-1..1] */
- float y = float(gl_VertexID & 2) - 1.0; /* [-1..1] */
-
- bool use_curr = is_dot || (x == -1.0);
-
- vec3 wpos_adj = transform_point(model_mat, (use_curr) ? pos.xyz : pos3.xyz);
- vec3 wpos1 = transform_point(model_mat, pos1.xyz);
- vec3 wpos2 = transform_point(model_mat, pos2.xyz);
-
- vec4 ndc_adj = point_world_to_ndc(wpos_adj);
- vec4 ndc1 = point_world_to_ndc(wpos1);
- vec4 ndc2 = point_world_to_ndc(wpos2);
-
- gl_Position = (use_curr) ? ndc1 : ndc2;
- finalPos = (use_curr) ? wpos1 : wpos2;
-
- vec2 ss_adj = project_to_screenspace(ndc_adj);
- vec2 ss1 = project_to_screenspace(ndc1);
- vec2 ss2 = project_to_screenspace(ndc2);
- /* Screenspace Lines tangents. */
- float line_len;
- vec2 line = safe_normalize_len(ss2 - ss1, line_len);
- vec2 line_adj = safe_normalize((use_curr) ? (ss1 - ss_adj) : (ss_adj - ss2));
-
- float thickness = abs((use_curr) ? thickness1 : thickness2);
- thickness = stroke_thickness_modulate(thickness);
- float clampedThickness = clamp_small_stroke_thickness(thickness);
-
- finalUvs = vec2(x, y) * 0.5 + 0.5;
- strokeHardeness = decode_hardness(use_curr ? hardness1 : hardness2);
-
- if (is_dot) {
-# ifdef GP_MATERIAL_BUFFER_LEN
- int alignement = GP_FLAG(m) & GP_STROKE_ALIGNMENT;
- /* For one point strokes use object alignment. */
- if (ma.x == -1 && ma2.x == -1 && alignement == GP_STROKE_ALIGNMENT_STROKE) {
- alignement = GP_STROKE_ALIGNMENT_OBJECT;
- }
-# endif
-
- vec2 x_axis;
-# ifdef GP_MATERIAL_BUFFER_LEN
- if (alignement == GP_STROKE_ALIGNMENT_STROKE) {
- x_axis = (ma2.x == -1) ? line_adj : line;
- }
- else if (alignement == GP_STROKE_ALIGNMENT_FIXED) {
- /* Default for no-material drawing. */
- x_axis = vec2(1.0, 0.0);
- }
- else
-# endif
- { /* GP_STROKE_ALIGNMENT_OBJECT */
- vec4 ndc_x = point_world_to_ndc(wpos1 + model_mat[0].xyz);
- vec2 ss_x = project_to_screenspace(ndc_x);
- x_axis = safe_normalize(ss_x - ss1);
- }
-
- /* Rotation: Encoded as Cos + Sin sign. */
- float uv_rot = decode_uvrot(uvrot1);
- float rot_sin = sqrt(max(0.0, 1.0 - uv_rot * uv_rot)) * sign(uv_rot);
- float rot_cos = abs(uv_rot);
- x_axis = mat2(rot_cos, -rot_sin, rot_sin, rot_cos) * x_axis;
-
-# ifdef GP_MATERIAL_BUFFER_LEN
- if (is_dot) {
- float alignment_cos = MATERIAL(m).fill_uv_offset.z;
- float alignment_sin = MATERIAL(m).fill_uv_offset.w;
- x_axis = mat2(alignment_cos, -alignment_sin, alignment_sin, alignment_cos) * x_axis;
- }
-# endif
-
- vec2 y_axis = rotate_90deg(x_axis);
-
- strokeAspect = decode_aspect(aspect1);
-
- x *= strokeAspect.x;
- y *= strokeAspect.y;
-
- /* Invert for vertex shader. */
- strokeAspect = 1.0 / strokeAspect;
-
- gl_Position.xy += (x * x_axis + y * y_axis) * sizeViewportInv.xy * clampedThickness;
-
- strokePt1 = ss1;
- strokePt2 = ss1 + x_axis * 0.5;
- strokeThickness = (is_squares) ? 1e18 : (clampedThickness / gl_Position.w);
- unclampedThickness = (is_squares) ? 1e18 : (thickness / gl_Position.w);
- }
- else {
- bool is_stroke_start = (ma.x == -1 && x == -1);
- bool is_stroke_end = (ma3.x == -1 && x == 1);
-
- /* Mitter tangent vector. */
- vec2 miter_tan = safe_normalize(line_adj + line);
- float miter_dot = dot(miter_tan, line_adj);
- /* Break corners after a certain angle to avoid really thick corners. */
- const float miter_limit = 0.5; /* cos(60°) */
- bool miter_break = (miter_dot < miter_limit);
- miter_tan = (miter_break || is_stroke_start || is_stroke_end) ? line : (miter_tan / miter_dot);
-
- vec2 miter = rotate_90deg(miter_tan);
-
- strokePt1.xy = ss1;
- strokePt2.xy = ss2;
- strokeThickness = clampedThickness / gl_Position.w;
- unclampedThickness = thickness / gl_Position.w;
- strokeAspect = vec2(1.0);
-
- vec2 screen_ofs = miter * y;
-
- /* Reminder: we packed the cap flag into the sign of strength and thickness sign. */
- if ((is_stroke_start && strength1 > 0.0) || (is_stroke_end && thickness1 > 0.0) ||
- (miter_break && !is_stroke_start && !is_stroke_end)) {
- screen_ofs += line * x;
- }
-
- gl_Position.xy += screen_ofs * sizeViewportInv.xy * clampedThickness;
-
- finalUvs.x = (use_curr) ? uv1.z : uv2.z;
-# ifdef GP_MATERIAL_BUFFER_LEN
- finalUvs.x *= MATERIAL(m).stroke_u_scale;
-# endif
- }
-
-# ifdef GP_MATERIAL_BUFFER_LEN
- vec4 vert_col = (use_curr) ? col1 : col2;
- float vert_strength = abs((use_curr) ? strength1 : strength2);
- vec4 stroke_col = MATERIAL(m).stroke_color;
- float mix_tex = MATERIAL(m).stroke_texture_mix;
-
- /* Special case: We don't use vertex color if material Holdout. */
- if (GP_FLAG_TEST(GP_FLAG(m), GP_STROKE_HOLDOUT)) {
- vert_col = vec4(0.0);
- }
-
- color_output(stroke_col, vert_col, vert_strength, mix_tex);
-
- matFlag = GP_FLAG(m) & ~GP_FILL_FLAGS;
-# endif
-
- if (strokeOrder3d) {
- /* Use the fragment depth (see fragment shader). */
- depth = -1.0;
- }
-# ifdef GP_MATERIAL_BUFFER_LEN
- else if (GP_FLAG_TEST(GP_FLAG(m), GP_STROKE_OVERLAP)) {
- /* Use the index of the point as depth.
- * This means the stroke can overlap itself. */
- depth = (point_id1 + strokeIndexOffset + 1.0) * 0.0000002;
- }
-# endif
- else {
- /* Use the index of first point of the stroke as depth.
- * We render using a greater depth test this means the stroke
- * cannot overlap itself.
- * We offset by one so that the fill can be overlapped by its stroke.
- * The offset is ok since we pad the strokes data because of adjacency infos. */
- depth = (stroke_id1 + strokeIndexOffset + 1.0) * 0.0000002;
- }
-}
-
-void fill_vertex()
-{
- mat4 model_mat = model_matrix_get();
-
- vec3 wpos = transform_point(model_mat, pos1.xyz);
- gl_Position = point_world_to_ndc(wpos);
- finalPos = wpos;
-
-# ifdef GP_MATERIAL_BUFFER_LEN
- int m = ma1.x;
-
- vec4 fill_col = MATERIAL(m).fill_color;
- float mix_tex = MATERIAL(m).fill_texture_mix;
-
- /* Special case: We don't modulate alpha in gradient mode. */
- if (GP_FLAG_TEST(GP_FLAG(m), GP_FILL_GRADIENT_USE)) {
- fill_col.a = 1.0;
- }
-
- /* Decode fill opacity. */
- vec4 fcol_decode = vec4(fcol1.rgb, floor(fcol1.a / 10.0));
- float fill_opacity = fcol1.a - (fcol_decode.a * 10);
- fcol_decode.a /= 10000.0;
-
- /* Special case: We don't use vertex color if material Holdout. */
- if (GP_FLAG_TEST(GP_FLAG(m), GP_FILL_HOLDOUT)) {
- fcol_decode = vec4(0.0);
- }
-
- /* Apply opacity. */
- fill_col.a *= fill_opacity;
- /* If factor is > 1 force opacity. */
- if (fill_opacity > 1.0) {
- fill_col.a += fill_opacity - 1.0;
- }
-
- fill_col.a = clamp(fill_col.a, 0.0, 1.0);
-
- color_output(fill_col, fcol_decode, 1.0, mix_tex);
-
- matFlag = GP_FLAG(m) & GP_FILL_FLAGS;
- matFlag |= m << GP_MATID_SHIFT;
-
- vec2 loc = MATERIAL(m).fill_uv_offset.xy;
- mat2x2 rot_scale = mat2x2(MATERIAL(m).fill_uv_rot_scale.xy, MATERIAL(m).fill_uv_rot_scale.zw);
- finalUvs = rot_scale * uv1.xy + loc;
-# endif
-
- strokeHardeness = 1.0;
- strokeThickness = 1e18;
- unclampedThickness = 1e20;
- strokeAspect = vec2(1.0);
- strokePt1 = strokePt2 = vec2(0.0);
-
- if (strokeOrder3d) {
- /* Use the fragment depth (see fragment shader). */
- depth = -1.0;
- /* We still offset the fills a little to avoid overlaps */
- gl_Position.z += 0.000002;
- }
- else {
- /* Use the index of first point of the stroke as depth. */
- depth = (stroke_id1 + strokeIndexOffset) * 0.0000002;
- }
-}
-
-void gpencil_vertex()
-{
- /* Trick to detect if a drawcall is stroke or fill.
- * This does mean that we need to draw an empty stroke segment before starting
- * to draw the real stroke segments. */
- bool is_fill = (gl_InstanceID == 0);
-
- if (!is_fill) {
- stroke_vertex();
- }
- else {
- fill_vertex();
- }
-}
-
-#endif
diff --git a/source/blender/draw/engines/gpencil/shaders/gpencil_vert.glsl b/source/blender/draw/engines/gpencil/shaders/gpencil_vert.glsl
index 8ed03b23809..9b1db09ab3c 100644
--- a/source/blender/draw/engines/gpencil/shaders/gpencil_vert.glsl
+++ b/source/blender/draw/engines/gpencil/shaders/gpencil_vert.glsl
@@ -31,23 +31,11 @@ void main()
vec4 vert_color;
vec3 vert_N;
+ ivec4 ma1 = floatBitsToInt(texelFetch(gp_pos_tx, gpencil_stroke_point_id() * 3 + 1));
gpMaterial gp_mat = materials[ma1.x + gpMaterialOffset];
gpMaterialFlag gp_flag = floatBitsToUint(gp_mat._flag);
- gl_Position = gpencil_vertex(ma,
- ma1,
- ma2,
- ma3,
- pos,
- pos1,
- pos2,
- pos3,
- uv1,
- uv2,
- col1,
- col2,
- fcol1,
- vec4(viewportSize, 1.0 / viewportSize),
+ gl_Position = gpencil_vertex(vec4(viewportSize, 1.0 / viewportSize),
gp_flag,
gp_mat._alignment_rot,
gp_interp.pos,
@@ -60,7 +48,7 @@ void main()
gp_interp.thickness,
gp_interp.hardness);
- if (GPENCIL_IS_STROKE_VERTEX) {
+ if (gpencil_is_stroke_vertex()) {
if (!flag_test(gp_flag, GP_STROKE_ALIGNMENT)) {
gp_interp.uv.x *= gp_mat._stroke_u_scale;
}
@@ -96,6 +84,9 @@ void main()
}
}
else {
+ int stroke_point_id = gpencil_stroke_point_id();
+ vec4 uv1 = texelFetch(gp_col_tx, stroke_point_id * 2 + 2);
+ vec4 fcol1 = texelFetch(gp_col_tx, stroke_point_id * 2 + 1);
vec4 fill_col = gp_mat.fill_color;
/* Special case: We don't modulate alpha in gradient mode. */
diff --git a/source/blender/draw/engines/gpencil/shaders/infos/gpencil_info.hh b/source/blender/draw/engines/gpencil/shaders/infos/gpencil_info.hh
index edd51e71242..da2776254e6 100644
--- a/source/blender/draw/engines/gpencil/shaders/infos/gpencil_info.hh
+++ b/source/blender/draw/engines/gpencil/shaders/infos/gpencil_info.hh
@@ -22,10 +22,10 @@ GPU_SHADER_CREATE_INFO(gpencil_geometry)
.do_static_compilation(true)
.define("GP_LIGHT")
.typedef_source("gpencil_defines.h")
- .sampler(0, ImageType::FLOAT_2D, "gpFillTexture")
- .sampler(1, ImageType::FLOAT_2D, "gpStrokeTexture")
- .sampler(2, ImageType::DEPTH_2D, "gpSceneDepthTexture")
- .sampler(3, ImageType::FLOAT_2D, "gpMaskTexture")
+ .sampler(2, ImageType::FLOAT_2D, "gpFillTexture")
+ .sampler(3, ImageType::FLOAT_2D, "gpStrokeTexture")
+ .sampler(4, ImageType::DEPTH_2D, "gpSceneDepthTexture")
+ .sampler(5, ImageType::FLOAT_2D, "gpMaskTexture")
.uniform_buf(4, "gpMaterial", "materials[GPENCIL_MATERIAL_BUFFER_LEN]", Frequency::BATCH)
.uniform_buf(3, "gpLight", "lights[GPENCIL_LIGHT_BUFFER_LEN]", Frequency::BATCH)
.push_constant(Type::VEC2, "viewportSize")
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/overlay/overlay_outline.cc b/source/blender/draw/engines/overlay/overlay_outline.cc
index 5ea02376b67..50d42effe00 100644
--- a/source/blender/draw/engines/overlay/overlay_outline.cc
+++ b/source/blender/draw/engines/overlay/overlay_outline.cc
@@ -172,7 +172,6 @@ void OVERLAY_outline_cache_init(OVERLAY_Data *vedata)
typedef struct iterData {
Object *ob;
DRWShadingGroup *stroke_grp;
- DRWShadingGroup *fill_grp;
int cfra;
float plane[4];
} iterData;
@@ -193,12 +192,17 @@ static void gpencil_layer_cache_populate(bGPDlayer *gpl,
* Convert to world units (by default, 1 meter = 2000 pixels). */
float thickness_scale = (is_screenspace) ? -1.0f : (gpd->pixfactor / 2000.0f);
+ GPUVertBuf *position_tx = DRW_cache_gpencil_position_buffer_get(iter->ob, iter->cfra);
+ GPUVertBuf *color_tx = DRW_cache_gpencil_color_buffer_get(iter->ob, iter->cfra);
+
DRWShadingGroup *grp = iter->stroke_grp = DRW_shgroup_create_sub(iter->stroke_grp);
DRW_shgroup_uniform_bool_copy(grp, "gpStrokeOrder3d", is_stroke_order_3d);
DRW_shgroup_uniform_float_copy(grp, "gpThicknessScale", object_scale);
DRW_shgroup_uniform_float_copy(grp, "gpThicknessOffset", float(gpl->line_change));
DRW_shgroup_uniform_float_copy(grp, "gpThicknessWorldScale", thickness_scale);
DRW_shgroup_uniform_vec4_copy(grp, "gpDepthPlane", iter->plane);
+ DRW_shgroup_buffer_texture(grp, "gp_pos_tx", position_tx);
+ DRW_shgroup_buffer_texture(grp, "gp_col_tx", color_tx);
}
static void gpencil_stroke_cache_populate(bGPDlayer * /*gpl*/,
@@ -219,20 +223,19 @@ static void gpencil_stroke_cache_populate(bGPDlayer * /*gpl*/,
return;
}
+ struct GPUBatch *geom = DRW_cache_gpencil_get(iter->ob, iter->cfra);
+
if (show_fill) {
- struct GPUBatch *geom = DRW_cache_gpencil_fills_get(iter->ob, iter->cfra);
int vfirst = gps->runtime.fill_start * 3;
int vcount = gps->tot_triangles * 3;
- DRW_shgroup_call_range(iter->fill_grp, iter->ob, geom, vfirst, vcount);
+ DRW_shgroup_call_range(iter->stroke_grp, iter->ob, geom, vfirst, vcount);
}
if (show_stroke) {
- struct GPUBatch *geom = DRW_cache_gpencil_strokes_get(iter->ob, iter->cfra);
- /* Start one vert before to have gl_InstanceID > 0 (see shader). */
- int vfirst = gps->runtime.stroke_start - 1;
- /* Include "potential" cyclic vertex and start adj vertex (see shader). */
- int vcount = gps->totpoints + 1 + 1;
- DRW_shgroup_call_instance_range(iter->stroke_grp, iter->ob, geom, vfirst, vcount);
+ int vfirst = gps->runtime.stroke_start * 3;
+ /* Include "potential" cyclic vertex (see shader). */
+ int vcount = (gps->totpoints + 1) * 2 * 3;
+ DRW_shgroup_call_range(iter->stroke_grp, iter->ob, geom, vfirst, vcount);
}
}
@@ -247,7 +250,6 @@ static void OVERLAY_outline_gpencil(OVERLAY_PrivateData *pd, Object *ob)
iterData iter{};
iter.ob = ob;
iter.stroke_grp = pd->outlines_gpencil_grp;
- iter.fill_grp = DRW_shgroup_create_sub(pd->outlines_gpencil_grp);
iter.cfra = pd->cfra;
if (gpd->draw_mode == GP_DRAWMODE_2D) {
diff --git a/source/blender/draw/engines/overlay/overlay_particle.cc b/source/blender/draw/engines/overlay/overlay_particle.cc
index 6f77a777ba0..c9e3ccba008 100644
--- a/source/blender/draw/engines/overlay/overlay_particle.cc
+++ b/source/blender/draw/engines/overlay/overlay_particle.cc
@@ -181,14 +181,14 @@ void OVERLAY_particle_cache_populate(OVERLAY_Data *vedata, Object *ob)
default:
case PART_DRAW_DOT:
grp = DRW_shgroup_create_sub(pd->particle_dots_grp);
- DRW_shgroup_uniform_vec4_copy(grp, "color", color);
+ DRW_shgroup_uniform_vec4_copy(grp, "ucolor", color);
DRW_shgroup_call(grp, geom, nullptr);
break;
case PART_DRAW_AXIS:
case PART_DRAW_CIRC:
case PART_DRAW_CROSS:
grp = DRW_shgroup_create_sub(pd->particle_shapes_grp);
- DRW_shgroup_uniform_vec4_copy(grp, "color", color);
+ DRW_shgroup_uniform_vec4_copy(grp, "ucolor", color);
shape = DRW_cache_particles_get_prim(draw_as);
DRW_shgroup_call_instances_with_attrs(grp, nullptr, shape, geom);
break;
diff --git a/source/blender/draw/engines/overlay/shaders/overlay_motion_path_line_vert_no_geom.glsl b/source/blender/draw/engines/overlay/shaders/overlay_motion_path_line_vert_no_geom.glsl
index e3ddeb5c6a4..abaa814a4dc 100644
--- a/source/blender/draw/engines/overlay/shaders/overlay_motion_path_line_vert_no_geom.glsl
+++ b/source/blender/draw/engines/overlay/shaders/overlay_motion_path_line_vert_no_geom.glsl
@@ -108,8 +108,8 @@ void main()
vec3 in_pos0 = vertex_fetch_attribute(base_vertex_id, pos, vec3);
vec3 in_pos1 = vertex_fetch_attribute(base_vertex_id + 1, pos, vec3);
- vec4 out_pos0 = ProjectionMatrix * (ViewMatrix * vec4(in_pos0, 1.0));
- vec4 out_pos1 = ProjectionMatrix * (ViewMatrix * vec4(in_pos1, 1.0));
+ vec4 out_pos0 = drw_view.winmat * (drw_view.viewmat * vec4(in_pos0, 1.0));
+ vec4 out_pos1 = drw_view.winmat * (drw_view.viewmat * vec4(in_pos1, 1.0));
/* Final calculations required for Geometry Shader alternative.
* We need to calculate values for each vertex position to correctly determine the final output
@@ -130,28 +130,28 @@ void main()
float line_size = float(lineThickness) * sizePixel;
if (quad_vertex_id == 0) {
- view_clipping_distances(out_pos0);
+ view_clipping_distances(out_pos0.xyz);
interp.color = finalColor_geom[0];
t = edge_dir * (line_size * (is_persp ? out_pos0.w : 1.0));
gl_Position = out_pos0 + vec4(t, 0.0, 0.0);
}
else if (quad_vertex_id == 1 || quad_vertex_id == 3) {
- view_clipping_distances(out_pos0);
+ view_clipping_distances(out_pos0.xyz);
interp.color = finalColor_geom[0];
t = edge_dir * (line_size * (is_persp ? out_pos0.w : 1.0));
gl_Position = out_pos0 - vec4(t, 0.0, 0.0);
}
else if (quad_vertex_id == 2 || quad_vertex_id == 5) {
- view_clipping_distances(out_pos1);
+ view_clipping_distances(out_pos1.xyz);
interp.color = finalColor_geom[1];
t = edge_dir * (line_size * (is_persp ? out_pos1.w : 1.0));
gl_Position = out_pos1 + vec4(t, 0.0, 0.0);
}
else if (quad_vertex_id == 4) {
- view_clipping_distances(out_pos1);
+ view_clipping_distances(out_pos1.xyz);
interp.color = finalColor_geom[1];
t = edge_dir * (line_size * (is_persp ? out_pos1.w : 1.0));
diff --git a/source/blender/draw/engines/overlay/shaders/overlay_outline_prepass_gpencil_vert.glsl b/source/blender/draw/engines/overlay/shaders/overlay_outline_prepass_gpencil_vert.glsl
index 7d8fb0c2cb8..851e0884354 100644
--- a/source/blender/draw/engines/overlay/shaders/overlay_outline_prepass_gpencil_vert.glsl
+++ b/source/blender/draw/engines/overlay/shaders/overlay_outline_prepass_gpencil_vert.glsl
@@ -34,20 +34,7 @@ void main()
float unused_strength;
vec2 unused_uv;
- gl_Position = gpencil_vertex(ma,
- ma1,
- ma2,
- ma3,
- pos,
- pos1,
- pos2,
- pos3,
- uv1,
- uv2,
- col1,
- col2,
- fcol1,
- vec4(sizeViewport, sizeViewportInv),
+ gl_Position = gpencil_vertex(vec4(sizeViewport, sizeViewportInv),
world_pos,
unused_N,
unused_color,
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.h b/source/blender/draw/intern/draw_cache.h
index 058f28f094d..45154b41670 100644
--- a/source/blender/draw/intern/draw_cache.h
+++ b/source/blender/draw/intern/draw_cache.h
@@ -13,6 +13,7 @@ extern "C" {
struct GPUBatch;
struct GPUMaterial;
+struct GPUVertBuf;
struct ModifierData;
struct Object;
struct PTCacheEdit;
@@ -257,14 +258,17 @@ struct GPUBatch *DRW_cache_volume_selection_surface_get(struct Object *ob);
/* GPencil */
-struct GPUBatch *DRW_cache_gpencil_strokes_get(struct Object *ob, int cfra);
-struct GPUBatch *DRW_cache_gpencil_fills_get(struct Object *ob, int cfra);
+struct GPUBatch *DRW_cache_gpencil_get(struct Object *ob, int cfra);
+struct GPUVertBuf *DRW_cache_gpencil_position_buffer_get(struct Object *ob, int cfra);
+struct GPUVertBuf *DRW_cache_gpencil_color_buffer_get(struct Object *ob, int cfra);
struct GPUBatch *DRW_cache_gpencil_edit_lines_get(struct Object *ob, int cfra);
struct GPUBatch *DRW_cache_gpencil_edit_points_get(struct Object *ob, int cfra);
struct GPUBatch *DRW_cache_gpencil_edit_curve_handles_get(struct Object *ob, int cfra);
struct GPUBatch *DRW_cache_gpencil_edit_curve_points_get(struct Object *ob, int cfra);
-struct GPUBatch *DRW_cache_gpencil_sbuffer_stroke_get(struct Object *ob);
-struct GPUBatch *DRW_cache_gpencil_sbuffer_fill_get(struct Object *ob);
+struct GPUBatch *DRW_cache_gpencil_sbuffer_get(struct Object *ob, bool show_fill);
+struct GPUVertBuf *DRW_cache_gpencil_sbuffer_position_buffer_get(struct Object *ob,
+ bool show_fill);
+struct GPUVertBuf *DRW_cache_gpencil_sbuffer_color_buffer_get(struct Object *ob, bool show_fill);
int DRW_gpencil_material_count_get(struct bGPdata *gpd);
struct GPUBatch *DRW_cache_gpencil_face_wireframe_get(struct Object *ob);
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_gpencil.c b/source/blender/draw/intern/draw_cache_impl_gpencil.cc
index 7a43c7ee2e6..667ae380ae4 100644
--- a/source/blender/draw/intern/draw_cache_impl_gpencil.c
+++ b/source/blender/draw/intern/draw_cache_impl_gpencil.cc
@@ -23,12 +23,14 @@
#include "DEG_depsgraph_query.h"
#include "BLI_hash.h"
+#include "BLI_math_vec_types.hh"
#include "BLI_polyfill_2d.h"
#include "draw_cache.h"
#include "draw_cache_impl.h"
#include "../engines/gpencil/gpencil_defines.h"
+#include "../engines/gpencil/gpencil_shader_shared.h"
#define BEZIER_HANDLE (1 << 3)
#define COLOR_SHIFT 5
@@ -41,11 +43,13 @@ typedef struct GpencilBatchCache {
/** Instancing Data */
GPUVertBuf *vbo;
GPUVertBuf *vbo_col;
- /** Fill Topology */
+ /** Indices in material order, then stroke order with fill first.
+ * Strokes can be individually rendered using `gps->runtime.stroke_start` and
+ * `gps->runtime.fill_start`. */
GPUIndexBuf *ibo;
- /** Instancing Batches */
- GPUBatch *stroke_batch;
- GPUBatch *fill_batch;
+ /** Batches */
+ GPUBatch *geom_batch;
+ /** Stroke lines only */
GPUBatch *lines_batch;
/** Edit Mode */
@@ -97,7 +101,8 @@ static GpencilBatchCache *gpencil_batch_cache_init(Object *ob, int cfra)
GpencilBatchCache *cache = gpd->runtime.gpencil_cache;
if (!cache) {
- cache = gpd->runtime.gpencil_cache = MEM_callocN(sizeof(*cache), __func__);
+ cache = gpd->runtime.gpencil_cache = (GpencilBatchCache *)MEM_callocN(sizeof(*cache),
+ __func__);
}
else {
memset(cache, 0, sizeof(*cache));
@@ -116,8 +121,7 @@ static void gpencil_batch_cache_clear(GpencilBatchCache *cache)
}
GPU_BATCH_DISCARD_SAFE(cache->lines_batch);
- GPU_BATCH_DISCARD_SAFE(cache->fill_batch);
- GPU_BATCH_DISCARD_SAFE(cache->stroke_batch);
+ GPU_BATCH_DISCARD_SAFE(cache->geom_batch);
GPU_VERTBUF_DISCARD_SAFE(cache->vbo);
GPU_VERTBUF_DISCARD_SAFE(cache->vbo_col);
GPU_INDEXBUF_DISCARD_SAFE(cache->ibo);
@@ -172,9 +176,10 @@ void DRW_gpencil_batch_cache_free(bGPdata *gpd)
/* MUST match the format below. */
typedef struct gpStrokeVert {
- int32_t mat, stroke_id, point_id, packed_asp_hard_rot;
/** Position and thickness packed in the same attribute. */
float pos[3], thickness;
+ /** Material Index, Stroke Index, Point Index, Packed aspect + hardness + rotation. */
+ int32_t mat, stroke_id, point_id, packed_asp_hard_rot;
/** UV and strength packed in the same attribute. */
float uv_fill[2], u_stroke, strength;
} gpStrokeVert;
@@ -183,12 +188,9 @@ static GPUVertFormat *gpencil_stroke_format(void)
{
static GPUVertFormat format = {0};
if (format.attr_len == 0) {
- GPU_vertformat_attr_add(&format, "ma", GPU_COMP_I32, 4, GPU_FETCH_INT);
GPU_vertformat_attr_add(&format, "pos", GPU_COMP_F32, 4, GPU_FETCH_FLOAT);
+ GPU_vertformat_attr_add(&format, "ma", GPU_COMP_I32, 4, GPU_FETCH_INT);
GPU_vertformat_attr_add(&format, "uv", GPU_COMP_F32, 4, GPU_FETCH_FLOAT);
- /* IMPORTANT: This means having only 4 attributes
- * to fit into GPU module limit of 16 attributes. */
- GPU_vertformat_multiload_enable(&format, 4);
}
return &format;
}
@@ -238,9 +240,6 @@ static GPUVertFormat *gpencil_color_format(void)
if (format.attr_len == 0) {
GPU_vertformat_attr_add(&format, "col", GPU_COMP_F32, 4, GPU_FETCH_FLOAT);
GPU_vertformat_attr_add(&format, "fcol", GPU_COMP_F32, 4, GPU_FETCH_FLOAT);
- /* IMPORTANT: This means having only 4 attributes
- * to fit into GPU module limit of 16 attributes. */
- GPU_vertformat_multiload_enable(&format, 4);
}
return &format;
}
@@ -295,7 +294,8 @@ BLI_INLINE int32_t pack_rotation_aspect_hardness(float rot, float asp, float har
return packed;
}
-static void gpencil_buffer_add_point(gpStrokeVert *verts,
+static void gpencil_buffer_add_point(GPUIndexBufBuilder *ibo,
+ gpStrokeVert *verts,
gpColorVert *cols,
const bGPDstroke *gps,
const bGPDspoint *pt,
@@ -319,7 +319,7 @@ static void gpencil_buffer_add_point(gpStrokeVert *verts,
vert->strength = (round_cap0) ? pt->strength : -pt->strength;
vert->u_stroke = pt->uv_fac;
- vert->stroke_id = gps->runtime.stroke_start;
+ vert->stroke_id = gps->runtime.vertex_start;
vert->point_id = v;
vert->thickness = max_ff(0.0f, gps->thickness * pt->pressure) * (round_cap1 ? 1.0f : -1.0f);
/* Tag endpoint material to -1 so they get discarded by vertex shader. */
@@ -329,27 +329,36 @@ static void gpencil_buffer_add_point(gpStrokeVert *verts,
vert->packed_asp_hard_rot = pack_rotation_aspect_hardness(
pt->uv_rot, aspect_ratio, gps->hardeness);
+
+ if (!is_endpoint) {
+ /* Issue a Quad per point. */
+ /* The attribute loading uses a different shader and will undo this bit packing. */
+ int v_mat = (v << GP_VERTEX_ID_SHIFT) | GP_IS_STROKE_VERTEX_BIT;
+ GPU_indexbuf_add_tri_verts(ibo, v_mat + 0, v_mat + 1, v_mat + 2);
+ GPU_indexbuf_add_tri_verts(ibo, v_mat + 2, v_mat + 1, v_mat + 3);
+ }
}
-static void gpencil_buffer_add_stroke(gpStrokeVert *verts,
+static void gpencil_buffer_add_stroke(GPUIndexBufBuilder *ibo,
+ gpStrokeVert *verts,
gpColorVert *cols,
const bGPDstroke *gps)
{
const bGPDspoint *pts = gps->points;
int pts_len = gps->totpoints;
bool is_cyclic = gpencil_stroke_is_cyclic(gps);
- int v = gps->runtime.stroke_start;
+ int v = gps->runtime.vertex_start;
/* First point for adjacency (not drawn). */
int adj_idx = (is_cyclic) ? (pts_len - 1) : min_ii(pts_len - 1, 1);
- gpencil_buffer_add_point(verts, cols, gps, &pts[adj_idx], v++, true);
+ gpencil_buffer_add_point(ibo, verts, cols, gps, &pts[adj_idx], v++, true);
for (int i = 0; i < pts_len; i++) {
- gpencil_buffer_add_point(verts, cols, gps, &pts[i], v++, false);
+ gpencil_buffer_add_point(ibo, verts, cols, gps, &pts[i], v++, false);
}
/* Draw line to first point to complete the loop for cyclic strokes. */
if (is_cyclic) {
- gpencil_buffer_add_point(verts, cols, gps, &pts[0], v, false);
+ gpencil_buffer_add_point(ibo, verts, cols, gps, &pts[0], v, false);
/* UV factor needs to be adjusted for the last point to not be equal to the UV factor of the
* first point. It should be the factor of the last point plus the distance from the last point
* to the first.
@@ -360,16 +369,20 @@ static void gpencil_buffer_add_stroke(gpStrokeVert *verts,
}
/* Last adjacency point (not drawn). */
adj_idx = (is_cyclic) ? 1 : max_ii(0, pts_len - 2);
- gpencil_buffer_add_point(verts, cols, gps, &pts[adj_idx], v++, true);
+ gpencil_buffer_add_point(ibo, verts, cols, gps, &pts[adj_idx], v++, true);
}
static void gpencil_buffer_add_fill(GPUIndexBufBuilder *ibo, const bGPDstroke *gps)
{
int tri_len = gps->tot_triangles;
- int v = gps->runtime.stroke_start;
+ int v = gps->runtime.vertex_start + 1;
for (int i = 0; i < tri_len; i++) {
uint *tri = gps->triangles[i].verts;
- GPU_indexbuf_add_tri_verts(ibo, v + tri[0], v + tri[1], v + tri[2]);
+ /* The attribute loading uses a different shader and will undo this bit packing. */
+ GPU_indexbuf_add_tri_verts(ibo,
+ (v + tri[0]) << GP_VERTEX_ID_SHIFT,
+ (v + tri[1]) << GP_VERTEX_ID_SHIFT,
+ (v + tri[2]) << GP_VERTEX_ID_SHIFT);
}
}
@@ -379,10 +392,10 @@ static void gpencil_stroke_iter_cb(bGPDlayer *UNUSED(gpl),
void *thunk)
{
gpIterData *iter = (gpIterData *)thunk;
- gpencil_buffer_add_stroke(iter->verts, iter->cols, gps);
if (gps->tot_triangles > 0) {
gpencil_buffer_add_fill(&iter->ibo, gps);
}
+ gpencil_buffer_add_stroke(&iter->ibo, iter->verts, iter->cols, gps);
}
static void gpencil_object_verts_count_cb(bGPDlayer *UNUSED(gpl),
@@ -391,12 +404,15 @@ static void gpencil_object_verts_count_cb(bGPDlayer *UNUSED(gpl),
void *thunk)
{
gpIterData *iter = (gpIterData *)thunk;
-
- /* Store first index offset */
- gps->runtime.stroke_start = iter->vert_len;
+ int stroke_vert_len = gps->totpoints + gpencil_stroke_is_cyclic(gps);
+ gps->runtime.vertex_start = iter->vert_len;
+ /* Add additional padding at the start and end. */
+ iter->vert_len += 1 + stroke_vert_len + 1;
+ /* Store first index offset. */
gps->runtime.fill_start = iter->tri_len;
- iter->vert_len += gps->totpoints + 2 + gpencil_stroke_is_cyclic(gps);
iter->tri_len += gps->tot_triangles;
+ gps->runtime.stroke_start = iter->tri_len;
+ iter->tri_len += stroke_vert_len * 2;
}
static void gpencil_batches_ensure(Object *ob, GpencilBatchCache *cache, int cfra)
@@ -406,7 +422,7 @@ static void gpencil_batches_ensure(Object *ob, GpencilBatchCache *cache, int cfr
if (cache->vbo == NULL) {
/* Should be discarded together. */
BLI_assert(cache->vbo == NULL && cache->ibo == NULL);
- BLI_assert(cache->fill_batch == NULL && cache->stroke_batch == NULL);
+ BLI_assert(cache->geom_batch == NULL);
/* TODO/PERF: Could be changed to only do it if needed.
* For now it's simpler to assume we always need it
* since multiple viewport could or could not need it.
@@ -415,29 +431,29 @@ static void gpencil_batches_ensure(Object *ob, GpencilBatchCache *cache, int cfr
bool do_onion = true;
/* First count how many vertices and triangles are needed for the whole object. */
- gpIterData iter = {
- .gpd = gpd,
- .verts = NULL,
- .ibo = {0},
- .vert_len = 1, /* Start at 1 for the gl_InstanceID trick to work (see vert shader). */
- .tri_len = 0,
- .curve_len = 0,
- };
+ gpIterData iter = {};
+ iter.gpd = gpd;
+ iter.verts = NULL;
+ iter.ibo = {0};
+ iter.vert_len = 0;
+ iter.tri_len = 0;
+ iter.curve_len = 0;
BKE_gpencil_visible_stroke_advanced_iter(
NULL, ob, NULL, gpencil_object_verts_count_cb, &iter, do_onion, cfra);
+ GPUUsageType vbo_flag = GPU_USAGE_STATIC | GPU_USAGE_FLAG_BUFFER_TEXTURE_ONLY;
/* Create VBOs. */
GPUVertFormat *format = gpencil_stroke_format();
GPUVertFormat *format_col = gpencil_color_format();
- cache->vbo = GPU_vertbuf_create_with_format(format);
- cache->vbo_col = GPU_vertbuf_create_with_format(format_col);
+ cache->vbo = GPU_vertbuf_create_with_format_ex(format, vbo_flag);
+ cache->vbo_col = GPU_vertbuf_create_with_format_ex(format_col, vbo_flag);
/* Add extra space at the end of the buffer because of quad load. */
GPU_vertbuf_data_alloc(cache->vbo, iter.vert_len + 2);
GPU_vertbuf_data_alloc(cache->vbo_col, iter.vert_len + 2);
iter.verts = (gpStrokeVert *)GPU_vertbuf_get_data(cache->vbo);
iter.cols = (gpColorVert *)GPU_vertbuf_get_data(cache->vbo_col);
/* Create IBO. */
- GPU_indexbuf_init(&iter.ibo, GPU_PRIM_TRIS, iter.tri_len, iter.vert_len);
+ GPU_indexbuf_init(&iter.ibo, GPU_PRIM_TRIS, iter.tri_len, 0xFFFFFFFFu);
/* Fill buffers with data. */
BKE_gpencil_visible_stroke_advanced_iter(
@@ -452,33 +468,39 @@ static void gpencil_batches_ensure(Object *ob, GpencilBatchCache *cache, int cfr
/* Finish the IBO. */
cache->ibo = GPU_indexbuf_build(&iter.ibo);
-
/* Create the batches */
- cache->fill_batch = GPU_batch_create(GPU_PRIM_TRIS, cache->vbo, cache->ibo);
- GPU_batch_vertbuf_add(cache->fill_batch, cache->vbo_col);
- cache->stroke_batch = GPU_batch_create(GPU_PRIM_TRI_STRIP, gpencil_dummy_buffer_get(), NULL);
- GPU_batch_instbuf_add_ex(cache->stroke_batch, cache->vbo, 0);
- GPU_batch_instbuf_add_ex(cache->stroke_batch, cache->vbo_col, 0);
+ cache->geom_batch = GPU_batch_create(GPU_PRIM_TRIS, cache->vbo, cache->ibo);
+ /* Allow creation of buffer texture. */
+ GPU_vertbuf_use(cache->vbo);
+ GPU_vertbuf_use(cache->vbo_col);
gpd->flag &= ~GP_DATA_CACHE_IS_DIRTY;
cache->is_dirty = false;
}
}
-GPUBatch *DRW_cache_gpencil_strokes_get(Object *ob, int cfra)
+GPUBatch *DRW_cache_gpencil_get(Object *ob, int cfra)
+{
+ GpencilBatchCache *cache = gpencil_batch_cache_get(ob, cfra);
+ gpencil_batches_ensure(ob, cache, cfra);
+
+ return cache->geom_batch;
+}
+
+GPUVertBuf *DRW_cache_gpencil_position_buffer_get(Object *ob, int cfra)
{
GpencilBatchCache *cache = gpencil_batch_cache_get(ob, cfra);
gpencil_batches_ensure(ob, cache, cfra);
- return cache->stroke_batch;
+ return cache->vbo;
}
-GPUBatch *DRW_cache_gpencil_fills_get(Object *ob, int cfra)
+GPUVertBuf *DRW_cache_gpencil_color_buffer_get(Object *ob, int cfra)
{
GpencilBatchCache *cache = gpencil_batch_cache_get(ob, cfra);
gpencil_batches_ensure(ob, cache, cfra);
- return cache->fill_batch;
+ return cache->vbo_col;
}
static void gpencil_lines_indices_cb(bGPDlayer *UNUSED(gpl),
@@ -489,7 +511,7 @@ static void gpencil_lines_indices_cb(bGPDlayer *UNUSED(gpl),
gpIterData *iter = (gpIterData *)thunk;
int pts_len = gps->totpoints + gpencil_stroke_is_cyclic(gps);
- int start = gps->runtime.stroke_start + 1;
+ int start = gps->runtime.vertex_start + 1;
int end = start + pts_len;
for (int i = start; i < end; i++) {
GPU_indexbuf_add_generic_vert(&iter->ibo, i);
@@ -508,10 +530,9 @@ GPUBatch *DRW_cache_gpencil_face_wireframe_get(Object *ob)
if (cache->lines_batch == NULL) {
GPUVertBuf *vbo = cache->vbo;
- gpIterData iter = {
- .gpd = ob->data,
- .ibo = {0},
- };
+ gpIterData iter = {};
+ iter.gpd = (bGPdata *)ob->data;
+ iter.ibo = {0};
uint vert_len = GPU_vertbuf_get_vertex_len(vbo);
GPU_indexbuf_init_ex(&iter.ibo, GPU_PRIM_LINE_STRIP, vert_len, vert_len);
@@ -540,7 +561,7 @@ bGPDstroke *DRW_cache_gpencil_sbuffer_stroke_data_get(Object *ob)
Brush *brush = gpd->runtime.sbuffer_brush;
/* Convert the sbuffer to a bGPDstroke. */
if (gpd->runtime.sbuffer_gps == NULL) {
- bGPDstroke *gps = MEM_callocN(sizeof(*gps), "bGPDstroke sbuffer");
+ bGPDstroke *gps = (bGPDstroke *)MEM_callocN(sizeof(*gps), "bGPDstroke sbuffer");
gps->totpoints = gpd->runtime.sbuffer_used;
gps->mat_nr = max_ii(0, gpd->runtime.matid - 1);
gps->flag = gpd->runtime.sbuffer_sflag;
@@ -553,7 +574,9 @@ bGPDstroke *DRW_cache_gpencil_sbuffer_stroke_data_get(Object *ob)
gps->tot_triangles = max_ii(0, gpd->runtime.sbuffer_used - 2);
gps->caps[0] = gps->caps[1] = GP_STROKE_CAP_ROUND;
- gps->runtime.stroke_start = 1; /* Add one for the adjacency index. */
+ gps->runtime.vertex_start = 0;
+ gps->runtime.fill_start = 0;
+ gps->runtime.stroke_start = 0;
copy_v4_v4(gps->vert_color_fill, gpd->runtime.vert_color_fill);
/* Caps. */
gps->caps[0] = gps->caps[1] = (short)brush->gpencil_settings->caps_type;
@@ -563,17 +586,17 @@ bGPDstroke *DRW_cache_gpencil_sbuffer_stroke_data_get(Object *ob)
return gpd->runtime.sbuffer_gps;
}
-static void gpencil_sbuffer_stroke_ensure(bGPdata *gpd, bool do_stroke, bool do_fill)
+static void gpencil_sbuffer_stroke_ensure(bGPdata *gpd, bool do_fill)
{
- tGPspoint *tpoints = gpd->runtime.sbuffer;
+ tGPspoint *tpoints = (tGPspoint *)gpd->runtime.sbuffer;
bGPDstroke *gps = gpd->runtime.sbuffer_gps;
int vert_len = gpd->runtime.sbuffer_used;
/* DRW_cache_gpencil_sbuffer_stroke_data_get need to have been called previously. */
BLI_assert(gps != NULL);
- if (do_stroke && (gpd->runtime.sbuffer_stroke_batch == NULL)) {
- gps->points = MEM_mallocN(vert_len * sizeof(*gps->points), __func__);
+ if (gpd->runtime.sbuffer_batch == NULL) {
+ gps->points = (bGPDspoint *)MEM_mallocN(vert_len * sizeof(*gps->points), __func__);
const DRWContextState *draw_ctx = DRW_context_state_get();
Scene *scene = draw_ctx->scene;
@@ -596,36 +619,25 @@ static void gpencil_sbuffer_stroke_ensure(bGPdata *gpd, bool do_stroke, bool do_
/* Calc uv data along the stroke. */
BKE_gpencil_stroke_uv_update(gps);
+ int tri_len = gps->tot_triangles + (gps->totpoints + gpencil_stroke_is_cyclic(gps)) * 2;
+ /* Create IBO. */
+ GPUIndexBufBuilder ibo_builder;
+ GPU_indexbuf_init(&ibo_builder, GPU_PRIM_TRIS, tri_len, 0xFFFFFFFFu);
/* Create VBO. */
+ GPUUsageType vbo_flag = GPU_USAGE_STATIC | GPU_USAGE_FLAG_BUFFER_TEXTURE_ONLY;
GPUVertFormat *format = gpencil_stroke_format();
GPUVertFormat *format_color = gpencil_color_format();
- GPUVertBuf *vbo = GPU_vertbuf_create_with_format(format);
- GPUVertBuf *vbo_col = GPU_vertbuf_create_with_format(format_color);
- /* Add extra space at the end (and start) of the buffer because of quad load and cyclic. */
- GPU_vertbuf_data_alloc(vbo, 1 + vert_len + 1 + 2);
- GPU_vertbuf_data_alloc(vbo_col, 1 + vert_len + 1 + 2);
+ GPUVertBuf *vbo = GPU_vertbuf_create_with_format_ex(format, vbo_flag);
+ GPUVertBuf *vbo_col = GPU_vertbuf_create_with_format_ex(format_color, vbo_flag);
+ /* Add extra space at the end the buffer because of quad load and cyclic. */
+ GPU_vertbuf_data_alloc(vbo, vert_len + 2);
+ GPU_vertbuf_data_alloc(vbo_col, vert_len + 2);
gpStrokeVert *verts = (gpStrokeVert *)GPU_vertbuf_get_data(vbo);
gpColorVert *cols = (gpColorVert *)GPU_vertbuf_get_data(vbo_col);
- /* Fill buffers with data. */
- gpencil_buffer_add_stroke(verts, cols, gps);
-
- GPUBatch *batch = GPU_batch_create(GPU_PRIM_TRI_STRIP, gpencil_dummy_buffer_get(), NULL);
- GPU_batch_instbuf_add_ex(batch, vbo, true);
- GPU_batch_instbuf_add_ex(batch, vbo_col, true);
-
- gpd->runtime.sbuffer_stroke_batch = batch;
-
- MEM_freeN(gps->points);
- }
-
- if (do_fill && (gpd->runtime.sbuffer_fill_batch == NULL)) {
- /* Create IBO. */
- GPUIndexBufBuilder ibo_builder;
- GPU_indexbuf_init(&ibo_builder, GPU_PRIM_TRIS, gps->tot_triangles, vert_len);
-
- if (gps->tot_triangles > 0) {
- float(*tpoints2d)[2] = MEM_mallocN(sizeof(*tpoints2d) * vert_len, __func__);
+ /* Create fill indices. */
+ if (do_fill && gps->tot_triangles > 0) {
+ float(*tpoints2d)[2] = (float(*)[2])MEM_mallocN(sizeof(*tpoints2d) * vert_len, __func__);
/* Triangulate in 2D. */
for (int i = 0; i < vert_len; i++) {
copy_v2_v2(tpoints2d[i], tpoints[i].m_xy);
@@ -633,51 +645,72 @@ static void gpencil_sbuffer_stroke_ensure(bGPdata *gpd, bool do_stroke, bool do_
/* Compute directly inside the IBO data buffer. */
/* OPTI: This is a bottleneck if the stroke is very long. */
BLI_polyfill_calc(tpoints2d, (uint)vert_len, 0, (uint(*)[3])ibo_builder.data);
- /* Add stroke start offset. */
+ /* Add stroke start offset and shift. */
for (int i = 0; i < gps->tot_triangles * 3; i++) {
- ibo_builder.data[i] += gps->runtime.stroke_start;
+ ibo_builder.data[i] = (ibo_builder.data[i] + 1) << GP_VERTEX_ID_SHIFT;
}
/* HACK since we didn't use the builder API to avoid another malloc and copy,
* we need to set the number of indices manually. */
ibo_builder.index_len = gps->tot_triangles * 3;
+ ibo_builder.index_min = 0;
+ /* For this case, do not allow index compaction to avoid yet another preprocessing step. */
+ ibo_builder.index_max = 0xFFFFFFFFu - 1u;
+
+ gps->runtime.stroke_start = gps->tot_triangles;
MEM_freeN(tpoints2d);
}
- GPUIndexBuf *ibo = GPU_indexbuf_build(&ibo_builder);
- GPUVertBuf *vbo = gpd->runtime.sbuffer_stroke_batch->inst[0];
- GPUVertBuf *vbo_col = gpd->runtime.sbuffer_stroke_batch->inst[1];
+ /* Fill buffers with data. */
+ gpencil_buffer_add_stroke(&ibo_builder, verts, cols, gps);
- GPUBatch *batch = GPU_batch_create_ex(GPU_PRIM_TRIS, vbo, ibo, GPU_BATCH_OWNS_INDEX);
- GPU_batch_vertbuf_add(batch, vbo_col);
+ GPUBatch *batch = GPU_batch_create_ex(GPU_PRIM_TRIS,
+ gpencil_dummy_buffer_get(),
+ GPU_indexbuf_build(&ibo_builder),
+ GPU_BATCH_OWNS_INDEX);
- gpd->runtime.sbuffer_fill_batch = batch;
+ gpd->runtime.sbuffer_position_buf = vbo;
+ gpd->runtime.sbuffer_color_buf = vbo_col;
+ gpd->runtime.sbuffer_batch = batch;
+
+ MEM_freeN(gps->points);
}
}
-GPUBatch *DRW_cache_gpencil_sbuffer_stroke_get(Object *ob)
+GPUBatch *DRW_cache_gpencil_sbuffer_get(Object *ob, bool show_fill)
{
bGPdata *gpd = (bGPdata *)ob->data;
- gpencil_sbuffer_stroke_ensure(gpd, true, false);
+ /* Fill batch also need stroke batch to be created (vbo is shared). */
+ gpencil_sbuffer_stroke_ensure(gpd, show_fill);
- return gpd->runtime.sbuffer_stroke_batch;
+ return gpd->runtime.sbuffer_batch;
}
-GPUBatch *DRW_cache_gpencil_sbuffer_fill_get(Object *ob)
+GPUVertBuf *DRW_cache_gpencil_sbuffer_position_buffer_get(Object *ob, bool show_fill)
{
bGPdata *gpd = (bGPdata *)ob->data;
/* Fill batch also need stroke batch to be created (vbo is shared). */
- gpencil_sbuffer_stroke_ensure(gpd, true, true);
+ gpencil_sbuffer_stroke_ensure(gpd, show_fill);
- return gpd->runtime.sbuffer_fill_batch;
+ return gpd->runtime.sbuffer_position_buf;
+}
+
+GPUVertBuf *DRW_cache_gpencil_sbuffer_color_buffer_get(Object *ob, bool show_fill)
+{
+ bGPdata *gpd = (bGPdata *)ob->data;
+ /* Fill batch also need stroke batch to be created (vbo is shared). */
+ gpencil_sbuffer_stroke_ensure(gpd, show_fill);
+
+ return gpd->runtime.sbuffer_color_buf;
}
void DRW_cache_gpencil_sbuffer_clear(Object *ob)
{
bGPdata *gpd = (bGPdata *)ob->data;
MEM_SAFE_FREE(gpd->runtime.sbuffer_gps);
- GPU_BATCH_DISCARD_SAFE(gpd->runtime.sbuffer_fill_batch);
- GPU_BATCH_DISCARD_SAFE(gpd->runtime.sbuffer_stroke_batch);
+ GPU_BATCH_DISCARD_SAFE(gpd->runtime.sbuffer_batch);
+ GPU_VERTBUF_DISCARD_SAFE(gpd->runtime.sbuffer_position_buf);
+ GPU_VERTBUF_DISCARD_SAFE(gpd->runtime.sbuffer_color_buf);
}
/** \} */
@@ -728,7 +761,7 @@ static void gpencil_edit_stroke_iter_cb(bGPDlayer *gpl,
{
gpEditIterData *iter = (gpEditIterData *)thunk;
const int v_len = gps->totpoints;
- const int v = gps->runtime.stroke_start + 1;
+ const int v = gps->runtime.vertex_start + 1;
MDeformVert *dvert = ((iter->vgindex > -1) && gps->dvert) ? gps->dvert : NULL;
gpEditVert *vert_ptr = iter->verts + v;
@@ -743,9 +776,12 @@ static void gpencil_edit_stroke_iter_cb(bGPDlayer *gpl,
vert_ptr->weight = gpencil_point_edit_weight(dvert, i, iter->vgindex);
vert_ptr++;
}
- /* Draw line to first point to complete the loop for cyclic strokes. */
- vert_ptr->vflag = sflag | gpencil_point_edit_flag(layer_lock, &gps->points[0], 0, v_len);
- vert_ptr->weight = gpencil_point_edit_weight(dvert, 0, iter->vgindex);
+
+ if (gpencil_stroke_is_cyclic(gps)) {
+ /* Draw line to first point to complete the loop for cyclic strokes. */
+ vert_ptr->vflag = sflag | gpencil_point_edit_flag(layer_lock, &gps->points[0], 0, v_len);
+ vert_ptr->weight = gpencil_point_edit_weight(dvert, 0, iter->vgindex);
+ }
}
static void gpencil_edit_curve_stroke_count_cb(bGPDlayer *gpl,
@@ -876,14 +912,13 @@ static void gpencil_edit_batches_ensure(Object *ob, GpencilBatchCache *cache, in
/* Curve Handles and Points for Editing. */
if (cache->edit_curve_vbo == NULL) {
- gpIterData iterdata = {
- .gpd = gpd,
- .verts = NULL,
- .ibo = {0},
- .vert_len = 0,
- .tri_len = 0,
- .curve_len = 0,
- };
+ gpIterData iterdata = {};
+ iterdata.gpd = gpd;
+ iterdata.verts = NULL;
+ iterdata.ibo = {0};
+ iterdata.vert_len = 0;
+ iterdata.tri_len = 0;
+ iterdata.curve_len = 0;
/* Create VBO. */
GPUVertFormat *format = gpencil_edit_curve_format();
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_curves.cc b/source/blender/draw/intern/draw_curves.cc
index a61769e7a63..8847e3f6016 100644
--- a/source/blender/draw/intern/draw_curves.cc
+++ b/source/blender/draw/intern/draw_curves.cc
@@ -394,6 +394,11 @@ DRWShadingGroup *DRW_shgroup_curves_create_sub(Object *object,
DRW_shgroup_uniform_float_copy(shgrp, "hairRadRoot", hair_rad_root);
DRW_shgroup_uniform_float_copy(shgrp, "hairRadTip", hair_rad_tip);
DRW_shgroup_uniform_bool_copy(shgrp, "hairCloseTip", hair_close_tip);
+ if (gpu_material) {
+ /* \note: This needs to happen before the drawcall to allow correct attribute extraction.
+ * (see T101896) */
+ DRW_shgroup_add_material_resources(shgrp, gpu_material);
+ }
/* TODO(fclem): Until we have a better way to cull the curves and render with orco, bypass
* culling test. */
GPUBatch *geom = curves_cache->final[subdiv].proc_hairs[thickness_res - 1];
diff --git a/source/blender/draw/intern/draw_debug.cc b/source/blender/draw/intern/draw_debug.cc
index a78dc59cb7e..55de779d85c 100644
--- a/source/blender/draw/intern/draw_debug.cc
+++ b/source/blender/draw/intern/draw_debug.cc
@@ -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_hair.cc b/source/blender/draw/intern/draw_hair.cc
index 4e44967e5e9..281e58ea230 100644
--- a/source/blender/draw/intern/draw_hair.cc
+++ b/source/blender/draw/intern/draw_hair.cc
@@ -293,6 +293,11 @@ DRWShadingGroup *DRW_shgroup_hair_create_sub(Object *object,
DRW_shgroup_uniform_float_copy(shgrp, "hairRadRoot", hair_rad_root);
DRW_shgroup_uniform_float_copy(shgrp, "hairRadTip", hair_rad_tip);
DRW_shgroup_uniform_bool_copy(shgrp, "hairCloseTip", hair_close_tip);
+ if (gpu_material) {
+ /* \note: This needs to happen before the drawcall to allow correct attribute extraction.
+ * (see T101896) */
+ DRW_shgroup_add_material_resources(shgrp, gpu_material);
+ }
/* TODO(fclem): Until we have a better way to cull the hair and render with orco, bypass
* culling test. */
GPUBatch *geom = hair_cache->final[subdiv].proc_hairs[thickness_res - 1];
diff --git a/source/blender/draw/intern/draw_manager.c b/source/blender/draw/intern/draw_manager.c
index 28abbc6ab71..b9a9780e651 100644
--- a/source/blender/draw/intern/draw_manager.c
+++ b/source/blender/draw/intern/draw_manager.c
@@ -422,7 +422,8 @@ static void draw_prune_vlattrs(DRWData *drw_data)
/* 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, (void *)attr->hash_code, NULL, NULL);
+ BLI_ghash_remove(
+ drw_data->vlattrs_name_cache, POINTER_FROM_UINT(attr->hash_code), NULL, NULL);
BLI_freelinkN(&drw_data->vlattrs_name_list, attr);
}
}
@@ -1958,20 +1959,6 @@ void DRW_render_gpencil(struct RenderEngine *engine, struct Depsgraph *depsgraph
DST.buffer_finish_called = false;
}
-/* Callback function for RE_engine_update_render_passes to ensure all
- * render passes are registered. */
-static void draw_render_result_ensure_pass_cb(void *user_data,
- struct Scene *UNUSED(scene),
- struct ViewLayer *view_layer,
- const char *name,
- int channels,
- const char *chanid,
- eNodeSocketDatatype UNUSED(type))
-{
- RenderEngine *engine = user_data;
- RE_engine_add_pass(engine, name, channels, chanid, view_layer->name);
-}
-
void DRW_render_to_image(RenderEngine *engine, struct Depsgraph *depsgraph)
{
Scene *scene = DEG_get_evaluated_scene(depsgraph);
@@ -2022,10 +2009,6 @@ void DRW_render_to_image(RenderEngine *engine, struct Depsgraph *depsgraph)
/* set default viewport */
GPU_viewport(0, 0, size[0], size[1]);
- /* Update the render passes. This needs to be done before acquiring the render result. */
- RE_engine_update_render_passes(
- engine, scene, view_layer, draw_render_result_ensure_pass_cb, engine);
-
/* Init render result. */
RenderResult *render_result = RE_engine_begin_result(engine,
0,
diff --git a/source/blender/draw/intern/draw_manager.h b/source/blender/draw/intern/draw_manager.h
index ce316a31cf9..52129049269 100644
--- a/source/blender/draw/intern/draw_manager.h
+++ b/source/blender/draw/intern/draw_manager.h
@@ -697,7 +697,7 @@ void drw_uniform_attrs_pool_update(struct GHash *table,
struct Object *dupli_parent,
struct DupliObject *dupli_source);
-GPUUniformBuf *drw_ensure_layer_attribute_buffer();
+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);
diff --git a/source/blender/draw/intern/draw_manager_data.cc b/source/blender/draw/intern/draw_manager_data.cc
index 030b13177f1..b9e0db71122 100644
--- a/source/blender/draw/intern/draw_manager_data.cc
+++ b/source/blender/draw/intern/draw_manager_data.cc
@@ -589,7 +589,7 @@ void DRW_shgroup_buffer_texture(DRWShadingGroup *shgroup,
const char *name,
GPUVertBuf *vertex_buffer)
{
- int location = GPU_shader_get_ssbo(shgroup->shader, name);
+ int location = GPU_shader_get_texture_binding(shgroup->shader, name);
if (location == -1) {
return;
}
@@ -606,7 +606,7 @@ void DRW_shgroup_buffer_texture_ref(DRWShadingGroup *shgroup,
const char *name,
GPUVertBuf **vertex_buffer)
{
- int location = GPU_shader_get_ssbo(shgroup->shader, name);
+ int location = GPU_shader_get_texture_binding(shgroup->shader, name);
if (location == -1) {
return;
}
@@ -1347,7 +1347,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,
@@ -1714,23 +1714,32 @@ static void drw_shgroup_init(DRWShadingGroup *shgroup, GPUShader *shader)
}
#ifdef DEBUG
- int debug_print_location = GPU_shader_get_builtin_ssbo(shader, GPU_STORAGE_BUFFER_DEBUG_PRINT);
- if (debug_print_location != -1) {
- GPUStorageBuf *buf = drw_debug_gpu_print_buf_get();
- drw_shgroup_uniform_create_ex(
- shgroup, debug_print_location, DRW_UNIFORM_STORAGE_BLOCK, buf, GPU_SAMPLER_DEFAULT, 0, 1);
+ /* TODO(Metal): Support Shader debug print.
+ * This is not currently supported by Metal Backend. */
+ if (GPU_backend_get_type() != GPU_BACKEND_METAL) {
+ int debug_print_location = GPU_shader_get_builtin_ssbo(shader, GPU_STORAGE_BUFFER_DEBUG_PRINT);
+ if (debug_print_location != -1) {
+ GPUStorageBuf *buf = drw_debug_gpu_print_buf_get();
+ drw_shgroup_uniform_create_ex(shgroup,
+ debug_print_location,
+ DRW_UNIFORM_STORAGE_BLOCK,
+ buf,
+ GPU_SAMPLER_DEFAULT,
+ 0,
+ 1);
# ifndef DISABLE_DEBUG_SHADER_PRINT_BARRIER
- /* Add a barrier to allow multiple shader writing to the same buffer. */
- DRW_shgroup_barrier(shgroup, GPU_BARRIER_SHADER_STORAGE);
+ /* Add a barrier to allow multiple shader writing to the same buffer. */
+ DRW_shgroup_barrier(shgroup, GPU_BARRIER_SHADER_STORAGE);
# endif
- }
+ }
- int debug_draw_location = GPU_shader_get_builtin_ssbo(shader, GPU_STORAGE_BUFFER_DEBUG_VERTS);
- if (debug_draw_location != -1) {
- GPUStorageBuf *buf = drw_debug_gpu_draw_buf_get();
- drw_shgroup_uniform_create_ex(
- shgroup, debug_draw_location, DRW_UNIFORM_STORAGE_BLOCK, buf, GPU_SAMPLER_DEFAULT, 0, 1);
- /* NOTE(fclem): No barrier as ordering is not important. */
+ int debug_draw_location = GPU_shader_get_builtin_ssbo(shader, GPU_STORAGE_BUFFER_DEBUG_VERTS);
+ if (debug_draw_location != -1) {
+ GPUStorageBuf *buf = drw_debug_gpu_draw_buf_get();
+ drw_shgroup_uniform_create_ex(
+ shgroup, debug_draw_location, DRW_UNIFORM_STORAGE_BLOCK, buf, GPU_SAMPLER_DEFAULT, 0, 1);
+ /* NOTE(fclem): No barrier as ordering is not important. */
+ }
}
#endif
diff --git a/source/blender/draw/intern/draw_manager_shader.c b/source/blender/draw/intern/draw_manager_shader.c
index 8b287e116bc..40b05dff51f 100644
--- a/source/blender/draw/intern/draw_manager_shader.c
+++ b/source/blender/draw/intern/draw_manager_shader.c
@@ -252,7 +252,7 @@ static void drw_register_shader_vlattrs(GPUMaterial *mat)
GPULayerAttr **p_val;
/* Add to the table and list if newly seen. */
- if (!BLI_ghash_ensure_p(hash, (void *)attr->hash_code, (void ***)&p_val)) {
+ 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);
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..38fb6d55245 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_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/common_gpencil_lib.glsl b/source/blender/draw/intern/shaders/common_gpencil_lib.glsl
index 123c493b572..def841b07aa 100644
--- a/source/blender/draw/intern/shaders/common_gpencil_lib.glsl
+++ b/source/blender/draw/intern/shaders/common_gpencil_lib.glsl
@@ -90,10 +90,15 @@ float gpencil_clamp_small_stroke_thickness(float thickness, vec4 ndc_pos)
#ifdef GPU_VERTEX_SHADER
-/* Trick to detect if a drawcall is stroke or fill.
- * This does mean that we need to draw an empty stroke segment before starting
- * to draw the real stroke segments. */
-# define GPENCIL_IS_STROKE_VERTEX (gl_InstanceID != 0)
+int gpencil_stroke_point_id()
+{
+ return (gl_VertexID & ~GP_IS_STROKE_VERTEX_BIT) >> GP_VERTEX_ID_SHIFT;
+}
+
+bool gpencil_is_stroke_vertex()
+{
+ return flag_test(gl_VertexID, GP_IS_STROKE_VERTEX_BIT);
+}
/**
* Returns value of gl_Position.
@@ -120,20 +125,7 @@ float gpencil_clamp_small_stroke_thickness(float thickness, vec4 ndc_pos)
* WARNING: Max attribute count is actually 14 because OSX OpenGL implementation
* considers gl_VertexID and gl_InstanceID as vertex attribute. (see T74536)
*/
-vec4 gpencil_vertex(ivec4 ma,
- ivec4 ma1,
- ivec4 ma2,
- ivec4 ma3,
- vec4 pos,
- vec4 pos1,
- vec4 pos2,
- vec4 pos3,
- vec4 uv1,
- vec4 uv2,
- vec4 col1,
- vec4 col2,
- vec4 fcol1,
- vec4 viewport_size,
+vec4 gpencil_vertex(vec4 viewport_size,
gpMaterialFlag material_flags,
vec2 alignment_rot,
/* World Position. */
@@ -155,6 +147,24 @@ vec4 gpencil_vertex(ivec4 ma,
/* Stroke hardness. */
out float out_hardness)
{
+ int stroke_point_id = (gl_VertexID & ~GP_IS_STROKE_VERTEX_BIT) >> GP_VERTEX_ID_SHIFT;
+
+ /* Attribute Loading. */
+ vec4 pos = texelFetch(gp_pos_tx, (stroke_point_id - 1) * 3 + 0);
+ vec4 pos1 = texelFetch(gp_pos_tx, (stroke_point_id + 0) * 3 + 0);
+ vec4 pos2 = texelFetch(gp_pos_tx, (stroke_point_id + 1) * 3 + 0);
+ vec4 pos3 = texelFetch(gp_pos_tx, (stroke_point_id + 2) * 3 + 0);
+ ivec4 ma = floatBitsToInt(texelFetch(gp_pos_tx, (stroke_point_id - 1) * 3 + 1));
+ ivec4 ma1 = floatBitsToInt(texelFetch(gp_pos_tx, (stroke_point_id + 0) * 3 + 1));
+ ivec4 ma2 = floatBitsToInt(texelFetch(gp_pos_tx, (stroke_point_id + 1) * 3 + 1));
+ ivec4 ma3 = floatBitsToInt(texelFetch(gp_pos_tx, (stroke_point_id + 2) * 3 + 1));
+ vec4 uv1 = texelFetch(gp_pos_tx, (stroke_point_id + 0) * 3 + 2);
+ vec4 uv2 = texelFetch(gp_pos_tx, (stroke_point_id + 1) * 3 + 2);
+
+ vec4 col1 = texelFetch(gp_col_tx, (stroke_point_id + 0) * 2 + 0);
+ vec4 col2 = texelFetch(gp_col_tx, (stroke_point_id + 1) * 2 + 0);
+ vec4 fcol1 = texelFetch(gp_col_tx, (stroke_point_id + 0) * 2 + 1);
+
# define thickness1 pos1.w
# define thickness2 pos2.w
# define strength1 uv1.w
@@ -167,7 +177,7 @@ vec4 gpencil_vertex(ivec4 ma,
vec4 out_ndc;
- if (GPENCIL_IS_STROKE_VERTEX) {
+ if (gpencil_is_stroke_vertex()) {
bool is_dot = flag_test(material_flags, GP_STROKE_ALIGNMENT);
bool is_squares = !flag_test(material_flags, GP_STROKE_DOTS);
@@ -177,13 +187,6 @@ vec4 gpencil_vertex(ivec4 ma,
is_squares = false;
}
- /* Endpoints, we discard the vertices. */
- if (ma1.x == -1 || (!is_dot && ma2.x == -1)) {
- /* We set the vertex at the camera origin to generate 0 fragments. */
- out_ndc = vec4(0.0, 0.0, -3e36, 0.0);
- return out_ndc;
- }
-
/* Avoid using a vertex attribute for quad positioning. */
float x = float(gl_VertexID & 1) * 2.0 - 1.0; /* [-1..1] */
float y = float(gl_VertexID & 2) - 1.0; /* [-1..1] */
@@ -336,8 +339,7 @@ vec4 gpencil_vertex(ivec4 ma,
out_N = safe_normalize(N);
/* Decode fill opacity. */
- out_color = vec4(fcol1.rgb, floor(fcol1.a / 10.0));
- out_color.a /= 10000.0;
+ out_color = vec4(fcol1.rgb, floor(fcol1.a / 10.0) / 10000.0);
/* We still offset the fills a little to avoid overlaps */
out_ndc.z += 0.000002;
@@ -355,20 +357,7 @@ vec4 gpencil_vertex(ivec4 ma,
return out_ndc;
}
-vec4 gpencil_vertex(ivec4 ma,
- ivec4 ma1,
- ivec4 ma2,
- ivec4 ma3,
- vec4 pos,
- vec4 pos1,
- vec4 pos2,
- vec4 pos3,
- vec4 uv1,
- vec4 uv2,
- vec4 col1,
- vec4 col2,
- vec4 fcol1,
- vec4 viewport_size,
+vec4 gpencil_vertex(vec4 viewport_size,
out vec3 out_P,
out vec3 out_N,
out vec4 out_color,
@@ -379,20 +368,7 @@ vec4 gpencil_vertex(ivec4 ma,
out vec2 out_thickness,
out float out_hardness)
{
- return gpencil_vertex(ma,
- ma1,
- ma2,
- ma3,
- pos,
- pos1,
- pos2,
- pos3,
- uv1,
- uv2,
- col1,
- col2,
- fcol1,
- viewport_size,
+ return gpencil_vertex(viewport_size,
0u,
vec2(1.0, 0.0),
out_P,
diff --git a/source/blender/draw/intern/shaders/draw_view_info.hh b/source/blender/draw/intern/shaders/draw_view_info.hh
index 7b500f66a68..114dbab799f 100644
--- a/source/blender/draw/intern/shaders/draw_view_info.hh
+++ b/source/blender/draw/intern/shaders/draw_view_info.hh
@@ -122,26 +122,15 @@ GPU_SHADER_CREATE_INFO(draw_volume).additional_info("draw_modelmat", "draw_resou
GPU_SHADER_CREATE_INFO(draw_gpencil)
.typedef_source("gpencil_shader_shared.h")
.define("DRW_GPENCIL_INFO")
- .vertex_in(0, Type::IVEC4, "ma")
- .vertex_in(1, Type::IVEC4, "ma1")
- .vertex_in(2, Type::IVEC4, "ma2")
- .vertex_in(3, Type::IVEC4, "ma3")
- .vertex_in(4, Type::VEC4, "pos")
- .vertex_in(5, Type::VEC4, "pos1")
- .vertex_in(6, Type::VEC4, "pos2")
- .vertex_in(7, Type::VEC4, "pos3")
- .vertex_in(8, Type::VEC4, "uv1")
- .vertex_in(9, Type::VEC4, "uv2")
- .vertex_in(10, Type::VEC4, "col1")
- .vertex_in(11, Type::VEC4, "col2")
- .vertex_in(12, Type::VEC4, "fcol1")
+ .sampler(0, ImageType::FLOAT_BUFFER, "gp_pos_tx")
+ .sampler(1, ImageType::FLOAT_BUFFER, "gp_col_tx")
/* Per Object */
.push_constant(Type::FLOAT, "gpThicknessScale") /* TODO(fclem): Replace with object info. */
.push_constant(Type::FLOAT, "gpThicknessWorldScale") /* TODO(fclem): Same as above. */
.define("gpThicknessIsScreenSpace", "(gpThicknessWorldScale < 0.0)")
/* Per Layer */
.push_constant(Type::FLOAT, "gpThicknessOffset")
- .additional_info("draw_modelmat", "draw_resource_id_uniform", "draw_object_infos");
+ .additional_info("draw_modelmat", "draw_object_infos");
/** \} */
diff --git a/source/blender/editors/armature/pose_transform.c b/source/blender/editors/armature/pose_transform.c
index 2a23615caa3..9ed963f0c66 100644
--- a/source/blender/editors/armature/pose_transform.c
+++ b/source/blender/editors/armature/pose_transform.c
@@ -788,7 +788,7 @@ static int pose_copy_exec(bContext *C, wmOperator *op)
* existing on its own.
*/
BKE_copybuffer_copy_tag_ID(&ob_copy.id);
- BLI_join_dirfile(str, sizeof(str), BKE_tempdir_base(), "copybuffer_pose.blend");
+ BLI_path_join(str, sizeof(str), BKE_tempdir_base(), "copybuffer_pose.blend");
BKE_copybuffer_copy_end(temp_bmain, str, op->reports);
/* We clear the lists so no datablocks gets freed,
* This is required because objects in temp bmain shares same pointers
@@ -844,7 +844,7 @@ static int pose_paste_exec(bContext *C, wmOperator *op)
Main *tmp_bmain = BKE_main_new();
STRNCPY(tmp_bmain->filepath, BKE_main_blendfile_path_from_global());
- BLI_join_dirfile(str, sizeof(str), BKE_tempdir_base(), "copybuffer_pose.blend");
+ BLI_path_join(str, sizeof(str), BKE_tempdir_base(), "copybuffer_pose.blend");
if (!BKE_copybuffer_read(tmp_bmain, str, op->reports, FILTER_ID_OB)) {
BKE_report(op->reports, RPT_ERROR, "Copy buffer is empty");
BKE_main_free(tmp_bmain);
diff --git a/source/blender/editors/asset/intern/asset_list.cc b/source/blender/editors/asset/intern/asset_list.cc
index b0ff5c86520..7fdb924d769 100644
--- a/source/blender/editors/asset/intern/asset_list.cc
+++ b/source/blender/editors/asset/intern/asset_list.cc
@@ -488,7 +488,7 @@ std::string ED_assetlist_asset_filepath_get(const bContext *C,
const char *asset_relpath = asset_handle.file_data->relpath;
char path[FILE_MAX_LIBEXTRA];
- BLI_join_dirfile(path, sizeof(path), library_path, asset_relpath);
+ BLI_path_join(path, sizeof(path), library_path, asset_relpath);
return path;
}
diff --git a/source/blender/editors/asset/intern/asset_ops.cc b/source/blender/editors/asset/intern/asset_ops.cc
index 08259090e0c..d1c46a8259f 100644
--- a/source/blender/editors/asset/intern/asset_ops.cc
+++ b/source/blender/editors/asset/intern/asset_ops.cc
@@ -860,7 +860,7 @@ static bool set_filepath_for_asset_lib(const Main *bmain, struct wmOperator *op)
}
char file_path[PATH_MAX];
- BLI_join_dirfile(file_path, sizeof(file_path), lib->path, blend_filename);
+ BLI_path_join(file_path, sizeof(file_path), lib->path, blend_filename);
RNA_string_set(op->ptr, "filepath", file_path);
return true;
diff --git a/source/blender/editors/gpencil/annotate_paint.c b/source/blender/editors/gpencil/annotate_paint.c
index 677bf1bb392..2fd58a9cee0 100644
--- a/source/blender/editors/gpencil/annotate_paint.c
+++ b/source/blender/editors/gpencil/annotate_paint.c
@@ -13,9 +13,6 @@
#include "MEM_guardedalloc.h"
-#include "BLI_blenlib.h"
-#include "BLI_math.h"
-#include "BLI_math_geom.h"
#include "BLI_utildefines.h"
#include "BLT_translation.h"
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..b97cd6a9099 100644
--- a/source/blender/editors/include/ED_uvedit.h
+++ b/source/blender/editors/include/ED_uvedit.h
@@ -339,12 +339,22 @@ 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;
+
+/** See also #UnwrapOptions. */
struct UVPackIsland_Params {
uint rotate : 1;
uint only_selected_uvs : 1;
uint only_selected_faces : 1;
uint use_seams : 1;
uint correct_aspect : 1;
+ bool ignore_pinned; /* Ignore islands which have any pinned UVs. */
+ eUVPackIsland_MarginMethod margin_method; /* Which formula to use when scaling island margin. */
+ float margin; /* Additional space to add around each island. */
};
/**
@@ -353,9 +363,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_interface.h b/source/blender/editors/include/UI_interface.h
index 2a1941f0d9e..7e9422ff867 100644
--- a/source/blender/editors/include/UI_interface.h
+++ b/source/blender/editors/include/UI_interface.h
@@ -1683,6 +1683,7 @@ int UI_search_items_find_index(uiSearchItems *items, const char *name);
* Adds a hint to the button which draws right aligned, grayed out and never clipped.
*/
void UI_but_hint_drawstr_set(uiBut *but, const char *string);
+void UI_but_icon_indicator_number_set(uiBut *but, const int indicator_number);
void UI_but_node_link_set(uiBut *but, struct bNodeSocket *socket, const float draw_color[4]);
@@ -2788,7 +2789,8 @@ typedef struct uiPropertySplitWrapper {
uiPropertySplitWrapper uiItemPropertySplitWrapperCreate(uiLayout *parent_layout);
void uiItemL(uiLayout *layout, const char *name, int icon); /* label */
-void uiItemL_ex(uiLayout *layout, const char *name, int icon, bool highlight, bool redalert);
+struct uiBut *uiItemL_ex(
+ uiLayout *layout, const char *name, int icon, bool highlight, bool redalert);
/**
* Helper to add a label and creates a property split layout if needed.
*/
diff --git a/source/blender/editors/include/UI_interface.hh b/source/blender/editors/include/UI_interface.hh
index 6c756984203..fc03b0218c0 100644
--- a/source/blender/editors/include/UI_interface.hh
+++ b/source/blender/editors/include/UI_interface.hh
@@ -35,6 +35,7 @@ struct ContextPathItem {
std::string name;
/* #BIFIconID */
int icon;
+ int icon_indicator_number;
};
void context_path_add_generic(Vector<ContextPathItem> &path,
diff --git a/source/blender/editors/include/UI_interface_icons.h b/source/blender/editors/include/UI_interface_icons.h
index a1a98a4b08c..9669e242dac 100644
--- a/source/blender/editors/include/UI_interface_icons.h
+++ b/source/blender/editors/include/UI_interface_icons.h
@@ -27,6 +27,12 @@ typedef struct IconFile {
int index;
} IconFile;
+typedef struct IconTextOverlay {
+ char text[5];
+} IconTextOverlay;
+
+#define UI_NO_ICON_OVERLAY_TEXT NULL
+
#define ICON_DEFAULT_HEIGHT 16
#define ICON_DEFAULT_WIDTH 16
@@ -105,7 +111,8 @@ void UI_icon_draw_ex(float x,
float alpha,
float desaturate,
const uchar mono_color[4],
- bool mono_border);
+ bool mono_border,
+ const struct IconTextOverlay *text_overlay);
void UI_icons_free(void);
void UI_icons_free_drawinfo(void *drawinfo);
@@ -124,6 +131,9 @@ int UI_icon_from_library(const struct ID *id);
int UI_icon_from_object_mode(int mode);
int UI_icon_color_from_collection(const struct Collection *collection);
+void UI_icon_text_overlay_init_from_count(struct IconTextOverlay *text_overlay,
+ const int icon_indicator_number);
+
#ifdef __cplusplus
}
#endif
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.cc b/source/blender/editors/interface/interface.cc
index 422fc34aa50..1f88d25af2b 100644
--- a/source/blender/editors/interface/interface.cc
+++ b/source/blender/editors/interface/interface.cc
@@ -6452,6 +6452,11 @@ void UI_but_hint_drawstr_set(uiBut *but, const char *string)
ui_but_add_shortcut(but, string, false);
}
+void UI_but_icon_indicator_number_set(uiBut *but, const int indicator_number)
+{
+ UI_icon_text_overlay_init_from_count(&but->icon_overlay_text, indicator_number);
+}
+
void UI_but_node_link_set(uiBut *but, bNodeSocket *socket, const float draw_color[4])
{
but->flag |= UI_BUT_NODE_LINK;
diff --git a/source/blender/editors/interface/interface_context_path.cc b/source/blender/editors/interface/interface_context_path.cc
index e8f552e26a3..91b2f9613de 100644
--- a/source/blender/editors/interface/interface_context_path.cc
+++ b/source/blender/editors/interface/interface_context_path.cc
@@ -17,6 +17,8 @@
#include "UI_interface.hh"
#include "UI_resources.h"
+#include "RNA_prototypes.h"
+
#include "WM_api.h"
namespace blender::ui {
@@ -41,7 +43,13 @@ void context_path_add_generic(Vector<ContextPathItem> &path,
static_cast<BIFIconID>(RNA_struct_ui_icon(rna_ptr.type)) :
icon_override;
- path.append({name, int(icon)});
+ if (&rna_type == &RNA_NodeTree) {
+ ID *id = (ID *)ptr;
+ path.append({name, int(icon), id->us});
+ }
+ else {
+ path.append({name, int(icon), 1});
+ }
}
/* -------------------------------------------------------------------- */
@@ -60,7 +68,9 @@ void template_breadcrumbs(uiLayout &layout, Span<ContextPathItem> context_path)
if (i > 0) {
uiItemL(sub_row, "", ICON_RIGHTARROW_THIN);
}
- uiItemL(sub_row, context_path[i].name.c_str(), context_path[i].icon);
+ uiBut *but = uiItemL_ex(
+ sub_row, context_path[i].name.c_str(), context_path[i].icon, false, false);
+ UI_but_icon_indicator_number_set(but, context_path[i].icon_indicator_number);
}
}
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_icons.c b/source/blender/editors/interface/interface_icons.c
index c080dce0f08..9a4f98ebcd6 100644
--- a/source/blender/editors/interface/interface_icons.c
+++ b/source/blender/editors/interface/interface_icons.c
@@ -415,8 +415,15 @@ static void vicon_collection_color_draw(
const float aspect = (float)ICON_DEFAULT_WIDTH / (float)w;
- UI_icon_draw_ex(
- x, y, ICON_OUTLINER_COLLECTION, aspect, 1.0f, 0.0f, collection_color->color, true);
+ UI_icon_draw_ex(x,
+ y,
+ ICON_OUTLINER_COLLECTION,
+ aspect,
+ 1.0f,
+ 0.0f,
+ collection_color->color,
+ true,
+ UI_NO_ICON_OVERLAY_TEXT);
}
# define DEF_ICON_COLLECTION_COLOR_DRAW(index, color) \
@@ -444,7 +451,8 @@ static void vicon_strip_color_draw(
const float aspect = (float)ICON_DEFAULT_WIDTH / (float)w;
- UI_icon_draw_ex(x, y, ICON_SNAP_FACE, aspect, 1.0f, 0.0f, strip_color->color, true);
+ UI_icon_draw_ex(
+ x, y, ICON_SNAP_FACE, aspect, 1.0f, 0.0f, strip_color->color, true, UI_NO_ICON_OVERLAY_TEXT);
}
# define DEF_ICON_STRIP_COLOR_DRAW(index, color) \
@@ -472,8 +480,15 @@ static void vicon_strip_color_draw_library_data_indirect(
{
const float aspect = (float)ICON_DEFAULT_WIDTH / (float)w;
- UI_icon_draw_ex(
- x, y, ICON_LIBRARY_DATA_DIRECT, aspect, ICON_INDIRECT_DATA_ALPHA * alpha, 0.0f, NULL, false);
+ UI_icon_draw_ex(x,
+ y,
+ ICON_LIBRARY_DATA_DIRECT,
+ aspect,
+ ICON_INDIRECT_DATA_ALPHA * alpha,
+ 0.0f,
+ NULL,
+ false,
+ UI_NO_ICON_OVERLAY_TEXT);
}
static void vicon_strip_color_draw_library_data_override_noneditable(
@@ -488,7 +503,8 @@ static void vicon_strip_color_draw_library_data_override_noneditable(
ICON_INDIRECT_DATA_ALPHA * alpha * 0.75f,
0.0f,
NULL,
- false);
+ false,
+ UI_NO_ICON_OVERLAY_TEXT);
}
/* Dynamically render icon instead of rendering a plain color to a texture/buffer
@@ -923,7 +939,7 @@ static void init_internal_icons(void)
char iconfilestr[FILE_MAX];
if (icondir) {
- BLI_join_dirfile(iconfilestr, sizeof(iconfilestr), icondir, btheme->tui.iconfile);
+ BLI_path_join(iconfilestr, sizeof(iconfilestr), icondir, btheme->tui.iconfile);
/* if the image is missing bbuf will just be NULL */
bbuf = IMB_loadiffname(iconfilestr, IB_rect, NULL);
@@ -1047,7 +1063,7 @@ static void init_iconfile_list(struct ListBase *list)
/* check to see if the image is the right size, continue if not */
/* copying strings here should go ok, assuming that we never get back
* a complete path to file longer than 256 chars */
- BLI_join_dirfile(iconfilestr, sizeof(iconfilestr), icondir, filename);
+ BLI_path_join(iconfilestr, sizeof(iconfilestr), icondir, filename);
bbuf = IMB_loadiffname(iconfilestr, IB_rect);
if (bbuf) {
@@ -1716,9 +1732,47 @@ static void icon_draw_texture(float x,
int ih,
float alpha,
const float rgb[3],
- bool with_border)
-{
- if (g_icon_draw_cache.enabled) {
+ bool with_border,
+ const IconTextOverlay *text_overlay)
+{
+ const float zoom_factor = w / UI_DPI_ICON_SIZE;
+ float text_width = 0.0f;
+
+ /* No need to show if too zoomed out, otherwise it just adds noise. */
+ const bool show_indicator = (text_overlay && text_overlay->text[0] != '\0') &&
+ (zoom_factor > 0.7f);
+
+ if (show_indicator) {
+ /* Handle the little numbers on top of the icon. */
+ uchar text_color[4];
+ UI_GetThemeColor3ubv(TH_TEXT, text_color);
+ text_color[3] = 255;
+
+ uiFontStyle fstyle_small = *UI_FSTYLE_WIDGET;
+ fstyle_small.points *= zoom_factor;
+ fstyle_small.points *= 0.8f;
+
+ rcti text_rect = {
+ .xmax = x + UI_UNIT_X * zoom_factor,
+ .xmin = x,
+ .ymax = y,
+ .ymin = y,
+ };
+
+ UI_fontstyle_draw(&fstyle_small,
+ &text_rect,
+ text_overlay->text,
+ sizeof(text_overlay->text),
+ text_color,
+ &(struct uiFontStyleDraw_Params){
+ .align = UI_STYLE_TEXT_RIGHT,
+ });
+ text_width = (float)UI_fontstyle_string_width(&fstyle_small, text_overlay->text) / UI_UNIT_X /
+ zoom_factor;
+ }
+
+ /* Draw the actual icon. */
+ if (!show_indicator && g_icon_draw_cache.enabled) {
icon_draw_texture_cached(x, y, w, h, ix, iy, iw, ih, alpha, rgb, with_border);
return;
}
@@ -1735,7 +1789,7 @@ static void icon_draw_texture(float x,
GPUTexture *texture = with_border ? icongltex.tex[1] : icongltex.tex[0];
- GPUShader *shader = GPU_shader_get_builtin_shader(GPU_SHADER_2D_IMAGE_RECT_COLOR);
+ GPUShader *shader = GPU_shader_get_builtin_shader(GPU_SHADER_ICON);
GPU_shader_bind(shader);
const int img_binding = GPU_shader_get_texture_binding(shader, "image");
@@ -1752,6 +1806,7 @@ static void icon_draw_texture(float x,
GPU_shader_uniform_vector(shader, rect_tex_loc, 4, 1, (float[4]){x1, y1, x2, y2});
GPU_shader_uniform_vector(shader, rect_geom_loc, 4, 1, (float[4]){x, y, x + w, y + h});
+ GPU_shader_uniform_1f(shader, "text_width", text_width);
GPU_texture_bind_ex(texture, GPU_SAMPLER_ICON, img_binding, false);
@@ -1786,7 +1841,8 @@ static void icon_draw_size(float x,
int draw_size,
const float desaturate,
const uchar mono_rgba[4],
- const bool mono_border)
+ const bool mono_border,
+ const IconTextOverlay *text_overlay)
{
bTheme *btheme = UI_GetTheme();
const float fdraw_size = (float)draw_size;
@@ -1874,7 +1930,8 @@ static void icon_draw_size(float x,
di->data.texture.h,
alpha,
NULL,
- false);
+ false,
+ text_overlay);
}
else if (di->type == ICON_TYPE_MONO_TEXTURE) {
/* Monochrome icon that uses text or theme color. */
@@ -1908,7 +1965,8 @@ static void icon_draw_size(float x,
di->data.texture.h + 2 * border_texel,
color[3],
color,
- with_border);
+ with_border,
+ text_overlay);
}
else if (di->type == ICON_TYPE_BUFFER) {
@@ -2425,17 +2483,27 @@ int UI_icon_color_from_collection(const Collection *collection)
void UI_icon_draw(float x, float y, int icon_id)
{
- UI_icon_draw_ex(x, y, icon_id, U.inv_dpi_fac, 1.0f, 0.0f, NULL, false);
+ UI_icon_draw_ex(x, y, icon_id, U.inv_dpi_fac, 1.0f, 0.0f, NULL, false, UI_NO_ICON_OVERLAY_TEXT);
}
void UI_icon_draw_alpha(float x, float y, int icon_id, float alpha)
{
- UI_icon_draw_ex(x, y, icon_id, U.inv_dpi_fac, alpha, 0.0f, NULL, false);
+ UI_icon_draw_ex(x, y, icon_id, U.inv_dpi_fac, alpha, 0.0f, NULL, false, UI_NO_ICON_OVERLAY_TEXT);
}
void UI_icon_draw_preview(float x, float y, int icon_id, float aspect, float alpha, int size)
{
- icon_draw_size(x, y, icon_id, aspect, alpha, ICON_SIZE_PREVIEW, size, false, NULL, false);
+ icon_draw_size(x,
+ y,
+ icon_id,
+ aspect,
+ alpha,
+ ICON_SIZE_PREVIEW,
+ size,
+ false,
+ NULL,
+ false,
+ UI_NO_ICON_OVERLAY_TEXT);
}
void UI_icon_draw_ex(float x,
@@ -2445,7 +2513,8 @@ void UI_icon_draw_ex(float x,
float alpha,
float desaturate,
const uchar mono_color[4],
- const bool mono_border)
+ const bool mono_border,
+ const IconTextOverlay *text_overlay)
{
const int draw_size = get_draw_size(ICON_SIZE_ICON);
icon_draw_size(x,
@@ -2457,7 +2526,19 @@ void UI_icon_draw_ex(float x,
draw_size,
desaturate,
mono_color,
- mono_border);
+ mono_border,
+ text_overlay);
+}
+
+void UI_icon_text_overlay_init_from_count(IconTextOverlay *text_overlay,
+ const int icon_indicator_number)
+{
+ /* The icon indicator is used as an aggregator, no need to show if it is 1. */
+ if (icon_indicator_number < 2) {
+ text_overlay->text[0] = '\0';
+ return;
+ }
+ BLI_str_format_integer_unit(text_overlay->text, icon_indicator_number);
}
/* ********** Alert Icons ********** */
diff --git a/source/blender/editors/interface/interface_intern.h b/source/blender/editors/interface/interface_intern.h
index 6ef7d346418..6ef81ad897e 100644
--- a/source/blender/editors/interface/interface_intern.h
+++ b/source/blender/editors/interface/interface_intern.h
@@ -23,6 +23,7 @@ struct ARegion;
struct AnimationEvalContext;
struct CurveMapping;
struct CurveProfile;
+struct IconTextOverlay;
struct ID;
struct ImBuf;
struct Main;
@@ -275,6 +276,9 @@ struct uiBut {
uiButPushedStateFunc pushed_state_func;
const void *pushed_state_arg;
+ /** Little indicator (e.g., counter) displayed on top of some icons. */
+ struct IconTextOverlay icon_overlay_text;
+
/* pointer back */
uiBlock *block;
};
diff --git a/source/blender/editors/interface/interface_layout.c b/source/blender/editors/interface/interface_layout.c
index c906a5b36f1..496f72c089a 100644
--- a/source/blender/editors/interface/interface_layout.c
+++ b/source/blender/editors/interface/interface_layout.c
@@ -3235,7 +3235,7 @@ static uiBut *uiItemL_(uiLayout *layout, const char *name, int icon)
return but;
}
-void uiItemL_ex(
+uiBut *uiItemL_ex(
uiLayout *layout, const char *name, int icon, const bool highlight, const bool redalert)
{
uiBut *but = uiItemL_(layout, name, icon);
@@ -3248,6 +3248,8 @@ void uiItemL_ex(
if (redalert) {
UI_but_flag_enable(but, UI_BUT_REDALERT);
}
+
+ return but;
}
void uiItemL(uiLayout *layout, const char *name, int icon)
diff --git a/source/blender/editors/interface/interface_ops.cc b/source/blender/editors/interface/interface_ops.cc
index 8b29f1075b8..e089642963d 100644
--- a/source/blender/editors/interface/interface_ops.cc
+++ b/source/blender/editors/interface/interface_ops.cc
@@ -1859,7 +1859,7 @@ static void edittranslation_find_po_file(const char *root,
/* First, full lang code. */
BLI_snprintf(tstr, sizeof(tstr), "%s.po", uilng);
- BLI_join_dirfile(path, maxlen, root, uilng);
+ BLI_path_join(path, maxlen, root, uilng);
BLI_path_append(path, maxlen, tstr);
if (BLI_is_file(path)) {
return;
@@ -1885,7 +1885,7 @@ static void edittranslation_find_po_file(const char *root,
BLI_strncpy(tstr + szt, tc, sizeof(tstr) - szt);
}
- BLI_join_dirfile(path, maxlen, root, tstr);
+ BLI_path_join(path, maxlen, root, tstr);
strcat(tstr, ".po");
BLI_path_append(path, maxlen, tstr);
if (BLI_is_file(path)) {
diff --git a/source/blender/editors/interface/interface_panel.cc b/source/blender/editors/interface/interface_panel.cc
index 7a69e2f9b2f..24d8281aad8 100644
--- a/source/blender/editors/interface/interface_panel.cc
+++ b/source/blender/editors/interface/interface_panel.cc
@@ -1112,7 +1112,8 @@ static void panel_draw_aligned_widgets(const uiStyle *style,
0.7f,
0.0f,
title_color,
- false);
+ false,
+ UI_NO_ICON_OVERLAY_TEXT);
GPU_blend(GPU_BLEND_NONE);
}
@@ -1140,7 +1141,8 @@ static void panel_draw_aligned_widgets(const uiStyle *style,
1.0f,
0.0f,
title_color,
- false);
+ false,
+ UI_NO_ICON_OVERLAY_TEXT);
GPU_blend(GPU_BLEND_NONE);
}
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/interface/interface_widgets.c b/source/blender/editors/interface/interface_widgets.c
index 6ba80e2e0d9..1bad9b34a72 100644
--- a/source/blender/editors/interface/interface_widgets.c
+++ b/source/blender/editors/interface/interface_widgets.c
@@ -1420,21 +1420,25 @@ static void widget_draw_icon(
/* to indicate draggable */
if (ui_but_drag_is_draggable(but) && (but->flag & UI_ACTIVE)) {
- UI_icon_draw_ex(xs, ys, icon, aspect, 1.25f, 0.0f, color, has_theme);
+ UI_icon_draw_ex(
+ xs, ys, icon, aspect, 1.25f, 0.0f, color, has_theme, &but->icon_overlay_text);
}
else if (but->flag & (UI_ACTIVE | UI_SELECT | UI_SELECT_DRAW)) {
- UI_icon_draw_ex(xs, ys, icon, aspect, alpha, 0.0f, color, has_theme);
+ UI_icon_draw_ex(
+ xs, ys, icon, aspect, alpha, 0.0f, color, has_theme, &but->icon_overlay_text);
}
else if (!((but->icon != ICON_NONE) && UI_but_is_tool(but))) {
if (has_theme) {
alpha *= 0.8f;
}
- UI_icon_draw_ex(xs, ys, icon, aspect, alpha, 0.0f, color, has_theme);
+ UI_icon_draw_ex(
+ xs, ys, icon, aspect, alpha, 0.0f, color, has_theme, &but->icon_overlay_text);
}
else {
const bTheme *btheme = UI_GetTheme();
const float desaturate = 1.0 - btheme->tui.icon_saturation;
- UI_icon_draw_ex(xs, ys, icon, aspect, alpha, desaturate, color, has_theme);
+ UI_icon_draw_ex(
+ xs, ys, icon, aspect, alpha, desaturate, color, has_theme, &but->icon_overlay_text);
}
}
@@ -5426,7 +5430,8 @@ void ui_draw_menu_item(const uiFontStyle *fstyle,
GPU_blend(GPU_BLEND_ALPHA);
/* XXX scale weak get from fstyle? */
- UI_icon_draw_ex(xs, ys, iconid, aspect, 1.0f, 0.0f, wt->wcol.text, false);
+ UI_icon_draw_ex(
+ xs, ys, iconid, aspect, 1.0f, 0.0f, wt->wcol.text, false, UI_NO_ICON_OVERLAY_TEXT);
GPU_blend(GPU_BLEND_NONE);
}
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_gpencil_import.c b/source/blender/editors/io/io_gpencil_import.c
index c7a6b20af7b..5325965e9a5 100644
--- a/source/blender/editors/io/io_gpencil_import.c
+++ b/source/blender/editors/io/io_gpencil_import.c
@@ -111,7 +111,7 @@ static int wm_gpencil_import_svg_exec(bContext *C, wmOperator *op)
char file_path[FILE_MAX];
RNA_PROP_BEGIN (op->ptr, itemptr, prop) {
char *filename = RNA_string_get_alloc(&itemptr, "name", NULL, 0, NULL);
- BLI_join_dirfile(file_path, sizeof(file_path), directory, filename);
+ BLI_path_join(file_path, sizeof(file_path), directory, filename);
MEM_freeN(filename);
/* Do Import. */
diff --git a/source/blender/editors/io/io_obj.c b/source/blender/editors/io/io_obj.c
index cb8eafeb52d..27994af8fe7 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");
@@ -425,8 +427,7 @@ static int wm_obj_import_exec(bContext *C, wmOperator *op)
for (int i = 0; i < files_len; i++) {
RNA_property_collection_lookup_int(op->ptr, prop, i, &fileptr);
RNA_string_get(&fileptr, "name", file_only);
- BLI_join_dirfile(
- import_params.filepath, sizeof(import_params.filepath), dir_only, file_only);
+ BLI_path_join(import_params.filepath, sizeof(import_params.filepath), dir_only, file_only);
import_params.clear_selection = (i == 0);
OBJ_import(C, &import_params);
}
@@ -459,6 +460,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 +491,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 +508,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..bbdb494e48a 100644
--- a/source/blender/editors/io/io_stl_ops.c
+++ b/source/blender/editors/io/io_stl_ops.c
@@ -49,7 +49,7 @@ static int wm_stl_import_execute(bContext *C, wmOperator *op)
for (int i = 0; i < files_len; i++) {
RNA_property_collection_lookup_int(op->ptr, prop, i, &fileptr);
RNA_string_get(&fileptr, "name", file_only);
- BLI_join_dirfile(params.filepath, sizeof(params.filepath), dir_only, file_only);
+ BLI_path_join(params.filepath, sizeof(params.filepath), dir_only, file_only);
STL_import(C, &params);
}
}
@@ -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_mask_extract.c b/source/blender/editors/mesh/editmesh_mask_extract.c
index fdf4746ab09..070f748c78e 100644
--- a/source/blender/editors/mesh/editmesh_mask_extract.c
+++ b/source/blender/editors/mesh/editmesh_mask_extract.c
@@ -88,7 +88,7 @@ static int geometry_extract_apply(bContext *C,
ED_object_sculptmode_exit(C, depsgraph);
- BKE_sculpt_mask_layers_ensure(ob, NULL);
+ BKE_sculpt_mask_layers_ensure(depsgraph, bmain, ob, NULL);
/* Ensures that deformation from sculpt mode is taken into account before duplicating the mesh to
* extract the geometry. */
@@ -481,7 +481,7 @@ static int paint_mask_slice_exec(bContext *C, wmOperator *op)
Object *ob = CTX_data_active_object(C);
View3D *v3d = CTX_wm_view3d(C);
- BKE_sculpt_mask_layers_ensure(ob, NULL);
+ BKE_sculpt_mask_layers_ensure(NULL, NULL, ob, NULL);
Mesh *mesh = ob->data;
Mesh *new_mesh = (Mesh *)BKE_id_copy(bmain, &mesh->id);
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_add.cc b/source/blender/editors/object/object_add.cc
index 3ce39b695e0..f6eee7c0c9e 100644
--- a/source/blender/editors/object/object_add.cc
+++ b/source/blender/editors/object/object_add.cc
@@ -3556,11 +3556,62 @@ void OBJECT_OT_convert(wmOperatorType *ot)
/** \name Duplicate Object Operator
* \{ */
+static void object_add_sync_base_collection(
+ Main *bmain, Scene *scene, ViewLayer *view_layer, Base *base_src, Object *object_new)
+{
+ if ((base_src != nullptr) && (base_src->flag & BASE_ENABLED_AND_MAYBE_VISIBLE_IN_VIEWPORT)) {
+ BKE_collection_object_add_from(bmain, scene, base_src->object, object_new);
+ }
+ else {
+ LayerCollection *layer_collection = BKE_layer_collection_get_active(view_layer);
+ BKE_collection_object_add(bmain, layer_collection->collection, object_new);
+ }
+}
+
+static void object_add_sync_local_view(Base *base_src, Base *base_new)
+{
+ base_new->local_view_bits = base_src->local_view_bits;
+}
+
+static void object_add_sync_rigid_body(Main *bmain, Object *object_src, Object *object_new)
+{
+ /* 1) duplis should end up in same collection as the original
+ * 2) Rigid Body sim participants MUST always be part of a collection...
+ */
+ /* XXX: is 2) really a good measure here? */
+ if (object_src->rigidbody_object || object_src->rigidbody_constraint) {
+ LISTBASE_FOREACH (Collection *, collection, &bmain->collections) {
+ if (BKE_collection_has_object(collection, object_src)) {
+ BKE_collection_object_add(bmain, collection, object_new);
+ }
+ }
+ }
+}
+
/**
* - Assumes `id.new` is correct.
* - Leaves selection of base/object unaltered.
* - Sets #ID.newid pointers.
*/
+static void object_add_duplicate_internal(Main *bmain,
+ Object *ob,
+ const eDupli_ID_Flags dupflag,
+ const eLibIDDuplicateFlags duplicate_options,
+ Object **r_ob_new)
+{
+ if (ob->mode & OB_MODE_POSE) {
+ return;
+ }
+
+ Object *obn = static_cast<Object *>(
+ ID_NEW_SET(ob, BKE_object_duplicate(bmain, ob, dupflag, duplicate_options)));
+ if (r_ob_new) {
+ *r_ob_new = obn;
+ }
+ DEG_id_tag_update(&obn->id, ID_RECALC_TRANSFORM | ID_RECALC_GEOMETRY);
+ return;
+}
+
static Base *object_add_duplicate_internal(Main *bmain,
Scene *scene,
ViewLayer *view_layer,
@@ -3569,49 +3620,25 @@ static Base *object_add_duplicate_internal(Main *bmain,
const eLibIDDuplicateFlags duplicate_options,
Object **r_ob_new)
{
- Base *base, *basen = nullptr;
- Object *obn;
-
- if (ob->mode & OB_MODE_POSE) {
- /* nothing? */
+ Object *object_new = nullptr;
+ object_add_duplicate_internal(bmain, ob, dupflag, duplicate_options, &object_new);
+ if (r_ob_new) {
+ *r_ob_new = object_new;
+ }
+ if (object_new == nullptr) {
+ return nullptr;
}
- else {
- obn = static_cast<Object *>(
- ID_NEW_SET(ob, BKE_object_duplicate(bmain, ob, dupflag, duplicate_options)));
- if (r_ob_new) {
- *r_ob_new = obn;
- }
- DEG_id_tag_update(&obn->id, ID_RECALC_TRANSFORM | ID_RECALC_GEOMETRY);
-
- BKE_view_layer_synced_ensure(scene, view_layer);
- base = BKE_view_layer_base_find(view_layer, ob);
- if ((base != nullptr) && (base->flag & BASE_ENABLED_AND_MAYBE_VISIBLE_IN_VIEWPORT)) {
- BKE_collection_object_add_from(bmain, scene, ob, obn);
- }
- else {
- LayerCollection *layer_collection = BKE_layer_collection_get_active(view_layer);
- BKE_collection_object_add(bmain, layer_collection->collection, obn);
- }
-
- BKE_view_layer_synced_ensure(scene, view_layer);
- basen = BKE_view_layer_base_find(view_layer, obn);
- if (base != nullptr && basen != nullptr) {
- basen->local_view_bits = base->local_view_bits;
- }
- /* 1) duplis should end up in same collection as the original
- * 2) Rigid Body sim participants MUST always be part of a collection...
- */
- /* XXX: is 2) really a good measure here? */
- if (ob->rigidbody_object || ob->rigidbody_constraint) {
- LISTBASE_FOREACH (Collection *, collection, &bmain->collections) {
- if (BKE_collection_has_object(collection, ob)) {
- BKE_collection_object_add(bmain, collection, obn);
- }
- }
- }
+ BKE_view_layer_synced_ensure(scene, view_layer);
+ Base *base_src = BKE_view_layer_base_find(view_layer, ob);
+ object_add_sync_base_collection(bmain, scene, view_layer, base_src, object_new);
+ BKE_view_layer_synced_ensure(scene, view_layer);
+ Base *base_new = BKE_view_layer_base_find(view_layer, object_new);
+ if (base_src && base_new) {
+ object_add_sync_local_view(base_src, base_new);
}
- return basen;
+ object_add_sync_rigid_body(bmain, ob, object_new);
+ return base_new;
}
Base *ED_object_add_duplicate(
@@ -3665,70 +3692,70 @@ static int duplicate_exec(bContext *C, wmOperator *op)
* we also want to remap pointers between those... */
BKE_main_id_newptr_and_tag_clear(bmain);
- /* Do not do collection re-syncs for each object; will do it once afterwards.
- * However this means we can't get to new duplicated Base's immediately, will
- * have to process them after the sync. */
- BKE_layer_collection_resync_forbid();
-
/* Duplicate the selected objects, remember data needed to process
- * after the sync (the base of the original object, and the copy of the
- * original object). */
- blender::Vector<std::pair<Base *, Object *>> source_bases_new_objects;
- Object *ob_new_active = nullptr;
+ * after the sync. */
+ struct DuplicateObjectLink {
+ Base *base_src = nullptr;
+ Object *object_new = nullptr;
+
+ DuplicateObjectLink(Base *base_src) : base_src(base_src)
+ {
+ }
+ };
+ blender::Vector<DuplicateObjectLink> object_base_links;
CTX_DATA_BEGIN (C, Base *, base, selected_bases) {
- Object *ob_new = nullptr;
+ object_base_links.append(DuplicateObjectLink(base));
+ }
+ CTX_DATA_END;
+
+ bool new_objects_created = false;
+ for (DuplicateObjectLink &link : object_base_links) {
object_add_duplicate_internal(bmain,
- scene,
- view_layer,
- base->object,
+ link.base_src->object,
dupflag,
LIB_ID_DUPLICATE_IS_SUBPROCESS | LIB_ID_DUPLICATE_IS_ROOT_ID,
- &ob_new);
- if (ob_new == nullptr) {
- continue;
- }
- source_bases_new_objects.append({base, ob_new});
-
- /* note that this is safe to do with this context iterator,
- * the list is made in advance */
- ED_object_base_select(base, BA_DESELECT);
-
- /* new object will become active */
- BKE_view_layer_synced_ensure(scene, view_layer);
- if (BKE_view_layer_active_base_get(view_layer) == base) {
- ob_new_active = ob_new;
+ &link.object_new);
+ if (link.object_new) {
+ new_objects_created = true;
}
}
- CTX_DATA_END;
- BKE_layer_collection_resync_allow();
- if (source_bases_new_objects.is_empty()) {
+ if (!new_objects_created) {
return OPERATOR_CANCELLED;
}
- /* Sync the collection now, after everything is duplicated. */
- BKE_main_collection_sync(bmain);
+ /* Sync that could tag the view_layer out of sync. */
+ for (DuplicateObjectLink &link : object_base_links) {
+ /* note that this is safe to do with this context iterator,
+ * the list is made in advance */
+ ED_object_base_select(link.base_src, BA_DESELECT);
+ if (link.object_new) {
+ object_add_sync_base_collection(bmain, scene, view_layer, link.base_src, link.object_new);
+ object_add_sync_rigid_body(bmain, link.base_src->object, link.object_new);
+ }
+ }
- /* After sync we can get to the new Base data, process it here. */
- for (const auto &item : source_bases_new_objects) {
- Object *ob_new = item.second;
- Base *base_source = item.first;
- BKE_view_layer_synced_ensure(scene, view_layer);
- Base *base_new = BKE_view_layer_base_find(view_layer, ob_new);
- if (base_new == nullptr) {
+ /* Sync the view layer. Everything else should not tag the view_layer out of sync. */
+ BKE_view_layer_synced_ensure(scene, view_layer);
+ const Base *active_base = BKE_view_layer_active_base_get(view_layer);
+ for (DuplicateObjectLink &link : object_base_links) {
+ if (!link.object_new) {
continue;
}
+
+ Base *base_new = BKE_view_layer_base_find(view_layer, link.object_new);
+ BLI_assert(base_new);
ED_object_base_select(base_new, BA_SELECT);
- if (ob_new == ob_new_active) {
+ if (active_base == link.base_src) {
ED_object_base_activate(C, base_new);
}
- if (base_new->object->data) {
- DEG_id_tag_update(static_cast<ID *>(base_new->object->data), 0);
+
+ if (link.object_new->data) {
+ DEG_id_tag_update(static_cast<ID *>(link.object_new->data), 0);
}
- /* #object_add_duplicate_internal will not have done this, since
- * before the collection sync it would not have found the new base yet. */
- base_new->local_view_bits = base_source->local_view_bits;
+
+ object_add_sync_local_view(link.base_src, base_new);
}
/* Note that this will also clear newid pointers and tags. */
diff --git a/source/blender/editors/object/object_modifier.cc b/source/blender/editors/object/object_modifier.cc
index 872d2367332..85a35861329 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"
@@ -217,7 +218,7 @@ ModifierData *ED_object_modifier_add(
if (ob->mode & OB_MODE_SCULPT) {
/* ensure that grid paint mask layer is created */
- BKE_sculpt_mask_layers_ensure(ob, (MultiresModifierData *)new_md);
+ BKE_sculpt_mask_layers_ensure(nullptr, nullptr, ob, (MultiresModifierData *)new_md);
}
}
else if (type == eModifierType_Skin) {
@@ -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;
}
@@ -2008,7 +2041,8 @@ static int multires_subdivide_exec(bContext *C, wmOperator *op)
if (object->mode & OB_MODE_SCULPT) {
/* ensure that grid paint mask layer is created */
- BKE_sculpt_mask_layers_ensure(object, mmd);
+ BKE_sculpt_mask_layers_ensure(
+ CTX_data_ensure_evaluated_depsgraph(C), CTX_data_main(C), object, mmd);
}
return OPERATOR_FINISHED;
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 a63e06d6866..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;
+ 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);
- i1 = BKE_lattice_index_from_uvw(lt, u, v, w);
- i2 = BKE_lattice_index_from_uvw(lt, u_inv, v, w);
+ const BPoint *bp = &lt->def[i1];
+ const BPoint *bp_mirr = &lt->def[i2];
- bp = &lt->def[i1];
- 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++;
}
}
diff --git a/source/blender/editors/physics/dynamicpaint_ops.c b/source/blender/editors/physics/dynamicpaint_ops.c
index 1ce90849a88..41238eb171b 100644
--- a/source/blender/editors/physics/dynamicpaint_ops.c
+++ b/source/blender/editors/physics/dynamicpaint_ops.c
@@ -405,7 +405,7 @@ static void dynamicPaint_bakeImageSequence(DynamicPaintBakeJob *job)
/* primary output layer */
if (surface->flags & MOD_DPAINT_OUT1) {
/* set filepath */
- BLI_join_dirfile(
+ BLI_path_join(
filepath, sizeof(filepath), surface->image_output_path, surface->output_name);
BLI_path_frame(filepath, frame, 4);
@@ -415,7 +415,7 @@ static void dynamicPaint_bakeImageSequence(DynamicPaintBakeJob *job)
/* secondary output */
if (surface->flags & MOD_DPAINT_OUT2 && surface->type == MOD_DPAINT_SURFACE_T_PAINT) {
/* set filepath */
- BLI_join_dirfile(
+ BLI_path_join(
filepath, sizeof(filepath), surface->image_output_path, surface->output_name2);
BLI_path_frame(filepath, frame, 4);
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..210757173eb 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;
@@ -1204,9 +1204,7 @@ static bool copy_particle_systems_to_object(const bContext *C,
#undef PSYS_FROM_FIRST
#undef PSYS_FROM_NEXT
- if (duplicate_settings) {
- DEG_relations_tag_update(bmain);
- }
+ DEG_relations_tag_update(bmain);
DEG_id_tag_update(&ob_to->id, ID_RECALC_GEOMETRY);
WM_main_add_notifier(NC_OBJECT | ND_PARTICLE | NA_EDITED, ob_to);
return true;
@@ -1269,8 +1267,7 @@ static int copy_particle_systems_exec(bContext *C, wmOperator *op)
CTX_DATA_END;
if (changed_tot > 0) {
- Depsgraph *depsgraph = CTX_data_depsgraph_pointer(C);
- DEG_graph_tag_relations_update(depsgraph);
+ DEG_relations_tag_update(CTX_data_main(C));
}
if ((changed_tot == 0 && fail == 0) || fail) {
diff --git a/source/blender/editors/physics/physics_fluid.c b/source/blender/editors/physics/physics_fluid.c
index 07e8f5c5743..314796e96e4 100644
--- a/source/blender/editors/physics/physics_fluid.c
+++ b/source/blender/editors/physics/physics_fluid.c
@@ -368,7 +368,7 @@ static void fluid_bake_startjob(void *customdata, short *stop, short *do_update,
BKE_spacedata_draw_locks(true);
if (fluid_is_bake_noise(job) || fluid_is_bake_all(job)) {
- BLI_path_join(temp_dir, sizeof(temp_dir), fds->cache_directory, FLUID_DOMAIN_DIR_NOISE, NULL);
+ BLI_path_join(temp_dir, sizeof(temp_dir), fds->cache_directory, FLUID_DOMAIN_DIR_NOISE);
BLI_path_abs(temp_dir, relbase);
BLI_dir_create_recursive(temp_dir); /* Create 'noise' subdir if it does not exist already */
fds->cache_flag &= ~(FLUID_DOMAIN_BAKED_NOISE | FLUID_DOMAIN_OUTDATED_NOISE);
@@ -376,7 +376,7 @@ static void fluid_bake_startjob(void *customdata, short *stop, short *do_update,
job->pause_frame = &fds->cache_frame_pause_noise;
}
if (fluid_is_bake_mesh(job) || fluid_is_bake_all(job)) {
- BLI_path_join(temp_dir, sizeof(temp_dir), fds->cache_directory, FLUID_DOMAIN_DIR_MESH, NULL);
+ BLI_path_join(temp_dir, sizeof(temp_dir), fds->cache_directory, FLUID_DOMAIN_DIR_MESH);
BLI_path_abs(temp_dir, relbase);
BLI_dir_create_recursive(temp_dir); /* Create 'mesh' subdir if it does not exist already */
fds->cache_flag &= ~(FLUID_DOMAIN_BAKED_MESH | FLUID_DOMAIN_OUTDATED_MESH);
@@ -384,8 +384,7 @@ static void fluid_bake_startjob(void *customdata, short *stop, short *do_update,
job->pause_frame = &fds->cache_frame_pause_mesh;
}
if (fluid_is_bake_particle(job) || fluid_is_bake_all(job)) {
- BLI_path_join(
- temp_dir, sizeof(temp_dir), fds->cache_directory, FLUID_DOMAIN_DIR_PARTICLES, NULL);
+ BLI_path_join(temp_dir, sizeof(temp_dir), fds->cache_directory, FLUID_DOMAIN_DIR_PARTICLES);
BLI_path_abs(temp_dir, relbase);
/* Create 'particles' subdir if it does not exist already */
@@ -396,7 +395,7 @@ static void fluid_bake_startjob(void *customdata, short *stop, short *do_update,
job->pause_frame = &fds->cache_frame_pause_particles;
}
if (fluid_is_bake_guiding(job) || fluid_is_bake_all(job)) {
- BLI_path_join(temp_dir, sizeof(temp_dir), fds->cache_directory, FLUID_DOMAIN_DIR_GUIDE, NULL);
+ BLI_path_join(temp_dir, sizeof(temp_dir), fds->cache_directory, FLUID_DOMAIN_DIR_GUIDE);
BLI_path_abs(temp_dir, relbase);
BLI_dir_create_recursive(temp_dir); /* Create 'guiding' subdir if it does not exist already */
fds->cache_flag &= ~(FLUID_DOMAIN_BAKED_GUIDE | FLUID_DOMAIN_OUTDATED_GUIDE);
@@ -404,11 +403,11 @@ static void fluid_bake_startjob(void *customdata, short *stop, short *do_update,
job->pause_frame = &fds->cache_frame_pause_guide;
}
if (fluid_is_bake_data(job) || fluid_is_bake_all(job)) {
- BLI_path_join(temp_dir, sizeof(temp_dir), fds->cache_directory, FLUID_DOMAIN_DIR_CONFIG, NULL);
+ BLI_path_join(temp_dir, sizeof(temp_dir), fds->cache_directory, FLUID_DOMAIN_DIR_CONFIG);
BLI_path_abs(temp_dir, relbase);
BLI_dir_create_recursive(temp_dir); /* Create 'config' subdir if it does not exist already */
- BLI_path_join(temp_dir, sizeof(temp_dir), fds->cache_directory, FLUID_DOMAIN_DIR_DATA, NULL);
+ BLI_path_join(temp_dir, sizeof(temp_dir), fds->cache_directory, FLUID_DOMAIN_DIR_DATA);
BLI_path_abs(temp_dir, relbase);
BLI_dir_create_recursive(temp_dir); /* Create 'data' subdir if it does not exist already */
fds->cache_flag &= ~(FLUID_DOMAIN_BAKED_DATA | FLUID_DOMAIN_OUTDATED_DATA);
@@ -416,8 +415,7 @@ static void fluid_bake_startjob(void *customdata, short *stop, short *do_update,
job->pause_frame = &fds->cache_frame_pause_data;
if (fds->flags & FLUID_DOMAIN_EXPORT_MANTA_SCRIPT) {
- BLI_path_join(
- temp_dir, sizeof(temp_dir), fds->cache_directory, FLUID_DOMAIN_DIR_SCRIPT, NULL);
+ BLI_path_join(temp_dir, sizeof(temp_dir), fds->cache_directory, FLUID_DOMAIN_DIR_SCRIPT);
BLI_path_abs(temp_dir, relbase);
BLI_dir_create_recursive(temp_dir); /* Create 'script' subdir if it does not exist already */
}
diff --git a/source/blender/editors/render/render_preview.cc b/source/blender/editors/render/render_preview.cc
index ad24f46f923..140199209da 100644
--- a/source/blender/editors/render/render_preview.cc
+++ b/source/blender/editors/render/render_preview.cc
@@ -1325,7 +1325,7 @@ static ImBuf *icon_preview_imbuf_from_brush(Brush *brush)
const char *brushicons_dir = BKE_appdir_folder_id(BLENDER_DATAFILES, "brushicons");
/* Expected to be found, but don't crash if it's not. */
if (brushicons_dir) {
- BLI_join_dirfile(filepath, sizeof(filepath), brushicons_dir, brush->icon_filepath);
+ BLI_path_join(filepath, sizeof(filepath), brushicons_dir, brush->icon_filepath);
/* Use default color spaces. */
brush->icon_imbuf = IMB_loadiffname(filepath, flags, nullptr);
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/screen/area.c b/source/blender/editors/screen/area.c
index 39e3c7a2f0a..8db968cbb8a 100644
--- a/source/blender/editors/screen/area.c
+++ b/source/blender/editors/screen/area.c
@@ -187,7 +187,8 @@ static void area_draw_azone_fullscreen(
min_ff(alpha, 0.75f),
0.0f,
NULL,
- false);
+ false,
+ UI_NO_ICON_OVERLAY_TEXT);
}
/**
diff --git a/source/blender/editors/screen/workspace_edit.c b/source/blender/editors/screen/workspace_edit.c
index 9a6bdc98d76..8cf11583b3a 100644
--- a/source/blender/editors/screen/workspace_edit.c
+++ b/source/blender/editors/screen/workspace_edit.c
@@ -405,7 +405,7 @@ static WorkspaceConfigFileData *workspace_config_file_read(const char *app_templ
char startup_file_path[FILE_MAX] = {0};
if (cfgdir) {
- BLI_join_dirfile(startup_file_path, sizeof(startup_file_path), cfgdir, BLENDER_STARTUP_FILE);
+ BLI_path_join(startup_file_path, sizeof(startup_file_path), cfgdir, BLENDER_STARTUP_FILE);
}
bool has_path = BLI_exists(startup_file_path);
@@ -425,8 +425,7 @@ static WorkspaceConfigFileData *workspace_system_file_read(const char *app_templ
}
char startup_file_path[FILE_MAX];
- BLI_join_dirfile(
- startup_file_path, sizeof(startup_file_path), template_dir, BLENDER_STARTUP_FILE);
+ BLI_path_join(startup_file_path, sizeof(startup_file_path), template_dir, BLENDER_STARTUP_FILE);
bool has_path = BLI_exists(startup_file_path);
return (has_path) ? BKE_blendfile_workspace_config_read(startup_file_path, NULL, 0, NULL) : NULL;
diff --git a/source/blender/editors/sculpt_paint/paint_image_2d.c b/source/blender/editors/sculpt_paint/paint_image_2d.c
index 79316361e53..b7ce4b2973c 100644
--- a/source/blender/editors/sculpt_paint/paint_image_2d.c
+++ b/source/blender/editors/sculpt_paint/paint_image_2d.c
@@ -402,7 +402,8 @@ static ImBuf *brush_painter_imbuf_new(
if (is_texbrush) {
brush_imbuf_tex_co(&tex_mapping, x, y, texco);
- BKE_brush_sample_tex_3d(scene, brush, texco, rgba, thread, pool);
+ const MTex *mtex = &brush->mtex;
+ BKE_brush_sample_tex_3d(scene, brush, mtex, texco, rgba, thread, pool);
/* TODO(sergey): Support texture paint color space. */
if (!use_float) {
IMB_colormanagement_scene_linear_to_display_v3(rgba, display);
@@ -446,6 +447,7 @@ static void brush_painter_imbuf_update(BrushPainter *painter,
{
Scene *scene = painter->scene;
Brush *brush = painter->brush;
+ const MTex *mtex = &brush->mtex;
BrushPainterCache *cache = &tile->cache;
const char *display_device = scene->display_settings.display_device;
@@ -485,7 +487,7 @@ static void brush_painter_imbuf_update(BrushPainter *painter,
if (!use_texture_old) {
if (is_texbrush) {
brush_imbuf_tex_co(&tex_mapping, x, y, texco);
- BKE_brush_sample_tex_3d(scene, brush, texco, rgba, thread, pool);
+ BKE_brush_sample_tex_3d(scene, brush, mtex, texco, rgba, thread, pool);
/* TODO(sergey): Support texture paint color space. */
if (!use_float) {
IMB_colormanagement_scene_linear_to_display_v3(rgba, display);
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..d9aa11a2847 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");
@@ -5370,7 +5370,7 @@ static void do_projectpaint_thread(TaskPool *__restrict UNUSED(pool), void *ph_v
/* Color texture (alpha used as mask). */
if (ps->is_texbrush) {
- MTex *mtex = &brush->mtex;
+ const MTex *mtex = BKE_brush_color_texture_get(brush, OB_MODE_TEXTURE_PAINT);
float samplecos[3];
float texrgba[4];
@@ -5386,7 +5386,8 @@ static void do_projectpaint_thread(TaskPool *__restrict UNUSED(pool), void *ph_v
/* NOTE: for clone and smear,
* we only use the alpha, could be a special function */
- BKE_brush_sample_tex_3d(ps->scene, brush, samplecos, texrgba, thread_index, pool);
+ BKE_brush_sample_tex_3d(
+ ps->scene, brush, mtex, samplecos, texrgba, thread_index, pool);
copy_v3_v3(texrgb, texrgba);
custom_mask *= texrgba[3];
diff --git a/source/blender/editors/sculpt_paint/paint_mask.c b/source/blender/editors/sculpt_paint/paint_mask.c
index e1fd731a4b7..571ebd79764 100644
--- a/source/blender/editors/sculpt_paint/paint_mask.c
+++ b/source/blender/editors/sculpt_paint/paint_mask.c
@@ -31,6 +31,7 @@
#include "BKE_multires.h"
#include "BKE_paint.h"
#include "BKE_pbvh.h"
+#include "BKE_scene.h"
#include "BKE_subsurf.h"
#include "DEG_depsgraph.h"
@@ -146,7 +147,7 @@ static int mask_flood_fill_exec(bContext *C, wmOperator *op)
value = RNA_float_get(op->ptr, "value");
MultiresModifierData *mmd = BKE_sculpt_multires_active(scene, ob);
- BKE_sculpt_mask_layers_ensure(ob, mmd);
+ BKE_sculpt_mask_layers_ensure(depsgraph, CTX_data_main(C), ob, mmd);
BKE_sculpt_update_object_for_edit(depsgraph, ob, false, true, false);
pbvh = ob->sculpt->pbvh;
@@ -861,7 +862,9 @@ static void sculpt_gesture_mask_end(bContext *C, SculptGestureContext *sgcontext
BKE_pbvh_update_vertex_data(sgcontext->ss->pbvh, PBVH_UpdateMask);
}
-static void sculpt_gesture_init_mask_properties(SculptGestureContext *sgcontext, wmOperator *op)
+static void sculpt_gesture_init_mask_properties(bContext *C,
+ SculptGestureContext *sgcontext,
+ wmOperator *op)
{
sgcontext->operation = MEM_callocN(sizeof(SculptGestureMaskOperation), "Mask Operation");
@@ -869,7 +872,8 @@ static void sculpt_gesture_init_mask_properties(SculptGestureContext *sgcontext,
Object *object = sgcontext->vc.obact;
MultiresModifierData *mmd = BKE_sculpt_multires_active(sgcontext->vc.scene, object);
- BKE_sculpt_mask_layers_ensure(sgcontext->vc.obact, mmd);
+ BKE_sculpt_mask_layers_ensure(
+ CTX_data_depsgraph_pointer(C), CTX_data_main(C), sgcontext->vc.obact, mmd);
mask_operation->op.sculpt_gesture_begin = sculpt_gesture_mask_begin;
mask_operation->op.sculpt_gesture_apply_for_symmetry_pass =
@@ -1514,7 +1518,7 @@ static int paint_mask_gesture_box_exec(bContext *C, wmOperator *op)
if (!sgcontext) {
return OPERATOR_CANCELLED;
}
- sculpt_gesture_init_mask_properties(sgcontext, op);
+ sculpt_gesture_init_mask_properties(C, sgcontext, op);
sculpt_gesture_apply(C, sgcontext, op);
sculpt_gesture_context_free(sgcontext);
return OPERATOR_FINISHED;
@@ -1526,7 +1530,7 @@ static int paint_mask_gesture_lasso_exec(bContext *C, wmOperator *op)
if (!sgcontext) {
return OPERATOR_CANCELLED;
}
- sculpt_gesture_init_mask_properties(sgcontext, op);
+ sculpt_gesture_init_mask_properties(C, sgcontext, op);
sculpt_gesture_apply(C, sgcontext, op);
sculpt_gesture_context_free(sgcontext);
return OPERATOR_FINISHED;
@@ -1538,7 +1542,7 @@ static int paint_mask_gesture_line_exec(bContext *C, wmOperator *op)
if (!sgcontext) {
return OPERATOR_CANCELLED;
}
- sculpt_gesture_init_mask_properties(sgcontext, op);
+ sculpt_gesture_init_mask_properties(C, sgcontext, op);
sculpt_gesture_apply(C, sgcontext, op);
sculpt_gesture_context_free(sgcontext);
return OPERATOR_FINISHED;
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/paint_vertex.cc b/source/blender/editors/sculpt_paint/paint_vertex.cc
index 6e3504332ed..acd8b1a6bb1 100644
--- a/source/blender/editors/sculpt_paint/paint_vertex.cc
+++ b/source/blender/editors/sculpt_paint/paint_vertex.cc
@@ -433,9 +433,10 @@ static void paint_and_tex_color_alpha_intern(VPaint *vp,
float r_rgba[4])
{
const Brush *brush = BKE_paint_brush(&vp->paint);
- BLI_assert(brush->mtex.tex != nullptr);
- if (brush->mtex.brush_map_mode == MTEX_MAP_MODE_3D) {
- BKE_brush_sample_tex_3d(vc->scene, brush, co, r_rgba, 0, nullptr);
+ const MTex *mtex = BKE_brush_mask_texture_get(brush, OB_MODE_SCULPT);
+ BLI_assert(mtex->tex != nullptr);
+ if (mtex->brush_map_mode == MTEX_MAP_MODE_3D) {
+ BKE_brush_sample_tex_3d(vc->scene, brush, mtex, co, r_rgba, 0, nullptr);
}
else {
float co_ss[2]; /* screenspace */
@@ -445,7 +446,7 @@ static void paint_and_tex_color_alpha_intern(VPaint *vp,
co_ss,
(eV3DProjTest)(V3D_PROJ_TEST_CLIP_BB | V3D_PROJ_TEST_CLIP_NEAR)) == V3D_PROJ_RET_OK) {
const float co_ss_3d[3] = {co_ss[0], co_ss[1], 0.0f}; /* we need a 3rd empty value */
- BKE_brush_sample_tex_3d(vc->scene, brush, co_ss_3d, r_rgba, 0, nullptr);
+ BKE_brush_sample_tex_3d(vc->scene, brush, mtex, co_ss_3d, r_rgba, 0, nullptr);
}
else {
zero_v4(r_rgba);
diff --git a/source/blender/editors/sculpt_paint/sculpt.c b/source/blender/editors/sculpt_paint/sculpt.c
index 9e1b1cda0c3..95192114429 100644
--- a/source/blender/editors/sculpt_paint/sculpt.c
+++ b/source/blender/editors/sculpt_paint/sculpt.c
@@ -41,6 +41,7 @@
#include "BKE_paint.h"
#include "BKE_pbvh.h"
#include "BKE_report.h"
+#include "BKE_scene.h"
#include "BKE_subdiv_ccg.h"
#include "BKE_subsurf.h"
@@ -1981,7 +1982,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] = {
@@ -2457,7 +2458,7 @@ float SCULPT_brush_strength_factor(SculptSession *ss,
{
StrokeCache *cache = ss->cache;
const Scene *scene = cache->vc->scene;
- const MTex *mtex = &br->mtex;
+ const MTex *mtex = BKE_brush_mask_texture_get(br, OB_MODE_SCULPT);
float avg = 1.0f;
float rgba[4];
float point[3];
@@ -2469,7 +2470,7 @@ float SCULPT_brush_strength_factor(SculptSession *ss,
}
else if (mtex->brush_map_mode == MTEX_MAP_MODE_3D) {
/* Get strength by feeding the vertex location directly into a texture. */
- avg = BKE_brush_sample_tex_3d(scene, br, point, rgba, 0, ss->tex_pool);
+ avg = BKE_brush_sample_tex_3d(scene, br, mtex, point, rgba, 0, ss->tex_pool);
}
else {
float symm_point[3], point_2d[2];
@@ -2498,19 +2499,19 @@ float SCULPT_brush_strength_factor(SculptSession *ss,
x = symm_point[0];
y = symm_point[1];
- x *= br->mtex.size[0];
- y *= br->mtex.size[1];
+ x *= mtex->size[0];
+ y *= mtex->size[1];
- x += br->mtex.ofs[0];
- y += br->mtex.ofs[1];
+ x += mtex->ofs[0];
+ y += mtex->ofs[1];
- avg = paint_get_tex_pixel(&br->mtex, x, y, ss->tex_pool, thread_id);
+ avg = paint_get_tex_pixel(mtex, x, y, ss->tex_pool, thread_id);
avg += br->texture_sample_bias;
}
else {
const float point_3d[3] = {point_2d[0], point_2d[1], 0.0f};
- avg = BKE_brush_sample_tex_3d(scene, br, point_3d, rgba, 0, ss->tex_pool);
+ avg = BKE_brush_sample_tex_3d(scene, br, mtex, point_3d, rgba, 0, ss->tex_pool);
}
}
@@ -3265,7 +3266,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);
}
}
@@ -4272,7 +4273,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);
@@ -4407,6 +4409,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
@@ -5658,7 +5667,7 @@ static int sculpt_brush_stroke_invoke(bContext *C, wmOperator *op, const wmEvent
}
if (SCULPT_tool_is_mask(brush->sculpt_tool)) {
MultiresModifierData *mmd = BKE_sculpt_multires_active(ss->scene, ob);
- BKE_sculpt_mask_layers_ensure(ob, mmd);
+ BKE_sculpt_mask_layers_ensure(CTX_data_depsgraph_pointer(C), CTX_data_main(C), ob, mmd);
}
if (SCULPT_tool_is_face_sets(brush->sculpt_tool)) {
Mesh *mesh = BKE_object_get_original_mesh(ob);
@@ -5749,15 +5758,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_expand.c b/source/blender/editors/sculpt_paint/sculpt_expand.c
index 90279cb339c..3133bb2007e 100644
--- a/source/blender/editors/sculpt_paint/sculpt_expand.c
+++ b/source/blender/editors/sculpt_paint/sculpt_expand.c
@@ -27,6 +27,7 @@
#include "BKE_paint.h"
#include "BKE_pbvh.h"
#include "BKE_report.h"
+#include "BKE_scene.h"
#include "BKE_subdiv_ccg.h"
#include "DEG_depsgraph.h"
@@ -166,15 +167,16 @@ static float sculpt_expand_falloff_value_vertex_get(SculptSession *ss,
if (expand_cache->texture_distortion_strength == 0.0f) {
return expand_cache->vert_falloff[v_i];
}
-
- if (!expand_cache->brush->mtex.tex) {
+ const Brush *brush = expand_cache->brush;
+ const MTex *mtex = BKE_brush_mask_texture_get(brush, OB_MODE_SCULPT);
+ if (!mtex->tex) {
return expand_cache->vert_falloff[v_i];
}
float rgba[4];
const float *vertex_co = SCULPT_vertex_co_get(ss, v);
const float avg = BKE_brush_sample_tex_3d(
- expand_cache->scene, expand_cache->brush, vertex_co, rgba, 0, ss->tex_pool);
+ expand_cache->scene, brush, mtex, vertex_co, rgba, 0, ss->tex_pool);
const float distortion = (avg - 0.5f) * expand_cache->texture_distortion_strength *
expand_cache->max_vert_falloff;
@@ -2107,6 +2109,11 @@ static int sculpt_expand_invoke(bContext *C, wmOperator *op, const wmEvent *even
depsgraph = CTX_data_ensure_evaluated_depsgraph(C);
}
+ if (ss->expand_cache->target == SCULPT_EXPAND_TARGET_MASK) {
+ MultiresModifierData *mmd = BKE_sculpt_multires_active(ss->scene, ob);
+ BKE_sculpt_mask_layers_ensure(depsgraph, CTX_data_main(C), ob, mmd);
+ }
+
BKE_sculpt_update_object_for_edit(depsgraph, ob, true, true, needs_colors);
/* Do nothing when the mesh has 0 vertices. */
@@ -2121,11 +2128,6 @@ static int sculpt_expand_invoke(bContext *C, wmOperator *op, const wmEvent *even
ss->face_sets = BKE_sculpt_face_sets_ensure(mesh);
}
- if (ss->expand_cache->target == SCULPT_EXPAND_TARGET_MASK) {
- MultiresModifierData *mmd = BKE_sculpt_multires_active(ss->scene, ob);
- BKE_sculpt_mask_layers_ensure(ob, mmd);
- }
-
/* Face Set operations are not supported in dyntopo. */
if (ss->expand_cache->target == SCULPT_EXPAND_TARGET_FACE_SETS &&
BKE_pbvh_type(ss->pbvh) == PBVH_BMESH) {
diff --git a/source/blender/editors/sculpt_paint/sculpt_face_set.cc b/source/blender/editors/sculpt_paint/sculpt_face_set.cc
index 15a91e4eaab..8fb4dea668e 100644
--- a/source/blender/editors/sculpt_paint/sculpt_face_set.cc
+++ b/source/blender/editors/sculpt_paint/sculpt_face_set.cc
@@ -18,6 +18,7 @@
#include "BLI_math_vector.hh"
#include "BLI_span.hh"
#include "BLI_task.h"
+#include "BLI_task.hh"
#include "DNA_brush_types.h"
#include "DNA_customdata_types.h"
@@ -198,8 +199,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 +262,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);
}
}
@@ -312,6 +314,7 @@ static EnumPropertyItem prop_sculpt_face_set_create_types[] = {
static int sculpt_face_set_create_exec(bContext *C, wmOperator *op)
{
+ using namespace blender;
Object *ob = CTX_data_active_object(C);
SculptSession *ss = ob->sculpt;
Depsgraph *depsgraph = CTX_data_depsgraph_pointer(C);
@@ -395,25 +398,16 @@ static int sculpt_face_set_create_exec(bContext *C, wmOperator *op)
}
if (mode == SCULPT_FACE_SET_SELECTION) {
- BMesh *bm;
- const BMAllocTemplate allocsize = BMALLOC_TEMPLATE_FROM_ME(mesh);
- BMeshCreateParams create_params{};
- create_params.use_toolflags = true;
- bm = BM_mesh_create(&allocsize, &create_params);
-
- BMeshFromMeshParams convert_params{};
- convert_params.calc_vert_normal = true;
- convert_params.calc_face_normal = true;
- BM_mesh_bm_from_me(bm, mesh, &convert_params);
-
- BMIter iter;
- BMFace *f;
- BM_ITER_MESH (f, &iter, bm, BM_FACES_OF_MESH) {
- if (BM_elem_flag_test(f, BM_ELEM_SELECT)) {
- ss->face_sets[BM_elem_index_get(f)] = next_face_set;
+ const bke::AttributeAccessor attributes = mesh->attributes();
+ const VArraySpan<bool> select_poly = attributes.lookup_or_default<bool>(
+ ".select_poly", ATTR_DOMAIN_FACE, false);
+ threading::parallel_for(IndexRange(mesh->totvert), 4096, [&](const IndexRange range) {
+ for (const int i : range) {
+ if (select_poly[i]) {
+ ss->face_sets[i] = next_face_set;
+ }
}
- }
- BM_mesh_free(bm);
+ });
}
for (int i = 0; i < totnode; i++) {
@@ -827,9 +821,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 +833,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 +927,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_filter_mask.c b/source/blender/editors/sculpt_paint/sculpt_filter_mask.c
index 69eac9a6168..8e199a72858 100644
--- a/source/blender/editors/sculpt_paint/sculpt_filter_mask.c
+++ b/source/blender/editors/sculpt_paint/sculpt_filter_mask.c
@@ -16,6 +16,7 @@
#include "BKE_context.h"
#include "BKE_paint.h"
#include "BKE_pbvh.h"
+#include "BKE_scene.h"
#include "DEG_depsgraph.h"
@@ -166,7 +167,7 @@ static int sculpt_mask_filter_exec(bContext *C, wmOperator *op)
int filter_type = RNA_enum_get(op->ptr, "filter_type");
MultiresModifierData *mmd = BKE_sculpt_multires_active(scene, ob);
- BKE_sculpt_mask_layers_ensure(ob, mmd);
+ BKE_sculpt_mask_layers_ensure(CTX_data_depsgraph_pointer(C), CTX_data_main(C), ob, mmd);
BKE_sculpt_update_object_for_edit(depsgraph, ob, true, true, false);
diff --git a/source/blender/editors/sculpt_paint/sculpt_intern.h b/source/blender/editors/sculpt_paint/sculpt_intern.h
index edb681466b5..bf47b64d176 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_mask_expand.c b/source/blender/editors/sculpt_paint/sculpt_mask_expand.c
index 56ddb99fe28..1b8cc5347ac 100644
--- a/source/blender/editors/sculpt_paint/sculpt_mask_expand.c
+++ b/source/blender/editors/sculpt_paint/sculpt_mask_expand.c
@@ -14,6 +14,7 @@
#include "DNA_brush_types.h"
#include "DNA_meshdata_types.h"
+#include "DNA_modifier_types.h"
#include "DNA_object_types.h"
#include "BKE_ccg.h"
@@ -331,6 +332,11 @@ static int sculpt_mask_expand_invoke(bContext *C, wmOperator *op, const wmEvent
SculptCursorGeometryInfo sgi;
const float mval_fl[2] = {UNPACK2(event->mval)};
+ MultiresModifierData *mmd = BKE_sculpt_multires_active(CTX_data_scene(C), ob);
+ BKE_sculpt_mask_layers_ensure(depsgraph, CTX_data_main(C), ob, mmd);
+
+ BKE_sculpt_update_object_for_edit(depsgraph, ob, true, true, false);
+
SCULPT_vertex_random_access_ensure(ss);
op->customdata = MEM_mallocN(sizeof(float[2]), "initial mouse position");
@@ -338,8 +344,6 @@ static int sculpt_mask_expand_invoke(bContext *C, wmOperator *op, const wmEvent
SCULPT_cursor_geometry_info_update(C, &sgi, mval_fl, false);
- BKE_sculpt_update_object_for_edit(depsgraph, ob, true, true, false);
-
int vertex_count = SCULPT_vertex_count_get(ss);
ss->filter_cache = MEM_callocN(sizeof(FilterCache), "filter cache");
diff --git a/source/blender/editors/sculpt_paint/sculpt_mask_init.c b/source/blender/editors/sculpt_paint/sculpt_mask_init.c
index 5d7ef9aab15..99a7bb8a926 100644
--- a/source/blender/editors/sculpt_paint/sculpt_mask_init.c
+++ b/source/blender/editors/sculpt_paint/sculpt_mask_init.c
@@ -15,6 +15,7 @@
#include "DNA_brush_types.h"
#include "DNA_meshdata_types.h"
+#include "DNA_modifier_types.h"
#include "DNA_object_types.h"
#include "BKE_ccg.h"
@@ -110,6 +111,9 @@ static int sculpt_mask_init_exec(bContext *C, wmOperator *op)
const int mode = RNA_enum_get(op->ptr, "mode");
+ MultiresModifierData *mmd = BKE_sculpt_multires_active(CTX_data_scene(C), ob);
+ BKE_sculpt_mask_layers_ensure(depsgraph, CTX_data_main(C), ob, mmd);
+
BKE_sculpt_update_object_for_edit(depsgraph, ob, true, true, false);
PBVH *pbvh = ob->sculpt->pbvh;
diff --git a/source/blender/editors/sculpt_paint/sculpt_ops.c b/source/blender/editors/sculpt_paint/sculpt_ops.c
index 1042356489b..a740ec2773b 100644
--- a/source/blender/editors/sculpt_paint/sculpt_ops.c
+++ b/source/blender/editors/sculpt_paint/sculpt_ops.c
@@ -21,6 +21,7 @@
#include "DNA_listBase.h"
#include "DNA_mesh_types.h"
#include "DNA_meshdata_types.h"
+#include "DNA_modifier_types.h"
#include "DNA_node_types.h"
#include "DNA_object_types.h"
#include "DNA_scene_types.h"
@@ -1041,12 +1042,12 @@ static int sculpt_bake_cavity_exec(bContext *C, wmOperator *op)
Sculpt *sd = CTX_data_tool_settings(C)->sculpt;
Brush *brush = BKE_paint_brush(&sd->paint);
+ MultiresModifierData *mmd = BKE_sculpt_multires_active(CTX_data_scene(C), ob);
+ BKE_sculpt_mask_layers_ensure(depsgraph, CTX_data_main(C), ob, mmd);
+
BKE_sculpt_update_object_for_edit(depsgraph, ob, true, true, false);
SCULPT_vertex_random_access_ensure(ss);
- MultiresModifierData *mmd = BKE_sculpt_multires_active(CTX_data_scene(C), ob);
- BKE_sculpt_mask_layers_ensure(ob, mmd);
-
SCULPT_undo_push_begin(ob, op);
CavityBakeMixMode mode = RNA_enum_get(op->ptr, "mix_mode");
@@ -1116,10 +1117,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 +1292,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..486f9f9ccb0 100644
--- a/source/blender/editors/space_clip/clip_ops.c
+++ b/source/blender/editors/space_clip/clip_ops.c
@@ -201,7 +201,7 @@ static int open_exec(bContext *C, wmOperator *op)
RNA_property_collection_lookup_int(op->ptr, prop, 0, &fileptr);
RNA_string_get(&fileptr, "name", file_only);
- BLI_join_dirfile(str, sizeof(str), dir_only, file_only);
+ BLI_path_join(str, sizeof(str), dir_only, file_only);
}
else {
BKE_report(op->reports, RPT_ERROR, "No files selected to be opened");
@@ -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_file/file_draw.c b/source/blender/editors/space_file/file_draw.c
index 554b628ba0f..240901318b5 100644
--- a/source/blender/editors/space_file/file_draw.c
+++ b/source/blender/editors/space_file/file_draw.c
@@ -410,8 +410,15 @@ static void file_draw_preview(const SpaceFile *sfile,
}
icon_x = xco + (ex / 2.0f) - (icon_size / 2.0f);
icon_y = yco + (ey / 2.0f) - (icon_size * ((file->typeflag & FILE_TYPE_DIR) ? 0.78f : 0.75f));
- UI_icon_draw_ex(
- icon_x, icon_y, icon, icon_aspect / U.dpi_fac, icon_opacity, 0.0f, icon_color, false);
+ UI_icon_draw_ex(icon_x,
+ icon_y,
+ icon,
+ icon_aspect / U.dpi_fac,
+ icon_opacity,
+ 0.0f,
+ icon_color,
+ false,
+ UI_NO_ICON_OVERLAY_TEXT);
}
if (is_link || is_offline) {
@@ -424,8 +431,24 @@ static void file_draw_preview(const SpaceFile *sfile,
/* At very bottom-left if preview style. */
const uchar dark[4] = {0, 0, 0, 255};
const uchar light[4] = {255, 255, 255, 255};
- UI_icon_draw_ex(icon_x + 1, icon_y - 1, arrow, 1.0f / U.dpi_fac, 0.2f, 0.0f, dark, false);
- UI_icon_draw_ex(icon_x, icon_y, arrow, 1.0f / U.dpi_fac, 0.6f, 0.0f, light, false);
+ UI_icon_draw_ex(icon_x + 1,
+ icon_y - 1,
+ arrow,
+ 1.0f / U.dpi_fac,
+ 0.2f,
+ 0.0f,
+ dark,
+ false,
+ UI_NO_ICON_OVERLAY_TEXT);
+ UI_icon_draw_ex(icon_x,
+ icon_y,
+ arrow,
+ 1.0f / U.dpi_fac,
+ 0.6f,
+ 0.0f,
+ light,
+ false,
+ UI_NO_ICON_OVERLAY_TEXT);
}
else {
/* Link to folder or non-previewed file. */
@@ -433,8 +456,15 @@ static void file_draw_preview(const SpaceFile *sfile,
UI_GetThemeColor4ubv(TH_BACK, icon_color);
icon_x = xco + ((file->typeflag & FILE_TYPE_DIR) ? 0.14f : 0.23f) * scaledx;
icon_y = yco + ((file->typeflag & FILE_TYPE_DIR) ? 0.24f : 0.14f) * scaledy;
- UI_icon_draw_ex(
- icon_x, icon_y, arrow, icon_aspect / U.dpi_fac * 1.8, 0.3f, 0.0f, icon_color, false);
+ UI_icon_draw_ex(icon_x,
+ icon_y,
+ arrow,
+ icon_aspect / U.dpi_fac * 1.8,
+ 0.3f,
+ 0.0f,
+ icon_color,
+ false,
+ UI_NO_ICON_OVERLAY_TEXT);
}
}
else if (icon && !is_icon && !(file->typeflag & FILE_TYPE_FTFONT)) {
@@ -444,8 +474,17 @@ static void file_draw_preview(const SpaceFile *sfile,
const uchar light[4] = {255, 255, 255, 255};
icon_x = xco + (2.0f * UI_DPI_FAC);
icon_y = yco + (2.0f * UI_DPI_FAC);
- UI_icon_draw_ex(icon_x + 1, icon_y - 1, icon, 1.0f / U.dpi_fac, 0.2f, 0.0f, dark, false);
- UI_icon_draw_ex(icon_x, icon_y, icon, 1.0f / U.dpi_fac, 0.6f, 0.0f, light, false);
+ UI_icon_draw_ex(icon_x + 1,
+ icon_y - 1,
+ icon,
+ 1.0f / U.dpi_fac,
+ 0.2f,
+ 0.0f,
+ dark,
+ false,
+ UI_NO_ICON_OVERLAY_TEXT);
+ UI_icon_draw_ex(
+ icon_x, icon_y, icon, 1.0f / U.dpi_fac, 0.6f, 0.0f, light, false, UI_NO_ICON_OVERLAY_TEXT);
}
const bool is_current_main_data = filelist_file_get_id(file) != NULL;
@@ -456,7 +495,15 @@ static void file_draw_preview(const SpaceFile *sfile,
const uchar light[4] = {255, 255, 255, 255};
icon_x = xco + ex - UI_UNIT_X;
icon_y = yco + ey - UI_UNIT_Y;
- UI_icon_draw_ex(icon_x, icon_y, ICON_CURRENT_FILE, 1.0f / U.dpi_fac, 0.6f, 0.0f, light, false);
+ UI_icon_draw_ex(icon_x,
+ icon_y,
+ ICON_CURRENT_FILE,
+ 1.0f / U.dpi_fac,
+ 0.6f,
+ 0.0f,
+ light,
+ false,
+ UI_NO_ICON_OVERLAY_TEXT);
}
/* Contrasting outline around some preview types. */
@@ -544,10 +591,10 @@ static void renamebutton_cb(bContext *C, void *UNUSED(arg1), char *oldname)
ARegion *region = CTX_wm_region(C);
FileSelectParams *params = ED_fileselect_get_active_params(sfile);
- BLI_join_dirfile(orgname, sizeof(orgname), params->dir, oldname);
+ BLI_path_join(orgname, sizeof(orgname), params->dir, oldname);
BLI_strncpy(filename, params->renamefile, sizeof(filename));
BLI_filename_make_safe(filename);
- BLI_join_dirfile(newname, sizeof(newname), params->dir, filename);
+ BLI_path_join(newname, sizeof(newname), params->dir, filename);
if (!STREQ(orgname, newname)) {
if (!BLI_exists(newname)) {
@@ -952,7 +999,7 @@ void file_draw_list(const bContext *C, ARegion *region)
file = filelist_file(files, i);
file_selflag = filelist_entry_select_get(sfile->files, file, CHECK_ALL);
- BLI_join_dirfile(path, sizeof(path), root, file->relpath);
+ BLI_path_join(path, sizeof(path), root, file->relpath);
if (!(file_selflag & FILE_SEL_EDITING)) {
if ((params->highlight_file == i) || (file_selflag & FILE_SEL_HIGHLIGHTED) ||
diff --git a/source/blender/editors/space_file/file_ops.c b/source/blender/editors/space_file/file_ops.c
index f7fd910d6e9..a4d4bf98474 100644
--- a/source/blender/editors/space_file/file_ops.c
+++ b/source/blender/editors/space_file/file_ops.c
@@ -386,7 +386,7 @@ static bool fsmenu_write_file_and_refresh_or_report_error(struct FSMenu *fsmenu,
}
char filepath[FILE_MAX];
- BLI_join_dirfile(filepath, sizeof(filepath), cfgdir, BLENDER_BOOKMARK_FILE);
+ BLI_path_join(filepath, sizeof(filepath), cfgdir, BLENDER_BOOKMARK_FILE);
if (UNLIKELY(!fsmenu_write_file(fsmenu, filepath))) {
BKE_reportf(reports, RPT_ERROR, "Unable to open or write bookmark file \"%s\"", filepath);
return false;
@@ -1564,7 +1564,7 @@ void file_sfile_to_operator_ex(
PropertyRNA *prop;
/* XXX, not real length */
- BLI_join_dirfile(filepath, FILE_MAX, params->dir, params->file);
+ BLI_path_join(filepath, FILE_MAX, params->dir, params->file);
if ((prop = RNA_struct_find_property(op->ptr, "relative_path"))) {
if (RNA_property_boolean_get(op->ptr, prop)) {
@@ -1741,7 +1741,7 @@ bool file_draw_check_exists(SpaceFile *sfile)
const FileSelectParams *params = ED_fileselect_get_active_params(sfile);
if (params && (params->flag & FILE_CHECK_EXISTING)) {
char filepath[FILE_MAX];
- BLI_join_dirfile(filepath, sizeof(filepath), params->dir, params->file);
+ BLI_path_join(filepath, sizeof(filepath), params->dir, params->file);
if (BLI_is_file(filepath)) {
return true;
}
@@ -2311,13 +2311,13 @@ static bool new_folder_path(const char *parent, char folder[FILE_MAX], char name
int len = 0;
BLI_strncpy(name, "New Folder", FILE_MAXFILE);
- BLI_join_dirfile(folder, FILE_MAX, parent, name);
+ BLI_path_join(folder, FILE_MAX, parent, name);
/* check whether folder with the name already exists, in this case
* add number to the name. Check length of generated name to avoid
* crazy case of huge number of folders each named 'New Folder (x)' */
while (BLI_exists(folder) && (len < FILE_MAXFILE)) {
len = BLI_snprintf(name, FILE_MAXFILE, "New Folder(%d)", i);
- BLI_join_dirfile(folder, FILE_MAX, parent, name);
+ BLI_path_join(folder, FILE_MAX, parent, name);
i++;
}
@@ -2457,8 +2457,7 @@ static void file_expand_directory(bContext *C)
else if (params->dir[0] == '~') {
char tmpstr[sizeof(params->dir) - 1];
BLI_strncpy(tmpstr, params->dir + 1, sizeof(tmpstr));
- BLI_path_join(
- params->dir, sizeof(params->dir), BKE_appdir_folder_default_or_root(), tmpstr, NULL);
+ BLI_path_join(params->dir, sizeof(params->dir), BKE_appdir_folder_default_or_root(), tmpstr);
}
else if (params->dir[0] == '\0')
@@ -2622,7 +2621,7 @@ void file_filename_enter_handle(bContext *C, void *UNUSED(arg_unused), void *arg
}
if (matches == 1) {
- BLI_join_dirfile(filepath, sizeof(params->dir), params->dir, params->file);
+ BLI_path_join(filepath, sizeof(params->dir), params->dir, params->file);
/* if directory, open it and empty filename field */
if (filelist_is_dir(sfile->files, filepath)) {
@@ -2850,7 +2849,7 @@ static bool file_delete_single(const FileSelectParams *params,
const char **r_error_message)
{
char str[FILE_MAX];
- BLI_join_dirfile(str, sizeof(str), params->dir, file->relpath);
+ BLI_path_join(str, sizeof(str), params->dir, file->relpath);
if (BLI_delete_soft(str, r_error_message) != 0 || BLI_exists(str)) {
return false;
}
diff --git a/source/blender/editors/space_file/filelist.cc b/source/blender/editors/space_file/filelist.cc
index c2dc8e9196d..f177eebf6f2 100644
--- a/source/blender/editors/space_file/filelist.cc
+++ b/source/blender/editors/space_file/filelist.cc
@@ -115,6 +115,9 @@ struct FileListInternEntry {
* Owning pointer. */
AssetMetaData *imported_asset_data;
+ /* See #FILE_ENTRY_BLENDERLIB_NO_PREVIEW. */
+ bool blenderlib_has_no_preview;
+
/** Defined in BLI_fileops.h */
eFileAttributes attributes;
BLI_stat_t st;
@@ -844,7 +847,7 @@ static bool is_filtered_lib_type(FileListInternEntry *file,
{
char path[FILE_MAX_LIBEXTRA], dir[FILE_MAX_LIBEXTRA], *group, *name;
- BLI_join_dirfile(path, sizeof(path), root, file->relpath);
+ BLI_path_join(path, sizeof(path), root, file->relpath);
if (BLO_library_path_explode(path, dir, &group, &name)) {
return is_filtered_id_file_type(file, group, name, filter);
@@ -1204,7 +1207,7 @@ static int filelist_geticon_ex(const FileDirEntry *file,
target = file->redirection_path;
}
else if (root) {
- BLI_join_dirfile(fullpath, sizeof(fullpath), root, file->relpath);
+ BLI_path_join(fullpath, sizeof(fullpath), root, file->relpath);
BLI_path_slash_ensure(fullpath);
}
for (; tfsm; tfsm = tfsm->next) {
@@ -1575,6 +1578,14 @@ static void filelist_cache_previews_push(FileList *filelist, FileDirEntry *entry
return;
}
+ /* If we know this is an external ID without a preview, skip loading the preview. Can save quite
+ * some time in heavy files, because otherwise for each missing preview and for each preview
+ * reload, we'd reopen the .blend to look for the preview. */
+ if ((entry->typeflag & FILE_TYPE_BLENDERLIB) &&
+ (entry->flags & FILE_ENTRY_BLENDERLIB_NO_PREVIEW)) {
+ return;
+ }
+
FileListInternEntry *intern_entry = filelist->filelist_intern.filtered[index];
PreviewImage *preview_in_memory = intern_entry->local_data.preview_image;
if (preview_in_memory && !BKE_previewimg_is_finished(preview_in_memory, ICON_SIZE_PREVIEW)) {
@@ -1606,7 +1617,7 @@ static void filelist_cache_previews_push(FileList *filelist, FileDirEntry *entry
BLI_strncpy(preview->filepath, entry->redirection_path, FILE_MAXDIR);
}
else {
- BLI_join_dirfile(
+ BLI_path_join(
preview->filepath, sizeof(preview->filepath), filelist->filelist.root, entry->relpath);
}
// printf("%s: %d - %s\n", __func__, preview->index, preview->filepath);
@@ -1894,7 +1905,7 @@ static char *fileentry_uiname(const char *root,
if (typeflag & FILE_TYPE_FTFONT && !(typeflag & FILE_TYPE_BLENDERLIB)) {
char abspath[FILE_MAX_LIBEXTRA];
- BLI_join_dirfile(abspath, sizeof(abspath), root, relpath);
+ BLI_path_join(abspath, sizeof(abspath), root, relpath);
name = BLF_display_name_from_file(abspath);
if (name) {
/* Allocated string, so no need to #BLI_strdup. */
@@ -1906,7 +1917,7 @@ static char *fileentry_uiname(const char *root,
char abspath[FILE_MAX_LIBEXTRA];
char *group;
- BLI_join_dirfile(abspath, sizeof(abspath), root, relpath);
+ BLI_path_join(abspath, sizeof(abspath), root, relpath);
BLO_library_path_explode(abspath, buff, &group, &name);
if (!name) {
name = group;
@@ -2042,6 +2053,9 @@ static FileDirEntry *filelist_file_create_entry(FileList *filelist, const int in
ret->preview_icon_id = BKE_icon_imbuf_create(ibuf);
}
}
+ if (entry->blenderlib_has_no_preview) {
+ ret->flags |= FILE_ENTRY_BLENDERLIB_NO_PREVIEW;
+ }
BLI_addtail(&cache->cached_entries, ret);
return ret;
}
@@ -2887,7 +2901,7 @@ static int filelist_readjob_list_dir(const char *root,
entry->relpath = static_cast<char *>(MEM_dupallocN(files[i].relname));
entry->st = files[i].s;
- BLI_join_dirfile(full_path, FILE_MAX, root, entry->relpath);
+ BLI_path_join(full_path, FILE_MAX, root, entry->relpath);
char *target = full_path;
/* Set initial file type and attributes. */
@@ -2995,10 +3009,15 @@ static void filelist_readjob_list_lib_add_datablock(ListBase *entries,
entry->relpath = BLI_strdup(datablock_info->name);
}
entry->typeflag |= FILE_TYPE_BLENDERLIB;
- if (datablock_info && datablock_info->asset_data) {
- entry->typeflag |= FILE_TYPE_ASSET;
- /* Moves ownership! */
- entry->imported_asset_data = datablock_info->asset_data;
+
+ if (datablock_info) {
+ entry->blenderlib_has_no_preview = datablock_info->no_preview_found;
+
+ if (datablock_info->asset_data) {
+ entry->typeflag |= FILE_TYPE_ASSET;
+ /* Moves ownership! */
+ entry->imported_asset_data = datablock_info->asset_data;
+ }
}
entry->blentype = idcode;
BLI_addtail(entries, entry);
@@ -3525,7 +3544,7 @@ static void filelist_readjob_recursive_dir_add_items(const bool do_lib,
/* When loading entries recursive, the rel_path should be relative from the root dir.
* we combine the relative path to the subdir with the relative path of the entry. */
- BLI_join_dirfile(dir, sizeof(dir), rel_subdir, entry->relpath);
+ BLI_path_join(dir, sizeof(dir), rel_subdir, entry->relpath);
MEM_freeN(entry->relpath);
entry->relpath = BLI_strdup(dir + 2); /* + 2 to remove '//'
* added by BLI_path_rel to rel_subdir. */
@@ -3535,7 +3554,7 @@ static void filelist_readjob_recursive_dir_add_items(const bool do_lib,
if (filelist_readjob_should_recurse_into_entry(
max_recursion, is_lib, recursion_level, entry)) {
/* We have a directory we want to list, add it to todo list! */
- BLI_join_dirfile(dir, sizeof(dir), root, entry->relpath);
+ BLI_path_join(dir, sizeof(dir), root, entry->relpath);
BLI_path_normalize_dir(job_params->main_name, dir);
td_dir = static_cast<TodoDir *>(BLI_stack_push_r(todo_dirs));
td_dir->level = recursion_level + 1;
diff --git a/source/blender/editors/space_file/filesel.c b/source/blender/editors/space_file/filesel.c
index 9ebc4872544..df7e9702e85 100644
--- a/source/blender/editors/space_file/filesel.c
+++ b/source/blender/editors/space_file/filesel.c
@@ -1174,7 +1174,7 @@ int autocomplete_directory(struct bContext *C, char *str, void *UNUSED(arg_v))
char path[FILE_MAX];
BLI_stat_t status;
- BLI_join_dirfile(path, sizeof(path), dirname, de->d_name);
+ BLI_path_join(path, sizeof(path), dirname, de->d_name);
if (BLI_stat(path, &status) == 0) {
if (S_ISDIR(status.st_mode)) { /* is subdir */
diff --git a/source/blender/editors/space_file/fsmenu.c b/source/blender/editors/space_file/fsmenu.c
index 35ce7ef364c..cea53908d4f 100644
--- a/source/blender/editors/space_file/fsmenu.c
+++ b/source/blender/editors/space_file/fsmenu.c
@@ -113,10 +113,10 @@ static GHash *fsmenu_xdg_user_dirs_parse(const char *home)
char filepath[FILE_MAX];
const char *xdg_config_home = getenv("XDG_CONFIG_HOME");
if (xdg_config_home != NULL) {
- BLI_path_join(filepath, sizeof(filepath), xdg_config_home, "user-dirs.dirs", NULL);
+ BLI_path_join(filepath, sizeof(filepath), xdg_config_home, "user-dirs.dirs");
}
else {
- BLI_path_join(filepath, sizeof(filepath), home, ".config", "user-dirs.dirs", NULL);
+ BLI_path_join(filepath, sizeof(filepath), home, ".config", "user-dirs.dirs");
}
fp = BLI_fopen(filepath, "r");
if (!fp) {
@@ -147,7 +147,7 @@ static GHash *fsmenu_xdg_user_dirs_parse(const char *home)
* Based on the 'user-dirs.dirs' man page,
* there is no need to resolve arbitrary environment variables. */
if (STRPREFIX(l_value, "$HOME" SEP_STR)) {
- BLI_path_join(l_value_expanded, sizeof(l_value_expanded), home, l_value + 6, NULL);
+ BLI_path_join(l_value_expanded, sizeof(l_value_expanded), home, l_value + 6);
l_value_final = l_value_expanded;
}
@@ -186,7 +186,7 @@ static void fsmenu_xdg_insert_entry(GHash *xdg_map,
char xdg_path_buf[FILE_MAXDIR];
const char *xdg_path = xdg_map ? BLI_ghash_lookup(xdg_map, key) : NULL;
if (xdg_path == NULL) {
- BLI_path_join(xdg_path_buf, sizeof(xdg_path_buf), home, default_path, NULL);
+ BLI_path_join(xdg_path_buf, sizeof(xdg_path_buf), home, default_path);
xdg_path = xdg_path_buf;
}
fsmenu_insert_entry(
@@ -254,10 +254,10 @@ void ED_fsmenu_entry_set_path(struct FSMenuEntry *fsentry, const char *path)
fsentry->path = (path && path[0]) ? BLI_strdup(path) : NULL;
- BLI_join_dirfile(tmp_name,
- sizeof(tmp_name),
- BKE_appdir_folder_id_create(BLENDER_USER_CONFIG, NULL),
- BLENDER_BOOKMARK_FILE);
+ BLI_path_join(tmp_name,
+ sizeof(tmp_name),
+ BKE_appdir_folder_id_create(BLENDER_USER_CONFIG, NULL),
+ BLENDER_BOOKMARK_FILE);
fsmenu_write_file(ED_fsmenu_get(), tmp_name);
}
}
@@ -318,10 +318,10 @@ void ED_fsmenu_entry_set_name(struct FSMenuEntry *fsentry, const char *name)
BLI_strncpy(fsentry->name, name, sizeof(fsentry->name));
}
- BLI_join_dirfile(tmp_name,
- sizeof(tmp_name),
- BKE_appdir_folder_id_create(BLENDER_USER_CONFIG, NULL),
- BLENDER_BOOKMARK_FILE);
+ BLI_path_join(tmp_name,
+ sizeof(tmp_name),
+ BKE_appdir_folder_id_create(BLENDER_USER_CONFIG, NULL),
+ BLENDER_BOOKMARK_FILE);
fsmenu_write_file(ED_fsmenu_get(), tmp_name);
}
}
@@ -983,7 +983,7 @@ void fsmenu_read_system(struct FSMenu *fsmenu, int read_bookmarks)
if (xdg_runtime_dir != NULL) {
struct direntry *dirs;
char name[FILE_MAX];
- BLI_join_dirfile(name, sizeof(name), xdg_runtime_dir, "gvfs/");
+ BLI_path_join(name, sizeof(name), xdg_runtime_dir, "gvfs/");
const uint dirs_num = BLI_filelist_dir_contents(name, &dirs);
for (uint i = 0; i < dirs_num; i++) {
if (dirs[i].type & S_IFDIR) {
diff --git a/source/blender/editors/space_file/space_file.c b/source/blender/editors/space_file/space_file.c
index a3182222263..74f1b8e838a 100644
--- a/source/blender/editors/space_file/space_file.c
+++ b/source/blender/editors/space_file/space_file.c
@@ -1157,7 +1157,7 @@ void ED_file_read_bookmarks(void)
if (cfgdir) {
char name[FILE_MAX];
- BLI_join_dirfile(name, sizeof(name), cfgdir, BLENDER_BOOKMARK_FILE);
+ BLI_path_join(name, sizeof(name), cfgdir, BLENDER_BOOKMARK_FILE);
fsmenu_read_bookmarks(ED_fsmenu_get(), name);
}
}
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/image_sequence.c b/source/blender/editors/space_image/image_sequence.c
index 7108c258665..d2725652979 100644
--- a/source/blender/editors/space_image/image_sequence.c
+++ b/source/blender/editors/space_image/image_sequence.c
@@ -62,14 +62,14 @@ static void image_sequence_get_frame_ranges(wmOperator *op, ListBase *ranges)
STREQLEN(base_tail, tail, FILE_MAX)) {
/* Set filepath to first frame in the range. */
if (frame->framenr < range_first_frame) {
- BLI_join_dirfile(range->filepath, sizeof(range->filepath), dir, filename);
+ BLI_path_join(range->filepath, sizeof(range->filepath), dir, filename);
range_first_frame = frame->framenr;
}
}
else {
/* start a new frame range */
range = MEM_callocN(sizeof(*range), __func__);
- BLI_join_dirfile(range->filepath, sizeof(range->filepath), dir, filename);
+ BLI_path_join(range->filepath, sizeof(range->filepath), dir, filename);
BLI_addtail(ranges, range);
BLI_strncpy(base_head, head, sizeof(base_head));
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_info/textview.c b/source/blender/editors/space_info/textview.c
index aee72860a0a..12ee6f45991 100644
--- a/source/blender/editors/space_info/textview.c
+++ b/source/blender/editors/space_info/textview.c
@@ -235,7 +235,8 @@ static bool textview_draw_string(TextViewDrawState *tds,
1.0f,
0.0f,
icon_fg,
- false);
+ false,
+ UI_NO_ICON_OVERLAY_TEXT);
GPU_blend(GPU_BLEND_NONE);
}
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..98b2cacd162 100644
--- a/source/blender/editors/space_node/node_draw.cc
+++ b/source/blender/editors/space_node/node_draw.cc
@@ -2145,6 +2145,9 @@ static void node_draw_basis(const bContext &C,
0,
"");
UI_but_func_set(but, node_toggle_button_cb, &node, (void *)"NODE_OT_group_edit");
+ if (node.id) {
+ UI_but_icon_indicator_number_set(but, node.id->us);
+ }
UI_block_emboss_set(&block, UI_EMBOSS);
}
if (node.type == NODE_CUSTOM && node.typeinfo->ui_icon != ICON_NONE) {
@@ -3011,7 +3014,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..637c795d4d7 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
* \{ */
@@ -815,7 +815,8 @@ static void draw_draglink_tooltip(const bContext * /*C*/, ARegion * /*region*/,
nldrag->cursor[0];
const float y = nldrag->cursor[1] - 2.0f * UI_DPI_FAC;
- UI_icon_draw_ex(x, y, ICON_ADD, U.inv_dpi_fac, 1.0f, 0.0f, text_col, false);
+ UI_icon_draw_ex(
+ x, y, ICON_ADD, U.inv_dpi_fac, 1.0f, 0.0f, text_col, false, UI_NO_ICON_OVERLAY_TEXT);
}
static void draw_draglink_tooltip_activate(const ARegion &region, bNodeLinkDrag &nldrag)
@@ -1750,29 +1751,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 +1884,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 +1944,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 +1967,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 +2086,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 +2464,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..699dd6d4844 100644
--- a/source/blender/editors/space_outliner/outliner_draw.cc
+++ b/source/blender/editors/space_outliner/outliner_draw.cc
@@ -2877,7 +2877,8 @@ static bool tselem_draw_icon(uiBlock *block,
TreeStoreElem *tselem,
TreeElement *te,
float alpha,
- const bool is_clickable)
+ const bool is_clickable,
+ const int num_elements)
{
TreeElementIcon data = tree_element_get_icon(tselem, te);
if (data.icon == 0) {
@@ -2885,6 +2886,8 @@ static bool tselem_draw_icon(uiBlock *block,
}
const bool is_collection = outliner_is_collection_tree_element(te);
+ IconTextOverlay text_overlay;
+ UI_icon_text_overlay_init_from_count(&text_overlay, num_elements);
/* Collection colors and icons covered by restrict buttons. */
if (!is_clickable || x >= xmax || is_collection) {
@@ -2904,7 +2907,8 @@ static bool tselem_draw_icon(uiBlock *block,
alpha,
0.0f,
btheme->collection_color[collection->color_tag].color,
- true);
+ true,
+ &text_overlay);
return true;
}
}
@@ -2915,10 +2919,10 @@ static bool tselem_draw_icon(uiBlock *block,
/* Restrict column clip. it has been coded by simply overdrawing, doesn't work for buttons. */
uchar color[4];
if (UI_icon_get_theme_color(data.icon, color)) {
- UI_icon_draw_ex(x, y, data.icon, U.inv_dpi_fac, alpha, 0.0f, color, true);
+ UI_icon_draw_ex(x, y, data.icon, U.inv_dpi_fac, alpha, 0.0f, color, true, &text_overlay);
}
else {
- UI_icon_draw_ex(x, y, data.icon, U.inv_dpi_fac, alpha, 0.0f, nullptr, false);
+ UI_icon_draw_ex(x, y, data.icon, U.inv_dpi_fac, alpha, 0.0f, nullptr, false, &text_overlay);
}
}
else {
@@ -2941,53 +2945,6 @@ static bool tselem_draw_icon(uiBlock *block,
return true;
}
-/**
- * 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,
- int offsx,
- int ys,
- const int num_elements)
-{
- const float color[4] = {0.0f, 0.0f, 0.0f, 1.0f};
- float ufac = 0.25f * UI_UNIT_X;
- float offset_x = float(offsx) + UI_UNIT_X * 0.35f;
- rctf rect{};
- BLI_rctf_init(&rect,
- offset_x + ufac,
- offset_x + UI_UNIT_X - ufac,
- float(ys) - UI_UNIT_Y * 0.2f + ufac,
- float(ys) - UI_UNIT_Y * 0.2f + UI_UNIT_Y - ufac);
-
- UI_draw_roundbox_corner_set(UI_CNR_ALL);
- UI_draw_roundbox_aa(&rect, true, float(UI_UNIT_Y) / 2.0f - ufac, color);
-
- /* Now the numbers. */
- uchar text_col[4];
-
- UI_GetThemeColor3ubv(TH_TEXT_HI, text_col);
- text_col[3] = 255;
-
- uiFontStyle fstyle_small = *fstyle;
- fstyle_small.points *= 0.8f;
-
- /* We treat +99 as 4 digits to make sure the (eyeballed) alignment looks nice. */
- int num_digits = 4;
- char number_text[4] = "+99";
- if (num_elements < 100) {
- BLI_snprintf(number_text, sizeof(number_text), "%d", num_elements);
- num_digits = num_elements < 10 ? 1 : 2;
- }
- UI_fontstyle_draw_simple(&fstyle_small,
- (offset_x + ufac + UI_UNIT_X * (2 - num_digits) * 0.12f),
- float(ys) - UI_UNIT_Y * 0.095f + ufac,
- number_text,
- text_col);
- UI_fontstyle_set(fstyle);
- GPU_blend(GPU_BLEND_ALPHA); /* Round-box and text drawing disables. */
-}
-
static void outliner_icon_background_colors(float icon_color[4], float icon_border[4])
{
float text[4];
@@ -3020,7 +2977,6 @@ static void outliner_draw_active_indicator(const float minx,
static void outliner_draw_iconrow_doit(uiBlock *block,
TreeElement *te,
- const uiFontStyle *fstyle,
int xmax,
int *offsx,
int ys,
@@ -3049,13 +3005,13 @@ static void outliner_draw_iconrow_doit(uiBlock *block,
if (tselem->flag & TSE_HIGHLIGHTED_ICON) {
alpha_fac += 0.5;
}
- tselem_draw_icon(block, xmax, float(*offsx), float(ys), tselem, te, alpha_fac, false);
+ tselem_draw_icon(
+ block, xmax, float(*offsx), float(ys), tselem, te, alpha_fac, false, num_elements);
te->xs = *offsx;
te->ys = ys;
te->xend = short(*offsx) + UI_UNIT_X;
if (num_elements > 1) {
- outliner_draw_iconrow_number(fstyle, *offsx, ys, num_elements);
te->flag |= TE_ICONROW_MERGED;
}
else {
@@ -3098,6 +3054,7 @@ static void outliner_draw_iconrow(bContext *C,
int *offsx,
int ys,
float alpha_fac,
+ bool in_bone_hierarchy,
MergedIconRow *merged)
{
eOLDrawState active = OL_DRAWSEL_NONE;
@@ -3107,8 +3064,12 @@ static void outliner_draw_iconrow(bContext *C,
te->flag &= ~(TE_ICONROW | TE_ICONROW_MERGED);
/* object hierarchy always, further constrained on level */
+ /* Bones are also hierarchies and get a merged count, but we only start recursing into them if
+ * an they are at the root level of a collapsed subtree (e.g. not "hidden" in a collapsed
+ * collection). */
+ const bool is_bone = ELEM(tselem->type, TSE_BONE, TSE_EBONE, TSE_POSE_CHANNEL);
if ((level < 1) || ((tselem->type == TSE_SOME_ID) && (te->idcode == ID_OB)) ||
- ELEM(tselem->type, TSE_BONE, TSE_EBONE, TSE_POSE_CHANNEL)) {
+ (in_bone_hierarchy && is_bone)) {
/* active blocks get white circle */
if (tselem->type == TSE_SOME_ID) {
if (te->idcode == ID_OB) {
@@ -3139,7 +3100,7 @@ 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(block, te, xmax, offsx, ys, alpha_fac, active, 1);
}
else {
const int index = tree_element_id_type_to_index(te);
@@ -3151,8 +3112,13 @@ static void outliner_draw_iconrow(bContext *C,
}
}
- /* this tree element always has same amount of branches, so don't draw */
- if (tselem->type != TSE_R_LAYER) {
+ /* TSE_R_LAYER tree element always has same amount of branches, so don't draw. */
+ /* Also only recurse into bone hierarchies if a direct child of the collapsed element to merge
+ * into. */
+ const bool is_root_level_bone = is_bone && (level == 0);
+ in_bone_hierarchy |= is_root_level_bone;
+ if (!ELEM(tselem->type, TSE_R_LAYER, TSE_BONE, TSE_EBONE, TSE_POSE_CHANNEL) ||
+ in_bone_hierarchy) {
outliner_draw_iconrow(C,
block,
fstyle,
@@ -3164,6 +3130,7 @@ static void outliner_draw_iconrow(bContext *C,
offsx,
ys,
alpha_fac,
+ in_bone_hierarchy,
merged);
}
}
@@ -3181,7 +3148,6 @@ static void outliner_draw_iconrow(bContext *C,
if (merged->num_elements[index] != 0) {
outliner_draw_iconrow_doit(block,
merged->tree_element[index],
- fstyle,
xmax,
offsx,
ys,
@@ -3370,7 +3336,8 @@ static void outliner_draw_tree_element(bContext *C,
tselem,
te,
(tselem->flag & TSE_HIGHLIGHTED_ICON) ? alpha_fac + 0.5f : alpha_fac,
- true)) {
+ true,
+ 1)) {
offsx += UI_UNIT_X + 4 * ufac;
}
else {
@@ -3425,6 +3392,7 @@ static void outliner_draw_tree_element(bContext *C,
&tempx,
*starty,
alpha_fac,
+ false,
&merged);
GPU_blend(GPU_BLEND_NONE);
diff --git a/source/blender/editors/space_outliner/outliner_edit.cc b/source/blender/editors/space_outliner/outliner_edit.cc
index 6eca6fffece..9a6a25fdbae 100644
--- a/source/blender/editors/space_outliner/outliner_edit.cc
+++ b/source/blender/editors/space_outliner/outliner_edit.cc
@@ -809,7 +809,7 @@ static int outliner_id_copy_exec(bContext *C, wmOperator *op)
return OPERATOR_CANCELLED;
}
- BLI_join_dirfile(str, sizeof(str), BKE_tempdir_base(), "copybuffer.blend");
+ BLI_path_join(str, sizeof(str), BKE_tempdir_base(), "copybuffer.blend");
BKE_copybuffer_copy_end(bmain, str, op->reports);
BKE_reportf(op->reports, RPT_INFO, "Copied %d selected data-block(s)", num_ids);
@@ -843,7 +843,7 @@ static int outliner_id_paste_exec(bContext *C, wmOperator *op)
char str[FILE_MAX];
const short flag = FILE_AUTOSELECT | FILE_ACTIVE_COLLECTION;
- BLI_join_dirfile(str, sizeof(str), BKE_tempdir_base(), "copybuffer.blend");
+ BLI_path_join(str, sizeof(str), BKE_tempdir_base(), "copybuffer.blend");
const int num_pasted = BKE_copybuffer_paste(C, str, flag, op->reports, 0);
if (num_pasted == 0) {
diff --git a/source/blender/editors/space_sequencer/sequencer_add.c b/source/blender/editors/space_sequencer/sequencer_add.c
index 6ef8d7fd108..b17d0bfac4e 100644
--- a/source/blender/editors/space_sequencer/sequencer_add.c
+++ b/source/blender/editors/space_sequencer/sequencer_add.c
@@ -274,7 +274,7 @@ static void load_data_init_from_operator(SeqLoadData *load_data, bContext *C, wm
RNA_PROP_BEGIN (op->ptr, itemptr, prop) {
char *filename = RNA_string_get_alloc(&itemptr, "name", NULL, 0, NULL);
BLI_strncpy(load_data->name, filename, sizeof(load_data->name));
- BLI_join_dirfile(load_data->path, sizeof(load_data->path), directory, filename);
+ BLI_path_join(load_data->path, sizeof(load_data->path), directory, filename);
MEM_freeN(filename);
break;
}
@@ -834,7 +834,7 @@ static void sequencer_add_movie_multiple_strips(bContext *C,
char file_only[FILE_MAX];
RNA_string_get(op->ptr, "directory", dir_only);
RNA_string_get(&itemptr, "name", file_only);
- BLI_join_dirfile(load_data->path, sizeof(load_data->path), dir_only, file_only);
+ BLI_path_join(load_data->path, sizeof(load_data->path), dir_only, file_only);
BLI_strncpy(load_data->name, file_only, sizeof(load_data->name));
Sequence *seq_movie = NULL;
Sequence *seq_sound = NULL;
@@ -1082,7 +1082,7 @@ static void sequencer_add_sound_multiple_strips(bContext *C,
char file_only[FILE_MAX];
RNA_string_get(op->ptr, "directory", dir_only);
RNA_string_get(&itemptr, "name", file_only);
- BLI_join_dirfile(load_data->path, sizeof(load_data->path), dir_only, file_only);
+ BLI_path_join(load_data->path, sizeof(load_data->path), dir_only, file_only);
BLI_strncpy(load_data->name, file_only, sizeof(load_data->name));
Sequence *seq = SEQ_add_sound_strip(bmain, scene, ed->seqbasep, load_data);
if (seq == NULL) {
diff --git a/source/blender/editors/space_sequencer/sequencer_draw.c b/source/blender/editors/space_sequencer/sequencer_draw.c
index 201425dafab..a6916f9d031 100644
--- a/source/blender/editors/space_sequencer/sequencer_draw.c
+++ b/source/blender/editors/space_sequencer/sequencer_draw.c
@@ -804,7 +804,7 @@ static void draw_seq_text_get_source(Sequence *seq, char *r_source, size_t sourc
switch (seq->type) {
case SEQ_TYPE_IMAGE:
case SEQ_TYPE_MOVIE: {
- BLI_join_dirfile(r_source, source_len, seq->strip->dir, seq->strip->stripdata->name);
+ BLI_path_join(r_source, source_len, seq->strip->dir, seq->strip->stripdata->name);
break;
}
case SEQ_TYPE_SOUND_RAM: {
diff --git a/source/blender/editors/space_sequencer/sequencer_edit.c b/source/blender/editors/space_sequencer/sequencer_edit.c
index 2938513f130..c0c7782c60c 100644
--- a/source/blender/editors/space_sequencer/sequencer_edit.c
+++ b/source/blender/editors/space_sequencer/sequencer_edit.c
@@ -2939,7 +2939,7 @@ static int sequencer_change_path_invoke(bContext *C, wmOperator *op, const wmEve
Sequence *seq = SEQ_select_active_get(scene);
char filepath[FILE_MAX];
- BLI_join_dirfile(filepath, sizeof(filepath), seq->strip->dir, seq->strip->stripdata->name);
+ BLI_path_join(filepath, sizeof(filepath), seq->strip->dir, seq->strip->stripdata->name);
RNA_string_set(op->ptr, "directory", seq->strip->dir);
RNA_string_set(op->ptr, "filepath", filepath);
diff --git a/source/blender/editors/space_sequencer/space_sequencer.c b/source/blender/editors/space_sequencer/space_sequencer.c
index 8b6d37caa41..1d20926d16c 100644
--- a/source/blender/editors/space_sequencer/space_sequencer.c
+++ b/source/blender/editors/space_sequencer/space_sequencer.c
@@ -129,7 +129,6 @@ static SpaceLink *sequencer_create(const ScrArea *UNUSED(area), const Scene *sce
region->regiontype = RGN_TYPE_TOOLS;
region->alignment = RGN_ALIGN_LEFT;
region->flag = RGN_FLAG_HIDDEN;
- region->v2d.flag |= V2D_VIEWSYNC_AREA_VERTICAL;
/* Channels. */
region = MEM_callocN(sizeof(ARegion), "channels for sequencer");
@@ -137,6 +136,7 @@ static SpaceLink *sequencer_create(const ScrArea *UNUSED(area), const Scene *sce
BLI_addtail(&sseq->regionbase, region);
region->regiontype = RGN_TYPE_CHANNELS;
region->alignment = RGN_ALIGN_LEFT;
+ region->v2d.flag |= V2D_VIEWSYNC_AREA_VERTICAL;
/* Preview region. */
/* NOTE: if you change values here, also change them in sequencer_init_preview_region. */
diff --git a/source/blender/editors/space_spreadsheet/spreadsheet_column.cc b/source/blender/editors/space_spreadsheet/spreadsheet_column.cc
index 46e98acb8e8..af41225f42a 100644
--- a/source/blender/editors/space_spreadsheet/spreadsheet_column.cc
+++ b/source/blender/editors/space_spreadsheet/spreadsheet_column.cc
@@ -12,6 +12,7 @@
#include "BLI_string_ref.hh"
#include "BKE_geometry_set.hh"
+#include "BKE_instances.hh"
#include "spreadsheet_column.hh"
#include "spreadsheet_column_values.hh"
@@ -44,7 +45,7 @@ eSpreadsheetColumnValueType cpp_type_to_column_type(const CPPType &type)
if (type.is<std::string>()) {
return SPREADSHEET_VALUE_TYPE_STRING;
}
- if (type.is<InstanceReference>()) {
+ if (type.is<bke::InstanceReference>()) {
return SPREADSHEET_VALUE_TYPE_INSTANCES;
}
if (type.is<ColorGeometry4b>()) {
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..59a8daf4f4a 100644
--- a/source/blender/editors/space_spreadsheet/spreadsheet_data_source_geometry.cc
+++ b/source/blender/editors/space_spreadsheet/spreadsheet_data_source_geometry.cc
@@ -10,6 +10,7 @@
#include "BKE_editmesh.h"
#include "BKE_geometry_fields.hh"
#include "BKE_global.h"
+#include "BKE_instances.hh"
#include "BKE_lib_id.h"
#include "BKE_mesh.h"
#include "BKE_mesh_wrapper.h"
@@ -143,29 +144,31 @@ std::unique_ptr<ColumnValues> GeometryDataSource::get_column_values(
}
if (component_->type() == GEO_COMPONENT_TYPE_INSTANCES) {
- const InstancesComponent &instances = static_cast<const InstancesComponent &>(*component_);
- if (STREQ(column_id.name, "Name")) {
- Span<int> reference_handles = instances.instance_reference_handles();
- Span<InstanceReference> references = instances.references();
- return std::make_unique<ColumnValues>(
- column_id.name,
- VArray<InstanceReference>::ForFunc(domain_num,
- [reference_handles, references](int64_t index) {
- return references[reference_handles[index]];
- }));
- }
- Span<float4x4> transforms = instances.instance_transforms();
- if (STREQ(column_id.name, "Rotation")) {
- return std::make_unique<ColumnValues>(
- column_id.name, VArray<float3>::ForFunc(domain_num, [transforms](int64_t index) {
- return transforms[index].to_euler();
- }));
- }
- if (STREQ(column_id.name, "Scale")) {
- return std::make_unique<ColumnValues>(
- column_id.name, VArray<float3>::ForFunc(domain_num, [transforms](int64_t index) {
- return transforms[index].scale();
- }));
+ if (const bke::Instances *instances =
+ static_cast<const InstancesComponent &>(*component_).get_for_read()) {
+ if (STREQ(column_id.name, "Name")) {
+ Span<int> reference_handles = instances->reference_handles();
+ Span<bke::InstanceReference> references = instances->references();
+ return std::make_unique<ColumnValues>(
+ column_id.name,
+ VArray<bke::InstanceReference>::ForFunc(
+ domain_num, [reference_handles, references](int64_t index) {
+ return references[reference_handles[index]];
+ }));
+ }
+ Span<float4x4> transforms = instances->transforms();
+ if (STREQ(column_id.name, "Rotation")) {
+ return std::make_unique<ColumnValues>(
+ column_id.name, VArray<float3>::ForFunc(domain_num, [transforms](int64_t index) {
+ return transforms[index].to_euler();
+ }));
+ }
+ if (STREQ(column_id.name, "Scale")) {
+ return std::make_unique<ColumnValues>(
+ column_id.name, VArray<float3>::ForFunc(domain_num, [transforms](int64_t index) {
+ return transforms[index].scale();
+ }));
+ }
}
}
else if (G.debug_value == 4001 && component_->type() == GEO_COMPONENT_TYPE_MESH) {
@@ -487,37 +490,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_spreadsheet/spreadsheet_layout.cc b/source/blender/editors/space_spreadsheet/spreadsheet_layout.cc
index b4b8417c172..06eb338bd00 100644
--- a/source/blender/editors/space_spreadsheet/spreadsheet_layout.cc
+++ b/source/blender/editors/space_spreadsheet/spreadsheet_layout.cc
@@ -6,6 +6,7 @@
#include "BLI_math_vec_types.hh"
#include "BKE_geometry_set.hh"
+#include "BKE_instances.hh"
#include "spreadsheet_column_values.hh"
#include "spreadsheet_layout.hh"
@@ -197,10 +198,10 @@ class SpreadsheetLayoutDrawer : public SpreadsheetDrawer {
const ColorGeometry4b value = data.get<ColorGeometry4b>(real_index);
this->draw_byte_color(params, value);
}
- else if (data.type().is<InstanceReference>()) {
- const InstanceReference value = data.get<InstanceReference>(real_index);
+ else if (data.type().is<bke::InstanceReference>()) {
+ const bke::InstanceReference value = data.get<bke::InstanceReference>(real_index);
switch (value.type()) {
- case InstanceReference::Type::Object: {
+ case bke::InstanceReference::Type::Object: {
const Object &object = value.object();
uiDefIconTextBut(params.block,
UI_BTYPE_LABEL,
@@ -219,7 +220,7 @@ class SpreadsheetLayoutDrawer : public SpreadsheetDrawer {
nullptr);
break;
}
- case InstanceReference::Type::Collection: {
+ case bke::InstanceReference::Type::Collection: {
Collection &collection = value.collection();
uiDefIconTextBut(params.block,
UI_BTYPE_LABEL,
@@ -238,7 +239,7 @@ class SpreadsheetLayoutDrawer : public SpreadsheetDrawer {
nullptr);
break;
}
- case InstanceReference::Type::GeometrySet: {
+ case bke::InstanceReference::Type::GeometrySet: {
uiDefIconTextBut(params.block,
UI_BTYPE_LABEL,
0,
@@ -256,7 +257,7 @@ class SpreadsheetLayoutDrawer : public SpreadsheetDrawer {
nullptr);
break;
}
- case InstanceReference::Type::None: {
+ case bke::InstanceReference::Type::None: {
break;
}
}
diff --git a/source/blender/editors/space_spreadsheet/spreadsheet_row_filter.cc b/source/blender/editors/space_spreadsheet/spreadsheet_row_filter.cc
index 96827692a25..3586389b00b 100644
--- a/source/blender/editors/space_spreadsheet/spreadsheet_row_filter.cc
+++ b/source/blender/editors/space_spreadsheet/spreadsheet_row_filter.cc
@@ -14,6 +14,8 @@
#include "RNA_access.h"
+#include "BKE_instances.hh"
+
#include "spreadsheet_data_source_geometry.hh"
#include "spreadsheet_intern.hh"
#include "spreadsheet_layout.hh"
@@ -280,22 +282,22 @@ static void apply_row_filter(const SpreadsheetRowFilter &row_filter,
}
}
}
- else if (column_data.type().is<InstanceReference>()) {
+ else if (column_data.type().is<bke::InstanceReference>()) {
const StringRef value = row_filter.value_string;
apply_filter_operation(
- column_data.typed<InstanceReference>(),
- [&](const InstanceReference cell) {
+ column_data.typed<bke::InstanceReference>(),
+ [&](const bke::InstanceReference cell) {
switch (cell.type()) {
- case InstanceReference::Type::Object: {
+ case bke::InstanceReference::Type::Object: {
return value == (reinterpret_cast<ID &>(cell.object()).name + 2);
}
- case InstanceReference::Type::Collection: {
+ case bke::InstanceReference::Type::Collection: {
return value == (reinterpret_cast<ID &>(cell.collection()).name + 2);
}
- case InstanceReference::Type::GeometrySet: {
+ case bke::InstanceReference::Type::GeometrySet: {
return false;
}
- case InstanceReference::Type::None: {
+ case bke::InstanceReference::Type::None: {
return false;
}
}
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/space_view3d/view3d_navigate_walk.c b/source/blender/editors/space_view3d/view3d_navigate_walk.c
index 3e0ce892b5a..fcb4f549353 100644
--- a/source/blender/editors/space_view3d/view3d_navigate_walk.c
+++ b/source/blender/editors/space_view3d/view3d_navigate_walk.c
@@ -849,11 +849,15 @@ static void walkEvent(WalkInfo *walk, const wmEvent *event)
if (ret) {
WalkTeleport *teleport = &walk->teleport;
+
+ /* Store the current navigation mode if we are not already teleporting. */
+ if (teleport->state == WALK_TELEPORT_STATE_OFF) {
+ teleport->navigation_mode = walk->navigation_mode;
+ }
teleport->state = WALK_TELEPORT_STATE_ON;
teleport->initial_time = PIL_check_seconds_timer();
teleport->duration = U.walk_navigation.teleport_time;
- teleport->navigation_mode = walk->navigation_mode;
walk_navigation_mode_set(walk, WALK_MODE_FREE);
copy_v3_v3(teleport->origin, walk->rv3d->viewinv[3]);
@@ -864,9 +868,7 @@ static void walkEvent(WalkInfo *walk, const wmEvent *event)
sub_v3_v3v3(teleport->direction, loc, teleport->origin);
}
- else {
- walk->teleport.state = WALK_TELEPORT_STATE_OFF;
- }
+
break;
}
@@ -1229,11 +1231,11 @@ static int walkApply(bContext *C, WalkInfo *walk, bool is_confirm)
/* keep moving if we were moving */
copy_v2_v2(dvec, walk->teleport.direction);
- z_cur = walk->rv3d->viewinv[3][2];
- z_new = walk->teleport.origin[2] - getFreeFallDistance(walk->gravity, t) * walk->grid;
+ z_cur = walk->rv3d->viewinv[3][2] / walk->grid;
+ z_new = (walk->teleport.origin[2] / walk->grid) - getFreeFallDistance(walk->gravity, t);
/* jump */
- z_new += t * walk->speed_jump * walk->grid;
+ z_new += t * walk->speed_jump;
/* duration is the jump duration */
if (t > walk->teleport.duration) {
diff --git a/source/blender/editors/space_view3d/view3d_ops.c b/source/blender/editors/space_view3d/view3d_ops.c
index 6fbd553e17b..ad12aef6d67 100644
--- a/source/blender/editors/space_view3d/view3d_ops.c
+++ b/source/blender/editors/space_view3d/view3d_ops.c
@@ -59,7 +59,7 @@ static int view3d_copybuffer_exec(bContext *C, wmOperator *op)
}
CTX_DATA_END;
- BLI_join_dirfile(str, sizeof(str), BKE_tempdir_base(), "copybuffer.blend");
+ BLI_path_join(str, sizeof(str), BKE_tempdir_base(), "copybuffer.blend");
BKE_copybuffer_copy_end(bmain, str, op->reports);
BKE_reportf(op->reports, RPT_INFO, "Copied %d selected object(s)", num_copied);
@@ -91,7 +91,7 @@ static int view3d_pastebuffer_exec(bContext *C, wmOperator *op)
flag |= FILE_ACTIVE_COLLECTION;
}
- BLI_join_dirfile(str, sizeof(str), BKE_tempdir_base(), "copybuffer.blend");
+ BLI_path_join(str, sizeof(str), BKE_tempdir_base(), "copybuffer.blend");
const int num_pasted = BKE_copybuffer_paste(C, str, flag, op->reports, FILTER_ID_OB);
if (num_pasted == 0) {
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..5b194ae7237 100644
--- a/source/blender/editors/transform/transform.c
+++ b/source/blender/editors/transform/transform.c
@@ -60,8 +60,6 @@
* and being able to set it to zero is handy. */
/* #define USE_NUM_NO_ZERO */
-static void initSnapSpatial(TransInfo *t, float r_snap[2]);
-
bool transdata_check_local_islands(TransInfo *t, short around)
{
if (t->options & (CTX_CURSOR | CTX_TEXTURE_SPACE)) {
@@ -1518,26 +1516,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 +1574,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. */
@@ -1588,9 +1594,9 @@ void saveTransform(bContext *C, TransInfo *t, wmOperator *op)
RNA_enum_set(op->ptr, "snap_target", t->tsnap.source_select);
eSnapTargetSelect target = t->tsnap.target_select;
- RNA_boolean_set(op->ptr, "use_snap_self", (target & SCE_SNAP_TARGET_NOT_ACTIVE) != 0);
- RNA_boolean_set(op->ptr, "use_snap_edit", (target & SCE_SNAP_TARGET_NOT_EDITED) != 0);
- RNA_boolean_set(op->ptr, "use_snap_nonedit", (target & SCE_SNAP_TARGET_NOT_NONEDITED) != 0);
+ RNA_boolean_set(op->ptr, "use_snap_self", (target & SCE_SNAP_TARGET_NOT_ACTIVE) == 0);
+ RNA_boolean_set(op->ptr, "use_snap_edit", (target & SCE_SNAP_TARGET_NOT_EDITED) == 0);
+ RNA_boolean_set(op->ptr, "use_snap_nonedit", (target & SCE_SNAP_TARGET_NOT_NONEDITED) == 0);
RNA_boolean_set(
op->ptr, "use_snap_selectable", (target & SCE_SNAP_TARGET_ONLY_SELECTABLE) != 0);
}
@@ -1635,14 +1641,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);
}
@@ -1723,13 +1721,18 @@ void saveTransform(bContext *C, TransInfo *t, wmOperator *op)
}
}
-static void initSnapSpatial(TransInfo *t, float r_snap[2])
+static void initSnapSpatial(TransInfo *t, float r_snap[3], float *r_snap_precision)
{
+ /* Default values. */
+ r_snap[0] = r_snap[1] = 1.0f;
+ r_snap[1] = 0.0f;
+ *r_snap_precision = 0.1f;
+
if (t->spacetype == SPACE_VIEW3D) {
if (t->region->regiondata) {
View3D *v3d = t->area->spacedata.first;
- r_snap[0] = ED_view3d_grid_view_scale(t->scene, v3d, t->region, NULL) * 1.0f;
- r_snap[1] = r_snap[0] * 0.1f;
+ r_snap[0] = r_snap[1] = r_snap[2] = ED_view3d_grid_view_scale(
+ t->scene, v3d, t->region, NULL);
}
}
else if (t->spacetype == SPACE_IMAGE) {
@@ -1737,33 +1740,22 @@ static void initSnapSpatial(TransInfo *t, float r_snap[2])
View2D *v2d = &t->region->v2d;
int grid_size = SI_GRID_STEPS_LEN;
float zoom_factor = ED_space_image_zoom_level(v2d, grid_size);
- float grid_steps[SI_GRID_STEPS_LEN];
+ float grid_steps_x[SI_GRID_STEPS_LEN];
float grid_steps_y[SI_GRID_STEPS_LEN];
- ED_space_image_grid_steps(sima, grid_steps, grid_steps_y, grid_size);
+ ED_space_image_grid_steps(sima, grid_steps_x, grid_steps_y, grid_size);
/* Snapping value based on what type of grid is used (adaptive-subdividing or custom-grid). */
- r_snap[0] = ED_space_image_increment_snap_value(grid_size, grid_steps, zoom_factor);
- r_snap[1] = r_snap[0] / 2.0f;
-
- /* TODO: Implement snapping for custom grid sizes with `grid_steps[0] != grid_steps_y[0]`.
- * r_snap_y[0] = ED_space_image_increment_snap_value(grid_size, grid_steps_y, zoom_factor);
- * r_snap_y[1] = r_snap_y[0] / 2.0f;
- */
+ r_snap[0] = ED_space_image_increment_snap_value(grid_size, grid_steps_x, zoom_factor);
+ r_snap[1] = ED_space_image_increment_snap_value(grid_size, grid_steps_y, zoom_factor);
+ *r_snap_precision = 0.5f;
}
else if (t->spacetype == SPACE_CLIP) {
- r_snap[0] = 0.125f;
- r_snap[1] = 0.0625f;
+ r_snap[0] = r_snap[1] = 0.125f;
+ *r_snap_precision = 0.5f;
}
else if (t->spacetype == SPACE_NODE) {
r_snap[0] = r_snap[1] = ED_node_grid_size();
}
- else if (t->spacetype == SPACE_GRAPH) {
- r_snap[0] = 1.0;
- r_snap[1] = 0.1f;
- }
- else {
- r_snap[0] = r_snap[1] = 1.0f;
- }
}
bool initTransform(bContext *C, TransInfo *t, wmOperator *op, const wmEvent *event, int mode)
@@ -1903,7 +1895,7 @@ bool initTransform(bContext *C, TransInfo *t, wmOperator *op, const wmEvent *eve
initSnapping(t, op); /* Initialize snapping data AFTER mode flags */
- initSnapSpatial(t, t->snap_spatial);
+ initSnapSpatial(t, t->snap_spatial, &t->snap_spatial_precision);
/* EVIL! posemode code can switch translation to rotate when 1 bone is selected.
* will be removed (ton) */
diff --git a/source/blender/editors/transform/transform.h b/source/blender/editors/transform/transform.h
index 09fc07f57f4..90f2795184b 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)
@@ -550,7 +555,12 @@ typedef struct TransInfo {
/** Snapping Gears. */
float snap[2];
/** Spatial snapping gears(even when rotating, scaling... etc). */
- float snap_spatial[2];
+ float snap_spatial[3];
+ /**
+ * Precision factor that is multiplied to snap_spatial when precision
+ * modifier is enabled for snap to grid or incremental snap.
+ */
+ float snap_spatial_precision;
/** Mouse side of the current frame, 'L', 'R' or 'B' */
char frame_side;
@@ -864,3 +874,7 @@ bool checkUseAxisMatrix(TransInfo *t);
th++, i++)
/** \} */
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/source/blender/editors/transform/transform_constraints.c b/source/blender/editors/transform/transform_constraints.c
index fa56456d8e7..7abf0e5c00c 100644
--- a/source/blender/editors/transform/transform_constraints.c
+++ b/source/blender/editors/transform/transform_constraints.c
@@ -404,9 +404,11 @@ static void applyAxisConstraintVec(const TransInfo *t,
}
}
+ /* Fallback for when axes are aligned. */
+ mul_m3_v3(t->con.pmtx, out);
+
if (is_snap_to_point) {
- /* With snap points, a projection is alright, no adjustments needed. */
- mul_m3_v3(t->con.pmtx, out);
+ /* Pass. With snap points, a projection is alright, no adjustments needed. */
}
else {
const int dims = getConstraintSpaceDimension(t);
@@ -422,14 +424,9 @@ static void applyAxisConstraintVec(const TransInfo *t,
/* Disabled, as it has not proven to be really useful. (See T82386). */
// constraint_snap_plane_to_face(t, plane, out);
}
- else {
+ else if (!isPlaneProjectionViewAligned(t, plane)) {
/* View alignment correction. */
- if (!isPlaneProjectionViewAligned(t, plane)) {
- planeProjection(t, plane, in, out);
- }
- else {
- mul_m3_v3(t->con.pmtx, out);
- }
+ planeProjection(t, plane, in, out);
}
}
}
diff --git a/source/blender/editors/transform/transform_convert.h b/source/blender/editors/transform/transform_convert.h
index f32bff6dcff..4798d666d70 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;
@@ -222,8 +226,6 @@ void transform_convert_mesh_crazyspace_transdata_set(const float mtx[3][3],
struct TransData *r_td);
void transform_convert_mesh_crazyspace_free(struct TransMeshDataCrazySpace *r_crazyspace_data);
-void special_aftertrans_update__mesh(bContext *C, TransInfo *t);
-
/* transform_convert_mesh_edge.c */
extern TransConvertTypeInfo TransConvertType_MeshEdge;
@@ -244,7 +246,7 @@ extern TransConvertTypeInfo TransConvertType_MeshVertCData;
extern TransConvertTypeInfo TransConvertType_NLA;
-/* transform_convert_node.c */
+/* transform_convert_node.cc */
extern TransConvertTypeInfo TransConvertType_Node;
@@ -279,3 +281,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_mesh.c b/source/blender/editors/transform/transform_convert_mesh.c
index af7982f862a..7e237c9eb32 100644
--- a/source/blender/editors/transform/transform_convert_mesh.c
+++ b/source/blender/editors/transform/transform_convert_mesh.c
@@ -2068,7 +2068,7 @@ static void recalcData_mesh(TransInfo *t)
/** \name Special After Transform Mesh
* \{ */
-void special_aftertrans_update__mesh(bContext *UNUSED(C), TransInfo *t)
+static void special_aftertrans_update__mesh(bContext *UNUSED(C), TransInfo *t)
{
const bool is_canceling = (t->state == TRANS_CANCEL);
const bool use_automerge = !is_canceling && (t->flag & (T_AUTOMERGE | T_AUTOSPLIT)) != 0;
diff --git a/source/blender/editors/transform/transform_convert_mesh_edge.c b/source/blender/editors/transform/transform_convert_mesh_edge.c
index 7f26029850b..0ce4c592f53 100644
--- a/source/blender/editors/transform/transform_convert_mesh_edge.c
+++ b/source/blender/editors/transform/transform_convert_mesh_edge.c
@@ -125,5 +125,5 @@ TransConvertTypeInfo TransConvertType_MeshEdge = {
/* flags */ T_EDIT,
/* createTransData */ createTransEdge,
/* recalcData */ recalcData_mesh_edge,
- /* special_aftertrans_update */ special_aftertrans_update__mesh,
+ /* special_aftertrans_update */ NULL,
};
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..6ab0e1fe701 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) {
@@ -156,14 +155,59 @@ static void createTransNodeData(bContext *UNUSED(C), TransInfo *t)
/** \} */
/* -------------------------------------------------------------------- */
-/** \name Node Transform Creation
+/** \name Flush Transform Nodes
* \{ */
+static void node_snap_grid_apply(TransInfo *t)
+{
+ int i;
+
+ if (!(activeSnap(t) && (t->tsnap.mode & (SCE_SNAP_MODE_INCREMENT | SCE_SNAP_MODE_GRID)))) {
+ return;
+ }
+
+ float grid_size[2];
+ copy_v2_v2(grid_size, t->snap_spatial);
+ if (t->modifiers & MOD_PRECISION) {
+ mul_v2_fl(grid_size, t->snap_spatial_precision);
+ }
+
+ /* Early exit on unusable grid size. */
+ if (is_zero_v2(grid_size)) {
+ return;
+ }
+
+ FOREACH_TRANS_DATA_CONTAINER (t, tc) {
+ TransData *td;
+
+ for (i = 0, td = tc->data; i < tc->data_len; i++, td++) {
+ float iloc[2], loc[2], tvec[2];
+ if (td->flag & TD_SKIP) {
+ continue;
+ }
+
+ if ((t->flag & T_PROP_EDIT) && (td->factor == 0.0f)) {
+ continue;
+ }
+
+ copy_v2_v2(iloc, td->loc);
+
+ loc[0] = roundf(iloc[0] / grid_size[0]) * grid_size[0];
+ loc[1] = roundf(iloc[1] / grid_size[1]) * grid_size[1];
+
+ sub_v2_v2v2(tvec, loc, iloc);
+ add_v2_v2(td->loc, tvec);
+ }
+ }
+}
+
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) {
@@ -190,13 +234,13 @@ static void flushTransNodes(TransInfo *t)
}
FOREACH_TRANS_DATA_CONTAINER (t, tc) {
- applyGridAbsolute(t);
+ node_snap_grid_apply(t);
/* flush to 2d vector from internally used 3d vector */
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 +265,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 +278,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 +299,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_mode_curveshrinkfatten.c b/source/blender/editors/transform/transform_mode_curveshrinkfatten.c
index f7f9e14b8ac..0b87b45679a 100644
--- a/source/blender/editors/transform/transform_mode_curveshrinkfatten.c
+++ b/source/blender/editors/transform/transform_mode_curveshrinkfatten.c
@@ -8,6 +8,7 @@
#include <stdlib.h>
#include "BLI_math.h"
+#include "BLI_math_bits.h"
#include "BLI_string.h"
#include "BKE_context.h"
@@ -62,7 +63,14 @@ static void applyCurveShrinkFatten(TransInfo *t, const int UNUSED(mval[2]))
}
if (td->val) {
- *td->val = td->ival * ratio;
+ if (td->ival == 0.0f && ratio > 1.0f) {
+ /* Allow Shrink/Fatten for zero radius. */
+ *td->val = (ratio - 1.0f) * uint_as_float(POINTER_AS_UINT(t->custom.mode.data));
+ }
+ else {
+ *td->val = td->ival * ratio;
+ }
+
/* apply PET */
*td->val = interpf(*td->val, td->ival, td->factor);
CLAMP_MIN(*td->val, 0.0f);
@@ -92,6 +100,18 @@ void initCurveShrinkFatten(TransInfo *t)
t->num.unit_type[0] = B_UNIT_NONE;
t->flag |= T_NO_CONSTRAINT;
+
+ float scale_factor = 0.0f;
+ if (((t->spacetype == SPACE_VIEW3D) && (t->region->regiontype == RGN_TYPE_WINDOW) &&
+ (t->data_len_all == 1)) ||
+ (t->data_len_all == 3 && TRANS_DATA_CONTAINER_FIRST_OK(t)->data[0].val == NULL)) {
+ /* For cases where only one point on the curve is being transformed and the radius of that
+ * point is zero, use the factor to multiply the offset of the ratio and allow scaling.
+ * Note that for bezier curves, 3 TransData equals 1 point in most cases. */
+ RegionView3D *rv3d = t->region->regiondata;
+ scale_factor = rv3d->pixsize * t->mouse.factor * t->zfac;
+ }
+ t->custom.mode.data = POINTER_FROM_UINT(float_as_uint(scale_factor));
}
/** \} */
diff --git a/source/blender/editors/transform/transform_mode_translate.c b/source/blender/editors/transform/transform_mode_translate.c
index 8f6ec7bd98f..59d34c3918b 100644
--- a/source/blender/editors/transform/transform_mode_translate.c
+++ b/source/blender/editors/transform/transform_mode_translate.c
@@ -170,7 +170,7 @@ static void transdata_elem_translate_fn(void *__restrict iter_data_v,
/** \} */
/* -------------------------------------------------------------------- */
-/** \name Transform (Translation)
+/** \name Transform (Translation) Header
* \{ */
static void translate_dist_to_str(char *r_str,
@@ -341,6 +341,96 @@ static void headerTranslation(TransInfo *t, const float vec[3], char str[UI_MAX_
}
}
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Transform (Translation) Snapping
+ * \{ */
+
+static void translate_snap_target_grid_ensure(TransInfo *t)
+{
+ /* Only need to calculate once. */
+ if ((t->tsnap.status & TARGET_GRID_INIT) == 0) {
+ if (t->data_type == &TransConvertType_Cursor3D) {
+ /* Use a fallback when transforming the cursor.
+ * In this case the center is _not_ derived from the cursor which is being transformed. */
+ copy_v3_v3(t->tsnap.snapTargetGrid, TRANS_DATA_CONTAINER_FIRST_SINGLE(t)->data->iloc);
+ }
+ else if (t->around == V3D_AROUND_CURSOR) {
+ /* Use a fallback for cursor selection,
+ * this isn't useful as a global center for absolute grid snapping
+ * since its not based on the position of the selection. */
+ tranform_snap_target_median_calc(t, t->tsnap.snapTargetGrid);
+ }
+ else {
+ copy_v3_v3(t->tsnap.snapTargetGrid, t->center_global);
+ }
+ t->tsnap.status |= TARGET_GRID_INIT;
+ }
+}
+
+static void translate_snap_grid_apply(TransInfo *t,
+ const int max_index,
+ const float grid_dist[3],
+ const float loc[3],
+ float r_out[3])
+{
+ BLI_assert(max_index <= 2);
+ translate_snap_target_grid_ensure(t);
+ const float *center_global = t->tsnap.snapTargetGrid;
+ const float *asp = t->aspect;
+
+ float in[3];
+ if (t->con.mode & CON_APPLY) {
+ BLI_assert(t->tsnap.snapElem == SCE_SNAP_MODE_NONE);
+ t->con.applyVec(t, NULL, NULL, loc, in);
+ }
+ else {
+ copy_v3_v3(in, loc);
+ }
+
+ for (int i = 0; i <= max_index; i++) {
+ const float iter_fac = grid_dist[i] * asp[i];
+ r_out[i] = iter_fac * roundf((in[i] + center_global[i]) / iter_fac) - center_global[i];
+ }
+}
+
+static bool translate_snap_grid(TransInfo *t, float *val)
+{
+ if (!activeSnap(t)) {
+ return false;
+ }
+
+ if (!(t->tsnap.mode & SCE_SNAP_MODE_GRID) || validSnap(t)) {
+ /* Don't do grid snapping if there is a valid snap point. */
+ return false;
+ }
+
+ /* Don't do grid snapping if not in 3D viewport or UV editor */
+ if (!ELEM(t->spacetype, SPACE_VIEW3D, SPACE_IMAGE)) {
+ return false;
+ }
+
+ if (t->mode != TFM_TRANSLATION) {
+ return false;
+ }
+
+ float grid_dist[3];
+ copy_v3_v3(grid_dist, t->snap_spatial);
+ if (t->modifiers & MOD_PRECISION) {
+ mul_v3_fl(grid_dist, t->snap_spatial_precision);
+ }
+
+ /* Early bailing out if no need to snap */
+ if (is_zero_v3(grid_dist)) {
+ return false;
+ }
+
+ translate_snap_grid_apply(t, t->idx_max, grid_dist, val, val);
+ t->tsnap.snapElem = SCE_SNAP_MODE_GRID;
+ return true;
+}
+
static void ApplySnapTranslation(TransInfo *t, float vec[3])
{
float point[3];
@@ -372,6 +462,12 @@ static void ApplySnapTranslation(TransInfo *t, float vec[3])
}
}
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Transform (Translation)
+ * \{ */
+
static void applyTranslationValue(TransInfo *t, const float vec[3])
{
struct TranslateCustomData *custom_data = t->custom.mode.data;
@@ -514,7 +610,7 @@ static void applyTranslation(TransInfo *t, const int UNUSED(mval[2]))
t->tsnap.snapElem = SCE_SNAP_MODE_NONE;
applySnappingAsGroup(t, global_dir);
- transform_snap_grid(t, global_dir);
+ translate_snap_grid(t, global_dir);
if (t->con.mode & CON_APPLY) {
float in[3];
@@ -590,7 +686,8 @@ void initTranslation(TransInfo *t)
t->num.flag = 0;
t->num.idx_max = t->idx_max;
- copy_v2_v2(t->snap, t->snap_spatial);
+ t->snap[0] = t->snap_spatial[0];
+ t->snap[1] = t->snap_spatial[0] * t->snap_spatial_precision;
copy_v3_fl(t->num.val_inc, t->snap[0]);
t->num.unit_sys = t->scene->unit.system;
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.c b/source/blender/editors/transform/transform_snap.c
index 3f9cca55138..672d947936d 100644
--- a/source/blender/editors/transform/transform_snap.c
+++ b/source/blender/editors/transform/transform_snap.c
@@ -511,56 +511,6 @@ void applySnappingIndividual(TransInfo *t)
}
}
-void applyGridAbsolute(TransInfo *t)
-{
- int i;
-
- if (!(activeSnap(t) && (t->tsnap.mode & (SCE_SNAP_MODE_INCREMENT | SCE_SNAP_MODE_GRID)))) {
- return;
- }
-
- float grid_size = (t->modifiers & MOD_PRECISION) ? t->snap_spatial[1] : t->snap_spatial[0];
-
- /* early exit on unusable grid size */
- if (grid_size == 0.0f) {
- return;
- }
-
- FOREACH_TRANS_DATA_CONTAINER (t, tc) {
- TransData *td;
-
- for (i = 0, td = tc->data; i < tc->data_len; i++, td++) {
- float iloc[3], loc[3], tvec[3];
- if (td->flag & TD_SKIP) {
- continue;
- }
-
- if ((t->flag & T_PROP_EDIT) && (td->factor == 0.0f)) {
- continue;
- }
-
- copy_v3_v3(iloc, td->loc);
- if (tc->use_local_mat) {
- mul_m4_v3(tc->mat, iloc);
- }
- else if (t->options & CTX_OBJECT) {
- BKE_object_eval_transform_all(t->depsgraph, t->scene, td->ob);
- copy_v3_v3(iloc, td->ob->obmat[3]);
- }
-
- mul_v3_v3fl(loc, iloc, 1.0f / grid_size);
- loc[0] = roundf(loc[0]);
- loc[1] = roundf(loc[1]);
- loc[2] = roundf(loc[2]);
- mul_v3_fl(loc, grid_size);
-
- sub_v3_v3v3(tvec, loc, iloc);
- mul_m3_v3(td->smtx, tvec);
- add_v3_v3(td->loc, tvec);
- }
- }
-}
-
void applySnappingAsGroup(TransInfo *t, float *vec)
{
if (!activeSnap_SnappingAsGroup(t)) {
@@ -1187,7 +1137,7 @@ static void snap_calc_sequencer_fn(TransInfo *t, float *UNUSED(vec))
/** \name Target
* \{ */
-static void snap_target_median_impl(TransInfo *t, float r_median[3])
+void tranform_snap_target_median_calc(const TransInfo *t, float r_median[3])
{
int i_accum = 0;
@@ -1223,28 +1173,6 @@ static void snap_target_median_impl(TransInfo *t, float r_median[3])
// TargetSnapOffset(t, NULL);
}
-static void snap_target_grid_ensure(TransInfo *t)
-{
- /* Only need to calculate once. */
- if ((t->tsnap.status & TARGET_GRID_INIT) == 0) {
- if (t->data_type == &TransConvertType_Cursor3D) {
- /* Use a fallback when transforming the cursor.
- * In this case the center is _not_ derived from the cursor which is being transformed. */
- copy_v3_v3(t->tsnap.snapTargetGrid, TRANS_DATA_CONTAINER_FIRST_SINGLE(t)->data->iloc);
- }
- else if (t->around == V3D_AROUND_CURSOR) {
- /* Use a fallback for cursor selection,
- * this isn't useful as a global center for absolute grid snapping
- * since its not based on the position of the selection. */
- snap_target_median_impl(t, t->tsnap.snapTargetGrid);
- }
- else {
- copy_v3_v3(t->tsnap.snapTargetGrid, t->center_global);
- }
- t->tsnap.status |= TARGET_GRID_INIT;
- }
-}
-
static void TargetSnapOffset(TransInfo *t, TransData *td)
{
if (t->spacetype == SPACE_NODE && td != NULL) {
@@ -1316,7 +1244,7 @@ static void TargetSnapMedian(TransInfo *t)
{
/* Only need to calculate once. */
if ((t->tsnap.status & TARGET_INIT) == 0) {
- snap_target_median_impl(t, t->tsnap.snapTarget);
+ tranform_snap_target_median_calc(t, t->tsnap.snapTarget);
t->tsnap.status |= TARGET_INIT;
}
}
@@ -1654,61 +1582,6 @@ bool snapNodesTransform(
/** \name snap Grid
* \{ */
-static void snap_grid_apply(
- TransInfo *t, const int max_index, const float grid_dist, const float loc[3], float r_out[3])
-{
- BLI_assert(max_index <= 2);
- snap_target_grid_ensure(t);
- const float *center_global = t->tsnap.snapTargetGrid;
- const float *asp = t->aspect;
-
- float in[3];
- if (t->con.mode & CON_APPLY) {
- BLI_assert(t->tsnap.snapElem == SCE_SNAP_MODE_NONE);
- t->con.applyVec(t, NULL, NULL, loc, in);
- }
- else {
- copy_v3_v3(in, loc);
- }
-
- for (int i = 0; i <= max_index; i++) {
- const float iter_fac = grid_dist * asp[i];
- r_out[i] = iter_fac * roundf((in[i] + center_global[i]) / iter_fac) - center_global[i];
- }
-}
-
-bool transform_snap_grid(TransInfo *t, float *val)
-{
- if (!activeSnap(t)) {
- return false;
- }
-
- if (!(t->tsnap.mode & SCE_SNAP_MODE_GRID) || validSnap(t)) {
- /* Don't do grid snapping if there is a valid snap point. */
- return false;
- }
-
- /* Don't do grid snapping if not in 3D viewport or UV editor */
- if (!ELEM(t->spacetype, SPACE_VIEW3D, SPACE_IMAGE)) {
- return false;
- }
-
- if (t->mode != TFM_TRANSLATION) {
- return false;
- }
-
- float grid_dist = (t->modifiers & MOD_PRECISION) ? t->snap[1] : t->snap[0];
-
- /* Early bailing out if no need to snap */
- if (grid_dist == 0.0f) {
- return false;
- }
-
- snap_grid_apply(t, t->idx_max, grid_dist, val, val);
- t->tsnap.snapElem = SCE_SNAP_MODE_GRID;
- return true;
-}
-
static void snap_increment_apply_ex(const TransInfo *UNUSED(t),
const int max_index,
const float increment_val,
diff --git a/source/blender/editors/transform/transform_snap.h b/source/blender/editors/transform/transform_snap.h
index 3672e76c778..16d9062e978 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,
@@ -34,10 +38,10 @@ bool snapNodesTransform(struct TransInfo *t,
bool transformModeUseSnap(const TransInfo *t);
+void tranform_snap_target_median_calc(const TransInfo *t, float r_median[3]);
bool transform_snap_increment_ex(const TransInfo *t, bool use_local_space, float *r_val);
bool transform_snap_increment(const TransInfo *t, float *val);
float transform_snap_increment_get(const TransInfo *t);
-bool transform_snap_grid(TransInfo *t, float *val);
bool activeSnap(const TransInfo *t);
bool activeSnap_SnappingIndividual(const TransInfo *t);
@@ -48,7 +52,6 @@ bool validSnap(const TransInfo *t);
void initSnapping(struct TransInfo *t, struct wmOperator *op);
void freeSnapping(struct TransInfo *t);
void applySnappingIndividual(TransInfo *t);
-void applyGridAbsolute(TransInfo *t);
void applySnappingAsGroup(TransInfo *t, float *vec);
void resetSnapping(TransInfo *t);
eRedrawFlag handleSnapping(TransInfo *t, const struct wmEvent *event);
@@ -92,3 +95,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/util/ed_util.c b/source/blender/editors/util/ed_util.c
index 12e77c6ef00..92d65688bf1 100644
--- a/source/blender/editors/util/ed_util.c
+++ b/source/blender/editors/util/ed_util.c
@@ -374,7 +374,7 @@ void unpack_menu(bContext *C,
char local_name[FILE_MAXDIR + FILE_MAX], fi[FILE_MAX];
BLI_split_file_part(abs_name, fi, sizeof(fi));
- BLI_path_join(local_name, sizeof(local_name), "//", folder, fi, NULL);
+ BLI_path_join(local_name, sizeof(local_name), "//", folder, fi);
if (!STREQ(abs_name, local_name)) {
switch (BKE_packedfile_compare_to_file(blendfile_path, local_name, pf)) {
case PF_CMP_NOFILE:
diff --git a/source/blender/editors/util/ed_viewer_path.cc b/source/blender/editors/util/ed_viewer_path.cc
index 5c03367cba8..4da1559b726 100644
--- a/source/blender/editors/util/ed_viewer_path.cc
+++ b/source/blender/editors/util/ed_viewer_path.cc
@@ -249,6 +249,9 @@ bool is_active_geometry_nodes_viewer(const bContext &C,
if (md->type != eModifierType_Nodes) {
return false;
}
+ if ((md->mode & eModifierMode_Realtime) == 0) {
+ return false;
+ }
modifier = reinterpret_cast<const NodesModifierData *>(md);
break;
}
diff --git a/source/blender/editors/uvedit/uvedit_islands.cc b/source/blender/editors/uvedit/uvedit_islands.cc
index 2648ec5e2f6..92745667505 100644
--- a/source/blender/editors/uvedit/uvedit_islands.cc
+++ b/source/blender/editors/uvedit/uvedit_islands.cc
@@ -403,6 +403,219 @@ 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;
+}
+
+static bool island_has_pins(FaceIsland *island)
+{
+ BMLoop *l;
+ BMIter iter;
+ const int cd_loop_uv_offset = island->cd_loop_uv_offset;
+ for (int i = 0; i < island->faces_len; i++) {
+ BM_ITER_ELEM (l, &iter, island->faces[i], BM_LOOPS_OF_FACE) {
+ MLoopUV *luv = static_cast<MLoopUV *>(BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset));
+ if (luv->flag & MLOOPUV_PINNED) {
+ return true;
+ }
+ }
+ }
+ return false;
+}
+
/* -------------------------------------------------------------------- */
/** \name Public UV Island Packing
*
@@ -412,6 +625,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 +633,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 +659,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,
@@ -445,8 +667,14 @@ void ED_uvedit_pack_islands_multi(const Scene *scene,
aspect_y,
cd_loop_uv_offset);
- int index;
- LISTBASE_FOREACH_INDEX (struct FaceIsland *, island, &island_list, index) {
+ /* Remove from linked list and append to blender::Vector. */
+ LISTBASE_FOREACH_MUTABLE (struct FaceIsland *, island, &island_list) {
+ BLI_remlink(&island_list, island);
+ if (params->ignore_pinned && island_has_pins(island)) {
+ MEM_freeN(island->faces);
+ MEM_freeN(island);
+ continue;
+ }
island_vector.append(island);
}
}
@@ -455,19 +683,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 +710,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 +719,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 +770,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 +797,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_ops.c b/source/blender/editors/uvedit/uvedit_ops.c
index 5e2d9097abd..b65f4889347 100644
--- a/source/blender/editors/uvedit/uvedit_ops.c
+++ b/source/blender/editors/uvedit/uvedit_ops.c
@@ -37,6 +37,7 @@
#include "BKE_node.h"
#include "DEG_depsgraph.h"
+#include "DEG_depsgraph_query.h"
#include "ED_image.h"
#include "ED_mesh.h"
@@ -113,7 +114,8 @@ bool ED_object_get_active_image(Object *ob,
bNode **r_node,
bNodeTree **r_ntree)
{
- Material *ma = BKE_object_material_get(ob, mat_nr);
+ Material *ma = DEG_is_evaluated_object(ob) ? BKE_object_material_get_eval(ob, mat_nr) :
+ BKE_object_material_get(ob, mat_nr);
bNodeTree *ntree = (ma && ma->use_nodes) ? ma->nodetree : NULL;
bNode *node = (ntree) ? nodeGetActiveTexture(ntree) : NULL;
diff --git a/source/blender/editors/uvedit/uvedit_unwrap_ops.c b/source/blender/editors/uvedit/uvedit_unwrap_ops.c
index 661a2a1b05b..ecaba3234a7 100644
--- a/source/blender/editors/uvedit/uvedit_unwrap_ops.c
+++ b/source/blender/editors/uvedit/uvedit_unwrap_ops.c
@@ -1050,50 +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.
- *
- * TODO: remove this function, in favor of #ED_uvedit_pack_islands_multi.
- */
-static void uvedit_pack_islands_multi(const Scene *scene,
- Object **objects,
- const uint objects_len,
- const UnwrapOptions *options,
- bool rotate,
- bool ignore_pinned)
-{
- ParamHandle *handle = construct_param_handle_multi(scene, objects, objects_len, options);
- GEO_uv_parametrizer_pack(handle, scene->toolsettings->uvcalc_margin, rotate, ignore_pinned);
- GEO_uv_parametrizer_flush(handle);
- GEO_uv_parametrizer_delete(handle);
-
- for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
- Object *obedit = objects[ob_index];
- DEG_id_tag_update(obedit->data, ID_RECALC_GEOMETRY);
- WM_main_add_notifier(NC_GEOM | ND_DATA, obedit->data);
- }
-}
-
/* Packing targets. */
enum {
PACK_UDIM_SRC_CLOSEST = 0,
@@ -1125,7 +1081,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 +1094,42 @@ 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);
+ const struct UVPackIsland_Params pack_island_params = {
+ .rotate = RNA_boolean_get(op->ptr, "rotate"),
+ .only_selected_uvs = options.only_selected_uvs,
+ .only_selected_faces = options.only_selected_faces,
+ .use_seams = !options.topology_from_uvs || options.topology_from_uvs_use_seams,
+ .correct_aspect = options.correct_aspect,
+ .ignore_pinned = false,
+ .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,
- &(struct UVPackIsland_Params){
- .rotate = rotate,
- .only_selected_uvs = true,
- .only_selected_faces = true,
- .correct_aspect = true,
- });
+ &pack_island_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 +1156,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);
}
@@ -1892,12 +1870,19 @@ void ED_uvedit_live_unwrap(const Scene *scene, Object **objects, int objects_len
.fill_holes = (scene->toolsettings->uvcalc_flag & UVCALC_FILLHOLES) != 0,
.correct_aspect = (scene->toolsettings->uvcalc_flag & UVCALC_NO_ASPECT_CORRECT) == 0,
};
-
- bool rotate = true;
- bool ignore_pinned = true;
-
uvedit_unwrap_multi(scene, objects, objects_len, &options, NULL);
- uvedit_pack_islands_multi(scene, objects, objects_len, &options, rotate, ignore_pinned);
+
+ const struct UVPackIsland_Params pack_island_params = {
+ .rotate = true,
+ .only_selected_uvs = options.only_selected_uvs,
+ .only_selected_faces = options.only_selected_faces,
+ .use_seams = !options.topology_from_uvs || options.topology_from_uvs_use_seams,
+ .correct_aspect = options.correct_aspect,
+ .ignore_pinned = true,
+ .margin_method = ED_UVPACK_MARGIN_SCALED,
+ .margin = scene->toolsettings->uvcalc_margin,
+ };
+ ED_uvedit_pack_islands_multi(scene, objects, objects_len, NULL, NULL, &pack_island_params);
}
}
@@ -1929,8 +1914,6 @@ static int unwrap_exec(bContext *C, wmOperator *op)
.correct_aspect = RNA_boolean_get(op->ptr, "correct_aspect"),
};
- bool rotate = true;
- bool ignore_pinned = true;
if (CTX_wm_space_image(C)) {
/* Inside the UV Editor, only unwrap selected UVs. */
options.only_selected_uvs = true;
@@ -2035,7 +2018,18 @@ static int unwrap_exec(bContext *C, wmOperator *op)
.count_failed = 0,
};
uvedit_unwrap_multi(scene, objects, objects_len, &options, &result_info);
- uvedit_pack_islands_multi(scene, objects, objects_len, &options, rotate, ignore_pinned);
+
+ const struct UVPackIsland_Params pack_island_params = {
+ .rotate = true,
+ .only_selected_uvs = options.only_selected_uvs,
+ .only_selected_faces = options.only_selected_faces,
+ .use_seams = !options.topology_from_uvs || options.topology_from_uvs_use_seams,
+ .correct_aspect = options.correct_aspect,
+ .ignore_pinned = 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, NULL, &pack_island_params);
MEM_freeN(objects);
@@ -2098,6 +2092,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 +2114,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 +2407,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 +2459,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 +3158,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/freestyle/intern/blender_interface/BlenderFileLoader.cpp b/source/blender/freestyle/intern/blender_interface/BlenderFileLoader.cpp
index 19589491bc4..0d41b5a773d 100644
--- a/source/blender/freestyle/intern/blender_interface/BlenderFileLoader.cpp
+++ b/source/blender/freestyle/intern/blender_interface/BlenderFileLoader.cpp
@@ -73,7 +73,8 @@ NodeGroup *BlenderFileLoader::Load()
break;
}
- if (ob->base_flag & (BASE_HOLDOUT | BASE_INDIRECT_ONLY)) {
+ if ((ob->base_flag & (BASE_HOLDOUT | BASE_INDIRECT_ONLY)) ||
+ (ob->visibility_flag & OB_HOLDOUT)) {
continue;
}
diff --git a/source/blender/freestyle/intern/python/BPy_Freestyle.cpp b/source/blender/freestyle/intern/python/BPy_Freestyle.cpp
index 96887f7a83b..237f1802026 100644
--- a/source/blender/freestyle/intern/python/BPy_Freestyle.cpp
+++ b/source/blender/freestyle/intern/python/BPy_Freestyle.cpp
@@ -531,7 +531,7 @@ PyObject *Freestyle_Init(void)
const char *const path = BKE_appdir_folder_id(BLENDER_SYSTEM_SCRIPTS, "freestyle");
if (path) {
char modpath[FILE_MAX];
- BLI_join_dirfile(modpath, sizeof(modpath), path, "modules");
+ BLI_path_join(modpath, sizeof(modpath), path, "modules");
PyObject *sys_path = PySys_GetObject("path"); /* borrow */
PyObject *py_modpath = PyUnicode_FromString(modpath);
PyList_Append(sys_path, py_modpath);
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/geometry/intern/fillet_curves.cc b/source/blender/geometry/intern/fillet_curves.cc
index 1bbbee6edef..2479458f88d 100644
--- a/source/blender/geometry/intern/fillet_curves.cc
+++ b/source/blender/geometry/intern/fillet_curves.cc
@@ -148,12 +148,14 @@ static float limit_radius(const float3 &position_prev,
const float displacement_prev = radius_prev * std::tan(angle_prev / 2.0f);
const float segment_length_prev = math::distance(position, position_prev);
const float total_displacement_prev = displacement_prev + displacement;
- const float factor_prev = std::clamp(segment_length_prev / total_displacement_prev, 0.0f, 1.0f);
+ const float factor_prev = std::clamp(
+ safe_divide(segment_length_prev, total_displacement_prev), 0.0f, 1.0f);
const float displacement_next = radius_next * std::tan(angle_next / 2.0f);
const float segment_length_next = math::distance(position, position_next);
const float total_displacement_next = displacement_next + displacement;
- const float factor_next = std::clamp(segment_length_next / total_displacement_next, 0.0f, 1.0f);
+ const float factor_next = std::clamp(
+ safe_divide(segment_length_next, total_displacement_next), 0.0f, 1.0f);
return radius * std::min(factor_prev, factor_next);
}
diff --git a/source/blender/geometry/intern/realize_instances.cc b/source/blender/geometry/intern/realize_instances.cc
index 7b3c307cf37..c649bde06ca 100644
--- a/source/blender/geometry/intern/realize_instances.cc
+++ b/source/blender/geometry/intern/realize_instances.cc
@@ -17,6 +17,7 @@
#include "BKE_curves.hh"
#include "BKE_deform.h"
#include "BKE_geometry_set_instances.hh"
+#include "BKE_instances.hh"
#include "BKE_material.h"
#include "BKE_mesh.h"
#include "BKE_pointcloud.h"
@@ -30,6 +31,8 @@ using blender::bke::AttributeMetaData;
using blender::bke::custom_data_type_to_cpp_type;
using blender::bke::CustomDataAttributes;
using blender::bke::GSpanAttributeWriter;
+using blender::bke::InstanceReference;
+using blender::bke::Instances;
using blender::bke::object_get_evaluated_geometry_set;
using blender::bke::SpanAttributeWriter;
@@ -370,11 +373,11 @@ static void gather_realize_tasks_recursive(GatherTasksInfo &gather_info,
*/
static Vector<std::pair<int, GSpan>> prepare_attribute_fallbacks(
GatherTasksInfo &gather_info,
- const InstancesComponent &instances_component,
+ const Instances &instances,
const OrderedAttributes &ordered_attributes)
{
Vector<std::pair<int, GSpan>> attributes_to_override;
- const CustomDataAttributes &attributes = instances_component.instance_attributes();
+ const CustomDataAttributes &attributes = instances.custom_data_attributes();
attributes.foreach_attribute(
[&](const AttributeIDRef &attribute_id, const AttributeMetaData &meta_data) {
const int attribute_index = ordered_attributes.ids.index_of_try(attribute_id);
@@ -394,7 +397,7 @@ static Vector<std::pair<int, GSpan>> prepare_attribute_fallbacks(
}
/* Convert the attribute on the instances component to the expected attribute type. */
std::unique_ptr<GArray<>> temporary_array = std::make_unique<GArray<>>(
- to_type, instances_component.instances_num());
+ to_type, instances.instances_num());
conversions.convert_to_initialized_n(span, temporary_array->as_mutable_span());
span = temporary_array->as_span();
gather_info.r_temporary_arrays.append(std::move(temporary_array));
@@ -450,17 +453,17 @@ static void foreach_geometry_in_reference(
}
static void gather_realize_tasks_for_instances(GatherTasksInfo &gather_info,
- const InstancesComponent &instances_component,
+ const Instances &instances,
const float4x4 &base_transform,
const InstanceContext &base_instance_context)
{
- const Span<InstanceReference> references = instances_component.references();
- const Span<int> handles = instances_component.instance_reference_handles();
- const Span<float4x4> transforms = instances_component.instance_transforms();
+ const Span<InstanceReference> references = instances.references();
+ const Span<int> handles = instances.reference_handles();
+ const Span<float4x4> transforms = instances.transforms();
Span<int> stored_instance_ids;
if (gather_info.create_id_attribute_on_any_component) {
- std::optional<GSpan> ids = instances_component.instance_attributes().get_for_read("id");
+ std::optional<GSpan> ids = instances.custom_data_attributes().get_for_read("id");
if (ids.has_value()) {
stored_instance_ids = ids->typed<int>();
}
@@ -469,11 +472,11 @@ static void gather_realize_tasks_for_instances(GatherTasksInfo &gather_info,
/* Prepare attribute fallbacks. */
InstanceContext instance_context = base_instance_context;
Vector<std::pair<int, GSpan>> pointcloud_attributes_to_override = prepare_attribute_fallbacks(
- gather_info, instances_component, gather_info.pointclouds.attributes);
+ gather_info, instances, gather_info.pointclouds.attributes);
Vector<std::pair<int, GSpan>> mesh_attributes_to_override = prepare_attribute_fallbacks(
- gather_info, instances_component, gather_info.meshes.attributes);
+ gather_info, instances, gather_info.meshes.attributes);
Vector<std::pair<int, GSpan>> curve_attributes_to_override = prepare_attribute_fallbacks(
- gather_info, instances_component, gather_info.curves.attributes);
+ gather_info, instances, gather_info.curves.attributes);
for (const int i : transforms.index_range()) {
const int handle = handles[i];
@@ -584,8 +587,11 @@ static void gather_realize_tasks_recursive(GatherTasksInfo &gather_info,
case GEO_COMPONENT_TYPE_INSTANCES: {
const InstancesComponent &instances_component = *static_cast<const InstancesComponent *>(
component);
- gather_realize_tasks_for_instances(
- gather_info, instances_component, base_transform, base_instance_context);
+ const Instances *instances = instances_component.get_for_read();
+ if (instances != nullptr && instances->instances_num() > 0) {
+ gather_realize_tasks_for_instances(
+ gather_info, *instances, base_transform, base_instance_context);
+ }
break;
}
case GEO_COMPONENT_TYPE_VOLUME: {
@@ -645,8 +651,7 @@ static void gather_pointclouds_to_realize(const GeometrySet &geometry_set,
r_pointclouds.add(pointcloud);
}
}
- if (const InstancesComponent *instances =
- geometry_set.get_component_for_read<InstancesComponent>()) {
+ if (const Instances *instances = geometry_set.get_instances_for_read()) {
instances->foreach_referenced_geometry([&](const GeometrySet &instance_geometry_set) {
gather_pointclouds_to_realize(instance_geometry_set, r_pointclouds);
});
@@ -827,8 +832,7 @@ static void gather_meshes_to_realize(const GeometrySet &geometry_set,
r_meshes.add(mesh);
}
}
- if (const InstancesComponent *instances =
- geometry_set.get_component_for_read<InstancesComponent>()) {
+ if (const Instances *instances = geometry_set.get_instances_for_read()) {
instances->foreach_referenced_geometry([&](const GeometrySet &instance_geometry_set) {
gather_meshes_to_realize(instance_geometry_set, r_meshes);
});
@@ -855,6 +859,7 @@ static AllMeshesInfo preprocess_meshes(const GeometrySet &geometry_set,
}
}
}
+ info.create_material_index_attribute |= info.materials.size() > 1;
info.realize_info.reinitialize(info.order.size());
for (const int mesh_index : info.realize_info.index_range()) {
MeshRealizeInfo &mesh_info = info.realize_info[mesh_index];
@@ -1148,8 +1153,7 @@ static void gather_curves_to_realize(const GeometrySet &geometry_set,
r_curves.add(curves);
}
}
- if (const InstancesComponent *instances =
- geometry_set.get_component_for_read<InstancesComponent>()) {
+ if (const Instances *instances = geometry_set.get_instances_for_read()) {
instances->foreach_referenced_geometry([&](const GeometrySet &instance_geometry_set) {
gather_curves_to_realize(instance_geometry_set, r_curves);
});
@@ -1415,9 +1419,8 @@ static void execute_realize_curve_tasks(const RealizeInstancesOptions &options,
static void remove_id_attribute_from_instances(GeometrySet &geometry_set)
{
geometry_set.modify_geometry_sets([&](GeometrySet &sub_geometry) {
- if (sub_geometry.has<InstancesComponent>()) {
- InstancesComponent &component = sub_geometry.get_component_for_write<InstancesComponent>();
- component.instance_attributes().remove("id");
+ if (Instances *instances = sub_geometry.get_instances_for_write()) {
+ instances->custom_data_attributes().remove("id");
}
});
}
diff --git a/source/blender/geometry/intern/resample_curves.cc b/source/blender/geometry/intern/resample_curves.cc
index a7f6ac16f8d..3be850ec097 100644
--- a/source/blender/geometry/intern/resample_curves.cc
+++ b/source/blender/geometry/intern/resample_curves.cc
@@ -139,6 +139,9 @@ static void gather_point_attributes_to_interpolate(
if (meta_data.domain != ATTR_DOMAIN_POINT) {
return true;
}
+ if (meta_data.data_type == CD_PROP_STRING) {
+ return true;
+ }
if (!interpolate_attribute_to_curves(id, dst_curves.curve_type_counts())) {
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..58b1cd0a50b 100644
--- a/source/blender/gpu/CMakeLists.txt
+++ b/source/blender/gpu/CMakeLists.txt
@@ -186,9 +186,11 @@ set(OPENGL_SRC
set(METAL_SRC
metal/mtl_backend.mm
+ metal/mtl_batch.mm
metal/mtl_command_buffer.mm
metal/mtl_context.mm
metal/mtl_debug.mm
+ metal/mtl_drawlist.mm
metal/mtl_framebuffer.mm
metal/mtl_immediate.mm
metal/mtl_index_buffer.mm
@@ -280,6 +282,8 @@ set(GLSL_SRC
shaders/gpu_shader_2D_image_vert.glsl
shaders/gpu_shader_2D_image_rect_vert.glsl
shaders/gpu_shader_2D_image_multi_rect_vert.glsl
+ shaders/gpu_shader_icon_frag.glsl
+ shaders/gpu_shader_icon_vert.glsl
shaders/gpu_shader_image_frag.glsl
shaders/gpu_shader_image_desaturate_frag.glsl
shaders/gpu_shader_image_overlays_merge_frag.glsl
@@ -332,6 +336,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 +351,8 @@ 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_normalize.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
@@ -353,6 +360,8 @@ set(GLSL_SRC
shaders/compositor/compositor_split_viewer.glsl
shaders/compositor/compositor_symmetric_blur.glsl
shaders/compositor/compositor_symmetric_separable_blur.glsl
+ shaders/compositor/compositor_tone_map_photoreceptor.glsl
+ shaders/compositor/compositor_tone_map_simple.glsl
shaders/compositor/library/gpu_shader_compositor_alpha_over.glsl
shaders/compositor/library/gpu_shader_compositor_blur_common.glsl
@@ -602,6 +611,7 @@ set(SRC_SHADER_CREATE_INFOS
shaders/infos/gpu_shader_3D_smooth_color_info.hh
shaders/infos/gpu_shader_3D_uniform_color_info.hh
shaders/infos/gpu_shader_gpencil_stroke_info.hh
+ shaders/infos/gpu_shader_icon_info.hh
shaders/infos/gpu_shader_instance_varying_color_varying_size_info.hh
shaders/infos/gpu_shader_keyframe_shape_info.hh
shaders/infos/gpu_shader_line_dashed_uniform_color_info.hh
@@ -612,6 +622,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 +637,8 @@ 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_normalize_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
@@ -633,6 +646,8 @@ set(SRC_SHADER_CREATE_INFOS
shaders/compositor/infos/compositor_split_viewer_info.hh
shaders/compositor/infos/compositor_symmetric_blur_info.hh
shaders/compositor/infos/compositor_symmetric_separable_blur_info.hh
+ shaders/compositor/infos/compositor_tone_map_photoreceptor_info.hh
+ shaders/compositor/infos/compositor_tone_map_simple_info.hh
)
set(SRC_SHADER_CREATE_INFOS_MTL
diff --git a/source/blender/gpu/GPU_context.h b/source/blender/gpu/GPU_context.h
index b59ea9e55d2..ac82774039a 100644
--- a/source/blender/gpu/GPU_context.h
+++ b/source/blender/gpu/GPU_context.h
@@ -21,6 +21,8 @@ extern "C" {
* automatically initializes the back-end, and #GPU_context_discard frees it when there
* are no more contexts. */
bool GPU_backend_supported(void);
+void GPU_backend_type_selection_set(const eGPUBackendType backend);
+eGPUBackendType GPU_backend_type_selection_get(void);
eGPUBackendType GPU_backend_get_type(void);
/** Opaque type hiding blender::gpu::Context. */
diff --git a/source/blender/gpu/GPU_shader.h b/source/blender/gpu/GPU_shader.h
index 3f35db42eb9..1148207fc57 100644
--- a/source/blender/gpu/GPU_shader.h
+++ b/source/blender/gpu/GPU_shader.h
@@ -209,6 +209,10 @@ typedef enum eGPUBuiltinShader {
GPU_SHADER_KEYFRAME_SHAPE,
GPU_SHADER_SIMPLE_LIGHTING,
/**
+ * Draw an icon, leaving a semi-transparent rectangle on top of the icon.
+ */
+ GPU_SHADER_ICON,
+ /**
* Take a 2D position and color for each vertex with linear interpolation in window space.
*
* \param color: in vec4
diff --git a/source/blender/gpu/intern/gpu_context.cc b/source/blender/gpu/intern/gpu_context.cc
index 48d7b2019c5..f6b88c4231c 100644
--- a/source/blender/gpu/intern/gpu_context.cc
+++ b/source/blender/gpu/intern/gpu_context.cc
@@ -223,9 +223,19 @@ void GPU_render_step()
/* NOTE: To enable Metal API, we need to temporarily change this to `GPU_BACKEND_METAL`.
* Until a global switch is added, Metal also needs to be enabled in GHOST_ContextCGL:
* `m_useMetalForRendering = true`. */
-static const eGPUBackendType g_backend_type = GPU_BACKEND_OPENGL;
+static eGPUBackendType g_backend_type = GPU_BACKEND_OPENGL;
static GPUBackend *g_backend = nullptr;
+void GPU_backend_type_selection_set(const eGPUBackendType backend)
+{
+ g_backend_type = backend;
+}
+
+eGPUBackendType GPU_backend_type_selection_get()
+{
+ return g_backend_type;
+}
+
bool GPU_backend_supported(void)
{
switch (g_backend_type) {
diff --git a/source/blender/gpu/intern/gpu_framebuffer_private.hh b/source/blender/gpu/intern/gpu_framebuffer_private.hh
index 76e816e7f65..5afcc102e44 100644
--- a/source/blender/gpu/intern/gpu_framebuffer_private.hh
+++ b/source/blender/gpu/intern/gpu_framebuffer_private.hh
@@ -95,11 +95,6 @@ class FrameBuffer {
#endif
public:
- /* Reference of a pointer that needs to be cleaned when deallocating the frame-buffer.
- * Points to #BPyGPUFrameBuffer::fb */
- void **ref = nullptr;
-
- public:
FrameBuffer(const char *name);
virtual ~FrameBuffer();
diff --git a/source/blender/gpu/intern/gpu_immediate.cc b/source/blender/gpu/intern/gpu_immediate.cc
index 3b4accf9cc5..81c0a65bb7c 100644
--- a/source/blender/gpu/intern/gpu_immediate.cc
+++ b/source/blender/gpu/intern/gpu_immediate.cc
@@ -45,7 +45,7 @@ void immBindShader(GPUShader *shader)
BLI_assert(imm->shader == nullptr);
imm->shader = shader;
- imm->builtin_shader_bound = GPU_SHADER_TEXT; /* Default value. */
+ imm->builtin_shader_bound = std::nullopt;
if (!imm->vertex_format.packed) {
VertexFormat_pack(&imm->vertex_format);
@@ -125,9 +125,12 @@ static void wide_line_workaround_start(GPUPrimType prim_type)
/* No need to change the shader. */
return;
}
+ if (!imm->builtin_shader_bound) {
+ return;
+ }
eGPUBuiltinShader polyline_sh;
- switch (imm->builtin_shader_bound) {
+ switch (*imm->builtin_shader_bound) {
case GPU_SHADER_3D_CLIPPED_UNIFORM_COLOR:
polyline_sh = GPU_SHADER_3D_POLYLINE_CLIPPED_UNIFORM_COLOR;
break;
@@ -180,8 +183,8 @@ static void wide_line_workaround_end()
}
immUnbindProgram();
- immBindBuiltinProgram(imm->prev_builtin_shader);
- imm->prev_builtin_shader = GPU_SHADER_TEXT;
+ immBindBuiltinProgram(*imm->prev_builtin_shader);
+ imm->prev_builtin_shader = std::nullopt;
}
}
diff --git a/source/blender/gpu/intern/gpu_immediate_private.hh b/source/blender/gpu/intern/gpu_immediate_private.hh
index 74ebbdc7ae3..c4e11e7082b 100644
--- a/source/blender/gpu/intern/gpu_immediate_private.hh
+++ b/source/blender/gpu/intern/gpu_immediate_private.hh
@@ -9,6 +9,8 @@
#pragma once
+#include <optional>
+
#include "GPU_batch.h"
#include "GPU_primitive.h"
#include "GPU_shader.h"
@@ -42,9 +44,9 @@ class Immediate {
/** Wide Line workaround. */
/** Previously bound shader to restore after drawing. */
- eGPUBuiltinShader prev_builtin_shader = GPU_SHADER_TEXT;
- /** Builtin shader index. Used to test if the workaround can be done. */
- eGPUBuiltinShader builtin_shader_bound = GPU_SHADER_TEXT;
+ std::optional<eGPUBuiltinShader> prev_builtin_shader;
+ /** Builtin shader index. Used to test if the line width workaround can be done. */
+ std::optional<eGPUBuiltinShader> builtin_shader_bound;
/** Uniform color: Kept here to update the wide-line shader just before #immBegin. */
float uniform_color[4];
diff --git a/source/blender/gpu/intern/gpu_shader_builder.cc b/source/blender/gpu/intern/gpu_shader_builder.cc
index 3aa2963ecd0..abb45ca074a 100644
--- a/source/blender/gpu/intern/gpu_shader_builder.cc
+++ b/source/blender/gpu/intern/gpu_shader_builder.cc
@@ -15,6 +15,8 @@
#include "GPU_init_exit.h"
#include "gpu_shader_create_info_private.hh"
+#include "BLI_vector.hh"
+
#include "CLG_log.h"
namespace blender::gpu::shader_builder {
@@ -41,6 +43,22 @@ void ShaderBuilder::init()
CLG_init();
GHOST_GLSettings glSettings = {0};
+ switch (GPU_backend_type_selection_get()) {
+ case GPU_BACKEND_OPENGL:
+ glSettings.context_type = GHOST_kDrawingContextTypeOpenGL;
+ break;
+
+#ifdef WITH_METAL_BACKEND
+ case GPU_BACKEND_METAL:
+ glSettings.context_type = GHOST_kDrawingContextTypeMetal;
+ break;
+#endif
+
+ default:
+ BLI_assert_unreachable();
+ break;
+ }
+
ghost_system_ = GHOST_CreateSystem();
ghost_context_ = GHOST_CreateOpenGLContext(ghost_system_, glSettings);
GHOST_ActivateOpenGLContext(ghost_context_);
@@ -73,13 +91,32 @@ int main(int argc, const char *argv[])
int exit_code = 0;
- blender::gpu::shader_builder::ShaderBuilder builder;
- builder.init();
- if (!builder.bake_create_infos()) {
- exit_code = 1;
+ struct NamedBackend {
+ std::string name;
+ eGPUBackendType backend;
+ };
+
+ blender::Vector<NamedBackend> backends_to_validate;
+ backends_to_validate.append({"OpenGL", GPU_BACKEND_OPENGL});
+#ifdef WITH_METAL_BACKEND
+ backends_to_validate.append({"Metal", GPU_BACKEND_METAL});
+#endif
+ for (NamedBackend &backend : backends_to_validate) {
+ GPU_backend_type_selection_set(backend.backend);
+ if (!GPU_backend_supported()) {
+ printf("%s isn't supported on this platform. Shader compilation is skipped\n",
+ backend.name.c_str());
+ continue;
+ }
+ blender::gpu::shader_builder::ShaderBuilder builder;
+ builder.init();
+ if (!builder.bake_create_infos()) {
+ printf("Shader compilation failed for %s backend\n", backend.name.c_str());
+ exit_code = 1;
+ }
+ builder.exit();
}
- builder.exit();
- exit(exit_code);
+ exit(exit_code);
return exit_code;
}
diff --git a/source/blender/gpu/intern/gpu_shader_builder_stubs.cc b/source/blender/gpu/intern/gpu_shader_builder_stubs.cc
index 7a06ede5c6d..65bda7ba858 100644
--- a/source/blender/gpu/intern/gpu_shader_builder_stubs.cc
+++ b/source/blender/gpu/intern/gpu_shader_builder_stubs.cc
@@ -46,6 +46,15 @@ void IMB_freeImBuf(ImBuf * /*ibuf*/)
BLI_assert_unreachable();
}
+struct ImBuf *IMB_allocImBuf(unsigned int /*x*/,
+ unsigned int /*y*/,
+ unsigned char /*planes*/,
+ unsigned int /*flags*/)
+{
+ BLI_assert_unreachable();
+ return nullptr;
+}
+
/** \} */
/* -------------------------------------------------------------------- */
diff --git a/source/blender/gpu/intern/gpu_shader_builtin.c b/source/blender/gpu/intern/gpu_shader_builtin.c
index 8a6586e06f6..470643ba863 100644
--- a/source/blender/gpu/intern/gpu_shader_builtin.c
+++ b/source/blender/gpu/intern/gpu_shader_builtin.c
@@ -153,6 +153,11 @@ static const GPUShaderStages builtin_shader_stages[GPU_SHADER_BUILTIN_LEN] = {
.create_info = "gpu_shader_2D_diag_stripes",
},
+ [GPU_SHADER_ICON] =
+ {
+ .name = "GPU_SHADER_ICON",
+ .create_info = "gpu_shader_icon",
+ },
[GPU_SHADER_2D_IMAGE_OVERLAYS_MERGE] =
{
.name = "GPU_SHADER_2D_IMAGE_OVERLAYS_MERGE",
diff --git a/source/blender/gpu/intern/gpu_texture_private.hh b/source/blender/gpu/intern/gpu_texture_private.hh
index b96a9b870e5..124b1751b96 100644
--- a/source/blender/gpu/intern/gpu_texture_private.hh
+++ b/source/blender/gpu/intern/gpu_texture_private.hh
@@ -431,15 +431,16 @@ inline bool validate_data_format(eGPUTextureFormat tex_format, eGPUDataFormat da
case GPU_DEPTH_COMPONENT24:
case GPU_DEPTH_COMPONENT16:
case GPU_DEPTH_COMPONENT32F:
- return data_format == GPU_DATA_FLOAT;
+ return ELEM(data_format, GPU_DATA_FLOAT, GPU_DATA_UINT);
case GPU_DEPTH24_STENCIL8:
case GPU_DEPTH32F_STENCIL8:
- return data_format == GPU_DATA_UINT_24_8;
+ return ELEM(data_format, GPU_DATA_UINT_24_8, GPU_DATA_UINT);
case GPU_R8UI:
case GPU_R16UI:
case GPU_RG16UI:
case GPU_R32UI:
return data_format == GPU_DATA_UINT;
+ case GPU_R32I:
case GPU_RG16I:
case GPU_R16I:
return data_format == GPU_DATA_INT;
@@ -453,6 +454,8 @@ inline bool validate_data_format(eGPUTextureFormat tex_format, eGPUDataFormat da
return ELEM(data_format, GPU_DATA_2_10_10_10_REV, GPU_DATA_FLOAT);
case GPU_R11F_G11F_B10F:
return ELEM(data_format, GPU_DATA_10_11_11_REV, GPU_DATA_FLOAT);
+ case GPU_RGBA16F:
+ return ELEM(data_format, GPU_DATA_HALF_FLOAT, GPU_DATA_FLOAT);
default:
return data_format == GPU_DATA_FLOAT;
}
@@ -585,7 +588,7 @@ inline eGPUFrameBufferBits to_framebuffer_bits(eGPUTextureFormat tex_format)
static inline eGPUTextureFormat to_texture_format(const GPUVertFormat *format)
{
- if (format->attr_len > 1 || format->attr_len == 0) {
+ if (format->attr_len == 0) {
BLI_assert_msg(0, "Incorrect vertex format for buffer texture");
return GPU_DEPTH_COMPONENT24;
}
diff --git a/source/blender/gpu/intern/gpu_vertex_format.cc b/source/blender/gpu/intern/gpu_vertex_format.cc
index b30e3c358c8..76d95ac1b55 100644
--- a/source/blender/gpu/intern/gpu_vertex_format.cc
+++ b/source/blender/gpu/intern/gpu_vertex_format.cc
@@ -361,8 +361,12 @@ void VertexFormat_texture_buffer_pack(GPUVertFormat *format)
* minimum per-vertex stride, which mandates 4-byte alignment in Metal.
* This additional alignment padding caused smaller data types, e.g. U16,
* to mis-align. */
- BLI_assert_msg(format->attr_len == 1,
- "Texture buffer mode should only use a single vertex attribute.");
+ for (int i = 0; i < format->attr_len; i++) {
+ /* The buffer texture setup uses the first attribute for type and size.
+ * Make sure all attributes use the same size. */
+ BLI_assert_msg(format->attrs[i].size == format->attrs[0].size,
+ "Texture buffer mode should only use a attributes with the same size.");
+ }
/* Pack vertex format without minimum stride, as this is not required by texture buffers. */
VertexFormat_pack_impl(format, 1);
diff --git a/source/blender/gpu/intern/gpu_viewport.c b/source/blender/gpu/intern/gpu_viewport.c
index 71bdf9e336b..e267d5a2f12 100644
--- a/source/blender/gpu/intern/gpu_viewport.c
+++ b/source/blender/gpu/intern/gpu_viewport.c
@@ -147,6 +147,10 @@ static void gpu_viewport_textures_create(GPUViewport *viewport)
if (viewport->depth_tx == NULL) {
viewport->depth_tx = GPU_texture_create_2d(
"dtxl_depth", UNPACK2(size), 1, GPU_DEPTH24_STENCIL8, NULL);
+ if (GPU_clear_viewport_workaround()) {
+ static int depth_clear = 0;
+ GPU_texture_clear(viewport->depth_tx, GPU_DATA_UINT_24_8, &depth_clear);
+ }
}
if (!viewport->depth_tx || !viewport->color_render_tx[0] || !viewport->color_overlay_tx[0]) {
diff --git a/source/blender/gpu/metal/mtl_backend.mm b/source/blender/gpu/metal/mtl_backend.mm
index 2ca1fd3f3d0..240951c1ebd 100644
--- a/source/blender/gpu/metal/mtl_backend.mm
+++ b/source/blender/gpu/metal/mtl_backend.mm
@@ -47,13 +47,11 @@ Context *MTLBackend::context_alloc(void *ghost_window, void *ghost_context)
Batch *MTLBackend::batch_alloc()
{
- /* TODO(Metal): Full MTLBatch implementation. */
return new MTLBatch();
};
DrawList *MTLBackend::drawlist_alloc(int list_length)
{
- /* TODO(Metal): Full MTLDrawList implementation. */
return new MTLDrawList(list_length);
};
@@ -420,6 +418,7 @@ void MTLBackend::capabilities_init(MTLContext *ctx)
GCaps.depth_blitting_workaround = false;
GCaps.use_main_context_workaround = false;
GCaps.broken_amd_driver = false;
+ GCaps.clear_viewport_workaround = true;
/* Metal related workarounds. */
/* Minimum per-vertex stride is 4 bytes in Metal.
diff --git a/source/blender/gpu/metal/mtl_batch.hh b/source/blender/gpu/metal/mtl_batch.hh
index 236367bf5a4..9e179e662b5 100644
--- a/source/blender/gpu/metal/mtl_batch.hh
+++ b/source/blender/gpu/metal/mtl_batch.hh
@@ -10,31 +10,126 @@
#pragma once
#include "MEM_guardedalloc.h"
-
#include "gpu_batch_private.hh"
+#include "mtl_index_buffer.hh"
+#include "mtl_primitive.hh"
+#include "mtl_shader.hh"
+#include "mtl_vertex_buffer.hh"
+
+namespace blender::gpu {
+
+class MTLContext;
+class MTLShaderInterface;
+
+#define GPU_VAO_STATIC_LEN 64
-namespace blender {
-namespace gpu {
+struct VertexBufferID {
+ uint32_t id : 16;
+ uint32_t is_instance : 15;
+ uint32_t used : 1;
+};
-/* Pass-through MTLBatch. TODO(Metal): Implement. */
class MTLBatch : public Batch {
+
+ /* Vertex Bind-state Caching for a given shader interface used with the Batch. */
+ struct VertexDescriptorShaderInterfacePair {
+ MTLVertexDescriptor vertex_descriptor{};
+ const ShaderInterface *interface = nullptr;
+ uint16_t attr_mask{};
+ int num_buffers{};
+ VertexBufferID bufferIds[GPU_BATCH_VBO_MAX_LEN] = {};
+ /* Cache life index compares a cache entry with the active MTLBatch state.
+ * This is initially set to the cache life index of MTLBatch. If the batch has been modified,
+ * this index is incremented to cheaply invalidate existing cache entries. */
+ uint32_t cache_life_index = 0;
+ };
+
+ class MTLVertexDescriptorCache {
+
+ private:
+ MTLBatch *batch_;
+
+ VertexDescriptorShaderInterfacePair cache_[GPU_VAO_STATIC_LEN] = {};
+ MTLContext *cache_context_ = nullptr;
+ uint32_t cache_life_index_ = 0;
+
+ public:
+ MTLVertexDescriptorCache(MTLBatch *batch) : batch_(batch){};
+ VertexDescriptorShaderInterfacePair *find(const ShaderInterface *interface);
+ bool insert(VertexDescriptorShaderInterfacePair &data);
+
+ private:
+ void vertex_descriptor_cache_init(MTLContext *ctx);
+ void vertex_descriptor_cache_clear();
+ void vertex_descriptor_cache_ensure();
+ };
+
+ private:
+ MTLShader *active_shader_ = nullptr;
+ bool shader_in_use_ = false;
+ MTLVertexDescriptorCache vao_cache = {this};
+
+ /* Topology emulation. */
+ gpu::MTLBuffer *emulated_topology_buffer_ = nullptr;
+ GPUPrimType emulated_topology_type_;
+ uint32_t topology_buffer_input_v_count_ = 0;
+ uint32_t topology_buffer_output_v_count_ = 0;
+
public:
- void draw(int v_first, int v_count, int i_first, int i_count) override
- {
- }
+ MTLBatch(){};
+ ~MTLBatch(){};
+ void draw(int v_first, int v_count, int i_first, int i_count) override;
void draw_indirect(GPUStorageBuf *indirect_buf, intptr_t offset) override
{
+ /* TODO(Metal): Support indirect draw commands. */
}
-
void multi_draw_indirect(GPUStorageBuf *indirect_buf,
int count,
intptr_t offset,
intptr_t stride) override
{
+ /* TODO(Metal): Support indirect draw commands. */
+ }
+
+ /* Returns an initialized RenderComandEncoder for drawing if all is good.
+ * Otherwise, nil. */
+ id<MTLRenderCommandEncoder> bind(uint v_first, uint v_count, uint i_first, uint i_count);
+ void unbind();
+
+ /* Convenience getters. */
+ MTLIndexBuf *elem_() const
+ {
+ return static_cast<MTLIndexBuf *>(unwrap(elem));
+ }
+ MTLVertBuf *verts_(const int index) const
+ {
+ return static_cast<MTLVertBuf *>(unwrap(verts[index]));
}
+ MTLVertBuf *inst_(const int index) const
+ {
+ return static_cast<MTLVertBuf *>(unwrap(inst[index]));
+ }
+ MTLShader *active_shader_get() const
+ {
+ return active_shader_;
+ }
+
+ private:
+ void shader_bind();
+ void draw_advanced(int v_first, int v_count, int i_first, int i_count);
+ int prepare_vertex_binding(MTLVertBuf *verts,
+ MTLRenderPipelineStateDescriptor &desc,
+ const MTLShaderInterface *interface,
+ uint16_t &attr_mask,
+ bool instanced);
+
+ id<MTLBuffer> get_emulated_toplogy_buffer(GPUPrimType &in_out_prim_type, uint32_t &v_count);
+
+ void prepare_vertex_descriptor_and_bindings(
+ MTLVertBuf **buffers, int &num_buffers, int v_first, int v_count, int i_first, int i_count);
+
MEM_CXX_CLASS_ALLOC_FUNCS("MTLBatch");
};
-} // namespace gpu
-} // namespace blender
+} // namespace blender::gpu
diff --git a/source/blender/gpu/metal/mtl_batch.mm b/source/blender/gpu/metal/mtl_batch.mm
new file mode 100644
index 00000000000..988fb9b793b
--- /dev/null
+++ b/source/blender/gpu/metal/mtl_batch.mm
@@ -0,0 +1,998 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+
+/** \file
+ * \ingroup gpu
+ *
+ * Metal implementation of GPUBatch.
+ */
+
+#include "BLI_assert.h"
+#include "BLI_span.hh"
+
+#include "BKE_global.h"
+
+#include "GPU_common.h"
+#include "gpu_batch_private.hh"
+#include "gpu_shader_private.hh"
+
+#include "mtl_batch.hh"
+#include "mtl_context.hh"
+#include "mtl_debug.hh"
+#include "mtl_index_buffer.hh"
+#include "mtl_shader.hh"
+#include "mtl_vertex_buffer.hh"
+
+#include <string>
+
+namespace blender::gpu {
+
+/* -------------------------------------------------------------------- */
+/** \name Creation & Deletion
+ * \{ */
+void MTLBatch::draw(int v_first, int v_count, int i_first, int i_count)
+{
+ if (this->flag & GPU_BATCH_INVALID) {
+ this->shader_in_use_ = false;
+ }
+ this->draw_advanced(v_first, v_count, i_first, i_count);
+}
+
+void MTLBatch::shader_bind()
+{
+ if (active_shader_ && active_shader_->is_valid()) {
+ active_shader_->bind();
+ shader_in_use_ = true;
+ }
+}
+
+void MTLBatch::MTLVertexDescriptorCache::vertex_descriptor_cache_init(MTLContext *ctx)
+{
+ BLI_assert(ctx != nullptr);
+ this->vertex_descriptor_cache_clear();
+ cache_context_ = ctx;
+}
+
+void MTLBatch::MTLVertexDescriptorCache::vertex_descriptor_cache_clear()
+{
+ cache_life_index_++;
+ cache_context_ = nullptr;
+}
+
+void MTLBatch::MTLVertexDescriptorCache::vertex_descriptor_cache_ensure()
+{
+ if (this->cache_context_ != nullptr) {
+
+ /* Invalidate vertex descriptor bindings cache if batch has changed. */
+ if (batch_->flag & GPU_BATCH_DIRTY) {
+ batch_->flag &= ~GPU_BATCH_DIRTY;
+ this->vertex_descriptor_cache_clear();
+ }
+ }
+
+ /* Initialize cache if not ready. */
+ if (cache_context_ == nullptr) {
+ this->vertex_descriptor_cache_init(MTLContext::get());
+ }
+}
+
+MTLBatch::VertexDescriptorShaderInterfacePair *MTLBatch::MTLVertexDescriptorCache::find(
+ const ShaderInterface *interface)
+{
+ this->vertex_descriptor_cache_ensure();
+ for (int i = 0; i < GPU_VAO_STATIC_LEN; ++i) {
+ if (cache_[i].interface == interface && cache_[i].cache_life_index == cache_life_index_) {
+ return &cache_[i];
+ }
+ }
+ return nullptr;
+}
+
+bool MTLBatch::MTLVertexDescriptorCache::insert(
+ MTLBatch::VertexDescriptorShaderInterfacePair &data)
+{
+ vertex_descriptor_cache_ensure();
+ for (int i = 0; i < GPU_VAO_STATIC_LEN; ++i) {
+ if (cache_[i].interface == nullptr || cache_[i].cache_life_index != cache_life_index_) {
+ cache_[i] = data;
+ cache_[i].cache_life_index = cache_life_index_;
+ return true;
+ }
+ }
+ return false;
+}
+
+int MTLBatch::prepare_vertex_binding(MTLVertBuf *verts,
+ MTLRenderPipelineStateDescriptor &desc,
+ const MTLShaderInterface *interface,
+ uint16_t &attr_mask,
+ bool instanced)
+{
+
+ const GPUVertFormat *format = &verts->format;
+ /* Whether the current vertex buffer has been added to the buffer layout descriptor. */
+ bool buffer_added = false;
+ /* Per-vertex stride of current vertex buffer. */
+ int buffer_stride = format->stride;
+ /* Buffer binding index of the vertex buffer once added to the buffer layout descriptor. */
+ int buffer_index = -1;
+ int attribute_offset = 0;
+
+ if (!active_shader_->get_uses_ssbo_vertex_fetch()) {
+ BLI_assert(
+ buffer_stride >= 4 &&
+ "In Metal, Vertex buffer stride should be 4. SSBO Vertex fetch is not affected by this");
+ }
+
+ /* Iterate over GPUVertBuf vertex format and find attributes matching those in the active
+ * shader's interface. */
+ for (uint32_t a_idx = 0; a_idx < format->attr_len; a_idx++) {
+ const GPUVertAttr *a = &format->attrs[a_idx];
+
+ if (format->deinterleaved) {
+ attribute_offset += ((a_idx == 0) ? 0 : format->attrs[a_idx - 1].size) * verts->vertex_len;
+ buffer_stride = a->size;
+ }
+ else {
+ attribute_offset = a->offset;
+ }
+
+ /* Find attribute with the matching name. Attributes may have multiple compatible
+ * name aliases. */
+ for (uint32_t n_idx = 0; n_idx < a->name_len; n_idx++) {
+ const char *name = GPU_vertformat_attr_name_get(format, a, n_idx);
+ const ShaderInput *input = interface->attr_get(name);
+
+ if (input == nullptr || input->location == -1) {
+ /* Vertex/instance buffers provided have attribute data for attributes which are not needed
+ * by this particular shader. This shader only needs binding information for the attributes
+ * has in the shader interface. */
+ MTL_LOG_WARNING(
+ "MTLBatch: Could not find attribute with name '%s' (defined in active vertex format) "
+ "in the shader interface for shader '%s'\n",
+ name,
+ interface->get_name());
+ continue;
+ }
+
+ /* Fetch metal attribute information. */
+ const MTLShaderInputAttribute &mtl_attr = interface->get_attribute(input->location);
+ BLI_assert(mtl_attr.location >= 0);
+ /* Verify that the attribute location from the shader interface
+ * matches the attribute location returned. */
+ BLI_assert(mtl_attr.location == input->location);
+
+ /* Check if attribute is already present in the given slot. */
+ if ((~attr_mask) & (1 << mtl_attr.location)) {
+ MTL_LOG_INFO(
+ " -- [Batch] Skipping attribute with input location %d (As one is already bound)\n",
+ mtl_attr.location);
+ }
+ else {
+
+ /* Update attribute used-slot mask. */
+ attr_mask &= ~(1 << mtl_attr.location);
+
+ /* Add buffer layout entry in descriptor if it has not yet been added
+ * for current vertex buffer. */
+ if (!buffer_added) {
+ buffer_index = desc.vertex_descriptor.num_vert_buffers;
+ desc.vertex_descriptor.buffer_layouts[buffer_index].step_function =
+ (instanced) ? MTLVertexStepFunctionPerInstance : MTLVertexStepFunctionPerVertex;
+ desc.vertex_descriptor.buffer_layouts[buffer_index].step_rate = 1;
+ desc.vertex_descriptor.buffer_layouts[buffer_index].stride = buffer_stride;
+ desc.vertex_descriptor.num_vert_buffers++;
+ buffer_added = true;
+
+ MTL_LOG_INFO(" -- [Batch] Adding source %s buffer (Index: %d, Stride: %d)\n",
+ (instanced) ? "instance" : "vertex",
+ buffer_index,
+ buffer_stride);
+ }
+ else {
+ /* Ensure stride is correct for de-interleaved attributes. */
+ desc.vertex_descriptor.buffer_layouts[buffer_index].stride = buffer_stride;
+ }
+
+ /* Handle Matrix/Array vertex attribute types.
+ * Metal does not natively support these as attribute types, so we handle these cases
+ * by stacking together compatible types (e.g. 4xVec4 for Mat4) and combining
+ * the data in the shader.
+ * The generated Metal shader will contain a generated input binding, which reads
+ * in individual attributes and merges them into the desired type after vertex
+ * assembly. e.g. a Mat4 (Float4x4) will generate 4 Float4 attributes. */
+ if (a->comp_len == 16 || a->comp_len == 12 || a->comp_len == 8) {
+ BLI_assert_msg(
+ a->comp_len == 16,
+ "only mat4 attributes currently supported -- Not ready to handle other long "
+ "component length attributes yet");
+
+ /* SSBO Vertex Fetch Attribute safety checks. */
+ if (active_shader_->get_uses_ssbo_vertex_fetch()) {
+ /* When using SSBO vertex fetch, we do not need to expose split attributes,
+ * A matrix can be read directly as a whole block of contiguous data. */
+ MTLSSBOAttribute ssbo_attr(mtl_attr.index,
+ buffer_index,
+ attribute_offset,
+ buffer_stride,
+ GPU_SHADER_ATTR_TYPE_MAT4,
+ instanced);
+ active_shader_->ssbo_vertex_fetch_bind_attribute(ssbo_attr);
+ desc.vertex_descriptor.ssbo_attributes[desc.vertex_descriptor.num_ssbo_attributes] =
+ ssbo_attr;
+ desc.vertex_descriptor.num_ssbo_attributes++;
+ }
+ else {
+
+ /* Handle Mat4 attributes. */
+ if (a->comp_len == 16) {
+ /* Debug safety checks. */
+ BLI_assert_msg(mtl_attr.matrix_element_count == 4,
+ "mat4 type expected but there are fewer components");
+ BLI_assert_msg(mtl_attr.size == 16, "Expecting subtype 'vec4' with 16 bytes");
+ BLI_assert_msg(
+ mtl_attr.format == MTLVertexFormatFloat4,
+ "Per-attribute vertex format MUST be float4 for an input type of 'mat4'");
+
+ /* We have found the 'ROOT' attribute. A mat4 contains 4 consecutive float4 attribute
+ * locations we must map to. */
+ for (int i = 0; i < a->comp_len / 4; i++) {
+ desc.vertex_descriptor.attributes[mtl_attr.location + i].format =
+ MTLVertexFormatFloat4;
+ /* Data is consecutive in the buffer for the whole matrix, each float4 will shift
+ * the offset by 16 bytes. */
+ desc.vertex_descriptor.attributes[mtl_attr.location + i].offset =
+ attribute_offset + i * 16;
+ /* All source data for a matrix is in the same singular buffer. */
+ desc.vertex_descriptor.attributes[mtl_attr.location + i].buffer_index =
+ buffer_index;
+
+ /* Update total attribute account. */
+ desc.vertex_descriptor.num_attributes = max_ii(
+ mtl_attr.location + i + 1, desc.vertex_descriptor.num_attributes);
+ MTL_LOG_INFO("-- Sub-Attrib Location: %d, offset: %d, buffer index: %d\n",
+ mtl_attr.location + i,
+ attribute_offset + i * 16,
+ buffer_index);
+ }
+ MTL_LOG_INFO(
+ "Float4x4 attribute type added for '%s' at attribute locations: %d to %d\n",
+ name,
+ mtl_attr.location,
+ mtl_attr.location + 3);
+ }
+
+ /* Ensure we are not exceeding the attribute limit. */
+ BLI_assert(desc.vertex_descriptor.num_attributes <= MTL_MAX_VERTEX_INPUT_ATTRIBUTES);
+ }
+ }
+ else {
+
+ /* Handle Any required format conversions.
+ * NOTE(Metal): If there is a mis-match between the format of an attribute
+ * in the shader interface, and the specified format in the VertexBuffer VertexFormat,
+ * we need to perform a format conversion.
+ *
+ * The Metal API can perform certain conversions internally during vertex assembly:
+ * - Type Normalization e.g short2 to float2 between 0.0 to 1.0.
+ * - Type Truncation e.g. Float4 to Float2.
+ * - Type expansion e,g, Float3 to Float4 (Following 0,0,0,1 for assignment to empty
+ * elements).
+ *
+ * Certain conversion cannot be performed however, and in these cases, we need to
+ * instruct the shader to generate a specialized version with a conversion routine upon
+ * attribute read.
+ * - This handles cases such as conversion between types e.g. Integer to float without
+ * normalization.
+ *
+ * For more information on the supported and unsupported conversions, see:
+ * https://developer.apple.com/documentation/metal/mtlvertexattributedescriptor/1516081-format?language=objc
+ */
+ MTLVertexFormat converted_format;
+ bool can_use_internal_conversion = mtl_convert_vertex_format(
+ mtl_attr.format,
+ (GPUVertCompType)a->comp_type,
+ a->comp_len,
+ (GPUVertFetchMode)a->fetch_mode,
+ &converted_format);
+ bool is_floating_point_format = (a->comp_type == GPU_COMP_F32);
+
+ if (can_use_internal_conversion) {
+ desc.vertex_descriptor.attributes[mtl_attr.location].format = converted_format;
+ desc.vertex_descriptor.attributes[mtl_attr.location].format_conversion_mode =
+ is_floating_point_format ? (GPUVertFetchMode)GPU_FETCH_FLOAT :
+ (GPUVertFetchMode)GPU_FETCH_INT;
+ BLI_assert(converted_format != MTLVertexFormatInvalid);
+ }
+ else {
+ /* The internal implicit conversion is not supported.
+ * In this case, we need to handle conversion inside the shader.
+ * This is handled using `format_conversion_mode`.
+ * `format_conversion_mode` is assigned the blender-specified fetch mode (GPU_FETCH_*).
+ * This then controls how a given attribute is interpreted. The data will be read
+ * as specified and then converted appropriately to the correct form.
+ *
+ * e.g. if `GPU_FETCH_INT_TO_FLOAT` is specified, the specialized read-routine
+ * in the shader will read the data as an int, and cast this to floating point
+ * representation. (Rather than reading the source data as float).
+ *
+ * NOTE: Even if full conversion is not supported, we may still partially perform an
+ * implicit conversion where possible, such as vector truncation or expansion. */
+ MTLVertexFormat converted_format;
+ bool can_convert = mtl_vertex_format_resize(
+ mtl_attr.format, a->comp_len, &converted_format);
+ desc.vertex_descriptor.attributes[mtl_attr.location].format = can_convert ?
+ converted_format :
+ mtl_attr.format;
+ desc.vertex_descriptor.attributes[mtl_attr.location].format_conversion_mode =
+ (GPUVertFetchMode)a->fetch_mode;
+ BLI_assert(desc.vertex_descriptor.attributes[mtl_attr.location].format !=
+ MTLVertexFormatInvalid);
+ }
+ desc.vertex_descriptor.attributes[mtl_attr.location].offset = attribute_offset;
+ desc.vertex_descriptor.attributes[mtl_attr.location].buffer_index = buffer_index;
+ desc.vertex_descriptor.num_attributes = ((mtl_attr.location + 1) >
+ desc.vertex_descriptor.num_attributes) ?
+ (mtl_attr.location + 1) :
+ desc.vertex_descriptor.num_attributes;
+
+ /* SSBO Vertex Fetch attribute bind. */
+ if (active_shader_->get_uses_ssbo_vertex_fetch()) {
+ BLI_assert_msg(desc.vertex_descriptor.attributes[mtl_attr.location].format ==
+ mtl_attr.format,
+ "SSBO Vertex Fetch does not support attribute conversion.");
+
+ MTLSSBOAttribute ssbo_attr(
+ mtl_attr.index,
+ buffer_index,
+ attribute_offset,
+ buffer_stride,
+ MTLShader::ssbo_vertex_type_to_attr_type(
+ desc.vertex_descriptor.attributes[mtl_attr.location].format),
+ instanced);
+
+ active_shader_->ssbo_vertex_fetch_bind_attribute(ssbo_attr);
+ desc.vertex_descriptor.ssbo_attributes[desc.vertex_descriptor.num_ssbo_attributes] =
+ ssbo_attr;
+ desc.vertex_descriptor.num_ssbo_attributes++;
+ }
+
+ /* NOTE: We are setting num_attributes to be up to the maximum found index, because of
+ * this, it is possible that we may skip over certain attributes if they were not in the
+ * source GPUVertFormat. */
+ MTL_LOG_INFO(
+ " -- Batch Attribute(%d): ORIG Shader Format: %d, ORIG Vert format: %d, Vert "
+ "components: %d, Fetch Mode %d --> FINAL FORMAT: %d\n",
+ mtl_attr.location,
+ (int)mtl_attr.format,
+ (int)a->comp_type,
+ (int)a->comp_len,
+ (int)a->fetch_mode,
+ (int)desc.vertex_descriptor.attributes[mtl_attr.location].format);
+
+ MTL_LOG_INFO(
+ " -- [Batch] matching %s attribute '%s' (Attribute Index: %d, Buffer index: %d, "
+ "offset: %d)\n",
+ (instanced) ? "instance" : "vertex",
+ name,
+ mtl_attr.location,
+ buffer_index,
+ attribute_offset);
+ }
+ }
+ }
+ }
+ if (buffer_added) {
+ return buffer_index;
+ }
+ return -1;
+}
+
+id<MTLRenderCommandEncoder> MTLBatch::bind(uint v_first, uint v_count, uint i_first, uint i_count)
+{
+ /* Setup draw call and render pipeline state here. Called by every draw, but setup here so that
+ * MTLDrawList only needs to perform setup a single time. */
+ BLI_assert(this);
+
+ /* Fetch Metal device. */
+ MTLContext *ctx = MTLContext::get();
+ if (!ctx) {
+ BLI_assert_msg(false, "No context available for rendering.");
+ return nil;
+ }
+
+ /* Verify Shader. */
+ active_shader_ = (shader) ? static_cast<MTLShader *>(unwrap(shader)) : nullptr;
+
+ if (active_shader_ == nullptr || !active_shader_->is_valid()) {
+ /* Skip drawing if there is no valid Metal shader.
+ * This will occur if the path through which the shader is prepared
+ * is invalid (e.g. Python without create-info), or, the source shader uses a geometry pass. */
+ BLI_assert_msg(false, "No valid Metal shader!");
+ return nil;
+ }
+
+ /* Check if using SSBO Fetch Mode.
+ * This is an alternative drawing mode to geometry shaders, wherein vertex buffers
+ * are bound as readable (random-access) GPU buffers and certain descriptor properties
+ * are passed using Shader uniforms. */
+ bool uses_ssbo_fetch = active_shader_->get_uses_ssbo_vertex_fetch();
+
+ /* Prepare Vertex Descriptor and extract VertexBuffers to bind. */
+ MTLVertBuf *buffers[GPU_BATCH_VBO_MAX_LEN] = {nullptr};
+ int num_buffers = 0;
+
+ /* Ensure Index Buffer is ready. */
+ MTLIndexBuf *mtl_elem = static_cast<MTLIndexBuf *>(reinterpret_cast<IndexBuf *>(this->elem));
+ if (mtl_elem != NULL) {
+ mtl_elem->upload_data();
+ }
+
+ /* Populate vertex descriptor with attribute binding information.
+ * The vertex descriptor and buffer layout descriptors describe
+ * how vertex data from bound vertex buffers maps to the
+ * shader's input.
+ * A unique vertex descriptor will result in a new PipelineStateObject
+ * being generated for the currently bound shader. */
+ prepare_vertex_descriptor_and_bindings(buffers, num_buffers, v_first, v_count, i_first, i_count);
+
+ /* Prepare Vertex Buffers - Run before RenderCommandEncoder in case BlitCommandEncoder buffer
+ * data operations are required. */
+ for (int i = 0; i < num_buffers; i++) {
+ MTLVertBuf *buf_at_index = buffers[i];
+ if (buf_at_index == NULL) {
+ BLI_assert_msg(
+ false,
+ "Total buffer count does not match highest buffer index, could be gaps in bindings");
+ continue;
+ }
+
+ MTLVertBuf *mtlvbo = static_cast<MTLVertBuf *>(reinterpret_cast<VertBuf *>(buf_at_index));
+ mtlvbo->bind();
+ }
+
+ /* Ensure render pass is active and fetch active RenderCommandEncoder. */
+ id<MTLRenderCommandEncoder> rec = ctx->ensure_begin_render_pass();
+
+ /* Fetch RenderPassState to enable resource binding for active pass. */
+ MTLRenderPassState &rps = ctx->main_command_buffer.get_render_pass_state();
+
+ /* Debug Check: Ensure Frame-buffer instance is not dirty. */
+ BLI_assert(!ctx->main_command_buffer.get_active_framebuffer()->get_dirty());
+
+ /* Bind Shader. */
+ this->shader_bind();
+
+ /* GPU debug markers. */
+ if (G.debug & G_DEBUG_GPU) {
+ [rec pushDebugGroup:[NSString stringWithFormat:@"batch_bind%@(shader: %s)",
+ this->elem ? @"(indexed)" : @"",
+ active_shader_->get_interface()->get_name()]];
+ [rec insertDebugSignpost:[NSString
+ stringWithFormat:@"batch_bind%@(shader: %s)",
+ this->elem ? @"(indexed)" : @"",
+ active_shader_->get_interface()->get_name()]];
+ }
+
+ /* Ensure Context Render Pipeline State is fully setup and ready to execute the draw. */
+ MTLPrimitiveType mtl_prim_type = gpu_prim_type_to_metal(this->prim_type);
+ if (!ctx->ensure_render_pipeline_state(mtl_prim_type)) {
+ printf("FAILED TO ENSURE RENDER PIPELINE STATE");
+ BLI_assert(false);
+
+ if (G.debug & G_DEBUG_GPU) {
+ [rec popDebugGroup];
+ }
+ return nil;
+ }
+
+ /*** Bind Vertex Buffers and Index Buffers **/
+
+ /* SSBO Vertex Fetch Buffer bindings. */
+ if (uses_ssbo_fetch) {
+
+ /* SSBO Vertex Fetch - Bind Index Buffer to appropriate slot -- if used. */
+ id<MTLBuffer> idx_buffer = nil;
+ GPUPrimType final_prim_type = this->prim_type;
+
+ if (mtl_elem != nullptr) {
+
+ /* Fetch index buffer. This function can situationally return an optimized
+ * index buffer of a different primitive type. If this is the case, `final_prim_type`
+ * and `v_count` will be updated with the new format.
+ * NOTE: For indexed rendering, v_count represents the number of indices. */
+ idx_buffer = mtl_elem->get_index_buffer(final_prim_type, v_count);
+ BLI_assert(idx_buffer != nil);
+
+ /* Update uniforms for SSBO-vertex-fetch-mode indexed rendering to flag usage. */
+ int &uniform_ssbo_index_mode_u16 = active_shader_->uni_ssbo_uses_index_mode_u16;
+ BLI_assert(uniform_ssbo_index_mode_u16 != -1);
+ int uses_index_mode_u16 = (mtl_elem->index_type_ == GPU_INDEX_U16) ? 1 : 0;
+ active_shader_->uniform_int(uniform_ssbo_index_mode_u16, 1, 1, &uses_index_mode_u16);
+ }
+ else {
+ idx_buffer = ctx->get_null_buffer();
+ }
+ rps.bind_vertex_buffer(idx_buffer, 0, MTL_SSBO_VERTEX_FETCH_IBO_INDEX);
+
+ /* Ensure all attributes are set */
+ active_shader_->ssbo_vertex_fetch_bind_attributes_end(rec);
+
+ /* Bind NULL Buffers for unused vertex data slots. */
+ id<MTLBuffer> null_buffer = ctx->get_null_buffer();
+ BLI_assert(null_buffer != nil);
+ for (int i = num_buffers; i < MTL_SSBO_VERTEX_FETCH_MAX_VBOS; i++) {
+ if (rps.cached_vertex_buffer_bindings[i].metal_buffer == nil) {
+ rps.bind_vertex_buffer(null_buffer, 0, i);
+ }
+ }
+
+ /* Flag whether Indexed rendering is used or not. */
+ int &uniform_ssbo_use_indexed = active_shader_->uni_ssbo_uses_indexed_rendering;
+ BLI_assert(uniform_ssbo_use_indexed != -1);
+ int uses_indexed_rendering = (mtl_elem != NULL) ? 1 : 0;
+ active_shader_->uniform_int(uniform_ssbo_use_indexed, 1, 1, &uses_indexed_rendering);
+
+ /* Set SSBO-fetch-mode status uniforms. */
+ BLI_assert(active_shader_->uni_ssbo_input_prim_type_loc != -1);
+ BLI_assert(active_shader_->uni_ssbo_input_vert_count_loc != -1);
+ GPU_shader_uniform_vector_int(reinterpret_cast<GPUShader *>(wrap(active_shader_)),
+ active_shader_->uni_ssbo_input_prim_type_loc,
+ 1,
+ 1,
+ (const int *)(&final_prim_type));
+ GPU_shader_uniform_vector_int(reinterpret_cast<GPUShader *>(wrap(active_shader_)),
+ active_shader_->uni_ssbo_input_vert_count_loc,
+ 1,
+ 1,
+ (const int *)(&v_count));
+ }
+
+ /* Bind Vertex Buffers. */
+ for (int i = 0; i < num_buffers; i++) {
+ MTLVertBuf *buf_at_index = buffers[i];
+ if (buf_at_index == NULL) {
+ BLI_assert_msg(
+ false,
+ "Total buffer count does not match highest buffer index, could be gaps in bindings");
+ continue;
+ }
+ /* Buffer handle. */
+ MTLVertBuf *mtlvbo = static_cast<MTLVertBuf *>(reinterpret_cast<VertBuf *>(buf_at_index));
+ mtlvbo->flag_used();
+
+ /* Fetch buffer from MTLVertexBuffer and bind. */
+ id<MTLBuffer> mtl_buffer = mtlvbo->get_metal_buffer();
+
+ BLI_assert(mtl_buffer != nil);
+ rps.bind_vertex_buffer(mtl_buffer, 0, i);
+ }
+
+ if (G.debug & G_DEBUG_GPU) {
+ [rec popDebugGroup];
+ }
+
+ /* Return Render Command Encoder used with setup. */
+ return rec;
+}
+
+void MTLBatch::unbind()
+{
+}
+
+void MTLBatch::prepare_vertex_descriptor_and_bindings(
+ MTLVertBuf **buffers, int &num_buffers, int v_first, int v_count, int i_first, int i_count)
+{
+
+ /* Here we populate the MTLContext vertex descriptor and resolve which buffers need to be bound.
+ */
+ MTLStateManager *state_manager = static_cast<MTLStateManager *>(
+ MTLContext::get()->state_manager);
+ MTLRenderPipelineStateDescriptor &desc = state_manager->get_pipeline_descriptor();
+ const MTLShaderInterface *interface = active_shader_->get_interface();
+ uint16_t attr_mask = interface->get_enabled_attribute_mask();
+
+ /* Reset vertex descriptor to default state. */
+ desc.reset_vertex_descriptor();
+
+ /* Fetch Vertex and Instance Buffers. */
+ Span<MTLVertBuf *> mtl_verts(reinterpret_cast<MTLVertBuf **>(this->verts),
+ GPU_BATCH_VBO_MAX_LEN);
+ Span<MTLVertBuf *> mtl_inst(reinterpret_cast<MTLVertBuf **>(this->inst),
+ GPU_BATCH_INST_VBO_MAX_LEN);
+
+ /* SSBO Vertex fetch also passes vertex descriptor information into the shader. */
+ if (active_shader_->get_uses_ssbo_vertex_fetch()) {
+ active_shader_->ssbo_vertex_fetch_bind_attributes_begin();
+ }
+
+ /* Resolve Metal vertex buffer bindings. */
+ /* Vertex Descriptors
+ * ------------------
+ * Vertex Descriptors are required to generate a pipeline state, based on the current Batch's
+ * buffer bindings. These bindings are a unique matching, depending on what input attributes a
+ * batch has in its buffers, and those which are supported by the shader interface.
+
+ * We iterate through the buffers and resolve which attributes satisfy the requirements of the
+ * currently bound shader. We cache this data, for a given Batch<->ShderInterface pairing in a
+ * VAO cache to avoid the need to recalculate this data. */
+ bool buffer_is_instanced[GPU_BATCH_VBO_MAX_LEN] = {false};
+
+ VertexDescriptorShaderInterfacePair *descriptor = this->vao_cache.find(interface);
+ if (descriptor) {
+ desc.vertex_descriptor = descriptor->vertex_descriptor;
+ attr_mask = descriptor->attr_mask;
+ num_buffers = descriptor->num_buffers;
+
+ for (int bid = 0; bid < GPU_BATCH_VBO_MAX_LEN; ++bid) {
+ if (descriptor->bufferIds[bid].used) {
+ if (descriptor->bufferIds[bid].is_instance) {
+ buffers[bid] = mtl_inst[descriptor->bufferIds[bid].id];
+ buffer_is_instanced[bid] = true;
+ }
+ else {
+ buffers[bid] = mtl_verts[descriptor->bufferIds[bid].id];
+ buffer_is_instanced[bid] = false;
+ }
+ }
+ }
+
+ /* Use cached ssbo attribute binding data. */
+ if (active_shader_->get_uses_ssbo_vertex_fetch()) {
+ BLI_assert(desc.vertex_descriptor.uses_ssbo_vertex_fetch);
+ for (int attr_id = 0; attr_id < desc.vertex_descriptor.num_ssbo_attributes; attr_id++) {
+ active_shader_->ssbo_vertex_fetch_bind_attribute(
+ desc.vertex_descriptor.ssbo_attributes[attr_id]);
+ }
+ }
+ }
+ else {
+ VertexDescriptorShaderInterfacePair pair{};
+ pair.interface = interface;
+
+ for (int i = 0; i < GPU_BATCH_VBO_MAX_LEN; ++i) {
+ pair.bufferIds[i].id = -1;
+ pair.bufferIds[i].is_instance = 0;
+ pair.bufferIds[i].used = 0;
+ }
+ /* NOTE: Attribute extraction order from buffer is the reverse of the OpenGL as we flag once an
+ * attribute is found, rather than pre-setting the mask. */
+ /* Extract Instance attributes (These take highest priority). */
+ for (int v = 0; v < GPU_BATCH_INST_VBO_MAX_LEN; v++) {
+ if (mtl_inst[v]) {
+ MTL_LOG_INFO(" -- [Batch] Checking bindings for bound instance buffer %p\n", mtl_inst[v]);
+ int buffer_ind = this->prepare_vertex_binding(
+ mtl_inst[v], desc, interface, attr_mask, true);
+ if (buffer_ind >= 0) {
+ buffers[buffer_ind] = mtl_inst[v];
+ buffer_is_instanced[buffer_ind] = true;
+
+ pair.bufferIds[buffer_ind].id = v;
+ pair.bufferIds[buffer_ind].used = 1;
+ pair.bufferIds[buffer_ind].is_instance = 1;
+ num_buffers = ((buffer_ind + 1) > num_buffers) ? (buffer_ind + 1) : num_buffers;
+ }
+ }
+ }
+
+ /* Extract Vertex attributes (First-bound vertex buffer takes priority). */
+ for (int v = 0; v < GPU_BATCH_VBO_MAX_LEN; v++) {
+ if (mtl_verts[v] != NULL) {
+ MTL_LOG_INFO(" -- [Batch] Checking bindings for bound vertex buffer %p\n", mtl_verts[v]);
+ int buffer_ind = this->prepare_vertex_binding(
+ mtl_verts[v], desc, interface, attr_mask, false);
+ if (buffer_ind >= 0) {
+ buffers[buffer_ind] = mtl_verts[v];
+ buffer_is_instanced[buffer_ind] = false;
+
+ pair.bufferIds[buffer_ind].id = v;
+ pair.bufferIds[buffer_ind].used = 1;
+ pair.bufferIds[buffer_ind].is_instance = 0;
+ num_buffers = ((buffer_ind + 1) > num_buffers) ? (buffer_ind + 1) : num_buffers;
+ }
+ }
+ }
+
+ /* Add to VertexDescriptor cache */
+ desc.vertex_descriptor.uses_ssbo_vertex_fetch = active_shader_->get_uses_ssbo_vertex_fetch();
+ pair.attr_mask = attr_mask;
+ pair.vertex_descriptor = desc.vertex_descriptor;
+ pair.num_buffers = num_buffers;
+ if (!this->vao_cache.insert(pair)) {
+ printf(
+ "[Performance Warning] cache is full (Size: %d), vertex descriptor will not be cached\n",
+ GPU_VAO_STATIC_LEN);
+ }
+ }
+
+/* DEBUG: verify if our attribute bindings have been fully provided as expected. */
+#if MTL_DEBUG_SHADER_ATTRIBUTES == 1
+ if (attr_mask != 0) {
+ for (uint16_t mask = 1, a = 0; a < 16; a++, mask <<= 1) {
+ if (attr_mask & mask) {
+ /* Fallback for setting default attributes, for missed slots. Attributes flagged with
+ * 'MTLVertexFormatInvalid' in the vertex descriptor are bound to a NULL buffer during PSO
+ * creation. */
+ MTL_LOG_WARNING("MTLBatch: Missing expected attribute '%s' at index '%d' for shader: %s\n",
+ this->active_shader->interface->attributes[a].name,
+ a,
+ interface->name);
+ /* Ensure any assigned attribute has not been given an invalid format. This should not
+ * occur and may be the result of an unsupported attribute type conversion. */
+ BLI_assert(desc.attributes[a].format == MTLVertexFormatInvalid);
+ }
+ }
+ }
+#endif
+}
+
+void MTLBatch::draw_advanced(int v_first, int v_count, int i_first, int i_count)
+{
+
+#if TRUST_NO_ONE
+ BLI_assert(v_count > 0 && i_count > 0);
+#endif
+
+ /* Setup RenderPipelineState for batch. */
+ MTLContext *ctx = reinterpret_cast<MTLContext *>(GPU_context_active_get());
+ id<MTLRenderCommandEncoder> rec = this->bind(v_first, v_count, i_first, i_count);
+ if (rec == nil) {
+ return;
+ }
+
+ /* Fetch IndexBuffer and resolve primitive type. */
+ MTLIndexBuf *mtl_elem = static_cast<MTLIndexBuf *>(reinterpret_cast<IndexBuf *>(this->elem));
+ MTLPrimitiveType mtl_prim_type = gpu_prim_type_to_metal(this->prim_type);
+
+ /* Render using SSBO Vertex Fetch. */
+ if (active_shader_->get_uses_ssbo_vertex_fetch()) {
+
+ /* Submit draw call with modified vertex count, which reflects vertices per primitive defined
+ * in the USE_SSBO_VERTEX_FETCH pragma. */
+ int num_input_primitives = gpu_get_prim_count_from_type(v_count, this->prim_type);
+ int output_num_verts = num_input_primitives *
+ active_shader_->get_ssbo_vertex_fetch_output_num_verts();
+ BLI_assert_msg(
+ mtl_vertex_count_fits_primitive_type(
+ output_num_verts, active_shader_->get_ssbo_vertex_fetch_output_prim_type()),
+ "Output Vertex count is not compatible with the requested output vertex primitive type");
+ [rec drawPrimitives:active_shader_->get_ssbo_vertex_fetch_output_prim_type()
+ vertexStart:0
+ vertexCount:output_num_verts
+ instanceCount:i_count
+ baseInstance:i_first];
+ ctx->main_command_buffer.register_draw_counters(output_num_verts * i_count);
+ }
+ /* Perform regular draw. */
+ else if (mtl_elem == NULL) {
+
+ /* Primitive Type toplogy emulation. */
+ if (mtl_needs_topology_emulation(this->prim_type)) {
+
+ /* Generate index buffer for primitive types requiring emulation. */
+ GPUPrimType emulated_prim_type = this->prim_type;
+ uint32_t emulated_v_count = v_count;
+ id<MTLBuffer> generated_index_buffer = this->get_emulated_toplogy_buffer(emulated_prim_type,
+ emulated_v_count);
+ BLI_assert(generated_index_buffer != nil);
+
+ MTLPrimitiveType emulated_mtl_prim_type = gpu_prim_type_to_metal(emulated_prim_type);
+
+ /* Temp: Disable culling for emulated primitive types.
+ * TODO(Metal): Support face winding in topology buffer. */
+ [rec setCullMode:MTLCullModeNone];
+
+ if (generated_index_buffer != nil) {
+ BLI_assert(emulated_mtl_prim_type == MTLPrimitiveTypeTriangle ||
+ emulated_mtl_prim_type == MTLPrimitiveTypeLine);
+ if (emulated_mtl_prim_type == MTLPrimitiveTypeTriangle) {
+ BLI_assert(emulated_v_count % 3 == 0);
+ }
+ if (emulated_mtl_prim_type == MTLPrimitiveTypeLine) {
+ BLI_assert(emulated_v_count % 2 == 0);
+ }
+
+ /* Set depth stencil state (requires knowledge of primitive type). */
+ ctx->ensure_depth_stencil_state(emulated_mtl_prim_type);
+
+ [rec drawIndexedPrimitives:emulated_mtl_prim_type
+ indexCount:emulated_v_count
+ indexType:MTLIndexTypeUInt32
+ indexBuffer:generated_index_buffer
+ indexBufferOffset:0
+ instanceCount:i_count
+ baseVertex:v_first
+ baseInstance:i_first];
+ }
+ else {
+ printf("[Note] Cannot draw batch -- Emulated Topology mode: %u not yet supported\n",
+ this->prim_type);
+ }
+ }
+ else {
+ /* Set depth stencil state (requires knowledge of primitive type). */
+ ctx->ensure_depth_stencil_state(mtl_prim_type);
+
+ /* Issue draw call. */
+ [rec drawPrimitives:mtl_prim_type
+ vertexStart:v_first
+ vertexCount:v_count
+ instanceCount:i_count
+ baseInstance:i_first];
+ }
+ ctx->main_command_buffer.register_draw_counters(v_count * i_count);
+ }
+ /* Perform indexed draw. */
+ else {
+
+ MTLIndexType index_type = MTLIndexBuf::gpu_index_type_to_metal(mtl_elem->index_type_);
+ uint32_t base_index = mtl_elem->index_base_;
+ uint32_t index_size = (mtl_elem->index_type_ == GPU_INDEX_U16) ? 2 : 4;
+ uint32_t v_first_ofs = ((v_first + mtl_elem->index_start_) * index_size);
+ BLI_assert_msg((v_first_ofs % index_size) == 0,
+ "Index offset is not 2/4-byte aligned as per METAL spec");
+
+ /* Fetch index buffer. May return an index buffer of a differing format,
+ * if index buffer optimization is used. In these cases, final_prim_type and
+ * index_count get updated with the new properties. */
+ GPUPrimType final_prim_type = this->prim_type;
+ uint index_count = v_count;
+
+ id<MTLBuffer> index_buffer = mtl_elem->get_index_buffer(final_prim_type, index_count);
+ mtl_prim_type = gpu_prim_type_to_metal(final_prim_type);
+ BLI_assert(index_buffer != nil);
+
+ if (index_buffer != nil) {
+
+ /* Set depth stencil state (requires knowledge of primitive type). */
+ ctx->ensure_depth_stencil_state(mtl_prim_type);
+
+ /* Issue draw call. */
+ [rec drawIndexedPrimitives:mtl_prim_type
+ indexCount:index_count
+ indexType:index_type
+ indexBuffer:index_buffer
+ indexBufferOffset:v_first_ofs
+ instanceCount:i_count
+ baseVertex:base_index
+ baseInstance:i_first];
+ ctx->main_command_buffer.register_draw_counters(index_count * i_count);
+ }
+ else {
+ BLI_assert_msg(false, "Index buffer does not have backing Metal buffer");
+ }
+ }
+
+ /* End of draw. */
+ this->unbind();
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Topology emulation and optimization
+ * \{ */
+
+id<MTLBuffer> MTLBatch::get_emulated_toplogy_buffer(GPUPrimType &in_out_prim_type,
+ uint32_t &in_out_v_count)
+{
+
+ BLI_assert(in_out_v_count > 0);
+ /* Determine emulated primitive types. */
+ GPUPrimType input_prim_type = in_out_prim_type;
+ uint32_t v_count = in_out_v_count;
+ GPUPrimType output_prim_type;
+ switch (input_prim_type) {
+ case GPU_PRIM_POINTS:
+ case GPU_PRIM_LINES:
+ case GPU_PRIM_TRIS:
+ BLI_assert_msg(false, "Optimal primitive types should not reach here.");
+ return nil;
+ break;
+ case GPU_PRIM_LINES_ADJ:
+ case GPU_PRIM_TRIS_ADJ:
+ BLI_assert_msg(false, "Adjacency primitive types should not reach here.");
+ return nil;
+ break;
+ case GPU_PRIM_LINE_STRIP:
+ case GPU_PRIM_LINE_LOOP:
+ case GPU_PRIM_LINE_STRIP_ADJ:
+ output_prim_type = GPU_PRIM_LINES;
+ break;
+ case GPU_PRIM_TRI_STRIP:
+ case GPU_PRIM_TRI_FAN:
+ output_prim_type = GPU_PRIM_TRIS;
+ break;
+ default:
+ BLI_assert_msg(false, "Invalid primitive type.");
+ return nil;
+ }
+
+ /* Check if topology buffer exists and is valid. */
+ if (this->emulated_topology_buffer_ != nullptr &&
+ (emulated_topology_type_ != input_prim_type || topology_buffer_input_v_count_ != v_count)) {
+
+ /* Release existing topology buffer. */
+ emulated_topology_buffer_->free();
+ emulated_topology_buffer_ = nullptr;
+ }
+
+ /* Generate new topology index buffer. */
+ if (this->emulated_topology_buffer_ == nullptr) {
+ /* Calculate IB len. */
+ uint32_t output_prim_count = 0;
+ switch (input_prim_type) {
+ case GPU_PRIM_LINE_STRIP:
+ case GPU_PRIM_LINE_STRIP_ADJ:
+ output_prim_count = v_count - 1;
+ break;
+ case GPU_PRIM_LINE_LOOP:
+ output_prim_count = v_count;
+ break;
+ case GPU_PRIM_TRI_STRIP:
+ case GPU_PRIM_TRI_FAN:
+ output_prim_count = v_count - 2;
+ break;
+ default:
+ BLI_assert_msg(false, "Cannot generate optimized topology buffer for other types.");
+ break;
+ }
+ uint32_t output_IB_elems = output_prim_count * ((output_prim_type == GPU_PRIM_TRIS) ? 3 : 2);
+
+ /* Allocate buffer. */
+ uint32_t buffer_bytes = output_IB_elems * 4;
+ BLI_assert(buffer_bytes > 0);
+ this->emulated_topology_buffer_ = MTLContext::get_global_memory_manager().allocate(
+ buffer_bytes, true);
+
+ /* Populate. */
+ uint32_t *data = (uint32_t *)this->emulated_topology_buffer_->get_host_ptr();
+ BLI_assert(data != nullptr);
+
+ /* TODO(Metal): Support inverse winding modes. */
+ bool winding_clockwise = false;
+ UNUSED_VARS(winding_clockwise);
+
+ switch (input_prim_type) {
+ /* Line Loop. */
+ case GPU_PRIM_LINE_LOOP: {
+ int line = 0;
+ for (line = 0; line < output_prim_count - 1; line++) {
+ data[line * 3 + 0] = line + 0;
+ data[line * 3 + 1] = line + 1;
+ }
+ /* Closing line. */
+ data[line * 2 + 0] = line + 0;
+ data[line * 2 + 1] = 0;
+ } break;
+
+ /* Triangle Fan. */
+ case GPU_PRIM_TRI_FAN: {
+ for (int triangle = 0; triangle < output_prim_count; triangle++) {
+ data[triangle * 3 + 0] = 0; /* Always 0 */
+ data[triangle * 3 + 1] = triangle + 1;
+ data[triangle * 3 + 2] = triangle + 2;
+ }
+ } break;
+
+ default:
+ BLI_assert_msg(false, "Other primitive types do not require emulation.");
+ return nil;
+ }
+
+ /* Flush. */
+ this->emulated_topology_buffer_->flush();
+ /* Assign members relating to current cached IB. */
+ topology_buffer_input_v_count_ = v_count;
+ topology_buffer_output_v_count_ = output_IB_elems;
+ emulated_topology_type_ = input_prim_type;
+ }
+
+ /* Return. */
+ in_out_v_count = topology_buffer_output_v_count_;
+ in_out_prim_type = output_prim_type;
+ return (emulated_topology_buffer_) ? emulated_topology_buffer_->get_metal_buffer() : nil;
+}
+
+/** \} */
+
+} // blender::gpu
diff --git a/source/blender/gpu/metal/mtl_context.mm b/source/blender/gpu/metal/mtl_context.mm
index ef66a1f2111..50576379f0d 100644
--- a/source/blender/gpu/metal/mtl_context.mm
+++ b/source/blender/gpu/metal/mtl_context.mm
@@ -995,19 +995,21 @@ bool MTLContext::ensure_uniform_buffer_bindings(
if (ubo.buffer_index >= 0) {
- const uint32_t buffer_index = ubo.buffer_index;
+ /* Uniform Buffer index offset by 1 as the first shader buffer binding slot is reserved for
+ * the uniform PushConstantBlock. */
+ const uint32_t buffer_index = ubo.buffer_index + 1;
int ubo_offset = 0;
id<MTLBuffer> ubo_buffer = nil;
int ubo_size = 0;
bool bind_dummy_buffer = false;
- if (this->pipeline_state.ubo_bindings[buffer_index].bound) {
+ if (this->pipeline_state.ubo_bindings[ubo_index].bound) {
/* Fetch UBO global-binding properties from slot. */
ubo_offset = 0;
- ubo_buffer = this->pipeline_state.ubo_bindings[buffer_index].ubo->get_metal_buffer(
+ ubo_buffer = this->pipeline_state.ubo_bindings[ubo_index].ubo->get_metal_buffer(
&ubo_offset);
- ubo_size = this->pipeline_state.ubo_bindings[buffer_index].ubo->get_size();
+ ubo_size = this->pipeline_state.ubo_bindings[ubo_index].ubo->get_size();
/* Use dummy zero buffer if no buffer assigned -- this is an optimization to avoid
* allocating zero buffers. */
diff --git a/source/blender/gpu/metal/mtl_drawlist.hh b/source/blender/gpu/metal/mtl_drawlist.hh
index ed99c76faa7..47055f3d7f4 100644
--- a/source/blender/gpu/metal/mtl_drawlist.hh
+++ b/source/blender/gpu/metal/mtl_drawlist.hh
@@ -9,34 +9,50 @@
#pragma once
-#pragma once
-
+#include "BLI_sys_types.h"
+#include "GPU_batch.h"
+#include "MEM_guardedalloc.h"
#include "gpu_drawlist_private.hh"
-namespace blender {
-namespace gpu {
+#include "mtl_batch.hh"
+#include "mtl_context.hh"
+
+namespace blender::gpu {
/**
- * TODO(Metal): MTLDrawList Implementation. Included as temporary stub.
- */
+ * Implementation of Multi Draw Indirect using OpenGL.
+ **/
class MTLDrawList : public DrawList {
+
+ private:
+ /** Batch for which we are recording commands for. */
+ MTLBatch *batch_;
+ /** Mapped memory bounds. */
+ void *data_;
+ /** Length of the mapped buffer (in byte). */
+ size_t data_size_;
+ /** Current offset inside the mapped buffer (in byte). */
+ size_t command_offset_;
+ /** Current number of command recorded inside the mapped buffer. */
+ uint32_t command_len_;
+ /** Is UINT_MAX if not drawing indexed geom. Also Avoid dereferencing batch. */
+ uint32_t base_index_;
+ /** Also Avoid dereferencing batch. */
+ uint32_t v_first_, v_count_;
+ /** Length of whole the buffer (in byte). */
+ uint32_t buffer_size_;
+
public:
- MTLDrawList(int length)
- {
- }
- ~MTLDrawList()
- {
- }
-
- void append(GPUBatch *batch, int i_first, int i_count) override
- {
- }
- void submit() override
- {
- }
+ MTLDrawList(int length);
+ ~MTLDrawList();
+
+ void append(GPUBatch *batch, int i_first, int i_count) override;
+ void submit() override;
+
+ private:
+ void init();
MEM_CXX_CLASS_ALLOC_FUNCS("MTLDrawList");
};
-} // namespace gpu
-} // namespace blender
+} // namespace blender::gpu
diff --git a/source/blender/gpu/metal/mtl_drawlist.mm b/source/blender/gpu/metal/mtl_drawlist.mm
new file mode 100644
index 00000000000..99194d2b72c
--- /dev/null
+++ b/source/blender/gpu/metal/mtl_drawlist.mm
@@ -0,0 +1,284 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+
+/** \file
+ * \ingroup gpu
+ *
+ * Implementation of Multi Draw Indirect using OpenGL.
+ * Fallback if the needed extensions are not supported.
+ */
+
+#include "BLI_assert.h"
+
+#include "GPU_batch.h"
+#include "mtl_common.hh"
+#include "mtl_drawlist.hh"
+#include "mtl_primitive.hh"
+
+using namespace blender::gpu;
+
+namespace blender::gpu {
+
+/* Indirect draw call structure for reference. */
+/* MTLDrawPrimitivesIndirectArguments --
+ * https://developer.apple.com/documentation/metal/mtldrawprimitivesindirectarguments?language=objc
+ */
+/* struct MTLDrawPrimitivesIndirectArguments {
+ * uint32_t vertexCount;
+ * uint32_t instanceCount;
+ * uint32_t vertexStart;
+ * uint32_t baseInstance;
+};*/
+
+/* MTLDrawIndexedPrimitivesIndirectArguments --
+ * https://developer.apple.com/documentation/metal/mtldrawindexedprimitivesindirectarguments?language=objc
+ */
+/* struct MTLDrawIndexedPrimitivesIndirectArguments {
+ * uint32_t indexCount;
+ * uint32_t instanceCount;
+ * uint32_t indexStart;
+ * uint32_t baseVertex;
+ * uint32_t baseInstance;
+};*/
+
+#define MDI_ENABLED (buffer_size_ != 0)
+#define MDI_DISABLED (buffer_size_ == 0)
+#define MDI_INDEXED (base_index_ != UINT_MAX)
+
+MTLDrawList::MTLDrawList(int length)
+{
+ BLI_assert(length > 0);
+ batch_ = nullptr;
+ command_len_ = 0;
+ base_index_ = 0;
+ command_offset_ = 0;
+ data_size_ = 0;
+ buffer_size_ = sizeof(MTLDrawIndexedPrimitivesIndirectArguments) * length;
+ data_ = (void *)MEM_mallocN(buffer_size_, __func__);
+}
+
+MTLDrawList::~MTLDrawList()
+{
+ if (data_) {
+ MEM_freeN(data_);
+ data_ = nullptr;
+ }
+}
+
+void MTLDrawList::init()
+{
+ MTLContext *ctx = reinterpret_cast<MTLContext *>(GPU_context_active_get());
+ BLI_assert(ctx);
+ BLI_assert(MDI_ENABLED);
+ BLI_assert(data_ == nullptr);
+ UNUSED_VARS_NDEBUG(ctx);
+
+ batch_ = nullptr;
+ command_len_ = 0;
+ BLI_assert(data_);
+
+ command_offset_ = 0;
+}
+
+void MTLDrawList::append(GPUBatch *gpu_batch, int i_first, int i_count)
+{
+ /* Fallback when MultiDrawIndirect is not supported/enabled. */
+ MTLShader *shader = static_cast<MTLShader *>(unwrap(gpu_batch->shader));
+ bool requires_ssbo = (shader->get_uses_ssbo_vertex_fetch());
+ bool requires_emulation = mtl_needs_topology_emulation(gpu_batch->prim_type);
+ if (MDI_DISABLED || requires_ssbo || requires_emulation) {
+ GPU_batch_draw_advanced(gpu_batch, 0, 0, i_first, i_count);
+ return;
+ }
+
+ if (data_ == nullptr) {
+ this->init();
+ }
+ BLI_assert(data_);
+
+ MTLBatch *mtl_batch = static_cast<MTLBatch *>(gpu_batch);
+ BLI_assert(mtl_batch);
+ if (mtl_batch != batch_) {
+ /* Submit existing calls. */
+ this->submit();
+
+ /* Begin new batch. */
+ batch_ = mtl_batch;
+
+ /* Cached for faster access. */
+ MTLIndexBuf *el = batch_->elem_();
+ base_index_ = el ? el->index_base_ : UINT_MAX;
+ v_first_ = el ? el->index_start_ : 0;
+ v_count_ = el ? el->index_len_ : batch_->verts_(0)->vertex_len;
+ }
+
+ if (v_count_ == 0) {
+ /* Nothing to draw. */
+ return;
+ }
+
+ if (MDI_INDEXED) {
+ MTLDrawIndexedPrimitivesIndirectArguments *cmd =
+ reinterpret_cast<MTLDrawIndexedPrimitivesIndirectArguments *>((char *)data_ +
+ command_offset_);
+ cmd->indexStart = v_first_;
+ cmd->indexCount = v_count_;
+ cmd->instanceCount = i_count;
+ cmd->baseVertex = base_index_;
+ cmd->baseInstance = i_first;
+ }
+ else {
+ MTLDrawPrimitivesIndirectArguments *cmd =
+ reinterpret_cast<MTLDrawPrimitivesIndirectArguments *>((char *)data_ + command_offset_);
+ cmd->vertexStart = v_first_;
+ cmd->vertexCount = v_count_;
+ cmd->instanceCount = i_count;
+ cmd->baseInstance = i_first;
+ }
+
+ size_t command_size = MDI_INDEXED ? sizeof(MTLDrawIndexedPrimitivesIndirectArguments) :
+ sizeof(MTLDrawPrimitivesIndirectArguments);
+
+ command_offset_ += command_size;
+ command_len_++;
+
+ /* Check if we can fit at least one other command. */
+ if (command_offset_ + command_size > buffer_size_) {
+ this->submit();
+ }
+
+ return;
+}
+
+void MTLDrawList::submit()
+{
+ /* Metal does not support MDI from the host side, but we still benefit from only executing the
+ * batch bind a single time, rather than per-draw.
+ * NOTE(Metal): Consider using #MTLIndirectCommandBuffer to achieve similar behavior. */
+ if (command_len_ == 0) {
+ return;
+ }
+
+ /* Something's wrong if we get here without MDI support. */
+ BLI_assert(MDI_ENABLED);
+ BLI_assert(data_);
+
+ /* Host-side MDI Currently unsupported on Metal. */
+ bool can_use_MDI = false;
+
+ /* Verify context. */
+ MTLContext *ctx = reinterpret_cast<MTLContext *>(GPU_context_active_get());
+ BLI_assert(ctx);
+
+ /* Execute indirect draw calls. */
+ MTLShader *shader = static_cast<MTLShader *>(unwrap(batch_->shader));
+ bool SSBO_MODE = (shader->get_uses_ssbo_vertex_fetch());
+ if (SSBO_MODE) {
+ can_use_MDI = false;
+ BLI_assert(false);
+ return;
+ }
+
+ /* Heuristic to determine whether using indirect drawing is more efficient. */
+ size_t command_size = MDI_INDEXED ? sizeof(MTLDrawIndexedPrimitivesIndirectArguments) :
+ sizeof(MTLDrawPrimitivesIndirectArguments);
+ const bool is_finishing_a_buffer = (command_offset_ + command_size > buffer_size_);
+ can_use_MDI = can_use_MDI && (is_finishing_a_buffer || command_len_ > 2);
+
+ /* Bind Batch to setup render pipeline state. */
+ id<MTLRenderCommandEncoder> rec = batch_->bind(0, 0, 0, 0);
+ if (!rec) {
+ BLI_assert_msg(false, "A RenderCommandEncoder should always be available!\n");
+ return;
+ }
+
+ /* Common properties. */
+ MTLPrimitiveType mtl_prim_type = gpu_prim_type_to_metal(batch_->prim_type);
+
+ /* Execute multi-draw indirect. */
+ if (can_use_MDI && false) {
+ /* Metal Doesn't support MDI -- Singular Indirect draw calls are supported,
+ * but Multi-draw is not.
+ * TODO(Metal): Consider using #IndirectCommandBuffers to provide similar
+ * behavior. */
+ }
+ else {
+
+ /* Execute draws manually. */
+ if (MDI_INDEXED) {
+ MTLDrawIndexedPrimitivesIndirectArguments *cmd =
+ (MTLDrawIndexedPrimitivesIndirectArguments *)data_;
+ MTLIndexBuf *mtl_elem = static_cast<MTLIndexBuf *>(
+ reinterpret_cast<IndexBuf *>(batch_->elem));
+ BLI_assert(mtl_elem);
+ MTLIndexType index_type = MTLIndexBuf::gpu_index_type_to_metal(mtl_elem->index_type_);
+ uint32_t index_size = (mtl_elem->index_type_ == GPU_INDEX_U16) ? 2 : 4;
+ uint32_t v_first_ofs = (mtl_elem->index_start_ * index_size);
+ uint32_t index_count = cmd->indexCount;
+
+ /* Fetch index buffer. May return an index buffer of a differing format,
+ * if index buffer optimization is used. In these cases, mtl_prim_type and
+ * index_count get updated with the new properties. */
+ GPUPrimType final_prim_type = batch_->prim_type;
+ id<MTLBuffer> index_buffer = mtl_elem->get_index_buffer(final_prim_type, index_count);
+ BLI_assert(index_buffer != nil);
+
+ /* Final primitive type. */
+ mtl_prim_type = gpu_prim_type_to_metal(final_prim_type);
+
+ if (index_buffer != nil) {
+
+ /* Set depth stencil state (requires knowledge of primitive type). */
+ ctx->ensure_depth_stencil_state(mtl_prim_type);
+
+ for (int i = 0; i < command_len_; i++, cmd++) {
+ [rec drawIndexedPrimitives:mtl_prim_type
+ indexCount:index_count
+ indexType:index_type
+ indexBuffer:index_buffer
+ indexBufferOffset:v_first_ofs
+ instanceCount:cmd->instanceCount
+ baseVertex:cmd->baseVertex
+ baseInstance:cmd->baseInstance];
+ ctx->main_command_buffer.register_draw_counters(cmd->indexCount * cmd->instanceCount);
+ }
+ }
+ else {
+ BLI_assert_msg(false, "Index buffer does not have backing Metal buffer");
+ }
+ }
+ else {
+ MTLDrawPrimitivesIndirectArguments *cmd = (MTLDrawPrimitivesIndirectArguments *)data_;
+
+ /* Verify if topology emulation is required. */
+ if (mtl_needs_topology_emulation(batch_->prim_type)) {
+ BLI_assert_msg(false, "topology emulation cases should use fallback.");
+ }
+ else {
+
+ /* Set depth stencil state (requires knowledge of primitive type). */
+ ctx->ensure_depth_stencil_state(mtl_prim_type);
+
+ for (int i = 0; i < command_len_; i++, cmd++) {
+ [rec drawPrimitives:mtl_prim_type
+ vertexStart:cmd->vertexStart
+ vertexCount:cmd->vertexCount
+ instanceCount:cmd->instanceCount
+ baseInstance:cmd->baseInstance];
+ ctx->main_command_buffer.register_draw_counters(cmd->vertexCount * cmd->instanceCount);
+ }
+ }
+ }
+ }
+
+ /* Unbind batch. */
+ batch_->unbind();
+
+ /* Reset command offsets. */
+ command_len_ = 0;
+ command_offset_ = 0;
+
+ /* Avoid keeping reference to the batch. */
+ batch_ = nullptr;
+}
+
+} // namespace blender::gpu
diff --git a/source/blender/gpu/metal/mtl_immediate.mm b/source/blender/gpu/metal/mtl_immediate.mm
index aaebe7e20f8..ee48bdd6ee1 100644
--- a/source/blender/gpu/metal/mtl_immediate.mm
+++ b/source/blender/gpu/metal/mtl_immediate.mm
@@ -99,6 +99,9 @@ void MTLImmediate::end()
MTLRenderPipelineStateDescriptor &desc = state_manager->get_pipeline_descriptor();
const MTLShaderInterface *interface = active_mtl_shader->get_interface();
+ /* Reset vertex descriptor to default state. */
+ desc.reset_vertex_descriptor();
+
desc.vertex_descriptor.num_attributes = interface->get_total_attributes();
desc.vertex_descriptor.num_vert_buffers = 1;
@@ -125,7 +128,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/metal/mtl_pso_descriptor_state.hh b/source/blender/gpu/metal/mtl_pso_descriptor_state.hh
index 198d309874b..04ceb5bdf03 100644
--- a/source/blender/gpu/metal/mtl_pso_descriptor_state.hh
+++ b/source/blender/gpu/metal/mtl_pso_descriptor_state.hh
@@ -243,6 +243,19 @@ struct MTLRenderPipelineStateDescriptor {
return hash;
}
+
+ /* Reset the Vertex Descriptor to default. */
+ void reset_vertex_descriptor()
+ {
+ vertex_descriptor.num_attributes = 0;
+ vertex_descriptor.num_vert_buffers = 0;
+ for (int i = 0; i < GPU_VERT_ATTR_MAX_LEN; i++) {
+ vertex_descriptor.attributes[i].format = MTLVertexFormatInvalid;
+ vertex_descriptor.attributes[i].offset = 0;
+ }
+ vertex_descriptor.uses_ssbo_vertex_fetch = false;
+ vertex_descriptor.num_ssbo_attributes = 0;
+ }
};
} // namespace blender::gpu
diff --git a/source/blender/gpu/metal/mtl_shader_interface.mm b/source/blender/gpu/metal/mtl_shader_interface.mm
index 3703d5b5684..97a82345761 100644
--- a/source/blender/gpu/metal/mtl_shader_interface.mm
+++ b/source/blender/gpu/metal/mtl_shader_interface.mm
@@ -117,9 +117,7 @@ uint32_t MTLShaderInterface::add_uniform_block(uint32_t name_offset,
MTLShaderUniformBlock &uni_block = ubos_[total_uniform_blocks_];
uni_block.name_offset = name_offset;
- /* We offset the buffer binding index by one, as the first slot is reserved for push constant
- * data. */
- uni_block.buffer_index = buffer_index + 1;
+ uni_block.buffer_index = buffer_index;
uni_block.size = size;
uni_block.current_offset = 0;
uni_block.stage_mask = ShaderStage::BOTH;
@@ -297,8 +295,10 @@ void MTLShaderInterface::prepare_common_shader_inputs()
current_input->name_hash = BLI_hash_string(this->get_name_at_offset(shd_ubo.name_offset));
/* Location refers to the index in the ubos_ array. */
current_input->location = ubo_index;
- /* Final binding location refers to the buffer binding index within the shader (Relative to
- * MTL_uniform_buffer_base_index). */
+ /* Binding location refers to the UBO bind slot in
+ * #MTLContextGlobalShaderPipelineState::ubo_bindings. The buffer bind index [[buffer(N)]]
+ * within the shader will apply an offset for bound vertex buffers and the default uniform
+ * PushConstantBlock. */
current_input->binding = shd_ubo.buffer_index;
current_input++;
}
diff --git a/source/blender/gpu/metal/mtl_texture.hh b/source/blender/gpu/metal/mtl_texture.hh
index ebc9eb2e00e..28b55306707 100644
--- a/source/blender/gpu/metal/mtl_texture.hh
+++ b/source/blender/gpu/metal/mtl_texture.hh
@@ -51,9 +51,9 @@ struct TextureUpdateRoutineSpecialisation {
uint64_t hash() const
{
blender::DefaultHash<std::string> string_hasher;
- return uint64_t(string_hasher(
+ return (uint64_t)string_hasher(
this->input_data_type + this->output_data_type +
- std::to_string((this->component_count_input << 8) + this->component_count_output)));
+ std::to_string((this->component_count_input << 8) + this->component_count_output));
}
};
diff --git a/source/blender/gpu/metal/mtl_texture.mm b/source/blender/gpu/metal/mtl_texture.mm
index 32029db6fd9..29dcc8d32ee 100644
--- a/source/blender/gpu/metal/mtl_texture.mm
+++ b/source/blender/gpu/metal/mtl_texture.mm
@@ -337,20 +337,6 @@ void gpu::MTLTexture::blit(gpu::MTLTexture *dst,
GPU_batch_draw(quad);
- /* TMP draw with IMM TODO(Metal): Remove this once GPUBatch is supported. */
- GPUVertFormat *imm_format = immVertexFormat();
- uint pos = GPU_vertformat_attr_add(imm_format, "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
-
- immBindShader(shader);
- immBegin(GPU_PRIM_TRI_STRIP, 4);
- immVertex2f(pos, 1, 0);
- immVertex2f(pos, 0, 0);
- immVertex2f(pos, 1, 1);
- immVertex2f(pos, 0, 1);
- immEnd();
- immUnbindProgram();
- /**********************/
-
/* restoring old pipeline state. */
GPU_depth_mask(depth_write_prev);
GPU_stencil_write_mask_set(stencil_mask_prev);
@@ -1472,10 +1458,82 @@ bool gpu::MTLTexture::init_internal()
bool gpu::MTLTexture::init_internal(GPUVertBuf *vbo)
{
- /* Not a valid vertex buffer format, though verifying texture is not set as such
- * as this is not supported on Apple Silicon. */
- BLI_assert_msg(this->format_ != GPU_DEPTH24_STENCIL8,
- "Apple silicon does not support GPU_DEPTH24_S8");
+ if (this->format_ == GPU_DEPTH24_STENCIL8) {
+ /* Apple Silicon requires GPU_DEPTH32F_STENCIL8 instead of GPU_DEPTH24_STENCIL8. */
+ this->format_ = GPU_DEPTH32F_STENCIL8;
+ }
+
+ MTLPixelFormat mtl_format = gpu_texture_format_to_metal(this->format_);
+ mtl_max_mips_ = 1;
+ mipmaps_ = 0;
+ this->mip_range_set(0, 0);
+
+ /* Create texture from GPUVertBuf's buffer. */
+ MTLVertBuf *mtl_vbo = static_cast<MTLVertBuf *>(unwrap(vbo));
+ mtl_vbo->bind();
+ mtl_vbo->flag_used();
+
+ /* Get Metal Buffer. */
+ id<MTLBuffer> source_buffer = mtl_vbo->get_metal_buffer();
+ BLI_assert(source_buffer);
+
+ /* Verify size. */
+ if (w_ <= 0) {
+ MTL_LOG_WARNING("Allocating texture buffer of width 0!\n");
+ w_ = 1;
+ }
+
+ /* Verify Texture and vertex buffer alignment. */
+ int bytes_per_pixel = get_mtl_format_bytesize(mtl_format);
+ int bytes_per_row = bytes_per_pixel * w_;
+
+ MTLContext *mtl_ctx = MTLContext::get();
+ uint32_t align_requirement = static_cast<uint32_t>(
+ [mtl_ctx->device minimumLinearTextureAlignmentForPixelFormat:mtl_format]);
+
+ /* Verify per-vertex size aligns with texture size. */
+ const GPUVertFormat *format = GPU_vertbuf_get_format(vbo);
+ BLI_assert(bytes_per_pixel == format->stride &&
+ "Pixel format stride MUST match the texture format stride -- These being different "
+ "is likely caused by Metal's VBO padding to a minimum of 4-bytes per-vertex");
+ UNUSED_VARS_NDEBUG(format);
+
+ /* Create texture descriptor. */
+ BLI_assert(type_ == GPU_TEXTURE_BUFFER);
+ texture_descriptor_ = [[MTLTextureDescriptor alloc] init];
+ texture_descriptor_.pixelFormat = mtl_format;
+ texture_descriptor_.textureType = MTLTextureTypeTextureBuffer;
+ texture_descriptor_.width = w_;
+ texture_descriptor_.height = 1;
+ texture_descriptor_.depth = 1;
+ texture_descriptor_.arrayLength = 1;
+ texture_descriptor_.mipmapLevelCount = mtl_max_mips_;
+ texture_descriptor_.usage =
+ MTLTextureUsageShaderRead | MTLTextureUsageShaderWrite |
+ MTLTextureUsagePixelFormatView; /* TODO(Metal): Optimize usage flags. */
+ texture_descriptor_.storageMode = [source_buffer storageMode];
+ texture_descriptor_.sampleCount = 1;
+ texture_descriptor_.cpuCacheMode = [source_buffer cpuCacheMode];
+ texture_descriptor_.hazardTrackingMode = [source_buffer hazardTrackingMode];
+
+ texture_ = [source_buffer
+ newTextureWithDescriptor:texture_descriptor_
+ offset:0
+ bytesPerRow:ceil_to_multiple_u(bytes_per_row, align_requirement)];
+ aligned_w_ = bytes_per_row / bytes_per_pixel;
+
+ BLI_assert(texture_);
+ texture_.label = [NSString stringWithUTF8String:this->get_name()];
+ is_baked_ = true;
+ is_dirty_ = false;
+ resource_mode_ = MTL_TEXTURE_MODE_VBO;
+
+ /* Track Status. */
+ vert_buffer_ = mtl_vbo;
+ vert_buffer_mtl_ = source_buffer;
+ /* Cleanup. */
+ [texture_descriptor_ release];
+ texture_descriptor_ = nullptr;
return true;
}
@@ -1522,7 +1580,6 @@ bool gpu::MTLTexture::texture_is_baked()
/* Prepare texture parameters after initialization, but before baking. */
void gpu::MTLTexture::prepare_internal()
{
-
/* Derive implicit usage flags for Depth/Stencil attachments. */
if (format_flag_ & GPU_FORMAT_DEPTH || format_flag_ & GPU_FORMAT_STENCIL) {
gpu_image_usage_flags_ |= GPU_TEXTURE_USAGE_ATTACHMENT;
@@ -1687,7 +1744,7 @@ void gpu::MTLTexture::ensure_baked()
/* Determine Resource Mode. */
resource_mode_ = MTL_TEXTURE_MODE_DEFAULT;
- /* Create texture. */
+ /* Standard texture allocation. */
texture_ = [ctx->device newTextureWithDescriptor:texture_descriptor_];
[texture_descriptor_ release];
diff --git a/source/blender/gpu/opengl/gl_batch.cc b/source/blender/gpu/opengl/gl_batch.cc
index ff8867fe3e6..28105e326ee 100644
--- a/source/blender/gpu/opengl/gl_batch.cc
+++ b/source/blender/gpu/opengl/gl_batch.cc
@@ -272,8 +272,8 @@ void GLBatch::bind(int i_first)
#if GPU_TRACK_INDEX_RANGE
/* Can be removed if GL 4.3 is required. */
- if (!GLContext::fixed_restart_index_support && (elem != nullptr)) {
- glPrimitiveRestartIndex(this->elem_()->restart_index());
+ if (!GLContext::fixed_restart_index_support) {
+ glPrimitiveRestartIndex((elem != nullptr) ? this->elem_()->restart_index() : 0xFFFFFFFFu);
}
#endif
diff --git a/source/blender/gpu/opengl/gl_shader_interface.cc b/source/blender/gpu/opengl/gl_shader_interface.cc
index c9432fca561..ef97d74bf81 100644
--- a/source/blender/gpu/opengl/gl_shader_interface.cc
+++ b/source/blender/gpu/opengl/gl_shader_interface.cc
@@ -200,6 +200,9 @@ static Type gpu_type_from_gl_type(int gl_type)
GLShaderInterface::GLShaderInterface(GLuint program)
{
+ GLuint last_program;
+ glGetIntegerv(GL_CURRENT_PROGRAM, (GLint *)&last_program);
+
/* Necessary to make #glUniform works. */
glUseProgram(program);
@@ -385,6 +388,8 @@ GLShaderInterface::GLShaderInterface(GLuint program)
// this->debug_print();
this->sort_inputs();
+
+ glUseProgram(last_program);
}
GLShaderInterface::GLShaderInterface(GLuint program, const shader::ShaderCreateInfo &info)
@@ -442,6 +447,9 @@ GLShaderInterface::GLShaderInterface(GLuint program, const shader::ShaderCreateI
uint32_t name_buffer_offset = 0;
/* Necessary to make #glUniform works. TODO(fclem) Remove. */
+ GLuint last_program;
+ glGetIntegerv(GL_CURRENT_PROGRAM, (GLint *)&last_program);
+
glUseProgram(program);
/* Attributes */
@@ -552,6 +560,8 @@ GLShaderInterface::GLShaderInterface(GLuint program, const shader::ShaderCreateI
this->sort_inputs();
// this->debug_print();
+
+ glUseProgram(last_program);
}
GLShaderInterface::~GLShaderInterface()
diff --git a/source/blender/gpu/shaders/compositor/compositor_blur.glsl b/source/blender/gpu/shaders/compositor/compositor_blur.glsl
index 4f981c84f59..c7ac620f99b 100644
--- a/source/blender/gpu/shaders/compositor/compositor_blur.glsl
+++ b/source/blender/gpu/shaders/compositor/compositor_blur.glsl
@@ -18,13 +18,24 @@ vec4 load_input(ivec2 texel)
}
/* 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. */
+ * the weights texture, where the given texel (0, 0) corresponds the center of weights texture.
+ * Note that we load the weights texture inverted along both directions to maintain the shape of
+ * the weights if it was not symmetrical. To understand why inversion makes sense, consider a 1D
+ * weights texture whose right half is all ones and whose left half is all zeros. Further, consider
+ * that we are blurring a single white pixel on a black background. When computing the value of a
+ * pixel that is to the right of the white pixel, the white pixel will be in the left region of the
+ * search window, and consequently, without inversion, a zero will be sampled from the left side of
+ * the weights texture and result will be zero. However, what we expect is that pixels to the right
+ * of the white pixel will be white, that is, they should sample a weight of 1 from the right side
+ * of the weights texture, hence the need for inversion. */
vec4 load_weight(ivec2 texel)
{
- /* 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));
+ /* Add the radius to transform the texel into the range [0, radius * 2], with an additional 0.5
+ * to sample at the center of the pixels, 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,
+ * invert the textures coordinates by subtracting from 1 to maintain the shape of the weights as
+ * mentioned in the function description. */
+ return texture(weights_tx, 1.0 - ((texel + vec2(radius + 0.5)) / (radius * 2 + 1)));
}
void main()
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..9383bbf9825
--- /dev/null
+++ b/source/blender/gpu/shaders/compositor/compositor_blur_variable_size.glsl
@@ -0,0 +1,71 @@
+#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 given texel (0, 0) corresponds the center of weights texture.
+ * Note that we load the weights texture inverted along both directions to maintain the shape of
+ * the weights if it was not symmetrical. To understand why inversion makes sense, consider a 1D
+ * weights texture whose right half is all ones and whose left half is all zeros. Further, consider
+ * that we are blurring a single white pixel on a black background. When computing the value of a
+ * pixel that is to the right of the white pixel, the white pixel will be in the left region of the
+ * search window, and consequently, without inversion, a zero will be sampled from the left side of
+ * the weights texture and result will be zero. However, what we expect is that pixels to the right
+ * of the white pixel will be white, that is, they should sample a weight of 1 from the right side
+ * of the weights texture, hence the need for inversion. */
+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], with an additional 0.5
+ * to sample at the center of the pixels, 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,
+ * invert the textures coordinates by subtracting from 1 to maintain the shape of the weights as
+ * mentioned in the function description. */
+ return texture(weights_tx, 1.0 - ((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_normalize.glsl b/source/blender/gpu/shaders/compositor/compositor_normalize.glsl
new file mode 100644
index 00000000000..53dfeb01730
--- /dev/null
+++ b/source/blender/gpu/shaders/compositor/compositor_normalize.glsl
@@ -0,0 +1,10 @@
+#pragma BLENDER_REQUIRE(gpu_shader_compositor_texture_utilities.glsl)
+
+void main()
+{
+ ivec2 texel = ivec2(gl_GlobalInvocationID.xy);
+ float value = texture_load(input_tx, texel).x;
+ float normalized_value = (value - minimum) * scale;
+ float clamped_value = clamp(normalized_value, 0.0, 1.0);
+ imageStore(output_img, texel, vec4(clamped_value));
+}
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/compositor_tone_map_photoreceptor.glsl b/source/blender/gpu/shaders/compositor/compositor_tone_map_photoreceptor.glsl
new file mode 100644
index 00000000000..167006585ca
--- /dev/null
+++ b/source/blender/gpu/shaders/compositor/compositor_tone_map_photoreceptor.glsl
@@ -0,0 +1,22 @@
+#pragma BLENDER_REQUIRE(gpu_shader_compositor_texture_utilities.glsl)
+
+/* Tone mapping based on equation (1) and the trilinear interpolation between equations (6) and (7)
+ * from Reinhard, Erik, and Kate Devlin. "Dynamic range reduction inspired by photoreceptor
+ * physiology." IEEE transactions on visualization and computer graphics 11.1 (2005): 13-24. */
+void main()
+{
+ ivec2 texel = ivec2(gl_GlobalInvocationID.xy);
+
+ vec4 input_color = texture_load(input_tx, texel);
+ float input_luminance = dot(input_color.rgb, luminance_coefficients);
+
+ /* Trilinear interpolation between equations (6) and (7) from Reinhard's 2005 paper. */
+ vec4 local_adaptation_level = mix(vec4(input_luminance), input_color, chromatic_adaptation);
+ vec4 adaptation_level = mix(global_adaptation_level, local_adaptation_level, light_adaptation);
+
+ /* Equation (1) from Reinhard's 2005 paper, assuming Vmax is 1. */
+ vec4 semi_saturation = pow(intensity * adaptation_level, vec4(contrast));
+ vec4 tone_mapped_color = input_color / (input_color + semi_saturation);
+
+ imageStore(output_img, texel, vec4(tone_mapped_color.rgb, input_color.a));
+}
diff --git a/source/blender/gpu/shaders/compositor/compositor_tone_map_simple.glsl b/source/blender/gpu/shaders/compositor/compositor_tone_map_simple.glsl
new file mode 100644
index 00000000000..ce42d021dd1
--- /dev/null
+++ b/source/blender/gpu/shaders/compositor/compositor_tone_map_simple.glsl
@@ -0,0 +1,26 @@
+#pragma BLENDER_REQUIRE(gpu_shader_compositor_texture_utilities.glsl)
+#pragma BLENDER_REQUIRE(gpu_shader_common_math_utils.glsl)
+
+/* Tone mapping based on equation (3) from Reinhard, Erik, et al. "Photographic tone reproduction
+ * for digital images." Proceedings of the 29th annual conference on Computer graphics and
+ * interactive techniques. 2002. */
+void main()
+{
+ ivec2 texel = ivec2(gl_GlobalInvocationID.xy);
+
+ vec4 input_color = texture_load(input_tx, texel);
+
+ /* Equation (2) from Reinhard's 2002 paper. */
+ vec4 scaled_color = input_color * luminance_scale;
+
+ /* Equation (3) from Reinhard's 2002 paper, but with the 1 replaced with the blend factor for
+ * more flexibility. See ToneMapOperation::compute_luminance_scale_blend_factor. */
+ vec4 denominator = luminance_scale_blend_factor + scaled_color;
+ vec4 tone_mapped_color = safe_divide(scaled_color, denominator);
+
+ if (inverse_gamma != 0.0) {
+ tone_mapped_color = pow(max(tone_mapped_color, vec4(0.0)), vec4(inverse_gamma));
+ }
+
+ imageStore(output_img, texel, vec4(tone_mapped_color.rgb, input_color.a));
+}
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_normalize_info.hh b/source/blender/gpu/shaders/compositor/infos/compositor_normalize_info.hh
new file mode 100644
index 00000000000..02fdc424014
--- /dev/null
+++ b/source/blender/gpu/shaders/compositor/infos/compositor_normalize_info.hh
@@ -0,0 +1,12 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+
+#include "gpu_shader_create_info.hh"
+
+GPU_SHADER_CREATE_INFO(compositor_normalize)
+ .local_group_size(16, 16)
+ .push_constant(Type::FLOAT, "minimum")
+ .push_constant(Type::FLOAT, "scale")
+ .sampler(0, ImageType::FLOAT_2D, "input_tx")
+ .image(0, GPU_R16F, Qualifier::WRITE, ImageType::FLOAT_2D, "output_img")
+ .compute_source("compositor_normalize.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..e2252b14758
--- /dev/null
+++ b/source/blender/gpu/shaders/compositor/infos/compositor_parallel_reduction_info.hh
@@ -0,0 +1,149 @@
+/* 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_shared)
+ .additional_info("compositor_parallel_reduction_shared")
+ .define("IDENTITY", "vec4(0.0)")
+ .define("REDUCE(lhs, rhs)", "lhs + rhs");
+
+GPU_SHADER_CREATE_INFO(compositor_sum_float_shared)
+ .additional_info("compositor_sum_shared")
+ .image(0, GPU_R32F, Qualifier::WRITE, ImageType::FLOAT_2D, "output_img")
+ .define("TYPE", "float")
+ .define("LOAD(value)", "value.x");
+
+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);
+
+GPU_SHADER_CREATE_INFO(compositor_sum_log_luminance)
+ .additional_info("compositor_sum_float_shared")
+ .push_constant(Type::VEC3, "luminance_coefficients")
+ .define("INITIALIZE(value)", "log(max(dot(value.rgb, luminance_coefficients), 1e-5))")
+ .do_static_compilation(true);
+
+GPU_SHADER_CREATE_INFO(compositor_sum_color)
+ .additional_info("compositor_sum_shared")
+ .image(0, GPU_RGBA32F, Qualifier::WRITE, ImageType::FLOAT_2D, "output_img")
+ .define("TYPE", "vec4")
+ .define("INITIALIZE(value)", "value")
+ .define("LOAD(value)", "value")
+ .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);
+
+/* --------------------------------------------------------------------
+ * Maximum Reductions.
+ */
+
+GPU_SHADER_CREATE_INFO(compositor_maximum_luminance)
+ .additional_info("compositor_parallel_reduction_shared")
+ .typedef_source("common_math_lib.glsl")
+ .image(0, GPU_R32F, Qualifier::WRITE, ImageType::FLOAT_2D, "output_img")
+ .push_constant(Type::VEC3, "luminance_coefficients")
+ .define("TYPE", "float")
+ .define("IDENTITY", "vec4(FLT_MIN)")
+ .define("INITIALIZE(value)", "dot(value.rgb, luminance_coefficients)")
+ .define("LOAD(value)", "value.x")
+ .define("REDUCE(lhs, rhs)", "max(lhs, rhs)")
+ .do_static_compilation(true);
+
+GPU_SHADER_CREATE_INFO(compositor_maximum_float_in_range)
+ .additional_info("compositor_parallel_reduction_shared")
+ .image(0, GPU_R32F, Qualifier::WRITE, ImageType::FLOAT_2D, "output_img")
+ .push_constant(Type::FLOAT, "lower_bound")
+ .push_constant(Type::FLOAT, "upper_bound")
+ .define("TYPE", "float")
+ .define("IDENTITY", "vec4(lower_bound)")
+ .define("INITIALIZE(v)", "((v.x <= upper_bound) && (v.x >= lower_bound)) ? v.x : lower_bound")
+ .define("LOAD(value)", "value.x")
+ .define("REDUCE(lhs, rhs)", "((rhs > lhs) && (rhs <= upper_bound)) ? rhs : lhs")
+ .do_static_compilation(true);
+
+/* --------------------------------------------------------------------
+ * Minimum Reductions.
+ */
+
+GPU_SHADER_CREATE_INFO(compositor_minimum_luminance)
+ .additional_info("compositor_parallel_reduction_shared")
+ .typedef_source("common_math_lib.glsl")
+ .image(0, GPU_R32F, Qualifier::WRITE, ImageType::FLOAT_2D, "output_img")
+ .push_constant(Type::VEC3, "luminance_coefficients")
+ .define("TYPE", "float")
+ .define("IDENTITY", "vec4(FLT_MAX)")
+ .define("INITIALIZE(value)", "dot(value.rgb, luminance_coefficients)")
+ .define("LOAD(value)", "value.x")
+ .define("REDUCE(lhs, rhs)", "min(lhs, rhs)")
+ .do_static_compilation(true);
+
+GPU_SHADER_CREATE_INFO(compositor_minimum_float_in_range)
+ .additional_info("compositor_parallel_reduction_shared")
+ .image(0, GPU_R32F, Qualifier::WRITE, ImageType::FLOAT_2D, "output_img")
+ .push_constant(Type::FLOAT, "lower_bound")
+ .push_constant(Type::FLOAT, "upper_bound")
+ .define("TYPE", "float")
+ .define("IDENTITY", "vec4(upper_bound)")
+ .define("INITIALIZE(v)", "((v.x <= upper_bound) && (v.x >= lower_bound)) ? v.x : upper_bound")
+ .define("LOAD(value)", "value.x")
+ .define("REDUCE(lhs, rhs)", "((rhs < lhs) && (rhs >= lower_bound)) ? rhs : lhs")
+ .do_static_compilation(true);
diff --git a/source/blender/gpu/shaders/compositor/infos/compositor_tone_map_photoreceptor_info.hh b/source/blender/gpu/shaders/compositor/infos/compositor_tone_map_photoreceptor_info.hh
new file mode 100644
index 00000000000..a460c9d58a6
--- /dev/null
+++ b/source/blender/gpu/shaders/compositor/infos/compositor_tone_map_photoreceptor_info.hh
@@ -0,0 +1,16 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+
+#include "gpu_shader_create_info.hh"
+
+GPU_SHADER_CREATE_INFO(compositor_tone_map_photoreceptor)
+ .local_group_size(16, 16)
+ .push_constant(Type::VEC4, "global_adaptation_level")
+ .push_constant(Type::FLOAT, "contrast")
+ .push_constant(Type::FLOAT, "intensity")
+ .push_constant(Type::FLOAT, "chromatic_adaptation")
+ .push_constant(Type::FLOAT, "light_adaptation")
+ .push_constant(Type::VEC3, "luminance_coefficients")
+ .sampler(0, ImageType::FLOAT_2D, "input_tx")
+ .image(0, GPU_RGBA16F, Qualifier::WRITE, ImageType::FLOAT_2D, "output_img")
+ .compute_source("compositor_tone_map_photoreceptor.glsl")
+ .do_static_compilation(true);
diff --git a/source/blender/gpu/shaders/compositor/infos/compositor_tone_map_simple_info.hh b/source/blender/gpu/shaders/compositor/infos/compositor_tone_map_simple_info.hh
new file mode 100644
index 00000000000..2b220af9460
--- /dev/null
+++ b/source/blender/gpu/shaders/compositor/infos/compositor_tone_map_simple_info.hh
@@ -0,0 +1,13 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+
+#include "gpu_shader_create_info.hh"
+
+GPU_SHADER_CREATE_INFO(compositor_tone_map_simple)
+ .local_group_size(16, 16)
+ .push_constant(Type::FLOAT, "luminance_scale")
+ .push_constant(Type::FLOAT, "luminance_scale_blend_factor")
+ .push_constant(Type::FLOAT, "inverse_gamma")
+ .sampler(0, ImageType::FLOAT_2D, "input_tx")
+ .image(0, GPU_RGBA16F, Qualifier::WRITE, ImageType::FLOAT_2D, "output_img")
+ .compute_source("compositor_tone_map_simple.glsl")
+ .do_static_compilation(true);
diff --git a/source/blender/gpu/shaders/gpu_shader_icon_frag.glsl b/source/blender/gpu/shaders/gpu_shader_icon_frag.glsl
new file mode 100644
index 00000000000..4452349f23c
--- /dev/null
+++ b/source/blender/gpu/shaders/gpu_shader_icon_frag.glsl
@@ -0,0 +1,42 @@
+/**
+ * Draw the icons, leaving a semi-transparent rectangle on top of the icon.
+ *
+ * The top-left corner of the rectangle is rounded and drawned with anti-alias.
+ * The anti-alias is done by transitioning from the outer to the inner radius of
+ * the rounded corner, and the rectangle sides.
+ */
+
+void main()
+{
+ /* Top-left rounded corner parameters. */
+ const float circle_radius_outer = 0.1;
+ const float circle_radius_inner = 0.075;
+
+ /**
+ * Add a bit transparency to see a bit of the icon, without
+ * getting on the way of readability. */
+ const float mask_transparency = 0.25;
+
+ vec2 circle_center = vec2(circle_radius_outer - text_width, 0.5);
+ fragColor = texture(image, texCoord_interp) * color;
+
+ /* radius in icon space (1 is the icon width). */
+ float radius = length(mask_coord_interp - circle_center);
+ float mask = smoothstep(circle_radius_inner, circle_radius_outer, radius);
+
+ bool lower_half = mask_coord_interp.y < circle_center.y;
+ bool right_half = mask_coord_interp.x > circle_center.x;
+
+ if (right_half && mask_coord_interp.y < circle_center.y + circle_radius_outer) {
+ mask = smoothstep(circle_center.y + circle_radius_inner,
+ circle_center.y + circle_radius_outer,
+ mask_coord_interp.y);
+ }
+ if (lower_half && mask_coord_interp.x > circle_center.x - circle_radius_outer) {
+ mask = smoothstep(circle_center.x - circle_radius_inner,
+ circle_center.x - circle_radius_outer,
+ mask_coord_interp.x);
+ }
+
+ fragColor = mix(vec4(0.0), fragColor, max(mask_transparency, mask));
+}
diff --git a/source/blender/gpu/shaders/gpu_shader_icon_vert.glsl b/source/blender/gpu/shaders/gpu_shader_icon_vert.glsl
new file mode 100644
index 00000000000..25f64bfe0b6
--- /dev/null
+++ b/source/blender/gpu/shaders/gpu_shader_icon_vert.glsl
@@ -0,0 +1,37 @@
+/**
+ * Simple shader that just draw one icon at the specified location
+ * does not need any vertex input (producing less call to immBegin/End)
+ */
+
+void main()
+{
+ vec2 uv;
+ vec2 co;
+
+ if (gl_VertexID == 0) {
+ co = rect_geom.xw;
+ uv = rect_icon.xw;
+ mask_coord_interp = vec2(0, 1);
+ }
+ else if (gl_VertexID == 1) {
+ co = rect_geom.xy;
+ uv = rect_icon.xy;
+ mask_coord_interp = vec2(0, 0);
+ }
+ else if (gl_VertexID == 2) {
+ co = rect_geom.zw;
+ uv = rect_icon.zw;
+ mask_coord_interp = vec2(1, 1);
+ }
+ else {
+ co = rect_geom.zy;
+ uv = rect_icon.zy;
+ mask_coord_interp = vec2(1, 0);
+ }
+
+ /* Put origin in lower right corner. */
+ mask_coord_interp.x -= 1;
+
+ gl_Position = ModelViewProjectionMatrix * vec4(co, 0.0f, 1.0f);
+ texCoord_interp = uv;
+}
diff --git a/source/blender/gpu/shaders/infos/gpu_interface_info.hh b/source/blender/gpu/shaders/infos/gpu_interface_info.hh
index d77c65e48a7..060def16f81 100644
--- a/source/blender/gpu/shaders/infos/gpu_interface_info.hh
+++ b/source/blender/gpu/shaders/infos/gpu_interface_info.hh
@@ -18,3 +18,6 @@ GPU_SHADER_INTERFACE_INFO(smooth_radii_outline_iface, "").smooth(Type::VEC4, "ra
GPU_SHADER_INTERFACE_INFO(flat_color_smooth_tex_coord_interp_iface, "")
.flat(Type::VEC4, "finalColor")
.smooth(Type::VEC2, "texCoord_interp");
+GPU_SHADER_INTERFACE_INFO(smooth_icon_interp_iface, "")
+ .smooth(Type::VEC2, "texCoord_interp")
+ .smooth(Type::VEC2, "mask_coord_interp");
diff --git a/source/blender/gpu/shaders/infos/gpu_shader_icon_info.hh b/source/blender/gpu/shaders/infos/gpu_shader_icon_info.hh
new file mode 100644
index 00000000000..3d4077bdb09
--- /dev/null
+++ b/source/blender/gpu/shaders/infos/gpu_shader_icon_info.hh
@@ -0,0 +1,22 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later
+ * Copyright 2022 Blender Foundation. All rights reserved. */
+
+/** \file
+ * \ingroup gpu
+ */
+
+#include "gpu_interface_info.hh"
+#include "gpu_shader_create_info.hh"
+
+GPU_SHADER_CREATE_INFO(gpu_shader_icon)
+ .vertex_out(smooth_icon_interp_iface)
+ .fragment_out(0, Type::VEC4, "fragColor")
+ .push_constant(Type::MAT4, "ModelViewProjectionMatrix")
+ .push_constant(Type::VEC4, "color")
+ .push_constant(Type::VEC4, "rect_icon")
+ .push_constant(Type::VEC4, "rect_geom")
+ .push_constant(Type::FLOAT, "text_width")
+ .sampler(0, ImageType::FLOAT_2D, "image")
+ .vertex_source("gpu_shader_icon_vert.glsl")
+ .fragment_source("gpu_shader_icon_frag.glsl")
+ .do_static_compilation(true);
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/colormanagement.c b/source/blender/imbuf/intern/colormanagement.c
index ea5f4ec275d..5e132826a4c 100644
--- a/source/blender/imbuf/intern/colormanagement.c
+++ b/source/blender/imbuf/intern/colormanagement.c
@@ -668,7 +668,7 @@ void colormanagement_init(void)
configdir = BKE_appdir_folder_id(BLENDER_DATAFILES, "colormanagement");
if (configdir) {
- BLI_join_dirfile(configfile, sizeof(configfile), configdir, BCM_CONFIG_FILE);
+ BLI_path_join(configfile, sizeof(configfile), configdir, BCM_CONFIG_FILE);
#ifdef WIN32
{
diff --git a/source/blender/imbuf/intern/indexer.c b/source/blender/imbuf/intern/indexer.c
index 735472b6bdf..eaa72441fb6 100644
--- a/source/blender/imbuf/intern/indexer.c
+++ b/source/blender/imbuf/intern/indexer.c
@@ -426,7 +426,7 @@ static bool get_proxy_filepath(struct anim *anim,
return false;
}
- BLI_join_dirfile(filepath, FILE_MAXFILE + FILE_MAXDIR, index_dir, proxy_name);
+ BLI_path_join(filepath, FILE_MAXFILE + FILE_MAXDIR, index_dir, proxy_name);
return true;
}
@@ -457,7 +457,7 @@ static void get_tc_filename(struct anim *anim, IMB_Timecode_Type tc, char *filep
get_index_dir(anim, index_dir, sizeof(index_dir));
- BLI_join_dirfile(filepath, FILE_MAXFILE + FILE_MAXDIR, index_dir, index_name);
+ BLI_path_join(filepath, FILE_MAXFILE + FILE_MAXDIR, index_dir, index_name);
}
/* ----------------------------------------------------------------------
@@ -498,7 +498,9 @@ static struct proxy_output_ctx *alloc_proxy_output_ffmpeg(
rv->anim = anim;
get_proxy_filepath(rv->anim, rv->proxy_size, filepath, true);
- BLI_make_existing_file(filepath);
+ if (!BLI_make_existing_file(filepath)) {
+ return NULL;
+ }
rv->of = avformat_alloc_context();
rv->of->oformat = av_guess_format("avi", NULL, NULL);
@@ -905,6 +907,14 @@ static IndexBuildContext *index_ffmpeg_create_context(struct anim *anim,
}
}
+ if (context->proxy_ctx[0] == NULL && context->proxy_ctx[1] == NULL &&
+ context->proxy_ctx[2] == NULL && context->proxy_ctx[3] == NULL) {
+ avformat_close_input(&context->iFormatCtx);
+ avcodec_free_context(&context->iCodecCtx);
+ MEM_freeN(context);
+ return NULL; /* Nothing to transcode. */
+ }
+
for (i = 0; i < num_indexers; i++) {
if (tcs_in_use & tc_types[i]) {
char filepath[FILE_MAX];
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..35cdefbaaeb 100644
--- a/source/blender/imbuf/intern/util_gpu.c
+++ b/source/blender/imbuf/intern/util_gpu.c
@@ -174,6 +174,7 @@ static void *imb_gpu_get_data(const ImBuf *ibuf,
/* Other colorspace, store as float texture to avoid precision loss. */
data_rect = MEM_mallocN(sizeof(float[4]) * ibuf->x * ibuf->y, __func__);
*r_freedata = freedata = true;
+ is_float_rect = true;
if (data_rect == NULL) {
return NULL;
@@ -300,6 +301,16 @@ GPUTexture *IMB_create_gpu_texture(const char *name,
int size[2] = {GPU_texture_size_with_limit(ibuf->x), GPU_texture_size_with_limit(ibuf->y)};
bool do_rescale = (ibuf->x != size[0]) || (ibuf->y != size[1]);
+ /* Correct the smaller size to maintain the original aspect ratio of the image. */
+ if (do_rescale && ibuf->x != ibuf->y) {
+ if (size[0] > size[1]) {
+ size[1] = (int)(ibuf->y * ((float)size[0] / ibuf->x));
+ }
+ else {
+ size[0] = (int)(ibuf->x * ((float)size[1] / ibuf->y));
+ }
+ }
+
#ifdef WITH_DDS
if (ibuf->ftype == IMB_FTYPE_DDS) {
eGPUTextureFormat compressed_format;
@@ -370,3 +381,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/abc_reader_mesh.cc b/source/blender/io/alembic/intern/abc_reader_mesh.cc
index f08514dc45c..2531bd62609 100644
--- a/source/blender/io/alembic/intern/abc_reader_mesh.cc
+++ b/source/blender/io/alembic/intern/abc_reader_mesh.cc
@@ -763,7 +763,7 @@ Mesh *AbcMeshReader::read_mesh(Mesh *existing_mesh,
std::map<std::string, int> mat_map;
bke::MutableAttributeAccessor attributes = new_mesh->attributes_for_write();
bke::SpanAttributeWriter<int> material_indices =
- attributes.lookup_or_add_for_write_only_span<int>("material_index", ATTR_DOMAIN_FACE);
+ attributes.lookup_or_add_for_write_span<int>("material_index", ATTR_DOMAIN_FACE);
assign_facesets_to_material_indices(sample_sel, material_indices.span, mat_map);
material_indices.finish();
}
@@ -823,8 +823,8 @@ void AbcMeshReader::readFaceSetsSample(Main *bmain, Mesh *mesh, const ISampleSel
{
std::map<std::string, int> mat_map;
bke::MutableAttributeAccessor attributes = mesh->attributes_for_write();
- bke::SpanAttributeWriter<int> material_indices =
- attributes.lookup_or_add_for_write_only_span<int>("material_index", ATTR_DOMAIN_FACE);
+ bke::SpanAttributeWriter<int> material_indices = attributes.lookup_or_add_for_write_span<int>(
+ "material_index", ATTR_DOMAIN_FACE);
assign_facesets_to_material_indices(sample_sel, material_indices.span, mat_map);
material_indices.finish();
utils::assign_materials(bmain, m_object, mat_map);
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/collada/DocumentExporter.cpp b/source/blender/io/collada/DocumentExporter.cpp
index 56adbca13bd..07392e9c4ce 100644
--- a/source/blender/io/collada/DocumentExporter.cpp
+++ b/source/blender/io/collada/DocumentExporter.cpp
@@ -145,7 +145,7 @@ static COLLADABU::NativeString make_temp_filepath(const char *name, const char *
name = "untitled";
}
- BLI_join_dirfile(tempfile, sizeof(tempfile), BKE_tempdir_session(), name);
+ BLI_path_join(tempfile, sizeof(tempfile), BKE_tempdir_session(), name);
if (extension) {
BLI_path_extension_ensure(tempfile, FILE_MAX, extension);
diff --git a/source/blender/io/collada/DocumentImporter.cpp b/source/blender/io/collada/DocumentImporter.cpp
index 660bbd7edb2..5e432682564 100644
--- a/source/blender/io/collada/DocumentImporter.cpp
+++ b/source/blender/io/collada/DocumentImporter.cpp
@@ -937,7 +937,7 @@ bool DocumentImporter::writeImage(const COLLADAFW::Image *image)
const char *workpath;
BLI_split_dir_part(this->import_settings->filepath, dir, sizeof(dir));
- BLI_join_dirfile(absolute_path, sizeof(absolute_path), dir, imagepath.c_str());
+ BLI_path_join(absolute_path, sizeof(absolute_path), dir, imagepath.c_str());
if (BLI_exists(absolute_path)) {
workpath = absolute_path;
}
diff --git a/source/blender/io/collada/ImageExporter.cpp b/source/blender/io/collada/ImageExporter.cpp
index 1223abbaf95..070eb36de31 100644
--- a/source/blender/io/collada/ImageExporter.cpp
+++ b/source/blender/io/collada/ImageExporter.cpp
@@ -70,7 +70,7 @@ void ImagesExporter::export_UV_Image(Image *image, bool use_copies)
BLI_strncpy(export_file, name.c_str(), sizeof(export_file));
BKE_image_path_ensure_ext_from_imformat(export_file, &imageFormat);
- BLI_join_dirfile(export_path, sizeof(export_path), export_dir, export_file);
+ BLI_path_join(export_path, sizeof(export_path), export_dir, export_file);
/* make dest directory if it doesn't exist */
BLI_make_existing_file(export_path);
diff --git a/source/blender/io/common/intern/path_util.cc b/source/blender/io/common/intern/path_util.cc
index 18632b410f8..63ff6cf29ee 100644
--- a/source/blender/io/common/intern/path_util.cc
+++ b/source/blender/io/common/intern/path_util.cc
@@ -28,8 +28,7 @@ std::string path_reference(StringRefNull filepath,
}
else if (mode == PATH_REFERENCE_COPY) {
char filepath_cpy[PATH_MAX];
- BLI_path_join(
- filepath_cpy, PATH_MAX, base_dst.c_str(), BLI_path_basename(filepath_abs), nullptr);
+ BLI_path_join(filepath_cpy, PATH_MAX, base_dst.c_str(), BLI_path_basename(filepath_abs));
copy_set->add(std::make_pair(filepath_abs, filepath_cpy));
BLI_strncpy(filepath_abs, filepath_cpy, PATH_MAX);
mode = PATH_REFERENCE_RELATIVE;
diff --git a/source/blender/io/stl/CMakeLists.txt b/source/blender/io/stl/CMakeLists.txt
index 3a21da5c579..f7eb933d198 100644
--- a/source/blender/io/stl/CMakeLists.txt
+++ b/source/blender/io/stl/CMakeLists.txt
@@ -2,7 +2,7 @@
set(INC
.
- ./importer
+ importer
../common
../../blenkernel
../../blenlib
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/usd/intern/usd_reader_mesh.cc b/source/blender/io/usd/intern/usd_reader_mesh.cc
index 77c79852141..01db6baeb5c 100644
--- a/source/blender/io/usd/intern/usd_reader_mesh.cc
+++ b/source/blender/io/usd/intern/usd_reader_mesh.cc
@@ -804,8 +804,8 @@ void USDMeshReader::readFaceSetsSample(Main *bmain, Mesh *mesh, const double mot
std::map<pxr::SdfPath, int> mat_map;
bke::MutableAttributeAccessor attributes = mesh->attributes_for_write();
- bke::SpanAttributeWriter<int> material_indices =
- attributes.lookup_or_add_for_write_only_span<int>("material_index", ATTR_DOMAIN_FACE);
+ bke::SpanAttributeWriter<int> material_indices = attributes.lookup_or_add_for_write_span<int>(
+ "material_index", ATTR_DOMAIN_FACE);
this->assign_facesets_to_material_indices(motionSampleTime, material_indices.span, &mat_map);
material_indices.finish();
/* Build material name map if it's not built yet. */
@@ -914,7 +914,7 @@ Mesh *USDMeshReader::read_mesh(Mesh *existing_mesh,
std::map<pxr::SdfPath, int> mat_map;
bke::MutableAttributeAccessor attributes = active_mesh->attributes_for_write();
bke::SpanAttributeWriter<int> material_indices =
- attributes.lookup_or_add_for_write_only_span<int>("material_index", ATTR_DOMAIN_FACE);
+ attributes.lookup_or_add_for_write_span<int>("material_index", ATTR_DOMAIN_FACE);
assign_facesets_to_material_indices(motionSampleTime, material_indices.span, &mat_map);
material_indices.finish();
}
diff --git a/source/blender/io/usd/intern/usd_writer_material.cc b/source/blender/io/usd/intern/usd_writer_material.cc
index c195bf0e0bd..75abae79519 100644
--- a/source/blender/io/usd/intern/usd_writer_material.cc
+++ b/source/blender/io/usd/intern/usd_writer_material.cc
@@ -380,7 +380,7 @@ static void export_in_memory_texture(Image *ima,
BKE_image_path_ensure_ext_from_imformat(file_name, &imageFormat);
char export_path[FILE_MAX];
- BLI_path_join(export_path, FILE_MAX, export_dir.c_str(), file_name, nullptr);
+ BLI_path_join(export_path, FILE_MAX, export_dir.c_str(), file_name);
if (!allow_overwrite && BLI_exists(export_path)) {
return;
@@ -576,7 +576,7 @@ static std::string get_tex_image_asset_path(bNode *node,
BLI_split_file_part(path.c_str(), file_path, FILE_MAX);
if (export_params.relative_paths) {
- BLI_path_join(exp_path, FILE_MAX, ".", "textures", file_path, nullptr);
+ BLI_path_join(exp_path, FILE_MAX, ".", "textures", file_path);
}
else {
/* Create absolute path in the textures directory. */
@@ -588,7 +588,7 @@ static std::string get_tex_image_asset_path(bNode *node,
char dir_path[FILE_MAX];
BLI_split_dir_part(stage_path.c_str(), dir_path, FILE_MAX);
- BLI_path_join(exp_path, FILE_MAX, dir_path, "textures", file_path, nullptr);
+ BLI_path_join(exp_path, FILE_MAX, dir_path, "textures", file_path);
}
BLI_str_replace_char(exp_path, '\\', '/');
return exp_path;
@@ -645,7 +645,7 @@ static void copy_tiled_textures(Image *ima,
BLI_split_file_part(src_tile_path, dest_filename, sizeof(dest_filename));
char dest_tile_path[FILE_MAX];
- BLI_path_join(dest_tile_path, FILE_MAX, dest_dir.c_str(), dest_filename, nullptr);
+ BLI_path_join(dest_tile_path, FILE_MAX, dest_dir.c_str(), dest_filename);
if (!allow_overwrite && BLI_exists(dest_tile_path)) {
continue;
@@ -680,7 +680,7 @@ static void copy_single_file(Image *ima, const std::string &dest_dir, const bool
BLI_split_file_part(source_path, file_name, FILE_MAX);
char dest_path[FILE_MAX];
- BLI_path_join(dest_path, FILE_MAX, dest_dir.c_str(), file_name, nullptr);
+ BLI_path_join(dest_path, FILE_MAX, dest_dir.c_str(), file_name);
if (!allow_overwrite && BLI_exists(dest_path)) {
return;
@@ -726,7 +726,7 @@ static void export_texture(bNode *node,
BLI_split_dir_part(stage_path.c_str(), usd_dir_path, FILE_MAX);
char tex_dir_path[FILE_MAX];
- BLI_path_join(tex_dir_path, FILE_MAX, usd_dir_path, "textures", SEP_STR, nullptr);
+ BLI_path_join(tex_dir_path, FILE_MAX, usd_dir_path, "textures", SEP_STR);
BLI_dir_create_recursive(tex_dir_path);
diff --git a/source/blender/io/usd/intern/usd_writer_volume.cc b/source/blender/io/usd/intern/usd_writer_volume.cc
index 8cc3c65ee70..c6a27c5f663 100644
--- a/source/blender/io/usd/intern/usd_writer_volume.cc
+++ b/source/blender/io/usd/intern/usd_writer_volume.cc
@@ -152,7 +152,7 @@ std::optional<std::string> USDVolumeWriter::construct_vdb_file_path(const Volume
strcat(vdb_file_name, ".vdb");
char vdb_file_path[FILE_MAX];
- BLI_path_join(vdb_file_path, sizeof(vdb_file_path), vdb_directory_path, vdb_file_name, nullptr);
+ BLI_path_join(vdb_file_path, sizeof(vdb_file_path), vdb_directory_path, vdb_file_name);
return vdb_file_path;
}
diff --git a/source/blender/io/usd/tests/usd_tests_common.cc b/source/blender/io/usd/tests/usd_tests_common.cc
index 9f18a289433..ea4e704006d 100644
--- a/source/blender/io/usd/tests/usd_tests_common.cc
+++ b/source/blender/io/usd/tests/usd_tests_common.cc
@@ -29,7 +29,7 @@ std::string register_usd_plugins_for_tests()
}
const size_t path_len = BLI_path_join(
- usd_datafiles_dir, FILE_MAX, release_dir.c_str(), "datafiles", "usd", nullptr);
+ usd_datafiles_dir, FILE_MAX, release_dir.c_str(), "datafiles", "usd");
/* #BLI_path_join removes trailing slashes, but the USD library requires one in order to
* recognize the path as directory. */
diff --git a/source/blender/io/wavefront_obj/CMakeLists.txt b/source/blender/io/wavefront_obj/CMakeLists.txt
index f7958ef4ec6..bfbc715a45f 100644
--- a/source/blender/io/wavefront_obj/CMakeLists.txt
+++ b/source/blender/io/wavefront_obj/CMakeLists.txt
@@ -2,8 +2,8 @@
set(INC
.
- ./exporter
- ./importer
+ exporter
+ importer
../common
../../blenkernel
../../blenlib
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..7d5f023af4b 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);
}
@@ -753,7 +765,7 @@ MTLParser::MTLParser(StringRefNull mtl_library, StringRefNull obj_filepath)
{
char obj_file_dir[FILE_MAXDIR];
BLI_split_dir_part(obj_filepath.data(), obj_file_dir, FILE_MAXDIR);
- BLI_path_join(mtl_file_path_, FILE_MAX, obj_file_dir, mtl_library.data(), nullptr);
+ BLI_path_join(mtl_file_path_, FILE_MAX, obj_file_dir, mtl_library.data());
BLI_split_dir_part(mtl_file_path_, mtl_dir_path_, FILE_MAXDIR);
}
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_defaults.h b/source/blender/makesdna/DNA_brush_defaults.h
index 348e8f4e098..6e88275672a 100644
--- a/source/blender/makesdna/DNA_brush_defaults.h
+++ b/source/blender/makesdna/DNA_brush_defaults.h
@@ -92,7 +92,7 @@
.hardness = 0.0f, \
.automasking_boundary_edges_propagation_steps = 1, \
.automasking_cavity_blur_steps = 0,\
- .automasking_cavity_factor = 0.5f,\
+ .automasking_cavity_factor = 1.0f,\
\
/* A kernel radius of 1 has almost no effect (T63233). */ \
.blur_kernel_radius = 2, \
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_gpencil_types.h b/source/blender/makesdna/DNA_gpencil_types.h
index 26dbb544f52..8b3f4956cfe 100644
--- a/source/blender/makesdna/DNA_gpencil_types.h
+++ b/source/blender/makesdna/DNA_gpencil_types.h
@@ -243,12 +243,15 @@ typedef struct bGPDstroke_Runtime {
/** Runtime falloff factor (only for transform). */
float multi_frame_falloff;
- /** Vertex offset in the VBO where this stroke starts. */
+ /** Triangle offset in the IBO where this stroke starts. */
int stroke_start;
/** Triangle offset in the IBO where this fill starts. */
int fill_start;
+ /** Vertex offset in the VBO where this stroke starts. */
+ int vertex_start;
/** Curve Handles offset in the IBO where this handle starts. */
int curve_start;
+ int _pad0;
/** Original stroke (used to dereference evaluated data) */
struct bGPDstroke *gps_orig;
@@ -613,8 +616,9 @@ typedef struct bGPdata_Runtime {
/** Stroke buffer. */
void *sbuffer;
/** Temp batches cleared after drawing. */
- struct GPUBatch *sbuffer_stroke_batch;
- struct GPUBatch *sbuffer_fill_batch;
+ struct GPUVertBuf *sbuffer_position_buf;
+ struct GPUVertBuf *sbuffer_color_buf;
+ struct GPUBatch *sbuffer_batch;
/** Temp stroke used for drawing. */
struct bGPDstroke *sbuffer_gps;
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_node_types.h b/source/blender/makesdna/DNA_node_types.h
index 9cd056e5a0c..748033cb015 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;
@@ -2082,6 +2079,21 @@ 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;
+
+/* Tone Map Node. Stored in NodeTonemap.type. */
+typedef enum CMPNodeToneMapType {
+ CMP_NODE_TONE_MAP_SIMPLE = 0,
+ CMP_NODE_TONE_MAP_PHOTORECEPTOR = 1,
+} CMPNodeToneMapType;
+
/* Plane track deform node. */
enum {
diff --git a/source/blender/makesdna/DNA_scene_types.h b/source/blender/makesdna/DNA_scene_types.h
index 5fa5d4c7787..28359038be5 100644
--- a/source/blender/makesdna/DNA_scene_types.h
+++ b/source/blender/makesdna/DNA_scene_types.h
@@ -472,6 +472,7 @@ typedef struct ImageFormatData {
#define R_IMF_IMTYPE_THEORA 33
#define R_IMF_IMTYPE_PSD 34
#define R_IMF_IMTYPE_WEBP 35
+#define R_IMF_IMTYPE_AV1 36
#define R_IMF_IMTYPE_INVALID 255
diff --git a/source/blender/makesdna/DNA_space_types.h b/source/blender/makesdna/DNA_space_types.h
index 7f0dd2f9be6..d2d20bcde78 100644
--- a/source/blender/makesdna/DNA_space_types.h
+++ b/source/blender/makesdna/DNA_space_types.h
@@ -1169,6 +1169,10 @@ enum {
FILE_ENTRY_NAME_FREE = 1 << 1,
/* The preview for this entry is being loaded on another thread. */
FILE_ENTRY_PREVIEW_LOADING = 1 << 2,
+ /** For #FILE_TYPE_BLENDERLIB only: Denotes that the ID is known to not have a preview (none was
+ * found in the .blend). Stored so we don't keep trying to find non-existent previews every time
+ * we reload previews. When dealing with heavy files this can have quite an impact. */
+ FILE_ENTRY_BLENDERLIB_NO_PREVIEW = 1 << 3,
};
/** \} */
@@ -1184,6 +1188,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 +1240,9 @@ typedef struct SpaceImage {
char around;
char gizmo_flag;
- char _pad1[3];
+
+ char grid_shape_source;
+ char _pad1[2];
int flag;
@@ -1239,7 +1251,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 +1278,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 +1312,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/makesdna/intern/CMakeLists.txt b/source/blender/makesdna/intern/CMakeLists.txt
index 0d04d7df067..50fd51e88a1 100644
--- a/source/blender/makesdna/intern/CMakeLists.txt
+++ b/source/blender/makesdna/intern/CMakeLists.txt
@@ -116,8 +116,8 @@ blender_add_lib(bf_dna "${SRC}" "${INC}" "${INC_SYS}" "${LIB}")
# -----------------------------------------------------------------------------
# Build bf_dna_blenlib library
set(INC
+ ..
../../blenlib
- ../../makesdna
../../../../intern/atomic
../../../../intern/guardedalloc
)
diff --git a/source/blender/makesrna/intern/CMakeLists.txt b/source/blender/makesrna/intern/CMakeLists.txt
index 2b06daf34e3..f028b199098 100644
--- a/source/blender/makesrna/intern/CMakeLists.txt
+++ b/source/blender/makesrna/intern/CMakeLists.txt
@@ -200,7 +200,7 @@ set(INC
../../imbuf
../../makesdna
../../modifiers
- ../../nodes/
+ ../../nodes
../../sequencer
../../simulation
../../windowmanager
diff --git a/source/blender/makesrna/intern/rna_brush.c b/source/blender/makesrna/intern/rna_brush.c
index 3c9590ddcbe..137020ce3f8 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"},
@@ -3240,18 +3240,20 @@ static void rna_def_brush(BlenderRNA *brna)
RNA_def_property_update(prop, 0, "rna_Brush_update");
} while ((++entry)->identifier);
- prop = RNA_def_property(srna, "automasking_cavity_factor", PROP_FLOAT, PROP_NONE);
+ prop = RNA_def_property(srna, "automasking_cavity_factor", PROP_FLOAT, PROP_FACTOR);
RNA_def_property_float_sdna(prop, NULL, "automasking_cavity_factor");
RNA_def_property_ui_text(prop, "Cavity Factor", "The contrast of the cavity mask");
- RNA_def_property_ui_range(prop, 0.0f, 1.0f, 0.1, 3);
RNA_def_property_range(prop, 0.0f, 5.0f);
+ RNA_def_property_ui_range(prop, 0.0f, 1.0f, 0.1, 3);
RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_LIBRARY);
RNA_def_property_update(prop, 0, "rna_Brush_update");
prop = RNA_def_property(srna, "automasking_cavity_blur_steps", PROP_INT, PROP_NONE);
RNA_def_property_int_sdna(prop, NULL, "automasking_cavity_blur_steps");
+ RNA_def_property_int_default(prop, 0);
RNA_def_property_ui_text(prop, "Blur Steps", "The number of times the cavity mask is blurred");
- RNA_def_property_range(prop, 0.0f, 25.0f);
+ RNA_def_property_range(prop, 0, 25);
+ RNA_def_property_ui_range(prop, 0, 10, 1, 1);
RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_LIBRARY);
RNA_def_property_update(prop, 0, "rna_Brush_update");
@@ -3614,6 +3616,10 @@ static void rna_def_brush(BlenderRNA *brna)
RNA_def_property_ui_text(
prop, "Use Vertex", "Use this brush in grease pencil vertex color mode");
+ prop = RNA_def_property(srna, "use_paint_sculpt_curves", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "ob_mode", OB_MODE_SCULPT_CURVES);
+ RNA_def_property_ui_text(prop, "Use Sculpt", "Use this brush in sculpt curves mode");
+
/* texture */
prop = RNA_def_property(srna, "texture_slot", PROP_POINTER, PROP_NONE);
RNA_def_property_struct_type(prop, "BrushTextureSlot");
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_gpencil_modifier.c b/source/blender/makesrna/intern/rna_gpencil_modifier.c
index 4a36443ca42..320ef169ae5 100644
--- a/source/blender/makesrna/intern/rna_gpencil_modifier.c
+++ b/source/blender/makesrna/intern/rna_gpencil_modifier.c
@@ -9,11 +9,8 @@
#include <stdlib.h>
#include "DNA_armature_types.h"
-#include "DNA_brush_types.h"
-#include "DNA_cachefile_types.h"
#include "DNA_gpencil_modifier_types.h"
#include "DNA_gpencil_types.h"
-#include "DNA_mesh_types.h"
#include "DNA_modifier_types.h"
#include "DNA_object_force_types.h"
#include "DNA_object_types.h"
@@ -21,20 +18,13 @@
#include "MEM_guardedalloc.h"
-#include "BLI_math.h"
-#include "BLI_rand.h"
+#include "BLI_math_base.h"
+#include "BLI_math_rotation.h"
#include "BLI_string_utils.h"
#include "BLT_translation.h"
#include "BKE_animsys.h"
-#include "BKE_data_transfer.h"
-#include "BKE_dynamicpaint.h"
-#include "BKE_effect.h"
-#include "BKE_fluid.h" /* For BKE_fluid_modifier_free & BKE_fluid_modifier_create_type_data */
-#include "BKE_mesh_mapping.h"
-#include "BKE_mesh_remap.h"
-#include "BKE_multires.h"
#include "RNA_access.h"
#include "RNA_define.h"
diff --git a/source/blender/makesrna/intern/rna_internal.h b/source/blender/makesrna/intern/rna_internal.h
index 8e652753ec0..ea829e5cd86 100644
--- a/source/blender/makesrna/intern/rna_internal.h
+++ b/source/blender/makesrna/intern/rna_internal.h
@@ -322,7 +322,9 @@ void rna_object_vcollayer_name_set(struct PointerRNA *ptr,
PointerRNA rna_object_shapekey_index_get(struct ID *id, int value);
int rna_object_shapekey_index_set(struct ID *id, PointerRNA value, int current);
-void rna_def_object_type_visibility_flags_common(StructRNA *srna, int noteflag);
+void rna_def_object_type_visibility_flags_common(StructRNA *srna,
+ int noteflag,
+ const char *update_func);
int rna_object_type_visibility_icon_get_common(int object_type_exclude_viewport,
const int *object_type_exclude_select);
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 b694e9da85f..7db97387ad7 100644
--- a/source/blender/makesrna/intern/rna_nodetree.c
+++ b/source/blender/makesrna/intern/rna_nodetree.c
@@ -5509,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);
@@ -5573,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");
}
@@ -6811,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_object_api.c b/source/blender/makesrna/intern/rna_object_api.c
index c99c5fb723d..366a3597ce6 100644
--- a/source/blender/makesrna/intern/rna_object_api.c
+++ b/source/blender/makesrna/intern/rna_object_api.c
@@ -199,7 +199,7 @@ static bool rna_Object_holdout_get(Object *ob, bContext *C, PointerRNA *view_lay
return false;
}
- return ((base->flag & BASE_HOLDOUT) != 0);
+ return ((base->flag & BASE_HOLDOUT) != 0) || ((ob->visibility_flag & OB_HOLDOUT) != 0);
}
static bool rna_Object_indirect_only_get(Object *ob, bContext *C, PointerRNA *view_layer_ptr)
diff --git a/source/blender/makesrna/intern/rna_scene.c b/source/blender/makesrna/intern/rna_scene.c
index 70afc763c2d..58455ff7de5 100644
--- a/source/blender/makesrna/intern/rna_scene.c
+++ b/source/blender/makesrna/intern/rna_scene.c
@@ -5928,6 +5928,7 @@ static void rna_def_scene_ffmpeg_settings(BlenderRNA *brna)
{FFMPEG_MKV, "MKV", 0, "Matroska", ""},
{FFMPEG_FLV, "FLASH", 0, "Flash", ""},
{FFMPEG_WEBM, "WEBM", 0, "WebM", ""},
+ {AV_CODEC_ID_AV1, "AV1", 0, "AV1", ""},
{0, NULL, 0, NULL, NULL},
};
@@ -5945,7 +5946,7 @@ static void rna_def_scene_ffmpeg_settings(BlenderRNA *brna)
{AV_CODEC_ID_PNG, "PNG", 0, "PNG", ""},
{AV_CODEC_ID_QTRLE, "QTRLE", 0, "QT rle / QT Animation", ""},
{AV_CODEC_ID_THEORA, "THEORA", 0, "Theora", ""},
- {AV_CODEC_ID_VP9, "WEBM", 0, "WEBM / VP9", ""},
+ {AV_CODEC_ID_VP9, "WEBM", 0, "WebM / VP9", ""},
{0, NULL, 0, NULL, NULL},
};
@@ -7861,6 +7862,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_sculpt_paint.c b/source/blender/makesrna/intern/rna_sculpt_paint.c
index d8ad3d1f41e..440309849ab 100644
--- a/source/blender/makesrna/intern/rna_sculpt_paint.c
+++ b/source/blender/makesrna/intern/rna_sculpt_paint.c
@@ -927,17 +927,20 @@ static void rna_def_sculpt(BlenderRNA *brna)
RNA_def_property_update(prop, NC_SCENE | ND_TOOLSETTINGS, NULL);
} while ((++entry)->identifier);
- prop = RNA_def_property(srna, "automasking_cavity_factor", PROP_FLOAT, PROP_NONE);
+ prop = RNA_def_property(srna, "automasking_cavity_factor", PROP_FLOAT, PROP_FACTOR);
RNA_def_property_float_sdna(prop, NULL, "automasking_cavity_factor");
RNA_def_property_ui_text(prop, "Cavity Factor", "The contrast of the cavity mask");
- RNA_def_property_ui_range(prop, 0.0f, 1.0f, 0.1, 3);
+ RNA_def_property_float_default(prop, 1.0f);
RNA_def_property_range(prop, 0.0f, 5.0f);
+ RNA_def_property_ui_range(prop, 0.0f, 1.0f, 0.1, 3);
RNA_def_property_update(prop, NC_SCENE | ND_TOOLSETTINGS, NULL);
prop = RNA_def_property(srna, "automasking_cavity_blur_steps", PROP_INT, PROP_NONE);
RNA_def_property_int_sdna(prop, NULL, "automasking_cavity_blur_steps");
RNA_def_property_ui_text(prop, "Blur Steps", "The number of times the cavity mask is blurred");
- RNA_def_property_range(prop, 0.0f, 25.0f);
+ RNA_def_property_int_default(prop, 0);
+ RNA_def_property_range(prop, 0, 25);
+ RNA_def_property_ui_range(prop, 0, 10, 1, 1);
RNA_def_property_update(prop, NC_SCENE | ND_TOOLSETTINGS, NULL);
prop = RNA_def_property(srna, "automasking_cavity_curve", PROP_POINTER, PROP_NONE);
diff --git a/source/blender/makesrna/intern/rna_sequencer.c b/source/blender/makesrna/intern/rna_sequencer.c
index 634754d54cc..c952210eecf 100644
--- a/source/blender/makesrna/intern/rna_sequencer.c
+++ b/source/blender/makesrna/intern/rna_sequencer.c
@@ -778,7 +778,7 @@ static void rna_Sequence_filepath_get(PointerRNA *ptr, char *value)
{
Sequence *seq = (Sequence *)(ptr->data);
- BLI_join_dirfile(value, FILE_MAX, seq->strip->dir, seq->strip->stripdata->name);
+ BLI_path_join(value, FILE_MAX, seq->strip->dir, seq->strip->stripdata->name);
}
static int rna_Sequence_filepath_length(PointerRNA *ptr)
@@ -786,7 +786,7 @@ static int rna_Sequence_filepath_length(PointerRNA *ptr)
Sequence *seq = (Sequence *)(ptr->data);
char path[FILE_MAX];
- BLI_join_dirfile(path, sizeof(path), seq->strip->dir, seq->strip->stripdata->name);
+ BLI_path_join(path, sizeof(path), seq->strip->dir, seq->strip->stripdata->name);
return strlen(path);
}
@@ -804,7 +804,7 @@ static void rna_Sequence_proxy_filepath_get(PointerRNA *ptr, char *value)
{
StripProxy *proxy = (StripProxy *)(ptr->data);
- BLI_join_dirfile(value, FILE_MAX, proxy->dir, proxy->file);
+ BLI_path_join(value, FILE_MAX, proxy->dir, proxy->file);
}
static int rna_Sequence_proxy_filepath_length(PointerRNA *ptr)
@@ -812,7 +812,7 @@ static int rna_Sequence_proxy_filepath_length(PointerRNA *ptr)
StripProxy *proxy = (StripProxy *)(ptr->data);
char path[FILE_MAX];
- BLI_join_dirfile(path, sizeof(path), proxy->dir, proxy->file);
+ BLI_path_join(path, sizeof(path), proxy->dir, proxy->file);
return strlen(path);
}
diff --git a/source/blender/makesrna/intern/rna_space.c b/source/blender/makesrna/intern/rna_space.c
index 738b41828e0..b2663b89333 100644
--- a/source/blender/makesrna/intern/rna_space.c
+++ b/source/blender/makesrna/intern/rna_space.c
@@ -426,7 +426,11 @@ static const EnumPropertyItem rna_enum_shading_color_type_items[] = {
{V3D_SHADING_OBJECT_COLOR, "OBJECT", 0, "Object", "Show object color"},
{V3D_SHADING_RANDOM_COLOR, "RANDOM", 0, "Random", "Show random object color"},
{V3D_SHADING_VERTEX_COLOR, "VERTEX", 0, "Attribute", "Show active color attribute"},
- {V3D_SHADING_TEXTURE_COLOR, "TEXTURE", 0, "Texture", "Show texture"},
+ {V3D_SHADING_TEXTURE_COLOR,
+ "TEXTURE",
+ 0,
+ "Texture",
+ "Show the texture from the active image texture node using the active UV map coordinates"},
{0, NULL, 0, NULL, NULL},
};
@@ -986,6 +990,13 @@ static PointerRNA rna_SpaceView3D_region_3d_get(PointerRNA *ptr)
return rna_pointer_inherit_refine(ptr, &RNA_RegionView3D, regiondata);
}
+static void rna_SpaceView3D_object_type_visibility_update(Main *UNUSED(bmain),
+ Scene *scene,
+ PointerRNA *UNUSED(ptr))
+{
+ DEG_id_tag_update(&scene->id, ID_RECALC_BASE_FLAGS);
+}
+
static void rna_SpaceView3D_region_quadviews_begin(CollectionPropertyIterator *iter,
PointerRNA *ptr)
{
@@ -3510,6 +3521,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 +3601,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 +4104,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);
@@ -5075,7 +5093,8 @@ static void rna_def_space_view3d(BlenderRNA *brna)
prop, NC_SPACE | ND_SPACE_VIEW3D, "rna_SpaceView3D_mirror_xr_session_update");
rna_def_object_type_visibility_flags_common(srna,
- NC_SPACE | ND_SPACE_VIEW3D | NS_VIEW3D_SHADING);
+ NC_SPACE | ND_SPACE_VIEW3D | NS_VIEW3D_SHADING,
+ "rna_SpaceView3D_object_type_visibility_update");
/* Helper for drawing the icon. */
prop = RNA_def_property(srna, "icon_from_show_object_viewport", PROP_INT, PROP_NONE);
@@ -5265,6 +5284,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 +6582,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 +7335,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 +7538,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_space_api.c b/source/blender/makesrna/intern/rna_space_api.c
index b3896919275..9790a85e1c8 100644
--- a/source/blender/makesrna/intern/rna_space_api.c
+++ b/source/blender/makesrna/intern/rna_space_api.c
@@ -119,7 +119,9 @@ void RNA_api_space_text(StructRNA *srna)
RNA_def_function_output(func, parm);
}
-void rna_def_object_type_visibility_flags_common(StructRNA *srna, int noteflag)
+void rna_def_object_type_visibility_flags_common(StructRNA *srna,
+ int noteflag,
+ const char *update_func)
{
PropertyRNA *prop;
@@ -173,7 +175,7 @@ void rna_def_object_type_visibility_flags_common(StructRNA *srna, int noteflag)
RNA_def_property_boolean_negative_sdna(
prop, NULL, view_mask_member[mask_index], info[type_index].type_mask);
RNA_def_property_ui_text(prop, info[type_index].name, "");
- RNA_def_property_update(prop, noteflag, NULL);
+ RNA_def_property_update(prop, noteflag, update_func);
}
}
}
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..eebe595820e 100644
--- a/source/blender/makesrna/intern/rna_wm.c
+++ b/source/blender/makesrna/intern/rna_wm.c
@@ -99,13 +99,6 @@ static const EnumPropertyItem event_ndof_type_items[] = {
{NDOF_BUTTON_DOMINANT, "NDOF_BUTTON_DOMINANT", 0, "Dominant", ""},
{NDOF_BUTTON_PLUS, "NDOF_BUTTON_PLUS", 0, "Plus", ""},
{NDOF_BUTTON_MINUS, "NDOF_BUTTON_MINUS", 0, "Minus", ""},
-# if 0 /* Never used (converted to keyboard events by GHOST). */
- /* keyboard emulation */
- {NDOF_BUTTON_ESC, "NDOF_BUTTON_ESC", 0, "Esc"},
- {NDOF_BUTTON_ALT, "NDOF_BUTTON_ALT", 0, "Alt"},
- {NDOF_BUTTON_SHIFT, "NDOF_BUTTON_SHIFT", 0, "Shift"},
- {NDOF_BUTTON_CTRL, "NDOF_BUTTON_CTRL", 0, "Ctrl"},
-# endif
/* general-purpose buttons */
{NDOF_BUTTON_1, "NDOF_BUTTON_1", 0, "Button 1", ""},
{NDOF_BUTTON_2, "NDOF_BUTTON_2", 0, "Button 2", ""},
@@ -120,6 +113,21 @@ static const EnumPropertyItem event_ndof_type_items[] = {
{NDOF_BUTTON_A, "NDOF_BUTTON_A", 0, "Button A", ""},
{NDOF_BUTTON_B, "NDOF_BUTTON_B", 0, "Button B", ""},
{NDOF_BUTTON_C, "NDOF_BUTTON_C", 0, "Button C", ""},
+ /* View buttons. */
+ {NDOF_BUTTON_V1, "NDOF_BUTTON_V1", 0, "View 1", ""},
+ {NDOF_BUTTON_V2, "NDOF_BUTTON_V2", 0, "View 2", ""},
+ {NDOF_BUTTON_V3, "NDOF_BUTTON_V3", 0, "View 3", ""},
+# if 0 /* Never used (converted to keyboard events by GHOST). */
+ /* keyboard emulation */
+ {NDOF_BUTTON_ESC, "NDOF_BUTTON_ESC", 0, "Esc"},
+ {NDOF_BUTTON_ENTER, "NDOF_BUTTON_ENTER", 0, "Enter"},
+ {NDOF_BUTTON_DELETE, "NDOF_BUTTON_DELETE", 0, "Delete"},
+ {NDOF_BUTTON_TAB, "NDOF_BUTTON_TAB", 0, "Tab"},
+ {NDOF_BUTTON_SPACE, "NDOF_BUTTON_SPACE", 0, "Space"},
+ {NDOF_BUTTON_ALT, "NDOF_BUTTON_ALT", 0, "Alt"},
+ {NDOF_BUTTON_SHIFT, "NDOF_BUTTON_SHIFT", 0, "Shift"},
+ {NDOF_BUTTON_CTRL, "NDOF_BUTTON_CTRL", 0, "Ctrl"},
+# endif
{0, NULL, 0, NULL, NULL},
};
#endif /* RNA_RUNTIME */
@@ -1644,12 +1652,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 +1664,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 +1866,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/makesrna/intern/rna_xr.c b/source/blender/makesrna/intern/rna_xr.c
index dcfa1bbca51..c803e5dc9a8 100644
--- a/source/blender/makesrna/intern/rna_xr.c
+++ b/source/blender/makesrna/intern/rna_xr.c
@@ -2052,7 +2052,7 @@ static void rna_def_xr_session_settings(BlenderRNA *brna)
"Allow the VR tracking origin to be defined independently of the headset location");
RNA_def_property_update(prop, NC_WM | ND_XR_DATA_CHANGED, NULL);
- rna_def_object_type_visibility_flags_common(srna, NC_WM | ND_XR_DATA_CHANGED);
+ rna_def_object_type_visibility_flags_common(srna, NC_WM | ND_XR_DATA_CHANGED, NULL);
/* Helper for drawing the icon. */
prop = RNA_def_property(srna, "icon_from_show_object_viewport", PROP_INT, PROP_NONE);
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 fd3f94d264a..3cd25bdde3c 100644
--- a/source/blender/nodes/NOD_static_types.h
+++ b/source/blender/nodes/NOD_static_types.h
@@ -370,7 +370,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_normalize.cc b/source/blender/nodes/composite/nodes/node_composite_normalize.cc
index 21765825468..34fd63e5805 100644
--- a/source/blender/nodes/composite/nodes/node_composite_normalize.cc
+++ b/source/blender/nodes/composite/nodes/node_composite_normalize.cc
@@ -5,7 +5,9 @@
* \ingroup cmpnodes
*/
+#include "COM_algorithm_parallel_reduction.hh"
#include "COM_node_operation.hh"
+#include "COM_utilities.hh"
#include "node_composite_util.hh"
@@ -15,19 +17,60 @@ namespace blender::nodes::node_composite_normalize_cc {
static void cmp_node_normalize_declare(NodeDeclarationBuilder &b)
{
- b.add_input<decl::Float>(N_("Value")).default_value(1.0f).min(0.0f).max(1.0f);
+ b.add_input<decl::Float>(N_("Value"))
+ .default_value(1.0f)
+ .min(0.0f)
+ .max(1.0f)
+ .compositor_domain_priority(0);
b.add_output<decl::Float>(N_("Value"));
}
using namespace blender::realtime_compositor;
class NormalizeOperation : public NodeOperation {
+ private:
+ /* The normalize operation is specifically designed to normalize Z Depth information. But since Z
+ * Depth can contain near infinite values, normalization is limited to [-range_, range], meaning
+ * that values outside of that range will be ignored when computing the maximum and minimum for
+ * normalization and will eventually be 0 or 1 if they are less than or larger than the range
+ * respectively. */
+ constexpr static float range_ = 10000.0f;
+
public:
using NodeOperation::NodeOperation;
void execute() override
{
- get_input("Value").pass_through(get_result("Value"));
+ Result &input_image = get_input("Value");
+ Result &output_image = get_result("Value");
+ if (input_image.is_single_value()) {
+ input_image.pass_through(output_image);
+ return;
+ }
+
+ const float maximum = maximum_float_in_range(
+ context(), input_image.texture(), -range_, range_);
+ const float minimum = minimum_float_in_range(
+ context(), input_image.texture(), -range_, range_);
+ const float scale = (maximum != minimum) ? (1.0f / (maximum - minimum)) : 0.0f;
+
+ GPUShader *shader = shader_manager().get("compositor_normalize");
+ GPU_shader_bind(shader);
+
+ GPU_shader_uniform_1f(shader, "minimum", minimum);
+ GPU_shader_uniform_1f(shader, "scale", scale);
+
+ input_image.bind_as_texture(shader, "input_tx");
+
+ const Domain domain = compute_domain();
+ 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();
}
};
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/composite/nodes/node_composite_tonemap.cc b/source/blender/nodes/composite/nodes/node_composite_tonemap.cc
index 2e06ad99df1..d26a01bb3c9 100644
--- a/source/blender/nodes/composite/nodes/node_composite_tonemap.cc
+++ b/source/blender/nodes/composite/nodes/node_composite_tonemap.cc
@@ -5,20 +5,35 @@
* \ingroup cmpnodes
*/
+#include <cmath>
+
+#include "BLI_assert.h"
+#include "BLI_math_base.hh"
+#include "BLI_math_vec_types.hh"
+#include "BLI_math_vector.hh"
+
#include "RNA_access.h"
#include "UI_interface.h"
#include "UI_resources.h"
+#include "IMB_colormanagement.h"
+
+#include "COM_algorithm_parallel_reduction.hh"
#include "COM_node_operation.hh"
+#include "COM_utilities.hh"
#include "node_composite_util.hh"
namespace blender::nodes::node_composite_tonemap_cc {
+NODE_STORAGE_FUNCS(NodeTonemap)
+
static void cmp_node_tonemap_declare(NodeDeclarationBuilder &b)
{
- b.add_input<decl::Color>(N_("Image")).default_value({1.0f, 1.0f, 1.0f, 1.0f});
+ b.add_input<decl::Color>(N_("Image"))
+ .default_value({1.0f, 1.0f, 1.0f, 1.0f})
+ .compositor_domain_priority(0);
b.add_output<decl::Color>(N_("Image"));
}
@@ -68,7 +83,236 @@ class ToneMapOperation : public NodeOperation {
void execute() override
{
- get_input("Image").pass_through(get_result("Image"));
+ Result &input_image = get_input("Image");
+ Result &output_image = get_result("Image");
+ if (input_image.is_single_value()) {
+ input_image.pass_through(output_image);
+ return;
+ }
+
+ switch (get_type()) {
+ case CMP_NODE_TONE_MAP_SIMPLE:
+ execute_simple();
+ return;
+ case CMP_NODE_TONE_MAP_PHOTORECEPTOR:
+ execute_photoreceptor();
+ return;
+ default:
+ BLI_assert_unreachable();
+ return;
+ }
+ }
+
+ /* Tone mapping based on equation (3) from Reinhard, Erik, et al. "Photographic tone reproduction
+ * for digital images." Proceedings of the 29th annual conference on Computer graphics and
+ * interactive techniques. 2002. */
+ void execute_simple()
+ {
+ const float luminance_scale = compute_luminance_scale();
+ const float luminance_scale_blend_factor = compute_luminance_scale_blend_factor();
+ const float gamma = node_storage(bnode()).gamma;
+ const float inverse_gamma = gamma != 0.0f ? 1.0f / gamma : 0.0f;
+
+ GPUShader *shader = shader_manager().get("compositor_tone_map_simple");
+ GPU_shader_bind(shader);
+
+ GPU_shader_uniform_1f(shader, "luminance_scale", luminance_scale);
+ GPU_shader_uniform_1f(shader, "luminance_scale_blend_factor", luminance_scale_blend_factor);
+ GPU_shader_uniform_1f(shader, "inverse_gamma", inverse_gamma);
+
+ const Result &input_image = get_input("Image");
+ input_image.bind_as_texture(shader, "input_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();
+ }
+
+ /* Computes the scaling factor in equation (2) from Reinhard's 2002 paper. */
+ float compute_luminance_scale()
+ {
+ const float geometric_mean = compute_geometric_mean_of_luminance();
+ return geometric_mean != 0.0 ? node_storage(bnode()).key / geometric_mean : 0.0f;
+ }
+
+ /* Computes equation (1) from Reinhard's 2002 paper. However, note that the equation in the paper
+ * is most likely wrong, and the intention is actually to compute the geometric mean through a
+ * logscale arithmetic mean, that is, the division should happen inside the exponential function,
+ * not outside of it. That's because the sum of the log luminance will be a very large negative
+ * number, whose exponential will almost always be zero, which is unexpected and useless. */
+ float compute_geometric_mean_of_luminance()
+ {
+ return std::exp(compute_average_log_luminance());
+ }
+
+ /* Equation (3) from Reinhard's 2002 paper blends between high luminance scaling for high
+ * luminance values and low luminance scaling for low luminance values. This is done by adding 1
+ * to the denominator, since for low luminance values, the denominator will be close to 1 and for
+ * high luminance values, the 1 in the denominator will be relatively insignificant. But the
+ * response of such function is not always ideal, so in this implementation, the 1 was exposed as
+ * a parameter to the user for more flexibility. */
+ float compute_luminance_scale_blend_factor()
+ {
+ return node_storage(bnode()).offset;
+ }
+
+ /* Tone mapping based on equation (1) and the trilinear interpolation between equations (6) and
+ * (7) from Reinhard, Erik, and Kate Devlin. "Dynamic range reduction inspired by photoreceptor
+ * physiology." IEEE transactions on visualization and computer graphics 11.1 (2005): 13-24. */
+ void execute_photoreceptor()
+ {
+ const float4 global_adaptation_level = compute_global_adaptation_level();
+ const float contrast = compute_contrast();
+ const float intensity = compute_intensity();
+ const float chromatic_adaptation = get_chromatic_adaptation();
+ const float light_adaptation = get_light_adaptation();
+
+ GPUShader *shader = shader_manager().get("compositor_tone_map_photoreceptor");
+ GPU_shader_bind(shader);
+
+ GPU_shader_uniform_4fv(shader, "global_adaptation_level", global_adaptation_level);
+ GPU_shader_uniform_1f(shader, "contrast", contrast);
+ GPU_shader_uniform_1f(shader, "intensity", intensity);
+ GPU_shader_uniform_1f(shader, "chromatic_adaptation", chromatic_adaptation);
+ GPU_shader_uniform_1f(shader, "light_adaptation", light_adaptation);
+
+ float luminance_coefficients[3];
+ IMB_colormanagement_get_luminance_coefficients(luminance_coefficients);
+ GPU_shader_uniform_3fv(shader, "luminance_coefficients", luminance_coefficients);
+
+ const Result &input_image = get_input("Image");
+ input_image.bind_as_texture(shader, "input_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();
+ }
+
+ /* Computes the global adaptation level from the trilinear interpolation equations constructed
+ * from equations (6) and (7) in Reinhard's 2005 paper. */
+ float4 compute_global_adaptation_level()
+ {
+ const float4 average_color = compute_average_color();
+ const float average_luminance = compute_average_luminance();
+ const float chromatic_adaptation = get_chromatic_adaptation();
+ return math::interpolate(float4(average_luminance), average_color, chromatic_adaptation);
+ }
+
+ float4 compute_average_color()
+ {
+ /* The average color will reduce to zero if chromatic adaptation is zero, so just return zero
+ * in this case to avoid needlessly computing the average. See the trilinear interpolation
+ * equations constructed from equations (6) and (7) in Reinhard's 2005 paper. */
+ if (get_chromatic_adaptation() == 0.0f) {
+ return float4(0.0f);
+ }
+
+ const Result &input = get_input("Image");
+ return sum_color(context(), input.texture()) / (input.domain().size.x * input.domain().size.y);
+ }
+
+ float compute_average_luminance()
+ {
+ /* The average luminance will reduce to zero if chromatic adaptation is one, so just return
+ * zero in this case to avoid needlessly computing the average. See the trilinear interpolation
+ * equations constructed from equations (6) and (7) in Reinhard's 2005 paper. */
+ if (get_chromatic_adaptation() == 1.0f) {
+ return 0.0f;
+ }
+
+ float luminance_coefficients[3];
+ IMB_colormanagement_get_luminance_coefficients(luminance_coefficients);
+ const Result &input = get_input("Image");
+ float sum = sum_luminance(context(), input.texture(), luminance_coefficients);
+ return sum / (input.domain().size.x * input.domain().size.y);
+ }
+
+ /* Computes equation (5) from Reinhard's 2005 paper. */
+ float compute_intensity()
+ {
+ return std::exp(-node_storage(bnode()).f);
+ }
+
+ /* If the contrast is not zero, return it, otherwise, a zero contrast denote automatic derivation
+ * of the contrast value based on equations (2) and (4) from Reinhard's 2005 paper. */
+ float compute_contrast()
+ {
+ if (node_storage(bnode()).m != 0.0f) {
+ return node_storage(bnode()).m;
+ }
+
+ const float log_maximum_luminance = compute_log_maximum_luminance();
+ const float log_minimum_luminance = compute_log_minimum_luminance();
+
+ /* This is merely to guard against zero division later. */
+ if (log_maximum_luminance == log_minimum_luminance) {
+ return 1.0f;
+ }
+
+ const float average_log_luminance = compute_average_log_luminance();
+ const float dynamic_range = log_maximum_luminance - log_minimum_luminance;
+ const float luminance_key = (log_maximum_luminance - average_log_luminance) / (dynamic_range);
+
+ return 0.3f + 0.7f * std::pow(luminance_key, 1.4f);
+ }
+
+ float compute_average_log_luminance()
+ {
+ const Result &input_image = get_input("Image");
+
+ float luminance_coefficients[3];
+ IMB_colormanagement_get_luminance_coefficients(luminance_coefficients);
+ const float sum_of_log_luminance = sum_log_luminance(
+ context(), input_image.texture(), luminance_coefficients);
+
+ return sum_of_log_luminance / (input_image.domain().size.x * input_image.domain().size.y);
+ }
+
+ float compute_log_maximum_luminance()
+ {
+ float luminance_coefficients[3];
+ IMB_colormanagement_get_luminance_coefficients(luminance_coefficients);
+ const float maximum = maximum_luminance(
+ context(), get_input("Image").texture(), luminance_coefficients);
+ return std::log(math::max(maximum, 1e-5f));
+ }
+
+ float compute_log_minimum_luminance()
+ {
+ float luminance_coefficients[3];
+ IMB_colormanagement_get_luminance_coefficients(luminance_coefficients);
+ const float minimum = minimum_luminance(
+ context(), get_input("Image").texture(), luminance_coefficients);
+ return std::log(math::max(minimum, 1e-5f));
+ }
+
+ float get_chromatic_adaptation()
+ {
+ return node_storage(bnode()).c;
+ }
+
+ float get_light_adaptation()
+ {
+ return node_storage(bnode()).a;
+ }
+
+ CMPNodeToneMapType get_type()
+ {
+ return static_cast<CMPNodeToneMapType>(node_storage(bnode()).type);
}
};
diff --git a/source/blender/nodes/geometry/nodes/node_geo_collection_info.cc b/source/blender/nodes/geometry/nodes/node_geo_collection_info.cc
index c4bee09e07b..df677e1c399 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_collection_info.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_collection_info.cc
@@ -8,6 +8,7 @@
#include "UI_resources.h"
#include "BKE_collection.h"
+#include "BKE_instances.hh"
#include "node_geometry_util.hh"
@@ -69,8 +70,7 @@ static void node_geo_exec(GeoNodeExecParams params)
const bool use_relative_transform = (storage.transform_space ==
GEO_NODE_TRANSFORM_SPACE_RELATIVE);
- GeometrySet geometry_set_out;
- InstancesComponent &instances = geometry_set_out.get_component_for_write<InstancesComponent>();
+ std::unique_ptr<bke::Instances> instances = std::make_unique<bke::Instances>();
const bool separate_children = params.get_input<bool>("Separate Children");
if (separate_children) {
@@ -84,7 +84,7 @@ static void node_geo_exec(GeoNodeExecParams params)
children_objects.append(collection_object->ob);
}
- instances.reserve(children_collections.size() + children_objects.size());
+ instances->reserve(children_collections.size() + children_objects.size());
Vector<InstanceListEntry> entries;
entries.reserve(children_collections.size() + children_objects.size());
@@ -99,11 +99,11 @@ static void node_geo_exec(GeoNodeExecParams params)
sub_v3_v3(transform.values[3], collection->instance_offset);
}
}
- const int handle = instances.add_reference(*child_collection);
+ const int handle = instances->add_reference(*child_collection);
entries.append({handle, &(child_collection->id.name[2]), transform});
}
for (Object *child_object : children_objects) {
- const int handle = instances.add_reference(*child_object);
+ const int handle = instances->add_reference(*child_object);
float4x4 transform = float4x4::identity();
if (!reset_children) {
if (use_relative_transform) {
@@ -123,7 +123,7 @@ static void node_geo_exec(GeoNodeExecParams params)
return BLI_strcasecmp_natural(a.name, b.name) < 0;
});
for (const InstanceListEntry &entry : entries) {
- instances.add_instance(entry.handle, entry.transform);
+ instances->add_instance(entry.handle, entry.transform);
}
}
else {
@@ -133,11 +133,11 @@ static void node_geo_exec(GeoNodeExecParams params)
mul_m4_m4_pre(transform.values, self_object->imat);
}
- const int handle = instances.add_reference(*collection);
- instances.add_instance(handle, transform);
+ const int handle = instances->add_reference(*collection);
+ instances->add_instance(handle, transform);
}
- params.set_output("Geometry", geometry_set_out);
+ params.set_output("Geometry", GeometrySet::create_with_instances(instances.release()));
}
} // namespace blender::nodes::node_geo_collection_info_cc
diff --git a/source/blender/nodes/geometry/nodes/node_geo_deform_curves_on_surface.cc b/source/blender/nodes/geometry/nodes/node_geo_deform_curves_on_surface.cc
index a12ae9bbb92..0932624bdc3 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_deform_curves_on_surface.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_deform_curves_on_surface.cc
@@ -379,19 +379,22 @@ static void node_geo_exec(GeoNodeExecParams params)
invalid_uv_count);
/* Then also deform edit curve information for use in sculpt mode. */
const CurvesGeometry &curves_orig = CurvesGeometry::wrap(edit_hints->curves_id_orig.geometry);
- deform_curves(curves_orig,
- *surface_mesh_orig,
- *surface_mesh_eval,
- surface_uv_coords,
- reverse_uv_sampler_orig,
- reverse_uv_sampler_eval,
- corner_normals_orig,
- corner_normals_eval,
- rest_positions,
- transforms.surface_to_curves,
- edit_hint_positions,
- edit_hint_rotations,
- invalid_uv_count);
+ const Span<float2> surface_uv_coords_orig = curves_orig.surface_uv_coords();
+ if (!surface_uv_coords_orig.is_empty()) {
+ deform_curves(curves_orig,
+ *surface_mesh_orig,
+ *surface_mesh_eval,
+ surface_uv_coords_orig,
+ reverse_uv_sampler_orig,
+ reverse_uv_sampler_eval,
+ corner_normals_orig,
+ corner_normals_eval,
+ rest_positions,
+ transforms.surface_to_curves,
+ edit_hint_positions,
+ edit_hint_rotations,
+ invalid_uv_count);
+ }
}
curves.tag_positions_changed();
diff --git a/source/blender/nodes/geometry/nodes/node_geo_delete_geometry.cc b/source/blender/nodes/geometry/nodes/node_geo_delete_geometry.cc
index 86c8cd64489..3e48a9fd923 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_delete_geometry.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_delete_geometry.cc
@@ -4,6 +4,7 @@
#include "UI_resources.h"
#include "BLI_array.hh"
+#include "BLI_array_utils.hh"
#include "DNA_mesh_types.h"
#include "DNA_meshdata_types.h"
@@ -12,6 +13,7 @@
#include "BKE_attribute_math.hh"
#include "BKE_curves.hh"
#include "BKE_customdata.h"
+#include "BKE_instances.hh"
#include "BKE_mesh.h"
#include "BKE_pointcloud.h"
@@ -22,15 +24,9 @@ namespace blender::nodes::node_geo_delete_geometry_cc {
using blender::bke::CustomDataAttributes;
template<typename T>
-static void copy_data_based_on_mask(Span<T> data, MutableSpan<T> r_data, IndexMask mask)
-{
- for (const int i_out : mask.index_range()) {
- r_data[i_out] = data[mask[i_out]];
- }
-}
-
-template<typename T>
-static void copy_data_based_on_map(Span<T> src, MutableSpan<T> dst, Span<int> index_map)
+static void copy_data_based_on_map(const Span<T> src,
+ const Span<int> index_map,
+ MutableSpan<T> dst)
{
for (const int i_src : index_map.index_range()) {
const int i_dst = index_map[i_src];
@@ -54,26 +50,17 @@ static void copy_attributes(const Map<AttributeIDRef, AttributeKind> &attributes
if (!attribute) {
continue;
}
-
/* Only copy if it is on a domain we want. */
if (!domains.contains(attribute.domain)) {
continue;
}
const eCustomDataType data_type = bke::cpp_type_to_custom_data_type(attribute.varray.type());
-
GSpanAttributeWriter result_attribute = dst_attributes.lookup_or_add_for_write_only_span(
attribute_id, attribute.domain, data_type);
-
if (!result_attribute) {
continue;
}
-
- attribute_math::convert_to_static_type(data_type, [&](auto dummy) {
- using T = decltype(dummy);
- VArraySpan<T> span{attribute.varray.typed<T>()};
- MutableSpan<T> out_span = result_attribute.span.typed<T>();
- out_span.copy_from(span);
- });
+ attribute.varray.materialize(result_attribute.span.data());
result_attribute.finish();
}
}
@@ -94,26 +81,19 @@ static void copy_attributes_based_on_mask(const Map<AttributeIDRef, AttributeKin
if (!attribute) {
continue;
}
-
/* Only copy if it is on a domain we want. */
if (domain != attribute.domain) {
continue;
}
const eCustomDataType data_type = bke::cpp_type_to_custom_data_type(attribute.varray.type());
-
GSpanAttributeWriter result_attribute = dst_attributes.lookup_or_add_for_write_only_span(
attribute_id, attribute.domain, data_type);
-
if (!result_attribute) {
continue;
}
- attribute_math::convert_to_static_type(data_type, [&](auto dummy) {
- using T = decltype(dummy);
- VArraySpan<T> span{attribute.varray.typed<T>()};
- MutableSpan<T> out_span = result_attribute.span.typed<T>();
- copy_data_based_on_mask(span, out_span, mask);
- });
+ array_utils::gather(attribute.varray, mask, result_attribute.span);
+
result_attribute.finish();
}
}
@@ -130,16 +110,13 @@ static void copy_attributes_based_on_map(const Map<AttributeIDRef, AttributeKind
if (!attribute) {
continue;
}
-
/* Only copy if it is on a domain we want. */
if (domain != attribute.domain) {
continue;
}
const eCustomDataType data_type = bke::cpp_type_to_custom_data_type(attribute.varray.type());
-
GSpanAttributeWriter result_attribute = dst_attributes.lookup_or_add_for_write_only_span(
attribute_id, attribute.domain, data_type);
-
if (!result_attribute) {
continue;
}
@@ -148,7 +125,7 @@ static void copy_attributes_based_on_map(const Map<AttributeIDRef, AttributeKind
using T = decltype(dummy);
VArraySpan<T> span{attribute.varray.typed<T>()};
MutableSpan<T> out_span = result_attribute.span.typed<T>();
- copy_data_based_on_map(span, out_span, index_map);
+ copy_data_based_on_map(span, index_map, out_span);
});
result_attribute.finish();
}
@@ -392,8 +369,8 @@ static void separate_point_cloud_selection(GeometrySet &geometry_set,
static void delete_selected_instances(GeometrySet &geometry_set,
const Field<bool> &selection_field)
{
- InstancesComponent &instances = geometry_set.get_component_for_write<InstancesComponent>();
- bke::GeometryFieldContext field_context{instances, ATTR_DOMAIN_INSTANCE};
+ bke::Instances &instances = *geometry_set.get_instances_for_write();
+ bke::InstancesFieldContext field_context{instances};
fn::FieldEvaluator evaluator{field_context, instances.instances_num()};
evaluator.set_selection(selection_field);
@@ -404,7 +381,7 @@ static void delete_selected_instances(GeometrySet &geometry_set,
return;
}
- instances.remove_instances(selection);
+ instances.remove(selection);
}
static void compute_selected_verts_from_vertex_selection(const Span<bool> vertex_selection,
diff --git a/source/blender/nodes/geometry/nodes/node_geo_distribute_points_in_volume.cc b/source/blender/nodes/geometry/nodes/node_geo_distribute_points_in_volume.cc
index 091337c28cf..95173bd23a5 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_distribute_points_in_volume.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_distribute_points_in_volume.cc
@@ -15,6 +15,8 @@
#include "UI_interface.h"
#include "UI_resources.h"
+#include "DEG_depsgraph_query.h"
+
#include "node_geometry_util.hh"
namespace blender::nodes {
@@ -208,6 +210,7 @@ static void geo_node_distribute_points_in_volume_exec(GeoNodeExecParams params)
}
const VolumeComponent *component = geometry_set.get_component_for_read<VolumeComponent>();
const Volume *volume = component->get_for_read();
+ BKE_volume_load(volume, DEG_get_bmain(params.depsgraph()));
Vector<float3> positions;
diff --git a/source/blender/nodes/geometry/nodes/node_geo_dual_mesh.cc b/source/blender/nodes/geometry/nodes/node_geo_dual_mesh.cc
index 84e63845b84..9b1c13bf563 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_dual_mesh.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_dual_mesh.cc
@@ -1,5 +1,6 @@
/* SPDX-License-Identifier: GPL-2.0-or-later */
+#include "BLI_array_utils.hh"
#include "BLI_task.hh"
#include "DNA_mesh_types.h"
@@ -105,18 +106,6 @@ static void copy_data_based_on_pairs(Span<T> data,
}
}
-/* Copy using the map. */
-template<typename T>
-static void copy_data_based_on_new_to_old_map(Span<T> data,
- MutableSpan<T> r_data,
- const Span<int> new_to_old_map)
-{
- for (const int i : r_data.index_range()) {
- const int old_i = new_to_old_map[i];
- r_data[i] = data[old_i];
- }
-}
-
/**
* Transfers the attributes from the original mesh to the new mesh using the following logic:
* - If the attribute was on the face domain it is now on the point domain, and this is true
@@ -168,7 +157,6 @@ static void transfer_attributes(
src_attribute.varray.type());
GSpanAttributeWriter dst_attribute = dst_attributes.lookup_or_add_for_write_only_span(
attribute_id, out_domain, data_type);
-
if (!dst_attribute) {
continue;
}
@@ -177,20 +165,24 @@ static void transfer_attributes(
using T = decltype(dummy);
VArraySpan<T> span{src_attribute.varray.typed<T>()};
MutableSpan<T> dst_span = dst_attribute.span.typed<T>();
- if (src_attribute.domain == ATTR_DOMAIN_FACE) {
- dst_span.take_front(span.size()).copy_from(span);
- if (keep_boundaries) {
- copy_data_based_on_pairs(span, dst_span, boundary_vertex_to_relevant_face_map);
- }
- }
- else if (src_attribute.domain == ATTR_DOMAIN_POINT) {
- copy_data_based_on_vertex_types(span, dst_span, vertex_types, keep_boundaries);
- }
- else if (src_attribute.domain == ATTR_DOMAIN_EDGE) {
- copy_data_based_on_new_to_old_map(span, dst_span, new_to_old_edges_map);
- }
- else {
- copy_data_based_on_new_to_old_map(span, dst_span, new_to_old_face_corners_map);
+ switch (src_attribute.domain) {
+ case ATTR_DOMAIN_POINT:
+ copy_data_based_on_vertex_types(span, dst_span, vertex_types, keep_boundaries);
+ break;
+ case ATTR_DOMAIN_EDGE:
+ array_utils::gather(span, new_to_old_edges_map, dst_span);
+ break;
+ case ATTR_DOMAIN_FACE:
+ dst_span.take_front(span.size()).copy_from(span);
+ if (keep_boundaries) {
+ copy_data_based_on_pairs(span, dst_span, boundary_vertex_to_relevant_face_map);
+ }
+ break;
+ case ATTR_DOMAIN_CORNER:
+ array_utils::gather(span, new_to_old_face_corners_map, dst_span);
+ break;
+ default:
+ BLI_assert_unreachable();
}
});
dst_attribute.finish();
diff --git a/source/blender/nodes/geometry/nodes/node_geo_duplicate_elements.cc b/source/blender/nodes/geometry/nodes/node_geo_duplicate_elements.cc
index 82d7e1d3652..486f900aca5 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_duplicate_elements.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_duplicate_elements.cc
@@ -1,5 +1,6 @@
/* SPDX-License-Identifier: GPL-2.0-or-later */
+#include "BLI_array_utils.hh"
#include "BLI_map.hh"
#include "BLI_noise.hh"
#include "BLI_span.hh"
@@ -11,6 +12,7 @@
#include "BKE_attribute_math.hh"
#include "BKE_curves.hh"
+#include "BKE_instances.hh"
#include "BKE_mesh.h"
#include "BKE_pointcloud.h"
@@ -104,16 +106,6 @@ static void threaded_slice_fill(Span<int> offsets,
});
}
-template<typename T>
-static void threaded_mapped_copy(const Span<int> mapping, const Span<T> src, MutableSpan<T> dst)
-{
- threading::parallel_for(mapping.index_range(), 512, [&](IndexRange range) {
- for (const int i : range) {
- dst[i] = src[mapping[i]];
- }
- });
-}
-
static void copy_hashed_ids(const Span<int> src, const int hash, MutableSpan<int> dst)
{
for (const int i : src.index_range()) {
@@ -439,17 +431,17 @@ static void copy_face_attributes_without_id(GeometrySet &geometry_set,
MutableSpan<T> dst = dst_attribute.span.typed<T>();
switch (out_domain) {
- case ATTR_DOMAIN_FACE:
- threaded_slice_fill<T>(offsets, selection, src, dst);
+ case ATTR_DOMAIN_POINT:
+ array_utils::gather(src, vert_mapping, dst);
break;
case ATTR_DOMAIN_EDGE:
- threaded_mapped_copy<T>(edge_mapping, src, dst);
+ array_utils::gather(src, edge_mapping, dst);
break;
- case ATTR_DOMAIN_POINT:
- threaded_mapped_copy<T>(vert_mapping, src, dst);
+ case ATTR_DOMAIN_FACE:
+ threaded_slice_fill<T>(offsets, selection, src, dst);
break;
case ATTR_DOMAIN_CORNER:
- threaded_mapped_copy<T>(loop_mapping, src, dst);
+ array_utils::gather(src, loop_mapping, dst);
break;
default:
break;
@@ -652,7 +644,7 @@ static void copy_edge_attributes_without_id(GeometrySet &geometry_set,
threaded_slice_fill<T>(offsets, selection, src, dst);
break;
case ATTR_DOMAIN_POINT:
- threaded_mapped_copy<T>(point_mapping, src, dst);
+ array_utils::gather(src, point_mapping, dst);
break;
default:
break;
@@ -1031,10 +1023,9 @@ static void duplicate_instances(GeometrySet &geometry_set,
return;
}
- const InstancesComponent &src_instances =
- *geometry_set.get_component_for_read<InstancesComponent>();
+ const bke::Instances &src_instances = *geometry_set.get_instances_for_read();
- bke::GeometryFieldContext field_context{src_instances, ATTR_DOMAIN_INSTANCE};
+ bke::InstancesFieldContext field_context{src_instances};
FieldEvaluator evaluator{field_context, src_instances.instances_num()};
evaluator.add(count_field);
evaluator.set_selection(selection_field);
@@ -1048,20 +1039,20 @@ static void duplicate_instances(GeometrySet &geometry_set,
return;
}
- GeometrySet dst_geometry;
- InstancesComponent &dst_instances = dst_geometry.get_component_for_write<InstancesComponent>();
- dst_instances.resize(offsets.last());
+ std::unique_ptr<bke::Instances> dst_instances = std::make_unique<bke::Instances>();
+
+ dst_instances->resize(offsets.last());
for (const int i_selection : selection.index_range()) {
const IndexRange range = range_for_offsets_index(offsets, i_selection);
if (range.size() == 0) {
continue;
}
- const int old_handle = src_instances.instance_reference_handles()[i_selection];
- const InstanceReference reference = src_instances.references()[old_handle];
- const int new_handle = dst_instances.add_reference(reference);
- const float4x4 transform = src_instances.instance_transforms()[i_selection];
- dst_instances.instance_transforms().slice(range).fill(transform);
- dst_instances.instance_reference_handles().slice(range).fill(new_handle);
+ const int old_handle = src_instances.reference_handles()[i_selection];
+ const bke::InstanceReference reference = src_instances.references()[old_handle];
+ const int new_handle = dst_instances->add_reference(reference);
+ const float4x4 transform = src_instances.transforms()[i_selection];
+ dst_instances->transforms().slice(range).fill(transform);
+ dst_instances->reference_handles().slice(range).fill(new_handle);
}
copy_attributes_without_id(geometry_set,
@@ -1069,18 +1060,18 @@ static void duplicate_instances(GeometrySet &geometry_set,
ATTR_DOMAIN_INSTANCE,
offsets,
selection,
- *src_instances.attributes(),
- *dst_instances.attributes_for_write());
+ src_instances.attributes(),
+ dst_instances->attributes_for_write());
if (attribute_outputs.duplicate_index) {
- create_duplicate_index_attribute(*dst_instances.attributes_for_write(),
+ create_duplicate_index_attribute(dst_instances->attributes_for_write(),
ATTR_DOMAIN_INSTANCE,
selection,
attribute_outputs,
offsets);
}
- geometry_set = std::move(dst_geometry);
+ geometry_set = GeometrySet::create_with_instances(dst_instances.release());
}
/** \} */
diff --git a/source/blender/nodes/geometry/nodes/node_geo_extrude_mesh.cc b/source/blender/nodes/geometry/nodes/node_geo_extrude_mesh.cc
index 1d8c9d6312c..151ba3e59cc 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_extrude_mesh.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_extrude_mesh.cc
@@ -1,5 +1,6 @@
/* SPDX-License-Identifier: GPL-2.0-or-later */
+#include "BLI_array_utils.hh"
#include "BLI_disjoint_set.hh"
#include "BLI_task.hh"
#include "BLI_vector_set.hh"
@@ -175,24 +176,6 @@ static MPoly new_poly(const int loopstart, const int totloop)
return poly;
}
-template<typename T> void copy_with_indices(MutableSpan<T> dst, Span<T> src, Span<int> indices)
-{
- BLI_assert(dst.size() == indices.size());
- for (const int i : dst.index_range()) {
- dst[i] = src[indices[i]];
- }
-}
-
-template<typename T> void copy_with_mask(MutableSpan<T> dst, Span<T> src, IndexMask mask)
-{
- BLI_assert(dst.size() == mask.size());
- threading::parallel_for(mask.index_range(), 512, [&](const IndexRange range) {
- for (const int i : range) {
- dst[i] = src[mask[i]];
- }
- });
-}
-
/**
* \param get_mix_indices_fn: Returns a Span of indices of the source points to mix for every
* result point.
@@ -260,28 +243,29 @@ static void extrude_mesh_vertices(Mesh &mesh,
if (!ELEM(meta_data.domain, ATTR_DOMAIN_POINT, ATTR_DOMAIN_EDGE)) {
return true;
}
+ if (meta_data.data_type == CD_PROP_STRING) {
+ return true;
+ }
GSpanAttributeWriter attribute = attributes.lookup_or_add_for_write_span(
id, meta_data.domain, meta_data.data_type);
- attribute_math::convert_to_static_type(meta_data.data_type, [&](auto dummy) {
- using T = decltype(dummy);
- MutableSpan<T> data = attribute.span.typed<T>();
- switch (attribute.domain) {
- case ATTR_DOMAIN_POINT: {
- /* New vertices copy the attribute values from their source vertex. */
- copy_with_mask(data.slice(new_vert_range), data.as_span(), selection);
- break;
- }
- case ATTR_DOMAIN_EDGE: {
+ switch (attribute.domain) {
+ case ATTR_DOMAIN_POINT:
+ /* New vertices copy the attribute values from their source vertex. */
+ array_utils::gather(attribute.span, selection, attribute.span.slice(new_vert_range));
+ break;
+ case ATTR_DOMAIN_EDGE:
+ attribute_math::convert_to_static_type(meta_data.data_type, [&](auto dummy) {
+ using T = decltype(dummy);
+ MutableSpan<T> data = attribute.span.typed<T>();
/* New edge values are mixed from of all the edges connected to the source vertex. */
copy_with_mixing(data.slice(new_edge_range), data.as_span(), [&](const int i) {
return vert_to_edge_map[selection[i]].as_span();
});
- break;
- }
- default:
- BLI_assert_unreachable();
- }
- });
+ });
+ break;
+ default:
+ BLI_assert_unreachable();
+ }
attribute.finish();
return true;
@@ -506,6 +490,9 @@ static void extrude_mesh_edges(Mesh &mesh,
MutableAttributeAccessor attributes = mesh.attributes_for_write();
attributes.for_all([&](const AttributeIDRef &id, const AttributeMetaData meta_data) {
+ if (meta_data.data_type == CD_PROP_STRING) {
+ return true;
+ }
GSpanAttributeWriter attribute = attributes.lookup_or_add_for_write_span(
id, meta_data.domain, meta_data.data_type);
if (!attribute) {
@@ -518,13 +505,14 @@ static void extrude_mesh_edges(Mesh &mesh,
switch (attribute.domain) {
case ATTR_DOMAIN_POINT: {
/* New vertices copy the attribute values from their source vertex. */
- copy_with_indices(data.slice(new_vert_range), data.as_span(), new_vert_indices);
+ array_utils::gather(
+ data.as_span(), new_vert_indices.as_span(), data.slice(new_vert_range));
break;
}
case ATTR_DOMAIN_EDGE: {
/* Edges parallel to original edges copy the edge attributes from the original edges. */
MutableSpan<T> duplicate_data = data.slice(duplicate_edge_range);
- copy_with_mask(duplicate_data, data.as_span(), edge_selection);
+ array_utils::gather(data.as_span(), edge_selection, duplicate_data);
/* Edges connected to original vertices mix values of selected connected edges. */
MutableSpan<T> connect_data = data.slice(connect_edge_range);
@@ -889,6 +877,9 @@ static void extrude_mesh_face_regions(Mesh &mesh,
MutableAttributeAccessor attributes = mesh.attributes_for_write();
attributes.for_all([&](const AttributeIDRef &id, const AttributeMetaData meta_data) {
+ if (meta_data.data_type == CD_PROP_STRING) {
+ return true;
+ }
GSpanAttributeWriter attribute = attributes.lookup_or_add_for_write_span(
id, meta_data.domain, meta_data.data_type);
if (!attribute) {
@@ -901,17 +892,18 @@ static void extrude_mesh_face_regions(Mesh &mesh,
switch (attribute.domain) {
case ATTR_DOMAIN_POINT: {
/* New vertices copy the attributes from their original vertices. */
- copy_with_indices(data.slice(new_vert_range), data.as_span(), new_vert_indices);
+ array_utils::gather(
+ data.as_span(), new_vert_indices.as_span(), data.slice(new_vert_range));
break;
}
case ATTR_DOMAIN_EDGE: {
/* Edges parallel to original edges copy the edge attributes from the original edges. */
MutableSpan<T> boundary_data = data.slice(boundary_edge_range);
- copy_with_indices(boundary_data, data.as_span(), boundary_edge_indices);
+ array_utils::gather(data.as_span(), boundary_edge_indices.as_span(), boundary_data);
/* Edges inside of face regions also just duplicate their source data. */
MutableSpan<T> new_inner_data = data.slice(new_inner_edge_range);
- copy_with_indices(new_inner_data, data.as_span(), new_inner_edge_indices);
+ array_utils::gather(data.as_span(), new_inner_edge_indices.as_span(), new_inner_data);
/* Edges connected to original vertices mix values of selected connected edges. */
MutableSpan<T> connect_data = data.slice(connect_edge_range);
@@ -923,8 +915,8 @@ static void extrude_mesh_face_regions(Mesh &mesh,
case ATTR_DOMAIN_FACE: {
/* New faces on the side of extrusions get the values from the corresponding selected
* face. */
- copy_with_indices(
- data.slice(side_poly_range), data.as_span(), edge_extruded_face_indices);
+ array_utils::gather(
+ data.as_span(), edge_extruded_face_indices.as_span(), data.slice(side_poly_range));
break;
}
case ATTR_DOMAIN_CORNER: {
@@ -1143,6 +1135,9 @@ static void extrude_individual_mesh_faces(Mesh &mesh,
MutableAttributeAccessor attributes = mesh.attributes_for_write();
attributes.for_all([&](const AttributeIDRef &id, const AttributeMetaData meta_data) {
+ if (meta_data.data_type == CD_PROP_STRING) {
+ return true;
+ }
GSpanAttributeWriter attribute = attributes.lookup_or_add_for_write_span(
id, meta_data.domain, meta_data.data_type);
if (!attribute) {
diff --git a/source/blender/nodes/geometry/nodes/node_geo_flip_faces.cc b/source/blender/nodes/geometry/nodes/node_geo_flip_faces.cc
index 613425716d4..95a0013a9e1 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_flip_faces.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_flip_faces.cc
@@ -47,6 +47,9 @@ static void mesh_flip_faces(Mesh &mesh, const Field<bool> &selection_field)
MutableAttributeAccessor attributes = mesh.attributes_for_write();
attributes.for_all(
[&](const bke::AttributeIDRef &attribute_id, const AttributeMetaData &meta_data) {
+ if (meta_data.data_type == CD_PROP_STRING) {
+ return true;
+ }
if (meta_data.domain == ATTR_DOMAIN_CORNER) {
GSpanAttributeWriter attribute = attributes.lookup_or_add_for_write_span(
attribute_id, ATTR_DOMAIN_CORNER, meta_data.data_type);
diff --git a/source/blender/nodes/geometry/nodes/node_geo_geometry_to_instance.cc b/source/blender/nodes/geometry/nodes/node_geo_geometry_to_instance.cc
index 8e64209a418..45808ff9996 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_geometry_to_instance.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_geometry_to_instance.cc
@@ -1,5 +1,7 @@
/* SPDX-License-Identifier: GPL-2.0-or-later */
+#include "BKE_instances.hh"
+
#include "node_geometry_util.hh"
namespace blender::nodes::node_geo_geometry_to_instance_cc {
@@ -13,15 +15,13 @@ static void node_declare(NodeDeclarationBuilder &b)
static void node_geo_exec(GeoNodeExecParams params)
{
Vector<GeometrySet> geometries = params.extract_input<Vector<GeometrySet>>("Geometry");
- GeometrySet instances_geometry;
- InstancesComponent &instances_component =
- instances_geometry.get_component_for_write<InstancesComponent>();
+ std::unique_ptr<bke::Instances> instances = std::make_unique<bke::Instances>();
for (GeometrySet &geometry : geometries) {
geometry.ensure_owns_direct_data();
- const int handle = instances_component.add_reference(std::move(geometry));
- instances_component.add_instance(handle, float4x4::identity());
+ const int handle = instances->add_reference(std::move(geometry));
+ instances->add_instance(handle, float4x4::identity());
}
- params.set_output("Instances", std::move(instances_geometry));
+ params.set_output("Instances", GeometrySet::create_with_instances(instances.release()));
}
} // namespace blender::nodes::node_geo_geometry_to_instance_cc
diff --git a/source/blender/nodes/geometry/nodes/node_geo_input_instance_rotation.cc b/source/blender/nodes/geometry/nodes/node_geo_input_instance_rotation.cc
index 75d43d2f771..f78815ebe74 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_input_instance_rotation.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_input_instance_rotation.cc
@@ -2,6 +2,8 @@
#include "node_geometry_util.hh"
+#include "BKE_instances.hh"
+
namespace blender::nodes::node_geo_input_instance_rotation_cc {
static void node_declare(NodeDeclarationBuilder &b)
@@ -15,12 +17,9 @@ class InstanceRotationFieldInput final : public bke::InstancesFieldInput {
{
}
- GVArray get_varray_for_context(const InstancesComponent &instances,
- const IndexMask /*mask*/) const final
+ GVArray get_varray_for_context(const bke::Instances &instances, IndexMask /*mask*/) const final
{
- auto rotation_fn = [&](const int i) -> float3 {
- return instances.instance_transforms()[i].to_euler();
- };
+ auto rotation_fn = [&](const int i) -> float3 { return instances.transforms()[i].to_euler(); };
return VArray<float3>::ForFunc(instances.instances_num(), rotation_fn);
}
diff --git a/source/blender/nodes/geometry/nodes/node_geo_input_instance_scale.cc b/source/blender/nodes/geometry/nodes/node_geo_input_instance_scale.cc
index dbb98d7e393..12ac48f8f11 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_input_instance_scale.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_input_instance_scale.cc
@@ -2,6 +2,8 @@
#include "node_geometry_util.hh"
+#include "BKE_instances.hh"
+
namespace blender::nodes::node_geo_input_instance_scale_cc {
static void node_declare(NodeDeclarationBuilder &b)
@@ -15,12 +17,9 @@ class InstanceScaleFieldInput final : public bke::InstancesFieldInput {
{
}
- GVArray get_varray_for_context(const InstancesComponent &instances,
- const IndexMask /*mask*/) const final
+ GVArray get_varray_for_context(const bke::Instances &instances, IndexMask /*mask*/) const final
{
- auto scale_fn = [&](const int i) -> float3 {
- return instances.instance_transforms()[i].scale();
- };
+ auto scale_fn = [&](const int i) -> float3 { return instances.transforms()[i].scale(); };
return VArray<float3>::ForFunc(instances.instances_num(), scale_fn);
}
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_instance_on_points.cc b/source/blender/nodes/geometry/nodes/node_geo_instance_on_points.cc
index c6f214e72ac..64546684186 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_instance_on_points.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_instance_on_points.cc
@@ -2,6 +2,7 @@
#include "DNA_collection_types.h"
+#include "BLI_array_utils.hh"
#include "BLI_hash.h"
#include "BLI_task.hh"
@@ -9,6 +10,7 @@
#include "UI_resources.h"
#include "BKE_attribute_math.hh"
+#include "BKE_instances.hh"
#include "node_geometry_util.hh"
@@ -43,7 +45,7 @@ static void node_declare(NodeDeclarationBuilder &b)
}
static void add_instances_from_component(
- InstancesComponent &dst_component,
+ bke::Instances &dst_component,
const GeometryComponent &src_component,
const GeometrySet &instance,
const GeoNodeExecParams &params,
@@ -80,25 +82,23 @@ static void add_instances_from_component(
const int select_len = selection.index_range().size();
dst_component.resize(start_len + select_len);
- MutableSpan<int> dst_handles = dst_component.instance_reference_handles().slice(start_len,
- select_len);
- MutableSpan<float4x4> dst_transforms = dst_component.instance_transforms().slice(start_len,
- select_len);
+ MutableSpan<int> dst_handles = dst_component.reference_handles().slice(start_len, select_len);
+ MutableSpan<float4x4> dst_transforms = dst_component.transforms().slice(start_len, select_len);
VArray<float3> positions = src_component.attributes()->lookup_or_default<float3>(
"position", domain, {0, 0, 0});
- const InstancesComponent *src_instances = instance.get_component_for_read<InstancesComponent>();
+ const bke::Instances *src_instances = instance.get_instances_for_read();
/* Maps handles from the source instances to handles on the new instance. */
Array<int> handle_mapping;
/* Only fill #handle_mapping when it may be used below. */
if (src_instances != nullptr &&
(!pick_instance.is_single() || pick_instance.get_internal_single())) {
- Span<InstanceReference> src_references = src_instances->references();
+ Span<bke::InstanceReference> src_references = src_instances->references();
handle_mapping.reinitialize(src_references.size());
for (const int src_instance_handle : src_references.index_range()) {
- const InstanceReference &reference = src_references[src_instance_handle];
+ const bke::InstanceReference &reference = src_references[src_instance_handle];
const int dst_instance_handle = dst_component.add_reference(reference);
handle_mapping[src_instance_handle] = dst_instance_handle;
}
@@ -106,7 +106,7 @@ static void add_instances_from_component(
const int full_instance_handle = dst_component.add_reference(instance);
/* Add this reference last, because it is the most likely one to be removed later on. */
- const int empty_reference_handle = dst_component.add_reference(InstanceReference());
+ const int empty_reference_handle = dst_component.add_reference(bke::InstanceReference());
threading::parallel_for(selection.index_range(), 1024, [&](IndexRange selection_range) {
for (const int range_i : selection_range) {
@@ -129,12 +129,11 @@ static void add_instances_from_component(
const int index = mod_i(original_index, std::max(src_instances_num, 1));
if (index < src_instances_num) {
/* Get the reference to the source instance. */
- const int src_handle = src_instances->instance_reference_handles()[index];
+ const int src_handle = src_instances->reference_handles()[index];
dst_handle = handle_mapping[src_handle];
/* Take transforms of the source instance into account. */
- mul_m4_m4_post(dst_transform.values,
- src_instances->instance_transforms()[index].values);
+ mul_m4_m4_post(dst_transform.values, src_instances->transforms()[index].values);
}
}
}
@@ -157,7 +156,7 @@ static void add_instances_from_component(
}
}
- bke::CustomDataAttributes &instance_attributes = dst_component.instance_attributes();
+ bke::CustomDataAttributes &instance_attributes = dst_component.custom_data_attributes();
for (const auto item : attributes_to_propagate.items()) {
const AttributeIDRef &attribute_id = item.key;
const AttributeKind attribute_kind = item.value;
@@ -174,18 +173,7 @@ static void add_instances_from_component(
dst_attribute_opt = instance_attributes.get_for_write(attribute_id);
}
BLI_assert(dst_attribute_opt);
- const GMutableSpan dst_attribute = dst_attribute_opt->slice(start_len, select_len);
- threading::parallel_for(selection.index_range(), 1024, [&](IndexRange selection_range) {
- attribute_math::convert_to_static_type(attribute_kind.data_type, [&](auto dummy) {
- using T = decltype(dummy);
- VArray<T> src = src_attribute.typed<T>();
- MutableSpan<T> dst = dst_attribute.typed<T>();
- for (const int range_i : selection_range) {
- const int i = selection[range_i];
- dst[range_i] = src[i];
- }
- });
- });
+ array_utils::gather(src_attribute, selection, dst_attribute_opt->slice(start_len, select_len));
}
}
@@ -196,7 +184,15 @@ static void node_geo_exec(GeoNodeExecParams params)
instance.ensure_owns_direct_data();
geometry_set.modify_geometry_sets([&](GeometrySet &geometry_set) {
- InstancesComponent &instances = geometry_set.get_component_for_write<InstancesComponent>();
+ /* It's important not to invalidate the existing #InstancesComponent because it owns references
+ * to other geometry sets that are processed by this node. */
+ InstancesComponent &instances_component =
+ geometry_set.get_component_for_write<InstancesComponent>();
+ bke::Instances *dst_instances = instances_component.get_for_write();
+ if (dst_instances == nullptr) {
+ dst_instances = new bke::Instances();
+ instances_component.replace(dst_instances);
+ }
const Array<GeometryComponentType> types{
GEO_COMPONENT_TYPE_MESH, GEO_COMPONENT_TYPE_POINT_CLOUD, GEO_COMPONENT_TYPE_CURVE};
@@ -208,14 +204,13 @@ static void node_geo_exec(GeoNodeExecParams params)
for (const GeometryComponentType type : types) {
if (geometry_set.has(type)) {
- add_instances_from_component(instances,
+ add_instances_from_component(*dst_instances,
*geometry_set.get_component_for_read(type),
instance,
params,
attributes_to_propagate);
}
}
-
geometry_set.remove_geometry_during_modify();
});
@@ -223,8 +218,9 @@ static void node_geo_exec(GeoNodeExecParams params)
* process them needlessly.
* This should eventually be moved into the loop above, but currently this is quite tricky
* because it might remove references that the loop still wants to iterate over. */
- InstancesComponent &instances = geometry_set.get_component_for_write<InstancesComponent>();
- instances.remove_unused_references();
+ if (bke::Instances *instances = geometry_set.get_instances_for_write()) {
+ instances->remove_unused_references();
+ }
params.set_output("Instances", std::move(geometry_set));
}
diff --git a/source/blender/nodes/geometry/nodes/node_geo_instances_to_points.cc b/source/blender/nodes/geometry/nodes/node_geo_instances_to_points.cc
index d4072a05e5f..acd00d119ab 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_instances_to_points.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_instances_to_points.cc
@@ -3,6 +3,7 @@
#include "DNA_pointcloud_types.h"
#include "BKE_attribute_math.hh"
+#include "BKE_instances.hh"
#include "BKE_pointcloud.h"
#include "node_geometry_util.hh"
@@ -27,7 +28,7 @@ static void convert_instances_to_points(GeometrySet &geometry_set,
Field<float> radius_field,
const Field<bool> selection_field)
{
- const InstancesComponent &instances = *geometry_set.get_component_for_read<InstancesComponent>();
+ const bke::Instances &instances = *geometry_set.get_instances_for_read();
const bke::InstancesFieldContext context{instances};
fn::FieldEvaluator evaluator{context, instances.instances_num()};
@@ -70,7 +71,7 @@ static void convert_instances_to_points(GeometrySet &geometry_set,
const AttributeIDRef &attribute_id = item.key;
const AttributeKind attribute_kind = item.value;
- const GVArray src = instances.attributes()->lookup_or_default(
+ const GVArray src = instances.attributes().lookup_or_default(
attribute_id, ATTR_DOMAIN_INSTANCE, attribute_kind.data_type);
BLI_assert(src);
GSpanAttributeWriter dst = point_attributes.lookup_or_add_for_write_only_span(
diff --git a/source/blender/nodes/geometry/nodes/node_geo_join_geometry.cc b/source/blender/nodes/geometry/nodes/node_geo_join_geometry.cc
index 74d1b5561bb..ea2646a9786 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_join_geometry.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_join_geometry.cc
@@ -2,6 +2,8 @@
#include "GEO_realize_instances.hh"
+#include "BKE_instances.hh"
+
#include "node_geometry_util.hh"
namespace blender::nodes::node_geo_join_geometry_cc {
@@ -29,6 +31,9 @@ static Map<AttributeIDRef, AttributeMetaData> get_final_attribute_info(
if (attribute_id.is_named() && ignored_attributes.contains(attribute_id.name())) {
return true;
}
+ if (meta_data.data_type == CD_PROP_STRING) {
+ return true;
+ }
info.add_or_modify(
attribute_id,
[&](AttributeMetaData *meta_data_final) { *meta_data_final = meta_data; },
@@ -97,31 +102,36 @@ static void join_attributes(Span<const GeometryComponent *> src_components,
static void join_components(Span<const InstancesComponent *> src_components, GeometrySet &result)
{
- InstancesComponent &dst_component = result.get_component_for_write<InstancesComponent>();
+ std::unique_ptr<bke::Instances> dst_instances = std::make_unique<bke::Instances>();
int tot_instances = 0;
for (const InstancesComponent *src_component : src_components) {
- tot_instances += src_component->instances_num();
+ tot_instances += src_component->get_for_read()->instances_num();
}
- dst_component.reserve(tot_instances);
+ dst_instances->reserve(tot_instances);
for (const InstancesComponent *src_component : src_components) {
- Span<InstanceReference> src_references = src_component->references();
+ const bke::Instances &src_instances = *src_component->get_for_read();
+
+ Span<bke::InstanceReference> src_references = src_instances.references();
Array<int> handle_map(src_references.size());
for (const int src_handle : src_references.index_range()) {
- handle_map[src_handle] = dst_component.add_reference(src_references[src_handle]);
+ handle_map[src_handle] = dst_instances->add_reference(src_references[src_handle]);
}
- Span<float4x4> src_transforms = src_component->instance_transforms();
- Span<int> src_reference_handles = src_component->instance_reference_handles();
+ Span<float4x4> src_transforms = src_instances.transforms();
+ Span<int> src_reference_handles = src_instances.reference_handles();
for (const int i : src_transforms.index_range()) {
const int src_handle = src_reference_handles[i];
const int dst_handle = handle_map[src_handle];
const float4x4 &transform = src_transforms[i];
- dst_component.add_instance(dst_handle, transform);
+ dst_instances->add_instance(dst_handle, transform);
}
}
+
+ result.replace_instances(dst_instances.release());
+ InstancesComponent &dst_component = result.get_component_for_write<InstancesComponent>();
join_attributes(to_base_components(src_components), dst_component, {"position"});
}
@@ -151,25 +161,23 @@ static void join_component_type(Span<GeometrySet> src_geometry_sets, GeometrySet
return;
}
- GeometrySet instances_geometry_set;
- InstancesComponent &instances =
- instances_geometry_set.get_component_for_write<InstancesComponent>();
-
if constexpr (is_same_any_v<Component, InstancesComponent, VolumeComponent>) {
join_components(components, result);
}
else {
+ std::unique_ptr<bke::Instances> instances = std::make_unique<bke::Instances>();
for (const Component *component : components) {
GeometrySet tmp_geo;
tmp_geo.add(*component);
- const int handle = instances.add_reference(InstanceReference{tmp_geo});
- instances.add_instance(handle, float4x4::identity());
+ const int handle = instances->add_reference(bke::InstanceReference{tmp_geo});
+ instances->add_instance(handle, float4x4::identity());
}
geometry::RealizeInstancesOptions options;
options.keep_original_ids = true;
options.realize_instance_attributes = false;
- GeometrySet joined_components = geometry::realize_instances(instances_geometry_set, options);
+ GeometrySet joined_components = geometry::realize_instances(
+ GeometrySet::create_with_instances(instances.release()), options);
result.add(joined_components.get_component_for_write<Component>());
}
}
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..036af2d3b93 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};
@@ -93,6 +93,10 @@ class CornersOfVertInput final : public bke::MeshFieldInput {
}
const Span<int> corners = vert_to_loop_map[vert_i];
+ if (corners.is_empty()) {
+ corner_of_vertex[selection_i] = 0;
+ continue;
+ }
/* Retrieve the connected edge indices as 64 bit integers for #materialize_compressed. */
corner_indices.reinitialize(corners.size());
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..f0cc191e217 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};
@@ -93,6 +93,10 @@ class EdgesOfVertInput final : public bke::MeshFieldInput {
}
const Span<int> edges = vert_to_edge_map[vert_i];
+ if (edges.is_empty()) {
+ edge_of_vertex[selection_i] = 0;
+ continue;
+ }
/* Retrieve the connected edge indices as 64 bit integers for #materialize_compressed. */
edge_indices.reinitialize(edges.size());
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/geometry/nodes/node_geo_object_info.cc b/source/blender/nodes/geometry/nodes/node_geo_object_info.cc
index 3ce16fac464..bf064c6fcbe 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_object_info.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_object_info.cc
@@ -3,6 +3,7 @@
#include "BLI_math_matrix.h"
#include "BKE_geometry_set_instances.hh"
+#include "BKE_instances.hh"
#include "UI_interface.h"
#include "UI_resources.h"
@@ -68,14 +69,15 @@ static void node_geo_exec(GeoNodeExecParams params)
GeometrySet geometry_set;
if (params.get_input<bool>("As Instance")) {
- InstancesComponent &instances = geometry_set.get_component_for_write<InstancesComponent>();
- const int handle = instances.add_reference(*object);
+ std::unique_ptr<bke::Instances> instances = std::make_unique<bke::Instances>();
+ const int handle = instances->add_reference(*object);
if (transform_space_relative) {
- instances.add_instance(handle, transform);
+ instances->add_instance(handle, transform);
}
else {
- instances.add_instance(handle, float4x4::identity());
+ instances->add_instance(handle, float4x4::identity());
}
+ geometry_set = GeometrySet::create_with_instances(instances.release());
}
else {
geometry_set = bke::object_get_evaluated_geometry_set(*object);
diff --git a/source/blender/nodes/geometry/nodes/node_geo_rotate_instances.cc b/source/blender/nodes/geometry/nodes/node_geo_rotate_instances.cc
index 4ed94e67e74..fac92a7500c 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_rotate_instances.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_rotate_instances.cc
@@ -2,6 +2,8 @@
#include "BLI_task.hh"
+#include "BKE_instances.hh"
+
#include "node_geometry_util.hh"
namespace blender::nodes::node_geo_rotate_instances_cc {
@@ -16,10 +18,10 @@ static void node_declare(NodeDeclarationBuilder &b)
b.add_output<decl::Geometry>(N_("Instances"));
}
-static void rotate_instances(GeoNodeExecParams &params, InstancesComponent &instances_component)
+static void rotate_instances(GeoNodeExecParams &params, bke::Instances &instances)
{
- const bke::InstancesFieldContext context{instances_component};
- fn::FieldEvaluator evaluator{context, instances_component.instances_num()};
+ const bke::InstancesFieldContext context{instances};
+ fn::FieldEvaluator evaluator{context, instances.instances_num()};
evaluator.set_selection(params.extract_input<Field<bool>>("Selection"));
evaluator.add(params.extract_input<Field<float3>>("Rotation"));
evaluator.add(params.extract_input<Field<float3>>("Pivot Point"));
@@ -31,14 +33,14 @@ static void rotate_instances(GeoNodeExecParams &params, InstancesComponent &inst
const VArray<float3> pivots = evaluator.get_evaluated<float3>(1);
const VArray<bool> local_spaces = evaluator.get_evaluated<bool>(2);
- MutableSpan<float4x4> instance_transforms = instances_component.instance_transforms();
+ MutableSpan<float4x4> transforms = instances.transforms();
threading::parallel_for(selection.index_range(), 512, [&](IndexRange range) {
for (const int i_selection : range) {
const int i = selection[i_selection];
const float3 pivot = pivots[i];
const float3 euler = rotations[i];
- float4x4 &instance_transform = instance_transforms[i];
+ float4x4 &instance_transform = transforms[i];
float4x4 rotation_matrix;
float3 used_pivot;
@@ -81,9 +83,8 @@ static void rotate_instances(GeoNodeExecParams &params, InstancesComponent &inst
static void node_geo_exec(GeoNodeExecParams params)
{
GeometrySet geometry_set = params.extract_input<GeometrySet>("Instances");
- if (geometry_set.has_instances()) {
- InstancesComponent &instances = geometry_set.get_component_for_write<InstancesComponent>();
- rotate_instances(params, instances);
+ if (bke::Instances *instances = geometry_set.get_instances_for_write()) {
+ rotate_instances(params, *instances);
}
params.set_output("Instances", std::move(geometry_set));
}
diff --git a/source/blender/nodes/geometry/nodes/node_geo_sample_nearest_surface.cc b/source/blender/nodes/geometry/nodes/node_geo_sample_nearest_surface.cc
index 44851a0ade5..95bf7199d63 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_sample_nearest_surface.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_sample_nearest_surface.cc
@@ -240,7 +240,11 @@ static void node_geo_exec(GeoNodeExecParams params)
params.set_default_remaining_outputs();
return;
}
- if (mesh->totpoly == 0 && mesh->totvert != 0) {
+ if (mesh->totvert == 0) {
+ params.set_default_remaining_outputs();
+ return;
+ }
+ if (mesh->totpoly == 0) {
params.error_message_add(NodeWarningType::Error, TIP_("The source mesh must have faces"));
params.set_default_remaining_outputs();
return;
diff --git a/source/blender/nodes/geometry/nodes/node_geo_scale_instances.cc b/source/blender/nodes/geometry/nodes/node_geo_scale_instances.cc
index 21fe724e194..dacb130337f 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_scale_instances.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_scale_instances.cc
@@ -2,6 +2,8 @@
#include "BLI_task.hh"
+#include "BKE_instances.hh"
+
#include "node_geometry_util.hh"
namespace blender::nodes::node_geo_scale_instances_cc {
@@ -19,10 +21,10 @@ static void node_declare(NodeDeclarationBuilder &b)
b.add_output<decl::Geometry>(N_("Instances"));
}
-static void scale_instances(GeoNodeExecParams &params, InstancesComponent &instances_component)
+static void scale_instances(GeoNodeExecParams &params, bke::Instances &instances)
{
- const bke::InstancesFieldContext context{instances_component};
- fn::FieldEvaluator evaluator{context, instances_component.instances_num()};
+ const bke::InstancesFieldContext context{instances};
+ fn::FieldEvaluator evaluator{context, instances.instances_num()};
evaluator.set_selection(params.extract_input<Field<bool>>("Selection"));
evaluator.add(params.extract_input<Field<float3>>("Scale"));
evaluator.add(params.extract_input<Field<float3>>("Center"));
@@ -34,13 +36,13 @@ static void scale_instances(GeoNodeExecParams &params, InstancesComponent &insta
const VArray<float3> pivots = evaluator.get_evaluated<float3>(1);
const VArray<bool> local_spaces = evaluator.get_evaluated<bool>(2);
- MutableSpan<float4x4> instance_transforms = instances_component.instance_transforms();
+ MutableSpan<float4x4> transforms = instances.transforms();
threading::parallel_for(selection.index_range(), 512, [&](IndexRange range) {
for (const int i_selection : range) {
const int i = selection[i_selection];
const float3 pivot = pivots[i];
- float4x4 &instance_transform = instance_transforms[i];
+ float4x4 &instance_transform = transforms[i];
if (local_spaces[i]) {
instance_transform *= float4x4::from_location(pivot);
@@ -61,9 +63,8 @@ static void scale_instances(GeoNodeExecParams &params, InstancesComponent &insta
static void node_geo_exec(GeoNodeExecParams params)
{
GeometrySet geometry_set = params.extract_input<GeometrySet>("Instances");
- if (geometry_set.has_instances()) {
- InstancesComponent &instances = geometry_set.get_component_for_write<InstancesComponent>();
- scale_instances(params, instances);
+ if (bke::Instances *instances = geometry_set.get_instances_for_write()) {
+ scale_instances(params, *instances);
}
params.set_output("Instances", std::move(geometry_set));
}
diff --git a/source/blender/nodes/geometry/nodes/node_geo_string_to_curves.cc b/source/blender/nodes/geometry/nodes/node_geo_string_to_curves.cc
index bbdabc09099..769a63f58cf 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_string_to_curves.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_string_to_curves.cc
@@ -6,6 +6,7 @@
#include "BKE_curve.h"
#include "BKE_curve_legacy_convert.hh"
#include "BKE_curves.hh"
+#include "BKE_instances.hh"
#include "BKE_vfont.h"
#include "BLI_hash.h"
@@ -270,7 +271,7 @@ static std::optional<TextLayout> get_text_layout(GeoNodeExecParams &params)
/* Returns a mapping of UTF-32 character code to instance handle. */
static Map<int, int> create_curve_instances(GeoNodeExecParams &params,
TextLayout &layout,
- InstancesComponent &instances)
+ bke::Instances &instances)
{
VFont *vfont = reinterpret_cast<VFont *>(params.node().id);
Map<int, int> handles;
@@ -315,13 +316,13 @@ static Map<int, int> create_curve_instances(GeoNodeExecParams &params,
return handles;
}
-static void add_instances_from_handles(InstancesComponent &instances,
+static void add_instances_from_handles(bke::Instances &instances,
const Map<int, int> &char_handles,
const TextLayout &layout)
{
instances.resize(layout.positions.size());
- MutableSpan<int> handles = instances.instance_reference_handles();
- MutableSpan<float4x4> transforms = instances.instance_transforms();
+ MutableSpan<int> handles = instances.reference_handles();
+ MutableSpan<float4x4> transforms = instances.transforms();
threading::parallel_for(IndexRange(layout.positions.size()), 256, [&](IndexRange range) {
for (const int i : range) {
@@ -333,9 +334,9 @@ static void add_instances_from_handles(InstancesComponent &instances,
static void create_attributes(GeoNodeExecParams &params,
const TextLayout &layout,
- InstancesComponent &instances)
+ bke::Instances &instances)
{
- MutableAttributeAccessor attributes = *instances.attributes_for_write();
+ MutableAttributeAccessor attributes = instances.attributes_for_write();
if (params.output_is_required("Line")) {
StrongAnonymousAttributeID line_id = StrongAnonymousAttributeID("Line");
@@ -385,13 +386,12 @@ static void node_geo_exec(GeoNodeExecParams params)
}
/* Create and add instances. */
- GeometrySet geometry_set_out;
- InstancesComponent &instances = geometry_set_out.get_component_for_write<InstancesComponent>();
- Map<int, int> char_handles = create_curve_instances(params, *layout, instances);
- add_instances_from_handles(instances, char_handles, *layout);
- create_attributes(params, *layout, instances);
+ std::unique_ptr<bke::Instances> instances = std::make_unique<bke::Instances>();
+ Map<int, int> char_handles = create_curve_instances(params, *layout, *instances);
+ add_instances_from_handles(*instances, char_handles, *layout);
+ create_attributes(params, *layout, *instances);
- params.set_output("Curve Instances", std::move(geometry_set_out));
+ params.set_output("Curve Instances", GeometrySet::create_with_instances(instances.release()));
}
} // namespace blender::nodes::node_geo_string_to_curves_cc
diff --git a/source/blender/nodes/geometry/nodes/node_geo_transform.cc b/source/blender/nodes/geometry/nodes/node_geo_transform.cc
index 4130cad3bda..3c8a3f3ca76 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_transform.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_transform.cc
@@ -11,6 +11,7 @@
#include "DNA_volume_types.h"
#include "BKE_curves.hh"
+#include "BKE_instances.hh"
#include "BKE_mesh.h"
#include "BKE_pointcloud.h"
#include "BKE_volume.h"
@@ -67,18 +68,18 @@ static void transform_pointcloud(PointCloud &pointcloud, const float4x4 &transfo
position.finish();
}
-static void translate_instances(InstancesComponent &instances, const float3 translation)
+static void translate_instances(bke::Instances &instances, const float3 translation)
{
- MutableSpan<float4x4> transforms = instances.instance_transforms();
+ MutableSpan<float4x4> transforms = instances.transforms();
for (float4x4 &transform : transforms) {
add_v3_v3(transform.ptr()[3], translation);
}
}
-static void transform_instances(InstancesComponent &instances, const float4x4 &transform)
+static void transform_instances(bke::Instances &instances, const float4x4 &transform)
{
- MutableSpan<float4x4> instance_transforms = instances.instance_transforms();
- for (float4x4 &instance_transform : instance_transforms) {
+ MutableSpan<float4x4> transforms = instances.transforms();
+ for (float4x4 &instance_transform : transforms) {
instance_transform = transform * instance_transform;
}
}
@@ -185,8 +186,8 @@ static void translate_geometry_set(GeoNodeExecParams &params,
if (Volume *volume = geometry.get_volume_for_write()) {
translate_volume(params, *volume, translation, depsgraph);
}
- if (geometry.has_instances()) {
- translate_instances(geometry.get_component_for_write<InstancesComponent>(), translation);
+ if (bke::Instances *instances = geometry.get_instances_for_write()) {
+ translate_instances(*instances, translation);
}
if (bke::CurvesEditHints *curve_edit_hints = geometry.get_curve_edit_hints_for_write()) {
translate_curve_edit_hints(*curve_edit_hints, translation);
@@ -210,8 +211,8 @@ void transform_geometry_set(GeoNodeExecParams &params,
if (Volume *volume = geometry.get_volume_for_write()) {
transform_volume(params, *volume, transform, depsgraph);
}
- if (geometry.has_instances()) {
- transform_instances(geometry.get_component_for_write<InstancesComponent>(), transform);
+ if (bke::Instances *instances = geometry.get_instances_for_write()) {
+ transform_instances(*instances, transform);
}
if (bke::CurvesEditHints *curve_edit_hints = geometry.get_curve_edit_hints_for_write()) {
transform_curve_edit_hints(*curve_edit_hints, transform);
diff --git a/source/blender/nodes/geometry/nodes/node_geo_translate_instances.cc b/source/blender/nodes/geometry/nodes/node_geo_translate_instances.cc
index 3e9fe99adb0..23052abddc4 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_translate_instances.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_translate_instances.cc
@@ -2,6 +2,8 @@
#include "BLI_task.hh"
+#include "BKE_instances.hh"
+
#include "node_geometry_util.hh"
namespace blender::nodes::node_geo_translate_instances_cc {
@@ -15,10 +17,10 @@ static void node_declare(NodeDeclarationBuilder &b)
b.add_output<decl::Geometry>(N_("Instances"));
}
-static void translate_instances(GeoNodeExecParams &params, InstancesComponent &instances_component)
+static void translate_instances(GeoNodeExecParams &params, bke::Instances &instances)
{
- const bke::InstancesFieldContext context{instances_component};
- fn::FieldEvaluator evaluator{context, instances_component.instances_num()};
+ const bke::InstancesFieldContext context{instances};
+ fn::FieldEvaluator evaluator{context, instances.instances_num()};
evaluator.set_selection(params.extract_input<Field<bool>>("Selection"));
evaluator.add(params.extract_input<Field<float3>>("Translation"));
evaluator.add(params.extract_input<Field<bool>>("Local Space"));
@@ -28,16 +30,16 @@ static void translate_instances(GeoNodeExecParams &params, InstancesComponent &i
const VArray<float3> translations = evaluator.get_evaluated<float3>(0);
const VArray<bool> local_spaces = evaluator.get_evaluated<bool>(1);
- MutableSpan<float4x4> instance_transforms = instances_component.instance_transforms();
+ MutableSpan<float4x4> transforms = instances.transforms();
threading::parallel_for(selection.index_range(), 1024, [&](IndexRange range) {
for (const int i_selection : range) {
const int i = selection[i_selection];
if (local_spaces[i]) {
- instance_transforms[i] *= float4x4::from_location(translations[i]);
+ transforms[i] *= float4x4::from_location(translations[i]);
}
else {
- add_v3_v3(instance_transforms[i].values[3], translations[i]);
+ add_v3_v3(transforms[i].values[3], translations[i]);
}
}
});
@@ -46,9 +48,8 @@ static void translate_instances(GeoNodeExecParams &params, InstancesComponent &i
static void node_geo_exec(GeoNodeExecParams params)
{
GeometrySet geometry_set = params.extract_input<GeometrySet>("Instances");
- if (geometry_set.has_instances()) {
- InstancesComponent &instances = geometry_set.get_component_for_write<InstancesComponent>();
- translate_instances(params, instances);
+ if (bke::Instances *instances = geometry_set.get_instances_for_write()) {
+ translate_instances(params, *instances);
}
params.set_output("Instances", std::move(geometry_set));
}
diff --git a/source/blender/nodes/intern/geometry_nodes_lazy_function.cc b/source/blender/nodes/intern/geometry_nodes_lazy_function.cc
index 6475a16477a..197f0997160 100644
--- a/source/blender/nodes/intern/geometry_nodes_lazy_function.cc
+++ b/source/blender/nodes/intern/geometry_nodes_lazy_function.cc
@@ -158,8 +158,9 @@ class LazyFunctionForMultiInput : public LazyFunction {
base_type_ = get_socket_cpp_type(socket);
BLI_assert(base_type_ != nullptr);
BLI_assert(socket.is_multi_input());
+ const bNodeTree &btree = socket.owner_tree();
for (const bNodeLink *link : socket.directly_linked_links()) {
- if (!link->is_muted()) {
+ if (!(link->is_muted() || nodeIsDanglingReroute(&btree, link->fromnode))) {
inputs_.append({"Input", *base_type_});
}
}
@@ -603,6 +604,7 @@ class LazyFunctionForGroupNode : public LazyFunction {
private:
const bNode &group_node_;
bool has_many_nodes_ = false;
+ bool use_fallback_outputs_ = false;
std::optional<GeometryNodesLazyFunctionLogger> lf_logger_;
std::optional<GeometryNodesLazyFunctionSideEffectProvider> lf_side_effect_provider_;
std::optional<lf::GraphExecutor> graph_executor_;
@@ -639,6 +641,9 @@ class LazyFunctionForGroupNode : public LazyFunction {
}
}
}
+ else {
+ use_fallback_outputs_ = true;
+ }
lf_logger_.emplace(lf_graph_info);
lf_side_effect_provider_.emplace();
@@ -659,6 +664,11 @@ class LazyFunctionForGroupNode : public LazyFunction {
* if every individual node is very small. */
lazy_threading::send_hint();
}
+ if (use_fallback_outputs_) {
+ /* The node group itself does not have an output node, so use default values as outputs.
+ * The group should still be executed in case it has side effects. */
+ params.set_default_remaining_outputs();
+ }
/* The compute context changes when entering a node group. */
bke::NodeGroupComputeContext compute_context{user_data->compute_context, group_node_.name};
@@ -1073,9 +1083,7 @@ struct GeometryNodesLazyFunctionGraphBuilder {
void insert_links_from_socket(const bNodeSocket &from_bsocket, lf::OutputSocket &from_lf_socket)
{
- const bNode &from_bnode = from_bsocket.owner_node();
- if (this->is_dangling_reroute_input(from_bnode)) {
- /* Dangling reroutes should not be used as source of values. */
+ if (nodeIsDanglingReroute(&btree_, &from_bsocket.owner_node())) {
return;
}
@@ -1145,7 +1153,8 @@ struct GeometryNodesLazyFunctionGraphBuilder {
if (multi_input_link == link) {
break;
}
- if (!multi_input_link->is_muted()) {
+ if (!(multi_input_link->is_muted() ||
+ nodeIsDanglingReroute(&btree_, multi_input_link->fromnode))) {
link_index++;
}
}
@@ -1174,33 +1183,6 @@ struct GeometryNodesLazyFunctionGraphBuilder {
}
}
- bool is_dangling_reroute_input(const bNode &node)
- {
- if (!node.is_reroute()) {
- return false;
- }
- const bNode *iter_node = &node;
- /* It is guaranteed at a higher level that there are no link cycles. */
- while (true) {
- const Span<const bNodeLink *> links = iter_node->input_socket(0).directly_linked_links();
- BLI_assert(links.size() <= 1);
- if (links.is_empty()) {
- return true;
- }
- const bNodeLink &link = *links[0];
- if (!link.is_available()) {
- return false;
- }
- if (link.is_muted()) {
- return false;
- }
- iter_node = link.fromnode;
- if (!iter_node->is_reroute()) {
- return false;
- }
- }
- }
-
lf::OutputSocket *insert_type_conversion_if_necessary(
lf::OutputSocket &from_socket,
const CPPType &to_type,
diff --git a/source/blender/nodes/intern/geometry_nodes_log.cc b/source/blender/nodes/intern/geometry_nodes_log.cc
index 167bfef0f83..0f122307328 100644
--- a/source/blender/nodes/intern/geometry_nodes_log.cc
+++ b/source/blender/nodes/intern/geometry_nodes_log.cc
@@ -101,7 +101,7 @@ GeometryInfoLog::GeometryInfoLog(const GeometrySet &geometry_set)
case GEO_COMPONENT_TYPE_INSTANCES: {
const InstancesComponent &instances_component = *(const InstancesComponent *)component;
InstancesInfo &info = this->instances_info.emplace();
- info.instances_num = instances_component.instances_num();
+ info.instances_num = instances_component.attribute_domain_size(ATTR_DOMAIN_INSTANCE);
break;
}
case GEO_COMPONENT_TYPE_EDIT: {
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_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/CMakeLists.txt b/source/blender/nodes/texture/CMakeLists.txt
index 77db71d4b1a..2d704ac2228 100644
--- a/source/blender/nodes/texture/CMakeLists.txt
+++ b/source/blender/nodes/texture/CMakeLists.txt
@@ -2,7 +2,7 @@
set(INC
.
- ../
+ ..
../intern
../../editors/include
../../blenkernel
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/gpu/gpu_py_platform.c b/source/blender/python/gpu/gpu_py_platform.c
index b877e3ceb98..51366d199b0 100644
--- a/source/blender/python/gpu/gpu_py_platform.c
+++ b/source/blender/python/gpu/gpu_py_platform.c
@@ -11,6 +11,7 @@
#include "BLI_utildefines.h"
+#include "GPU_context.h"
#include "GPU_platform.h"
#include "gpu_py_platform.h" /* Own include. */
@@ -83,6 +84,28 @@ static PyObject *pygpu_platform_device_type_get(PyObject *UNUSED(self))
return PyUnicode_FromString("UNKNOWN");
}
+PyDoc_STRVAR(pygpu_platform_backend_type_get_doc,
+ ".. function:: backend_type_get()\n"
+ "\n"
+ " Get actuve GPU backend.\n"
+ "\n"
+ " :return: Backend type ('OPENGL', 'METAL', 'NONE', 'UNKNOWN').\n"
+ " :rtype: str\n");
+static PyObject *pygpu_platform_backend_type_get(PyObject *UNUSED(self))
+{
+ switch (GPU_backend_get_type()) {
+ case GPU_BACKEND_METAL:
+ return PyUnicode_FromString("METAL");
+ case GPU_BACKEND_NONE:
+ return PyUnicode_FromString("NONE");
+ case GPU_BACKEND_OPENGL:
+ return PyUnicode_FromString("OPENGL");
+ case GPU_BACKEND_ANY:
+ break;
+ }
+ return PyUnicode_FromString("UNKNOWN");
+}
+
/** \} */
/* -------------------------------------------------------------------- */
@@ -106,6 +129,10 @@ static struct PyMethodDef pygpu_platform__tp_methods[] = {
(PyCFunction)pygpu_platform_device_type_get,
METH_NOARGS,
pygpu_platform_device_type_get_doc},
+ {"backend_type_get",
+ (PyCFunction)pygpu_platform_backend_type_get,
+ METH_NOARGS,
+ pygpu_platform_backend_type_get_doc},
{NULL, NULL, 0, NULL},
};
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/engine.cc b/source/blender/render/intern/engine.cc
index 5eb4db6faa4..b8757d33580 100644
--- a/source/blender/render/intern/engine.cc
+++ b/source/blender/render/intern/engine.cc
@@ -969,6 +969,40 @@ static void engine_render_view_layer(Render *re,
engine_depsgraph_exit(engine);
}
+/* Callback function for engine_render_create_result to add all render passes to the result. */
+static void engine_render_add_result_pass_cb(void *user_data,
+ struct Scene *UNUSED(scene),
+ struct ViewLayer *view_layer,
+ const char *name,
+ int channels,
+ const char *chanid,
+ eNodeSocketDatatype UNUSED(type))
+{
+ RenderResult *rr = (RenderResult *)user_data;
+ RE_create_render_pass(rr, name, channels, chanid, view_layer->name, RR_ALL_VIEWS, false);
+}
+
+static RenderResult *engine_render_create_result(Render *re)
+{
+ RenderResult *rr = render_result_new(re, &re->disprect, RR_ALL_LAYERS, RR_ALL_VIEWS);
+ if (rr == nullptr) {
+ return nullptr;
+ }
+
+ FOREACH_VIEW_LAYER_TO_RENDER_BEGIN (re, view_layer) {
+ RE_engine_update_render_passes(
+ re->engine, re->scene, view_layer, engine_render_add_result_pass_cb, rr);
+ }
+ FOREACH_VIEW_LAYER_TO_RENDER_END;
+
+ /* Preview does not support deferred render result allocation. */
+ if (re->r.scemode & R_BUTS_PREVIEW) {
+ render_result_passes_allocated_ensure(rr);
+ }
+
+ return rr;
+}
+
bool RE_engine_render(Render *re, bool do_all)
{
RenderEngineType *type = RE_engines_find(re->r.engine);
@@ -1008,6 +1042,14 @@ bool RE_engine_render(Render *re, bool do_all)
render_update_anim_renderdata(re, &re->scene->r, &re->scene->view_layers);
}
+ /* Create engine. */
+ RenderEngine *engine = re->engine;
+
+ if (!engine) {
+ engine = RE_engine_create(type);
+ re->engine = engine;
+ }
+
/* create render result */
BLI_rw_mutex_lock(&re->resultmutex, THREAD_LOCK_WRITE);
if (re->result == nullptr || !(re->r.scemode & R_BUTS_PREVIEW)) {
@@ -1015,7 +1057,7 @@ bool RE_engine_render(Render *re, bool do_all)
render_result_free(re->result);
}
- re->result = render_result_new(re, &re->disprect, RR_ALL_LAYERS, RR_ALL_VIEWS);
+ re->result = engine_render_create_result(re);
}
BLI_rw_mutex_unlock(&re->resultmutex);
@@ -1024,6 +1066,9 @@ bool RE_engine_render(Render *re, bool do_all)
if (re->draw_lock) {
re->draw_lock(re->dlh, false);
}
+ /* Free engine. */
+ RE_engine_free(engine);
+ re->engine = nullptr;
/* Too small image is handled earlier, here it could only happen if
* there was no sufficient memory to allocate all passes.
*/
@@ -1036,14 +1081,6 @@ bool RE_engine_render(Render *re, bool do_all)
re->i.cfra = re->scene->r.cfra;
BLI_strncpy(re->i.scene_name, re->scene->id.name + 2, sizeof(re->i.scene_name));
- /* render */
- RenderEngine *engine = re->engine;
-
- if (!engine) {
- engine = RE_engine_create(type);
- re->engine = engine;
- }
-
engine->flag |= RE_ENGINE_RENDERING;
/* TODO: actually link to a parent which shouldn't happen */
diff --git a/source/blender/render/intern/render_result.cc b/source/blender/render/intern/render_result.cc
index e8603f5e1b3..f9524fdbf05 100644
--- a/source/blender/render/intern/render_result.cc
+++ b/source/blender/render/intern/render_result.cc
@@ -290,90 +290,8 @@ RenderResult *render_result_new(Render *re,
}
}
-#define RENDER_LAYER_ADD_PASS_SAFE(rr, rl, channels, name, viewname, chan_id) \
- do { \
- if (render_layer_add_pass(rr, rl, channels, name, viewname, chan_id, false) == nullptr) { \
- render_result_free(rr); \
- return nullptr; \
- } \
- } while (false)
-
/* A render-layer should always have a "Combined" pass. */
render_layer_add_pass(rr, rl, 4, "Combined", view, "RGBA", false);
-
- if (view_layer->passflag & SCE_PASS_Z) {
- RENDER_LAYER_ADD_PASS_SAFE(rr, rl, 1, RE_PASSNAME_Z, view, "Z");
- }
- if (view_layer->passflag & SCE_PASS_VECTOR) {
- RENDER_LAYER_ADD_PASS_SAFE(rr, rl, 4, RE_PASSNAME_VECTOR, view, "XYZW");
- }
- if (view_layer->passflag & SCE_PASS_NORMAL) {
- RENDER_LAYER_ADD_PASS_SAFE(rr, rl, 3, RE_PASSNAME_NORMAL, view, "XYZ");
- }
- if (view_layer->passflag & SCE_PASS_POSITION) {
- RENDER_LAYER_ADD_PASS_SAFE(rr, rl, 3, RE_PASSNAME_POSITION, view, "XYZ");
- }
- if (view_layer->passflag & SCE_PASS_UV) {
- RENDER_LAYER_ADD_PASS_SAFE(rr, rl, 3, RE_PASSNAME_UV, view, "UVA");
- }
- if (view_layer->passflag & SCE_PASS_EMIT) {
- RENDER_LAYER_ADD_PASS_SAFE(rr, rl, 3, RE_PASSNAME_EMIT, view, "RGB");
- }
- if (view_layer->passflag & SCE_PASS_AO) {
- RENDER_LAYER_ADD_PASS_SAFE(rr, rl, 3, RE_PASSNAME_AO, view, "RGB");
- }
- if (view_layer->passflag & SCE_PASS_ENVIRONMENT) {
- RENDER_LAYER_ADD_PASS_SAFE(rr, rl, 3, RE_PASSNAME_ENVIRONMENT, view, "RGB");
- }
- if (view_layer->passflag & SCE_PASS_SHADOW) {
- RENDER_LAYER_ADD_PASS_SAFE(rr, rl, 3, RE_PASSNAME_SHADOW, view, "RGB");
- }
- if (view_layer->passflag & SCE_PASS_INDEXOB) {
- RENDER_LAYER_ADD_PASS_SAFE(rr, rl, 1, RE_PASSNAME_INDEXOB, view, "X");
- }
- if (view_layer->passflag & SCE_PASS_INDEXMA) {
- RENDER_LAYER_ADD_PASS_SAFE(rr, rl, 1, RE_PASSNAME_INDEXMA, view, "X");
- }
- if (view_layer->passflag & SCE_PASS_MIST) {
- RENDER_LAYER_ADD_PASS_SAFE(rr, rl, 1, RE_PASSNAME_MIST, view, "Z");
- }
- if (view_layer->passflag & SCE_PASS_DIFFUSE_DIRECT) {
- RENDER_LAYER_ADD_PASS_SAFE(rr, rl, 3, RE_PASSNAME_DIFFUSE_DIRECT, view, "RGB");
- }
- if (view_layer->passflag & SCE_PASS_DIFFUSE_INDIRECT) {
- RENDER_LAYER_ADD_PASS_SAFE(rr, rl, 3, RE_PASSNAME_DIFFUSE_INDIRECT, view, "RGB");
- }
- if (view_layer->passflag & SCE_PASS_DIFFUSE_COLOR) {
- RENDER_LAYER_ADD_PASS_SAFE(rr, rl, 3, RE_PASSNAME_DIFFUSE_COLOR, view, "RGB");
- }
- if (view_layer->passflag & SCE_PASS_GLOSSY_DIRECT) {
- RENDER_LAYER_ADD_PASS_SAFE(rr, rl, 3, RE_PASSNAME_GLOSSY_DIRECT, view, "RGB");
- }
- if (view_layer->passflag & SCE_PASS_GLOSSY_INDIRECT) {
- RENDER_LAYER_ADD_PASS_SAFE(rr, rl, 3, RE_PASSNAME_GLOSSY_INDIRECT, view, "RGB");
- }
- if (view_layer->passflag & SCE_PASS_GLOSSY_COLOR) {
- RENDER_LAYER_ADD_PASS_SAFE(rr, rl, 3, RE_PASSNAME_GLOSSY_COLOR, view, "RGB");
- }
- if (view_layer->passflag & SCE_PASS_TRANSM_DIRECT) {
- RENDER_LAYER_ADD_PASS_SAFE(rr, rl, 3, RE_PASSNAME_TRANSM_DIRECT, view, "RGB");
- }
- if (view_layer->passflag & SCE_PASS_TRANSM_INDIRECT) {
- RENDER_LAYER_ADD_PASS_SAFE(rr, rl, 3, RE_PASSNAME_TRANSM_INDIRECT, view, "RGB");
- }
- if (view_layer->passflag & SCE_PASS_TRANSM_COLOR) {
- RENDER_LAYER_ADD_PASS_SAFE(rr, rl, 3, RE_PASSNAME_TRANSM_COLOR, view, "RGB");
- }
- if (view_layer->passflag & SCE_PASS_SUBSURFACE_DIRECT) {
- RENDER_LAYER_ADD_PASS_SAFE(rr, rl, 3, RE_PASSNAME_SUBSURFACE_DIRECT, view, "RGB");
- }
- if (view_layer->passflag & SCE_PASS_SUBSURFACE_INDIRECT) {
- RENDER_LAYER_ADD_PASS_SAFE(rr, rl, 3, RE_PASSNAME_SUBSURFACE_INDIRECT, view, "RGB");
- }
- if (view_layer->passflag & SCE_PASS_SUBSURFACE_COLOR) {
- RENDER_LAYER_ADD_PASS_SAFE(rr, rl, 3, RE_PASSNAME_SUBSURFACE_COLOR, view, "RGB");
- }
-#undef RENDER_LAYER_ADD_PASS_SAFE
}
}
FOREACH_VIEW_LAYER_TO_RENDER_END;
@@ -411,11 +329,6 @@ RenderResult *render_result_new(Render *re,
rr->xof = re->disprect.xmin + BLI_rcti_cent_x(&re->disprect) - (re->winx / 2);
rr->yof = re->disprect.ymin + BLI_rcti_cent_y(&re->disprect) - (re->winy / 2);
- /* Preview does not support deferred render result allocation. */
- if (re->r.scemode & R_BUTS_PREVIEW) {
- render_result_passes_allocated_ensure(rr);
- }
-
return rr;
}
@@ -962,7 +875,7 @@ static void render_result_exr_file_cache_path(Scene *sce,
sce->id.name + 2,
path_hexdigest);
- BLI_join_dirfile(r_path, FILE_CACHE_MAX, root, filename_full);
+ BLI_path_join(r_path, FILE_CACHE_MAX, root, filename_full);
if (BLI_path_is_rel(r_path)) {
BLI_path_abs(r_path, dirname);
}
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/sequencer/intern/proxy.c b/source/blender/sequencer/intern/proxy.c
index 4220efab8bf..9f08db2aa45 100644
--- a/source/blender/sequencer/intern/proxy.c
+++ b/source/blender/sequencer/intern/proxy.c
@@ -106,7 +106,7 @@ bool seq_proxy_get_custom_file_fname(Sequence *seq, char *name, const int view_i
return false;
}
- BLI_join_dirfile(fname, PROXY_MAXFILE, proxy->dir, proxy->file);
+ BLI_path_join(fname, PROXY_MAXFILE, proxy->dir, proxy->file);
BLI_path_abs(fname, BKE_main_blendfile_path_from_global());
if (view_id > 0) {
@@ -325,7 +325,7 @@ static bool seq_proxy_multiview_context_invalid(Sequence *seq, Scene *scene, con
if (view_id == 0) {
char path[FILE_MAX];
- BLI_join_dirfile(path, sizeof(path), seq->strip->dir, seq->strip->stripdata->name);
+ BLI_path_join(path, sizeof(path), seq->strip->dir, seq->strip->stripdata->name);
BLI_path_abs(path, BKE_main_blendfile_path_from_global());
BKE_scene_multiview_view_prefix_get(scene, path, prefix, &ext);
}
diff --git a/source/blender/sequencer/intern/render.c b/source/blender/sequencer/intern/render.c
index 91ecccbe0f8..dbbece73695 100644
--- a/source/blender/sequencer/intern/render.c
+++ b/source/blender/sequencer/intern/render.c
@@ -938,7 +938,7 @@ static ImBuf *seq_render_image_strip(const SeqRenderData *context,
return NULL;
}
- BLI_join_dirfile(name, sizeof(name), seq->strip->dir, s_elem->name);
+ BLI_path_join(name, sizeof(name), seq->strip->dir, s_elem->name);
BLI_path_abs(name, BKE_main_blendfile_path_from_global());
/* Try to get a proxy image. */
diff --git a/source/blender/sequencer/intern/strip_add.c b/source/blender/sequencer/intern/strip_add.c
index 753a6ee39e0..7f4c91724fc 100644
--- a/source/blender/sequencer/intern/strip_add.c
+++ b/source/blender/sequencer/intern/strip_add.c
@@ -204,7 +204,7 @@ void SEQ_add_image_init_alpha_mode(Sequence *seq)
char name[FILE_MAX];
ImBuf *ibuf;
- BLI_join_dirfile(name, sizeof(name), seq->strip->dir, seq->strip->stripdata->name);
+ BLI_path_join(name, sizeof(name), seq->strip->dir, seq->strip->stripdata->name);
BLI_path_abs(name, BKE_main_blendfile_path_from_global());
/* Initialize input color space. */
@@ -545,7 +545,7 @@ void SEQ_add_reload_new_file(Main *bmain, Scene *scene, Sequence *seq, const boo
const bool is_multiview = (seq->flag & SEQ_USE_VIEWS) != 0 &&
(scene->r.scemode & R_MULTIVIEW) != 0;
- BLI_join_dirfile(path, sizeof(path), seq->strip->dir, seq->strip->stripdata->name);
+ BLI_path_join(path, sizeof(path), seq->strip->dir, seq->strip->stripdata->name);
BLI_path_abs(path, BKE_main_blendfile_path_from_global());
SEQ_relations_sequence_free_anim(seq);
diff --git a/source/blender/sequencer/intern/utils.c b/source/blender/sequencer/intern/utils.c
index 6d182b6bcca..5b70bc33e88 100644
--- a/source/blender/sequencer/intern/utils.c
+++ b/source/blender/sequencer/intern/utils.c
@@ -224,7 +224,7 @@ void seq_open_anim_file(Scene *scene, Sequence *seq, bool openfile)
/* reset all the previously created anims */
SEQ_relations_sequence_free_anim(seq);
- BLI_join_dirfile(name, sizeof(name), seq->strip->dir, seq->strip->stripdata->name);
+ BLI_path_join(name, sizeof(name), seq->strip->dir, seq->strip->stripdata->name);
BLI_path_abs(name, BKE_main_blendfile_path_from_global());
proxy = seq->strip->proxy;
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_dragdrop.cc b/source/blender/windowmanager/intern/wm_dragdrop.cc
index 0896daec561..fb63abed9e9 100644
--- a/source/blender/windowmanager/intern/wm_dragdrop.cc
+++ b/source/blender/windowmanager/intern/wm_dragdrop.cc
@@ -853,7 +853,8 @@ static void wm_drag_draw_icon(bContext * /*C*/, wmWindow * /*win*/, wmDrag *drag
y = xy[1] - 2 * UI_DPI_FAC;
const uchar text_col[] = {255, 255, 255, 255};
- UI_icon_draw_ex(x, y, drag->icon, U.inv_dpi_fac, 0.8, 0.0f, text_col, false);
+ UI_icon_draw_ex(
+ x, y, drag->icon, U.inv_dpi_fac, 0.8, 0.0f, text_col, false, UI_NO_ICON_OVERLAY_TEXT);
}
}
diff --git a/source/blender/windowmanager/intern/wm_event_system.cc b/source/blender/windowmanager/intern/wm_event_system.cc
index affe0bcf45a..181ec89cabd 100644
--- a/source/blender/windowmanager/intern/wm_event_system.cc
+++ b/source/blender/windowmanager/intern/wm_event_system.cc
@@ -5620,7 +5620,7 @@ void wm_event_add_ghostevent(wmWindowManager *wm, wmWindow *win, int type, void
case GHOST_kEventNDOFButton: {
GHOST_TEventNDOFButtonData *e = static_cast<GHOST_TEventNDOFButtonData *>(customdata);
- event.type = NDOF_BUTTON_NONE + e->button;
+ event.type = NDOF_BUTTON_INDEX_AS_EVENT(e->button);
switch (e->action) {
case GHOST_kPress:
diff --git a/source/blender/windowmanager/intern/wm_files.c b/source/blender/windowmanager/intern/wm_files.c
index 7ac55b2c27a..b009a67efba 100644
--- a/source/blender/windowmanager/intern/wm_files.c
+++ b/source/blender/windowmanager/intern/wm_files.c
@@ -1166,12 +1166,10 @@ void wm_homefile_read_ex(bContext *C,
const char *const cfgdir = BKE_appdir_folder_id(BLENDER_USER_CONFIG, NULL);
if (!use_factory_settings) {
if (cfgdir) {
- BLI_path_join(
- filepath_startup, sizeof(filepath_startup), cfgdir, BLENDER_STARTUP_FILE, NULL);
+ BLI_path_join(filepath_startup, sizeof(filepath_startup), cfgdir, BLENDER_STARTUP_FILE);
filepath_startup_is_factory = false;
if (use_userdef) {
- BLI_path_join(
- filepath_userdef, sizeof(filepath_startup), cfgdir, BLENDER_USERPREF_FILE, NULL);
+ BLI_path_join(filepath_userdef, sizeof(filepath_startup), cfgdir, BLENDER_USERPREF_FILE);
}
}
else {
@@ -1214,12 +1212,9 @@ void wm_homefile_read_ex(bContext *C,
/* note that the path is being set even when 'use_factory_settings == true'
* this is done so we can load a templates factory-settings */
if (!use_factory_settings) {
- BLI_path_join(app_template_config, sizeof(app_template_config), cfgdir, app_template, NULL);
- BLI_path_join(filepath_startup,
- sizeof(filepath_startup),
- app_template_config,
- BLENDER_STARTUP_FILE,
- NULL);
+ BLI_path_join(app_template_config, sizeof(app_template_config), cfgdir, app_template);
+ BLI_path_join(
+ filepath_startup, sizeof(filepath_startup), app_template_config, BLENDER_STARTUP_FILE);
filepath_startup_is_factory = false;
if (BLI_access(filepath_startup, R_OK) != 0) {
filepath_startup[0] = '\0';
@@ -1230,11 +1225,8 @@ void wm_homefile_read_ex(bContext *C,
}
if (filepath_startup[0] == '\0') {
- BLI_path_join(filepath_startup,
- sizeof(filepath_startup),
- app_template_system,
- BLENDER_STARTUP_FILE,
- NULL);
+ BLI_path_join(
+ filepath_startup, sizeof(filepath_startup), app_template_system, BLENDER_STARTUP_FILE);
filepath_startup_is_factory = true;
/* Update defaults only for system templates. */
@@ -1303,16 +1295,14 @@ void wm_homefile_read_ex(bContext *C,
char temp_path[FILE_MAX];
temp_path[0] = '\0';
if (!use_factory_settings) {
- BLI_path_join(
- temp_path, sizeof(temp_path), app_template_config, BLENDER_USERPREF_FILE, NULL);
+ BLI_path_join(temp_path, sizeof(temp_path), app_template_config, BLENDER_USERPREF_FILE);
if (BLI_access(temp_path, R_OK) != 0) {
temp_path[0] = '\0';
}
}
if (temp_path[0] == '\0') {
- BLI_path_join(
- temp_path, sizeof(temp_path), app_template_system, BLENDER_USERPREF_FILE, NULL);
+ BLI_path_join(temp_path, sizeof(temp_path), app_template_system, BLENDER_USERPREF_FILE);
}
if (use_userdef) {
@@ -1416,7 +1406,7 @@ void wm_history_file_read(void)
LinkNode *l;
int num;
- BLI_join_dirfile(name, sizeof(name), cfgdir, BLENDER_HISTORY_FILE);
+ BLI_path_join(name, sizeof(name), cfgdir, BLENDER_HISTORY_FILE);
LinkNode *lines = BLI_file_read_as_lines(name);
@@ -1479,7 +1469,7 @@ static void wm_history_file_write(void)
return;
}
- BLI_join_dirfile(name, sizeof(name), user_config_dir, BLENDER_HISTORY_FILE);
+ BLI_path_join(name, sizeof(name), user_config_dir, BLENDER_HISTORY_FILE);
fp = BLI_fopen(name, "w");
if (fp) {
@@ -1940,7 +1930,7 @@ static void wm_autosave_location(char filepath[FILE_MAX])
}
#endif
- BLI_join_dirfile(filepath, FILE_MAX, tempdir_base, path);
+ BLI_path_join(filepath, FILE_MAX, tempdir_base, path);
}
static void wm_autosave_write(Main *bmain, wmWindowManager *wm)
@@ -2030,7 +2020,7 @@ void wm_autosave_delete(void)
if (BLI_exists(filepath)) {
char str[FILE_MAX];
- BLI_join_dirfile(str, sizeof(str), BKE_tempdir_base(), BLENDER_QUIT_FILE);
+ BLI_path_join(str, sizeof(str), BKE_tempdir_base(), BLENDER_QUIT_FILE);
/* if global undo; remove tempsave, otherwise rename */
if (U.uiflag & USER_GLOBALUNDO) {
@@ -2132,7 +2122,7 @@ static int wm_homefile_write_exec(bContext *C, wmOperator *op)
/* update keymaps in user preferences */
WM_keyconfig_update(wm);
- BLI_path_join(filepath, sizeof(filepath), cfgdir, BLENDER_STARTUP_FILE, NULL);
+ BLI_path_join(filepath, sizeof(filepath), cfgdir, BLENDER_STARTUP_FILE);
printf("Writing homefile: '%s' ", filepath);
@@ -2925,7 +2915,7 @@ void WM_OT_revert_mainfile(wmOperatorType *ot)
bool WM_file_recover_last_session(bContext *C, ReportList *reports)
{
char filepath[FILE_MAX];
- BLI_join_dirfile(filepath, sizeof(filepath), BKE_tempdir_base(), BLENDER_QUIT_FILE);
+ BLI_path_join(filepath, sizeof(filepath), BKE_tempdir_base(), BLENDER_QUIT_FILE);
G.fileflags |= G_FILE_RECOVER_READ;
const bool success = wm_file_read_opwrap(C, filepath, reports);
G.fileflags &= ~G_FILE_RECOVER_READ;
diff --git a/source/blender/windowmanager/intern/wm_files_link.c b/source/blender/windowmanager/intern/wm_files_link.c
index 0ea783af1af..bbe53bf7355 100644
--- a/source/blender/windowmanager/intern/wm_files_link.c
+++ b/source/blender/windowmanager/intern/wm_files_link.c
@@ -210,7 +210,7 @@ static int wm_link_append_exec(bContext *C, wmOperator *op)
RNA_string_get(op->ptr, "filename", relname);
RNA_string_get(op->ptr, "directory", root);
- BLI_join_dirfile(path, sizeof(path), root, relname);
+ BLI_path_join(path, sizeof(path), root, relname);
/* test if we have a valid data */
if (!BLO_library_path_explode(path, libname, &group, &name)) {
@@ -284,7 +284,7 @@ static int wm_link_append_exec(bContext *C, wmOperator *op)
RNA_BEGIN (op->ptr, itemptr, "files") {
RNA_string_get(&itemptr, "name", relname);
- BLI_join_dirfile(path, sizeof(path), root, relname);
+ BLI_path_join(path, sizeof(path), root, relname);
if (BLO_library_path_explode(path, libname, &group, &name)) {
if (!wm_link_append_item_poll(NULL, path, group, name, do_append)) {
@@ -303,7 +303,7 @@ static int wm_link_append_exec(bContext *C, wmOperator *op)
RNA_BEGIN (op->ptr, itemptr, "files") {
RNA_string_get(&itemptr, "name", relname);
- BLI_join_dirfile(path, sizeof(path), root, relname);
+ BLI_path_join(path, sizeof(path), root, relname);
if (BLO_library_path_explode(path, libname, &group, &name)) {
BlendfileLinkAppendContextItem *item;
@@ -683,7 +683,7 @@ static int wm_lib_relocate_exec_do(bContext *C, wmOperator *op, bool do_reload)
return OPERATOR_CANCELLED;
}
- BLI_join_dirfile(path, sizeof(path), root, libname);
+ BLI_path_join(path, sizeof(path), root, libname);
if (!BLI_exists(path)) {
BKE_reportf(op->reports,
@@ -739,7 +739,7 @@ static int wm_lib_relocate_exec_do(bContext *C, wmOperator *op, bool do_reload)
RNA_BEGIN (op->ptr, itemptr, "files") {
RNA_string_get(&itemptr, "name", relname);
- BLI_join_dirfile(path, sizeof(path), root, relname);
+ BLI_path_join(path, sizeof(path), root, relname);
if (BLI_path_cmp(path, lib->filepath_abs) == 0 || !BLO_has_bfile_extension(relname)) {
continue;
diff --git a/source/blender/windowmanager/intern/wm_init_exit.c b/source/blender/windowmanager/intern/wm_init_exit.c
index 32890b4014f..c5d7152246c 100644
--- a/source/blender/windowmanager/intern/wm_init_exit.c
+++ b/source/blender/windowmanager/intern/wm_init_exit.c
@@ -447,7 +447,7 @@ void WM_exit_ex(bContext *C, const bool do_python)
bool has_edited;
const int fileflags = G.fileflags & ~G_FILE_COMPRESS;
- BLI_join_dirfile(filepath, sizeof(filepath), BKE_tempdir_base(), BLENDER_QUIT_FILE);
+ BLI_path_join(filepath, sizeof(filepath), BKE_tempdir_base(), BLENDER_QUIT_FILE);
has_edited = ED_editors_flush_edits(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_platform_support.c b/source/blender/windowmanager/intern/wm_platform_support.c
index a0519506d29..ee93621545f 100644
--- a/source/blender/windowmanager/intern/wm_platform_support.c
+++ b/source/blender/windowmanager/intern/wm_platform_support.c
@@ -42,7 +42,7 @@ static bool wm_platform_support_check_approval(const char *platform_support_key,
bool result = false;
char filepath[FILE_MAX];
- BLI_join_dirfile(filepath, sizeof(filepath), cfgdir, BLENDER_PLATFORM_SUPPORT_FILE);
+ BLI_path_join(filepath, sizeof(filepath), cfgdir, BLENDER_PLATFORM_SUPPORT_FILE);
LinkNode *lines = BLI_file_read_as_lines(filepath);
for (LinkNode *line_node = lines; line_node; line_node = line_node->next) {
char *line = line_node->link;
diff --git a/source/blender/windowmanager/intern/wm_playanim.c b/source/blender/windowmanager/intern/wm_playanim.c
index bf793ee41a0..3e5399a6f56 100644
--- a/source/blender/windowmanager/intern/wm_playanim.c
+++ b/source/blender/windowmanager/intern/wm_playanim.c
@@ -59,6 +59,8 @@
#include "DEG_depsgraph.h"
+#include "wm_window_private.h"
+
#include "WM_api.h" /* only for WM_main_playanim */
#ifdef WITH_AUDASPACE
@@ -1340,6 +1342,8 @@ static bool ghost_event_proc(GHOST_EventHandle evt, GHOST_TUserDataPtr ps_void)
static void playanim_window_open(const char *title, int posx, int posy, int sizex, int sizey)
{
GHOST_GLSettings glsettings = {0};
+ const eGPUBackendType gpu_backend = GPU_backend_type_selection_get();
+ glsettings.context_type = wm_ghost_drawing_context_type(gpu_backend);
uint32_t scr_w, scr_h;
GHOST_GetMainDisplayDimensions(g_WS.ghost_system, &scr_w, &scr_h);
@@ -1356,7 +1360,6 @@ static void playanim_window_open(const char *title, int posx, int posy, int size
/* Could optionally start full-screen. */
GHOST_kWindowStateNormal,
false,
- GHOST_kDrawingContextTypeOpenGL,
glsettings);
}
diff --git a/source/blender/windowmanager/intern/wm_splash_screen.c b/source/blender/windowmanager/intern/wm_splash_screen.c
index 8fca3deef92..16e5f983bea 100644
--- a/source/blender/windowmanager/intern/wm_splash_screen.c
+++ b/source/blender/windowmanager/intern/wm_splash_screen.c
@@ -140,7 +140,7 @@ static ImBuf *wm_block_splash_image(int width, int *r_height)
char template_directory[FILE_MAX];
if (BKE_appdir_app_template_id_search(
U.app_template, template_directory, sizeof(template_directory))) {
- BLI_join_dirfile(splash_filepath, sizeof(splash_filepath), template_directory, "splash.png");
+ BLI_path_join(splash_filepath, sizeof(splash_filepath), template_directory, "splash.png");
ibuf = IMB_loadiffname(splash_filepath, IB_rect, NULL);
}
}
@@ -218,7 +218,7 @@ static uiBlock *wm_block_create_splash(bContext *C, ARegion *region, void *UNUSE
const char *const cfgdir = BKE_appdir_folder_id(BLENDER_USER_CONFIG, NULL);
if (cfgdir) {
- BLI_path_join(userpref, sizeof(userpref), cfgdir, BLENDER_USERPREF_FILE, NULL);
+ BLI_path_join(userpref, sizeof(userpref), cfgdir, BLENDER_USERPREF_FILE);
}
/* Draw setup screen if no preferences have been saved yet. */
diff --git a/source/blender/windowmanager/intern/wm_window.c b/source/blender/windowmanager/intern/wm_window.c
index a4f92da2774..2ca7b5f470d 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),
@@ -553,6 +556,9 @@ static void wm_window_ghostwindow_add(wmWindowManager *wm,
glSettings.flags |= GHOST_glDebugContext;
}
+ eGPUBackendType gpu_backend = GPU_backend_type_selection_get();
+ glSettings.context_type = wm_ghost_drawing_context_type(gpu_backend);
+
int scr_w, scr_h;
wm_get_desktopsize(&scr_w, &scr_h);
int posy = (scr_h - win->posy - win->sizey);
@@ -570,7 +576,6 @@ static void wm_window_ghostwindow_add(wmWindowManager *wm,
win->sizey,
(GHOST_TWindowState)win->windowstate,
is_dialog,
- GHOST_kDrawingContextTypeOpenGL,
glSettings);
if (ghostwin) {
@@ -1552,6 +1557,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 +1605,41 @@ 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
+}
+
+GHOST_TDrawingContextType wm_ghost_drawing_context_type(const eGPUBackendType gpu_backend)
+{
+ switch (gpu_backend) {
+ case GPU_BACKEND_NONE:
+ return GHOST_kDrawingContextTypeNone;
+ case GPU_BACKEND_ANY:
+ case GPU_BACKEND_OPENGL:
+ return GHOST_kDrawingContextTypeOpenGL;
+ case GPU_BACKEND_METAL:
+#ifdef WITH_METAL_BACKEND
+ return GHOST_kDrawingContextTypeMetal;
+#else
+ BLI_assert_unreachable();
+ return GHOST_kDrawingContextTypeNone;
+#endif
+ }
+
+ /* Avoid control reaches end of non-void function compilation warning, which could be promoted
+ * to error. */
+ BLI_assert_unreachable();
+ return GHOST_kDrawingContextTypeNone;
+}
+
/** \} */
/* -------------------------------------------------------------------- */
diff --git a/source/blender/windowmanager/intern/wm_window_private.h b/source/blender/windowmanager/intern/wm_window_private.h
index f68d4e3e693..dad3e749817 100644
--- a/source/blender/windowmanager/intern/wm_window_private.h
+++ b/source/blender/windowmanager/intern/wm_window_private.h
@@ -7,8 +7,11 @@
#pragma once
#include "BLI_sys_types.h"
+
#include "GHOST_Types.h"
+#include "GPU_context.h"
+
/* *************** Message box *************** */
/* `WM_ghost_show_message_box` is implemented in `wm_windows.c` it is
* defined here as it was implemented to be used for showing
@@ -21,3 +24,5 @@ void WM_ghost_show_message_box(const char *title,
const char *continue_label,
const char *link,
GHOST_DialogOptions dialog_options);
+
+GHOST_TDrawingContextType wm_ghost_drawing_context_type(const eGPUBackendType gpu_backend);
diff --git a/source/blender/windowmanager/wm_event_types.h b/source/blender/windowmanager/wm_event_types.h
index 405b7225bd5..c36c57a12ae 100644
--- a/source/blender/windowmanager/wm_event_types.h
+++ b/source/blender/windowmanager/wm_event_types.h
@@ -252,8 +252,6 @@ enum {
#define _NDOF_MIN NDOF_MOTION
#define _NDOF_BUTTON_MIN NDOF_BUTTON_MENU
- /* used internally, never sent */
- NDOF_BUTTON_NONE = NDOF_MOTION,
/* these two are available from any 3Dconnexion device */
NDOF_BUTTON_MENU = 0x0191, /* 401 */
@@ -281,35 +279,42 @@ enum {
NDOF_BUTTON_DOMINANT = 0x01a3, /* 419 */
NDOF_BUTTON_PLUS = 0x01a4, /* 420 */
NDOF_BUTTON_MINUS = 0x01a5, /* 421 */
+ /* General-purpose buttons. */
+ NDOF_BUTTON_1 = 0x01a6, /* 422 */
+ NDOF_BUTTON_2 = 0x01a7, /* 423 */
+ NDOF_BUTTON_3 = 0x01a8, /* 424 */
+ NDOF_BUTTON_4 = 0x01a9, /* 425 */
+ NDOF_BUTTON_5 = 0x01aa, /* 426 */
+ NDOF_BUTTON_6 = 0x01ab, /* 427 */
+ NDOF_BUTTON_7 = 0x01ac, /* 428 */
+ NDOF_BUTTON_8 = 0x01ad, /* 429 */
+ NDOF_BUTTON_9 = 0x01ae, /* 430 */
+ NDOF_BUTTON_10 = 0x01af, /* 431 */
+ /* more general-purpose buttons */
+ NDOF_BUTTON_A = 0x01b0, /* 432 */
+ NDOF_BUTTON_B = 0x01b1, /* 433 */
+ NDOF_BUTTON_C = 0x01b2, /* 434 */
+ /* Store/restore views. */
+ NDOF_BUTTON_V1 = 0x01b3, /* 435 */
+ NDOF_BUTTON_V2 = 0x01b4, /* 436 */
+ NDOF_BUTTON_V3 = 0x01b5, /* 437 */
/* Disabled as GHOST converts these to keyboard events
* which use regular keyboard event handling logic. */
#if 0
/* keyboard emulation */
- NDOF_BUTTON_ESC = 0x01a6, /* 422 */
- NDOF_BUTTON_ALT = 0x01a7, /* 423 */
- NDOF_BUTTON_SHIFT = 0x01a8, /* 424 */
- NDOF_BUTTON_CTRL = 0x01a9, /* 425 */
+ NDOF_BUTTON_ESC = 0x01b6, /* 438 */
+ NDOF_BUTTON_ENTER = 0x01b7, /* 439 */
+ NDOF_BUTTON_DELETE = 0x01b8, /* 440 */
+ NDOF_BUTTON_TAB = 0x01b9, /* 441 */
+ NDOF_BUTTON_SPACE = 0x01ba, /* 442 */
+ NDOF_BUTTON_ALT = 0x01bb, /* 443 */
+ NDOF_BUTTON_SHIFT = 0x01bc, /* 444 */
+ NDOF_BUTTON_CTRL = 0x01bd, /* 445 */
#endif
- /* general-purpose buttons */
- NDOF_BUTTON_1 = 0x01aa, /* 426 */
- NDOF_BUTTON_2 = 0x01ab, /* 427 */
- NDOF_BUTTON_3 = 0x01ac, /* 428 */
- NDOF_BUTTON_4 = 0x01ad, /* 429 */
- NDOF_BUTTON_5 = 0x01ae, /* 430 */
- NDOF_BUTTON_6 = 0x01af, /* 431 */
- NDOF_BUTTON_7 = 0x01b0, /* 432 */
- NDOF_BUTTON_8 = 0x01b1, /* 433 */
- NDOF_BUTTON_9 = 0x01b2, /* 434 */
- NDOF_BUTTON_10 = 0x01b3, /* 435 */
- /* more general-purpose buttons */
- NDOF_BUTTON_A = 0x01b4, /* 436 */
- NDOF_BUTTON_B = 0x01b5, /* 437 */
- NDOF_BUTTON_C = 0x01b6, /* 438 */
-
-#define _NDOF_MAX NDOF_BUTTON_C
-#define _NDOF_BUTTON_MAX NDOF_BUTTON_C
+#define _NDOF_MAX NDOF_BUTTON_V3
+#define _NDOF_BUTTON_MAX NDOF_BUTTON_V3
/* ********** End of Input devices. ********** */
@@ -449,6 +454,8 @@ enum eEventType_Mask {
(EVT_TYPE_MASK_KEYBOARD | EVT_TYPE_MASK_MOUSE | EVT_TYPE_MASK_NDOF)
#define EVT_TYPE_MASK_HOTKEY_EXCLUDE EVT_TYPE_MASK_KEYBOARD_MODIFIER
+#define NDOF_BUTTON_INDEX_AS_EVENT(i) (_NDOF_BUTTON_MIN + (i))
+
bool WM_event_type_mask_test(int event_type, enum eEventType_Mask mask);
/** \} */
diff --git a/source/creator/creator_args.c b/source/creator/creator_args.c
index 06b898587bf..4144603555b 100644
--- a/source/creator/creator_args.c
+++ b/source/creator/creator_args.c
@@ -42,6 +42,8 @@
# include "BKE_scene.h"
# include "BKE_sound.h"
+# include "GPU_context.h"
+
# ifdef WITH_FFMPEG
# include "IMB_imbuf.h"
# endif
@@ -1111,6 +1113,44 @@ static int arg_handle_debug_gpu_set(int UNUSED(argc),
return 0;
}
+static const char arg_handle_gpu_backend_set_doc[] =
+ "\n"
+ "\tForce to use a specific GPU backend. Valid options: "
+# ifdef WITH_METAL_BACKEND
+ "'metal', "
+# endif
+ "'opengl').";
+static int arg_handle_gpu_backend_set(int argc, const char **argv, void *UNUSED(data))
+{
+ if (argc == 0) {
+ printf("\nError: GPU backend must follow '--gpu-backend'.\n");
+ return 0;
+ }
+
+ eGPUBackendType gpu_backend = GPU_BACKEND_NONE;
+
+ if (STREQ(argv[1], "opengl")) {
+ gpu_backend = GPU_BACKEND_OPENGL;
+ }
+# ifdef WITH_METAL_BACKEND
+ else if (STREQ(argv[1], "metal")) {
+ gpu_backend = GPU_BACKEND_METAL;
+ }
+# endif
+ else {
+ printf("\nError: Unrecognized GPU backend for '--gpu-backend'.\n");
+ return 0;
+ }
+
+ GPU_backend_type_selection_set(gpu_backend);
+ if (!GPU_backend_supported()) {
+ printf("\nError: GPU backend not supported.\n");
+ return 0;
+ }
+
+ return 1;
+}
+
static const char arg_handle_debug_fpe_set_doc[] =
"\n\t"
"Enable floating-point exceptions.";
@@ -2074,6 +2114,10 @@ void main_args_setup(bContext *C, bArgs *ba)
BLI_args_add(ba, NULL, "--log-show-timestamp", CB(arg_handle_log_show_timestamp_set), ba);
BLI_args_add(ba, NULL, "--log-file", CB(arg_handle_log_file_set), ba);
+ /* GPU backend selection should be part of ARG_PASS_ENVIRONMENT for correct GPU context selection
+ * for anim player. */
+ BLI_args_add(ba, NULL, "--gpu-backend", CB(arg_handle_gpu_backend_set), NULL);
+
/* Pass: Background Mode & Settings
*
* Also and commands that exit after usage. */
diff --git a/source/creator/creator_signals.c b/source/creator/creator_signals.c
index c016372e6b0..c733ee617cb 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)
{
@@ -103,7 +101,7 @@ static void sig_handle_crash(int signum)
char fname[FILE_MAX];
if (!(G_MAIN && G_MAIN->filepath[0])) {
- BLI_join_dirfile(fname, sizeof(fname), BKE_tempdir_base(), "crash.blend");
+ BLI_path_join(fname, sizeof(fname), BKE_tempdir_base(), "crash.blend");
}
else {
STRNCPY(fname, G_MAIN->filepath);
@@ -124,11 +122,10 @@ static void sig_handle_crash(int signum)
char fname[FILE_MAX];
if (!(G_MAIN && G_MAIN->filepath[0])) {
- BLI_join_dirfile(fname, sizeof(fname), BKE_tempdir_base(), "blender.crash.txt");
+ BLI_path_join(fname, sizeof(fname), BKE_tempdir_base(), "blender.crash.txt");
}
else {
- BLI_join_dirfile(
- fname, sizeof(fname), BKE_tempdir_base(), BLI_path_basename(G_MAIN->filepath));
+ BLI_path_join(fname, sizeof(fname), BKE_tempdir_base(), BLI_path_basename(G_MAIN->filepath));
BLI_path_extension_replace(fname, sizeof(fname), ".crash.txt");
}
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",
]