WIP: uv-simple-select #1

Closed
Chris Blackbourn wants to merge 182 commits from uv-simple-select into main

When changing the target branch, be careful to rebase the branch in your fork to match. See documentation.
881 changed files with 9217 additions and 5570 deletions

View File

@ -1,8 +0,0 @@
{
"project_id" : "Blender",
"conduit_uri" : "https://developer.blender.org/",
"phabricator.uri" : "https://developer.blender.org/",
"git.default-relative-commit" : "origin/master",
"arc.land.update.default" : "rebase",
"arc.land.onto.default" : "master"
}

View File

@ -236,6 +236,8 @@ ForEachMacros:
- LOOP_UNSELECTED_POINTS - LOOP_UNSELECTED_POINTS
- LOOP_VISIBLE_KEYS - LOOP_VISIBLE_KEYS
- LOOP_VISIBLE_POINTS - LOOP_VISIBLE_POINTS
- LIGHT_FOREACH_BEGIN_DIRECTIONAL
- LIGHT_FOREACH_BEGIN_LOCAL
- LISTBASE_CIRCULAR_BACKWARD_BEGIN - LISTBASE_CIRCULAR_BACKWARD_BEGIN
- LISTBASE_CIRCULAR_FORWARD_BEGIN - LISTBASE_CIRCULAR_FORWARD_BEGIN
- LISTBASE_FOREACH - LISTBASE_FOREACH

View File

@ -524,7 +524,7 @@ endif()
if(NOT APPLE) if(NOT APPLE)
option(WITH_CYCLES_DEVICE_HIP "Enable Cycles AMD HIP support" ON) option(WITH_CYCLES_DEVICE_HIP "Enable Cycles AMD HIP support" ON)
option(WITH_CYCLES_HIP_BINARIES "Build Cycles AMD HIP binaries" OFF) option(WITH_CYCLES_HIP_BINARIES "Build Cycles AMD HIP binaries" OFF)
set(CYCLES_HIP_BINARIES_ARCH gfx1010 gfx1011 gfx1012 gfx1030 gfx1031 gfx1032 gfx1034 gfx1035 gfx1100 gfx1101 gfx1102 CACHE STRING "AMD HIP architectures to build binaries for") set(CYCLES_HIP_BINARIES_ARCH gfx900 gfx906 gfx90c gfx902 gfx1010 gfx1011 gfx1012 gfx1030 gfx1031 gfx1032 gfx1034 gfx1035 gfx1100 gfx1101 gfx1102 CACHE STRING "AMD HIP architectures to build binaries for")
mark_as_advanced(WITH_CYCLES_DEVICE_HIP) mark_as_advanced(WITH_CYCLES_DEVICE_HIP)
mark_as_advanced(CYCLES_HIP_BINARIES_ARCH) mark_as_advanced(CYCLES_HIP_BINARIES_ARCH)
endif() endif()
@ -625,8 +625,10 @@ mark_as_advanced(
# Vulkan # Vulkan
option(WITH_VULKAN_BACKEND "Enable Vulkan as graphics backend (only for development)" OFF) option(WITH_VULKAN_BACKEND "Enable Vulkan as graphics backend (only for development)" OFF)
option(WITH_VULKAN_GUARDEDALLOC "Use guardedalloc for host allocations done inside Vulkan (development option)" OFF)
mark_as_advanced( mark_as_advanced(
WITH_VULKAN_BACKEND WITH_VULKAN_BACKEND
WITH_VULKAN_GUARDEDALLOC
) )
# Metal # Metal

View File

@ -299,7 +299,11 @@ else
ifneq ("$(wildcard $(DEPS_BUILD_DIR)/build.ninja)","") ifneq ("$(wildcard $(DEPS_BUILD_DIR)/build.ninja)","")
DEPS_BUILD_COMMAND:=ninja DEPS_BUILD_COMMAND:=ninja
else else
ifeq ($(OS), Darwin)
DEPS_BUILD_COMMAND:=make -s DEPS_BUILD_COMMAND:=make -s
else
DEPS_BUILD_COMMAND:="$(BLENDER_DIR)/build_files/build_environment/linux/make_deps_wrapper.sh" -s
endif
endif endif
endif endif
@ -398,7 +402,7 @@ endif
deps: .FORCE deps: .FORCE
@echo @echo
@echo Configuring dependencies in \"$(DEPS_BUILD_DIR)\" @echo Configuring dependencies in \"$(DEPS_BUILD_DIR)\", install to \"$(DEPS_INSTALL_DIR)\"
@cmake -H"$(DEPS_SOURCE_DIR)" \ @cmake -H"$(DEPS_SOURCE_DIR)" \
-B"$(DEPS_BUILD_DIR)" \ -B"$(DEPS_BUILD_DIR)" \

View File

@ -22,7 +22,7 @@ elseif(UNIX AND NOT APPLE)
) )
endif() endif()
# Boolean crashes with Arm assembly, see T103423. # Boolean crashes with Arm assembly, see #103423.
if(BLENDER_PLATFORM_ARM) if(BLENDER_PLATFORM_ARM)
set(GMP_OPTIONS set(GMP_OPTIONS
${GMP_OPTIONS} ${GMP_OPTIONS}

View File

@ -0,0 +1,74 @@
#!/usr/bin/env bash
# SPDX-License-Identifier: GPL-2.0-or-later
# This script ensures:
# - One dependency is built at a time.
# - That dependency uses all available cores.
#
# Without this, simply calling `make -j$(nproc)` from the `${CMAKE_BUILD_DIR}/deps/`
# directory will build many projects at once.
#
# This is undesirable for the following reasons:
#
# - The output from projects is mixed together,
# making it difficult to track down the cause of a build failure.
#
# - Larger dependencies such as LLVM can bottleneck the build process,
# making it necessary to cancel the build and manually run build commands in each directory.
#
# - Building many projects at once means canceling (Control-C) can lead to the build being in an undefined state.
# It's possible canceling happens as a patch is being applied or files are being copied.
# (steps that aren't part of the compilation process where it's typically safe to cancel).
if [[ -z "$MY_MAKE_CALL_LEVEL" ]]; then
export MY_MAKE_CALL_LEVEL=0
export MY_MAKEFLAGS=$MAKEFLAGS
# Extract the jobs argument (`-jN`, `-j N`, `--jobs=N`).
add_next=0
for i in "$@"; do
case $i in
-j*)
export MY_JOBS_ARG=$i
if [ "$MY_JOBS_ARG" = "-j" ]; then
add_next=1
fi
;;
--jobs=*)
shift # past argument=value
MY_JOBS_ARG=$i
;;
*)
if (( add_next == 1 )); then
MY_JOBS_ARG="$MY_JOBS_ARG $i"
add_next=0
fi
;;
esac
done
unset i add_next
if [[ -z "$MY_JOBS_ARG" ]]; then
MY_JOBS_ARG="-j$(nproc)"
fi
export MY_JOBS_ARG
# Support user defined `MAKEFLAGS`.
export MAKEFLAGS="$MY_MAKEFLAGS -j1"
else
export MY_MAKE_CALL_LEVEL=$(( MY_MAKE_CALL_LEVEL + 1 ))
if (( MY_MAKE_CALL_LEVEL == 1 )); then
# Important to set jobs to 1, otherwise user defined jobs argument is used.
export MAKEFLAGS="$MY_MAKEFLAGS -j1"
elif (( MY_MAKE_CALL_LEVEL == 2 )); then
# This is the level used by each sub-project.
export MAKEFLAGS="$MY_MAKEFLAGS $MY_JOBS_ARG"
fi
# Else leave `MY_MAKEFLAGS` flags as-is, avoids setting a high number of jobs on recursive
# calls (which may easily run out of memory). Let the job-server handle the rest.
fi
# Useful for troubleshooting the wrapper.
# echo "Call level: $MY_MAKE_CALL_LEVEL, args=$@".
# Call actual make but ensure recursive calls run via this script.
exec make MAKE="$0" "$@"

View File

@ -85,7 +85,7 @@ if(NOT APPLE)
set(WITH_CYCLES_DEVICE_OPTIX ON CACHE BOOL "" FORCE) set(WITH_CYCLES_DEVICE_OPTIX ON CACHE BOOL "" FORCE)
set(WITH_CYCLES_CUDA_BINARIES ON CACHE BOOL "" FORCE) set(WITH_CYCLES_CUDA_BINARIES ON CACHE BOOL "" FORCE)
set(WITH_CYCLES_CUBIN_COMPILER OFF CACHE BOOL "" FORCE) set(WITH_CYCLES_CUBIN_COMPILER OFF CACHE BOOL "" FORCE)
set(WITH_CYCLES_HIP_BINARIES ON CACHE BOOL "" FORCE) set(WITH_CYCLES_HIP_BINARIES OFF CACHE BOOL "" FORCE)
set(WITH_CYCLES_DEVICE_ONEAPI ON CACHE BOOL "" FORCE) set(WITH_CYCLES_DEVICE_ONEAPI ON CACHE BOOL "" FORCE)
set(WITH_CYCLES_ONEAPI_BINARIES ON CACHE BOOL "" FORCE) set(WITH_CYCLES_ONEAPI_BINARIES ON CACHE BOOL "" FORCE)
endif() endif()

View File

@ -544,7 +544,7 @@ endfunction()
function(setup_platform_linker_libs function(setup_platform_linker_libs
target target
) )
# jemalloc must be early in the list, to be before pthread (see T57998) # jemalloc must be early in the list, to be before pthread (see #57998).
if(WITH_MEM_JEMALLOC) if(WITH_MEM_JEMALLOC)
target_link_libraries(${target} ${JEMALLOC_LIBRARIES}) target_link_libraries(${target} ${JEMALLOC_LIBRARIES})
endif() endif()

View File

@ -440,7 +440,7 @@ string(APPEND PLATFORM_LINKFLAGS " -stdlib=libc++")
# Make stack size more similar to Embree, required for Embree. # Make stack size more similar to Embree, required for Embree.
string(APPEND PLATFORM_LINKFLAGS_EXECUTABLE " -Wl,-stack_size,0x100000") string(APPEND PLATFORM_LINKFLAGS_EXECUTABLE " -Wl,-stack_size,0x100000")
# Suppress ranlib "has no symbols" warnings (workaround for T48250) # Suppress ranlib "has no symbols" warnings (workaround for #48250).
set(CMAKE_C_ARCHIVE_CREATE "<CMAKE_AR> Scr <TARGET> <LINK_FLAGS> <OBJECTS>") set(CMAKE_C_ARCHIVE_CREATE "<CMAKE_AR> Scr <TARGET> <LINK_FLAGS> <OBJECTS>")
set(CMAKE_CXX_ARCHIVE_CREATE "<CMAKE_AR> Scr <TARGET> <LINK_FLAGS> <OBJECTS>") set(CMAKE_CXX_ARCHIVE_CREATE "<CMAKE_AR> Scr <TARGET> <LINK_FLAGS> <OBJECTS>")
# llvm-ranlib doesn't support this flag. Xcode's libtool does. # llvm-ranlib doesn't support this flag. Xcode's libtool does.

View File

@ -121,7 +121,7 @@ if(WITH_WINDOWS_BUNDLE_CRT)
include(InstallRequiredSystemLibraries) include(InstallRequiredSystemLibraries)
# ucrtbase(d).dll cannot be in the manifest, due to the way windows 10 handles # ucrtbase(d).dll cannot be in the manifest, due to the way windows 10 handles
# redirects for this dll, for details see T88813. # redirects for this dll, for details see #88813.
foreach(lib ${CMAKE_INSTALL_SYSTEM_RUNTIME_LIBS}) foreach(lib ${CMAKE_INSTALL_SYSTEM_RUNTIME_LIBS})
string(FIND ${lib} "ucrtbase" pos) string(FIND ${lib} "ucrtbase" pos)
if(NOT pos EQUAL -1) if(NOT pos EQUAL -1)
@ -295,7 +295,7 @@ unset(MATERIALX_LIB_FOLDER_EXISTS)
if(NOT MSVC_CLANG AND # Available with MSVC 15.7+ but not for CLANG. if(NOT MSVC_CLANG AND # Available with MSVC 15.7+ but not for CLANG.
NOT WITH_WINDOWS_SCCACHE AND # And not when sccache is enabled NOT WITH_WINDOWS_SCCACHE AND # And not when sccache is enabled
NOT VS_CLANG_TIDY) # Clang-tidy does not like these options NOT VS_CLANG_TIDY) # Clang-tidy does not like these options
add_compile_options(/experimental:external /external:templates- /external:I "${LIBDIR}" /external:W0) add_compile_options(/experimental:external /external:I "${LIBDIR}" /external:W0)
endif() endif()
# Add each of our libraries to our cmake_prefix_path so find_package() could work # Add each of our libraries to our cmake_prefix_path so find_package() could work

View File

@ -38,7 +38,7 @@ PROJECT_NAME = Blender
# could be handy for archiving the generated documentation or if some version # could be handy for archiving the generated documentation or if some version
# control system is used. # control system is used.
PROJECT_NUMBER = V3.5 PROJECT_NUMBER = V3.6
# Using the PROJECT_BRIEF tag one can provide an optional one line description # Using the PROJECT_BRIEF tag one can provide an optional one line description
# for a project that appears at the top of each page and should give viewer a # for a project that appears at the top of each page and should give viewer a

View File

@ -476,7 +476,7 @@ MODULE_GROUPING = {
# -------------------------------BLENDER---------------------------------------- # -------------------------------BLENDER----------------------------------------
# converting bytes to strings, due to T30154 # Converting bytes to strings, due to #30154.
BLENDER_REVISION = str(bpy.app.build_hash, 'utf_8') BLENDER_REVISION = str(bpy.app.build_hash, 'utf_8')
BLENDER_REVISION_TIMESTAMP = bpy.app.build_commit_timestamp BLENDER_REVISION_TIMESTAMP = bpy.app.build_commit_timestamp
@ -487,7 +487,7 @@ BLENDER_VERSION_DOTS = "%d.%d" % (bpy.app.version[0], bpy.app.version[1])
if BLENDER_REVISION != "Unknown": if BLENDER_REVISION != "Unknown":
# SHA1 Git hash # SHA1 Git hash
BLENDER_VERSION_HASH = BLENDER_REVISION BLENDER_VERSION_HASH = BLENDER_REVISION
BLENDER_VERSION_HASH_HTML_LINK = "<a href=https://developer.blender.org/rB%s>%s</a>" % ( BLENDER_VERSION_HASH_HTML_LINK = "<a href=https://projects.blender.org/blender/blender/commit/%s>%s</a>" % (
BLENDER_VERSION_HASH, BLENDER_VERSION_HASH, BLENDER_VERSION_HASH, BLENDER_VERSION_HASH,
) )
BLENDER_VERSION_DATE = time.strftime("%d/%m/%Y", time.localtime(BLENDER_REVISION_TIMESTAMP)) BLENDER_VERSION_DATE = time.strftime("%d/%m/%Y", time.localtime(BLENDER_REVISION_TIMESTAMP))
@ -647,7 +647,7 @@ def undocumented_message(module_name, type_name, identifier):
module_name, type_name, identifier, module_name, type_name, identifier,
) )
return "Undocumented, consider `contributing <https://developer.blender.org/T51061>`__." return "Undocumented, consider `contributing <https://developer.blender.org/>`__."
def range_str(val): def range_str(val):
@ -2200,7 +2200,7 @@ def write_rst_enum_items(basepath, key, key_no_prefix, enum_items):
Write a single page for a static enum in RST. Write a single page for a static enum in RST.
This helps avoiding very large lists being in-lined in many places which is an issue This helps avoiding very large lists being in-lined in many places which is an issue
especially with icons in ``bpy.types.UILayout``. See T87008. especially with icons in ``bpy.types.UILayout``. See #87008.
""" """
filepath = os.path.join(basepath, "%s.rst" % key_no_prefix) filepath = os.path.join(basepath, "%s.rst" % key_no_prefix)
with open(filepath, "w", encoding="utf-8") as fh: with open(filepath, "w", encoding="utf-8") as fh:

View File

@ -1676,15 +1676,18 @@ class CyclesPreferences(bpy.types.AddonPreferences):
col.label(text="and NVIDIA driver version %s or newer" % driver_version, col.label(text="and NVIDIA driver version %s or newer" % driver_version,
icon='BLANK1', translate=False) icon='BLANK1', translate=False)
elif device_type == 'HIP': elif device_type == 'HIP':
if True:
col.label(text="HIP temporarily disabled due to compiler bugs", icon='BLANK1')
else:
import sys import sys
if sys.platform[:3] == "win": if sys.platform[:3] == "win":
driver_version = "21.Q4" driver_version = "21.Q4"
col.label(text="Requires AMD GPU with RDNA architecture", icon='BLANK1') col.label(text="Requires AMD GPU with Vega or RDNA architecture", icon='BLANK1')
col.label(text=iface_("and AMD Radeon Pro %s driver or newer") % driver_version, col.label(text=iface_("and AMD Radeon Pro %s driver or newer") % driver_version,
icon='BLANK1', translate=False) icon='BLANK1', translate=False)
elif sys.platform.startswith("linux"): elif sys.platform.startswith("linux"):
driver_version = "22.10" driver_version = "22.10"
col.label(text="Requires AMD GPU with RDNA architecture", icon='BLANK1') col.label(text="Requires AMD GPU with Vega or RDNA architecture", icon='BLANK1')
col.label(text=iface_("and AMD driver version %s or newer") % driver_version, icon='BLANK1', col.label(text=iface_("and AMD driver version %s or newer") % driver_version, icon='BLANK1',
translate=False) translate=False)
elif device_type == 'ONEAPI': elif device_type == 'ONEAPI':

View File

@ -20,7 +20,7 @@ class CyclesPresetPanel(PresetPanel, Panel):
@staticmethod @staticmethod
def post_cb(context): def post_cb(context):
# Modify an arbitrary built-in scene property to force a depsgraph # Modify an arbitrary built-in scene property to force a depsgraph
# update, because add-on properties don't. (see T62325) # update, because add-on properties don't. (see #62325)
render = context.scene.render render = context.scene.render
render.filter_size = render.filter_size render.filter_size = render.filter_size

View File

@ -105,11 +105,12 @@ GPUShader *BlenderFallbackDisplayShader::bind(int width, int height)
/* Bind shader now to enable uniform assignment. */ /* Bind shader now to enable uniform assignment. */
GPU_shader_bind(shader_program_); GPU_shader_bind(shader_program_);
GPU_shader_uniform_int(shader_program_, image_texture_location_, 0); int slot = 0;
GPU_shader_uniform_int_ex(shader_program_, image_texture_location_, 1, 1, &slot);
float size[2]; float size[2];
size[0] = width; size[0] = width;
size[1] = height; size[1] = height;
GPU_shader_uniform_vector(shader_program_, fullscreen_location_, 2, 1, size); GPU_shader_uniform_float_ex(shader_program_, fullscreen_location_, 2, 1, size);
return shader_program_; return shader_program_;
} }

View File

@ -20,7 +20,7 @@ BlenderImageLoader::BlenderImageLoader(BL::Image b_image,
: b_image(b_image), : b_image(b_image),
frame(frame), frame(frame),
tile_number(tile_number), tile_number(tile_number),
/* Don't free cache for preview render to avoid race condition from T93560, to be fixed /* Don't free cache for preview render to avoid race condition from #93560, to be fixed
* properly later as we are close to release. */ * properly later as we are close to release. */
free_cache(!is_preview_render && !b_image.has_data()) free_cache(!is_preview_render && !b_image.has_data())
{ {
@ -72,7 +72,7 @@ bool BlenderImageLoader::load_metadata(const ImageDeviceFeatures &, ImageMetaDat
metadata.colorspace = u_colorspace_raw; metadata.colorspace = u_colorspace_raw;
} }
else { else {
/* In some cases (e.g. T94135), the colorspace setting in Blender gets updated as part of the /* In some cases (e.g. #94135), the colorspace setting in Blender gets updated as part of the
* metadata queries in this function, so update the colorspace setting here. */ * metadata queries in this function, so update the colorspace setting here. */
PointerRNA colorspace_ptr = b_image.colorspace_settings().ptr; PointerRNA colorspace_ptr = b_image.colorspace_settings().ptr;
metadata.colorspace = get_enum_identifier(colorspace_ptr, "name"); metadata.colorspace = get_enum_identifier(colorspace_ptr, "name");

View File

@ -24,7 +24,7 @@ void BlenderSync::sync_light(BL::Object &b_parent,
Light *light = light_map.find(key); Light *light = light_map.find(key);
/* Check if the transform was modified, in case a linked collection is moved we do not get a /* Check if the transform was modified, in case a linked collection is moved we do not get a
* specific depsgraph update (T88515). This also mimics the behavior for Objects. */ * specific depsgraph update (#88515). This also mimics the behavior for Objects. */
const bool tfm_updated = (light && light->get_tfm() != tfm); const bool tfm_updated = (light && light->get_tfm() != tfm);
/* Update if either object or light data changed. */ /* Update if either object or light data changed. */

View File

@ -94,7 +94,7 @@ void python_thread_state_restore(void **python_thread_state)
*python_thread_state = NULL; *python_thread_state = NULL;
} }
static const char *PyC_UnicodeAsByte(PyObject *py_str, PyObject **coerce) static const char *PyC_UnicodeAsBytes(PyObject *py_str, PyObject **coerce)
{ {
const char *result = PyUnicode_AsUTF8(py_str); const char *result = PyUnicode_AsUTF8(py_str);
if (result) { if (result) {
@ -131,8 +131,8 @@ static PyObject *init_func(PyObject * /*self*/, PyObject *args)
} }
PyObject *path_coerce = nullptr, *user_path_coerce = nullptr; PyObject *path_coerce = nullptr, *user_path_coerce = nullptr;
path_init(PyC_UnicodeAsByte(path, &path_coerce), path_init(PyC_UnicodeAsBytes(path, &path_coerce),
PyC_UnicodeAsByte(user_path, &user_path_coerce)); PyC_UnicodeAsBytes(user_path, &user_path_coerce));
Py_XDECREF(path_coerce); Py_XDECREF(path_coerce);
Py_XDECREF(user_path_coerce); Py_XDECREF(user_path_coerce);

View File

@ -404,7 +404,7 @@ void BlenderSession::render(BL::Depsgraph &b_depsgraph_)
* point we know that we've got everything to render current view layer. * point we know that we've got everything to render current view layer.
*/ */
/* At the moment we only free if we are not doing multi-view /* At the moment we only free if we are not doing multi-view
* (or if we are rendering the last view). See T58142/D4239 for discussion. * (or if we are rendering the last view). See #58142/D4239 for discussion.
*/ */
if (view_index == num_views - 1) { if (view_index == num_views - 1) {
free_blender_memory_if_possible(); free_blender_memory_if_possible();

View File

@ -766,7 +766,7 @@ void BlenderSync::free_data_after_sync(BL::Depsgraph &b_depsgraph)
(BlenderSession::headless || is_interface_locked) && (BlenderSession::headless || is_interface_locked) &&
/* Baking re-uses the depsgraph multiple times, clearing crashes /* Baking re-uses the depsgraph multiple times, clearing crashes
* reading un-evaluated mesh data which isn't aligned with the * reading un-evaluated mesh data which isn't aligned with the
* geometry we're baking, see T71012. */ * geometry we're baking, see #71012. */
!scene->bake_manager->get_baking() && !scene->bake_manager->get_baking() &&
/* Persistent data must main caches for performance and correctness. */ /* Persistent data must main caches for performance and correctness. */
!is_persistent_data; !is_persistent_data;

View File

@ -42,12 +42,15 @@ endif()
########################################################################### ###########################################################################
if(WITH_CYCLES_HIP_BINARIES AND WITH_CYCLES_DEVICE_HIP) if(WITH_CYCLES_HIP_BINARIES AND WITH_CYCLES_DEVICE_HIP)
find_package(HIP) set(WITH_CYCLES_HIP_BINARIES OFF)
set_and_warn_library_found("HIP compiler" HIP_FOUND WITH_CYCLES_HIP_BINARIES) message(STATUS "HIP temporarily disabled due to compiler bugs")
if(HIP_FOUND) # find_package(HIP)
message(STATUS "Found HIP ${HIP_HIPCC_EXECUTABLE} (${HIP_VERSION})") # set_and_warn_library_found("HIP compiler" HIP_FOUND WITH_CYCLES_HIP_BINARIES)
endif()
# if(HIP_FOUND)
# message(STATUS "Found HIP ${HIP_HIPCC_EXECUTABLE} (${HIP_VERSION})")
# endif()
endif() endif()
if(NOT WITH_HIP_DYNLOAD) if(NOT WITH_HIP_DYNLOAD)

View File

@ -906,7 +906,7 @@ bool HIPDevice::should_use_graphics_interop()
* possible, but from the empiric measurements it can be considerably slower than using naive * possible, but from the empiric measurements it can be considerably slower than using naive
* pixels copy. */ * pixels copy. */
/* Disable graphics interop for now, because of driver bug in 21.40. See T92972 */ /* Disable graphics interop for now, because of driver bug in 21.40. See #92972 */
# if 0 # if 0
HIPContextScope scope(this); HIPContextScope scope(this);

View File

@ -51,7 +51,7 @@ static inline bool hipSupportsDevice(const int hipDevId)
hipDeviceGetAttribute(&major, hipDeviceAttributeComputeCapabilityMajor, hipDevId); hipDeviceGetAttribute(&major, hipDeviceAttributeComputeCapabilityMajor, hipDevId);
hipDeviceGetAttribute(&minor, hipDeviceAttributeComputeCapabilityMinor, hipDevId); hipDeviceGetAttribute(&minor, hipDeviceAttributeComputeCapabilityMinor, hipDevId);
return (major >= 10); return (major >= 9);
} }
CCL_NAMESPACE_END CCL_NAMESPACE_END

View File

@ -586,7 +586,7 @@ void MetalDevice::erase_allocation(device_memory &mem)
if (it != metal_mem_map.end()) { if (it != metal_mem_map.end()) {
MetalMem *mmem = it->second.get(); MetalMem *mmem = it->second.get();
/* blank out reference to MetalMem* in the launch params (fixes crash T94736) */ /* blank out reference to MetalMem* in the launch params (fixes crash #94736) */
if (mmem->pointer_index >= 0) { if (mmem->pointer_index >= 0) {
device_ptr *pointers = (device_ptr *)&launch_params; device_ptr *pointers = (device_ptr *)&launch_params;
pointers[mmem->pointer_index] = 0; pointers[mmem->pointer_index] = 0;

View File

@ -886,7 +886,7 @@ int RenderScheduler::get_num_samples_during_navigation(int resolution_divider) c
{ {
/* Special trick for fast navigation: schedule multiple samples during fast navigation /* Special trick for fast navigation: schedule multiple samples during fast navigation
* (which will prefer to use lower resolution to keep up with refresh rate). This gives more * (which will prefer to use lower resolution to keep up with refresh rate). This gives more
* usable visual feedback for artists. There are a couple of tricks though. */ * usable visual feedback for artists. */
if (is_denoise_active_during_update()) { if (is_denoise_active_during_update()) {
/* When denoising is used during navigation prefer using a higher resolution with less samples /* When denoising is used during navigation prefer using a higher resolution with less samples
@ -896,25 +896,12 @@ int RenderScheduler::get_num_samples_during_navigation(int resolution_divider) c
return 1; return 1;
} }
if (resolution_divider <= pixel_size_) { /* Schedule samples equal to the resolution divider up to a maximum of 4.
/* When resolution divider is at or below pixel size, schedule one sample. This doesn't effect * The idea is to have enough information on the screen by increasing the sample count as the
* the sample count at this resolution division, but instead assists in the calculation of * resolution is decreased. */
* the resolution divider. */ /* NOTE: Changing this formula will change the formula in
return 1; * `RenderScheduler::calculate_resolution_divider_for_time()`. */
} return min(max(1, resolution_divider / pixel_size_), 4);
if (resolution_divider == pixel_size_ * 2) {
/* When resolution divider is the previous step to the final resolution, schedule two samples.
* This is so that rendering on lower resolution does not exceed time that it takes to render
* first sample at the full resolution. */
return 2;
}
/* Always render 4 samples, even if scene is configured for less.
* The idea here is to have enough information on the screen. Resolution divider of 2 allows us
* to have 4 time extra samples, so overall worst case timing is the same as the final resolution
* at one sample. */
return 4;
} }
bool RenderScheduler::work_need_adaptive_filter() const bool RenderScheduler::work_need_adaptive_filter() const
@ -1100,9 +1087,10 @@ void RenderScheduler::update_start_resolution_divider()
/* TODO(sergey): Need to add hysteresis to avoid resolution divider bouncing around when actual /* TODO(sergey): Need to add hysteresis to avoid resolution divider bouncing around when actual
* render time is somewhere on a boundary between two resolutions. */ * render time is somewhere on a boundary between two resolutions. */
/* Never increase resolution to higher than the pixel size (which is possible if the scene is /* Don't let resolution drop below the desired one. It's better to be slow than provide an
* simple and compute device is fast). */ * unreadable viewport render. */
start_resolution_divider_ = max(resolution_divider_for_update, pixel_size_); start_resolution_divider_ = min(resolution_divider_for_update,
default_start_resolution_divider_);
VLOG_WORK << "Calculated resolution divider is " << start_resolution_divider_; VLOG_WORK << "Calculated resolution divider is " << start_resolution_divider_;
} }
@ -1187,24 +1175,24 @@ void RenderScheduler::check_time_limit_reached()
int RenderScheduler::calculate_resolution_divider_for_time(double desired_time, double actual_time) int RenderScheduler::calculate_resolution_divider_for_time(double desired_time, double actual_time)
{ {
/* TODO(sergey): There should a non-iterative analytical formula here. */ const double ratio_between_times = actual_time / desired_time;
int resolution_divider = 1; /* We can pass `ratio_between_times` to `get_num_samples_during_navigation()` to get our
* navigation samples because the equation for calculating the resolution divider is as follows:
* `actual_time / desired_time = sqr(resolution_divider) / sample_count`.
* While `resolution_divider` is less than or equal to 4, `resolution_divider = sample_count`
* (This relationship is determined in `get_num_samples_during_navigation()`). With some
* substitution we end up with `actual_time / desired_time = resolution_divider` while the
* resolution divider is less than or equal to 4. Once the resolution divider increases above 4,
* the relationship of `actual_time / desired_time = resolution_divider` is no longer true,
* however the sample count retrieved from `get_num_samples_during_navigation()` is still
* accurate if we continue using this assumption. It should be noted that the interaction between
* `pixel_size`, sample count, and resolution divider are automatically accounted for and that's
* why `pixel_size` isn't included in any of the equations. */
const int navigation_samples = get_num_samples_during_navigation(
ceil_to_int(ratio_between_times));
/* This algorithm iterates through resolution dividers until a divider is found that achieves return ceil_to_int(sqrt(navigation_samples * ratio_between_times));
* the desired render time. A limit of default_start_resolution_divider_ is put in place as the
* maximum resolution divider to avoid an unreadable viewport due to a low resolution.
* pre_resolution_division_samples and post_resolution_division_samples are used in this
* calculation to better predict the performance impact of changing resolution divisions as
* the sample count can also change between resolution divisions. */
while (actual_time > desired_time && resolution_divider < default_start_resolution_divider_) {
int pre_resolution_division_samples = get_num_samples_during_navigation(resolution_divider);
resolution_divider = resolution_divider * 2;
int post_resolution_division_samples = get_num_samples_during_navigation(resolution_divider);
actual_time /= 4.0 * pre_resolution_division_samples / post_resolution_division_samples;
}
return resolution_divider;
} }
int calculate_resolution_divider_for_resolution(int width, int height, int resolution) int calculate_resolution_divider_for_resolution(int width, int height, int resolution)

View File

@ -412,11 +412,12 @@ if(WITH_CYCLES_CUDA_BINARIES)
# warn for other versions # warn for other versions
if((CUDA_VERSION STREQUAL "101") OR if((CUDA_VERSION STREQUAL "101") OR
(CUDA_VERSION STREQUAL "102") OR (CUDA_VERSION STREQUAL "102") OR
(CUDA_VERSION_MAJOR STREQUAL "11")) (CUDA_VERSION_MAJOR STREQUAL "11") OR
(CUDA_VERSION_MAJOR STREQUAL "12"))
else() else()
message(WARNING message(WARNING
"CUDA version ${CUDA_VERSION_MAJOR}.${CUDA_VERSION_MINOR} detected, " "CUDA version ${CUDA_VERSION_MAJOR}.${CUDA_VERSION_MINOR} detected, "
"build may succeed but only CUDA 11, 10.2 and 10.1 have been tested") "build may succeed but only CUDA 12, 11, 10.2 and 10.1 have been tested")
endif() endif()
# build for each arch # build for each arch
@ -514,6 +515,16 @@ if(WITH_CYCLES_CUDA_BINARIES)
else() else()
message(STATUS "CUDA binaries for ${arch} require CUDA 10 or earlier, skipped.") message(STATUS "CUDA binaries for ${arch} require CUDA 10 or earlier, skipped.")
endif() endif()
elseif(${arch} MATCHES ".*_3.")
if(DEFINED CUDA11_NVCC_EXECUTABLE)
set(cuda_nvcc_executable ${CUDA11_NVCC_EXECUTABLE})
set(cuda_toolkit_root_dir ${CUDA11_TOOLKIT_ROOT_DIR})
elseif("${CUDA_VERSION}" LESS 120) # Support for sm_35, sm_37 was removed in CUDA 12
set(cuda_nvcc_executable ${CUDA_NVCC_EXECUTABLE})
set(cuda_toolkit_root_dir ${CUDA_TOOLKIT_ROOT_DIR})
else()
message(STATUS "CUDA binaries for ${arch} require CUDA 11 or earlier, skipped.")
endif()
elseif(${arch} MATCHES ".*_7." AND "${CUDA_VERSION}" LESS 100) elseif(${arch} MATCHES ".*_7." AND "${CUDA_VERSION}" LESS 100)
message(STATUS "CUDA binaries for ${arch} require CUDA 10.0+, skipped.") message(STATUS "CUDA binaries for ${arch} require CUDA 10.0+, skipped.")
elseif(${arch} MATCHES ".*_8.") elseif(${arch} MATCHES ".*_8.")

View File

@ -686,7 +686,7 @@ ccl_device_inline Spectrum bsdf_albedo(ccl_private const ShaderData *sd,
albedo *= ((ccl_private const PrincipledSheenBsdf *)sc)->avg_value; albedo *= ((ccl_private const PrincipledSheenBsdf *)sc)->avg_value;
break; break;
case CLOSURE_BSDF_HAIR_PRINCIPLED_ID: case CLOSURE_BSDF_HAIR_PRINCIPLED_ID:
albedo *= bsdf_principled_hair_albedo(sc); albedo *= bsdf_principled_hair_albedo(sd, sc);
break; break;
default: default:
break; break;

View File

@ -478,10 +478,18 @@ ccl_device_inline float bsdf_principled_hair_albedo_roughness_scale(
return (((((0.245f * x) + 5.574f) * x - 10.73f) * x + 2.532f) * x - 0.215f) * x + 5.969f; return (((((0.245f * x) + 5.574f) * x - 10.73f) * x + 2.532f) * x - 0.215f) * x + 5.969f;
} }
ccl_device Spectrum bsdf_principled_hair_albedo(ccl_private const ShaderClosure *sc) ccl_device Spectrum bsdf_principled_hair_albedo(ccl_private const ShaderData *sd,
ccl_private const ShaderClosure *sc)
{ {
ccl_private PrincipledHairBSDF *bsdf = (ccl_private PrincipledHairBSDF *)sc; ccl_private PrincipledHairBSDF *bsdf = (ccl_private PrincipledHairBSDF *)sc;
return exp(-sqrt(bsdf->sigma) * bsdf_principled_hair_albedo_roughness_scale(bsdf->v));
const float cos_theta_o = cos_from_sin(dot(sd->wi, safe_normalize(sd->dPdu)));
const float cos_gamma_o = cos_from_sin(bsdf->extra->geom.w);
const float f = fresnel_dielectric_cos(cos_theta_o * cos_gamma_o, bsdf->eta);
const float roughness_scale = bsdf_principled_hair_albedo_roughness_scale(bsdf->v);
/* TODO(lukas): Adding the Fresnel term here as a workaround until the proper refactor. */
return exp(-sqrt(bsdf->sigma) * roughness_scale) + make_spectrum(f);
} }
ccl_device_inline Spectrum ccl_device_inline Spectrum

View File

@ -10,7 +10,7 @@
#ifndef WITH_CYCLES_OPTIMIZED_KERNEL_AVX2 #ifndef WITH_CYCLES_OPTIMIZED_KERNEL_AVX2
# define KERNEL_STUB # define KERNEL_STUB
#else #else
/* SSE optimization disabled for now on 32 bit, see bug T36316. */ /* SSE optimization disabled for now on 32 bit, see bug #36316. */
# if !(defined(__GNUC__) && (defined(i386) || defined(_M_IX86))) # if !(defined(__GNUC__) && (defined(i386) || defined(_M_IX86)))
# define __KERNEL_SSE__ # define __KERNEL_SSE__
# define __KERNEL_SSE2__ # define __KERNEL_SSE2__

View File

@ -10,7 +10,7 @@
#ifndef WITH_CYCLES_OPTIMIZED_KERNEL_SSE2 #ifndef WITH_CYCLES_OPTIMIZED_KERNEL_SSE2
# define KERNEL_STUB # define KERNEL_STUB
#else #else
/* SSE optimization disabled for now on 32 bit, see bug T36316. */ /* SSE optimization disabled for now on 32 bit, see bug #36316. */
# if !(defined(__GNUC__) && (defined(i386) || defined(_M_IX86))) # if !(defined(__GNUC__) && (defined(i386) || defined(_M_IX86)))
# define __KERNEL_SSE2__ # define __KERNEL_SSE2__
# endif # endif

View File

@ -10,7 +10,7 @@
#ifndef WITH_CYCLES_OPTIMIZED_KERNEL_SSE41 #ifndef WITH_CYCLES_OPTIMIZED_KERNEL_SSE41
# define KERNEL_STUB # define KERNEL_STUB
#else #else
/* SSE optimization disabled for now on 32 bit, see bug T36316. */ /* SSE optimization disabled for now on 32 bit, see bug #36316. */
# if !(defined(__GNUC__) && (defined(i386) || defined(_M_IX86))) # if !(defined(__GNUC__) && (defined(i386) || defined(_M_IX86)))
# define __KERNEL_SSE2__ # define __KERNEL_SSE2__
# define __KERNEL_SSE3__ # define __KERNEL_SSE3__

View File

@ -645,7 +645,7 @@ ccl_device_inline void kernel_gpu_film_convert_half_write(ccl_global uchar4 *rgb
const int y, const int y,
const half4 half_pixel) const half4 half_pixel)
{ {
/* Work around HIP issue with half float display, see T92972. */ /* Work around HIP issue with half float display, see #92972. */
#ifdef __KERNEL_HIP__ #ifdef __KERNEL_HIP__
ccl_global half *out = ((ccl_global half *)rgba) + (rgba_offset + y * rgba_stride + x) * 4; ccl_global half *out = ((ccl_global half *)rgba) + (rgba_offset + y * rgba_stride + x) * 4;
out[0] = half_pixel.x; out[0] = half_pixel.x;

View File

@ -394,7 +394,7 @@ bool OSLShaderManager::osl_compile(const string &inputfile, const string &output
/* Compile. /* Compile.
* *
* Mutex protected because the OSL compiler does not appear to be thread safe, see T92503. */ * Mutex protected because the OSL compiler does not appear to be thread safe, see #92503. */
static thread_mutex osl_compiler_mutex; static thread_mutex osl_compiler_mutex;
thread_scoped_lock lock(osl_compiler_mutex); thread_scoped_lock lock(osl_compiler_mutex);

View File

@ -573,7 +573,7 @@ void ShaderManager::device_update_common(Device * /*device*/,
kfilm->is_rec709 = is_rec709; kfilm->is_rec709 = is_rec709;
} }
void ShaderManager::device_free_common(Device *, DeviceScene *dscene, Scene *scene) void ShaderManager::device_free_common(Device * /*device*/, DeviceScene *dscene, Scene * /*scene*/)
{ {
dscene->shaders.free(); dscene->shaders.free();
} }

View File

@ -520,7 +520,7 @@ bool TileManager::write_tile(const RenderBuffers &tile_buffers)
/* If there is an overscan used for the tile copy pixels into single continuous block of memory /* If there is an overscan used for the tile copy pixels into single continuous block of memory
* without any "gaps". * without any "gaps".
* This is a workaround for bug in OIIO (https://github.com/OpenImageIO/oiio/pull/3176). * This is a workaround for bug in OIIO (https://github.com/OpenImageIO/oiio/pull/3176).
* Our task reference: T93008. */ * Our task reference: #93008. */
if (tile_params.window_x || tile_params.window_y || if (tile_params.window_x || tile_params.window_y ||
tile_params.window_width != tile_params.width || tile_params.window_width != tile_params.width ||
tile_params.window_height != tile_params.height) { tile_params.window_height != tile_params.height) {

View File

@ -421,7 +421,7 @@ ccl_device_inline float fast_expf(float x)
#if !defined(__KERNEL_GPU__) && !defined(_MSC_VER) #if !defined(__KERNEL_GPU__) && !defined(_MSC_VER)
/* MSVC seems to have a code-gen bug here in at least SSE41/AVX, see /* MSVC seems to have a code-gen bug here in at least SSE41/AVX, see
* T78047 and T78869 for details. Just disable for now, it only makes * #78047 and #78869 for details. Just disable for now, it only makes
* a small difference in denoising performance. */ * a small difference in denoising performance. */
ccl_device float4 fast_exp2f4(float4 x) ccl_device float4 fast_exp2f4(float4 x)
{ {

View File

@ -516,7 +516,7 @@ GHOST_TSuccess GHOST_ContextCGL::releaseNativeHandles()
/* OpenGL on Metal /* OpenGL on Metal
* *
* Use Metal layer to avoid Viewport lagging on macOS, see T60043. */ * Use Metal layer to avoid Viewport lagging on macOS, see #60043. */
static const MTLPixelFormat METAL_FRAMEBUFFERPIXEL_FORMAT = MTLPixelFormatBGRA8Unorm; static const MTLPixelFormat METAL_FRAMEBUFFERPIXEL_FORMAT = MTLPixelFormatBGRA8Unorm;
static const OSType METAL_CORE_VIDEO_PIXEL_FORMAT = kCVPixelFormatType_32BGRA; static const OSType METAL_CORE_VIDEO_PIXEL_FORMAT = kCVPixelFormatType_32BGRA;

View File

@ -141,7 +141,7 @@ GHOST_TSuccess GHOST_ContextGLX::initializeDrawingContext()
/* -------------------------------------------------------------------- */ /* -------------------------------------------------------------------- */
#else #else
/* Important to initialize only GLXEW (_not_ GLEW), /* Important to initialize only GLXEW (_not_ GLEW),
* since this breaks w/ Mesa's `swrast`, see: T46431. */ * since this breaks w/ Mesa's `swrast`, see: #46431. */
glxewInit(); glxewInit();
#endif /* USE_GLXEW_INIT_WORKAROUND */ #endif /* USE_GLXEW_INIT_WORKAROUND */

View File

@ -302,7 +302,7 @@ bool GHOST_NDOFManager::setDevice(ushort vendor_id, ushort product_id)
switch (product_id) { switch (product_id) {
case 0xC62E: /* Plugged in. */ case 0xC62E: /* Plugged in. */
case 0xC62F: /* Wireless. */ case 0xC62F: /* Wireless. */
case 0xC658: /* Wireless (3DConnexion Universal Wireless Receiver in WIN32), see T82412. */ case 0xC658: /* Wireless (3DConnexion Universal Wireless Receiver in WIN32), see #82412. */
{ {
device_type_ = NDOF_SpaceMouseWireless; device_type_ = NDOF_SpaceMouseWireless;
hid_map_button_num_ = 2; hid_map_button_num_ = 2;

View File

@ -141,7 +141,7 @@ constexpr size_t events_pending_default_size = 4096 / sizeof(void *);
* \{ */ * \{ */
/** /**
* GNOME (mutter 42.2 had a bug with confine not respecting scale - Hi-DPI), See: T98793. * GNOME (mutter 42.2 had a bug with confine not respecting scale - Hi-DPI), See: #98793.
* Even though this has been fixed, at time of writing it's not yet in a release. * Even though this has been fixed, at time of writing it's not yet in a release.
* Workaround the problem by implementing confine with a software cursor. * Workaround the problem by implementing confine with a software cursor.
* While this isn't ideal, it's not adding a lot of overhead as software * While this isn't ideal, it's not adding a lot of overhead as software
@ -176,7 +176,7 @@ static bool use_gnome_confine_hack = false;
/** /**
* KDE (plasma 5.26.1) has a bug where the cursor surface needs to be committed * KDE (plasma 5.26.1) has a bug where the cursor surface needs to be committed
* (via `wl_surface_commit`) when it was hidden and is being set to visible again, see: T102048. * (via `wl_surface_commit`) when it was hidden and is being set to visible again, see: #102048.
* See: https://bugs.kde.org/show_bug.cgi?id=461001 * See: https://bugs.kde.org/show_bug.cgi?id=461001
*/ */
#define USE_KDE_TABLET_HIDDEN_CURSOR_HACK #define USE_KDE_TABLET_HIDDEN_CURSOR_HACK
@ -197,8 +197,8 @@ static bool use_gnome_confine_hack = false;
* \{ */ * \{ */
/** /**
* Fix short-cut part of keyboard reading code not properly handling some keys, see: T102194. * Fix short-cut part of keyboard reading code not properly handling some keys, see: #102194.
* \note This is similar to X11 workaround by the same name, see: T47228. * \note This is similar to X11 workaround by the same name, see: #47228.
*/ */
#define USE_NON_LATIN_KB_WORKAROUND #define USE_NON_LATIN_KB_WORKAROUND
@ -1328,7 +1328,7 @@ static void ghost_wl_display_report_error(struct wl_display *display)
* So in practice re-connecting to the display server isn't an option. * So in practice re-connecting to the display server isn't an option.
* *
* Exit since leaving the process open will simply flood the output and do nothing. * Exit since leaving the process open will simply flood the output and do nothing.
* Although as the process is in a valid state, auto-save for e.g. is possible, see: T100855. */ * Although as the process is in a valid state, auto-save for e.g. is possible, see: #100855. */
::exit(-1); ::exit(-1);
} }
@ -1442,7 +1442,7 @@ static GHOST_TKey xkb_map_gkey(const xkb_keysym_t sym)
/* Additional keys for non US layouts. */ /* Additional keys for non US layouts. */
/* Uses the same physical key as #XKB_KEY_KP_Decimal for QWERTZ layout, see: T102287. */ /* Uses the same physical key as #XKB_KEY_KP_Decimal for QWERTZ layout, see: #102287. */
GXMAP(gkey, XKB_KEY_KP_Separator, GHOST_kKeyNumpadPeriod); GXMAP(gkey, XKB_KEY_KP_Separator, GHOST_kKeyNumpadPeriod);
default: default:
@ -3810,7 +3810,7 @@ static xkb_keysym_t xkb_state_key_get_one_sym_without_modifiers(
/* NOTE(@ideasman42): Only perform the number-locked lookup as a fallback /* NOTE(@ideasman42): Only perform the number-locked lookup as a fallback
* when a number-pad key has been pressed. This is important as some key-maps use number lock * when a number-pad key has been pressed. This is important as some key-maps use number lock
* for switching other layers (in particular `de(neo_qwertz)` turns on layer-4), see: T96170. * for switching other layers (in particular `de(neo_qwertz)` turns on layer-4), see: #96170.
* Alternative solutions could be to inspect the layout however this could get involved * Alternative solutions could be to inspect the layout however this could get involved
* and turning on the number-lock is only needed for a limited set of keys. */ * and turning on the number-lock is only needed for a limited set of keys. */
@ -4467,7 +4467,7 @@ static void xdg_output_handle_logical_size(void *data,
#ifdef USE_GNOME_CONFINE_HACK #ifdef USE_GNOME_CONFINE_HACK
/* Use a bug in GNOME to check GNOME is in use. If the bug is fixed this won't cause an issue /* Use a bug in GNOME to check GNOME is in use. If the bug is fixed this won't cause an issue
* as T98793 has been fixed up-stream too, but not in a release at time of writing. */ * as #98793 has been fixed up-stream too, but not in a release at time of writing. */
use_gnome_confine_hack = true; use_gnome_confine_hack = true;
#endif #endif

View File

@ -208,7 +208,7 @@ class GHOST_SystemWayland : public GHOST_System {
* Clear all references to this output. * Clear all references to this output.
* *
* \note The compositor should have already called the `wl_surface_listener.leave` callback, * \note The compositor should have already called the `wl_surface_listener.leave` callback,
* however some compositors may not (see T103586). * however some compositors may not (see #103586).
* So remove references to the output before it's destroyed to avoid crashing. * So remove references to the output before it's destroyed to avoid crashing.
* *
* \return true when any references were removed. * \return true when any references were removed.

View File

@ -565,8 +565,8 @@ GHOST_TKey GHOST_SystemWin32::hardKey(RAWINPUT const &raw, bool *r_key_down)
/** /**
* \note this function can be extended to include other exotic cases as they arise. * \note this function can be extended to include other exotic cases as they arise.
* *
* This function was added in response to bug T25715. * This function was added in response to bug #25715.
* This is going to be a long list T42426. * This is going to be a long list #42426.
*/ */
GHOST_TKey GHOST_SystemWin32::processSpecialKey(short vKey, short scanCode) const GHOST_TKey GHOST_SystemWin32::processSpecialKey(short vKey, short scanCode) const
{ {
@ -1083,7 +1083,7 @@ GHOST_EventCursor *GHOST_SystemWin32::processCursorEvent(GHOST_WindowWin32 *wind
* so the box needs to small enough not to let the cursor escape the window but large * so the box needs to small enough not to let the cursor escape the window but large
* enough that the cursor isn't being warped every time. * enough that the cursor isn't being warped every time.
* If this was not the case it would be less trouble to simply warp the cursor to the * If this was not the case it would be less trouble to simply warp the cursor to the
* center of the screen on every motion, see: D16558 (alternative fix for T102346). */ * center of the screen on every motion, see: D16558 (alternative fix for #102346). */
const int32_t subregion_div = 4; /* One quarter of the region. */ const int32_t subregion_div = 4; /* One quarter of the region. */
const int32_t size[2] = {bounds.getWidth(), bounds.getHeight()}; const int32_t size[2] = {bounds.getWidth(), bounds.getHeight()};
const int32_t center[2] = {(bounds.m_l + bounds.m_r) / 2, (bounds.m_t + bounds.m_b) / 2}; const int32_t center[2] = {(bounds.m_l + bounds.m_r) / 2, (bounds.m_t + bounds.m_b) / 2};
@ -1209,7 +1209,7 @@ GHOST_EventKey *GHOST_SystemWin32::processKeyEvent(GHOST_WindowWin32 *window, RA
const bool ctrl_pressed = has_state && state[VK_CONTROL] & 0x80; const bool ctrl_pressed = has_state && state[VK_CONTROL] & 0x80;
const bool alt_pressed = has_state && state[VK_MENU] & 0x80; const bool alt_pressed = has_state && state[VK_MENU] & 0x80;
/* We can be here with !key_down if processing dead keys (diacritics). See T103119. */ /* We can be here with !key_down if processing dead keys (diacritics). See #103119. */
/* No text with control key pressed (Alt can be used to insert special characters though!). */ /* No text with control key pressed (Alt can be used to insert special characters though!). */
if (ctrl_pressed && !alt_pressed) { if (ctrl_pressed && !alt_pressed) {

View File

@ -46,7 +46,7 @@
#ifdef WITH_X11_XFIXES #ifdef WITH_X11_XFIXES
# include <X11/extensions/Xfixes.h> # include <X11/extensions/Xfixes.h>
/* Workaround for XWayland grab glitch: T53004. */ /* Workaround for XWayland grab glitch: #53004. */
# define WITH_XWAYLAND_HACK # define WITH_XWAYLAND_HACK
#endif #endif
@ -71,11 +71,11 @@
# define USE_XINPUT_HOTPLUG # define USE_XINPUT_HOTPLUG
#endif #endif
/* see T34039 Fix Alt key glitch on Unity desktop */ /* see #34039 Fix Alt key glitch on Unity desktop */
#define USE_UNITY_WORKAROUND #define USE_UNITY_WORKAROUND
/* Fix 'shortcut' part of keyboard reading code only ever using first defined key-map /* Fix 'shortcut' part of keyboard reading code only ever using first defined key-map
* instead of active one. See T47228 and D1746 */ * instead of active one. See #47228 and D1746 */
#define USE_NON_LATIN_KB_WORKAROUND #define USE_NON_LATIN_KB_WORKAROUND
static uchar bit_is_on(const uchar *ptr, int bit) static uchar bit_is_on(const uchar *ptr, int bit)
@ -928,7 +928,7 @@ void GHOST_SystemX11::processEvent(XEvent *xe)
window->getClientBounds(bounds); window->getClientBounds(bounds);
/* TODO(@ideasman42): warp the cursor to `window->getCursorGrabInitPos`, /* TODO(@ideasman42): warp the cursor to `window->getCursorGrabInitPos`,
* on every motion event, see: D16557 (alternative fix for T102346). */ * on every motion event, see: D16557 (alternative fix for #102346). */
const int32_t subregion_div = 4; /* One quarter of the region. */ const int32_t subregion_div = 4; /* One quarter of the region. */
const int32_t size[2] = {bounds.getWidth(), bounds.getHeight()}; const int32_t size[2] = {bounds.getWidth(), bounds.getHeight()};
const int32_t center[2] = { const int32_t center[2] = {
@ -964,7 +964,7 @@ void GHOST_SystemX11::processEvent(XEvent *xe)
if (x_new != xme.x_root || y_new != xme.y_root) { if (x_new != xme.x_root || y_new != xme.y_root) {
/* Use time of last event to avoid wrapping several times on the 'same' actual wrap. /* Use time of last event to avoid wrapping several times on the 'same' actual wrap.
* Note that we need to deal with X and Y separately as those might wrap at the same time * Note that we need to deal with X and Y separately as those might wrap at the same time
* but still in two different events (corner case, see T74918). * but still in two different events (corner case, see #74918).
* We also have to add a few extra milliseconds of 'padding', as sometimes we get two * We also have to add a few extra milliseconds of 'padding', as sometimes we get two
* close events that will generate extra wrap on the same axis within those few * close events that will generate extra wrap on the same axis within those few
* milliseconds. */ * milliseconds. */
@ -1028,7 +1028,7 @@ void GHOST_SystemX11::processEvent(XEvent *xe)
/* XXX: Code below is kinda awfully convoluted... Issues are: /* XXX: Code below is kinda awfully convoluted... Issues are:
* - In keyboards like Latin ones, numbers need a 'Shift' to be accessed but key_sym * - In keyboards like Latin ones, numbers need a 'Shift' to be accessed but key_sym
* is unmodified (or anyone swapping the keys with `xmodmap`). * is unmodified (or anyone swapping the keys with `xmodmap`).
* - #XLookupKeysym seems to always use first defined key-map (see T47228), which generates * - #XLookupKeysym seems to always use first defined key-map (see #47228), which generates
* key-codes unusable by ghost_key_from_keysym for non-Latin-compatible key-maps. * key-codes unusable by ghost_key_from_keysym for non-Latin-compatible key-maps.
* *
* To address this, we: * To address this, we:
@ -1715,7 +1715,7 @@ GHOST_TSuccess GHOST_SystemX11::setCursorPosition(int32_t x, int32_t y)
#if defined(WITH_X11_XINPUT) && defined(USE_X11_XINPUT_WARP) #if defined(WITH_X11_XINPUT) && defined(USE_X11_XINPUT_WARP)
if ((m_xinput_version.present) && (m_xinput_version.major_version >= 2)) { if ((m_xinput_version.present) && (m_xinput_version.major_version >= 2)) {
/* Needed to account for XInput "Coordinate Transformation Matrix", see T48901 */ /* Needed to account for XInput "Coordinate Transformation Matrix", see #48901 */
int device_id; int device_id;
if (XIGetClientPointer(m_display, None, &device_id) != False) { if (XIGetClientPointer(m_display, None, &device_id) != False) {
XIWarpPointer(m_display, device_id, None, None, 0, 0, 0, 0, relx, rely); XIWarpPointer(m_display, device_id, None, None, 0, 0, 0, 0, relx, rely);

View File

@ -20,8 +20,8 @@
/* Disable XINPUT warp, currently not implemented by Xorg for multi-head display. /* Disable XINPUT warp, currently not implemented by Xorg for multi-head display.
* (see comment in XSERVER `Xi/xiwarppointer.c` -> `FIXME: panoramix stuff is missing` ~ v1.13.4) * (see comment in XSERVER `Xi/xiwarppointer.c` -> `FIXME: panoramix stuff is missing` ~ v1.13.4)
* If this is supported we can add back XINPUT for warping (fixing T48901). * If this is supported we can add back XINPUT for warping (fixing #48901).
* For now disable (see T50383). */ * For now disable (see #50383). */
// # define USE_X11_XINPUT_WARP // # define USE_X11_XINPUT_WARP
#endif #endif

View File

@ -306,14 +306,23 @@ static void gwl_window_frame_update_from_pending(GWL_Window *win);
#ifdef USE_EVENT_BACKGROUND_THREAD #ifdef USE_EVENT_BACKGROUND_THREAD
enum eGWL_PendingWindowActions { enum eGWL_PendingWindowActions {
PENDING_FRAME_CONFIGURE = 0, /**
PENDING_EGL_RESIZE, * The state of the window frame has changed, apply the state from #GWL_Window::frame_pending.
*/
PENDING_WINDOW_FRAME_CONFIGURE = 0,
/** The EGL buffer must be resized to match #GWL_WindowFrame::size. */
PENDING_EGL_WINDOW_RESIZE,
# ifdef GHOST_OPENGL_ALPHA # ifdef GHOST_OPENGL_ALPHA
/** Draw an opaque region behind the window. */
PENDING_OPAQUE_SET, PENDING_OPAQUE_SET,
# endif # endif
PENDING_SCALE_UPDATE, /**
* The DPI for a monitor has changed or the monitors (outputs)
* this window is visible on may have changed. Recalculate the windows scale.
*/
PENDING_OUTPUT_SCALE_UPDATE,
}; };
# define PENDING_NUM (PENDING_SCALE_UPDATE + 1) # define PENDING_NUM (PENDING_OUTPUT_SCALE_UPDATE + 1)
static void gwl_window_pending_actions_tag(GWL_Window *win, enum eGWL_PendingWindowActions type) static void gwl_window_pending_actions_tag(GWL_Window *win, enum eGWL_PendingWindowActions type)
{ {
@ -323,10 +332,10 @@ static void gwl_window_pending_actions_tag(GWL_Window *win, enum eGWL_PendingWin
static void gwl_window_pending_actions_handle(GWL_Window *win) static void gwl_window_pending_actions_handle(GWL_Window *win)
{ {
if (win->pending_actions[PENDING_FRAME_CONFIGURE].exchange(false)) { if (win->pending_actions[PENDING_WINDOW_FRAME_CONFIGURE].exchange(false)) {
gwl_window_frame_update_from_pending(win); gwl_window_frame_update_from_pending(win);
} }
if (win->pending_actions[PENDING_EGL_RESIZE].exchange(false)) { if (win->pending_actions[PENDING_EGL_WINDOW_RESIZE].exchange(false)) {
wl_egl_window_resize(win->egl_window, UNPACK2(win->frame.size), 0, 0); wl_egl_window_resize(win->egl_window, UNPACK2(win->frame.size), 0, 0);
} }
# ifdef GHOST_OPENGL_ALPHA # ifdef GHOST_OPENGL_ALPHA
@ -334,7 +343,7 @@ static void gwl_window_pending_actions_handle(GWL_Window *win)
win->ghost_window->setOpaque(); win->ghost_window->setOpaque();
} }
# endif # endif
if (win->pending_actions[PENDING_SCALE_UPDATE].exchange(false)) { if (win->pending_actions[PENDING_OUTPUT_SCALE_UPDATE].exchange(false)) {
win->ghost_window->outputs_changed_update_scale(); win->ghost_window->outputs_changed_update_scale();
} }
} }
@ -342,9 +351,10 @@ static void gwl_window_pending_actions_handle(GWL_Window *win)
#endif /* USE_EVENT_BACKGROUND_THREAD */ #endif /* USE_EVENT_BACKGROUND_THREAD */
/** /**
* Update the window's #GWL_WindowFrame * Update the window's #GWL_WindowFrame.
* The caller must handle locking & run from the main thread.
*/ */
static void gwl_window_frame_update_from_pending_lockfree(GWL_Window *win) static void gwl_window_frame_update_from_pending_no_lock(GWL_Window *win)
{ {
#ifdef USE_EVENT_BACKGROUND_THREAD #ifdef USE_EVENT_BACKGROUND_THREAD
GHOST_ASSERT(win->ghost_system->main_thread_id == std::this_thread::get_id(), GHOST_ASSERT(win->ghost_system->main_thread_id == std::this_thread::get_id(),
@ -381,7 +391,7 @@ static void gwl_window_frame_update_from_pending(GWL_Window *win)
#ifdef USE_EVENT_BACKGROUND_THREAD #ifdef USE_EVENT_BACKGROUND_THREAD
std::lock_guard lock_frame_guard{win->frame_pending_mutex}; std::lock_guard lock_frame_guard{win->frame_pending_mutex};
#endif #endif
gwl_window_frame_update_from_pending_lockfree(win); gwl_window_frame_update_from_pending_no_lock(win);
} }
/** \} */ /** \} */
@ -576,12 +586,12 @@ static void frame_handle_configure(struct libdecor_frame *frame,
GHOST_SystemWayland *system = win->ghost_system; GHOST_SystemWayland *system = win->ghost_system;
const bool is_main_thread = system->main_thread_id == std::this_thread::get_id(); const bool is_main_thread = system->main_thread_id == std::this_thread::get_id();
if (!is_main_thread) { if (!is_main_thread) {
gwl_window_pending_actions_tag(win, PENDING_FRAME_CONFIGURE); gwl_window_pending_actions_tag(win, PENDING_WINDOW_FRAME_CONFIGURE);
} }
else else
# endif # endif
{ {
gwl_window_frame_update_from_pending_lockfree(win); gwl_window_frame_update_from_pending_no_lock(win);
} }
} }
} }
@ -671,7 +681,7 @@ static void xdg_surface_handle_configure(void *data,
if (!is_main_thread) { if (!is_main_thread) {
/* NOTE(@ideasman42): this only gets one redraw, /* NOTE(@ideasman42): this only gets one redraw,
* I could not find a case where this causes problems. */ * I could not find a case where this causes problems. */
gwl_window_pending_actions_tag(win, PENDING_FRAME_CONFIGURE); gwl_window_pending_actions_tag(win, PENDING_WINDOW_FRAME_CONFIGURE);
} }
else else
#endif #endif
@ -812,12 +822,12 @@ GHOST_WindowWayland::GHOST_WindowWayland(GHOST_SystemWayland *system,
* when the `window_->scale` changed. */ * when the `window_->scale` changed. */
const int32_t size_min[2] = {320, 240}; const int32_t size_min[2] = {320, 240};
/* This value is expected to match the base name of the `.desktop` file. see T101805. /* This value is expected to match the base name of the `.desktop` file. see #101805.
* *
* NOTE: the XDG desktop-entry-spec defines that this should follow the "reverse DNS" convention. * NOTE: the XDG desktop-entry-spec defines that this should follow the "reverse DNS" convention.
* For e.g. `org.blender.Blender` - however the `.desktop` file distributed with Blender is * For e.g. `org.blender.Blender` - however the `.desktop` file distributed with Blender is
* simply called `blender.desktop`, so the it's important to follow that name. * simply called `blender.desktop`, so the it's important to follow that name.
* Other distributions such as SNAP & FLATPAK may need to change this value T101779. * Other distributions such as SNAP & FLATPAK may need to change this value #101779.
* Currently there isn't a way to configure this, we may want to support that. */ * Currently there isn't a way to configure this, we may want to support that. */
const char *xdg_app_id = ( const char *xdg_app_id = (
#ifdef WITH_GHOST_WAYLAND_APP_ID #ifdef WITH_GHOST_WAYLAND_APP_ID
@ -1080,7 +1090,7 @@ GHOST_WindowWayland::~GHOST_WindowWayland()
/* NOTE(@ideasman42): Flushing will often run the appropriate handlers event /* NOTE(@ideasman42): Flushing will often run the appropriate handlers event
* (#wl_surface_listener.leave in particular) to avoid attempted access to the freed surfaces. * (#wl_surface_listener.leave in particular) to avoid attempted access to the freed surfaces.
* This is not fool-proof though, hence the call to #window_surface_unref, see: T99078. */ * This is not fool-proof though, hence the call to #window_surface_unref, see: #99078. */
wl_display_flush(system_->wl_display()); wl_display_flush(system_->wl_display());
delete window_; delete window_;
@ -1373,7 +1383,7 @@ bool GHOST_WindowWayland::outputs_changed_update_scale()
{ {
#ifdef USE_EVENT_BACKGROUND_THREAD #ifdef USE_EVENT_BACKGROUND_THREAD
if (system_->main_thread_id != std::this_thread::get_id()) { if (system_->main_thread_id != std::this_thread::get_id()) {
gwl_window_pending_actions_tag(window_, PENDING_SCALE_UPDATE); gwl_window_pending_actions_tag(window_, PENDING_OUTPUT_SCALE_UPDATE);
return false; return false;
} }
#endif #endif

View File

@ -15,7 +15,7 @@
#include <wayland-util.h> /* For #wl_fixed_t */ #include <wayland-util.h> /* For #wl_fixed_t */
/** /**
* Define to workaround for a bug/limitation in WAYLAND, see: T100855 & upstream report: * Define to workaround for a bug/limitation in WAYLAND, see: #100855 & upstream report:
* https://gitlab.freedesktop.org/wayland/wayland/-/issues/159 * https://gitlab.freedesktop.org/wayland/wayland/-/issues/159
* *
* Consume events from WAYLAND in a thread, this is needed because overflowing the event queue * Consume events from WAYLAND in a thread, this is needed because overflowing the event queue

View File

@ -93,7 +93,7 @@ GHOST_WindowWin32::GHOST_WindowWin32(GHOST_SystemWin32 *system,
} }
RECT win_rect = {left, top, long(left + width), long(top + height)}; RECT win_rect = {left, top, long(left + width), long(top + height)};
adjustWindowRectForClosestMonitor(&win_rect, style, extended_style); adjustWindowRectForDesktop(&win_rect, style, extended_style);
wchar_t *title_16 = alloc_utf16_from_8((char *)title, 0); wchar_t *title_16 = alloc_utf16_from_8((char *)title, 0);
m_hWnd = ::CreateWindowExW(extended_style, /* window extended style */ m_hWnd = ::CreateWindowExW(extended_style, /* window extended style */
@ -154,7 +154,7 @@ GHOST_WindowWin32::GHOST_WindowWin32(GHOST_SystemWin32 *system,
} }
if (parentwindow) { if (parentwindow) {
/* Release any parent capture to allow immediate interaction (T90110). */ /* Release any parent capture to allow immediate interaction (#90110). */
::ReleaseCapture(); ::ReleaseCapture();
parentwindow->lostMouseCapture(); parentwindow->lostMouseCapture();
} }
@ -298,24 +298,52 @@ GHOST_WindowWin32::~GHOST_WindowWin32()
m_directManipulationHelper = NULL; m_directManipulationHelper = NULL;
} }
void GHOST_WindowWin32::adjustWindowRectForClosestMonitor(LPRECT win_rect, void GHOST_WindowWin32::adjustWindowRectForDesktop(LPRECT win_rect, DWORD dwStyle, DWORD dwExStyle)
DWORD dwStyle,
DWORD dwExStyle)
{ {
/* Get Details of the closest monitor. */ /* Windows can span multiple monitors, but must be usable. The desktop can have a larger
HMONITOR hmonitor = MonitorFromRect(win_rect, MONITOR_DEFAULTTONEAREST); * surface than all monitors combined, for example when two monitors are aligned diagonally.
* Therefore we ensure that all the window's corners are within some monitor's Work area. */
POINT pt;
HMONITOR hmonitor;
MONITORINFOEX monitor; MONITORINFOEX monitor;
monitor.cbSize = sizeof(MONITORINFOEX); monitor.cbSize = sizeof(MONITORINFOEX);
monitor.dwFlags = 0; monitor.dwFlags = 0;
GetMonitorInfo(hmonitor, &monitor);
/* Constrain requested size and position to fit within this monitor. */ /* Note that with MonitorFromPoint using MONITOR_DEFAULTTONEAREST, it will return
LONG width = min(monitor.rcWork.right - monitor.rcWork.left, win_rect->right - win_rect->left); * the exact monitor if there is one at the location or the nearest monitor if not. */
LONG height = min(monitor.rcWork.bottom - monitor.rcWork.top, win_rect->bottom - win_rect->top);
win_rect->left = min(max(monitor.rcWork.left, win_rect->left), monitor.rcWork.right - width); /* Top-left. */
win_rect->right = win_rect->left + width; pt.x = win_rect->left;
win_rect->top = min(max(monitor.rcWork.top, win_rect->top), monitor.rcWork.bottom - height); pt.y = win_rect->top;
win_rect->bottom = win_rect->top + height; hmonitor = MonitorFromPoint(pt, MONITOR_DEFAULTTONEAREST);
GetMonitorInfo(hmonitor, &monitor);
win_rect->top = max(win_rect->top, monitor.rcWork.top);
win_rect->left = max(win_rect->left, monitor.rcWork.left);
/* Top-right. */
pt.x = win_rect->right;
pt.y = win_rect->top;
hmonitor = MonitorFromPoint(pt, MONITOR_DEFAULTTONEAREST);
GetMonitorInfo(hmonitor, &monitor);
win_rect->top = max(win_rect->top, monitor.rcWork.top);
win_rect->right = min(win_rect->right, monitor.rcWork.right);
/* Bottom-left. */
pt.x = win_rect->left;
pt.y = win_rect->bottom;
hmonitor = MonitorFromPoint(pt, MONITOR_DEFAULTTONEAREST);
GetMonitorInfo(hmonitor, &monitor);
win_rect->bottom = min(win_rect->bottom, monitor.rcWork.bottom);
win_rect->left = max(win_rect->left, monitor.rcWork.left);
/* Bottom-right. */
pt.x = win_rect->right;
pt.y = win_rect->bottom;
hmonitor = MonitorFromPoint(pt, MONITOR_DEFAULTTONEAREST);
GetMonitorInfo(hmonitor, &monitor);
win_rect->bottom = min(win_rect->bottom, monitor.rcWork.bottom);
win_rect->right = min(win_rect->right, monitor.rcWork.right);
/* With Windows 10 and newer we can adjust for chrome that differs with DPI and scale. */ /* With Windows 10 and newer we can adjust for chrome that differs with DPI and scale. */
GHOST_WIN32_AdjustWindowRectExForDpi fpAdjustWindowRectExForDpi = nullptr; GHOST_WIN32_AdjustWindowRectExForDpi fpAdjustWindowRectExForDpi = nullptr;
@ -334,9 +362,6 @@ void GHOST_WindowWin32::adjustWindowRectForClosestMonitor(LPRECT win_rect,
else { else {
AdjustWindowRectEx(win_rect, dwStyle & ~WS_OVERLAPPED, FALSE, dwExStyle); AdjustWindowRectEx(win_rect, dwStyle & ~WS_OVERLAPPED, FALSE, dwExStyle);
} }
/* But never allow a top position that can hide part of the title bar. */
win_rect->top = max(monitor.rcWork.top, win_rect->top);
} }
bool GHOST_WindowWin32::getValid() const bool GHOST_WindowWin32::getValid() const

View File

@ -87,12 +87,12 @@ class GHOST_WindowWin32 : public GHOST_Window {
~GHOST_WindowWin32(); ~GHOST_WindowWin32();
/** /**
* Adjusts a requested window rect to fit and position correctly in monitor. * Adjusts a requested window rect to fit and position within the desktop.
* \param win_rect: pointer to rectangle that will be modified. * \param win_rect: pointer to rectangle that will be modified.
* \param dwStyle: The Window Style of the window whose required size is to be calculated. * \param dwStyle: The Window Style of the window whose required size is to be calculated.
* \param dwExStyle: The Extended Window Style of the window. * \param dwExStyle: The Extended Window Style of the window.
*/ */
void adjustWindowRectForClosestMonitor(LPRECT win_rect, DWORD dwStyle, DWORD dwExStyle); void adjustWindowRectForDesktop(LPRECT win_rect, DWORD dwStyle, DWORD dwExStyle);
/** /**
* Returns indication as to whether the window is valid. * Returns indication as to whether the window is valid.

View File

@ -418,7 +418,7 @@ void GHOST_WindowX11::refreshXInputDevices()
for (GHOST_SystemX11::GHOST_TabletX11 &xtablet : m_system->GetXTablets()) { for (GHOST_SystemX11::GHOST_TabletX11 &xtablet : m_system->GetXTablets()) {
/* With modern XInput (XLIB 1.6.2 at least and/or EVDEV 2.9.0) and some 'no-name' tablets /* With modern XInput (XLIB 1.6.2 at least and/or EVDEV 2.9.0) and some 'no-name' tablets
* like 'UC-LOGIC Tablet WP5540U', we also need to 'select' ButtonPress for motion event, * like 'UC-LOGIC Tablet WP5540U', we also need to 'select' ButtonPress for motion event,
* otherwise we do not get any tablet motion event once pen is pressed... See T43367. * otherwise we do not get any tablet motion event once pen is pressed... See #43367.
*/ */
XEventClass ev; XEventClass ev;
@ -1467,7 +1467,7 @@ GHOST_TSuccess GHOST_WindowX11::setWindowCursorGrab(GHOST_TGrabCursorMode mode)
} }
} }
/* Perform this last so to workaround XWayland bug, see: T53004. */ /* Perform this last so to workaround XWayland bug, see: #53004. */
if (m_cursorGrab == GHOST_kGrabHide) { if (m_cursorGrab == GHOST_kGrabHide) {
setWindowCursorVisibility(true); setWindowCursorVisibility(true);
} }

View File

@ -281,6 +281,8 @@ inline T *MEM_new(const char *allocation_name, Args &&...args)
*/ */
template<typename T> inline void MEM_delete(const T *ptr) template<typename T> inline void MEM_delete(const T *ptr)
{ {
static_assert(!std::is_void_v<T>,
"MEM_delete on a void pointer not possible. Cast it to a non-void type?");
if (ptr == nullptr) { if (ptr == nullptr) {
/* Support #ptr being null, because C++ `delete` supports that as well. */ /* Support #ptr being null, because C++ `delete` supports that as well. */
return; return;

View File

@ -108,7 +108,7 @@ void bl_locale_set(const char *locale)
} }
/* Extra catch on `std::runtime_error` is needed for macOS/Clang as it seems that exceptions /* Extra catch on `std::runtime_error` is needed for macOS/Clang as it seems that exceptions
* like `boost::locale::conv::conversion_error` (which inherit from `std::runtime_error`) are * like `boost::locale::conv::conversion_error` (which inherit from `std::runtime_error`) are
* not caught by their ancestor `std::exception`. See T88877#1177108 */ * not caught by their ancestor `std::exception`. See #88877#1177108 */
catch (std::runtime_error const &e) { catch (std::runtime_error const &e) {
std::cout << "bl_locale_set(" << locale << "): " << e.what() << " \n"; std::cout << "bl_locale_set(" << locale << "): " << e.what() << " \n";
} }

View File

@ -23,7 +23,7 @@ const char *osx_user_locale()
[myNSLocale autorelease]; [myNSLocale autorelease];
// This produces gettext-invalid locale in recent macOS versions (11.4), // This produces gettext-invalid locale in recent macOS versions (11.4),
// like `ko-Kore_KR` instead of `ko_KR`. See T88877. // like `ko-Kore_KR` instead of `ko_KR`. See #88877.
// NSString *nsIdentifier = [myNSLocale localeIdentifier]; // NSString *nsIdentifier = [myNSLocale localeIdentifier];
const NSString *nsIdentifier = [myNSLocale languageCode]; const NSString *nsIdentifier = [myNSLocale languageCode];

View File

@ -193,7 +193,7 @@ static bool createGPUShader(OCIO_GPUShader &shader,
info.fragment_source("gpu_shader_display_transform_frag.glsl"); info.fragment_source("gpu_shader_display_transform_frag.glsl");
info.fragment_source_generated = source; info.fragment_source_generated = source;
/* T96502: Work around for incorrect OCIO GLSL code generation when using /* #96502: Work around for incorrect OCIO GLSL code generation when using
* GradingPrimaryTransform. Should be reevaluated when changing to a next version of OCIO. * GradingPrimaryTransform. Should be reevaluated when changing to a next version of OCIO.
* (currently v2.1.1). */ * (currently v2.1.1). */
info.define("inf 1e32"); info.define("inf 1e32");

View File

@ -145,7 +145,7 @@ const UserDef U_default = {
.ndof_flag = (NDOF_MODE_ORBIT | NDOF_LOCK_HORIZON | NDOF_SHOULD_PAN | NDOF_SHOULD_ZOOM | .ndof_flag = (NDOF_MODE_ORBIT | NDOF_LOCK_HORIZON | NDOF_SHOULD_PAN | NDOF_SHOULD_ZOOM |
NDOF_SHOULD_ROTATE | NDOF_SHOULD_ROTATE |
/* Software from the driver authors follows this convention /* Software from the driver authors follows this convention
* so invert this by default, see: T67579. */ * so invert this by default, see: #67579. */
NDOF_ROTX_INVERT_AXIS | NDOF_ROTY_INVERT_AXIS | NDOF_ROTZ_INVERT_AXIS | NDOF_ROTX_INVERT_AXIS | NDOF_ROTY_INVERT_AXIS | NDOF_ROTZ_INVERT_AXIS |
NDOF_PANX_INVERT_AXIS | NDOF_PANY_INVERT_AXIS | NDOF_PANZ_INVERT_AXIS | NDOF_PANX_INVERT_AXIS | NDOF_PANY_INVERT_AXIS | NDOF_PANZ_INVERT_AXIS |
NDOF_ZOOM_INVERT | NDOF_CAMERA_PAN_ZOOM), NDOF_ZOOM_INVERT | NDOF_CAMERA_PAN_ZOOM),

View File

@ -370,6 +370,7 @@ const bTheme U_theme_default = {
.clipping_border_3d = RGBA(0x3f3f3fff), .clipping_border_3d = RGBA(0x3f3f3fff),
.bundle_solid = RGBA(0xc8c8c8ff), .bundle_solid = RGBA(0xc8c8c8ff),
.camera_path = RGBA(0x000000ff), .camera_path = RGBA(0x000000ff),
.camera_passepartout = RGBA(0x000000),
.gp_vertex_size = 3, .gp_vertex_size = 3,
.gp_vertex = RGBA(0x000000ff), .gp_vertex = RGBA(0x000000ff),
.gp_vertex_select = RGBA(0xff8500ff), .gp_vertex_select = RGBA(0xff8500ff),

View File

@ -286,7 +286,7 @@ class pySketchyChainingIterator(ChainingIterator):
if not found: if not found:
# This is a fatal error condition: self.current_edge must be found # This is a fatal error condition: self.current_edge must be found
# among the edges seen by the AdjacencyIterator [bug T35695]. # among the edges seen by the AdjacencyIterator [bug #35695].
if bpy.app.debug_freestyle: if bpy.app.debug_freestyle:
print('pySketchyChainingIterator: current edge not found') print('pySketchyChainingIterator: current edge not found')
return None return None

View File

@ -113,7 +113,7 @@ def expand(line, cursor, namespace, *, private=True):
if len(matches) == 1: if len(matches) == 1:
scrollback = '' scrollback = ''
else: else:
# causes blender bug T27495 since string keys may contain '.' # causes blender bug #27495 since string keys may contain '.'
# scrollback = ' '.join([m.split('.')[-1] for m in matches]) # scrollback = ' '.join([m.split('.')[-1] for m in matches])
# add white space to align with the cursor # add white space to align with the cursor

View File

@ -30,7 +30,7 @@ def url_prefill_from_blender(*, addon_info=None):
"**Blender Version**\n" "**Blender Version**\n"
) )
fh.write( fh.write(
"Broken: version: %s, branch: %s, commit date: %s %s, hash: `rB%s`\n" % ( "Broken: version: %s, branch: %s, commit date: %s %s, hash: `%s`\n" % (
bpy.app.version_string, bpy.app.version_string,
bpy.app.build_branch.decode('utf-8', 'replace'), bpy.app.build_branch.decode('utf-8', 'replace'),
bpy.app.build_commit_date.decode('utf-8', 'replace'), bpy.app.build_commit_date.decode('utf-8', 'replace'),

View File

@ -32,7 +32,7 @@ class _BPyOpsSubModOp:
# XXX You never quite know what you get from bpy.types, # XXX You never quite know what you get from bpy.types,
# with operators... Operator and OperatorProperties # with operators... Operator and OperatorProperties
# are shadowing each other, and not in the same way for # are shadowing each other, and not in the same way for
# native ops and py ones! See T39158. # native ops and py ones! See #39158.
# op_class = getattr(bpy.types, idname) # op_class = getattr(bpy.types, idname)
op_class = _op_get_rna_type(idname) op_class = _op_get_rna_type(idname)
descr = op_class.description descr = op_class.description

View File

@ -259,15 +259,15 @@ def bake_action_iter(
if is_new_action: if is_new_action:
action = bpy.data.actions.new("Action") action = bpy.data.actions.new("Action")
# Only leave tweak mode if we actually need to modify the action (T57159) # Only leave tweak mode if we actually need to modify the action (#57159)
if action != atd.action: if action != atd.action:
# Leave tweak mode before trying to modify the action (T48397) # Leave tweak mode before trying to modify the action (#48397)
if atd.use_tweak_mode: if atd.use_tweak_mode:
atd.use_tweak_mode = False atd.use_tweak_mode = False
atd.action = action atd.action = action
# Baking the action only makes sense in Replace mode, so force it (T69105) # Baking the action only makes sense in Replace mode, so force it (#69105)
if not atd.use_tweak_mode: if not atd.use_tweak_mode:
atd.action_blend_type = 'REPLACE' atd.action_blend_type = 'REPLACE'

View File

@ -111,7 +111,7 @@ def orientation_helper(axis_forward='Y', axis_up='Z'):
""" """
def wrapper(cls): def wrapper(cls):
# Without that, we may end up adding those fields to some **parent** class' __annotations__ property # Without that, we may end up adding those fields to some **parent** class' __annotations__ property
# (like the ImportHelper or ExportHelper ones)! See T58772. # (like the ImportHelper or ExportHelper ones)! See #58772.
if "__annotations__" not in cls.__dict__: if "__annotations__" not in cls.__dict__:
setattr(cls, "__annotations__", {}) setattr(cls, "__annotations__", {})

View File

@ -564,7 +564,7 @@ class Mesh(bpy_types.ID):
face_lengths = tuple(map(len, faces)) face_lengths = tuple(map(len, faces))
# NOTE: check non-empty lists by length because of how `numpy` handles truth tests, see: T90268. # NOTE: check non-empty lists by length because of how `numpy` handles truth tests, see: #90268.
vertices_len = len(vertices) vertices_len = len(vertices)
edges_len = len(edges) edges_len = len(edges)
faces_len = len(faces) faces_len = len(faces)

View File

@ -991,6 +991,7 @@ url_manual_mapping = (
("bpy.types.geometrynodeinputmeshfacearea*", "modeling/geometry_nodes/mesh/read/face_area.html#bpy-types-geometrynodeinputmeshfacearea"), ("bpy.types.geometrynodeinputmeshfacearea*", "modeling/geometry_nodes/mesh/read/face_area.html#bpy-types-geometrynodeinputmeshfacearea"),
("bpy.types.geometrynodeinputsplinecyclic*", "modeling/geometry_nodes/curve/read/is_spline_cyclic.html#bpy-types-geometrynodeinputsplinecyclic"), ("bpy.types.geometrynodeinputsplinecyclic*", "modeling/geometry_nodes/curve/read/is_spline_cyclic.html#bpy-types-geometrynodeinputsplinecyclic"),
("bpy.types.geometrynodeinstancestopoints*", "modeling/geometry_nodes/instances/instances_to_points.html#bpy-types-geometrynodeinstancestopoints"), ("bpy.types.geometrynodeinstancestopoints*", "modeling/geometry_nodes/instances/instances_to_points.html#bpy-types-geometrynodeinstancestopoints"),
("bpy.types.geometrynodematerialselection*", "modeling/geometry_nodes/material/material_selection.html#bpy-types-geometrynodematerialselection"),
("bpy.types.gpencillayer.viewlayer_render*", "grease_pencil/properties/layers.html#bpy-types-gpencillayer-viewlayer-render"), ("bpy.types.gpencillayer.viewlayer_render*", "grease_pencil/properties/layers.html#bpy-types-gpencillayer-viewlayer-render"),
("bpy.types.imagepaint.use_normal_falloff*", "sculpt_paint/brush/falloff.html#bpy-types-imagepaint-use-normal-falloff"), ("bpy.types.imagepaint.use_normal_falloff*", "sculpt_paint/brush/falloff.html#bpy-types-imagepaint-use-normal-falloff"),
("bpy.types.layercollection.hide_viewport*", "editors/outliner/interface.html#bpy-types-layercollection-hide-viewport"), ("bpy.types.layercollection.hide_viewport*", "editors/outliner/interface.html#bpy-types-layercollection-hide-viewport"),
@ -2027,6 +2028,7 @@ url_manual_mapping = (
("bpy.ops.graph.equalize_handles*", "editors/graph_editor/fcurves/editing.html#bpy-ops-graph-equalize-handles"), ("bpy.ops.graph.equalize_handles*", "editors/graph_editor/fcurves/editing.html#bpy-ops-graph-equalize-handles"),
("bpy.ops.mball.delete_metaelems*", "modeling/metas/editing.html#bpy-ops-mball-delete-metaelems"), ("bpy.ops.mball.delete_metaelems*", "modeling/metas/editing.html#bpy-ops-mball-delete-metaelems"),
("bpy.ops.mball.reveal_metaelems*", "modeling/metas/properties.html#bpy-ops-mball-reveal-metaelems"), ("bpy.ops.mball.reveal_metaelems*", "modeling/metas/properties.html#bpy-ops-mball-reveal-metaelems"),
("bpy.ops.mesh.bridge_edge_loops*", "modeling/meshes/editing/edge/bridge_edge_loops.html#bpy-ops-mesh-bridge-edge-loops"),
("bpy.ops.mesh.intersect_boolean*", "modeling/meshes/editing/face/intersect_boolean.html#bpy-ops-mesh-intersect-boolean"), ("bpy.ops.mesh.intersect_boolean*", "modeling/meshes/editing/face/intersect_boolean.html#bpy-ops-mesh-intersect-boolean"),
("bpy.ops.mesh.loop_multi_select*", "modeling/meshes/selecting/loops.html#bpy-ops-mesh-loop-multi-select"), ("bpy.ops.mesh.loop_multi_select*", "modeling/meshes/selecting/loops.html#bpy-ops-mesh-loop-multi-select"),
("bpy.ops.mesh.vert_connect_path*", "modeling/meshes/editing/vertex/connect_vertex_path.html#bpy-ops-mesh-vert-connect-path"), ("bpy.ops.mesh.vert_connect_path*", "modeling/meshes/editing/vertex/connect_vertex_path.html#bpy-ops-mesh-vert-connect-path"),
@ -3021,6 +3023,7 @@ url_manual_mapping = (
("bpy.types.bakesettings*", "render/cycles/baking.html#bpy-types-bakesettings"), ("bpy.types.bakesettings*", "render/cycles/baking.html#bpy-types-bakesettings"),
("bpy.types.blendtexture*", "render/materials/legacy_textures/types/blend.html#bpy-types-blendtexture"), ("bpy.types.blendtexture*", "render/materials/legacy_textures/types/blend.html#bpy-types-blendtexture"),
("bpy.types.brush.height*", "sculpt_paint/sculpting/tools/layer.html#bpy-types-brush-height"), ("bpy.types.brush.height*", "sculpt_paint/sculpting/tools/layer.html#bpy-types-brush-height"),
("bpy.types.brush.jitter*", "sculpt_paint/brush/stroke.html#bpy-types-brush-jitter"),
("bpy.types.castmodifier*", "modeling/modifiers/deform/cast.html#bpy-types-castmodifier"), ("bpy.types.castmodifier*", "modeling/modifiers/deform/cast.html#bpy-types-castmodifier"),
("bpy.types.curve.offset*", "modeling/curves/properties/geometry.html#bpy-types-curve-offset"), ("bpy.types.curve.offset*", "modeling/curves/properties/geometry.html#bpy-types-curve-offset"),
("bpy.types.geometrynode*", "modeling/geometry_nodes/index.html#bpy-types-geometrynode"), ("bpy.types.geometrynode*", "modeling/geometry_nodes/index.html#bpy-types-geometrynode"),

View File

@ -29,11 +29,11 @@
icon_modifier="#84b8ffff" icon_modifier="#84b8ffff"
icon_shading="#ea7581ff" icon_shading="#ea7581ff"
icon_folder="#e3c16eff" icon_folder="#e3c16eff"
icon_border_intensity="0.85" icon_border_intensity="1"
> >
<wcol_regular> <wcol_regular>
<ThemeWidgetColors <ThemeWidgetColors
outline="#b8b8b8" outline="#4d4d4d"
inner="#dbdbdbff" inner="#dbdbdbff"
inner_sel="#668cccff" inner_sel="#668cccff"
item="#191919ff" item="#191919ff"
@ -48,7 +48,7 @@
</wcol_regular> </wcol_regular>
<wcol_tool> <wcol_tool>
<ThemeWidgetColors <ThemeWidgetColors
outline="#b8b8b8" outline="#4d4d4d"
inner="#dbdbdbff" inner="#dbdbdbff"
inner_sel="#5680c2ff" inner_sel="#5680c2ff"
item="#191919ff" item="#191919ff"
@ -63,7 +63,7 @@
</wcol_tool> </wcol_tool>
<wcol_toolbar_item> <wcol_toolbar_item>
<ThemeWidgetColors <ThemeWidgetColors
outline="#363636" outline="#4d4d4d"
inner="#434343ff" inner="#434343ff"
inner_sel="#5680c2ff" inner_sel="#5680c2ff"
item="#e6e6e6cc" item="#e6e6e6cc"
@ -78,7 +78,7 @@
</wcol_toolbar_item> </wcol_toolbar_item>
<wcol_radio> <wcol_radio>
<ThemeWidgetColors <ThemeWidgetColors
outline="#434343" outline="#4d4d4d"
inner="#3b3b3bff" inner="#3b3b3bff"
inner_sel="#5680c2e6" inner_sel="#5680c2e6"
item="#ffffffff" item="#ffffffff"
@ -93,7 +93,7 @@
</wcol_radio> </wcol_radio>
<wcol_text> <wcol_text>
<ThemeWidgetColors <ThemeWidgetColors
outline="#666666" outline="#4d4d4d"
inner="#282828ff" inner="#282828ff"
inner_sel="#333333ff" inner_sel="#333333ff"
item="#5680c2ff" item="#5680c2ff"
@ -108,7 +108,7 @@
</wcol_text> </wcol_text>
<wcol_option> <wcol_option>
<ThemeWidgetColors <ThemeWidgetColors
outline="#373737" outline="#4d4d4d"
inner="#3c3c3cff" inner="#3c3c3cff"
inner_sel="#5680c2ff" inner_sel="#5680c2ff"
item="#ffffffff" item="#ffffffff"
@ -123,8 +123,8 @@
</wcol_option> </wcol_option>
<wcol_toggle> <wcol_toggle>
<ThemeWidgetColors <ThemeWidgetColors
outline="#999999" outline="#4d4d4d"
inner="#c0c0c0ff" inner="#dbdbdbff"
inner_sel="#5680c2ff" inner_sel="#5680c2ff"
item="#191919ff" item="#191919ff"
text="#000000" text="#000000"
@ -138,7 +138,7 @@
</wcol_toggle> </wcol_toggle>
<wcol_num> <wcol_num>
<ThemeWidgetColors <ThemeWidgetColors
outline="#b8b8b8" outline="#4d4d4d"
inner="#d3d3d3ff" inner="#d3d3d3ff"
inner_sel="#5680c2ff" inner_sel="#5680c2ff"
item="#80b1ffff" item="#80b1ffff"
@ -153,7 +153,7 @@
</wcol_num> </wcol_num>
<wcol_numslider> <wcol_numslider>
<ThemeWidgetColors <ThemeWidgetColors
outline="#b8b8b8" outline="#4d4d4d"
inner="#999999ff" inner="#999999ff"
inner_sel="#999999ff" inner_sel="#999999ff"
item="#e6e6e6ff" item="#e6e6e6ff"
@ -168,8 +168,8 @@
</wcol_numslider> </wcol_numslider>
<wcol_box> <wcol_box>
<ThemeWidgetColors <ThemeWidgetColors
outline="#959595" outline="#4d4d4d"
inner="#cccccc80" inner="#80808080"
inner_sel="#5680c2ff" inner_sel="#5680c2ff"
item="#191919ff" item="#191919ff"
text="#333333" text="#333333"
@ -183,7 +183,7 @@
</wcol_box> </wcol_box>
<wcol_menu> <wcol_menu>
<ThemeWidgetColors <ThemeWidgetColors
outline="#3b3b3b" outline="#3d3d3d"
inner="#3b3b3bff" inner="#3b3b3bff"
inner_sel="#767676ff" inner_sel="#767676ff"
item="#808080ff" item="#808080ff"
@ -217,7 +217,7 @@
inner="#c0c0c0ff" inner="#c0c0c0ff"
inner_sel="#cdcdcdff" inner_sel="#cdcdcdff"
item="#727272ff" item="#727272ff"
text="#1a1a1a" text="#4d4d4d"
text_sel="#1a1a1a" text_sel="#1a1a1a"
show_shaded="FALSE" show_shaded="FALSE"
shadetop="25" shadetop="25"
@ -304,11 +304,11 @@
<wcol_list_item> <wcol_list_item>
<ThemeWidgetColors <ThemeWidgetColors
outline="#e6e6e6" outline="#e6e6e6"
inner="#00000000" inner="#1a1a1a00"
inner_sel="#808080ff" inner_sel="#c0c0c0ff"
item="#1a1a1aff" item="#1a1a1aff"
text="#1a1a1a" text="#1a1a1a"
text_sel="#ffffff" text_sel="#000000"
show_shaded="FALSE" show_shaded="FALSE"
shadetop="0" shadetop="0"
shadedown="0" shadedown="0"
@ -316,6 +316,21 @@
> >
</ThemeWidgetColors> </ThemeWidgetColors>
</wcol_list_item> </wcol_list_item>
<wcol_view_item>
<ThemeWidgetColors
outline="#e6e6e6"
inner="#c0c0c044"
inner_sel="#c0c0c0ff"
item="#1a1a1aff"
text="#1a1a1a"
text_sel="#000000"
show_shaded="FALSE"
shadetop="0"
shadedown="0"
roundness="0.4"
>
</ThemeWidgetColors>
</wcol_view_item>
<wcol_state> <wcol_state>
<ThemeWidgetStateColors <ThemeWidgetStateColors
inner_anim="#73be4c" inner_anim="#73be4c"
@ -334,8 +349,8 @@
</wcol_state> </wcol_state>
<wcol_tab> <wcol_tab>
<ThemeWidgetColors <ThemeWidgetColors
outline="#656565" outline="#333333"
inner="#818181ff" inner="#808080cc"
inner_sel="#b3b3b3ff" inner_sel="#b3b3b3ff"
item="#28292dff" item="#28292dff"
text="#1a1a1a" text="#1a1a1a"
@ -414,6 +429,7 @@
bone_locked_weight="#ff000080" bone_locked_weight="#ff000080"
bundle_solid="#c8c8c8" bundle_solid="#c8c8c8"
camera_path="#000000" camera_path="#000000"
camera_passepartout="#000000"
skin_root="#b44d4d" skin_root="#b44d4d"
view_overlay="#000000" view_overlay="#000000"
transform="#ffffff" transform="#ffffff"
@ -452,9 +468,9 @@
</gradients> </gradients>
<panelcolors> <panelcolors>
<ThemePanelColors <ThemePanelColors
header="#b3b3b3ff" header="#ccccccff"
back="#b3b3b3cc" back="#ccccccff"
sub_back="#00000024" sub_back="#0000000f"
> >
</ThemePanelColors> </ThemePanelColors>
</panelcolors> </panelcolors>
@ -519,9 +535,9 @@
> >
<panelcolors> <panelcolors>
<ThemePanelColors <ThemePanelColors
header="#42424200" header="#ccccccff"
back="#00000028" back="#ccccccff"
sub_back="#00000024" sub_back="#0000000f"
> >
</ThemePanelColors> </ThemePanelColors>
</panelcolors> </panelcolors>
@ -552,7 +568,7 @@
header="#adadadff" header="#adadadff"
header_text="#000000" header_text="#000000"
header_text_hi="#ffffff" header_text_hi="#ffffff"
button="#999999e6" button="#b3b3b3ff"
button_title="#1a1a1a" button_title="#1a1a1a"
button_text="#000000" button_text="#000000"
button_text_hi="#000000" button_text_hi="#000000"
@ -565,9 +581,9 @@
> >
<panelcolors> <panelcolors>
<ThemePanelColors <ThemePanelColors
header="#42424200" header="#ccccccff"
back="#00000028" back="#ccccccff"
sub_back="#00000024" sub_back="#0000000f"
> >
</ThemePanelColors> </ThemePanelColors>
</panelcolors> </panelcolors>
@ -623,9 +639,9 @@
> >
<panelcolors> <panelcolors>
<ThemePanelColors <ThemePanelColors
header="#42424200" header="#ccccccff"
back="#00000028" back="#ccccccff"
sub_back="#00000024" sub_back="#0000000f"
> >
</ThemePanelColors> </ThemePanelColors>
</panelcolors> </panelcolors>
@ -698,9 +714,9 @@
> >
<panelcolors> <panelcolors>
<ThemePanelColors <ThemePanelColors
header="#42424200" header="#ccccccff"
back="#00000028" back="#ccccccff"
sub_back="#00000024" sub_back="#0000000f"
> >
</ThemePanelColors> </ThemePanelColors>
</panelcolors> </panelcolors>
@ -783,9 +799,9 @@
> >
<panelcolors> <panelcolors>
<ThemePanelColors <ThemePanelColors
header="#b3b3b3ff" header="#ccccccff"
back="#b3b3b3cc" back="#ccccccff"
sub_back="#00000024" sub_back="#0000000f"
> >
</ThemePanelColors> </ThemePanelColors>
</panelcolors> </panelcolors>
@ -843,14 +859,23 @@
> >
<panelcolors> <panelcolors>
<ThemePanelColors <ThemePanelColors
header="#b3b3b3ff" header="#ccccccff"
back="#b3b3b3cc" back="#ccccccff"
sub_back="#00000024" sub_back="#0000000f"
> >
</ThemePanelColors> </ThemePanelColors>
</panelcolors> </panelcolors>
</ThemeSpaceGeneric> </ThemeSpaceGeneric>
</space> </space>
<space_list>
<ThemeSpaceListGeneric
list="#181818"
list_title="#ffffff"
list_text="#ffffff"
list_text_hi="#ffffff"
>
</ThemeSpaceListGeneric>
</space_list>
</ThemeSequenceEditor> </ThemeSequenceEditor>
</sequence_editor> </sequence_editor>
<properties> <properties>
@ -871,7 +896,7 @@
button_title="#000000" button_title="#000000"
button_text="#000000" button_text="#000000"
button_text_hi="#000000" button_text_hi="#000000"
navigation_bar="#656565ff" navigation_bar="#1d1d1dff"
execution_buts="#00000000" execution_buts="#00000000"
tab_active="#6697e6" tab_active="#6697e6"
tab_inactive="#535353" tab_inactive="#535353"
@ -880,9 +905,9 @@
> >
<panelcolors> <panelcolors>
<ThemePanelColors <ThemePanelColors
header="#b3b3b300" header="#ccccccff"
back="#a3a3a3cc" back="#ccccccff"
sub_back="#00000024" sub_back="#0000000f"
> >
</ThemePanelColors> </ThemePanelColors>
</panelcolors> </panelcolors>
@ -927,9 +952,9 @@
> >
<panelcolors> <panelcolors>
<ThemePanelColors <ThemePanelColors
header="#42424200" header="#ccccccff"
back="#00000028" back="#ccccccff"
sub_back="#00000024" sub_back="#0000000f"
> >
</ThemePanelColors> </ThemePanelColors>
</panelcolors> </panelcolors>
@ -939,44 +964,44 @@
</text_editor> </text_editor>
<node_editor> <node_editor>
<ThemeNodeEditor <ThemeNodeEditor
grid="#1B1B1B" grid="#282828"
node_selected="#f15800" node_selected="#ed5700"
node_active="#f15800" node_active="#ffffff"
wire="#191919" wire="#1a1a1aff"
wire_inner="#999999" wire_inner="#8d8d8d"
wire_select="#ffa733" wire_select="#ffffffb3"
selected_text="#7f7070" selected_text="#7f7f7f"
node_backdrop="#e6e6e6ff" node_backdrop="#666666ff"
converter_node="#66c4ff" converter_node="#12adff"
color_node="#ffcb4d" color_node="#cccc00"
group_node="#59b36ab9" group_node="#3b660a"
group_socket_node="#dfc300" group_socket_node="#000000"
frame_node="#9b9b9b60" frame_node="#0f0f0fcc"
matte_node="#977474" matte_node="#973c3c"
distor_node="#749797" distor_node="#4c9797"
noodle_curving="4" noodle_curving="4"
grid_levels="3" grid_levels="3"
dash_alpha="0.5" dash_alpha="0.5"
input_node="#cb3d4a" input_node="#ff3371"
output_node="#cb3d4a" output_node="#4d0017"
filter_node="#6c696f" filter_node="#551a80"
vector_node="#9999ff" vector_node="#4d4dff"
texture_node="#ffc399" texture_node="#e66800"
shader_node="#ea7581" shader_node="#24b524"
script_node="#6c696f" script_node="#084d4d"
pattern_node="#6c696f" pattern_node="#6c696f"
layout_node="#6c696f" layout_node="#6c696f"
geometry_node="#00d7a4" geometry_node="#00d6a3"
attribute_node="#3f5980" attribute_node="#001566"
> >
<space> <space>
<ThemeSpaceGeneric <ThemeSpaceGeneric
back="#353535" back="#1d1d1d"
title="#000000" title="#eeeeee"
text="#000000" text="#e6e6e6"
text_hi="#ffffff" text_hi="#ffffff"
header="#b3b3b3ff" header="#b3b3b3ff"
header_text="#000000" header_text="#eeeeee"
header_text_hi="#ffffff" header_text_hi="#ffffff"
button="#99999900" button="#99999900"
button_title="#1a1a1a" button_title="#1a1a1a"
@ -991,9 +1016,9 @@
> >
<panelcolors> <panelcolors>
<ThemePanelColors <ThemePanelColors
header="#b3b3b3ff" header="#ccccccff"
back="#b3b3b3cc" back="#ccccccff"
sub_back="#00000024" sub_back="#0000000f"
> >
</ThemePanelColors> </ThemePanelColors>
</panelcolors> </panelcolors>
@ -1013,8 +1038,8 @@
<outliner> <outliner>
<ThemeOutliner <ThemeOutliner
match="#337f33" match="#337f33"
selected_highlight="#7a8e99" selected_highlight="#7a8499"
active="#92aab7" active="#929eb7"
selected_object="#ffddb3" selected_object="#ffddb3"
active_object="#ffffff" active_object="#ffffff"
edited_object="#0080624d" edited_object="#0080624d"
@ -1042,9 +1067,9 @@
> >
<panelcolors> <panelcolors>
<ThemePanelColors <ThemePanelColors
header="#42424200" header="#ccccccff"
back="#00000028" back="#ccccccff"
sub_back="#00000024" sub_back="#0000000f"
> >
</ThemePanelColors> </ThemePanelColors>
</panelcolors> </panelcolors>
@ -1091,9 +1116,9 @@
> >
<panelcolors> <panelcolors>
<ThemePanelColors <ThemePanelColors
header="#42424200" header="#ccccccff"
back="#00000028" back="#ccccccff"
sub_back="#00000024" sub_back="#0000000f"
> >
</ThemePanelColors> </ThemePanelColors>
</panelcolors> </panelcolors>
@ -1125,9 +1150,9 @@
> >
<panelcolors> <panelcolors>
<ThemePanelColors <ThemePanelColors
header="#b3b3b300" header="#ccccccff"
back="#a3a3a3cc" back="#ccccccff"
sub_back="#00000024" sub_back="#0000000f"
> >
</ThemePanelColors> </ThemePanelColors>
</panelcolors> </panelcolors>
@ -1137,26 +1162,26 @@
</preferences> </preferences>
<console> <console>
<ThemeConsole <ThemeConsole
line_output="#6080ff" line_output="#71a8ff"
line_input="#ffffff" line_input="#f2f2f2"
line_info="#00aa00" line_info="#95d600"
line_error="#dc6060" line_error="#ff4d84"
cursor="#dc6060" cursor="#ff0000"
select="#ffffff30" select="#ffffff30"
> >
<space> <space>
<ThemeSpaceGeneric <ThemeSpaceGeneric
back="#000000" back="#1d1d1d"
title="#000000" title="#eeeeee"
text="#000000" text="#e6e6e6"
text_hi="#ffffff" text_hi="#ffffff"
header="#b3b3b3ff" header="#b3b3b3ff"
header_text="#000000" header_text="#000000"
header_text_hi="#ffffff" header_text_hi="#ffffff"
button="#7272727f" button="#30303000"
button_title="#000000" button_title="#ffffff"
button_text="#000000" button_text="#cccccc"
button_text_hi="#000000" button_text_hi="#ffffff"
navigation_bar="#00000000" navigation_bar="#00000000"
execution_buts="#00000000" execution_buts="#00000000"
tab_active="#6697e6" tab_active="#6697e6"
@ -1166,9 +1191,9 @@
> >
<panelcolors> <panelcolors>
<ThemePanelColors <ThemePanelColors
header="#42424200" header="#ccccccff"
back="#00000028" back="#ccccccff"
sub_back="#00000024" sub_back="#0000000f"
> >
</ThemePanelColors> </ThemePanelColors>
</panelcolors> </panelcolors>
@ -1231,9 +1256,9 @@
> >
<panelcolors> <panelcolors>
<ThemePanelColors <ThemePanelColors
header="#42424200" header="#ccccccff"
back="#00000028" back="#ccccccff"
sub_back="#00000024" sub_back="#0000000f"
> >
</ThemePanelColors> </ThemePanelColors>
</panelcolors> </panelcolors>
@ -1274,9 +1299,9 @@
> >
<panelcolors> <panelcolors>
<ThemePanelColors <ThemePanelColors
header="#42424200" header="#ccccccff"
back="#00000028" back="#ccccccff"
sub_back="#00000024" sub_back="#0000000f"
> >
</ThemePanelColors> </ThemePanelColors>
</panelcolors> </panelcolors>
@ -1292,7 +1317,7 @@
title="#ffffff" title="#ffffff"
text="#ffffff" text="#ffffff"
text_hi="#ffffff" text_hi="#ffffff"
header="#adadadff" header="#999999ff"
header_text="#1a1a1a" header_text="#1a1a1a"
header_text_hi="#ffffff" header_text_hi="#ffffff"
button="#2f303500" button="#2f303500"
@ -1308,9 +1333,9 @@
> >
<panelcolors> <panelcolors>
<ThemePanelColors <ThemePanelColors
header="#42424200" header="#ccccccff"
back="#00000028" back="#ccccccff"
sub_back="#00000024" sub_back="#0000000f"
> >
</ThemePanelColors> </ThemePanelColors>
</panelcolors> </panelcolors>
@ -1331,7 +1356,7 @@
header="#adadadff" header="#adadadff"
header_text="#000000" header_text="#000000"
header_text_hi="#ffffff" header_text_hi="#ffffff"
button="#999999e6" button="#b3b3b3ff"
button_title="#1a1a1a" button_title="#1a1a1a"
button_text="#000000" button_text="#000000"
button_text_hi="#000000" button_text_hi="#000000"
@ -1344,9 +1369,9 @@
> >
<panelcolors> <panelcolors>
<ThemePanelColors <ThemePanelColors
header="#42424200" header="#ccccccff"
back="#00000028" back="#ccccccff"
sub_back="#00000024" sub_back="#0000000f"
> >
</ThemePanelColors> </ThemePanelColors>
</panelcolors> </panelcolors>
@ -1585,8 +1610,8 @@
shadow="3" shadow="3"
shadow_offset_x="0" shadow_offset_x="0"
shadow_offset_y="-1" shadow_offset_y="-1"
shadow_alpha="0.3" shadow_alpha="1"
shadow_value="0.7" shadow_value="0.8"
> >
</ThemeFontStyle> </ThemeFontStyle>
</panel_title> </panel_title>
@ -1596,8 +1621,8 @@
shadow="3" shadow="3"
shadow_offset_x="0" shadow_offset_x="0"
shadow_offset_y="-1" shadow_offset_y="-1"
shadow_alpha="0.3" shadow_alpha="0"
shadow_value="0.7" shadow_value="0.8"
> >
</ThemeFontStyle> </ThemeFontStyle>
</widget_label> </widget_label>
@ -1607,8 +1632,8 @@
shadow="1" shadow="1"
shadow_offset_x="0" shadow_offset_x="0"
shadow_offset_y="-1" shadow_offset_y="-1"
shadow_alpha="0.3" shadow_alpha="0"
shadow_value="0.7" shadow_value="0.8"
> >
</ThemeFontStyle> </ThemeFontStyle>
</widget> </widget>

View File

@ -86,7 +86,7 @@ class Prefs(bpy.types.KeyConfigPreferences):
update=update_fn, update=update_fn,
) )
# Experimental: only show with developer extras, see: T96544. # Experimental: only show with developer extras, see: #96544.
use_tweak_select_passthrough: BoolProperty( use_tweak_select_passthrough: BoolProperty(
name="Tweak Select: Mouse Select & Move", name="Tweak Select: Mouse Select & Move",
description=( description=(
@ -96,7 +96,7 @@ class Prefs(bpy.types.KeyConfigPreferences):
default=False, default=False,
update=update_fn, update=update_fn,
) )
# Experimental: only show with developer extras, see: T96544. # Experimental: only show with developer extras, see: #96544.
use_tweak_tool_lmb_interaction: BoolProperty( use_tweak_tool_lmb_interaction: BoolProperty(
name="Tweak Tool: Left Mouse Select & Move", name="Tweak Tool: Left Mouse Select & Move",
description=( description=(

View File

@ -37,7 +37,7 @@ class Params:
# instead be bound to a binding that doesn't de-select all, this way: # instead be bound to a binding that doesn't de-select all, this way:
# - Click-drag moves the current selection. # - Click-drag moves the current selection.
# - Click selects only the item at the cursor position. # - Click selects only the item at the cursor position.
# See: T97032. # See: #97032.
"use_tweak_select_passthrough", "use_tweak_select_passthrough",
"use_tweak_tool_lmb_interaction", "use_tweak_tool_lmb_interaction",
"use_mouse_emulate_3_button", "use_mouse_emulate_3_button",
@ -465,7 +465,7 @@ def _template_items_tool_select(
fallback=False, fallback=False,
): ):
if not params.legacy and not fallback: if not params.legacy and not fallback:
# Experimental support for LMB interaction for the tweak tool. see: T96544. # Experimental support for LMB interaction for the tweak tool. see: #96544.
# NOTE: For RMB-select this is a much bigger change as it disables 3D cursor placement on LMB. # NOTE: For RMB-select this is a much bigger change as it disables 3D cursor placement on LMB.
# For LMB-select this means an LMB -drag will not first de-select all (similar to node/graph editor). # For LMB-select this means an LMB -drag will not first de-select all (similar to node/graph editor).
select_passthrough = False select_passthrough = False
@ -498,7 +498,7 @@ def _template_items_tool_select(
{"properties": [("toggle", True), *operator_props]}), {"properties": [("toggle", True), *operator_props]}),
# Fallback key-map must transform as the primary tool is expected # Fallback key-map must transform as the primary tool is expected
# to be accessed via gizmos in this case. See: T96885. # to be accessed via gizmos in this case. See: #96885.
*(() if not fallback else ( *(() if not fallback else (
("transform.translate", {"type": 'LEFTMOUSE', "value": 'CLICK_DRAG'}, ("transform.translate", {"type": 'LEFTMOUSE', "value": 'CLICK_DRAG'},
{"properties": [("release_confirm", True)]}), {"properties": [("release_confirm", True)]}),
@ -4730,7 +4730,7 @@ def _template_paint_radial_control(paint, rotation=False, secondary_rotation=Fal
def _template_view3d_select(*, type, value, legacy, select_passthrough, exclude_mod=None): def _template_view3d_select(*, type, value, legacy, select_passthrough, exclude_mod=None):
# NOTE: `exclude_mod` is needed since we don't want this tool to exclude Control-RMB actions when this is used # NOTE: `exclude_mod` is needed since we don't want this tool to exclude Control-RMB actions when this is used
# as a tool key-map with RMB-select and `use_fallback_tool` is enabled with RMB select. See T92467. # as a tool key-map with RMB-select and `use_fallback_tool` is enabled with RMB select. See #92467.
props_vert_without_handles = () props_vert_without_handles = ()
if select_passthrough: if select_passthrough:
@ -5629,6 +5629,10 @@ def km_curves(params):
("curves.disable_selection", {"type": 'TWO', "value": 'PRESS', "alt": True}, None), ("curves.disable_selection", {"type": 'TWO', "value": 'PRESS', "alt": True}, None),
*_template_items_select_actions(params, "curves.select_all"), *_template_items_select_actions(params, "curves.select_all"),
("curves.select_linked", {"type": 'L', "value": 'PRESS', "ctrl": True}, None), ("curves.select_linked", {"type": 'L', "value": 'PRESS', "ctrl": True}, None),
("curves.delete", {"type": 'X', "value": 'PRESS'}, None),
("curves.delete", {"type": 'DEL', "value": 'PRESS'}, None),
("curves.select_more", {"type": 'NUMPAD_PLUS', "value": 'PRESS', "ctrl": True, "repeat": True}, None),
("curves.select_less", {"type": 'NUMPAD_MINUS', "value": 'PRESS', "ctrl": True, "repeat": True}, None),
]) ])
return keymap return keymap
@ -5683,7 +5687,7 @@ def km_object_non_modal(params):
]) ])
else: else:
items.extend([ items.extend([
# NOTE: this shortcut (while not temporary) is not ideal, see: T89757. # NOTE: this shortcut (while not temporary) is not ideal, see: #89757.
("object.transfer_mode", {"type": 'Q', "value": 'PRESS', "alt": True}, None), ("object.transfer_mode", {"type": 'Q', "value": 'PRESS', "alt": True}, None),
]) ])
@ -6345,9 +6349,8 @@ def km_node_link_modal_map(_params):
return keymap return keymap
# Fallback for gizmos that don't have custom a custom key-map. # Fallback for gizmos that don't have custom a custom key-map.
def km_generic_gizmo(_params): def km_generic_gizmo(_params):
keymap = ( keymap = (
"Generic Gizmo", "Generic Gizmo",

View File

@ -6,8 +6,8 @@ from bpy.types import Operator
from bpy.app.translations import pgettext_data as data_ from bpy.app.translations import pgettext_data as data_
def geometry_node_group_empty_new(): def build_default_empty_geometry_node_group(name):
group = bpy.data.node_groups.new(data_("Geometry Nodes"), 'GeometryNodeTree') group = bpy.data.node_groups.new(name, 'GeometryNodeTree')
group.inputs.new('NodeSocketGeometry', data_("Geometry")) group.inputs.new('NodeSocketGeometry', data_("Geometry"))
group.outputs.new('NodeSocketGeometry', data_("Geometry")) group.outputs.new('NodeSocketGeometry', data_("Geometry"))
input_node = group.nodes.new('NodeGroupInput') input_node = group.nodes.new('NodeGroupInput')
@ -20,8 +20,12 @@ def geometry_node_group_empty_new():
input_node.location.x = -200 - input_node.width input_node.location.x = -200 - input_node.width
output_node.location.x = 200 output_node.location.x = 200
group.links.new(output_node.inputs[0], input_node.outputs[0]) return group
def geometry_node_group_empty_new():
group = build_default_empty_geometry_node_group(data_("Geometry Nodes"))
group.links.new(group.nodes["Group Input"].outputs[0], group.nodes["Group Output"].inputs[0])
return group return group
@ -35,6 +39,158 @@ def geometry_modifier_poll(context):
return True return True
def get_context_modifier(context):
if context.area.type == 'PROPERTIES':
modifier = context.modifier
else:
modifier = context.object.modifiers.active
if modifier is None or modifier.type != 'NODES':
return None
return modifier
def edit_geometry_nodes_modifier_poll(context):
return get_context_modifier(context) is not None
def socket_idname_to_attribute_type(idname):
if idname.startswith("NodeSocketInt"):
return "INT"
elif idname.startswith("NodeSocketColor"):
return "FLOAT_COLOR"
elif idname.startswith("NodeSocketVector"):
return "FLOAT_VECTOR"
elif idname.startswith("NodeSocketBool"):
return "BOOLEAN"
elif idname.startswith("NodeSocketFloat"):
return "FLOAT"
raise ValueError("Unsupported socket type")
return ""
def modifier_attribute_name_get(modifier, identifier):
try:
return modifier[identifier + "_attribute_name"]
except KeyError:
return None
def modifier_input_use_attribute(modifier, identifier):
try:
return modifier[identifier + "_use_attribute"] != 0
except KeyError:
return False
def get_socket_with_identifier(sockets, identifier):
for socket in sockets:
if socket.identifier == identifier:
return socket
return None
def get_enabled_socket_with_name(sockets, name):
for socket in sockets:
if socket.name == name and socket.enabled:
return socket
return None
class MoveModifierToNodes(Operator):
"""Move inputs and outputs from in the modifier to a new node group"""
bl_idname = "object.geometry_nodes_move_to_nodes"
bl_label = "Move to Nodes"
bl_options = {'REGISTER', 'UNDO'}
@classmethod
def poll(cls, context):
return edit_geometry_nodes_modifier_poll(context)
def execute(self, context):
modifier = get_context_modifier(context)
if not modifier:
return {'CANCELLED'}
old_group = modifier.node_group
if not old_group:
return {'CANCELLED'}
wrapper_name = old_group.name + ".wrapper"
group = build_default_empty_geometry_node_group(wrapper_name)
group_node = group.nodes.new("GeometryNodeGroup")
group_node.node_tree = old_group
group_node.update()
group_input_node = group.nodes["Group Input"]
group_output_node = group.nodes["Group Output"]
# Copy default values for inputs and create named attribute input nodes.
input_nodes = []
first_geometry_input = None
for input_socket in old_group.inputs:
identifier = input_socket.identifier
group_node_input = get_socket_with_identifier(group_node.inputs, identifier)
if modifier_input_use_attribute(modifier, identifier):
input_node = group.nodes.new("GeometryNodeInputNamedAttribute")
input_nodes.append(input_node)
input_node.data_type = socket_idname_to_attribute_type(input_socket.bl_socket_idname)
attribute_name = modifier_attribute_name_get(modifier, identifier)
input_node.inputs["Name"].default_value = attribute_name
output_socket = get_enabled_socket_with_name(input_node.outputs, "Attribute")
group.links.new(output_socket, group_node_input)
elif hasattr(input_socket, "default_value"):
group_node_input.default_value = modifier[identifier]
elif input_socket.bl_socket_idname == 'NodeSocketGeometry':
if not first_geometry_input:
first_geometry_input = group_node_input
group.links.new(group_input_node.outputs[0], first_geometry_input)
# Adjust locations of named attribute input nodes and group input node to make some space.
if input_nodes:
for i, node in enumerate(input_nodes):
node.location.x = -175
node.location.y = i * -50
group_input_node.location.x = -350
# Connect outputs to store named attribute nodes to replace modifier attribute outputs.
store_nodes = []
first_geometry_output = None
for output_socket in old_group.outputs:
identifier = output_socket.identifier
group_node_output = get_socket_with_identifier(group_node.outputs, identifier)
attribute_name = modifier_attribute_name_get(modifier, identifier)
if attribute_name:
store_node = group.nodes.new("GeometryNodeStoreNamedAttribute")
store_nodes.append(store_node)
store_node.data_type = socket_idname_to_attribute_type(output_socket.bl_socket_idname)
store_node.domain = output_socket.attribute_domain
store_node.inputs["Name"].default_value = attribute_name
input_socket = get_enabled_socket_with_name(store_node.inputs, "Value")
group.links.new(group_node_output, input_socket)
elif output_socket.bl_socket_idname == 'NodeSocketGeometry':
if not first_geometry_output:
first_geometry_output = group_node_output
# Adjust locations of store named attribute nodes and move group output.
if store_nodes:
for i, node in enumerate(store_nodes):
node.location.x = (i + 1) * 175
node.location.y = 0
group_output_node.location.x = (len(store_nodes) + 1) * 175
group.links.new(first_geometry_output, store_nodes[0].inputs["Geometry"])
for i in range(len(store_nodes) - 1):
group.links.new(store_nodes[i].outputs["Geometry"], store_nodes[i + 1].inputs["Geometry"])
group.links.new(store_nodes[-1].outputs["Geometry"], group_output_node.inputs["Geometry"])
else:
group.links.new(first_geometry_output, group_output_node.inputs["Geometry"])
modifier.node_group = group
return {'FINISHED'}
class NewGeometryNodesModifier(Operator): class NewGeometryNodesModifier(Operator):
"""Create a new modifier with a new geometry node group""" """Create a new modifier with a new geometry node group"""
@ -48,7 +204,6 @@ class NewGeometryNodesModifier(Operator):
def execute(self, context): def execute(self, context):
modifier = context.object.modifiers.new(data_("GeometryNodes"), "NODES") modifier = context.object.modifiers.new(data_("GeometryNodes"), "NODES")
if not modifier: if not modifier:
return {'CANCELLED'} return {'CANCELLED'}
@ -70,11 +225,7 @@ class NewGeometryNodeTreeAssign(Operator):
return geometry_modifier_poll(context) return geometry_modifier_poll(context)
def execute(self, context): def execute(self, context):
if context.area.type == 'PROPERTIES': modifier = get_context_modifier(context)
modifier = context.modifier
else:
modifier = context.object.modifiers.active
if not modifier: if not modifier:
return {'CANCELLED'} return {'CANCELLED'}
@ -87,4 +238,5 @@ class NewGeometryNodeTreeAssign(Operator):
classes = ( classes = (
NewGeometryNodesModifier, NewGeometryNodesModifier,
NewGeometryNodeTreeAssign, NewGeometryNodeTreeAssign,
MoveModifierToNodes,
) )

View File

@ -790,7 +790,7 @@ class TransformsToDeltasAnim(Operator):
continue continue
# first pass over F-Curves: ensure that we don't have conflicting # first pass over F-Curves: ensure that we don't have conflicting
# transforms already (e.g. if this was applied already) T29110. # transforms already (e.g. if this was applied already) #29110.
existingFCurves = {} existingFCurves = {}
for fcu in adt.action.fcurves: for fcu in adt.action.fcurves:
# get "delta" path - i.e. the final paths which may clash # get "delta" path - i.e. the final paths which may clash

View File

@ -36,67 +36,136 @@ class ObjectModeOperator:
class QuickFur(ObjectModeOperator, Operator): class QuickFur(ObjectModeOperator, Operator):
"""Add fur setup to the selected objects""" """Add a fur setup to the selected objects"""
bl_idname = "object.quick_fur" bl_idname = "object.quick_fur"
bl_label = "Quick Fur" bl_label = "Quick Fur"
bl_options = {'REGISTER', 'UNDO'} bl_options = {'REGISTER', 'UNDO'}
density: EnumProperty( density: EnumProperty(
name="Fur Density", name="Density",
items=( items=(
('LIGHT', "Light", ""), ('LOW', "Low", ""),
('MEDIUM', "Medium", ""), ('MEDIUM', "Medium", ""),
('HEAVY', "Heavy", ""), ('HIGH', "High", ""),
), ),
default='MEDIUM', default='MEDIUM',
) )
view_percentage: IntProperty(
name="View %",
min=1, max=100,
soft_min=1, soft_max=100,
default=10,
)
length: FloatProperty( length: FloatProperty(
name="Length", name="Length",
min=0.001, max=100, min=0.001, max=100,
soft_min=0.01, soft_max=10, soft_min=0.01, soft_max=10,
default=0.1, default=0.1,
subtype='DISTANCE'
)
radius: FloatProperty(
name="Hair Radius",
min=0.0, max=10,
soft_min=0.0001, soft_max=0.1,
default=0.001,
subtype='DISTANCE'
)
view_percentage: FloatProperty(
name="View Percentage",
min=0.0, max=1.0,
default=1.0,
subtype='FACTOR'
)
apply_hair_guides: BoolProperty(
name="Apply Hair Guides",
default=True,
)
use_noise: BoolProperty(
name="Noise",
default=True,
)
use_frizz: BoolProperty(
name="Frizz",
default=True,
) )
def execute(self, context): def execute(self, context):
fake_context = context.copy() import os
mesh_objects = [obj for obj in context.selected_objects mesh_objects = [obj for obj in context.selected_objects if obj.type == 'MESH']
if obj.type == 'MESH']
if not mesh_objects: if not mesh_objects:
self.report({'ERROR'}, "Select at least one mesh object") self.report({'ERROR'}, "Select at least one mesh object")
return {'CANCELLED'} return {'CANCELLED'}
mat = bpy.data.materials.new("Fur Material") if self.density == 'LOW':
count = 1000
for obj in mesh_objects:
fake_context["object"] = obj
bpy.ops.object.particle_system_add(fake_context)
psys = obj.particle_systems[-1]
psys.settings.type = 'HAIR'
if self.density == 'LIGHT':
psys.settings.count = 100
elif self.density == 'MEDIUM': elif self.density == 'MEDIUM':
psys.settings.count = 1000 count = 10000
elif self.density == 'HEAVY': elif self.density == 'HIGH':
psys.settings.count = 10000 count = 100000
psys.settings.child_nbr = self.view_percentage node_groups_to_append = {"Generate Hair Curves", "Set Hair Curve Profile", "Interpolate Hair Curves"}
psys.settings.hair_length = self.length if self.use_noise:
psys.settings.use_strand_primitive = True node_groups_to_append.add("Hair Curves Noise")
psys.settings.use_hair_bspline = True if self.use_frizz:
psys.settings.child_type = 'INTERPOLATED' node_groups_to_append.add("Frizz Hair Curves")
psys.settings.tip_radius = 0.25 assets_directory = os.path.join(bpy.utils.system_resource('DATAFILES'),
"assets",
"geometry_nodes",
"procedural_hair_node_assets.blend",
"NodeTree")
for name in node_groups_to_append:
bpy.ops.wm.append(directory=assets_directory,
filename=name,
use_recursive=True,
clear_asset_data=True,
do_reuse_local_id=True)
generate_group = bpy.data.node_groups["Generate Hair Curves"]
interpolate_group = bpy.data.node_groups["Interpolate Hair Curves"]
radius_group = bpy.data.node_groups["Set Hair Curve Profile"]
noise_group = bpy.data.node_groups["Hair Curves Noise"] if self.use_noise else None
frizz_group = bpy.data.node_groups["Frizz Hair Curves"] if self.use_frizz else None
obj.data.materials.append(mat) material = bpy.data.materials.new("Fur Material")
psys.settings.material = len(obj.data.materials)
for mesh_object in mesh_objects:
mesh = mesh_object.data
with context.temp_override(active_object=mesh_object):
bpy.ops.object.curves_empty_hair_add()
curves_object = context.active_object
curves = curves_object.data
curves.materials.append(material)
area = 0.0
for poly in mesh.polygons:
area += poly.area
density = count / area
generate_modifier = curves_object.modifiers.new(name="Generate", type='NODES')
generate_modifier.node_group = generate_group
generate_modifier["Input_2"] = mesh_object
generate_modifier["Input_18_attribute_name"] = curves.surface_uv_map
generate_modifier["Input_20"] = self.length
generate_modifier["Input_22"] = material
generate_modifier["Input_15"] = density * 0.01
curves_object.modifiers.move(1, 0)
radius_modifier = curves_object.modifiers.new(name="Set Hair Curve Profile", type='NODES')
radius_modifier.node_group = radius_group
radius_modifier["Input_3"] = self.radius
interpolate_modifier = curves_object.modifiers.new(name="Interpolate Hair Curves", type='NODES')
interpolate_modifier.node_group = interpolate_group
interpolate_modifier["Input_2"] = mesh_object
interpolate_modifier["Input_18_attribute_name"] = curves.surface_uv_map
interpolate_modifier["Input_15"] = density
interpolate_modifier["Input_17"] = self.view_percentage
interpolate_modifier["Input_24"] = True
if noise_group:
noise_modifier = curves_object.modifiers.new(name="Hair Curves Noise", type='NODES')
noise_modifier.node_group = noise_group
if frizz_group:
frizz_modifier = curves_object.modifiers.new(name="Frizz Hair Curves", type='NODES')
frizz_modifier.node_group = frizz_group
if self.apply_hair_guides:
with context.temp_override(object=curves_object):
bpy.ops.object.modifier_apply(modifier=generate_modifier.name)
return {'FINISHED'} return {'FINISHED'}

View File

@ -700,7 +700,7 @@ class PREFERENCES_OT_addon_install(Operator):
addons_new.discard("modules") addons_new.discard("modules")
# disable any addons we may have enabled previously and removed. # disable any addons we may have enabled previously and removed.
# this is unlikely but do just in case. bug T23978. # this is unlikely but do just in case. bug #23978.
for new_addon in addons_new: for new_addon in addons_new:
addon_utils.disable(new_addon, default_set=True) addon_utils.disable(new_addon, default_set=True)

View File

@ -581,7 +581,7 @@ class LightMapPack(Operator):
# Proper solution would be to make undo stack aware of such things, # Proper solution would be to make undo stack aware of such things,
# but for now just disable redo. Keep undo here so unwanted changes to uv # but for now just disable redo. Keep undo here so unwanted changes to uv
# coords might be undone. # coords might be undone.
# This fixes infinite image creation reported there T30968 (sergey) # This fixes infinite image creation reported there #30968 (sergey)
bl_options = {'UNDO'} bl_options = {'UNDO'}
PREF_CONTEXT: bpy.props.EnumProperty( PREF_CONTEXT: bpy.props.EnumProperty(

View File

@ -90,7 +90,7 @@ def applyVertexDirt(me, blur_iterations, blur_strength, clamp_dirt, clamp_clean,
tone_range = max_tone - min_tone tone_range = max_tone - min_tone
if tone_range < 0.0001: if tone_range < 0.0001:
# weak, don't cancel, see T43345 # weak, don't cancel, see #43345
tone_range = 0.0 tone_range = 0.0
else: else:
tone_range = 1.0 / tone_range tone_range = 1.0 / tone_range

View File

@ -42,7 +42,7 @@ class VIEW3D_OT_edit_mesh_extrude_individual_move(Operator):
bpy.ops.mesh.extrude_vertices_move('INVOKE_REGION_WIN') bpy.ops.mesh.extrude_vertices_move('INVOKE_REGION_WIN')
# ignore return from operators above because they are 'RUNNING_MODAL', # ignore return from operators above because they are 'RUNNING_MODAL',
# and cause this one not to be freed. T24671. # and cause this one not to be freed. #24671.
return {'FINISHED'} return {'FINISHED'}
def invoke(self, context, _event): def invoke(self, context, _event):
@ -104,7 +104,7 @@ class VIEW3D_OT_edit_mesh_extrude_move(Operator):
'INVOKE_REGION_WIN', 'INVOKE_REGION_WIN',
TRANSFORM_OT_translate={ TRANSFORM_OT_translate={
# Don't set the constraint axis since users will expect MMB # Don't set the constraint axis since users will expect MMB
# to use the user setting, see: T61637 # to use the user setting, see: #61637
# "orient_type": 'NORMAL', # "orient_type": 'NORMAL',
# Not a popular choice, too restrictive for retopo. # Not a popular choice, too restrictive for retopo.
# "constraint_axis": (True, True, False)}) # "constraint_axis": (True, True, False)})
@ -114,7 +114,7 @@ class VIEW3D_OT_edit_mesh_extrude_move(Operator):
bpy.ops.mesh.extrude_region_move('INVOKE_REGION_WIN') bpy.ops.mesh.extrude_region_move('INVOKE_REGION_WIN')
# ignore return from operators above because they are 'RUNNING_MODAL', # ignore return from operators above because they are 'RUNNING_MODAL',
# and cause this one not to be freed. T24671. # and cause this one not to be freed. #24671.
return {'FINISHED'} return {'FINISHED'}
def execute(self, context): def execute(self, context):

View File

@ -1249,7 +1249,31 @@ class WM_OT_doc_view_manual(Operator):
# XXX, for some reason all RNA ID's are stored lowercase # XXX, for some reason all RNA ID's are stored lowercase
# Adding case into all ID's isn't worth the hassle so force lowercase. # Adding case into all ID's isn't worth the hassle so force lowercase.
rna_id = rna_id.lower() rna_id = rna_id.lower()
# NOTE: `fnmatch` in Python is slow as it translate the string to a regular-expression
# which needs to be compiled (as of Python 3.11), this is slow enough to cause a noticeable
# delay when opening manual links (approaching half a second).
#
# Resolve by matching characters that have a special meaning to `fnmatch`.
# The characters that can occur as the first special character are `*?[`.
# If any of these are used we must let `fnmatch` run its own matching logic.
# However, in most cases a literal prefix is used making it considerably faster
# to do a simple `startswith` check before performing a full match.
# An alternative solution could be to use `fnmatch` from C which is significantly
# faster than Python's, see !104581 for details.
import re
re_match_non_special = re.compile(r"^[^?\*\[]+").match
for pattern, url_suffix in url_mapping: for pattern, url_suffix in url_mapping:
# Simple optimization, makes a big difference (over 50x speedup).
# Even when `non_special.end()` is zero (resulting in an empty-string),
# the `startswith` check succeeds so there is no need to check for an empty match.
non_special = re_match_non_special(pattern)
if non_special is None or not rna_id.startswith(pattern[:non_special.end()]):
continue
# End simple optimization.
if fnmatchcase(rna_id, pattern): if fnmatchcase(rna_id, pattern):
if verbose: if verbose:
print(" match found: '%s' --> '%s'" % (pattern, url_suffix)) print(" match found: '%s' --> '%s'" % (pattern, url_suffix))
@ -1725,7 +1749,7 @@ class WM_OT_properties_edit(Operator):
for nt in adt.nla_tracks: for nt in adt.nla_tracks:
_update_strips(nt.strips) _update_strips(nt.strips)
# Otherwise existing buttons which reference freed memory may crash Blender (T26510). # Otherwise existing buttons which reference freed memory may crash Blender (#26510).
for win in context.window_manager.windows: for win in context.window_manager.windows:
for area in win.screen.areas: for area in win.screen.areas:
area.tag_redraw() area.tag_redraw()

View File

@ -604,7 +604,7 @@ class DATA_PT_mesh_attributes(MeshButtonsPanel, Panel):
colliding_names = [] colliding_names = []
for collection in ( for collection in (
# Built-in names. # Built-in names.
{"shade_smooth": None, "normal": None, "crease": None}, {"shade_smooth": None, "crease": None},
mesh.attributes, mesh.attributes,
None if ob is None else ob.vertex_groups, None if ob is None else ob.vertex_groups,
): ):

View File

@ -1141,6 +1141,11 @@ def brush_texture_settings(layout, brush, sculpt):
# texture_sample_bias # texture_sample_bias
layout.prop(brush, "texture_sample_bias", slider=True, text="Sample Bias") layout.prop(brush, "texture_sample_bias", slider=True, text="Sample Bias")
if brush.sculpt_tool == 'DRAW':
col = layout.column()
col.active = tex_slot.map_mode == 'AREA_PLANE'
col.prop(brush, "use_color_as_displacement", text="Vector Displacement")
def brush_mask_texture_settings(layout, brush): def brush_mask_texture_settings(layout, brush):
mask_tex_slot = brush.mask_texture_slot mask_tex_slot = brush.mask_texture_slot

View File

@ -91,7 +91,7 @@ class TEXTURE_PT_preview(TextureButtonsPanel, Panel):
else: else:
layout.template_preview(tex, slot=slot) layout.template_preview(tex, slot=slot)
# Show Alpha Button for Brush Textures, see T29502. # Show Alpha Button for Brush Textures, see #29502.
idblock = context_tex_datablock(context) idblock = context_tex_datablock(context)
if isinstance(idblock, Brush): if isinstance(idblock, Brush):
layout.prop(tex, "use_preview_alpha") layout.prop(tex, "use_preview_alpha")

View File

@ -22,7 +22,7 @@ class FILEBROWSER_HT_header(Header):
layout.separator_spacer() layout.separator_spacer()
if params.asset_library_ref != 'LOCAL': if params.asset_library_ref not in {'LOCAL', 'ESSENTIALS'}:
layout.prop(params, "import_type", text="") layout.prop(params, "import_type", text="")
layout.separator_spacer() layout.separator_spacer()

View File

@ -62,7 +62,7 @@ class NODE_HT_header(Header):
types_that_support_material = {'MESH', 'CURVE', 'SURFACE', 'FONT', 'META', types_that_support_material = {'MESH', 'CURVE', 'SURFACE', 'FONT', 'META',
'GPENCIL', 'VOLUME', 'CURVES', 'POINTCLOUD'} 'GPENCIL', 'VOLUME', 'CURVES', 'POINTCLOUD'}
# disable material slot buttons when pinned, cannot find correct slot within id_from (T36589) # disable material slot buttons when pinned, cannot find correct slot within id_from (#36589)
# disable also when the selected object does not support materials # disable also when the selected object does not support materials
has_material_slots = not snode.pin and ob_type in types_that_support_material has_material_slots = not snode.pin and ob_type in types_that_support_material

View File

@ -407,7 +407,7 @@ class SEQUENCER_MT_view(Menu):
if st.view_type == 'PREVIEW': if st.view_type == 'PREVIEW':
# Specifying the REGION_PREVIEW context is needed in preview-only # Specifying the REGION_PREVIEW context is needed in preview-only
# mode, else the lookup for the shortcut will fail in # mode, else the lookup for the shortcut will fail in
# wm_keymap_item_find_props() (see T32595). # wm_keymap_item_find_props() (see #32595).
layout.operator_context = 'INVOKE_REGION_PREVIEW' layout.operator_context = 'INVOKE_REGION_PREVIEW'
layout.prop(st, "show_region_ui") layout.prop(st, "show_region_ui")
layout.prop(st, "show_region_tool_header") layout.prop(st, "show_region_tool_header")
@ -429,7 +429,7 @@ class SEQUENCER_MT_view(Menu):
layout.operator_context = 'INVOKE_REGION_WIN' layout.operator_context = 'INVOKE_REGION_WIN'
if st.view_type == 'PREVIEW': if st.view_type == 'PREVIEW':
# See above (T32595) # See above (#32595)
layout.operator_context = 'INVOKE_REGION_PREVIEW' layout.operator_context = 'INVOKE_REGION_PREVIEW'
layout.operator("sequencer.view_selected", text="Frame Selected") layout.operator("sequencer.view_selected", text="Frame Selected")
@ -931,8 +931,14 @@ class SEQUENCER_MT_strip(Menu):
if has_sequencer: if has_sequencer:
layout.operator("sequencer.split", text="Split").type = 'SOFT' props = layout.operator("sequencer.split", text="Split")
layout.operator("sequencer.split", text="Hold Split").type = 'HARD' props.type = 'SOFT'
props.side = 'RIGHT'
props = layout.operator("sequencer.split", text="Hold Split")
props.type = 'HARD'
props.side = 'RIGHT'
layout.separator() layout.separator()
if has_sequencer: if has_sequencer:

File diff suppressed because it is too large Load Diff

View File

@ -326,7 +326,7 @@ class TOPBAR_MT_file_new(Menu):
# Expand template paths. # Expand template paths.
# Use a set to avoid duplicate user/system templates. # Use a set to avoid duplicate user/system templates.
# This is a corner case, but users managed to do it! T76849. # This is a corner case, but users managed to do it! #76849.
app_templates = set() app_templates = set()
for path in template_paths: for path in template_paths:
for d in os.listdir(path): for d in os.listdir(path):

View File

@ -1424,34 +1424,40 @@ class USERPREF_PT_file_paths_asset_libraries(FilePathsPanel, Panel):
layout.use_property_decorate = False layout.use_property_decorate = False
paths = context.preferences.filepaths paths = context.preferences.filepaths
active_library_index = paths.active_asset_library
box = layout.box() row = layout.row()
split = box.split(factor=0.35)
name_col = split.column()
path_col = split.column()
row = name_col.row(align=True) # Padding row.template_list(
row.separator() "USERPREF_UL_asset_libraries", "user_asset_libraries",
row.label(text="Name") paths, "asset_libraries",
paths, "active_asset_library"
)
row = path_col.row(align=True) # Padding col = row.column(align=True)
row.separator() col.operator("preferences.asset_library_add", text="", icon='ADD')
row.label(text="Path") props = col.operator("preferences.asset_library_remove", text="", icon='REMOVE')
props.index = active_library_index
for i, library in enumerate(paths.asset_libraries): if active_library_index < 0:
row = name_col.row() return
row.alert = not library.name
row.prop(library, "name", text="")
row = path_col.row() layout.separator()
subrow = row.row()
subrow.alert = not library.path
subrow.prop(library, "path", text="")
row.operator("preferences.asset_library_remove", text="", icon='X', emboss=False).index = i
row = box.row() active_library = paths.asset_libraries[active_library_index]
row.alignment = 'RIGHT' layout.prop(active_library, "path")
row.operator("preferences.asset_library_add", text="", icon='ADD', emboss=False) layout.prop(active_library, "import_method", text="Import Method")
class USERPREF_UL_asset_libraries(bpy.types.UIList):
def draw_item(self, _context, layout, _data, item, icon, _active_data, _active_propname, _index):
asset_library = item
if self.layout_type in {'DEFAULT', 'COMPACT'}:
layout.prop(asset_library, "name", text="", emboss=False)
elif self.layout_type == 'GRID':
layout.alignment = 'CENTER'
layout.prop(asset_library, "name", text="", emboss=False)
# ----------------------------------------------------------------------------- # -----------------------------------------------------------------------------
@ -2319,19 +2325,13 @@ class USERPREF_PT_experimental_new_features(ExperimentalPanel, Panel):
bl_label = "New Features" bl_label = "New Features"
def draw(self, context): def draw(self, context):
self._draw_items(context, self._draw_items(
(({"property": "use_sculpt_tools_tilt"}, context, (
("blender/blender/issues/82877", ({"property": "use_sculpt_tools_tilt"}, ("blender/blender/issues/82877", "#82877")),
"#82877")),
({"property": "use_extended_asset_browser"}, ({"property": "use_extended_asset_browser"},
("blender/blender/projects/10", ("blender/blender/projects/10", "Pipeline, Assets & IO Project Page")),
"Pipeline, Assets & IO Project Page")), ({"property": "use_override_templates"}, ("blender/blender/issues/73318", "Milestone 4")),
({"property": "use_override_templates"}, ({"property": "use_new_volume_nodes"}, ("blender/blender/issues/103248", "#103248")),
("blender/blender/issues/73318",
"Milestone 4")),
({"property": "use_new_volume_nodes"},
("blender/blender/issues/103248",
"#103248")),
), ),
) )
@ -2493,6 +2493,9 @@ classes = (
# USERPREF_PT_experimental_tweaks, # USERPREF_PT_experimental_tweaks,
USERPREF_PT_experimental_debugging, USERPREF_PT_experimental_debugging,
# UI lists
USERPREF_UL_asset_libraries,
# Add dynamically generated editor theme panels last, # Add dynamically generated editor theme panels last,
# so they show up last in the theme section. # so they show up last in the theme section.
*ThemeGenericClassGenerator.generate_panel_classes_from_theme_areas(), *ThemeGenericClassGenerator.generate_panel_classes_from_theme_areas(),

View File

@ -161,6 +161,8 @@ class VIEW3D_HT_tool_header(Header):
sub.prop(context.object.data, "use_mirror_y", text="Y", toggle=True) sub.prop(context.object.data, "use_mirror_y", text="Y", toggle=True)
sub.prop(context.object.data, "use_mirror_z", text="Z", toggle=True) sub.prop(context.object.data, "use_mirror_z", text="Z", toggle=True)
layout.prop(context.object.data, "use_sculpt_collision", icon='MOD_PHYSICS', icon_only=True, toggle=True)
# Expand panels from the side-bar as popovers. # Expand panels from the side-bar as popovers.
popover_kw = {"space_type": 'VIEW_3D', "region_type": 'UI', "category": "Tool"} popover_kw = {"space_type": 'VIEW_3D', "region_type": 'UI', "category": "Tool"}
@ -520,7 +522,8 @@ class _draw_tool_settings_context_mode:
if curves_tool == 'COMB': if curves_tool == 'COMB':
layout.prop(brush, "falloff_shape", expand=True) layout.prop(brush, "falloff_shape", expand=True)
layout.popover("VIEW3D_PT_tools_brush_falloff") layout.popover("VIEW3D_PT_tools_brush_falloff", text="Brush Falloff")
layout.popover("VIEW3D_PT_curves_sculpt_parameter_falloff", text="Curve Falloff")
elif curves_tool == 'ADD': elif curves_tool == 'ADD':
layout.prop(brush, "falloff_shape", expand=True) layout.prop(brush, "falloff_shape", expand=True)
layout.prop(brush.curves_sculpt_settings, "add_amount") layout.prop(brush.curves_sculpt_settings, "add_amount")
@ -890,7 +893,7 @@ class VIEW3D_HT_header(Header):
row.active = (object_mode == 'EDIT') or (shading.type in {'WIREFRAME', 'SOLID'}) row.active = (object_mode == 'EDIT') or (shading.type in {'WIREFRAME', 'SOLID'})
# While exposing `shading.show_xray(_wireframe)` is correct. # While exposing `shading.show_xray(_wireframe)` is correct.
# this hides the key shortcut from users: T70433. # this hides the key shortcut from users: #70433.
if has_pose_mode: if has_pose_mode:
draw_depressed = overlay.show_xray_bone draw_depressed = overlay.show_xray_bone
elif shading.type == 'WIREFRAME': elif shading.type == 'WIREFRAME':
@ -2041,6 +2044,16 @@ class VIEW3D_MT_select_paint_mask_vertex(Menu):
layout.operator("paint.vert_select_linked", text="Select Linked") layout.operator("paint.vert_select_linked", text="Select Linked")
class VIEW3D_MT_edit_curves_select_more_less(Menu):
bl_label = "Select More/Less"
def draw(self, _context):
layout = self.layout
layout.operator("curves.select_more", text="More")
layout.operator("curves.select_less", text="Less")
class VIEW3D_MT_select_edit_curves(Menu): class VIEW3D_MT_select_edit_curves(Menu):
bl_label = "Select" bl_label = "Select"
@ -2050,10 +2063,17 @@ class VIEW3D_MT_select_edit_curves(Menu):
layout.operator("curves.select_all", text="All").action = 'SELECT' layout.operator("curves.select_all", text="All").action = 'SELECT'
layout.operator("curves.select_all", text="None").action = 'DESELECT' layout.operator("curves.select_all", text="None").action = 'DESELECT'
layout.operator("curves.select_all", text="Invert").action = 'INVERT' layout.operator("curves.select_all", text="Invert").action = 'INVERT'
layout.separator()
layout.operator("curves.select_random", text="Random") layout.operator("curves.select_random", text="Random")
layout.operator("curves.select_end", text="Endpoints") layout.operator("curves.select_end", text="Endpoints")
layout.operator("curves.select_linked", text="Linked") layout.operator("curves.select_linked", text="Linked")
layout.separator()
layout.menu("VIEW3D_MT_edit_curves_select_more_less")
class VIEW3D_MT_select_sculpt_curves(Menu): class VIEW3D_MT_select_sculpt_curves(Menu):
bl_label = "Select" bl_label = "Select"
@ -2114,6 +2134,7 @@ class VIEW3D_MT_curve_add(Menu):
layout.separator() layout.separator()
layout.operator("object.curves_empty_hair_add", text="Empty Hair", icon='CURVES_DATA') layout.operator("object.curves_empty_hair_add", text="Empty Hair", icon='CURVES_DATA')
layout.operator("object.quick_fur", text="Fur", icon='CURVES_DATA')
experimental = context.preferences.experimental experimental = context.preferences.experimental
if experimental.use_new_curves_tools: if experimental.use_new_curves_tools:
@ -2268,7 +2289,7 @@ class VIEW3D_MT_add(Menu):
# NOTE: don't use 'EXEC_SCREEN' or operators won't get the `v3d` context. # NOTE: don't use 'EXEC_SCREEN' or operators won't get the `v3d` context.
# NOTE: was `EXEC_AREA`, but this context does not have the `rv3d`, which prevents # NOTE: was `EXEC_AREA`, but this context does not have the `rv3d`, which prevents
# "align_view" to work on first call (see T32719). # "align_view" to work on first call (see #32719).
layout.operator_context = 'EXEC_REGION_WIN' layout.operator_context = 'EXEC_REGION_WIN'
# layout.operator_menu_enum("object.mesh_add", "type", text="Mesh", icon='OUTLINER_OB_MESH') # layout.operator_menu_enum("object.mesh_add", "type", text="Mesh", icon='OUTLINER_OB_MESH')
@ -3867,6 +3888,7 @@ class VIEW3D_MT_edit_mesh(Menu):
layout.menu("VIEW3D_MT_edit_mesh_normals") layout.menu("VIEW3D_MT_edit_mesh_normals")
layout.menu("VIEW3D_MT_edit_mesh_shading") layout.menu("VIEW3D_MT_edit_mesh_shading")
layout.menu("VIEW3D_MT_edit_mesh_weights") layout.menu("VIEW3D_MT_edit_mesh_weights")
layout.operator("mesh.attribute_set")
layout.operator_menu_enum("mesh.sort_elements", "type", text="Sort Elements...") layout.operator_menu_enum("mesh.sort_elements", "type", text="Sort Elements...")
layout.separator() layout.separator()
@ -5308,6 +5330,7 @@ class VIEW3D_MT_edit_curves(Menu):
layout.menu("VIEW3D_MT_transform") layout.menu("VIEW3D_MT_transform")
layout.separator() layout.separator()
layout.operator("curves.delete")
class VIEW3D_MT_object_mode_pie(Menu): class VIEW3D_MT_object_mode_pie(Menu):
@ -5376,7 +5399,7 @@ class VIEW3D_MT_shading_ex_pie(Menu):
pie.prop_enum(view.shading, "type", value='WIREFRAME') pie.prop_enum(view.shading, "type", value='WIREFRAME')
pie.prop_enum(view.shading, "type", value='SOLID') pie.prop_enum(view.shading, "type", value='SOLID')
# Note this duplicates "view3d.toggle_xray" logic, so we can see the active item: T58661. # Note this duplicates "view3d.toggle_xray" logic, so we can see the active item: #58661.
if context.pose_object: if context.pose_object:
pie.prop(view.overlay, "show_xray_bone", icon='XRAY') pie.prop(view.overlay, "show_xray_bone", icon='XRAY')
else: else:
@ -6718,15 +6741,15 @@ class VIEW3D_PT_overlay_sculpt(Panel):
overlay = view.overlay overlay = view.overlay
row = layout.row(align=True) row = layout.row(align=True)
row.prop(overlay, "sculpt_show_mask", text="") row.prop(overlay, "show_sculpt_mask", text="")
sub = row.row() sub = row.row()
sub.active = overlay.sculpt_show_mask sub.active = overlay.show_sculpt_mask
sub.prop(overlay, "sculpt_mode_mask_opacity", text="Mask") sub.prop(overlay, "sculpt_mode_mask_opacity", text="Mask")
row = layout.row(align=True) row = layout.row(align=True)
row.prop(overlay, "sculpt_show_face_sets", text="") row.prop(overlay, "show_sculpt_face_sets", text="")
sub = row.row() sub = row.row()
sub.active = overlay.sculpt_show_face_sets sub.active = overlay.show_sculpt_face_sets
row.prop(overlay, "sculpt_mode_face_sets_opacity", text="Face Sets") row.prop(overlay, "sculpt_mode_face_sets_opacity", text="Face Sets")
@ -6753,6 +6776,13 @@ class VIEW3D_PT_overlay_sculpt_curves(Panel):
row.active = overlay.show_overlays row.active = overlay.show_overlays
row.prop(overlay, "sculpt_mode_mask_opacity", text="Selection Opacity") row.prop(overlay, "sculpt_mode_mask_opacity", text="Selection Opacity")
row = layout.row(align=True)
row.active = overlay.show_overlays
row.prop(overlay, "show_sculpt_curves_cage", text="")
subrow = row.row(align=True)
subrow.active = overlay.show_sculpt_curves_cage
subrow.prop(overlay, "sculpt_curves_cage_opacity", text="Cage Opacity")
class VIEW3D_PT_overlay_bones(Panel): class VIEW3D_PT_overlay_bones(Panel):
bl_space_type = 'VIEW_3D' bl_space_type = 'VIEW_3D'
@ -7934,6 +7964,28 @@ class VIEW3D_PT_curves_sculpt_add_shape(Panel):
col.prop(brush.curves_sculpt_settings, "points_per_curve", text="Points") col.prop(brush.curves_sculpt_settings, "points_per_curve", text="Points")
class VIEW3D_PT_curves_sculpt_parameter_falloff(Panel):
# Only for popover, these are dummy values.
bl_space_type = 'VIEW_3D'
bl_region_type = 'WINDOW'
bl_label = "Curves Sculpt Parameter Falloff"
def draw(self, context):
layout = self.layout
settings = UnifiedPaintPanel.paint_settings(context)
brush = settings.brush
layout.template_curve_mapping(brush.curves_sculpt_settings, "curve_parameter_falloff")
row = layout.row(align=True)
row.operator("brush.sculpt_curves_falloff_preset", icon='SMOOTHCURVE', text="").shape = 'SMOOTH'
row.operator("brush.sculpt_curves_falloff_preset", icon='SPHERECURVE', text="").shape = 'ROUND'
row.operator("brush.sculpt_curves_falloff_preset", icon='ROOTCURVE', text="").shape = 'ROOT'
row.operator("brush.sculpt_curves_falloff_preset", icon='SHARPCURVE', text="").shape = 'SHARP'
row.operator("brush.sculpt_curves_falloff_preset", icon='LINCURVE', text="").shape = 'LINE'
row.operator("brush.sculpt_curves_falloff_preset", icon='NOCURVE', text="").shape = 'MAX'
class VIEW3D_PT_curves_sculpt_grow_shrink_scaling(Panel): class VIEW3D_PT_curves_sculpt_grow_shrink_scaling(Panel):
# Only for popover, these are dummy values. # Only for popover, these are dummy values.
bl_space_type = 'VIEW_3D' bl_space_type = 'VIEW_3D'
@ -8011,6 +8063,7 @@ classes = (
VIEW3D_MT_select_gpencil, VIEW3D_MT_select_gpencil,
VIEW3D_MT_select_paint_mask, VIEW3D_MT_select_paint_mask,
VIEW3D_MT_select_paint_mask_vertex, VIEW3D_MT_select_paint_mask_vertex,
VIEW3D_MT_edit_curves_select_more_less,
VIEW3D_MT_select_edit_curves, VIEW3D_MT_select_edit_curves,
VIEW3D_MT_select_sculpt_curves, VIEW3D_MT_select_sculpt_curves,
VIEW3D_MT_mesh_add, VIEW3D_MT_mesh_add,
@ -8211,6 +8264,7 @@ classes = (
TOPBAR_PT_gpencil_vertexcolor, TOPBAR_PT_gpencil_vertexcolor,
TOPBAR_PT_annotation_layers, TOPBAR_PT_annotation_layers,
VIEW3D_PT_curves_sculpt_add_shape, VIEW3D_PT_curves_sculpt_add_shape,
VIEW3D_PT_curves_sculpt_parameter_falloff,
VIEW3D_PT_curves_sculpt_grow_shrink_scaling, VIEW3D_PT_curves_sculpt_grow_shrink_scaling,
VIEW3D_PT_viewport_debug, VIEW3D_PT_viewport_debug,
) )

View File

@ -639,7 +639,7 @@ class BUILTIN_KSI_DeltaScale(KeyingSetInfo):
# Note that this controls order of options in `insert keyframe` menu. # Note that this controls order of options in `insert keyframe` menu.
# Better try to keep some logical order here beyond mere alphabetical one, also because of menu entries shortcut. # Better try to keep some logical order here beyond mere alphabetical one, also because of menu entries shortcut.
# See also T51867. # See also #51867.
classes = ( classes = (
BUILTIN_KSI_Available, BUILTIN_KSI_Available,
BUILTIN_KSI_Location, BUILTIN_KSI_Location,

View File

@ -58,6 +58,11 @@ class AssetLibrary {
std::function<void(AssetLibrary &self)> on_refresh_; std::function<void(AssetLibrary &self)> on_refresh_;
std::optional<eAssetImportMethod> import_method_;
/** Assets owned by this library may be imported with a different method than set in
* #import_method_ above, it's just a default. */
bool may_override_import_method_ = false;
bCallbackFuncStore on_save_callback_store_{}; bCallbackFuncStore on_save_callback_store_{};
public: public:
@ -68,6 +73,7 @@ class AssetLibrary {
std::unique_ptr<AssetCatalogService> catalog_service; std::unique_ptr<AssetCatalogService> catalog_service;
friend class AssetLibraryService; friend class AssetLibraryService;
friend class AssetRepresentation;
public: public:
/** /**

View File

@ -22,6 +22,8 @@ const char *AS_asset_representation_name_get(const AssetRepresentation *asset)
AssetMetaData *AS_asset_representation_metadata_get(const AssetRepresentation *asset) AssetMetaData *AS_asset_representation_metadata_get(const AssetRepresentation *asset)
ATTR_WARN_UNUSED_RESULT; ATTR_WARN_UNUSED_RESULT;
bool AS_asset_representation_is_local_id(const AssetRepresentation *asset) ATTR_WARN_UNUSED_RESULT; bool AS_asset_representation_is_local_id(const AssetRepresentation *asset) ATTR_WARN_UNUSED_RESULT;
bool AS_asset_representation_is_never_link(const AssetRepresentation *asset)
ATTR_WARN_UNUSED_RESULT;
#ifdef __cplusplus #ifdef __cplusplus
} }

View File

@ -12,10 +12,13 @@
#pragma once #pragma once
#include <memory> #include <memory>
#include <optional>
#include <string> #include <string>
#include "BLI_string_ref.hh" #include "BLI_string_ref.hh"
#include "DNA_asset_types.h"
#include "AS_asset_identifier.hh" #include "AS_asset_identifier.hh"
struct AssetMetaData; struct AssetMetaData;
@ -23,11 +26,15 @@ struct ID;
namespace blender::asset_system { namespace blender::asset_system {
class AssetLibrary;
class AssetRepresentation { class AssetRepresentation {
AssetIdentifier identifier_; AssetIdentifier identifier_;
/** Indicate if this is a local or external asset, and as such, which of the union members below /** Indicate if this is a local or external asset, and as such, which of the union members below
* should be used. */ * should be used. */
const bool is_local_id_ = false; const bool is_local_id_ = false;
/** Asset library that owns this asset representation. */
const AssetLibrary *owner_asset_library_;
struct ExternalAsset { struct ExternalAsset {
std::string name; std::string name;
@ -44,10 +51,13 @@ class AssetRepresentation {
/** Constructs an asset representation for an external ID. The asset will not be editable. */ /** Constructs an asset representation for an external ID. The asset will not be editable. */
AssetRepresentation(AssetIdentifier &&identifier, AssetRepresentation(AssetIdentifier &&identifier,
StringRef name, StringRef name,
std::unique_ptr<AssetMetaData> metadata); std::unique_ptr<AssetMetaData> metadata,
const AssetLibrary &owner_asset_library);
/** Constructs an asset representation for an ID stored in the current file. This makes the asset /** Constructs an asset representation for an ID stored in the current file. This makes the asset
* local and fully editable. */ * local and fully editable. */
AssetRepresentation(AssetIdentifier &&identifier, ID &id); AssetRepresentation(AssetIdentifier &&identifier,
ID &id,
const AssetLibrary &owner_asset_library);
AssetRepresentation(AssetRepresentation &&other); AssetRepresentation(AssetRepresentation &&other);
/* Non-copyable type. */ /* Non-copyable type. */
AssetRepresentation(const AssetRepresentation &other) = delete; AssetRepresentation(const AssetRepresentation &other) = delete;
@ -63,8 +73,18 @@ class AssetRepresentation {
StringRefNull get_name() const; StringRefNull get_name() const;
AssetMetaData &get_metadata() const; AssetMetaData &get_metadata() const;
/** Get the import method to use for this asset. A different one may be used if
* #may_override_import_method() returns true, otherwise, the returned value must be used. If
* there is no import method predefined for this asset no value is returned.
*/
std::optional<eAssetImportMethod> get_import_method() const;
/** Returns if this asset may be imported with an import method other than the one returned by
* #get_import_method(). Also returns true if there is no predefined import method
* (when #get_import_method() returns no value). */
bool may_override_import_method() const;
/** Returns if this asset is stored inside this current file, and as such fully editable. */ /** Returns if this asset is stored inside this current file, and as such fully editable. */
bool is_local_id() const; bool is_local_id() const;
const AssetLibrary &owner_asset_library() const;
}; };
} // namespace blender::asset_system } // namespace blender::asset_system
@ -73,3 +93,6 @@ class AssetRepresentation {
struct AssetRepresentation; struct AssetRepresentation;
const std::string AS_asset_representation_full_path_get(const ::AssetRepresentation *asset); const std::string AS_asset_representation_full_path_get(const ::AssetRepresentation *asset);
std::optional<eAssetImportMethod> AS_asset_representation_import_method_get(
const ::AssetRepresentation *asset_handle);
bool AS_asset_representation_may_override_import_method(const ::AssetRepresentation *asset_handle);

View File

@ -0,0 +1,15 @@
/* SPDX-License-Identifier: GPL-2.0-or-later */
/** \file
* \ingroup asset_system
*/
#pragma once
#include "BLI_string_ref.hh"
namespace blender::asset_system {
StringRefNull essentials_directory_path();
}

View File

@ -17,6 +17,7 @@ set(SRC
intern/asset_catalog.cc intern/asset_catalog.cc
intern/asset_catalog_path.cc intern/asset_catalog_path.cc
intern/asset_catalog_tree.cc intern/asset_catalog_tree.cc
intern/asset_essentials_library.cc
intern/asset_identifier.cc intern/asset_identifier.cc
intern/asset_library.cc intern/asset_library.cc
intern/asset_library_service.cc intern/asset_library_service.cc
@ -30,6 +31,7 @@ set(SRC
AS_asset_identifier.hh AS_asset_identifier.hh
AS_asset_library.hh AS_asset_library.hh
AS_asset_representation.hh AS_asset_representation.hh
AS_essentials_library.hh
intern/asset_library_service.hh intern/asset_library_service.hh
intern/asset_storage.hh intern/asset_storage.hh
intern/utils.hh intern/utils.hh

View File

@ -0,0 +1,24 @@
/* SPDX-License-Identifier: GPL-2.0-or-later */
/** \file
* \ingroup asset_system
*/
#include "BLI_path_util.h"
#include "BKE_appdir.h"
#include "AS_essentials_library.hh"
namespace blender::asset_system {
StringRefNull essentials_directory_path()
{
static std::string path = []() {
const char *datafiles_path = BKE_appdir_folder_id(BLENDER_DATAFILES, "assets");
return datafiles_path;
}();
return path;
}
} // namespace blender::asset_system

View File

@ -169,13 +169,14 @@ AssetRepresentation &AssetLibrary::add_external_asset(StringRef relative_asset_p
std::unique_ptr<AssetMetaData> metadata) std::unique_ptr<AssetMetaData> metadata)
{ {
AssetIdentifier identifier = asset_identifier_from_library(relative_asset_path); AssetIdentifier identifier = asset_identifier_from_library(relative_asset_path);
return asset_storage_->add_external_asset(std::move(identifier), name, std::move(metadata)); return asset_storage_->add_external_asset(
std::move(identifier), name, std::move(metadata), *this);
} }
AssetRepresentation &AssetLibrary::add_local_id_asset(StringRef relative_asset_path, ID &id) AssetRepresentation &AssetLibrary::add_local_id_asset(StringRef relative_asset_path, ID &id)
{ {
AssetIdentifier identifier = asset_identifier_from_library(relative_asset_path); AssetIdentifier identifier = asset_identifier_from_library(relative_asset_path);
return asset_storage_->add_local_id_asset(std::move(identifier), id); return asset_storage_->add_local_id_asset(std::move(identifier), id, *this);
} }
bool AssetLibrary::remove_asset(AssetRepresentation &asset) bool AssetLibrary::remove_asset(AssetRepresentation &asset)
@ -259,6 +260,12 @@ StringRefNull AssetLibrary::root_path() const
Vector<AssetLibraryReference> all_valid_asset_library_refs() Vector<AssetLibraryReference> all_valid_asset_library_refs()
{ {
Vector<AssetLibraryReference> result; Vector<AssetLibraryReference> result;
{
AssetLibraryReference library_ref{};
library_ref.custom_library_index = -1;
library_ref.type = ASSET_LIBRARY_ESSENTIALS;
result.append(library_ref);
}
int i; int i;
LISTBASE_FOREACH_INDEX (const bUserAssetLibrary *, asset_library, &U.asset_libraries, i) { LISTBASE_FOREACH_INDEX (const bUserAssetLibrary *, asset_library, &U.asset_libraries, i) {
if (!BLI_is_dir(asset_library->path)) { if (!BLI_is_dir(asset_library->path)) {

View File

@ -16,6 +16,7 @@
#include "AS_asset_catalog_tree.hh" #include "AS_asset_catalog_tree.hh"
#include "AS_asset_library.hh" #include "AS_asset_library.hh"
#include "AS_essentials_library.hh"
#include "asset_library_service.hh" #include "asset_library_service.hh"
#include "utils.hh" #include "utils.hh"
@ -60,6 +61,14 @@ AssetLibrary *AssetLibraryService::get_asset_library(
const eAssetLibraryType type = eAssetLibraryType(library_reference.type); const eAssetLibraryType type = eAssetLibraryType(library_reference.type);
switch (type) { switch (type) {
case ASSET_LIBRARY_ESSENTIALS: {
const StringRefNull root_path = essentials_directory_path();
AssetLibrary *library = get_asset_library_on_disk(root_path);
library->import_method_ = ASSET_IMPORT_APPEND_REUSE;
return library;
}
case ASSET_LIBRARY_LOCAL: { case ASSET_LIBRARY_LOCAL: {
/* For the "Current File" library we get the asset library root path based on main. */ /* For the "Current File" library we get the asset library root path based on main. */
std::string root_path = bmain ? AS_asset_library_find_suitable_root_path_from_main(bmain) : std::string root_path = bmain ? AS_asset_library_find_suitable_root_path_from_main(bmain) :
@ -74,12 +83,22 @@ AssetLibrary *AssetLibraryService::get_asset_library(
case ASSET_LIBRARY_ALL: case ASSET_LIBRARY_ALL:
return get_asset_library_all(bmain); return get_asset_library_all(bmain);
case ASSET_LIBRARY_CUSTOM: { case ASSET_LIBRARY_CUSTOM: {
std::string root_path = root_path_from_library_ref(library_reference); bUserAssetLibrary *custom_library = find_custom_asset_library_from_library_ref(
library_reference);
if (!root_path.empty()) { if (!custom_library) {
return get_asset_library_on_disk(root_path); return nullptr;
} }
break;
std::string root_path = custom_library->path;
if (root_path.empty()) {
return nullptr;
}
AssetLibrary *library = get_asset_library_on_disk(root_path);
library->import_method_ = eAssetImportMethod(custom_library->import_method);
library->may_override_import_method_ = true;
return library;
} }
} }
@ -180,6 +199,15 @@ AssetLibrary *AssetLibraryService::get_asset_library_all(const Main *bmain)
return all_library_.get(); return all_library_.get();
} }
bUserAssetLibrary *AssetLibraryService::find_custom_asset_library_from_library_ref(
const AssetLibraryReference &library_reference)
{
BLI_assert(library_reference.type == ASSET_LIBRARY_CUSTOM);
BLI_assert(library_reference.custom_library_index >= 0);
return BKE_preferences_asset_library_find_from_index(&U, library_reference.custom_library_index);
}
std::string AssetLibraryService::root_path_from_library_ref( std::string AssetLibraryService::root_path_from_library_ref(
const AssetLibraryReference &library_reference) const AssetLibraryReference &library_reference)
{ {
@ -187,16 +215,13 @@ std::string AssetLibraryService::root_path_from_library_ref(
return ""; return "";
} }
BLI_assert(library_reference.type == ASSET_LIBRARY_CUSTOM); bUserAssetLibrary *custom_library = find_custom_asset_library_from_library_ref(
BLI_assert(library_reference.custom_library_index >= 0); library_reference);
if (!custom_library || !custom_library->path[0]) {
bUserAssetLibrary *user_library = BKE_preferences_asset_library_find_from_index(
&U, library_reference.custom_library_index);
if (!user_library || !user_library->path[0]) {
return ""; return "";
} }
return user_library->path; return custom_library->path;
} }
void AssetLibraryService::allocate_service_instance() void AssetLibraryService::allocate_service_instance()

View File

@ -14,6 +14,7 @@
#include <memory> #include <memory>
struct AssetLibraryReference; struct AssetLibraryReference;
struct bUserAssetLibrary;
namespace blender::asset_system { namespace blender::asset_system {
@ -58,6 +59,8 @@ class AssetLibraryService {
static void destroy(); static void destroy();
static std::string root_path_from_library_ref(const AssetLibraryReference &library_reference); static std::string root_path_from_library_ref(const AssetLibraryReference &library_reference);
static bUserAssetLibrary *find_custom_asset_library_from_library_ref(
const AssetLibraryReference &library_reference);
AssetLibrary *get_asset_library(const Main *bmain, AssetLibrary *get_asset_library(const Main *bmain,
const AssetLibraryReference &library_reference); const AssetLibraryReference &library_reference);

View File

@ -8,8 +8,10 @@
#include "DNA_ID.h" #include "DNA_ID.h"
#include "DNA_asset_types.h" #include "DNA_asset_types.h"
#include "DNA_userdef_types.h"
#include "AS_asset_identifier.hh" #include "AS_asset_identifier.hh"
#include "AS_asset_library.hh"
#include "AS_asset_representation.h" #include "AS_asset_representation.h"
#include "AS_asset_representation.hh" #include "AS_asset_representation.hh"
@ -17,15 +19,24 @@ namespace blender::asset_system {
AssetRepresentation::AssetRepresentation(AssetIdentifier &&identifier, AssetRepresentation::AssetRepresentation(AssetIdentifier &&identifier,
StringRef name, StringRef name,
std::unique_ptr<AssetMetaData> metadata) std::unique_ptr<AssetMetaData> metadata,
: identifier_(identifier), is_local_id_(false), external_asset_() const AssetLibrary &owner_asset_library)
: identifier_(identifier),
is_local_id_(false),
owner_asset_library_(&owner_asset_library),
external_asset_()
{ {
external_asset_.name = name; external_asset_.name = name;
external_asset_.metadata_ = std::move(metadata); external_asset_.metadata_ = std::move(metadata);
} }
AssetRepresentation::AssetRepresentation(AssetIdentifier &&identifier, ID &id) AssetRepresentation::AssetRepresentation(AssetIdentifier &&identifier,
: identifier_(identifier), is_local_id_(true), local_asset_id_(&id) ID &id,
const AssetLibrary &owner_asset_library)
: identifier_(identifier),
is_local_id_(true),
owner_asset_library_(&owner_asset_library),
local_asset_id_(&id)
{ {
if (!id.asset_data) { if (!id.asset_data) {
throw std::invalid_argument("Passed ID is not an asset"); throw std::invalid_argument("Passed ID is not an asset");
@ -70,11 +81,32 @@ AssetMetaData &AssetRepresentation::get_metadata() const
return is_local_id_ ? *local_asset_id_->asset_data : *external_asset_.metadata_; return is_local_id_ ? *local_asset_id_->asset_data : *external_asset_.metadata_;
} }
std::optional<eAssetImportMethod> AssetRepresentation::get_import_method() const
{
if (!owner_asset_library_) {
return {};
}
return owner_asset_library_->import_method_;
}
bool AssetRepresentation::may_override_import_method() const
{
if (!owner_asset_library_ || !owner_asset_library_->import_method_) {
return true;
}
return owner_asset_library_->may_override_import_method_;
}
bool AssetRepresentation::is_local_id() const bool AssetRepresentation::is_local_id() const
{ {
return is_local_id_; return is_local_id_;
} }
const AssetLibrary &AssetRepresentation::owner_asset_library() const
{
return *owner_asset_library_;
}
} // namespace blender::asset_system } // namespace blender::asset_system
using namespace blender; using namespace blender;
@ -87,6 +119,21 @@ const std::string AS_asset_representation_full_path_get(const AssetRepresentatio
return identifier.full_path(); return identifier.full_path();
} }
std::optional<eAssetImportMethod> AS_asset_representation_import_method_get(
const AssetRepresentation *asset_handle)
{
const asset_system::AssetRepresentation *asset =
reinterpret_cast<const asset_system::AssetRepresentation *>(asset_handle);
return asset->get_import_method();
}
bool AS_asset_representation_may_override_import_method(const AssetRepresentation *asset_handle)
{
const asset_system::AssetRepresentation *asset =
reinterpret_cast<const asset_system::AssetRepresentation *>(asset_handle);
return asset->may_override_import_method();
}
/* ---------------------------------------------------------------------- */ /* ---------------------------------------------------------------------- */
/** \name C-API /** \name C-API
* \{ */ * \{ */

View File

@ -15,18 +15,21 @@
namespace blender::asset_system { namespace blender::asset_system {
AssetRepresentation &AssetStorage::add_local_id_asset(AssetIdentifier &&identifier, ID &id) AssetRepresentation &AssetStorage::add_local_id_asset(AssetIdentifier &&identifier,
ID &id,
const AssetLibrary &owner_asset_library)
{ {
return *local_id_assets_.lookup_key_or_add( return *local_id_assets_.lookup_key_or_add(
std::make_unique<AssetRepresentation>(std::move(identifier), id)); std::make_unique<AssetRepresentation>(std::move(identifier), id, owner_asset_library));
} }
AssetRepresentation &AssetStorage::add_external_asset(AssetIdentifier &&identifier, AssetRepresentation &AssetStorage::add_external_asset(AssetIdentifier &&identifier,
StringRef name, StringRef name,
std::unique_ptr<AssetMetaData> metadata) std::unique_ptr<AssetMetaData> metadata,
const AssetLibrary &owner_asset_library)
{ {
return *external_assets_.lookup_key_or_add( return *external_assets_.lookup_key_or_add(std::make_unique<AssetRepresentation>(
std::make_unique<AssetRepresentation>(std::move(identifier), name, std::move(metadata))); std::move(identifier), name, std::move(metadata), owner_asset_library));
} }
bool AssetStorage::remove_asset(AssetRepresentation &asset) bool AssetStorage::remove_asset(AssetRepresentation &asset)

View File

@ -35,9 +35,12 @@ class AssetStorage {
/** See #AssetLibrary::add_external_asset(). */ /** See #AssetLibrary::add_external_asset(). */
AssetRepresentation &add_external_asset(AssetIdentifier &&identifier, AssetRepresentation &add_external_asset(AssetIdentifier &&identifier,
StringRef name, StringRef name,
std::unique_ptr<AssetMetaData> metadata); std::unique_ptr<AssetMetaData> metadata,
const AssetLibrary &owner_asset_library);
/** See #AssetLibrary::add_external_asset(). */ /** See #AssetLibrary::add_external_asset(). */
AssetRepresentation &add_local_id_asset(AssetIdentifier &&identifier, ID &id); AssetRepresentation &add_local_id_asset(AssetIdentifier &&identifier,
ID &id,
const AssetLibrary &owner_asset_library);
/** See #AssetLibrary::remove_asset(). */ /** See #AssetLibrary::remove_asset(). */
bool remove_asset(AssetRepresentation &asset); bool remove_asset(AssetRepresentation &asset);

View File

@ -165,7 +165,7 @@ int BLF_load_unique(const char *name)
/* XXX: Temporarily disable kerning in our main font. Kerning had been accidentally removed from /* XXX: Temporarily disable kerning in our main font. Kerning had been accidentally removed from
* our font in 3.1. In 3.4 we disable kerning here in the new version to keep spacing the same * our font in 3.1. In 3.4 we disable kerning here in the new version to keep spacing the same
* (T101506). Enable again later with change of font, placement, or rendering - Harley. */ * (#101506). Enable again later with change of font, placement, or rendering - Harley. */
if (font && BLI_str_endswith(filepath, BLF_DEFAULT_PROPORTIONAL_FONT)) { if (font && BLI_str_endswith(filepath, BLF_DEFAULT_PROPORTIONAL_FONT)) {
font->face_flags &= ~FT_FACE_FLAG_KERNING; font->face_flags &= ~FT_FACE_FLAG_KERNING;
} }

View File

@ -271,7 +271,7 @@ struct bPoseChannel *BKE_pose_channel_active_if_layer_visible(struct Object *ob)
* In this case the active-selected is an obvious choice when finding the target for a * In this case the active-selected is an obvious choice when finding the target for a
* constraint for eg. however from the users perspective the active pose bone of the * constraint for eg. however from the users perspective the active pose bone of the
* active object is the _real_ active bone, so any other non-active selected bone * active object is the _real_ active bone, so any other non-active selected bone
* is a candidate for being the other selected bone, see: T58447. * is a candidate for being the other selected bone, see: #58447.
*/ */
struct bPoseChannel *BKE_pose_channel_active_or_first_selected(struct Object *ob); struct bPoseChannel *BKE_pose_channel_active_or_first_selected(struct Object *ob);
/** /**

View File

@ -37,7 +37,7 @@ struct bActionGroup;
/* Container for data required to do FCurve and Driver evaluation. */ /* Container for data required to do FCurve and Driver evaluation. */
typedef struct AnimationEvalContext { typedef struct AnimationEvalContext {
/* For drivers, so that they have access to the dependency graph and the current view layer. See /* For drivers, so that they have access to the dependency graph and the current view layer. See
* T77086. */ * #77086. */
struct Depsgraph *depsgraph; struct Depsgraph *depsgraph;
/* FCurves and Drivers can be evaluated at a different time than the current scene time, for /* FCurves and Drivers can be evaluated at a different time than the current scene time, for

Some files were not shown because too many files have changed in this diff Show More