Animation: Move Graph Editor settings to User Preferences #104532

Merged
Christoph Lendenfeld merged 14 commits from ChrisLend/blender:user_pref_only_selected_keys into main 2023-03-09 14:15:36 +01:00
956 changed files with 10469 additions and 6450 deletions
Showing only changes of commit e1c779747c - Show all commits

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

4
.gitmodules vendored
View File

@ -2,15 +2,19 @@
path = release/scripts/addons path = release/scripts/addons
url = ../blender-addons.git url = ../blender-addons.git
branch = main branch = main
ignore = all
[submodule "release/scripts/addons_contrib"] [submodule "release/scripts/addons_contrib"]
path = release/scripts/addons_contrib path = release/scripts/addons_contrib
url = ../blender-addons-contrib.git url = ../blender-addons-contrib.git
branch = main branch = main
ignore = all
[submodule "release/datafiles/locale"] [submodule "release/datafiles/locale"]
path = release/datafiles/locale path = release/datafiles/locale
url = ../blender-translations.git url = ../blender-translations.git
branch = main branch = main
ignore = all
[submodule "source/tools"] [submodule "source/tools"]
path = source/tools path = source/tools
url = ../blender-dev-tools.git url = ../blender-dev-tools.git
branch = main branch = main
ignore = all

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

@ -105,6 +105,7 @@ MetalDevice::MetalDevice(const DeviceInfo &info, Stats &stats, Profiler &profile
} }
case METAL_GPU_AMD: { case METAL_GPU_AMD: {
max_threads_per_threadgroup = 128; max_threads_per_threadgroup = 128;
use_metalrt = info.use_metalrt;
break; break;
} }
case METAL_GPU_APPLE: { case METAL_GPU_APPLE: {
@ -585,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;
@ -341,7 +341,7 @@ bool GHOST_NDOFManager::setDevice(ushort vendor_id, ushort product_id)
hid_map_button_mask_ = int(~(UINT_MAX << hid_map_button_num_)); hid_map_button_mask_ = int(~(UINT_MAX << hid_map_button_num_));
} }
CLOG_INFO(LOG, 2, "%d buttons -> hex:%X", hid_map_button_num_, (uint)hid_map_button_mask_); CLOG_INFO(LOG, 2, "%d buttons -> hex:%X", hid_map_button_num_, uint(hid_map_button_mask_));
return device_type_ != NDOF_UnknownDevice; return device_type_ != NDOF_UnknownDevice;
} }
@ -445,14 +445,14 @@ void GHOST_NDOFManager::updateButton(int button_number, bool press, uint64_t tim
2, 2,
"button=%d, press=%d (out of range %d, ignoring!)", "button=%d, press=%d (out of range %d, ignoring!)",
button_number, button_number,
(int)press, int(press),
hid_map_button_num_); hid_map_button_num_);
return; return;
} }
const NDOF_ButtonT button = hid_map_[button_number]; const NDOF_ButtonT button = hid_map_[button_number];
if (button == NDOF_BUTTON_NONE) { if (button == NDOF_BUTTON_NONE) {
CLOG_INFO( CLOG_INFO(
LOG, 2, "button=%d, press=%d (mapped to none, ignoring!)", button_number, (int)press); LOG, 2, "button=%d, press=%d (mapped to none, ignoring!)", button_number, int(press));
return; return;
} }
@ -460,7 +460,7 @@ void GHOST_NDOFManager::updateButton(int button_number, bool press, uint64_t tim
2, 2,
"button=%d, press=%d, name=%s", "button=%d, press=%d, name=%s",
button_number, button_number,
(int)press, int(press),
ndof_button_names[button]); ndof_button_names[button]);
GHOST_IWindow *window = system_.getWindowManager()->getActiveWindow(); GHOST_IWindow *window = system_.getWindowManager()->getActiveWindow();

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

@ -424,10 +424,9 @@ bool GHOST_SystemWin32::processEvents(bool waitForEvent)
processTrackpad(); processTrackpad();
/* PeekMessage above is allowed to dispatch messages to the wndproc without us /* `PeekMessage` above is allowed to dispatch messages to the `wndproc` without us
* noticing, so we need to check the event manager here to see if there are * noticing, so we need to check the event manager here to see if there are
* events waiting in the queue. * events waiting in the queue. */
*/
hasEventHandled |= this->m_eventManager->getNumEvents() > 0; hasEventHandled |= this->m_eventManager->getNumEvents() > 0;
} while (waitForEvent && !hasEventHandled); } while (waitForEvent && !hasEventHandled);
@ -566,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
{ {
@ -1084,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};
@ -1210,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

@ -487,7 +487,7 @@ def disable_all():
def _blender_manual_url_prefix(): def _blender_manual_url_prefix():
return "https://docs.blender.org/manual/en/%d.%d" % _bpy.app.version[:2] return "https://docs.blender.org/manual/%s/%d.%d" % (_bpy.utils.manual_language_code(), *_bpy.app.version[:2])
def module_bl_info(mod, *, info_basis=None): def module_bl_info(mod, *, info_basis=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

@ -26,6 +26,7 @@ __all__ = (
"register_tool", "register_tool",
"make_rna_paths", "make_rna_paths",
"manual_map", "manual_map",
"manual_language_code",
"previews", "previews",
"resource_path", "resource_path",
"script_path_user", "script_path_user",
@ -1035,6 +1036,53 @@ def manual_map():
yield prefix, url_manual_mapping yield prefix, url_manual_mapping
# Languages which are supported by the user manual (commented when there is no translation).
_manual_language_codes = {
"ar_EG": "ar", # Arabic
# "bg_BG": "bg", # Bulgarian
# "ca_AD": "ca", # Catalan
# "cs_CZ": "cz", # Czech
"de_DE": "de", # German
# "el_GR": "el", # Greek
"es": "es", # Spanish
"fi_FI": "fi", # Finnish
"fr_FR": "fr", # French
"id_ID": "id", # Indonesian
"it_IT": "it", # Italian
"ja_JP": "ja", # Japanese
"ko_KR": "ko", # Korean
# "nb": "nb", # Norwegian
# "nl_NL": "nl", # Dutch
# "pl_PL": "pl", # Polish
"pt_PT": "pt", # Portuguese
# Portuguese - Brazil, for until we have a pt_BR version.
"pt_BR": "pt",
"ru_RU": "ru", # Russian
"sk_SK": "sk", # Slovak
# "sl": "sl", # Slovenian
"sr_RS": "sr", # Serbian
# "sv_SE": "sv", # Swedish
# "tr_TR": "th", # Thai
"uk_UA": "uk", # Ukrainian
"vi_VN": "vi", # Vietnamese
"zh_CN": "zh-hans", # Simplified Chinese
"zh_TW": "zh-hant", # Traditional Chinese
}
def manual_language_code(default="en"):
"""
:return:
The language code used for user manual URL component based on the current language user-preference,
falling back to the ``default`` when unavailable.
:rtype: str
"""
language = _bpy.context.preferences.view.language
if language == 'DEFAULT':
language = _os.getenv("LANG", "").split(".")[0]
return _manual_language_codes.get(language, default)
# Build an RNA path from struct/property/enum names. # Build an RNA path from struct/property/enum names.
def make_rna_paths(struct_name, prop_name, enum_name): def make_rna_paths(struct_name, prop_name, enum_name):
""" """

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

@ -4,38 +4,10 @@
# autopep8: off # autopep8: off
import bpy import bpy
manual_version = '%d.%d' % bpy.app.version[:2] url_manual_prefix = "https://docs.blender.org/manual/%s/%d.%d/" % (
bpy.utils.manual_language_code(),
url_manual_prefix = "https://docs.blender.org/manual/en/" + manual_version + "/" *bpy.app.version[:2],
)
language = bpy.context.preferences.view.language
if language == 'DEFAULT':
import os
language = os.getenv('LANG', '').split('.')[0]
LANG = {
"ar_EG": "ar",
"de_DE": "de",
"es": "es",
"fi_FI": "fi",
"fr_FR": "fr",
"id_ID": "id",
"it_IT": "it",
"ja_JP": "ja",
"ko_KR": "ko",
"pt_PT": "pt",
"pt_BR": "pt",
"ru_RU": "ru",
"sk_SK": "sk",
"sr_RS": "sr",
"uk_UA": "uk",
"vi_VN": "vi",
"zh_CN": "zh-hans",
"zh_TW": "zh-hant",
}.get(language)
if LANG is not None:
url_manual_prefix = url_manual_prefix.replace("manual/en", "manual/" + LANG)
url_manual_mapping = ( url_manual_mapping = (
("bpy.types.movietrackingsettings.refine_intrinsics_tangential_distortion*", "movie_clip/tracking/clip/toolbar/solve.html#bpy-types-movietrackingsettings-refine-intrinsics-tangential-distortion"), ("bpy.types.movietrackingsettings.refine_intrinsics_tangential_distortion*", "movie_clip/tracking/clip/toolbar/solve.html#bpy-types-movietrackingsettings-refine-intrinsics-tangential-distortion"),
@ -641,7 +613,6 @@ url_manual_mapping = (
("bpy.types.volumedisplay.interpolation_method*", "modeling/volumes/properties.html#bpy-types-volumedisplay-interpolation-method"), ("bpy.types.volumedisplay.interpolation_method*", "modeling/volumes/properties.html#bpy-types-volumedisplay-interpolation-method"),
("bpy.ops.geometry.color_attribute_render_set*", "modeling/meshes/properties/object_data.html#bpy-ops-geometry-color-attribute-render-set"), ("bpy.ops.geometry.color_attribute_render_set*", "modeling/meshes/properties/object_data.html#bpy-ops-geometry-color-attribute-render-set"),
("bpy.ops.mesh.customdata_crease_vertex_clear*", "modeling/meshes/properties/custom_data.html#bpy-ops-mesh-customdata-crease-vertex-clear"), ("bpy.ops.mesh.customdata_crease_vertex_clear*", "modeling/meshes/properties/custom_data.html#bpy-ops-mesh-customdata-crease-vertex-clear"),
("bpy.types.brush.html#bpy.types.brush.jitter*", "sculpt_paint/brush/stroke.html#bpy-types-brush-html-bpy-types-brush-jitter"),
("bpy.types.brushgpencilsettings.angle_factor*", "grease_pencil/modes/draw/tools/draw.html#bpy-types-brushgpencilsettings-angle-factor"), ("bpy.types.brushgpencilsettings.angle_factor*", "grease_pencil/modes/draw/tools/draw.html#bpy-types-brushgpencilsettings-angle-factor"),
("bpy.types.brushgpencilsettings.pen_strength*", "grease_pencil/modes/draw/tools/erase.html#bpy-types-brushgpencilsettings-pen-strength"), ("bpy.types.brushgpencilsettings.pen_strength*", "grease_pencil/modes/draw/tools/erase.html#bpy-types-brushgpencilsettings-pen-strength"),
("bpy.types.clothcollisionsettings.collection*", "physics/cloth/settings/collisions.html#bpy-types-clothcollisionsettings-collection"), ("bpy.types.clothcollisionsettings.collection*", "physics/cloth/settings/collisions.html#bpy-types-clothcollisionsettings-collection"),
@ -672,7 +643,7 @@ url_manual_mapping = (
("bpy.types.geometrynodeinputmeshedgevertices*", "modeling/geometry_nodes/mesh/read/edge_vertices.html#bpy-types-geometrynodeinputmeshedgevertices"), ("bpy.types.geometrynodeinputmeshedgevertices*", "modeling/geometry_nodes/mesh/read/edge_vertices.html#bpy-types-geometrynodeinputmeshedgevertices"),
("bpy.types.geometrynodeinputmeshfaceisplanar*", "modeling/geometry_nodes/mesh/read/face_is_planar.html#bpy-types-geometrynodeinputmeshfaceisplanar"), ("bpy.types.geometrynodeinputmeshfaceisplanar*", "modeling/geometry_nodes/mesh/read/face_is_planar.html#bpy-types-geometrynodeinputmeshfaceisplanar"),
("bpy.types.geometrynodeinputsplineresolution*", "modeling/geometry_nodes/curve/read/spline_resolution.html#bpy-types-geometrynodeinputsplineresolution"), ("bpy.types.geometrynodeinputsplineresolution*", "modeling/geometry_nodes/curve/read/spline_resolution.html#bpy-types-geometrynodeinputsplineresolution"),
("bpy.types.geometrynodemeshfacesetboundaries*", "modeling/geometry_nodes/mesh/read/face_set_boundaries.html#bpy-types-geometrynodemeshfacesetboundaries"), ("bpy.types.geometrynodemeshfacesetboundaries*", "modeling/geometry_nodes/mesh/read/face_group_boundaries.html#bpy-types-geometrynodemeshfacesetboundaries"),
("bpy.types.greasepencil.curve_edit_threshold*", "grease_pencil/modes/edit/curve_editing.html#bpy-types-greasepencil-curve-edit-threshold"), ("bpy.types.greasepencil.curve_edit_threshold*", "grease_pencil/modes/edit/curve_editing.html#bpy-types-greasepencil-curve-edit-threshold"),
("bpy.types.lineartgpencilmodifier.use_crease*", "grease_pencil/modifiers/generate/line_art.html#bpy-types-lineartgpencilmodifier-use-crease"), ("bpy.types.lineartgpencilmodifier.use_crease*", "grease_pencil/modifiers/generate/line_art.html#bpy-types-lineartgpencilmodifier-use-crease"),
("bpy.types.lineartgpencilmodifier.use_shadow*", "grease_pencil/modifiers/generate/line_art.html#bpy-types-lineartgpencilmodifier-use-shadow"), ("bpy.types.lineartgpencilmodifier.use_shadow*", "grease_pencil/modifiers/generate/line_art.html#bpy-types-lineartgpencilmodifier-use-shadow"),
@ -1020,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"),
@ -1417,6 +1389,7 @@ url_manual_mapping = (
("bpy.types.functionnodereplacestring*", "modeling/geometry_nodes/utilities/text/replace_string.html#bpy-types-functionnodereplacestring"), ("bpy.types.functionnodereplacestring*", "modeling/geometry_nodes/utilities/text/replace_string.html#bpy-types-functionnodereplacestring"),
("bpy.types.functionnodeseparatecolor*", "modeling/geometry_nodes/utilities/color/separate_color.html#bpy-types-functionnodeseparatecolor"), ("bpy.types.functionnodeseparatecolor*", "modeling/geometry_nodes/utilities/color/separate_color.html#bpy-types-functionnodeseparatecolor"),
("bpy.types.functionnodevaluetostring*", "modeling/geometry_nodes/utilities/text/value_to_string.html#bpy-types-functionnodevaluetostring"), ("bpy.types.functionnodevaluetostring*", "modeling/geometry_nodes/utilities/text/value_to_string.html#bpy-types-functionnodevaluetostring"),
("bpy.types.geometrynodeblurattribute*", "modeling/geometry_nodes/attribute/blur_attribute.html#bpy-types-geometrynodeblurattribute"),
("bpy.types.geometrynodecurvetopoints*", "modeling/geometry_nodes/curve/operations/curve_to_points.html#bpy-types-geometrynodecurvetopoints"), ("bpy.types.geometrynodecurvetopoints*", "modeling/geometry_nodes/curve/operations/curve_to_points.html#bpy-types-geometrynodecurvetopoints"),
("bpy.types.geometrynodeedgesofcorner*", "modeling/geometry_nodes/mesh/topology/edges_of_corner.html#bpy-types-geometrynodeedgesofcorner"), ("bpy.types.geometrynodeedgesofcorner*", "modeling/geometry_nodes/mesh/topology/edges_of_corner.html#bpy-types-geometrynodeedgesofcorner"),
("bpy.types.geometrynodeedgesofvertex*", "modeling/geometry_nodes/mesh/topology/edges_of_vertex.html#bpy-types-geometrynodeedgesofvertex"), ("bpy.types.geometrynodeedgesofvertex*", "modeling/geometry_nodes/mesh/topology/edges_of_vertex.html#bpy-types-geometrynodeedgesofvertex"),
@ -2055,7 +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.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"),
@ -2111,7 +2084,6 @@ url_manual_mapping = (
("bpy.types.geometrynodeboundbox*", "modeling/geometry_nodes/geometry/operations/bounding_box.html#bpy-types-geometrynodeboundbox"), ("bpy.types.geometrynodeboundbox*", "modeling/geometry_nodes/geometry/operations/bounding_box.html#bpy-types-geometrynodeboundbox"),
("bpy.types.geometrynodecurvearc*", "modeling/geometry_nodes/curve/primitives/arc.html#bpy-types-geometrynodecurvearc"), ("bpy.types.geometrynodecurvearc*", "modeling/geometry_nodes/curve/primitives/arc.html#bpy-types-geometrynodecurvearc"),
("bpy.types.geometrynodedualmesh*", "modeling/geometry_nodes/mesh/operations/dual_mesh.html#bpy-types-geometrynodedualmesh"), ("bpy.types.geometrynodedualmesh*", "modeling/geometry_nodes/mesh/operations/dual_mesh.html#bpy-types-geometrynodedualmesh"),
("bpy.types.geometrynodematerial*", "-1"),
("bpy.types.geometrynodemeshcone*", "modeling/geometry_nodes/mesh/primitives/cone.html#bpy-types-geometrynodemeshcone"), ("bpy.types.geometrynodemeshcone*", "modeling/geometry_nodes/mesh/primitives/cone.html#bpy-types-geometrynodemeshcone"),
("bpy.types.geometrynodemeshcube*", "modeling/geometry_nodes/mesh/primitives/cube.html#bpy-types-geometrynodemeshcube"), ("bpy.types.geometrynodemeshcube*", "modeling/geometry_nodes/mesh/primitives/cube.html#bpy-types-geometrynodemeshcube"),
("bpy.types.geometrynodemeshgrid*", "modeling/geometry_nodes/mesh/primitives/grid.html#bpy-types-geometrynodemeshgrid"), ("bpy.types.geometrynodemeshgrid*", "modeling/geometry_nodes/mesh/primitives/grid.html#bpy-types-geometrynodemeshgrid"),
@ -3051,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)]}),
@ -3478,7 +3478,8 @@ def km_animation_channels(params):
# Selection. # Selection.
*_template_items_select_actions(params, "anim.channels_select_all"), *_template_items_select_actions(params, "anim.channels_select_all"),
("anim.channels_select_box", {"type": 'B', "value": 'PRESS'}, None), ("anim.channels_select_box", {"type": 'B', "value": 'PRESS'}, None),
("anim.channels_select_box", {"type": 'LEFTMOUSE', "value": 'CLICK_DRAG'}, None), ("anim.channels_select_box", {"type": 'LEFTMOUSE', "value": 'CLICK_DRAG'},
{"properties": [("extend", False)]}),
("anim.channels_select_box", {"type": 'LEFTMOUSE', "value": 'CLICK_DRAG', "shift": True}, ("anim.channels_select_box", {"type": 'LEFTMOUSE', "value": 'CLICK_DRAG', "shift": True},
{"properties": [("extend", True)]}), {"properties": [("extend", True)]}),
("anim.channels_select_box", {"type": 'LEFTMOUSE', "value": 'CLICK_DRAG', "ctrl": True}, ("anim.channels_select_box", {"type": 'LEFTMOUSE', "value": 'CLICK_DRAG', "ctrl": True},
@ -4729,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:
@ -5627,6 +5628,11 @@ def km_curves(params):
("curves.disable_selection", {"type": 'ONE', "value": 'PRESS', "alt": True}, None), ("curves.disable_selection", {"type": 'ONE', "value": 'PRESS', "alt": True}, None),
("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.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
@ -5681,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),
]) ])
@ -6343,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,135 @@ 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,
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

@ -1056,7 +1056,7 @@ class WM_OT_url_open_preset(Operator):
return "https://www.blender.org/download/releases/%d-%d/" % bpy.app.version[:2] return "https://www.blender.org/download/releases/%d-%d/" % bpy.app.version[:2]
def _url_from_manual(self, _context): def _url_from_manual(self, _context):
return "https://docs.blender.org/manual/en/%d.%d/" % bpy.app.version[:2] return "https://docs.blender.org/manual/%s/%d.%d/" % (bpy.utils.manual_language_code(), *bpy.app.version[:2])
def _url_from_api(self, _context): def _url_from_api(self, _context):
return "https://docs.blender.org/api/%d.%d/" % bpy.app.version[:2] return "https://docs.blender.org/api/%d.%d/" % bpy.app.version[:2]
@ -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

@ -35,19 +35,10 @@ def draw_node_group_add_menu(context, layout):
if node_tree: if node_tree:
from nodeitems_builtins import node_tree_group_type from nodeitems_builtins import node_tree_group_type
def contains_group(nodetree, group):
if nodetree == group:
return True
for node in nodetree.nodes:
if node.bl_idname in node_tree_group_type.values() and node.node_tree is not None:
if contains_group(node.node_tree, group):
return True
return False
groups = [ groups = [
group for group in context.blend_data.node_groups group for group in context.blend_data.node_groups
if (group.bl_idname == node_tree.bl_idname and if (group.bl_idname == node_tree.bl_idname and
not contains_group(group, node_tree) and not group.contains_tree(node_tree) and
not group.name.startswith('.')) not group.name.startswith('.'))
] ]
if groups: if groups:

View File

@ -485,7 +485,6 @@ class DATA_PT_customdata(MeshButtonsPanel, Panel):
layout.use_property_split = True layout.use_property_split = True
layout.use_property_decorate = False layout.use_property_decorate = False
obj = context.object
me = context.mesh me = context.mesh
col = layout.column() col = layout.column()
@ -605,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

@ -62,7 +62,6 @@ class PARTICLE_MT_context_menu(Menu):
def draw(self, context): def draw(self, context):
layout = self.layout layout = self.layout
psys = context.particle_system psys = context.particle_system
experimental = context.preferences.experimental
props = layout.operator( props = layout.operator(
"particle.copy_particle_systems", "particle.copy_particle_systems",
@ -508,7 +507,7 @@ class PARTICLE_PT_hair_dynamics_structure(ParticleButtonsPanel, Panel):
sub.prop(psys.settings, "bending_random", text="Random") sub.prop(psys.settings, "bending_random", text="Random")
col.prop(cloth, "bending_damping", text="Damping") col.prop(cloth, "bending_damping", text="Damping")
# XXX has no noticeable effect with stiff hair structure springs # XXX has no noticeable effect with stiff hair structure springs
#col.prop(cloth, "spring_damping", text="Damping") # col.prop(cloth, "spring_damping", text="Damping")
class PARTICLE_PT_hair_dynamics_volume(ParticleButtonsPanel, Panel): class PARTICLE_PT_hair_dynamics_volume(ParticleButtonsPanel, Panel):
@ -1100,7 +1099,7 @@ class PARTICLE_PT_physics_relations(ParticleButtonsPanel, Panel):
if part.physics_type == 'KEYED': if part.physics_type == 'KEYED':
col = layout.column() col = layout.column()
# doesn't work yet # doesn't work yet
#col.alert = key.valid # col.alert = key.valid
col.prop(key, "object") col.prop(key, "object")
col.prop(key, "system", text="System") col.prop(key, "system", text="System")
sub = col.column(align=True) sub = col.column(align=True)
@ -1110,7 +1109,7 @@ class PARTICLE_PT_physics_relations(ParticleButtonsPanel, Panel):
elif part.physics_type == 'BOIDS': elif part.physics_type == 'BOIDS':
sub = layout.column() sub = layout.column()
# doesn't work yet # doesn't work yet
#sub.alert = key.valid # sub.alert = key.valid
sub.prop(key, "object") sub.prop(key, "object")
sub.prop(key, "system", text="System") sub.prop(key, "system", text="System")
layout.prop(key, "alliance") layout.prop(key, "alliance")
@ -1157,7 +1156,7 @@ class PARTICLE_PT_physics_fluid_interaction(ParticleButtonsPanel, Panel):
if key: if key:
sub = layout.column() sub = layout.column()
# doesn't work yet # doesn't work yet
#sub.alert = key.valid # sub.alert = key.valid
sub.prop(key, "object") sub.prop(key, "object")
sub.prop(key, "system", text="System") sub.prop(key, "system", text="System")

View File

@ -641,7 +641,6 @@ class RENDER_PT_eevee_next_film(RenderButtonsPanel, Panel):
scene = context.scene scene = context.scene
rd = scene.render rd = scene.render
props = scene.eevee
col = layout.column() col = layout.column()
col.prop(rd, "filter_size") col.prop(rd, "filter_size")

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

@ -1426,34 +1426,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)
# ----------------------------------------------------------------------------- # -----------------------------------------------------------------------------
@ -2321,16 +2327,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")),
), ),
) )
@ -2492,6 +2495,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,8 +2063,16 @@ 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.separator()
layout.menu("VIEW3D_MT_edit_curves_select_more_less")
class VIEW3D_MT_select_sculpt_curves(Menu): class VIEW3D_MT_select_sculpt_curves(Menu):
@ -2113,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:
@ -2267,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')
@ -3866,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()
@ -5307,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):
@ -5375,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:
@ -6706,27 +6730,26 @@ class VIEW3D_PT_overlay_sculpt(Panel):
def poll(cls, context): def poll(cls, context):
return ( return (
context.mode == 'SCULPT' and context.mode == 'SCULPT' and
(context.sculpt_object and context.tool_settings.sculpt) context.sculpt_object
) )
def draw(self, context): def draw(self, context):
layout = self.layout layout = self.layout
tool_settings = context.tool_settings tool_settings = context.tool_settings
sculpt = tool_settings.sculpt
view = context.space_data view = context.space_data
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

@ -76,21 +76,11 @@ def node_group_items(context):
yield NodeItemCustom(draw=lambda self, layout, context: layout.separator()) yield NodeItemCustom(draw=lambda self, layout, context: layout.separator())
def contains_group(nodetree, group):
if nodetree == group:
return True
else:
for node in nodetree.nodes:
if node.bl_idname in node_tree_group_type.values() and node.node_tree is not None:
if contains_group(node.node_tree, group):
return True
return False
for group in context.blend_data.node_groups: for group in context.blend_data.node_groups:
if group.bl_idname != ntree.bl_idname: if group.bl_idname != ntree.bl_idname:
continue continue
# filter out recursive groups # filter out recursive groups
if contains_group(group, ntree): if group.contains_tree(ntree):
continue continue
# filter out hidden nodetrees # filter out hidden nodetrees
if group.name.startswith('.'): if group.name.startswith('.'):

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()

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