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:
authorFalk David <falkdavid@gmx.de>2022-05-17 12:19:52 +0300
committerFalk David <falkdavid@gmx.de>2022-05-17 12:19:52 +0300
commit91cf6fdd8e49144853d3dfa3a54f02575eb73963 (patch)
treea5ea9af05ab94c59a5675b24d2c085f352534623
parent2f8087b2c881b2ec728048937a73d987006bddca (diff)
parent210d0f1b801fb23c7edabb35b67224eab671e363 (diff)
Merge branch 'blender-v3.2-release' into spa-studios-v2.0.0-release
-rw-r--r--build_files/build_environment/CMakeLists.txt3
-rw-r--r--build_files/build_environment/cmake/clew.cmake12
-rw-r--r--build_files/build_environment/cmake/cuew.cmake13
-rw-r--r--build_files/build_environment/cmake/download.cmake4
-rw-r--r--build_files/build_environment/cmake/glfw.cmake12
-rw-r--r--build_files/build_environment/cmake/opencolorio.cmake3
-rw-r--r--build_files/build_environment/cmake/opensubdiv.cmake23
-rw-r--r--build_files/build_environment/cmake/versions.cmake21
-rw-r--r--build_files/build_environment/dependencies.dot4
-rw-r--r--build_files/build_environment/patches/cuew.diff26
-rw-r--r--build_files/build_environment/patches/usd.diff49
-rw-r--r--intern/cycles/blender/mesh.cpp51
-rw-r--r--intern/cycles/blender/util.h5
-rw-r--r--intern/cycles/integrator/denoiser_oidn.cpp1
-rw-r--r--intern/cycles/kernel/integrator/mnee.h80
-rw-r--r--intern/cycles/kernel/light/sample.h2
m---------release/datafiles/locale0
m---------release/scripts/addons0
-rw-r--r--release/scripts/modules/bl_i18n_utils/bl_extract_messages.py3
-rw-r--r--release/scripts/presets/keyconfig/keymap_data/blender_default.py68
-rw-r--r--release/scripts/startup/bl_ui/space_node.py29
-rw-r--r--release/scripts/startup/bl_ui/space_userpref.py1
-rw-r--r--release/scripts/startup/bl_ui/space_view3d.py28
-rw-r--r--release/scripts/startup/nodeitems_builtins.py4
-rw-r--r--source/blender/blenkernel/BKE_unit.h2
-rw-r--r--source/blender/blenkernel/intern/blendfile_link_append.c4
-rw-r--r--source/blender/blenkernel/intern/brush.c4
-rw-r--r--source/blender/blenkernel/intern/curve_to_mesh_convert.cc4
-rw-r--r--source/blender/blenkernel/intern/image_save.cc9
-rw-r--r--source/blender/blenkernel/intern/lib_override.c41
-rw-r--r--source/blender/blenkernel/intern/subdiv_modifier.c2
-rw-r--r--source/blender/blenlib/BLI_string.h8
-rw-r--r--source/blender/blenlib/intern/string.c18
-rw-r--r--source/blender/bmesh/intern/bmesh_log.c7
-rw-r--r--source/blender/depsgraph/intern/builder/deg_builder_relations.cc16
-rw-r--r--source/blender/draw/CMakeLists.txt1
-rw-r--r--source/blender/draw/engines/eevee/eevee_cryptomatte.c8
-rw-r--r--source/blender/draw/engines/eevee/eevee_data.c10
-rw-r--r--source/blender/draw/engines/eevee/eevee_motion_blur.c9
-rw-r--r--source/blender/draw/engines/eevee/eevee_private.h10
-rw-r--r--source/blender/draw/engines/eevee/eevee_shaders.c6
-rw-r--r--source/blender/draw/engines/eevee/shaders/closure_eval_surface_lib.glsl7
-rw-r--r--source/blender/draw/engines/eevee/shaders/closure_eval_volume_lib.glsl4
-rw-r--r--source/blender/draw/engines/eevee/shaders/closure_type_lib.glsl4
-rw-r--r--source/blender/draw/engines/eevee/shaders/cryptomatte_vert.glsl6
-rw-r--r--source/blender/draw/engines/eevee/shaders/surface_lib.glsl8
-rw-r--r--source/blender/draw/engines/eevee_next/shaders/eevee_attributes_lib.glsl2
-rw-r--r--source/blender/draw/engines/eevee_next/shaders/eevee_geom_curves_vert.glsl2
-rw-r--r--source/blender/draw/engines/eevee_next/shaders/eevee_nodetree_lib.glsl1
-rw-r--r--source/blender/draw/engines/eevee_next/shaders/eevee_surf_lib.glsl7
-rw-r--r--source/blender/draw/engines/eevee_next/shaders/infos/eevee_material_info.hh1
-rw-r--r--source/blender/draw/engines/overlay/overlay_shader.c4
-rw-r--r--source/blender/draw/engines/overlay/shaders/edit_uv_edges_geom.glsl3
-rw-r--r--source/blender/draw/intern/draw_cache_extract.h1
-rw-r--r--source/blender/draw/intern/draw_cache_extract_mesh.cc5
-rw-r--r--source/blender/draw/intern/draw_cache_impl_mesh.c16
-rw-r--r--source/blender/draw/intern/draw_cache_impl_subdivision.cc3
-rw-r--r--source/blender/draw/intern/draw_manager.c2
-rw-r--r--source/blender/draw/intern/draw_subdivision.h1
-rw-r--r--source/blender/draw/intern/mesh_extractors/extract_mesh_ibo_edituv.cc14
-rw-r--r--source/blender/editors/gpencil/gpencil_select.c1
-rw-r--r--source/blender/editors/include/ED_select_utils.h12
-rw-r--r--source/blender/editors/include/ED_uvedit.h4
-rw-r--r--source/blender/editors/include/UI_interface.h32
-rw-r--r--source/blender/editors/interface/interface.cc25
-rw-r--r--source/blender/editors/interface/interface_handlers.c67
-rw-r--r--source/blender/editors/interface/interface_intern.h8
-rw-r--r--source/blender/editors/interface/interface_query.cc32
-rw-r--r--source/blender/editors/io/CMakeLists.txt1
-rw-r--r--source/blender/editors/io/io_obj.c24
-rw-r--r--source/blender/editors/io/io_usd.c15
-rw-r--r--source/blender/editors/mask/mask_select.c2
-rw-r--r--source/blender/editors/mesh/editmesh_knife.c155
-rw-r--r--source/blender/editors/object/object_relations.c2
-rw-r--r--source/blender/editors/sculpt_paint/paint_image_2d.c55
-rw-r--r--source/blender/editors/sculpt_paint/paint_image_proj.c138
-rw-r--r--source/blender/editors/sculpt_paint/paint_stroke.c2
-rw-r--r--source/blender/editors/sculpt_paint/sculpt_filter_color.c4
-rw-r--r--source/blender/editors/space_action/action_select.c1
-rw-r--r--source/blender/editors/space_clip/tracking_select.c1
-rw-r--r--source/blender/editors/space_graph/graph_select.c1
-rw-r--r--source/blender/editors/space_node/node_select.cc173
-rw-r--r--source/blender/editors/space_outliner/outliner_draw.cc24
-rw-r--r--source/blender/editors/space_outliner/tree/tree_element_overrides.cc7
-rw-r--r--source/blender/editors/space_outliner/tree/tree_element_overrides.hh5
-rw-r--r--source/blender/editors/space_sequencer/sequencer_add.c2
-rw-r--r--source/blender/editors/space_sequencer/sequencer_select.c1
-rw-r--r--source/blender/editors/space_view3d/view3d_select.c6
-rw-r--r--source/blender/editors/transform/transform_convert_tracking.c11
-rw-r--r--source/blender/editors/transform/transform_snap_object.cc15
-rw-r--r--source/blender/editors/util/select_utils.c62
-rw-r--r--source/blender/editors/uvedit/uvedit_select.c4
-rw-r--r--source/blender/editors/uvedit/uvedit_unwrap_ops.c160
-rw-r--r--source/blender/functions/FN_multi_function_builder.hh26
-rw-r--r--source/blender/gpu/GPU_capabilities.h2
-rw-r--r--source/blender/gpu/intern/gpu_capabilities.cc11
-rw-r--r--source/blender/gpu/intern/gpu_capabilities_private.hh2
-rw-r--r--source/blender/gpu/intern/gpu_codegen.cc36
-rw-r--r--source/blender/gpu/intern/gpu_index_buffer.cc1
-rw-r--r--source/blender/gpu/intern/gpu_index_buffer_private.hh7
-rw-r--r--source/blender/gpu/intern/gpu_node_graph.c6
-rw-r--r--source/blender/gpu/intern/gpu_shader_builtin.c10
-rw-r--r--source/blender/gpu/intern/gpu_shader_dependency.cc44
-rw-r--r--source/blender/gpu/intern/gpu_viewport.c28
-rw-r--r--source/blender/gpu/opengl/gl_backend.cc8
-rw-r--r--source/blender/gpu/shaders/gpu_shader_codegen_lib.glsl4
-rw-r--r--source/blender/gpu/shaders/gpu_shader_image_overlays_stereo_merge_frag.glsl12
-rw-r--r--source/blender/gpu/shaders/infos/gpu_shader_2D_image_overlays_stereo_merge_info.hh4
-rw-r--r--source/blender/gpu/shaders/material/gpu_shader_material_add_shader.glsl2
-rw-r--r--source/blender/gpu/shaders/material/gpu_shader_material_eevee_specular.glsl6
-rw-r--r--source/blender/gpu/shaders/material/gpu_shader_material_geometry.glsl2
-rw-r--r--source/blender/gpu/shaders/material/gpu_shader_material_hair.glsl2
-rw-r--r--source/blender/gpu/shaders/material/gpu_shader_material_hair_info.glsl4
-rw-r--r--source/blender/gpu/shaders/material/gpu_shader_material_mix_shader.glsl2
-rw-r--r--source/blender/gpu/shaders/material/gpu_shader_material_principled.glsl6
-rw-r--r--source/blender/imbuf/intern/openexr/openexr_api.cpp31
-rw-r--r--source/blender/io/alembic/intern/abc_reader_mesh.cc2
-rw-r--r--source/blender/io/common/CMakeLists.txt3
-rw-r--r--source/blender/io/common/IO_path_util.hh29
-rw-r--r--source/blender/io/common/IO_path_util_types.h18
-rw-r--r--source/blender/io/common/intern/path_util.cc81
-rw-r--r--source/blender/io/usd/intern/usd_reader_mesh.cc2
-rw-r--r--source/blender/io/wavefront_obj/IO_wavefront_obj.h4
-rw-r--r--source/blender/io/wavefront_obj/exporter/obj_export_file_writer.cc34
-rw-r--r--source/blender/io/wavefront_obj/exporter/obj_export_file_writer.hh11
-rw-r--r--source/blender/io/wavefront_obj/exporter/obj_export_mtl.cc6
-rw-r--r--source/blender/io/wavefront_obj/exporter/obj_exporter.cc11
-rw-r--r--source/blender/io/wavefront_obj/importer/obj_import_mesh.cc2
-rw-r--r--source/blender/io/wavefront_obj/tests/obj_exporter_tests.cc25
-rw-r--r--source/blender/io/wavefront_obj/tests/obj_exporter_tests.hh2
-rw-r--r--source/blender/makesdna/DNA_mesh_types.h2
-rw-r--r--source/blender/makesdna/DNA_scene_types.h3
-rw-r--r--source/blender/makesdna/DNA_userdef_types.h2
-rw-r--r--source/blender/makesrna/intern/rna_ID.c2
-rw-r--r--source/blender/makesrna/intern/rna_access.c13
-rw-r--r--source/blender/makesrna/intern/rna_userdef.c4
-rw-r--r--source/blender/modifiers/intern/MOD_meshdeform.c19
-rw-r--r--source/blender/modifiers/intern/MOD_screw.c10
-rw-r--r--source/blender/modifiers/intern/MOD_warp.c14
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_vertex_color.cc16
-rw-r--r--source/blender/python/intern/bpy_utils_units.c14
-rw-r--r--source/blender/render/intern/bake.c16
-rw-r--r--source/blender/windowmanager/gizmo/intern/wm_gizmo_map.c205
-rw-r--r--source/blender/windowmanager/intern/wm_draw.c2
m---------source/tools0
-rw-r--r--tests/python/bl_rigging_symmetrize.py5
146 files changed, 1602 insertions, 955 deletions
diff --git a/build_files/build_environment/CMakeLists.txt b/build_files/build_environment/CMakeLists.txt
index 8f4738d1f1c..b63e86a3ac2 100644
--- a/build_files/build_environment/CMakeLists.txt
+++ b/build_files/build_environment/CMakeLists.txt
@@ -54,9 +54,6 @@ include(cmake/freetype.cmake)
include(cmake/freeglut.cmake)
include(cmake/glew.cmake)
include(cmake/alembic.cmake)
-include(cmake/glfw.cmake)
-include(cmake/clew.cmake)
-include(cmake/cuew.cmake)
include(cmake/opensubdiv.cmake)
include(cmake/sdl.cmake)
include(cmake/opencollada.cmake)
diff --git a/build_files/build_environment/cmake/clew.cmake b/build_files/build_environment/cmake/clew.cmake
deleted file mode 100644
index 8c965d52d2c..00000000000
--- a/build_files/build_environment/cmake/clew.cmake
+++ /dev/null
@@ -1,12 +0,0 @@
-# SPDX-License-Identifier: GPL-2.0-or-later
-
-set(CLEW_EXTRA_ARGS)
-
-ExternalProject_Add(external_clew
- URL file://${PACKAGE_DIR}/${CLEW_FILE}
- DOWNLOAD_DIR ${DOWNLOAD_DIR}
- URL_HASH ${CLEW_HASH_TYPE}=${CLEW_HASH}
- PREFIX ${BUILD_DIR}/clew
- CMAKE_ARGS -DCMAKE_INSTALL_PREFIX=${LIBDIR}/clew -Wno-dev ${DEFAULT_CMAKE_FLAGS} ${CLEW_EXTRA_ARGS}
- INSTALL_DIR ${LIBDIR}/clew
-)
diff --git a/build_files/build_environment/cmake/cuew.cmake b/build_files/build_environment/cmake/cuew.cmake
deleted file mode 100644
index 8beb8b4fade..00000000000
--- a/build_files/build_environment/cmake/cuew.cmake
+++ /dev/null
@@ -1,13 +0,0 @@
-# SPDX-License-Identifier: GPL-2.0-or-later
-
-set(CUEW_EXTRA_ARGS)
-
-ExternalProject_Add(external_cuew
- URL file://${PACKAGE_DIR}/${CUEW_FILE}
- DOWNLOAD_DIR ${DOWNLOAD_DIR}
- URL_HASH ${CUEW_HASH_TYPE}=${CUEW_HASH}
- PREFIX ${BUILD_DIR}/cuew
- PATCH_COMMAND ${PATCH_CMD} --verbose -p 0 -N -d ${BUILD_DIR}/cuew/src/external_cuew < ${PATCH_DIR}/cuew.diff
- CMAKE_ARGS -DCMAKE_INSTALL_PREFIX=${LIBDIR}/cuew -Wno-dev ${DEFAULT_CMAKE_FLAGS} ${CUEW_EXTRA_ARGS}
- INSTALL_DIR ${LIBDIR}/cuew
-)
diff --git a/build_files/build_environment/cmake/download.cmake b/build_files/build_environment/cmake/download.cmake
index 92dea453133..e305b05ee70 100644
--- a/build_files/build_environment/cmake/download.cmake
+++ b/build_files/build_environment/cmake/download.cmake
@@ -39,10 +39,6 @@ download_source(FREETYPE)
download_source(GLEW)
download_source(FREEGLUT)
download_source(ALEMBIC)
-download_source(GLFW)
-download_source(CLEW)
-download_source(GLFW)
-download_source(CUEW)
download_source(OPENSUBDIV)
download_source(SDL)
download_source(OPENCOLLADA)
diff --git a/build_files/build_environment/cmake/glfw.cmake b/build_files/build_environment/cmake/glfw.cmake
deleted file mode 100644
index 29fce7609e5..00000000000
--- a/build_files/build_environment/cmake/glfw.cmake
+++ /dev/null
@@ -1,12 +0,0 @@
-# SPDX-License-Identifier: GPL-2.0-or-later
-
-set(GLFW_EXTRA_ARGS)
-
-ExternalProject_Add(external_glfw
- URL file://${PACKAGE_DIR}/${GLFW_FILE}
- DOWNLOAD_DIR ${DOWNLOAD_DIR}
- URL_HASH ${GLFW_HASH_TYPE}=${GLFW_HASH}
- PREFIX ${BUILD_DIR}/glfw
- CMAKE_ARGS -DCMAKE_INSTALL_PREFIX=${LIBDIR}/glfw -Wno-dev ${DEFAULT_CMAKE_FLAGS} ${GLFW_EXTRA_ARGS}
- INSTALL_DIR ${LIBDIR}/glfw
-)
diff --git a/build_files/build_environment/cmake/opencolorio.cmake b/build_files/build_environment/cmake/opencolorio.cmake
index 2246031be83..4e2d1503406 100644
--- a/build_files/build_environment/cmake/opencolorio.cmake
+++ b/build_files/build_environment/cmake/opencolorio.cmake
@@ -53,7 +53,8 @@ add_dependencies(
external_opencolorio
external_yamlcpp
external_expat
- external_openexr
+ external_imath
+ external_pystring
)
if(WIN32)
diff --git a/build_files/build_environment/cmake/opensubdiv.cmake b/build_files/build_environment/cmake/opensubdiv.cmake
index 6d6e3568406..a142160b9cc 100644
--- a/build_files/build_environment/cmake/opensubdiv.cmake
+++ b/build_files/build_environment/cmake/opensubdiv.cmake
@@ -10,20 +10,16 @@ set(OPENSUBDIV_EXTRA_ARGS
-DNO_OMP=ON
-DNO_TBB=OFF
-DNO_CUDA=ON
- -DNO_OPENCL=OFF
- -DNO_CLEW=OFF
+ -DNO_OPENCL=ON
+ -DNO_CLEW=ON
-DNO_OPENGL=OFF
-DNO_METAL=OFF
-DNO_DX=ON
-DNO_TESTS=ON
-DNO_GLTESTS=ON
- -DNO_GLEW=OFF
- -DNO_GLFW=OFF
+ -DNO_GLEW=ON
+ -DNO_GLFW=ON
-DNO_GLFW_X11=ON
- -DGLEW_INCLUDE_DIR=${LIBDIR}/glew/include
- -DGLEW_LIBRARY=${LIBDIR}/glew/lib/libGLEW${LIBEXT}
- -DGLFW_INCLUDE_DIR=${LIBDIR}/glfw/include
- -DGLFW_LIBRARIES=${LIBDIR}/glfw/lib/glfw3${LIBEXT}
)
if(WIN32)
@@ -31,19 +27,12 @@ if(WIN32)
${OPENSUBDIV_EXTRA_ARGS}
-DTBB_INCLUDE_DIR=${LIBDIR}/tbb/include
-DTBB_LIBRARIES=${LIBDIR}/tbb/lib/tbb.lib
- -DCLEW_INCLUDE_DIR=${LIBDIR}/clew/include/CL
- -DCLEW_LIBRARY=${LIBDIR}/clew/lib/clew${LIBEXT}
- -DCUEW_INCLUDE_DIR=${LIBDIR}/cuew/include
- -DCUEW_LIBRARY=${LIBDIR}/cuew/lib/cuew${LIBEXT}
)
else()
set(OPENSUBDIV_EXTRA_ARGS
${OPENSUBDIV_EXTRA_ARGS}
-DTBB_INCLUDE_DIR=${LIBDIR}/tbb/include
-DTBB_tbb_LIBRARY=${LIBDIR}/tbb/lib/${LIBPREFIX}tbb_static${LIBEXT}
- -DCUEW_INCLUDE_DIR=${LIBDIR}/cuew/include
- -DCLEW_INCLUDE_DIR=${LIBDIR}/clew/include/CL
- -DCLEW_LIBRARY=${LIBDIR}/clew/lib/static/${LIBPREFIX}clew${LIBEXT}
)
endif()
@@ -75,9 +64,5 @@ endif()
add_dependencies(
external_opensubdiv
- external_glew
- external_glfw
- external_clew
- external_cuew
external_tbb
)
diff --git a/build_files/build_environment/cmake/versions.cmake b/build_files/build_environment/cmake/versions.cmake
index 25267273db0..550be86b6b6 100644
--- a/build_files/build_environment/cmake/versions.cmake
+++ b/build_files/build_environment/cmake/versions.cmake
@@ -98,27 +98,6 @@ set(ALEMBIC_HASH 2cd8d6e5a3ac4a014e24a4b04f4fadf9)
set(ALEMBIC_HASH_TYPE MD5)
set(ALEMBIC_FILE alembic-${ALEMBIC_VERSION}.tar.gz)
-# hash is for 3.1.2
-set(GLFW_GIT_UID 30306e54705c3adae9fe082c816a3be71963485c)
-set(GLFW_URI https://github.com/glfw/glfw/archive/${GLFW_GIT_UID}.zip)
-set(GLFW_HASH 20cacb1613da7eeb092f3ac4f6b2b3d0)
-set(GLFW_HASH_TYPE MD5)
-set(GLFW_FILE glfw-${GLFW_GIT_UID}.zip)
-
-# latest uid in git as of 2016-04-01
-set(CLEW_GIT_UID 277db43f6cafe8b27c6f1055f69dc67da4aeb299)
-set(CLEW_URI https://github.com/OpenCLWrangler/clew/archive/${CLEW_GIT_UID}.zip)
-set(CLEW_HASH 2c699d10ed78362e71f56fae2a4c5f98)
-set(CLEW_HASH_TYPE MD5)
-set(CLEW_FILE clew-${CLEW_GIT_UID}.zip)
-
-# latest uid in git as of 2016-04-01
-set(CUEW_GIT_UID 1744972026de9cf27c8a7dc39cf39cd83d5f922f)
-set(CUEW_URI https://github.com/CudaWrangler/cuew/archive/${CUEW_GIT_UID}.zip)
-set(CUEW_HASH 86760d62978ebfd96cd93f5aa1abaf4a)
-set(CUEW_HASH_TYPE MD5)
-set(CUEW_FILE cuew-${CUEW_GIT_UID}.zip)
-
set(OPENSUBDIV_VERSION v3_4_4)
set(OPENSUBDIV_URI https://github.com/PixarAnimationStudios/OpenSubdiv/archive/${OPENSUBDIV_VERSION}.tar.gz)
set(OPENSUBDIV_HASH 39ecc5caf0abebc943d1ce131855e76e)
diff --git a/build_files/build_environment/dependencies.dot b/build_files/build_environment/dependencies.dot
index 62949f3de62..7e8637fbced 100644
--- a/build_files/build_environment/dependencies.dot
+++ b/build_files/build_environment/dependencies.dot
@@ -37,10 +37,6 @@ graph[autosize = false, size = "25.7,8.3!", resolution = 300, overlap = false, s
external_openimageio -- external_webp;
external_openimageio -- external_opencolorio_extra;
external_openmp -- external_clang;
- external_opensubdiv -- external_glew;
- external_opensubdiv -- external_glfw;
- external_opensubdiv -- external_clew;
- external_opensubdiv -- external_cuew;
external_opensubdiv -- external_tbb;
openvdb -- external_tbb;
openvdb -- external_boost;
diff --git a/build_files/build_environment/patches/cuew.diff b/build_files/build_environment/patches/cuew.diff
deleted file mode 100644
index 0363034cd93..00000000000
--- a/build_files/build_environment/patches/cuew.diff
+++ /dev/null
@@ -1,26 +0,0 @@
---- CmakeLists.txt.orig 2015-12-31 03:46:41 -0700
-+++ CMakeLists.txt 2016-04-01 13:28:33 -0600
-@@ -22,3 +22,10 @@
-
- add_executable(testcuew cuewTest/cuewTest.c include/cuew.h)
- target_link_libraries(testcuew cuew ${CMAKE_DL_LIBS})
-+
-+install(TARGETS cuew
-+ LIBRARY DESTINATION lib COMPONENT libraries
-+ ARCHIVE DESTINATION lib/static COMPONENT libraries)
-+
-+INSTALL(FILES ${CMAKE_CURRENT_SOURCE_DIR}/include/cuew.h
-+ DESTINATION include/)
-\ No newline at end of file
---- src/cuew.c 2016-04-01 13:41:43 -0600
-+++ src/cuew.c 2016-04-01 13:41:11 -0600
-@@ -15,7 +15,9 @@
- */
-
- #ifdef _MSC_VER
-+#if _MSC_VER < 1900
- # define snprintf _snprintf
-+#endif
- # define popen _popen
- # define pclose _pclose
- # define _CRT_SECURE_NO_WARNINGS
diff --git a/build_files/build_environment/patches/usd.diff b/build_files/build_environment/patches/usd.diff
index eb5905109a7..3d0aa4498b7 100644
--- a/build_files/build_environment/patches/usd.diff
+++ b/build_files/build_environment/patches/usd.diff
@@ -51,3 +51,52 @@ diff --git a/pxr/usd/sdr/shaderMetadataHelpers.h b/pxr/usd/sdr/shaderMetadataHel
/// \namespace ShaderMetadataHelpers
+diff --git a/pxr/base/arch/timing.h b/pxr/base/arch/timing.h
+index 517561f..fda5a1f 100644
+--- a/pxr/base/arch/timing.h
++++ b/pxr/base/arch/timing.h
+@@ -91,6 +91,10 @@ ArchGetTickTime()
+ inline uint64_t
+ ArchGetStartTickTime()
+ {
++ // BLENDER: avoid using rdtsc instruction that is not supported on older CPUs.
++ return ArchGetTickTime();
++
++#if 0
+ uint64_t t;
+ #if defined (ARCH_OS_DARWIN)
+ return ArchGetTickTime();
+@@ -123,6 +127,7 @@ ArchGetStartTickTime()
+ #error "Unsupported architecture."
+ #endif
+ return t;
++#endif
+ }
+
+ /// Get a "stop" tick time for measuring an interval of time. See
+@@ -132,6 +137,10 @@ ArchGetStartTickTime()
+ inline uint64_t
+ ArchGetStopTickTime()
+ {
++ // BLENDER: avoid using rdtsc instruction that is not supported on older CPUs.
++ return ArchGetTickTime();
++
++#if 0
+ uint64_t t;
+ #if defined (ARCH_OS_DARWIN)
+ return ArchGetTickTime();
+@@ -162,11 +171,11 @@ ArchGetStopTickTime()
+ #error "Unsupported architecture."
+ #endif
+ return t;
++#endif
+ }
+
+-#if defined (doxygen) || \
+- (!defined(ARCH_OS_DARWIN) && defined(ARCH_CPU_INTEL) && \
+- (defined(ARCH_COMPILER_CLANG) || defined(ARCH_COMPILER_GCC)))
++// BLENDER: avoid using rdtsc instruction that is not supported on older CPUs.
++#if 0
+
+ /// A simple timer class for measuring an interval of time using the
+ /// ArchTickTimer facilities.
diff --git a/intern/cycles/blender/mesh.cpp b/intern/cycles/blender/mesh.cpp
index 624a07762f2..de67e27923d 100644
--- a/intern/cycles/blender/mesh.cpp
+++ b/intern/cycles/blender/mesh.cpp
@@ -301,11 +301,11 @@ static void attr_create_sculpt_vertex_color(Scene *scene,
template<typename TypeInCycles, typename GetValueAtIndex>
static void fill_generic_attribute(BL::Mesh &b_mesh,
TypeInCycles *data,
- const AttributeElement element,
+ const BL::Attribute::domain_enum b_domain,
const GetValueAtIndex &get_value_at_index)
{
- switch (element) {
- case ATTR_ELEMENT_CORNER: {
+ switch (b_domain) {
+ case BL::Attribute::domain_CORNER: {
for (BL::MeshLoopTriangle &t : b_mesh.loop_triangles) {
const int index = t.index() * 3;
BL::Array<int, 3> loops = t.loops();
@@ -315,14 +315,37 @@ static void fill_generic_attribute(BL::Mesh &b_mesh,
}
break;
}
- case ATTR_ELEMENT_VERTEX: {
+ case BL::Attribute::domain_EDGE: {
+ /* Averge edge attributes at vertices. */
+ const size_t num_verts = b_mesh.vertices.length();
+ vector<int> count(num_verts, 0);
+
+ for (BL::MeshEdge &e : b_mesh.edges) {
+ BL::Array<int, 2> vertices = e.vertices();
+ TypeInCycles value = get_value_at_index(e.index());
+
+ data[vertices[0]] += value;
+ data[vertices[1]] += value;
+ count[vertices[0]]++;
+ count[vertices[1]]++;
+ }
+
+ for (size_t i = 0; i < num_verts; i++) {
+ if (count[i] > 1) {
+ data[i] /= (float)count[i];
+ }
+ }
+
+ break;
+ }
+ case BL::Attribute::domain_POINT: {
const int num_verts = b_mesh.vertices.length();
for (int i = 0; i < num_verts; i++) {
data[i] = get_value_at_index(i);
}
break;
}
- case ATTR_ELEMENT_FACE: {
+ case BL::Attribute::domain_FACE: {
for (BL::MeshLoopTriangle &t : b_mesh.loop_triangles) {
data[t.index()] = get_value_at_index(t.polygon_index());
}
@@ -404,6 +427,9 @@ static void attr_create_generic(Scene *scene,
case BL::Attribute::domain_POINT:
element = ATTR_ELEMENT_VERTEX;
break;
+ case BL::Attribute::domain_EDGE:
+ element = ATTR_ELEMENT_VERTEX;
+ break;
case BL::Attribute::domain_FACE:
element = ATTR_ELEMENT_FACE;
break;
@@ -420,15 +446,16 @@ static void attr_create_generic(Scene *scene,
Attribute *attr = attributes.add(name, TypeFloat, element);
float *data = attr->data_float();
fill_generic_attribute(
- b_mesh, data, element, [&](int i) { return b_float_attribute.data[i].value(); });
+ b_mesh, data, b_domain, [&](int i) { return b_float_attribute.data[i].value(); });
break;
}
case BL::Attribute::data_type_BOOLEAN: {
BL::BoolAttribute b_bool_attribute{b_attribute};
Attribute *attr = attributes.add(name, TypeFloat, element);
float *data = attr->data_float();
- fill_generic_attribute(
- b_mesh, data, element, [&](int i) { return (float)b_bool_attribute.data[i].value(); });
+ fill_generic_attribute(b_mesh, data, b_domain, [&](int i) {
+ return (float)b_bool_attribute.data[i].value();
+ });
break;
}
case BL::Attribute::data_type_INT: {
@@ -436,14 +463,14 @@ static void attr_create_generic(Scene *scene,
Attribute *attr = attributes.add(name, TypeFloat, element);
float *data = attr->data_float();
fill_generic_attribute(
- b_mesh, data, element, [&](int i) { return (float)b_int_attribute.data[i].value(); });
+ b_mesh, data, b_domain, [&](int i) { return (float)b_int_attribute.data[i].value(); });
break;
}
case BL::Attribute::data_type_FLOAT_VECTOR: {
BL::FloatVectorAttribute b_vector_attribute{b_attribute};
Attribute *attr = attributes.add(name, TypeVector, element);
float3 *data = attr->data_float3();
- fill_generic_attribute(b_mesh, data, element, [&](int i) {
+ fill_generic_attribute(b_mesh, data, b_domain, [&](int i) {
BL::Array<float, 3> v = b_vector_attribute.data[i].vector();
return make_float3(v[0], v[1], v[2]);
});
@@ -453,7 +480,7 @@ static void attr_create_generic(Scene *scene,
BL::FloatColorAttribute b_color_attribute{b_attribute};
Attribute *attr = attributes.add(name, TypeRGBA, element);
float4 *data = attr->data_float4();
- fill_generic_attribute(b_mesh, data, element, [&](int i) {
+ fill_generic_attribute(b_mesh, data, b_domain, [&](int i) {
BL::Array<float, 4> v = b_color_attribute.data[i].color();
return make_float4(v[0], v[1], v[2], v[3]);
});
@@ -463,7 +490,7 @@ static void attr_create_generic(Scene *scene,
BL::Float2Attribute b_float2_attribute{b_attribute};
Attribute *attr = attributes.add(name, TypeFloat2, element);
float2 *data = attr->data_float2();
- fill_generic_attribute(b_mesh, data, element, [&](int i) {
+ fill_generic_attribute(b_mesh, data, b_domain, [&](int i) {
BL::Array<float, 2> v = b_float2_attribute.data[i].vector();
return make_float2(v[0], v[1]);
});
diff --git a/intern/cycles/blender/util.h b/intern/cycles/blender/util.h
index eead6cec08c..49cecb6d0f3 100644
--- a/intern/cycles/blender/util.h
+++ b/intern/cycles/blender/util.h
@@ -262,8 +262,11 @@ static inline bool BKE_object_is_modified(BL::Object &self, BL::Scene &scene, bo
static inline bool BKE_object_is_deform_modified(BObjectInfo &self, BL::Scene &scene, bool preview)
{
if (!self.is_real_object_data()) {
- return false;
+ /* Comes from geometry nodes, can't use heuristic to guess if it's animated. */
+ return true;
}
+
+ /* Use heuristic to quickly check if object is potentially animated. */
return self.real_object.is_deform_modified(scene, (preview) ? (1 << 0) : (1 << 1)) ? true :
false;
}
diff --git a/intern/cycles/integrator/denoiser_oidn.cpp b/intern/cycles/integrator/denoiser_oidn.cpp
index 41e5165623c..b074408e229 100644
--- a/intern/cycles/integrator/denoiser_oidn.cpp
+++ b/intern/cycles/integrator/denoiser_oidn.cpp
@@ -626,6 +626,7 @@ uint OIDNDenoiser::get_device_type_mask() const
Device *OIDNDenoiser::ensure_denoiser_device(Progress *progress)
{
#ifndef WITH_OPENIMAGEDENOISE
+ (void)progress;
path_trace_device_->set_error("Build without OpenImageDenoiser");
return nullptr;
#else
diff --git a/intern/cycles/kernel/integrator/mnee.h b/intern/cycles/kernel/integrator/mnee.h
index 455d15b28c2..7b86c660380 100644
--- a/intern/cycles/kernel/integrator/mnee.h
+++ b/intern/cycles/kernel/integrator/mnee.h
@@ -36,7 +36,7 @@
* https://cg.ivd.kit.edu/english/HSLT.php
*/
-# define MNEE_MAX_ITERATIONS 32
+# define MNEE_MAX_ITERATIONS 64
# define MNEE_MAX_INTERSECTION_COUNT 10
# define MNEE_SOLVER_THRESHOLD 0.001f
# define MNEE_MINIMUM_STEP_SIZE 0.0001f
@@ -140,26 +140,8 @@ ccl_device_forceinline void mnee_update_light_sample(KernelGlobals kg,
ls->D = normalize_len(ls->P - P, &ls->t);
ls->pdf = fabsf(klight->area.invarea);
}
-}
-/* Compute orthonormal basis
- * https://graphics.pixar.com/library/OrthonormalB/paper.pdf */
-ccl_device_forceinline void mnee_make_orthonormals(const float3 n,
- ccl_private float3 *dp_du,
- ccl_private float3 *dp_dv)
-{
- if (n.z < 0.0f) {
- const float a = 1.0f / (1.0f - n.z);
- const float b = n.x * n.y * a;
- *dp_du = make_float3(1.0f - n.x * n.x * a, -b, n.x);
- *dp_dv = make_float3(b, n.y * n.y * a - 1.0f, -n.y);
- }
- else {
- const float a = 1.0f / (1.0f + n.z);
- const float b = -n.x * n.y * a;
- *dp_du = make_float3(1.0f - n.x * n.x * a, b, -n.x);
- *dp_dv = make_float3(b, 1.0f - n.y * n.y * a, -n.y);
- }
+ ls->pdf *= kernel_data.integrator.pdf_lights;
}
/* Manifold vertex setup from ray and intersection data */
@@ -170,8 +152,7 @@ ccl_device_forceinline void mnee_setup_manifold_vertex(KernelGlobals kg,
const float2 n_offset,
ccl_private const Ray *ray,
ccl_private const Intersection *isect,
- ccl_private ShaderData *sd_vtx,
- bool seed)
+ ccl_private ShaderData *sd_vtx)
{
sd_vtx->object = (isect->object == OBJECT_NONE) ? kernel_tex_fetch(__prim_object, isect->prim) :
isect->object;
@@ -263,30 +244,13 @@ ccl_device_forceinline void mnee_setup_manifold_vertex(KernelGlobals kg,
dp_dv *= inv_len_dp_dv;
dn_dv *= inv_len_dp_dv;
- /* Final local differential geometry. */
- if (seed) {
- vtx->dp_du = dp_du;
- vtx->dp_dv = dp_dv;
- vtx->dn_du = dn_du;
- vtx->dn_dv = dn_dv;
- }
- else {
- /* Find angle subtended by reference direction (travel direction). */
- const float3 reference_direction = normalize(sd_vtx->P - vtx->p);
- const float reference_theta = atan2(dot(reference_direction, vtx->dp_dv),
- dot(reference_direction, vtx->dp_du));
- const float current_theta = atan2(dot(reference_direction, dp_dv),
- dot(reference_direction, dp_du));
- const float theta = reference_theta - current_theta;
-
- /* Rotate (dp_du,dp_dv) to be consistent with previous tangent frame. */
- float cos_theta, sin_theta;
- fast_sincosf(theta, &sin_theta, &cos_theta);
- vtx->dp_du = cos_theta * dp_du - sin_theta * dp_dv;
- vtx->dp_dv = sin_theta * dp_du + cos_theta * dp_dv;
- vtx->dn_du = cos_theta * dn_du - sin_theta * dn_dv;
- vtx->dn_dv = sin_theta * dn_du + cos_theta * dn_dv;
- }
+ /* Find consistent tangent frame for every point on the surface. */
+ make_orthonormals(vtx->ng, &vtx->dp_du, &vtx->dp_dv);
+ /* Apply the equivalent rotation to the normal derivatives. */
+ const float cos_theta = dot(dp_du, vtx->dp_du);
+ const float sin_theta = -dot(dp_dv, vtx->dp_du);
+ vtx->dn_du = cos_theta * dn_du - sin_theta * dn_dv;
+ vtx->dn_dv = sin_theta * dn_du + cos_theta * dn_dv;
/* Manifold vertex position. */
vtx->p = sd_vtx->P;
@@ -577,8 +541,7 @@ ccl_device_forceinline bool mnee_newton_solver(KernelGlobals kg,
mv.n_offset,
&projection_ray,
&projection_isect,
- sd_vtx,
- false);
+ sd_vtx);
/* Fail newton solve if we are not making progress, probably stuck trying to move off the
* edge of the mesh. */
@@ -749,7 +712,7 @@ ccl_device_forceinline bool mnee_compute_transfer_matrix(ccl_private const Shade
/* Local differential geometry. */
float3 dp_du, dp_dv;
- mnee_make_orthonormals(ls->Ng, &dp_du, &dp_dv);
+ make_orthonormals(ls->Ng, &dp_du, &dp_dv);
/* Direction toward surface sample. */
float3 wi = vertex_count == 1 ? sd->P - m.p : vertices[mi - 1].p - m.p;
@@ -1026,7 +989,9 @@ ccl_device_forceinline int kernel_path_mnee_sample(KernelGlobals kg,
if (bsdf->type == CLOSURE_BSDF_MICROFACET_BECKMANN_REFRACTION_ID ||
bsdf->type == CLOSURE_BSDF_MICROFACET_GGX_REFRACTION_ID ||
bsdf->type == CLOSURE_BSDF_MICROFACET_MULTI_GGX_GLASS_ID ||
- bsdf->type == CLOSURE_BSDF_MICROFACET_MULTI_GGX_GLASS_FRESNEL_ID) {
+ bsdf->type == CLOSURE_BSDF_MICROFACET_MULTI_GGX_GLASS_FRESNEL_ID ||
+ bsdf->type == CLOSURE_BSDF_REFRACTION_ID ||
+ bsdf->type == CLOSURE_BSDF_SHARP_GLASS_ID) {
/* Note that CLOSURE_BSDF_MICROFACET_MULTI_GGX_GLASS_ID and
* CLOSURE_BSDF_MICROFACET_MULTI_GGX_GLASS_FRESNEL_ID are treated as
* CLOSURE_BSDF_MICROFACET_GGX_REFRACTION_ID further below. */
@@ -1038,15 +1003,18 @@ ccl_device_forceinline int kernel_path_mnee_sample(KernelGlobals kg,
const float eta = (sd_mnee->flag & SD_BACKFACING) ? 1.0f / microfacet_bsdf->ior :
microfacet_bsdf->ior;
- /* Sample transmissive microfacet bsdf. */
- float bsdf_u, bsdf_v;
- path_state_rng_2D(kg, rng_state, PRNG_BSDF_U, &bsdf_u, &bsdf_v);
- float2 h = mnee_sample_bsdf_dh(
- bsdf->type, microfacet_bsdf->alpha_x, microfacet_bsdf->alpha_y, bsdf_u, bsdf_v);
+ float2 h = zero_float2();
+ if (microfacet_bsdf->alpha_x > 0.f && microfacet_bsdf->alpha_y > 0.f) {
+ /* Sample transmissive microfacet bsdf. */
+ float bsdf_u, bsdf_v;
+ path_state_rng_2D(kg, rng_state, PRNG_BSDF_U, &bsdf_u, &bsdf_v);
+ h = mnee_sample_bsdf_dh(
+ bsdf->type, microfacet_bsdf->alpha_x, microfacet_bsdf->alpha_y, bsdf_u, bsdf_v);
+ }
/* Setup differential geometry on vertex. */
mnee_setup_manifold_vertex(
- kg, &mv, bsdf, eta, h, &probe_ray, &probe_isect, sd_mnee, true);
+ kg, &mv, bsdf, eta, h, &probe_ray, &probe_isect, sd_mnee);
break;
}
}
diff --git a/intern/cycles/kernel/light/sample.h b/intern/cycles/kernel/light/sample.h
index 5acfc92cca1..9bbbd5b0d10 100644
--- a/intern/cycles/kernel/light/sample.h
+++ b/intern/cycles/kernel/light/sample.h
@@ -143,7 +143,7 @@ ccl_device_inline float3 shadow_ray_smooth_surface_offset(
float3 n = N[0] * u + N[1] * v + N[2] * w; /* We get away without normalization */
if (!(sd->object_flag & SD_OBJECT_TRANSFORM_APPLIED)) {
- object_normal_transform(kg, sd, &n); /* Normal x scale, world space */
+ object_dir_transform(kg, sd, &n); /* Normal x scale, to world space */
}
/* Parabolic approximation */
diff --git a/release/datafiles/locale b/release/datafiles/locale
-Subproject 44cf4b4bf74f22fff55941e39cebeacec68a5a8
+Subproject fb1eac2ec80c0adee69990a5386b74a5bd4ca00
diff --git a/release/scripts/addons b/release/scripts/addons
-Subproject b87642c5dcbfe5d2779e070984ce0914b8f64f7
+Subproject d3eda2e271c00c7204a57e8106164e923c2f408
diff --git a/release/scripts/modules/bl_i18n_utils/bl_extract_messages.py b/release/scripts/modules/bl_i18n_utils/bl_extract_messages.py
index 87d54213d1b..604a577eec9 100644
--- a/release/scripts/modules/bl_i18n_utils/bl_extract_messages.py
+++ b/release/scripts/modules/bl_i18n_utils/bl_extract_messages.py
@@ -341,7 +341,8 @@ def dump_rna_messages(msgs, reports, settings, verbose=False):
msgsrc = "bpy.types." + bl_rna.identifier
msgctxt = bl_rna.translation_context or default_context
- if bl_rna.name and (bl_rna.name != bl_rna.identifier or msgctxt != default_context):
+ if bl_rna.name and (bl_rna.name != bl_rna.identifier or
+ (msgctxt != default_context and not hasattr(bl_rna, 'bl_label'))):
process_msg(msgs, msgctxt, bl_rna.name, msgsrc, reports, check_ctxt_rna, settings)
if bl_rna.description:
diff --git a/release/scripts/presets/keyconfig/keymap_data/blender_default.py b/release/scripts/presets/keyconfig/keymap_data/blender_default.py
index 1d322c68cd7..5603668222b 100644
--- a/release/scripts/presets/keyconfig/keymap_data/blender_default.py
+++ b/release/scripts/presets/keyconfig/keymap_data/blender_default.py
@@ -2038,37 +2038,20 @@ def km_node_editor(params):
{"items": items},
)
- def node_select_ops(select_mouse):
- return [
- ("node.select", {"type": select_mouse, "value": 'PRESS'},
- {"properties": [("deselect_all", True)]}),
- ("node.select", {"type": select_mouse, "value": 'PRESS', "ctrl": True}, None),
- ("node.select", {"type": select_mouse, "value": 'PRESS', "alt": True}, None),
- ("node.select", {"type": select_mouse, "value": 'PRESS', "ctrl": True, "alt": True}, None),
- ("node.select", {"type": select_mouse, "value": 'PRESS', "shift": True},
- {"properties": [("extend", True)]}),
- ("node.select", {"type": select_mouse, "value": 'PRESS', "shift": True, "ctrl": True},
- {"properties": [("extend", True)]}),
- ("node.select", {"type": select_mouse, "value": 'PRESS', "shift": True, "alt": True},
- {"properties": [("extend", True)]}),
- ("node.select", {"type": select_mouse, "value": 'PRESS', "shift": True, "ctrl": True, "alt": True},
- {"properties": [("extend", True)]}),
- ]
-
- # Allow node selection with both for RMB select
if not params.legacy:
+ items.extend(_template_node_select(type=params.select_mouse,
+ value=params.select_mouse_value, select_passthrough=True))
+ # Allow node selection with both for RMB select.
if params.select_mouse == 'RIGHTMOUSE':
- items.extend(node_select_ops('LEFTMOUSE'))
- items.extend(node_select_ops('RIGHTMOUSE'))
- else:
- items.extend(node_select_ops('LEFTMOUSE'))
+ items.extend(_template_node_select(type='LEFTMOUSE', value='PRESS', select_passthrough=True))
else:
- items.extend(node_select_ops('RIGHTMOUSE'))
+ items.extend(_template_node_select(
+ type='RIGHTMOUSE', value=params.select_mouse_value, select_passthrough=False))
items.extend([
("node.select", {"type": 'LEFTMOUSE', "value": 'PRESS'},
{"properties": [("deselect_all", False)]}),
("node.select", {"type": 'LEFTMOUSE', "value": 'PRESS', "shift": True},
- {"properties": [("extend", True)]}),
+ {"properties": [("toggle", True)]}),
])
items.extend([
@@ -4801,6 +4784,35 @@ def _template_view3d_gpencil_select(*, type, value, legacy, use_select_mouse=Tru
]
+def _template_node_select(*, type, value, select_passthrough):
+ items = [
+ ("node.select", {"type": type, "value": value},
+ {"properties": [("deselect_all", True), ("select_passthrough", True)]}),
+ ("node.select", {"type": type, "value": value, "ctrl": True}, None),
+ ("node.select", {"type": type, "value": value, "alt": True}, None),
+ ("node.select", {"type": type, "value": value, "ctrl": True, "alt": True}, None),
+ ("node.select", {"type": type, "value": value, "shift": True},
+ {"properties": [("toggle", True)]}),
+ ("node.select", {"type": type, "value": value, "shift": True, "ctrl": True},
+ {"properties": [("toggle", True)]}),
+ ("node.select", {"type": type, "value": value, "shift": True, "alt": True},
+ {"properties": [("toggle", True)]}),
+ ("node.select", {"type": type, "value": value, "shift": True, "ctrl": True, "alt": True},
+ {"properties": [("toggle", True)]}),
+ ]
+
+ if select_passthrough and (value == 'PRESS'):
+ # Add an additional click item to de-select all other items,
+ # needed so pass-through is able to de-select other items.
+ items.append((
+ "node.select",
+ {"type": type, "value": 'CLICK'},
+ {"properties": [("deselect_all", True)]},
+ ))
+
+ return items
+
+
def _template_uv_select(*, type, value, select_passthrough, legacy):
# See: `use_tweak_select_passthrough` doc-string.
@@ -6562,10 +6574,8 @@ def km_node_editor_tool_select(params, *, fallback):
_fallback_id("Node Tool: Tweak", fallback),
{"space_type": 'NODE_EDITOR', "region_type": 'WINDOW'},
{"items": [
- *([] if (fallback and (params.select_mouse == 'RIGHTMOUSE')) else [
- ("node.select", {"type": params.select_mouse, "value": 'PRESS'},
- {"properties": [("deselect_all", not params.legacy)]}),
- ]),
+ *([] if (fallback and (params.select_mouse == 'RIGHTMOUSE')) else
+ _template_node_select(type=params.select_mouse, value='PRESS', select_passthrough=True)),
]},
)
@@ -6582,6 +6592,8 @@ def km_node_editor_tool_select_box(params, *, fallback):
params.tool_tweak_event),
properties=[("tweak", True)],
)),
+ *([] if (params.select_mouse == 'RIGHTMOUSE') else
+ _template_node_select(type='LEFTMOUSE', value='PRESS', select_passthrough=True)),
]},
)
diff --git a/release/scripts/startup/bl_ui/space_node.py b/release/scripts/startup/bl_ui/space_node.py
index e105b07ec53..813a799db24 100644
--- a/release/scripts/startup/bl_ui/space_node.py
+++ b/release/scripts/startup/bl_ui/space_node.py
@@ -727,7 +727,20 @@ class NODE_UL_interface_sockets(bpy.types.UIList):
layout.template_node_socket(color=color)
-class NodeTreeInterfacePanel:
+class NodeTreeInterfacePanel(Panel):
+
+ @classmethod
+ def poll(cls, context):
+ snode = context.space_data
+ if snode is None:
+ return False
+ tree = snode.edit_tree
+ if tree is None:
+ return False
+ if tree.is_embedded_data:
+ return False
+ return True
+
def draw_socket_list(self, context, in_out, sockets_propname, active_socket_propname):
layout = self.layout
@@ -804,32 +817,22 @@ class NodeTreeInterfacePanel:
active_socket.draw(context, layout)
-class NODE_PT_node_tree_interface_inputs(NodeTreeInterfacePanel, Panel):
+class NODE_PT_node_tree_interface_inputs(NodeTreeInterfacePanel):
bl_space_type = 'NODE_EDITOR'
bl_region_type = 'UI'
bl_category = "Group"
bl_label = "Inputs"
- @classmethod
- def poll(cls, context):
- snode = context.space_data
- return snode.edit_tree is not None
-
def draw(self, context):
self.draw_socket_list(context, "IN", "inputs", "active_input")
-class NODE_PT_node_tree_interface_outputs(NodeTreeInterfacePanel, Panel):
+class NODE_PT_node_tree_interface_outputs(NodeTreeInterfacePanel):
bl_space_type = 'NODE_EDITOR'
bl_region_type = 'UI'
bl_category = "Group"
bl_label = "Outputs"
- @classmethod
- def poll(cls, context):
- snode = context.space_data
- return snode.edit_tree is not None
-
def draw(self, context):
self.draw_socket_list(context, "OUT", "outputs", "active_output")
diff --git a/release/scripts/startup/bl_ui/space_userpref.py b/release/scripts/startup/bl_ui/space_userpref.py
index 9cc21228090..089dcd1c1a7 100644
--- a/release/scripts/startup/bl_ui/space_userpref.py
+++ b/release/scripts/startup/bl_ui/space_userpref.py
@@ -2277,6 +2277,7 @@ class USERPREF_PT_experimental_prototypes(ExperimentalPanel, Panel):
({"property": "use_new_point_cloud_type"}, "T75717"),
({"property": "use_full_frame_compositor"}, "T88150"),
({"property": "enable_eevee_next"}, "T93220"),
+ ({"property": "use_draw_manager_acquire_lock"}, "T98016"),
),
)
diff --git a/release/scripts/startup/bl_ui/space_view3d.py b/release/scripts/startup/bl_ui/space_view3d.py
index 94a4988f791..b9f2ad6259a 100644
--- a/release/scripts/startup/bl_ui/space_view3d.py
+++ b/release/scripts/startup/bl_ui/space_view3d.py
@@ -1235,24 +1235,23 @@ class VIEW3D_MT_view_viewpoint(Menu):
def draw(self, _context):
layout = self.layout
- i18n_text_ctxt = bpy.app.translations.contexts_C_to_py['BLT_I18NCONTEXT_EDITOR_VIEW3D']
- layout.operator("view3d.view_camera", text="Camera", text_ctxt=i18n_text_ctxt)
+ layout.operator("view3d.view_camera", text="Camera", text_ctxt=i18n_contexts.editor_view3d)
layout.separator()
- layout.operator("view3d.view_axis", text="Top", text_ctxt=i18n_text_ctxt).type = 'TOP'
- layout.operator("view3d.view_axis", text="Bottom", text_ctxt=i18n_text_ctxt).type = 'BOTTOM'
+ layout.operator("view3d.view_axis", text="Top", text_ctxt=i18n_contexts.editor_view3d).type = 'TOP'
+ layout.operator("view3d.view_axis", text="Bottom", text_ctxt=i18n_contexts.editor_view3d).type = 'BOTTOM'
layout.separator()
- layout.operator("view3d.view_axis", text="Front", text_ctxt=i18n_text_ctxt).type = 'FRONT'
- layout.operator("view3d.view_axis", text="Back", text_ctxt=i18n_text_ctxt).type = 'BACK'
+ layout.operator("view3d.view_axis", text="Front", text_ctxt=i18n_contexts.editor_view3d).type = 'FRONT'
+ layout.operator("view3d.view_axis", text="Back", text_ctxt=i18n_contexts.editor_view3d).type = 'BACK'
layout.separator()
- layout.operator("view3d.view_axis", text="Right", text_ctxt=i18n_text_ctxt).type = 'RIGHT'
- layout.operator("view3d.view_axis", text="Left", text_ctxt=i18n_text_ctxt).type = 'LEFT'
+ layout.operator("view3d.view_axis", text="Right", text_ctxt=i18n_contexts.editor_view3d).type = 'RIGHT'
+ layout.operator("view3d.view_axis", text="Left", text_ctxt=i18n_contexts.editor_view3d).type = 'LEFT'
class VIEW3D_MT_view_navigation(Menu):
@@ -1319,33 +1318,32 @@ class VIEW3D_MT_view_align_selected(Menu):
def draw(self, _context):
layout = self.layout
- i18n_text_ctxt = bpy.app.translations.contexts_C_to_py['BLT_I18NCONTEXT_EDITOR_VIEW3D']
- props = layout.operator("view3d.view_axis", text="Top", text_ctxt=i18n_text_ctxt)
+ props = layout.operator("view3d.view_axis", text="Top", text_ctxt=i18n_contexts.editor_view3d)
props.align_active = True
props.type = 'TOP'
- props = layout.operator("view3d.view_axis", text="Bottom", text_ctxt=i18n_text_ctxt)
+ props = layout.operator("view3d.view_axis", text="Bottom", text_ctxt=i18n_contexts.editor_view3d)
props.align_active = True
props.type = 'BOTTOM'
layout.separator()
- props = layout.operator("view3d.view_axis", text="Front", text_ctxt=i18n_text_ctxt)
+ props = layout.operator("view3d.view_axis", text="Front", text_ctxt=i18n_contexts.editor_view3d)
props.align_active = True
props.type = 'FRONT'
- props = layout.operator("view3d.view_axis", text="Back", text_ctxt=i18n_text_ctxt)
+ props = layout.operator("view3d.view_axis", text="Back", text_ctxt=i18n_contexts.editor_view3d)
props.align_active = True
props.type = 'BACK'
layout.separator()
- props = layout.operator("view3d.view_axis", text="Right", text_ctxt=i18n_text_ctxt)
+ props = layout.operator("view3d.view_axis", text="Right", text_ctxt=i18n_contexts.editor_view3d)
props.align_active = True
props.type = 'RIGHT'
- props = layout.operator("view3d.view_axis", text="Left", text_ctxt=i18n_text_ctxt)
+ props = layout.operator("view3d.view_axis", text="Left", text_ctxt=i18n_contexts.editor_view3d)
props.align_active = True
props.type = 'LEFT'
diff --git a/release/scripts/startup/nodeitems_builtins.py b/release/scripts/startup/nodeitems_builtins.py
index 4f94184f006..f9bd4342b6e 100644
--- a/release/scripts/startup/nodeitems_builtins.py
+++ b/release/scripts/startup/nodeitems_builtins.py
@@ -145,10 +145,10 @@ def geometry_node_items(context):
yield NodeItem("GeometryNodeConvexHull")
yield NodeItem("GeometryNodeDeleteGeometry")
yield NodeItem("GeometryNodeDuplicateElements")
- yield NodeItem("GeometryNodeGeometryToInstance")
- yield NodeItem("GeometryNodeMergeByDistance")
yield NodeItem("GeometryNodeProximity")
+ yield NodeItem("GeometryNodeGeometryToInstance")
yield NodeItem("GeometryNodeJoinGeometry")
+ yield NodeItem("GeometryNodeMergeByDistance")
yield NodeItem("GeometryNodeRaycast")
yield NodeItem("GeometryNodeSeparateComponents")
yield NodeItem("GeometryNodeSeparateGeometry")
diff --git a/source/blender/blenkernel/BKE_unit.h b/source/blender/blenkernel/BKE_unit.h
index d6de95a19b7..823d32f83ba 100644
--- a/source/blender/blenkernel/BKE_unit.h
+++ b/source/blender/blenkernel/BKE_unit.h
@@ -91,7 +91,7 @@ const char *BKE_unit_identifier_get(const void *usys_pt, int index);
double BKE_unit_scalar_get(const void *usys_pt, int index);
bool BKE_unit_is_suppressed(const void *usys_pt, int index);
-/** Aligned with #PropertyUnit. */
+/** Aligned with #PropertyUnit and `bpyunits_ucategories_items` in `bpy_utils_units.c`. */
enum {
B_UNIT_NONE = 0,
B_UNIT_LENGTH = 1,
diff --git a/source/blender/blenkernel/intern/blendfile_link_append.c b/source/blender/blenkernel/intern/blendfile_link_append.c
index 555c4690308..f9eea52360e 100644
--- a/source/blender/blenkernel/intern/blendfile_link_append.c
+++ b/source/blender/blenkernel/intern/blendfile_link_append.c
@@ -400,7 +400,9 @@ typedef struct LooseDataInstantiateContext {
static bool object_in_any_scene(Main *bmain, Object *ob)
{
LISTBASE_FOREACH (Scene *, sce, &bmain->scenes) {
- if (BKE_scene_object_find(sce, ob)) {
+ /* #BKE_scene_has_object checks bases cache of the scenes' viewlayer, not actual content of
+ * their collections. */
+ if (BKE_collection_has_object_recursive(sce->master_collection, ob)) {
return true;
}
}
diff --git a/source/blender/blenkernel/intern/brush.c b/source/blender/blenkernel/intern/brush.c
index 0593db34e20..3f243d04965 100644
--- a/source/blender/blenkernel/intern/brush.c
+++ b/source/blender/blenkernel/intern/brush.c
@@ -2029,7 +2029,7 @@ float BKE_brush_sample_tex_3d(const Scene *scene,
/* leave the coordinates relative to the screen */
/* use unadjusted size for tiled mode */
- invradius = 1.0f / BKE_brush_size_get(scene, br);
+ invradius = 1.0f / ups->start_pixel_radius;
x = point_2d[0];
y = point_2d[1];
@@ -2142,7 +2142,7 @@ float BKE_brush_sample_masktex(
/* leave the coordinates relative to the screen */
/* use unadjusted size for tiled mode */
- invradius = 1.0f / BKE_brush_size_get(scene, br);
+ invradius = 1.0f / ups->start_pixel_radius;
x = point_2d[0];
y = point_2d[1];
diff --git a/source/blender/blenkernel/intern/curve_to_mesh_convert.cc b/source/blender/blenkernel/intern/curve_to_mesh_convert.cc
index 88e0bae0c13..ef921797698 100644
--- a/source/blender/blenkernel/intern/curve_to_mesh_convert.cc
+++ b/source/blender/blenkernel/intern/curve_to_mesh_convert.cc
@@ -668,12 +668,12 @@ Mesh *curve_to_mesh_sweep(const CurvesGeometry &main,
Vector<std::byte> eval_buffer;
- Curves main_id = {nullptr};
+ Curves main_id = {{nullptr}};
main_id.geometry = reinterpret_cast<const ::CurvesGeometry &>(main);
CurveComponent main_component;
main_component.replace(&main_id, GeometryOwnershipType::Editable);
- Curves profile_id = {nullptr};
+ Curves profile_id = {{nullptr}};
profile_id.geometry = reinterpret_cast<const ::CurvesGeometry &>(profile);
CurveComponent profile_component;
profile_component.replace(&profile_id, GeometryOwnershipType::Editable);
diff --git a/source/blender/blenkernel/intern/image_save.cc b/source/blender/blenkernel/intern/image_save.cc
index 0d7d238f3b2..5361f234a63 100644
--- a/source/blender/blenkernel/intern/image_save.cc
+++ b/source/blender/blenkernel/intern/image_save.cc
@@ -600,10 +600,11 @@ bool BKE_image_render_write_exr(ReportList *reports,
const bool pass_half_float = half_float && pass_RGBA;
/* Colorspace conversion only happens on RGBA passes. */
- float *output_rect = (save_as_render && pass_RGBA) ?
- image_exr_from_scene_linear_to_output(
- rp->rect, rr->rectx, rr->recty, 4, imf, tmp_output_rects) :
- rp->rect;
+ float *output_rect =
+ (save_as_render && pass_RGBA) ?
+ image_exr_from_scene_linear_to_output(
+ rp->rect, rr->rectx, rr->recty, rp->channels, imf, tmp_output_rects) :
+ rp->rect;
for (int a = 0; a < rp->channels; a++) {
/* Save Combined as RGBA if single layer save. */
diff --git a/source/blender/blenkernel/intern/lib_override.c b/source/blender/blenkernel/intern/lib_override.c
index a2338eb9b39..67df6b5527e 100644
--- a/source/blender/blenkernel/intern/lib_override.c
+++ b/source/blender/blenkernel/intern/lib_override.c
@@ -1105,8 +1105,8 @@ static void lib_override_library_create_post_process(Main *bmain,
if (ID_REAL_USERS(ob_new) != 0) {
continue;
}
- default_instantiating_collection = BKE_collection_add(
- bmain, (Collection *)id_root, "OVERRIDE_HIDDEN");
+ default_instantiating_collection = BKE_id_new(bmain, ID_GR, "OVERRIDE_HIDDEN");
+ id_us_min(&default_instantiating_collection->id);
/* Hide the collection from viewport and render. */
default_instantiating_collection->flag |= COLLECTION_HIDE_VIEWPORT |
COLLECTION_HIDE_RENDER;
@@ -1140,6 +1140,20 @@ static void lib_override_library_create_post_process(Main *bmain,
}
}
+ if (id_root != NULL && !ELEM(default_instantiating_collection, NULL, scene->master_collection)) {
+ ID *id_ref = id_root->newid != NULL ? id_root->newid : id_root;
+ switch (GS(id_ref->name)) {
+ case ID_GR:
+ BKE_collection_add_from_collection(
+ bmain, scene, (Collection *)id_ref, default_instantiating_collection);
+ break;
+ default:
+ /* Add to master collection. */
+ BKE_collection_add_from_collection(bmain, scene, NULL, default_instantiating_collection);
+ break;
+ }
+ }
+
BLI_gset_free(all_objects_in_scene, NULL);
}
@@ -1384,7 +1398,21 @@ void BKE_lib_override_library_main_hierarchy_root_ensure(Main *bmain)
continue;
}
if (id->override_library->hierarchy_root != NULL) {
- continue;
+ if (!ID_IS_OVERRIDE_LIBRARY_REAL(id->override_library->hierarchy_root) ||
+ id->override_library->hierarchy_root->lib != id->lib) {
+ CLOG_ERROR(
+ &LOG,
+ "Existing override hierarchy root ('%s') for ID '%s' is invalid, will try to find a "
+ "new valid one",
+ id->override_library->hierarchy_root != NULL ?
+ id->override_library->hierarchy_root->name :
+ "<NONE>",
+ id->name);
+ id->override_library->hierarchy_root = NULL;
+ }
+ else {
+ continue;
+ }
}
BKE_main_relations_tag_set(bmain, MAINIDRELATIONS_ENTRY_TAGS_PROCESSED, false);
@@ -1402,7 +1430,7 @@ void BKE_lib_override_library_main_hierarchy_root_ensure(Main *bmain)
continue;
}
- lib_override_root_hierarchy_set(bmain, id_root, id_root, NULL);
+ lib_override_root_hierarchy_set(bmain, id_root, id, NULL);
BLI_assert(id->override_library->hierarchy_root != NULL);
}
@@ -1451,6 +1479,7 @@ static void lib_override_library_remap(Main *bmain,
remapper,
ID_REMAP_FORCE_USER_REFCOUNT | ID_REMAP_FORCE_NEVER_NULL_USAGE);
BKE_id_remapper_free(remapper);
+ BLI_linklist_free(nomain_ids, NULL);
}
static bool lib_override_library_resync(Main *bmain,
@@ -2058,6 +2087,10 @@ static bool lib_override_resync_tagging_finalize_recurse(
CLOG_INFO(&LOG, 4, "Found root ID '%s' for resync root ID '%s'", id_root->name, id->name);
+ if (id_root->override_library == NULL) {
+ BLI_assert(0);
+ }
+
LinkNodePair **id_resync_roots_p;
if (!BLI_ghash_ensure_p(id_roots, id_root, (void ***)&id_resync_roots_p)) {
*id_resync_roots_p = MEM_callocN(sizeof(**id_resync_roots_p), __func__);
diff --git a/source/blender/blenkernel/intern/subdiv_modifier.c b/source/blender/blenkernel/intern/subdiv_modifier.c
index 83772f153d9..3692a3cc4f7 100644
--- a/source/blender/blenkernel/intern/subdiv_modifier.c
+++ b/source/blender/blenkernel/intern/subdiv_modifier.c
@@ -77,7 +77,7 @@ static bool is_subdivision_evaluation_possible_on_gpu(void)
return false;
}
- if (GPU_max_shader_storage_buffer_bindings() < MAX_GPU_SUBDIV_SSBOS) {
+ if (GPU_max_compute_shader_storage_blocks() < MAX_GPU_SUBDIV_SSBOS) {
return false;
}
diff --git a/source/blender/blenlib/BLI_string.h b/source/blender/blenlib/BLI_string.h
index 45abac33795..0344622e81d 100644
--- a/source/blender/blenlib/BLI_string.h
+++ b/source/blender/blenlib/BLI_string.h
@@ -343,8 +343,16 @@ int BLI_strcmp_ignore_pad(const char *str1, const char *str2, char pad) ATTR_WAR
*/
size_t BLI_strnlen(const char *str, size_t maxlen) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
+/**
+ * String case conversion, not affected by locale.
+ */
+
void BLI_str_tolower_ascii(char *str, size_t len) ATTR_NONNULL();
void BLI_str_toupper_ascii(char *str, size_t len) ATTR_NONNULL();
+
+char BLI_tolower_ascii(const char c);
+char BLI_toupper_ascii(const char c);
+
/**
* Strip white-space from end of the string.
*/
diff --git a/source/blender/blenlib/intern/string.c b/source/blender/blenlib/intern/string.c
index 74559751d91..8387eb5f4f9 100644
--- a/source/blender/blenlib/intern/string.c
+++ b/source/blender/blenlib/intern/string.c
@@ -914,14 +914,22 @@ size_t BLI_strnlen(const char *s, const size_t maxlen)
/** \name String Case Conversion
* \{ */
+char BLI_tolower_ascii(const char c)
+{
+ return (c >= 'A' && c <= 'Z') ? c + ('a' - 'A') : c;
+}
+
+char BLI_toupper_ascii(const char c)
+{
+ return (c >= 'a' && c <= 'z') ? c - ('a' - 'A') : c;
+}
+
void BLI_str_tolower_ascii(char *str, const size_t len)
{
size_t i;
for (i = 0; (i < len) && str[i]; i++) {
- if (str[i] >= 'A' && str[i] <= 'Z') {
- str[i] += 'a' - 'A';
- }
+ str[i] = BLI_tolower_ascii(str[i]);
}
}
@@ -930,9 +938,7 @@ void BLI_str_toupper_ascii(char *str, const size_t len)
size_t i;
for (i = 0; (i < len) && str[i]; i++) {
- if (str[i] >= 'a' && str[i] <= 'z') {
- str[i] -= 'a' - 'A';
- }
+ str[i] = BLI_toupper_ascii(str[i]);
}
}
diff --git a/source/blender/bmesh/intern/bmesh_log.c b/source/blender/bmesh/intern/bmesh_log.c
index a398f14b312..a55eb74285d 100644
--- a/source/blender/bmesh/intern/bmesh_log.c
+++ b/source/blender/bmesh/intern/bmesh_log.c
@@ -288,6 +288,8 @@ static void bm_log_verts_restore(BMesh *bm, BMLog *log, GHash *verts)
static void bm_log_faces_restore(BMesh *bm, BMLog *log, GHash *faces)
{
GHashIterator gh_iter;
+ const int cd_face_sets = CustomData_get_offset(&bm->pdata, CD_SCULPT_FACE_SETS);
+
GHASH_ITER (gh_iter, faces) {
void *key = BLI_ghashIterator_getKey(&gh_iter);
BMLogFace *lf = BLI_ghashIterator_getValue(&gh_iter);
@@ -301,6 +303,11 @@ static void bm_log_faces_restore(BMesh *bm, BMLog *log, GHash *faces)
f = BM_face_create_verts(bm, v, 3, NULL, BM_CREATE_NOP, true);
f->head.hflag = lf->hflag;
bm_log_face_id_set(log, f, POINTER_AS_UINT(key));
+
+ /* Ensure face sets have valid values. Fixes T80174. */
+ if (cd_face_sets != -1) {
+ BM_ELEM_CD_SET_INT(f, cd_face_sets, 1);
+ }
}
}
diff --git a/source/blender/depsgraph/intern/builder/deg_builder_relations.cc b/source/blender/depsgraph/intern/builder/deg_builder_relations.cc
index 23147b63e27..5eccb5a4eb2 100644
--- a/source/blender/depsgraph/intern/builder/deg_builder_relations.cc
+++ b/source/blender/depsgraph/intern/builder/deg_builder_relations.cc
@@ -1693,6 +1693,22 @@ void DepsgraphRelationBuilder::build_driver_variables(ID *id, FCurve *fcu)
continue;
}
add_relation(variable_exit_key, driver_key, "RNA Target -> Driver");
+
+ /* The RNA getter for `object.data` can write to the mesh datablock due
+ * to the call to `BKE_mesh_wrapper_ensure_subdivision()`. This relation
+ * ensures it is safe to call when the driver is evaluated.
+ *
+ * For the sake of making the code more generic/defensive, the relation
+ * is added for any geometry type.
+ *
+ * See T96289 for more info. */
+ if (object != nullptr && OB_TYPE_IS_GEOMETRY(object->type)) {
+ StringRef rna_path(dtar->rna_path);
+ if (rna_path == "data" || rna_path.startswith("data.")) {
+ ComponentKey ob_key(target_id, NodeType::GEOMETRY);
+ add_relation(ob_key, driver_key, "ID -> Driver");
+ }
+ }
}
else {
/* If rna_path is nullptr, and DTAR_FLAG_STRUCT_REF isn't set, this
diff --git a/source/blender/draw/CMakeLists.txt b/source/blender/draw/CMakeLists.txt
index ed90e77572e..1ff7585165b 100644
--- a/source/blender/draw/CMakeLists.txt
+++ b/source/blender/draw/CMakeLists.txt
@@ -333,6 +333,7 @@ set(GLSL_SRC
engines/eevee/shaders/renderpass_lib.glsl
engines/eevee/shaders/renderpass_postprocess_frag.glsl
engines/eevee/shaders/cryptomatte_frag.glsl
+ engines/eevee/shaders/cryptomatte_vert.glsl
engines/eevee/shaders/ltc_lib.glsl
engines/eevee/shaders/ssr_lib.glsl
engines/eevee/shaders/surface_frag.glsl
diff --git a/source/blender/draw/engines/eevee/eevee_cryptomatte.c b/source/blender/draw/engines/eevee/eevee_cryptomatte.c
index 50302eaa87a..b17efe4b68d 100644
--- a/source/blender/draw/engines/eevee/eevee_cryptomatte.c
+++ b/source/blender/draw/engines/eevee/eevee_cryptomatte.c
@@ -189,11 +189,8 @@ void EEVEE_cryptomatte_cache_init(EEVEE_ViewLayerData *UNUSED(sldata), EEVEE_Dat
}
}
-static DRWShadingGroup *eevee_cryptomatte_shading_group_create(EEVEE_Data *vedata,
- EEVEE_ViewLayerData *UNUSED(sldata),
- Object *ob,
- Material *material,
- bool is_hair)
+static DRWShadingGroup *eevee_cryptomatte_shading_group_create(
+ EEVEE_Data *vedata, EEVEE_ViewLayerData *sldata, Object *ob, Material *material, bool is_hair)
{
const DRWContextState *draw_ctx = DRW_context_state_get();
const ViewLayer *view_layer = draw_ctx->view_layer;
@@ -229,6 +226,7 @@ static DRWShadingGroup *eevee_cryptomatte_shading_group_create(EEVEE_Data *vedat
DRWShadingGroup *grp = DRW_shgroup_create(EEVEE_shaders_cryptomatte_sh_get(is_hair),
psl->cryptomatte_ps);
DRW_shgroup_uniform_vec4_copy(grp, "cryptohash", cryptohash);
+ DRW_shgroup_uniform_block(grp, "shadow_block", sldata->shadow_ubo);
return grp;
}
diff --git a/source/blender/draw/engines/eevee/eevee_data.c b/source/blender/draw/engines/eevee/eevee_data.c
index 0c56b67ca99..1a1e3b80bad 100644
--- a/source/blender/draw/engines/eevee/eevee_data.c
+++ b/source/blender/draw/engines/eevee/eevee_data.c
@@ -114,7 +114,9 @@ void EEVEE_motion_blur_data_free(EEVEE_MotionBlurData *mb)
}
}
-EEVEE_ObjectMotionData *EEVEE_motion_blur_object_data_get(EEVEE_MotionBlurData *mb, Object *ob)
+EEVEE_ObjectMotionData *EEVEE_motion_blur_object_data_get(EEVEE_MotionBlurData *mb,
+ Object *ob,
+ bool is_psys)
{
if (mb->object == NULL) {
return NULL;
@@ -123,14 +125,16 @@ EEVEE_ObjectMotionData *EEVEE_motion_blur_object_data_get(EEVEE_MotionBlurData *
EEVEE_ObjectKey key, *key_p;
/* Assumes that all instances have the same object pointer. This is currently the case because
* instance objects are temporary objects on the stack. */
- key.ob = ob;
+ /* WORKAROUND: Duplicate object key for particle system (hairs) to be able to store dupli offset
+ * matrix along with the emitter obmat. (see T97380) */
+ key.ob = (void *)((char *)ob + is_psys);
DupliObject *dup = DRW_object_get_dupli(ob);
if (dup) {
key.parent = DRW_object_get_dupli_parent(ob);
memcpy(key.id, dup->persistent_id, sizeof(key.id));
}
else {
- key.parent = key.ob;
+ key.parent = ob;
memset(key.id, 0, sizeof(key.id));
}
diff --git a/source/blender/draw/engines/eevee/eevee_motion_blur.c b/source/blender/draw/engines/eevee/eevee_motion_blur.c
index 2e0937dbe49..a3ca19c88e1 100644
--- a/source/blender/draw/engines/eevee/eevee_motion_blur.c
+++ b/source/blender/draw/engines/eevee/eevee_motion_blur.c
@@ -226,7 +226,8 @@ void EEVEE_motion_blur_hair_cache_populate(EEVEE_ViewLayerData *UNUSED(sldata),
}
/* For now we assume hair objects are always moving. */
- EEVEE_ObjectMotionData *mb_data = EEVEE_motion_blur_object_data_get(&effects->motion_blur, ob);
+ EEVEE_ObjectMotionData *mb_data = EEVEE_motion_blur_object_data_get(
+ &effects->motion_blur, ob, true);
if (mb_data) {
int mb_step = effects->motion_blur_step;
@@ -283,7 +284,8 @@ void EEVEE_motion_blur_curves_cache_populate(EEVEE_ViewLayerData *UNUSED(sldata)
}
/* For now we assume curves objects are always moving. */
- EEVEE_ObjectMotionData *mb_data = EEVEE_motion_blur_object_data_get(&effects->motion_blur, ob);
+ EEVEE_ObjectMotionData *mb_data = EEVEE_motion_blur_object_data_get(
+ &effects->motion_blur, ob, false);
if (mb_data == NULL) {
return;
}
@@ -354,7 +356,8 @@ void EEVEE_motion_blur_cache_populate(EEVEE_ViewLayerData *UNUSED(sldata),
return;
}
- EEVEE_ObjectMotionData *mb_data = EEVEE_motion_blur_object_data_get(&effects->motion_blur, ob);
+ EEVEE_ObjectMotionData *mb_data = EEVEE_motion_blur_object_data_get(
+ &effects->motion_blur, ob, false);
if (mb_data) {
int mb_step = effects->motion_blur_step;
diff --git a/source/blender/draw/engines/eevee/eevee_private.h b/source/blender/draw/engines/eevee/eevee_private.h
index 6128556d364..b03a4fa70b4 100644
--- a/source/blender/draw/engines/eevee/eevee_private.h
+++ b/source/blender/draw/engines/eevee/eevee_private.h
@@ -644,8 +644,10 @@ typedef struct EEVEE_MotionBlurData {
} EEVEE_MotionBlurData;
typedef struct EEVEE_ObjectKey {
- /** Object or source object for duplis */
- struct Object *ob;
+ /** Object or source object for duplis. */
+ /** WORKAROUND: The pointer is different for particle systems and do not point to the real
+ * object. (See T97380) */
+ void *ob;
/** Parent object for duplis */
struct Object *parent;
/** Dupli objects recursive unique identifier */
@@ -1093,7 +1095,9 @@ EEVEE_ViewLayerData *EEVEE_view_layer_data_ensure_ex(struct ViewLayer *view_laye
EEVEE_ViewLayerData *EEVEE_view_layer_data_ensure(void);
EEVEE_ObjectEngineData *EEVEE_object_data_get(Object *ob);
EEVEE_ObjectEngineData *EEVEE_object_data_ensure(Object *ob);
-EEVEE_ObjectMotionData *EEVEE_motion_blur_object_data_get(EEVEE_MotionBlurData *mb, Object *ob);
+EEVEE_ObjectMotionData *EEVEE_motion_blur_object_data_get(EEVEE_MotionBlurData *mb,
+ Object *ob,
+ bool is_psys);
EEVEE_GeometryMotionData *EEVEE_motion_blur_geometry_data_get(EEVEE_ObjectMotionData *mb_data);
EEVEE_HairMotionData *EEVEE_motion_blur_hair_data_get(EEVEE_ObjectMotionData *mb_data, Object *ob);
EEVEE_HairMotionData *EEVEE_motion_blur_curves_data_get(EEVEE_ObjectMotionData *mb_data);
diff --git a/source/blender/draw/engines/eevee/eevee_shaders.c b/source/blender/draw/engines/eevee/eevee_shaders.c
index 85cc7f65126..105600d2333 100644
--- a/source/blender/draw/engines/eevee/eevee_shaders.c
+++ b/source/blender/draw/engines/eevee/eevee_shaders.c
@@ -183,6 +183,7 @@ extern char datatoc_closure_eval_volume_lib_glsl[];
extern char datatoc_common_uniforms_lib_glsl[];
extern char datatoc_common_utiltex_lib_glsl[];
extern char datatoc_cryptomatte_frag_glsl[];
+extern char datatoc_cryptomatte_vert_glsl[];
extern char datatoc_cubemap_lib_glsl[];
extern char datatoc_default_frag_glsl[];
extern char datatoc_lookdev_world_frag_glsl[];
@@ -305,6 +306,7 @@ static void eevee_shader_library_ensure(void)
DRW_SHADER_LIB_ADD(e_data.lib, closure_eval_refraction_lib);
DRW_SHADER_LIB_ADD(e_data.lib, closure_eval_surface_lib);
DRW_SHADER_LIB_ADD(e_data.lib, closure_eval_volume_lib);
+ DRW_SHADER_LIB_ADD(e_data.lib, surface_vert);
e_data.surface_lit_frag = DRW_shader_library_create_shader_string(e_data.lib,
datatoc_surface_frag_glsl);
@@ -718,7 +720,7 @@ GPUShader *EEVEE_shaders_cryptomatte_sh_get(bool is_hair)
if (e_data.cryptomatte_sh[index] == NULL) {
DynStr *ds = BLI_dynstr_new();
BLI_dynstr_append(ds, SHADER_DEFINES);
-
+ BLI_dynstr_append(ds, "#define attrib_load(a) \n");
if (is_hair) {
BLI_dynstr_append(ds, "#define HAIR_SHADER\n");
}
@@ -727,7 +729,7 @@ GPUShader *EEVEE_shaders_cryptomatte_sh_get(bool is_hair)
}
char *defines = BLI_dynstr_get_cstring(ds);
e_data.cryptomatte_sh[index] = DRW_shader_create_with_shaderlib(
- datatoc_surface_vert_glsl, NULL, datatoc_cryptomatte_frag_glsl, e_data.lib, defines);
+ datatoc_cryptomatte_vert_glsl, NULL, datatoc_cryptomatte_frag_glsl, e_data.lib, defines);
BLI_dynstr_free(ds);
MEM_freeN(defines);
}
diff --git a/source/blender/draw/engines/eevee/shaders/closure_eval_surface_lib.glsl b/source/blender/draw/engines/eevee/shaders/closure_eval_surface_lib.glsl
index f85ef4a89a4..0f5290a7c07 100644
--- a/source/blender/draw/engines/eevee/shaders/closure_eval_surface_lib.glsl
+++ b/source/blender/draw/engines/eevee/shaders/closure_eval_surface_lib.glsl
@@ -309,16 +309,19 @@ vec4 closure_to_rgba(Closure closure)
return vec4(closure.radiance, 1.0 - saturate(avg(closure.transmittance)));
}
-Closure closure_add(Closure cl1, Closure cl2)
+Closure closure_add(inout Closure cl1, inout Closure cl2)
{
Closure cl;
cl.radiance = cl1.radiance + cl2.radiance;
cl.transmittance = cl1.transmittance + cl2.transmittance;
cl.holdout = cl1.holdout + cl2.holdout;
+ /* Make sure each closure is only added once to the result. */
+ cl1 = CLOSURE_DEFAULT;
+ cl2 = CLOSURE_DEFAULT;
return cl;
}
-Closure closure_mix(Closure cl1, Closure cl2, float fac)
+Closure closure_mix(inout Closure cl1, inout Closure cl2, float fac)
{
/* Weights have already been applied. */
return closure_add(cl1, cl2);
diff --git a/source/blender/draw/engines/eevee/shaders/closure_eval_volume_lib.glsl b/source/blender/draw/engines/eevee/shaders/closure_eval_volume_lib.glsl
index e450b8ad3c8..5e34d654cfd 100644
--- a/source/blender/draw/engines/eevee/shaders/closure_eval_volume_lib.glsl
+++ b/source/blender/draw/engines/eevee/shaders/closure_eval_volume_lib.glsl
@@ -92,7 +92,7 @@ vec4 closure_to_rgba(Closure closure)
return vec4(0.0);
}
-Closure closure_mix(Closure cl1, Closure cl2, float fac)
+Closure closure_mix(inout Closure cl1, inout Closure cl2, float fac)
{
Closure cl;
cl.absorption = mix(cl1.absorption, cl2.absorption, fac);
@@ -102,7 +102,7 @@ Closure closure_mix(Closure cl1, Closure cl2, float fac)
return cl;
}
-Closure closure_add(Closure cl1, Closure cl2)
+Closure closure_add(inout Closure cl1, inout Closure cl2)
{
Closure cl;
cl.absorption = cl1.absorption + cl2.absorption;
diff --git a/source/blender/draw/engines/eevee/shaders/closure_type_lib.glsl b/source/blender/draw/engines/eevee/shaders/closure_type_lib.glsl
index 9698b5ea6f5..21d347942ca 100644
--- a/source/blender/draw/engines/eevee/shaders/closure_type_lib.glsl
+++ b/source/blender/draw/engines/eevee/shaders/closure_type_lib.glsl
@@ -87,8 +87,8 @@ Closure closure_eval(ClosureDiffuse diffuse,
ClosureReflection clearcoat,
ClosureRefraction refraction);
-Closure closure_add(Closure cl1, Closure cl2);
-Closure closure_mix(Closure cl1, Closure cl2, float fac);
+Closure closure_add(inout Closure cl1, inout Closure cl2);
+Closure closure_mix(inout Closure cl1, inout Closure cl2, float fac);
float ambient_occlusion_eval(vec3 normal,
float distance,
diff --git a/source/blender/draw/engines/eevee/shaders/cryptomatte_vert.glsl b/source/blender/draw/engines/eevee/shaders/cryptomatte_vert.glsl
new file mode 100644
index 00000000000..f8dbc4772e9
--- /dev/null
+++ b/source/blender/draw/engines/eevee/shaders/cryptomatte_vert.glsl
@@ -0,0 +1,6 @@
+
+#pragma BLENDER_REQUIRE(closure_type_lib.glsl)
+#pragma BLENDER_REQUIRE(common_view_lib.glsl)
+#pragma BLENDER_REQUIRE(common_math_lib.glsl)
+#pragma BLENDER_REQUIRE(common_attribute_lib.glsl)
+#pragma BLENDER_REQUIRE(surface_vert.glsl)
diff --git a/source/blender/draw/engines/eevee/shaders/surface_lib.glsl b/source/blender/draw/engines/eevee/shaders/surface_lib.glsl
index 1f2f7cb65cc..696e5d4c97b 100644
--- a/source/blender/draw/engines/eevee/shaders/surface_lib.glsl
+++ b/source/blender/draw/engines/eevee/shaders/surface_lib.glsl
@@ -112,6 +112,7 @@ GlobalData init_globals(void)
surf.N = -surf.N;
}
# ifdef HAIR_SHADER
+ vec3 V = cameraVec(surf.P);
/* Shade as a cylinder. */
vec3 B = normalize(cross(worldNormal, hairTangent));
float cos_theta;
@@ -125,7 +126,10 @@ GlobalData init_globals(void)
}
float sin_theta = sqrt(max(0.0, 1.0 - cos_theta * cos_theta));
surf.N = safe_normalize(worldNormal * sin_theta + B * cos_theta);
- surf.T = hairTangent;
+ surf.curve_T = -hairTangent;
+ /* Costly, but follows cycles per pixel tangent space (not following curve shape). */
+ surf.curve_B = cross(V, surf.curve_T);
+ surf.curve_N = safe_normalize(cross(surf.curve_T, surf.curve_B));
surf.is_strand = true;
surf.hair_time = hairTime;
surf.hair_thickness = hairThickness;
@@ -134,7 +138,7 @@ GlobalData init_globals(void)
surf.barycentric_coords = hair_resolve_barycentric(hairBary);
# endif
# else
- surf.T = vec3(0.0);
+ surf.curve_T = surf.curve_B = surf.curve_N = vec3(0.0);
surf.is_strand = false;
surf.hair_time = 0.0;
surf.hair_thickness = 0.0;
diff --git a/source/blender/draw/engines/eevee_next/shaders/eevee_attributes_lib.glsl b/source/blender/draw/engines/eevee_next/shaders/eevee_attributes_lib.glsl
index abecb373995..3c5acf62e30 100644
--- a/source/blender/draw/engines/eevee_next/shaders/eevee_attributes_lib.glsl
+++ b/source/blender/draw/engines/eevee_next/shaders/eevee_attributes_lib.glsl
@@ -164,7 +164,7 @@ float attr_load_float(samplerBuffer cd_buf)
* \{ */
# ifndef OBINFO_LIB
-# error "draw_object_infos is mandatory for volume objects"
+# error draw_object_infos is mandatory for volume objects
# endif
vec3 g_orco;
diff --git a/source/blender/draw/engines/eevee_next/shaders/eevee_geom_curves_vert.glsl b/source/blender/draw/engines/eevee_next/shaders/eevee_geom_curves_vert.glsl
index 11f93ad0d14..708bd153e84 100644
--- a/source/blender/draw/engines/eevee_next/shaders/eevee_geom_curves_vert.glsl
+++ b/source/blender/draw/engines/eevee_next/shaders/eevee_geom_curves_vert.glsl
@@ -18,7 +18,7 @@ void main()
ViewMatrixInverse[3].xyz,
ViewMatrixInverse[2].xyz,
interp.P,
- T,
+ interp.curves_tangent,
interp.curves_binormal,
interp.curves_time,
interp.curves_thickness,
diff --git a/source/blender/draw/engines/eevee_next/shaders/eevee_nodetree_lib.glsl b/source/blender/draw/engines/eevee_next/shaders/eevee_nodetree_lib.glsl
index 06191a5c007..277b2e35d8b 100644
--- a/source/blender/draw/engines/eevee_next/shaders/eevee_nodetree_lib.glsl
+++ b/source/blender/draw/engines/eevee_next/shaders/eevee_nodetree_lib.glsl
@@ -9,6 +9,7 @@ float g_holdout;
/* The Closure type is never used. Use float as dummy type. */
#define Closure float
+#define CLOSURE_DEFAULT 0.0
/* Sampled closure parameters. */
ClosureDiffuse g_diffuse_data;
diff --git a/source/blender/draw/engines/eevee_next/shaders/eevee_surf_lib.glsl b/source/blender/draw/engines/eevee_next/shaders/eevee_surf_lib.glsl
index 0d8644c9901..30b48edaa78 100644
--- a/source/blender/draw/engines/eevee_next/shaders/eevee_surf_lib.glsl
+++ b/source/blender/draw/engines/eevee_next/shaders/eevee_surf_lib.glsl
@@ -42,6 +42,12 @@ void init_globals_curves()
float sin_theta = sqrt(max(0.0, 1.0 - cos_theta * cos_theta));
g_data.N = normalize(interp.N * sin_theta + interp.curves_binormal * cos_theta);
+ /* Costly, but follows cycles per pixel tangent space (not following curve shape). */
+ vec3 V = cameraVec(g_data.P);
+ g_data.curve_T = -interp.curves_tangent;
+ g_data.curve_B = cross(V, g_data.curve_T);
+ g_data.curve_N = safe_normalize(cross(g_data.curve_T, g_data.curve_B));
+
g_data.is_strand = true;
g_data.hair_time = interp.curves_time;
g_data.hair_thickness = interp.curves_thickness;
@@ -94,6 +100,7 @@ void init_interface()
interp.P = vec3(0.0);
interp.N = vec3(0.0);
interp.barycentric_coords = vec2(0.0);
+ interp.curves_tangent = vec3(0.0);
interp.curves_binormal = vec3(0.0);
interp.curves_time = 0.0;
interp.curves_time_width = 0.0;
diff --git a/source/blender/draw/engines/eevee_next/shaders/infos/eevee_material_info.hh b/source/blender/draw/engines/eevee_next/shaders/infos/eevee_material_info.hh
index e829a41d682..4d6895bcde0 100644
--- a/source/blender/draw/engines/eevee_next/shaders/infos/eevee_material_info.hh
+++ b/source/blender/draw/engines/eevee_next/shaders/infos/eevee_material_info.hh
@@ -54,6 +54,7 @@ GPU_SHADER_INTERFACE_INFO(eevee_surf_iface, "interp")
.smooth(Type::VEC3, "P")
.smooth(Type::VEC3, "N")
.smooth(Type::VEC2, "barycentric_coords")
+ .smooth(Type::VEC3, "curves_tangent")
.smooth(Type::VEC3, "curves_binormal")
.smooth(Type::FLOAT, "curves_time")
.smooth(Type::FLOAT, "curves_time_width")
diff --git a/source/blender/draw/engines/overlay/overlay_shader.c b/source/blender/draw/engines/overlay/overlay_shader.c
index d63ae6750d6..48146fbddfb 100644
--- a/source/blender/draw/engines/overlay/overlay_shader.c
+++ b/source/blender/draw/engines/overlay/overlay_shader.c
@@ -893,7 +893,7 @@ GPUShader *OVERLAY_shader_edit_uv_edges_get(void)
{
OVERLAY_Shaders *sh_data = &e_data.sh_data[0];
if (!sh_data->edit_uv_edges) {
- sh_data->edit_uv_edges = GPU_shader_create_from_info_name("overlay_edit_uv_edges_select");
+ sh_data->edit_uv_edges = GPU_shader_create_from_info_name("overlay_edit_uv_edges");
}
return sh_data->edit_uv_edges;
}
@@ -903,7 +903,7 @@ GPUShader *OVERLAY_shader_edit_uv_edges_for_edge_select_get(void)
OVERLAY_Shaders *sh_data = &e_data.sh_data[0];
if (!sh_data->edit_uv_edges_for_edge_select) {
sh_data->edit_uv_edges_for_edge_select = GPU_shader_create_from_info_name(
- "overlay_edit_uv_edges");
+ "overlay_edit_uv_edges_select");
}
return sh_data->edit_uv_edges_for_edge_select;
}
diff --git a/source/blender/draw/engines/overlay/shaders/edit_uv_edges_geom.glsl b/source/blender/draw/engines/overlay/shaders/edit_uv_edges_geom.glsl
index 1012b50e0e1..ac8d33cd727 100644
--- a/source/blender/draw/engines/overlay/shaders/edit_uv_edges_geom.glsl
+++ b/source/blender/draw/engines/overlay/shaders/edit_uv_edges_geom.glsl
@@ -1,8 +1,5 @@
#pragma BLENDER_REQUIRE(common_overlay_lib.glsl)
-layout(lines) in;
-layout(triangle_strip, max_vertices = 4) out;
-
void do_vertex(
vec4 pos, float selection_fac, vec2 stipple_start, vec2 stipple_pos, float coord, vec2 offset)
{
diff --git a/source/blender/draw/intern/draw_cache_extract.h b/source/blender/draw/intern/draw_cache_extract.h
index 4567e470146..cb6006e303a 100644
--- a/source/blender/draw/intern/draw_cache_extract.h
+++ b/source/blender/draw/intern/draw_cache_extract.h
@@ -328,7 +328,6 @@ void mesh_buffer_cache_create_requested(struct TaskGraph *task_graph,
const float obmat[4][4],
bool do_final,
bool do_uvedit,
- bool use_subsurf_fdots,
const Scene *scene,
const struct ToolSettings *ts,
bool use_hide);
diff --git a/source/blender/draw/intern/draw_cache_extract_mesh.cc b/source/blender/draw/intern/draw_cache_extract_mesh.cc
index 8a7b4fc9703..ec544d8e786 100644
--- a/source/blender/draw/intern/draw_cache_extract_mesh.cc
+++ b/source/blender/draw/intern/draw_cache_extract_mesh.cc
@@ -563,7 +563,6 @@ static void mesh_buffer_cache_create_requested(struct TaskGraph *task_graph,
const float obmat[4][4],
const bool do_final,
const bool do_uvedit,
- const bool use_subsurf_fdots,
const Scene *scene,
const ToolSettings *ts,
const bool use_hide)
@@ -687,7 +686,7 @@ static void mesh_buffer_cache_create_requested(struct TaskGraph *task_graph,
MeshRenderData *mr = mesh_render_data_create(
object, me, is_editmode, is_paint_mode, is_mode_active, obmat, do_final, do_uvedit, ts);
mr->use_hide = use_hide;
- mr->use_subsurf_fdots = use_subsurf_fdots;
+ mr->use_subsurf_fdots = mr->me && mr->me->runtime.subsurf_face_dot_tags != nullptr;
mr->use_final_mesh = do_final;
#ifdef DEBUG_TIME
@@ -919,7 +918,6 @@ void mesh_buffer_cache_create_requested(struct TaskGraph *task_graph,
const float obmat[4][4],
const bool do_final,
const bool do_uvedit,
- const bool use_subsurf_fdots,
const Scene *scene,
const ToolSettings *ts,
const bool use_hide)
@@ -935,7 +933,6 @@ void mesh_buffer_cache_create_requested(struct TaskGraph *task_graph,
obmat,
do_final,
do_uvedit,
- use_subsurf_fdots,
scene,
ts,
use_hide);
diff --git a/source/blender/draw/intern/draw_cache_impl_mesh.c b/source/blender/draw/intern/draw_cache_impl_mesh.c
index 917216b92e6..7dc0244275d 100644
--- a/source/blender/draw/intern/draw_cache_impl_mesh.c
+++ b/source/blender/draw/intern/draw_cache_impl_mesh.c
@@ -708,12 +708,18 @@ static DRW_MeshCDMask mesh_cd_calc_used_gpu_layers(const Object *object,
case CD_MCOL:
case CD_PROP_BYTE_COLOR:
case CD_PROP_COLOR: {
+ /* First check Color attributes, when not found check mesh attributes. Geometry nodes
+ * can generate those layers. */
int vcol_bit = mesh_cd_calc_gpu_layers_vcol_used(&me_query, cd_vdata, cd_ldata, name);
if (vcol_bit != -1) {
cd_used.vcol |= 1UL << (uint)vcol_bit;
+ break;
}
+ if (layer != -1 && domain != ATTR_DOMAIN_NUM) {
+ drw_mesh_attributes_add_request(attributes, type, layer, domain);
+ }
break;
}
case CD_PROP_FLOAT3:
@@ -1231,11 +1237,11 @@ static void sculpt_request_active_vcol(MeshBatchCache *cache, Object *object, Me
&me_query.id, render, ATTR_DOMAIN_MASK_COLOR, CD_MASK_COLOR_ALL);
if (active_i >= 0) {
- cache->cd_used.vcol |= 1UL << (uint)active_i;
+ cache->cd_needed.vcol |= 1UL << (uint)active_i;
}
if (render_i >= 0) {
- cache->cd_used.vcol |= 1UL << (uint)render_i;
+ cache->cd_needed.vcol |= 1UL << (uint)render_i;
}
}
@@ -2128,8 +2134,6 @@ void DRW_mesh_batch_cache_create_requested(struct TaskGraph *task_graph,
MDEPS_ASSERT_MAP_INDEX(TRIS_PER_MAT_INDEX);
- const bool use_subsurf_fdots = me->runtime.subsurf_face_dot_tags != NULL;
-
if (do_uvcage) {
mesh_buffer_cache_create_requested(task_graph,
cache,
@@ -2142,7 +2146,6 @@ void DRW_mesh_batch_cache_create_requested(struct TaskGraph *task_graph,
ob->obmat,
false,
true,
- false,
scene,
ts,
true);
@@ -2160,7 +2163,6 @@ void DRW_mesh_batch_cache_create_requested(struct TaskGraph *task_graph,
ob->obmat,
false,
false,
- use_subsurf_fdots,
scene,
ts,
true);
@@ -2178,7 +2180,6 @@ void DRW_mesh_batch_cache_create_requested(struct TaskGraph *task_graph,
ob->obmat,
true,
false,
- use_subsurf_fdots,
ts,
use_hide);
}
@@ -2199,7 +2200,6 @@ void DRW_mesh_batch_cache_create_requested(struct TaskGraph *task_graph,
ob->obmat,
true,
false,
- use_subsurf_fdots,
scene,
ts,
use_hide);
diff --git a/source/blender/draw/intern/draw_cache_impl_subdivision.cc b/source/blender/draw/intern/draw_cache_impl_subdivision.cc
index 7d245f4158b..8eb0509d615 100644
--- a/source/blender/draw/intern/draw_cache_impl_subdivision.cc
+++ b/source/blender/draw/intern/draw_cache_impl_subdivision.cc
@@ -1904,7 +1904,6 @@ static bool draw_subdiv_create_requested_buffers(const Scene *scene,
const float obmat[4][4],
const bool do_final,
const bool do_uvedit,
- const bool /*use_subsurf_fdots*/,
const ToolSettings *ts,
const bool /*use_hide*/,
OpenSubdiv_EvaluatorCache *evaluator_cache)
@@ -2103,7 +2102,6 @@ void DRW_create_subdivision(const Scene *scene,
const float obmat[4][4],
const bool do_final,
const bool do_uvedit,
- const bool use_subsurf_fdots,
const ToolSettings *ts,
const bool use_hide)
{
@@ -2128,7 +2126,6 @@ void DRW_create_subdivision(const Scene *scene,
obmat,
do_final,
do_uvedit,
- use_subsurf_fdots,
ts,
use_hide,
g_evaluator_cache)) {
diff --git a/source/blender/draw/intern/draw_manager.c b/source/blender/draw/intern/draw_manager.c
index 6ab8d30109e..4bbcf6eaf42 100644
--- a/source/blender/draw/intern/draw_manager.c
+++ b/source/blender/draw/intern/draw_manager.c
@@ -1287,7 +1287,7 @@ void DRW_notify_view_update(const DRWUpdateContext *update_ctx)
const bool gpencil_engine_needed = drw_gpencil_engine_needed(depsgraph, v3d);
- if (G.is_rendering) {
+ if (G.is_rendering && U.experimental.use_draw_manager_acquire_lock) {
return;
}
diff --git a/source/blender/draw/intern/draw_subdivision.h b/source/blender/draw/intern/draw_subdivision.h
index d803fad5052..b7cd520f54f 100644
--- a/source/blender/draw/intern/draw_subdivision.h
+++ b/source/blender/draw/intern/draw_subdivision.h
@@ -194,7 +194,6 @@ void DRW_create_subdivision(const struct Scene *scene,
const float obmat[4][4],
const bool do_final,
const bool do_uvedit,
- const bool use_subsurf_fdots,
const ToolSettings *ts,
const bool use_hide);
diff --git a/source/blender/draw/intern/mesh_extractors/extract_mesh_ibo_edituv.cc b/source/blender/draw/intern/mesh_extractors/extract_mesh_ibo_edituv.cc
index 43aa52f08c8..2c4e7bfa802 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
@@ -387,8 +387,7 @@ static void extract_edituv_points_iter_poly_mesh(const MeshRenderData *mr,
for (int ml_index = mp->loopstart; ml_index < ml_index_end; ml_index += 1) {
const MLoop *ml = &mloop[ml_index];
- const bool real_vert = (mr->extract_type == MR_EXTRACT_MAPPED && (mr->v_origindex) &&
- mr->v_origindex[ml->v] != ORIGINDEX_NONE);
+ const bool real_vert = !mr->v_origindex || mr->v_origindex[ml->v] != ORIGINDEX_NONE;
edituv_point_add(
data, ((mp->flag & ME_HIDE) != 0) || !real_vert, (mp->flag & ME_FACE_SEL) != 0, ml_index);
}
@@ -449,9 +448,8 @@ static void extract_edituv_points_iter_subdiv_mesh(const DRWSubdivCache *subdiv_
uint end_loop_idx = (subdiv_quad_index + 1) * 4;
for (uint i = start_loop_idx; i < end_loop_idx; i++) {
const int vert_origindex = subdiv_loop_vert_index[i];
- const bool real_vert = (mr->extract_type == MR_EXTRACT_MAPPED && (mr->v_origindex) &&
- vert_origindex != -1 &&
- mr->v_origindex[vert_origindex] != ORIGINDEX_NONE);
+ const bool real_vert = !mr->v_origindex || (vert_origindex != -1 &&
+ mr->v_origindex[vert_origindex] != ORIGINDEX_NONE);
edituv_point_add(data,
((coarse_quad->flag & ME_HIDE) != 0) || !real_vert,
(coarse_quad->flag & ME_FACE_SEL) != 0,
@@ -543,8 +541,7 @@ static void extract_edituv_fdots_iter_poly_mesh(const MeshRenderData *mr,
for (int ml_index = mp->loopstart; ml_index < ml_index_end; ml_index += 1) {
const MLoop *ml = &mloop[ml_index];
- const bool real_fdot = (mr->extract_type == MR_EXTRACT_MAPPED && mr->p_origindex &&
- mr->p_origindex[mp_index] != ORIGINDEX_NONE);
+ const bool real_fdot = !mr->p_origindex || (mr->p_origindex[mp_index] != ORIGINDEX_NONE);
const bool subd_fdot = BLI_BITMAP_TEST(facedot_tags, ml->v);
edituv_facedot_add(data,
((mp->flag & ME_HIDE) != 0) || !real_fdot || !subd_fdot,
@@ -553,8 +550,7 @@ static void extract_edituv_fdots_iter_poly_mesh(const MeshRenderData *mr,
}
}
else {
- const bool real_fdot = (mr->extract_type == MR_EXTRACT_MAPPED && mr->p_origindex &&
- mr->p_origindex[mp_index] != ORIGINDEX_NONE);
+ const bool real_fdot = !mr->p_origindex || (mr->p_origindex[mp_index] != ORIGINDEX_NONE);
edituv_facedot_add(
data, ((mp->flag & ME_HIDE) != 0) || !real_fdot, (mp->flag & ME_FACE_SEL) != 0, mp_index);
}
diff --git a/source/blender/editors/gpencil/gpencil_select.c b/source/blender/editors/gpencil/gpencil_select.c
index fe2fa832477..da5c8b311e7 100644
--- a/source/blender/editors/gpencil/gpencil_select.c
+++ b/source/blender/editors/gpencil/gpencil_select.c
@@ -2685,6 +2685,7 @@ void GPENCIL_OT_select(wmOperatorType *ot)
ot->invoke = gpencil_select_invoke;
ot->exec = gpencil_select_exec;
ot->poll = gpencil_select_poll;
+ ot->get_name = ED_select_pick_get_name;
/* flag */
ot->flag = OPTYPE_UNDO;
diff --git a/source/blender/editors/include/ED_select_utils.h b/source/blender/editors/include/ED_select_utils.h
index dbe1b582132..fa02ebe18f6 100644
--- a/source/blender/editors/include/ED_select_utils.h
+++ b/source/blender/editors/include/ED_select_utils.h
@@ -14,6 +14,7 @@ extern "C" {
struct KDTree_1d;
struct wmOperator;
+struct wmOperatorType;
enum {
SEL_TOGGLE = 0,
@@ -96,16 +97,23 @@ struct SelectPick_Params {
/**
* Utility to get #eSelectPickMode from booleans for convenience.
*/
-eSelectOp ED_select_op_from_operator(struct wmOperator *op)
+eSelectOp ED_select_op_from_operator(struct PointerRNA *ptr)
ATTR_NONNULL(1) ATTR_WARN_UNUSED_RESULT;
/**
* Initialize `params` from `op`,
* these properties are defined by #WM_operator_properties_mouse_select.
*/
-void ED_select_pick_params_from_operator(struct wmOperator *op, struct SelectPick_Params *params)
+void ED_select_pick_params_from_operator(struct PointerRNA *ptr, struct SelectPick_Params *params)
ATTR_NONNULL(1, 2);
+/**
+ * Get-name callback for #wmOperatorType.get_name, this is mainly useful so the selection
+ * action is shown in the status-bar.
+ */
+const char *ED_select_pick_get_name(struct wmOperatorType *ot, PointerRNA *ptr);
+const char *ED_select_circle_get_name(struct wmOperatorType *ot, PointerRNA *ptr);
+
#ifdef __cplusplus
}
#endif
diff --git a/source/blender/editors/include/ED_uvedit.h b/source/blender/editors/include/ED_uvedit.h
index 4c01c75e06c..06134f1d7b5 100644
--- a/source/blender/editors/include/ED_uvedit.h
+++ b/source/blender/editors/include/ED_uvedit.h
@@ -268,6 +268,10 @@ struct BMLoop **ED_uvedit_selected_verts(const struct Scene *scene,
int *r_verts_len);
void ED_uvedit_get_aspect(struct Object *obedit, float *r_aspx, float *r_aspy);
+void ED_uvedit_get_aspect_from_material(Object *ob,
+ const int material_index,
+ float *r_aspx,
+ float *r_aspy);
void ED_uvedit_active_vert_loop_set(struct BMesh *bm, struct BMLoop *l);
struct BMLoop *ED_uvedit_active_vert_loop_get(struct BMesh *bm);
diff --git a/source/blender/editors/include/UI_interface.h b/source/blender/editors/include/UI_interface.h
index 0ae3cb010ed..3d247a9b5e3 100644
--- a/source/blender/editors/include/UI_interface.h
+++ b/source/blender/editors/include/UI_interface.h
@@ -184,26 +184,26 @@ enum {
/** #uiBut.flag general state flags. */
enum {
- /* WARNING: the first 7 flags are internal (see #UI_SELECT definition). */
- UI_BUT_ICON_SUBMENU = 1 << 7,
- UI_BUT_ICON_PREVIEW = 1 << 8,
+ /* WARNING: the first 8 flags are internal (see #UI_SELECT definition). */
+ UI_BUT_ICON_SUBMENU = 1 << 8,
+ UI_BUT_ICON_PREVIEW = 1 << 9,
- UI_BUT_NODE_LINK = 1 << 9,
- UI_BUT_NODE_ACTIVE = 1 << 10,
- UI_BUT_DRAG_LOCK = 1 << 11,
+ UI_BUT_NODE_LINK = 1 << 10,
+ UI_BUT_NODE_ACTIVE = 1 << 11,
+ UI_BUT_DRAG_LOCK = 1 << 12,
/** Grayed out and un-editable. */
- UI_BUT_DISABLED = 1 << 12,
+ UI_BUT_DISABLED = 1 << 13,
- UI_BUT_ANIMATED = 1 << 13,
- UI_BUT_ANIMATED_KEY = 1 << 14,
- UI_BUT_DRIVEN = 1 << 15,
- UI_BUT_REDALERT = 1 << 16,
+ UI_BUT_ANIMATED = 1 << 14,
+ UI_BUT_ANIMATED_KEY = 1 << 15,
+ UI_BUT_DRIVEN = 1 << 16,
+ UI_BUT_REDALERT = 1 << 17,
/** Grayed out but still editable. */
- UI_BUT_INACTIVE = 1 << 17,
- UI_BUT_LAST_ACTIVE = 1 << 18,
- UI_BUT_UNDO = 1 << 19,
- UI_BUT_IMMEDIATE = 1 << 20,
- UI_BUT_NO_UTF8 = 1 << 21,
+ UI_BUT_INACTIVE = 1 << 18,
+ UI_BUT_LAST_ACTIVE = 1 << 19,
+ UI_BUT_UNDO = 1 << 20,
+ UI_BUT_IMMEDIATE = 1 << 21,
+ UI_BUT_NO_UTF8 = 1 << 22,
/** For popups, pressing return activates this button, overriding the highlighted button.
* For non-popups this is just used as a display hint for the user to let them
diff --git a/source/blender/editors/interface/interface.cc b/source/blender/editors/interface/interface.cc
index b7098c26bcd..480044118f1 100644
--- a/source/blender/editors/interface/interface.cc
+++ b/source/blender/editors/interface/interface.cc
@@ -1861,15 +1861,32 @@ bool ui_but_context_poll_operator_ex(bContext *C,
const wmOperatorCallParams *optype_params)
{
bool result;
+ int old_but_flag = 0;
- if (but && but->context) {
- CTX_store_set(C, but->context);
+ if (but) {
+ old_but_flag = but->flag;
+
+ /* Temporarily make this button override the active one, in case the poll acts on the active
+ * button. */
+ const_cast<uiBut *>(but)->flag |= UI_BUT_ACTIVE_OVERRIDE;
+
+ if (but->context) {
+ CTX_store_set(C, but->context);
+ }
}
result = WM_operator_poll_context(C, optype_params->optype, optype_params->opcontext);
- if (but && but->context) {
- CTX_store_set(C, nullptr);
+ if (but) {
+ BLI_assert_msg((but->flag & ~UI_BUT_ACTIVE_OVERRIDE) ==
+ (old_but_flag & ~UI_BUT_ACTIVE_OVERRIDE),
+ "Operator polls shouldn't change button flags");
+
+ const_cast<uiBut *>(but)->flag = old_but_flag;
+
+ if (but->context) {
+ CTX_store_set(C, nullptr);
+ }
}
return result;
diff --git a/source/blender/editors/interface/interface_handlers.c b/source/blender/editors/interface/interface_handlers.c
index 2c408619fe7..9d7d76f0bdb 100644
--- a/source/blender/editors/interface/interface_handlers.c
+++ b/source/blender/editors/interface/interface_handlers.c
@@ -384,6 +384,12 @@ typedef struct uiHandleButtonData {
/* True when alt is held and the preference for displaying tooltips should be ignored. */
bool tooltip_force;
+ /**
+ * Behave as if #UI_BUT_DISABLED is set (without drawing grayed out).
+ * Needed so non-interactive labels can be activated for the purpose of showing tool-tips,
+ * without them blocking interaction with nodes, see: T97386.
+ */
+ bool disable_force;
/* auto open */
bool used_mouse;
@@ -1669,7 +1675,7 @@ static void ui_drag_toggle_set(bContext *C, uiDragToggleHandle *drag_info, const
*/
if (drag_info->is_xy_lock_init == false) {
/* first store the buttons original coords */
- uiBut *but = ui_but_find_mouse_over_ex(region, xy_input, true, NULL, NULL);
+ uiBut *but = ui_but_find_mouse_over_ex(region, xy_input, true, false, NULL, NULL);
if (but) {
if (but->flag & UI_BUT_DRAG_LOCK) {
@@ -1739,7 +1745,7 @@ static int ui_handler_region_drag_toggle(bContext *C, const wmEvent *event, void
if (done) {
wmWindow *win = CTX_wm_window(C);
const ARegion *region = CTX_wm_region(C);
- uiBut *but = ui_but_find_mouse_over_ex(region, drag_info->xy_init, true, NULL, NULL);
+ uiBut *but = ui_but_find_mouse_over_ex(region, drag_info->xy_init, true, false, NULL, NULL);
if (but) {
ui_apply_but_undo(but);
@@ -4324,7 +4330,7 @@ static uiBut *ui_but_list_row_text_activate(bContext *C,
uiButtonActivateType activate_type)
{
ARegion *region = CTX_wm_region(C);
- uiBut *labelbut = ui_but_find_mouse_over_ex(region, event->xy, true, NULL, NULL);
+ uiBut *labelbut = ui_but_find_mouse_over_ex(region, event->xy, true, false, NULL, NULL);
if (labelbut && labelbut->type == UI_BTYPE_TEXT && !(labelbut->flag & UI_BUT_DISABLED)) {
/* exit listrow */
@@ -4346,14 +4352,14 @@ static uiBut *ui_but_list_row_text_activate(bContext *C,
* \{ */
static uiButExtraOpIcon *ui_but_extra_operator_icon_mouse_over_get(uiBut *but,
- uiHandleButtonData *data,
+ ARegion *region,
const wmEvent *event)
{
float xmax = but->rect.xmax;
const float icon_size = 0.8f * BLI_rctf_size_y(&but->rect); /* ICON_SIZE_FROM_BUTRECT */
int x = event->xy[0], y = event->xy[1];
- ui_window_to_block(data->region, but->block, &x, &y);
+ ui_window_to_block(region, but->block, &x, &y);
if (!BLI_rctf_isect_pt(&but->rect, x, y)) {
return NULL;
}
@@ -4382,7 +4388,7 @@ static bool ui_do_but_extra_operator_icon(bContext *C,
uiHandleButtonData *data,
const wmEvent *event)
{
- uiButExtraOpIcon *op_icon = ui_but_extra_operator_icon_mouse_over_get(but, data, event);
+ uiButExtraOpIcon *op_icon = ui_but_extra_operator_icon_mouse_over_get(but, data->region, event);
if (!op_icon) {
return false;
@@ -4417,7 +4423,7 @@ static void ui_do_but_extra_operator_icons_mousemove(uiBut *but,
op_icon->highlighted = false;
}
- uiButExtraOpIcon *hovered = ui_but_extra_operator_icon_mouse_over_get(but, data, event);
+ uiButExtraOpIcon *hovered = ui_but_extra_operator_icon_mouse_over_get(but, data->region, event);
if (hovered) {
hovered->highlighted = true;
@@ -4656,7 +4662,7 @@ static int ui_do_but_TEX(
/* pass */
}
else {
- if (!ui_but_extra_operator_icon_mouse_over_get(but, data, event)) {
+ if (!ui_but_extra_operator_icon_mouse_over_get(but, data->region, event)) {
button_activate_state(C, but, BUTTON_STATE_TEXT_EDITING);
}
return WM_UI_HANDLER_BREAK;
@@ -4782,7 +4788,7 @@ static int ui_do_but_TREEROW(bContext *C,
switch (event->val) {
case KM_PRESS:
/* Extra icons have priority, don't mess with them. */
- if (ui_but_extra_operator_icon_mouse_over_get(but, data, event)) {
+ if (ui_but_extra_operator_icon_mouse_over_get(but, data->region, event)) {
return WM_UI_HANDLER_BREAK;
}
button_activate_state(C, but, BUTTON_STATE_WAIT_DRAG);
@@ -7899,7 +7905,7 @@ static int ui_do_button(bContext *C, uiBlock *block, uiBut *but, const wmEvent *
uiHandleButtonData *data = but->active;
int retval = WM_UI_HANDLER_CONTINUE;
- const bool is_disabled = but->flag & UI_BUT_DISABLED;
+ const bool is_disabled = but->flag & UI_BUT_DISABLED || data->disable_force;
/* if but->pointype is set, but->poin should be too */
BLI_assert(!but->pointype || but->poin);
@@ -8216,7 +8222,7 @@ static ARegion *ui_but_tooltip_init(
if (but) {
const wmWindow *win = CTX_wm_window(C);
uiButExtraOpIcon *extra_icon = ui_but_extra_operator_icon_mouse_over_get(
- but, but->active, win->eventstate);
+ but, but->active ? but->active->region : region, win->eventstate);
return UI_tooltip_create_from_button_or_extra_icon(C, region, but, extra_icon, is_label);
}
@@ -8703,20 +8709,38 @@ static uiBut *ui_context_button_active(const ARegion *region, bool (*but_check_c
uiBut *but_found = NULL;
while (region) {
- uiBut *activebut = NULL;
+ /* Follow this exact priority (from highest to lowest priority):
+ * 1) Active-override button (#UI_BUT_ACTIVE_OVERRIDE).
+ * 2) The real active button.
+ * 3) The previously active button (#UI_BUT_LAST_ACTIVE).
+ */
+ uiBut *active_but_override = NULL;
+ uiBut *active_but_real = NULL;
+ uiBut *active_but_last = NULL;
/* find active button */
LISTBASE_FOREACH (uiBlock *, block, &region->uiblocks) {
LISTBASE_FOREACH (uiBut *, but, &block->buttons) {
+ if (but->flag & UI_BUT_ACTIVE_OVERRIDE) {
+ active_but_override = but;
+ }
if (but->active) {
- activebut = but;
+ active_but_real = but;
}
- else if (!activebut && (but->flag & UI_BUT_LAST_ACTIVE)) {
- activebut = but;
+ if (but->flag & UI_BUT_LAST_ACTIVE) {
+ active_but_last = but;
}
}
}
+ uiBut *activebut = active_but_override;
+ if (!activebut) {
+ activebut = active_but_real;
+ }
+ if (!activebut) {
+ activebut = active_but_last;
+ }
+
if (activebut && (but_check_cb == NULL || but_check_cb(activebut))) {
uiHandleButtonData *data = activebut->active;
@@ -8947,7 +8971,12 @@ static uiBut *ui_but_find_open_event(ARegion *region, const wmEvent *event)
static int ui_handle_button_over(bContext *C, const wmEvent *event, ARegion *region)
{
if (event->type == MOUSEMOVE) {
- uiBut *but = ui_but_find_mouse_over(region, event);
+ const bool labeledit = event->modifier & KM_CTRL;
+ /* Allow buttons to be activated to show the tool-tip,
+ * then force-disable them if they're not considered interactive
+ * so they don't swallow events but can still display tips. */
+ const bool for_tooltip = true;
+ uiBut *but = ui_but_find_mouse_over_ex(region, event->xy, labeledit, for_tooltip, NULL, NULL);
if (but) {
button_activate_init(C, region, but, BUTTON_ACTIVATE_OVER);
@@ -8956,6 +8985,10 @@ static int ui_handle_button_over(bContext *C, const wmEvent *event, ARegion *reg
* preferences. */
but->active->tooltip_force = true;
}
+
+ if (but->active && !ui_but_is_interactive(but, labeledit)) {
+ but->active->disable_force = true;
+ }
}
}
else if (event->type == EVT_BUT_OPEN) {
@@ -9435,7 +9468,7 @@ static bool ui_list_is_hovering_draggable_but(bContext *C,
int mouse_xy[2];
WM_event_drag_start_xy(event, mouse_xy);
- const uiBut *hovered_but = ui_but_find_mouse_over_ex(region, mouse_xy, false, NULL, NULL);
+ const uiBut *hovered_but = ui_but_find_mouse_over_ex(region, mouse_xy, false, false, NULL, NULL);
if (list->dyn_data->custom_drag_optype) {
if (ui_but_context_poll_operator(C, list->dyn_data->custom_drag_optype, hovered_but)) {
diff --git a/source/blender/editors/interface/interface_intern.h b/source/blender/editors/interface/interface_intern.h
index c09ff68bbca..1c79d3218fb 100644
--- a/source/blender/editors/interface/interface_intern.h
+++ b/source/blender/editors/interface/interface_intern.h
@@ -74,6 +74,12 @@ enum {
UI_SELECT_DRAW = (1 << 5),
/** Property search filter is active and the button does not match. */
UI_SEARCH_FILTER_NO_MATCH = (1 << 6),
+
+ /** Temporarily override the active button for lookups in context, regions, etc. (everything
+ * using #ui_context_button_active()). For example, so that operators normally acting on the
+ * active button can be polled on non-active buttons to (e.g. for disabling). */
+ UI_BUT_ACTIVE_OVERRIDE = (1 << 7),
+
/* WARNING: rest of #uiBut.flag in UI_interface.h */
};
@@ -1352,6 +1358,7 @@ bool ui_but_is_toggle(const uiBut *but) ATTR_WARN_UNUSED_RESULT;
* \note ctrl is kind of a hack currently,
* so that non-embossed UI_BTYPE_TEXT button behaves as a label when ctrl is not pressed.
*/
+bool ui_but_is_interactive_ex(const uiBut *but, const bool labeledit, const bool for_tooltip);
bool ui_but_is_interactive(const uiBut *but, bool labeledit) ATTR_WARN_UNUSED_RESULT;
bool ui_but_is_popover_once_compat(const uiBut *but) ATTR_WARN_UNUSED_RESULT;
bool ui_but_has_array_value(const uiBut *but) ATTR_WARN_UNUSED_RESULT;
@@ -1388,6 +1395,7 @@ typedef bool (*uiButFindPollFn)(const uiBut *but, const void *customdata);
uiBut *ui_but_find_mouse_over_ex(const struct ARegion *region,
const int xy[2],
bool labeledit,
+ bool for_tooltip,
const uiButFindPollFn find_poll,
const void *find_custom_data)
ATTR_NONNULL(1, 2) ATTR_WARN_UNUSED_RESULT;
diff --git a/source/blender/editors/interface/interface_query.cc b/source/blender/editors/interface/interface_query.cc
index 337b2852d57..ea1fe3923e4 100644
--- a/source/blender/editors/interface/interface_query.cc
+++ b/source/blender/editors/interface/interface_query.cc
@@ -58,12 +58,23 @@ bool ui_but_is_toggle(const uiBut *but)
UI_BTYPE_TREEROW);
}
-bool ui_but_is_interactive(const uiBut *but, const bool labeledit)
+bool ui_but_is_interactive_ex(const uiBut *but, const bool labeledit, const bool for_tooltip)
{
/* NOTE: #UI_BTYPE_LABEL is included for highlights, this allows drags. */
- if ((but->type == UI_BTYPE_LABEL) && but->dragpoin == nullptr && but->tip_func == nullptr) {
- return false;
+ if (but->type == UI_BTYPE_LABEL) {
+ if (for_tooltip) {
+ /* It's important labels are considered interactive for the purpose of showing tooltip. */
+ if (but->dragpoin == nullptr && but->tip_func == nullptr) {
+ return false;
+ }
+ }
+ else {
+ if (but->dragpoin == nullptr) {
+ return false;
+ }
+ }
}
+
if (ELEM(but->type, UI_BTYPE_ROUNDBOX, UI_BTYPE_SEPR, UI_BTYPE_SEPR_LINE, UI_BTYPE_LISTBOX)) {
return false;
}
@@ -84,6 +95,11 @@ bool ui_but_is_interactive(const uiBut *but, const bool labeledit)
return true;
}
+bool ui_but_is_interactive(const uiBut *but, const bool labeledit)
+{
+ return ui_but_is_interactive_ex(but, labeledit, false);
+}
+
bool UI_but_is_utf8(const uiBut *but)
{
if (but->rnaprop) {
@@ -266,6 +282,7 @@ static uiBut *ui_but_find(const ARegion *region,
uiBut *ui_but_find_mouse_over_ex(const ARegion *region,
const int xy[2],
const bool labeledit,
+ const bool for_tooltip,
const uiButFindPollFn find_poll,
const void *find_custom_data)
{
@@ -282,7 +299,7 @@ uiBut *ui_but_find_mouse_over_ex(const ARegion *region,
if (find_poll && find_poll(but, find_custom_data) == false) {
continue;
}
- if (ui_but_is_interactive(but, labeledit)) {
+ if (ui_but_is_interactive_ex(but, labeledit, for_tooltip)) {
if (but->pie_dir != UI_RADIAL_NONE) {
if (ui_but_isect_pie_seg(block, but)) {
butover = but;
@@ -310,7 +327,8 @@ uiBut *ui_but_find_mouse_over_ex(const ARegion *region,
uiBut *ui_but_find_mouse_over(const ARegion *region, const wmEvent *event)
{
- return ui_but_find_mouse_over_ex(region, event->xy, event->modifier & KM_CTRL, nullptr, nullptr);
+ return ui_but_find_mouse_over_ex(
+ region, event->xy, event->modifier & KM_CTRL, false, nullptr, nullptr);
}
uiBut *ui_but_find_rect_over(const struct ARegion *region, const rcti *rect_px)
@@ -414,7 +432,7 @@ static bool ui_but_is_listrow(const uiBut *but, const void *UNUSED(customdata))
uiBut *ui_list_row_find_mouse_over(const ARegion *region, const int xy[2])
{
- return ui_but_find_mouse_over_ex(region, xy, false, ui_but_is_listrow, nullptr);
+ return ui_but_find_mouse_over_ex(region, xy, false, false, ui_but_is_listrow, nullptr);
}
struct ListRowFindIndexData {
@@ -446,7 +464,7 @@ static bool ui_but_is_treerow(const uiBut *but, const void *UNUSED(customdata))
uiBut *ui_tree_row_find_mouse_over(const ARegion *region, const int xy[2])
{
- return ui_but_find_mouse_over_ex(region, xy, false, ui_but_is_treerow, nullptr);
+ return ui_but_find_mouse_over_ex(region, xy, false, false, ui_but_is_treerow, nullptr);
}
static bool ui_but_is_active_treerow(const uiBut *but, const void *customdata)
diff --git a/source/blender/editors/io/CMakeLists.txt b/source/blender/editors/io/CMakeLists.txt
index 418a399db28..ef093a01ff8 100644
--- a/source/blender/editors/io/CMakeLists.txt
+++ b/source/blender/editors/io/CMakeLists.txt
@@ -9,6 +9,7 @@ set(INC
../../depsgraph
../../io/alembic
../../io/collada
+ ../../io/common
../../io/gpencil
../../io/usd
../../io/wavefront_obj
diff --git a/source/blender/editors/io/io_obj.c b/source/blender/editors/io/io_obj.c
index 9156ff15ded..886586ff236 100644
--- a/source/blender/editors/io/io_obj.c
+++ b/source/blender/editors/io/io_obj.c
@@ -29,6 +29,7 @@
#include "DEG_depsgraph.h"
+#include "IO_path_util_types.h"
#include "IO_wavefront_obj.h"
#include "io_obj.h"
@@ -59,6 +60,15 @@ static const EnumPropertyItem io_obj_export_evaluation_mode[] = {
"Export objects as they appear in the viewport"},
{0, NULL, 0, NULL, NULL}};
+static const EnumPropertyItem io_obj_path_mode[] = {
+ {PATH_REFERENCE_AUTO, "AUTO", 0, "Auto", "Use Relative paths with subdirectories only"},
+ {PATH_REFERENCE_ABSOLUTE, "ABSOLUTE", 0, "Absolute", "Always write absolute paths"},
+ {PATH_REFERENCE_RELATIVE, "RELATIVE", 0, "Relative", "Write relative paths where possible"},
+ {PATH_REFERENCE_MATCH, "MATCH", 0, "Match", "Match Absolute/Relative setting with input path"},
+ {PATH_REFERENCE_STRIP, "STRIP", 0, "Strip", "Write filename only"},
+ {PATH_REFERENCE_COPY, "COPY", 0, "Copy", "Copy the file to the destination path"},
+ {0, NULL, 0, NULL, NULL}};
+
static int wm_obj_export_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
{
if (!RNA_struct_property_is_set(op->ptr, "filepath")) {
@@ -87,6 +97,7 @@ static int wm_obj_export_exec(bContext *C, wmOperator *op)
return OPERATOR_CANCELLED;
}
struct OBJExportParams export_params;
+ export_params.file_base_for_tests[0] = '\0';
RNA_string_get(op->ptr, "filepath", export_params.filepath);
export_params.blen_filepath = CTX_data_main(C)->filepath;
export_params.export_animation = RNA_boolean_get(op->ptr, "export_animation");
@@ -103,6 +114,7 @@ static int wm_obj_export_exec(bContext *C, wmOperator *op)
export_params.export_uv = RNA_boolean_get(op->ptr, "export_uv");
export_params.export_normals = RNA_boolean_get(op->ptr, "export_normals");
export_params.export_materials = RNA_boolean_get(op->ptr, "export_materials");
+ export_params.path_mode = RNA_enum_get(op->ptr, "path_mode");
export_params.export_triangulated_mesh = RNA_boolean_get(op->ptr, "export_triangulated_mesh");
export_params.export_curves_as_nurbs = RNA_boolean_get(op->ptr, "export_curves_as_nurbs");
@@ -119,9 +131,9 @@ static int wm_obj_export_exec(bContext *C, wmOperator *op)
static void ui_obj_export_settings(uiLayout *layout, PointerRNA *imfptr)
{
-
const bool export_animation = RNA_boolean_get(imfptr, "export_animation");
const bool export_smooth_groups = RNA_boolean_get(imfptr, "export_smooth_groups");
+ const bool export_materials = RNA_boolean_get(imfptr, "export_materials");
uiLayoutSetPropSep(layout, true);
uiLayoutSetPropDecorate(layout, false);
@@ -150,6 +162,9 @@ static void ui_obj_export_settings(uiLayout *layout, PointerRNA *imfptr)
uiItemR(sub, imfptr, "export_selected_objects", 0, IFACE_("Selected Only"), ICON_NONE);
uiItemR(sub, imfptr, "apply_modifiers", 0, IFACE_("Apply Modifiers"), ICON_NONE);
uiItemR(sub, imfptr, "export_eval_mode", 0, IFACE_("Properties"), ICON_NONE);
+ sub = uiLayoutColumn(sub, false);
+ uiLayoutSetEnabled(sub, export_materials);
+ uiItemR(sub, imfptr, "path_mode", 0, IFACE_("Path Mode"), ICON_NONE);
/* Options for what to write. */
box = uiLayoutBox(layout);
@@ -162,6 +177,7 @@ static void ui_obj_export_settings(uiLayout *layout, PointerRNA *imfptr)
uiItemR(sub, imfptr, "export_triangulated_mesh", 0, IFACE_("Triangulated Mesh"), ICON_NONE);
uiItemR(sub, imfptr, "export_curves_as_nurbs", 0, IFACE_("Curves as NURBS"), ICON_NONE);
+ /* Grouping options. */
box = uiLayoutBox(layout);
uiItemL(box, IFACE_("Grouping"), ICON_GROUP);
col = uiLayoutColumn(box, false);
@@ -322,6 +338,12 @@ void WM_OT_obj_export(struct wmOperatorType *ot)
"Export Materials",
"Export MTL library. There must be a Principled-BSDF node for image textures to "
"be exported to the MTL file");
+ RNA_def_enum(ot->srna,
+ "path_mode",
+ io_obj_path_mode,
+ PATH_REFERENCE_AUTO,
+ "Path Mode",
+ "Method used to reference paths");
RNA_def_boolean(ot->srna,
"export_triangulated_mesh",
false,
diff --git a/source/blender/editors/io/io_usd.c b/source/blender/editors/io/io_usd.c
index e0616a0cec3..ca9c2de63a4 100644
--- a/source/blender/editors/io/io_usd.c
+++ b/source/blender/editors/io/io_usd.c
@@ -190,6 +190,20 @@ static void wm_usd_export_draw(bContext *UNUSED(C), wmOperator *op)
uiItemR(box, ptr, "use_instancing", 0, NULL, ICON_NONE);
}
+static bool wm_usd_export_check(bContext *UNUSED(C), wmOperator *op)
+{
+ char filepath[FILE_MAX];
+ RNA_string_get(op->ptr, "filepath", filepath);
+
+ if (!BLI_path_extension_check_n(filepath, ".usd", ".usda", ".usdc", NULL)) {
+ BLI_path_extension_ensure(filepath, FILE_MAX, ".usdc");
+ RNA_string_set(op->ptr, "filepath", filepath);
+ return true;
+ }
+
+ return false;
+}
+
void WM_OT_usd_export(struct wmOperatorType *ot)
{
ot->name = "Export USD";
@@ -200,6 +214,7 @@ void WM_OT_usd_export(struct wmOperatorType *ot)
ot->exec = wm_usd_export_exec;
ot->poll = WM_operator_winactive;
ot->ui = wm_usd_export_draw;
+ ot->check = wm_usd_export_check;
ot->flag = OPTYPE_REGISTER; /* No UNDO possible. */
diff --git a/source/blender/editors/mask/mask_select.c b/source/blender/editors/mask/mask_select.c
index 0bd054e1b89..1c84cffbcad 100644
--- a/source/blender/editors/mask/mask_select.c
+++ b/source/blender/editors/mask/mask_select.c
@@ -402,6 +402,7 @@ void MASK_OT_select(wmOperatorType *ot)
ot->exec = select_exec;
ot->invoke = select_invoke;
ot->poll = ED_maskedit_mask_poll;
+ ot->get_name = ED_select_pick_get_name;
/* flags */
ot->flag = OPTYPE_UNDO;
@@ -748,6 +749,7 @@ void MASK_OT_select_circle(wmOperatorType *ot)
ot->modal = WM_gesture_circle_modal;
ot->exec = circle_select_exec;
ot->poll = ED_maskedit_mask_poll;
+ ot->get_name = ED_select_pick_get_name;
/* flags */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
diff --git a/source/blender/editors/mesh/editmesh_knife.c b/source/blender/editors/mesh/editmesh_knife.c
index ee40431c101..5d8cf176b87 100644
--- a/source/blender/editors/mesh/editmesh_knife.c
+++ b/source/blender/editors/mesh/editmesh_knife.c
@@ -190,6 +190,22 @@ typedef struct KnifeBVH {
} KnifeBVH;
+/** Additional per-object data. */
+typedef struct KnifeObjectInfo {
+ const float (*cagecos)[3];
+
+ /**
+ * Optionally allocate triangle indices, these are needed for non-interactive knife
+ * projection as multiple cuts are made without the BVH being updated.
+ * Using these indices the it's possible to access `cagecos` even if the face has been cut
+ * and the loops in `em->looptris` no longer refer to the original triangles, see:
+ */
+ const int (*tri_indices)[3];
+
+ /** Only assigned for convenient access. */
+ BMEditMesh *em;
+} KnifeObjectInfo;
+
/* struct for properties used while drawing */
typedef struct KnifeTool_OpData {
ARegion *region; /* Region that knifetool was activated in. */
@@ -203,6 +219,9 @@ typedef struct KnifeTool_OpData {
Object **objects;
uint objects_len;
+ /** Array `objects_len` length of additional per-object data. */
+ KnifeObjectInfo *objects_info;
+
MemArena *arena;
/* Reused for edge-net filling. */
@@ -220,7 +239,6 @@ typedef struct KnifeTool_OpData {
GHash *facetrimap;
KnifeBVH bvh;
- const float (**cagecos)[3];
BLI_mempool *kverts;
BLI_mempool *kedges;
@@ -1134,6 +1152,52 @@ static void knife_update_header(bContext *C, wmOperator *op, KnifeTool_OpData *k
/** \} */
/* -------------------------------------------------------------------- */
+/** \name Knife Object Info Accessors (#KnifeObjectInfo)
+ * \{ */
+
+static const int *knife_bm_tri_index_get(const KnifeTool_OpData *kcd,
+ int base_index,
+ int tri_index,
+ int tri_index_buf[3])
+{
+ const KnifeObjectInfo *obinfo = &kcd->objects_info[base_index];
+ if (obinfo->tri_indices) {
+ return obinfo->tri_indices[tri_index];
+ }
+ for (int i = 0; i < 3; i++) {
+ tri_index_buf[i] = BM_elem_index_get(obinfo->em->looptris[tri_index][i]->v);
+ }
+ return tri_index_buf;
+}
+
+static void knife_bm_tri_cagecos_get(const KnifeTool_OpData *kcd,
+ int base_index,
+ int tri_index,
+ float cos[3][3])
+{
+ const KnifeObjectInfo *obinfo = &kcd->objects_info[base_index];
+ int tri_ind_buf[3];
+ const int *tri_ind = knife_bm_tri_index_get(kcd, base_index, tri_index, tri_ind_buf);
+ for (int i = 0; i < 3; i++) {
+ copy_v3_v3(cos[i], obinfo->cagecos[tri_ind[i]]);
+ }
+}
+
+static void knife_bm_tri_cagecos_get_worldspace(const KnifeTool_OpData *kcd,
+ int base_index,
+ int tri_index,
+ float cos[3][3])
+{
+ knife_bm_tri_cagecos_get(kcd, base_index, tri_index, cos);
+ const Object *ob = kcd->objects[base_index];
+ for (int i = 0; i < 3; i++) {
+ mul_m4_v3(ob->obmat, cos[i]);
+ }
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
/** \name Knife BVH Utils
* \{ */
@@ -1219,16 +1283,7 @@ static void knife_bvh_init(KnifeTool_OpData *kcd)
if (!test_fn_ret) {
continue;
}
-
- copy_v3_v3(cos[0], kcd->cagecos[b][BM_elem_index_get(looptris[i][0]->v)]);
- copy_v3_v3(cos[1], kcd->cagecos[b][BM_elem_index_get(looptris[i][1]->v)]);
- copy_v3_v3(cos[2], kcd->cagecos[b][BM_elem_index_get(looptris[i][2]->v)]);
-
- /* Convert to world-space. */
- mul_m4_v3(ob->obmat, cos[0]);
- mul_m4_v3(ob->obmat, cos[1]);
- mul_m4_v3(ob->obmat, cos[2]);
-
+ knife_bm_tri_cagecos_get_worldspace(kcd, b, i, cos);
BLI_bvhtree_insert(kcd->bvh.tree, i + tottri, (float *)cos, 3);
}
@@ -1282,12 +1337,7 @@ static void knife_bvh_raycast_cb(void *userdata,
}
}
- copy_v3_v3(tri_cos[0], kcd->cagecos[b][BM_elem_index_get(ltri[0]->v)]);
- copy_v3_v3(tri_cos[1], kcd->cagecos[b][BM_elem_index_get(ltri[1]->v)]);
- copy_v3_v3(tri_cos[2], kcd->cagecos[b][BM_elem_index_get(ltri[2]->v)]);
- mul_m4_v3(ob->obmat, tri_cos[0]);
- mul_m4_v3(ob->obmat, tri_cos[1]);
- mul_m4_v3(ob->obmat, tri_cos[2]);
+ knife_bm_tri_cagecos_get_worldspace(kcd, b, index, tri_cos);
isect =
(ray->radius > 0.0f ?
@@ -1684,7 +1734,7 @@ static KnifeVert *get_bm_knife_vert(KnifeTool_OpData *kcd, BMVert *v, Object *ob
BMFace *f;
if (BM_elem_index_get(v) >= 0) {
- cageco = kcd->cagecos[base_index][BM_elem_index_get(v)];
+ cageco = kcd->objects_info[base_index].cagecos[BM_elem_index_get(v)];
}
else {
cageco = v->co;
@@ -2545,12 +2595,8 @@ static bool knife_ray_intersect_face(KnifeTool_OpData *kcd,
if (tri[0]->f != f) {
break;
}
- copy_v3_v3(lv[0], kcd->cagecos[base_index][BM_elem_index_get(tri[0]->v)]);
- copy_v3_v3(lv[1], kcd->cagecos[base_index][BM_elem_index_get(tri[1]->v)]);
- copy_v3_v3(lv[2], kcd->cagecos[base_index][BM_elem_index_get(tri[2]->v)]);
- mul_m4_v3(ob->obmat, lv[0]);
- mul_m4_v3(ob->obmat, lv[1]);
- mul_m4_v3(ob->obmat, lv[2]);
+
+ knife_bm_tri_cagecos_get_worldspace(kcd, base_index, tri_i, lv);
/* Using epsilon test in case ray is directly through an internal
* tessellation edge and might not hit either tessellation tri with
@@ -2605,9 +2651,10 @@ static void calc_ortho_extent(KnifeTool_OpData *kcd)
ob = kcd->objects[b];
em = BKE_editmesh_from_object(ob);
- if (kcd->cagecos[b]) {
+ const float(*cagecos)[3] = kcd->objects_info[b].cagecos;
+ if (cagecos) {
for (int i = 0; i < em->bm->totvert; i++) {
- copy_v3_v3(ws, kcd->cagecos[b][i]);
+ copy_v3_v3(ws, cagecos[i]);
mul_m4_v3(ob->obmat, ws);
minmax_v3v3_v3(min, max, ws);
}
@@ -3961,10 +4008,13 @@ static void knifetool_undo(KnifeTool_OpData *kcd)
/** \} */
/* -------------------------------------------------------------------- */
-/** \name #KnifeTool_OpData (#op->customdata) Init and Free
+/** \name #KnifeObjectInfo (#kcd->objects_info) Init and Free
* \{ */
-static void knifetool_init_cagecos(KnifeTool_OpData *kcd, Object *ob, uint base_index)
+static void knifetool_init_obinfo(KnifeTool_OpData *kcd,
+ Object *ob,
+ uint base_index,
+ bool use_tri_indices)
{
Scene *scene_eval = (Scene *)DEG_get_evaluated_id(kcd->vc.depsgraph, &kcd->scene->id);
@@ -3973,18 +4023,36 @@ static void knifetool_init_cagecos(KnifeTool_OpData *kcd, Object *ob, uint base_
BM_mesh_elem_index_ensure(em_eval->bm, BM_VERT);
- kcd->cagecos[base_index] = (const float(*)[3])BKE_editmesh_vert_coords_alloc(
+ KnifeObjectInfo *obinfo = &kcd->objects_info[base_index];
+ obinfo->em = em_eval;
+ obinfo->cagecos = (const float(*)[3])BKE_editmesh_vert_coords_alloc(
kcd->vc.depsgraph, em_eval, scene_eval, obedit_eval, NULL);
+
+ if (use_tri_indices) {
+ BMLoop *(*looptris)[3] = em_eval->looptris;
+ int(*tri_indices)[3] = MEM_mallocN(sizeof(int[3]) * em_eval->tottri, __func__);
+ for (int i = 0; i < em_eval->tottri; i++) {
+ BMLoop **tri = looptris[i];
+ tri_indices[i][0] = BM_elem_index_get(tri[0]->v);
+ tri_indices[i][1] = BM_elem_index_get(tri[1]->v);
+ tri_indices[i][2] = BM_elem_index_get(tri[2]->v);
+ }
+ obinfo->tri_indices = tri_indices;
+ }
}
-static void knifetool_free_cagecos(KnifeTool_OpData *kcd, uint base_index)
+static void knifetool_free_obinfo(KnifeTool_OpData *kcd, uint base_index)
{
- if (kcd->cagecos[base_index]) {
- MEM_freeN((void *)kcd->cagecos[base_index]);
- kcd->cagecos[base_index] = NULL;
- }
+ MEM_SAFE_FREE(kcd->objects_info[base_index].cagecos);
+ MEM_SAFE_FREE(kcd->objects_info[base_index].tri_indices);
}
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name #KnifeTool_OpData (#op->customdata) Init and Free
+ * \{ */
+
static void knife_init_colors(KnifeColors *colors)
{
/* Possible BMESH_TODO: add explicit themes or calculate these by
@@ -4018,6 +4086,10 @@ static void knifetool_init(bContext *C,
const float angle_snapping_increment,
const bool is_interactive)
{
+ /* Needed so multiple non-interactive cuts (also called knife-project)
+ * doesn't access indices of loops that were created by cutting, see: T97153. */
+ bool use_tri_indices = !is_interactive;
+
kcd->vc = *vc;
Scene *scene = vc->scene;
@@ -4031,11 +4103,11 @@ static void knifetool_init(bContext *C,
Object *ob;
BMEditMesh *em;
- kcd->cagecos = MEM_callocN(sizeof(*kcd->cagecos) * kcd->objects_len, "knife cagecos");
+ kcd->objects_info = MEM_callocN(sizeof(*kcd->objects_info) * kcd->objects_len, "knife cagecos");
for (uint b = 0; b < kcd->objects_len; b++) {
ob = kcd->objects[b];
em = BKE_editmesh_from_object(ob);
- knifetool_init_cagecos(kcd, ob, b);
+ knifetool_init_obinfo(kcd, ob, b, use_tri_indices);
/* Can't usefully select resulting edges in face mode. */
kcd->select_result = (em->selectmode != SCE_SELECT_FACE);
@@ -4139,9 +4211,9 @@ static void knifetool_exit_ex(KnifeTool_OpData *kcd)
/* Knife BVH cleanup. */
for (int i = 0; i < kcd->objects_len; i++) {
- knifetool_free_cagecos(kcd, i);
+ knifetool_free_obinfo(kcd, i);
}
- MEM_freeN((void *)kcd->cagecos);
+ MEM_freeN((void *)kcd->objects_info);
knife_bvh_free(kcd);
/* Line-hits cleanup. */
@@ -4391,7 +4463,8 @@ static int knifetool_modal(bContext *C, wmOperator *op, const wmEvent *event)
ED_workspace_status_text(C, NULL);
return OPERATOR_CANCELLED;
- case KNF_MODAL_CONFIRM:
+ case KNF_MODAL_CONFIRM: {
+ const bool changed = (kcd->totkvert != 0);
/* finish */
ED_region_tag_redraw(kcd->region);
@@ -4400,11 +4473,11 @@ static int knifetool_modal(bContext *C, wmOperator *op, const wmEvent *event)
ED_workspace_status_text(C, NULL);
/* Cancel to prevent undo push for empty cuts. */
- if (kcd->totkvert == 0) {
+ if (!changed) {
return OPERATOR_CANCELLED;
}
-
return OPERATOR_FINISHED;
+ }
case KNF_MODAL_UNDO:
if (BLI_stack_is_empty(kcd->undostack)) {
ED_region_tag_redraw(kcd->region);
diff --git a/source/blender/editors/object/object_relations.c b/source/blender/editors/object/object_relations.c
index 5ef8e573e27..76dcfbd8d36 100644
--- a/source/blender/editors/object/object_relations.c
+++ b/source/blender/editors/object/object_relations.c
@@ -1964,7 +1964,7 @@ static void single_objectdata_action_users(
ID *id_act = (ID *)adt->action;
if (single_data_needs_duplication(id_act)) {
DEG_id_tag_update(&ob->id, ID_RECALC_GEOMETRY);
- BKE_animdata_duplicate_id_action(bmain, &ob->id, USER_DUP_ACT | USER_DUP_LINKED_ID);
+ BKE_animdata_duplicate_id_action(bmain, id_obdata, USER_DUP_ACT | USER_DUP_LINKED_ID);
}
}
}
diff --git a/source/blender/editors/sculpt_paint/paint_image_2d.c b/source/blender/editors/sculpt_paint/paint_image_2d.c
index d30aa4dfab1..fae2e6863fa 100644
--- a/source/blender/editors/sculpt_paint/paint_image_2d.c
+++ b/source/blender/editors/sculpt_paint/paint_image_2d.c
@@ -621,39 +621,38 @@ static void brush_painter_imbuf_partial_update(BrushPainter *painter,
}
static void brush_painter_2d_tex_mapping(ImagePaintState *s,
- ImBuf *canvas,
+ ImagePaintTile *tile,
const int diameter,
- const float startpos[2],
const float pos[2],
const float mouse[2],
int mapmode,
rctf *mapping)
{
- float invw = 1.0f / (float)canvas->x;
- float invh = 1.0f / (float)canvas->y;
- int xmin, ymin, xmax, ymax;
- int ipos[2];
+ float invw = 1.0f / (float)tile->canvas->x;
+ float invh = 1.0f / (float)tile->canvas->y;
+ float start[2];
/* find start coordinate of brush in canvas */
- ipos[0] = (int)floorf((pos[0] - diameter / 2) + 1.0f);
- ipos[1] = (int)floorf((pos[1] - diameter / 2) + 1.0f);
+ start[0] = pos[0] - diameter / 2.0f;
+ start[1] = pos[1] - diameter / 2.0f;
if (mapmode == MTEX_MAP_MODE_STENCIL) {
/* map from view coordinates of brush to region coordinates */
- UI_view2d_view_to_region(s->v2d, ipos[0] * invw, ipos[1] * invh, &xmin, &ymin);
- UI_view2d_view_to_region(
- s->v2d, (ipos[0] + diameter) * invw, (ipos[1] + diameter) * invh, &xmax, &ymax);
+ float xmin, ymin, xmax, ymax;
+ UI_view2d_view_to_region_fl(s->v2d, start[0] * invw, start[1] * invh, &xmin, &ymin);
+ UI_view2d_view_to_region_fl(
+ s->v2d, (start[0] + diameter) * invw, (start[1] + diameter) * invh, &xmax, &ymax);
/* output mapping from brush ibuf x/y to region coordinates */
- mapping->xmin = xmin;
- mapping->ymin = ymin;
mapping->xmax = (xmax - xmin) / (float)diameter;
mapping->ymax = (ymax - ymin) / (float)diameter;
+ mapping->xmin = xmin + (tile->uv_origin[0] * tile->size[0] * mapping->xmax);
+ mapping->ymin = ymin + (tile->uv_origin[1] * tile->size[1] * mapping->ymax);
}
else if (mapmode == MTEX_MAP_MODE_3D) {
/* 3D mapping, just mapping to canvas 0..1. */
- mapping->xmin = 2.0f * (ipos[0] * invw - 0.5f);
- mapping->ymin = 2.0f * (ipos[1] * invh - 0.5f);
+ mapping->xmin = 2.0f * (start[0] * invw - 0.5f);
+ mapping->ymin = 2.0f * (start[1] * invh - 0.5f);
mapping->xmax = 2.0f * invw;
mapping->ymax = 2.0f * invh;
}
@@ -665,8 +664,10 @@ static void brush_painter_2d_tex_mapping(ImagePaintState *s,
mapping->ymax = 1.0f;
}
else /* if (mapmode == MTEX_MAP_MODE_TILED) */ {
- mapping->xmin = (int)(-diameter * 0.5) + (int)floorf(pos[0]) - (int)floorf(startpos[0]);
- mapping->ymin = (int)(-diameter * 0.5) + (int)floorf(pos[1]) - (int)floorf(startpos[1]);
+ mapping->xmin = (int)(-diameter * 0.5) + (int)floorf(pos[0]) -
+ (int)floorf(tile->start_paintpos[0]);
+ mapping->ymin = (int)(-diameter * 0.5) + (int)floorf(pos[1]) -
+ (int)floorf(tile->start_paintpos[1]);
mapping->xmax = 1.0f;
mapping->ymax = 1.0f;
}
@@ -711,14 +712,8 @@ static void brush_painter_2d_refresh_cache(ImagePaintState *s,
do_partial_update = true;
}
- brush_painter_2d_tex_mapping(s,
- tile->canvas,
- diameter,
- tile->start_paintpos,
- pos,
- mouse,
- brush->mtex.brush_map_mode,
- &painter->tex_mapping);
+ brush_painter_2d_tex_mapping(
+ s, tile, diameter, pos, mouse, brush->mtex.brush_map_mode, &painter->tex_mapping);
}
if (cache->is_maskbrush) {
@@ -745,14 +740,8 @@ static void brush_painter_2d_refresh_cache(ImagePaintState *s,
renew_maxmask) {
MEM_SAFE_FREE(cache->tex_mask);
- brush_painter_2d_tex_mapping(s,
- tile->canvas,
- diameter,
- tile->start_paintpos,
- pos,
- mouse,
- brush->mask_mtex.brush_map_mode,
- &painter->mask_mapping);
+ brush_painter_2d_tex_mapping(
+ s, tile, diameter, pos, mouse, brush->mask_mtex.brush_map_mode, &painter->mask_mapping);
if (do_partial_update_mask) {
brush_painter_mask_imbuf_partial_update(painter, tile, pos, diameter);
diff --git a/source/blender/editors/sculpt_paint/paint_image_proj.c b/source/blender/editors/sculpt_paint/paint_image_proj.c
index 1303da71435..e442cd53639 100644
--- a/source/blender/editors/sculpt_paint/paint_image_proj.c
+++ b/source/blender/editors/sculpt_paint/paint_image_proj.c
@@ -83,6 +83,8 @@
#include "RNA_define.h"
#include "RNA_enum_types.h"
+#include "NOD_shader.h"
+
#include "IMB_colormanagement.h"
//#include "bmesh_tools.h"
@@ -6422,6 +6424,17 @@ static const EnumPropertyItem layer_type_items[] = {
{0, NULL, 0, NULL, NULL},
};
+static Material *get_or_create_current_material(bContext *C, Object *ob)
+{
+ Material *ma = BKE_object_material_get(ob, ob->actcol);
+ if (!ma) {
+ Main *bmain = CTX_data_main(C);
+ ma = BKE_material_add(bmain, "Material");
+ BKE_object_material_assign(bmain, ob, ma, ob->actcol, BKE_MAT_ASSIGN_USERPREF);
+ }
+ return ma;
+}
+
static Image *proj_paint_image_create(wmOperator *op, Main *bmain, bool is_data)
{
Image *ima;
@@ -6459,55 +6472,65 @@ static Image *proj_paint_image_create(wmOperator *op, Main *bmain, bool is_data)
return ima;
}
-static void proj_paint_default_color(wmOperator *op, int type, Material *ma)
+/**
+ * Get a default color for the paint slot layer from a material's Principled BSDF.
+ *
+ * \param layer_type: The layer type of the paint slot
+ * \param ma: The material to attempt using as the default color source.
+ * If this fails or \p ma is null, a default Principled BSDF is used instead.
+ */
+static void default_paint_slot_color_get(int layer_type, Material *ma, float color[4])
{
- if (RNA_struct_property_is_set(op->ptr, "color")) {
- return;
- }
-
- bNode *in_node = ntreeFindType(ma->nodetree, SH_NODE_BSDF_PRINCIPLED);
- if (in_node == NULL) {
- return;
- }
-
- float color[4];
-
- if (type >= LAYER_BASE_COLOR && type < LAYER_NORMAL) {
- /* Copy color from node, so result is unchanged after assigning textures. */
- bNodeSocket *in_sock = nodeFindSocket(in_node, SOCK_IN, layer_type_items[type].name);
-
- switch (in_sock->type) {
- case SOCK_FLOAT: {
- bNodeSocketValueFloat *socket_data = in_sock->default_value;
- copy_v3_fl(color, socket_data->value);
- color[3] = 1.0f;
- break;
+ switch (layer_type) {
+ case LAYER_BASE_COLOR:
+ case LAYER_SPECULAR:
+ case LAYER_ROUGHNESS:
+ case LAYER_METALLIC: {
+ bNodeTree *ntree = NULL;
+ bNode *in_node = ma ? ntreeFindType(ma->nodetree, SH_NODE_BSDF_PRINCIPLED) : NULL;
+ if (!in_node) {
+ /* An existing material or Principled BSDF node could not be found.
+ * Copy default color values from a default Principled BSDF instead. */
+ ntree = ntreeAddTree(NULL, "Temporary Shader Nodetree", ntreeType_Shader->idname);
+ in_node = nodeAddStaticNode(NULL, ntree, SH_NODE_BSDF_PRINCIPLED);
}
- case SOCK_VECTOR:
- case SOCK_RGBA: {
- bNodeSocketValueRGBA *socket_data = in_sock->default_value;
- copy_v3_v3(color, socket_data->value);
- color[3] = 1.0f;
- break;
+ bNodeSocket *in_sock = nodeFindSocket(in_node, SOCK_IN, layer_type_items[layer_type].name);
+ switch (in_sock->type) {
+ case SOCK_FLOAT: {
+ bNodeSocketValueFloat *socket_data = in_sock->default_value;
+ copy_v3_fl(color, socket_data->value);
+ color[3] = 1.0f;
+ break;
+ }
+ case SOCK_VECTOR:
+ case SOCK_RGBA: {
+ bNodeSocketValueRGBA *socket_data = in_sock->default_value;
+ copy_v3_v3(color, socket_data->value);
+ color[3] = 1.0f;
+ break;
+ }
+ default:
+ BLI_assert_unreachable();
+ rgba_float_args_set(color, 0.0f, 0.0f, 0.0f, 1.0f);
+ break;
}
- default: {
- return;
+ /* Cleanup */
+ if (ntree) {
+ ntreeFreeTree(ntree);
+ MEM_freeN(ntree);
}
+ return;
}
+ case LAYER_NORMAL:
+ /* Neutral tangent space normal map. */
+ rgba_float_args_set(color, 0.5f, 0.5f, 1.0f, 1.0f);
+ break;
+ case LAYER_BUMP:
+ case LAYER_DISPLACEMENT:
+ /* Neutral displacement and bump map. */
+ rgba_float_args_set(color, 0.5f, 0.5f, 0.5f, 1.0f);
+ break;
}
- else if (type == LAYER_NORMAL) {
- /* Neutral tangent space normal map. */
- rgba_float_args_set(color, 0.5f, 0.5f, 1.0f, 1.0f);
- }
- else if (ELEM(type, LAYER_BUMP, LAYER_DISPLACEMENT)) {
- /* Neutral displacement and bump map. */
- rgba_float_args_set(color, 0.5f, 0.5f, 0.5f, 1.0f);
- }
- else {
- return;
- }
-
- RNA_float_set_array(op->ptr, "color", color);
}
static bool proj_paint_add_slot(bContext *C, wmOperator *op)
@@ -6521,7 +6544,7 @@ static bool proj_paint_add_slot(bContext *C, wmOperator *op)
return false;
}
- ma = BKE_object_material_get(ob, ob->actcol);
+ ma = get_or_create_current_material(C, ob);
if (ma) {
Main *bmain = CTX_data_main(C);
@@ -6632,25 +6655,8 @@ static int get_texture_layer_type(wmOperator *op, const char *prop_name)
return type;
}
-static Material *get_or_create_current_material(bContext *C, Object *ob)
-{
- Material *ma = BKE_object_material_get(ob, ob->actcol);
- if (!ma) {
- Main *bmain = CTX_data_main(C);
- ma = BKE_material_add(bmain, "Material");
- BKE_object_material_assign(bmain, ob, ma, ob->actcol, BKE_MAT_ASSIGN_USERPREF);
- }
- return ma;
-}
-
static int texture_paint_add_texture_paint_slot_exec(bContext *C, wmOperator *op)
{
- Object *ob = ED_object_active_context(C);
- Material *ma = get_or_create_current_material(C, ob);
-
- int type = get_texture_layer_type(op, "type");
- proj_paint_default_color(op, type, ma);
-
if (proj_paint_add_slot(C, op)) {
return OPERATOR_FINISHED;
}
@@ -6671,17 +6677,21 @@ static int texture_paint_add_texture_paint_slot_invoke(bContext *C,
wmOperator *op,
const wmEvent *UNUSED(event))
{
- /* Get material and default color to display in the popup. */
Object *ob = ED_object_active_context(C);
- Material *ma = get_or_create_current_material(C, ob);
+ Material *ma = BKE_object_material_get(ob, ob->actcol);
int type = get_texture_layer_type(op, "type");
- proj_paint_default_color(op, type, ma);
+ /* Set default name. */
char imagename[MAX_ID_NAME - 2];
get_default_texture_layer_name_for_object(ob, type, (char *)&imagename, sizeof(imagename));
RNA_string_set(op->ptr, "name", imagename);
+ /* Set default color. Copy the color from nodes, so it matches the existing material. */
+ float color[4];
+ default_paint_slot_color_get(type, ma, color);
+ RNA_float_set_array(op->ptr, "color", color);
+
return WM_operator_props_dialog_popup(C, op, 300);
}
diff --git a/source/blender/editors/sculpt_paint/paint_stroke.c b/source/blender/editors/sculpt_paint/paint_stroke.c
index d2005473512..210cffcbcda 100644
--- a/source/blender/editors/sculpt_paint/paint_stroke.c
+++ b/source/blender/editors/sculpt_paint/paint_stroke.c
@@ -923,6 +923,8 @@ PaintStroke *paint_stroke_new(bContext *C,
BKE_paint_set_overlay_override(br->overlay_flags);
+ ups->start_pixel_radius = BKE_brush_size_get(CTX_data_scene(C), br);
+
return stroke;
}
diff --git a/source/blender/editors/sculpt_paint/sculpt_filter_color.c b/source/blender/editors/sculpt_paint/sculpt_filter_color.c
index c0db587f69a..9bddc2ad855 100644
--- a/source/blender/editors/sculpt_paint/sculpt_filter_color.c
+++ b/source/blender/editors/sculpt_paint/sculpt_filter_color.c
@@ -124,8 +124,8 @@ static void color_filter_task_cb(void *__restrict userdata,
}
case COLOR_FILTER_HUE:
rgb_to_hsv_v(orig_color, hsv_color);
- hue = hsv_color[0] + fade;
- hsv_color[0] = fabs((hsv_color[0] + fade) - hue);
+ hue = hsv_color[0];
+ hsv_color[0] = fmod((hsv_color[0] + fabs(fade)) - hue,1);
hsv_to_rgb_v(hsv_color, final_color);
break;
case COLOR_FILTER_SATURATION:
diff --git a/source/blender/editors/space_action/action_select.c b/source/blender/editors/space_action/action_select.c
index 38ca9e16004..c0f7b7bd2b7 100644
--- a/source/blender/editors/space_action/action_select.c
+++ b/source/blender/editors/space_action/action_select.c
@@ -887,6 +887,7 @@ void ACTION_OT_select_circle(wmOperatorType *ot)
ot->exec = action_circle_select_exec;
ot->poll = ED_operator_action_active;
ot->cancel = WM_gesture_circle_cancel;
+ ot->get_name = ED_select_pick_get_name;
/* flags */
ot->flag = OPTYPE_UNDO;
diff --git a/source/blender/editors/space_clip/tracking_select.c b/source/blender/editors/space_clip/tracking_select.c
index 5f940b817a9..f267d948a53 100644
--- a/source/blender/editors/space_clip/tracking_select.c
+++ b/source/blender/editors/space_clip/tracking_select.c
@@ -835,6 +835,7 @@ void CLIP_OT_select_circle(wmOperatorType *ot)
ot->modal = WM_gesture_circle_modal;
ot->exec = circle_select_exec;
ot->poll = ED_space_clip_tracking_poll;
+ ot->get_name = ED_select_pick_get_name;
/* flags */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
diff --git a/source/blender/editors/space_graph/graph_select.c b/source/blender/editors/space_graph/graph_select.c
index 39b980ac4c3..b8295150478 100644
--- a/source/blender/editors/space_graph/graph_select.c
+++ b/source/blender/editors/space_graph/graph_select.c
@@ -1080,6 +1080,7 @@ void GRAPH_OT_select_circle(wmOperatorType *ot)
ot->exec = graph_circle_select_exec;
ot->poll = graphop_visible_keyframes_poll;
ot->cancel = WM_gesture_circle_cancel;
+ ot->get_name = ED_select_pick_get_name;
/* flags */
ot->flag = OPTYPE_UNDO;
diff --git a/source/blender/editors/space_node/node_select.cc b/source/blender/editors/space_node/node_select.cc
index 1d0097068f1..db523651534 100644
--- a/source/blender/editors/space_node/node_select.cc
+++ b/source/blender/editors/space_node/node_select.cc
@@ -193,11 +193,6 @@ static bool is_event_over_node_or_socket(bContext *C, const wmEvent *event)
return is_position_over_node_or_socket(*snode, mouse);
}
-static void node_toggle(bNode *node)
-{
- nodeSetSelected(node, !(node->flag & SELECT));
-}
-
void node_socket_select(bNode *node, bNodeSocket &sock)
{
sock.flag |= SELECT;
@@ -510,10 +505,10 @@ void node_select_single(bContext &C, bNode &node)
WM_event_add_notifier(&C, NC_NODE | NA_SELECTED, nullptr);
}
-static int node_mouse_select(bContext *C,
- wmOperator *op,
- const int mval[2],
- bool wait_to_deselect_others)
+static bool node_mouse_select(bContext *C,
+ wmOperator *op,
+ const int mval[2],
+ struct SelectPick_Params *params)
{
Main &bmain = *CTX_data_main(C);
SpaceNode &snode = *CTX_wm_space_node(C);
@@ -525,36 +520,38 @@ static int node_mouse_select(bContext *C,
bNodeSocket *sock = nullptr;
bNodeSocket *tsock;
float cursor[2];
- int ret_value = OPERATOR_CANCELLED;
- const bool extend = RNA_boolean_get(op->ptr, "extend");
/* always do socket_select when extending selection. */
- const bool socket_select = extend || RNA_boolean_get(op->ptr, "socket_select");
- const bool deselect_all = RNA_boolean_get(op->ptr, "deselect_all");
-
- /* These cases are never modal. */
- if (extend || socket_select) {
- wait_to_deselect_others = false;
- }
+ const bool socket_select = (params->sel_op == SEL_OP_XOR) ||
+ RNA_boolean_get(op->ptr, "socket_select");
+ bool changed = false;
+ bool found = false;
+ bool node_was_selected = false;
/* get mouse coordinates in view2d space */
UI_view2d_region_to_view(&region.v2d, mval[0], mval[1], &cursor[0], &cursor[1]);
/* first do socket selection, these generally overlap with nodes. */
if (socket_select) {
+ /* NOTE: unlike nodes #SelectPick_Params isn't fully supported. */
+ const bool extend = (params->sel_op == SEL_OP_XOR);
if (node_find_indicated_socket(snode, &node, &sock, cursor, SOCK_IN)) {
+ found = true;
+ node_was_selected = node->flag & SELECT;
+
/* NOTE: SOCK_IN does not take into account the extend case...
* This feature is not really used anyway currently? */
node_socket_toggle(node, *sock, true);
- ret_value = OPERATOR_FINISHED;
+ changed = true;
}
else if (node_find_indicated_socket(snode, &node, &sock, cursor, SOCK_OUT)) {
+ found = true;
+ node_was_selected = node->flag & SELECT;
+
if (sock->flag & SELECT) {
if (extend) {
node_socket_deselect(node, *sock, true);
- }
- else {
- ret_value = OPERATOR_FINISHED;
+ changed = true;
}
}
else {
@@ -566,6 +563,7 @@ static int node_mouse_select(bContext *C,
continue;
}
node_socket_deselect(node, *tsock, true);
+ changed = true;
}
}
if (!extend) {
@@ -575,69 +573,71 @@ static int node_mouse_select(bContext *C,
}
for (tsock = (bNodeSocket *)tnode->outputs.first; tsock; tsock = tsock->next) {
node_socket_deselect(tnode, *tsock, true);
+ changed = true;
}
}
}
node_socket_select(node, *sock);
- ret_value = OPERATOR_FINISHED;
+ changed = true;
}
}
}
if (!sock) {
+
/* find the closest visible node */
node = node_under_mouse_select(*snode.edittree, (int)cursor[0], (int)cursor[1]);
+ found = (node != nullptr);
+ node_was_selected = node && (node->flag & SELECT);
- if (extend) {
- if (node != nullptr) {
- /* If node is selected but not active, we want to make it active,
- * but not toggle (deselect) it. */
- if (!((node->flag & SELECT) && (node->flag & NODE_ACTIVE) == 0)) {
- node_toggle(node);
- }
- ret_value = OPERATOR_FINISHED;
+ if (params->sel_op == SEL_OP_SET) {
+ if ((found && params->select_passthrough) && (node->flag & SELECT)) {
+ found = false;
}
- }
- else if (deselect_all && node == nullptr) {
- /* Rather than deselecting others, users may want to drag to box-select (drag from empty
- * space) or tweak-translate an already selected item. If these cases may apply, delay
- * deselection. */
- if (wait_to_deselect_others) {
- ret_value = OPERATOR_RUNNING_MODAL;
- }
- else {
- /* Deselect in empty space. */
+ else if (found || params->deselect_all) {
+ /* Deselect everything. */
for (tnode = (bNode *)snode.edittree->nodes.first; tnode; tnode = tnode->next) {
nodeSetSelected(tnode, false);
}
- ret_value = OPERATOR_FINISHED;
+ changed = true;
}
}
- else if (node != nullptr) {
- /* When clicking on an already selected node, we want to wait to deselect
- * others and allow the user to start moving the node without that. */
- if (wait_to_deselect_others && (node->flag & SELECT)) {
- ret_value = OPERATOR_RUNNING_MODAL;
- }
- else {
- nodeSetSelected(node, true);
- for (tnode = (bNode *)snode.edittree->nodes.first; tnode; tnode = tnode->next) {
- if (tnode != node) {
- nodeSetSelected(tnode, false);
- }
+ if (found) {
+ switch (params->sel_op) {
+ case SEL_OP_ADD: {
+ nodeSetSelected(node, true);
+ break;
+ }
+ case SEL_OP_SUB: {
+ nodeSetSelected(node, false);
+ break;
+ }
+ case SEL_OP_XOR: {
+ /* Check active so clicking on an inactive node activates it. */
+ bool is_selected = (node->flag & NODE_SELECT) && (node->flag & NODE_ACTIVE);
+ nodeSetSelected(node, !is_selected);
+ break;
+ }
+ case SEL_OP_SET: {
+ nodeSetSelected(node, true);
+ break;
+ }
+ case SEL_OP_AND: {
+ BLI_assert_unreachable(); /* Doesn't make sense for picking. */
+ break;
}
-
- ret_value = OPERATOR_FINISHED;
}
+
+ changed = true;
}
}
/* update node order */
- if (ret_value != OPERATOR_CANCELLED) {
+ if (changed || found) {
bool active_texture_changed = false;
bool viewer_node_changed = false;
- if (node != nullptr && ret_value != OPERATOR_RUNNING_MODAL) {
+ if ((node != nullptr) && (node_was_selected == false || params->select_passthrough == false)) {
viewer_node_changed = (node->flag & NODE_DO_OUTPUT) == 0 && node->type == GEO_NODE_VIEWER;
ED_node_set_active(&bmain, &snode, snode.edittree, node, &active_texture_changed);
}
@@ -654,23 +654,35 @@ static int node_mouse_select(bContext *C,
WM_event_add_notifier(C, NC_NODE | NA_SELECTED, nullptr);
}
- return ret_value;
+ return changed || found;
}
static int node_select_exec(bContext *C, wmOperator *op)
{
- const bool wait_to_deselect_others = RNA_boolean_get(op->ptr, "wait_to_deselect_others");
-
/* get settings from RNA properties for operator */
int mval[2];
- mval[0] = RNA_int_get(op->ptr, "mouse_x");
- mval[1] = RNA_int_get(op->ptr, "mouse_y");
+ RNA_int_get_array(op->ptr, "location", mval);
+
+ struct SelectPick_Params params = {};
+ ED_select_pick_params_from_operator(op->ptr, &params);
/* perform the select */
- const int ret_value = node_mouse_select(C, op, mval, wait_to_deselect_others);
+ const bool changed = node_mouse_select(C, op, mval, &params);
- /* allow tweak event to work too */
- return ret_value | OPERATOR_PASS_THROUGH;
+ if (changed) {
+ return OPERATOR_PASS_THROUGH | OPERATOR_FINISHED;
+ }
+ /* Nothing selected, just passthrough. */
+ return OPERATOR_PASS_THROUGH | OPERATOR_CANCELLED;
+}
+
+static int node_select_invoke(bContext *C, wmOperator *op, const wmEvent *event)
+{
+ RNA_int_set_array(op->ptr, "location", event->mval);
+
+ const int retval = node_select_exec(C, op);
+
+ return WM_operator_flag_only_pass_through_on_press(retval, event);
}
void NODE_OT_select(wmOperatorType *ot)
@@ -684,24 +696,29 @@ void NODE_OT_select(wmOperatorType *ot)
/* api callbacks */
ot->exec = node_select_exec;
- ot->invoke = WM_generic_select_invoke;
- ot->modal = WM_generic_select_modal;
+ ot->invoke = node_select_invoke;
ot->poll = ED_operator_node_active;
+ ot->get_name = ED_select_pick_get_name;
/* flags */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
/* properties */
- WM_operator_properties_generic_select(ot);
- prop = RNA_def_boolean(ot->srna, "extend", false, "Extend", "");
- RNA_def_property_flag(prop, PROP_SKIP_SAVE);
+ WM_operator_properties_mouse_select(ot);
+
+ prop = RNA_def_int_vector(ot->srna,
+ "location",
+ 2,
+ NULL,
+ INT_MIN,
+ INT_MAX,
+ "Location",
+ "Mouse location",
+ INT_MIN,
+ INT_MAX);
+ RNA_def_property_flag(prop, PROP_HIDDEN);
+
RNA_def_boolean(ot->srna, "socket_select", false, "Socket Select", "");
- prop = RNA_def_boolean(ot->srna,
- "deselect_all",
- false,
- "Deselect On Nothing",
- "Deselect all when nothing under the cursor");
- RNA_def_property_flag(prop, PROP_SKIP_SAVE);
}
/** \} */
@@ -871,8 +888,8 @@ void NODE_OT_select_circle(wmOperatorType *ot)
ot->invoke = WM_gesture_circle_invoke;
ot->exec = node_circleselect_exec;
ot->modal = WM_gesture_circle_modal;
-
ot->poll = ED_operator_node_active;
+ ot->get_name = ED_select_circle_get_name;
/* flags */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
diff --git a/source/blender/editors/space_outliner/outliner_draw.cc b/source/blender/editors/space_outliner/outliner_draw.cc
index d898be4eb2c..36e21cf51a5 100644
--- a/source/blender/editors/space_outliner/outliner_draw.cc
+++ b/source/blender/editors/space_outliner/outliner_draw.cc
@@ -1808,6 +1808,25 @@ static void outliner_draw_overrides_rna_buts(uiBlock *block,
TreeElementOverridesProperty &override_elem = *tree_element_cast<TreeElementOverridesProperty>(
te);
+ if (!override_elem.is_rna_path_valid) {
+ uiBut *but = uiDefBut(block,
+ UI_BTYPE_LABEL,
+ 0,
+ override_elem.rna_path.c_str(),
+ x + pad_x,
+ te->ys + pad_y,
+ item_max_width,
+ item_height,
+ NULL,
+ 0.0f,
+ 0.0f,
+ 0.0f,
+ 0.0f,
+ "");
+ UI_but_flag_enable(but, UI_BUT_REDALERT);
+ continue;
+ }
+
PointerRNA *ptr = &override_elem.override_rna_ptr;
PropertyRNA *prop = &override_elem.override_rna_prop;
const PropertyType prop_type = RNA_property_type(prop);
@@ -1935,8 +1954,9 @@ static bool outliner_draw_overrides_warning_buts(uiBlock *block,
break;
}
case TSE_LIBRARY_OVERRIDE: {
- const bool is_rna_path_valid = (bool)(POINTER_AS_UINT(te->directdata));
- if (!is_rna_path_valid) {
+ TreeElementOverridesProperty &te_override_prop =
+ *tree_element_cast<TreeElementOverridesProperty>(te);
+ if (!te_override_prop.is_rna_path_valid) {
item_has_warnings = true;
if (do_draw) {
tip = TIP_(
diff --git a/source/blender/editors/space_outliner/tree/tree_element_overrides.cc b/source/blender/editors/space_outliner/tree/tree_element_overrides.cc
index 857f5577e59..3a039da86c2 100644
--- a/source/blender/editors/space_outliner/tree/tree_element_overrides.cc
+++ b/source/blender/editors/space_outliner/tree/tree_element_overrides.cc
@@ -84,14 +84,13 @@ TreeElementOverridesProperty::TreeElementOverridesProperty(TreeElement &legacy_t
TreeElementOverridesData &override_data)
: AbstractTreeElement(legacy_te),
override_rna_ptr(override_data.override_rna_ptr),
- override_rna_prop(override_data.override_rna_prop)
+ override_rna_prop(override_data.override_rna_prop),
+ rna_path(override_data.override_property.rna_path),
+ is_rna_path_valid(override_data.is_rna_path_valid)
{
BLI_assert(legacy_te.store_elem->type == TSE_LIBRARY_OVERRIDE);
legacy_te.name = override_data.override_property.rna_path;
- /* Abusing this for now, better way to do it is also pending current refactor of the whole tree
- * code to use C++. */
- legacy_te.directdata = POINTER_FROM_UINT(override_data.is_rna_path_valid);
}
} // namespace blender::ed::outliner
diff --git a/source/blender/editors/space_outliner/tree/tree_element_overrides.hh b/source/blender/editors/space_outliner/tree/tree_element_overrides.hh
index a2d1409f193..b42e1c37a0f 100644
--- a/source/blender/editors/space_outliner/tree/tree_element_overrides.hh
+++ b/source/blender/editors/space_outliner/tree/tree_element_overrides.hh
@@ -8,6 +8,8 @@
#include "RNA_types.h"
+#include "BLI_string_ref.hh"
+
#include "tree_element.hh"
struct ID;
@@ -39,6 +41,9 @@ class TreeElementOverridesProperty final : public AbstractTreeElement {
PointerRNA override_rna_ptr;
PropertyRNA &override_rna_prop;
+ StringRefNull rna_path;
+ bool is_rna_path_valid;
+
public:
TreeElementOverridesProperty(TreeElement &legacy_te, TreeElementOverridesData &override_data);
};
diff --git a/source/blender/editors/space_sequencer/sequencer_add.c b/source/blender/editors/space_sequencer/sequencer_add.c
index e162968fa3b..939fcfeb7d9 100644
--- a/source/blender/editors/space_sequencer/sequencer_add.c
+++ b/source/blender/editors/space_sequencer/sequencer_add.c
@@ -136,7 +136,7 @@ static void sequencer_generic_props__internal(wmOperatorType *ot, int flag)
ot->srna,
"overlap_shuffle_override",
false,
- "Override Overlap Shuffle Behaviour",
+ "Override Overlap Shuffle Behavior",
"Use the overlap_mode tool settings to determine how to shuffle overlapping strips");
RNA_def_property_flag(prop, PROP_HIDDEN | PROP_SKIP_SAVE);
diff --git a/source/blender/editors/space_sequencer/sequencer_select.c b/source/blender/editors/space_sequencer/sequencer_select.c
index 4651d5b31a9..4e4e570d331 100644
--- a/source/blender/editors/space_sequencer/sequencer_select.c
+++ b/source/blender/editors/space_sequencer/sequencer_select.c
@@ -999,6 +999,7 @@ void SEQUENCER_OT_select(wmOperatorType *ot)
ot->invoke = sequencer_select_invoke;
ot->modal = WM_generic_select_modal;
ot->poll = ED_operator_sequencer_active;
+ ot->get_name = ED_select_pick_get_name;
/* Flags. */
ot->flag = OPTYPE_UNDO;
diff --git a/source/blender/editors/space_view3d/view3d_select.c b/source/blender/editors/space_view3d/view3d_select.c
index ffd33006cc2..d99063a9b26 100644
--- a/source/blender/editors/space_view3d/view3d_select.c
+++ b/source/blender/editors/space_view3d/view3d_select.c
@@ -1646,7 +1646,7 @@ static int bone_select_menu_exec(bContext *C, wmOperator *op)
const int name_index = RNA_enum_get(op->ptr, "name");
const struct SelectPick_Params params = {
- .sel_op = ED_select_op_from_operator(op),
+ .sel_op = ED_select_op_from_operator(op->ptr),
};
View3D *v3d = CTX_wm_view3d(C);
@@ -2875,7 +2875,7 @@ static int view3d_select_exec(bContext *C, wmOperator *op)
Object *obact = CTX_data_active_object(C);
struct SelectPick_Params params = {0};
- ED_select_pick_params_from_operator(op, &params);
+ ED_select_pick_params_from_operator(op->ptr, &params);
bool center = RNA_boolean_get(op->ptr, "center");
bool enumerate = RNA_boolean_get(op->ptr, "enumerate");
@@ -2987,6 +2987,7 @@ void VIEW3D_OT_select(wmOperatorType *ot)
ot->invoke = view3d_select_invoke;
ot->exec = view3d_select_exec;
ot->poll = ED_operator_view3d_active;
+ ot->get_name = ED_select_pick_get_name;
/* flags */
ot->flag = OPTYPE_UNDO;
@@ -4739,6 +4740,7 @@ void VIEW3D_OT_select_circle(wmOperatorType *ot)
ot->exec = view3d_circle_select_exec;
ot->poll = view3d_selectable_data;
ot->cancel = view3d_circle_select_cancel;
+ ot->get_name = ED_select_circle_get_name;
/* flags */
ot->flag = OPTYPE_UNDO;
diff --git a/source/blender/editors/transform/transform_convert_tracking.c b/source/blender/editors/transform/transform_convert_tracking.c
index 45f17512c09..bf9f929dd65 100644
--- a/source/blender/editors/transform/transform_convert_tracking.c
+++ b/source/blender/editors/transform/transform_convert_tracking.c
@@ -621,7 +621,7 @@ static void flushTransTracking(TransInfo *t)
TransData *td;
TransData2D *td2d;
TransDataTracking *tdt;
- int a;
+ int td_index;
if (t->state == TRANS_CANCEL) {
cancelTransTracking(t);
@@ -630,8 +630,9 @@ static void flushTransTracking(TransInfo *t)
TransDataContainer *tc = TRANS_DATA_CONTAINER_FIRST_SINGLE(t);
/* flush to 2d vector from internally used 3d vector */
- for (a = 0, td = tc->data, td2d = tc->data_2d, tdt = tc->custom.type.data; a < tc->data_len;
- a++, td2d++, td++, tdt++) {
+ for (td_index = 0, td = tc->data, td2d = tc->data_2d, tdt = tc->custom.type.data;
+ td_index < tc->data_len;
+ td_index++, td2d++, td++, tdt++) {
if (tdt->mode == transDataTracking_ModeTracks) {
float loc2d[2];
@@ -655,7 +656,7 @@ static void flushTransTracking(TransInfo *t)
if (!tdt->smarkers) {
tdt->smarkers = MEM_callocN(sizeof(*tdt->smarkers) * tdt->markersnr,
"flushTransTracking markers");
- for (a = 0; a < tdt->markersnr; a++) {
+ for (int a = 0; a < tdt->markersnr; a++) {
copy_v2_v2(tdt->smarkers[a], tdt->markers[a].pos);
}
}
@@ -665,7 +666,7 @@ static void flushTransTracking(TransInfo *t)
sub_v2_v2v2(d2, loc2d, tdt->srelative);
- for (a = 0; a < tdt->markersnr; a++) {
+ for (int a = 0; a < tdt->markersnr; a++) {
add_v2_v2v2(tdt->markers[a].pos, tdt->smarkers[a], d2);
}
diff --git a/source/blender/editors/transform/transform_snap_object.cc b/source/blender/editors/transform/transform_snap_object.cc
index fade7f47d9c..0505772c668 100644
--- a/source/blender/editors/transform/transform_snap_object.cc
+++ b/source/blender/editors/transform/transform_snap_object.cc
@@ -168,8 +168,13 @@ struct SnapObjectContext {
/** \name Utilities
* \{ */
-/* Mesh used for snapping.
- * If nullptr the BMesh should be used. */
+/**
+ * Mesh used for snapping.
+ *
+ * - When the return value is null the `BKE_editmesh_from_object(ob_eval)` should be used.
+ * - In rare cases there is no evaluated mesh available and a null result doesn't imply an
+ * edit-mesh, so callers need to account for a null edit-mesh too, see: T96536.
+ */
static const Mesh *mesh_for_snap(Object *ob_eval, eSnapEditType edit_mode_type, bool *r_use_hide)
{
const Mesh *me_eval = BKE_object_get_evaluated_mesh(ob_eval);
@@ -998,6 +1003,9 @@ static void raycast_obj_fn(SnapObjectContext *sctx,
const Mesh *me_eval = mesh_for_snap(ob_eval, edit_mode_type, &use_hide);
if (me_eval == nullptr) {
BMEditMesh *em = BKE_editmesh_from_object(ob_eval);
+ if (UNLIKELY(!em)) { /* See #mesh_for_snap doc-string. */
+ return;
+ }
BLI_assert_msg(em == BKE_editmesh_from_object(DEG_get_original_object(ob_eval)),
"Make sure there is only one pointer for looptris");
retval = raycastEditMesh(sctx,
@@ -2696,6 +2704,9 @@ static void snap_obj_fn(SnapObjectContext *sctx,
const Mesh *me_eval = mesh_for_snap(ob_eval, edit_mode_type, &use_hide);
if (me_eval == nullptr) {
BMEditMesh *em = BKE_editmesh_from_object(ob_eval);
+ if (UNLIKELY(!em)) { /* See #mesh_for_snap doc-string. */
+ return;
+ }
BLI_assert_msg(em == BKE_editmesh_from_object(DEG_get_original_object(ob_eval)),
"Make sure there is only one pointer for looptris");
retval = snapEditMesh(
diff --git a/source/blender/editors/util/select_utils.c b/source/blender/editors/util/select_utils.c
index 53f9aca8e8d..263ef06718f 100644
--- a/source/blender/editors/util/select_utils.c
+++ b/source/blender/editors/util/select_utils.c
@@ -119,11 +119,11 @@ bool ED_select_similar_compare_float_tree(const KDTree_1d *tree,
return false;
}
-eSelectOp ED_select_op_from_operator(wmOperator *op)
+eSelectOp ED_select_op_from_operator(PointerRNA *ptr)
{
- const bool extend = RNA_boolean_get(op->ptr, "extend");
- const bool deselect = RNA_boolean_get(op->ptr, "deselect");
- const bool toggle = RNA_boolean_get(op->ptr, "toggle");
+ const bool extend = RNA_boolean_get(ptr, "extend");
+ const bool deselect = RNA_boolean_get(ptr, "deselect");
+ const bool toggle = RNA_boolean_get(ptr, "toggle");
if (extend) {
return SEL_OP_ADD;
@@ -137,10 +137,56 @@ eSelectOp ED_select_op_from_operator(wmOperator *op)
return SEL_OP_SET;
}
-void ED_select_pick_params_from_operator(wmOperator *op, struct SelectPick_Params *params)
+void ED_select_pick_params_from_operator(PointerRNA *ptr, struct SelectPick_Params *params)
{
memset(params, 0x0, sizeof(*params));
- params->sel_op = ED_select_op_from_operator(op);
- params->deselect_all = RNA_boolean_get(op->ptr, "deselect_all");
- params->select_passthrough = RNA_boolean_get(op->ptr, "select_passthrough");
+ params->sel_op = ED_select_op_from_operator(ptr);
+ params->deselect_all = RNA_boolean_get(ptr, "deselect_all");
+ params->select_passthrough = RNA_boolean_get(ptr, "select_passthrough");
}
+
+/* -------------------------------------------------------------------- */
+/** \name Operator Naming Callbacks
+ * \{ */
+
+const char *ED_select_pick_get_name(wmOperatorType *UNUSED(ot), PointerRNA *ptr)
+{
+ struct SelectPick_Params params = {0};
+ ED_select_pick_params_from_operator(ptr, &params);
+ switch (params.sel_op) {
+ case SEL_OP_ADD:
+ return "Select (Extend)";
+ case SEL_OP_SUB:
+ return "Select (Deselect)";
+ case SEL_OP_XOR:
+ return "Select (Toggle)";
+ case SEL_OP_AND:
+ BLI_assert_unreachable();
+ ATTR_FALLTHROUGH;
+ case SEL_OP_SET:
+ break;
+ }
+ return "Select";
+}
+
+const char *ED_select_circle_get_name(wmOperatorType *UNUSED(ot), PointerRNA *ptr)
+{
+ /* Matches options in #WM_operator_properties_select_operation_simple */
+ const eSelectOp sel_op = RNA_enum_get(ptr, "mode");
+ switch (sel_op) {
+ case SEL_OP_ADD:
+ return "Circle Select (Extend)";
+ case SEL_OP_SUB:
+ return "Circle Select (Deselect)";
+ case SEL_OP_XOR:
+ ATTR_FALLTHROUGH;
+ case SEL_OP_AND:
+ BLI_assert_unreachable();
+ ATTR_FALLTHROUGH;
+ case SEL_OP_SET:
+ break;
+ }
+ return "Circle Select";
+}
+
+/** \} */
diff --git a/source/blender/editors/uvedit/uvedit_select.c b/source/blender/editors/uvedit/uvedit_select.c
index 1287804d9ee..2c1cdb1d93e 100644
--- a/source/blender/editors/uvedit/uvedit_select.c
+++ b/source/blender/editors/uvedit/uvedit_select.c
@@ -2624,7 +2624,7 @@ static int uv_select_exec(bContext *C, wmOperator *op)
RNA_float_get_array(op->ptr, "location", co);
struct SelectPick_Params params = {0};
- ED_select_pick_params_from_operator(op, &params);
+ ED_select_pick_params_from_operator(op->ptr, &params);
const bool changed = uv_mouse_select(C, co, &params);
@@ -2659,6 +2659,7 @@ void UV_OT_select(wmOperatorType *ot)
ot->exec = uv_select_exec;
ot->invoke = uv_select_invoke;
ot->poll = ED_operator_uvedit; /* requires space image */
+ ot->get_name = ED_select_pick_get_name;
/* properties */
PropertyRNA *prop;
@@ -3828,6 +3829,7 @@ void UV_OT_select_circle(wmOperatorType *ot)
ot->exec = uv_circle_select_exec;
ot->poll = ED_operator_uvedit_space_image; /* requires space image */
ot->cancel = WM_gesture_circle_cancel;
+ ot->get_name = ED_select_circle_get_name;
/* flags */
ot->flag = OPTYPE_UNDO;
diff --git a/source/blender/editors/uvedit/uvedit_unwrap_ops.c b/source/blender/editors/uvedit/uvedit_unwrap_ops.c
index 34fae2ffb2a..c0ea753ed51 100644
--- a/source/blender/editors/uvedit/uvedit_unwrap_ops.c
+++ b/source/blender/editors/uvedit/uvedit_unwrap_ops.c
@@ -267,26 +267,35 @@ static bool uvedit_have_selection_multi(const Scene *scene,
return have_select;
}
+void ED_uvedit_get_aspect_from_material(Object *ob,
+ const int material_index,
+ float *r_aspx,
+ float *r_aspy)
+{
+ if (UNLIKELY(material_index < 0 || material_index >= ob->totcol)) {
+ *r_aspx = 1.0f;
+ *r_aspy = 1.0f;
+ return;
+ }
+ Image *ima;
+ ED_object_get_active_image(ob, material_index + 1, &ima, NULL, NULL, NULL);
+ ED_image_get_uv_aspect(ima, NULL, r_aspx, r_aspy);
+}
+
void ED_uvedit_get_aspect(Object *ob, float *r_aspx, float *r_aspy)
{
BMEditMesh *em = BKE_editmesh_from_object(ob);
BLI_assert(em != NULL);
bool sloppy = true;
bool selected = false;
- BMFace *efa;
- Image *ima;
-
- efa = BM_mesh_active_face_get(em->bm, sloppy, selected);
-
- if (efa) {
- ED_object_get_active_image(ob, efa->mat_nr + 1, &ima, NULL, NULL, NULL);
-
- ED_image_get_uv_aspect(ima, NULL, r_aspx, r_aspy);
- }
- else {
+ BMFace *efa = BM_mesh_active_face_get(em->bm, sloppy, selected);
+ if (!efa) {
*r_aspx = 1.0f;
*r_aspy = 1.0f;
+ return;
}
+
+ ED_uvedit_get_aspect_from_material(ob, efa->mat_nr, r_aspx, r_aspy);
}
static void construct_param_handle_face_add(ParamHandle *handle,
@@ -1527,49 +1536,88 @@ static void uv_transform_properties(wmOperatorType *ot, int radius)
}
}
-static void correct_uv_aspect(Object *ob, BMEditMesh *em)
+static void shrink_loop_uv_by_aspect_ratio(BMFace *efa,
+ const int cd_loop_uv_offset,
+ const float aspect_y)
{
+ BLI_assert(aspect_y != 1.0f); /* Nothing to do, should be handled by caller. */
+ BLI_assert(aspect_y > 0.0f); /* Negative aspect ratios are not supported. */
+
BMLoop *l;
- BMIter iter, liter;
- MLoopUV *luv;
- BMFace *efa;
- float scale, aspx, aspy;
+ BMIter iter;
+ BM_ITER_ELEM (l, &iter, efa, BM_LOOPS_OF_FACE) {
+ MLoopUV *luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
+ if (aspect_y > 1.0f) {
+ /* Reduce round-off error, i.e. `u = (u - 0.5) / aspect_y + 0.5`. */
+ luv->uv[0] = luv->uv[0] / aspect_y + (0.5f - 0.5f / aspect_y);
+ }
+ else {
+ /* Reduce round-off error, i.e. `v = (v - 0.5) * aspect_y + 0.5`. */
+ luv->uv[1] = luv->uv[1] * aspect_y + (0.5f - 0.5f * aspect_y);
+ }
+ }
+}
+static void correct_uv_aspect(Object *ob, BMEditMesh *em)
+{
const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV);
-
+ float aspx, aspy;
ED_uvedit_get_aspect(ob, &aspx, &aspy);
+ const float aspect_y = aspx / aspy;
+ if (aspect_y == 1.0f) {
+ /* Scaling by 1.0 has no effect. */
+ return;
+ }
+ BMFace *efa;
+ BMIter iter;
+ BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
+ if (BM_elem_flag_test(efa, BM_ELEM_SELECT)) {
+ shrink_loop_uv_by_aspect_ratio(efa, cd_loop_uv_offset, aspect_y);
+ }
+ }
+}
- if (aspx == aspy) {
+static void correct_uv_aspect_per_face(Object *ob, BMEditMesh *em)
+{
+ const int materials_num = ob->totcol;
+ if (materials_num == 0) {
+ /* Without any materials, there is no aspect_y information and nothing to do. */
return;
}
- if (aspx > aspy) {
- scale = aspy / aspx;
+ float *material_aspect_y = BLI_array_alloca(material_aspect_y, materials_num);
+ /* Lazily initialize aspect ratio for materials. */
+ copy_vn_fl(material_aspect_y, materials_num, -1.0f);
- BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
- if (!BM_elem_flag_test(efa, BM_ELEM_SELECT)) {
- continue;
- }
+ const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV);
- BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
- luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
- luv->uv[0] = ((luv->uv[0] - 0.5f) * scale) + 0.5f;
- }
+ BMFace *efa;
+ BMIter iter;
+ BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
+ if (!BM_elem_flag_test(efa, BM_ELEM_SELECT)) {
+ continue;
}
- }
- else {
- scale = aspx / aspy;
- BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
- if (!BM_elem_flag_test(efa, BM_ELEM_SELECT)) {
- continue;
- }
+ const int material_index = efa->mat_nr;
+ if (UNLIKELY(material_index < 0 || material_index >= materials_num)) {
+ /* The index might be for a material slot which is not currently setup. */
+ continue;
+ }
- BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
- luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
- luv->uv[1] = ((luv->uv[1] - 0.5f) * scale) + 0.5f;
- }
+ float aspect_y = material_aspect_y[material_index];
+ if (aspect_y == -1.0f) {
+ /* Lazily initialize aspect ratio for materials. */
+ float aspx, aspy;
+ ED_uvedit_get_aspect_from_material(ob, material_index, &aspx, &aspy);
+ aspect_y = aspx / aspy;
+ material_aspect_y[material_index] = aspect_y;
}
+
+ if (aspect_y == 1.0f) {
+ /* Scaling by 1.0 has no effect. */
+ continue;
+ }
+ shrink_loop_uv_by_aspect_ratio(efa, cd_loop_uv_offset, aspect_y);
}
}
@@ -1613,7 +1661,17 @@ static void uv_map_clip_correct_properties(wmOperatorType *ot)
uv_map_clip_correct_properties_ex(ot, true);
}
-static void uv_map_clip_correct_multi(Object **objects, uint objects_len, wmOperator *op)
+/**
+ * \param per_face_aspect: Calculate the aspect ratio per-face,
+ * otherwise use a single aspect for all UV's based on the material of the active face.
+ * TODO: using per-face aspect may split UV islands so more advanced UV projection methods
+ * such as "Unwrap" & "Smart UV Projections" will need to handle aspect correction themselves.
+ * For now keep using a single aspect for all faces in this case.
+ */
+static void uv_map_clip_correct_multi(Object **objects,
+ uint objects_len,
+ wmOperator *op,
+ bool per_face_aspect)
{
BMFace *efa;
BMLoop *l;
@@ -1633,9 +1691,14 @@ static void uv_map_clip_correct_multi(Object **objects, uint objects_len, wmOper
BMEditMesh *em = BKE_editmesh_from_object(ob);
const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV);
- /* correct for image aspect ratio */
+ /* Correct for image aspect ratio. */
if (correct_aspect) {
- correct_uv_aspect(ob, em);
+ if (per_face_aspect) {
+ correct_uv_aspect_per_face(ob, em);
+ }
+ else {
+ correct_uv_aspect(ob, em);
+ }
}
if (scale_to_bounds) {
@@ -1678,6 +1741,11 @@ static void uv_map_clip_correct_multi(Object **objects, uint objects_len, wmOper
dy = 1.0f / dy;
}
+ if (dx == 1.0f && dy == 1.0f) {
+ /* Scaling by 1.0 has no effect. */
+ return;
+ }
+
for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
Object *ob = objects[ob_index];
@@ -1702,7 +1770,7 @@ static void uv_map_clip_correct_multi(Object **objects, uint objects_len, wmOper
static void uv_map_clip_correct(Object *ob, wmOperator *op)
{
- uv_map_clip_correct_multi(&ob, 1, op);
+ uv_map_clip_correct_multi(&ob, 1, op, true);
}
/** \} */
@@ -2283,7 +2351,9 @@ static int smart_project_exec(bContext *C, wmOperator *op)
.use_seams = true,
});
- uv_map_clip_correct_multi(objects_changed, object_changed_len, op);
+ /* #ED_uvedit_pack_islands_multi only supports `per_face_aspect = false`. */
+ const bool per_face_aspect = false;
+ uv_map_clip_correct_multi(objects_changed, object_changed_len, op, per_face_aspect);
}
MEM_freeN(objects_changed);
@@ -2485,7 +2555,7 @@ static int uv_from_view_exec(bContext *C, wmOperator *op)
}
if (changed_multi) {
- uv_map_clip_correct_multi(objects, objects_len, op);
+ uv_map_clip_correct_multi(objects, objects_len, op, true);
}
MEM_freeN(objects);
diff --git a/source/blender/functions/FN_multi_function_builder.hh b/source/blender/functions/FN_multi_function_builder.hh
index a35339b2495..e6dc01eb539 100644
--- a/source/blender/functions/FN_multi_function_builder.hh
+++ b/source/blender/functions/FN_multi_function_builder.hh
@@ -207,9 +207,9 @@ void execute_materialized(TypeSequence<ParamTags...> /* param_tags */,
(
/* Setup information for all parameters. */
[&] {
- using ParamTag = ParamTags;
- using T = typename ParamTag::base_type;
- ArgInfo<ParamTags> &arg_info = std::get<I>(args_info);
+ typedef ParamTags ParamTag;
+ typedef typename ParamTag::base_type T;
+ [[maybe_unused]] ArgInfo<ParamTags> &arg_info = std::get<I>(args_info);
if constexpr (ParamTag::category == MFParamCategory::SingleInput) {
VArray<T> &varray = *args;
if (varray.is_single()) {
@@ -246,7 +246,7 @@ void execute_materialized(TypeSequence<ParamTags...> /* param_tags */,
[&] {
using ParamTag = ParamTags;
using T = typename ParamTag::base_type;
- ArgInfo<ParamTags> &arg_info = std::get<I>(args_info);
+ [[maybe_unused]] ArgInfo<ParamTags> &arg_info = std::get<I>(args_info);
if constexpr (ParamTag::category == MFParamCategory::SingleInput) {
if (arg_info.mode == ArgMode::Single) {
/* The single value has been filled into a buffer already reused for every chunk. */
@@ -282,9 +282,9 @@ void execute_materialized(TypeSequence<ParamTags...> /* param_tags */,
(
/* Destruct values that have been materialized before. */
[&] {
- using ParamTag = ParamTags;
- using T = typename ParamTag::base_type;
- ArgInfo<ParamTags> &arg_info = std::get<I>(args_info);
+ typedef ParamTags ParamTag;
+ typedef typename ParamTag::base_type T;
+ [[maybe_unused]] ArgInfo<ParamTags> &arg_info = std::get<I>(args_info);
if constexpr (ParamTag::category == MFParamCategory::SingleInput) {
if (arg_info.mode == ArgMode::Materialized) {
T *in_chunk = std::get<I>(buffers_owner).ptr();
@@ -298,9 +298,9 @@ void execute_materialized(TypeSequence<ParamTags...> /* param_tags */,
(
/* Destruct buffers for single value inputs. */
[&] {
- using ParamTag = ParamTags;
- using T = typename ParamTag::base_type;
- ArgInfo<ParamTags> &arg_info = std::get<I>(args_info);
+ typedef ParamTags ParamTag;
+ typedef typename ParamTag::base_type T;
+ [[maybe_unused]] ArgInfo<ParamTags> &arg_info = std::get<I>(args_info);
if constexpr (ParamTag::category == MFParamCategory::SingleInput) {
if (arg_info.mode == ArgMode::Single) {
MutableSpan<T> in_chunk = std::get<I>(buffers);
@@ -347,8 +347,8 @@ template<typename... ParamTags> class CustomMF : public MultiFunction {
(
/* Get all parameters from #params and store them in #retrieved_params. */
[&]() {
- using ParamTag = typename TagsSequence::template at_index<I>;
- using T = typename ParamTag::base_type;
+ typedef typename TagsSequence::template at_index<I> ParamTag;
+ typedef typename ParamTag::base_type T;
if constexpr (ParamTag::category == MFParamCategory::SingleInput) {
std::get<I>(retrieved_params) = params.readonly_single_input<T>(I);
@@ -402,7 +402,7 @@ template<typename... ParamTags> class CustomMF : public MultiFunction {
(
/* Loop over all parameter types and add an entry for each in the signature. */
[&] {
- using ParamTag = typename TagsSequence::template at_index<I>;
+ typedef typename TagsSequence::template at_index<I> ParamTag;
signature.add(ParamTag(), "");
}(),
...);
diff --git a/source/blender/gpu/GPU_capabilities.h b/source/blender/gpu/GPU_capabilities.h
index 0d0542aa528..061b850619f 100644
--- a/source/blender/gpu/GPU_capabilities.h
+++ b/source/blender/gpu/GPU_capabilities.h
@@ -30,6 +30,7 @@ int GPU_max_batch_vertices(void);
int GPU_max_vertex_attribs(void);
int GPU_max_varying_floats(void);
int GPU_max_shader_storage_buffer_bindings(void);
+int GPU_max_compute_shader_storage_blocks(void);
int GPU_extensions_len(void);
const char *GPU_extension_get(int i);
@@ -40,6 +41,7 @@ bool GPU_mip_render_workaround(void);
bool GPU_depth_blitting_workaround(void);
bool GPU_use_main_context_workaround(void);
bool GPU_use_hq_normals_workaround(void);
+bool GPU_clear_viewport_workaround(void);
bool GPU_crappy_amd_driver(void);
bool GPU_compute_shader_support(void);
diff --git a/source/blender/gpu/intern/gpu_capabilities.cc b/source/blender/gpu/intern/gpu_capabilities.cc
index b750dacaca6..6ef015492c7 100644
--- a/source/blender/gpu/intern/gpu_capabilities.cc
+++ b/source/blender/gpu/intern/gpu_capabilities.cc
@@ -142,6 +142,11 @@ bool GPU_use_hq_normals_workaround()
return GCaps.use_hq_normals_workaround;
}
+bool GPU_clear_viewport_workaround()
+{
+ return GCaps.clear_viewport_workaround;
+}
+
bool GPU_compute_shader_support()
{
return GCaps.compute_shader_support;
@@ -162,6 +167,12 @@ int GPU_max_shader_storage_buffer_bindings()
return GCaps.max_shader_storage_buffer_bindings;
}
+int GPU_max_compute_shader_storage_blocks()
+{
+ return GCaps.max_compute_shader_storage_blocks;
+}
+
+
/** \} */
/* -------------------------------------------------------------------- */
diff --git a/source/blender/gpu/intern/gpu_capabilities_private.hh b/source/blender/gpu/intern/gpu_capabilities_private.hh
index 4a951eb8458..a17dbe7f8e6 100644
--- a/source/blender/gpu/intern/gpu_capabilities_private.hh
+++ b/source/blender/gpu/intern/gpu_capabilities_private.hh
@@ -36,6 +36,7 @@ struct GPUCapabilities {
int max_vertex_attribs = 0;
int max_varying_floats = 0;
int max_shader_storage_buffer_bindings = 0;
+ int max_compute_shader_storage_blocks = 0;
int extensions_len = 0;
const char *(*extension_get)(int);
@@ -51,6 +52,7 @@ struct GPUCapabilities {
bool use_main_context_workaround = false;
bool broken_amd_driver = false;
bool use_hq_normals_workaround = false;
+ bool clear_viewport_workaround = false;
/* Vulkan related workarounds. */
/* Metal related workarounds. */
diff --git a/source/blender/gpu/intern/gpu_codegen.cc b/source/blender/gpu/intern/gpu_codegen.cc
index b6b0825a993..f1b46f8bf86 100644
--- a/source/blender/gpu/intern/gpu_codegen.cc
+++ b/source/blender/gpu/intern/gpu_codegen.cc
@@ -32,6 +32,7 @@
#include "GPU_vertex_format.h"
#include "BLI_sys_types.h" /* for intptr_t support */
+#include "BLI_vector.hh"
#include "gpu_codegen.h"
#include "gpu_material_library.h"
@@ -58,18 +59,27 @@ struct GPUCodegenCreateInfo : ShaderCreateInfo {
/** Duplicate attribute names to avoid reference the GPUNodeGraph directly. */
char attr_names[16][GPU_MAX_SAFE_ATTR_NAME + 1];
char var_names[16][8];
+ blender::Vector<std::array<char, 32>, 16> sampler_names;
+
+ /* Returns the appended name memory location */
+ const char *append_sampler_name(const char name[32])
+ {
+ auto index = sampler_names.append_and_get_index(std::array<char, 32>());
+ char *name_buffer = sampler_names[index].data();
+ memcpy(name_buffer, name, 32);
+ return name_buffer;
+ }
};
/** Optional generated interface. */
StageInterfaceInfo *interface_generated = nullptr;
/** Optional name buffer containing names referenced by StringRefNull. */
- NameBuffer *name_buffer = nullptr;
+ NameBuffer name_buffer;
GPUCodegenCreateInfo(const char *name) : ShaderCreateInfo(name){};
~GPUCodegenCreateInfo()
{
delete interface_generated;
- MEM_delete(name_buffer);
};
};
@@ -288,7 +298,6 @@ void GPUCodegen::generate_attribs()
GPUCodegenCreateInfo &info = *create_info;
- info.name_buffer = MEM_new<GPUCodegenCreateInfo::NameBuffer>("info.name_buffer");
info.interface_generated = new StageInterfaceInfo("codegen_iface", "var_attrs");
StageInterfaceInfo &iface = *info.interface_generated;
info.vertex_out(iface);
@@ -302,11 +311,11 @@ void GPUCodegen::generate_attribs()
BLI_assert_msg(0, "Too many attributes");
break;
}
- STRNCPY(info.name_buffer->attr_names[slot], attr->input_name);
- SNPRINTF(info.name_buffer->var_names[slot], "v%d", attr->id);
+ STRNCPY(info.name_buffer.attr_names[slot], attr->input_name);
+ SNPRINTF(info.name_buffer.var_names[slot], "v%d", attr->id);
- blender::StringRefNull attr_name = info.name_buffer->attr_names[slot];
- blender::StringRefNull var_name = info.name_buffer->var_names[slot];
+ blender::StringRefNull attr_name = info.name_buffer.attr_names[slot];
+ blender::StringRefNull var_name = info.name_buffer.var_names[slot];
eGPUType input_type, iface_type;
@@ -348,14 +357,19 @@ void GPUCodegen::generate_resources()
/* Textures. */
LISTBASE_FOREACH (GPUMaterialTexture *, tex, &graph.textures) {
if (tex->colorband) {
- info.sampler(0, ImageType::FLOAT_1D_ARRAY, tex->sampler_name, Frequency::BATCH);
+ const char *name = info.name_buffer.append_sampler_name(tex->sampler_name);
+ info.sampler(0, ImageType::FLOAT_1D_ARRAY, name, Frequency::BATCH);
}
else if (tex->tiled_mapping_name[0] != '\0') {
- info.sampler(0, ImageType::FLOAT_2D_ARRAY, tex->sampler_name, Frequency::BATCH);
- info.sampler(0, ImageType::FLOAT_1D_ARRAY, tex->tiled_mapping_name, Frequency::BATCH);
+ const char *name = info.name_buffer.append_sampler_name(tex->sampler_name);
+ info.sampler(0, ImageType::FLOAT_2D_ARRAY, name, Frequency::BATCH);
+
+ const char *name_mapping = info.name_buffer.append_sampler_name(tex->tiled_mapping_name);
+ info.sampler(0, ImageType::FLOAT_1D_ARRAY, name_mapping, Frequency::BATCH);
}
else {
- info.sampler(0, ImageType::FLOAT_2D, tex->sampler_name, Frequency::BATCH);
+ const char *name = info.name_buffer.append_sampler_name(tex->sampler_name);
+ info.sampler(0, ImageType::FLOAT_2D, name, Frequency::BATCH);
}
}
diff --git a/source/blender/gpu/intern/gpu_index_buffer.cc b/source/blender/gpu/intern/gpu_index_buffer.cc
index 54473b3a44d..146461d1dfb 100644
--- a/source/blender/gpu/intern/gpu_index_buffer.cc
+++ b/source/blender/gpu/intern/gpu_index_buffer.cc
@@ -232,6 +232,7 @@ void IndexBuf::init(uint indices_len, uint32_t *indices, uint min_index, uint ma
data_ = indices;
index_start_ = 0;
index_len_ = indices_len;
+ is_empty_ = min_index > max_index;
#if GPU_TRACK_INDEX_RANGE
/* Everything remains 32 bit while building to keep things simple.
diff --git a/source/blender/gpu/intern/gpu_index_buffer_private.hh b/source/blender/gpu/intern/gpu_index_buffer_private.hh
index 9323a81d393..6ce62ae852e 100644
--- a/source/blender/gpu/intern/gpu_index_buffer_private.hh
+++ b/source/blender/gpu/intern/gpu_index_buffer_private.hh
@@ -45,6 +45,8 @@ class IndexBuf {
bool is_init_ = false;
/** Is this object only a reference to a subrange of another IndexBuf. */
bool is_subrange_ = false;
+ /** True if buffer only contains restart indices. */
+ bool is_empty_ = false;
union {
/** Mapped buffer data. non-NULL indicates not yet sent to VRAM. */
@@ -61,9 +63,12 @@ class IndexBuf {
void init_subrange(IndexBuf *elem_src, uint start, uint length);
void init_build_on_device(uint index_len);
+ /* Returns render index count (not precise). */
uint32_t index_len_get() const
{
- return index_len_;
+ /* Return 0 to bypass drawing for index buffers full of restart indices.
+ * They can lead to graphical glitches on some systems. (See T96892) */
+ return is_empty_ ? 0 : index_len_;
}
/* Return size in byte of the drawable data buffer range. Actual buffer size might be bigger. */
size_t size_get() const
diff --git a/source/blender/gpu/intern/gpu_node_graph.c b/source/blender/gpu/intern/gpu_node_graph.c
index bc7ace792bb..91fb0544cf6 100644
--- a/source/blender/gpu/intern/gpu_node_graph.c
+++ b/source/blender/gpu/intern/gpu_node_graph.c
@@ -333,6 +333,8 @@ static char attr_prefix_get(CustomDataType type)
switch (type) {
case CD_TANGENT:
return 't';
+ case CD_MCOL:
+ return 'c';
case CD_AUTO_FROM_NAME:
return 'a';
case CD_HAIRLENGTH:
@@ -611,7 +613,7 @@ bool GPU_link(GPUMaterial *mat, const char *name, ...)
va_start(params, name);
for (i = 0; i < function->totparam; i++) {
- if (function->paramqual[i] != FUNCTION_QUAL_IN) {
+ if (function->paramqual[i] == FUNCTION_QUAL_OUT) {
linkptr = va_arg(params, GPUNodeLink **);
gpu_node_output(node, function->paramtype[i], linkptr);
}
@@ -669,7 +671,7 @@ static bool gpu_stack_link_v(GPUMaterial *material,
}
for (i = 0; i < function->totparam; i++) {
- if (function->paramqual[i] != FUNCTION_QUAL_IN) {
+ if (function->paramqual[i] == FUNCTION_QUAL_OUT) {
if (totout == 0) {
linkptr = va_arg(params, GPUNodeLink **);
gpu_node_output(node, function->paramtype[i], linkptr);
diff --git a/source/blender/gpu/intern/gpu_shader_builtin.c b/source/blender/gpu/intern/gpu_shader_builtin.c
index 13238a03688..1100272b712 100644
--- a/source/blender/gpu/intern/gpu_shader_builtin.c
+++ b/source/blender/gpu/intern/gpu_shader_builtin.c
@@ -367,6 +367,16 @@ GPUShader *GPU_shader_get_builtin_shader_with_config(eGPUBuiltinShader shader,
if (sh_cfg == GPU_SHADER_CFG_DEFAULT) {
if (stages->create_info != NULL) {
*sh_p = GPU_shader_create_from_info_name(stages->create_info);
+ if (ELEM(shader,
+ GPU_SHADER_3D_POLYLINE_CLIPPED_UNIFORM_COLOR,
+ GPU_SHADER_3D_POLYLINE_UNIFORM_COLOR,
+ GPU_SHADER_3D_POLYLINE_FLAT_COLOR,
+ GPU_SHADER_3D_POLYLINE_SMOOTH_COLOR)) {
+ /* Set a default value for `lineSmooth`.
+ * Ideally this value should be set by the caller. */
+ GPU_shader_bind(*sh_p);
+ GPU_shader_uniform_1i(*sh_p, "lineSmooth", 1);
+ }
}
else {
*sh_p = GPU_shader_create_from_arrays_named(
diff --git a/source/blender/gpu/intern/gpu_shader_dependency.cc b/source/blender/gpu/intern/gpu_shader_dependency.cc
index 460b6d32967..f69c56b5f3f 100644
--- a/source/blender/gpu/intern/gpu_shader_dependency.cc
+++ b/source/blender/gpu/intern/gpu_shader_dependency.cc
@@ -8,6 +8,7 @@
* shader files.
*/
+#include <algorithm>
#include <iomanip>
#include <iostream>
#include <sstream>
@@ -98,6 +99,10 @@ struct GPUSource {
/* Limit to shared header files to avoid the temptation to use C++ syntax in .glsl files. */
if (filename.endswith(".h") || filename.endswith(".hh")) {
enum_preprocess();
+ quote_preprocess();
+ }
+ else {
+ check_no_quotes();
}
if (is_from_material_library()) {
@@ -174,6 +179,44 @@ struct GPUSource {
}
/**
+ * Some drivers completely forbid quote characters even in unused preprocessor directives.
+ * We fix the cases where we can't manually patch in `enum_preprocess()`.
+ * This check ensure none are present in non-patched sources. (see T97545)
+ */
+ void check_no_quotes()
+ {
+#ifdef DEBUG
+ int64_t pos = -1;
+ do {
+ pos = source.find('"', pos + 1);
+ if (pos == -1) {
+ break;
+ }
+ if (!is_in_comment(source, pos)) {
+ print_error(source, pos, "Quote characters are forbidden in GLSL files");
+ }
+ } while (true);
+#endif
+ }
+
+ /**
+ * Some drivers completely forbid string characters even in unused preprocessor directives.
+ * This fixes the cases we cannot manually patch: Shared headers #includes. (see T97545)
+ * TODO(fclem): This could be done during the datatoc step.
+ */
+ void quote_preprocess()
+ {
+ if (source.find_first_of('"') == -1) {
+ return;
+ }
+
+ processed_source = source;
+ std::replace(processed_source.begin(), processed_source.end(), '"', ' ');
+
+ source = processed_source.c_str();
+ }
+
+ /**
* Transform C,C++ enum declaration into GLSL compatible defines and constants:
*
* \code{.cpp}
@@ -282,6 +325,7 @@ struct GPUSource {
if (last_pos != 0) {
output += input.substr(last_pos);
}
+
processed_source = output;
source = processed_source.c_str();
};
diff --git a/source/blender/gpu/intern/gpu_viewport.c b/source/blender/gpu/intern/gpu_viewport.c
index a0efe12f523..c3118ca320c 100644
--- a/source/blender/gpu/intern/gpu_viewport.c
+++ b/source/blender/gpu/intern/gpu_viewport.c
@@ -21,6 +21,7 @@
#include "DNA_userdef_types.h"
#include "DNA_vec_types.h"
+#include "GPU_capabilities.h"
#include "GPU_framebuffer.h"
#include "GPU_immediate.h"
#include "GPU_matrix.h"
@@ -126,19 +127,23 @@ static void gpu_viewport_textures_create(GPUViewport *viewport)
if (viewport->color_render_tx[0] == NULL) {
viewport->color_render_tx[0] = GPU_texture_create_2d(
"dtxl_color", UNPACK2(size), 1, GPU_RGBA16F, NULL);
- GPU_texture_clear(viewport->color_render_tx[0], GPU_DATA_FLOAT, empty_pixel);
viewport->color_overlay_tx[0] = GPU_texture_create_2d(
"dtxl_color_overlay", UNPACK2(size), 1, GPU_SRGB8_A8, NULL);
- GPU_texture_clear(viewport->color_overlay_tx[0], GPU_DATA_FLOAT, empty_pixel);
+ if (GPU_clear_viewport_workaround()) {
+ GPU_texture_clear(viewport->color_render_tx[0], GPU_DATA_FLOAT, empty_pixel);
+ GPU_texture_clear(viewport->color_overlay_tx[0], GPU_DATA_FLOAT, empty_pixel);
+ }
}
if ((viewport->flag & GPU_VIEWPORT_STEREO) != 0 && viewport->color_render_tx[1] == NULL) {
viewport->color_render_tx[1] = GPU_texture_create_2d(
"dtxl_color_stereo", UNPACK2(size), 1, GPU_RGBA16F, NULL);
- GPU_texture_clear(viewport->color_render_tx[1], GPU_DATA_FLOAT, empty_pixel);
viewport->color_overlay_tx[1] = GPU_texture_create_2d(
"dtxl_color_overlay_stereo", UNPACK2(size), 1, GPU_SRGB8_A8, NULL);
- GPU_texture_clear(viewport->color_overlay_tx[1], GPU_DATA_FLOAT, empty_pixel);
+ if (GPU_clear_viewport_workaround()) {
+ GPU_texture_clear(viewport->color_render_tx[1], GPU_DATA_FLOAT, empty_pixel);
+ GPU_texture_clear(viewport->color_overlay_tx[1], GPU_DATA_FLOAT, empty_pixel);
+ }
}
/* Can be shared with GPUOffscreen. */
@@ -262,12 +267,15 @@ void GPU_viewport_stereo_composite(GPUViewport *viewport, Stereo3dFormat *stereo
return;
}
/* The composite framebuffer object needs to be created in the window context. */
- GPU_framebuffer_ensure_config(&viewport->stereo_comp_fb,
- {
- GPU_ATTACHMENT_NONE,
- GPU_ATTACHMENT_TEXTURE(viewport->color_overlay_tx[0]),
- GPU_ATTACHMENT_TEXTURE(viewport->color_render_tx[0]),
- });
+ GPU_framebuffer_ensure_config(
+ &viewport->stereo_comp_fb,
+ {
+ GPU_ATTACHMENT_NONE,
+ /* We need the sRGB attachment to be first for GL_FRAMEBUFFER_SRGB to be turned on.
+ * Note that this is the opposite of what the texture binding is. */
+ GPU_ATTACHMENT_TEXTURE(viewport->color_overlay_tx[0]),
+ GPU_ATTACHMENT_TEXTURE(viewport->color_render_tx[0]),
+ });
GPUVertFormat *vert_format = immVertexFormat();
uint pos = GPU_vertformat_attr_add(vert_format, "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
diff --git a/source/blender/gpu/opengl/gl_backend.cc b/source/blender/gpu/opengl/gl_backend.cc
index 610fd5d980f..1cd2301aa4e 100644
--- a/source/blender/gpu/opengl/gl_backend.cc
+++ b/source/blender/gpu/opengl/gl_backend.cc
@@ -419,6 +419,13 @@ static void detect_workarounds()
GCaps.shader_storage_buffer_objects_support = false;
}
+ /* Certain Intel/AMD based platforms don't clear the viewport textures. Always clearing leads to
+ * noticeable performance regressions on other platforms as well. */
+ if (GPU_type_matches(GPU_DEVICE_ANY, GPU_OS_MAC, GPU_DRIVER_ANY) ||
+ GPU_type_matches(GPU_DEVICE_INTEL, GPU_OS_UNIX, GPU_DRIVER_ANY)) {
+ GCaps.clear_viewport_workaround = true;
+ }
+
/* Metal-related Workarounds. */
/* Minimum Per-Vertex stride is 1 byte for OpenGL. */
@@ -503,6 +510,7 @@ void GLBackend::capabilities_init()
glGetIntegeri_v(GL_MAX_COMPUTE_WORK_GROUP_SIZE, 2, &GCaps.max_work_group_size[2]);
glGetIntegerv(GL_MAX_SHADER_STORAGE_BUFFER_BINDINGS,
&GCaps.max_shader_storage_buffer_bindings);
+ glGetIntegerv(GL_MAX_COMPUTE_SHADER_STORAGE_BLOCKS, &GCaps.max_compute_shader_storage_blocks);
}
GCaps.shader_storage_buffer_objects_support = GLEW_ARB_shader_storage_buffer_object;
/* GL specific capabilities. */
diff --git a/source/blender/gpu/shaders/gpu_shader_codegen_lib.glsl b/source/blender/gpu/shaders/gpu_shader_codegen_lib.glsl
index 5c97eada77d..6091a5c834a 100644
--- a/source/blender/gpu/shaders/gpu_shader_codegen_lib.glsl
+++ b/source/blender/gpu/shaders/gpu_shader_codegen_lib.glsl
@@ -191,8 +191,8 @@ struct GlobalData {
vec3 N;
/** Geometric Normal. */
vec3 Ng;
- /** Surface default Tangent. */
- vec3 T;
+ /** Curve Tangent Space. */
+ vec3 curve_T, curve_B, curve_N;
/** Barycentric coordinates. */
vec2 barycentric_coords;
vec3 barycentric_dists;
diff --git a/source/blender/gpu/shaders/gpu_shader_image_overlays_stereo_merge_frag.glsl b/source/blender/gpu/shaders/gpu_shader_image_overlays_stereo_merge_frag.glsl
index 9b1e6fe9d23..522f6de169d 100644
--- a/source/blender/gpu/shaders/gpu_shader_image_overlays_stereo_merge_frag.glsl
+++ b/source/blender/gpu/shaders/gpu_shader_image_overlays_stereo_merge_frag.glsl
@@ -5,18 +5,6 @@
#define S3D_INTERLACE_COLUMN 1
#define S3D_INTERLACE_CHECKERBOARD 2
-/* Composite stereo textures */
-
-#ifndef USE_GPU_SHADER_CREATE_INFO
-uniform sampler2D imageTexture;
-uniform sampler2D overlayTexture;
-
-uniform int stereoDisplaySettings;
-
-layout(location = 0) out vec4 imageColor;
-layout(location = 1) out vec4 overlayColor;
-#endif
-
#define stereo_display_mode (stereoDisplaySettings & ((1 << 3) - 1))
#define stereo_interlace_mode ((stereoDisplaySettings >> 3) & ((1 << 3) - 1))
#define stereo_interlace_swap bool(stereoDisplaySettings >> 6)
diff --git a/source/blender/gpu/shaders/infos/gpu_shader_2D_image_overlays_stereo_merge_info.hh b/source/blender/gpu/shaders/infos/gpu_shader_2D_image_overlays_stereo_merge_info.hh
index 4b2d59cc159..3cacd0f4b8d 100644
--- a/source/blender/gpu/shaders/infos/gpu_shader_2D_image_overlays_stereo_merge_info.hh
+++ b/source/blender/gpu/shaders/infos/gpu_shader_2D_image_overlays_stereo_merge_info.hh
@@ -9,8 +9,8 @@
GPU_SHADER_CREATE_INFO(gpu_shader_2D_image_overlays_stereo_merge)
.vertex_in(0, Type::VEC2, "pos")
- .fragment_out(0, Type::VEC4, "imageColor")
- .fragment_out(1, Type::VEC4, "overlayColor")
+ .fragment_out(0, Type::VEC4, "overlayColor")
+ .fragment_out(1, Type::VEC4, "imageColor")
.sampler(0, ImageType::FLOAT_2D, "imageTexture")
.sampler(1, ImageType::FLOAT_2D, "overlayTexture")
.push_constant(Type::MAT4, "ModelViewProjectionMatrix")
diff --git a/source/blender/gpu/shaders/material/gpu_shader_material_add_shader.glsl b/source/blender/gpu/shaders/material/gpu_shader_material_add_shader.glsl
index 99117400c57..3f42b6d9094 100644
--- a/source/blender/gpu/shaders/material/gpu_shader_material_add_shader.glsl
+++ b/source/blender/gpu/shaders/material/gpu_shader_material_add_shader.glsl
@@ -1,4 +1,4 @@
-void node_add_shader(Closure shader1, Closure shader2, out Closure shader)
+void node_add_shader(inout Closure shader1, inout Closure shader2, out Closure shader)
{
shader = closure_add(shader1, shader2);
}
diff --git a/source/blender/gpu/shaders/material/gpu_shader_material_eevee_specular.glsl b/source/blender/gpu/shaders/material/gpu_shader_material_eevee_specular.glsl
index c81880184e3..530907859e9 100644
--- a/source/blender/gpu/shaders/material/gpu_shader_material_eevee_specular.glsl
+++ b/source/blender/gpu/shaders/material/gpu_shader_material_eevee_specular.glsl
@@ -64,6 +64,8 @@ void node_eevee_specular(vec4 diffuse,
else {
result = closure_eval(diffuse_data, reflection_data);
}
- result = closure_add(result, closure_eval(emission_data));
- result = closure_add(result, closure_eval(transparency_data));
+ Closure emission_cl = closure_eval(emission_data);
+ Closure transparency_cl = closure_eval(transparency_data);
+ result = closure_add(result, emission_cl);
+ result = closure_add(result, transparency_cl);
}
diff --git a/source/blender/gpu/shaders/material/gpu_shader_material_geometry.glsl b/source/blender/gpu/shaders/material/gpu_shader_material_geometry.glsl
index 5e86a4577ee..4c9ff31622f 100644
--- a/source/blender/gpu/shaders/material/gpu_shader_material_geometry.glsl
+++ b/source/blender/gpu/shaders/material/gpu_shader_material_geometry.glsl
@@ -18,7 +18,7 @@ void node_geometry(vec3 orco,
true_normal = g_data.Ng;
if (g_data.is_strand) {
- tangent = g_data.T;
+ tangent = g_data.curve_T;
}
else {
tangent_orco_z(orco, orco);
diff --git a/source/blender/gpu/shaders/material/gpu_shader_material_hair.glsl b/source/blender/gpu/shaders/material/gpu_shader_material_hair.glsl
index 7bf8795495a..b24f9ab65f0 100644
--- a/source/blender/gpu/shaders/material/gpu_shader_material_hair.glsl
+++ b/source/blender/gpu/shaders/material/gpu_shader_material_hair.glsl
@@ -40,7 +40,7 @@ void node_bsdf_hair_principled(vec4 color,
hair_data.color = color.rgb;
hair_data.offset = offset;
hair_data.roughness = vec2(0.0);
- hair_data.T = g_data.T;
+ hair_data.T = g_data.curve_B;
result = closure_eval(hair_data);
}
diff --git a/source/blender/gpu/shaders/material/gpu_shader_material_hair_info.glsl b/source/blender/gpu/shaders/material/gpu_shader_material_hair_info.glsl
index a8b4b039370..2d5114c3bad 100644
--- a/source/blender/gpu/shaders/material/gpu_shader_material_hair_info.glsl
+++ b/source/blender/gpu/shaders/material/gpu_shader_material_hair_info.glsl
@@ -5,14 +5,14 @@ void node_hair_info(float hair_length,
out float intercept,
out float out_length,
out float thickness,
- out vec3 tangent,
+ out vec3 normal,
out float random)
{
is_strand = float(g_data.is_strand);
intercept = g_data.hair_time;
thickness = g_data.hair_thickness;
out_length = hair_length;
- tangent = g_data.T;
+ normal = g_data.curve_N;
/* TODO: could be precomputed per strand instead. */
random = wang_hash_noise(uint(g_data.hair_strand_id));
}
diff --git a/source/blender/gpu/shaders/material/gpu_shader_material_mix_shader.glsl b/source/blender/gpu/shaders/material/gpu_shader_material_mix_shader.glsl
index c303d21d7c1..00cfba3ca12 100644
--- a/source/blender/gpu/shaders/material/gpu_shader_material_mix_shader.glsl
+++ b/source/blender/gpu/shaders/material/gpu_shader_material_mix_shader.glsl
@@ -1,4 +1,4 @@
-void node_mix_shader(float fac, Closure shader1, Closure shader2, out Closure shader)
+void node_mix_shader(float fac, inout Closure shader1, inout Closure shader2, out Closure shader)
{
shader = closure_mix(shader1, shader2, fac);
}
diff --git a/source/blender/gpu/shaders/material/gpu_shader_material_principled.glsl b/source/blender/gpu/shaders/material/gpu_shader_material_principled.glsl
index 033dc05c57d..2e695fa3e14 100644
--- a/source/blender/gpu/shaders/material/gpu_shader_material_principled.glsl
+++ b/source/blender/gpu/shaders/material/gpu_shader_material_principled.glsl
@@ -169,6 +169,8 @@ void node_bsdf_principled(vec4 base_color,
/* Un-optimized case. */
result = closure_eval(diffuse_data, reflection_data, clearcoat_data, refraction_data);
}
- result = closure_add(result, closure_eval(emission_data));
- result = closure_add(result, closure_eval(transparency_data));
+ Closure emission_cl = closure_eval(emission_data);
+ Closure transparency_cl = closure_eval(transparency_data);
+ result = closure_add(result, emission_cl);
+ result = closure_add(result, transparency_cl);
}
diff --git a/source/blender/imbuf/intern/openexr/openexr_api.cpp b/source/blender/imbuf/intern/openexr/openexr_api.cpp
index 9948aaac5da..2281d8d85b3 100644
--- a/source/blender/imbuf/intern/openexr/openexr_api.cpp
+++ b/source/blender/imbuf/intern/openexr/openexr_api.cpp
@@ -1394,12 +1394,10 @@ static int imb_exr_split_channel_name(ExrChannel *echan, char *layname, char *pa
const char *name = echan->m->name.c_str();
const char *end = name + strlen(name);
const char *token;
- char tokenbuf[EXR_TOT_MAXNAME];
- int len;
/* some multilayers have the combined buffer with names A B G R saved */
if (name[1] == 0) {
- echan->chan_id = name[0];
+ echan->chan_id = BLI_toupper_ascii(name[0]);
layname[0] = '\0';
if (ELEM(name[0], 'R', 'G', 'B', 'A')) {
@@ -1416,13 +1414,17 @@ static int imb_exr_split_channel_name(ExrChannel *echan, char *layname, char *pa
}
/* last token is channel identifier */
- len = imb_exr_split_token(name, end, &token);
+ size_t len = imb_exr_split_token(name, end, &token);
if (len == 0) {
printf("multilayer read: bad channel name: %s\n", name);
return 0;
}
+
+ char channelname[EXR_TOT_MAXNAME];
+ BLI_strncpy(channelname, token, std::min(len + 1, sizeof(channelname)));
+
if (len == 1) {
- echan->chan_id = token[0];
+ echan->chan_id = BLI_toupper_ascii(channelname[0]);
}
else if (len > 1) {
bool ok = false;
@@ -1436,36 +1438,35 @@ static int imb_exr_split_channel_name(ExrChannel *echan, char *layname, char *pa
*
* Here we do some magic to distinguish such cases.
*/
- if (ELEM(token[1], 'X', 'Y', 'Z') || ELEM(token[1], 'R', 'G', 'B') ||
- ELEM(token[1], 'U', 'V', 'A')) {
- echan->chan_id = token[1];
+ const char chan_id = BLI_toupper_ascii(channelname[1]);
+ if (ELEM(chan_id, 'X', 'Y', 'Z', 'R', 'G', 'B', 'U', 'V', 'A')) {
+ echan->chan_id = chan_id;
ok = true;
}
}
- else if (BLI_strcaseeq(token, "red")) {
+ else if (BLI_strcaseeq(channelname, "red")) {
echan->chan_id = 'R';
ok = true;
}
- else if (BLI_strcaseeq(token, "green")) {
+ else if (BLI_strcaseeq(channelname, "green")) {
echan->chan_id = 'G';
ok = true;
}
- else if (BLI_strcaseeq(token, "blue")) {
+ else if (BLI_strcaseeq(channelname, "blue")) {
echan->chan_id = 'B';
ok = true;
}
- else if (BLI_strcaseeq(token, "alpha")) {
+ else if (BLI_strcaseeq(channelname, "alpha")) {
echan->chan_id = 'A';
ok = true;
}
- else if (BLI_strcaseeq(token, "depth")) {
+ else if (BLI_strcaseeq(channelname, "depth")) {
echan->chan_id = 'Z';
ok = true;
}
if (ok == false) {
- BLI_strncpy(tokenbuf, token, std::min(len + 1, EXR_TOT_MAXNAME));
- printf("multilayer read: unknown channel token: %s\n", tokenbuf);
+ printf("multilayer read: unknown channel token: %s\n", channelname);
return 0;
}
}
diff --git a/source/blender/io/alembic/intern/abc_reader_mesh.cc b/source/blender/io/alembic/intern/abc_reader_mesh.cc
index 2d2dcfb1f42..8c62484028d 100644
--- a/source/blender/io/alembic/intern/abc_reader_mesh.cc
+++ b/source/blender/io/alembic/intern/abc_reader_mesh.cc
@@ -622,7 +622,7 @@ void AbcMeshReader::readObjectData(Main *bmain, const Alembic::Abc::ISampleSelec
if (read_mesh != mesh) {
/* XXX FIXME: after 2.80; mesh->flag isn't copied by #BKE_mesh_nomain_to_mesh(). */
/* read_mesh can be freed by BKE_mesh_nomain_to_mesh(), so get the flag before that happens. */
- short autosmooth = (read_mesh->flag & ME_AUTOSMOOTH);
+ uint16_t autosmooth = (read_mesh->flag & ME_AUTOSMOOTH);
BKE_mesh_nomain_to_mesh(read_mesh, mesh, m_object, &CD_MASK_EVERYTHING, true);
mesh->flag |= autosmooth;
}
diff --git a/source/blender/io/common/CMakeLists.txt b/source/blender/io/common/CMakeLists.txt
index b1add38bf01..b5766b44025 100644
--- a/source/blender/io/common/CMakeLists.txt
+++ b/source/blender/io/common/CMakeLists.txt
@@ -19,10 +19,13 @@ set(SRC
intern/dupli_parent_finder.cc
intern/dupli_persistent_id.cc
intern/object_identifier.cc
+ intern/path_util.cc
intern/string_utils.cc
IO_abstract_hierarchy_iterator.h
IO_dupli_persistent_id.hh
+ IO_path_util.hh
+ IO_path_util_types.h
IO_string_utils.hh
IO_types.h
intern/dupli_parent_finder.hh
diff --git a/source/blender/io/common/IO_path_util.hh b/source/blender/io/common/IO_path_util.hh
new file mode 100644
index 00000000000..ac2f935523e
--- /dev/null
+++ b/source/blender/io/common/IO_path_util.hh
@@ -0,0 +1,29 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+#pragma once
+
+#include "BLI_string_ref.hh"
+#include "BLI_set.hh"
+
+#include "IO_path_util_types.h"
+
+namespace blender::io {
+
+/**
+ * Return a filepath relative to a destination directory, for use with
+ * exporters.
+ *
+ * When PATH_REFERENCE_COPY mode is used, the file path pair (source
+ * path, destination path) is added to the `copy_set`.
+ *
+ * Equivalent of bpy_extras.io_utils.path_reference.
+ */
+std::string path_reference(StringRefNull filepath,
+ StringRefNull base_src,
+ StringRefNull base_dst,
+ ePathReferenceMode mode,
+ Set<std::pair<std::string, std::string>> *copy_set = nullptr);
+
+/** Execute copying files of path_reference. */
+void path_reference_copy(const Set<std::pair<std::string, std::string>> &copy_set);
+
+} // namespace blender::io
diff --git a/source/blender/io/common/IO_path_util_types.h b/source/blender/io/common/IO_path_util_types.h
new file mode 100644
index 00000000000..0233f601a81
--- /dev/null
+++ b/source/blender/io/common/IO_path_util_types.h
@@ -0,0 +1,18 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+#pragma once
+
+/** Method used to reference paths. Equivalent of bpy_extras.io_utils.path_reference_mode. */
+typedef enum {
+ /** Use Relative paths with subdirectories only. */
+ PATH_REFERENCE_AUTO = 0,
+ /** Always write absolute paths. */
+ PATH_REFERENCE_ABSOLUTE = 1,
+ /** Write relative paths where possible. */
+ PATH_REFERENCE_RELATIVE = 2,
+ /** Match Absolute/Relative setting with input path. */
+ PATH_REFERENCE_MATCH = 3,
+ /** Filename only. */
+ PATH_REFERENCE_STRIP = 4,
+ /** Copy the file to the destination path. */
+ PATH_REFERENCE_COPY = 5,
+} ePathReferenceMode;
diff --git a/source/blender/io/common/intern/path_util.cc b/source/blender/io/common/intern/path_util.cc
new file mode 100644
index 00000000000..2b9a1d67b44
--- /dev/null
+++ b/source/blender/io/common/intern/path_util.cc
@@ -0,0 +1,81 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+#include "IO_path_util.hh"
+
+#include "BLI_fileops.h"
+#include "BLI_path_util.h"
+
+namespace blender::io {
+
+std::string path_reference(StringRefNull filepath,
+ StringRefNull base_src,
+ StringRefNull base_dst,
+ ePathReferenceMode mode,
+ Set<std::pair<std::string, std::string>> *copy_set)
+{
+ const bool is_relative = BLI_path_is_rel(filepath.c_str());
+ char filepath_abs[PATH_MAX];
+ BLI_strncpy(filepath_abs, filepath.c_str(), PATH_MAX);
+ BLI_path_abs(filepath_abs, base_src.c_str());
+ BLI_path_normalize(nullptr, filepath_abs);
+
+ /* Figure out final mode to be used. */
+ if (mode == PATH_REFERENCE_MATCH) {
+ mode = is_relative ? PATH_REFERENCE_RELATIVE : PATH_REFERENCE_ABSOLUTE;
+ }
+ else if (mode == PATH_REFERENCE_AUTO) {
+ mode = BLI_path_contains(base_dst.c_str(), filepath_abs) ? PATH_REFERENCE_RELATIVE :
+ PATH_REFERENCE_ABSOLUTE;
+ }
+ else if (mode == PATH_REFERENCE_COPY) {
+ char filepath_cpy[PATH_MAX];
+ BLI_path_join(filepath_cpy, PATH_MAX, base_dst.c_str(), BLI_path_basename(filepath_abs), nullptr);
+ copy_set->add(std::make_pair(filepath_abs, filepath_cpy));
+ BLI_strncpy(filepath_abs, filepath_cpy, PATH_MAX);
+ mode = PATH_REFERENCE_RELATIVE;
+ }
+
+ /* Now we know the final path mode. */
+ if (mode == PATH_REFERENCE_ABSOLUTE) {
+ return filepath_abs;
+ }
+ else if (mode == PATH_REFERENCE_RELATIVE) {
+ char rel_path[PATH_MAX];
+ BLI_strncpy(rel_path, filepath_abs, PATH_MAX);
+ BLI_path_rel(rel_path, base_dst.c_str());
+ /* Can't always find relative path (e.g. between different drives). */
+ if (!BLI_path_is_rel(rel_path)) {
+ return filepath_abs;
+ }
+ return rel_path + 2; /* Skip blender's internal "//" prefix. */
+ }
+ else if (mode == PATH_REFERENCE_STRIP) {
+ return BLI_path_basename(filepath_abs);
+ }
+ BLI_assert_msg(false, "Invalid path reference mode");
+ return filepath_abs;
+}
+
+void path_reference_copy(const Set<std::pair<std::string, std::string>> &copy_set)
+{
+ for (const auto &copy : copy_set) {
+ const char *src = copy.first.c_str();
+ const char *dst = copy.second.c_str();
+ if (!BLI_exists(src)) {
+ fprintf(stderr, "Missing source file '%s', not copying\n", src);
+ continue;
+ }
+ if (0 == BLI_path_cmp_normalized(src, dst)) {
+ continue; /* Source and dest are the same. */
+ }
+ if (!BLI_make_existing_file(dst)) {
+ fprintf(stderr, "Can't make directory for '%s', not copying\n", dst);
+ continue;
+ }
+ if (!BLI_copy(src, dst)) {
+ fprintf(stderr, "Can't copy '%s' to '%s'\n", src, dst);
+ continue;
+ }
+ }
+}
+
+} // namespace blender::io
diff --git a/source/blender/io/usd/intern/usd_reader_mesh.cc b/source/blender/io/usd/intern/usd_reader_mesh.cc
index 328b4109616..e2562eca69b 100644
--- a/source/blender/io/usd/intern/usd_reader_mesh.cc
+++ b/source/blender/io/usd/intern/usd_reader_mesh.cc
@@ -200,7 +200,7 @@ void USDMeshReader::read_object_data(Main *bmain, const double motionSampleTime)
if (read_mesh != mesh) {
/* FIXME: after 2.80; `mesh->flag` isn't copied by #BKE_mesh_nomain_to_mesh() */
/* read_mesh can be freed by BKE_mesh_nomain_to_mesh(), so get the flag before that happens. */
- short autosmooth = (read_mesh->flag & ME_AUTOSMOOTH);
+ uint16_t autosmooth = (read_mesh->flag & ME_AUTOSMOOTH);
BKE_mesh_nomain_to_mesh(read_mesh, mesh, object_, &CD_MASK_MESH, true);
mesh->flag |= autosmooth;
}
diff --git a/source/blender/io/wavefront_obj/IO_wavefront_obj.h b/source/blender/io/wavefront_obj/IO_wavefront_obj.h
index 8b71ec750c0..f7bf678310f 100644
--- a/source/blender/io/wavefront_obj/IO_wavefront_obj.h
+++ b/source/blender/io/wavefront_obj/IO_wavefront_obj.h
@@ -9,6 +9,7 @@
#include "BKE_context.h"
#include "BLI_path_util.h"
#include "DEG_depsgraph.h"
+#include "IO_path_util_types.h"
#ifdef __cplusplus
extern "C" {
@@ -37,6 +38,8 @@ static const int TOTAL_AXES = 3;
struct OBJExportParams {
/** Full path to the destination .OBJ file. */
char filepath[FILE_MAX];
+ /** Pretend that destination file folder is this, if non-empty. Used only for tests. */
+ char file_base_for_tests[FILE_MAX];
/** Full path to current blender file (used for comments in output). */
const char *blen_filepath;
@@ -62,6 +65,7 @@ struct OBJExportParams {
bool export_materials;
bool export_triangulated_mesh;
bool export_curves_as_nurbs;
+ ePathReferenceMode path_mode;
/* Grouping options. */
bool export_object_groups;
diff --git a/source/blender/io/wavefront_obj/exporter/obj_export_file_writer.cc b/source/blender/io/wavefront_obj/exporter/obj_export_file_writer.cc
index 194583e71fe..b027df73b1e 100644
--- a/source/blender/io/wavefront_obj/exporter/obj_export_file_writer.cc
+++ b/source/blender/io/wavefront_obj/exporter/obj_export_file_writer.cc
@@ -13,6 +13,8 @@
#include "BLI_path_util.h"
#include "BLI_task.hh"
+#include "IO_path_util.hh"
+
#include "obj_export_mesh.hh"
#include "obj_export_mtl.hh"
#include "obj_export_nurbs.hh"
@@ -530,7 +532,11 @@ void MTLWriter::write_bsdf_properties(const MTLMaterial &mtl_material)
void MTLWriter::write_texture_map(
const MTLMaterial &mtl_material,
- const Map<const eMTLSyntaxElement, tex_map_XX>::Item &texture_map)
+ const Map<const eMTLSyntaxElement, tex_map_XX>::Item &texture_map,
+ const char *blen_filedir,
+ const char *dest_dir,
+ ePathReferenceMode path_mode,
+ Set<std::pair<std::string, std::string>> &copy_set)
{
std::string options;
/* Option strings should have their own leading spaces. */
@@ -546,7 +552,11 @@ void MTLWriter::write_texture_map(
#define SYNTAX_DISPATCH(eMTLSyntaxElement) \
if (texture_map.key == eMTLSyntaxElement) { \
- fmt_handler_.write<eMTLSyntaxElement>(options, texture_map.value.image_path); \
+ std::string path = path_reference( \
+ texture_map.value.image_path.c_str(), blen_filedir, dest_dir, path_mode, &copy_set); \
+ /* Always emit forward slashes for cross-platform compatibility. */ \
+ std::replace(path.begin(), path.end(), '\\', '/'); \
+ fmt_handler_.write<eMTLSyntaxElement>(options, path.c_str()); \
return; \
}
@@ -561,25 +571,35 @@ void MTLWriter::write_texture_map(
BLI_assert(!"This map type was not written to the file.");
}
-void MTLWriter::write_materials()
+void MTLWriter::write_materials(const char *blen_filepath,
+ ePathReferenceMode path_mode,
+ const char *dest_dir)
{
if (mtlmaterials_.size() == 0) {
return;
}
+
+ char blen_filedir[PATH_MAX];
+ BLI_split_dir_part(blen_filepath, blen_filedir, PATH_MAX);
+ BLI_path_slash_native(blen_filedir);
+ BLI_path_normalize(nullptr, blen_filedir);
+
std::sort(mtlmaterials_.begin(),
mtlmaterials_.end(),
[](const MTLMaterial &a, const MTLMaterial &b) { return a.name < b.name; });
+ Set<std::pair<std::string, std::string>> copy_set;
for (const MTLMaterial &mtlmat : mtlmaterials_) {
fmt_handler_.write<eMTLSyntaxElement::string>("\n");
fmt_handler_.write<eMTLSyntaxElement::newmtl>(mtlmat.name);
write_bsdf_properties(mtlmat);
- for (const Map<const eMTLSyntaxElement, tex_map_XX>::Item &texture_map :
- mtlmat.texture_maps.items()) {
- if (!texture_map.value.image_path.empty()) {
- write_texture_map(mtlmat, texture_map);
+ for (const auto &tex : mtlmat.texture_maps.items()) {
+ if (tex.value.image_path.empty()) {
+ continue;
}
+ write_texture_map(mtlmat, tex, blen_filedir, dest_dir, path_mode, copy_set);
}
}
+ path_reference_copy(copy_set);
}
Vector<int> MTLWriter::add_materials(const OBJMesh &mesh_to_export)
diff --git a/source/blender/io/wavefront_obj/exporter/obj_export_file_writer.hh b/source/blender/io/wavefront_obj/exporter/obj_export_file_writer.hh
index 96f7d434338..77da7b44276 100644
--- a/source/blender/io/wavefront_obj/exporter/obj_export_file_writer.hh
+++ b/source/blender/io/wavefront_obj/exporter/obj_export_file_writer.hh
@@ -9,6 +9,7 @@
#include "DNA_meshdata_types.h"
#include "BLI_map.hh"
+#include "BLI_set.hh"
#include "BLI_vector.hh"
#include "IO_wavefront_obj.h"
@@ -181,7 +182,9 @@ class MTLWriter : NonMovable, NonCopyable {
* For consistency of output from run to run (useful for testing),
* the materials are sorted by name before writing.
*/
- void write_materials();
+ void write_materials(const char *blen_filepath,
+ ePathReferenceMode path_mode,
+ const char *dest_dir);
StringRefNull mtl_file_path() const;
/**
* Add the materials of the given object to #MTLWriter, de-duplicating
@@ -203,6 +206,10 @@ class MTLWriter : NonMovable, NonCopyable {
* Write a texture map in the form "map_XX -s 1. 1. 1. -o 0. 0. 0. [-bm 1.] path/to/image".
*/
void write_texture_map(const MTLMaterial &mtl_material,
- const Map<const eMTLSyntaxElement, tex_map_XX>::Item &texture_map);
+ const Map<const eMTLSyntaxElement, tex_map_XX>::Item &texture_map,
+ const char *blen_filedir,
+ const char *dest_dir,
+ ePathReferenceMode mode,
+ Set<std::pair<std::string, std::string>> &copy_set);
};
} // namespace blender::io::obj
diff --git a/source/blender/io/wavefront_obj/exporter/obj_export_mtl.cc b/source/blender/io/wavefront_obj/exporter/obj_export_mtl.cc
index c48d5a5f7f0..4ed148ec64e 100644
--- a/source/blender/io/wavefront_obj/exporter/obj_export_mtl.cc
+++ b/source/blender/io/wavefront_obj/exporter/obj_export_mtl.cc
@@ -113,8 +113,7 @@ static const bNode *get_node_of_type(Span<const nodes::OutputSocketRef *> socket
/**
* From a texture image shader node, get the image's filepath.
- * Returned filepath is stripped of initial "//". If packed image is found,
- * only the file "name" is returned.
+ * If packed image is found, only the file "name" is returned.
*/
static const char *get_image_filepath(const bNode *tex_node)
{
@@ -134,9 +133,6 @@ static const char *get_image_filepath(const bNode *tex_node)
"directory as the .MTL file.\n",
path);
}
- if (path[0] == '/' && path[1] == '/') {
- path += 2;
- }
return path;
}
diff --git a/source/blender/io/wavefront_obj/exporter/obj_exporter.cc b/source/blender/io/wavefront_obj/exporter/obj_exporter.cc
index 78b709c884a..b6e636b389d 100644
--- a/source/blender/io/wavefront_obj/exporter/obj_exporter.cc
+++ b/source/blender/io/wavefront_obj/exporter/obj_exporter.cc
@@ -284,7 +284,16 @@ void export_frame(Depsgraph *depsgraph, const OBJExportParams &export_params, co
std::move(exportable_as_mesh), *frame_writer, mtl_writer.get(), export_params);
if (mtl_writer) {
mtl_writer->write_header(export_params.blen_filepath);
- mtl_writer->write_materials();
+ char dest_dir[PATH_MAX];
+ if (export_params.file_base_for_tests[0] == '\0') {
+ BLI_split_dir_part(export_params.filepath, dest_dir, PATH_MAX);
+ }
+ else {
+ BLI_strncpy(dest_dir, export_params.file_base_for_tests, PATH_MAX);
+ }
+ BLI_path_slash_native(dest_dir);
+ BLI_path_normalize(nullptr, dest_dir);
+ mtl_writer->write_materials(export_params.blen_filepath, export_params.path_mode, dest_dir);
}
write_nurbs_curve_objects(std::move(exportable_as_nurbs), *frame_writer);
}
diff --git a/source/blender/io/wavefront_obj/importer/obj_import_mesh.cc b/source/blender/io/wavefront_obj/importer/obj_import_mesh.cc
index fc40333c24d..8d560bd2c8c 100644
--- a/source/blender/io/wavefront_obj/importer/obj_import_mesh.cc
+++ b/source/blender/io/wavefront_obj/importer/obj_import_mesh.cc
@@ -62,7 +62,7 @@ Object *MeshFromGeometry::create_mesh(Main *bmain,
transform_object(obj, import_params);
/* FIXME: after 2.80; `mesh->flag` isn't copied by #BKE_mesh_nomain_to_mesh() */
- const short autosmooth = (mesh->flag & ME_AUTOSMOOTH);
+ const uint16_t autosmooth = (mesh->flag & ME_AUTOSMOOTH);
Mesh *dst = static_cast<Mesh *>(obj->data);
BKE_mesh_nomain_to_mesh(mesh, dst, obj, &CD_MASK_EVERYTHING, true);
dst->flag |= autosmooth;
diff --git a/source/blender/io/wavefront_obj/tests/obj_exporter_tests.cc b/source/blender/io/wavefront_obj/tests/obj_exporter_tests.cc
index f74bfc155dd..8c49af90a82 100644
--- a/source/blender/io/wavefront_obj/tests/obj_exporter_tests.cc
+++ b/source/blender/io/wavefront_obj/tests/obj_exporter_tests.cc
@@ -11,12 +11,15 @@
#include "BKE_appdir.h"
#include "BKE_blender_version.h"
+#include "BKE_main.h"
#include "BLI_fileops.h"
#include "BLI_index_range.hh"
#include "BLI_string_utf8.h"
#include "BLI_vector.hh"
+#include "BLO_readfile.h"
+
#include "DEG_depsgraph.h"
#include "obj_export_file_writer.hh"
@@ -259,11 +262,12 @@ class obj_exporter_regression_test : public obj_exporter_test {
std::string tempdir = std::string(BKE_tempdir_base());
std::string out_file_path = tempdir + BLI_path_basename(golden_obj.c_str());
strncpy(params.filepath, out_file_path.c_str(), FILE_MAX - 1);
- params.blen_filepath = blendfile.c_str();
+ params.blen_filepath = bfile->main->filepath;
+ std::string golden_file_path = blender::tests::flags_test_asset_dir() + "/" + golden_obj;
+ BLI_split_dir_part(golden_file_path.c_str(), params.file_base_for_tests, PATH_MAX);
export_frame(depsgraph, params, out_file_path.c_str());
std::string output_str = read_temp_file_in_string(out_file_path);
- std::string golden_file_path = blender::tests::flags_test_asset_dir() + "/" + golden_obj;
std::string golden_str = read_temp_file_in_string(golden_file_path);
bool are_equal = strings_equal_after_first_lines(output_str, golden_str);
if (save_failing_test_output && !are_equal) {
@@ -432,19 +436,26 @@ TEST_F(obj_exporter_regression_test, cubes_positioned)
_export.params);
}
-/* Note: texture paths in the resulting mtl file currently are always
- * as they are stored in the source .blend file; not relative to where
- * the export is done. When that is properly fixed, the expected .mtl
- * file should be updated. */
-TEST_F(obj_exporter_regression_test, cubes_with_textures)
+TEST_F(obj_exporter_regression_test, cubes_with_textures_strip)
{
OBJExportParamsDefault _export;
+ _export.params.path_mode = PATH_REFERENCE_STRIP;
compare_obj_export_to_golden("io_tests/blend_geometry/cubes_with_textures.blend",
"io_tests/obj/cubes_with_textures.obj",
"io_tests/obj/cubes_with_textures.mtl",
_export.params);
}
+TEST_F(obj_exporter_regression_test, cubes_with_textures_relative)
+{
+ OBJExportParamsDefault _export;
+ _export.params.path_mode = PATH_REFERENCE_RELATIVE;
+ compare_obj_export_to_golden("io_tests/blend_geometry/cubes_with_textures.blend",
+ "io_tests/obj/cubes_with_textures_rel.obj",
+ "io_tests/obj/cubes_with_textures_rel.mtl",
+ _export.params);
+}
+
TEST_F(obj_exporter_regression_test, suzanne_all_data)
{
OBJExportParamsDefault _export;
diff --git a/source/blender/io/wavefront_obj/tests/obj_exporter_tests.hh b/source/blender/io/wavefront_obj/tests/obj_exporter_tests.hh
index 6a821e0b1bf..ef27a65fb4b 100644
--- a/source/blender/io/wavefront_obj/tests/obj_exporter_tests.hh
+++ b/source/blender/io/wavefront_obj/tests/obj_exporter_tests.hh
@@ -11,6 +11,7 @@ struct OBJExportParamsDefault {
OBJExportParamsDefault()
{
params.filepath[0] = '\0';
+ params.file_base_for_tests[0] = '\0';
params.blen_filepath = "";
params.export_animation = false;
params.start_frame = 0;
@@ -26,6 +27,7 @@ struct OBJExportParamsDefault {
params.export_uv = true;
params.export_normals = true;
params.export_materials = true;
+ params.path_mode = PATH_REFERENCE_AUTO;
params.export_triangulated_mesh = false;
params.export_curves_as_nurbs = false;
diff --git a/source/blender/makesdna/DNA_mesh_types.h b/source/blender/makesdna/DNA_mesh_types.h
index b98c9dd2886..4a57f60be26 100644
--- a/source/blender/makesdna/DNA_mesh_types.h
+++ b/source/blender/makesdna/DNA_mesh_types.h
@@ -280,7 +280,7 @@ typedef struct Mesh {
/** Various flags used when editing the mesh. */
char editflag;
/** Mostly more flags used when editing or displaying the mesh. */
- short flag;
+ uint16_t flag;
/**
* The angle for auto smooth in radians. `M_PI` (180 degrees) causes all edges to be smooth.
diff --git a/source/blender/makesdna/DNA_scene_types.h b/source/blender/makesdna/DNA_scene_types.h
index d7926e918a3..bc9b664ab34 100644
--- a/source/blender/makesdna/DNA_scene_types.h
+++ b/source/blender/makesdna/DNA_scene_types.h
@@ -1264,8 +1264,7 @@ typedef struct UnifiedPaintSettings {
* In case of anchored brushes contains the anchored radius */
float pixel_radius;
float initial_pixel_radius;
-
- char _pad[4];
+ float start_pixel_radius;
/* drawing pressure */
float size_pressure_value;
diff --git a/source/blender/makesdna/DNA_userdef_types.h b/source/blender/makesdna/DNA_userdef_types.h
index 49c16d1b514..7da3b2696fa 100644
--- a/source/blender/makesdna/DNA_userdef_types.h
+++ b/source/blender/makesdna/DNA_userdef_types.h
@@ -652,7 +652,7 @@ typedef struct UserDef_Experimental {
char enable_eevee_next;
char use_sculpt_texture_paint;
- char _pad[1];
+ char use_draw_manager_acquire_lock;
/** `makesdna` does not allow empty structs. */
} UserDef_Experimental;
diff --git a/source/blender/makesrna/intern/rna_ID.c b/source/blender/makesrna/intern/rna_ID.c
index b65e08311fe..b0488bbfa7a 100644
--- a/source/blender/makesrna/intern/rna_ID.c
+++ b/source/blender/makesrna/intern/rna_ID.c
@@ -1976,7 +1976,7 @@ static void rna_def_ID(BlenderRNA *brna)
RNA_def_property_ui_text(
prop,
"Extra User",
- "Indicates wether an extra user is set or not (mainly for internal/debug usages)");
+ "Indicates whether an extra user is set or not (mainly for internal/debug usages)");
RNA_def_property_boolean_funcs(prop, NULL, "rna_ID_extra_user_set");
prop = RNA_def_property(srna, "is_embedded_data", PROP_BOOLEAN, PROP_NONE);
diff --git a/source/blender/makesrna/intern/rna_access.c b/source/blender/makesrna/intern/rna_access.c
index aa4c4acdd5e..c96163be562 100644
--- a/source/blender/makesrna/intern/rna_access.c
+++ b/source/blender/makesrna/intern/rna_access.c
@@ -5548,7 +5548,12 @@ static char *rna_idp_path(PointerRNA *ptr,
if (iter->type == IDP_GROUP) {
if (prop->type == PROP_POINTER) {
PointerRNA child_ptr = RNA_property_pointer_get(ptr, prop);
- BLI_assert(!RNA_pointer_is_null(&child_ptr));
+ if (RNA_pointer_is_null(&child_ptr)) {
+ /* Pointer ID prop might be a 'leaf' in the IDProp group hierarchy, in which case a NULL
+ * value is perfectly valid. Just means it won't match the searched needle. */
+ continue;
+ }
+
link.name = iter->name;
link.index = -1;
if ((path = rna_idp_path(&child_ptr, iter, needle, &link))) {
@@ -5570,7 +5575,11 @@ static char *rna_idp_path(PointerRNA *ptr,
for (j = 0; j < iter->len; j++, array++) {
PointerRNA child_ptr;
if (RNA_property_collection_lookup_int(ptr, prop, j, &child_ptr)) {
- BLI_assert(!RNA_pointer_is_null(&child_ptr));
+ if (RNA_pointer_is_null(&child_ptr)) {
+ /* Array item ID prop might be a 'leaf' in the IDProp group hierarchy, in which case
+ * a NULL value is perfectly valid. Just means it won't match the searched needle. */
+ continue;
+ }
link.index = j;
if ((path = rna_idp_path(&child_ptr, array, needle, &link))) {
break;
diff --git a/source/blender/makesrna/intern/rna_userdef.c b/source/blender/makesrna/intern/rna_userdef.c
index af44fc62e6d..dfd216bc85c 100644
--- a/source/blender/makesrna/intern/rna_userdef.c
+++ b/source/blender/makesrna/intern/rna_userdef.c
@@ -6418,6 +6418,10 @@ static void rna_def_userdef_experimental(BlenderRNA *brna)
RNA_def_property_boolean_sdna(prop, NULL, "use_sculpt_texture_paint", 1);
RNA_def_property_ui_text(prop, "Sculpt Texture Paint", "Use texture painting in Sculpt Mode");
+ prop = RNA_def_property(srna, "use_draw_manager_acquire_lock", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "use_draw_manager_acquire_lock", 1);
+ RNA_def_property_ui_text(prop, "Draw Manager Locking", "Don't lock UI during background rendering");
+
prop = RNA_def_property(srna, "use_extended_asset_browser", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_ui_text(prop,
"Extended Asset Browser",
diff --git a/source/blender/modifiers/intern/MOD_meshdeform.c b/source/blender/modifiers/intern/MOD_meshdeform.c
index 09e6819a2ae..c2e9e5ebe7d 100644
--- a/source/blender/modifiers/intern/MOD_meshdeform.c
+++ b/source/blender/modifiers/intern/MOD_meshdeform.c
@@ -587,7 +587,16 @@ static void blendWrite(BlendWriter *writer, const ModifierData *md)
int size = mmd->dyngridsize;
BLO_write_struct_array(writer, MDefInfluence, mmd->influences_num, mmd->bindinfluences);
- BLO_write_int32_array(writer, mmd->verts_num + 1, mmd->bindoffsets);
+
+ /* NOTE: `bindoffset` is abusing `verts_num + 1` as its size, this becomes an incorrect value in
+ * case `verts_num == 0`, since `bindoffset` is then NULL, not a size 1 allocated array. */
+ if (mmd->verts_num > 0) {
+ BLO_write_int32_array(writer, mmd->verts_num + 1, mmd->bindoffsets);
+ }
+ else {
+ BLI_assert(mmd->bindoffsets == NULL);
+ }
+
BLO_write_float3_array(writer, mmd->cage_verts_num, mmd->bindcagecos);
BLO_write_struct_array(writer, MDefCell, size * size * size, mmd->dyngrid);
BLO_write_struct_array(writer, MDefInfluence, mmd->influences_num, mmd->dyninfluences);
@@ -599,7 +608,13 @@ static void blendRead(BlendDataReader *reader, ModifierData *md)
MeshDeformModifierData *mmd = (MeshDeformModifierData *)md;
BLO_read_data_address(reader, &mmd->bindinfluences);
- BLO_read_int32_array(reader, mmd->verts_num + 1, &mmd->bindoffsets);
+
+ /* NOTE: `bindoffset` is abusing `verts_num + 1` as its size, this becomes an incorrect value in
+ * case `verts_num == 0`, since `bindoffset` is then NULL, not a size 1 allocated array. */
+ if (mmd->verts_num > 0) {
+ BLO_read_int32_array(reader, mmd->verts_num + 1, &mmd->bindoffsets);
+ }
+
BLO_read_float3_array(reader, mmd->cage_verts_num, &mmd->bindcagecos);
BLO_read_data_address(reader, &mmd->dyngrid);
BLO_read_data_address(reader, &mmd->dyninfluences);
diff --git a/source/blender/modifiers/intern/MOD_screw.c b/source/blender/modifiers/intern/MOD_screw.c
index 05072cf340c..08925e8aeb1 100644
--- a/source/blender/modifiers/intern/MOD_screw.c
+++ b/source/blender/modifiers/intern/MOD_screw.c
@@ -439,7 +439,7 @@ static Mesh *modifyMesh(ModifierData *md, const ModifierEvalContext *ctx, Mesh *
/* Tag mvert as not loose. */
BLI_BITMAP_ENABLE(vert_tag, med_orig->v1);
- BLI_BITMAP_ENABLE(vert_tag, med_orig->v1);
+ BLI_BITMAP_ENABLE(vert_tag, med_orig->v2);
}
/* build polygon -> edge map */
@@ -1118,6 +1118,10 @@ static Mesh *modifyMesh(ModifierData *md, const ModifierEvalContext *ctx, Mesh *
MEM_freeN(vert_loop_map);
}
+ if ((ltmd->flag & MOD_SCREW_NORMAL_CALC)) {
+ BKE_mesh_vertex_normals_clear_dirty(result);
+ }
+
if ((ltmd->flag & MOD_SCREW_MERGE) && (screw_ofs == 0.0f)) {
result = mesh_remove_doubles_on_axis(result,
mvert_new,
@@ -1128,10 +1132,6 @@ static Mesh *modifyMesh(ModifierData *md, const ModifierEvalContext *ctx, Mesh *
ltmd->merge_dist);
}
- if ((ltmd->flag & MOD_SCREW_NORMAL_CALC)) {
- BKE_mesh_vertex_normals_clear_dirty(result);
- }
-
return result;
}
diff --git a/source/blender/modifiers/intern/MOD_warp.c b/source/blender/modifiers/intern/MOD_warp.c
index e95d2983639..79972d1911d 100644
--- a/source/blender/modifiers/intern/MOD_warp.c
+++ b/source/blender/modifiers/intern/MOD_warp.c
@@ -491,20 +491,20 @@ static void panelRegister(ARegionType *region_type)
static void blendWrite(BlendWriter *writer, const ModifierData *md)
{
- const WarpModifierData *tmd = (const WarpModifierData *)md;
+ const WarpModifierData *wmd = (const WarpModifierData *)md;
- if (tmd->curfalloff) {
- BKE_curvemapping_blend_write(writer, tmd->curfalloff);
+ if (wmd->curfalloff) {
+ BKE_curvemapping_blend_write(writer, wmd->curfalloff);
}
}
static void blendRead(BlendDataReader *reader, ModifierData *md)
{
- WarpModifierData *tmd = (WarpModifierData *)md;
+ WarpModifierData *wmd = (WarpModifierData *)md;
- BLO_read_data_address(reader, &tmd->curfalloff);
- if (tmd->curfalloff) {
- BKE_curvemapping_blend_read(reader, tmd->curfalloff);
+ BLO_read_data_address(reader, &wmd->curfalloff);
+ if (wmd->curfalloff) {
+ BKE_curvemapping_blend_read(reader, wmd->curfalloff);
}
}
diff --git a/source/blender/nodes/shader/nodes/node_shader_vertex_color.cc b/source/blender/nodes/shader/nodes/node_shader_vertex_color.cc
index a2a9aa9ad91..cba944c671c 100644
--- a/source/blender/nodes/shader/nodes/node_shader_vertex_color.cc
+++ b/source/blender/nodes/shader/nodes/node_shader_vertex_color.cc
@@ -42,10 +42,20 @@ static int node_shader_gpu_vertex_color(GPUMaterial *mat,
GPUNodeStack *out)
{
NodeShaderVertexColor *vertexColor = (NodeShaderVertexColor *)node->storage;
- /* NOTE: using CD_AUTO_FROM_NAME instead of CD_MCOL or CD_PROP_COLOR as geometry nodes may
- * overwrite data which will also change the CustomDataType. This will also make EEVEE and Cycles
+ /* NOTE: using CD_AUTO_FROM_NAME instead of CD_MCOL or CD_PROP_COLOR for named attributes
+ * as geometry nodes may overwrite data which will also change the CustomDataType.
+ * This will also make EEVEE and Cycles
* consistent. See T93179. */
- GPUNodeLink *vertexColorLink = GPU_attribute(mat, CD_AUTO_FROM_NAME, vertexColor->layer_name);
+
+ GPUNodeLink *vertexColorLink;
+
+ if (vertexColor->layer_name[0]) {
+ vertexColorLink = GPU_attribute(mat, CD_AUTO_FROM_NAME, vertexColor->layer_name);
+ }
+ else { /* Fall back on active render color attribute. */
+ vertexColorLink = GPU_attribute(mat, CD_MCOL, vertexColor->layer_name);
+ }
+
return GPU_stack_link(mat, node, "node_vertex_color", in, out, vertexColorLink);
}
diff --git a/source/blender/python/intern/bpy_utils_units.c b/source/blender/python/intern/bpy_utils_units.c
index 3e0698caa50..1e5856a3285 100644
--- a/source/blender/python/intern/bpy_utils_units.c
+++ b/source/blender/python/intern/bpy_utils_units.c
@@ -35,7 +35,7 @@ static const char *bpyunits_usystem_items[] = {
NULL,
};
-static const char *bpyunits_ucategorie_items[] = {
+static const char *bpyunits_ucategories_items[] = {
"NONE",
"LENGTH",
"AREA",
@@ -43,20 +43,26 @@ static const char *bpyunits_ucategorie_items[] = {
"MASS",
"ROTATION",
"TIME",
+ "TIME_ABSOLUTE",
"VELOCITY",
"ACCELERATION",
"CAMERA",
"POWER",
+ "TEMPERATURE",
NULL,
};
+BLI_STATIC_ASSERT(
+ ARRAY_SIZE(bpyunits_ucategories_items) == B_UNIT_TYPE_TOT + 1,
+ "`bpyunits_ucategories_items` should match `B_UNIT_` enum items in `BKE_units.h`")
+
/**
* These fields are just empty placeholders, actual values get set in initializations functions.
* This allows us to avoid many handwriting, and above all,
* to keep all systems/categories definition stuff in `BKE_unit.h`.
*/
static PyStructSequence_Field bpyunits_systems_fields[ARRAY_SIZE(bpyunits_usystem_items)];
-static PyStructSequence_Field bpyunits_categories_fields[ARRAY_SIZE(bpyunits_ucategorie_items)];
+static PyStructSequence_Field bpyunits_categories_fields[ARRAY_SIZE(bpyunits_ucategories_items)];
static PyStructSequence_Desc bpyunits_systems_desc = {
"bpy.utils.units.systems", /* name */
@@ -114,7 +120,7 @@ static bool bpyunits_validate(const char *usys_str, const char *ucat_str, int *r
return false;
}
- *r_ucat = BLI_str_index_in_array(ucat_str, bpyunits_ucategorie_items);
+ *r_ucat = BLI_str_index_in_array(ucat_str, bpyunits_ucategories_items);
if (*r_ucat < 0) {
PyErr_Format(PyExc_ValueError, "Unknown unit category specified: %.200s.", ucat_str);
return false;
@@ -356,7 +362,7 @@ PyObject *BPY_utils_units(void)
/* bpy.utils.units.categories */
item = py_structseq_from_strings(
- &BPyUnitsCategoriesType, &bpyunits_categories_desc, bpyunits_ucategorie_items);
+ &BPyUnitsCategoriesType, &bpyunits_categories_desc, bpyunits_ucategories_items);
PyModule_AddObject(submodule, "categories", item); /* steals ref */
return submodule;
diff --git a/source/blender/render/intern/bake.c b/source/blender/render/intern/bake.c
index 5953c0f0f8f..bf876163013 100644
--- a/source/blender/render/intern/bake.c
+++ b/source/blender/render/intern/bake.c
@@ -330,10 +330,10 @@ static bool cast_ray_highpoly(BVHTreeFromMesh *treeData,
{
int i;
int hit_mesh = -1;
- float hit_distance = max_ray_distance;
- if (hit_distance == 0.0f) {
+ float hit_distance_squared = max_ray_distance * max_ray_distance;
+ if (hit_distance_squared == 0.0f) {
/* No ray distance set, use maximum. */
- hit_distance = FLT_MAX;
+ hit_distance_squared = FLT_MAX;
}
BVHTreeRayHit *hits;
@@ -365,16 +365,14 @@ static bool cast_ray_highpoly(BVHTreeFromMesh *treeData,
}
if (hits[i].index != -1) {
- float distance;
- float hit_world[3];
-
/* distance comparison in world space */
+ float hit_world[3];
mul_v3_m4v3(hit_world, highpoly[i].obmat, hits[i].co);
- distance = len_squared_v3v3(hit_world, co);
+ float distance_squared = len_squared_v3v3(hit_world, co);
- if (distance < hit_distance) {
+ if (distance_squared < hit_distance_squared) {
hit_mesh = i;
- hit_distance = distance;
+ hit_distance_squared = distance_squared;
}
}
}
diff --git a/source/blender/windowmanager/gizmo/intern/wm_gizmo_map.c b/source/blender/windowmanager/gizmo/intern/wm_gizmo_map.c
index a61d73b9f0b..f481f19045d 100644
--- a/source/blender/windowmanager/gizmo/intern/wm_gizmo_map.c
+++ b/source/blender/windowmanager/gizmo/intern/wm_gizmo_map.c
@@ -492,7 +492,8 @@ void WM_gizmomap_draw(wmGizmoMap *gzmap,
static void gizmo_draw_select_3d_loop(const bContext *C,
wmGizmo **visible_gizmos,
- const int visible_gizmos_len)
+ const int visible_gizmos_len,
+ bool *r_use_select_bias)
{
/* TODO(campbell): this depends on depth buffer being written to,
@@ -528,6 +529,10 @@ static void gizmo_draw_select_3d_loop(const bContext *C,
is_depth_skip_prev = is_depth_skip;
}
+ if (gz->select_bias != 0.0) {
+ *r_use_select_bias = true;
+ }
+
/* pass the selection id shifted by 8 bits. Last 8 bits are used for selected gizmo part id */
gz->type->draw_select(C, gz, select_id << 8);
@@ -545,10 +550,7 @@ static int gizmo_find_intersected_3d_intern(wmGizmo **visible_gizmos,
const int visible_gizmos_len,
const bContext *C,
const int co[2],
- const int hotspot,
- const bool use_depth_test,
- const bool has_3d_select_bias,
- int *r_hits)
+ const int hotspot)
{
const wmWindowManager *wm = CTX_wm_manager(C);
ScrArea *area = CTX_wm_area(C);
@@ -562,76 +564,30 @@ static int gizmo_find_intersected_3d_intern(wmGizmo **visible_gizmos,
BLI_rcti_init_pt_radius(&rect, co, hotspot);
- /* The selection mode is assigned for the following reasons:
- *
- * - #GPU_SELECT_ALL: Use it to check if there is anything at the cursor location
- * (only ever runs once).
- * - #GPU_SELECT_PICK_NEAREST: Use if there are more than 1 item at the cursor location,
- * pick the nearest one.
- * - #GPU_SELECT_PICK_ALL: Use for the same purpose as #GPU_SELECT_PICK_NEAREST
- * when the selection depths need to re-ordered based on a bias.
- * */
- const eGPUSelectMode gpu_select_mode =
- (use_depth_test ? (has_3d_select_bias ?
- /* Using select bias means the depths need to be
- * re-calculated based on the bias to pick the best. */
- GPU_SELECT_PICK_ALL :
- /* No bias, just pick the closest. */
- GPU_SELECT_PICK_NEAREST) :
- /* Fast-path (occlusion queries). */
- GPU_SELECT_ALL);
-
- /* When switching between modes and the mouse pointer is over a gizmo, the highlight test is
- * performed before the viewport is fully initialized (region->draw_buffer = NULL).
- * When this is the case we should not use depth testing. */
- GPUViewport *gpu_viewport = WM_draw_region_get_viewport(region);
- if (use_depth_test && gpu_viewport == NULL) {
- return -1;
- }
+ ED_view3d_draw_setup_view(
+ wm, CTX_wm_window(C), depsgraph, CTX_data_scene(C), region, v3d, NULL, NULL, &rect);
- if (GPU_select_is_cached()) {
- GPU_select_begin(buffer, ARRAY_SIZE(buffer), &rect, gpu_select_mode, 0);
- GPU_select_cache_load_id();
- hits = GPU_select_end();
- }
- else {
- /* TODO: waiting for the GPU in the middle of the event loop for every
- * mouse move is bad for performance, we need to find a solution to not
- * use the GPU or draw something once. (see T61474) */
+ bool use_select_bias = false;
- ED_view3d_draw_setup_view(
- wm, CTX_wm_window(C), depsgraph, CTX_data_scene(C), region, v3d, NULL, NULL, &rect);
+ /* TODO: waiting for the GPU in the middle of the event loop for every
+ * mouse move is bad for performance, we need to find a solution to not
+ * use the GPU or draw something once. (see T61474) */
+ GPU_select_begin(buffer, ARRAY_SIZE(buffer), &rect, GPU_SELECT_NEAREST_FIRST_PASS, 0);
+ /* do the drawing */
+ gizmo_draw_select_3d_loop(C, visible_gizmos, visible_gizmos_len, &use_select_bias);
- /* There is no need to bind to the depth buffer outside this function
- * because all future passes the will use the cached depths. */
- GPUFrameBuffer *depth_read_fb = NULL;
- if (use_depth_test) {
- GPUTexture *depth_tx = GPU_viewport_depth_texture(gpu_viewport);
- GPU_framebuffer_ensure_config(&depth_read_fb,
- {
- GPU_ATTACHMENT_TEXTURE(depth_tx),
- GPU_ATTACHMENT_NONE,
- });
- GPU_framebuffer_bind(depth_read_fb);
- }
+ hits = GPU_select_end();
- GPU_select_begin(buffer, ARRAY_SIZE(buffer), &rect, gpu_select_mode, 0);
- gizmo_draw_select_3d_loop(C, visible_gizmos, visible_gizmos_len);
- hits = GPU_select_end();
-
- if (use_depth_test) {
- GPU_framebuffer_restore();
- GPU_framebuffer_free(depth_read_fb);
- }
-
- ED_view3d_draw_setup_view(
- wm, CTX_wm_window(C), depsgraph, CTX_data_scene(C), region, v3d, NULL, NULL, NULL);
+ if (hits > 0) {
+ GPU_select_begin(buffer, ARRAY_SIZE(buffer), &rect, GPU_SELECT_NEAREST_SECOND_PASS, hits);
+ gizmo_draw_select_3d_loop(C, visible_gizmos, visible_gizmos_len, &use_select_bias);
+ GPU_select_end();
}
- /* When selection bias is needed, this function will run again with `use_depth_test` enabled. */
- int hit_found = -1;
+ ED_view3d_draw_setup_view(
+ wm, CTX_wm_window(C), depsgraph, CTX_data_scene(C), region, v3d, NULL, NULL, NULL);
- if (has_3d_select_bias && use_depth_test && (hits > 1)) {
+ if (use_select_bias && (hits > 1)) {
float co_direction[3];
float co_screen[3] = {co[0], co[1], 0.0f};
ED_view3d_win_to_vector(region, (float[2]){UNPACK2(co)}, co_direction);
@@ -643,6 +599,7 @@ static int gizmo_find_intersected_3d_intern(wmGizmo **visible_gizmos,
GPU_matrix_unproject_3fv(co_screen, rv3d->viewinv, rv3d->winmat, viewport, co_3d_origin);
GPUSelectResult *buf_iter = buffer;
+ int hit_found = -1;
float dot_best = FLT_MAX;
for (int i = 0; i < hits; i++, buf_iter++) {
@@ -662,16 +619,11 @@ static int gizmo_find_intersected_3d_intern(wmGizmo **visible_gizmos,
hit_found = buf_iter->id;
}
}
- }
- else {
- const GPUSelectResult *hit_near = GPU_select_buffer_near(buffer, hits);
- if (hit_near) {
- hit_found = hit_near->id;
- }
+ return hit_found;
}
- *r_hits = hits;
- return hit_found;
+ const GPUSelectResult *hit_near = GPU_select_buffer_near(buffer, hits);
+ return hit_near ? hit_near->id : -1;
}
/**
@@ -694,7 +646,6 @@ static wmGizmo *gizmo_find_intersected_3d(bContext *C,
/* Search for 3D gizmo's that use the 2D callback for checking intersections. */
bool has_3d = false;
- bool has_3d_select_bias = false;
{
for (int select_id = 0; select_id < visible_gizmos_len; select_id++) {
wmGizmo *gz = visible_gizmos[select_id];
@@ -710,9 +661,6 @@ static wmGizmo *gizmo_find_intersected_3d(bContext *C,
}
else if (gz->type->draw_select != NULL) {
has_3d = true;
- if (gz->select_bias != 0.0f) {
- has_3d_select_bias = true;
- }
}
}
}
@@ -721,86 +669,39 @@ static wmGizmo *gizmo_find_intersected_3d(bContext *C,
* This way we always use the first hit. */
if (has_3d) {
- /* NOTE(@campbellbarton): The selection logic here uses a fast-path that exits early
- * where possible. This is important as this runs on cursor-motion in the 3D view-port.
- *
- * - First, don't use the depth buffer at all, use occlusion queries to detect any gizmos.
- * If there are no gizmos or only one - early exit, otherwise.
- *
- * - Bind the depth buffer and use selection picking logic.
- * This is much slower than occlusion queries (since it's reading depths while drawing).
- * When there is a single gizmo under the cursor (quite common), early exit, otherwise.
- *
- * - Perform another pass at a reduced size (see: `hotspot_radii`),
- * since the result depths are cached this pass is practically free.
- *
- * Other notes:
- *
- * - If any of these passes fail, use the nearest result from the previous pass.
- *
- * - Drawing is only ever done twice.
- */
-
- /* Order largest to smallest so the first pass can be used as cache for
- * later passes (when `use_depth_test == true`). */
- const int hotspot_radii[] = {
- 10 * U.pixelsize,
- /* This runs on mouse move, careful doing too many tests! */
- 3 * U.pixelsize,
- };
-
- /* Narrowing may assign zero to `hit`, allow falling back to the previous test. */
- int hit_prev = -1;
+ /* The depth buffer is needed for for gizmos to obscure eachother. */
+ GPUViewport *viewport = WM_draw_region_get_viewport(CTX_wm_region(C));
- bool use_depth_test = false;
- bool use_depth_cache = false;
-
- /* Workaround for MS-Windows & NVidia failing to detect any gizmo undo the cursor unless the
- * depth test is enabled, see: T97124.
- * NOTE(@campbellbarton): Ideally the exact cause of this could be tracked down,
- * disable as I don't have a system to test this configuration. */
- if (GPU_type_matches(GPU_DEVICE_NVIDIA | GPU_DEVICE_SOFTWARE, GPU_OS_WIN, GPU_DRIVER_ANY)) {
- use_depth_test = true;
+ /* When switching between modes and the mouse pointer is over a gizmo, the highlight test is
+ * performed before the viewport is fully initialized (region->draw_buffer = NULL).
+ * When this is the case we should not use depth testing. */
+ if (viewport == NULL) {
+ return NULL;
}
+ GPUTexture *depth_tx = GPU_viewport_depth_texture(viewport);
+ GPUFrameBuffer *depth_read_fb = NULL;
+ GPU_framebuffer_ensure_config(&depth_read_fb,
+ {
+ GPU_ATTACHMENT_TEXTURE(depth_tx),
+ GPU_ATTACHMENT_NONE,
+ });
+ GPU_framebuffer_bind(depth_read_fb);
+ const int hotspot_radii[] = {
+ 3 * U.pixelsize,
+ /* This runs on mouse move, careful doing too many tests! */
+ 10 * U.pixelsize,
+ };
for (int i = 0; i < ARRAY_SIZE(hotspot_radii); i++) {
-
- if (use_depth_test && (use_depth_cache == false)) {
- GPU_select_cache_begin();
- use_depth_cache = true;
- }
-
- int hit_count;
- hit = gizmo_find_intersected_3d_intern(visible_gizmos,
- visible_gizmos_len_trim,
- C,
- co,
- hotspot_radii[i],
- use_depth_test,
- has_3d_select_bias,
- &hit_count);
- /* Only continue searching when there are multiple options to narrow down. */
- if (hit_count < 2) {
+ hit = gizmo_find_intersected_3d_intern(
+ visible_gizmos, visible_gizmos_len_trim, C, co, hotspot_radii[i]);
+ if (hit != -1) {
break;
}
-
- /* Fast path for simple case, one item or nothing. */
- if (use_depth_test == false) {
- /* Restart, using depth buffer (slower). */
- use_depth_test = true;
- i = -1;
- }
- hit_prev = hit;
- }
- /* Narrowing the search area may yield no hits,
- * in this case fall back to the previous search. */
- if (hit == -1) {
- hit = hit_prev;
}
- if (use_depth_cache) {
- GPU_select_cache_end();
- }
+ GPU_framebuffer_restore();
+ GPU_framebuffer_free(depth_read_fb);
if (hit != -1) {
const int select_id = hit >> 8;
diff --git a/source/blender/windowmanager/intern/wm_draw.c b/source/blender/windowmanager/intern/wm_draw.c
index 02da798495b..d2ade7b0376 100644
--- a/source/blender/windowmanager/intern/wm_draw.c
+++ b/source/blender/windowmanager/intern/wm_draw.c
@@ -467,7 +467,7 @@ static bool wm_draw_region_bind(bContext *C, ARegion *region, int view)
}
if (region->draw_buffer->viewport) {
- if (G.is_rendering && C != NULL) {
+ if (G.is_rendering && C != NULL && U.experimental.use_draw_manager_acquire_lock) {
Scene *scene = CTX_data_scene(C);
RenderEngineType *render_engine_type = RE_engines_find(scene->r.engine);
if (RE_engine_is_opengl(render_engine_type)) {
diff --git a/source/tools b/source/tools
-Subproject c1586ae29595713b597c22f6baa08d6cce42376
+Subproject 53b7c02a062c3d6ec6b38ce670836321b4e78fa
diff --git a/tests/python/bl_rigging_symmetrize.py b/tests/python/bl_rigging_symmetrize.py
index 3a5a0777d6c..cac5e9b0856 100644
--- a/tests/python/bl_rigging_symmetrize.py
+++ b/tests/python/bl_rigging_symmetrize.py
@@ -134,9 +134,8 @@ def check_constraints(self, input_arm, expected_arm, bone, exp_bone):
"Missmatching constraint boolean in pose.bones[%s].constraints[%s].%s" % (
bone.name, const_name, var))
else:
- self.assertAlmostEqual(value, exp_value,
- "Missmatching constraint value in pose.bones[%s].constraints[%s].%s" % (
- bone.name, const_name, var))
+ msg = "Missmatching constraint value in pose.bones[%s].constraints[%s].%s" % (bone.name, const_name, var)
+ self.assertAlmostEqual(value, exp_value, places=6, msg=msg)
class AbstractAnimationTest: